summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Styk <mastyk@redhat.com>2019-05-21 14:06:56 +0200
committerMartin Styk <mastyk@redhat.com>2019-05-21 14:07:12 +0200
commite568a899ee3cc624cdf4257b65d0c9ffcdc0da34 (patch)
tree766e08ec80167dd0f40207b050d20b351bd1adb4
parent4f269a8f2a4d3f08b3eac13285a654e1cb0ce4c3 (diff)
parentf82355fbf45e456f29df852401a06221da288548 (diff)
Merge branch 'release-26' into develop
Change-Id: I98a4ad3bc08a2414e22a2a4d1cf2009156bca65a Signed-off-by: Martin Styk <mastyk@redhat.com>
-rw-r--r--Client/setup.py2
-rw-r--r--Client/src/bkr/client/commands/cmd_job_list.py31
-rw-r--r--Client/src/bkr/client/commands/cmd_system_details.py21
-rw-r--r--Client/src/bkr/client/commands/cmd_update_openstack_trust.py57
-rw-r--r--Common/bkr/common/__init__.py2
-rw-r--r--Common/setup.py2
-rw-r--r--IntegrationTests/setup.py2
-rw-r--r--IntegrationTests/src/bkr/inttest/__init__.py22
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_distro_trees_list.py9
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_distro_trees_verify.py3
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_distros_edit_version.py6
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_distros_list.py12
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_distros_tag.py4
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_distros_untag.py2
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_group_create.py16
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_group_list.py2
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_group_members.py2
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_group_modify.py42
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_harness_test.py6
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_job_cancel.py10
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_job_clone.py6
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_job_comment.py8
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_job_delete.py21
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_job_list.py78
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_job_logs.py5
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_job_modify.py6
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_job_results.py4
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_job_submit.py2
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_job_watch.py6
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_labcontroller_create.py3
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_labcontroller_list.py1
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_labcontroller_modify.py4
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_loan_management.py6
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_machine_test.py6
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_policy_list.py2
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_policy_revoke.py1
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_pool_list.py4
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_pool_systems.py6
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_remove_account.py13
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_system_delete.py10
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_system_details.py14
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_system_list.py53
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_system_power.py14
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_system_release.py6
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_system_status.py8
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_task_add.py18
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_task_details.py9
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_update_openstack_trust.py46
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_update_prefs.py2
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_user_modify.py5
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_watchdog_extend.py6
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_watchdogs_extend.py7
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_watchdogs_show.py2
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_whoami.py8
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_wizard.py8
-rw-r--r--IntegrationTests/src/bkr/inttest/client/test_workflow_simple.py261
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/AtomicHost-defaults.expected20
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-harness-contained-custom.expected16
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-harness-contained.expected20
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-scheduler-defaults.expected18
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/Fedorarawhide-scheduler-defaults.expected14
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/RHVH-defaults.expected18
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux3-scheduler-defaults.expected18
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux4-scheduler-defaults.expected18
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-defaults-beaker-create-kickstart.expected18
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-defaults.expected18
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-guest.expected18
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-manual.expected18
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux7-scheduler-defaults.expected18
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux7-scheduler-manual.expected18
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinuxAlternateArchitectures7-scheduler-defaults.expected18
-rw-r--r--IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinuxServer5-scheduler-defaults.expected18
-rw-r--r--IntegrationTests/src/bkr/inttest/server/selenium/test_prefs.py13
-rw-r--r--IntegrationTests/src/bkr/inttest/server/selenium/test_reserve_system.py16
-rw-r--r--IntegrationTests/src/bkr/inttest/server/selenium/test_system_search.py30
-rw-r--r--IntegrationTests/src/bkr/inttest/server/selenium/test_systems.py2
-rw-r--r--IntegrationTests/src/bkr/inttest/server/test_beakerd.py170
-rw-r--r--IntegrationTests/src/bkr/inttest/server/test_kickstart.py14
-rw-r--r--LabController/aux/anamon1
-rw-r--r--LabController/aux/anamon31
-rw-r--r--LabController/setup.py2
-rwxr-xr-xMisc/generate_release_notes.py31
-rw-r--r--Server/assets/recipe.less4
-rw-r--r--Server/bkr/server/controller_utilities.py4
-rw-r--r--Server/bkr/server/dynamic_virt.py368
-rw-r--r--Server/bkr/server/job_matrix.py2
-rw-r--r--Server/bkr/server/jobs.py28
-rw-r--r--Server/bkr/server/model/identity.py3
-rw-r--r--Server/bkr/server/model/inventory.py3
-rw-r--r--Server/bkr/server/model/scheduler.py36
-rw-r--r--Server/bkr/server/reserve_workflow.py9
-rw-r--r--Server/bkr/server/search_utility.py16
-rw-r--r--Server/bkr/server/snippets/beah11
-rw-r--r--Server/bkr/server/snippets/docker_harness20
-rw-r--r--Server/bkr/server/snippets/harness9
-rw-r--r--Server/bkr/server/snippets/rhts_post7
-rw-r--r--Server/bkr/server/tests/data_setup.py47
-rw-r--r--Server/bkr/server/tools/beakerd.py52
-rw-r--r--Server/bkr/server/tools/ipxe_image.py50
-rwxr-xr-xServer/bkr/server/tools/product_update.py15
-rw-r--r--Server/bkr/server/user.py47
-rw-r--r--Server/server.cfg101
-rw-r--r--Server/setup.py2
-rw-r--r--beaker.spec12
-rw-r--r--documentation/admin-guide/man/beaker-create-ipxe-image.rst56
-rw-r--r--documentation/admin-guide/openstack.rst61
-rw-r--r--documentation/user-guide/job-xml.rst44
-rw-r--r--documentation/user-guide/task-metadata.rst352
-rw-r--r--documentation/user-guide/tasks.rst39
-rw-r--r--documentation/whats-new/release-26.rst49
110 files changed, 1995 insertions, 930 deletions
diff --git a/Client/setup.py b/Client/setup.py
index 7b1abec..d90b4b0 100644
--- a/Client/setup.py
+++ b/Client/setup.py
@@ -22,7 +22,7 @@ def bash_completion_dir():
setup(
name='beaker-client',
- version='26.4',
+ version='26.5',
description='Command-line client for interacting with Beaker',
author='Red Hat, Inc.',
author_email='beaker-devel@lists.fedorahosted.org',
diff --git a/Client/src/bkr/client/commands/cmd_job_list.py b/Client/src/bkr/client/commands/cmd_job_list.py
index 7ef186f..4818f40 100644
--- a/Client/src/bkr/client/commands/cmd_job_list.py
+++ b/Client/src/bkr/client/commands/cmd_job_list.py
@@ -162,6 +162,19 @@ class Job_List(BeakerCommand):
)
self.parser.add_option(
+ "-g",
+ "--group",
+ help="Jobs with a particular group"
+ )
+
+ self.parser.add_option(
+ "--my-groups", "--mygroups",
+ action="store_true",
+ dest='my-groups',
+ help="Jobs with a particular group that querying user is part of"
+ )
+
+ self.parser.add_option(
"-w",
"--whiteboard",
metavar='STRING',
@@ -170,7 +183,6 @@ class Job_List(BeakerCommand):
self.parser.add_option(
"--mine",
- default=False,
action="store_true",
help="Jobs owned by the querying user"
)
@@ -219,6 +231,8 @@ class Job_List(BeakerCommand):
product = kwargs.pop('product', None)
complete_days = kwargs.pop('completeDays', None)
owner = kwargs.pop('owner', None)
+ group = kwargs.pop('group', None)
+ my_groups = kwargs.pop('my-groups', None)
whiteboard = kwargs.pop('whiteboard', None)
mine = kwargs.pop('mine', None)
limit = kwargs.pop('limit', None)
@@ -239,17 +253,6 @@ class Job_List(BeakerCommand):
if complete_days is not None and complete_days < 1:
self.parser.error('Please pass a positive integer to completeDays')
- if (complete_days is None
- and tags is None
- and family is None
- and product is None
- and owner is None
- and mine is None
- and whiteboard is None
- ):
- self.parser.error('Please pass either the completeDays time delta, a tag'
- ', product, family, or owner')
-
if args:
self.parser.error('This command does not accept any arguments')
@@ -262,13 +265,15 @@ class Job_List(BeakerCommand):
is_finished = False
self.set_hub(**kwargs)
- if mine:
+ if mine or my_groups:
self.hub._login()
jobs = self.hub.jobs.filter(dict(tags=tags,
daysComplete=complete_days,
family=family,
product=product,
owner=owner,
+ group=group,
+ my_groups=my_groups,
whiteboard=whiteboard,
mine=mine,
minid=minid,
diff --git a/Client/src/bkr/client/commands/cmd_system_details.py b/Client/src/bkr/client/commands/cmd_system_details.py
index 9255da0..cdf67a1 100644
--- a/Client/src/bkr/client/commands/cmd_system_details.py
+++ b/Client/src/bkr/client/commands/cmd_system_details.py
@@ -14,19 +14,20 @@ Synopsis
--------
:program:`bkr system-details` [*options*] <fqdn>
+| [:option:'--format' <json_or_xml>]
Description
-----------
Prints to stdout an RDF/XML description of the given system.
-A copy of the Beaker RDF schema definition is installed as
+A copy of the Beaker RDF schema definition is installed as
:file:`/usr/lib/python2.{x}/bkr/common/schema/beaker-inventory.ttl`.
Options
-------
-Common :program:`bkr` options are described in the :ref:`Options
+Common :program:`bkr` options are described in the :ref:`Options
<common-options>` section of :manpage:`bkr(1)`.
Exit status
@@ -41,6 +42,10 @@ Export RDF/XML for a particular system::
bkr system-details system1.example.invalid
+Display details of a system in JSON format::
+
+ bkr system-details --format json system1.example.invalid
+
See also
--------
@@ -62,13 +67,23 @@ class System_Details(BeakerCommand):
def options(self):
self.parser.usage = "%%prog %s [options] <fqdn>" % self.normalized_name
+ self.parser.add_option('--format',
+ type='choice',
+ choices=['json', 'xml'],
+ default='xml',
+ help='Display results in FORMAT: '
+ 'json, xml [default: %default]')
def run(self, *args, **kwargs):
if len(args) != 1:
self.parser.error('Exactly one system fqdn must be given')
fqdn = args[0]
+ format = kwargs.get('format')
- system_url = 'view/%s?tg_format=rdfxml' % parse.quote(fqdn, '')
+ if format == 'json':
+ system_url = 'systems/%s/' % parse.quote(fqdn, '')
+ else:
+ system_url = 'view/%s?tg_format=rdfxml' % parse.quote(fqdn, '')
# This will log us in using XML-RPC
self.set_hub(**kwargs)
diff --git a/Client/src/bkr/client/commands/cmd_update_openstack_trust.py b/Client/src/bkr/client/commands/cmd_update_openstack_trust.py
index ed290c2..3e36769 100644
--- a/Client/src/bkr/client/commands/cmd_update_openstack_trust.py
+++ b/Client/src/bkr/client/commands/cmd_update_openstack_trust.py
@@ -20,6 +20,8 @@ Synopsis
| :option:`--os-username` <username>
| :option:`--os-password` <password>
| :option:`--os-project-name` <project-name>
+| [:option:`--os-user-domain-name` <user-domain-name>]
+| [:option:`--os-project-domain-name` <project-domain-name>]
Description
-----------
@@ -34,9 +36,30 @@ OpenStack integration (see :ref:`openstack`).
Options
-------
-.. option:: --os-username <username>, --os-password <password>, --os-project-name <project-name>
+.. option:: --os-username <username>
- OpenStack credentials for establishing a new trust between Beaker and the given user.
+ OpenStack user name for establishing a new trust between Beaker and the
+ given user.
+
+.. option:: --os-password <password>
+
+ OpenStack user password for establishing a new trust between Beaker and
+ the given user.
+
+.. option:: --os-project-name <project-name>
+
+ OpenStack project name for establishing a new trust between Beaker and
+ the given user.
+
+.. option:: --os-user-domain-name <user-domain-name>
+
+ OpenStack user domain name for establishing a new trust between Beaker
+ and the given user.
+
+.. option:: --os-project-domain-name <project-domain-name>
+
+ OpenStack project domain name for establishing a new trust between Beaker
+ and the given user.
Common :program:`bkr` options are described in the :ref:`Options
<common-options>` section of :manpage:`bkr(1)`.
@@ -51,8 +74,12 @@ Examples
Add a new OpenStack trust to your user::
- bkr update-openstack-trust --os-username=user1 --os-password='supersecret' \\
- --os-project-name=test-project
+ bkr update-openstack-trust \
+ --os-username=user1 \
+ --os-password='supersecret' \
+ --os-project-name=beaker \
+ --os-user-domain-name=domain.com \
+ --os-project-domain-name=domain.com
See also
--------
@@ -60,7 +87,6 @@ See also
:manpage:`bkr(1)`
"""
-
from bkr.client import BeakerCommand
@@ -82,16 +108,31 @@ class Update_Openstack_Trust(BeakerCommand):
action='store',
type='string',
help='OpenStack project name')
+ self.parser.add_option('--os-project-domain-name',
+ action='store',
+ type='string',
+ help='OpenStack project domain name')
+ self.parser.add_option('--os-user-domain-name',
+ action='store',
+ type='string',
+ help='OpenStack user domain name')
def run(self, *args, **kwargs):
self.set_hub(**kwargs)
requests_session = self.requests_session()
data = {'openstack_username': kwargs.get('os_username'),
'openstack_password': kwargs.get('os_password'),
- 'openstack_project_name': kwargs.get('os_project_name'),
- }
+ 'openstack_project_name': kwargs.get('os_project_name')}
if not all(data.values()):
- self.parser.error('All options are required: --os-username, --os-password and --os-project-name')
+ self.parser.error('The following options are required: '
+ ' --os-username, --os-password and --os-project-name')
+
+ # These command line arguments are optional because they were not
+ # required for all OpenStack instances.
+ if kwargs.get('os_project_domain_name'):
+ data["openstack_project_domain_name"] = kwargs.get('os_project_domain_name')
+ if kwargs.get('os_user_domain_name'):
+ data["openstack_user_domain_name"] = kwargs.get('os_user_domain_name')
res = requests_session.put('users/+self/keystone-trust', json=data)
res.raise_for_status()
diff --git a/Common/bkr/common/__init__.py b/Common/bkr/common/__init__.py
index 673f7f2..5835a79 100644
--- a/Common/bkr/common/__init__.py
+++ b/Common/bkr/common/__init__.py
@@ -2,4 +2,4 @@
# code in bkr.__init__), the version details are retrieved from here in
# order to correctly handle module shadowing on sys.path
-__version__ = '26.4'
+__version__ = '26.5'
diff --git a/Common/setup.py b/Common/setup.py
index 6a51e5d..b366f78 100644
--- a/Common/setup.py
+++ b/Common/setup.py
@@ -12,7 +12,7 @@ from setuptools import setup, find_packages
setup(
name='beaker-common',
- version='26.4',
+ version='26.5',
description='Common components for Beaker packages',
author='Red Hat, Inc.',
author_email='beaker-devel@lists.fedorahosted.org',
diff --git a/IntegrationTests/setup.py b/IntegrationTests/setup.py
index 3ce95cd..8ae0f44 100644
--- a/IntegrationTests/setup.py
+++ b/IntegrationTests/setup.py
@@ -12,7 +12,7 @@ def get_compose_layout():
setup(
name='beaker-integration-tests',
- version='26.4',
+ version='26.5',
description='Integration tests for Beaker',
author='Red Hat, Inc.',
author_email='beaker-devel@lists.fedorahosted.org',
diff --git a/IntegrationTests/src/bkr/inttest/__init__.py b/IntegrationTests/src/bkr/inttest/__init__.py
index 2714f8f..d8af976 100644
--- a/IntegrationTests/src/bkr/inttest/__init__.py
+++ b/IntegrationTests/src/bkr/inttest/__init__.py
@@ -303,22 +303,16 @@ def _glance():
password = os.environ['OPENSTACK_DUMMY_PASSWORD']
project_name = os.environ['OPENSTACK_DUMMY_PROJECT_NAME']
auth_url = turbogears.config.get('openstack.identity_api_url')
+ user_domain_name = os.environ.get('OPENSTACK_DUMMY_USER_DOMAIN_NAME')
+ project_domain_name = os.environ.get('OPENSTACK_DUMMY_PROJECT_DOMAIN_NAME')
- # 2019/01/30 - Based on the URL below, using the method call
- # keystoneclient.v3.client.Client to get the keystone is deprecated and
- # will be removed in v2.0 of the code.
- # Ticket filed to fix: bug #1671054
- # https://docs.openstack.org/python-keystoneclient/latest/using-api-v3.html
- user_domain_name = None
- if 'OPENSTACK_USER_DOMAIN_NAME' in os.environ:
- user_domain_name = os.environ['OPENSTACK_USER_DOMAIN_NAME']
keystone = keystoneclient.v3.client.Client(
- username=username,
- password=password,
- user_domain_name=user_domain_name,
- project_name=project_name,
- auth_url=auth_url)
-
+ username=username,
+ password=password,
+ project_name=project_name,
+ user_domain_name=user_domain_name,
+ project_domain_name=project_domain_name,
+ auth_url=auth_url)
glance_url = keystone.service_catalog.url_for(
service_type='image', endpoint_type='publicURL')
return glanceclient.v2.client.Client(glance_url, token=keystone.auth_token)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_distro_trees_list.py b/IntegrationTests/src/bkr/inttest/client/test_distro_trees_list.py
index fa201cc..5cad14f 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_distro_trees_list.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_distro_trees_list.py
@@ -4,7 +4,6 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-import unittest
import datetime
import json
from turbogears.database import session
@@ -43,7 +42,7 @@ class DistroTreesListTest(DatabaseTestCase):
try:
run_client(['bkr', 'distro-trees-list', '--name', 'NOTEXIST'])
fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assertEqual(e.stderr_output, 'Nothing Matches\n')
@@ -98,9 +97,9 @@ class DistroTreesListTest(DatabaseTestCase):
def test_output_is_ordered_by_date_created(self):
with session.begin():
- # Insert them in reverse order (oldest last), just because the most
- # likely regression here is that we aren't sorting at all and thus
- # the output is in database insertion order. So this proves that's
+ # Insert them in reverse order (oldest last), just because the most
+ # likely regression here is that we aren't sorting at all and thus
+ # the output is in database insertion order. So this proves that's
# not happening.
data_setup.create_distro_tree(date_created=datetime.datetime(2021, 1, 1, 0, 0))
data_setup.create_distro_tree(date_created=datetime.datetime(2004, 1, 1, 0, 0))
diff --git a/IntegrationTests/src/bkr/inttest/client/test_distro_trees_verify.py b/IntegrationTests/src/bkr/inttest/client/test_distro_trees_verify.py
index e6d3ec1..9327381 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_distro_trees_verify.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_distro_trees_verify.py
@@ -4,9 +4,8 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-from turbogears.database import session
from bkr.inttest import data_setup, with_transaction
-from bkr.inttest.client import run_client, ClientError, ClientTestCase
+from bkr.inttest.client import run_client, ClientTestCase
class DistroTreesVerifyTest(ClientTestCase):
diff --git a/IntegrationTests/src/bkr/inttest/client/test_distros_edit_version.py b/IntegrationTests/src/bkr/inttest/client/test_distros_edit_version.py
index a816ce1..e93f33a 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_distros_edit_version.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_distros_edit_version.py
@@ -1,4 +1,3 @@
-
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
@@ -6,7 +5,8 @@
from turbogears.database import session
from bkr.inttest import data_setup
-from bkr.inttest.client import run_client, ClientError, ClientTestCase
+from bkr.inttest.client import run_client, ClientTestCase
+
class DistrosEditVersionTest(ClientTestCase):
@@ -14,7 +14,7 @@ class DistrosEditVersionTest(ClientTestCase):
with session.begin():
distro = data_setup.create_distro()
run_client(['bkr', 'distros-edit-version', '--name', distro.name,
- 'SillyVersion2.1'])
+ 'SillyVersion2.1'])
with session.begin():
session.refresh(distro)
self.assertEquals(distro.osversion.osmajor.osmajor, u'SillyVersion2')
diff --git a/IntegrationTests/src/bkr/inttest/client/test_distros_list.py b/IntegrationTests/src/bkr/inttest/client/test_distros_list.py
index 729c928..35d11fe 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_distros_list.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_distros_list.py
@@ -9,7 +9,7 @@ import datetime
from turbogears.database import session
from bkr.inttest import data_setup, with_transaction
from bkr.inttest.client import run_client, ClientError, ClientTestCase
-from bkr.server.model import LabControllerDistroTree, Distro
+from bkr.server.model import Distro
class DistrosListTest(ClientTestCase):
@@ -41,16 +41,16 @@ class DistrosListTest(ClientTestCase):
try:
run_client(['bkr', 'distros-list', '--name', self.distro.name,
'--tag', 'NOTEXIST'])
- fail('should raise')
- except ClientError, e:
+ self.fail('should raise')
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assertEqual(e.stderr_output, 'Nothing Matches\n')
def test_output_is_ordered_by_date_created(self):
with session.begin():
- # Insert them in reverse order (oldest last), just because the most
- # likely regression here is that we aren't sorting at all and thus
- # the output is in database insertion order. So this proves that's
+ # Insert them in reverse order (oldest last), just because the most
+ # likely regression here is that we aren't sorting at all and thus
+ # the output is in database insertion order. So this proves that's
# not happening.
new_distro = data_setup.create_distro(date_created=datetime.datetime(2021, 1, 1, 0, 0))
data_setup.create_distro_tree(distro=new_distro)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_distros_tag.py b/IntegrationTests/src/bkr/inttest/client/test_distros_tag.py
index 3140966..d05c59e 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_distros_tag.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_distros_tag.py
@@ -23,7 +23,7 @@ class DistrosTagTest(ClientTestCase):
try:
run_client(['bkr', 'distros-tag'])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 2)
self.assertIn('Please specify a tag', e.stderr_output)
@@ -31,7 +31,7 @@ class DistrosTagTest(ClientTestCase):
try:
run_client(['bkr', 'distros-tag', 'asdf'])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 2)
self.assertIn('If you really want to tag every distro in Beaker, use --name=%', e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_distros_untag.py b/IntegrationTests/src/bkr/inttest/client/test_distros_untag.py
index 73f370f..8fed848 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_distros_untag.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_distros_untag.py
@@ -6,7 +6,7 @@
from turbogears.database import session
from bkr.inttest import data_setup
-from bkr.inttest.client import run_client, ClientError, ClientTestCase
+from bkr.inttest.client import run_client, ClientTestCase
class DistrosUntagTest(ClientTestCase):
diff --git a/IntegrationTests/src/bkr/inttest/client/test_group_create.py b/IntegrationTests/src/bkr/inttest/client/test_group_create.py
index cf0e2d6..9b7635a 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_group_create.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_group_create.py
@@ -54,14 +54,14 @@ class GroupCreateTest(ClientTestCase):
out = run_client(['bkr', 'group-create',
group_name, group_name])
self.fail('Must fail or die')
- except ClientError,e:
+ except ClientError as e:
self.assert_('Exactly one group name must be specified' in
e.stderr_output, e.stderr_output)
try:
out = run_client(['bkr', 'group-create',
'areallylonggroupname'*20])
self.fail('Must fail or die')
- except ClientError,e:
+ except ClientError as e:
self.assertIn(
'Group name must be not more than 255 characters long',
e.stderr_output)
@@ -71,7 +71,7 @@ class GroupCreateTest(ClientTestCase):
'A really long group display name'*20,
'agroup'])
self.fail('Must fail or die')
- except ClientError,e:
+ except ClientError as e:
self.assertIn(
'Group display name must be not more than 255 characters long',
e.stderr_output)
@@ -104,7 +104,7 @@ class GroupCreateTest(ClientTestCase):
group_name],
config = rand_client_config)
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('Only admins can create LDAP groups' in
e.stderr_output)
@@ -118,7 +118,7 @@ class GroupCreateTest(ClientTestCase):
'--display-name', 'Test Display Name',
group_name])
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('LDAP is not enabled', e.stderr_output)
def test_group_passwords(self):
@@ -129,7 +129,7 @@ class GroupCreateTest(ClientTestCase):
'--root-password', 'fa1l',
group_name])
self.fail('Expected to fail due to short password')
- except ClientError, e:
+ except ClientError as e:
# Number of req chars was changed in RPM, however RHEL is using older one
# RHEL requires 7, Fedora requires 8 at this moment
self.assertTrue(
@@ -141,7 +141,7 @@ class GroupCreateTest(ClientTestCase):
group_name])
self.fail('Expected to fail due to dictionary words')
- except ClientError, e:
+ except ClientError as e:
self.assertTrue('The group root password fails the dictionary check' in
e.stderr_output, e.stderr_output)
out = run_client(['bkr', 'group-create',
@@ -162,7 +162,7 @@ class GroupCreateTest(ClientTestCase):
out = run_client(['bkr', 'group-create',
group_name])
self.fail('Must fail or die')
- except ClientError,e:
+ except ClientError as e:
self.assert_('Group already exists' in e.stderr_output,
e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_group_list.py b/IntegrationTests/src/bkr/inttest/client/test_group_list.py
index ddb8bf8..1879ec5 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_group_list.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_group_list.py
@@ -1,6 +1,6 @@
from bkr.server.model import session
from bkr.inttest import data_setup
-from bkr.inttest.client import run_client, ClientError, ClientTestCase, create_client_config
+from bkr.inttest.client import run_client, ClientError, ClientTestCase
class GroupList(ClientTestCase):
diff --git a/IntegrationTests/src/bkr/inttest/client/test_group_members.py b/IntegrationTests/src/bkr/inttest/client/test_group_members.py
index dcac245..197ac92 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_group_members.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_group_members.py
@@ -49,7 +49,7 @@ class GroupMembersTest(ClientTestCase):
run_client(['bkr', 'group-members',
non_existent_group])
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('Group %s does not exist' % non_existent_group,
e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_group_modify.py b/IntegrationTests/src/bkr/inttest/client/test_group_modify.py
index 402467c..3a06ac2 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_group_modify.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_group_modify.py
@@ -62,7 +62,7 @@ class GroupModifyTest(ClientTestCase):
self.group.group_name],
config = self.client_config)
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('Please specify an attribute to modify'
in e.stderr_output, e.stderr_output)
@@ -87,7 +87,7 @@ class GroupModifyTest(ClientTestCase):
'random', self.group.group_name],
config = self.client_config)
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('Exactly one group name must be specified' in
e.stderr_output, e.stderr_output)
@@ -127,7 +127,7 @@ class GroupModifyTest(ClientTestCase):
self.group.group_name],
config = self.client_config)
self.fail('Must fail or die')
- except ClientError,e:
+ except ClientError as e:
self.assertIn(
'Group display name must be not more than 255 characters long',
e.stderr_output)
@@ -156,7 +156,7 @@ class GroupModifyTest(ClientTestCase):
self.group.group_name],
config = self.client_config)
self.fail('Must fail or die')
- except ClientError,e:
+ except ClientError as e:
self.assertIn(
'Group name must be not more than 255 characters long',
e.stderr_output)
@@ -196,7 +196,7 @@ class GroupModifyTest(ClientTestCase):
run_client(['bkr', 'group-modify', '--root-password', short_password,
self.group.group_name], config=self.client_config)
self.fail('Should fail with short password')
- except ClientError, e:
+ except ClientError as e:
# Number of req chars was changed in RPM, however RHEL is using older one
# RHEL requires 7, Fedora requires 8 at this moment
self.assertTrue(
@@ -250,7 +250,7 @@ class GroupModifyTest(ClientTestCase):
'--display-name', 'this is also unchanged',
protected_group_name])
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('Cannot rename protected group' in
e.stderr_output, e.stderr_output)
@@ -308,7 +308,7 @@ class GroupModifyTest(ClientTestCase):
self.group.group_name],
config = self.client_config)
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('User idontexist does not exist' in
e.stderr_output, e.stderr_output)
@@ -318,7 +318,7 @@ class GroupModifyTest(ClientTestCase):
self.group.group_name],
config = self.client_config)
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('User %s is already a member of group %s'
% (user.user_name, self.group.group_name)
in e.stderr_output, e.stderr_output)
@@ -338,7 +338,7 @@ class GroupModifyTest(ClientTestCase):
'--add-member', user.user_name,
self.fake_ldap_group.group_name])
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('Cannot edit membership of group %s'
% self.fake_ldap_group.group_name
in e.stderr_output,e.stderr_output)
@@ -397,7 +397,7 @@ class GroupModifyTest(ClientTestCase):
self.group.group_name],
config = self.client_config)
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('User idontexist does not exist' in
e.stderr_output, e.stderr_output)
try:
@@ -406,7 +406,7 @@ class GroupModifyTest(ClientTestCase):
self.group.group_name],
config = self.client_config)
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('User %s is not a member of group %s'
% (user.user_name, self.group.group_name)
in e.stderr_output, e.stderr_output)
@@ -417,7 +417,7 @@ class GroupModifyTest(ClientTestCase):
self.group.group_name],
config = self.client_config)
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('Cannot remove user' in
e.stderr_output, e.stderr_output)
@@ -443,7 +443,7 @@ class GroupModifyTest(ClientTestCase):
out = run_client(['bkr', 'group-modify',
'--remove-member', 'admin', 'admin'])
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('Cannot remove user' in
e.stderr_output, e.stderr_output)
@@ -452,7 +452,7 @@ class GroupModifyTest(ClientTestCase):
'--remove-member', user.user_name,
self.fake_ldap_group.group_name])
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('Cannot edit membership of group %s'
% self.fake_ldap_group.group_name
in e.stderr_output, e.stderr_output)
@@ -496,7 +496,7 @@ class GroupModifyTest(ClientTestCase):
self.group.group_name],
config=self.client_config)
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('User %s is not a member of group %s'
% (user1.user_name, self.group.group_name)
in e.stderr_output, e.stderr_output)
@@ -519,7 +519,7 @@ class GroupModifyTest(ClientTestCase):
self.group.group_name],
config=self.client_config)
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assert_('User %s is already a member of group %s'
% (user1.user_name, self.group.group_name)
in e.stderr_output, e.stderr_output)
@@ -571,8 +571,8 @@ class GroupModifyTest(ClientTestCase):
self.fake_ldap_group.group_name],
config = self.client_config)
self.fail('Must fail or die')
- except ClientError, e:
- self.assert_('Cannot modify group ownership')
+ except ClientError as e:
+ self.assert_('Cannot edit ownership of group' in e.stderr_output, e.stderr_output)
def test_inverted_group_modify_grant_owner(self):
with session.begin():
@@ -641,7 +641,7 @@ class GroupModifyTest(ClientTestCase):
self.group.group_name],
config = self.client_config)
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assert_('User is not a member of group' in e.stderr_output)
try:
out = run_client(['bkr', 'group-modify',
@@ -649,8 +649,8 @@ class GroupModifyTest(ClientTestCase):
self.fake_ldap_group.group_name],
config = self.client_config)
self.fail('Must fail or die')
- except ClientError, e:
- self.assert_('Cannot modify group ownership')
+ except ClientError as e:
+ self.assert_('Cannot edit ownership of group' in e.stderr_output, e.stderr_output)
def test_escapes_uri_characters_in_group_name(self):
bad_group_name = u'!@#$%^&*()_+{}|:><?'
diff --git a/IntegrationTests/src/bkr/inttest/client/test_harness_test.py b/IntegrationTests/src/bkr/inttest/client/test_harness_test.py
index f7a6b3a..7022720 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_harness_test.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_harness_test.py
@@ -1,3 +1,9 @@
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
from bkr.inttest.client import run_client, ClientTestCase
from bkr.inttest import data_setup, with_transaction
from bkr.server.model import session, Arch, Job
diff --git a/IntegrationTests/src/bkr/inttest/client/test_job_cancel.py b/IntegrationTests/src/bkr/inttest/client/test_job_cancel.py
index cd186ed..8d8445e 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_job_cancel.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_job_cancel.py
@@ -34,7 +34,7 @@ class JobCancelTest(ClientTestCase):
run_client(['bkr', 'job-cancel',
self.job.recipesets[0].recipes[0].t_id])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assert_('Taskspec type must be one of'
in e.stderr_output, e.stderr_output)
@@ -42,8 +42,8 @@ class JobCancelTest(ClientTestCase):
def test_invalid_taskspec(self):
try:
run_client(['bkr', 'job-cancel', '12345'])
- fail('should raise')
- except ClientError, e:
+ self.fail('should raise')
+ except ClientError as e:
self.assert_('Invalid taskspec' in e.stderr_output)
# https://bugzilla.redhat.com/show_bug.cgi?id=649608
@@ -56,7 +56,7 @@ class JobCancelTest(ClientTestCase):
try:
run_client(['bkr', 'job-cancel', '--username', user1.user_name, '--password', 'abc', job.t_id])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEquals(e.status, 1)
self.assert_('You don\'t have permission to cancel'
in e.stderr_output, e.stderr_output)
@@ -113,5 +113,5 @@ class JobCancelTest(ClientTestCase):
try:
run_client(['bkr', 'job-cancel', 'T:9q9999q'])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('Invalid T 9q9999q', e.stderr_output) \ No newline at end of file
diff --git a/IntegrationTests/src/bkr/inttest/client/test_job_clone.py b/IntegrationTests/src/bkr/inttest/client/test_job_clone.py
index 9bb50f3..5d3d1f8 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_job_clone.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_job_clone.py
@@ -109,8 +109,8 @@ class JobCloneTest(ClientTestCase):
def test_invalid_taskspec(self):
try:
run_client(['bkr', 'job-clone', '12345'])
- fail('should raise')
- except ClientError, e:
+ self.fail('should raise')
+ except ClientError as e:
self.assert_('Invalid taskspec' in e.stderr_output)
# https://bugzilla.redhat.com/show_bug.cgi?id=1014623
@@ -161,6 +161,6 @@ class JobCloneTest(ClientTestCase):
def test_must_provide_job_or_recipeset(self):
try:
run_client(['bkr', 'job-clone',])
- except ClientError, e:
+ except ClientError as e:
self.assertIn("Please specify a job or recipeset to clone",
e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_job_comment.py b/IntegrationTests/src/bkr/inttest/client/test_job_comment.py
index d981ffc..40815ce 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_job_comment.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_job_comment.py
@@ -20,7 +20,7 @@ class JobCommentTest(ClientTestCase):
try:
run_client(['bkr', 'job-comment', '12345'])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('Invalid taskspec', e.stderr_output)
def test_post_comment_to_recipeset(self):
@@ -70,7 +70,7 @@ class JobCommentTest(ClientTestCase):
run_client(['bkr', 'job-comment', self.job.recipesets[0].t_id,
'--message', comment_text], config=client_config)
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEquals(e.status, 1)
self.assertIn('Invalid username or password', e.stderr_output)
@@ -79,7 +79,7 @@ class JobCommentTest(ClientTestCase):
run_client(['bkr', 'job-comment', self.job.recipesets[0].t_id,
'--message', ''])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('Comment text cannot be empty', e.stderr_output)
def test_post_comment_on_multiple_taskspec(self):
@@ -102,5 +102,5 @@ class JobCommentTest(ClientTestCase):
run_client(['bkr', 'job-comment', 'TR:thisisnotanint', '--message',
comment_text])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('Recipe task result not found', e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_job_delete.py b/IntegrationTests/src/bkr/inttest/client/test_job_delete.py
index e72d899..e1065d2 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_job_delete.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_job_delete.py
@@ -4,11 +4,8 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-import os
-from unittest2 import SkipTest
from turbogears.database import session
-from bkr.inttest import data_setup, with_transaction, start_process, \
- stop_process, CONFIG_FILE, edit_file
+from bkr.inttest import data_setup, with_transaction
from bkr.inttest.client import run_client, create_client_config, ClientError, \
ClientTestCase
@@ -50,13 +47,13 @@ class JobDeleteTest(ClientTestCase):
try:
out = run_client(['bkr', 'job-delete', other_job.t_id],
config=self.client_config)
- fail('should raise')
- except ClientError, e:
+ self.fail('should raise')
+ except ClientError as e:
self.assert_("don't have permission" in e.stderr_output)
def test_cant_delete_group_mates_job(self):
- # The test_delete_group_job case above is similar, but here the job is
- # *not* declared as a group job, therefore we don't have permission to
+ # The test_delete_group_job case above is similar, but here the job is
+ # *not* declared as a group job, therefore we don't have permission to
# delete it.
with session.begin():
group = data_setup.create_group()
@@ -69,7 +66,7 @@ class JobDeleteTest(ClientTestCase):
config=self.client_config)
self.fail('We should not have permission to delete %s' % \
test_job.t_id)
- except ClientError, e:
+ except ClientError as e:
self.assertIn("You don't have permission to delete job %s" %
test_job.t_id, e.stderr_output)
@@ -78,7 +75,7 @@ class JobDeleteTest(ClientTestCase):
other_user = data_setup.create_user(password=u'asdf')
tag = data_setup.create_retention_tag(name=u'myblahtag')
job1 = data_setup.create_completed_job(owner=other_user)
- job2 = data_setup.create_completed_job(owner=other_user, \
+ job2 = data_setup.create_completed_job(owner=other_user,
retention_tag=tag.tag)
# As the default admin user
@@ -96,8 +93,8 @@ class JobDeleteTest(ClientTestCase):
def test_invalid_taskspec(self):
try:
run_client(['bkr', 'job-delete', '12345'])
- fail('should raise')
- except ClientError, e:
+ self.fail('should raise')
+ except ClientError as e:
self.assert_('Invalid taskspec' in e.stderr_output)
# https://bugzilla.redhat.com/show_bug.cgi?id=990943
diff --git a/IntegrationTests/src/bkr/inttest/client/test_job_list.py b/IntegrationTests/src/bkr/inttest/client/test_job_list.py
index 0f10309..b7c91cd 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_job_list.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_job_list.py
@@ -15,10 +15,16 @@ class JobListTest(ClientTestCase):
@with_transaction
def setUp(self):
- jobs_to_generate = 2;
- self.products = [data_setup.create_product() for product in range(jobs_to_generate)]
- self.users = [data_setup.create_user(password='mypass') for user in range(jobs_to_generate)]
- self.jobs = [data_setup.create_completed_job(product=self.products[x], owner=self.users[x]) for x in range(jobs_to_generate)]
+ jobs_to_generate = 2
+ self.products = [data_setup.create_product() for _ in range(jobs_to_generate)]
+ self.users = [data_setup.create_user(password='mypass') for _ in range(jobs_to_generate)]
+ self.groups = [data_setup.create_group() for _ in range(jobs_to_generate)]
+ _ = [group.add_member(self.users[i]) for i, group in enumerate(self.groups)]
+
+ self.jobs = [data_setup.create_completed_job(product=self.products[x],
+ owner=self.users[x],
+ group=self.groups[x])
+ for x in range(jobs_to_generate)]
self.client_configs = [create_client_config(username=user.user_name, password='mypass') for user in self.users]
def test_list_jobs_by_product(self):
@@ -29,12 +35,15 @@ class JobListTest(ClientTestCase):
def test_list_jobs_by_owner(self):
out = run_client(['bkr', 'job-list', '--owner', self.users[0].user_name])
self.assert_(self.jobs[0].t_id in out, out)
+
out = run_client(['bkr', 'job-list', '--owner', self.users[0].user_name, '--limit', '1'])
- self.assert_(len(out[0]) == 1, out)
- out = run_client(['bkr', 'job-list', '--owner', 'foobar'])
- self.assert_(self.jobs[0].t_id not in out, out)
- out = run_client(['bkr', 'job-list', '--owner', self.users[0].user_name, '--min-id', \
- '{0}'.format(self.jobs[0].id), '--max-id', '{0}'.format(self.jobs[0].id)])
+ self.assert_(len(json.loads(out)) == 1, out)
+
+ with self.assertRaisesRegexp(ClientError, 'Owner.*is invalid'):
+ run_client(['bkr', 'job-list', '--owner', 'foobar'])
+
+ out = run_client(['bkr', 'job-list', '--owner', self.users[0].user_name, '--min-id',
+ '{0}'.format(self.jobs[0].id), '--max-id', '{0}'.format(self.jobs[0].id)])
self.assert_(self.jobs[0].t_id in out and self.jobs[1].t_id not in out)
def test_list_jobs_by_whiteboard(self):
@@ -52,8 +61,8 @@ class JobListTest(ClientTestCase):
listed_job_ids = out.splitlines()
self.assertIn(included_job.t_id, listed_job_ids)
self.assertNotIn(excluded_job.t_id, listed_job_ids)
- # This was accidental undocumented functionality supported by the
- # original implementation of jobs.filter. Some people are probably
+ # This was accidental undocumented functionality supported by the
+ # original implementation of jobs.filter. Some people are probably
# relying on it.
out = run_client(['bkr', 'job-list', '--format=list', '--whiteboard=p%z_nce'])
listed_job_ids = out.splitlines()
@@ -94,15 +103,54 @@ class JobListTest(ClientTestCase):
out = json.loads(out)
self.assertIn(self.jobs[0].t_id, out)
self.assertNotIn(self.jobs[1].t_id, out)
- self.assertRaises(ClientError, run_client, ['bkr', 'job-list', '--mine', \
- '--username', 'xyz',\
- '--password','xyz'])
+ self.assertRaises(ClientError, run_client, ['bkr', 'job-list', '--mine',
+ '--username', 'xyz',
+ '--password','xyz'])
+
+ def test_list_jobs_my_groups(self):
+ out = run_client(['bkr', 'job-list', '--my-groups'], config=self.client_configs[0])
+ self.assert_(self.jobs[0].t_id in out and self.jobs[1].t_id not in out, out)
+
+ out = run_client(['bkr', 'job-list', '--my-groups'], config=self.client_configs[1])
+ self.assert_(self.jobs[1].t_id in out and self.jobs[0].t_id not in out, out)
+
+ out = run_client(['bkr', 'job-list', '--my-groups', '--format','json'],
+ config=self.client_configs[0])
+ out = json.loads(out)
+ self.assertIn(self.jobs[0].t_id, out)
+ self.assertNotIn(self.jobs[1].t_id, out)
+
+ self.assertRaises(ClientError, run_client, ['bkr', 'job-list', '--my-groups',
+ '--username', 'xyz',
+ '--password','xyz'])
+
+ def test_list_jobs_by_group(self):
+ out = run_client(['bkr', 'job-list', '--group', self.groups[0].group_name])
+ self.assert_(self.jobs[0].t_id in out and self.jobs[1].t_id not in out, out)
+
+ out = run_client(['bkr', 'job-list', '--group', self.groups[1].group_name])
+ self.assert_(self.jobs[1].t_id in out and self.jobs[0].t_id not in out, out)
+
+ out = run_client(['bkr', 'job-list', '--group', self.groups[1].group_name, '--limit', '1'])
+ self.assert_(len(json.loads(out)) == 1, out)
+
+ with self.assertRaisesRegexp(ClientError, 'No such group \'foobar\''):
+ run_client(['bkr', 'job-list', '--group', 'foobar'])
+
+ out = run_client(['bkr', 'job-list', '--group',
+ self.groups[0].group_name,
+ '--min-id', '{0}'.format(self.jobs[0].id), '--max-id', '{0}'.format(self.jobs[0].id)])
+ self.assert_(self.jobs[0].t_id in out and self.jobs[1].t_id not in out)
+
+ def test_list_jobs_both_by_mine_and_owner(self):
+ out = run_client(['bkr', 'job-list', '--mine', '--owner', self.users[1].user_name], config=self.client_configs[0])
+ self.assert_(self.jobs[0].t_id in out and self.jobs[1].t_id in out, out)
def test_cannot_specify_finished_and_unfinished_at_the_same_time (self):
try:
run_client(['bkr', 'job-list', '--finished', '--unfinished'])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 2)
self.assertIn("Only one of --finished or --unfinished may be specified", e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_job_logs.py b/IntegrationTests/src/bkr/inttest/client/test_job_logs.py
index d5f07e5..34faf1a 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_job_logs.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_job_logs.py
@@ -6,7 +6,6 @@
import sys
import os
-import urlparse
import shutil
import tempfile
import pkg_resources
@@ -96,8 +95,8 @@ class JobLogsTest(ClientTestCase):
def test_invalid_taskspec(self):
try:
run_client(['bkr', 'job-logs', '12345'])
- fail('should raise')
- except ClientError, e:
+ self.fail('should raise')
+ except ClientError as e:
self.assert_('Invalid taskspec' in e.stderr_output)
def test_prints_sizes(self):
diff --git a/IntegrationTests/src/bkr/inttest/client/test_job_modify.py b/IntegrationTests/src/bkr/inttest/client/test_job_modify.py
index cd3146a..5cf45e1 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_job_modify.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_job_modify.py
@@ -114,8 +114,8 @@ class JobModifyTest(ClientTestCase):
def test_invalid_taskspec(self):
try:
run_client(['bkr', 'job-modify', '12345', '--response', 'ack'])
- fail('should raise')
- except ClientError, e:
+ self.fail('should raise')
+ except ClientError as e:
self.assert_('Invalid taskspec' in e.stderr_output)
# https://bugzilla.redhat.com/show_bug.cgi?id=995012
@@ -174,7 +174,7 @@ class JobModifyTest(ClientTestCase):
self.assertEquals(recipe.whiteboard, u'found himself transformed')
def test_processes_all_arguments_even_if_one_fails(self):
- # This behaviour is actually contrary to what the other subcommands do,
+ # This behaviour is actually contrary to what the other subcommands do,
# but it's what we have, so let's test it anyway...
p = start_client(['bkr', 'job-modify', 'J:thiswillfail', self.job.t_id,
'--whiteboard', 'uneasy dreams'])
diff --git a/IntegrationTests/src/bkr/inttest/client/test_job_results.py b/IntegrationTests/src/bkr/inttest/client/test_job_results.py
index edde60e..f3146cd 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_job_results.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_job_results.py
@@ -38,8 +38,8 @@ class JobResultsTest(ClientTestCase):
def test_invalid_taskspec(self):
try:
run_client(['bkr', 'job-results', '12345'])
- fail('should raise')
- except ClientError, e:
+ self.fail('should raise')
+ except ClientError as e:
self.assert_('Invalid taskspec' in e.stderr_output)
# https://bugzilla.redhat.com/show_bug.cgi?id=1014623
diff --git a/IntegrationTests/src/bkr/inttest/client/test_job_submit.py b/IntegrationTests/src/bkr/inttest/client/test_job_submit.py
index 36937ef..870ee0e 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_job_submit.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_job_submit.py
@@ -9,7 +9,7 @@
from turbogears.database import session
from bkr.inttest import data_setup, with_transaction
from bkr.inttest.client import run_client, create_client_config, ClientTestCase, ClientError
-from bkr.server.model import Distro, Job
+from bkr.server.model import Job
import pkg_resources
class JobSubmitTest(ClientTestCase):
diff --git a/IntegrationTests/src/bkr/inttest/client/test_job_watch.py b/IntegrationTests/src/bkr/inttest/client/test_job_watch.py
index 81fded6..22cadfe 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_job_watch.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_job_watch.py
@@ -8,8 +8,6 @@ from turbogears.database import session
from bkr.inttest import data_setup
from bkr.inttest.client import start_client, run_client, ClientError, \
ClientTestCase
-import time
-from unittest2 import SkipTest
class JobWatchTest(ClientTestCase):
@@ -72,8 +70,8 @@ class JobWatchTest(ClientTestCase):
def test_invalid_taskspec(self):
try:
run_client(['bkr', 'job-watch', '12345'])
- fail('should raise')
- except ClientError, e:
+ self.fail('should raise')
+ except ClientError as e:
self.assert_('Invalid taskspec' in e.stderr_output)
# https://bugzilla.redhat.com/show_bug.cgi?id=1415104
diff --git a/IntegrationTests/src/bkr/inttest/client/test_labcontroller_create.py b/IntegrationTests/src/bkr/inttest/client/test_labcontroller_create.py
index 394d67f..edf18e9 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_labcontroller_create.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_labcontroller_create.py
@@ -8,6 +8,7 @@ from bkr.server.model import session, LabController, Group
from bkr.inttest import data_setup
from bkr.inttest.client import run_client, ClientTestCase, ClientError
+
class LabcontrollerCreateTest(ClientTestCase):
def test_lab_controller_create(self):
@@ -21,7 +22,7 @@ class LabcontrollerCreateTest(ClientTestCase):
self.assertEqual(lc.user.user_name, 'host/%s' % fqdn)
self.assertEqual(lc.user.email_address, 'lab1@%s.com' % fqdn)
self.assertIn(Group.by_name(u'lab_controller'), lc.user.groups)
- # cann't create duplicate lab controller
+ # can't create duplicate lab controller
try:
run_client(['bkr', 'labcontroller-create',
'--fqdn', fqdn,
diff --git a/IntegrationTests/src/bkr/inttest/client/test_labcontroller_list.py b/IntegrationTests/src/bkr/inttest/client/test_labcontroller_list.py
index 1b77b2b..8ee8790 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_labcontroller_list.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_labcontroller_list.py
@@ -5,7 +5,6 @@
# (at your option) any later version.
from datetime import datetime
-from turbogears.database import session
from bkr.inttest import data_setup, with_transaction
from bkr.inttest.client import run_client, ClientTestCase
diff --git a/IntegrationTests/src/bkr/inttest/client/test_labcontroller_modify.py b/IntegrationTests/src/bkr/inttest/client/test_labcontroller_modify.py
index 7974dce..5c3bc6c 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_labcontroller_modify.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_labcontroller_modify.py
@@ -14,7 +14,7 @@ class LabControllerModifyTest(ClientTestCase):
def test_change_fqdn(self):
with session.begin():
lc = data_setup.create_labcontroller()
- another_lc = data_setup.create_labcontroller()
+ data_setup.create_labcontroller()
new_fqdn = data_setup.unique_name(u'lab%s.testdata.invalid')
run_client(['bkr', 'labcontroller-modify',
'--fqdn', new_fqdn,
@@ -27,7 +27,7 @@ class LabControllerModifyTest(ClientTestCase):
with session.begin():
lc = data_setup.create_labcontroller()
another_lc = data_setup.create_labcontroller()
- new_fqdn = data_setup.unique_name(u'lab%s.testdata.invalid')
+ data_setup.unique_name(u'lab%s.testdata.invalid')
try:
run_client(['bkr', 'labcontroller-modify',
'--fqdn', another_lc.fqdn,
diff --git a/IntegrationTests/src/bkr/inttest/client/test_loan_management.py b/IntegrationTests/src/bkr/inttest/client/test_loan_management.py
index ede6344..006cd39 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_loan_management.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_loan_management.py
@@ -6,7 +6,7 @@
import contextlib
from turbogears.database import session
-from bkr.server.model import System, SystemAccessPolicy, SystemPermission
+from bkr.server.model import SystemPermission
from bkr.inttest import data_setup, with_transaction
from bkr.inttest.client import run_client, create_client_config, ClientError, \
ClientTestCase
@@ -52,8 +52,8 @@ class SystemLoanTest(ClientTestCase):
expected_error = "Insufficient permissions: %s" % details
try:
yield
- fail('Permissions error expected')
- except ClientError, e:
+ self.fail('Permissions error expected')
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assertRegexpMatches(e.stderr_output, expected_error)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_machine_test.py b/IntegrationTests/src/bkr/inttest/client/test_machine_test.py
index f487617..68298ba 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_machine_test.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_machine_test.py
@@ -33,11 +33,11 @@ class MachineTestTest(ClientTestCase):
#https://bugzilla.redhat.com/show_bug.cgi?id=893878
try:
- out = run_client(['bkr', 'machine-test','--machine',
+ out = run_client(['bkr', 'machine-test','--machine',
self.system.fqdn, '--tag','aTAG'])
except Exception as ex:
- self.assertEqual(ex.stderr_output.rstrip('\n'), \
- 'Could not find an appropriate distro to provision system with.')
+ self.assertEqual(ex.stderr_output.rstrip('\n'),
+ 'Could not find an appropriate distro to provision system with.')
# https://bugzilla.redhat.com/show_bug.cgi?id=876752
def test_filters_out_excluded_families(self):
diff --git a/IntegrationTests/src/bkr/inttest/client/test_policy_list.py b/IntegrationTests/src/bkr/inttest/client/test_policy_list.py
index c44b03a..15d01a5 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_policy_list.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_policy_list.py
@@ -164,7 +164,7 @@ class PolicyListTest(ClientTestCase):
def test_list_policy_filter_multiple(self):
try:
run_client(['bkr', 'policy-list',
- '--mine',
+ '--mine',
'--group', self.group.group_name,
self.system.fqdn])
self.fail('Must fail or die')
diff --git a/IntegrationTests/src/bkr/inttest/client/test_policy_revoke.py b/IntegrationTests/src/bkr/inttest/client/test_policy_revoke.py
index b13da34..75bd62b 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_policy_revoke.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_policy_revoke.py
@@ -4,7 +4,6 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-import unittest
from bkr.server.model import session, SystemPermission
from bkr.inttest import data_setup
from bkr.inttest.client import run_client, ClientError, ClientTestCase
diff --git a/IntegrationTests/src/bkr/inttest/client/test_pool_list.py b/IntegrationTests/src/bkr/inttest/client/test_pool_list.py
index a9a2122..602fc95 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_pool_list.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_pool_list.py
@@ -1,6 +1,6 @@
-from bkr.server.model import session, SystemPool
+from bkr.server.model import session
from bkr.inttest import data_setup
-from bkr.inttest.client import run_client, ClientError, ClientTestCase, create_client_config
+from bkr.inttest.client import run_client, ClientError, ClientTestCase
class PoolList(ClientTestCase):
diff --git a/IntegrationTests/src/bkr/inttest/client/test_pool_systems.py b/IntegrationTests/src/bkr/inttest/client/test_pool_systems.py
index 4ddb2a7..887ef68 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_pool_systems.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_pool_systems.py
@@ -1,4 +1,4 @@
-from bkr.server.model import session, SystemPool
+from bkr.server.model import session
from bkr.inttest import data_setup
from bkr.inttest.client import run_client, ClientTestCase, ClientError
@@ -31,7 +31,7 @@ class PoolSystems(ClientTestCase):
out = run_client(['bkr', 'pool-systems',
pool_name])
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('System pool %s does not exist' % pool_name,
e.stderr_output)
@@ -39,6 +39,6 @@ class PoolSystems(ClientTestCase):
try:
out = run_client(['bkr', 'pool-systems'])
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('Exactly one pool name must be specified',
e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_remove_account.py b/IntegrationTests/src/bkr/inttest/client/test_remove_account.py
index 9eb2a9a..0540030 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_remove_account.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_remove_account.py
@@ -4,11 +4,10 @@
# (at your option) any later version.
from turbogears.database import session
-from bkr.inttest import data_setup, with_transaction
+from bkr.inttest import data_setup
from bkr.inttest.client import run_client, create_client_config, ClientError, \
ClientTestCase
-from bkr.server.model import TaskStatus, Job, User, SystemPermission, SystemStatus
-from bkr.server.tools import beakerd
+from bkr.server.model import TaskStatus, User, SystemPermission, SystemStatus
class RemoveAccountTest(ClientTestCase):
@@ -16,7 +15,7 @@ class RemoveAccountTest(ClientTestCase):
try:
run_client(['bkr', 'remove-account', 'admin'])
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('You cannot remove yourself', e.stderr_output)
def test_remove_multiple_users(self):
@@ -38,7 +37,7 @@ class RemoveAccountTest(ClientTestCase):
try:
run_client(['bkr', 'remove-account', user.user_name])
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('User already removed', e.stderr_output)
def test_non_admin_cannot_delete(self):
@@ -51,7 +50,7 @@ class RemoveAccountTest(ClientTestCase):
run_client(['bkr', 'remove-account', user3.user_name],
config=client_config1)
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('Not member of group: admin', e.stderr_output)
# https://bugzilla.redhat.com/show_bug.cgi?id=1257020
@@ -150,5 +149,5 @@ class RemoveAccountTest(ClientTestCase):
try:
run_client(['bkr', 'remove-account', '--new-owner=%s' % invalid_username, user.user_name])
self.fail('Expected client to fail due to invalid new owner')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('Invalid user name for owner', e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_system_delete.py b/IntegrationTests/src/bkr/inttest/client/test_system_delete.py
index 873e9a1..4a053c1 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_system_delete.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_system_delete.py
@@ -30,8 +30,8 @@ class SystemDeleteTest(ClientTestCase):
try:
out = run_client(['bkr', 'system-delete', self.system.fqdn],
config=self.client_config2)
- fail('should raise')
- except ClientError, e:
+ self.fail('should raise')
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assert_(e.stderr_output.find("you don't own") != -1)
@@ -55,8 +55,8 @@ class SystemDeleteTest(ClientTestCase):
try:
out = run_client(['bkr', 'system-delete', self.system.fqdn],
config=self.client_config)
- fail('should raise')
- except ClientError, e:
+ self.fail('should raise')
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assert_(e.stderr_output.find('with reservations') != -1)
@@ -65,6 +65,6 @@ class SystemDeleteTest(ClientTestCase):
try:
run_client(['bkr', 'system-delete', fqdn])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assertIn("System %s does not exist" % fqdn, e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_system_details.py b/IntegrationTests/src/bkr/inttest/client/test_system_details.py
index 77e4874..6aab73e 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_system_details.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_system_details.py
@@ -4,9 +4,9 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-from turbogears.database import session
from bkr.inttest import data_setup, with_transaction
from bkr.inttest.client import run_client, ClientTestCase
+import json
import rdflib
class SystemDetailsTest(ClientTestCase):
@@ -15,8 +15,18 @@ class SystemDetailsTest(ClientTestCase):
def setUp(self):
self.system = data_setup.create_system()
- def test_system_details(self):
+ def test_system_details_xml(self):
out = run_client(['bkr', 'system-details', self.system.fqdn])
g = rdflib.Graph()
g.parse(data=out)
self.assert_(len(g) > 0)
+
+ def test_system_details_json(self):
+ out = run_client(['bkr', 'system-details', '--format', 'json',
+ self.system.fqdn])
+ self.assert_(len(out) > 0)
+
+ # Make sure you got what you asked for
+ payload = json.loads(out)
+ self.assertEquals(payload['fqdn'],
+ self.system.fqdn)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_system_list.py b/IntegrationTests/src/bkr/inttest/client/test_system_list.py
index f93e2ba..d0b9249 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_system_list.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_system_list.py
@@ -10,6 +10,7 @@ from bkr.inttest.client import run_client, ClientError, ClientTestCase
from bkr.server.model import System, Key, Key_Value_String, SystemStatus, Cpu
import datetime
+
class SystemListTest(ClientTestCase):
def check_systems(self, present=None, absent=None):
@@ -30,14 +31,14 @@ class SystemListTest(ClientTestCase):
def test_list_removed_systems(self):
with session.begin():
- system1 = data_setup.create_system()
+ data_setup.create_system()
system2 = data_setup.create_system(status=SystemStatus.removed)
out = run_client(['bkr', 'system-list', '--removed'])
self.assertIn(system2.fqdn, out.splitlines())
self.assertEqual(len(out.splitlines()),
System.query.filter(System.status==SystemStatus.removed).count())
- #https://bugzilla.redhat.com/show_bug.cgi?id=920018
+ # https://bugzilla.redhat.com/show_bug.cgi?id=920018
def test_list_systems_lc_disabled(self):
with session.begin():
lc1 = data_setup.create_labcontroller()
@@ -75,7 +76,7 @@ class SystemListTest(ClientTestCase):
Key_Value_String(module_key, u'kvm')])
without_module = data_setup.create_system()
out = run_client(['bkr', 'system-list',
- '--xml-filter', '<key_value key="MODULE" />'])
+ '--xml-filter', '<key_value key="MODULE" />'])
returned_systems = out.splitlines()
self.assert_(with_module.fqdn in returned_systems, returned_systems)
self.assert_(without_module.fqdn not in returned_systems,
@@ -85,8 +86,8 @@ class SystemListTest(ClientTestCase):
def test_handles_xml_syntax_error(self):
try:
run_client(['bkr', 'system-list', '--xml-filter', '<error'])
- sel.fail('should be an error')
- except ClientError, e:
+ self.fail('should be an error')
+ except ClientError as e:
self.assertIn('Invalid XML syntax for host filter', e.stderr_output)
# https://bugzilla.redhat.com/show_bug.cgi?id=1118523
@@ -96,7 +97,7 @@ class SystemListTest(ClientTestCase):
matching.cpu = Cpu(vendor=u'GenuineIntel', family=6, model=47, model_name=u'Intel')
nonmatching = data_setup.create_system()
out = run_client(['bkr', 'system-list',
- '--host-filter', 'INTEL__WESTMERE'])
+ '--host-filter', 'INTEL__WESTMERE'])
returned_systems = out.splitlines()
self.assertIn(matching.fqdn, returned_systems)
self.assertNotIn(nonmatching.fqdn, returned_systems)
@@ -110,14 +111,14 @@ class SystemListTest(ClientTestCase):
Key_Value_String(module_key, u'cciss'))
nonmatching = data_setup.create_system()
out = run_client(['bkr', 'system-list',
- '--xml-filter', '<not><lender value="shark"/></not>',
- '--xml-filter', '<key_value key="MODULE" value="cciss"/>',
- '--host-filter', 'INTEL__WESTMERE'])
+ '--xml-filter', '<not><lender value="shark"/></not>',
+ '--xml-filter', '<key_value key="MODULE" value="cciss"/>',
+ '--host-filter', 'INTEL__WESTMERE'])
returned_systems = out.splitlines()
self.assertIn(matching.fqdn, returned_systems)
self.assertNotIn(nonmatching.fqdn, returned_systems)
- #https://bugzilla.redhat.com/show_bug.cgi?id=949777
+ # https://bugzilla.redhat.com/show_bug.cgi?id=949777
def test_inventory_date_search(self):
# date times
@@ -182,7 +183,6 @@ class SystemListTest(ClientTestCase):
self.returned_systems = out.splitlines()
self.check_systems(present=[inv3], absent=[not_inv, inv1, inv2])
-
# Before a certain date
out = run_client(['bkr', 'system-list',
'--xml-filter',
@@ -211,12 +211,12 @@ class SystemListTest(ClientTestCase):
'<last_inventoried op="&gt;" value="%s 00:00:00" />'
'</system>' % today])
self.fail('Must Fail or Die')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assert_('Invalid date format' in e.stderr_output,
e.stderr_output)
- #https://bugzilla.redhat.com/show_bug.cgi?id=955868
+ # https://bugzilla.redhat.com/show_bug.cgi?id=955868
def test_added_date_search(self):
# date times
@@ -230,7 +230,6 @@ class SystemListTest(ClientTestCase):
date_today = time_now.date().isoformat()
date_tomorrow = time_tomorrow.date().isoformat()
-
with session.begin():
sys_today1 = data_setup.create_system(arch=u'i386', shared=True,
date_added=time_now)
@@ -253,25 +252,25 @@ class SystemListTest(ClientTestCase):
# on a datetime
try:
- out = run_client(['bkr', 'system-list',
- '--xml-filter',
- '<system>'
- '<added op="=" value="%s" />'
- '</system>' % time_now])
+ run_client(['bkr', 'system-list',
+ '--xml-filter',
+ '<system>'
+ '<added op="=" value="%s" />'
+ '</system>' % time_now])
self.fail('Must Fail or Die')
- except ClientError,e:
+ except ClientError as e:
self.assertEquals(e.status, 1)
self.assert_('Invalid date format' in e.stderr_output, e.stderr_output)
# date as " "
try:
- out = run_client(['bkr', 'system-list',
- '--xml-filter',
- '<system>'
- '<added op="=" value=" " />'
- '</system>'])
+ run_client(['bkr', 'system-list',
+ '--xml-filter',
+ '<system>'
+ '<added op="=" value=" " />'
+ '</system>'])
self.fail('Must Fail or die')
- except ClientError,e:
+ except ClientError as e:
self.assertEquals(e.status, 1)
self.assert_('Invalid date format' in e.stderr_output, e.stderr_output)
@@ -281,7 +280,7 @@ class SystemListTest(ClientTestCase):
pool = data_setup.create_system_pool()
inpool = data_setup.create_system()
pool.systems.append(inpool)
- nopool = data_setup.create_system()
+ data_setup.create_system()
out = run_client(['bkr', 'system-list', '--pool', pool.name])
self.assertEquals([inpool.fqdn], out.splitlines())
diff --git a/IntegrationTests/src/bkr/inttest/client/test_system_power.py b/IntegrationTests/src/bkr/inttest/client/test_system_power.py
index c9e7c52..180deb3 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_system_power.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_system_power.py
@@ -1,13 +1,13 @@
-
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
from turbogears.database import session
-from bkr.inttest import data_setup, with_transaction
+from bkr.inttest import data_setup
from bkr.inttest.client import run_client, ClientTestCase, ClientError
+
class PowerSystemTest(ClientTestCase):
# https://bugzilla.redhat.com/show_bug.cgi?id=1181700
@@ -26,7 +26,7 @@ class PowerSystemTest(ClientTestCase):
lc = data_setup.create_labcontroller()
system = data_setup.create_system(lab_controller=lc)
run_client(['bkr', 'system-power', '--action',
- 'reboot', '--clear-netboot', system.fqdn])
+ 'reboot', '--clear-netboot', system.fqdn])
self.assertEqual(len(system.command_queue), 3)
self.assertEqual(system.command_queue[0].action, 'on')
self.assertEqual(system.command_queue[1].action, 'off')
@@ -34,18 +34,18 @@ class PowerSystemTest(ClientTestCase):
def test_force(self):
with session.begin():
- user=data_setup.create_user()
+ user = data_setup.create_user()
lc = data_setup.create_labcontroller()
system = data_setup.create_system(lab_controller=lc)
system.user = user
try:
- res = run_client(['bkr', 'system-power', '--action',
- 'reboot', system.fqdn])
+ run_client(['bkr', 'system-power', '--action',
+ 'reboot', system.fqdn])
self.fail('Must fail')
except ClientError as e:
self.assertIn('You are not the current user of the system',
e.stderr_output)
run_client(['bkr', 'system-power', '--action',
- 'interrupt', '--force', system.fqdn])
+ 'interrupt', '--force', system.fqdn])
self.assertEqual(len(system.command_queue), 1)
self.assertEqual(system.command_queue[0].action, 'interrupt')
diff --git a/IntegrationTests/src/bkr/inttest/client/test_system_release.py b/IntegrationTests/src/bkr/inttest/client/test_system_release.py
index b8403bd..840092b 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_system_release.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_system_release.py
@@ -15,7 +15,7 @@ class SystemReleaseTest(ClientTestCase):
with session.begin():
system = data_setup.create_system()
try:
- res = run_client(['bkr', 'system-release', system.fqdn])
+ run_client(['bkr', 'system-release', system.fqdn])
self.fail('Must fail')
except ClientError as e:
self.assertIn('System %s is not currently reserved' % system.fqdn,
@@ -36,6 +36,6 @@ class SystemReleaseTest(ClientTestCase):
try:
run_client(['bkr', 'system-release', 'test.invalid.nonexistent.com'])
self.fail('Should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 1)
- self.assertIn('System not found', e.stderr_output) \ No newline at end of file
+ self.assertIn('System not found', e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_system_status.py b/IntegrationTests/src/bkr/inttest/client/test_system_status.py
index cb9b46d..393b9d4 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_system_status.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_system_status.py
@@ -5,13 +5,18 @@
# (at your option) any later version.
import textwrap
-import re
from turbogears.database import session
from bkr.server.model import SystemStatus, Recipe
from json import loads
from bkr.inttest import data_setup
from bkr.inttest.client import run_client, ClientError, ClientTestCase
+try:
+ unicode('')
+except:
+ unicode = str
+
+
class SystemStatusTest(ClientTestCase):
def test_unknown_fqdn(self):
@@ -22,7 +27,6 @@ class SystemStatusTest(ClientTestCase):
except ClientError as e:
self.assertIn('System not found', e.stderr_output)
-
def test_reserve_with_recipe(self):
with session.begin():
recipe = data_setup.create_recipe()
diff --git a/IntegrationTests/src/bkr/inttest/client/test_task_add.py b/IntegrationTests/src/bkr/inttest/client/test_task_add.py
index e824cbe..f068d34 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_task_add.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_task_add.py
@@ -19,8 +19,8 @@ class TaskAddTest(ClientTestCase):
def test_add_invalid_task(self):
try:
run_client(['bkr', 'task-add', '/dev/null'])
- fail('should raise')
- except ClientError, e:
+ self.fail('should raise')
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assert_('error reading package header' in e.stderr_output,
e.stderr_output)
@@ -55,7 +55,7 @@ class TaskAddTest(ClientTestCase):
# run this task-add twice to make duplicate error will show.
run_client(['bkr', 'task-add', import_rpm])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assertIn('Cannot import duplicate task', e.stderr_output)
@@ -65,7 +65,7 @@ class TaskAddTest(ClientTestCase):
try:
run_client(['bkr', 'task-add', unde_rpm])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assertIn('Name field not defined', e.stderr_output)
@@ -74,7 +74,7 @@ class TaskAddTest(ClientTestCase):
try:
run_client(['bkr', 'task-add', '/non/exist/task.rpm'])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assertIn("No such file or directory:", e.stderr_output)
@@ -85,7 +85,7 @@ class TaskAddTest(ClientTestCase):
try:
run_client(['bkr', 'task-add', overlen_rpm])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assertIn('Task name should be <= 255 characters', e.stderr_output)
@@ -96,7 +96,7 @@ class TaskAddTest(ClientTestCase):
try:
run_client(['bkr', 'task-add', redundant_rpm])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assertIn('Task name must not contain redundant slashes', e.stderr_output)
@@ -107,7 +107,7 @@ class TaskAddTest(ClientTestCase):
try:
run_client(['bkr', 'task-add', slash_rpm])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assertIn('Task name must not end with slash', e.stderr_output)
@@ -120,6 +120,6 @@ class TaskAddTest(ClientTestCase):
try:
run_client(['bkr', 'task-add', same_version_rpm])
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertEqual(e.status, 1)
self.assertIn('Failed to import, 1.1.2-0 is the same version we already have', e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_task_details.py b/IntegrationTests/src/bkr/inttest/client/test_task_details.py
index 0902f7c..af34655 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_task_details.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_task_details.py
@@ -51,8 +51,7 @@ class TaskDetailsTest(ClientTestCase):
pretty_out = run_client(['bkr', 'task-details', '--prettyxml', task.name])
pretty_minus_leading_name = re.sub(task.name, '', pretty_out, count=1)
task_elem_pretty = lxml.etree.tostring(task_elem, pretty_print=True, encoding='utf8')
- self.assert_(task_elem_pretty.strip() ==
- pretty_minus_leading_name.strip())
+ self.assert_(task_elem_pretty.strip() == pretty_minus_leading_name.strip())
# https://bugzilla.redhat.com/show_bug.cgi?id=624417
def test_details_include_owner_and_priority(self):
@@ -66,8 +65,8 @@ class TaskDetailsTest(ClientTestCase):
# https://bugzilla.redhat.com/show_bug.cgi?id=624417
def test_details_without_owner(self):
- # The original bug was that the owner was not filled in, so some older
- # task rows would still have None. However for bug 859785 these were
+ # The original bug was that the owner was not filled in, so some older
+ # task rows would still have None. However for bug 859785 these were
# coerced to empty string.
with session.begin():
task = data_setup.create_task()
@@ -126,5 +125,5 @@ class TaskDetailsTest(ClientTestCase):
try:
run_client(['bkr', 'task-details', 'idontexist'])
self.fail('Must fail or die')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('No such task: idontexist', e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_update_openstack_trust.py b/IntegrationTests/src/bkr/inttest/client/test_update_openstack_trust.py
index 043464c..614ed32 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_update_openstack_trust.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_update_openstack_trust.py
@@ -23,18 +23,29 @@ class UpdateOpenStackTrustTest(ClientTestCase):
self.user = data_setup.create_user(password=self.password)
self.client_config = create_client_config(username=self.user.user_name,
- password=self.password)
+ password=self.password)
def test_adds_openstack_trust_successfully(self):
username = os.environ['OPENSTACK_DUMMY_USERNAME']
password = os.environ['OPENSTACK_DUMMY_PASSWORD']
- project = os.environ['OPENSTACK_DUMMY_PROJECT_NAME']
+ project_name = os.environ['OPENSTACK_DUMMY_PROJECT_NAME']
+ user_domain_name = os.environ.get('OPENSTACK_DUMMY_USER_DOMAIN_NAME')
+ project_domain_name = os.environ.get('OPENSTACK_DUMMY_PROJECT_DOMAIN_NAME')
- run_client(['bkr', 'update-openstack-trust',
- '--os-username=%s' % username,
- '--os-password=%s' % password,
- '--os-project-name=%s' % project],
- config=self.client_config)
+ if (user_domain_name and project_domain_name):
+ run_client(['bkr', 'update-openstack-trust',
+ '--os-user-domain-name=%s' % user_domain_name,
+ '--os-username=%s' % username,
+ '--os-password=%s' % password,
+ '--os-project-domain-name=%s' % project_domain_name,
+ '--os-project-name=%s' % project_name],
+ config=self.client_config)
+ else:
+ run_client(['bkr', 'update-openstack-trust',
+ '--os-username=%s' % username,
+ '--os-password=%s' % password,
+ '--os-project-name=%s' % project_name],
+ config=self.client_config)
with session.begin():
session.refresh(self.user)
@@ -47,6 +58,23 @@ class UpdateOpenStackTrustTest(ClientTestCase):
'--os-password=invalid',
'--os-project-name=invalid-project'],
config=self.client_config)
- self.fail('should raise')
+ self.fail('should raise a ClientError')
+ except ClientError as e:
+ self.assertIn(
+ 'Could not authenticate with OpenStack using your credentials',
+ e.stderr_output)
+
+ def test_errors_if_unauthorised_with_domain_info(self):
+ try:
+ run_client(['bkr', 'update-openstack-trust',
+ '--os-user-domain-name=invalid',
+ '--os-username=invalid',
+ '--os-password=invalid',
+ '--os-project-domain-name=invalid',
+ '--os-project-name=beaker'],
+ config=self.client_config)
+ self.fail('should raise a ClientError')
except ClientError, e:
- self.assertIn('Could not authenticate with OpenStack using your credentials', e.stderr_output)
+ self.assertIn(
+ 'Could not authenticate with OpenStack using your credentials',
+ e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_update_prefs.py b/IntegrationTests/src/bkr/inttest/client/test_update_prefs.py
index ec0ae4d..8e28621 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_update_prefs.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_update_prefs.py
@@ -26,7 +26,7 @@ class UpdatePrefsTest(ClientTestCase):
run_client(['bkr', 'update-prefs', '--email=%s' % self.user1.email_address],
config=self.client_config1)
self.fail('should raise')
- except ClientError, e:
+ except ClientError as e:
self.assertIn('is same as before', e.stderr_output)
run_client(['bkr', 'update-prefs', '--email=%s' % self.user2.email_address],
diff --git a/IntegrationTests/src/bkr/inttest/client/test_user_modify.py b/IntegrationTests/src/bkr/inttest/client/test_user_modify.py
index 819a196..7303ca9 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_user_modify.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_user_modify.py
@@ -5,7 +5,6 @@
# (at your option) any later version.
from turbogears.database import session
-from bkr.server.model import User
from bkr.inttest import data_setup
from bkr.inttest.client import run_client, ClientError, create_client_config, \
ClientTestCase
@@ -21,7 +20,7 @@ class UserModifyTest(ClientTestCase):
out = run_client(['bkr', 'user-modify', '--add-submission-delegate',
'1thatdoesnotexist'], config=client_config)
self.fail('Added an invalid submission delegate')
- except ClientError, e:
+ except ClientError as e:
self.assertTrue('1thatdoesnotexist is not a valid user' in \
e.stderr_output, e.stderr_output)
@@ -48,7 +47,7 @@ class UserModifyTest(ClientTestCase):
run_client(['bkr', 'user-modify', '--remove-submission-delegate',
notadelegate.user_name], config=client_config)
self.fail('Does not throw error when removing non delegate')
- except ClientError, e:
+ except ClientError as e:
self.assertTrue('%s is not a submission delegate of %s' % \
(notadelegate.user_name, user) in e.stderr_output,
e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_watchdog_extend.py b/IntegrationTests/src/bkr/inttest/client/test_watchdog_extend.py
index 4fe1e01..ebbe201 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_watchdog_extend.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_watchdog_extend.py
@@ -24,20 +24,20 @@ class WatchdogExtend(ClientTestCase):
try:
run_client(['bkr','watchdog-extend'])
self.fail('Must fail')
- except ClientError, e:
+ except ClientError as e:
self.assert_('Please either specify one or more <taskspec> arguments or system FQDNs' in e.stderr_output)
try:
run_client(['bkr','watchdog-extend', '--by=ABC'])
self.fail('Must fail')
- except ClientError, e:
+ except ClientError as e:
self.assert_("invalid integer value: 'ABC'" in e.stderr_output)
def test_invalid_taskspec(self):
try:
run_client(['bkr','watchdog-extend', 'J:123'])
self.fail('Must fail')
- except ClientError, e:
+ except ClientError as e:
self.assert_('Taskspec type must be one of [R, T]' in e.stderr_output)
def test_nonexistent_watchdog(self):
diff --git a/IntegrationTests/src/bkr/inttest/client/test_watchdogs_extend.py b/IntegrationTests/src/bkr/inttest/client/test_watchdogs_extend.py
index d6704d3..093ffd1 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_watchdogs_extend.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_watchdogs_extend.py
@@ -8,6 +8,7 @@ from turbogears.database import session
from bkr.inttest import data_setup
from bkr.inttest.client import run_client, ClientError, ClientTestCase
+
class WatchdogsExtend(ClientTestCase):
# https://bugzilla.redhat.com/show_bug.cgi?id=906803
@@ -22,7 +23,7 @@ class WatchdogsExtend(ClientTestCase):
with session.begin():
user1 = data_setup.create_user(password='abc')
try:
- out = run_client(['bkr', 'watchdogs-extend',\
- '--username',user1.user_name,'--password','abc'])
- except ClientError, e:
+ run_client(['bkr', 'watchdogs-extend',
+ '--username',user1.user_name,'--password','abc'])
+ except ClientError as e:
self.assert_('Not member of group: admin' in e.stderr_output)
diff --git a/IntegrationTests/src/bkr/inttest/client/test_watchdogs_show.py b/IntegrationTests/src/bkr/inttest/client/test_watchdogs_show.py
index 2f8cfcb..f8fee09 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_watchdogs_show.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_watchdogs_show.py
@@ -9,7 +9,7 @@ import datetime
from turbogears.database import session
from bkr.inttest import data_setup
from bkr.inttest.client import run_client, ClientTestCase
-from bkr.server.model import RecipeTask
+
class WatchdogShowTest(ClientTestCase):
diff --git a/IntegrationTests/src/bkr/inttest/client/test_whoami.py b/IntegrationTests/src/bkr/inttest/client/test_whoami.py
index f48aab1..c5d0379 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_whoami.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_whoami.py
@@ -43,8 +43,8 @@ class WhoAmITest(ClientTestCase):
# https://bugzilla.redhat.com/show_bug.cgi?id=1072127
def test_password_not_set_on_server_side(self):
- # A user account might have a NULL password if the Beaker site is using
- # Kerberos authentication, or if their account is new and the admin
+ # A user account might have a NULL password if the Beaker site is using
+ # Kerberos authentication, or if their account is new and the admin
# hasn't set a password yet.
with session.begin():
user = data_setup.create_user(password=None)
@@ -65,8 +65,8 @@ class WhoAmITest(ClientTestCase):
# https://bugzilla.redhat.com/show_bug.cgi?id=844364
def test_config_is_read_from_user_config_and_system_config(self):
- # We tell the client to use a config which lacks HUB_URL. The correct
- # HUB_URL setting will be inherited from the system-wide config instead
+ # We tell the client to use a config which lacks HUB_URL. The correct
+ # HUB_URL setting will be inherited from the system-wide config instead
# and so the command still succeeds.
if not os.path.exists('/etc/beaker/client.conf'):
raise SkipTest('System-wide client config does not exist')
diff --git a/IntegrationTests/src/bkr/inttest/client/test_wizard.py b/IntegrationTests/src/bkr/inttest/client/test_wizard.py
index 54d067c..71caab5 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_wizard.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_wizard.py
@@ -42,7 +42,7 @@ class TestWizard(BaseWizardTestCase):
self.assertRegexpMatches(out, re.compile(r'\bBeaker Wizard\b', re.I), out)
def test_wizard_guesses_package_from_cwd(self):
- # When run with no args, beaker-wizard guesses the package from the cwd
+ # When run with no args, beaker-wizard guesses the package from the cwd
# and uses defaults for everything else.
package = 'bash'
test_path = os.path.join(self.tempdir, package)
@@ -52,9 +52,9 @@ class TestWizard(BaseWizardTestCase):
self.assertIn('Package : %s' % package, out)
def test_wizard_guesses_values_from_test_name(self):
- # When given a test name, beaker-wizard creates its output in that
- # subdirectory and also guesses some values based on the directory
- # structure. Here we cover each of the possibilities described in the
+ # When given a test name, beaker-wizard creates its output in that
+ # subdirectory and also guesses some values based on the directory
+ # structure. Here we cover each of the possibilities described in the
# man page.
# TESTNAME
diff --git a/IntegrationTests/src/bkr/inttest/client/test_workflow_simple.py b/IntegrationTests/src/bkr/inttest/client/test_workflow_simple.py
index db4d483..754ef95 100644
--- a/IntegrationTests/src/bkr/inttest/client/test_workflow_simple.py
+++ b/IntegrationTests/src/bkr/inttest/client/test_workflow_simple.py
@@ -1,4 +1,3 @@
-
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
@@ -15,6 +14,7 @@ from bkr.inttest.client import run_client, start_client, \
create_client_config, ClientError, ClientTestCase
from bkr.server.model import Job, SystemStatus
+
class WorkflowSimpleTest(ClientTestCase):
@with_transaction
@@ -32,7 +32,7 @@ class WorkflowSimpleTest(ClientTestCase):
'--arch', self.distro_tree.arch.arch,
'--family', self.distro.osversion.osmajor.osmajor])
self.assertIn(
- 'No tasks specified to be run\nHint', assertion.exception.stderr_output)
+ 'No tasks specified to be run\nHint', assertion.exception.stderr_output)
def test_package_option_without_assocaited_tasks_throws_error(self):
# package with associated task runs error-free
@@ -44,8 +44,8 @@ class WorkflowSimpleTest(ClientTestCase):
# package without associated task throws error
with self.assertRaises(ClientError) as assertion:
run_client(['bkr', 'workflow-simple',
- '--package', "nonexistentpackage",
- '--family', self.distro.osversion.osmajor.osmajor])
+ '--package', "nonexistentpackage",
+ '--family', self.distro.osversion.osmajor.osmajor])
self.assertIn(
'No tasks match the specified option(s)', assertion.exception.stderr_output)
@@ -58,12 +58,12 @@ class WorkflowSimpleTest(ClientTestCase):
# Test submitting on behalf of user's group
config1 = create_client_config(username=user_in_group.user_name,
- password='password')
+ password='password')
out = run_client(['bkr', 'workflow-simple', '--random',
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--job-group', group.group_name,
- '--task', self.task.name], config=config1)
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--job-group', group.group_name,
+ '--task', self.task.name], config=config1)
self.assertTrue(out.startswith('Submitted:'), out)
m = re.search('J:(\d+)', out)
job_id = m.group(1)
@@ -73,18 +73,18 @@ class WorkflowSimpleTest(ClientTestCase):
# Test submitting on behalf of group user does not belong to
config2 = create_client_config(username=user_not_in_group.user_name,
- password='password')
+ password='password')
try:
- out2 = run_client(['bkr', 'workflow-simple', '--random',
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--job-group', group.group_name,
- '--task', self.task.name], config=config2)
- fail('should raise')
- except ClientError, e:
+ run_client(['bkr', 'workflow-simple', '--random',
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--job-group', group.group_name,
+ '--task', self.task.name], config=config2)
+ self.fail('should raise')
+ except ClientError as e:
self.assertTrue('User %s is not a member of group %s' % \
- (user_not_in_group.user_name, group.group_name) in \
- e.stderr_output, e)
+ (user_not_in_group.user_name, group.group_name) in \
+ e.stderr_output, e)
def test_job_owner(self):
with session.begin():
@@ -93,10 +93,10 @@ class WorkflowSimpleTest(ClientTestCase):
user.add_submission_delegate(bot, service=u'testdata')
config = create_client_config(username=bot.user_name, password='bot')
out = run_client(['bkr', 'workflow-simple',
- '--job-owner', user.user_name,
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--task', self.task.name], config=config)
+ '--job-owner', user.user_name,
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--task', self.task.name], config=config)
self.assertTrue(out.startswith('Submitted:'), out)
m = re.search('J:(\d+)', out)
job_id = m.group(1)
@@ -106,9 +106,9 @@ class WorkflowSimpleTest(ClientTestCase):
def test_submit_job(self):
out = run_client(['bkr', 'workflow-simple', '--random',
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--task', self.task.name])
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--task', self.task.name])
self.assert_(out.startswith('Submitted:'), out)
def test_submit_job_wait(self):
@@ -136,25 +136,25 @@ class WorkflowSimpleTest(ClientTestCase):
def test_clean_defaults(self):
out = run_client(['bkr', 'workflow-simple',
- '--dryrun', '--prettyxml',
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--task', self.task.name])
+ '--dryrun', '--prettyxml',
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--task', self.task.name])
# Try to minimise noise in the default output
self.assertNotIn('ks_appends', out)
def test_hostrequire(self):
out = run_client(['bkr', 'workflow-simple',
- '--dryrun', '--prettyxml',
- '--hostrequire', 'hostlabcontroller=lab.example.com',
- '--systype', 'machine',
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--task', self.task.name])
+ '--dryrun', '--prettyxml',
+ '--hostrequire', 'hostlabcontroller=lab.example.com',
+ '--systype', 'machine',
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--task', self.task.name])
self.assertIn('<hostlabcontroller op="=" value="lab.example.com"/>', out)
self.assertIn('<system_type op="=" value="machine"/>', out)
- #https://bugzilla.redhat.com/show_bug.cgi?id=1081390
+ # https://bugzilla.redhat.com/show_bug.cgi?id=1081390
def test_hostfilter_preset(self):
out = run_client(['bkr', 'workflow-simple',
'--dryrun', '--prettyxml',
@@ -177,14 +177,14 @@ class WorkflowSimpleTest(ClientTestCase):
# Override $HOME and check if the updated defintion is read
test_home = pkg_resources.resource_filename \
- ('bkr.inttest.client', '.')
+ ('bkr.inttest.client', '.')
out = run_client(['bkr', 'workflow-simple',
'--dryrun', '--prettyxml',
'--host-filter', "INTEL__FAM15_CELERON",
'--arch', self.distro_tree.arch.arch,
'--family', self.distro.osversion.osmajor.osmajor,
- '--task', self.task.name],
- extra_env={'HOME':test_home})
+ '--task', self.task.name],
+ extra_env={'HOME': test_home})
self.assertIn('<model_name op="like" value="%MyCeleron%"/>', out)
# Non-existent filter
@@ -202,45 +202,45 @@ class WorkflowSimpleTest(ClientTestCase):
# https://bugzilla.redhat.com/show_bug.cgi?id=1014693
def test_hostrequire_raw_xml(self):
out = run_client(['bkr', 'workflow-simple',
- '--dryrun', '--prettyxml',
- '--hostrequire', '<device vendor_id="8086"/>',
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--task', self.task.name])
+ '--dryrun', '--prettyxml',
+ '--hostrequire', '<device vendor_id="8086"/>',
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--task', self.task.name])
self.assertIn('<device vendor_id="8086"/>', out)
# https://bugzilla.redhat.com/show_bug.cgi?id=883020
def test_hostrequire_shows_error_for_unparseable_values(self):
with self.assertRaises(ClientError) as assertion:
out = run_client(['bkr', 'workflow-simple',
- '--dryrun', '--prettyxml',
- '--hostrequire', 'asdf',
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--task', self.task.name])
+ '--dryrun', '--prettyxml',
+ '--hostrequire', 'asdf',
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--task', self.task.name])
self.assertIn(
- '--hostrequire option must be in the form "TAG OPERATOR VALUE"',
- assertion.exception.stderr_output)
+ '--hostrequire option must be in the form "TAG OPERATOR VALUE"',
+ assertion.exception.stderr_output)
def test_keyvalue_shows_error_for_unparseable_values(self):
with self.assertRaises(ClientError) as assertion:
out = run_client(['bkr', 'workflow-simple',
- '--dryrun', '--prettyxml',
- '--keyvalue', 'asdf',
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--task', self.task.name])
+ '--dryrun', '--prettyxml',
+ '--keyvalue', 'asdf',
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--task', self.task.name])
self.assertIn(
- '--keyvalue option must be in the form "KEY OPERATOR VALUE"',
- assertion.exception.stderr_output)
+ '--keyvalue option must be in the form "KEY OPERATOR VALUE"',
+ assertion.exception.stderr_output)
def test_reserve(self):
out = run_client(['bkr', 'workflow-simple',
- '--dry-run', '--pretty-xml',
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--task', self.task.name,
- '--reserve', '--reserve-duration', '3600'])
+ '--dry-run', '--pretty-xml',
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--task', self.task.name,
+ '--reserve', '--reserve-duration', '3600'])
self.assertIn('<reservesys duration="3600"/>', out)
# https://bugzilla.redhat.com/show_bug.cgi?id=1095026
@@ -273,12 +273,12 @@ class WorkflowSimpleTest(ClientTestCase):
# https://bugzilla.redhat.com/show_bug.cgi?id=1234323
def test_accepts_machine_and_systype(self):
out = run_client(['bkr', 'workflow-simple',
- '--dryrun', '--prettyxml',
- '--machine', 'system.example.com',
- '--systype', 'Prototype',
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--task', self.task.name])
+ '--dryrun', '--prettyxml',
+ '--machine', 'system.example.com',
+ '--systype', 'Prototype',
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--task', self.task.name])
self.assertIn('<hostname op="=" value="system.example.com"/>', out)
self.assertIn('<system_type op="=" value="Prototype"/>', out)
@@ -286,12 +286,12 @@ class WorkflowSimpleTest(ClientTestCase):
first_url = 'http://repo1.example.invalid'
second_url = 'ftp://repo2.example.invalid'
out = run_client(['bkr', 'workflow-simple',
- '--dryrun', '--prettyxml',
- '--repo', first_url,
- '--repo', second_url,
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--task', self.task.name])
+ '--dryrun', '--prettyxml',
+ '--repo', first_url,
+ '--repo', second_url,
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--task', self.task.name])
expected_snippet = '<repo name="myrepo_%(idx)s" url="%(repoloc)s"/>'
first_repo = expected_snippet % dict(idx=0, repoloc=first_url)
self.assertIn(first_repo, out)
@@ -303,12 +303,12 @@ class WorkflowSimpleTest(ClientTestCase):
first_url = 'http://repo1.example.invalid'
second_url = 'ftp://repo2.example.invalid'
out = run_client(['bkr', 'workflow-simple',
- '--dryrun', '--prettyxml',
- '--repo-post', first_url,
- '--repo-post', second_url,
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--task', self.task.name])
+ '--dryrun', '--prettyxml',
+ '--repo-post', first_url,
+ '--repo-post', second_url,
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--task', self.task.name])
expected_snippet = textwrap.dedent('''\
cat << EOF >/etc/yum.repos.d/beaker-postrepo%(idx)s.repo
[beaker-postrepo%(idx)s]
@@ -331,8 +331,8 @@ class WorkflowSimpleTest(ClientTestCase):
# https://bugzilla.redhat.com/show_bug.cgi?id=972417
def test_servers_default_zero(self):
out = run_client(['bkr', 'workflow-simple', '--distro', self.distro.name,
- '--task', '/distribution/reservesys',
- '--clients', '2'])
+ '--task', '/distribution/reservesys',
+ '--clients', '2'])
self.assertTrue(out.startswith('Submitted:'), out)
m = re.search('J:(\d+)', out)
job_id = m.group(1)
@@ -346,8 +346,8 @@ class WorkflowSimpleTest(ClientTestCase):
# https://bugzilla.redhat.com/show_bug.cgi?id=972417
def test_clients_default_zero(self):
out = run_client(['bkr', 'workflow-simple', '--distro', self.distro.name,
- '--task', '/distribution/reservesys',
- '--servers', '2'])
+ '--task', '/distribution/reservesys',
+ '--servers', '2'])
self.assertTrue(out.startswith('Submitted:'), out)
m = re.search('J:(\d+)', out)
job_id = m.group(1)
@@ -360,7 +360,7 @@ class WorkflowSimpleTest(ClientTestCase):
def submit_job_and_check_arches(self, workflow_options, expected_arches):
out = run_client(['bkr', 'workflow-simple', '--task', self.task.name]
- + workflow_options)
+ + workflow_options)
self.assertTrue(out.startswith('Submitted:'), out)
m = re.search('J:(\d+)', out)
job_id = m.group(1)
@@ -372,59 +372,59 @@ class WorkflowSimpleTest(ClientTestCase):
# https://bugzilla.redhat.com/show_bug.cgi?id=1078941
def test_lookup_arches_by_family(self):
- # When a family is given but no arches, the workflow commands are
- # supposed to look up all applicable arches and create a recipe set for
+ # When a family is given but no arches, the workflow commands are
+ # supposed to look up all applicable arches and create a recipe set for
# each one.
with session.begin():
distro = data_setup.create_distro(osmajor=u'DansAwesomeLinux7',
- tags=[u'STABLE'])
+ tags=[u'STABLE'])
data_setup.create_distro_tree(distro=distro, arch=u'x86_64')
data_setup.create_distro_tree(distro=distro, arch=u's390x')
self.submit_job_and_check_arches(
- ['--family', distro.osversion.osmajor.osmajor],
- [u'x86_64', u's390x'])
+ ['--family', distro.osversion.osmajor.osmajor],
+ [u'x86_64', u's390x'])
# https://bugzilla.redhat.com/show_bug.cgi?id=1255420
def test_looks_up_arches_for_suitable_osminor(self):
- # RHEL7 is the first time we have had differing arches across a single
- # OS major. We want the workflow command to use the set of arches for
- # the OS version which will actually match whatever distro filtering
- # options we are using, e.g. latest RedHatEnterpriseLinux7 should be
+ # RHEL7 is the first time we have had differing arches across a single
+ # OS major. We want the workflow command to use the set of arches for
+ # the OS version which will actually match whatever distro filtering
+ # options we are using, e.g. latest RedHatEnterpriseLinux7 should be
# using RHEL7.2 arches, not RHEL7.0.
with session.begin():
older_arches = [u'x86_64', u's390x']
older_distro = data_setup.create_distro(
- osmajor=u'DansAwesomeLinux8', osminor=u'0',
- arches=older_arches,
- date_created=datetime.datetime(2010, 1, 1, 0, 0),
- tags=[u'STABLE'])
+ osmajor=u'DansAwesomeLinux8', osminor=u'0',
+ arches=older_arches,
+ date_created=datetime.datetime(2010, 1, 1, 0, 0),
+ tags=[u'STABLE'])
for arch in older_arches:
data_setup.create_distro_tree(distro=older_distro, arch=arch)
newer_arches = [u'x86_64', u's390x', u'ppc64le']
newer_distro = data_setup.create_distro(
- osmajor=u'DansAwesomeLinux8', osminor=u'1',
- arches=newer_arches,
- date_created=datetime.datetime(2012, 1, 1, 0, 0),
- tags=[])
+ osmajor=u'DansAwesomeLinux8', osminor=u'1',
+ arches=newer_arches,
+ date_created=datetime.datetime(2012, 1, 1, 0, 0),
+ tags=[])
for arch in newer_arches:
data_setup.create_distro_tree(distro=newer_distro, arch=arch)
# Naming a specific distro should always use the corresponding OS minor arches.
self.submit_job_and_check_arches(['--distro', older_distro.name], older_arches)
self.submit_job_and_check_arches(['--distro', newer_distro.name], newer_arches)
- # Giving a family in addition to a specific distro is redundant, but it
+ # Giving a family in addition to a specific distro is redundant, but it
# shouldn't break the arch lookup.
self.submit_job_and_check_arches(
- ['--distro', older_distro.name, '--family', 'DansAwesomeLinux8'],
- older_arches)
+ ['--distro', older_distro.name, '--family', 'DansAwesomeLinux8'],
+ older_arches)
self.submit_job_and_check_arches(
- ['--distro', newer_distro.name, '--family', 'DansAwesomeLinux8'],
- newer_arches)
+ ['--distro', newer_distro.name, '--family', 'DansAwesomeLinux8'],
+ newer_arches)
# Naming just a family will use the latest distro in that family.
self.submit_job_and_check_arches(['--family', 'DansAwesomeLinux8'], newer_arches)
# Family filtered by tag can restrict it to an older release though.
self.submit_job_and_check_arches(
- ['--family', 'DansAwesomeLinux8', '--tag', 'STABLE'],
- older_arches)
+ ['--family', 'DansAwesomeLinux8', '--tag', 'STABLE'],
+ older_arches)
def test_kickstart_template(self):
template_contents = 'install\n%packages\n%end\n'
@@ -432,15 +432,15 @@ class WorkflowSimpleTest(ClientTestCase):
template_file.write(template_contents)
template_file.flush()
out = run_client(['bkr', 'workflow-simple', '--distro', self.distro.name,
- '--task', self.task.name,
- '--kickstart', template_file.name])
+ '--task', self.task.name,
+ '--kickstart', template_file.name])
self.assertTrue(out.startswith('Submitted:'), out)
m = re.search('J:(\d+)', out)
job_id = m.group(1)
with session.begin():
job = Job.by_id(job_id)
self.assertEquals(job.recipesets[0].recipes[0].kickstart,
- template_contents)
+ template_contents)
def test_kickstart_template_with_kernel_options(self):
template_contents = """
@@ -453,36 +453,36 @@ install
template_file.write(template_contents)
template_file.flush()
out = run_client(['bkr', 'workflow-simple', '--distro', self.distro.name,
- '--task', self.task.name,
- '--kickstart', template_file.name])
+ '--task', self.task.name,
+ '--kickstart', template_file.name])
self.assertTrue(out.startswith('Submitted:'), out)
m = re.search('J:(\d+)', out)
job_id = m.group(1)
with session.begin():
job = Job.by_id(job_id)
self.assertEquals(job.recipesets[0].recipes[0].kernel_options,
- "sshd=1")
+ "sshd=1")
# https://bugzilla.redhat.com/show_bug.cgi?id=856687
def test_ks_append(self):
first_ks = 'append1'
second_ks = 'append2'
out = run_client(['bkr', 'workflow-simple',
- '--dryrun', '--prettyxml',
- '--ks-append', first_ks,
- '--ks-append', second_ks,
- '--arch', self.distro_tree.arch.arch,
- '--family', self.distro.osversion.osmajor.osmajor,
- '--task', self.task.name])
+ '--dryrun', '--prettyxml',
+ '--ks-append', first_ks,
+ '--ks-append', second_ks,
+ '--arch', self.distro_tree.arch.arch,
+ '--family', self.distro.osversion.osmajor.osmajor,
+ '--task', self.task.name])
self.assertIn("<ks_append>\n<![CDATA[%s]]>\t\t\t\t</ks_append>" % first_ks, out)
self.assertIn("<ks_append>\n<![CDATA[%s]]>\t\t\t\t</ks_append>" % second_ks, out)
# https://bugzilla.redhat.com/show_bug.cgi?id=1220652
def test_no_default_install_method(self):
- # Not specifying a method in ks_meta means Beaker picks one. We want
+ # Not specifying a method in ks_meta means Beaker picks one. We want
# that to be the default behaviour if --method is not given.
out = run_client(['bkr', 'workflow-simple', '--distro', self.distro.name,
- '--task', self.task.name])
+ '--task', self.task.name])
self.assertTrue(out.startswith('Submitted:'), out)
m = re.search('J:(\d+)', out)
job_id = m.group(1)
@@ -493,10 +493,10 @@ install
# https://bugzilla.redhat.com/show_bug.cgi?id=1323921
def test_can_do_dry_run_anonymously(self):
config = create_client_config(username=u'ignored', password=u'ignored',
- auth_method=u'none')
+ auth_method=u'none')
out = run_client(['bkr', 'workflow-simple', '--distro', self.distro.name,
- '--task', self.task.name, '--dry-run', '--pretty-xml'],
- config=config)
+ '--task', self.task.name, '--dry-run', '--pretty-xml'],
+ config=config)
self.assertIn('<job', out)
# https://bugzilla.redhat.com/show_bug.cgi?id=1319988
@@ -504,7 +504,7 @@ install
with session.begin():
lc = data_setup.create_labcontroller()
system = data_setup.create_system(lab_controller=lc,
- status=SystemStatus.broken)
+ status=SystemStatus.broken)
out = run_client(['bkr', 'workflow-simple', '--distro', self.distro.name,
'--machine', system.fqdn,
'--ignore-system-status',
@@ -533,7 +533,8 @@ install
# https://bugzilla.redhat.com/show_bug.cgi?id=1197608
def test_filters_task_by_osmajor_with_given_taskfile(self):
with session.begin():
- ignored_task = data_setup.create_task(exclude_osmajors=[self.distro.osversion.osmajor.osmajor])
+ ignored_task = data_setup.create_task(
+ exclude_osmajors=[self.distro.osversion.osmajor.osmajor])
included_task = data_setup.create_task()
taskfile = NamedTemporaryFile()
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/AtomicHost-defaults.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/AtomicHost-defaults.expected
index 1a2aa2d..7c8d8ef 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/AtomicHost-defaults.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/AtomicHost-defaults.expected
@@ -299,20 +299,26 @@ EOF
# Create the Dockerfile for the container
cat << EOF > /root/Dockerfile
+if command -v dnf >/dev/null ; then
+ export package_command="dnf"
+else
+ export package_command="yum"
+fi
+
FROM registry.hub.docker.com/fedora:20
MAINTAINER Beaker Developers <beaker-devel@lists.fedoraproject.org>
ENV container docker
ADD beaker-tasks.repo /etc/yum.repos.d/
ADD customrepos/ /etc/yum.repos.d/
ADD beaker-harness-env.sh /etc/profile.d/beaker-harness-env.sh
-RUN yum -y update; yum clean all
+RUN $package_command -y update; $package_command clean all
# We assume that if the contained harness entrypoint is not
# defined, we are relying on systemd to start the harness
# for us
# Reference: http://developerblog.redhat.com/2014/05/05/running-systemd-within-docker-container/
-RUN yum -y remove fakesystemd || true
-RUN yum -y install systemd; \
+RUN $package_command -y remove fakesystemd || true
+RUN $package_command -y install systemd; \
(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ "\$i" == systemd-tmpfiles-setup.service ] || rm -f "\$i"; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
@@ -324,10 +330,10 @@ rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
# Install the harness
-RUN yum -y install restraint-rhts
-RUN yum -y install coreutils
-RUN yum -y install beakerlib || true
-RUN yum -y install beakerlib-redhat || true
+RUN $package_command -y install restraint-rhts
+RUN $package_command -y install coreutils
+RUN $package_command -y install beakerlib || true
+RUN $package_command -y install beakerlib-redhat || true
CMD ["/usr/sbin/init"]
EOF
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-harness-contained-custom.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-harness-contained-custom.expected
index 4767edf..8ee4ea4 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-harness-contained-custom.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-harness-contained-custom.expected
@@ -299,20 +299,26 @@ cp /etc/yum.repos.d/beaker-tasks.repo /root/
# Create the Dockerfile for the container
cat << EOF > /root/Dockerfile
+if command -v dnf >/dev/null ; then
+ export package_command="dnf"
+else
+ export package_command="yum"
+fi
+
FROM docker-registry.mysys.com/fedora:latest
MAINTAINER Beaker Developers <beaker-devel@lists.fedoraproject.org>
ENV container docker
ADD beaker-tasks.repo /etc/yum.repos.d/
ADD customrepos/ /etc/yum.repos.d/
ADD beaker-harness-env.sh /etc/profile.d/beaker-harness-env.sh
-RUN yum -y update; yum clean all
+RUN $package_command -y update; $package_command clean all
# Install the harness
-RUN yum -y install restraint-rhts
-RUN yum -y install coreutils
-RUN yum -y install beakerlib || true
-RUN yum -y install beakerlib-redhat || true
+RUN $package_command -y install restraint-rhts
+RUN $package_command -y install coreutils
+RUN $package_command -y install beakerlib || true
+RUN $package_command -y install beakerlib-redhat || true
CMD /usr/bin/mybinary
EOF
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-harness-contained.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-harness-contained.expected
index 1c7605f..f540b25 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-harness-contained.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-harness-contained.expected
@@ -318,20 +318,26 @@ EOF
# Create the Dockerfile for the container
cat << EOF > /root/Dockerfile
+if command -v dnf >/dev/null ; then
+ export package_command="dnf"
+else
+ export package_command="yum"
+fi
+
FROM registry.hub.docker.com/fedora:18
MAINTAINER Beaker Developers <beaker-devel@lists.fedoraproject.org>
ENV container docker
ADD beaker-tasks.repo /etc/yum.repos.d/
ADD customrepos/ /etc/yum.repos.d/
ADD beaker-harness-env.sh /etc/profile.d/beaker-harness-env.sh
-RUN yum -y update; yum clean all
+RUN $package_command -y update; $package_command clean all
# We assume that if the contained harness entrypoint is not
# defined, we are relying on systemd to start the harness
# for us
# Reference: http://developerblog.redhat.com/2014/05/05/running-systemd-within-docker-container/
-RUN yum -y remove fakesystemd || true
-RUN yum -y install systemd; \
+RUN $package_command -y remove fakesystemd || true
+RUN $package_command -y install systemd; \
(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ "\$i" == systemd-tmpfiles-setup.service ] || rm -f "\$i"; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
@@ -343,10 +349,10 @@ rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
# Install the harness
-RUN yum -y install restraint-rhts
-RUN yum -y install coreutils
-RUN yum -y install beakerlib || true
-RUN yum -y install beakerlib-redhat || true
+RUN $package_command -y install restraint-rhts
+RUN $package_command -y install coreutils
+RUN $package_command -y install beakerlib || true
+RUN $package_command -y install beakerlib-redhat || true
CMD ["/usr/sbin/init"]
EOF
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-scheduler-defaults.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-scheduler-defaults.expected
index 6ae6011..b51596f 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-scheduler-defaults.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedora18-scheduler-defaults.expected
@@ -308,14 +308,24 @@ skip_if_unavailable=1
EOF
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
-yum -y install beah rhts-test-env
-yum -y install beakerlib
+$package_command check-update > /dev/null 2>&1 || true
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command -y install beah rhts-test-env
+$package_command -y install beakerlib
# This may fail if you are outside of Red Hat..
-yum -y install beakerlib-redhat
+$package_command -y install beakerlib-redhat
cp /etc/beah_beaker.conf{,.default}
cat << EOF > /etc/beah_beaker.conf
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedorarawhide-scheduler-defaults.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedorarawhide-scheduler-defaults.expected
index 5ee8b3d..67dce5e 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedorarawhide-scheduler-defaults.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/Fedorarawhide-scheduler-defaults.expected
@@ -289,10 +289,15 @@ skip_if_unavailable=1
EOF
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
+$package_command check-update > /dev/null 2>&1 || true
cat <<"EOF" >/etc/profile.d/beaker-harness-env.sh
export BEAKER_LAB_CONTROLLER_URL="http://lab.test-kickstart.invalid:8000/"
export BEAKER_LAB_CONTROLLER=lab.test-kickstart.invalid
@@ -306,7 +311,12 @@ setenv BEAKER_RECIPE_ID @RECIPEID@
setenv BEAKER_HUB_URL "@BEAKER@"
EOF
-yum -y install restraint-rhts
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command -y install restraint-rhts
#Add test user account
useradd --password '$6$oIW3o2Mr$XbWZKaM7nA.cQqudfDJScupXOia5h1u517t6Htx/Q/MgXm82Pc/OcytatTeI4ULNWOMJzvpCigWiL4xKP9PX4.' test
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/RHVH-defaults.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/RHVH-defaults.expected
index 16c7e3e..1940280 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/RHVH-defaults.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/RHVH-defaults.expected
@@ -275,14 +275,24 @@ EOF
# Add distro and custom Repos
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
-yum -y install beah rhts-test-env
-yum -y install beakerlib
+$package_command check-update > /dev/null 2>&1 || true
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command -y install beah rhts-test-env
+$package_command -y install beakerlib
# This may fail if you are outside of Red Hat..
-yum -y install beakerlib-redhat
+$package_command -y install beakerlib-redhat
cp /etc/beah_beaker.conf{,.default}
cat << EOF > /etc/beah_beaker.conf
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux3-scheduler-defaults.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux3-scheduler-defaults.expected
index aff70b4..c31e800 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux3-scheduler-defaults.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux3-scheduler-defaults.expected
@@ -318,14 +318,24 @@ skip_if_unavailable=1
EOF
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
-yum -d 1 -y install beah rhts-test-env
-yum -d 1 -y install beakerlib
+$package_command check-update > /dev/null 2>&1 || true
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command -d 1 -y install beah rhts-test-env
+$package_command -d 1 -y install beakerlib
# This may fail if you are outside of Red Hat..
-yum -d 1 -y install beakerlib-redhat
+$package_command -d 1 -y install beakerlib-redhat
cp /etc/beah_beaker.conf{,.default}
cat << EOF > /etc/beah_beaker.conf
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux4-scheduler-defaults.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux4-scheduler-defaults.expected
index 2312d4f..952c22a 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux4-scheduler-defaults.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux4-scheduler-defaults.expected
@@ -298,14 +298,24 @@ skip_if_unavailable=1
EOF
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
-yum -d 1 -y install beah rhts-test-env
-yum -d 1 -y install beakerlib
+$package_command check-update > /dev/null 2>&1 || true
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command -d 1 -y install beah rhts-test-env
+$package_command -d 1 -y install beakerlib
# This may fail if you are outside of Red Hat..
-yum -d 1 -y install beakerlib-redhat
+$package_command -d 1 -y install beakerlib-redhat
cp /etc/beah_beaker.conf{,.default}
cat << EOF > /etc/beah_beaker.conf
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-defaults-beaker-create-kickstart.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-defaults-beaker-create-kickstart.expected
index c2be42c..db16184 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-defaults-beaker-create-kickstart.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-defaults-beaker-create-kickstart.expected
@@ -364,14 +364,24 @@ skip_if_unavailable=1
EOF
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
-yum -y install beah rhts-test-env
-yum -y install beakerlib
+$package_command check-update > /dev/null 2>&1 || true
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command -y install beah rhts-test-env
+$package_command -y install beakerlib
# This may fail if you are outside of Red Hat..
-yum -y install beakerlib-redhat
+$package_command -y install beakerlib-redhat
cp /etc/beah_beaker.conf{,.default}
cat << EOF > /etc/beah_beaker.conf
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-defaults.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-defaults.expected
index 90245da..9514701 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-defaults.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-defaults.expected
@@ -364,14 +364,24 @@ skip_if_unavailable=1
EOF
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
-yum -y install beah rhts-test-env
-yum -y install beakerlib
+$package_command check-update > /dev/null 2>&1 || true
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command -y install beah rhts-test-env
+$package_command -y install beakerlib
# This may fail if you are outside of Red Hat..
-yum -y install beakerlib-redhat
+$package_command -y install beakerlib-redhat
cp /etc/beah_beaker.conf{,.default}
cat << EOF > /etc/beah_beaker.conf
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-guest.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-guest.expected
index f41c61f..c6009c8 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-guest.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-guest.expected
@@ -351,14 +351,24 @@ skip_if_unavailable=1
EOF
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
-yum -y install beah rhts-test-env
-yum -y install beakerlib
+$package_command check-update > /dev/null 2>&1 || true
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command -y install beah rhts-test-env
+$package_command -y install beakerlib
# This may fail if you are outside of Red Hat..
-yum -y install beakerlib-redhat
+$package_command -y install beakerlib-redhat
cp /etc/beah_beaker.conf{,.default}
cat << EOF > /etc/beah_beaker.conf
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-manual.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-manual.expected
index 703340e..efab3ac 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-manual.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux6-scheduler-manual.expected
@@ -301,14 +301,24 @@ skip_if_unavailable=1
EOF
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
-yum -y install beah rhts-test-env
-yum -y install beakerlib
+$package_command check-update > /dev/null 2>&1 || true
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command -y install beah rhts-test-env
+$package_command -y install beakerlib
# This may fail if you are outside of Red Hat..
-yum -y install beakerlib-redhat
+$package_command -y install beakerlib-redhat
cp /etc/beah_beaker.conf{,.default}
cat << EOF > /etc/beah_beaker.conf
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux7-scheduler-defaults.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux7-scheduler-defaults.expected
index 6ebe3a1..efa9c2c 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux7-scheduler-defaults.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux7-scheduler-defaults.expected
@@ -339,14 +339,24 @@ skip_if_unavailable=1
EOF
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
-yum -y install beah rhts-test-env
-yum -y install beakerlib
+$package_command check-update > /dev/null 2>&1 || true
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command -y install beah rhts-test-env
+$package_command -y install beakerlib
# This may fail if you are outside of Red Hat..
-yum -y install beakerlib-redhat
+$package_command -y install beakerlib-redhat
cp /etc/beah_beaker.conf{,.default}
cat << EOF > /etc/beah_beaker.conf
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux7-scheduler-manual.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux7-scheduler-manual.expected
index 5791410..90ba3e4 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux7-scheduler-manual.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinux7-scheduler-manual.expected
@@ -278,14 +278,24 @@ skip_if_unavailable=1
EOF
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
-yum -y install beah rhts-test-env
-yum -y install beakerlib
+$package_command check-update > /dev/null 2>&1 || true
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command -y install beah rhts-test-env
+$package_command -y install beakerlib
# This may fail if you are outside of Red Hat..
-yum -y install beakerlib-redhat
+$package_command -y install beakerlib-redhat
cp /etc/beah_beaker.conf{,.default}
cat << EOF > /etc/beah_beaker.conf
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinuxAlternateArchitectures7-scheduler-defaults.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinuxAlternateArchitectures7-scheduler-defaults.expected
index d3fbe45..af28c62 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinuxAlternateArchitectures7-scheduler-defaults.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinuxAlternateArchitectures7-scheduler-defaults.expected
@@ -339,14 +339,24 @@ skip_if_unavailable=1
EOF
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
-yum -y install beah rhts-test-env
-yum -y install beakerlib
+$package_command check-update > /dev/null 2>&1 || true
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command -y install beah rhts-test-env
+$package_command -y install beakerlib
# This may fail if you are outside of Red Hat..
-yum -y install beakerlib-redhat
+$package_command -y install beakerlib-redhat
cp /etc/beah_beaker.conf{,.default}
cat << EOF > /etc/beah_beaker.conf
diff --git a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinuxServer5-scheduler-defaults.expected b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinuxServer5-scheduler-defaults.expected
index 3670b3a..037685a 100644
--- a/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinuxServer5-scheduler-defaults.expected
+++ b/IntegrationTests/src/bkr/inttest/server/kickstarts/RedHatEnterpriseLinuxServer5-scheduler-defaults.expected
@@ -328,14 +328,24 @@ skip_if_unavailable=1
EOF
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
-yum -y install beah rhts-test-env
-yum -y install beakerlib
+$package_command check-update > /dev/null 2>&1 || true
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command -y install beah rhts-test-env
+$package_command -y install beakerlib
# This may fail if you are outside of Red Hat..
-yum -y install beakerlib-redhat
+$package_command -y install beakerlib-redhat
cp /etc/beah_beaker.conf{,.default}
cat << EOF > /etc/beah_beaker.conf
diff --git a/IntegrationTests/src/bkr/inttest/server/selenium/test_prefs.py b/IntegrationTests/src/bkr/inttest/server/selenium/test_prefs.py
index 3d2735c..691d365 100644
--- a/IntegrationTests/src/bkr/inttest/server/selenium/test_prefs.py
+++ b/IntegrationTests/src/bkr/inttest/server/selenium/test_prefs.py
@@ -4,6 +4,7 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
+from bkr.server.model import SSHPubKey
from bkr.inttest.server.selenium import WebDriverTestCase
from bkr.inttest.server.webdriver_utils import login, logout, is_text_present, \
delete_and_confirm
@@ -178,6 +179,18 @@ class UserPrefs(WebDriverTestCase):
self.assertIn('SSH public keys may not contain newlines',
pane.find_element_by_class_name('alert-error').text)
+ # https://bugzilla.redhat.com/show_bug.cgi?id=1175584
+ def test_duplicate_ssh_key_not_accepted(self):
+ sshkey = (u'ssh-rsa', u'uniquekey', u'domain@example.com')
+ with session.begin():
+ self.user.sshpubkeys.append(SSHPubKey(*sshkey))
+ key = 'ssh-rsa %s different_domain@xample.com' % sshkey[1]
+ pane = self.go_to_prefs_tab('SSH Public Keys')
+ pane.find_element_by_name('key').send_keys(key)
+ pane.find_element_by_tag_name('form').submit()
+ self.assertIn('Duplicate SSH public key',
+ pane.find_element_by_class_name('alert-error').text)
+
# https://bugzilla.redhat.com/show_bug.cgi?id=830475
def test_invalid_ssh_key_not_accepted(self):
b = self.browser
diff --git a/IntegrationTests/src/bkr/inttest/server/selenium/test_reserve_system.py b/IntegrationTests/src/bkr/inttest/server/selenium/test_reserve_system.py
index cc72315..e4d547a 100644
--- a/IntegrationTests/src/bkr/inttest/server/selenium/test_reserve_system.py
+++ b/IntegrationTests/src/bkr/inttest/server/selenium/test_reserve_system.py
@@ -15,6 +15,8 @@ from selenium.webdriver.support.ui import Select
import unittest, time, re, os
from turbogears.database import session
+WORKFLOW_DESCR = "Reserve Workflow provision of distro %s on %s for %s seconds"
+
class ReserveWorkflow(WebDriverTestCase):
@with_transaction
@@ -157,6 +159,10 @@ class ReserveWorkflow(WebDriverTestCase):
b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click()
# should end up on the job page
b.find_element_by_xpath('//h1[contains(string(.), "J:")]')
+ wb_descr = (WORKFLOW_DESCR %
+ (self.distro.name, "any system", "86400"))
+ wboard = b.find_element_by_class_name('job-whiteboard')
+ self.assertIn(wb_descr, wboard.text, msg="Fail to match default whiteboard")
# one recipe set for the chosen distro tree
self.assertEquals(len(b.find_elements_by_class_name('recipeset')), 1)
b.find_element_by_xpath('//td[normalize-space(string(.))="%s Server i386"]'
@@ -264,6 +270,10 @@ class ReserveWorkflow(WebDriverTestCase):
b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click()
# should end up on the job page
job_id = b.find_element_by_xpath('//h1//span[@class="job-id"]').text
+ wb_descr = (WORKFLOW_DESCR %
+ (self.distro.name, "any lab system", "86400"))
+ wboard = b.find_element_by_class_name('job-whiteboard')
+ self.assertIn(wb_descr, wboard.text, msg="Fail to match default whiteboard")
with session.begin():
job = TaskBase.get_by_t_id(job_id)
cloned_job_xml = lxml.etree.tostring(job.to_xml(clone=True), encoding=unicode) # cloning re-parses hostRequires
@@ -296,6 +306,10 @@ class ReserveWorkflow(WebDriverTestCase):
b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click()
# should end up on the job page
job_id = b.find_element_by_xpath('//h1//span[@class="job-id"]').text
+ wb_descr = (WORKFLOW_DESCR %
+ ("None", "a specific system", "86400"))
+ wboard = b.find_element_by_class_name('job-whiteboard')
+ self.assertIn(wb_descr, wboard.text, msg="Fail to match default whiteboard")
with session.begin():
job = TaskBase.get_by_t_id(job_id)
cloned_job_xml = lxml.etree.tostring(job.to_xml(clone=True), encoding=unicode) # cloning re-parses hostRequires
@@ -350,7 +364,7 @@ class ReserveSystem(WebDriverTestCase):
b.find_element_by_link_text('Select All').click()
b.find_element_by_xpath("//form[@id='searchform']").submit()
columns = b.find_elements_by_xpath("//table[@id='widget']//th")
- self.assertEquals(len(columns), 33)
+ self.assertEquals(len(columns), 34)
def test_all_systems_included_when_no_distro_tree_selected(self):
login(self.browser)
diff --git a/IntegrationTests/src/bkr/inttest/server/selenium/test_system_search.py b/IntegrationTests/src/bkr/inttest/server/selenium/test_system_search.py
index 7c40675..ad2c141 100644
--- a/IntegrationTests/src/bkr/inttest/server/selenium/test_system_search.py
+++ b/IntegrationTests/src/bkr/inttest/server/selenium/test_system_search.py
@@ -290,6 +290,36 @@ class Search(WebDriverTestCase):
('System/Added', 'before', '2020-06-22')])
check_system_search_results(b, present=[new_system], absent=[old_system])
+ def test_by_notes(self):
+ with session.begin():
+ owner = data_setup.create_user()
+ new_system = data_setup.create_system()
+ new_system.add_note("Note1", owner)
+ old_system = data_setup.create_system()
+ old_system.add_note("Note2", owner)
+
+ b = self.browser
+
+ # System/Notes search is supposed to be case-insensitive
+ perform_search(b, [('System/Notes', 'contains', 'nOTe1')])
+ check_system_search_results(b, present=[new_system], absent=[old_system])
+
+ # Specific search
+ perform_search(b, [('System/Notes', 'is', 'Note2')])
+ check_system_search_results(b, present=[old_system], absent=[new_system])
+
+ # All systems without any note
+ perform_search(b, [('System/Notes', 'is', '')])
+ check_system_search_results(b, absent=[old_system, new_system])
+
+ # All systems with any note
+ perform_search(b, [('System/Notes', 'is not', '')])
+ check_system_search_results(b, present=[old_system, new_system])
+
+ perform_search(b, [('System/Notes', 'is', 'foobar')])
+ # no results
+ b.find_element_by_xpath('//table[@id="widget" and not(.//td)]')
+
def test_by_key_value_is(self):
with session.begin():
self.system.key_values_string.append(Key_Value_String(
diff --git a/IntegrationTests/src/bkr/inttest/server/selenium/test_systems.py b/IntegrationTests/src/bkr/inttest/server/selenium/test_systems.py
index ef48943..8567a1d 100644
--- a/IntegrationTests/src/bkr/inttest/server/selenium/test_systems.py
+++ b/IntegrationTests/src/bkr/inttest/server/selenium/test_systems.py
@@ -66,7 +66,7 @@ class TestSystemsGrid(WebDriverTestCase):
b = self.browser
# check number of columns in the table
ths = b.find_elements_by_xpath('//table[@id="widget"]//th')
- self.assertEquals(len(ths), 32)
+ self.assertEquals(len(ths), 33)
# https://bugzilla.redhat.com/show_bug.cgi?id=1321740
def test_grid_columns_order_is_preserved(self):
diff --git a/IntegrationTests/src/bkr/inttest/server/test_beakerd.py b/IntegrationTests/src/bkr/inttest/server/test_beakerd.py
index cc1fccf..799ec6e 100644
--- a/IntegrationTests/src/bkr/inttest/server/test_beakerd.py
+++ b/IntegrationTests/src/bkr/inttest/server/test_beakerd.py
@@ -475,6 +475,31 @@ class TestBeakerd(DatabaseTestCase):
job = Job.query.get(job.id)
self.assertEqual(job.status, TaskStatus.processed)
+ def test_like_named_machine(self):
+
+ with session.begin():
+ user = data_setup.create_user()
+ system1 = data_setup.create_system(status=u'Automated',
+ fqdn='boston1.redhat.com',
+ lab_controller=self.lab_controller)
+ # Notice name change s/bos/boz/ in next system create
+ system2 = data_setup.create_system(status=u'Automated',
+ fqdn='bozton2.redhat.com',
+ lab_controller=self.lab_controller)
+ job = data_setup.create_job(owner=user)
+ job.recipesets[0].recipes[0]._host_requires = (
+ u'<hostRequires><hostname op="like" value="%bos%"/></hostRequires>')
+
+ beakerd.process_new_recipes()
+ beakerd.update_dirty_jobs()
+
+ with session.begin():
+ job = Job.query.get(job.id)
+ self.assertEqual(job.status, TaskStatus.processed)
+ self.assertEqual(len(job.recipesets[0].recipes[0].systems), 1)
+ system = job.recipesets[0].recipes[0].systems[0]
+ self.assertEqual(system.fqdn, u'boston1.redhat.com')
+
def test_reservations_are_created(self):
with session.begin():
user = data_setup.create_user()
@@ -561,7 +586,7 @@ class TestBeakerd(DatabaseTestCase):
def check_user_cannot_run_job_on_system(self, user, system):
"""
- Asserts that the given user is not allowed to run a job against the
+ Asserts that the given user is not allowed to run a job against the
given system, i.e. that it aborts due to no matching systems.
"""
with session.begin():
@@ -578,8 +603,8 @@ class TestBeakerd(DatabaseTestCase):
def check_user_can_run_job_on_system(self, user, system):
"""
- Asserts that the given user *is* allowed to run a job against the given
- system, i.e. that it does not abort due to no matching systems. Inverse
+ Asserts that the given user *is* allowed to run a job against the given
+ system, i.e. that it does not abort due to no matching systems. Inverse
of the method above.
"""
with session.begin():
@@ -831,7 +856,7 @@ class TestBeakerd(DatabaseTestCase):
finally:
if not os.path.exists(harness_dir):
os.mkdir(harness_dir)
-
+
def test_success_harness_repo(self):
with session.begin():
user = data_setup.create_user()
@@ -894,14 +919,14 @@ class TestBeakerd(DatabaseTestCase):
# https://bugzilla.redhat.com/show_bug.cgi?id=1157348
def test_harness_repo_not_required_contained_harness(self):
with session.begin():
- distro_tree = data_setup.create_distro_tree(osmajor=u'MyAwesomeNewLinux',
+ distro_tree = data_setup.create_distro_tree(osmajor=u'MyAwesomeNewLinux',
harness_dir=False)
recipe = data_setup.create_recipe(distro_tree=distro_tree)
recipe.ks_meta = "contained_harness no_default_harness_repo"
job = data_setup.create_job_for_recipes([recipe])
data_setup.mark_recipe_waiting(recipe)
- # The test is just checking that recipe.provision() can be called
- # without exploding and aborting the recipe due to missing harness repo
+ # The test is just checking that recipe.provision() can be called
+ # without exploding and aborting the recipe due to missing harness repo
# directory.
def test_single_processor_priority(self):
@@ -1178,7 +1203,7 @@ class TestBeakerd(DatabaseTestCase):
xmljob = lxml.etree.fromstring("""
<job retention_tag="scratch">
<whiteboard>
-
+
</whiteboard>
<recipeSet priority="Normal">
<recipe kernel_options="" kernel_options_post="" ks_meta="" role="RECIPE_MEMBERS" whiteboard="Normal">
@@ -1443,7 +1468,7 @@ class TestBeakerd(DatabaseTestCase):
result = RecipeTaskResult.query.filter(
RecipeTaskResult.recipe_task_id == recipetask_id).one()
self.assertEquals(result.log,
- 'Recipe ID %s does not match any systems' %
+ 'Recipe ID %s does not match any systems' %
job.recipesets[0].recipes[0].id)
#https://bugzilla.redhat.com/show_bug.cgi?id=851354
@@ -1524,7 +1549,7 @@ class TestBeakerd(DatabaseTestCase):
with session.begin():
recipe = data_setup.create_recipe(
task_list=[Task.by_name(u'/distribution/check-install')] * 2,
- reservesys=True,
+ reservesys=True,
reservesys_duration=3600,
)
job = data_setup.create_job_for_recipes([recipe])
@@ -1606,7 +1631,7 @@ class TestBeakerd(DatabaseTestCase):
# https://bugzilla.redhat.com/show_bug.cgi?id=1120052
def test_bz1120052(self):
- # Due to the complexities of the not enough systems logic, the
+ # Due to the complexities of the not enough systems logic, the
# triggering circumstances for this bug are quite intricate...
# LC has 3 systems: A, B, C
# RS has 4 recipes:
@@ -1614,7 +1639,7 @@ class TestBeakerd(DatabaseTestCase):
# R1 -> [B]
# R2 -> [A, B]
# R3 -> [A, B, C]
- # The recipe set is aborted because R2 will have no candidates (they
+ # The recipe set is aborted because R2 will have no candidates (they
# will be removed in favour of R0 and R1).
with session.begin():
lc = data_setup.create_labcontroller()
@@ -1933,9 +1958,9 @@ class TestProvisionVirtRecipes(DatabaseTestCase):
self.virt_manager = dynamic_virt.VirtManager(self.user)
self.recipe = data_setup.create_recipe()
data_setup.create_job_for_recipes([self.recipe], owner=self.user)
- # We want our test recipe to go to OpenStack, so make sure there
- # are no shared idle systems left behind by previous tests. If
- # there are, the scheduler will prefer to use those instead of
+ # We want our test recipe to go to OpenStack, so make sure there
+ # are no shared idle systems left behind by previous tests. If
+ # there are, the scheduler will prefer to use those instead of
# OpenStack.
System.query.filter(System.status == SystemStatus.automated)\
.update(dict(status=SystemStatus.removed), synchronize_session=False)
@@ -1958,9 +1983,20 @@ class TestProvisionVirtRecipes(DatabaseTestCase):
self._run_beakerd_once()
with session.begin():
recipe = Recipe.query.get(self.recipe.id)
+ self.assertIsNotNone(recipe,
+ "Failed to get recipe ID %s" % self.recipe.id)
+ self.assertIsNotNone(recipe.resource,
+ "Recipe ID %s does not have a resource" % self.recipe.id)
self.assertEquals(recipe.status, TaskStatus.installing)
- self.assertIsNotNone(recipe.resource.instance_created)
- instance = self.virt_manager.novaclient.servers.get(recipe.resource.instance_id)
+ self.assertIsNotNone(
+ recipe.resource.instance_created,
+ "Recipe ID %s resource does not have instance_created" % self.recipe.id)
+ instance = self.virt_manager.novaclient.servers.get(
+ recipe.resource.instance_id)
+ self.assertIsNotNone(
+ instance,
+ "Instance not found for recipe ID %s, resource instance ID %s"
+ % (self.recipe.id, recipe.resource.instance_id))
self.assertTrue(instance.status, u'ACTIVE')
# https://bugzilla.redhat.com/show_bug.cgi?id=1361936
@@ -1972,9 +2008,9 @@ class TestProvisionVirtRecipes(DatabaseTestCase):
self.assertIsNotNone(recipe.installation.rebooted)
self.assertIsNotNone(recipe.watchdog.kill_time)
assert_datetime_within(
- recipe.watchdog.kill_time,
- tolerance=datetime.timedelta(seconds=10),
- reference=datetime.datetime.utcnow() + datetime.timedelta(seconds=3000))
+ recipe.watchdog.kill_time,
+ tolerance=datetime.timedelta(seconds=10),
+ reference=datetime.datetime.utcnow() + datetime.timedelta(seconds=3000))
# https://bugzilla.redhat.com/show_bug.cgi?id=1397649
def test_cheapest_OpenStack_flavor_should_be_picked(self):
@@ -1986,23 +2022,37 @@ class TestProvisionVirtRecipes(DatabaseTestCase):
beakerd.update_dirty_jobs()
with session.begin():
recipe = Recipe.query.get(self.recipe.id)
- instance = self.virt_manager.novaclient.servers.get(recipe.resource.instance_id)
+ self.assertIsNotNone(recipe,
+ "Failed to get recipe ID %s" % self.recipe.id)
+ self.assertIsNotNone(recipe.resource,
+ "Recipe ID %s does not have a resource" % self.recipe.id)
+ instance = self.virt_manager.novaclient.servers.get(
+ recipe.resource.instance_id)
available_flavors = self.virt_manager.available_flavors()
- #remove the flavor that has no disk.
+ # remove the flavor that has no disk.
for flavor in available_flavors:
if flavor.disk == 0:
available_flavors.remove(flavor)
- cheapest_flavor = sorted(available_flavors, key=lambda flavor: flavor.ram)[0]
+ # cheapest flavor is smallest disk and smallest ram
+ smallest_disk_list = sorted(available_flavors, key=lambda flavor: flavor.disk)
+ cheapest_flavor = sorted(smallest_disk_list, key=lambda flavor: flavor.ram)[0]
instance_flavor = self.virt_manager.novaclient.flavors.get(instance.flavor['id'])
self.assertEquals(instance_flavor.ram, cheapest_flavor.ram)
self.assertEquals(instance_flavor.id, cheapest_flavor.id)
# https://bugzilla.redhat.com/show_bug.cgi?id=1396851
def test_floating_ip_is_assigned(self):
+ if not self.virt_manager.is_create_floating_ip:
+ raise SkipTest('create_floating_ip is False')
self._run_beakerd_once()
with session.begin():
recipe = Recipe.query.get(self.recipe.id)
- port = self.virt_manager._get_instance_port(str(recipe.resource.instance_id))
+ self.assertIsNotNone(recipe,
+ "Failed to get recipe ID %s" % self.recipe.id)
+ self.assertIsNotNone(recipe.resource,
+ "Recipe ID %s does not have a resource" % self.recipe.id)
+ resource_instance_id = str(recipe.resource.instance_id)
+ port = self.virt_manager._get_instance_port(resource_instance_id)
fips = self.virt_manager.neutronclient.list_floatingips(port_id=port['id'])
# the port of the instance should be associated with a floating ip
self.assertEquals(len(fips['floatingips']), 1)
@@ -2013,7 +2063,12 @@ class TestProvisionVirtRecipes(DatabaseTestCase):
self._run_beakerd_once()
with session.begin():
recipe = Recipe.query.get(self.recipe.id)
- instance = self.virt_manager.novaclient.servers.get(recipe.resource.instance_id)
+ self.assertIsNotNone(recipe,
+ "Failed to get recipe ID %s" % self.recipe.id)
+ self.assertIsNotNone(recipe.resource,
+ "Recipe ID %s does not have a resource" % self.recipe.id)
+ instance = self.virt_manager.novaclient.servers.get(
+ recipe.resource.instance_id)
self.assertTrue(instance.status, u'ACTIVE')
recipe.recipeset.job.cancel()
recipe.recipeset.job.update_status()
@@ -2024,36 +2079,37 @@ class TestProvisionVirtRecipes(DatabaseTestCase):
except Exception, e:
self.assertIn('Instance %s could not be found' % recipe.resource.instance_id,
e.message)
- # the network should be deleted
- try:
- self.virt_manager.neutronclient.show_network(recipe.resource.network_id)
- self.fail('should raise')
- except Exception, e:
- # neutronclient on RHEL7+ raise NetworkNotFoundClient for missing nets
- if hasattr(e, 'status_code'):
- self.assertEquals(e.status_code, 404)
- else:
- self.assertEquals(e.response.status_code, 404)
- # the subnet should be deleted
- try:
- self.virt_manager.neutronclient.show_subnet(recipe.resource.subnet_id)
- self.fail('should raise')
- except Exception, e:
- if hasattr(e, 'status_code'):
- self.assertEquals(e.status_code, 404)
- else:
- self.assertEquals(e.response.status_code, 404)
- # the router should be deleted
- try:
- self.virt_manager.neutronclient.show_router(recipe.resource.router_id)
- self.fail('should raise')
- except Exception, e:
- if hasattr(e, 'status_code'):
- self.assertEquals(e.status_code, 404)
- else:
- self.assertEquals(e.response.status_code, 404)
- # the floating ip should be deleted
- self.assertFalse(self.virt_manager.neutronclient.list_floatingips(
+ if self.virt_manager.is_create_floating_ip:
+ # the network should be deleted
+ try:
+ self.virt_manager.neutronclient.show_network(recipe.resource.network_id)
+ self.fail('should raise')
+ except Exception, e:
+ # neutronclient on RHEL7+ raise NetworkNotFoundClient for missing nets
+ if hasattr(e, 'status_code'):
+ self.assertEquals(e.status_code, 404)
+ else:
+ self.assertEquals(e.response.status_code, 404)
+ # the subnet should be deleted
+ try:
+ self.virt_manager.neutronclient.show_subnet(recipe.resource.subnet_id)
+ self.fail('should raise')
+ except Exception, e:
+ if hasattr(e, 'status_code'):
+ self.assertEquals(e.status_code, 404)
+ else:
+ self.assertEquals(e.response.status_code, 404)
+ # the router should be deleted
+ try:
+ self.virt_manager.neutronclient.show_router(recipe.resource.router_id)
+ self.fail('should raise')
+ except Exception, e:
+ if hasattr(e, 'status_code'):
+ self.assertEquals(e.status_code, 404)
+ else:
+ self.assertEquals(e.response.status_code, 404)
+ # the floating IP address should be deleted
+ self.assertFalse(self.virt_manager.neutronclient.list_floatingips(
floating_ip_address=recipe.resource.floating_ip)['floatingips'])
@patch('bkr.server.tools.beakerd.metrics')
@@ -2062,8 +2118,8 @@ class TestBeakerdMetrics(DatabaseTestCase):
def setUp(self):
session.begin()
try:
- # Other tests might have left behind systems and system commands
- # and running recipes, so we remove or cancel them all so they
+ # Other tests might have left behind systems and system commands
+ # and running recipes, so we remove or cancel them all so they
# don't pollute our metrics
manually_reserved = System.query.filter(System.open_reservation != None)
for system in manually_reserved:
diff --git a/IntegrationTests/src/bkr/inttest/server/test_kickstart.py b/IntegrationTests/src/bkr/inttest/server/test_kickstart.py
index 8ec18e0..a1925e1 100644
--- a/IntegrationTests/src/bkr/inttest/server/test_kickstart.py
+++ b/IntegrationTests/src/bkr/inttest/server/test_kickstart.py
@@ -1978,7 +1978,7 @@ END
self.assert_('# Check in with Beaker Server' in klines, k)
self.assert_('%post --log=/dev/console' in klines, k)
self.assert_('# Add Harness Repo' in klines, k)
- self.assert_('yum -y install beah rhts-test-env' in klines, k)
+ self.assert_('$package_command -y install beah rhts-test-env' in klines, k)
def test_custom_kickstart_rhel7(self):
recipe = self.provision_recipe('''
@@ -2039,7 +2039,7 @@ END
self.assert_('# Check in with Beaker Server' in klines, k)
self.assert_('%post --log=/dev/console' in klines, k)
self.assert_('# Add Harness Repo' in klines, k)
- self.assert_('yum -y install beah rhts-test-env' in klines, k)
+ self.assert_('$package_command -y install beah rhts-test-env' in klines, k)
def test_custom_kickstart_fedora_rawhide(self):
recipe = self.provision_recipe('''
@@ -2099,7 +2099,7 @@ END
self.assert_('# Check in with Beaker Server' in klines, k)
self.assert_('%post --log=/dev/console' in klines, k)
self.assert_('# Add Harness Repo' in klines, k)
- self.assert_('yum -y install restraint-rhts' in klines, k)
+ self.assert_('$package_command -y install restraint-rhts' in klines, k)
def test_custom_kickstart_fedora(self):
recipe = self.provision_recipe('''
@@ -2159,7 +2159,7 @@ END
self.assert_('# Check in with Beaker Server' in klines, k)
self.assert_('%post --log=/dev/console' in klines, k)
self.assert_('# Add Harness Repo' in klines, k)
- self.assert_('yum -y install beah rhts-test-env' in klines, k)
+ self.assert_('$package_command -y install beah rhts-test-env' in klines, k)
# https://bugzilla.redhat.com/show_bug.cgi?id=801676
@@ -3121,7 +3121,7 @@ done
self.assert_('export BEAKER_LAB_CONTROLLER=%s' % self.lab_controller.fqdn in k, k)
self.assert_('export BEAKER_RECIPE_ID=%s' % recipe.id in k, k)
self.assert_('export BEAKER_HUB_URL="%s"' % get_server_base() in k, k)
- self.assert_('yum -y install my-alternative-harness' in k, k)
+ self.assert_('$package_command -y install my-alternative-harness' in k, k)
# https://bugzilla.redhat.com/show_bug.cgi?id=1328153
def test_harness_is_installed_with_multilib_policy_best_on_ia64(self):
@@ -3142,7 +3142,7 @@ done
self.assertIn(
'cp -p /etc/yum.conf{,.orig}\n'
'echo multilib_policy=best >>/etc/yum.conf\n'
- 'yum -y install restraint-rhts\n'
+ '$package_command -y install restraint-rhts\n'
'mv /etc/yum.conf{.orig,}\n',
recipe.installation.rendered_kickstart.kickstart)
@@ -3695,7 +3695,7 @@ part /boot --recommended --asprimary --fstype ext4 --ondisk=vdb
</recipeSet>
</job>''')
ks = recipe.installation.rendered_kickstart.kickstart
- self.assertIn('yum -y install beah-0.6.48 ', ks)
+ self.assertIn('$package_command -y install beah-0.6.48 ', ks)
# https://bugzilla.redhat.com/show_bug.cgi?id=1065811
def test_disable_ipv6_beah(self):
diff --git a/LabController/aux/anamon b/LabController/aux/anamon
index 05a67ee..fa79c9d 100644
--- a/LabController/aux/anamon
+++ b/LabController/aux/anamon
@@ -62,6 +62,7 @@ class WatchedCommand(UploadCommand):
return
while True:
+ time.sleep(4.5)
self.output = proc.stdout.readline()
# If the process dies, let's stop
if not self.output and proc.poll() is not None:
diff --git a/LabController/aux/anamon3 b/LabController/aux/anamon3
index a365dcd..5ff6913 100644
--- a/LabController/aux/anamon3
+++ b/LabController/aux/anamon3
@@ -62,6 +62,7 @@ class WatchedCommand(UploadCommand):
return
while True:
+ time.sleep(4.5)
self.output = proc.stdout.readline()
# If the process dies, let's stop
if not self.output and proc.poll() is not None:
diff --git a/LabController/setup.py b/LabController/setup.py
index 1c147c3..fb1a505 100644
--- a/LabController/setup.py
+++ b/LabController/setup.py
@@ -49,7 +49,7 @@ else:
setup(
name='beaker-lab-controller',
- version='26.4',
+ version='26.5',
description='Daemons for controlling a Beaker lab',
author='Red Hat, Inc.',
author_email='beaker-devel@lists.fedorahosted.org',
diff --git a/Misc/generate_release_notes.py b/Misc/generate_release_notes.py
index bc845a8..fa430a5 100755
--- a/Misc/generate_release_notes.py
+++ b/Misc/generate_release_notes.py
@@ -21,6 +21,7 @@ and that you have obtained a Bugzilla session cookie by executing:
$ bugzilla login
"""
+
import re
from optparse import OptionParser
from sys import exit
@@ -29,23 +30,19 @@ from checkbugs import get_bugs
# Super lame. At least python-bugzilla (and probably the Bugzilla API) does
# not return the name of the bug assignee, just their email.
_email_to_name = {
- 'dcallagh@redhat.com': 'Dan Callaghan',
- 'mjia@redhat.com': 'Matt Jia',
- 'rjoost@redhat.com': u'RĂ³man Joost',
- 'bmcivor@redhat.com': 'Blake McIvor',
- 'jorris@redhat.com': 'Jon Orris',
- 'achatter@redhat.com': 'Anwesha Chatterjee',
- 'jmckenzi@redhat.com': 'Jacob McKenzie',
- 'mtyson@redhat.com': 'Matt Tyson',
+ 'mastyk@redhat.com': 'Martin Styk',
+ 'tklohna@redhat.com': 'Tomas Klohna',
+ 'cbouchar@redhat.com': 'Carol Bouchard',
}
+
def main():
parser = OptionParser('usage: %prog [options]',
- description='Generates basic release note entries')
+ description='Generates basic release note entries')
parser.add_option('-m', '--milestone', metavar='MILESTONE',
- help='Create release note entries for bugs marked against MILESTONE')
+ help='Create release note entries for bugs marked against MILESTONE')
parser.add_option('-f', '--release-note-file',
- help='This is the release note file where the entries will be made')
+ help='This is the release note file where the entries will be made')
options, _ = parser.parse_args()
if not options.milestone:
@@ -56,10 +53,9 @@ def main():
milestone = options.milestone
bugs = get_bugs(milestone=milestone)
if not bugs:
- print 'There are no bugs for milestone %s' % milestone
+ print('There are no bugs for milestone %s' % milestone)
return 0
release_file_path = options.release_note_file
- contents = None
with open(release_file_path, 'r') as release_file:
# Release notes are not so big, safe enough to read all at once.
contents = release_file.read()
@@ -77,14 +73,15 @@ def main():
issue_string = ''
for bug in bugs_for_entry:
issue_string += '* :issue:`%s`: %s\n (Contributed by %s)\n' % \
- (bug.id, bug.summary,
- _email_to_name.get(bug.assigned_to, bug.assigned_to))
+ (bug.id, bug.summary,
+ _email_to_name.get(bug.assigned_to, bug.assigned_to))
if issue_string:
header = '\n\nAutogenerated bug list for Beaker %s:\n' % milestone
- with open(release_file_path, 'a') as release_file:
+ with open(release_file_path, 'ab') as release_file:
release_file.write(header.encode('utf-8'))
- release_file.write(issue_string.encode('utf-8').rstrip() + '\n')
+ release_file.write(issue_string.encode('utf-8').rstrip() + b'\n')
return 0
+
if __name__ in ('main', '__main__'):
exit(main())
diff --git a/Server/assets/recipe.less b/Server/assets/recipe.less
index 81c1080..1734a2e 100644
--- a/Server/assets/recipe.less
+++ b/Server/assets/recipe.less
@@ -112,7 +112,6 @@
.task-logs, .task-result-logs {
flex-grow: 0;
flex-shrink: 0;
- flex-basis: @mainLogWidth + 5em;
}
.task-comments, .task-result-comments {
flex-grow: 0;
@@ -122,7 +121,7 @@
.recipe-task-status, .task-result-result {
flex-grow: 0;
flex-shrink: 0;
- flex-basis: 12em;
+ flex-basis: 7em;
}
}
.recipe-tasks {
@@ -140,7 +139,6 @@
.recipe-task-flex-box;
.task-metadata {
min-width: 0;
- white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.task-version, .task-role {
diff --git a/Server/bkr/server/controller_utilities.py b/Server/bkr/server/controller_utilities.py
index f629d78..d17edc8 100644
--- a/Server/bkr/server/controller_utilities.py
+++ b/Server/bkr/server/controller_utilities.py
@@ -174,6 +174,10 @@ class Utility:
return lambda x: getattr(x.numa, 'nodes', 0)
@classmethod
+ def system_notes_getter(cls):
+ return lambda x: ' ---- '.join([note.text for note in x.notes])
+
+ @classmethod
def system_added_getter(cls):
return lambda x: x.date_added
diff --git a/Server/bkr/server/dynamic_virt.py b/Server/bkr/server/dynamic_virt.py
index 2f2ca88..f3265a7 100644
--- a/Server/bkr/server/dynamic_virt.py
+++ b/Server/bkr/server/dynamic_virt.py
@@ -9,12 +9,16 @@ import logging
import time
import uuid
from turbogears import config
+
try:
- import keystoneclient.v3.client, keystoneclient.session, keystoneclient.auth.identity.v3, \
- keystoneclient.exceptions
+ import keystoneclient.v3.client
+ import keystoneclient.session
+ import keystoneclient.auth.identity.v3
+ import keystoneclient.exceptions
has_keystoneclient = True
except ImportError:
has_keystoneclient = False
+
try:
from novaclient import client as nova_client
has_novaclient = True
@@ -25,26 +29,35 @@ try:
has_neutronclient = True
except ImportError:
has_neutronclient = False
+
from bkr.server.model import ConfigItem, VirtResource, OpenStackRegion
log = logging.getLogger(__name__)
+
class VirtManager(object):
def __init__(self, user):
self.user = user
self.auth_url = config.get('openstack.identity_api_url')
+ self.beaker_os_user_domain_name = config.get('openstack.user_domain_name')
self.beaker_os_username = config.get('openstack.username')
self.beaker_os_password = config.get('openstack.password')
+
# For now we just support a single region, in future this could be expanded.
self.region = OpenStackRegion.query.first()
self._do_sanity_check()
self.lab_controller = self.region.lab_controller
keystone_session = self._create_keystone_session()
- self.keystoneclient = keystoneclient.v3.client.Client(session=keystone_session, interface='public')
+ self.keystoneclient = keystoneclient.v3.client.Client(
+ session=keystone_session, interface='public')
self.novaclient = nova_client.Client('2', session=keystone_session)
self.neutronclient = neutron_client.Client(session=keystone_session)
+ # Default behavior is to create floating IP address
+ self.is_create_floating_ip = bool(config.get(
+ 'openstack.create_floating_ip', True))
+
def _do_sanity_check(self):
if not self.auth_url:
raise RuntimeError('OpenStack Identity API URL '
@@ -71,12 +84,24 @@ class VirtManager(object):
raise RuntimeError('No Keystone trust created by %s' % self.user)
def _create_keystone_session(self):
- auth = keystoneclient.auth.identity.v3.Password(
- username=self.beaker_os_username,
- password=self.beaker_os_password,
- user_domain_id=u'default',
- auth_url=self.auth_url,
- trust_id=self.user.openstack_trust_id)
+ log.debug('_create_keystone_session user_domain_name: %s username: %s',
+ self.beaker_os_user_domain_name, self.beaker_os_username)
+
+ if self.beaker_os_user_domain_name:
+ auth = keystoneclient.auth.identity.v3.Password(
+ user_domain_name=self.beaker_os_user_domain_name,
+ username=self.beaker_os_username,
+ password=self.beaker_os_password,
+ auth_url=self.auth_url,
+ trust_id=self.user.openstack_trust_id)
+ else:
+ auth = keystoneclient.auth.identity.v3.Password(
+ user_domain_id=u'default',
+ username=self.beaker_os_username,
+ password=self.beaker_os_password,
+ auth_url=self.auth_url,
+ trust_id=self.user.openstack_trust_id)
+
session = keystoneclient.session.Session(auth=auth)
# ensure this session is valid by getting a token
try:
@@ -94,9 +119,20 @@ class VirtManager(object):
image_id = self.region.ipxe_image_id
if not image_id:
raise RuntimeError('iPXE image has not been uploaded')
+ if self.is_create_floating_ip:
+ vm = self._create_vm_with_floating_ip(name, flavor, image_id)
+ else:
+ vm = self._create_vm_with_fixed_network(name, flavor, image_id)
+ return vm
+
+ def _create_vm_with_floating_ip(self, name, flavor, image_id):
+ """
+ Creates a VM (Virtual Machine) with a custom network and a floating
+ IP address.
+ """
with VirtNetwork(self.neutronclient, name) as net:
- instance = self.novaclient.servers.create(name, image_id, flavor,
- nics=[{'net-id': net.network_id}])
+ instance = self.novaclient.servers.create(
+ name, image_id, flavor, nics=[{'net-id': net.network_id}])
log.info('Created %r', instance)
try:
self._wait_for_build(instance)
@@ -104,20 +140,70 @@ class VirtManager(object):
# would be nice if nova let us build an instance without starting it
instance.stop()
self._wait_for_stop(instance)
- return VirtResource(uuid.UUID(instance.id), uuid.UUID(net.network_id),
- uuid.UUID(net.subnet_id), uuid.UUID(net.router_id),
- net.floating_ip.get('floating_ip_address'),
- self.lab_controller)
+ return VirtResource(uuid.UUID(instance.id),
+ uuid.UUID(net.network_id),
+ uuid.UUID(net.subnet_id),
+ uuid.UUID(net.router_id),
+ net.floating_ip.get('floating_ip_address'),
+ self.lab_controller)
except:
exc_type, exc_value, exc_tb = sys.exc_info()
try:
instance.delete()
except Exception:
log.exception('Failed to clean up %r during create_vm, leaked!',
- instance)
- # suppress this exception so the original one is not masked
+ instance)
+ # suppress instance.delete exception so the original one is not masked
raise exc_type, exc_value, exc_tb
+ def get_vm_ipv4_address(self, instance, network_name):
+ """
+ Get the OpenStack instance's IPv4 address on the provided network.
+ """
+ provider_addresses = instance.addresses.get(network_name)
+ if not provider_addresses:
+ raise RuntimeError('Server %s does not have addresses in network %s' %
+ (instance.name, network_name))
+ ipv4_found = next((address for address in provider_addresses
+ if address.get('version') == 4), None)
+ if not ipv4_found:
+ raise RuntimeError('No IPv4 address record found for VM %s' %
+ instance.name)
+ return ipv4_found.get('addr')
+
+ def _create_vm_with_fixed_network(self, system_name, flavor, image_id):
+ """
+ Creates a VM (Virtual Machine) with a fixed IP address (that is,
+ doesn't assign a floating IP addres).
+ """
+ network = FixedNetwork(self.neutronclient)
+ instance = self.novaclient.servers.create(
+ system_name, image_id, flavor, nics=[{'net-id': network.network_id}])
+ log.info('Created %r', instance)
+ try:
+ self._wait_for_build(instance)
+ ipv4_address = self.get_vm_ipv4_address(instance,
+ network.name)
+ network.set_ip_address(ipv4_address)
+ # would be nice if nova let us build an instance without starting it
+ instance.stop()
+ self._wait_for_stop(instance)
+ return VirtResource(instance_id=uuid.UUID(instance.id),
+ network_id=uuid.UUID(network.network_id),
+ subnet_id=uuid.UUID(network.subnet_id),
+ router_id=uuid.UUID(network.router_id),
+ floating_ip=ipv4_address,
+ lab_controller=self.lab_controller)
+ except:
+ exc_type, exc_value, exc_tb = sys.exc_info()
+ try:
+ instance.delete()
+ except Exception: # pylint: disable=broad-except
+ log.exception('Failed to clean up %r during create_vm, leaked!',
+ instance)
+ # suppress instance.delete exception so the original one is not masked
+ raise exc_type, exc_value, exc_tb
+
def _wait_for_build(self, instance):
for __ in range(20):
time.sleep(5)
@@ -127,7 +213,7 @@ class VirtManager(object):
break
if instance.status != 'ACTIVE':
raise RuntimeError('%r failed to build, status %s'
- % (instance, instance.status))
+ % (instance, instance.status))
def _wait_for_stop(self, instance):
for __ in range(20):
@@ -138,21 +224,22 @@ class VirtManager(object):
break
if instance.status != 'SHUTOFF':
raise RuntimeError('%r failed to stop, status %s'
- % (instance, instance.status))
+ % (instance, instance.status))
def _wait_for_delete(self, instance):
is_deleted = False
- for __ in range(20):
- time.sleep(5)
- log.debug('%r still deleting', instance)
+ for attempt in range(5, 50, 5):
+ time.sleep(attempt)
try:
instance.get()
+ log.debug('%r still deleting, status %s',
+ instance, instance.status)
except:
is_deleted = True
break
if not is_deleted:
raise RuntimeError('%r failed to delete, status %s'
- % (instance, instance.status))
+ % (instance, instance.status))
def _get_instance_port(self, instance_id):
ports = self.neutronclient.list_ports(device_id=instance_id)['ports']
@@ -162,8 +249,8 @@ class VirtManager(object):
def _assign_floating_ip(self, floating_ip, instance):
port = self._get_instance_port(instance.id)
- self.neutronclient.update_floatingip(floating_ip, {'floatingip': {
- 'port_id': port['id']}})
+ self.neutronclient.update_floatingip(
+ floating_ip, {'floatingip': {'port_id': port['id']}})
log.info('Associated floating ip %r to %r', floating_ip, instance)
def start_vm(self, instance_id):
@@ -173,41 +260,87 @@ class VirtManager(object):
instance = self.novaclient.servers.get(vm.instance_id)
self.novaclient.servers.delete(instance.id)
self._wait_for_delete(instance)
- self.neutronclient.remove_interface_router(str(vm.router_id),
- {'subnet_id': str(vm.subnet_id)})
- self.neutronclient.delete_router(str(vm.router_id))
- self.neutronclient.delete_network(str(vm.network_id))
- fips = self.neutronclient.list_floatingips(floating_ip_address=vm.floating_ip)
- for fip in fips['floatingips']:
- self.neutronclient.delete_floatingip(fip['id'])
+ if self.is_create_floating_ip:
+ self.neutronclient.remove_interface_router(str(vm.router_id),
+ {'subnet_id': str(vm.subnet_id)})
+ self.neutronclient.delete_router(str(vm.router_id))
+ self.neutronclient.delete_network(str(vm.network_id))
+ fips = self.neutronclient.list_floatingips(
+ floating_ip_address=vm.floating_ip)
+ for fip in fips['floatingips']:
+ self.neutronclient.delete_floatingip(fip['id'])
def get_console_output(self, instance_id, length):
- return self.novaclient.servers.get_console_output(instance_id,
- length)
+ return self.novaclient.servers.get_console_output(instance_id, length)
def delete_keystone_trust(self):
self.keystoneclient.trusts.delete(self.user.openstack_trust_id)
-def create_keystone_trust(username, password, project_name):
+
+def create_keystone_trust(trustor_username,
+ trustor_password,
+ trustor_project_name,
+ trustor_user_domain_name,
+ trustor_project_domain_name):
auth_url = config.get('openstack.identity_api_url')
- trustee_auth = keystoneclient.auth.identity.v3.Password(
- username=config.get('openstack.username'),
+
+ openstack_user_domain_name = config.get('openstack.user_domain_name',
+ trustor_user_domain_name)
+ openstack_user_name = config.get('openstack.username')
+ if openstack_user_domain_name:
+ trustee_auth = keystoneclient.auth.identity.v3.Password(
+ username=openstack_user_name,
+ password=config.get('openstack.password'),
+ user_domain_name=openstack_user_domain_name,
+ auth_url=auth_url)
+ else:
+ trustee_auth = keystoneclient.auth.identity.v3.Password(
+ username=openstack_user_name,
password=config.get('openstack.password'),
user_domain_id=u'default',
auth_url=auth_url)
+
trustee_session = keystoneclient.session.Session(auth=trustee_auth)
- trustee = keystoneclient.v3.client.Client(session=trustee_session, interface='public')
- trustee_auth_ref = trustee_auth.get_access(trustee_session)
+ trustee = keystoneclient.v3.client.Client(session=trustee_session,
+ interface='public')
try:
- trustor_auth = keystoneclient.auth.identity.v3.Password(
- username=username,
- password=password,
- project_name=project_name,
- user_domain_id=u'default',
- project_domain_id=u'default',
- auth_url=auth_url)
+ trustee_auth_ref = trustee_auth.get_access(trustee_session)
+ if trustor_user_domain_name and trustor_project_domain_name:
+ trustor_auth = keystoneclient.auth.identity.v3.Password(
+ username=trustor_username,
+ password=trustor_password,
+ project_name=trustor_project_name,
+ user_domain_name=trustor_user_domain_name,
+ project_domain_name=trustor_project_domain_name,
+ auth_url=auth_url)
+ elif trustor_user_domain_name and not trustor_project_domain_name:
+ trustor_auth = keystoneclient.auth.identity.v3.Password(
+ username=trustor_username,
+ password=trustor_password,
+ project_name=trustor_project_name,
+ user_domain_name=trustor_user_domain_name,
+ project_domain_id=u'default',
+ auth_url=auth_url)
+ elif not trustor_user_domain_name and trustor_project_domain_name:
+ trustor_auth = keystoneclient.auth.identity.v3.Password(
+ username=trustor_username,
+ password=trustor_password,
+ project_name=trustor_project_name,
+ user_domain_id=u'default',
+ project_domain_name=trustor_project_domain_name,
+ auth_url=auth_url)
+ else:
+ trustor_auth = keystoneclient.auth.identity.v3.Password(
+ username=trustor_username,
+ password=trustor_password,
+ project_name=trustor_project_name,
+ user_domain_id=u'default',
+ project_domain_id=u'default',
+ auth_url=auth_url)
+
trustor_session = keystoneclient.session.Session(auth=trustor_auth)
- trustor = keystoneclient.v3.client.Client(session=trustor_session, interface='public')
+ trustor = keystoneclient.v3.client.Client(session=trustor_session,
+ interface='public')
trustor_auth_ref = trustor_auth.get_access(trustor_session)
if keystoneclient.__version__.startswith('0.11.'):
# RHEL6 keystoneclient incorrectly uses the admin URL for all
@@ -215,10 +348,12 @@ def create_keystone_trust(username, password, project_name):
# So we have to make a raw HTTP request.
body = dict(trust=dict(trustor_user_id=trustor_auth_ref.user_id,
trustee_user_id=trustee_auth_ref.user_id,
- roles=[dict(name=name) for name in trustor_auth_ref.role_names],
+ roles=[dict(name=name) for name in
+ trustor_auth_ref.role_names],
impersonation=True,
project_id=trustor_auth_ref.project_id))
- resp, data = trustor.post('/OS-TRUST/trusts', body=body, management=False)
+ resp, data = trustor.post('/OS-TRUST/trusts', body=body,
+ management=False)
return data['trust']['id']
else:
trust = trustor.trusts.create(trustor_user=trustor_auth_ref.user_id,
@@ -230,9 +365,73 @@ def create_keystone_trust(username, password, project_name):
except keystoneclient.exceptions.Unauthorized as exc:
raise ValueError(exc.message)
+
+class FixedNetwork(object): # pylint: disable=too-few-public-methods
+ """
+ This is a class which defines a VM's network (neutron) when the
+ VM uses a predefined OpenStack virtual network.
+ """
+ def __init__(self, neutronclient):
+ external_network = self._get_external_network(neutronclient)
+ self.name = external_network.get('name')
+ self.network_id = external_network.get('id')
+ self.subnet_id = self.get_subnet_id(neutronclient, self.network_id)
+ self.floating_ip = None
+ # Router ID must be a valid UUID because of the scheduler
+ # validation code. This value represents a 'nil' UUID.
+ self.router_id = '00000000-0000-0000-0000-000000000000'
+
+ def _get_external_network(self, neutronclient):
+ """
+ Returns an external network name for the OpenStack instance.
+ This will be either a name specified in the config file
+ (openstack.external_network_name) or, if the config file doesn't
+ specify a network, the first network available that is external.
+ """
+ network_name = config.get('openstack.external_network_name')
+ networks = neutronclient.list_networks().get('networks')
+ if network_name:
+ external_network = next((network for network in networks
+ if network.get('name') == network_name),
+ None)
+ if not external_network:
+ raise RuntimeError('Network %s was not found' % network_name)
+ if not external_network.get('router:external'):
+ raise RuntimeError('Network %s is not an external network' %
+ network_name)
+ else:
+ external_network = next((network for network in networks
+ if network.get('router:external')), None)
+ if not external_network:
+ raise RuntimeError('No external network is available')
+ return external_network
+
+ def get_subnet_id(self, neutronclient, network_id):
+ """
+ Given a network ID, returns a subnet ID for the network.
+ """
+ all_subnets = neutronclient.list_subnets().get('subnets')
+ network_subnet = next((subnet for subnet in all_subnets
+ if subnet.get('network_id') == network_id),
+ None)
+ if not network_subnet:
+ raise RuntimeError('Subnet not found for network %s' % network_id)
+ return network_subnet.get('id')
+
+ def set_ip_address(self, ip_address):
+ self.floating_ip = ip_address
+
+ def __repr__(self):
+ return '%s(name=%r, network_id=%r, subnet_id=%r)' \
+ % (self.__class__.__name__,
+ self.name, self.network_id, self.subnet_id)
+
+
class VirtNetwork(object):
"""
- This is a context manager which sets up an OpenStack network(neutron).
+ This is a context manager which sets up an OpenStack virtual network
+ (neutron). That is, it creates a virtual network and assigns a floating
+ IP address to the VM on that network.
"""
def __init__(self, client, name):
self.neutron = client
@@ -244,63 +443,84 @@ class VirtNetwork(object):
self.floating_ip = None
def __repr__(self):
- return '%s(name=%r, network_id=%r, router_id=%r, subnet_id=%r, \
- interface_id=%r)' % (self.__class__.__name__, self.name,
- self.network_id, self.router_id, self.subnet_id, self.interface_id)
+ return '%s(name=%r, network_id=%r, router_id=%r, subnet_id=%r, interface_id=%r)' \
+ % (self.__class__.__name__, self.name, self.network_id,
+ self.router_id, self.subnet_id, self.interface_id)
def _create_router(self, external_network_id):
- external_gateway_info = {'external_gateway_info': {
- 'network_id': external_network_id},
- 'name': self.name,
- 'admin_state_up': True}
+ external_gateway_info = {
+ 'external_gateway_info': {'network_id': external_network_id},
+ 'name': self.name,
+ 'admin_state_up': True}
router = self.neutron.create_router({'router': external_gateway_info})
- log.info('Created router %r',router)
+ log.info('Created router %r', router)
return router['router']['id']
def _create_network(self):
- network = self.neutron.create_network({'network': {'name': self.name}})
+ network = self.neutron.create_network({'network': {'name': self.name}})
log.info('Created network %r', network)
return network['network']['id']
def _create_subnet(self, network_id):
- cidr = ConfigItem.by_name(u'guest_private_network').\
- current_value('192.168.10.0/24')
+ cidr = ConfigItem.by_name(
+ u'guest_private_network').current_value('192.168.10.0/24')
subnet_info = {'name': self.name, 'network_id': network_id, 'cidr': cidr,
- 'ip_version': 4}
+ 'ip_version': 4}
subnet = self.neutron.create_subnet({'subnet': subnet_info})
log.info('Created subnet %r', subnet)
return subnet['subnet']['id']
def _create_floating_ip(self, network_id):
- fip = self.neutron.create_floatingip({'floatingip': {
- 'floating_network_id': network_id}})
+ fip = self.neutron.create_floatingip(
+ {'floatingip': {'floating_network_id': network_id}})
log.info('Created floating ip %r', fip)
return fip['floatingip']
def _add_interface_to_router(self, router_id, subnet_id):
- interface = self.neutron.add_interface_router(router_id, {
- 'subnet_id': subnet_id
- })
+ interface = self.neutron.add_interface_router(router_id,
+ {'subnet_id': subnet_id})
log.info('Added interface %r', interface)
return interface['id']
- def _configure_network(self):
+ def _get_external_network(self):
+ """
+ Returns an external network name for the OpenStack instance.
+ This will be either a name specified in the config file
+ (openstack.external_network_name) or, if the config file doesn't
+ specify a network, the first network available that is external.
+ """
+ network_name = config.get('openstack.external_network_name')
networks = self.neutron.list_networks().get('networks')
- external_network = next((network for network in networks
- if network.get('router:external')), None)
- if not external_network:
- raise RuntimeError('No external network is available')
+ if network_name:
+ external_network = next((network for network in networks
+ if network.get('name') == network_name),
+ None)
+ if not external_network:
+ raise RuntimeError('Network %s was not found' % network_name)
+ if not external_network.get('router:external'):
+ raise RuntimeError('Network %s is not an external network' %
+ network_name)
+ else:
+ external_network = next((network for network in networks
+ if network.get('router:external')), None)
+ if not external_network:
+ raise RuntimeError('No external network is available')
+ return external_network
+
+ def _configure_network(self):
+ external_network = self._get_external_network()
self.router_id = self._create_router(external_network.get('id'))
self.network_id = self._create_network()
self.subnet_id = self._create_subnet(self.network_id)
self.interface_id = self._add_interface_to_router(self.router_id,
- self.subnet_id)
+ self.subnet_id)
self.floating_ip = self._create_floating_ip(external_network.get('id'))
def _cleanup(self):
try:
if self.interface_id:
- self.neutron.remove_interface_router(self.router_id, {'subnet_id': self.subnet_id})
+ self.neutron.remove_interface_router(
+ self.router_id, {'subnet_id': self.subnet_id})
if self.router_id:
self.neutron.delete_router(self.router_id)
if self.network_id:
diff --git a/Server/bkr/server/job_matrix.py b/Server/bkr/server/job_matrix.py
index 0fa9fc0..9068314 100644
--- a/Server/bkr/server/job_matrix.py
+++ b/Server/bkr/server/job_matrix.py
@@ -57,7 +57,7 @@ class JobMatrix:
if ('job_ids' in kw or 'whiteboard' in kw):
job_ids = []
if 'job_ids' in kw:
- job_ids = [int(j) for j in kw['job_ids'].split()]
+ job_ids = [int(j) if j.isdigit() else None for j in kw['job_ids'].split()]
# Filter out ids of deleted jobs
query = model.Job.query.filter(not_(model.Job.is_deleted)).filter(model.Job.id.in_(job_ids))
job_ids = [job_id for job_id, in query.values(model.Job.id)]
diff --git a/Server/bkr/server/jobs.py b/Server/bkr/server/jobs.py
index 9edd078..3d66320 100644
--- a/Server/bkr/server/jobs.py
+++ b/Server/bkr/server/jobs.py
@@ -212,6 +212,10 @@ class Jobs(RPCRoot):
Job owner username
'mine'
Inclusion is equivalent to including own username in 'owner'
+ 'group'
+ Job group name
+ 'my-group'
+ Jobs for any of the given user's groups.
'whiteboard'
Job whiteboard (substring match)
'limit'
@@ -242,23 +246,34 @@ class Jobs(RPCRoot):
family = filters.get('family', None)
product = filters.get('product', None)
owner = filters.get('owner', None)
+ group = filters.pop('group', None)
+ my_groups = filters.pop('my_groups', None)
whiteboard = filters.get('whiteboard', None)
mine = filters.get('mine', None)
limit = filters.get('limit', None)
is_finished = filters.get('is_finished', None)
- if mine and not identity.not_anonymous():
- raise BX(_('You should be authenticated to use the --mine filter.'))
+ # identity.not_anonymous() wrongly returns True for anonymous XML-RPC
+ if (mine or my_groups) and not identity.current.user:
+ raise BX(_('You need to be authenticated to use the --mine or --my_groups filter.'))
- if mine and identity.not_anonymous():
+ if mine:
if owner:
- if type(owner) is list:
+ if isinstance(owner, list):
owner.append(identity.current.user.user_name)
else:
owner = [owner, identity.current.user.user_name]
else:
owner = identity.current.user.user_name
+ if my_groups:
+ if group:
+ if isinstance(group, basestring):
+ group = [group]
+ group.extend([g.group_name for g in identity.current.user.groups])
+ else:
+ group = [g.group_name for g in identity.current.user.groups]
+
jobs = jobs.order_by(Job.id.desc())
if tags:
jobs = Job.by_tag(tags, jobs)
@@ -270,6 +285,11 @@ class Jobs(RPCRoot):
jobs = Job.by_product(product, jobs)
if owner:
jobs = Job.by_owner(owner, jobs)
+ if group:
+ try:
+ jobs = Job.by_groups(group, jobs)
+ except NoResultFound:
+ raise BX(_('No such group %r' % group))
if whiteboard:
jobs = jobs.filter(Job.whiteboard.like(u'%%%s%%' % whiteboard))
# is_finished is a tri-state value, True limit finished job, False limit unfinished job, None don't limit
diff --git a/Server/bkr/server/model/identity.py b/Server/bkr/server/model/identity.py
index 5ae0672..f11dcd2 100644
--- a/Server/bkr/server/model/identity.py
+++ b/Server/bkr/server/model/identity.py
@@ -557,8 +557,7 @@ class Group(DeclarativeMappedObject, ActivityMixin):
@classmethod
def by_name(cls, name, lockmode=False):
if lockmode:
- return cls.query.with_lockmode(lockmode).filter(cls.group_name ==
- name).one()
+ return cls.query.with_lockmode(lockmode).filter(cls.group_name == name).one()
else:
return cls.query.filter_by(group_name=name).one()
diff --git a/Server/bkr/server/model/inventory.py b/Server/bkr/server/model/inventory.py
index 30fb0df..4ca4aa6 100644
--- a/Server/bkr/server/model/inventory.py
+++ b/Server/bkr/server/model/inventory.py
@@ -2723,7 +2723,8 @@ class Key(DeclarativeMappedObject):
# from searching on these keys in the web UI, to encourage them to migrate
# to the structured columns instead (and to avoid the costly queries that
# sometimes result).
- obsoleted_keys = [u'MODULE', u'PCIID']
+ # * PCIID replaced by Device/Vendor_id
+ obsoleted_keys = [u'PCIID']
@classmethod
def get_all_keys(cls):
diff --git a/Server/bkr/server/model/scheduler.py b/Server/bkr/server/model/scheduler.py
index 6531294..8b4f76b 100644
--- a/Server/bkr/server/model/scheduler.py
+++ b/Server/bkr/server/model/scheduler.py
@@ -830,10 +830,9 @@ class Job(TaskBase, ActivityMixin):
def by_tag(cls, tag, query=None):
if query is None:
query = cls.query
- if type(tag) is list:
- tag_query = cls.retention_tag_id.in_([RetentionTag.by_tag(unicode(t)).id for t in tag])
- else:
- tag_query = cls.retention_tag==RetentionTag.by_tag(unicode(tag))
+ if isinstance(tag, basestring):
+ tag = [tag]
+ tag_query = cls.retention_tag_id.in_([RetentionTag.by_tag(unicode(t)).id for t in tag])
return query.filter(tag_query)
@@ -841,23 +840,36 @@ class Job(TaskBase, ActivityMixin):
def by_product(cls, product, query=None):
if query is None:
query=cls.query
- if type(product) is list:
- product_query = cls.product.in_(*[Product.by_name(p) for p in product])
- else:
- product_query = cls.product == Product.by_name(product)
+ if isinstance(product, basestring):
+ product = [product]
+ product_query = cls.product_id.in_([Product.by_name(p).id for p in product])
+
return query.join('product').filter(product_query)
@classmethod
def by_owner(cls, owner, query=None):
if query is None:
query=cls.query
- if type(owner) is list:
- owner_query = cls.owner.in_(*[User.by_user_name(p) for p in owner])
- else:
- owner_query = cls.owner == User.by_user_name(owner)
+ if isinstance(owner, basestring):
+ owner = [owner]
+ # by_user_name() returns None for non-existent users
+ for o in owner:
+ if User.by_user_name(o) is None:
+ raise NoResultFound('Owner %s is invalid' % o)
+ owner_query = cls.owner_id.in_([User.by_user_name(o).id for o in owner])
+
return query.join('owner').filter(owner_query)
@classmethod
+ def by_groups(cls, groups, query=None):
+ if query is None:
+ query=cls.query
+ if isinstance(groups, basestring):
+ groups = [groups]
+ groups_query = cls.group_id.in_([Group.by_name(g).id for g in groups])
+ return query.join('group').filter(groups_query)
+
+ @classmethod
def by_whiteboard(cls, desc, like=False):
if type(desc) is list and len(desc) <= 1:
desc = desc.pop()
diff --git a/Server/bkr/server/reserve_workflow.py b/Server/bkr/server/reserve_workflow.py
index 32c9f9b..2d5c808 100644
--- a/Server/bkr/server/reserve_workflow.py
+++ b/Server/bkr/server/reserve_workflow.py
@@ -35,15 +35,18 @@ def doit():
raise BadRequest400('Distro tree %r does not exist' % id)
job_details = {}
job_details['pick'] = request.form.get('pick') or 'auto'
+ system_choice = 'any system'
if job_details['pick'] == 'fqdn':
try:
job_details['system'] = System.by_fqdn(request.form.get('system'),
identity.current.user)
+ system_choice = 'a specific system'
except DatabaseLookupError:
raise BadRequest400('System %s not found' % request.form.get('system'))
elif job_details['pick'] == 'lab':
try:
job_details['lab'] = LabController.by_name(request.form.get('lab'))
+ system_choice = 'any lab system'
except NoResultFound:
raise BadRequest400('Lab controller %s not found' % request.form.get('lab'))
reservetime = int(request.form.get('reserve_duration') or DEFAULT_RESERVE_SECONDS)
@@ -51,6 +54,12 @@ def doit():
raise BadRequest400('Reservation time exceeds maximum time of %s hours' % MAX_HOURS_PROVISION)
job_details['reservetime'] = reservetime
job_details['whiteboard'] = request.form.get('whiteboard')
+ if not job_details['whiteboard']:
+ job_details['whiteboard'] = (
+ "Reserve Workflow provision of distro %s on %s for %d seconds" %
+ (request.form.get('distro'), system_choice,
+ job_details['reservetime']))
+
job_details['ks_meta'] = request.form.get('ks_meta')
job_details['koptions'] = request.form.get('koptions')
job_details['koptions_post'] = request.form.get('koptions_post')
diff --git a/Server/bkr/server/search_utility.py b/Server/bkr/server/search_utility.py
index a889bce..2533298 100644
--- a/Server/bkr/server/search_utility.py
+++ b/Server/bkr/server/search_utility.py
@@ -794,7 +794,7 @@ class SystemSearch(Search):
def get_column_descriptions(self):
return self.system_columns_desc
- def append_results(self,cls_ref,value,column,operation,**kw):
+ def append_results(self,cls_ref,value,column,operation,**kw):
"""
append_results() will take a value, column and operation from the search field,
as well as the class of which the search pertains to, and will append the join
@@ -1094,6 +1094,9 @@ class System(SystemObject):
'Memory' : MyColumn(column=model.System.memory,col_type='numeric'),
'Hypervisor': MyColumn(column=model.Hypervisor.hypervisor, col_type='string', relations='hypervisor'),
'NumaNodes' : MyColumn(column=model.Numa.nodes, col_type='numeric', relations='numa'),
+ 'Notes' : AliasedColumn(column_name='text',
+ col_type='string', relations=[model.Note],
+ onclause=model.System.notes),
'User' : AliasedColumn(column_name='user_name',
relations=[model.User],
col_type='string',
@@ -1186,6 +1189,17 @@ class System(SystemObject):
ids = [r.id for r in query]
return not_(model.System.id.in_(ids))
+ @classmethod
+ def notes_contains_filter(cls, col, val, **kw):
+ """
+ notes_contains_filter is a function dynamically called from append_results.
+ It serves to provide a table column operation specific method of filtering results of System/Notes
+
+ In this case it specifically searches case-insensitively through System/Notes
+ """
+ query = model.System.query.filter(model.System.notes.any(model.Note.text.ilike(val)))
+ return model.System.id.in_([x.id for x in query])
+
class Recipe(SystemObject):
search = RecipeSearch
searchable_columns = {
diff --git a/Server/bkr/server/snippets/beah b/Server/bkr/server/snippets/beah
index 04ba07f..97e5496 100644
--- a/Server/bkr/server/snippets/beah
+++ b/Server/bkr/server/snippets/beah
@@ -1,7 +1,12 @@
-yum{{ ' ' + yum_install_extra_opts if yum_install_extra_opts is defined else '' }} -y install {{ beah_rpm|default('beah') }} rhts-test-env
-yum{{ ' ' + yum_install_extra_opts if yum_install_extra_opts is defined else '' }} -y install beakerlib
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
+$package_command{{ ' ' + yum_install_extra_opts if yum_install_extra_opts is defined else '' }} -y install {{ beah_rpm|default('beah') }} rhts-test-env
+$package_command{{ ' ' + yum_install_extra_opts if yum_install_extra_opts is defined else '' }} -y install beakerlib
# This may fail if you are outside of Red Hat..
-yum{{ ' ' + yum_install_extra_opts if yum_install_extra_opts is defined else '' }} -y install beakerlib-redhat
+$package_command{{ ' ' + yum_install_extra_opts if yum_install_extra_opts is defined else '' }} -y install beakerlib-redhat
cp /etc/beah_beaker.conf{,.default}
cat << EOF > /etc/beah_beaker.conf
diff --git a/Server/bkr/server/snippets/docker_harness b/Server/bkr/server/snippets/docker_harness
index 7a26041..cd1ec4b 100644
--- a/Server/bkr/server/snippets/docker_harness
+++ b/Server/bkr/server/snippets/docker_harness
@@ -38,13 +38,19 @@ cat << EOF > /root/Dockerfile
{% set harness_docker_base_image=docker_registry + "/" + docker_image + ":" + docker_tag %}
{% endif %}
+if command -v dnf >/dev/null ; then
+ export package_command="dnf"
+else
+ export package_command="yum"
+fi
+
FROM {{ harness_docker_base_image }}
MAINTAINER Beaker Developers <beaker-devel@lists.fedoraproject.org>
ENV container docker
ADD beaker-tasks.repo /etc/yum.repos.d/
ADD customrepos/ /etc/yum.repos.d/
ADD beaker-harness-env.sh /etc/profile.d/beaker-harness-env.sh
-RUN yum -y update; yum clean all
+RUN $package_command -y update; $package_command clean all
{% if contained_harness_entrypoint is not defined %}
# We assume that if the contained harness entrypoint is not
@@ -52,8 +58,8 @@ RUN yum -y update; yum clean all
# for us
# Reference: http://developerblog.redhat.com/2014/05/05/running-systemd-within-docker-container/
{# In case we have fakesystemd installed, remove it #}
-RUN yum -y remove fakesystemd || true
-RUN yum -y install systemd; \
+RUN $package_command -y remove fakesystemd || true
+RUN $package_command -y install systemd; \
(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ "\$i" == systemd-tmpfiles-setup.service ] || rm -f "\$i"; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
@@ -66,10 +72,10 @@ VOLUME [ "/sys/fs/cgroup" ]
{% endif %}
# Install the harness
-RUN yum -y install {{ harness|default('restraint restraint-rhts') }}
-RUN yum -y install coreutils
-RUN yum -y install beakerlib || true
-RUN yum -y install beakerlib-redhat || true
+RUN $package_command -y install {{ harness|default('restraint restraint-rhts') }}
+RUN $package_command -y install coreutils
+RUN $package_command -y install beakerlib || true
+RUN $package_command -y install beakerlib-redhat || true
CMD {{ contained_harness_entrypoint|default('["/usr/sbin/init"]') }}
EOF
diff --git a/Server/bkr/server/snippets/harness b/Server/bkr/server/snippets/harness
index f5ca366..28a1fc2 100644
--- a/Server/bkr/server/snippets/harness
+++ b/Server/bkr/server/snippets/harness
@@ -11,6 +11,11 @@ setenv BEAKER_RECIPE_ID {{ recipe.id }}
setenv BEAKER_HUB_URL "{{ absolute_url('/', labdomain=True) }}"
EOF
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
{% if distro_tree is arch('ia64') %}
# We want to avoid installing i386/i686 harness packages on ia64, because ia64
# "multilib" support is kind of crazy and broken. See RHBZ#1328153 for details.
@@ -19,8 +24,8 @@ EOF
# the environment clean. (multilib_policy=best is the default in RHEL6+.)
cp -p /etc/yum.conf{,.orig}
echo multilib_policy=best >>/etc/yum.conf
-yum{{ ' ' + yum_install_extra_opts if yum_install_extra_opts is defined else '' }} -y install {{ harness }}
+$package_command{{ ' ' + yum_install_extra_opts if yum_install_extra_opts is defined else '' }} -y install {{ harness }}
mv /etc/yum.conf{.orig,}
{% else %}
-yum{{ ' ' + yum_install_extra_opts if yum_install_extra_opts is defined else '' }} -y install {{ harness }}
+$package_command{{ ' ' + yum_install_extra_opts if yum_install_extra_opts is defined else '' }} -y install {{ harness }}
{% endif %}
diff --git a/Server/bkr/server/snippets/rhts_post b/Server/bkr/server/snippets/rhts_post
index 25dbc9d..b5c2714 100644
--- a/Server/bkr/server/snippets/rhts_post
+++ b/Server/bkr/server/snippets/rhts_post
@@ -118,10 +118,15 @@ EOF
{% if contained_harness is defined or has_rpmostree is defined%}
{% snippet 'docker_harness' %}
{% else %}
+if command -v dnf >/dev/null ; then
+ package_command="dnf"
+else
+ package_command="yum"
+fi
# fill the yum cache and redirect output to /dev/null
# This speeds up yum because of a bug where it will update stdout too often.
# http://lists.baseurl.org/pipermail/yum-devel/2011-December/008857.html
-yum check-update > /dev/null 2>&1 || true
+$package_command check-update > /dev/null 2>&1 || true
{% if harness == 'beah' %}
{% snippet 'beah' %}
{% else %}
diff --git a/Server/bkr/server/tests/data_setup.py b/Server/bkr/server/tests/data_setup.py
index 9f54938..0cfb331 100644
--- a/Server/bkr/server/tests/data_setup.py
+++ b/Server/bkr/server/tests/data_setup.py
@@ -63,7 +63,7 @@ def setup_model(override=True):
_counter = itertools.count()
def unique_name(pattern):
"""
- Pass a %-format pattern, such as 'user%s', to generate a name that is
+ Pass a %-format pattern, such as 'user%s', to generate a name that is
unique within this test run.
"""
# time.time() * 1000 is no good, KVM guest wall clock is too dodgy
@@ -85,7 +85,7 @@ def create_labcontroller(fqdn=None, user=None):
if fqdn is None:
fqdn = unique_name(u'lab%s.testdata.invalid')
try:
- lc = LabController.by_name(fqdn)
+ lc = LabController.by_name(fqdn)
except NoResultFound:
if user is None:
user = User(user_name=u'host/%s' % fqdn,
@@ -95,8 +95,8 @@ def create_labcontroller(fqdn=None, user=None):
session.add(lc)
group = Group.by_name(u'lab_controller')
group.add_member(user, service=u'testdata')
- # Need to ensure it is inserted now, since we aren't using lazy_create
- # here so a subsequent call to create_labcontroller could try and
+ # Need to ensure it is inserted now, since we aren't using lazy_create
+ # here so a subsequent call to create_labcontroller could try and
# create the same LC again.
session.flush()
return lc
@@ -132,7 +132,7 @@ def create_admin(user_name=None, **kwargs):
group.add_member(user, service=u'testdata')
return user
-def add_system_lab_controller(system,lc):
+def add_system_lab_controller(system,lc):
system.lab_controller = lc
def create_group(permissions=None, group_name=None, display_name=None,
@@ -304,11 +304,11 @@ def create_system(arch=u'i386', type=SystemType.machine, status=None,
lab_controller=lab_controller, **kw)
session.add(system)
- # Normally the system would be "idle" when first added, and then becomes
- # "pending" when a user flips it to Automated status. But for simplicity in
- # the tests, we will just force it back to "idle" here since we know we
- # just created it. This lets a subsequent call to the scheduler pick it up
- # immediately, without going through an iteration of
+ # Normally the system would be "idle" when first added, and then becomes
+ # "pending" when a user flips it to Automated status. But for simplicity in
+ # the tests, we will just force it back to "idle" here since we know we
+ # just created it. This lets a subsequent call to the scheduler pick it up
+ # immediately, without going through an iteration of
# schedule_pending_systems() first.
system.scheduler_status = SystemSchedulerStatus.idle
@@ -398,7 +398,7 @@ def create_system_status_history(system, statuses):
def create_task(name=None, exclude_arches=None, exclusive_arches=None,
exclude_osmajors=None, exclusive_osmajors=None, version=u'1.0-1',
- uploader=None, owner=None, priority=u'Manual', valid=None, path=None,
+ uploader=None, owner=None, priority=u'Manual', valid=None, path=None,
description=None, requires=None, runfor=None, type=None, avg_time=1200):
if name is None:
name = unique_name(u'/distribution/test_task_%s')
@@ -648,8 +648,8 @@ def mark_recipe_tasks_finished(recipe, result=TaskResult.pass_,
mark_recipe_running(recipe, start_time=start_time,
task_start_time=start_time, **kwargs)
- # Need to make sure recipe.watchdog has been persisted, since we delete it
- # below when the recipe completes and sqlalchemy will barf on deleting an
+ # Need to make sure recipe.watchdog has been persisted, since we delete it
+ # below when the recipe completes and sqlalchemy will barf on deleting an
# instance that hasn't been persisted.
session.flush()
@@ -758,10 +758,10 @@ def mark_recipe_waiting(recipe, start_time=None, only=False, **kwargs):
with mock.patch('bkr.server.dynamic_virt.VirtManager', autospec=True):
recipe.provision()
if recipe.installation.commands:
- # Because we run a real beaker-provision in the dogfood tests, it will pick
- # up the freshly created configure_netboot commands and try pulling down
- # non-existent kernel+initrd images. When that fails, it will abort our
- # newly created recipe which we don't want. To work around this, we hack
+ # Because we run a real beaker-provision in the dogfood tests, it will pick
+ # up the freshly created configure_netboot commands and try pulling down
+ # non-existent kernel+initrd images. When that fails, it will abort our
+ # newly created recipe which we don't want. To work around this, we hack
# the commands to be already completed so that beaker-provision skips them.
# I would like to have a better solution here...
session.flush()
@@ -769,8 +769,8 @@ def mark_recipe_waiting(recipe, start_time=None, only=False, **kwargs):
cmd.change_status(CommandStatus.running)
cmd.change_status(CommandStatus.completed)
else:
- # System without power control, there are no power commands. In the
- # real world the recipe sits in Waiting with no watchdog kill time
+ # System without power control, there are no power commands. In the
+ # real world the recipe sits in Waiting with no watchdog kill time
# until someone powers on the system.
pass
recipe.waiting()
@@ -936,8 +936,11 @@ def create_openstack_region():
region.lab_controller = LabController.query.first()
def create_keystone_trust(user):
- trust_id = dynamic_virt.create_keystone_trust(os.environ['OPENSTACK_DUMMY_USERNAME'],
- os.environ['OPENSTACK_DUMMY_PASSWORD'],
- os.environ['OPENSTACK_DUMMY_PROJECT_NAME'])
+ trust_id = dynamic_virt.create_keystone_trust(
+ trustor_username=os.environ['OPENSTACK_DUMMY_USERNAME'],
+ trustor_password=os.environ['OPENSTACK_DUMMY_PASSWORD'],
+ trustor_project_name=os.environ['OPENSTACK_DUMMY_PROJECT_NAME'],
+ trustor_user_domain_name=os.environ.get('OPENSTACK_DUMMY_USER_DOMAIN_NAME'),
+ trustor_project_domain_name=os.environ.get('OPENSTACK_DUMMY_PROJECT_DOMAIN_NAME'))
user.openstack_trust_id = trust_id
log.debug('Created OpenStack trust %s for %s', trust_id, user)
diff --git a/Server/bkr/server/tools/beakerd.py b/Server/bkr/server/tools/beakerd.py
index 4c2e740..fc10bbe 100644
--- a/Server/bkr/server/tools/beakerd.py
+++ b/Server/bkr/server/tools/beakerd.py
@@ -6,7 +6,7 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-# pkg_resources.requires() does not work if multiple versions are installed in
+# pkg_resources.requires() does not work if multiple versions are installed in
# parallel. This semi-supported hack using __requires__ is the workaround.
# http://bugs.python.org/setuptools/issue139
# (Fedora/EPEL has python-cherrypy2 = 2.3 and python-cherrypy = 3)
@@ -102,7 +102,7 @@ def update_dirty_jobs():
try:
update_dirty_job(job_id)
session.commit()
- except Exception, e:
+ except Exception as e:
log.exception('Error in update_dirty_job(%s)', job_id)
session.rollback()
finally:
@@ -132,7 +132,7 @@ def process_new_recipes(*args):
try:
process_new_recipe(recipe_id)
session.commit()
- except Exception, e:
+ except Exception as e:
log.exception('Error in process_new_recipe(%s)', recipe_id)
session.rollback()
finally:
@@ -146,14 +146,14 @@ def process_new_recipe(recipe_id):
# Do the query twice.
- # First query verifies that the distro tree
+ # First query verifies that the distro tree
# exists in at least one lab that has a matching system.
# But if it's a user-supplied distro, we don't have a
# distro tree to match the lab against - so it will return
# all possible systems
systems = recipe.candidate_systems(only_in_lab=True)
- # Second query picks up all possible systems so that as
- # trees appear in other labs those systems will be
+ # Second query picks up all possible systems so that as
+ # trees appear in other labs those systems will be
# available.
all_systems = recipe.candidate_systems(only_in_lab=False)
# based on above queries, condition on systems but add
@@ -204,7 +204,7 @@ def queue_processed_recipesets(*args):
try:
queue_processed_recipeset(rs_id)
session.commit()
- except Exception, e:
+ except Exception as e:
log.exception('Error in queue_processed_recipeset(%s)', rs_id)
session.rollback()
finally:
@@ -249,7 +249,7 @@ def queue_processed_recipeset(recipeset_id):
# locks
enough_systems = True
if not enough_systems:
- log.debug("recipe: %s labController:%s entering not enough systems logic" %
+ log.debug("recipe: %s labController:%s entering not enough systems logic" %
(recipe.id, l_controller))
# Eliminate bad choices.
for recipe in recipeset.machine_recipes_orderby(l_controller)[:]:
@@ -381,7 +381,7 @@ def abort_dead_recipes(*args):
try:
abort_dead_recipe(recipe_id)
session.commit()
- except exceptions.Exception, e:
+ except exceptions.Exception as e:
log.exception('Error in abort_dead_recipe(%s)', recipe_id)
session.rollback()
finally:
@@ -417,7 +417,7 @@ def schedule_pending_systems():
try:
schedule_pending_system(system_id)
session.commit()
- except Exception, e:
+ except Exception as e:
log.exception('Error in schedule_pending_system(%s)', system_id)
session.rollback()
finally:
@@ -448,7 +448,7 @@ def schedule_pending_system(system_id):
# Remember the mapping of available systems could have happend hours or even
# days ago and groups or loans could have been put in place since.
if not recipe.candidate_systems().filter(System.id == system.id).first():
- log.debug("System : %s recipe: %s no longer has access. removing" % (system,
+ log.debug("System : %s recipe: %s no longer has access. removing" % (system,
recipe.id))
recipe.systems.remove(system)
# Try again on the next pass.
@@ -507,7 +507,8 @@ def provision_virt_recipe(recipe_id):
session.begin()
try:
recipe = Recipe.by_id(recipe_id)
- manager = dynamic_virt.VirtManager(recipe.recipeset.job.owner)
+ job_owner = recipe.recipeset.job.owner
+ manager = dynamic_virt.VirtManager(job_owner)
available_flavors = manager.available_flavors()
# We want them in order of smallest to largest, so that we can pick the
# smallest flavor that satisfies the recipe's requirements. Sorting by RAM
@@ -515,19 +516,18 @@ def provision_virt_recipe(recipe_id):
possible_flavors = XmlHost.from_string(recipe.host_requires)\
.filter_openstack_flavors(available_flavors, manager.lab_controller)
if not possible_flavors:
- log.debug('No OpenStack flavors matched recipe %s, marking precluded',
+ log.info('No OpenStack flavors matched recipe %s, marking precluded',
recipe.id)
recipe.virt_status = RecipeVirtStatus.precluded
return
- possible_flavors = sorted(possible_flavors, key=lambda flavor: flavor.ram)
+ # cheapest flavor is smallest disk and smallest ram
+ smallest_disk_list = sorted(possible_flavors, key=lambda flavor: flavor.disk)
+ possible_flavors = sorted(smallest_disk_list, key=lambda flavor: flavor.ram)
flavor = possible_flavors[0]
vm_name = '%srecipe-%s' % (
ConfigItem.by_name(u'guest_name_prefix').current_value(u'beaker-'),
recipe.id)
- # FIXME can we control use of virtio?
- #virtio_possible = True
- #if self.recipe.distro_tree.distro.osversion.osmajor.osmajor == "RedHatEnterpriseLinux3":
- # virtio_possible = False
+ log.debug('Creating VM named %s as flavor %s', vm_name, flavor)
vm = manager.create_vm(vm_name, flavor)
vm.instance_created = datetime.utcnow()
try:
@@ -538,21 +538,23 @@ def provision_virt_recipe(recipe_id):
recipe.recipeset.lab_controller = manager.lab_controller
recipe.virt_status = RecipeVirtStatus.succeeded
recipe.schedule()
- log.info("recipe ID %s moved from Queued to Scheduled by provision_virt_recipe" % recipe.id)
+ log.info("recipe ID %s moved from Queued to Scheduled by provision_virt_recipe",
+ recipe.id)
recipe.waiting()
recipe.provision()
- log.info("recipe ID %s moved from Scheduled to Waiting by provision_virt_recipe" % recipe.id)
+ log.info("recipe ID %s moved from Scheduled to Waiting by provision_virt_recipe",
+ recipe.id)
except:
exc_type, exc_value, exc_tb = sys.exc_info()
try:
manager.destroy_vm(vm)
except Exception:
- log.exception('Failed to clean up vm %s '
- 'during provision_virt_recipe, leaked!', vm.instance_id)
+ log.exception('Failed to clean up VM %s during provision_virt_recipe, leaked!',
+ vm.instance_id)
# suppress this exception so the original one is not masked
raise exc_type, exc_value, exc_tb
session.commit()
- except Exception, e:
+ except Exception as e:
log.exception('Error in provision_virt_recipe(%s)', recipe_id)
session.rollback()
# As an added precaution, let's try and avoid this recipe in future
@@ -604,7 +606,7 @@ def provision_scheduled_recipeset(recipeset_id):
# Online data migration
-# This is populated by schedule() on startup, and then updated by
+# This is populated by schedule() on startup, and then updated by
# run_data_migrations() as migrations are completed.
_outstanding_data_migrations = []
@@ -697,7 +699,7 @@ def system_command_metrics():
def dirty_job_metrics():
metrics.measure('gauges.dirty_jobs', Job.query.filter(Job.is_dirty).count())
-# These functions are run in separate threads, so we want to log any uncaught
+# These functions are run in separate threads, so we want to log any uncaught
# exceptions instead of letting them be written to stderr and lost to the ether
@log_traceback(log)
diff --git a/Server/bkr/server/tools/ipxe_image.py b/Server/bkr/server/tools/ipxe_image.py
index 71d65f3..bf8cf02 100644
--- a/Server/bkr/server/tools/ipxe_image.py
+++ b/Server/bkr/server/tools/ipxe_image.py
@@ -4,7 +4,7 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-# pkg_resources.requires() does not work if multiple versions are installed in
+# pkg_resources.requires() does not work if multiple versions are installed in
# parallel. This semi-supported hack using __requires__ is the workaround.
# http://bugs.python.org/setuptools/issue139
# (Fedora/EPEL has python-cherrypy2 = 2.3 and python-cherrypy = 3)
@@ -40,12 +40,11 @@ from bkr.server.model import session, OpenStackRegion
log = logging.getLogger(__name__)
def _image_name():
- # Beaker doesn't actually care about the image name at all, and OpenStack
- # doesn't require it to be unique, but we try to generate a descriptive
+ # Beaker doesn't actually care about the image name at all, and OpenStack
+ # doesn't require it to be unique, but we try to generate a descriptive
# name just to make it easier for the admin to find in Horizon.
- return 'ipxe-beaker-%s-%s' % (
- config.get('tg.url_domain', socket.getfqdn()),
- datetime.date.today().strftime('%Y%m%d'))
+ return 'ipxe-beaker-%s-%s' % (config.get('tg.url_domain', socket.getfqdn()),
+ datetime.date.today().strftime('%Y%m%d'))
def generate_image(delete=True):
f = tempfile.NamedTemporaryFile(suffix='.beaker-ipxe-image', delete=delete)
@@ -53,9 +52,9 @@ def generate_image(delete=True):
subprocess.check_call(['mformat', '-i', f.name, '-C', '-t', '4', '-h', '64', '-n', '32', '::'])
subprocess.check_call(['syslinux', '--install', f.name])
subprocess.check_call(['mcopy', '-i', f.name,
- '/usr/share/ipxe/ipxe.lkrn', '::ipxe.lkrn'])
+ '/usr/share/ipxe/ipxe.lkrn', '::ipxe.lkrn'])
mcopy = subprocess.Popen(['mcopy', '-i', f.name, '-', '::syslinux.cfg'],
- stdin=subprocess.PIPE)
+ stdin=subprocess.PIPE)
mcopy.communicate("""\
DEFAULT ipxe
LABEL ipxe
@@ -64,7 +63,7 @@ APPEND dhcp && chain %s
""" % absolute_url('/systems/by-uuid/${uuid}/ipxe-script', scheme='http', labdomain=True))
if mcopy.returncode != 0:
raise RuntimeError('mcopy syslinux.cfg failed with return code %s'
- % mcopy.returncode)
+ % mcopy.returncode)
return f
def upload_image(glance, visibility=u'public'):
@@ -76,8 +75,10 @@ def upload_image(glance, visibility=u'public'):
f.seek(0)
image_name = _image_name()
log.debug('Creating Glance image %s', image_name)
- image = glance.images.create(name=image_name,
- disk_format='raw', container_format='bare', visibility=visibility)
+
+ image = glance.images.create(name=image_name, disk_format='raw',
+ container_format='bare', visibility=visibility)
+
log.debug('Uploading image %s to Glance', f.name)
glance.images.upload(image.id, f)
region.ipxe_image_id = uuid.UUID(image.id)
@@ -86,13 +87,15 @@ def main():
parser = OptionParser(description=__description__, version=__version__)
parser.add_option('-c', '--config-file')
parser.add_option('--debug', action='store_true',
- help='Show detailed information about image creation')
+ help='Show detailed information about image creation')
parser.add_option('--no-upload', dest='upload', action='store_false',
- help='Skip uploading to Glance, leave image temp file on disk')
+ help='Skip uploading to Glance, leave image temp file on disk')
parser.add_option('--os-username', help='OpenStack username')
parser.add_option('--os-password', help='OpenStack password')
parser.add_option('--os-tenant-name', help=SUPPRESS_HELP)
parser.add_option('--os-project-name', help='OpenStack project name')
+ parser.add_option('--os-project-domain-name', help='OpenStack project domain name')
+ parser.add_option('--os-user-domain-name', help='OpenStack user domain name')
parser.set_defaults(debug=False, upload=True)
options, args = parser.parse_args()
load_config_or_exit(options.config_file)
@@ -116,15 +119,28 @@ def main():
project_name = options.os_tenant_name or os.environ.get('OS_TENANT_NAME')
if not project_name:
parser.error('Specify project with --os-project-name or env[OS_PROJECT_NAME]')
+
auth_url = config.get('openstack.identity_api_url')
if not auth_url:
parser.error('OpenStack Identity API URL is not set in the configuration')
+
+ user_domain_name = options.os_user_domain_name or \
+ os.environ.get('OS_USER_DOMAIN_NAME')
+ project_domain_name = options.os_project_domain_name or \
+ os.environ.get('OS_PROJECT_DOMAIN_NAME')
+
log.debug('Authenticating to Keystone')
- keystone = keystoneclient.v3.client.Client(username=username, password=password,
- project_name=project_name, auth_url=auth_url)
+ keystone = keystoneclient.v3.client.Client(
+ username=username,
+ password=password,
+ project_name=project_name,
+ user_domain_name=user_domain_name,
+ project_domain_name=project_domain_name,
+ auth_url=auth_url)
+
log.debug('Looking up Glance URL in service catalog')
- glance_url = keystone.service_catalog.url_for(
- service_type='image', endpoint_type='publicURL')
+ glance_url = keystone.service_catalog.url_for(service_type='image',
+ endpoint_type='publicURL')
log.debug('Using Glance URL %s', glance_url)
glance = glanceclient.v2.client.Client(glance_url, token=keystone.auth_token)
# Generate and upload the image.
diff --git a/Server/bkr/server/tools/product_update.py b/Server/bkr/server/tools/product_update.py
index d2df982..7e2fd4b 100755
--- a/Server/bkr/server/tools/product_update.py
+++ b/Server/bkr/server/tools/product_update.py
@@ -27,11 +27,16 @@ __description__ = 'Update CPE identifiers for products in Beaker'
def get_parser():
parser = OptionParser(description=__description__, version=__version__)
parser.add_option('-c', '--config-file', metavar='FILE', dest='configfile',
- help='Load Beaker server configuration from FILE')
+ help='Load Beaker server configuration from FILE')
parser.add_option('-f', '--product-file', metavar='FILE', dest='productfile',
- help='Load product XML data from FILE')
+ help='Load product XML data from FILE')
parser.add_option('--product-url', metavar='URL', dest='producturl',
- help='Load product XML or JSON data from URL')
+ help='Load product XML or JSON data from URL')
+ parser.add_option('--product-url-header', metavar='APPLICATION_TYPE', dest='producturl_header',
+ type='choice',
+ choices=['json', 'xml'],
+ default='json',
+ help='Define accept header for the product url. Options: JSON, XML. Default: JSON')
return parser
def update_products_from_xml(xml_file):
@@ -67,7 +72,9 @@ def main():
xml_file = open(opts.productfile, 'rb')
update_products_from_xml(xml_file)
elif opts.producturl:
- response = requests.get(opts.producturl, stream=True)
+ response = requests.get(opts.producturl,
+ stream=True,
+ headers=dict(Accept='application/%s' % opts.producturl_header))
response.raise_for_status()
mimetype, options = cgi.parse_header(response.headers['Content-Type'])
if mimetype in ['text/xml', 'application/xml']:
diff --git a/Server/bkr/server/user.py b/Server/bkr/server/user.py
index 0a6b1fb..3f71856 100644
--- a/Server/bkr/server/user.py
+++ b/Server/bkr/server/user.py
@@ -137,11 +137,11 @@ def get_users():
``email_address``
The user's email address.
``disabled``
- A boolean field which is true if the user has been temporarily disabled
- by the Beaker administrator (preventing them from logging in or running
+ A boolean field which is true if the user has been temporarily disabled
+ by the Beaker administrator (preventing them from logging in or running
jobs).
``removed``
- Timestamp when the user account was deleted, or null for a user account
+ Timestamp when the user account was deleted, or null for a user account
which has not been deleted.
"""
query = User.query.order_by(User.user_name)
@@ -181,8 +181,8 @@ def users_typeahead():
return jsonify(data=data)
def user_full_json(user):
- # Users have a minimal JSON representation which is embedded in many other
- # objects (system owner, system user, etc) but we need more info here on
+ # Users have a minimal JSON representation which is embedded in many other
+ # objects (system owner, system user, etc) but we need more info here on
# the user page.
attributes = user.to_json()
attributes['job_count'] = Job.query.filter(not_(Job.is_finished()))\
@@ -196,7 +196,7 @@ def user_full_json(user):
.filter(System.owner == user).count()
attributes['owned_pool_count'] = SystemPool.query\
.filter(SystemPool.owning_user == user).count()
- # Intentionally not counting membership in inverted groups because everyone
+ # Intentionally not counting membership in inverted groups because everyone
# is always in those
attributes['group_membership_count'] = len(user.group_user_assocs)
return attributes
@@ -277,14 +277,14 @@ def update_user(username):
Updates a Beaker user account.
:param username: The user's username.
- :jsonparam string user_name: New username. If the username is changed, the
- response will include a Location header referring to the new URL for newly
+ :jsonparam string user_name: New username. If the username is changed, the
+ response will include a Location header referring to the new URL for newly
renamed user resource.
:jsonparam string display_name: New display name.
:jsonparam string email_address: New email address.
- :jsonparam string password: New password. Only valid when Beaker is not
+ :jsonparam string password: New password. Only valid when Beaker is not
using external authentication for this account.
- :jsonparam string root_password: Root password to be set on systems
+ :jsonparam string root_password: Root password to be set on systems
provisioned by Beaker.
:jsonparam boolean use_old_job_page: True if the user has opted to use the
old, deprecated pre-Beaker-23 job page.
@@ -298,10 +298,10 @@ def update_user(username):
notifications of modifications to the groups the user belongs to.
:jsonparam boolean notify_reservesys: True if the user receives
notifications upon reservesys being ready.
- :jsonparam boolean disabled: Whether the user should be temporarily
- disabled. Disabled users cannot log in or submit jobs, and any running jobs
+ :jsonparam boolean disabled: Whether the user should be temporarily
+ disabled. Disabled users cannot log in or submit jobs, and any running jobs
are cancelled when their account is disabled.
- :jsonparam string removed: Pass the string 'now' to remove a user account.
+ :jsonparam string removed: Pass the string 'now' to remove a user account.
Pass null to un-remove a removed user account.
"""
user = _get_user(username)
@@ -387,7 +387,7 @@ def add_ssh_public_key(username):
"""
Adds a new SSH public key for the given user account.
- Accepts mimetype:`text/plain` request bodies containing the SSH public key
+ Accepts mimetype:`text/plain` request bodies containing the SSH public key
in the conventional OpenSSH format: <keytype> <key> <ident>.
:param username: The user's username.
@@ -404,6 +404,9 @@ def add_ssh_public_key(username):
elements = keytext.split(None, 2)
if len(elements) != 3:
raise ValueError('Invalid SSH public key')
+ # 0 - key type; 1 - key; 2 - identity
+ if elements[1] in [ssh_key.pubkey for ssh_key in user.sshpubkeys]:
+ raise ValueError('Duplicate SSH public key')
key = SSHPubKey(*elements)
user.sshpubkeys.append(key)
session.flush() # to populate id
@@ -432,7 +435,7 @@ def delete_ssh_public_key(username, id):
@auth_required
def add_submission_delegate(username):
"""
- Adds a submission delegate for a user account. Submission delegates are
+ Adds a submission delegate for a user account. Submission delegates are
other users who are allowed to submit jobs on behalf of this user.
:param username: The user's username.
@@ -511,7 +514,8 @@ def _create_keystone_trust(user):
if not config.get('openstack.identity_api_url'):
raise BadRequest400("OpenStack Integration is not enabled")
if not user.can_edit_keystone_trust(identity.current.user):
- raise Forbidden403('Cannot edit Keystone trust of user %s' % user.username)
+ raise Forbidden403('Cannot edit Keystone trust of user %s' % user.user_name)
+
data = read_json_request(request)
if 'openstack_username' not in data:
raise BadRequest400('No OpenStack username specified')
@@ -519,9 +523,14 @@ def _create_keystone_trust(user):
raise BadRequest400('No OpenStack password specified')
if 'openstack_project_name' not in data:
raise BadRequest400('No OpenStack project name specified')
+
try:
- trust_id = dynamic_virt.create_keystone_trust(data['openstack_username'],
- data['openstack_password'], data['openstack_project_name'])
+ trust_id = dynamic_virt.create_keystone_trust(
+ trustor_username=data['openstack_username'],
+ trustor_password=data['openstack_password'],
+ trustor_project_name=data['openstack_project_name'],
+ trustor_user_domain_name=data.get('openstack_user_domain_name'),
+ trustor_project_domain_name=data.get('openstack_project_domain_name'))
except ValueError as err:
raise BadRequest400(u'Could not authenticate with OpenStack using your credentials: %s' % unicode(err))
user.openstack_trust_id = trust_id
@@ -543,7 +552,7 @@ def delete_keystone_trust(username):
if not user.can_edit_keystone_trust(identity.current.user):
raise Forbidden403('Cannot edit Keystone trust of user %s' % username)
if not user.openstack_trust_id:
- raise BadRequest400('No Keystone trust created by %s' % user)
+ raise BadRequest400('No Keystone trust created by user %s' % username)
try:
manager = dynamic_virt.VirtManager(user)
manager.delete_keystone_trust()
diff --git a/Server/server.cfg b/Server/server.cfg
index fae6bbd..b35a713 100644
--- a/Server/server.cfg
+++ b/Server/server.cfg
@@ -1,6 +1,6 @@
[global]
-# This defines the URL prefix under which the Beaker web application will be
-# served. This must match the prefix used in the Alias and WSGIScriptAlias
+# This defines the URL prefix under which the Beaker web application will be
+# served. This must match the prefix used in the Alias and WSGIScriptAlias
# directives in /etc/httpd/conf.d/beaker-server.conf.
# The default configuration places the application at: http://example.com/bkr/
server.webpath = "/bkr/"
@@ -8,13 +8,13 @@ server.webpath = "/bkr/"
# Database connection URI for Beaker's database, in the form:
# <driver>://<user>:<password>@<hostname>:<port>/<database>?<options>
# The charset=utf8 option is required for proper Unicode support.
-# The pool_recycle setting is required for MySQL, which will (by default)
+# The pool_recycle setting is required for MySQL, which will (by default)
# terminate idle client connections after 10 hours.
sqlalchemy.dburi = "mysql://beaker:beaker@localhost/beaker?charset=utf8"
sqlalchemy.pool_recycle = 3600
-# If you want to send read-only report queries to a separate slave
-# database, configure it here. If not configured, report queries will
+# If you want to send read-only report queries to a separate slave
+# database, configure it here. If not configured, report queries will
# fall back to using the main Beaker database (above).
#reports_engine.dburi = "mysql://beaker_ro:beaker_ro@dbslave/beaker?charset=utf8"
#reports_engine.pool_recycle = 3600
@@ -22,32 +22,32 @@ sqlalchemy.pool_recycle = 3600
# Set to True to enable sending emails.
#mail.on = False
-# TurboMail transport to use. The default 'smtp' sends mails over SMTP to the
-# server configured below. Other transports may be available as TurboMail
+# TurboMail transport to use. The default 'smtp' sends mails over SMTP to the
+# server configured below. Other transports may be available as TurboMail
# extension packages.
#mail.transport = "smtp"
-# SMTP server where mails should be sent. By default we assume there is an
+# SMTP server where mails should be sent. By default we assume there is an
# SMTP-capable MTA running on the local host.
#mail.smtp.server = "127.0.0.1"
# The address which will appear as the From: address in emails sent by Beaker.
#beaker_email = "root@localhost.localdomain"
-# If this is set to a value greater than zero, Beaker will enforce a limit on
-# the number of concurrently running power/provision commands in each lab. Set
-# this option if you have a lab with many machines and are concerned about
+# If this is set to a value greater than zero, Beaker will enforce a limit on
+# the number of concurrently running power/provision commands in each lab. Set
+# this option if you have a lab with many machines and are concerned about
# a flood of commands overwhelming your lab controller.
#beaker.max_running_commands = 10
-# Timeout for authentication tokens. After this many minutes of inactivity
+# Timeout for authentication tokens. After this many minutes of inactivity
# users will be required to re-authenticate.
#visit.timeout = 360
-# Secret key for encrypting authentication tokens. Set this to a very long
-# random string and DO NOT disclose it. Changing this value will invalidate all
+# Secret key for encrypting authentication tokens. Set this to a very long
+# random string and DO NOT disclose it. Changing this value will invalidate all
# existing tokens and force users to re-authenticate.
-# If not set, a secret key will be generated and stored in /var/lib/beaker,
-# however this configuration impacts performance therefore you should supply
+# If not set, a secret key will be generated and stored in /var/lib/beaker,
+# however this configuration impacts performance therefore you should supply
# a secret key here.
#visit.token_secret_key = ""
@@ -57,20 +57,20 @@ sqlalchemy.pool_recycle = 3600
#identity.soldapprovider.uri = "ldaps://ldap.domain.com"
# Base DN for looking up user accounts.
#identity.soldapprovider.basedn = "dc=domain,dc=com"
-# If set to True, Beaker user acounts will be automatically created on demand
+# If set to True, Beaker user acounts will be automatically created on demand
# if they exist in LDAP. Account attributes are populated from LDAP.
#identity.soldapprovider.autocreate = False
# Timeout (seconds) for LDAP lookups.
#identity.soldapprovider.timeout = 20
-# Server principal and keytab for Kerberos authentication. If using Kerberos
-# authentication, this must match the mod_auth_kerb configuration in
+# Server principal and keytab for Kerberos authentication. If using Kerberos
+# authentication, this must match the mod_auth_kerb configuration in
# /etc/httpd/conf.d/beaker-server.conf.
#identity.krb_auth_principal = "HTTP/hostname@EXAMPLE.COM"
#identity.krb_auth_keytab = "/etc/krb5.keytab"
-# Automatically create user accounts if the user successfully authenticates
-# via Apache but there is no matching account in Beaker. The automatic creation
-# will only happen if REMOTE_USER_FULLNAME and REMOTE_USER_EMAIL variables are
+# Automatically create user accounts if the user successfully authenticates
+# via Apache but there is no matching account in Beaker. The automatic creation
+# will only happen if REMOTE_USER_FULLNAME and REMOTE_USER_EMAIL variables are
# also populated in the WSGI environment.
# mod_lookup_identity and mod_auth_mellon can be configured to do this.
#identity.autocreate = True
@@ -87,18 +87,18 @@ sqlalchemy.pool_recycle = 3600
#tg.lab_domain = "this.hostname.from.lab.domain"
# Tag for distros which are considered "reliable".
-# Broken system detection logic will be activated for distros with this tag
-# (see the bkr.server.model:System.suspicious_abort method). Leave this unset
+# Broken system detection logic will be activated for distros with this tag
+# (see the bkr.server.model:System.suspicious_abort method). Leave this unset
# to deactivate broken system detection.
#beaker.reliable_distro_tag = "RELEASED"
-# The contents of this file will be displayed to users on every page in Beaker.
+# The contents of this file will be displayed to users on every page in Beaker.
# If it exists, it must contain a valid HTML fragment (e.g. <span>...</span>).
#beaker.motd = "/etc/beaker/motd.xml"
-# The URL of a page describing your organisation's policies for reserving
-# Beaker machines. If configured, a message will appear on the reserve workflow
-# page, warning users to adhere to the policy with a hyperlink to this URL. By
+# The URL of a page describing your organisation's policies for reserving
+# Beaker machines. If configured, a message will appear on the reserve workflow
+# page, warning users to adhere to the policy with a hyperlink to this URL. By
# default no message is shown.
#beaker.reservation_policy_url = "http://example.com/reservation-policy"
@@ -108,49 +108,64 @@ sqlalchemy.pool_recycle = 3600
#beaker.kernel_options = "ksdevice=bootif"
#beaker.kernel_options_post = ""
-# When generating MAC addresses for virtual systems, Beaker will always pick
+# When generating MAC addresses for virtual systems, Beaker will always pick
# the lowest free address starting from this base address.
#beaker.base_mac_addr = "52:54:00:00:00:00"
-# Beaker increases the priority of recipes when it detects that they match only
+# Beaker increases the priority of recipes when it detects that they match only
# one candidate system. You can disable this behaviour here.
#beaker.priority_bumping_enabled = True
-# When generating RPM repos, we can configure what utility to use. The newer
-# createrepo_c implementation is recommended because it is faster and more
+# When generating RPM repos, we can configure what utility to use. The newer
+# createrepo_c implementation is recommended because it is faster and more
# memory-efficient, but the original createrepo command can also be used.
#beaker.createrepo_command = "createrepo_c"
-# If you have set up a log archive server (with beaker-transfer) and it
-# requires HTTP digest authentication for deleting old logs, set the username
+# If you have set up a log archive server (with beaker-transfer) and it
+# requires HTTP digest authentication for deleting old logs, set the username
# and password here.
#beaker.log_delete_user = "log-delete"
#beaker.log_delete_password = "examplepassword"
-# If carbon.address is set, Beaker will send various metrics to carbon
-# (collection daemon for Graphite) at the given address. The address must be
+# If carbon.address is set, Beaker will send various metrics to carbon
+# (collection daemon for Graphite) at the given address. The address must be
# a tuple of (hostname, port).
# The value of carbon.prefix is prepended to all names used by Beaker.
#carbon.address = ('graphite.example.invalid', 2023)
#carbon.prefix = 'beaker.'
# Use OpenStack for running recipes on dynamically created guests.
-# Beaker uses the credentials given here to authenticate to OpenStack,
+# Beaker uses the credentials given here to authenticate on OpenStack,
# when creating OpenStack instances on behalf of users.
-#openstack.identity_api_url = 'https://openstack.example.com:5000/v2.0'
+#openstack.identity_api_url = 'https://openstack.example.com:13000/v3/'
#openstack.dashboard_url = 'https://openstack.example.com/dashboard/'
#openstack.username = ""
#openstack.password = ""
-# Set this to limit the Beaker web application's address space to the given
-# size (in bytes). This may be helpful to catch excessive memory consumption by
+# The user domain name when authenticating on OpenStack. If not provided, Beaker
+# will not provide a domain name when connecting to OpenStack. This option is
+# required if the OpenStack instance has been configured to require a domain name.
+#openstack.user_domain_name = ""
+
+# OpenStack external network name for the instance. If not provided, Beaker
+# will search for an external network and use the first one it finds.
+#openstack.external_network_name = ""
+
+# Beaker will attempt to set up a floating IP address for a newly created
+# instance by default. You can disable this behavior here. If set to False,
+# the Beaker code will use the IP address assigned when the instance is
+# created as the public IP address of the instance.
+#openstack.create_floating_ip = True
+
+# Set this to limit the Beaker web application's address space to the given
+# size (in bytes). This may be helpful to catch excessive memory consumption by
# Beaker. On large deployments 1500000000 is a reasonable value.
# By default no address space limit is enforced.
#rlimit_as=
-# These limits are applied to all running recipes. They are intended as
-# a last-resort sanity check, to prevent a runaway task from accidentally
-# producing so many results that it can cause problems elsewhere in Beaker (for
+# These limits are applied to all running recipes. They are intended as
+# a last-resort sanity check, to prevent a runaway task from accidentally
+# producing so many results that it can cause problems elsewhere in Beaker (for
# example, excessive memory usage when rendering the results).
# Setting a limit to 0 means the limit will not be enforced.
#beaker.max_results_per_recipe = 7500
diff --git a/Server/setup.py b/Server/setup.py
index 0d68266..4c89135 100644
--- a/Server/setup.py
+++ b/Server/setup.py
@@ -186,7 +186,7 @@ else:
setup(
name='beaker-server',
namespace_packages = ['bkr'],
- version='26.4',
+ version='26.5',
description='Beaker scheduler and web interface',
long_description=
'Beaker is a system for full stack software integration testing '
diff --git a/beaker.spec b/beaker.spec
index ee4be5a..0b89bd2 100644
--- a/beaker.spec
+++ b/beaker.spec
@@ -20,10 +20,10 @@
# not representable in RPM. For example, a release candidate might be 0.15.0rc1
# but that is not usable for the RPM Version because it sorts higher than
# 0.15.0, so the RPM will have Version 0.15.0 and Release 0.rc1 in that case.
-%global upstream_version 26.4
+%global upstream_version 26.5
Name: beaker
-Version: 26.4
+Version: 26.5
Release: 1%{?dist}
Summary: Full-stack software and hardware integration testing system
Group: Applications/Internet
@@ -349,12 +349,20 @@ Requires: python2-flask
%else # old style Python package names
# These LC dependencies are needed in build due to tests
BuildRequires: python-lxml
+%if 0%{?rhel} == 7
+BuildRequires: python-gevent102
+%else
BuildRequires: python-gevent >= 1.0
+%endif
Requires: python-cpio
Requires: python-setuptools
Requires: python-lxml
Requires: python-gssapi
+%if 0%{?rhel} == 7
+Requires: python-gevent102
+%else
Requires: python-gevent >= 1.0
+%endif
Requires: python-daemon
Requires: python-werkzeug
Requires: python-flask
diff --git a/documentation/admin-guide/man/beaker-create-ipxe-image.rst b/documentation/admin-guide/man/beaker-create-ipxe-image.rst
index b19602e..079162a 100644
--- a/documentation/admin-guide/man/beaker-create-ipxe-image.rst
+++ b/documentation/admin-guide/man/beaker-create-ipxe-image.rst
@@ -11,28 +11,49 @@ Synopsis
Description
-----------
-Generates a bootable image containing the iPXE network boot loader, and
+Generates a bootable image containing the iPXE network boot loader, and
a configuration pointing at this Beaker instance.
-Beaker uses this image as part of the support for provisioning dynamic VMs in
-OpenStack. The image needs to be created once when OpenStack integration is
+Beaker uses this image as part of the support for provisioning dynamic VMs in
+OpenStack. The image needs to be created once when OpenStack integration is
enabled. The credentials given here need to have the permission to create a public
image in OpenStack.
-This command requires read access to the Beaker server configuration. Run it as
+This command requires read access to the Beaker server configuration. Run it as
root or as another user with read access to the configuration file.
Options
-------
-.. option:: --os-username <username>, --os-password <password>, --os-tenant-name <name>
+.. option:: --os-username <username>
- OpenStack credentials for uploading the generated image to Glance.
+ OpenStack user name for establishing a new trust between Beaker and the
+ given user.
+
+.. option:: --os-password <password>
+
+ OpenStack user password for establishing a new trust between Beaker and
+ the given user.
+
+.. option:: --os-project-name <project-name>
+
+ OpenStack project name for establishing a new trust between Beaker and
+ the given user.
+
+.. option:: --os-user-domain-name <user-domain-name>
+
+ OpenStack user domain name for establishing a new trust between Beaker
+ and the given user.
+
+.. option:: --os-project-domain-name <project-domain-name>
+
+ OpenStack project domain name for establishing a new trust between Beaker
+ and the given user.
.. option:: --no-upload
- Do not upload the generated image to OpenStack. The image temp file is left
- on disk and its filename is printed. Use this if you need to examine or
+ Do not upload the generated image to OpenStack. The image temp file is left
+ on disk and its filename is printed. Use this if you need to examine or
manipulate the image before uploading it to Glance manually.
Exit status
@@ -43,10 +64,23 @@ Non-zero on error, otherwise zero.
Examples
--------
-Once OpenStack integration is configured (see :ref:`openstack`), create
-a suitable iPXE image in Glance::
+OpenStack integration must be configured (see :ref:`openstack`) before running
+this command.
+
+This command creates an iPXE image in Glance where the OpenStack
+authentication uses default domain information::
+
+ beaker-create-ipxe-image \
+ --os-username beaker \
+ --os-password beaker \
+ --os-project-name beaker
+
+Use the options shown in this command when OpenStack requires user and project
+domain names::
beaker-create-ipxe-image \
--os-username beaker \
--os-password beaker \
- --os-tenant-name Beaker
+ --os-project-name beaker \
+ --os-user-domain-name=domain.com \
+ --os-project-domain-name=domain.com
diff --git a/documentation/admin-guide/openstack.rst b/documentation/admin-guide/openstack.rst
index 124dd29..4ad7928 100644
--- a/documentation/admin-guide/openstack.rst
+++ b/documentation/admin-guide/openstack.rst
@@ -7,21 +7,21 @@ Integration with OpenStack
.. note::
The OpenStack integration for dynamic system provisioning is classified as
- experimental. It has a number of limitations and may impact the scheduler's
- performance, therefore it is currently not recommended for use in production
+ experimental. It has a number of limitations and may impact the scheduler's
+ performance, therefore it is currently not recommended for use in production
on large Beaker instances.
Beaker can optionally be configured to use OpenStack to create
virtual machines on demand for running recipes.
When OpenStack integration is enabled, Beaker will attempt to create a new
-virtual machine for each recipe when it is scheduled. If creating the virtual
+virtual machine for each recipe when it is scheduled. If creating the virtual
machine fails, Beaker will fall back to using the regular hardware
pool for that recipe. Recipes with hardware requirements in
``<hostRequires/>`` which cannot be satisfied by a virtual machine are
excluded from this process.
-Package prerequisites
+Package prerequisites
---------------------
- python-keystoneclient >= 0.11.0
@@ -34,24 +34,43 @@ Juno EL6 repositories provided by CentOS in this case. See
`JunoEL6QuickStart <https://wiki.centos.org/Cloud/OpenStack/JunoEL6QuickStart>`_
for more details.
-Configuring OpenStack integration
+Configuring OpenStack integration
---------------------------------
-To enable OpenStack integration, configure the Identity API (Keystone) endpoint,
+To enable OpenStack integration, configure the Identity API (Keystone) endpoint,
dashboard (Horizon) URL and an OpenStack account of Beaker in :file:`/etc/beaker/server.cfg`::
# Use OpenStack for running recipes on dynamically created guests.
- openstack.identity_api_url = 'https://openstack.example.com:5000/v2.0'
+ # Beaker uses the credentials given here to authenticate to OpenStack
+ # when creating OpenStack instances on behalf of users.
+ openstack.identity_api_url = 'https://openstack.example.com:13000/v3.0'
openstack.dashboard_url = 'https://openstack.example.com/dashboard/'
- # Credentials of the OpenStack account of Beaker for authorization-based on
- # OpenStack identity trusts. Beaker uses the trust delegated by users to authenticate
- # to OpenStack when creating OpenStack instances on behalf of users.
openstack.username = ""
openstack.password = ""
-Currently Beaker does not support multiple OpenStack regions. Beaker expects
-a single row to exist in the ``openstack_region`` table, referencing the lab
-controller which should be used for OpenStack recipes. You must insert the row
+The user domain name when authenticating to OpenStack. Beaker does not
+provide a default domain name. This option is required if the OpenStack
+instance has been configured to require a domain name.
+
+ openstack.user_domain_name = ""
+
+The OpenStack external network name for the instance. If not provided, Beaker
+will search for an external network and use the first one it finds.
+
+ openstack.external_network_name = ""
+
+By default, Beaker will attempt to set up a floating IP address for a newly
+created instance to provide a public IP address. This assumes that the IP
+address assigned when the instance is created is on a private network. If the
+'create_floating_ip' flag is set to False, the Beaker code will use the IP
+address assigned when the instance is created as the public IP address of the
+instance.
+
+ openstack.create_floating_ip = True
+
+Currently Beaker does not support multiple OpenStack regions. Beaker expects
+a single row to exist in the ``openstack_region`` table, referencing the lab
+controller which should be used for OpenStack recipes. You must insert the row
manually::
INSERT INTO openstack_region (lab_controller_id)
@@ -60,14 +79,14 @@ manually::
Uploading iPXE image to Glance
------------------------------
-In order to boot distro installers on OpenStack instances, Beaker relies on
-a special image containing the iPXE network boot loader, which then loads its
-boot configuration from the Beaker server. The
-:program:`beaker-create-ipxe-image` tool creates and uploads a suitable image
+In order to boot distro installers on OpenStack instances, Beaker relies on
+a special image containing the iPXE network boot loader, which then loads its
+boot configuration from the Beaker server. The
+:program:`beaker-create-ipxe-image` tool creates and uploads a suitable image
to Glance. You must run this tool once after defining an OpenStack region.
-The name for each virtual machine is constructed from the ``guest_name_prefix``
-setting (see :ref:`admin-configuration`) combined with the recipe ID. If you
-have configured multiple Beaker instances to use the same OpenStack instance,
-make sure you set a distinct value for ``guest_name_prefix`` to avoid name
+The name for each virtual machine is constructed from the ``guest_name_prefix``
+setting (see :ref:`admin-configuration`) combined with the recipe ID. If you
+have configured multiple Beaker instances to use the same OpenStack instance,
+make sure you set a distinct value for ``guest_name_prefix`` to avoid name
collisions.
diff --git a/documentation/user-guide/job-xml.rst b/documentation/user-guide/job-xml.rst
index 2d13460..1f4f679 100644
--- a/documentation/user-guide/job-xml.rst
+++ b/documentation/user-guide/job-xml.rst
@@ -307,6 +307,29 @@ The above specification will try to find a host which is a Machine
with a network interface (with description as "Extreme Gigabit
Ethernet") and with a video device with the description as "VD 0190".
+If you want your recipe to run on a particular system and you know its FQDN,
+you can configure host filtering by setting ``hostname`` and assign FQDN to it.
+The job will run on that machine provided it is in available state. The following
+example allows you to configure a machine with a specific host name::
+
+ <hostRequires>
+ <and>
+ <system_type op="=" value="Machine"/>
+ <hostname op="=" value="my.hostx123.example.com"/>
+ </and>
+ </hostRequires>
+
+Another option to using ``hostname`` is entering wildcard '%' syntax in the name
+for chosing system(s)::
+
+ <hostRequires>
+ <and>
+ <system_type op="=" value="Machine"/>
+ <hostname op="like" value="my.%hostx%"/>
+ </and>
+ </hostRequires>
+
+
.. admonition:: Inventoried Systems Only
It is worthwhile to note here that if you submit device
@@ -317,17 +340,26 @@ Ethernet") and with a video device with the description as "VD 0190".
your job specification has been submitted. What this basically
means is that unless a system has been inventoried, Beaker won't be
able to find it, even if it has the particular device you are
- requesting. It may be a good idea to first search if there is any
+ requesting. It's a good idea to first search if there is any
system at all with the device you want to run your recipe on. (See:
:ref:`system-searching`).
.. _forced-system:
-If you want your recipe to run on a particular system and you know its
-FQDN, you can skip the host filtering described above and force the
-scheduler to pick a particular system for your recipe by using the
-``force=""`` attribute. For example, the following XML will force the
-recipe to be scheduled on ``my.host.example.com``::
+.. warning::
+ There is an ability to force a job to run on a specific system.
+ This capability is intended for administrators to perform
+ troubleshooting. It will cause the job to run on a machine
+ even if the system is in `broken, manual, or excluded` condition.
+ This is not the desired behavior for the majority users so this
+ configuration should be avoided. Use of ``force=`` configuration
+ is documented below but it's intended for use by system administrators.
+
+To force your recipe to run on a particular system and you know its FQDN,
+skip the host filtering described earlier and force the scheduler to pick
+a particular system for your recipe using the ``force=""`` attribute. For
+example, the following XML will force the recipe to be scheduled on
+``my.host.example.com``::
<hostRequires force="my.host.example.com" />
diff --git a/documentation/user-guide/task-metadata.rst b/documentation/user-guide/task-metadata.rst
index 3ddbcc8..a12d160 100644
--- a/documentation/user-guide/task-metadata.rst
+++ b/documentation/user-guide/task-metadata.rst
@@ -1,10 +1,12 @@
+.. _task_metadata:
+
Task metadata
=============
-This section describes the metadata which must be defined in each Beaker task.
-The beaker-wizard utility will help you to populate this metadata correctly
-when creating a new task (see :doc:`An example task <example-task>`). A sample
-Makefile is also included in the ``rhts-devel`` package as
+This section describes the metadata which must be defined in each Beaker task.
+The beaker-wizard utility will help you to populate this metadata correctly
+when creating a new task (see :doc:`An example task <example-task>`). A sample
+Makefile is also included in the ``rhts-devel`` package as
``/usr/share/doc/rhts-devel-*/Makefile.template``.
These details apply to tasks written using the default harness (``beah``).
@@ -17,60 +19,88 @@ specific harness in use.
Makefile variables
~~~~~~~~~~~~~~~~~~
-The following environment variables must be exported in the task's Makefile.
-These variables are used by ``rhts-make.include`` and its ancillary scripts
+The following environment variables must be exported in the task's Makefile.
+These variables are used by ``rhts-make.include`` and its anxillary scripts
when building the task RPM.
``TEST``
- The name of the task. The name is a hierarchical path beginning with
- a slash (``/``), similar to a filesystem path. For example,
- ``/distribution/mypackage/test-suite``. The task name is available as
+ The name of the task. The name is a hierarchical path beginning with
+ a slash (``/``), similar to a filesystem path. For example,
+ ``/distribution/mypackage/test-suite``. The task name is available as
:envvar:`TEST` in the task's environment.
- The task name is prefixed with ``/mnt/tests`` to form the directory where
- it will be installed on the system under test. This directory is available
+ The task name is prefixed with ``/mnt/tests`` to form the directory where
+ it will be installed on the system under test. This directory is available
as :envvar:`TESTPATH`.
- The task should report results relative to its name (see
+ The task should report results relative to its name (see
:ref:`rhts-report-result`).
``TESTVERSION``
- The version of the task. This becomes the version of the task RPM when it
- is built. As a consequence, it may contain only numbers, digits, and period
+ The version of the task. This becomes the version of the task RPM when it
+ is built. As a consequence, it may contain only numbers, digits, and period
(``.``).
``FILES``
- A whitespace-separated list of all the files to be included in the task
- RPM. This must include at least ``testinfo.desc`` (typically given as
- ``$(METADATA)``), ``runtest.sh``, and ``Makefile``. If a task uses any
+ A whitespace-separated list of all the files to be included in the task
+ RPM. This must include at least ``testinfo.desc`` (typically given as
+ ``$(METADATA)``), ``runtest.sh``, and ``Makefile``. If a task uses any
additional scripts or data, those files must be listed here.
``BUILT_FILES``
- Files which are generated or compiled by other rules in the Makefile should
- be listed in this variable, rather than in ``FILES``, so that they are
+ Files which are generated or compiled by other rules in the Makefile should
+ be listed in this variable, rather than in ``FILES``, so that they are
built when the task RPM is built.
+``TEST_DIR``
+ This can be used with the ``Path`` metadata field described in the next
+ section. It is not defined by the user but defined by rhts tools to
+ concatenate ``/mnt/tests`` with the name of the test or ``$(TEST)``.
+
.. _testinfo.desc:
Fields in ``testinfo.desc``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The ``testinfo.desc`` file declares metadata about the task. The metadata is
-extracted by Beaker and made available in the task library. The harness also
-uses this metadata, for example to determine the allowed watchdog time for the
+The ``testinfo.desc`` file declares metadata about the task. The metadata is
+extracted by Beaker and made available in the task library. The harness also
+uses this metadata, for example to determine the allowed watchdog time for the
task.
This file is typically generated by the Makefile as part of the build process,
although it can also be edited and committed directly to source control.
-The following fields are recognised by Beaker.
+The following fields are recognized by Beaker. They are ordered first
+with mandatory fields then optional.
-Owner
------
+Description
+-----------
+
+``Description`` (required) must contain exactly one string.
+
+For example:
+
+::
+
+ Description: This test tries to map five 1-gigabyte files with a single process.
+ Description: This test tries to exploit the recent security issue for large pix map files.
+ Description: This test tries to panic the kernel by creating thousands of processes.
+
+
+License
+-------
+
+``License`` (required) identifies the type of license protection this task
+has. These include ``GPL, GPLv2, GPLv2+, GPL3, Red Hat Internal, or
+Red Hat Confidential``. A sample configuration of this parameter appears
+as follows::
+
+ License: GPLv2+
+
+For further details on GNU Licensing, refer to http://www.gnu.org/licenses/.
+When 'Red Hat Internal or Confidential' is configured, this task rpm is not
+available for public use.
-``Owner`` (optional) is the person responsible for this task. Acceptable
-values are a subset of the set of valid email addresses, requiring the
-form: "Owner: human readable name <username@domain>".
Name
----
@@ -86,18 +116,27 @@ characters that are usable within a file system path.
For fast indexing purposes, task names are limited to 255 characters.
-Description
------------
-``Description`` (required) must contain exactly one string.
+Owner
+-----
-For example:
+``Owner`` (required) is the person responsible for this task. Acceptable
+values are a subset of the set of valid email addresses, requiring the
+form: "Owner: human readable name <username@domain>".
-::
- Description: This test tries to map five 1-gigabyte files with a single process.
- Description: This test tries to exploit the recent security issue for large pix map files.
- Description: This test tries to panic the kernel by creating thousands of processes.
+Path
+----
+
+``Path`` (required) specifies which directory the task rpm on the test
+system is installed. This is an informational attribute only and appears
+when displaying tasks when using the Task Library UI. If the
+user gets onto the test system, they can go to this directory to review their
+installed rpm data. To define this in the Makefile, it should
+appear as follows::
+
+ Path: $(TEST_DIR)
+
.. _testinfo-testtime:
@@ -133,6 +172,164 @@ For example:
TestTime: 1m # 1 minute
TestTime: 2h # 2 hours
+
+TestVersion
+-----------
+
+(required) This is the version of the task provided in the loaded RPM.
+Configuration of this attribute should appear as follows
+where this is an initial release::
+
+ TestVersion: 0.1 # OR
+ TestVersion: $(TESTVERSION) # if defined in Makefile
+
+
+Architectures
+-------------
+
+``Architectures`` (optional) provides the ability to classify tasks for specific
+architectures. You can provide a list of excluded architectures or a list of
+exclusive architectures. For an excluded list, each architecture provided must
+be proceeded with a minus sign(-). This includes all architectures except
+those listed. For an exclusive list, no proceeding sign is required. You
+can only configure an excluded or exclusive list and not a combination of both.
+
+If the task is expected to only run on x86_64 architecture, then
+configure the following::
+
+ Architectures: x86_64
+
+If the task is expect to NOT run on architecture x86_64 nor i386,
+do as follows::
+
+ Architectures: -x86_64 -i386
+
+The list of architectures you can choose from can be found in
+Distros Section.
+
+
+Bugs
+----
+
+``Bugs`` (optional) allows user to identify which bugs filed in Bugzilla
+are associated to this task. The following are sample configurations::
+
+ # Single Line
+ Bug: 9999999 OR Bugs: 9999999
+
+ # Multiple Bugzillas
+ Bugs: 77777777 88888888
+
+ # Or multiple Bugzillas on multiple lines
+ Bugs: 77777777
+ Bugs: 88888888
+
+
+Destructive
+-----------
+
+``Destructive`` (optional) is used to classify tasks which are destructive.
+Determination of what classifies as destructive is up to the user defining
+the test. To define this task as destructive, configure the following::
+
+ Destructive: Yes
+
+Since tasks can be filtered by the `bkr task-list` CLI, it is recommended
+to define the task with this attribute with Yes or No; otherwise, it will
+not be found.
+
+
+Environment
+-----------
+
+``Environment`` (optional) is used to pass task environment data to test
+harnesses. The following can be set to alter defaults in beah::
+
+ Environment: RHTS_PORT=<your chosen port> else beah uses random port(7080-7099)
+
+This field can occur multiple times within the metadata. So you can
+configure the following::
+
+ Environment: META_VAR1=<your var1 data>
+ Environment: META_VAR2=<your var2 data>
+ Environment: META_VAR3=<your var3 data>
+
+
+Priority
+--------
+
+``Priority`` (optional) allows user to classify a task's priority.
+This has no affect on the execution of the job.
+Recommended values are as follows::
+
+ Low, Medium, Normal, High, Manual
+
+The following is a sampling to configure this attribute::
+
+ Priority: High
+
+
+Provides
+--------
+
+``Provides`` (optional) allows the task creator to specify the capabilities
+that the task RPM provides upon install. In addition to the default
+``Provides`` generated by RPM, every task provides a virtual
+capability derived from the task name. For example, the
+``/distribution/check-install`` task also provides
+``test(/distribution/check-install)``.
+
+You can specify additional capabilities by adding new ``Provides``
+lines (using a similar syntax to ``Requires``). For example, if your
+task provides equivalent or better functionality than an old task, you
+can add a ``Provides`` such as the one below::
+
+ Provides: test(/old/task/name)
+
+
+.. _testinfo-releases:
+
+Releases
+--------
+
+(optional) Some tests are only applicable to certain distribution releases.
+For example, a kernel bug may only be applicable to RHEL3 which contains the
+2.4 kernel. Limiting the release should only be used when a task will
+not execute on a particular release. Otherwise, the release should not
+be restricted so that your test can run on as many different releases as
+possible.
+
+You can populate the optional ``Releases`` field in two different ways. To
+exclude certain releases but include all others, list the releases each
+prefixed with a minus sign (-). To include certain releases but exclude
+all others, list the included releases.
+
+For example, if your task runs only on RHEL6 and RHEL7::
+
+ Releases: RedHatEnterpriseLinux6 RedHatEnterpriseLinux7
+
+Or, if your task is expected to run on any release except for RHEL3 & RHEL4::
+
+ Releases: -RedHatEnterpriseLinux3 -RedHatEnterpriseLinux4
+
+Releases are identified by their OS major version. You can browse a list of OS
+versions in Beaker by selecting :menuselection:`Distros --> Family` from the
+menu. For example:
+
+- RedHatEnterpriseLinux3
+- RedHatEnterpriseLinux4
+- RedHatEnterpriseLinuxServer5
+- RedHatEnterpriseLinuxClient5
+- RedHatEnterpriseLinux6
+- RedHatEnterpriseLinux7
+- RedHatEnterpriseLinux8
+- Fedora17
+
+Your Beaker administrator may have configured compatibility aliases for some OS
+versions, which you can also use in the ``Releases`` field. See
+:ref:`admin-os-versions` in the Administration Guide.
+
+
Requires
--------
@@ -190,22 +387,15 @@ server(s), the union of the requirements for all of the roles must be
listed here.
-Provides
---------
+RhtsOptions
+-----------
-``Provides`` (optional) allows the task creator to specify the capabilities
-that the task RPM provides upon install. In addition to the default
-``Provides`` generated by RPM, every task provides a virtual
-capability derived from the task name. For example, the
-``/distribution/check-install`` task also provides
-``test(/distribution/check-install)``.
+(optional) You can indicate that your task does `not` need to be run inside the
+``rhts-compat`` service::
-You can specify additional capabilities by adding new ``Provides``
-lines (using a similar syntax to ``Requires``). For example, if your
-task provides equivalent or better functionality than an old task, you
-can add a ``Provides`` such as the one below::
+ RhtsOptions: -Compatible
- Provides: test(/old/task/name)
+This option has no effect on newer distros. See :doc:`rhts-compat`.
.. _rhts-requires:
@@ -213,35 +403,25 @@ can add a ``Provides`` such as the one below::
RhtsRequires
------------
-This field indicates the other beaker tests that are required to be
-installed on the test machine for the test to work.
+``RhtsRequires`` (optional) indicates the other beaker tests that are
+required to be installed on the test machine for the test to work.
This field can occur multiple times within the metadata. Each value
should consist of a task name in the form ``test(<task-name>)``. Each
task dependency named this way must exist in the Beaker task library
or the task will be aborted.
-For example::
+For example::
RhtsRequires: test(/distribution/rhts/common)
-RhtsOptions
------------
-
-You can indicate that your task does not need to be run inside the
-``rhts-compat`` service::
-
- RhtsOptions: -Compatible
-
-This option has no effect on newer distros. See :doc:`rhts-compat`.
-
RunFor
------
``RunFor`` (optional) allows entries in the Beaker task library to be
associated with specific packages for test execution and reporting purposes.
It is only relevant for tasks that are specifically written as tests for
-particular packages rather than as general utilities.
+particular packages rather than as general utilities.
When testing a specific package, that package should be listed in this
field. If the test might reasonably be affected by changes to another
@@ -252,43 +432,19 @@ should be listed here.
This field is optional and can occur multiple times within the
metadata. The value should be a space-separated list of package names.
-.. _testinfo-releases:
-
-Releases
---------
-Some tests are only applicable to certain distribution releases. For
-example, a kernel bug may only be applicable to RHEL3 which contains the
-2.4 kernel. Limiting the release should only be used when a task will
-not execute on a particular release. Otherwise, the release should not
-be restricted so that your test can run on as many different releases as
-possible.
-
-You can populate the optional ``Releases`` field in two different ways. To
-exclude certain releases but include all others, list the releases each
-prefixed with a minus sign (-). To include certain releases but exclude
-all others, list the included releases.
-
-For example, if your task runs only on RHEL3 and RHEL4::
-
- Releases: RedHatEnterpriseLinux3 RedHatEnterpriseLinux4
+Type
+----
-Or, if your task is expected to run on any release except for RHEL3::
+(optional) To classify the type of task, one of the following is recommended::
- Releases: -RedHatEnterpriseLinux3
+ Regression, Performance, Stress, Certification, Security,
+ Durations, Interoperability, Standardscompliance, Customeracceptance,
+ Releasecriterium, Crasher, Tier1, Tier2, Alpha,
+ KernelTier1, KernelTier2, Multihost, MultihostDriver, Install,
+ FedoraTier1, FedoraTier2, KernelRTTier1, KernelReporting, Sanity, Library
-Releases are identified by their OS major version. You can browse a list of OS
-versions in Beaker by selecting :menuselection:`Distros --> Family` from the
-menu. For example:
+Configuration of this attribute should appear as follows if you've
+chosen ``Sanity`` as your ``type``::
-- RedHatEnterpriseLinux3
-- RedHatEnterpriseLinux4
-- RedHatEnterpriseLinuxServer5
-- RedHatEnterpriseLinuxClient5
-- RedHatEnterpriseLinux6
-- RedHatEnterpriseLinux7
-- Fedora17
-
-Your Beaker administrator may have configured compatibility aliases for some OS
-versions, which you can also use in the ``Releases`` field. See
-:ref:`admin-os-versions` in the Administration Guide.
+ Type: Sanity
diff --git a/documentation/user-guide/tasks.rst b/documentation/user-guide/tasks.rst
index dca5374..ae030bc 100644
--- a/documentation/user-guide/tasks.rst
+++ b/documentation/user-guide/tasks.rst
@@ -6,15 +6,28 @@ Tasks
Task searching
~~~~~~~~~~~~~~
-To search for a task, select :menuselection:`Scheduler --> Task Library` from
+To search for a task, select :menuselection:`Scheduler --> Task Library` from
the menu. The default search is on the "Name" property, with the "contains"
-operator. See :ref:`system-searching` for
-further details.
+operator. Other metadata search attributes are as follows:
+
+- *Description*
+ - This is the description provided when creating the task.
+- *Version*
+ - This is the version of the task.
+- *Excluded OSMajor*
+ - This searches the Excluded OSMajor list of the task.
+- *Excluded Architecture*
+ - This searches the Excluded Architecures list of the task.
+- *Test Type*
+ - This is the type of test when task was defined.
+
+Refer to :ref:`task_metadata` for further details on metadata
+attributes.
Once you've found a particular task, you can see its details by clicking
on the link in the :guilabel:`Name` column.
-On the task page you can use the :guilabel:`Executed Tasks` search to search
+On the task page you can use the :guilabel:`Executed Tasks` search to search
history of past executions of the task.
.. _adding-tasks:
@@ -22,14 +35,18 @@ history of past executions of the task.
Uploading a task
~~~~~~~~~~~~~~~~
-If you already have a task packaged as an RPM, select :menuselection:`Scheduler
+If you already have a task packaged as an RPM, select :menuselection:`Scheduler
--> New Task` from the menu. Click the :guilabel:`Browse` button to
-locate the task RPM on your local system, and then click the :guilabel:`Submit
-Data` button to upload it. See :ref:`bkr task-add <bkr-task-add>` for how to do
+locate the task RPM on your local system, and then click the :guilabel:`Submit
+Data` button to upload it. See :ref:`bkr task-add <bkr-task-add>` for how to do
this via the beaker client.
-If you are updating an existing task, the version of the new task RPM must be
-higher than the existing version. This can be achieved by running ``make tag``
-(if the task is stored in version control), or manually adjusting the
-``TESTVERSION`` variable in the task's ``Makefile`` (see
+If you are updating an existing task, the version of the new task RPM must be
+higher than the existing version. This can be achieved by running ``make tag``
+(if the task is stored in version control), or manually adjusting the
+``TESTVERSION`` variable in the task's ``Makefile`` (see
:ref:`makefile-variables`).
+
+If you are uploading a new task, the rpm must contain a testinfo.desc file
+which contains all the mandatory fields described in the metadata section
+(see :ref:`testinfo.desc`).
diff --git a/documentation/whats-new/release-26.rst b/documentation/whats-new/release-26.rst
index 6f112f3..92a93d2 100644
--- a/documentation/whats-new/release-26.rst
+++ b/documentation/whats-new/release-26.rst
@@ -249,3 +249,52 @@ Beaker 26.4
* | :issue:`1689926`: Updated :program:`restraint` BJJ to use static build
from fetched tarballs.
| (Contributed by Martin Styk)
+
+.. internal workflow so it is not published in the release notes:
+ :issue:`1666204`, `1678595`
+
+
+Beaker 26.5
+~~~~~~~~~~~
+* | :issue:`1697479`: Fixed a regression in :program:`anamon` which caused
+ extensive writing to logs.
+ | (Contributed by Martin Styk)
+* | :issue:`1695029`: Previously, Beaker used program:`yum` in generated
+ kickstarts. Now, Beaker uses :program:`dnf` when it is available in OS
+ distribution.
+ | (Contributed by Martin Styk)
+* | :issue:`1043419`: Job Matrix no longer failing with code 500 Internal Error
+ when Job ID field contains non-integer chars.
+ | (Contributed by Tomas Klohna)
+* | :issue:`1175584`: Removed ability to store duplicate SSH key in Web UI.
+ | (Contributed by Tomas Klohna)
+* | :issue:`1672048`: Added MODULE key to Key/Value search in Web UI.
+ | (Contributed by Tomas Klohna)
+* | :issue:`1229802`: Added Notes column to search in Web UI.
+ | (Contributed by Tomas Klohna)
+* | :issue:`1414669`: Beaker client now allows to filter by group in job-list
+ command.
+ | (Contributed by Tomas Klohna)
+* | :issue:`1362048`: Task names are fully visible and no longer cropped in Web
+ UI.
+ | (Contributed by Tomas Klohna)
+* | :issue:`1597923`: Beaker client now supports JSON output for system-details
+ command.
+ | (Contributed by Carol Bouchard)
+* | :issue:`1688877`: Provisioning system through Reserve System no longer creates
+ Job with an empty whiteboard by default.
+ | (Contributed by Carol Bouchard)
+* | :issue:`1409676`: Added support for :program:`product-update` script to send
+ Accept header in HTTP requests.
+ | (Contributed by Tomas Klohna)
+* | :issue:`1384491`: Previously, Beaker Lab Controller (LC) daemons couldn't
+ start due to issue in python-gevent package on RHEL 7. Beaker now uses
+ python-gevent package which is not causing any issues in LC daemons.
+ | (Contributed by Martin Styk)
+* | :issue:`1686147`: Updated documentation for Job XML definition.
+ | (Contributed by Carol Bouchard)
+* | :issue:`1654848`: Extended OpenStack support.
+ | (Contributed by Chris Beer)
+
+.. internal workflow so it is not published in the release notes:
+ :issue:`1707057`, `1693758` \ No newline at end of file