Merge "Fix server creation n test_large_ops"
diff --git a/.testr.conf b/.testr.conf
index 4f6e0b3..95a4fb4 100644
--- a/.testr.conf
+++ b/.testr.conf
@@ -3,7 +3,7 @@
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-500} \
OS_TEST_LOCK_PATH=${OS_TEST_LOCK_PATH:-${TMPDIR:-'/tmp'}} \
- ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./tempest/test_discover} $LISTOPT $IDOPTION
+ ${PYTHON:-python} -m subunit.run discover -t ${OS_TOP_LEVEL:-./} ${OS_TEST_PATH:-./tempest/test_discover} $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list
group_regex=([^\.]*\.)*
diff --git a/README.rst b/README.rst
index ba93712..af24569 100644
--- a/README.rst
+++ b/README.rst
@@ -18,7 +18,7 @@
incorrect assessment of their cloud. Explicit is always better.
- Tempest uses OpenStack public interfaces. Tests in Tempest should
only touch public interfaces, API calls (native or 3rd party),
- public CLI or libraries.
+ or libraries.
- Tempest should not touch private or implementation specific
interfaces. This means not directly going to the database, not
directly hitting the hypervisors, not testing extensions not
@@ -117,8 +117,8 @@
Tempest suite.
Alternatively, you can use the run_tests.sh script which will create a venv and
-run the unit tests. There are also the py26, py27, or py33 tox jobs which will
-run the unit tests with the corresponding version of python.
+run the unit tests. There are also the py27 and py34 tox jobs which will run
+the unit tests with the corresponding version of python.
Python 2.6
----------
@@ -131,3 +131,16 @@
on an earlier release with python 2.6 you can easily run Tempest against it
from a remote system running python 2.7. (or deploy a cloud guest in your cloud
that has python 2.7)
+
+Python 3.4
+----------
+
+Starting during the Liberty release development cycle work began on enabling
+Tempest to run under both Python 2.7 and Python 3.4. Tempest strives to fully
+support running with Python 3.4. A gating unit test job was added to also run
+Tempest's unit tests under Python 3.4. This means that the Tempest code at
+least imports under Python 3.4 and things that have unit test coverage will
+work on Python 3.4. However, because large parts of Tempest are self verifying
+there might be uncaught issues running on Python 3.4. So until there is a gating
+job which does a full Tempest run using Python 3.4 there isn't any guarantee
+that running Tempest under Python 3.4 is bug free.
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index b6e00ce..eab7487 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -115,6 +115,8 @@
#. Provide tempest with the location of you accounts.yaml file with the
test_accounts_file option in the auth section
+ #. Set allow_tenant_isolation = False in the auth group
+
It is worth pointing out that each set of credentials in the accounts.yaml
should have a unique tenant. This is required to provide proper isolation
to the tests using the credentials, and failure to do this will likely cause
@@ -140,6 +142,11 @@
#. alt_password
#. alt_tenant_name
+And in the auth secion:
+
+ #. allow_tenant_isolation = False
+ #. comment out 'test_accounts_file' or keep it as empty
+
It only makes sense to use it if parallel execution isn't needed, since tempest
won't be able to properly isolate tests using this. Additionally, using the
traditional config options for credentials is not able to provide credentials to
@@ -303,6 +310,12 @@
will additionally be used as a fallback for server creation. However, unlike
accounts.yaml this should never be triggered.
+However, there is an option *create_isolated_networks* to disable tenant
+isolation's automatic provisioning of network resources. If this option is
+used you will have to either rely on there only being a single/default network
+available for the server creation, or use *fixed_network_name* to inform
+Tempest which network to use.
+
Configuring Available Services
------------------------------
OpenStack is really a constellation of several different projects which
diff --git a/doc/source/field_guide/cli.rst b/doc/source/field_guide/cli.rst
deleted file mode 120000
index 13caef5..0000000
--- a/doc/source/field_guide/cli.rst
+++ /dev/null
@@ -1 +0,0 @@
-../../../tempest/cli/README.rst
\ No newline at end of file
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 2a72635..b3aca42 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -40,14 +40,16 @@
#log_dir = <None>
# Use syslog for logging. Existing syslog format is DEPRECATED during
-# I, and will change in J to honor RFC5424. (boolean value)
+# I, and changed in J to honor RFC5424. (boolean value)
#use_syslog = false
# (Optional) Enables or disables syslog rfc5424 format for logging. If
# enabled, prefixes the MSG part of the syslog message with APP-NAME
-# (RFC5424). The format without the APP-NAME is deprecated in I, and
-# will be removed in J. (boolean value)
-#use_syslog_rfc_format = false
+# (RFC5424). The format without the APP-NAME is deprecated in K, and
+# will be removed in M, along with this option. (boolean value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+#use_syslog_rfc_format = true
# Syslog facility to receive log lines. (string value)
#syslog_log_facility = LOG_USER
@@ -67,7 +69,7 @@
# Prefix each line of exception output with this format. (string
# value)
-#logging_exception_prefix = %(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s
+#logging_exception_prefix = %(asctime)s.%(msecs)03d %(process)d ERROR %(name)s %(instance)s
# List of logger=LEVEL pairs. (list value)
#default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN
@@ -86,6 +88,9 @@
# (string value)
#instance_uuid_format = "[instance: %(uuid)s] "
+# Enables or disables fatal status of deprecations. (boolean value)
+#fatal_deprecations = false
+
[auth]
@@ -117,6 +122,14 @@
# the domain from theadmin user is used instead. (string value)
#tenant_isolation_domain_name = <None>
+# If allow_tenant_isolation is set to True and Neutron is enabled
+# Tempest will try to create a useable network, subnet, and router
+# when needed for each tenant it creates. However in some neutron
+# configurations, like with VLAN provider networks, this doesn't work.
+# So if set to False the isolated networks will not be created
+# (boolean value)
+#create_isolated_networks = true
+
[baremetal]
@@ -201,27 +214,6 @@
#build_interval = 1
-[cli]
-
-#
-# From tempest.config
-#
-
-# enable cli tests (boolean value)
-#enabled = true
-
-# directory where python client binaries are located (string value)
-#cli_dir = /usr/local/bin
-
-# Whether the tempest run location has access to the *-manage
-# commands. In a pure blackbox environment it will not. (boolean
-# value)
-#has_manage = true
-
-# Number of seconds to wait on a CLI timeout (integer value)
-#timeout = 15
-
-
[compute]
#
@@ -261,9 +253,6 @@
# value)
#build_timeout = 300
-# Should the tests ssh to instances? (boolean value)
-#run_ssh = false
-
# Auth method used for authenticate to the instance. Valid choices
# are: keypair, configured, adminpass and disabled. Keypair: start the
# servers with a ssh keypair. Configured: use the configured user and
@@ -310,7 +299,7 @@
#fixed_network_name = <None>
# Network used for SSH connections. Ignored if
-# use_floatingip_for_ssh=true or run_ssh=false. (string value)
+# use_floatingip_for_ssh=true or run_validation=false. (string value)
#network_for_ssh = public
# IP version used for SSH connections. (integer value)
@@ -396,6 +385,11 @@
# https://bugs.launchpad.net/nova/+bug/1398999 (boolean value)
#block_migrate_cinder_iscsi = false
+# Does the test system allow live-migration of paused instances? Note,
+# this is more than just the ANDing of paused and live_migrate, but
+# all 3 should be set to True to run those tests (boolean value)
+#live_migrate_paused_instances = false
+
# Enable VNC console. This configuration value should be same as
# [nova.vnc]->vnc_enabled in nova.conf (boolean value)
#vnc_console = false
@@ -590,6 +584,9 @@
# applies to user and project (string value)
#admin_domain_name = <None>
+# ID of the default domain (string value)
+#default_domain_id = default
+
[identity-feature-enabled]
@@ -954,6 +951,10 @@
# Image container format (string value)
#img_container_format = bare
+# Glance image properties. Use for custom images which require them
+# (dict value)
+#img_properties = <None>
+
# AMI image file name (string value)
#ami_img_file = cirros-0.3.1-x86_64-blank.img
@@ -1087,6 +1088,11 @@
# From tempest.config
#
+# Enable ssh on created servers and creation of additional validation
+# resources to enable remote access (boolean value)
+# Deprecated group/name - [compute]/run_ssh
+#run_validation = false
+
# Default IP type used for validation: -fixed: uses the first IP
# belonging to the fixed network -floating: creates and uses a
# floating IP (string value)
@@ -1185,3 +1191,7 @@
# Is the v2 volume API enabled (boolean value)
#api_v2 = true
+
+# Update bootable status of a volume Not implemented on icehouse
+# (boolean value)
+#bootable = false
diff --git a/requirements.txt b/requirements.txt
index 174c7c8..7fe8858 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
-pbr>=0.6,!=0.7,<1.0
+pbr>=0.11,<2.0
anyjson>=0.3.3
httplib2>=0.7.5
jsonschema>=2.0.0,<3.0.0
@@ -9,18 +9,17 @@
boto>=2.32.1
paramiko>=1.13.0
netaddr>=0.7.12
-python-glanceclient>=0.15.0
-python-cinderclient>=1.1.0
-python-heatclient>=0.3.0
testrepository>=0.0.18
-oslo.concurrency>=1.8.0,<1.9.0 # Apache-2.0
-oslo.config>=1.9.3,<1.10.0 # Apache-2.0
-oslo.i18n>=1.5.0,<1.6.0 # Apache-2.0
-oslo.log>=1.0.0,<1.1.0 # Apache-2.0
-oslo.serialization>=1.4.0,<1.5.0 # Apache-2.0
-oslo.utils>=1.4.0,<1.5.0 # Apache-2.0
+pyOpenSSL>=0.11
+oslo.concurrency>=1.8.0 # Apache-2.0
+oslo.config>=1.11.0 # Apache-2.0
+oslo.i18n>=1.5.0 # Apache-2.0
+oslo.log>=1.0.0 # Apache-2.0
+oslo.serialization>=1.4.0 # Apache-2.0
+oslo.utils>=1.4.0 # Apache-2.0
six>=1.9.0
iso8601>=0.1.9
fixtures>=0.3.14
testscenarios>=0.4
tempest-lib>=0.5.0
+PyYAML>=3.1.0
diff --git a/setup.cfg b/setup.cfg
index 2de9f34..3a14bba 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -15,6 +15,8 @@
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
+ Programming Language :: Python :: 3
+ Programming Language :: Python :: 3.4
[entry_points]
console_scripts =
@@ -22,6 +24,7 @@
javelin2 = tempest.cmd.javelin:main
run-tempest-stress = tempest.cmd.run_stress:main
tempest-cleanup = tempest.cmd.cleanup:main
+ tempest-account-generator = tempest.cmd.account_generator:main
oslo.config.opts =
tempest.config = tempest.config:list_opts
diff --git a/tempest/README.rst b/tempest/README.rst
index d28c3f9..fec2874 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -14,7 +14,6 @@
| tempest/
| api/ - API tests
-| cli/ - CLI tests
| scenario/ - complex scenario tests
| stress/ - stress tests
| thirdparty/ - 3rd party api tests
@@ -38,16 +37,6 @@
frameworks.
-:ref:`cli_field_guide`
-----------------------
-
-CLI tests use the openstack CLI to interact with the OpenStack
-cloud. CLI testing in unit tests is somewhat difficult because unlike
-server testing, there is no access to server code to
-instantiate. Tempest seems like a logical place for this, as it
-prereqs having a running OpenStack cloud.
-
-
:ref:`scenario_field_guide`
---------------------------
diff --git a/tempest/api/baremetal/admin/test_chassis.py b/tempest/api/baremetal/admin/test_chassis.py
index e9068f3..5ad05cc 100644
--- a/tempest/api/baremetal/admin/test_chassis.py
+++ b/tempest/api/baremetal/admin/test_chassis.py
@@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -28,7 +29,7 @@
def _assertExpected(self, expected, actual):
# Check if not expected keys/values exists in actual response body
- for key, value in expected.iteritems():
+ for key, value in six.iteritems(expected):
if key not in ('created_at', 'updated_at'):
self.assertIn(key, actual)
self.assertEqual(value, actual[key])
diff --git a/tempest/api/baremetal/admin/test_ports.py b/tempest/api/baremetal/admin/test_ports.py
index ee6bb9c..ece4471 100644
--- a/tempest/api/baremetal/admin/test_ports.py
+++ b/tempest/api/baremetal/admin/test_ports.py
@@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import decorators
from tempest_lib import exceptions as lib_exc
@@ -31,7 +32,7 @@
def _assertExpected(self, expected, actual):
# Check if not expected keys/values exists in actual response body
- for key, value in expected.iteritems():
+ for key, value in six.iteritems(expected):
if key not in ('created_at', 'updated_at'):
self.assertIn(key, actual)
self.assertEqual(value, actual[key])
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log.py b/tempest/api/compute/admin/test_instance_usage_audit_log.py
index 6634290..9da7901 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log.py
@@ -14,7 +14,8 @@
# under the License.
import datetime
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api.compute import base
from tempest import test
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
index ec9ad19..97d665b 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
@@ -14,8 +14,8 @@
# under the License.
import datetime
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api.compute import base
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 8a92326..d3b1f5e 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -84,10 +84,15 @@
self.volumes_client.wait_for_volume_status(volume_id, 'available')
self.volumes_client.delete_volume(volume_id)
- @test.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b')
- @testtools.skipIf(not CONF.compute_feature_enabled.live_migration,
- 'Live migration not available')
- def test_live_block_migration(self):
+ def _test_live_block_migration(self, state='ACTIVE'):
+ """Tests live block migration between two hosts.
+
+ Requires CONF.compute_feature_enabled.live_migration to be True.
+
+ :param state: The vm_state the migrated server should be in before and
+ after the live migration. Supported values are 'ACTIVE'
+ and 'PAUSED'.
+ """
# Live block migrate an instance to another host
if len(self._get_compute_hostnames()) < 2:
raise self.skipTest(
@@ -95,10 +100,33 @@
server_id = self._get_an_active_server()
actual_host = self._get_host_for_server(server_id)
target_host = self._get_host_other_than(actual_host)
+
+ if state == 'PAUSED':
+ self.admin_servers_client.pause_server(server_id)
+ self.admin_servers_client.wait_for_server_status(server_id, state)
+
self._migrate_server_to(server_id, target_host)
- self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+ self.servers_client.wait_for_server_status(server_id, state)
self.assertEqual(target_host, self._get_host_for_server(server_id))
+ @test.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b')
+ @testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
+ 'Live migration not available')
+ def test_live_block_migration(self):
+ self._test_live_block_migration()
+
+ @test.idempotent_id('1e107f21-61b2-4988-8f22-b196e938ab88')
+ @testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
+ 'Live migration not available')
+ @testtools.skipUnless(CONF.compute_feature_enabled.pause,
+ 'Pause is not available.')
+ @testtools.skipUnless(CONF.compute_feature_enabled
+ .live_migrate_paused_instances,
+ 'Live migration of paused instances is not '
+ 'available.')
+ def test_live_block_migration_paused(self):
+ self._test_live_block_migration(state='PAUSED')
+
@test.idempotent_id('e19c0cc6-6720-4ed8-be83-b6603ed5c812')
@testtools.skipIf(not CONF.compute_feature_enabled.live_migration or not
CONF.compute_feature_enabled.
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index eca634d..9aacfa5 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -52,7 +52,6 @@
def setup_credentials(cls):
cls.set_network_resources()
super(BaseComputeTest, cls).setup_credentials()
- cls.multi_user = cls.check_multi_user()
@classmethod
def setup_clients(cls):
@@ -112,14 +111,6 @@
super(BaseComputeTest, cls).resource_cleanup()
@classmethod
- def check_multi_user(cls):
- # We have a list of accounts now, so just checking if the list is gt 2
- if not cls.isolated_creds.is_multi_user():
- msg = "Not enough users available for multi-user testing"
- raise exceptions.InvalidConfiguration(msg)
- return True
-
- @classmethod
def clear_servers(cls):
LOG.debug('Clearing servers: %s', ','.join(
server['id'] for server in cls.servers))
@@ -312,7 +303,7 @@
if 'wait_until' in kwargs:
cls.images_client.wait_for_image_status(image_id,
kwargs['wait_until'])
- image = cls.images_client.get_image(image_id)
+ image = cls.images_client.show_image(image_id)
if kwargs['wait_until'] == 'ACTIVE':
if kwargs.get('wait_for_server', True):
@@ -334,6 +325,15 @@
return server['id']
@classmethod
+ def delete_server(cls, server_id):
+ """Deletes an existing server and waits for it to be gone."""
+ try:
+ cls.servers_client.delete_server(server_id)
+ cls.servers_client.wait_for_server_termination(server_id)
+ except Exception:
+ LOG.exception('Failed to delete server %s' % server_id)
+
+ @classmethod
def delete_volume(cls, volume_id):
"""Deletes the given volume and waits for it to be gone."""
cls._delete_volume(cls.volumes_extensions_client, volume_id)
diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py
index 6555b64..54a82e9 100644
--- a/tempest/api/compute/images/test_images_negative.py
+++ b/tempest/api/compute/images/test_images_negative.py
@@ -108,7 +108,7 @@
def test_delete_image_with_invalid_image_id(self):
# An image should not be deleted with invalid image id
self.assertRaises(lib_exc.NotFound, self.client.delete_image,
- '!@$%^&*()')
+ '!@$^&*()')
@test.attr(type=['negative'])
@test.idempotent_id('137aef61-39f7-44a1-8ddf-0adf82511701')
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index a92048f..3771a43 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -84,11 +84,11 @@
self.client.wait_for_image_status(image_id, 'ACTIVE')
# Verify the image was created correctly
- image = self.client.get_image(image_id)
+ image = self.client.show_image(image_id)
self.assertEqual(name, image['name'])
self.assertEqual('test', image['metadata']['image_type'])
- original_image = self.client.get_image(self.image_ref)
+ original_image = self.client.show_image(self.image_ref)
# Verify minRAM is the same as the original image
self.assertEqual(image['minRam'], original_image['minRam'])
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index aa12044..8a39d90 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -140,4 +140,4 @@
self.client.delete_image(image_id)
self.image_ids.remove(image_id)
- self.assertRaises(lib_exc.NotFound, self.client.get_image, image_id)
+ self.assertRaises(lib_exc.NotFound, self.client.show_image, image_id)
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index abe7be5..e2d4bd9 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -62,7 +62,7 @@
image_file = six.StringIO(('*' * 1024))
cls.glance_client.update_image(image_id, data=image_file)
cls.client.wait_for_image_status(image_id, 'ACTIVE')
- body = cls.client.get_image(image_id)
+ body = cls.client.show_image(image_id)
return body
# Create non-snapshot images via glance
@@ -249,7 +249,7 @@
# The detailed list of servers should be filtered by image type
params = {'type': 'snapshot'}
images = self.client.list_images_with_detail(params)
- self.client.get_image(self.image_ref)
+ self.client.show_image(self.image_ref)
self.assertTrue(any([i for i in images
if i['id'] == self.snapshot1_id]))
diff --git a/tempest/api/compute/images/test_list_image_filters_negative.py b/tempest/api/compute/images/test_list_image_filters_negative.py
index 334516b..4110619 100644
--- a/tempest/api/compute/images/test_list_image_filters_negative.py
+++ b/tempest/api/compute/images/test_list_image_filters_negative.py
@@ -41,5 +41,5 @@
def test_get_nonexistent_image(self):
# Check raises a NotFound
nonexistent_image = data_utils.rand_uuid()
- self.assertRaises(lib_exc.NotFound, self.client.get_image,
+ self.assertRaises(lib_exc.NotFound, self.client.show_image,
nonexistent_image)
diff --git a/tempest/api/compute/images/test_list_images.py b/tempest/api/compute/images/test_list_images.py
index 95f49c9..5b80c72 100644
--- a/tempest/api/compute/images/test_list_images.py
+++ b/tempest/api/compute/images/test_list_images.py
@@ -37,7 +37,7 @@
@test.idempotent_id('490d0898-e12a-463f-aef0-c50156b9f789')
def test_get_image(self):
# Returns the correct details for a single image
- image = self.client.get_image(self.image_ref)
+ image = self.client.show_image(self.image_ref)
self.assertEqual(self.image_ref, image['id'])
@test.idempotent_id('fd51b7f4-d4a3-4331-9885-866658112a6f')
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index c62ff89..9012d3d 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -43,6 +43,7 @@
@classmethod
def resource_setup(cls):
+ cls.set_validation_resources()
super(ServersTestJSON, cls).resource_setup()
cls.meta = {'hello': 'world'}
cls.accessIPv4 = '1.1.1.1'
@@ -94,7 +95,7 @@
self.assertTrue(found)
@test.idempotent_id('cbc0f52f-05aa-492b-bdc1-84b575ca294b')
- @testtools.skipUnless(CONF.compute.run_ssh,
+ @testtools.skipUnless(CONF.validation.run_validation,
'Instance validation tests are disabled.')
def test_verify_created_server_vcpus(self):
# Verify that the number of vcpus reported by the instance matches
@@ -105,7 +106,7 @@
self.assertEqual(flavor['vcpus'], linux_client.get_number_of_vcpus())
@test.idempotent_id('ac1ad47f-984b-4441-9274-c9079b7a0666')
- @testtools.skipUnless(CONF.compute.run_ssh,
+ @testtools.skipUnless(CONF.validation.run_validation,
'Instance validation tests are disabled.')
def test_host_name_is_same_as_server_name(self):
# Verify the instance host name is the same as the server name
@@ -205,7 +206,7 @@
cls.client = cls.servers_client
@test.idempotent_id('b3c7bcfc-bb5b-4e22-b517-c7f686b802ca')
- @testtools.skipUnless(CONF.compute.run_ssh,
+ @testtools.skipUnless(CONF.validation.run_validation,
'Instance validation tests are disabled.')
def test_verify_created_server_ephemeral_disk(self):
# Verify that the ephemeral disk is created when creating server
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 5374af0..d7607ab 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -56,13 +56,13 @@
# Do some sanity checks here. If one of the images does
# not exist, fail early since the tests won't work...
try:
- cls.images_client.get_image(cls.image_ref)
+ cls.images_client.show_image(cls.image_ref)
except lib_exc.NotFound:
raise RuntimeError("Image %s (image_ref) was not found!" %
cls.image_ref)
try:
- cls.images_client.get_image(cls.image_ref_alt)
+ cls.images_client.show_image(cls.image_ref_alt)
except lib_exc.NotFound:
raise RuntimeError("Image %s (image_ref_alt) was not found!" %
cls.image_ref_alt)
@@ -275,8 +275,14 @@
msg = 'fixed_network_name needs to be configured to run this test'
raise self.skipException(msg)
self.s1 = self.client.get_server(self.s1['id'])
- ip = self.s1['addresses'][self.fixed_network_name][0]['addr']
- params = {'ip': ip}
+ for addr_spec in self.s1['addresses'][self.fixed_network_name]:
+ ip = addr_spec['addr']
+ if addr_spec['version'] == 4:
+ params = {'ip': ip}
+ break
+ else:
+ msg = "Skipped until bug 1450859 is resolved"
+ raise self.skipException(msg)
body = self.client.list_servers(params)
servers = body['servers']
@@ -295,8 +301,12 @@
msg = 'fixed_network_name needs to be configured to run this test'
raise self.skipException(msg)
self.s1 = self.client.get_server(self.s1['id'])
- ip = self.s1['addresses'][self.fixed_network_name][0]['addr'][0:-3]
- params = {'ip': ip}
+ addr_spec = self.s1['addresses'][self.fixed_network_name][0]
+ ip = addr_spec['addr'][0:-3]
+ if addr_spec['version'] == 4:
+ params = {'ip': ip}
+ else:
+ params = {'ip6': ip}
body = self.client.list_servers(params)
servers = body['servers']
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index 0178c9e..fd4d902 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -21,7 +21,6 @@
class ListServersNegativeTestJSON(base.BaseV2ComputeTest):
- force_tenant_isolation = True
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/compute/servers/test_multiple_create.py b/tempest/api/compute/servers/test_multiple_create.py
index eed3be8..11b457b 100644
--- a/tempest/api/compute/servers/test_multiple_create.py
+++ b/tempest/api/compute/servers/test_multiple_create.py
@@ -30,7 +30,9 @@
This is the right way to create_multiple servers and manage to get the
created servers into the servers list to be cleaned up after all.
"""
- kwargs['name'] = kwargs.get('name', self._generate_name())
+ kwargs['name'] = name if name else self._generate_name()
+ if wait_until:
+ kwargs['wait_until'] = wait_until
body = self.create_test_server(**kwargs)
return body
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 3871db1..c2ed0ce 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -33,7 +33,7 @@
class ServerActionsTestJSON(base.BaseV2ComputeTest):
- run_ssh = CONF.compute.run_ssh
+ run_ssh = CONF.validation.run_validation
def setUp(self):
# NOTE(afazekas): Normally we use the same server with all test cases,
@@ -47,8 +47,6 @@
self.__class__.server_id = self.rebuild_server(self.server_id)
def tearDown(self):
- server = self.client.get_server(self.server_id)
- self.assertEqual(self.image_ref, server['image']['id'])
self.server_check_teardown()
super(ServerActionsTestJSON, self).tearDown()
@@ -110,6 +108,14 @@
# The server should be signaled to reboot gracefully
self._test_reboot_server('SOFT')
+ def _rebuild_server_and_check(self, image_ref):
+ rebuilt_server = self.client.rebuild(self.server_id, image_ref)
+ self.client.wait_for_server_status(self.server_id, 'ACTIVE')
+ msg = ('Server was not rebuilt to the original image. '
+ 'The original image: {0}. The current image: {1}'
+ .format(image_ref, rebuilt_server['image']['id']))
+ self.assertEqual(image_ref, rebuilt_server['image']['id'], msg)
+
@test.idempotent_id('aaa6cdf3-55a7-461a-add9-1c8596b9a07c')
def test_rebuild_server(self):
# The server should be rebuilt using the provided image and data
@@ -129,8 +135,7 @@
# If the server was rebuilt on a different image, restore it to the
# original image once the test ends
if self.image_ref_alt != self.image_ref:
- self.addCleanup(self.client.rebuild,
- (self.server_id, self.image_ref))
+ self.addCleanup(self._rebuild_server_and_check, self.image_ref)
# Verify the properties in the initial response are correct
self.assertEqual(self.server_id, rebuilt_server['id'])
@@ -157,11 +162,15 @@
# image and remain in SHUTOFF state
server = self.client.get_server(self.server_id)
old_image = server['image']['id']
- new_image = self.image_ref_alt \
- if old_image == self.image_ref else self.image_ref
+ new_image = (self.image_ref_alt
+ if old_image == self.image_ref else self.image_ref)
self.client.stop(self.server_id)
self.client.wait_for_server_status(self.server_id, 'SHUTOFF')
rebuilt_server = self.client.rebuild(self.server_id, new_image)
+ # If the server was rebuilt on a different image, restore it to the
+ # original image once the test ends
+ if self.image_ref_alt != self.image_ref:
+ self.addCleanup(self._rebuild_server_and_check, old_image)
# Verify the properties in the initial response are correct
self.assertEqual(self.server_id, rebuilt_server['id'])
@@ -175,33 +184,18 @@
rebuilt_image_id = server['image']['id']
self.assertEqual(new_image, rebuilt_image_id)
- # Restore to the original image (The tearDown will test it again)
- if self.image_ref_alt != self.image_ref:
- self.client.rebuild(self.server_id, old_image)
- self.client.wait_for_server_status(self.server_id, 'SHUTOFF')
self.client.start(self.server_id)
- def _detect_server_image_flavor(self, server_id):
- # Detects the current server image flavor ref.
- server = self.client.get_server(server_id)
- current_flavor = server['flavor']['id']
- new_flavor_ref = self.flavor_ref_alt \
- if current_flavor == self.flavor_ref else self.flavor_ref
- return current_flavor, new_flavor_ref
-
def _test_resize_server_confirm(self, stop=False):
# The server's RAM and disk space should be modified to that of
# the provided flavor
- previous_flavor_ref, new_flavor_ref = \
- self._detect_server_image_flavor(self.server_id)
-
if stop:
self.servers_client.stop(self.server_id)
self.servers_client.wait_for_server_status(self.server_id,
'SHUTOFF')
- self.client.resize(self.server_id, new_flavor_ref)
+ self.client.resize(self.server_id, self.flavor_ref_alt)
self.client.wait_for_server_status(self.server_id, 'VERIFY_RESIZE')
self.client.confirm_resize(self.server_id)
@@ -209,12 +203,16 @@
self.client.wait_for_server_status(self.server_id, expected_status)
server = self.client.get_server(self.server_id)
- self.assertEqual(new_flavor_ref, server['flavor']['id'])
+ self.assertEqual(self.flavor_ref_alt, server['flavor']['id'])
if stop:
# NOTE(mriedem): tearDown requires the server to be started.
self.client.start(self.server_id)
+ # NOTE(jlk): Explicitly delete the server to get a new one for later
+ # tests. Avoids resize down race issues.
+ self.addCleanup(self.delete_server, self.server_id)
+
@test.idempotent_id('1499262a-9328-4eda-9068-db1ac57498d2')
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
'Resize not available.')
@@ -234,17 +232,14 @@
# The server's RAM and disk space should return to its original
# values after a resize is reverted
- previous_flavor_ref, new_flavor_ref = \
- self._detect_server_image_flavor(self.server_id)
-
- self.client.resize(self.server_id, new_flavor_ref)
+ self.client.resize(self.server_id, self.flavor_ref_alt)
self.client.wait_for_server_status(self.server_id, 'VERIFY_RESIZE')
self.client.revert_resize(self.server_id)
self.client.wait_for_server_status(self.server_id, 'ACTIVE')
server = self.client.get_server(self.server_id)
- self.assertEqual(previous_flavor_ref, server['flavor']['id'])
+ self.assertEqual(self.flavor_ref, server['flavor']['id'])
@test.idempotent_id('b963d4f1-94b3-4c40-9e97-7b583f46e470')
@testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index d0dfc87..a17f581 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
+
from tempest.api.compute import base
from tempest import test
@@ -48,7 +50,7 @@
# We do not know the exact network configuration, but an instance
# should at least have a single public or private address
self.assertTrue(len(addresses) >= 1)
- for network_name, network_addresses in addresses.iteritems():
+ for network_name, network_addresses in six.iteritems(addresses):
self.assertTrue(len(network_addresses) >= 1)
for address in network_addresses:
self.assertTrue(address['addr'])
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index b333122..31078e3 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -64,6 +64,7 @@
key_name = data_utils.rand_name('key')
self.keypairs_client.create_keypair(key_name)
+ self.addCleanup(self.keypairs_client.delete_keypair, key_name)
self.keypairs_client.list_keypairs()
server = self.create_test_server(key_name=key_name)
self.client.wait_for_server_status(server['id'], 'ACTIVE')
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index 258ff1f..63b78a0 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -73,7 +73,7 @@
image_file = six.StringIO(('*' * 1024))
body = cls.glance_client.update_image(image_id, data=image_file)
cls.glance_client.wait_for_image_status(image_id, 'active')
- cls.image = cls.images_client.get_image(image_id)
+ cls.image = cls.images_client.show_image(image_id)
cls.keypairname = data_utils.rand_name('keypair')
cls.keypairs_client.create_keypair(cls.keypairname)
@@ -92,9 +92,11 @@
@classmethod
def resource_cleanup(cls):
- if cls.multi_user:
+ if hasattr(cls, 'image'):
cls.images_client.delete_image(cls.image['id'])
+ if hasattr(cls, 'keypairname'):
cls.keypairs_client.delete_keypair(cls.keypairname)
+ if hasattr(cls, 'security_group'):
cls.security_client.delete_security_group(cls.security_group['id'])
super(AuthorizationTestJSON, cls).resource_cleanup()
@@ -231,7 +233,7 @@
def test_get_image_for_alt_account_fails(self):
# A GET request for an image on another user's account should fail
self.assertRaises(lib_exc.NotFound,
- self.alt_images_client.get_image, self.image['id'])
+ self.alt_images_client.show_image, self.image['id'])
@test.idempotent_id('9facb962-f043-4a9d-b9ee-166a32dea098')
def test_delete_image_for_alt_account_fails(self):
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 7f345ae..580fb84 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -85,7 +85,8 @@
self.addCleanup(self._detach, self.server['id'], self.volume['id'])
@test.idempotent_id('52e9045a-e90d-4c0d-9087-79d657faffff')
- @testtools.skipUnless(CONF.compute.run_ssh, 'SSH required for this test')
+ @testtools.skipUnless(CONF.validation.run_validation,
+ 'SSH required for this test')
def test_attach_detach_volume(self):
# Stop and Start a server with an attached volume, ensuring that
# the volume remains attached.
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index 79943bb..b775e91 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -13,10 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.api.identity import base
+from tempest import config
+from tempest import test
+
from tempest_lib.common.utils import data_utils
-from tempest.api.identity import base
-from tempest import test
+CONF = config.CONF
class DomainsTestJSON(base.BaseIdentityV3AdminTest):
@@ -105,3 +108,18 @@
expected_data = {'name': d_name, 'enabled': True}
self.assertIsNone(domain['description'])
self.assertDictContainsSubset(expected_data, domain)
+
+
+class DefaultDomainTestJSON(base.BaseIdentityV3AdminTest):
+
+ @classmethod
+ def resource_setup(cls):
+ cls.domain_id = CONF.identity.default_domain_id
+ super(DefaultDomainTestJSON, cls).resource_setup()
+
+ @test.attr(type='smoke')
+ @test.idempotent_id('17a5de24-e6a0-4e4a-a9ee-d85b6e5612b5')
+ def test_default_domain_exists(self):
+ domain = self.client.get_domain(self.domain_id)
+
+ self.assertTrue(domain['enabled'])
diff --git a/tempest/api/identity/admin/v3/test_domains_negative.py b/tempest/api/identity/admin/v3/test_domains_negative.py
new file mode 100644
index 0000000..e2f3ef5
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_domains_negative.py
@@ -0,0 +1,38 @@
+# Copyright 2015 Red Hat Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.identity import base
+from tempest import test
+
+from tempest_lib.common.utils import data_utils
+from tempest_lib import exceptions as lib_exc
+
+
+class DomainsNegativeTestJSON(base.BaseIdentityV3AdminTest):
+ _interface = 'json'
+
+ @test.attr(type=['negative', 'gate'])
+ @test.idempotent_id('1f3fbff5-4e44-400d-9ca1-d953f05f609b')
+ def test_delete_active_domain(self):
+ d_name = data_utils.rand_name('domain')
+ d_desc = data_utils.rand_name('domain-desc')
+ domain = self.client.create_domain(d_name, description=d_desc)
+ domain_id = domain['id']
+
+ self.addCleanup(self.delete_domain, domain_id)
+
+ # domain need to be disabled before deleting
+ self.assertRaises(lib_exc.Forbidden, self.client.delete_domain,
+ domain_id)
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 5d66b9c..913e807 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -66,16 +66,9 @@
credentials = ['primary']
- @classmethod
- def setup_credentials(cls):
- super(BaseIdentityV2Test, cls).setup_credentials()
- cls.os = cls.get_client_manager(identity_version='v2')
-
- @classmethod
- def skip_checks(cls):
- super(BaseIdentityV2Test, cls).skip_checks()
- if not CONF.identity_feature_enabled.api_v2:
- raise cls.skipException("Identity api v2 is not enabled")
+ # identity v2 tests should obtain tokens and create accounts via v2
+ # regardless of the configured CONF.identity.auth_version
+ identity_version = 'v2'
@classmethod
def setup_clients(cls):
@@ -94,7 +87,7 @@
class BaseIdentityV2AdminTest(BaseIdentityV2Test):
- credentials = ['admin']
+ credentials = ['primary', 'admin']
@classmethod
def setup_clients(cls):
@@ -117,16 +110,9 @@
credentials = ['primary']
- @classmethod
- def setup_credentials(cls):
- super(BaseIdentityV3Test, cls).setup_credentials()
- cls.os = cls.get_client_manager(identity_version='v3')
-
- @classmethod
- def skip_checks(cls):
- super(BaseIdentityV3Test, cls).skip_checks()
- if not CONF.identity_feature_enabled.api_v3:
- raise cls.skipException("Identity api v3 is not enabled")
+ # identity v3 tests should obtain tokens and create accounts via v3
+ # regardless of the configured CONF.identity.auth_version
+ identity_version = 'v3'
@classmethod
def setup_clients(cls):
@@ -146,7 +132,7 @@
class BaseIdentityV3AdminTest(BaseIdentityV3Test):
- credentials = ['admin']
+ credentials = ['primary', 'admin']
@classmethod
def setup_clients(cls):
@@ -186,6 +172,12 @@
if len(role) > 0:
return role[0]
+ def delete_domain(self, domain_id):
+ # NOTE(mpavlase) It is necessary to disable the domain before deleting
+ # otherwise it raises Forbidden exception
+ self.client.update_domain(domain_id, enabled=False)
+ self.client.delete_domain(domain_id)
+
class DataGenerator(object):
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index acf8272..00959d9 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -146,7 +146,7 @@
cls.alt_tenant_id = cls.alt_img_client.tenant_id
def _list_image_ids_as_alt(self):
- image_list = self.alt_img_client.image_list()
+ image_list = self.alt_img_client.list_images()
image_ids = map(lambda x: x['id'], image_list)
return image_ids
diff --git a/tempest/api/image/v1/test_image_members.py b/tempest/api/image/v1/test_image_members.py
index d57cb93..4969858 100644
--- a/tempest/api/image/v1/test_image_members.py
+++ b/tempest/api/image/v1/test_image_members.py
@@ -23,12 +23,12 @@
def test_add_image_member(self):
image = self._create_image()
self.client.add_member(self.alt_tenant_id, image)
- body = self.client.get_image_membership(image)
+ body = self.client.list_image_members(image)
members = body['members']
members = map(lambda x: x['member_id'], members)
self.assertIn(self.alt_tenant_id, members)
# get image as alt user
- self.alt_img_cli.get_image(image)
+ self.alt_img_cli.show_image(image)
@test.idempotent_id('6a5328a5-80e8-4b82-bd32-6c061f128da9')
def test_get_shared_images(self):
@@ -47,6 +47,6 @@
image_id = self._create_image()
self.client.add_member(self.alt_tenant_id, image_id)
self.client.delete_member(self.alt_tenant_id, image_id)
- body = self.client.get_image_membership(image_id)
+ body = self.client.list_image_members(image_id)
members = body['members']
self.assertEqual(0, len(members), str(members))
diff --git a/tempest/api/image/v1/test_image_members_negative.py b/tempest/api/image/v1/test_image_members_negative.py
index b96cf71..df0e88a 100644
--- a/tempest/api/image/v1/test_image_members_negative.py
+++ b/tempest/api/image/v1/test_image_members_negative.py
@@ -52,5 +52,5 @@
# Image is hidden from another tenants.
image_id = self._create_image()
self.assertRaises(lib_exc.NotFound,
- self.alt_img_cli.get_image,
+ self.alt_img_cli.show_image,
image_id)
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index ea95059..6c25c93 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -77,7 +77,7 @@
self.assertEqual('New Http Image', body.get('name'))
self.assertFalse(body.get('is_public'))
self.client.wait_for_image_status(image_id, 'active')
- self.client.get_image(image_id)
+ self.client.show_image(image_id)
@test.idempotent_id('05b19d55-140c-40d0-b36b-fafd774d421b')
def test_register_image_with_min_ram(self):
@@ -168,14 +168,14 @@
@test.idempotent_id('246178ab-3b33-4212-9a4b-a7fe8261794d')
def test_index_no_params(self):
# Simple test to see all fixture images returned
- images_list = self.client.image_list()
+ images_list = self.client.list_images()
image_list = map(lambda x: x['id'], images_list)
for image_id in self.created_images:
self.assertIn(image_id, image_list)
@test.idempotent_id('f1755589-63d6-4468-b098-589820eb4031')
def test_index_disk_format(self):
- images_list = self.client.image_list(disk_format='ami')
+ images_list = self.client.list_images(disk_format='ami')
for image in images_list:
self.assertEqual(image['disk_format'], 'ami')
result_set = set(map(lambda x: x['id'], images_list))
@@ -184,7 +184,7 @@
@test.idempotent_id('2143655d-96d9-4bec-9188-8674206b4b3b')
def test_index_container_format(self):
- images_list = self.client.image_list(container_format='bare')
+ images_list = self.client.list_images(container_format='bare')
for image in images_list:
self.assertEqual(image['container_format'], 'bare')
result_set = set(map(lambda x: x['id'], images_list))
@@ -193,7 +193,7 @@
@test.idempotent_id('feb32ac6-22bb-4a16-afd8-9454bb714b14')
def test_index_max_size(self):
- images_list = self.client.image_list(size_max=42)
+ images_list = self.client.list_images(size_max=42)
for image in images_list:
self.assertTrue(image['size'] <= 42)
result_set = set(map(lambda x: x['id'], images_list))
@@ -202,7 +202,7 @@
@test.idempotent_id('6ffc16d0-4cbf-4401-95c8-4ac63eac34d8')
def test_index_min_size(self):
- images_list = self.client.image_list(size_min=142)
+ images_list = self.client.list_images(size_min=142)
for image in images_list:
self.assertTrue(image['size'] >= 142)
result_set = set(map(lambda x: x['id'], images_list))
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 32f80a2..8cccddd 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -59,7 +59,7 @@
self.client.store_image(image_id, image_file)
# Now try to get image details
- body = self.client.get_image(image_id)
+ body = self.client.show_image(image_id)
self.assertEqual(image_id, body['id'])
self.assertEqual(image_name, body['name'])
self.assertEqual(uuid, body['ramdisk_id'])
@@ -88,7 +88,7 @@
self.client.wait_for_resource_deletion(image_id)
# Verifying deletion
- images = self.client.image_list()
+ images = self.client.list_images()
images_id = [item['id'] for item in images]
self.assertNotIn(image_id, images_id)
@@ -118,7 +118,7 @@
# Verifying updating
- body = self.client.get_image(image_id)
+ body = self.client.show_image(image_id)
self.assertEqual(image_id, body['id'])
self.assertEqual(new_image_name, body['name'])
@@ -164,7 +164,7 @@
"""
Perform list action with given params and validates result.
"""
- images_list = self.client.image_list(params=params)
+ images_list = self.client.list_images(params=params)
# Validating params of fetched images
for image in images_list:
for key in params:
@@ -174,7 +174,7 @@
@test.idempotent_id('1e341d7a-90a9-494c-b143-2cdf2aeb6aee')
def test_index_no_params(self):
# Simple test to see all fixture images returned
- images_list = self.client.image_list()
+ images_list = self.client.list_images()
image_list = map(lambda x: x['id'], images_list)
for image in self.created_images:
@@ -203,7 +203,7 @@
# Test to get all images by size
image_id = self.created_images[1]
# Get image metadata
- image = self.client.get_image(image_id)
+ image = self.client.show_image(image_id)
params = {"size": image['size']}
self._list_by_param_value_and_assert(params)
@@ -213,11 +213,11 @@
# Test to get all images with size between 2000 to 3000
image_id = self.created_images[1]
# Get image metadata
- image = self.client.get_image(image_id)
+ image = self.client.show_image(image_id)
size = image['size']
params = {"size_min": size - 500, "size_max": size + 500}
- images_list = self.client.image_list(params=params)
+ images_list = self.client.list_images(params=params)
image_size_list = map(lambda x: x['size'], images_list)
for image_size in image_size_list:
@@ -235,7 +235,7 @@
def test_list_images_param_limit(self):
# Test to get images by limit
params = {"limit": 2}
- images_list = self.client.image_list(params=params)
+ images_list = self.client.list_images(params=params)
self.assertEqual(len(images_list), params['limit'],
"Failed to get images by limit")
diff --git a/tempest/api/image/v2/test_images_member.py b/tempest/api/image/v2/test_images_member.py
index 26d4197..07c2073 100644
--- a/tempest/api/image/v2/test_images_member.py
+++ b/tempest/api/image/v2/test_images_member.py
@@ -29,7 +29,7 @@
self.alt_tenant_id,
'accepted')
self.assertIn(image_id, self._list_image_ids_as_alt())
- body = self.os_img_client.get_image_membership(image_id)
+ body = self.os_img_client.list_image_members(image_id)
members = body['members']
member = members[0]
self.assertEqual(len(members), 1, str(members))
diff --git a/tempest/api/image/v2/test_images_negative.py b/tempest/api/image/v2/test_images_negative.py
index 60a10a2..c5c5e8b 100644
--- a/tempest/api/image/v2/test_images_negative.py
+++ b/tempest/api/image/v2/test_images_negative.py
@@ -25,7 +25,7 @@
class ImagesNegativeTest(base.BaseV2ImageTest):
"""
- here we have -ve tests for get_image and delete_image api
+ here we have -ve tests for show_image and delete_image api
Tests
** get non-existent image
@@ -41,7 +41,7 @@
def test_get_non_existent_image(self):
# get the non-existent image
non_existent_id = str(uuid.uuid4())
- self.assertRaises(lib_exc.NotFound, self.client.get_image,
+ self.assertRaises(lib_exc.NotFound, self.client.show_image,
non_existent_id)
@test.attr(type=['negative'])
@@ -49,7 +49,7 @@
def test_get_image_null_id(self):
# get image with image_id = NULL
image_id = ""
- self.assertRaises(lib_exc.NotFound, self.client.get_image, image_id)
+ self.assertRaises(lib_exc.NotFound, self.client.show_image, image_id)
@test.attr(type=['negative'])
@test.idempotent_id('e57fc127-7ba0-4693-92d7-1d8a05ebcba9')
@@ -64,7 +64,7 @@
self.client.wait_for_resource_deletion(image_id)
# get the deleted image
- self.assertRaises(lib_exc.NotFound, self.client.get_image, image_id)
+ self.assertRaises(lib_exc.NotFound, self.client.show_image, image_id)
# delete the deleted image
self.assertRaises(lib_exc.NotFound, self.client.delete_image,
diff --git a/tempest/api/image/v2/test_images_tags.py b/tempest/api/image/v2/test_images_tags.py
index 24688dc..e38136e 100644
--- a/tempest/api/image/v2/test_images_tags.py
+++ b/tempest/api/image/v2/test_images_tags.py
@@ -31,10 +31,10 @@
# Creating image tag and verify it.
self.client.add_image_tag(image_id, tag)
- body = self.client.get_image(image_id)
+ body = self.client.show_image(image_id)
self.assertIn(tag, body['tags'])
# Deleting image tag and verify it.
self.client.delete_image_tag(image_id, tag)
- body = self.client.get_image(image_id)
+ body = self.client.show_image(image_id)
self.assertNotIn(tag, body['tags'])
diff --git a/tempest/api/messaging/base.py b/tempest/api/messaging/base.py
index 2ddc3fc..34ac860 100644
--- a/tempest/api/messaging/base.py
+++ b/tempest/api/messaging/base.py
@@ -116,20 +116,6 @@
return resp, body
@classmethod
- def get_single_message(cls, message_uri):
- """Wrapper utility that gets a single message."""
- resp, body = cls.client.show_single_message(message_uri)
-
- return resp, body
-
- @classmethod
- def get_multiple_messages(cls, message_uri):
- """Wrapper utility that gets multiple messages."""
- resp, body = cls.client.show_multiple_messages(message_uri)
-
- return resp, body
-
- @classmethod
def delete_messages(cls, message_uri):
"""Wrapper utility that deletes messages."""
resp, body = cls.client.delete_messages(message_uri)
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 86fbc54..46d6651 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest.api.network import base
@@ -62,7 +63,7 @@
quota_set = self.admin_client.update_quotas(tenant_id,
**new_quotas)
self.addCleanup(self.admin_client.reset_quotas, tenant_id)
- for key, value in new_quotas.iteritems():
+ for key, value in six.iteritems(new_quotas):
self.assertEqual(value, quota_set[key])
# Confirm our tenant is listed among tenants with non default quotas
@@ -76,7 +77,7 @@
# Confirm from API quotas were changed as requested for tenant
quota_set = self.admin_client.show_quotas(tenant_id)
quota_set = quota_set['quota']
- for key, value in new_quotas.iteritems():
+ for key, value in six.iteritems(new_quotas):
self.assertEqual(value, quota_set[key])
# Reset quotas to default and confirm
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index 253d779..ca08fbd 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -16,6 +16,7 @@
import netaddr
import random
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -127,7 +128,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ kwargs = {k: v for k, v in six.iteritems(kwargs) if v}
real_ip, eui_ip = self._get_ips_from_subnet(**kwargs)
self._clean_network()
self.assertEqual(eui_ip, real_ip,
@@ -203,8 +204,8 @@
real_ips = dict([(k['subnet_id'], k['ip_address'])
for k in port['fixed_ips']])
real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
- for sub in subnet_dhcp,
- subnet_slaac]
+ for sub in [subnet_dhcp,
+ subnet_slaac]]
self.client.delete_port(port['id'])
self.ports.pop()
body = self.client.list_ports()
@@ -256,8 +257,8 @@
real_ips = dict([(k['subnet_id'], k['ip_address'])
for k in port['fixed_ips']])
real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
- for sub in subnet_dhcp,
- subnet_slaac]
+ for sub in [subnet_dhcp,
+ subnet_slaac]]
self._clean_network()
self.assertTrue({real_eui_ip,
real_dhcp_ip}.issubset([eui_ip] + dhcp_ip))
@@ -284,7 +285,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ kwargs = {k: v for k, v in six.iteritems(kwargs) if v}
subnet = self.create_subnet(self.network, **kwargs)
port = self.create_port(self.network)
port_ip = next(iter(port['fixed_ips']), None)['ip_address']
@@ -311,7 +312,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ kwargs = {k: v for k, v in six.iteritems(kwargs) if v}
subnet = self.create_subnet(self.network, **kwargs)
ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
subnet["allocation_pools"][0]["end"])
@@ -389,7 +390,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ kwargs = {k: v for k, v in six.iteritems(kwargs) if v}
subnet, port = self._create_subnet_router(kwargs)
port_ip = next(iter(port['fixed_ips']), None)['ip_address']
self._clean_network()
diff --git a/tempest/api/network/test_fwaas_extensions.py b/tempest/api/network/test_fwaas_extensions.py
index d007fb0..0622e87 100644
--- a/tempest/api/network/test_fwaas_extensions.py
+++ b/tempest/api/network/test_fwaas_extensions.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -145,7 +146,7 @@
def test_show_firewall_rule(self):
# show a created firewall rule
fw_rule = self.client.show_firewall_rule(self.fw_rule['id'])
- for key, value in fw_rule['firewall_rule'].iteritems():
+ for key, value in six.iteritems(fw_rule['firewall_rule']):
self.assertEqual(self.fw_rule[key], value)
@test.idempotent_id('1086dd93-a4c0-4bbb-a1bd-6d4bc62c199f')
@@ -187,7 +188,7 @@
# show a created firewall policy
fw_policy = self.client.show_firewall_policy(self.fw_policy['id'])
fw_policy = fw_policy['firewall_policy']
- for key, value in fw_policy.iteritems():
+ for key, value in six.iteritems(fw_policy):
self.assertEqual(self.fw_policy[key], value)
@test.idempotent_id('02082a03-3cdd-4789-986a-1327dd80bfb7')
@@ -216,7 +217,7 @@
firewall = self.client.show_firewall(firewall_id)
firewall = firewall['firewall']
- for key, value in firewall.iteritems():
+ for key, value in six.iteritems(firewall):
if key == 'status':
continue
self.assertEqual(created_firewall[key], value)
diff --git a/tempest/api/network/test_load_balancer.py b/tempest/api/network/test_load_balancer.py
index ace9f61..38a6fe9 100644
--- a/tempest/api/network/test_load_balancer.py
+++ b/tempest/api/network/test_load_balancer.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import decorators
@@ -75,7 +76,7 @@
body = create_obj(**kwargs)
obj = body[obj_name]
self.addCleanup(delete_obj, obj['id'])
- for key, value in obj.iteritems():
+ for key, value in six.iteritems(obj):
# It is not relevant to filter by all arguments. That is why
# there is a list of attr to except
if key not in attr_exceptions:
@@ -168,7 +169,7 @@
# Verifies the details of a vip
body = self.client.show_vip(self.vip['id'])
vip = body['vip']
- for key, value in vip.iteritems():
+ for key, value in six.iteritems(vip):
# 'status' should not be confirmed in api tests
if key != 'status':
self.assertEqual(self.vip[key], value)
@@ -185,7 +186,7 @@
# Verifies the details of a pool
body = self.client.show_pool(pool['id'])
shown_pool = body['pool']
- for key, value in pool.iteritems():
+ for key, value in six.iteritems(pool):
# 'status' should not be confirmed in api tests
if key != 'status':
self.assertEqual(value, shown_pool[key])
@@ -243,7 +244,7 @@
# Verifies the details of a member
body = self.client.show_member(self.member['id'])
member = body['member']
- for key, value in member.iteritems():
+ for key, value in six.iteritems(member):
# 'status' should not be confirmed in api tests
if key != 'status':
self.assertEqual(self.member[key], value)
@@ -316,7 +317,7 @@
# Verifies the details of a health_monitor
body = self.client.show_health_monitor(self.health_monitor['id'])
health_monitor = body['health_monitor']
- for key, value in health_monitor.iteritems():
+ for key, value in six.iteritems(health_monitor):
# 'status' should not be confirmed in api tests
if key != 'status':
self.assertEqual(self.health_monitor[key], value)
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 97273a6..7a96f34 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -15,6 +15,7 @@
import itertools
import netaddr
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -162,7 +163,7 @@
**kwargs)
compare_args_full = dict(gateway_ip=gateway, cidr=cidr,
mask_bits=mask_bits, **kwargs)
- compare_args = dict((k, v) for k, v in compare_args_full.iteritems()
+ compare_args = dict((k, v) for k, v in six.iteritems(compare_args_full)
if v is not None)
if 'dns_nameservers' in set(subnet).intersection(compare_args):
@@ -392,7 +393,9 @@
" in filtered list (%s)." % nonexternal)
self.assertIn(CONF.network.public_network_id, networks)
- subnets_iter = (network['subnets'] for network in body['networks'])
+ subnets_iter = (network['subnets']
+ for network in body['networks']
+ if not network['shared'])
# subnets_iter is a list (iterator) of lists. This flattens it to a
# list of UUIDs
public_subnets_iter = itertools.chain(*subnets_iter)
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 4362926..35072b4 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -14,6 +14,7 @@
# under the License.
import netaddr
+import six
from tempest_lib.common.utils import data_utils
from tempest.api.network import base_routers as base
@@ -176,7 +177,7 @@
self.assertIsNone(actual_ext_gw_info)
return
# Verify only keys passed in exp_ext_gw_info
- for k, v in exp_ext_gw_info.iteritems():
+ for k, v in six.iteritems(exp_ext_gw_info):
self.assertEqual(v, actual_ext_gw_info[k])
def _verify_gateway_port(self, router_id):
diff --git a/tempest/api/network/test_vpnaas_extensions.py b/tempest/api/network/test_vpnaas_extensions.py
index 718168b..9fe2a56 100644
--- a/tempest/api/network/test_vpnaas_extensions.py
+++ b/tempest/api/network/test_vpnaas_extensions.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -82,7 +83,7 @@
def _assertExpected(self, expected, actual):
# Check if not expected keys/values exists in actual response body
- for key, value in expected.iteritems():
+ for key, value in six.iteritems(expected):
self.assertIn(key, actual)
self.assertEqual(value, actual[key])
@@ -245,7 +246,7 @@
# Confirm that update was successful by verifying using 'show'
body = self.client.show_ikepolicy(ikepolicy['id'])
ike_policy = body['ikepolicy']
- for key, value in new_ike.iteritems():
+ for key, value in six.iteritems(new_ike):
self.assertIn(key, ike_policy)
self.assertEqual(value, ike_policy[key])
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 8bc9b12..41a7d65 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -15,8 +15,6 @@
from tempest_lib import exceptions as lib_exc
-from tempest import clients
-from tempest.common import credentials
from tempest.common import custom_matchers
from tempest import config
import tempest.test
@@ -26,6 +24,8 @@
class BaseObjectTest(tempest.test.BaseTestCase):
+ credentials = [['operator', CONF.object_storage.operator_role]]
+
@classmethod
def skip_checks(cls):
super(BaseObjectTest, cls).skip_checks()
@@ -37,20 +37,9 @@
def setup_credentials(cls):
cls.set_network_resources()
super(BaseObjectTest, cls).setup_credentials()
- operator_role = CONF.object_storage.operator_role
- # There are no credentials by type used by object storage tests so
- # isolated_creds must still be initialized
- cls.isolated_creds = credentials.get_isolated_credentials(
- cls.__name__, network_resources=cls.network_resources)
- if not cls.isolated_creds.is_role_available(operator_role):
- skip_msg = ("%s skipped because the configured credential provider"
- " is not able to provide credentials with the %s role "
- "assigned." % (cls.__name__, operator_role))
- raise cls.skipException(skip_msg)
- else:
- # Get isolated creds for normal user
- cls.os = clients.Manager(cls.isolated_creds.get_creds_by_roles(
- [operator_role]))
+ # credentials may be overwritten by children classes
+ if hasattr(cls, 'os_roles_operator'):
+ cls.os = cls.os_roles_operator
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py
index 364d6e1..bbdf367 100644
--- a/tempest/api/object_storage/test_account_quotas.py
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -15,7 +15,6 @@
from tempest_lib.common.utils import data_utils
from tempest.api.object_storage import base
-from tempest import clients
from tempest import config
from tempest import test
@@ -24,19 +23,14 @@
class AccountQuotasTest(base.BaseObjectTest):
+ credentials = [['operator', CONF.object_storage.operator_role],
+ ['reseller', CONF.object_storage.reseller_admin_role]]
+
@classmethod
def setup_credentials(cls):
super(AccountQuotasTest, cls).setup_credentials()
- reseller_admin_role = CONF.object_storage.reseller_admin_role
- if not cls.isolated_creds.is_role_available(reseller_admin_role):
- skip_msg = ("%s skipped because the configured credential provider"
- " is not able to provide credentials with the %s role "
- "assigned." % (cls.__name__, reseller_admin_role))
- raise cls.skipException(skip_msg)
- else:
- cls.os_reselleradmin = clients.Manager(
- cls.isolated_creds.get_creds_by_roles(
- roles=[reseller_admin_role]))
+ cls.os = cls.os_roles_operator
+ cls.os_reselleradmin = cls.os_roles_reseller
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/object_storage/test_account_quotas_negative.py b/tempest/api/object_storage/test_account_quotas_negative.py
index b32943c..e945e1e 100644
--- a/tempest/api/object_storage/test_account_quotas_negative.py
+++ b/tempest/api/object_storage/test_account_quotas_negative.py
@@ -17,7 +17,6 @@
from tempest_lib import exceptions as lib_exc
from tempest.api.object_storage import base
-from tempest import clients
from tempest import config
from tempest import test
@@ -26,19 +25,14 @@
class AccountQuotasNegativeTest(base.BaseObjectTest):
+ credentials = [['operator', CONF.object_storage.operator_role],
+ ['reseller', CONF.object_storage.reseller_admin_role]]
+
@classmethod
def setup_credentials(cls):
super(AccountQuotasNegativeTest, cls).setup_credentials()
- reseller_admin_role = CONF.object_storage.reseller_admin_role
- if not cls.isolated_creds.is_role_available(reseller_admin_role):
- skip_msg = ("%s skipped because the configured credential provider"
- " is not able to provide credentials with the %s role "
- "assigned." % (cls.__name__, reseller_admin_role))
- raise cls.skipException(skip_msg)
- else:
- cls.os_reselleradmin = clients.Manager(
- cls.isolated_creds.get_creds_by_roles(
- roles=[reseller_admin_role]))
+ cls.os = cls.os_roles_operator
+ cls.os_reselleradmin = cls.os_roles_reseller
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 77defd6..ac41148 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -20,7 +20,6 @@
import testtools
from tempest.api.object_storage import base
-from tempest import clients
from tempest.common import custom_matchers
from tempest import config
from tempest import test
@@ -30,14 +29,15 @@
class AccountTest(base.BaseObjectTest):
+ credentials = [['operator', CONF.object_storage.operator_role],
+ ['operator_alt', CONF.object_storage.operator_role]]
containers = []
@classmethod
def setup_credentials(cls):
super(AccountTest, cls).setup_credentials()
- cls.os_operator = clients.Manager(
- cls.isolated_creds.get_creds_by_roles(
- roles=[CONF.object_storage.operator_role], force_new=True))
+ cls.os = cls.os_roles_operator
+ cls.os_operator = cls.os_roles_operator_alt
@classmethod
def resource_setup(cls):
@@ -64,7 +64,6 @@
for container_name in self.containers:
self.assertIn(container_name, container_list)
- @test.attr(type='smoke')
@test.idempotent_id('884ec421-fbad-4fcc-916b-0580f2699565')
def test_list_no_containers(self):
# List request to empty account
@@ -93,7 +92,6 @@
self.assertEqual(len(container_list), 0)
- @test.attr(type='smoke')
@test.idempotent_id('1c7efa35-e8a2-4b0b-b5ff-862c7fd83704')
def test_list_containers_with_format_json(self):
# list containers setting format parameter to 'json'
@@ -106,7 +104,6 @@
self.assertTrue([c['count'] for c in container_list])
self.assertTrue([c['bytes'] for c in container_list])
- @test.attr(type='smoke')
@test.idempotent_id('4477b609-1ca6-4d4b-b25d-ad3f01086089')
def test_list_containers_with_format_xml(self):
# list containers setting format parameter to 'xml'
@@ -122,7 +119,6 @@
self.assertEqual(container_list.find(".//count").tag, 'count')
self.assertEqual(container_list.find(".//bytes").tag, 'bytes')
- @test.attr(type='smoke')
@test.idempotent_id('6eb04a6a-4860-4e31-ba91-ea3347d76b58')
@testtools.skipIf(
not CONF.object_storage_feature_enabled.discoverability,
@@ -132,7 +128,6 @@
self.assertThat(resp, custom_matchers.AreAllWellFormatted())
- @test.attr(type='smoke')
@test.idempotent_id('5cfa4ab2-4373-48dd-a41f-a532b12b08b2')
def test_list_containers_with_limit(self):
# list containers one of them, half of them then all of them
@@ -144,7 +139,6 @@
self.assertEqual(len(container_list), limit)
- @test.attr(type='smoke')
@test.idempotent_id('638f876d-6a43-482a-bbb3-0840bca101c6')
def test_list_containers_with_marker(self):
# list containers using marker param
@@ -165,7 +159,6 @@
self.assertEqual(len(container_list), self.containers_count / 2 - 1)
- @test.attr(type='smoke')
@test.idempotent_id('5ca164e4-7bde-43fa-bafb-913b53b9e786')
def test_list_containers_with_end_marker(self):
# list containers using end_marker param
@@ -184,7 +177,6 @@
self.assertHeaders(resp, 'Account', 'GET')
self.assertEqual(len(container_list), self.containers_count / 2)
- @test.attr(type='smoke')
@test.idempotent_id('ac8502c2-d4e4-4f68-85a6-40befea2ef5e')
def test_list_containers_with_marker_and_end_marker(self):
# list containers combining marker and end_marker param
@@ -195,7 +187,6 @@
self.assertHeaders(resp, 'Account', 'GET')
self.assertEqual(len(container_list), self.containers_count - 2)
- @test.attr(type='smoke')
@test.idempotent_id('f7064ae8-dbcc-48da-b594-82feef6ea5af')
def test_list_containers_with_limit_and_marker(self):
# list containers combining marker and limit param
@@ -210,7 +201,6 @@
self.assertTrue(len(container_list) <= limit, str(container_list))
- @test.attr(type='smoke')
@test.idempotent_id('888a3f0e-7214-4806-8e50-5e0c9a69bb5e')
def test_list_containers_with_limit_and_end_marker(self):
# list containers combining limit and end_marker param
@@ -223,7 +213,6 @@
self.assertEqual(len(container_list),
min(limit, self.containers_count / 2))
- @test.attr(type='smoke')
@test.idempotent_id('8cf98d9c-e3a0-4e44-971b-c87656fdddbd')
def test_list_containers_with_limit_and_marker_and_end_marker(self):
# list containers combining limit, marker and end_marker param
@@ -253,7 +242,6 @@
self.assertIn('x-account-meta-test-account-meta2', resp)
self.account_client.delete_account_metadata(metadata)
- @test.attr(type='smoke')
@test.idempotent_id('b904c2e3-24c2-4dba-ad7d-04e90a761be5')
def test_list_no_account_metadata(self):
# list no account metadata
@@ -261,7 +249,6 @@
self.assertHeaders(resp, 'Account', 'HEAD')
self.assertNotIn('x-account-meta-', str(resp))
- @test.attr(type='smoke')
@test.idempotent_id('e2a08b5f-3115-4768-a3ee-d4287acd6c08')
def test_update_account_metadata_with_create_metadata(self):
# add metadata to account
@@ -276,7 +263,6 @@
self.account_client.delete_account_metadata(metadata)
- @test.attr(type='smoke')
@test.idempotent_id('9f60348d-c46f-4465-ae06-d51dbd470953')
def test_update_account_metadata_with_delete_matadata(self):
# delete metadata from account
@@ -288,7 +274,6 @@
resp, _ = self.account_client.list_account_metadata()
self.assertNotIn('x-account-meta-test-account-meta1', resp)
- @test.attr(type='smoke')
@test.idempotent_id('64fd53f3-adbd-4639-af54-436e4982dbfb')
def test_update_account_metadata_with_create_matadata_key(self):
# if the value of metadata is not set, the metadata is not
@@ -300,7 +285,6 @@
resp, _ = self.account_client.list_account_metadata()
self.assertNotIn('x-account-meta-test-account-meta1', resp)
- @test.attr(type='smoke')
@test.idempotent_id('d4d884d3-4696-4b85-bc98-4f57c4dd2bf1')
def test_update_account_metadata_with_delete_matadata_key(self):
# Although the value of metadata is not set, the feature of
@@ -314,7 +298,6 @@
resp, _ = self.account_client.list_account_metadata()
self.assertNotIn('x-account-meta-test-account-meta1', resp)
- @test.attr(type='smoke')
@test.idempotent_id('8e5fc073-59b9-42ee-984a-29ed11b2c749')
def test_update_account_metadata_with_create_and_delete_metadata(self):
# Send a request adding and deleting metadata requests simultaneously
diff --git a/tempest/api/object_storage/test_account_services_negative.py b/tempest/api/object_storage/test_account_services_negative.py
index feccf18..998c2bd 100644
--- a/tempest/api/object_storage/test_account_services_negative.py
+++ b/tempest/api/object_storage/test_account_services_negative.py
@@ -15,7 +15,6 @@
from tempest_lib import exceptions as lib_exc
from tempest.api.object_storage import base
-from tempest import clients
from tempest import config
from tempest import test
@@ -24,12 +23,14 @@
class AccountNegativeTest(base.BaseObjectTest):
+ credentials = [['operator', CONF.object_storage.operator_role],
+ ['operator_alt', CONF.object_storage.operator_role]]
+
@classmethod
def setup_credentials(cls):
super(AccountNegativeTest, cls).setup_credentials()
- cls.os_operator = clients.Manager(
- cls.isolated_creds.get_creds_by_roles(
- roles=[CONF.object_storage.operator_role], force_new=True))
+ cls.os = cls.os_roles_operator
+ cls.os_operator = cls.os_roles_operator_alt
@test.attr(type=['negative'])
@test.idempotent_id('070e6aca-6152-4867-868d-1118d68fb38c')
diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py
index 73a976d..4df813d 100644
--- a/tempest/api/object_storage/test_container_acl.py
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -16,7 +16,6 @@
from tempest_lib.common.utils import data_utils
from tempest.api.object_storage import base
-from tempest import clients
from tempest import config
from tempest import test
@@ -25,12 +24,14 @@
class ObjectTestACLs(base.BaseObjectTest):
+ credentials = [['operator', CONF.object_storage.operator_role],
+ ['operator_alt', CONF.object_storage.operator_role]]
+
@classmethod
def setup_credentials(cls):
super(ObjectTestACLs, cls).setup_credentials()
- cls.os_operator = clients.Manager(
- cls.isolated_creds.get_creds_by_roles(
- roles=[CONF.object_storage.operator_role], force_new=True))
+ cls.os = cls.os_roles_operator
+ cls.os_operator = cls.os_roles_operator_alt
@classmethod
def resource_setup(cls):
@@ -46,7 +47,6 @@
self.delete_containers([self.container_name])
super(ObjectTestACLs, self).tearDown()
- @test.attr(type='smoke')
@test.idempotent_id('a3270f3f-7640-4944-8448-c7ea783ea5b6')
def test_read_object_with_rights(self):
# attempt to read object using authorized user
@@ -72,7 +72,6 @@
self.container_name, object_name)
self.assertHeaders(resp, 'Object', 'GET')
- @test.attr(type='smoke')
@test.idempotent_id('aa58bfa5-40d9-4bc3-82b4-d07f4a9e392a')
def test_write_object_with_rights(self):
# attempt to write object using authorized user
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index 2c6d3cc..1c42e97 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -16,7 +16,6 @@
from tempest_lib import exceptions as lib_exc
from tempest.api.object_storage import base
-from tempest import clients
from tempest import config
from tempest import test
@@ -25,12 +24,14 @@
class ObjectACLsNegativeTest(base.BaseObjectTest):
+ credentials = [['operator', CONF.object_storage.operator_role],
+ ['operator_alt', CONF.object_storage.operator_role]]
+
@classmethod
def setup_credentials(cls):
super(ObjectACLsNegativeTest, cls).setup_credentials()
- cls.os_operator = clients.Manager(
- cls.isolated_creds.get_creds_by_roles(
- roles=[CONF.object_storage.operator_role], force_new=True))
+ cls.os = cls.os_roles_operator
+ cls.os_operator = cls.os_roles_operator_alt
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 9f2adfe..0f107f5 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -55,7 +55,6 @@
self.containers.append(container_name)
self.assertHeaders(resp, 'Container', 'PUT')
- @test.attr(type='smoke')
@test.idempotent_id('49f866ed-d6af-4395-93e7-4187eb56d322')
def test_create_container_overwrite(self):
# overwrite container with the same name
@@ -66,7 +65,6 @@
resp, _ = self.container_client.create_container(container_name)
self.assertHeaders(resp, 'Container', 'PUT')
- @test.attr(type='smoke')
@test.idempotent_id('c2ac4d59-d0f5-40d5-ba19-0635056d48cd')
def test_create_container_with_metadata_key(self):
# create container with the blank value of metadata
@@ -84,7 +82,6 @@
# in the server
self.assertNotIn('x-container-meta-test-container-meta', resp)
- @test.attr(type='smoke')
@test.idempotent_id('e1e8df32-7b22-44e1-aa08-ccfd8d446b58')
def test_create_container_with_metadata_value(self):
# create container with metadata value
@@ -103,7 +100,6 @@
self.assertEqual(resp['x-container-meta-test-container-meta'],
metadata['test-container-meta'])
- @test.attr(type='smoke')
@test.idempotent_id('24d16451-1c0c-4e4f-b59c-9840a3aba40e')
def test_create_container_with_remove_metadata_key(self):
# create container with the blank value of remove metadata
@@ -124,7 +120,6 @@
container_name)
self.assertNotIn('x-container-meta-test-container-meta', resp)
- @test.attr(type='smoke')
@test.idempotent_id('8a21ebad-a5c7-4e29-b428-384edc8cd156')
def test_create_container_with_remove_metadata_value(self):
# create container with remove metadata
@@ -143,7 +138,6 @@
container_name)
self.assertNotIn('x-container-meta-test-container-meta', resp)
- @test.attr(type='smoke')
@test.idempotent_id('95d3a249-b702-4082-a2c4-14bb860cf06a')
def test_delete_container(self):
# create a container
@@ -165,7 +159,6 @@
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
- @test.attr(type='smoke')
@test.idempotent_id('4646ac2d-9bfb-4c7d-a3c5-0f527402b3df')
def test_list_container_contents_with_no_object(self):
# get empty container contents list
@@ -176,7 +169,6 @@
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual('', object_list.strip('\n'))
- @test.attr(type='smoke')
@test.idempotent_id('fe323a32-57b9-4704-a996-2e68f83b09bc')
def test_list_container_contents_with_delimiter(self):
# get container contents list using delimiter param
@@ -191,7 +183,6 @@
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name.split('/')[0], object_list.strip('/\n'))
- @test.attr(type='smoke')
@test.idempotent_id('55b4fa5c-e12e-4ca9-8fcf-a79afe118522')
def test_list_container_contents_with_end_marker(self):
# get container contents list using end_marker param
@@ -205,7 +196,6 @@
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
- @test.attr(type='smoke')
@test.idempotent_id('196f5034-6ab0-4032-9da9-a937bbb9fba9')
def test_list_container_contents_with_format_json(self):
# get container contents list using format_json param
@@ -225,7 +215,6 @@
self.assertTrue([c['content_type'] for c in object_list])
self.assertTrue([c['last_modified'] for c in object_list])
- @test.attr(type='smoke')
@test.idempotent_id('655a53ca-4d15-408c-a377-f4c6dbd0a1fa')
def test_list_container_contents_with_format_xml(self):
# get container contents list using format_xml param
@@ -250,7 +239,6 @@
self.assertEqual(object_list.find(".//last_modified").tag,
'last_modified')
- @test.attr(type='smoke')
@test.idempotent_id('297ec38b-2b61-4ff4-bcd1-7fa055e97b61')
def test_list_container_contents_with_limit(self):
# get container contents list using limit param
@@ -264,7 +252,6 @@
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
- @test.attr(type='smoke')
@test.idempotent_id('c31ddc63-2a58-4f6b-b25c-94d2937e6867')
def test_list_container_contents_with_marker(self):
# get container contents list using marker param
@@ -278,7 +265,6 @@
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
- @test.attr(type='smoke')
@test.idempotent_id('58ca6cc9-6af0-408d-aaec-2a6a7b2f0df9')
def test_list_container_contents_with_path(self):
# get container contents list using path param
@@ -293,7 +279,6 @@
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
- @test.attr(type='smoke')
@test.idempotent_id('77e742c7-caf2-4ec9-8aa4-f7d509a3344c')
def test_list_container_contents_with_prefix(self):
# get container contents list using prefix param
@@ -325,7 +310,6 @@
self.assertIn('x-container-meta-name', resp)
self.assertEqual(resp['x-container-meta-name'], metadata['name'])
- @test.attr(type='smoke')
@test.idempotent_id('a2faf936-6b13-4f8d-92a2-c2278355821e')
def test_list_no_container_metadata(self):
# HEAD container without metadata
@@ -336,7 +320,6 @@
self.assertHeaders(resp, 'Container', 'HEAD')
self.assertNotIn('x-container-meta-', str(resp))
- @test.attr(type='smoke')
@test.idempotent_id('cf19bc0b-7e16-4a5a-aaed-cb0c2fe8deef')
def test_update_container_metadata_with_create_and_delete_matadata(self):
# Send one request of adding and deleting metadata
@@ -360,7 +343,6 @@
self.assertEqual(resp['x-container-meta-test-container-meta2'],
metadata_2['test-container-meta2'])
- @test.attr(type='smoke')
@test.idempotent_id('2ae5f295-4bf1-4e04-bfad-21e54b62cec5')
def test_update_container_metadata_with_create_metadata(self):
# update container metadata using add metadata
@@ -378,7 +360,6 @@
self.assertEqual(resp['x-container-meta-test-container-meta1'],
metadata['test-container-meta1'])
- @test.attr(type='smoke')
@test.idempotent_id('3a5ce7d4-6e4b-47d0-9d87-7cd42c325094')
def test_update_container_metadata_with_delete_metadata(self):
# update container metadata using delete metadata
@@ -397,7 +378,6 @@
container_name)
self.assertNotIn('x-container-meta-test-container-meta1', resp)
- @test.attr(type='smoke')
@test.idempotent_id('31f40a5f-6a52-4314-8794-cd89baed3040')
def test_update_container_metadata_with_create_matadata_key(self):
# update container metadata with a blenk value of metadata
@@ -413,7 +393,6 @@
container_name)
self.assertNotIn('x-container-meta-test-container-meta1', resp)
- @test.attr(type='smoke')
@test.idempotent_id('a2e36378-6f1f-43f4-840a-ffd9cfd61914')
def test_update_container_metadata_with_delete_metadata_key(self):
# update container metadata with a blank value of matadata
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index 53bcfa6..06e700b 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -22,7 +22,6 @@
from tempest.api.object_storage import base
-from tempest import clients
from tempest import config
from tempest import test
@@ -38,11 +37,14 @@
class ContainerSyncTest(base.BaseObjectTest):
clients = {}
+ credentials = [['operator', CONF.object_storage.operator_role],
+ ['operator_alt', CONF.object_storage.operator_role]]
+
@classmethod
def setup_credentials(cls):
super(ContainerSyncTest, cls).setup_credentials()
- cls.os_alt = clients.Manager(cls.isolated_creds.get_creds_by_roles(
- [CONF.object_storage.operator_role], force_new=True))
+ cls.os = cls.os_roles_operator
+ cls.os_alt = cls.os_roles_operator_alt
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 6acd0f2..627895e 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -24,7 +24,6 @@
from tempest_lib.common.utils import data_utils
from tempest.api.object_storage import base
-from tempest import clients
from tempest.common import custom_matchers
from tempest import config
from tempest import test
@@ -89,6 +88,7 @@
for meta_key in not_in_meta:
self.assertNotIn('x-object-meta-' + meta_key, resp)
+ @test.attr(type='smoke')
@test.idempotent_id('5b4ce26f-3545-46c9-a2ba-5754358a4c62')
def test_create_object(self):
# create object
@@ -385,7 +385,6 @@
object_name)
self.assertNotIn('x-object-meta-test-meta1', resp)
- @test.attr(type='smoke')
@test.idempotent_id('f726174b-2ded-4708-bff7-729d12ce1f84')
def test_update_object_metadata_with_create_and_remove_metadata(self):
# creation and deletion of metadata with one request
@@ -413,7 +412,6 @@
self.assertIn('x-object-meta-test-meta2', resp)
self.assertEqual(resp['x-object-meta-test-meta2'], 'Meta2')
- @test.attr(type='smoke')
@test.idempotent_id('08854588-6449-4bb7-8cca-f2e1040f5e6f')
def test_update_object_metadata_with_x_object_manifest(self):
# update object metadata with x_object_manifest
@@ -460,7 +458,6 @@
self.assertIn('x-object-meta-test-meta', resp)
self.assertEqual(resp['x-object-meta-test-meta'], '')
- @test.attr(type='smoke')
@test.idempotent_id('9a88dca4-b684-425b-806f-306cd0e57e42')
def test_update_object_metadata_with_x_remove_object_metakey(self):
# update object metadata with a blank value of remove metadata
@@ -504,7 +501,6 @@
self.assertIn('x-object-meta-test-meta', resp)
self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
- @test.attr(type='smoke')
@test.idempotent_id('170fb90e-f5c3-4b1f-ae1b-a18810821172')
def test_list_no_object_metadata(self):
# get empty list of object metadata
@@ -516,7 +512,6 @@
self.assertHeaders(resp, 'Object', 'HEAD')
self.assertNotIn('x-object-meta-', str(resp))
- @test.attr(type='smoke')
@test.idempotent_id('23a3674c-d6de-46c3-86af-ff92bfc8a3da')
def test_list_object_metadata_with_x_object_manifest(self):
# get object metadata with x_object_manifest
@@ -571,7 +566,6 @@
self.assertEqual(body, data)
- @test.attr(type='smoke')
@test.idempotent_id('005f9bf6-e06d-41ec-968e-96c78e0b1d82')
def test_get_object_with_metadata(self):
# get object with metadata
@@ -591,7 +585,6 @@
self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
self.assertEqual(body, data)
- @test.attr(type='smoke')
@test.idempotent_id('05a1890e-7db9-4a6c-90a8-ce998a2bddfa')
def test_get_object_with_range(self):
# get object with range
@@ -610,7 +603,6 @@
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data[rand_num - 3: rand_num])
- @test.attr(type='smoke')
@test.idempotent_id('11b4515b-7ba7-4ca8-8838-357ded86fc10')
def test_get_object_with_x_object_manifest(self):
# get object with x_object_manifest
@@ -654,7 +646,6 @@
self.assertEqual(''.join(data_segments), body)
- @test.attr(type='smoke')
@test.idempotent_id('c05b4013-e4de-47af-be84-e598062b16fc')
def test_get_object_with_if_match(self):
# get object with if_match
@@ -675,7 +666,6 @@
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
- @test.attr(type='smoke')
@test.idempotent_id('be133639-e5d2-4313-9b1f-2d59fc054a16')
def test_get_object_with_if_modified_since(self):
# get object with if_modified_since
@@ -718,7 +708,6 @@
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
- @test.attr(type='smoke')
@test.idempotent_id('0aa1201c-10aa-467a-bee7-63cbdd463152')
def test_get_object_with_if_unmodified_since(self):
# get object with if_unmodified_since
@@ -734,7 +723,6 @@
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
- @test.attr(type='smoke')
@test.idempotent_id('94587078-475f-48f9-a40f-389c246e31cd')
def test_get_object_with_x_newest(self):
# get object with x_newest
@@ -748,7 +736,6 @@
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
- @test.attr(type='smoke')
@test.idempotent_id('1a9ab572-1b66-4981-8c21-416e2a5e6011')
def test_copy_object_in_same_container(self):
# create source object
@@ -775,7 +762,6 @@
dst_object_name)
self.assertEqual(body, src_data)
- @test.attr(type='smoke')
@test.idempotent_id('2248abba-415d-410b-9c30-22dff9cd6e67')
def test_copy_object_to_itself(self):
# change the content type of an existing object
@@ -797,7 +783,6 @@
object_name)
self.assertEqual(resp['content-type'], metadata['content-type'])
- @test.attr(type='smoke')
@test.idempotent_id('06f90388-2d0e-40aa-934c-e9a8833e958a')
def test_copy_object_2d_way(self):
# create source object
@@ -824,7 +809,6 @@
# check data
self._check_copied_obj(dst_object_name, src_data)
- @test.attr(type='smoke')
@test.idempotent_id('aa467252-44f3-472a-b5ae-5b57c3c9c147')
def test_copy_object_across_containers(self):
# create a container to use as asource container
@@ -865,7 +849,6 @@
self.assertIn(actual_meta_key, resp)
self.assertEqual(resp[actual_meta_key], meta_value)
- @test.attr(type='smoke')
@test.idempotent_id('5a9e2cc6-85b6-46fc-916d-0cbb7a88e5fd')
def test_copy_object_with_x_fresh_metadata(self):
# create source object
@@ -886,7 +869,6 @@
# check that destination object does NOT have any object-meta
self._check_copied_obj(dst_object_name, data, not_in_meta=["src"])
- @test.attr(type='smoke')
@test.idempotent_id('a28a8b99-e701-4d7e-9d84-3b66f121460b')
def test_copy_object_with_x_object_metakey(self):
# create source object
@@ -909,7 +891,6 @@
# check destination object
self._check_copied_obj(dst_obj_name, data, in_meta=["test", "src"])
- @test.attr(type='smoke')
@test.idempotent_id('edabedca-24c3-4322-9b70-d6d9f942a074')
def test_copy_object_with_x_object_meta(self):
# create source object
@@ -1008,12 +989,14 @@
class PublicObjectTest(base.BaseObjectTest):
+ credentials = [['operator', CONF.object_storage.operator_role],
+ ['operator_alt', CONF.object_storage.operator_role]]
+
@classmethod
def setup_credentials(cls):
super(PublicObjectTest, cls).setup_credentials()
- cls.os_alt = clients.Manager(
- cls.isolated_creds.get_creds_by_roles(
- roles=[CONF.object_storage.operator_role], force_new=True))
+ cls.os = cls.os_roles_operator
+ cls.os_alt = cls.os_roles_operator_alt
@classmethod
def setup_clients(cls):
@@ -1029,7 +1012,6 @@
self.delete_containers([self.container_name])
super(PublicObjectTest, self).tearDown()
- @test.attr(type='smoke')
@test.idempotent_id('07c9cf95-c0d4-4b49-b9c8-0ef2c9b27193')
def test_access_public_container_object_without_using_creds(self):
# make container public-readable and access an object in it object
@@ -1068,7 +1050,6 @@
self.assertEqual(body, data)
- @test.attr(type='smoke')
@test.idempotent_id('54e2a2fe-42dc-491b-8270-8e4217dd4cdc')
def test_access_public_object_with_another_user_creds(self):
# make container public-readable and access an object in it using
diff --git a/tempest/api/object_storage/test_object_version.py b/tempest/api/object_storage/test_object_version.py
index cd2d3c3..923166a 100644
--- a/tempest/api/object_storage/test_object_version.py
+++ b/tempest/api/object_storage/test_object_version.py
@@ -45,7 +45,6 @@
header_value = resp.get('x-versions-location', 'Missing Header')
self.assertEqual(header_value, versioned)
- @test.attr(type='smoke')
@test.idempotent_id('a151e158-dcbf-4a1f-a1e7-46cd65895a6f')
@testtools.skipIf(
not CONF.object_storage_feature_enabled.object_versioning,
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
index 35f51b9..af97794 100644
--- a/tempest/api/orchestration/base.py
+++ b/tempest/api/orchestration/base.py
@@ -17,7 +17,6 @@
from tempest_lib import exceptions as lib_exc
import yaml
-from tempest import clients
from tempest import config
import tempest.test
@@ -41,14 +40,7 @@
def setup_credentials(cls):
super(BaseOrchestrationTest, cls).setup_credentials()
stack_owner_role = CONF.orchestration.stack_owner_role
- if not cls.isolated_creds.is_role_available(stack_owner_role):
- skip_msg = ("%s skipped because the configured credential provider"
- " is not able to provide credentials with the %s role "
- "assigned." % (cls.__name__, stack_owner_role))
- raise cls.skipException(skip_msg)
- else:
- cls.os = clients.Manager(cls.isolated_creds.get_creds_by_roles(
- [stack_owner_role]))
+ cls.os = cls.get_client_manager(roles=[stack_owner_role])
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/orchestration/stacks/test_swift_resources.py b/tempest/api/orchestration/stacks/test_swift_resources.py
index d4fd3f9..dadabfa 100644
--- a/tempest/api/orchestration/stacks/test_swift_resources.py
+++ b/tempest/api/orchestration/stacks/test_swift_resources.py
@@ -31,6 +31,14 @@
raise cls.skipException("Swift support is required")
@classmethod
+ def setup_credentials(cls):
+ super(SwiftResourcesTestJSON, cls).setup_credentials()
+ stack_owner_role = CONF.orchestration.stack_owner_role
+ operator_role = CONF.object_storage.operator_role
+ cls.os = cls.get_client_manager(
+ roles=[stack_owner_role, operator_role])
+
+ @classmethod
def setup_clients(cls):
super(SwiftResourcesTestJSON, cls).setup_clients()
cls.account_client = cls.os.account_client
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index 814b46d..24c7c63 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest.api.volume import base
@@ -57,7 +58,7 @@
**new_quota_set)
cleanup_quota_set = dict(
- (k, v) for k, v in default_quota_set.iteritems()
+ (k, v) for k, v in six.iteritems(default_quota_set)
if k in QUOTA_KEYS)
self.addCleanup(self.quotas_client.update_quota_set,
self.demo_tenant_id, **cleanup_quota_set)
diff --git a/tempest/api/volume/test_snapshot_metadata.py b/tempest/api/volume/test_snapshot_metadata.py
index b8e87f0..641317a 100644
--- a/tempest/api/volume/test_snapshot_metadata.py
+++ b/tempest/api/volume/test_snapshot_metadata.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from testtools import matchers
+
from tempest.api.volume import base
from tempest import test
@@ -50,12 +52,14 @@
metadata)
# Get the metadata of the snapshot
body = self.client.show_snapshot_metadata(self.snapshot_id)
- self.assertEqual(metadata, body)
+ self.assertThat(body.items(), matchers.ContainsAll(metadata.items()))
+
# Delete one item metadata of the snapshot
self.client.delete_snapshot_metadata_item(
self.snapshot_id, "key1")
body = self.client.show_snapshot_metadata(self.snapshot_id)
- self.assertEqual(expected, body)
+ self.assertThat(body.items(), matchers.ContainsAll(expected.items()))
+ self.assertNotIn("key1", body)
@test.idempotent_id('bd2363bc-de92-48a4-bc98-28943c6e4be1')
def test_update_snapshot_metadata(self):
@@ -70,7 +74,8 @@
metadata)
# Get the metadata of the snapshot
body = self.client.show_snapshot_metadata(self.snapshot_id)
- self.assertEqual(metadata, body)
+ self.assertThat(body.items(), matchers.ContainsAll(metadata.items()))
+
# Update metadata item
body = self.client.update_snapshot_metadata(
self.snapshot_id, update)
@@ -93,13 +98,13 @@
metadata)
# Get the metadata of the snapshot
body = self.client.show_snapshot_metadata(self.snapshot_id)
- self.assertEqual(metadata, body)
+ self.assertThat(body.items(), matchers.ContainsAll(metadata.items()))
# Update metadata item
body = self.client.update_snapshot_metadata_item(
self.snapshot_id, "key3", update_item)
# Get the metadata of the snapshot
body = self.client.show_snapshot_metadata(self.snapshot_id)
- self.assertEqual(expect, body)
+ self.assertThat(body.items(), matchers.ContainsAll(expect.items()))
class SnapshotV1MetadataTestJSON(SnapshotV2MetadataTestJSON):
diff --git a/tempest/api/volume/test_volume_metadata.py b/tempest/api/volume/test_volume_metadata.py
index e89ff9a..8529cfc 100644
--- a/tempest/api/volume/test_volume_metadata.py
+++ b/tempest/api/volume/test_volume_metadata.py
@@ -75,7 +75,7 @@
self.volume_id, update)
# Get the metadata of the volume
body = self.volumes_client.show_volume_metadata(self.volume_id)
- self.assertThat(body.items(), matchers.ContainsAll(update.items()))
+ self.assertEqual(update, body)
@test.idempotent_id('862261c5-8df4-475a-8c21-946e50e36a20')
def test_update_volume_metadata_item(self):
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index f571f2d..375d34a 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -18,6 +18,7 @@
from tempest.api.volume import base
from tempest import config
from tempest import test
+import testtools
CONF = config.CONF
@@ -69,6 +70,18 @@
self.client.detach_volume(self.volume['id'])
self.client.wait_for_volume_status(self.volume['id'], 'available')
+ @test.idempotent_id('63e21b4c-0a0c-41f6-bfc3-7c2816815599')
+ @testtools.skipUnless(CONF.volume_feature_enabled.bootable,
+ 'Update bootable status of a volume is not enabled.')
+ def test_volume_bootable(self):
+ # Verify that a volume bootable flag is retrieved
+ for bool_bootable in [True, False]:
+ self.client.set_bootable_volume(self.volume['id'], bool_bootable)
+ fetched_volume = self.client.show_volume(self.volume['id'])
+ # Get Volume information
+ bool_flag = self._is_true(fetched_volume['bootable'])
+ self.assertEqual(bool_bootable, bool_flag)
+
@test.idempotent_id('9516a2c8-9135-488c-8dd6-5677a7e5f371')
@test.stresstest(class_setup_per='process')
@test.services('compute')
diff --git a/tempest/api_schema/response/compute/baremetal_nodes.py b/tempest/api_schema/response/compute/v2_1/baremetal_nodes.py
similarity index 100%
rename from tempest/api_schema/response/compute/baremetal_nodes.py
rename to tempest/api_schema/response/compute/v2_1/baremetal_nodes.py
diff --git a/tempest/api_schema/response/compute/v2_1/flavors.py b/tempest/api_schema/response/compute/v2_1/flavors.py
index 725d17a..26760ac 100644
--- a/tempest/api_schema/response/compute/v2_1/flavors.py
+++ b/tempest/api_schema/response/compute/v2_1/flavors.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api_schema.response.compute import parameter_types
+from tempest.api_schema.response.compute.v2_1 import parameter_types
list_flavors = {
'status_code': [200],
diff --git a/tempest/api_schema/response/compute/flavors_access.py b/tempest/api_schema/response/compute/v2_1/flavors_access.py
similarity index 100%
rename from tempest/api_schema/response/compute/flavors_access.py
rename to tempest/api_schema/response/compute/v2_1/flavors_access.py
diff --git a/tempest/api_schema/response/compute/flavors_extra_specs.py b/tempest/api_schema/response/compute/v2_1/flavors_extra_specs.py
similarity index 94%
rename from tempest/api_schema/response/compute/flavors_extra_specs.py
rename to tempest/api_schema/response/compute/v2_1/flavors_extra_specs.py
index 4003d36..faa25d0 100644
--- a/tempest/api_schema/response/compute/flavors_extra_specs.py
+++ b/tempest/api_schema/response/compute/v2_1/flavors_extra_specs.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-flavor_extra_specs = {
+set_get_flavor_extra_specs = {
'status_code': [200],
'response_body': {
'type': 'object',
@@ -28,7 +28,7 @@
}
}
-flavor_extra_specs_key = {
+set_get_flavor_extra_specs_key = {
'status_code': [200],
'response_body': {
'type': 'object',
diff --git a/tempest/api_schema/response/compute/v2_1/floating_ips.py b/tempest/api_schema/response/compute/v2_1/floating_ips.py
index 7369bec..ad1c531 100644
--- a/tempest/api_schema/response/compute/v2_1/floating_ips.py
+++ b/tempest/api_schema/response/compute/v2_1/floating_ips.py
@@ -48,7 +48,7 @@
}
}
-floating_ip = {
+create_get_floating_ip = {
'status_code': [200],
'response_body': {
'type': 'object',
@@ -59,7 +59,7 @@
}
}
-floating_ip_pools = {
+list_floating_ip_pools = {
'status_code': [200],
'response_body': {
'type': 'object',
diff --git a/tempest/api_schema/response/compute/v2_1/images.py b/tempest/api_schema/response/compute/v2_1/images.py
index 3c0b80e..e6f8db6 100644
--- a/tempest/api_schema/response/compute/v2_1/images.py
+++ b/tempest/api_schema/response/compute/v2_1/images.py
@@ -14,7 +14,7 @@
import copy
-from tempest.api_schema.response.compute import parameter_types
+from tempest.api_schema.response.compute.v2_1 import parameter_types
image_links = copy.deepcopy(parameter_types.links)
image_links['items']['properties'].update({'type': {'type': 'string'}})
diff --git a/tempest/api_schema/response/compute/v2_1/interfaces.py b/tempest/api_schema/response/compute/v2_1/interfaces.py
index 4de3309..033f816 100644
--- a/tempest/api_schema/response/compute/v2_1/interfaces.py
+++ b/tempest/api_schema/response/compute/v2_1/interfaces.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api_schema.response.compute import parameter_types
+from tempest.api_schema.response.compute.v2_1 import parameter_types
interface_common_info = {
'type': 'object',
diff --git a/tempest/api_schema/response/compute/migrations.py b/tempest/api_schema/response/compute/v2_1/migrations.py
similarity index 100%
rename from tempest/api_schema/response/compute/migrations.py
rename to tempest/api_schema/response/compute/v2_1/migrations.py
diff --git a/tempest/api_schema/response/compute/parameter_types.py b/tempest/api_schema/response/compute/v2_1/parameter_types.py
similarity index 100%
rename from tempest/api_schema/response/compute/parameter_types.py
rename to tempest/api_schema/response/compute/v2_1/parameter_types.py
diff --git a/tempest/api_schema/response/compute/v2_1/servers.py b/tempest/api_schema/response/compute/v2_1/servers.py
index 726f9b1..875f607 100644
--- a/tempest/api_schema/response/compute/v2_1/servers.py
+++ b/tempest/api_schema/response/compute/v2_1/servers.py
@@ -14,7 +14,7 @@
import copy
-from tempest.api_schema.response.compute import parameter_types
+from tempest.api_schema.response.compute.v2_1 import parameter_types
create_server = {
'status_code': [202],
diff --git a/tempest/api_schema/response/compute/services.py b/tempest/api_schema/response/compute/v2_1/services.py
similarity index 100%
rename from tempest/api_schema/response/compute/services.py
rename to tempest/api_schema/response/compute/v2_1/services.py
diff --git a/tempest/api_schema/response/compute/v2_1/tenant_usages.py b/tempest/api_schema/response/compute/v2_1/tenant_usages.py
index 0b824a1..d51ef12 100644
--- a/tempest/api_schema/response/compute/v2_1/tenant_usages.py
+++ b/tempest/api_schema/response/compute/v2_1/tenant_usages.py
@@ -66,7 +66,7 @@
'total_hours', 'total_local_gb_usage',
'total_memory_mb_usage', 'total_vcpus_usage']
-list_tenant = {
+list_tenant_usage = {
'status_code': [200],
'response_body': {
'type': 'object',
@@ -80,7 +80,7 @@
}
}
-get_tenant = {
+get_tenant_usage = {
'status_code': [200],
'response_body': {
'type': 'object',
diff --git a/tempest/api_schema/response/compute/version.py b/tempest/api_schema/response/compute/v2_1/version.py
similarity index 100%
rename from tempest/api_schema/response/compute/version.py
rename to tempest/api_schema/response/compute/v2_1/version.py
diff --git a/tempest/cli/README.rst b/tempest/cli/README.rst
deleted file mode 100644
index bc18084..0000000
--- a/tempest/cli/README.rst
+++ /dev/null
@@ -1,50 +0,0 @@
-.. _cli_field_guide:
-
-Tempest Field Guide to CLI tests
-================================
-
-
-What are these tests?
----------------------
-The cli tests test the various OpenStack command line interface tools
-to ensure that they minimally function. The current scope is read only
-operations on a cloud that are hard to test via unit tests.
-
-
-Why are these tests in tempest?
--------------------------------
-These tests exist here because it is extremely difficult to build a
-functional enough environment in the python-\*client unit tests to
-provide this kind of testing. Because we already put up a cloud in the
-gate with devstack + tempest it was decided it was better to have
-these as a side tree in tempest instead of another QA effort which
-would split review time.
-
-
-Scope of these tests
---------------------
-This should stay limited to the scope of testing the cli. Functional
-testing of the cloud should be elsewhere, this is about exercising the
-cli code.
-
-
-Example of a good test
-----------------------
-Tests should be isolated to a single command in one of the python
-clients.
-
-Tests should not modify the cloud.
-
-If a test is validating the cli for bad data, it should do it with
-assertRaises.
-
-A reasonable example of an existing test is as follows::
-
- def test_admin_list(self):
- self.nova('list')
- self.nova('list', params='--all-tenants 1')
- self.nova('list', params='--all-tenants 0')
- self.assertRaises(subprocess.CalledProcessError,
- self.nova,
- 'list',
- params='--all-tenants bad')
diff --git a/tempest/cli/__init__.py b/tempest/cli/__init__.py
deleted file mode 100644
index 6733204..0000000
--- a/tempest/cli/__init__.py
+++ /dev/null
@@ -1,126 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import functools
-
-from tempest_lib.cli import base
-from tempest_lib.cli import output_parser
-import testtools
-
-from tempest.common import credentials
-from tempest import config
-from tempest import exceptions
-from tempest.openstack.common import versionutils
-from tempest import test
-
-
-CONF = config.CONF
-
-
-def check_client_version(client, version):
- """Checks if the client's version is compatible with the given version
-
- @param client: The client to check.
- @param version: The version to compare against.
- @return: True if the client version is compatible with the given version
- parameter, False otherwise.
- """
- current_version = base.execute(client, '', params='--version',
- merge_stderr=True, cli_dir=CONF.cli.cli_dir)
-
- if not current_version.strip():
- raise exceptions.TempestException('"%s --version" output was empty' %
- client)
-
- return versionutils.is_compatible(version, current_version,
- same_major=False)
-
-
-def min_client_version(*args, **kwargs):
- """A decorator to skip tests if the client used isn't of the right version.
-
- @param client: The client command to run. For python-novaclient, this is
- 'nova', for python-cinderclient this is 'cinder', etc.
- @param version: The minimum version required to run the CLI test.
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*func_args, **func_kwargs):
- if not check_client_version(kwargs['client'], kwargs['version']):
- msg = "requires %s client version >= %s" % (kwargs['client'],
- kwargs['version'])
- raise testtools.TestCase.skipException(msg)
- return func(*func_args, **func_kwargs)
- return wrapper
- return decorator
-
-
-class ClientTestBase(test.BaseTestCase):
-
- @classmethod
- def skip_checks(cls):
- super(ClientTestBase, cls).skip_checks()
- if not CONF.identity_feature_enabled.api_v2:
- raise cls.skipException("CLI clients rely on identity v2 API, "
- "which is configured as not available")
-
- @classmethod
- def resource_setup(cls):
- if not CONF.cli.enabled:
- msg = "cli testing disabled"
- raise cls.skipException(msg)
- super(ClientTestBase, cls).resource_setup()
- cls.isolated_creds = credentials.get_isolated_credentials(cls.__name__)
- cls.creds = cls.isolated_creds.get_admin_creds()
-
- def _get_clients(self):
- clients = base.CLIClient(self.creds.username,
- self.creds.password,
- self.creds.tenant_name,
- CONF.identity.uri, CONF.cli.cli_dir)
- return clients
-
- # TODO(mtreinish): The following code is basically copied from tempest-lib.
- # The base cli test class in tempest-lib 0.0.1 doesn't work as a mixin like
- # is needed here. The code below should be removed when tempest-lib
- # provides a way to provide this functionality
- def setUp(self):
- super(ClientTestBase, self).setUp()
- self.clients = self._get_clients()
- self.parser = output_parser
-
- def assertTableStruct(self, items, field_names):
- """Verify that all items has keys listed in field_names.
-
- :param items: items to assert are field names in the output table
- :type items: list
- :param field_names: field names from the output table of the cmd
- :type field_names: list
- """
- for item in items:
- for field in field_names:
- self.assertIn(field, item)
-
- def assertFirstLineStartsWith(self, lines, beginning):
- """Verify that the first line starts with a string
-
- :param lines: strings for each line of output
- :type lines: list
- :param beginning: verify this is at the beginning of the first line
- :type beginning: string
- """
- self.assertTrue(lines[0].startswith(beginning),
- msg=('Beginning of first line has invalid content: %s'
- % lines[:3]))
diff --git a/tempest/cli/simple_read_only/README.txt b/tempest/cli/simple_read_only/README.txt
deleted file mode 100644
index ca5fa2f..0000000
--- a/tempest/cli/simple_read_only/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-This directory consists of simple read only python client tests.
diff --git a/tempest/cli/simple_read_only/__init__.py b/tempest/cli/simple_read_only/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/cli/simple_read_only/__init__.py
+++ /dev/null
diff --git a/tempest/cli/simple_read_only/heat_templates/heat_minimal.yaml b/tempest/cli/simple_read_only/heat_templates/heat_minimal.yaml
deleted file mode 100644
index 7dcda39..0000000
--- a/tempest/cli/simple_read_only/heat_templates/heat_minimal.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-HeatTemplateFormatVersion: '2012-12-12'
-Description: Minimal template to test validation
-Parameters:
- InstanceImage:
- Description: Glance image name
- Type: String
- InstanceType:
- Description: Nova instance type
- Type: String
- Default: m1.small
- AllowedValues: [m1.tiny, m1.small, m1.medium, m1.large, m1.nano, m1.xlarge, m1.micro]
- ConstraintDescription: must be a valid nova instance type.
-Resources:
- InstanceResource:
- Type: OS::Nova::Server
- Properties:
- flavor: {Ref: InstanceType}
- image: {Ref: InstanceImage}
diff --git a/tempest/cli/simple_read_only/heat_templates/heat_minimal_hot.yaml b/tempest/cli/simple_read_only/heat_templates/heat_minimal_hot.yaml
deleted file mode 100644
index 4657bfc..0000000
--- a/tempest/cli/simple_read_only/heat_templates/heat_minimal_hot.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-heat_template_version: 2013-05-23
-description: A minimal HOT test template
-parameters:
- instance_image:
- description: Glance image name
- type: string
- instance_type:
- description: Nova instance type
- type: string
- default: m1.small
- constraints:
- - allowed_values: [m1.small, m1.medium, m1.large]
- description: instance_type must be one of m1.small, m1.medium or m1.large
-resources:
- instance:
- type: OS::Nova::Server
- properties:
- image: { get_param: instance_image }
- flavor: { get_param: instance_type }
diff --git a/tempest/cli/simple_read_only/image/__init__.py b/tempest/cli/simple_read_only/image/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/cli/simple_read_only/image/__init__.py
+++ /dev/null
diff --git a/tempest/cli/simple_read_only/image/test_glance.py b/tempest/cli/simple_read_only/image/test_glance.py
deleted file mode 100644
index e38ca48..0000000
--- a/tempest/cli/simple_read_only/image/test_glance.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import re
-
-from oslo_log import log as logging
-from tempest_lib import exceptions
-
-from tempest import cli
-from tempest import config
-from tempest import test
-
-CONF = config.CONF
-
-LOG = logging.getLogger(__name__)
-
-
-class SimpleReadOnlyGlanceClientTest(cli.ClientTestBase):
- """Basic, read-only tests for Glance CLI client.
-
- Checks return values and output of read-only commands.
- These tests do not presume any content, nor do they create
- their own. They only verify the structure of output if present.
- """
-
- @classmethod
- def resource_setup(cls):
- if not CONF.service_available.glance:
- msg = ("%s skipped as Glance is not available" % cls.__name__)
- raise cls.skipException(msg)
- super(SimpleReadOnlyGlanceClientTest, cls).resource_setup()
-
- def glance(self, *args, **kwargs):
- return self.clients.glance(*args,
- endpoint_type=CONF.image.endpoint_type,
- **kwargs)
-
- @test.idempotent_id('c6bd9bf9-717f-4458-8d74-05b682ea7adf')
- def test_glance_fake_action(self):
- self.assertRaises(exceptions.CommandFailed,
- self.glance,
- 'this-does-not-exist')
-
- @test.idempotent_id('72bcdaf3-11cd-48cb-bb8e-62b329acc1ef')
- def test_glance_image_list(self):
- out = self.glance('image-list')
- endpoints = self.parser.listing(out)
- self.assertTableStruct(endpoints, [
- 'ID', 'Name', 'Disk Format', 'Container Format',
- 'Size', 'Status'])
-
- @test.idempotent_id('965d294c-8772-4899-ba33-26ee23406135')
- def test_glance_member_list(self):
- tenant_name = '--tenant-id %s' % CONF.identity.admin_tenant_name
- out = self.glance('member-list',
- params=tenant_name)
- endpoints = self.parser.listing(out)
- self.assertTableStruct(endpoints,
- ['Image ID', 'Member ID', 'Can Share'])
-
- @test.idempotent_id('43b80ee5-4297-47f3-ab4c-6f81b9c6edb3')
- def test_glance_help(self):
- help_text = self.glance('help')
- lines = help_text.split('\n')
- self.assertFirstLineStartsWith(lines, 'usage: glance')
-
- commands = []
- cmds_start = lines.index('Positional arguments:')
- cmds_end = lines.index('Optional arguments:')
- command_pattern = re.compile('^ {4}([a-z0-9\-\_]+)')
- for line in lines[cmds_start:cmds_end]:
- match = command_pattern.match(line)
- if match:
- commands.append(match.group(1))
- commands = set(commands)
- wanted_commands = set(('image-create', 'image-delete', 'help',
- 'image-download', 'image-show', 'image-update',
- 'member-create', 'member-delete',
- 'member-list', 'image-list'))
- self.assertFalse(wanted_commands - commands)
-
- # Optional arguments:
-
- @test.idempotent_id('3b2359ea-3719-4b47-81e5-44a042572b11')
- def test_glance_version(self):
- self.glance('', flags='--version')
-
- @test.idempotent_id('1a52d3bd-3edf-4d67-b3da-999a5d9e0c5e')
- def test_glance_debug_list(self):
- self.glance('image-list', flags='--debug')
-
- @test.idempotent_id('6f42b076-f9a7-4e2b-a729-579f53e7814e')
- def test_glance_timeout(self):
- self.glance('image-list', flags='--timeout %d' % CONF.cli.timeout)
diff --git a/tempest/cli/simple_read_only/orchestration/__init__.py b/tempest/cli/simple_read_only/orchestration/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/cli/simple_read_only/orchestration/__init__.py
+++ /dev/null
diff --git a/tempest/cli/simple_read_only/orchestration/test_heat.py b/tempest/cli/simple_read_only/orchestration/test_heat.py
deleted file mode 100644
index 8defe51..0000000
--- a/tempest/cli/simple_read_only/orchestration/test_heat.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import json
-import os
-
-from oslo_log import log as logging
-import yaml
-
-import tempest.cli
-from tempest import config
-from tempest import test
-
-CONF = config.CONF
-
-LOG = logging.getLogger(__name__)
-
-
-class SimpleReadOnlyHeatClientTest(tempest.cli.ClientTestBase):
- """Basic, read-only tests for Heat CLI client.
-
- Basic smoke test for the heat CLI commands which do not require
- creating or modifying stacks.
- """
-
- @classmethod
- def resource_setup(cls):
- if (not CONF.service_available.heat):
- msg = ("Skipping all Heat cli tests because it is "
- "not available")
- raise cls.skipException(msg)
- super(SimpleReadOnlyHeatClientTest, cls).resource_setup()
- cls.heat_template_path = os.path.join(os.path.dirname(
- os.path.dirname(os.path.realpath(__file__))),
- 'heat_templates/heat_minimal.yaml')
-
- def heat(self, *args, **kwargs):
- return self.clients.heat(
- *args, endpoint_type=CONF.orchestration.endpoint_type, **kwargs)
-
- @test.idempotent_id('0ae034bb-ce35-45e8-b7aa-3e339cd3140f')
- def test_heat_stack_list(self):
- self.heat('stack-list')
-
- @test.idempotent_id('a360d069-7250-4aed-9721-0a6f2db7c3fa')
- def test_heat_stack_list_debug(self):
- self.heat('stack-list', flags='--debug')
-
- @test.idempotent_id('e1b7c177-5ab4-4d3f-8a26-ea01ebbd2b8c')
- def test_heat_resource_template_fmt_default(self):
- ret = self.heat('resource-template OS::Nova::Server')
- self.assertIn('Type: OS::Nova::Server', ret)
-
- @test.idempotent_id('93f82f76-aab2-4910-9359-11cf48f2a46b')
- def test_heat_resource_template_fmt_arg_short_yaml(self):
- ret = self.heat('resource-template -F yaml OS::Nova::Server')
- self.assertIn('Type: OS::Nova::Server', ret)
- self.assertIsInstance(yaml.safe_load(ret), dict)
-
- @test.idempotent_id('7356a98c-e14d-43f0-8c25-c9f7daa0aafa')
- def test_heat_resource_template_fmt_arg_long_json(self):
- ret = self.heat('resource-template --format json OS::Nova::Server')
- self.assertIn('"Type": "OS::Nova::Server"', ret)
- self.assertIsInstance(json.loads(ret), dict)
-
- @test.idempotent_id('2fd99d20-beff-4667-b42e-de9095f671d7')
- def test_heat_resource_type_list(self):
- ret = self.heat('resource-type-list')
- rsrc_types = self.parser.listing(ret)
- self.assertTableStruct(rsrc_types, ['resource_type'])
-
- @test.idempotent_id('62f60dbf-d139-4698-b230-a09fb531d643')
- def test_heat_resource_type_show(self):
- rsrc_schema = self.heat('resource-type-show OS::Nova::Server')
- # resource-type-show returns a json resource schema
- self.assertIsInstance(json.loads(rsrc_schema), dict)
-
- @test.idempotent_id('6ca16ff7-9d5f-4448-a8c2-4cecc7b5ba3a')
- def test_heat_template_validate_yaml(self):
- ret = self.heat('template-validate -f %s' % self.heat_template_path)
- # On success template-validate returns a json representation
- # of the template parameters
- self.assertIsInstance(json.loads(ret), dict)
-
- @test.idempotent_id('35241014-16ea-4cb6-ad3e-4ee5f41446de')
- def test_heat_template_validate_hot(self):
- ret = self.heat('template-validate -f %s' % self.heat_template_path)
- self.assertIsInstance(json.loads(ret), dict)
-
- @test.idempotent_id('34d43e0a-36dc-4ea8-9b85-0189e3de89d8')
- def test_heat_help(self):
- self.heat('help')
-
- @tempest.cli.min_client_version(client='heat', version='0.2.7')
- @test.idempotent_id('c122c08b-839d-49d1-afd1-bc546b2d18d3')
- def test_heat_bash_completion(self):
- self.heat('bash-completion')
-
- @test.idempotent_id('1b045e12-2fa0-4895-9282-00668428dfbe')
- def test_heat_help_cmd(self):
- # Check requesting help for a specific command works
- help_text = self.heat('help resource-template')
- lines = help_text.split('\n')
- self.assertFirstLineStartsWith(lines, 'usage: heat resource-template')
-
- @test.idempotent_id('c7837f8f-d0a8-47fd-b75b-14ba3e3fa9a2')
- def test_heat_version(self):
- self.heat('', flags='--version')
diff --git a/tempest/cli/simple_read_only/volume/__init__.py b/tempest/cli/simple_read_only/volume/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/cli/simple_read_only/volume/__init__.py
+++ /dev/null
diff --git a/tempest/cli/simple_read_only/volume/test_cinder.py b/tempest/cli/simple_read_only/volume/test_cinder.py
deleted file mode 100644
index cb29cc8..0000000
--- a/tempest/cli/simple_read_only/volume/test_cinder.py
+++ /dev/null
@@ -1,220 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import logging
-import re
-
-from tempest_lib import exceptions
-import testtools
-
-from tempest import cli
-from tempest import clients
-from tempest import config
-from tempest import test
-
-
-CONF = config.CONF
-LOG = logging.getLogger(__name__)
-
-
-class SimpleReadOnlyCinderClientTest(cli.ClientTestBase):
- """Basic, read-only tests for Cinder CLI client.
-
- Checks return values and output of read-only commands.
- These tests do not presume any content, nor do they create
- their own. They only verify the structure of output if present.
- """
-
- @classmethod
- def resource_setup(cls):
- if not CONF.service_available.cinder:
- msg = ("%s skipped as Cinder is not available" % cls.__name__)
- raise cls.skipException(msg)
- super(SimpleReadOnlyCinderClientTest, cls).resource_setup()
- id_cl = clients.AdminManager().identity_client
- tenant = id_cl.get_tenant_by_name(CONF.identity.admin_tenant_name)
- cls.admin_tenant_id = tenant['id']
-
- def cinder(self, *args, **kwargs):
- return self.clients.cinder(*args,
- endpoint_type=CONF.volume.endpoint_type,
- **kwargs)
-
- @test.idempotent_id('229bc6dc-d804-4668-b753-b590caf63061')
- def test_cinder_fake_action(self):
- self.assertRaises(exceptions.CommandFailed,
- self.cinder,
- 'this-does-not-exist')
-
- @test.idempotent_id('77140216-14db-4fc5-a246-e2a587e9e99b')
- def test_cinder_absolute_limit_list(self):
- roles = self.parser.listing(self.cinder('absolute-limits'))
- self.assertTableStruct(roles, ['Name', 'Value'])
-
- @test.idempotent_id('2206b9ce-1a36-4a0a-a129-e5afc7cee1dd')
- def test_cinder_backup_list(self):
- backup_list = self.parser.listing(self.cinder('backup-list'))
- self.assertTableStruct(backup_list, ['ID', 'Volume ID', 'Status',
- 'Name', 'Size', 'Object Count',
- 'Container'])
-
- @test.idempotent_id('c7f50346-cd99-4e0b-953f-796ff5f47295')
- def test_cinder_extra_specs_list(self):
- extra_specs_list = self.parser.listing(self.cinder('extra-specs-list'))
- self.assertTableStruct(extra_specs_list, ['ID', 'Name', 'extra_specs'])
-
- @test.idempotent_id('9de694cb-b40b-442c-a30c-5f9873e144f7')
- def test_cinder_volumes_list(self):
- list = self.parser.listing(self.cinder('list'))
- self.assertTableStruct(list, ['ID', 'Status', 'Name', 'Size',
- 'Volume Type', 'Bootable',
- 'Attached to'])
- self.cinder('list', params='--all-tenants 1')
- self.cinder('list', params='--all-tenants 0')
- self.assertRaises(exceptions.CommandFailed,
- self.cinder,
- 'list',
- params='--all-tenants bad')
-
- @test.idempotent_id('56f7c15c-ee82-4f23-bbe8-ce99b66da493')
- def test_cinder_quota_class_show(self):
- """This CLI can accept and string as param."""
- roles = self.parser.listing(self.cinder('quota-class-show',
- params='abc'))
- self.assertTableStruct(roles, ['Property', 'Value'])
-
- @test.idempotent_id('a919a811-b7f0-47a7-b4e5-f3eb674dd200')
- def test_cinder_quota_defaults(self):
- """This CLI can accept and string as param."""
- roles = self.parser.listing(self.cinder('quota-defaults',
- params=self.admin_tenant_id))
- self.assertTableStruct(roles, ['Property', 'Value'])
-
- @test.idempotent_id('18166673-ffa8-4df3-b60c-6375532288bc')
- def test_cinder_quota_show(self):
- """This CLI can accept and string as param."""
- roles = self.parser.listing(self.cinder('quota-show',
- params=self.admin_tenant_id))
- self.assertTableStruct(roles, ['Property', 'Value'])
-
- @test.idempotent_id('b2c66ed9-ca96-4dc4-94cc-8083e664e516')
- def test_cinder_rate_limits(self):
- rate_limits = self.parser.listing(self.cinder('rate-limits'))
- self.assertTableStruct(rate_limits, ['Verb', 'URI', 'Value', 'Remain',
- 'Unit', 'Next_Available'])
-
- @test.idempotent_id('7a19955b-807c-481a-a2ee-9d76733eac28')
- @testtools.skipUnless(CONF.volume_feature_enabled.snapshot,
- 'Volume snapshot not available.')
- def test_cinder_snapshot_list(self):
- snapshot_list = self.parser.listing(self.cinder('snapshot-list'))
- self.assertTableStruct(snapshot_list, ['ID', 'Volume ID', 'Status',
- 'Name', 'Size'])
-
- @test.idempotent_id('6e54ecd9-7ba9-490d-8e3b-294b67139e73')
- def test_cinder_type_list(self):
- type_list = self.parser.listing(self.cinder('type-list'))
- self.assertTableStruct(type_list, ['ID', 'Name'])
-
- @test.idempotent_id('2c363583-24a0-4980-b9cb-b50c0d241e82')
- def test_cinder_list_extensions(self):
- roles = self.parser.listing(self.cinder('list-extensions'))
- self.assertTableStruct(roles, ['Name', 'Summary', 'Alias', 'Updated'])
-
- @test.idempotent_id('691bd6df-30ad-4be7-927b-a02d62aaa38a')
- def test_cinder_credentials(self):
- credentials = self.parser.listing(self.cinder('credentials'))
- self.assertTableStruct(credentials, ['User Credentials', 'Value'])
-
- @test.idempotent_id('5c6d71a3-4904-4a3a-aec9-7fd4aa830e95')
- def test_cinder_availability_zone_list(self):
- zone_list = self.parser.listing(self.cinder('availability-zone-list'))
- self.assertTableStruct(zone_list, ['Name', 'Status'])
-
- @test.idempotent_id('9b0fd5a6-f955-42b9-a42f-6f542a80b9a3')
- def test_cinder_endpoints(self):
- out = self.cinder('endpoints')
- tables = self.parser.tables(out)
- for table in tables:
- headers = table['headers']
- self.assertTrue(2 >= len(headers))
- self.assertEqual('Value', headers[1])
-
- @test.idempotent_id('301b5ae1-9591-4e9f-999c-d525a9bdf822')
- def test_cinder_service_list(self):
- service_list = self.parser.listing(self.cinder('service-list'))
- self.assertTableStruct(service_list, ['Binary', 'Host', 'Zone',
- 'Status', 'State', 'Updated_at'])
-
- @test.idempotent_id('7260ae52-b462-461e-9048-36d0bccf92c6')
- def test_cinder_transfer_list(self):
- transfer_list = self.parser.listing(self.cinder('transfer-list'))
- self.assertTableStruct(transfer_list, ['ID', 'Volume ID', 'Name'])
-
- @test.idempotent_id('0976dea8-14f3-45a9-8495-3617fc4fbb13')
- def test_cinder_bash_completion(self):
- self.cinder('bash-completion')
-
- @test.idempotent_id('b7c00361-be80-4512-8735-5f98fc54f2a9')
- def test_cinder_qos_list(self):
- qos_list = self.parser.listing(self.cinder('qos-list'))
- self.assertTableStruct(qos_list, ['ID', 'Name', 'Consumer', 'specs'])
-
- @test.idempotent_id('2e92dc6e-22b5-4d94-abfc-b543b0c50a89')
- def test_cinder_encryption_type_list(self):
- encrypt_list = self.parser.listing(self.cinder('encryption-type-list'))
- self.assertTableStruct(encrypt_list, ['Volume Type ID', 'Provider',
- 'Cipher', 'Key Size',
- 'Control Location'])
-
- @test.idempotent_id('0ee6cb4c-8de6-4811-a7be-7f4bb75b80cc')
- def test_admin_help(self):
- help_text = self.cinder('help')
- lines = help_text.split('\n')
- self.assertFirstLineStartsWith(lines, 'usage: cinder')
-
- commands = []
- cmds_start = lines.index('Positional arguments:')
- cmds_end = lines.index('Optional arguments:')
- command_pattern = re.compile('^ {4}([a-z0-9\-\_]+)')
- for line in lines[cmds_start:cmds_end]:
- match = command_pattern.match(line)
- if match:
- commands.append(match.group(1))
- commands = set(commands)
- wanted_commands = set(('absolute-limits', 'list', 'help',
- 'quota-show', 'type-list', 'snapshot-list'))
- self.assertFalse(wanted_commands - commands)
-
- # Optional arguments:
-
- @test.idempotent_id('2fd6f530-183c-4bda-8918-1e59e36c26b9')
- def test_cinder_version(self):
- self.cinder('', flags='--version')
-
- @test.idempotent_id('306bac51-c443-4426-a6cf-583a953fcd68')
- def test_cinder_debug_list(self):
- self.cinder('list', flags='--debug')
-
- @test.idempotent_id('6d97fcd2-5dd1-429d-af70-030c949d86cd')
- def test_cinder_retries_list(self):
- self.cinder('list', flags='--retries 3')
-
- @test.idempotent_id('95a2850c-35b4-4159-bb93-51647a5ad232')
- def test_cinder_region_list(self):
- region = CONF.volume.region
- if not region:
- region = CONF.identity.region
- self.cinder('list', flags='--os-region-name ' + region)
diff --git a/tempest/clients.py b/tempest/clients.py
index a0c9471..9f6a9bb 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -22,6 +22,7 @@
from tempest.common import cred_provider
from tempest.common import negative_rest_client
from tempest import config
+from tempest import exceptions
from tempest import manager
from tempest.services.baremetal.v1.json.baremetal_client import \
BaremetalClientJSON
@@ -343,11 +344,22 @@
self.credentials_client = CredentialsClientJSON(self.auth_provider,
**params)
# Token clients do not use the catalog. They only need default_params.
- self.token_client = TokenClientJSON(CONF.identity.uri,
- **self.default_params)
+ # They read auth_url, so they should only be set if the corresponding
+ # API version is marked as enabled
+ if CONF.identity_feature_enabled.api_v2:
+ if CONF.identity.uri:
+ self.token_client = TokenClientJSON(
+ CONF.identity.uri, **self.default_params)
+ else:
+ msg = 'Identity v2 API enabled, but no identity.uri set'
+ raise exceptions.InvalidConfiguration(msg)
if CONF.identity_feature_enabled.api_v3:
- self.token_v3_client = V3TokenClientJSON(CONF.identity.uri_v3,
- **self.default_params)
+ if CONF.identity.uri_v3:
+ self.token_v3_client = V3TokenClientJSON(
+ CONF.identity.uri_v3, **self.default_params)
+ else:
+ msg = 'Identity v3 API enabled, but no identity.uri_v3 set'
+ raise exceptions.InvalidConfiguration(msg)
def _set_volume_clients(self):
params = {
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
new file mode 100755
index 0000000..0a48b8d
--- /dev/null
+++ b/tempest/cmd/account_generator.py
@@ -0,0 +1,266 @@
+#!/usr/bin/env python
+
+# Copyright 2015 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import argparse
+import os
+
+from oslo_log import log as logging
+import yaml
+
+from tempest import config
+from tempest import exceptions
+from tempest.services.identity.v2.json import identity_client
+import tempest_lib.auth
+from tempest_lib.common.utils import data_utils
+import tempest_lib.exceptions
+
+LOG = None
+CONF = config.CONF
+
+
+def setup_logging():
+ global LOG
+ logging.setup(CONF, __name__)
+ LOG = logging.getLogger(__name__)
+
+
+def keystone_admin(opts):
+ _creds = tempest_lib.auth.KeystoneV2Credentials(
+ username=opts.os_username,
+ password=opts.os_password,
+ tenant_name=opts.os_tenant_name)
+ auth_params = {
+ 'disable_ssl_certificate_validation':
+ CONF.identity.disable_ssl_certificate_validation,
+ 'ca_certs': CONF.identity.ca_certificates_file,
+ 'trace_requests': CONF.debug.trace_requests
+ }
+ _auth = tempest_lib.auth.KeystoneV2AuthProvider(
+ _creds, CONF.identity.uri, **auth_params)
+ params = {
+ 'disable_ssl_certificate_validation':
+ CONF.identity.disable_ssl_certificate_validation,
+ 'ca_certs': CONF.identity.ca_certificates_file,
+ 'trace_requests': CONF.debug.trace_requests,
+ 'build_interval': CONF.compute.build_interval,
+ 'build_timeout': CONF.compute.build_timeout
+ }
+ return identity_client.IdentityClientJSON(
+ _auth,
+ CONF.identity.catalog_type,
+ CONF.identity.region,
+ endpoint_type='adminURL',
+ **params
+ )
+
+
+def create_resources(opts, resources):
+ admin = keystone_admin(opts)
+ roles = admin.list_roles()
+ for u in resources['users']:
+ u['role_ids'] = []
+ for r in u.get('roles', ()):
+ try:
+ role = filter(lambda r_: r_['name'] == r, roles)[0]
+ u['role_ids'] += [role['id']]
+ except IndexError:
+ raise exceptions.TempestException(
+ "Role: %s - doesn't exist" % r
+ )
+ existing = [x['name'] for x in admin.list_tenants()]
+ for tenant in resources['tenants']:
+ if tenant not in existing:
+ admin.create_tenant(tenant)
+ else:
+ LOG.warn("Tenant '%s' already exists in this environment" % tenant)
+ LOG.info('Tenants created')
+ for u in resources['users']:
+ try:
+ tenant = admin.get_tenant_by_name(u['tenant'])
+ except tempest_lib.exceptions.NotFound:
+ LOG.error("Tenant: %s - not found" % u['tenant'])
+ continue
+ while True:
+ try:
+ admin.get_user_by_username(tenant['id'], u['name'])
+ except tempest_lib.exceptions.NotFound:
+ admin.create_user(
+ u['name'], u['pass'], tenant['id'],
+ "%s@%s" % (u['name'], tenant['id']),
+ enabled=True)
+ break
+ else:
+ LOG.warn("User '%s' already exists in this environment. "
+ "New name generated" % u['name'])
+ u['name'] = random_user_name(opts.tag, u['prefix'])
+
+ LOG.info('Users created')
+ for u in resources['users']:
+ try:
+ tenant = admin.get_tenant_by_name(u['tenant'])
+ except tempest_lib.exceptions.NotFound:
+ LOG.error("Tenant: %s - not found" % u['tenant'])
+ continue
+ try:
+ user = admin.get_user_by_username(tenant['id'],
+ u['name'])
+ except tempest_lib.exceptions.NotFound:
+ LOG.error("User: %s - not found" % u['user'])
+ continue
+ for r in u['role_ids']:
+ try:
+ admin.assign_user_role(tenant['id'], user['id'], r)
+ except tempest_lib.exceptions.Conflict:
+ # don't care if it's already assigned
+ pass
+ LOG.info('Roles assigned')
+ LOG.info('Resources deployed successfully!')
+
+
+def random_user_name(tag, prefix):
+ if tag:
+ return data_utils.rand_name('-'.join((tag, prefix)))
+ else:
+ return data_utils.rand_name(prefix)
+
+
+def generate_resources(opts):
+ spec = [{'number': 1,
+ 'prefix': 'primary',
+ 'roles': (CONF.auth.tempest_roles +
+ [CONF.object_storage.operator_role])},
+ {'number': 1,
+ 'prefix': 'alt',
+ 'roles': (CONF.auth.tempest_roles +
+ [CONF.object_storage.operator_role])},
+ {'number': 1,
+ 'prefix': 'swift_admin',
+ 'roles': (CONF.auth.tempest_roles +
+ [CONF.object_storage.operator_role,
+ CONF.object_storage.reseller_admin_role])},
+ {'number': 1,
+ 'prefix': 'stack_owner',
+ 'roles': (CONF.auth.tempest_roles +
+ [CONF.orchestration.stack_owner_role])},
+ ]
+ if opts.admin:
+ spec.append({
+ 'number': 1,
+ 'prefix': 'admin',
+ 'roles': (CONF.auth.tempest_roles +
+ [CONF.identity.admin_role])
+ })
+ resources = {'tenants': [],
+ 'users': []}
+ for count in range(opts.concurrency):
+ for user_group in spec:
+ users = [random_user_name(opts.tag, user_group['prefix'])
+ for _ in range(user_group['number'])]
+ for user in users:
+ tenant = '-'.join((user, 'tenant'))
+ resources['tenants'].append(tenant)
+ resources['users'].append({
+ 'tenant': tenant,
+ 'name': user,
+ 'pass': data_utils.rand_name(),
+ 'prefix': user_group['prefix'],
+ 'roles': user_group['roles']
+ })
+ return resources
+
+
+def dump_accounts(opts, resources):
+ accounts = []
+ for user in resources['users']:
+ accounts.append({
+ 'username': user['name'],
+ 'tenant_name': user['tenant'],
+ 'password': user['pass'],
+ 'roles': user['roles']
+ })
+ if os.path.exists(opts.accounts):
+ os.rename(opts.accounts, '.'.join((opts.accounts, 'bak')))
+ with open(opts.accounts, 'w') as f:
+ yaml.dump(accounts, f, default_flow_style=False)
+ LOG.info('%s generated successfully!' % opts.accounts)
+
+
+def get_options():
+ usage_string = ('account_generator [-h] <ARG> ...\n\n'
+ 'To see help on specific argument, do:\n'
+ 'account_generator <ARG> -h')
+ parser = argparse.ArgumentParser(
+ description='Create accounts.yaml file for concurrent test runs. '
+ 'One primary user, one alt user, '
+ 'one swift admin, one stack owner '
+ 'and one admin (optionally) will be created '
+ 'for each concurrent thread.',
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+ usage=usage_string
+ )
+
+ parser.add_argument('-c', '--config-file',
+ metavar='/etc/tempest.conf',
+ help='path to tempest config file')
+ parser.add_argument('--os-username',
+ metavar='<auth-user-name>',
+ default=os.environ.get('OS_USERNAME'),
+ help='User should have permitions '
+ 'to create new user accounts and '
+ 'tenants. Defaults to env[OS_USERNAME].')
+ parser.add_argument('--os-password',
+ metavar='<auth-password>',
+ default=os.environ.get('OS_PASSWORD'),
+ help='Defaults to env[OS_PASSWORD].')
+ parser.add_argument('--os-tenant-name',
+ metavar='<auth-tenant-name>',
+ default=os.environ.get('OS_TENANT_NAME'),
+ help='Defaults to env[OS_TENANT_NAME].')
+ parser.add_argument('--tag',
+ default='',
+ required=False,
+ dest='tag',
+ help='Resources tag')
+ parser.add_argument('-r', '--concurrency',
+ default=1,
+ type=int,
+ required=True,
+ dest='concurrency',
+ help='Concurrency count')
+ parser.add_argument('--with-admin',
+ action='store_true',
+ dest='admin',
+ help='Create admin in every tenant')
+ parser.add_argument('accounts',
+ metavar='accounts_file.yaml',
+ help='Output accounts yaml file')
+
+ opts = parser.parse_args()
+ if opts.config_file:
+ config.CONF.set_config_path(opts.config_file)
+ return opts
+
+
+def main(opts=None):
+ if not opts:
+ opts = get_options()
+ setup_logging()
+ resources = generate_resources(opts)
+ create_resources(opts, resources)
+ dump_accounts(opts, resources)
+
+if __name__ == "__main__":
+ main()
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 1ad12eb..eb6f143 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -343,6 +343,44 @@
self.data['volumes'] = vols
+class VolumeQuotaService(BaseService):
+ def __init__(self, manager, **kwargs):
+ super(VolumeQuotaService, self).__init__(kwargs)
+ self.client = manager.volume_quotas_client
+
+ def delete(self):
+ client = self.client
+ try:
+ client.delete_quota_set(self.tenant_id)
+ except Exception as e:
+ LOG.exception("Delete Volume Quotas exception: %s" % e)
+ pass
+
+ def dry_run(self):
+ quotas = self.client.show_quota_usage(self.tenant_id)
+ self.data['volume_quotas'] = quotas
+
+
+class NovaQuotaService(BaseService):
+ def __init__(self, manager, **kwargs):
+ super(NovaQuotaService, self).__init__(kwargs)
+ self.client = manager.quotas_client
+ self.limits_client = manager.limits_client
+
+ def delete(self):
+ client = self.client
+ try:
+ client.delete_quota_set(self.tenant_id)
+ except Exception as e:
+ LOG.exception("Delete Quotas exception: %s" % e)
+ pass
+
+ def dry_run(self):
+ client = self.limits_client
+ quotas = client.get_absolute_limits()
+ self.data['compute_quotas'] = quotas
+
+
# Begin network service classes
class NetworkService(BaseService):
def __init__(self, manager, **kwargs):
@@ -667,7 +705,7 @@
self.data['pools'] = pools
-class NetworMeteringLabelRuleService(NetworkService):
+class NetworkMeteringLabelRuleService(NetworkService):
def list(self):
client = self.client
@@ -692,7 +730,7 @@
self.data['rules'] = rules
-class NetworMeteringLabelService(NetworkService):
+class NetworkMeteringLabelService(NetworkService):
def list(self):
client = self.client
@@ -1052,6 +1090,7 @@
tenant_services.append(ServerGroupService)
if not IS_NEUTRON:
tenant_services.append(FloatingIpService)
+ tenant_services.append(NovaQuotaService)
if IS_HEAT:
tenant_services.append(StackService)
if IS_NEUTRON:
@@ -1068,8 +1107,8 @@
tenant_services.append(NetworkVipService)
tenant_services.append(NetworkPoolService)
if test.is_extension_enabled('metering', 'network'):
- tenant_services.append(NetworMeteringLabelRuleService)
- tenant_services.append(NetworMeteringLabelService)
+ tenant_services.append(NetworkMeteringLabelRuleService)
+ tenant_services.append(NetworkMeteringLabelService)
tenant_services.append(NetworkRouterService)
tenant_services.append(NetworkFloatingIpService)
tenant_services.append(NetworkPortService)
@@ -1078,6 +1117,7 @@
if IS_CINDER:
tenant_services.append(SnapshotService)
tenant_services.append(VolumeService)
+ tenant_services.append(VolumeQuotaService)
return tenant_services
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index b2311b0..d3426c6 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -114,6 +114,7 @@
import netaddr
from oslo_log import log as logging
from oslo_utils import timeutils
+import six
from tempest_lib import auth
from tempest_lib import exceptions as lib_exc
import yaml
@@ -416,7 +417,7 @@
that things like tenantId didn't drift across versions.
"""
LOG.info("checking users")
- for name, user in self.users.iteritems():
+ for name, user in six.iteritems(self.users):
client = keystone_admin()
found = client.identity.get_user(user['id'])
self.assertEqual(found['name'], user['name'])
@@ -616,7 +617,7 @@
def _get_image_by_name(client, name):
- body = client.images.image_list()
+ body = client.images.list_images()
for image in body:
if name == image['name']:
return image
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index f1965bc..f51d9aa 100755
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -94,7 +94,7 @@
versions = map(lambda x: x['id'], body['versions']['values'])
else:
versions = map(lambda x: x['id'], body['versions'])
- return versions
+ return list(versions)
def verify_keystone_api_versions(os, update):
@@ -175,6 +175,7 @@
else:
extensions = map(lambda x: x['alias'], resp)
+ extensions = list(extensions)
if not results.get(service):
results[service] = {}
extensions_opt = get_enabled_extensions(service)
@@ -335,25 +336,28 @@
CONF_PARSER.optionxform = str
CONF_PARSER.readfp(conf_file)
icreds = credentials.get_isolated_credentials('verify_tempest_config')
- os = clients.Manager(icreds.get_primary_creds())
- services = check_service_availability(os, update)
- results = {}
- for service in ['nova', 'cinder', 'neutron', 'swift']:
- if service not in services:
- continue
- results = verify_extensions(os, service, results)
+ try:
+ os = clients.Manager(icreds.get_primary_creds())
+ services = check_service_availability(os, update)
+ results = {}
+ for service in ['nova', 'cinder', 'neutron', 'swift']:
+ if service not in services:
+ continue
+ results = verify_extensions(os, service, results)
- # Verify API versions of all services in the keystone catalog and keystone
- # itself.
- services.append('keystone')
- for service in services:
- verify_api_versions(os, service, update)
+ # Verify API versions of all services in the keystone catalog and
+ # keystone itself.
+ services.append('keystone')
+ for service in services:
+ verify_api_versions(os, service, update)
- display_results(results, update, replace)
- if update:
- conf_file.close()
- CONF_PARSER.write(outfile)
- outfile.close()
+ display_results(results, update, replace)
+ if update:
+ conf_file.close()
+ CONF_PARSER.write(outfile)
+ outfile.close()
+ finally:
+ icreds.clear_isolated_creds()
if __name__ == "__main__":
diff --git a/tempest/common/accounts.py b/tempest/common/accounts.py
index 93c8bcf..650faf1 100644
--- a/tempest/common/accounts.py
+++ b/tempest/common/accounts.py
@@ -17,6 +17,7 @@
from oslo_concurrency import lockutils
from oslo_log import log as logging
+import six
import yaml
from tempest import clients
@@ -75,7 +76,7 @@
if 'resources' in account:
resources = account.pop('resources')
temp_hash = hashlib.md5()
- temp_hash.update(str(account))
+ temp_hash.update(six.text_type(account).encode('utf-8'))
temp_hash_key = temp_hash.hexdigest()
hash_dict['creds'][temp_hash_key] = account
for role in roles:
@@ -244,17 +245,19 @@
def get_creds_by_roles(self, roles, force_new=False):
roles = list(set(roles))
- exist_creds = self.isolated_creds.get(str(roles), None)
+ exist_creds = self.isolated_creds.get(six.text_type(roles).encode(
+ 'utf-8'), None)
# The force kwarg is used to allocate an additional set of creds with
# the same role list. The index used for the previously allocation
# in the isolated_creds dict will be moved.
if exist_creds and not force_new:
return exist_creds
elif exist_creds and force_new:
- new_index = str(roles) + '-' + str(len(self.isolated_creds))
+ new_index = six.text_type(roles).encode('utf-8') + '-' + \
+ six.text_type(len(self.isolated_creds)).encode('utf-8')
self.isolated_creds[new_index] = exist_creds
net_creds = self._get_creds(roles=roles)
- self.isolated_creds[str(roles)] = net_creds
+ self.isolated_creds[six.text_type(roles).encode('utf-8')] = net_creds
return net_creds
def clear_isolated_creds(self):
@@ -283,8 +286,11 @@
net_clients = clients.Manager(credentials=credential)
compute_network_client = net_clients.networks_client
net_name = self.hash_dict['networks'].get(hash, None)
- network = fixed_network.get_network_from_name(
- net_name, compute_network_client)
+ try:
+ network = fixed_network.get_network_from_name(
+ net_name, compute_network_client)
+ except exceptions.InvalidConfiguration:
+ network = {}
net_creds.set_resources(network=network)
return net_creds
diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py
index 298a94e..839088c 100644
--- a/tempest/common/custom_matchers.py
+++ b/tempest/common/custom_matchers.py
@@ -14,6 +14,7 @@
import re
+import six
from testtools import helpers
@@ -121,7 +122,7 @@
"""
def match(self, actual):
- for key, value in actual.iteritems():
+ for key, value in six.iteritems(actual):
if key in ('content-length', 'x-account-bytes-used',
'x-account-container-count', 'x-account-object-count',
'x-container-bytes-used', 'x-container-object-count')\
diff --git a/tempest/common/fixed_network.py b/tempest/common/fixed_network.py
index 1557474..2c6e334 100644
--- a/tempest/common/fixed_network.py
+++ b/tempest/common/fixed_network.py
@@ -17,6 +17,7 @@
from tempest_lib import exceptions as lib_exc
from tempest import config
+from tempest import exceptions
CONF = config.CONF
@@ -29,51 +30,59 @@
:param str name: the name of the network to use
:param NetworksClientJSON compute_networks_client: The network client
object to use for making the network lists api request
- :return: The full dictionary for the network in question, unless the
- network for the supplied name can not be found. In which case a dict
- with just the name will be returned.
+ :return: The full dictionary for the network in question
:rtype: dict
+ :raises InvalidConfiguration: If the name provided is invalid, the networks
+ list returns a 404, there are no found networks, or the found network
+ is invalid
"""
caller = misc_utils.find_test_caller()
+
if not name:
- network = {'name': name}
+ raise exceptions.InvalidConfiguration()
+
+ try:
+ networks = compute_networks_client.list_networks(name=name)
+ except lib_exc.NotFound:
+ # In case of nova network, if the fixed_network_name is not
+ # owned by the tenant, and the network client is not an admin
+ # one, list_networks will not find it
+ msg = ('Unable to find network %s. '
+ 'Starting instance without specifying a network.' %
+ name)
+ if caller:
+ msg = '(%s) %s' % (caller, msg)
+ LOG.info(msg)
+ raise exceptions.InvalidConfiguration()
+
+ # Check that a network exists, else raise an InvalidConfigurationException
+ if len(networks) == 1:
+ network = sorted(networks)[0]
+ elif len(networks) > 1:
+ msg = ("Network with name: %s had multiple matching networks in the "
+ "list response: %s\n Unable to specify a single network" % (
+ name, networks))
+ if caller:
+ msg = '(%s) %s' % (caller, msg)
+ LOG.warn(msg)
+ raise exceptions.InvalidConfiguration()
else:
- try:
- resp = compute_networks_client.list_networks(name=name)
- if isinstance(resp, list):
- networks = resp
- elif isinstance(resp, dict):
- networks = resp['networks']
- else:
- raise lib_exc.NotFound()
- if len(networks) > 0:
- network = networks[0]
- else:
- msg = "Network with name: %s not found" % name
- if caller:
- LOG.warn('(%s) %s' % (caller, msg))
- else:
- LOG.warn(msg)
- raise lib_exc.NotFound()
- # To be consistent with network isolation, add name is only
- # label is available
- name = network.get('name', network.get('label'))
- if name:
- network['name'] = name
- else:
- raise lib_exc.NotFound()
- except lib_exc.NotFound:
- # In case of nova network, if the fixed_network_name is not
- # owned by the tenant, and the network client is not an admin
- # one, list_networks will not find it
- msg = ('Unable to find network %s. '
- 'Starting instance without specifying a network.' %
- name)
- if caller:
- LOG.info('(%s) %s' % (caller, msg))
- else:
- LOG.info(msg)
- network = {'name': name}
+ msg = "Network with name: %s not found" % name
+ if caller:
+ msg = '(%s) %s' % (caller, msg)
+ LOG.warn(msg)
+ raise exceptions.InvalidConfiguration()
+ # To be consistent between neutron and nova network always use name even
+ # if label is used in the api response. If neither is present than then
+ # the returned network is invalid.
+ name = network.get('name') or network.get('label')
+ if not name:
+ msg = "Network found from list doesn't contain a valid name or label"
+ if caller:
+ msg = '(%s) %s' % (caller, msg)
+ LOG.warn(msg)
+ raise exceptions.InvalidConfiguration()
+ network['name'] = name
return network
@@ -97,16 +106,17 @@
msg = ('No valid network provided or created, defaulting to '
'fixed_network_name')
if caller:
- LOG.debug('(%s) %s' % (caller, msg))
- else:
- LOG.debug(msg)
- network = get_network_from_name(fixed_network_name,
- compute_networks_client)
+ msg = '(%s) %s' % (caller, msg)
+ LOG.debug(msg)
+ try:
+ network = get_network_from_name(fixed_network_name,
+ compute_networks_client)
+ except exceptions.InvalidConfiguration:
+ network = {}
msg = ('Found network %s available for tenant' % network)
if caller:
- LOG.info('(%s) %s' % (caller, msg))
- else:
- LOG.info(msg)
+ msg = '(%s) %s' % (caller, msg)
+ LOG.info(msg)
return network
diff --git a/tempest/common/generator/base_generator.py b/tempest/common/generator/base_generator.py
index f81f405..3e09300 100644
--- a/tempest/common/generator/base_generator.py
+++ b/tempest/common/generator/base_generator.py
@@ -17,8 +17,8 @@
import functools
import jsonschema
-
from oslo_log import log as logging
+import six
LOG = logging.getLogger(__name__)
@@ -122,7 +122,7 @@
if schema_type == 'object':
properties = schema["properties"]
- for attribute, definition in properties.iteritems():
+ for attribute, definition in six.iteritems(properties):
current_path = copy.copy(path)
if path is not None:
current_path.append(attribute)
diff --git a/tempest/common/generator/valid_generator.py b/tempest/common/generator/valid_generator.py
index 0c63bf5..2213b4a 100644
--- a/tempest/common/generator/valid_generator.py
+++ b/tempest/common/generator/valid_generator.py
@@ -14,6 +14,7 @@
# under the License.
from oslo_log import log as logging
+import six
import tempest.common.generator.base_generator as base
@@ -51,7 +52,7 @@
@base.simple_generator
def generate_valid_object(self, schema):
obj = {}
- for k, v in schema["properties"].iteritems():
+ for k, v in six.iteritems(schema["properties"]):
obj[k] = self.generate_valid(v)
return obj
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index 1f85872..5ded3ee 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -311,7 +311,8 @@
LOG.info("Acquired isolated creds:\n credentials: %s"
% credentials)
if (CONF.service_available.neutron and
- not CONF.baremetal.driver_enabled):
+ not CONF.baremetal.driver_enabled and
+ CONF.auth.create_isolated_networks):
network, subnet, router = self._create_network_resources(
credentials.tenant_id)
credentials.set_resources(network=network, subnet=subnet,
@@ -413,7 +414,7 @@
if not self.isolated_creds:
return
self._clear_isolated_net_resources()
- for creds in self.isolated_creds.itervalues():
+ for creds in six.itervalues(self.isolated_creds):
try:
self.creds_client.delete_user(creds.user_id)
except lib_exc.NotFound:
diff --git a/tempest/common/ssh.py b/tempest/common/ssh.py
deleted file mode 100644
index d0e484c..0000000
--- a/tempest/common/ssh.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import select
-import socket
-import time
-import warnings
-
-from oslo_log import log as logging
-import six
-from six import moves
-
-from tempest import exceptions
-
-
-with warnings.catch_warnings():
- warnings.simplefilter("ignore")
- import paramiko
-
-
-LOG = logging.getLogger(__name__)
-
-
-class Client(object):
-
- def __init__(self, host, username, password=None, timeout=300, pkey=None,
- channel_timeout=10, look_for_keys=False, key_filename=None):
- self.host = host
- self.username = username
- self.password = password
- if isinstance(pkey, six.string_types):
- pkey = paramiko.RSAKey.from_private_key(
- moves.cStringIO(str(pkey)))
- self.pkey = pkey
- self.look_for_keys = look_for_keys
- self.key_filename = key_filename
- self.timeout = int(timeout)
- self.channel_timeout = float(channel_timeout)
- self.buf_size = 1024
-
- def _get_ssh_connection(self, sleep=1.5, backoff=1):
- """Returns an ssh connection to the specified host."""
- bsleep = sleep
- ssh = paramiko.SSHClient()
- ssh.set_missing_host_key_policy(
- paramiko.AutoAddPolicy())
- _start_time = time.time()
- if self.pkey is not None:
- LOG.info("Creating ssh connection to '%s' as '%s'"
- " with public key authentication",
- self.host, self.username)
- else:
- LOG.info("Creating ssh connection to '%s' as '%s'"
- " with password %s",
- self.host, self.username, str(self.password))
- attempts = 0
- while True:
- try:
- ssh.connect(self.host, username=self.username,
- password=self.password,
- look_for_keys=self.look_for_keys,
- key_filename=self.key_filename,
- timeout=self.channel_timeout, pkey=self.pkey)
- LOG.info("ssh connection to %s@%s successfuly created",
- self.username, self.host)
- return ssh
- except (socket.error,
- paramiko.SSHException) as e:
- if self._is_timed_out(_start_time):
- LOG.exception("Failed to establish authenticated ssh"
- " connection to %s@%s after %d attempts",
- self.username, self.host, attempts)
- raise exceptions.SSHTimeout(host=self.host,
- user=self.username,
- password=self.password)
- bsleep += backoff
- attempts += 1
- LOG.warning("Failed to establish authenticated ssh"
- " connection to %s@%s (%s). Number attempts: %s."
- " Retry after %d seconds.",
- self.username, self.host, e, attempts, bsleep)
- time.sleep(bsleep)
-
- def _is_timed_out(self, start_time):
- return (time.time() - self.timeout) > start_time
-
- def exec_command(self, cmd):
- """
- Execute the specified command on the server.
-
- Note that this method is reading whole command outputs to memory, thus
- shouldn't be used for large outputs.
-
- :returns: data read from standard output of the command.
- :raises: SSHExecCommandFailed if command returns nonzero
- status. The exception contains command status stderr content.
- """
- ssh = self._get_ssh_connection()
- transport = ssh.get_transport()
- channel = transport.open_session()
- channel.fileno() # Register event pipe
- channel.exec_command(cmd)
- channel.shutdown_write()
- out_data = []
- err_data = []
- poll = select.poll()
- poll.register(channel, select.POLLIN)
- start_time = time.time()
-
- while True:
- ready = poll.poll(self.channel_timeout)
- if not any(ready):
- if not self._is_timed_out(start_time):
- continue
- raise exceptions.TimeoutException(
- "Command: '{0}' executed on host '{1}'.".format(
- cmd, self.host))
- if not ready[0]: # If there is nothing to read.
- continue
- out_chunk = err_chunk = None
- if channel.recv_ready():
- out_chunk = channel.recv(self.buf_size)
- out_data += out_chunk,
- if channel.recv_stderr_ready():
- err_chunk = channel.recv_stderr(self.buf_size)
- err_data += err_chunk,
- if channel.closed and not err_chunk and not out_chunk:
- break
- exit_status = channel.recv_exit_status()
- if 0 != exit_status:
- raise exceptions.SSHExecCommandFailed(
- command=cmd, exit_status=exit_status,
- strerror=''.join(err_data))
- return ''.join(out_data)
-
- def test_connection_auth(self):
- """Raises an exception when we can not connect to server via ssh."""
- connection = self._get_ssh_connection()
- connection.close()
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 29fb493..4b3995b 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -15,8 +15,8 @@
import time
import six
+from tempest_lib.common import ssh
-from tempest.common import ssh
from tempest import config
from tempest import exceptions
@@ -46,6 +46,9 @@
channel_timeout=ssh_channel_timeout)
def exec_command(self, cmd):
+ # Shell options below add more clearness on failures,
+ # path is extended for some non-cirros guest oses (centos7)
+ cmd = "set -eu -o pipefail; PATH=$PATH:/sbin; " + cmd
return self.ssh_client.exec_command(cmd)
def validate_authentication(self):
@@ -95,26 +98,26 @@
return self.exec_command(cmd)
def get_mac_address(self):
- cmd = "/bin/ip addr | awk '/ether/ {print $2}'"
+ cmd = "ip addr | awk '/ether/ {print $2}'"
return self.exec_command(cmd)
def get_nic_name(self, address):
- cmd = "/bin/ip -o addr | awk '/%s/ {print $2}'" % address
+ cmd = "ip -o addr | awk '/%s/ {print $2}'" % address
return self.exec_command(cmd)
def get_ip_list(self):
- cmd = "/bin/ip address"
+ cmd = "ip address"
return self.exec_command(cmd)
def assign_static_ip(self, nic, addr):
- cmd = "sudo /bin/ip addr add {ip}/{mask} dev {nic}".format(
+ cmd = "sudo ip addr add {ip}/{mask} dev {nic}".format(
ip=addr, mask=CONF.network.tenant_network_mask_bits,
nic=nic
)
return self.exec_command(cmd)
def turn_nic_on(self, nic):
- cmd = "sudo /bin/ip link set {nic} up".format(nic=nic)
+ cmd = "sudo ip link set {nic} up".format(nic=nic)
return self.exec_command(cmd)
def get_pids(self, pr_name):
diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py
new file mode 100644
index 0000000..d370ebc
--- /dev/null
+++ b/tempest/common/validation_resources.py
@@ -0,0 +1,113 @@
+# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from oslo_log import log as logging
+
+from tempest import config
+from tempest_lib.common.utils import data_utils
+from tempest_lib import exceptions as lib_exc
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+def create_ssh_security_group(os, add_rule=False):
+ security_group_client = os.security_groups_client
+ sg_name = data_utils.rand_name('securitygroup-')
+ sg_description = data_utils.rand_name('description-')
+ security_group = \
+ security_group_client.create_security_group(sg_name, sg_description)
+ if add_rule:
+ security_group_client.create_security_group_rule(security_group['id'],
+ 'tcp', 22, 22)
+ security_group_client.create_security_group_rule(security_group['id'],
+ 'icmp', -1, -1)
+ LOG.debug("SSH Validation resource security group with tcp and icmp "
+ "rules %s created"
+ % sg_name)
+ return security_group
+
+
+def create_validation_resources(os, validation_resources=None):
+ # Create and Return the validation resources required to validate a VM
+ validation_data = {}
+ if validation_resources:
+ if validation_resources['keypair']:
+ keypair_name = data_utils.rand_name('keypair')
+ validation_data['keypair'] = \
+ os.keypairs_client.create_keypair(keypair_name)
+ LOG.debug("Validation resource key %s created" % keypair_name)
+ add_rule = False
+ if validation_resources['security_group']:
+ if validation_resources['security_group_rules']:
+ add_rule = True
+ validation_data['security_group'] = \
+ create_ssh_security_group(os, add_rule)
+ if validation_resources['floating_ip']:
+ floating_client = os.floating_ips_client
+ validation_data['floating_ip'] = \
+ floating_client.create_floating_ip()
+ return validation_data
+
+
+def clear_validation_resources(os, validation_data=None):
+ # Cleanup the vm validation resources
+ has_exception = None
+ if validation_data:
+ if 'keypair' in validation_data:
+ keypair_client = os.keypairs_client
+ keypair_name = validation_data['keypair']['name']
+ try:
+ keypair_client.delete_keypair(keypair_name)
+ except lib_exc.NotFound:
+ LOG.warn("Keypair %s is not found when attempting to delete"
+ % keypair_name)
+ except Exception as exc:
+ LOG.exception('Exception raised while deleting key %s'
+ % keypair_name)
+ if not has_exception:
+ has_exception = exc
+ if 'security_group' in validation_data:
+ security_group_client = os.security_groups_client
+ sec_id = validation_data['security_group']['id']
+ try:
+ security_group_client.delete_security_group(sec_id)
+ security_group_client.wait_for_resource_deletion(sec_id)
+ except lib_exc.NotFound:
+ LOG.warn("Security group %s is not found when attempting to "
+ " delete" % sec_id)
+ except lib_exc.Conflict as exc:
+ LOG.exception('Conflict while deleting security '
+ 'group %s VM might not be deleted ' % sec_id)
+ if not has_exception:
+ has_exception = exc
+ except Exception as exc:
+ LOG.exception('Exception raised while deleting security '
+ 'group %s ' % sec_id)
+ if not has_exception:
+ has_exception = exc
+ if 'floating_ip' in validation_data:
+ floating_client = os.floating_ips_client
+ fip_id = validation_data['floating_ip']['id']
+ try:
+ floating_client.delete_floating_ip(fip_id)
+ except lib_exc.NotFound:
+ LOG.warn('Floating ip %s not found while attempting to delete'
+ % fip_id)
+ except Exception as exc:
+ LOG.exception('Exception raised while deleting ip %s '
+ % fip_id)
+ if not has_exception:
+ has_exception = exc
+ if has_exception:
+ raise has_exception
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index 64ff7f2..249bac9 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -99,15 +99,15 @@
def wait_for_image_status(client, image_id, status):
"""Waits for an image to reach a given status.
- The client should have a get_image(image_id) method to get the image.
+ The client should have a show_image(image_id) method to get the image.
The client should also have build_interval and build_timeout attributes.
"""
- image = client.get_image(image_id)
+ image = client.show_image(image_id)
start = int(time.time())
while image['status'] != status:
time.sleep(client.build_interval)
- image = client.get_image(image_id)
+ image = client.show_image(image_id)
status_curr = image['status']
if status_curr == 'ERROR':
raise exceptions.AddImageException(image_id=image_id)
diff --git a/tempest/config.py b/tempest/config.py
index bcbe41f..603ccd2 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -69,7 +69,15 @@
help="Only applicable when identity.auth_version is v3."
"Domain within which isolated credentials are provisioned."
"The default \"None\" means that the domain from the"
- "admin user is used instead.")
+ "admin user is used instead."),
+ cfg.BoolOpt('create_isolated_networks',
+ default=True,
+ help="If allow_tenant_isolation is set to True and Neutron is "
+ "enabled Tempest will try to create a useable network, "
+ "subnet, and router when needed for each tenant it "
+ "creates. However in some neutron configurations, like "
+ "with VLAN provider networks, this doesn't work. So if "
+ "set to False the isolated networks will not be created"),
]
identity_group = cfg.OptGroup(name='identity',
@@ -142,6 +150,9 @@
cfg.StrOpt('admin_domain_name',
help="Admin domain name for authentication (Keystone V3)."
"The same domain applies to user and project"),
+ cfg.StrOpt('default_domain_id',
+ default='default',
+ help="ID of the default domain"),
]
identity_feature_group = cfg.OptGroup(name='identity-feature-enabled',
@@ -195,9 +206,6 @@
help="Timeout in seconds to wait for an instance to build. "
"Other services that do not define build_timeout will "
"inherit this value."),
- cfg.BoolOpt('run_ssh',
- default=False,
- help="Should the tests ssh to instances?"),
cfg.StrOpt('ssh_auth_method',
default='keypair',
help="Auth method used for authenticate to the instance. "
@@ -249,7 +257,7 @@
cfg.StrOpt('network_for_ssh',
default='public',
help="Network used for SSH connections. Ignored if "
- "use_floatingip_for_ssh=true or run_ssh=false."),
+ "use_floatingip_for_ssh=true or run_validation=false."),
cfg.IntOpt('ip_version_for_ssh',
default=4,
help="IP version used for SSH connections."),
@@ -335,6 +343,13 @@
help="Does the test environment block migration support "
"cinder iSCSI volumes. Note, libvirt doesn't support this, "
"see https://bugs.launchpad.net/nova/+bug/1398999"),
+ # TODO(gilliard): Remove live_migrate_paused_instances at juno-eol.
+ cfg.BoolOpt('live_migrate_paused_instances',
+ default=False,
+ help="Does the test system allow live-migration of paused "
+ "instances? Note, this is more than just the ANDing of "
+ "paused and live_migrate, but all 3 should be set to True "
+ "to run those tests"),
cfg.BoolOpt('vnc_console',
default=False,
help='Enable VNC console. This configuration value should '
@@ -551,6 +566,12 @@
title='SSH Validation options')
ValidationGroup = [
+ cfg.BoolOpt('run_validation',
+ default=False,
+ help='Enable ssh on created servers and creation of additional'
+ ' validation resources to enable remote access',
+ deprecated_opts=[cfg.DeprecatedOpt('run_ssh',
+ group='compute')]),
cfg.StrOpt('connect_method',
default='floating',
choices=['fixed', 'floating'],
@@ -647,6 +668,10 @@
cfg.BoolOpt('api_v2',
default=True,
help="Is the v2 volume API enabled"),
+ cfg.BoolOpt('bootable',
+ default=False,
+ help='Update bootable status of a volume '
+ 'Not implemented on icehouse ')
]
@@ -933,6 +958,8 @@
cfg.StrOpt('img_container_format',
default='bare',
help='Image container format'),
+ cfg.DictOpt('img_properties', help='Glance image properties. '
+ 'Use for custom images which require them'),
cfg.StrOpt('ami_img_file',
default='cirros-0.3.1-x86_64-blank.img',
help='AMI image file name'),
@@ -1091,25 +1118,6 @@
help="Timeout for unprovisioning an Ironic node.")
]
-cli_group = cfg.OptGroup(name='cli', title="cli Configuration Options")
-
-CLIGroup = [
- cfg.BoolOpt('enabled',
- default=True,
- help="enable cli tests"),
- cfg.StrOpt('cli_dir',
- default='/usr/local/bin',
- help="directory where python client binaries are located"),
- cfg.BoolOpt('has_manage',
- default=True,
- help=("Whether the tempest run location has access to the "
- "*-manage commands. In a pure blackbox environment "
- "it will not.")),
- cfg.IntOpt('timeout',
- default=15,
- help="Number of seconds to wait on a CLI timeout"),
-]
-
negative_group = cfg.OptGroup(name='negative', title="Negative Test Options")
NegativeGroup = [
@@ -1148,7 +1156,6 @@
(debug_group, DebugGroup),
(baremetal_group, BaremetalGroup),
(input_scenario_group, InputScenarioGroup),
- (cli_group, CLIGroup),
(negative_group, NegativeGroup)
]
@@ -1212,7 +1219,6 @@
self.debug = _CONF.debug
self.baremetal = _CONF.baremetal
self.input_scenario = _CONF['input-scenario']
- self.cli = _CONF.cli
self.negative = _CONF.negative
_CONF.set_default('domain_name', self.identity.admin_domain_name,
group='identity')
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 09f7016..15617c6 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -128,17 +128,6 @@
message = "Got identity error"
-class SSHTimeout(TempestException):
- message = ("Connection to the %(host)s via SSH timed out.\n"
- "User: %(user)s, Password: %(password)s")
-
-
-class SSHExecCommandFailed(TempestException):
- """Raised when remotely executed command returns nonzero status."""
- message = ("Command '%(command)s', exit status: %(exit_status)d, "
- "Error:\n%(strerror)s")
-
-
class ServerUnreachable(TempestException):
message = "The server is not reachable via the configured network"
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 98bacf0..5f8d605 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -20,9 +20,9 @@
from oslo_log import log
import six
from tempest_lib.common.utils import data_utils
+from tempest_lib.common.utils import misc as misc_utils
from tempest_lib import exceptions as lib_exc
-from tempest import clients
from tempest.common import fixed_network
from tempest.common.utils.linux import remote_client
from tempest import config
@@ -308,8 +308,13 @@
password=password)
try:
linux_client.validate_authentication()
- except Exception:
- LOG.exception('Initializing SSH connection to %s failed' % ip)
+ except Exception as e:
+ message = ('Initializing SSH connection to %(ip)s failed. '
+ 'Error: %(error)s' % {'ip': ip, 'error': e})
+ caller = misc_utils.find_test_caller()
+ if caller:
+ message = '(%s) %s' % (caller, message)
+ LOG.exception(message)
# If we don't explicitly set for which servers we want to
# log the console output then all the servers will be logged.
# See the definition of _log_console_output()
@@ -318,7 +323,8 @@
return linux_client
- def _image_create(self, name, fmt, path, properties=None):
+ def _image_create(self, name, fmt, path,
+ disk_format=None, properties=None):
if properties is None:
properties = {}
name = data_utils.rand_name('%s-' % name)
@@ -327,10 +333,10 @@
params = {
'name': name,
'container_format': fmt,
- 'disk_format': fmt,
+ 'disk_format': disk_format or fmt,
'is_public': 'False',
}
- params.update(properties)
+ params['properties'] = properties
image = self.image_client.create_image(**params)
self.addCleanup(self.image_client.delete_image, image['id'])
self.assertEqual("queued", image['status'])
@@ -344,23 +350,22 @@
ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
img_container_format = CONF.scenario.img_container_format
img_disk_format = CONF.scenario.img_disk_format
+ img_properties = CONF.scenario.img_properties
LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
- "ami: %s, ari: %s, aki: %s" %
+ "properties: %s, ami: %s, ari: %s, aki: %s" %
(img_path, img_container_format, img_disk_format,
- ami_img_path, ari_img_path, aki_img_path))
+ img_properties, ami_img_path, ari_img_path, aki_img_path))
try:
self.image = self._image_create('scenario-img',
img_container_format,
img_path,
- properties={'disk_format':
- img_disk_format})
+ disk_format=img_disk_format,
+ properties=img_properties)
except IOError:
LOG.debug("A qcow2 image was not found. Try to get a uec image.")
kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
- properties = {
- 'properties': {'kernel_id': kernel, 'ramdisk_id': ramdisk}
- }
+ properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
self.image = self._image_create('scenario-ami', 'ami',
path=ami_img_path,
properties=properties)
@@ -381,7 +386,7 @@
def _log_net_info(self, exc):
# network debug is called as part of ssh init
- if not isinstance(exc, exceptions.SSHTimeout):
+ if not isinstance(exc, lib_exc.SSHTimeout):
LOG.debug('Network information on a devstack host')
def create_server_snapshot(self, server, name=None):
@@ -408,9 +413,9 @@
return snapshot_image
def nova_volume_attach(self):
- # TODO(andreaf) Device should be here CONF.compute.volume_device_name
volume = self.servers_client.attach_volume(
- self.server['id'], self.volume['id'], '/dev/vdb')
+ self.server['id'], self.volume['id'], '/dev/%s'
+ % CONF.compute.volume_device_name)
self.assertEqual(self.volume['id'], volume['id'])
self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
# Refresh the volume after the attachment
@@ -741,7 +746,7 @@
# The target login is assumed to have been configured for
# key-based authentication by cloud-init.
try:
- for net_name, ip_addresses in server['addresses'].iteritems():
+ for net_name, ip_addresses in six.iteritems(server['addresses']):
for ip_address in ip_addresses:
self.check_vm_connectivity(ip_address['addr'],
username,
@@ -766,7 +771,7 @@
def ping_remote():
try:
source.ping_host(dest)
- except exceptions.SSHExecCommandFailed:
+ except lib_exc.SSHExecCommandFailed:
LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
% (dest, source.ssh_client.host))
return not should_succeed
@@ -986,7 +991,7 @@
router_id = CONF.network.public_router_id
network_id = CONF.network.public_network_id
if router_id:
- resp, body = client.show_router(router_id)
+ body = client.show_router(router_id)
return net_resources.AttributeDict(**body['router'])
elif network_id:
router = self._create_router(client, tenant_id)
@@ -1341,15 +1346,7 @@
cls.set_network_resources()
super(SwiftScenarioTest, cls).setup_credentials()
operator_role = CONF.object_storage.operator_role
- if not cls.isolated_creds.is_role_available(operator_role):
- skip_msg = ("%s skipped because the configured credential provider"
- " is not able to provide credentials with the %s role "
- "assigned." % (cls.__name__, operator_role))
- raise cls.skipException(skip_msg)
- else:
- cls.os_operator = clients.Manager(
- cls.isolated_creds.get_creds_by_roles(
- [operator_role]))
+ cls.os_operator = cls.get_client_manager(roles=[operator_role])
@classmethod
def setup_clients(cls):
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
index 5aec01f..eb018eb 100644
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -12,9 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-import HTMLParser
-import urllib
-import urllib2
+from six.moves import html_parser as HTMLParser
+from six.moves.urllib import parse
+from six.moves.urllib import request
from tempest import config
from tempest.scenario import manager
@@ -68,11 +68,11 @@
super(TestDashboardBasicOps, cls).setup_credentials()
def check_login_page(self):
- response = urllib2.urlopen(CONF.dashboard.dashboard_url)
+ response = request.urlopen(CONF.dashboard.dashboard_url)
self.assertIn("id_username", response.read())
def user_login(self, username, password):
- self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
+ self.opener = request.build_opener(request.HTTPCookieProcessor())
response = self.opener.open(CONF.dashboard.dashboard_url).read()
# Grab the CSRF token and default region
@@ -80,14 +80,14 @@
parser.feed(response)
# Prepare login form request
- req = urllib2.Request(CONF.dashboard.login_url)
+ req = request.Request(CONF.dashboard.login_url)
req.add_header('Content-type', 'application/x-www-form-urlencoded')
req.add_header('Referer', CONF.dashboard.dashboard_url)
params = {'username': username,
'password': password,
'region': parser.region,
'csrfmiddlewaretoken': parser.csrf_token}
- self.opener.open(req, urllib.urlencode(params))
+ self.opener.open(req, parse.urlencode(params))
def check_home_page(self):
response = self.opener.open(CONF.dashboard.dashboard_url)
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index 8f37d74..691c7c9 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -16,7 +16,9 @@
import tempfile
import time
-import urllib2
+
+import six
+from six.moves.urllib import request as urllib2
from tempest.common import commands
from tempest import config
@@ -158,7 +160,7 @@
1. SSH to the instance
2. Start two http backends listening on ports 80 and 88 respectively
"""
- for server_id, ip in self.server_ips.iteritems():
+ for server_id, ip in six.iteritems(self.server_ips):
private_key = self.servers_keypairs[server_id]['private_key']
server_name = self.servers_client.get_server(server_id)['name']
username = config.scenario.ssh_user
@@ -238,7 +240,7 @@
but with different ports to listen on.
"""
- for server_id, ip in self.server_fixed_ips.iteritems():
+ for server_id, ip in six.iteritems(self.server_fixed_ips):
if len(self.server_fixed_ips) == 1:
member1 = self._create_member(address=ip,
protocol_port=self.port1,
@@ -307,7 +309,7 @@
except urllib2.HTTPError:
continue
# Assert that each member of the pool gets balanced at least once
- for member, counter in counters.iteritems():
+ for member, counter in six.iteritems(counters):
self.assertGreater(counter, 0, 'Member %s never balanced' % member)
@test.idempotent_id('c0c6f1ca-603b-4509-9c0f-2c63f0d838ee')
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 16ff848..6e67c4b 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -16,6 +16,7 @@
import netaddr
from oslo_log import log as logging
+import six
from tempest import config
from tempest.scenario import manager
@@ -93,7 +94,7 @@
@staticmethod
def define_server_ips(srv):
- for net_name, nics in srv['addresses'].iteritems():
+ for net_name, nics in six.iteritems(srv['addresses']):
for nic in nics:
if nic['version'] == 6:
srv['accessIPv6'] = nic['addr']
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index a73ae1c..8ec10c7 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -440,7 +440,7 @@
@test.idempotent_id('e79f879e-debb-440c-a7e4-efeda05b6848')
@test.services('compute', 'network')
def test_cross_tenant_traffic(self):
- if not self.isolated_creds.is_multi_tenant():
+ if not self.credentials_provider.is_multi_tenant():
raise self.skipException("No secondary tenant defined")
try:
# deploy new tenant
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index f44fd5e..d9918f3 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -48,7 +48,7 @@
self.image_ref = CONF.compute.image_ref
if not hasattr(self, 'flavor_ref'):
self.flavor_ref = CONF.compute.flavor_ref
- self.image_utils = test_utils.ImageUtils()
+ self.image_utils = test_utils.ImageUtils(self.manager)
if not self.image_utils.is_flavor_enough(self.flavor_ref,
self.image_ref):
raise self.skipException(
@@ -56,7 +56,7 @@
image=self.image_ref, flavor=self.flavor_ref
)
)
- self.run_ssh = CONF.compute.run_ssh and \
+ self.run_ssh = CONF.validation.run_validation and \
self.image_utils.is_sshable_image(self.image_ref)
self.ssh_user = self.image_utils.ssh_user(self.image_ref)
LOG.debug('Starting test for i:{image}, f:{flavor}. '
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 53b471a..51c4c59 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -103,9 +103,9 @@
return self.create_volume(snapshot_id=snapshot_id)
def _attach_volume(self, server, volume):
- # TODO(andreaf) we should use device from config instead if vdb
attached_volume = self.servers_client.attach_volume(
- server['id'], volume['id'], device='/dev/vdb')
+ server['id'], volume['id'], device='/dev/%s'
+ % CONF.compute.volume_device_name)
self.assertEqual(volume['id'], attached_volume['id'])
self._wait_for_volume_status(attached_volume, 'in-use')
@@ -119,7 +119,7 @@
def _func():
part = ssh.get_partitions()
LOG.debug("Partitions:%s" % part)
- return 'vdb' in part
+ return CONF.compute.volume_device_name in part
if not tempest.test.call_until_true(_func,
CONF.compute.build_timeout,
@@ -128,15 +128,18 @@
def _create_timestamp(self, server_or_ip):
ssh_client = self._ssh_to_server(server_or_ip)
- ssh_client.exec_command('sudo /usr/sbin/mkfs.ext4 /dev/vdb')
- ssh_client.exec_command('sudo mount /dev/vdb /mnt')
+ ssh_client.exec_command('sudo /usr/sbin/mkfs.ext4 /dev/%s'
+ % CONF.compute.volume_device_name)
+ ssh_client.exec_command('sudo mount /dev/%s /mnt'
+ % CONF.compute.volume_device_name)
ssh_client.exec_command('sudo sh -c "date > /mnt/timestamp;sync"')
self.timestamp = ssh_client.exec_command('sudo cat /mnt/timestamp')
ssh_client.exec_command('sudo umount /mnt')
def _check_timestamp(self, server_or_ip):
ssh_client = self._ssh_to_server(server_or_ip)
- ssh_client.exec_command('sudo mount /dev/vdb /mnt')
+ ssh_client.exec_command('sudo mount /dev/%s /mnt'
+ % CONF.compute.volume_device_name)
got_timestamp = ssh_client.exec_command('sudo cat /mnt/timestamp')
self.assertEqual(self.timestamp, got_timestamp)
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 177697b..1731c48 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -41,8 +41,6 @@
super(TestVolumeBootPattern, cls).skip_checks()
if not CONF.volume_feature_enabled.snapshot:
raise cls.skipException("Cinder volume snapshots are disabled")
- if CONF.volume.storage_protocol == 'ceph':
- raise cls.skipException('Skip until bug 1439371 is fixed.')
def _create_volume_from_image(self):
img_uuid = CONF.compute.image_ref
diff --git a/tempest/scenario/utils.py b/tempest/scenario/utils.py
index 6c00d09..f8d9dd4 100644
--- a/tempest/scenario/utils.py
+++ b/tempest/scenario/utils.py
@@ -23,30 +23,28 @@
import testtools
from tempest import clients
-from tempest.common import cred_provider
+from tempest.common import credentials
from tempest import config
from tempest import exceptions
CONF = config.CONF
-@misc.singleton
class ImageUtils(object):
default_ssh_user = 'root'
- def __init__(self):
+ def __init__(self, os):
# Load configuration items
self.ssh_users = json.loads(CONF.input_scenario.ssh_user_regex)
self.non_ssh_image_pattern = \
CONF.input_scenario.non_ssh_image_regex
# Setup clients
- os = clients.Manager()
self.images_client = os.images_client
self.flavors_client = os.flavors_client
def ssh_user(self, image_id):
- _image = self.images_client.get_image(image_id)
+ _image = self.images_client.show_image(image_id)
for regex, user in self.ssh_users:
# First match wins
if re.match(regex, _image['name']) is not None:
@@ -59,14 +57,14 @@
string=str(image['name']))
def is_sshable_image(self, image_id):
- _image = self.images_client.get_image(image_id)
+ _image = self.images_client.show_image(image_id)
return self._is_sshable_image(_image)
def _is_flavor_enough(self, flavor, image):
return image['minDisk'] <= flavor['disk']
def is_flavor_enough(self, flavor_id, image_id):
- _image = self.images_client.get_image(image_id)
+ _image = self.images_client.show_image(image_id)
_flavor = self.flavors_client.get_flavor_details(flavor_id)
return self._is_flavor_enough(_flavor, _image)
@@ -100,8 +98,17 @@
digit=string.digits)
def __init__(self):
- os = clients.Manager(
- cred_provider.get_configured_credentials('user', fill_in=False))
+ network_resources = {
+ 'network': False,
+ 'router': False,
+ 'subnet': False,
+ 'dhcp': False,
+ }
+ self.isolated_creds = credentials.get_isolated_credentials(
+ name='InputScenarioUtils',
+ identity_version=CONF.identity.auth_version,
+ network_resources=network_resources)
+ os = clients.Manager(self.isolated_creds.get_primary_creds())
self.images_client = os.images_client
self.flavors_client = os.flavors_client
self.image_pattern = CONF.input_scenario.image_regex
@@ -112,6 +119,9 @@
nname = ''.join(c for c in nname if c in self.validchars)
return nname
+ def clear_creds(self):
+ self.isolated_creds.clear_isolated_creds()
+
@property
def scenario_images(self):
"""
@@ -158,12 +168,19 @@
loader, standard_tests, pattern = args
else:
standard_tests, module, loader = args
+ output = None
+ scenario_utils = None
try:
scenario_utils = InputScenarioUtils()
scenario_flavor = scenario_utils.scenario_flavors
scenario_image = scenario_utils.scenario_images
- except exceptions.InvalidConfiguration:
- return standard_tests
+ except (exceptions.InvalidConfiguration, TypeError):
+ output = standard_tests
+ finally:
+ if scenario_utils:
+ scenario_utils.clear_creds()
+ if output is not None:
+ return output
for test in testtools.iterate_tests(standard_tests):
setattr(test, 'scenarios', testscenarios.multiply_scenarios(
scenario_image,
diff --git a/tempest/services/baremetal/base.py b/tempest/services/baremetal/base.py
index 4c6a5bf..1461198 100644
--- a/tempest/services/baremetal/base.py
+++ b/tempest/services/baremetal/base.py
@@ -12,9 +12,9 @@
import functools
import json
-import urllib
import six
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/compute/json/agents_client.py b/tempest/services/compute/json/agents_client.py
index 403437d..c69e483 100644
--- a/tempest/services/compute/json/agents_client.py
+++ b/tempest/services/compute/json/agents_client.py
@@ -13,7 +13,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute.v2_1 import agents as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/baremetal_nodes_client.py b/tempest/services/compute/json/baremetal_nodes_client.py
index e4a4e88..d8f13c4 100644
--- a/tempest/services/compute/json/baremetal_nodes_client.py
+++ b/tempest/services/compute/json/baremetal_nodes_client.py
@@ -13,9 +13,11 @@
# under the License.
import json
-import urllib
-from tempest.api_schema.response.compute import baremetal_nodes as schema
+from six.moves.urllib import parse as urllib
+
+from tempest.api_schema.response.compute.v2_1 import baremetal_nodes \
+ as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 2de43cf..7938d8e 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -14,12 +14,14 @@
# under the License.
import json
-import urllib
-from tempest.api_schema.response.compute import flavors_access as schema_access
-from tempest.api_schema.response.compute import flavors_extra_specs \
- as schema_extra_specs
+from six.moves.urllib import parse as urllib
+
from tempest.api_schema.response.compute.v2_1 import flavors as schema
+from tempest.api_schema.response.compute.v2_1 import flavors_access \
+ as schema_access
+from tempest.api_schema.response.compute.v2_1 import flavors_extra_specs \
+ as schema_extra_specs
from tempest.common import service_client
@@ -102,7 +104,7 @@
resp, body = self.post('flavors/%s/os-extra_specs' % flavor_id,
post_body)
body = json.loads(body)
- self.validate_response(schema_extra_specs.flavor_extra_specs,
+ self.validate_response(schema_extra_specs.set_get_flavor_extra_specs,
resp, body)
return service_client.ResponseBody(resp, body['extra_specs'])
@@ -110,7 +112,7 @@
"""Gets extra Specs details of the mentioned flavor."""
resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id)
body = json.loads(body)
- self.validate_response(schema_extra_specs.flavor_extra_specs,
+ self.validate_response(schema_extra_specs.set_get_flavor_extra_specs,
resp, body)
return service_client.ResponseBody(resp, body['extra_specs'])
@@ -119,8 +121,9 @@
resp, body = self.get('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
key))
body = json.loads(body)
- self.validate_response(schema_extra_specs.flavor_extra_specs_key,
- resp, body)
+ self.validate_response(
+ schema_extra_specs.set_get_flavor_extra_specs_key,
+ resp, body)
return service_client.ResponseBody(resp, body)
def update_flavor_extra_spec(self, flavor_id, key, **kwargs):
@@ -128,8 +131,9 @@
resp, body = self.put('flavors/%s/os-extra_specs/%s' %
(flavor_id, key), json.dumps(kwargs))
body = json.loads(body)
- self.validate_response(schema_extra_specs.flavor_extra_specs_key,
- resp, body)
+ self.validate_response(
+ schema_extra_specs.set_get_flavor_extra_specs_key,
+ resp, body)
return service_client.ResponseBody(resp, body)
def unset_flavor_extra_spec(self, flavor_id, key):
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index 5bad527..f30bfdb 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -14,8 +14,8 @@
# under the License.
import json
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import floating_ips as schema
@@ -40,7 +40,7 @@
url = "os-floating-ips/%s" % str(floating_ip_id)
resp, body = self.get(url)
body = json.loads(body)
- self.validate_response(schema.floating_ip, resp, body)
+ self.validate_response(schema.create_get_floating_ip, resp, body)
return service_client.ResponseBody(resp, body['floating_ip'])
def create_floating_ip(self, pool_name=None):
@@ -50,7 +50,7 @@
post_body = json.dumps(post_body)
resp, body = self.post(url, post_body)
body = json.loads(body)
- self.validate_response(schema.floating_ip, resp, body)
+ self.validate_response(schema.create_get_floating_ip, resp, body)
return service_client.ResponseBody(resp, body['floating_ip'])
def delete_floating_ip(self, floating_ip_id):
@@ -108,7 +108,7 @@
resp, body = self.get(url)
body = json.loads(body)
- self.validate_response(schema.floating_ip_pools, resp, body)
+ self.validate_response(schema.list_floating_ip_pools, resp, body)
return service_client.ResponseBodyList(resp, body['floating_ip_pools'])
def create_floating_ips_bulk(self, ip_range, pool, interface):
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index 088e695..287482f 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -13,7 +13,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute.v2_1 import hosts as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index 1223fef..30aa962 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -14,8 +14,8 @@
# under the License.
import json
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import images as schema
@@ -65,7 +65,7 @@
self.validate_response(schema.list_images_details, resp, body)
return service_client.ResponseBodyList(resp, body['images'])
- def get_image(self, image_id):
+ def show_image(self, image_id):
"""Returns the details of a single image."""
resp, body = self.get("images/%s" % str(image_id))
self.expected_success(200, resp.status)
@@ -131,7 +131,7 @@
def is_resource_deleted(self, id):
try:
- self.get_image(id)
+ self.show_image(id)
except lib_exc.NotFound:
return True
return False
diff --git a/tempest/services/compute/json/migrations_client.py b/tempest/services/compute/json/migrations_client.py
index a65b655..f708a07 100644
--- a/tempest/services/compute/json/migrations_client.py
+++ b/tempest/services/compute/json/migrations_client.py
@@ -13,9 +13,10 @@
# under the License.
import json
-import urllib
-from tempest.api_schema.response.compute import migrations as schema
+from six.moves.urllib import parse as urllib
+
+from tempest.api_schema.response.compute.v2_1 import migrations as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index d8c8d63..2855e13 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -14,8 +14,8 @@
# under the License.
import json
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import security_groups as schema
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index c9ba2c3..1af1b37 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -16,8 +16,8 @@
import json
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import servers as schema
diff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py
index fc2274d..156ad8d 100644
--- a/tempest/services/compute/json/services_client.py
+++ b/tempest/services/compute/json/services_client.py
@@ -15,9 +15,10 @@
# under the License.
import json
-import urllib
-from tempest.api_schema.response.compute import services as schema
+from six.moves.urllib import parse as urllib
+
+from tempest.api_schema.response.compute.v2_1 import services as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/tenant_usages_client.py b/tempest/services/compute/json/tenant_usages_client.py
index ff6e7a2..52f46e2 100644
--- a/tempest/services/compute/json/tenant_usages_client.py
+++ b/tempest/services/compute/json/tenant_usages_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute.v2_1 import tenant_usages as schema
from tempest.common import service_client
@@ -29,7 +30,7 @@
resp, body = self.get(url)
body = json.loads(body)
- self.validate_response(schema.list_tenant, resp, body)
+ self.validate_response(schema.list_tenant_usage, resp, body)
return service_client.ResponseBodyList(resp, body['tenant_usages'][0])
def get_tenant_usage(self, tenant_id, params=None):
@@ -39,5 +40,5 @@
resp, body = self.get(url)
body = json.loads(body)
- self.validate_response(schema.get_tenant, resp, body)
+ self.validate_response(schema.get_tenant_usage, resp, body)
return service_client.ResponseBodyList(resp, body['tenant_usage'])
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index ba5921e..4d7a7aa 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -15,8 +15,8 @@
import json
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import volumes as schema
diff --git a/tempest/services/database/json/limits_client.py b/tempest/services/database/json/limits_client.py
index ae758bc..f99ceaa 100644
--- a/tempest/services/database/json/limits_client.py
+++ b/tempest/services/database/json/limits_client.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/database/json/versions_client.py b/tempest/services/database/json/versions_client.py
index aa2fef7..0db9c6a 100644
--- a/tempest/services/database/json/versions_client.py
+++ b/tempest/services/database/json/versions_client.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/identity/v2/json/token_client.py b/tempest/services/identity/v2/json/token_client.py
deleted file mode 100644
index e61ac84..0000000
--- a/tempest/services/identity/v2/json/token_client.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# Copyright 2015 NEC Corporation. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import json
-from tempest_lib.common import rest_client
-from tempest_lib import exceptions as lib_exc
-
-from tempest.common import service_client
-from tempest import exceptions
-
-
-class TokenClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_url, disable_ssl_certificate_validation=None,
- ca_certs=None, trace_requests=None):
- dscv = disable_ssl_certificate_validation
- super(TokenClientJSON, self).__init__(
- None, None, None, disable_ssl_certificate_validation=dscv,
- ca_certs=ca_certs, trace_requests=trace_requests)
-
- # Normalize URI to ensure /tokens is in it.
- if 'tokens' not in auth_url:
- auth_url = auth_url.rstrip('/') + '/tokens'
-
- self.auth_url = auth_url
-
- def auth(self, user, password, tenant=None):
- creds = {
- 'auth': {
- 'passwordCredentials': {
- 'username': user,
- 'password': password,
- },
- }
- }
-
- if tenant:
- creds['auth']['tenantName'] = tenant
-
- body = json.dumps(creds)
- resp, body = self.post(self.auth_url, body=body)
- self.expected_success(200, resp.status)
-
- return service_client.ResponseBody(resp, body['access'])
-
- def auth_token(self, token_id, tenant=None):
- creds = {
- 'auth': {
- 'token': {
- 'id': token_id,
- },
- }
- }
-
- if tenant:
- creds['auth']['tenantName'] = tenant
-
- body = json.dumps(creds)
- resp, body = self.post(self.auth_url, body=body)
- self.expected_success(200, resp.status)
-
- return service_client.ResponseBody(resp, body['access'])
-
- def request(self, method, url, extra_headers=False, headers=None,
- body=None):
- """A simple HTTP request interface."""
- if headers is None:
- headers = self.get_headers(accept_type="json")
- elif extra_headers:
- try:
- headers.update(self.get_headers(accept_type="json"))
- except (ValueError, TypeError):
- headers = self.get_headers(accept_type="json")
-
- resp, resp_body = self.raw_request(url, method,
- headers=headers, body=body)
- self._log_request(method, url, resp)
-
- if resp.status in [401, 403]:
- resp_body = json.loads(resp_body)
- raise lib_exc.Unauthorized(resp_body['error']['message'])
- elif resp.status not in [200, 201]:
- raise exceptions.IdentityError(
- 'Unexpected status code {0}'.format(resp.status))
-
- if isinstance(resp_body, str):
- resp_body = json.loads(resp_body)
- return resp, resp_body
-
- def get_token(self, user, password, tenant, auth_data=False):
- """
- Returns (token id, token data) for supplied credentials
- """
- body = self.auth(user, password, tenant)
-
- if auth_data:
- return body['token']['id'], body
- else:
- return body['token']['id']
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index bc90fd1..f3d02a8 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/identity/v3/json/region_client.py b/tempest/services/identity/v3/json/region_client.py
index faaf43c..02df354 100644
--- a/tempest/services/identity/v3/json/region_client.py
+++ b/tempest/services/identity/v3/json/region_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/identity/v3/json/token_client.py b/tempest/services/identity/v3/json/token_client.py
deleted file mode 100644
index 3e37403..0000000
--- a/tempest/services/identity/v3/json/token_client.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# Copyright 2015 NEC Corporation. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import json
-from tempest_lib.common import rest_client
-from tempest_lib import exceptions as lib_exc
-
-from tempest.common import service_client
-from tempest import exceptions
-
-
-class V3TokenClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_url, disable_ssl_certificate_validation=None,
- ca_certs=None, trace_requests=None):
- dscv = disable_ssl_certificate_validation
- super(V3TokenClientJSON, self).__init__(
- None, None, None, disable_ssl_certificate_validation=dscv,
- ca_certs=ca_certs, trace_requests=trace_requests)
- if not auth_url:
- raise exceptions.InvalidConfiguration('you must specify a v3 uri '
- 'if using the v3 identity '
- 'api')
- if 'auth/tokens' not in auth_url:
- auth_url = auth_url.rstrip('/') + '/auth/tokens'
-
- self.auth_url = auth_url
-
- def auth(self, user_id=None, username=None, password=None, project_id=None,
- project_name=None, user_domain_id=None, user_domain_name=None,
- project_domain_id=None, project_domain_name=None, domain_id=None,
- domain_name=None, token=None):
- """
- :param user_id: user id
- :param username: user name
- :param user_domain_id: the user domain id
- :param user_domain_name: the user domain name
- :param project_domain_id: the project domain id
- :param project_domain_name: the project domain name
- :param domain_id: a domain id to scope to
- :param domain_name: a domain name to scope to
- :param project_id: a project id to scope to
- :param project_name: a project name to scope to
- :param token: a token to re-scope.
-
- Accepts different combinations of credentials.
- Sample sample valid combinations:
- - token
- - token, project_name, project_domain_id
- - user_id, password
- - username, password, user_domain_id
- - username, password, project_name, user_domain_id, project_domain_id
- Validation is left to the server side.
- """
- creds = {
- 'auth': {
- 'identity': {
- 'methods': [],
- }
- }
- }
- id_obj = creds['auth']['identity']
- if token:
- id_obj['methods'].append('token')
- id_obj['token'] = {
- 'id': token
- }
-
- if (user_id or username) and password:
- id_obj['methods'].append('password')
- id_obj['password'] = {
- 'user': {
- 'password': password,
- }
- }
- if user_id:
- id_obj['password']['user']['id'] = user_id
- else:
- id_obj['password']['user']['name'] = username
-
- _domain = None
- if user_domain_id is not None:
- _domain = dict(id=user_domain_id)
- elif user_domain_name is not None:
- _domain = dict(name=user_domain_name)
- if _domain:
- id_obj['password']['user']['domain'] = _domain
-
- if (project_id or project_name):
- _project = dict()
-
- if project_id:
- _project['id'] = project_id
- elif project_name:
- _project['name'] = project_name
-
- if project_domain_id is not None:
- _project['domain'] = {'id': project_domain_id}
- elif project_domain_name is not None:
- _project['domain'] = {'name': project_domain_name}
-
- creds['auth']['scope'] = dict(project=_project)
- elif domain_id:
- creds['auth']['scope'] = dict(domain={'id': domain_id})
- elif domain_name:
- creds['auth']['scope'] = dict(domain={'name': domain_name})
-
- body = json.dumps(creds)
- resp, body = self.post(self.auth_url, body=body)
- self.expected_success(201, resp.status)
- return service_client.ResponseBody(resp, body)
-
- def request(self, method, url, extra_headers=False, headers=None,
- body=None):
- """A simple HTTP request interface."""
- if headers is None:
- # Always accept 'json', for xml token client too.
- # Because XML response is not easily
- # converted to the corresponding JSON one
- headers = self.get_headers(accept_type="json")
- elif extra_headers:
- try:
- headers.update(self.get_headers(accept_type="json"))
- except (ValueError, TypeError):
- headers = self.get_headers(accept_type="json")
-
- resp, resp_body = self.raw_request(url, method,
- headers=headers, body=body)
- self._log_request(method, url, resp)
-
- if resp.status in [401, 403]:
- resp_body = json.loads(resp_body)
- raise lib_exc.Unauthorized(resp_body['error']['message'])
- elif resp.status not in [200, 201, 204]:
- raise exceptions.IdentityError(
- 'Unexpected status code {0}'.format(resp.status))
-
- return resp, json.loads(resp_body)
-
- def get_token(self, **kwargs):
- """
- Returns (token id, token data) for supplied credentials
- """
-
- auth_data = kwargs.pop('auth_data', False)
-
- if not (kwargs.get('user_domain_id') or
- kwargs.get('user_domain_name')):
- kwargs['user_domain_name'] = 'Default'
-
- if not (kwargs.get('project_domain_id') or
- kwargs.get('project_domain_name')):
- kwargs['project_domain_name'] = 'Default'
-
- body = self.auth(**kwargs)
-
- token = body.response.get('x-subject-token')
- if auth_data:
- return token, body['token']
- else:
- return token
diff --git a/tempest/services/image/v1/json/image_client.py b/tempest/services/image/v1/json/image_client.py
index ec7900b..7c58f01 100644
--- a/tempest/services/image/v1/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -18,9 +18,10 @@
import json
import os
import time
-import urllib
from oslo_log import log as logging
+import six
+from six.moves.urllib import parse as urllib
from tempest_lib.common.utils import misc as misc_utils
from tempest_lib import exceptions as lib_exc
@@ -54,7 +55,7 @@
def _image_meta_from_headers(self, headers):
meta = {'properties': {}}
- for key, value in headers.iteritems():
+ for key, value in six.iteritems(headers):
if key.startswith('x-image-meta-property-'):
_key = key[22:]
meta['properties'][_key] = value
@@ -80,11 +81,11 @@
copy_from = fields_copy.pop('copy_from', None)
if copy_from is not None:
headers['x-glance-api-copy-from'] = copy_from
- for key, value in fields_copy.pop('properties', {}).iteritems():
+ for key, value in six.iteritems(fields_copy.pop('properties', {})):
headers['x-image-meta-property-%s' % key] = str(value)
- for key, value in fields_copy.pop('api', {}).iteritems():
+ for key, value in six.iteritems(fields_copy.pop('api', {})):
headers['x-glance-api-property-%s' % key] = str(value)
- for key, value in fields_copy.iteritems():
+ for key, value in six.iteritems(fields_copy):
headers['x-image-meta-%s' % key] = str(value)
return headers
@@ -200,7 +201,7 @@
self.expected_success(200, resp.status)
return service_client.ResponseBody(resp, body)
- def image_list(self, **kwargs):
+ def list_images(self, **kwargs):
url = 'v1/images'
if len(kwargs) > 0:
@@ -239,7 +240,7 @@
body = self._image_meta_from_headers(resp)
return service_client.ResponseBody(resp, body)
- def get_image(self, image_id):
+ def show_image(self, image_id):
url = 'v1/images/%s' % image_id
resp, body = self.get(url)
self.expected_success(200, resp.status)
@@ -257,7 +258,7 @@
"""Returns the primary type of resource this client works with."""
return 'image_meta'
- def get_image_membership(self, image_id):
+ def list_image_members(self, image_id):
url = 'v1/images/%s/members' % image_id
resp, body = self.get(url)
self.expected_success(200, resp.status)
diff --git a/tempest/services/image/v2/json/image_client.py b/tempest/services/image/v2/json/image_client.py
index 6b04144..a4cb48c 100644
--- a/tempest/services/image/v2/json/image_client.py
+++ b/tempest/services/image/v2/json/image_client.py
@@ -14,9 +14,9 @@
# under the License.
import json
-import urllib
import jsonschema
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import glance_http
@@ -102,7 +102,7 @@
self.expected_success(204, resp.status)
return service_client.ResponseBody(resp)
- def image_list(self, params=None):
+ def list_images(self, params=None):
url = 'v2/images'
if params:
@@ -114,7 +114,7 @@
self._validate_schema(body, type='images')
return service_client.ResponseBodyList(resp, body['images'])
- def get_image(self, image_id):
+ def show_image(self, image_id):
url = 'v2/images/%s' % image_id
resp, body = self.get(url)
self.expected_success(200, resp.status)
@@ -123,7 +123,7 @@
def is_resource_deleted(self, id):
try:
- self.get_image(id)
+ self.show_image(id)
except lib_exc.NotFound:
return True
return False
@@ -159,7 +159,7 @@
self.expected_success(204, resp.status)
return service_client.ResponseBody(resp)
- def get_image_membership(self, image_id):
+ def list_image_members(self, image_id):
url = 'v2/images/%s/members' % image_id
resp, body = self.get(url)
self.expected_success(200, resp.status)
diff --git a/tempest/services/messaging/json/messaging_client.py b/tempest/services/messaging/json/messaging_client.py
index 483ba93..5f6c32a 100644
--- a/tempest/services/messaging/json/messaging_client.py
+++ b/tempest/services/messaging/json/messaging_client.py
@@ -14,9 +14,10 @@
# limitations under the License.
import json
-import urllib
import uuid
+from six.moves.urllib import parse as urllib
+
from tempest.api_schema.response.messaging.v1 import queues as queues_schema
from tempest.common import service_client
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 53645a5..e93cc47 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -12,8 +12,8 @@
import json
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib.common.utils import misc
from tempest_lib import exceptions as lib_exc
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index af00eff..dece763 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -14,9 +14,10 @@
# under the License.
import json
-import urllib
from xml.etree import ElementTree as etree
+from six.moves.urllib import parse as urllib
+
from tempest.common import service_client
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index ed74de4..8e225b0 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -14,9 +14,10 @@
# under the License.
import json
-import urllib
from xml.etree import ElementTree as etree
+from six.moves.urllib import parse as urllib
+
from tempest.common import service_client
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 3466c8a..2265587 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -13,8 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
-
+import six
from six.moves import http_client as httplib
from six.moves.urllib import parse as urlparse
@@ -36,7 +35,7 @@
headers[str(key)] = metadata[key]
url = "%s/%s" % (str(container), str(object_name))
if params:
- url += '?%s' % urllib.urlencode(params)
+ url += '?%s' % urlparse.urlencode(params)
resp, body = self.put(url, data, headers)
self.expected_success(201, resp.status)
@@ -52,7 +51,7 @@
"""Delete storage object."""
url = "%s/%s" % (str(container), str(object_name))
if params:
- url += '?%s' % urllib.urlencode(params)
+ url += '?%s' % urlparse.urlencode(params)
resp, body = self.delete(url, headers={})
self.expected_success([200, 204], resp.status)
return resp, body
@@ -234,7 +233,7 @@
headers = {}
if hasattr(contents, 'read'):
conn.putrequest('PUT', path)
- for header, value in headers.iteritems():
+ for header, value in six.iteritems(headers):
conn.putheader(header, value)
if 'Content-Length' not in headers:
if 'Transfer-Encoding' not in headers:
diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py
index debf39b..4d443d3 100644
--- a/tempest/services/orchestration/json/orchestration_client.py
+++ b/tempest/services/orchestration/json/orchestration_client.py
@@ -16,8 +16,8 @@
import json
import re
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import service_client
diff --git a/tempest/services/telemetry/json/telemetry_client.py b/tempest/services/telemetry/json/telemetry_client.py
index 0c01908..554f574 100644
--- a/tempest/services/telemetry/json/telemetry_client.py
+++ b/tempest/services/telemetry/json/telemetry_client.py
@@ -13,9 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
-
from oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/volume/json/admin/volume_hosts_client.py b/tempest/services/volume/json/admin/volume_hosts_client.py
index 1cd92b7..1dfabaf 100644
--- a/tempest/services/volume/json/admin/volume_hosts_client.py
+++ b/tempest/services/volume/json/admin/volume_hosts_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/volume/json/admin/volume_quotas_client.py b/tempest/services/volume/json/admin/volume_quotas_client.py
index 5092afc..cbab3f0 100644
--- a/tempest/services/volume/json/admin/volume_quotas_client.py
+++ b/tempest/services/volume/json/admin/volume_quotas_client.py
@@ -12,9 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
-
from oslo_serialization import jsonutils
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/volume/json/admin/volume_services_client.py b/tempest/services/volume/json/admin/volume_services_client.py
index 1c4433f..94792e0 100644
--- a/tempest/services/volume/json/admin/volume_services_client.py
+++ b/tempest/services/volume/json/admin/volume_services_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/volume/json/admin/volume_types_client.py b/tempest/services/volume/json/admin/volume_types_client.py
index 9366984..2436d88 100644
--- a/tempest/services/volume/json/admin/volume_types_client.py
+++ b/tempest/services/volume/json/admin/volume_types_client.py
@@ -14,8 +14,8 @@
# under the License.
import json
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import service_client
diff --git a/tempest/services/volume/json/snapshots_client.py b/tempest/services/volume/json/snapshots_client.py
index 2140c62..cfa02bd 100644
--- a/tempest/services/volume/json/snapshots_client.py
+++ b/tempest/services/volume/json/snapshots_client.py
@@ -12,9 +12,9 @@
import json
import time
-import urllib
from oslo_log import log as logging
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import service_client
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index a82291a..65aa0f4 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -15,8 +15,8 @@
import json
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import service_client
@@ -123,6 +123,15 @@
self.expected_success(202, resp.status)
return service_client.ResponseBody(resp, body)
+ def set_bootable_volume(self, volume_id, bootable):
+ """set a bootable flag for a volume - true or false."""
+ post_body = {"bootable": bootable}
+ post_body = json.dumps({'os-set_bootable': post_body})
+ url = 'volumes/%s/action' % (volume_id)
+ resp, body = self.post(url, post_body)
+ self.expected_success(200, resp.status)
+ return service_client.ResponseBody(resp, body)
+
def detach_volume(self, volume_id):
"""Detaches a volume from an instance."""
post_body = {}
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index 62e60d6..3f8e537 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -19,12 +19,13 @@
from oslo_log import log as logging
from oslo_utils import importutils
+import six
from six import moves
+from tempest_lib.common import ssh
from tempest_lib.common.utils import data_utils
from tempest import clients
from tempest.common import isolated_creds
-from tempest.common import ssh
from tempest import config
from tempest import exceptions
from tempest.stress import cleanup
@@ -171,7 +172,7 @@
test_run = test_obj(manager, max_runs, stop_on_error)
kwargs = test.get('kwargs', {})
- test_run.setUp(**dict(kwargs.iteritems()))
+ test_run.setUp(**dict(six.iteritems(kwargs)))
LOG.debug("calling Target Object %s" %
test_run.__class__.__name__)
diff --git a/tempest/test.py b/tempest/test.py
index ae77284..0d709f6c 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -34,6 +34,7 @@
from tempest.common import credentials
from tempest.common import fixed_network
import tempest.common.generator.valid_generator as valid
+import tempest.common.validation_resources as vresources
from tempest import config
from tempest import exceptions
@@ -229,8 +230,12 @@
_service = None
# NOTE(andreaf) credentials holds a list of the credentials to be allocated
- # at class setup time. Credential types can be 'primary', 'alt' or 'admin'
+ # at class setup time. Credential types can be 'primary', 'alt', 'admin' or
+ # a list of roles - the first element of the list being a label, and the
+ # rest the actual roles
credentials = []
+ # Resources required to validate a server using ssh
+ validation_resources = {}
network_resources = {}
# NOTE(sdague): log_format is defined inline here instead of using the oslo
@@ -264,7 +269,7 @@
etype, cls.__name__))
cls.tearDownClass()
try:
- raise etype, value, trace
+ six.reraise(etype, value, trace)
finally:
del trace # to avoid circular refs
@@ -302,7 +307,7 @@
# the first one
if re_raise and etype is not None:
try:
- raise etype, value, trace
+ six.reraise(etype, value, trace)
finally:
del trace # to avoid circular refs
@@ -319,9 +324,16 @@
if 'admin' in cls.credentials and not credentials.is_admin_available():
msg = "Missing Identity Admin API credentials in configuration."
raise cls.skipException(msg)
- if 'alt' is cls.credentials and not credentials.is_alt_available():
+ if 'alt' in cls.credentials and not credentials.is_alt_available():
msg = "Missing a 2nd set of API credentials in configuration."
raise cls.skipException(msg)
+ if hasattr(cls, 'identity_version'):
+ if cls.identity_version == 'v2':
+ if not CONF.identity_feature_enabled.api_v2:
+ raise cls.skipException("Identity api v2 is not enabled")
+ elif cls.identity_version == 'v3':
+ if not CONF.identity_feature_enabled.api_v3:
+ raise cls.skipException("Identity api v3 is not enabled")
@classmethod
def setup_credentials(cls):
@@ -334,19 +346,24 @@
# This may raise an exception in case credentials are not available
# In that case we want to let the exception through and the test
# fail accordingly
- manager = cls.get_client_manager(
- credential_type=credentials_type)
- setattr(cls, 'os_%s' % credentials_type, manager)
- # Setup some common aliases
- # TODO(andreaf) The aliases below are a temporary hack
- # to avoid changing too much code in one patch. They should
- # be removed eventually
- if credentials_type == 'primary':
- cls.os = cls.manager = cls.os_primary
- if credentials_type == 'admin':
- cls.os_adm = cls.admin_manager = cls.os_admin
- if credentials_type == 'alt':
- cls.alt_manager = cls.os_alt
+ if isinstance(credentials_type, six.string_types):
+ manager = cls.get_client_manager(
+ credential_type=credentials_type)
+ setattr(cls, 'os_%s' % credentials_type, manager)
+ # Setup some common aliases
+ # TODO(andreaf) The aliases below are a temporary hack
+ # to avoid changing too much code in one patch. They should
+ # be removed eventually
+ if credentials_type == 'primary':
+ cls.os = cls.manager = cls.os_primary
+ if credentials_type == 'admin':
+ cls.os_adm = cls.admin_manager = cls.os_admin
+ if credentials_type == 'alt':
+ cls.alt_manager = cls.os_alt
+ elif isinstance(credentials_type, list):
+ manager = cls.get_client_manager(roles=credentials_type[1:],
+ force_new=True)
+ setattr(cls, 'os_roles_%s' % credentials_type[0], manager)
@classmethod
def setup_clients(cls):
@@ -360,7 +377,12 @@
def resource_setup(cls):
"""Class level resource setup for test cases.
"""
- pass
+ if hasattr(cls, "os"):
+ cls.validation_resources = vresources.create_validation_resources(
+ cls.os, cls.validation_resources)
+ else:
+ LOG.warn("Client manager not found, validation resources not"
+ " created")
@classmethod
def resource_cleanup(cls):
@@ -368,7 +390,14 @@
Resource cleanup must be able to handle the case of partially setup
resources, in case a failure during `resource_setup` should happen.
"""
- pass
+ if cls.validation_resources:
+ if hasattr(cls, "os"):
+ vresources.clear_validation_resources(cls.os,
+ cls.validation_resources)
+ cls.validation_resources = {}
+ else:
+ LOG.warn("Client manager not found, validation resources not"
+ " deleted")
def setUp(self):
super(BaseTestCase, self).setUp()
@@ -399,39 +428,117 @@
format=self.log_format,
level=None))
- @classmethod
- def get_client_manager(cls, identity_version=None,
- credential_type='primary'):
- """
- Returns an OpenStack client manager
- """
- force_tenant_isolation = getattr(cls, 'force_tenant_isolation', None)
- identity_version = identity_version or CONF.identity.auth_version
+ @property
+ def credentials_provider(self):
+ return self._get_credentials_provider()
- if (not hasattr(cls, 'isolated_creds') or
- not cls.isolated_creds.name == cls.__name__):
- cls.isolated_creds = credentials.get_isolated_credentials(
+ @classmethod
+ def _get_credentials_provider(cls):
+ """Returns a credentials provider
+
+ If no credential provider exists yet creates one.
+ It uses self.identity_version if defined, or the configuration value
+ """
+ if (not hasattr(cls, '_creds_provider') or not cls._creds_provider or
+ not cls._creds_provider.name == cls.__name__):
+ force_tenant_isolation = getattr(cls, 'force_tenant_isolation',
+ False)
+ identity_version = getattr(cls, 'identity_version', None)
+ identity_version = identity_version or CONF.identity.auth_version
+
+ cls._creds_provider = credentials.get_isolated_credentials(
name=cls.__name__, network_resources=cls.network_resources,
force_tenant_isolation=force_tenant_isolation,
- identity_version=identity_version
- )
+ identity_version=identity_version)
+ return cls._creds_provider
- credentials_method = 'get_%s_creds' % credential_type
- if hasattr(cls.isolated_creds, credentials_method):
- creds = getattr(cls.isolated_creds, credentials_method)()
+ @classmethod
+ def get_client_manager(cls, credential_type=None, roles=None,
+ force_new=None):
+ """Returns an OpenStack client manager
+
+ Returns an OpenStack client manager based on either credential_type
+ or a list of roles. If neither is specified, it defaults to
+ credential_type 'primary'
+ :param credential_type: string - primary, alt or admin
+ :param roles: list of roles
+
+ :returns the created client manager
+ :raises skipException: if the requested credentials are not available
+ """
+ if all([roles, credential_type]):
+ msg = "Cannot get credentials by type and roles at the same time"
+ raise ValueError(msg)
+ if not any([roles, credential_type]):
+ credential_type = 'primary'
+ cred_provider = cls._get_credentials_provider()
+ if roles:
+ for role in roles:
+ if not cred_provider.is_role_available(role):
+ skip_msg = (
+ "%s skipped because the configured credential provider"
+ " is not able to provide credentials with the %s role "
+ "assigned." % (cls.__name__, role))
+ raise cls.skipException(skip_msg)
+ params = dict(roles=roles)
+ if force_new is not None:
+ params.update(force_new=force_new)
+ creds = cred_provider.get_creds_by_roles(**params)
else:
- raise exceptions.InvalidCredentials(
- "Invalid credentials type %s" % credential_type)
- os = clients.Manager(credentials=creds, service=cls._service)
- return os
+ credentials_method = 'get_%s_creds' % credential_type
+ if hasattr(cred_provider, credentials_method):
+ creds = getattr(cred_provider, credentials_method)()
+ else:
+ raise exceptions.InvalidCredentials(
+ "Invalid credentials type %s" % credential_type)
+ return clients.Manager(credentials=creds, service=cls._service)
@classmethod
def clear_isolated_creds(cls):
"""
Clears isolated creds if set
"""
- if hasattr(cls, 'isolated_creds'):
- cls.isolated_creds.clear_isolated_creds()
+ if hasattr(cls, '_creds_provider'):
+ cls._creds_provider.clear_isolated_creds()
+
+ @classmethod
+ def set_validation_resources(cls, keypair=None, floating_ip=None,
+ security_group=None,
+ security_group_rules=None):
+ """Specify which ssh server validation resources should be created.
+ Each of the argument must be set to either None, True or False, with
+ None - use default from config (security groups and security group
+ rules get created when set to None)
+ False - Do not create the validation resource
+ True - create the validation resource
+
+ @param keypair
+ @param security_group
+ @param security_group_rules
+ @param floating_ip
+ """
+ if not CONF.validation.run_validation:
+ return
+ if keypair is None:
+ if CONF.validation.auth_method.lower() == "keypair":
+ keypair = True
+ else:
+ keypair = False
+ if floating_ip is None:
+ if CONF.validation.connect_method.lower() == "floating":
+ floating_ip = True
+ else:
+ floating_ip = False
+ if security_group is None:
+ security_group = True
+ if security_group_rules is None:
+ security_group_rules = True
+ if not cls.validation_resources:
+ cls.validation_resources = {
+ 'keypair': keypair,
+ 'security_group': security_group,
+ 'security_group_rules': security_group_rules,
+ 'floating_ip': floating_ip}
@classmethod
def set_network_resources(cls, network=False, router=False, subnet=False,
@@ -462,16 +569,16 @@
"""
# Make sure isolated_creds exists and get a network client
networks_client = cls.get_client_manager().networks_client
- isolated_creds = getattr(cls, 'isolated_creds', None)
+ cred_provider = cls._get_credentials_provider()
# In case of nova network, isolated tenants are not able to list the
# network configured in fixed_network_name, even if the can use it
# for their servers, so using an admin network client to validate
# the network name
if (not CONF.service_available.neutron and
credentials.is_admin_available()):
- admin_creds = isolated_creds.get_admin_creds()
+ admin_creds = cred_provider.get_admin_creds()
networks_client = clients.Manager(admin_creds).networks_client
- return fixed_network.get_tenant_network(isolated_creds,
+ return fixed_network.get_tenant_network(cred_provider,
networks_client)
def assertEmpty(self, list, msg=None):
@@ -621,7 +728,7 @@
msg = ("Missing Identity Admin API credentials in"
"configuration.")
raise self.skipException(msg)
- creds = self.isolated_creds.get_admin_creds()
+ creds = self.credentials_provider.get_admin_creds()
os_adm = clients.Manager(credentials=creds)
client = os_adm.negative_client
else:
diff --git a/tempest/test_discover/test_discover.py b/tempest/test_discover/test_discover.py
index 3fbb8e1..4a4b43a 100644
--- a/tempest/test_discover/test_discover.py
+++ b/tempest/test_discover/test_discover.py
@@ -25,7 +25,7 @@
suite = unittest.TestSuite()
base_path = os.path.split(os.path.dirname(os.path.abspath(__file__)))[0]
base_path = os.path.split(base_path)[0]
- for test_dir in ['./tempest/api', './tempest/cli', './tempest/scenario',
+ for test_dir in ['./tempest/api', './tempest/scenario',
'./tempest/thirdparty']:
if not pattern:
suite.addTests(loader.discover(test_dir, top_level_dir=base_path))
diff --git a/tempest/tests/cli/__init__.py b/tempest/tests/cli/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/tests/cli/__init__.py
+++ /dev/null
diff --git a/tempest/tests/cli/test_cli.py b/tempest/tests/cli/test_cli.py
deleted file mode 100644
index 8f18dfc..0000000
--- a/tempest/tests/cli/test_cli.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright 2014 IBM Corp.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import mock
-from tempest_lib.cli import base as cli_base
-import testtools
-
-from tempest import cli
-from tempest import config
-from tempest import exceptions
-from tempest.tests import base
-from tempest.tests import fake_config
-
-
-class TestMinClientVersion(base.TestCase):
- """Tests for the min_client_version decorator.
- """
-
- def setUp(self):
- super(TestMinClientVersion, self).setUp()
- self.useFixture(fake_config.ConfigFixture())
- self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
-
- def _test_min_version(self, required, installed, expect_skip):
-
- @cli.min_client_version(client='nova', version=required)
- def fake(self, expect_skip):
- if expect_skip:
- # If we got here, the decorator didn't raise a skipException as
- # expected so we need to fail.
- self.fail('Should not have gotten past the decorator.')
-
- with mock.patch.object(cli_base, 'execute',
- return_value=installed) as mock_cmd:
- if expect_skip:
- self.assertRaises(testtools.TestCase.skipException, fake,
- self, expect_skip)
- else:
- fake(self, expect_skip)
- mock_cmd.assert_called_once_with('nova', '', params='--version',
- cli_dir='/usr/local/bin',
- merge_stderr=True)
-
- def test_min_client_version(self):
- # required, installed, expect_skip
- cases = (('2.17.0', '2.17.0', False),
- ('2.17.0', '2.18.0', False),
- ('2.18.0', '2.17.0', True))
-
- for case in cases:
- self._test_min_version(*case)
-
- @mock.patch.object(cli_base, 'execute', return_value=' ')
- def test_check_client_version_empty_output(self, mock_execute):
- # Tests that an exception is raised if the command output is empty.
- self.assertRaises(exceptions.TempestException,
- cli.check_client_version, 'nova', '2.18.0')
diff --git a/tempest/tests/cmd/test_javelin.py b/tempest/tests/cmd/test_javelin.py
new file mode 100644
index 0000000..860599b
--- /dev/null
+++ b/tempest/tests/cmd/test_javelin.py
@@ -0,0 +1,233 @@
+#!/usr/bin/env python
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import mock
+from oslotest import mockpatch
+from tempest_lib import exceptions as lib_exc
+
+from tempest.cmd import javelin
+from tempest.tests import base
+
+
+class JavelinUnitTest(base.TestCase):
+
+ def setUp(self):
+ super(JavelinUnitTest, self).setUp()
+ javelin.setup_logging()
+ self.fake_client = mock.MagicMock()
+ self.fake_object = mock.MagicMock()
+
+
+class TestCreateResources(JavelinUnitTest):
+ def test_create_tenants(self):
+
+ self.fake_client.identity.list_tenants.return_value = []
+ self.useFixture(mockpatch.PatchObject(javelin, "keystone_admin",
+ return_value=self.fake_client))
+
+ javelin.create_tenants([self.fake_object['name']])
+
+ mocked_function = self.fake_client.identity.create_tenant
+ mocked_function.assert_called_once_with(self.fake_object['name'])
+
+ def test_create_duplicate_tenant(self):
+ self.fake_client.identity.list_tenants.return_value = [
+ {'name': self.fake_object['name']}]
+ self.useFixture(mockpatch.PatchObject(javelin, "keystone_admin",
+ return_value=self.fake_client))
+
+ javelin.create_tenants([self.fake_object['name']])
+
+ mocked_function = self.fake_client.identity.create_tenant
+ self.assertFalse(mocked_function.called)
+
+ def test_create_users(self):
+ self.fake_client.identity.get_tenant_by_name.return_value = \
+ self.fake_object['tenant']
+ self.fake_client.identity.get_user_by_username.side_effect = \
+ lib_exc.NotFound()
+ self.useFixture(mockpatch.PatchObject(javelin, "keystone_admin",
+ return_value=self.fake_client))
+
+ javelin.create_users([self.fake_object])
+
+ fake_tenant_id = self.fake_object['tenant']['id']
+ fake_email = "%s@%s" % (self.fake_object['user'], fake_tenant_id)
+ mocked_function = self.fake_client.identity.create_user
+ mocked_function.assert_called_once_with(self.fake_object['name'],
+ self.fake_object['password'],
+ fake_tenant_id,
+ fake_email,
+ enabled=True)
+
+ def test_create_user_missing_tenant(self):
+ self.fake_client.identity.get_tenant_by_name.side_effect = \
+ lib_exc.NotFound()
+ self.useFixture(mockpatch.PatchObject(javelin, "keystone_admin",
+ return_value=self.fake_client))
+
+ javelin.create_users([self.fake_object])
+
+ mocked_function = self.fake_client.identity.create_user
+ self.assertFalse(mocked_function.called)
+
+ def test_create_objects(self):
+
+ self.useFixture(mockpatch.PatchObject(javelin, "client_for_user",
+ return_value=self.fake_client))
+ self.useFixture(mockpatch.PatchObject(javelin, "_assign_swift_role"))
+ self.useFixture(mockpatch.PatchObject(javelin, "_file_contents",
+ return_value=self.fake_object.content))
+
+ javelin.create_objects([self.fake_object])
+
+ mocked_function = self.fake_client.containers.create_container
+ mocked_function.assert_called_once_with(self.fake_object['container'])
+ mocked_function = self.fake_client.objects.create_object
+ mocked_function.assert_called_once_with(self.fake_object['container'],
+ self.fake_object['name'],
+ self.fake_object.content)
+
+ def test_create_images(self):
+ self.fake_client.images.create_image.return_value = \
+ self.fake_object['body']
+
+ self.useFixture(mockpatch.PatchObject(javelin, "client_for_user",
+ return_value=self.fake_client))
+ self.useFixture(mockpatch.PatchObject(javelin, "_get_image_by_name",
+ return_value=[]))
+ self.useFixture(mockpatch.PatchObject(javelin, "_resolve_image",
+ return_value=(None, None)))
+
+ with mock.patch('six.moves.builtins.open', mock.mock_open(),
+ create=True) as open_mock:
+ javelin.create_images([self.fake_object])
+
+ mocked_function = self.fake_client.images.create_image
+ mocked_function.assert_called_once_with(self.fake_object['name'],
+ self.fake_object['format'],
+ self.fake_object['format'])
+
+ mocked_function = self.fake_client.images.store_image
+ fake_image_id = self.fake_object['body'].get('id')
+ mocked_function.assert_called_once_with(fake_image_id, open_mock())
+
+ def test_create_networks(self):
+ self.fake_client.networks.list_networks.return_value = {
+ 'networks': []}
+
+ self.useFixture(mockpatch.PatchObject(javelin, "client_for_user",
+ return_value=self.fake_client))
+
+ javelin.create_networks([self.fake_object])
+
+ mocked_function = self.fake_client.networks.create_network
+ mocked_function.assert_called_once_with(name=self.fake_object['name'])
+
+ def test_create_subnet(self):
+
+ fake_network = self.fake_object['network']
+
+ self.useFixture(mockpatch.PatchObject(javelin, "client_for_user",
+ return_value=self.fake_client))
+ self.useFixture(mockpatch.PatchObject(javelin, "_get_resource_by_name",
+ return_value=fake_network))
+
+ fake_netaddr = mock.MagicMock()
+ self.useFixture(mockpatch.PatchObject(javelin, "netaddr",
+ return_value=fake_netaddr))
+ fake_version = javelin.netaddr.IPNetwork().version
+
+ javelin.create_subnets([self.fake_object])
+
+ mocked_function = self.fake_client.networks.create_subnet
+ mocked_function.assert_called_once_with(network_id=fake_network['id'],
+ cidr=self.fake_object['range'],
+ name=self.fake_object['name'],
+ ip_version=fake_version)
+
+
+class TestDestroyResources(JavelinUnitTest):
+
+ def test_destroy_tenants(self):
+
+ fake_tenant = self.fake_object['tenant']
+
+ fake_auth = mock.MagicMock()
+ fake_auth.identity.get_tenant_by_name.return_value = fake_tenant
+
+ self.useFixture(mockpatch.PatchObject(javelin, "keystone_admin",
+ return_value=fake_auth))
+ javelin.destroy_tenants([fake_tenant])
+
+ mocked_function = fake_auth.identity.delete_tenant
+ mocked_function.assert_called_once_with(fake_tenant['id'])
+
+ def test_destroy_users(self):
+
+ fake_user = self.fake_object['user']
+ fake_tenant = self.fake_object['tenant']
+
+ fake_auth = mock.MagicMock()
+ fake_auth.identity.get_tenant_by_name.return_value = fake_tenant
+ fake_auth.identity.get_user_by_username.return_value = fake_user
+
+ self.useFixture(mockpatch.PatchObject(javelin, "keystone_admin",
+ return_value=fake_auth))
+
+ javelin.destroy_users([fake_user])
+
+ mocked_function = fake_auth.identity.delete_user
+ mocked_function.assert_called_once_with(fake_user['id'])
+
+ def test_destroy_objects(self):
+
+ fake_client = mock.MagicMock()
+ fake_client.objects.delete_object.return_value = {'status': "200"}, ""
+ self.useFixture(mockpatch.PatchObject(javelin, "client_for_user",
+ return_value=fake_client))
+ javelin.destroy_objects([self.fake_object])
+
+ mocked_function = fake_client.objects.delete_object
+ mocked_function.asswert_called_once(self.fake_object['container'],
+ self.fake_object['name'])
+
+ def test_destroy_images(self):
+
+ fake_client = mock.MagicMock()
+ self.useFixture(mockpatch.PatchObject(javelin, "client_for_user",
+ return_value=fake_client))
+ self.useFixture(mockpatch.PatchObject(javelin, "_get_image_by_name",
+ return_value=self.fake_object['image']))
+
+ javelin.destroy_images([self.fake_object])
+
+ mocked_function = fake_client.images.delete_image
+ mocked_function.assert_called_once_with(
+ self.fake_object['image']['id'])
+
+ def test_destroy_networks(self):
+
+ fake_client = mock.MagicMock()
+ self.useFixture(mockpatch.PatchObject(javelin, "client_for_user",
+ return_value=fake_client))
+ self.useFixture(mockpatch.PatchObject(
+ javelin, "_get_resource_by_name",
+ return_value=self.fake_object['resource']))
+
+ javelin.destroy_networks([self.fake_object])
+
+ mocked_function = fake_client.networks.delete_network
+ mocked_function.assert_called_once_with(
+ self.fake_object['resource']['id'])
diff --git a/tempest/tests/common/test_accounts.py b/tempest/tests/common/test_accounts.py
index f357bf4..596e811 100644
--- a/tempest/tests/common/test_accounts.py
+++ b/tempest/tests/common/test_accounts.py
@@ -20,6 +20,7 @@
from oslo_concurrency import lockutils
from oslo_config import cfg
from oslotest import mockpatch
+import six
from tempest_lib import auth
from tempest_lib.services.identity.v2 import token_client
@@ -79,7 +80,7 @@
hash_list = []
for account in accounts_list:
hash = hashlib.md5()
- hash.update(str(account))
+ hash.update(six.text_type(account).encode('utf-8'))
temp_hash = hash.hexdigest()
hash_list.append(temp_hash)
return hash_list
@@ -106,7 +107,8 @@
def test_create_hash_file_previous_file(self):
# Emulate the lock existing on the filesystem
self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
- with mock.patch('__builtin__.open', mock.mock_open(), create=True):
+ with mock.patch('six.moves.builtins.open', mock.mock_open(),
+ create=True):
test_account_class = accounts.Accounts('v2', 'test_name')
res = test_account_class._create_hash_file('12345')
self.assertFalse(res, "_create_hash_file should return False if the "
@@ -115,7 +117,8 @@
def test_create_hash_file_no_previous_file(self):
# Emulate the lock not existing on the filesystem
self.useFixture(mockpatch.Patch('os.path.isfile', return_value=False))
- with mock.patch('__builtin__.open', mock.mock_open(), create=True):
+ with mock.patch('six.moves.builtins.open', mock.mock_open(),
+ create=True):
test_account_class = accounts.Accounts('v2', 'test_name')
res = test_account_class._create_hash_file('12345')
self.assertTrue(res, "_create_hash_file should return True if the "
@@ -129,7 +132,7 @@
mkdir_mock = self.useFixture(mockpatch.Patch('os.mkdir'))
self.useFixture(mockpatch.Patch('os.path.isfile', return_value=False))
test_account_class = accounts.Accounts('v2', 'test_name')
- with mock.patch('__builtin__.open', mock.mock_open(),
+ with mock.patch('six.moves.builtins.open', mock.mock_open(),
create=True) as open_mock:
test_account_class._get_free_hash(hash_list)
lock_path = os.path.join(lockutils.get_lock_path(accounts.CONF),
@@ -148,7 +151,8 @@
# Emulate all lcoks in list are in use
self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
test_account_class = accounts.Accounts('v2', 'test_name')
- with mock.patch('__builtin__.open', mock.mock_open(), create=True):
+ with mock.patch('six.moves.builtins.open', mock.mock_open(),
+ create=True):
self.assertRaises(exceptions.InvalidConfiguration,
test_account_class._get_free_hash, hash_list)
@@ -167,7 +171,7 @@
return True
self.stubs.Set(os.path, 'isfile', _fake_is_file)
- with mock.patch('__builtin__.open', mock.mock_open(),
+ with mock.patch('six.moves.builtins.open', mock.mock_open(),
create=True) as open_mock:
test_account_class._get_free_hash(hash_list)
lock_path = os.path.join(lockutils.get_lock_path(accounts.CONF),
@@ -265,7 +269,7 @@
'tempest.common.accounts.read_accounts_yaml',
return_value=self.test_accounts))
test_accounts_class = accounts.Accounts('v2', 'test_name')
- hashes = test_accounts_class.hash_dict['creds'].keys()
+ hashes = list(test_accounts_class.hash_dict['creds'].keys())
admin_hashes = test_accounts_class.hash_dict['roles'][
cfg.CONF.identity.admin_role]
temp_hash = hashes[0]
diff --git a/tempest/tests/common/test_admin_available.py b/tempest/tests/common/test_admin_available.py
index 4e3aa4c..5c69c5e 100644
--- a/tempest/tests/common/test_admin_available.py
+++ b/tempest/tests/common/test_admin_available.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from oslo.config import cfg
+from oslo_config import cfg
from oslotest import mockpatch
from tempest.common import credentials
diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py
index d6377e6..3506856 100644
--- a/tempest/tests/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/common/utils/linux/test_remote_client.py
@@ -73,6 +73,7 @@
# the information using gnu/linux tools.
def _assert_exec_called_with(self, cmd):
+ cmd = "set -eu -o pipefail; PATH=$PATH:/sbin; " + cmd
self.ssh_mock.mock.exec_command.assert_called_with(cmd)
def test_get_number_of_vcpus(self):
@@ -119,7 +120,7 @@
self.assertEqual(self.conn.get_mac_address(), macs)
self._assert_exec_called_with(
- "/bin/ip addr | awk '/ether/ {print $2}'")
+ "ip addr | awk '/ether/ {print $2}'")
def test_get_ip_list(self):
ips = """1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue
@@ -136,7 +137,7 @@
valid_lft forever preferred_lft forever"""
self.ssh_mock.mock.exec_command.return_value = ips
self.assertEqual(self.conn.get_ip_list(), ips)
- self._assert_exec_called_with('/bin/ip address')
+ self._assert_exec_called_with('ip address')
def test_assign_static_ip(self):
self.ssh_mock.mock.exec_command.return_value = ''
@@ -144,9 +145,10 @@
nic = 'eth0'
self.assertEqual(self.conn.assign_static_ip(nic, ip), '')
self._assert_exec_called_with(
- "sudo /bin/ip addr add %s/%s dev %s" % (ip, '28', nic))
+ "sudo ip addr add %s/%s dev %s" % (ip, '28', nic))
def test_turn_nic_on(self):
nic = 'eth0'
self.conn.turn_nic_on(nic)
- self._assert_exec_called_with('sudo /bin/ip link set %s up' % nic)
+ self._assert_exec_called_with(
+ 'sudo ip link set %s up' % nic)
diff --git a/tempest/tests/common/utils/test_file_utils.py b/tempest/tests/common/utils/test_file_utils.py
index 605e82a..937aefa 100644
--- a/tempest/tests/common/utils/test_file_utils.py
+++ b/tempest/tests/common/utils/test_file_utils.py
@@ -22,7 +22,8 @@
class TestFileUtils(base.TestCase):
def test_have_effective_read_path(self):
- with mock.patch('__builtin__.open', mock.mock_open(), create=True):
+ with mock.patch('six.moves.builtins.open', mock.mock_open(),
+ create=True):
result = file_utils.have_effective_read_access('fake_path')
self.assertTrue(result)
diff --git a/tempest/tests/negative/test_negative_generators.py b/tempest/tests/negative/test_negative_generators.py
index 2fa6933..78fd80d 100644
--- a/tempest/tests/negative/test_negative_generators.py
+++ b/tempest/tests/negative/test_negative_generators.py
@@ -17,6 +17,7 @@
import jsonschema
import mock
+import six
from tempest.common.generator import base_generator
from tempest.common.generator import negative_generator
@@ -101,11 +102,11 @@
class fake_test_class(object):
def __init__(self, scenario):
- for k, v in scenario.iteritems():
+ for k, v in six.iteritems(scenario):
setattr(self, k, v)
def _validate_result(self, valid_schema, invalid_schema):
- for k, v in valid_schema.iteritems():
+ for k, v in six.iteritems(valid_schema):
self.assertTrue(k in invalid_schema)
def test_generator_mandatory_functions(self):
diff --git a/tempest/tests/stress/test_stress.py b/tempest/tests/stress/test_stress.py
index 3a7b436..16f1ac7 100644
--- a/tempest/tests/stress/test_stress.py
+++ b/tempest/tests/stress/test_stress.py
@@ -33,7 +33,7 @@
cmd = ' '.join([cmd, param])
LOG.info("running: '%s'" % cmd)
cmd_str = cmd
- cmd = shlex.split(cmd.encode('utf-8'))
+ cmd = shlex.split(cmd)
result = ''
result_err = ''
try:
diff --git a/tempest/tests/test_glance_http.py b/tempest/tests/test_glance_http.py
index b132f60..7850ee4 100644
--- a/tempest/tests/test_glance_http.py
+++ b/tempest/tests/test_glance_http.py
@@ -137,7 +137,7 @@
resp, body = self.client.raw_request('PUT', '/images', body=req_body)
self.assertEqual(200, resp.status)
self.assertEqual('fake_response_body', body.read())
- httplib.HTTPConnection.send.assert_call_count(req_body.len)
+ httplib.HTTPConnection.send.assert_call_count(req_body.tell())
def test_get_connection_class_for_https(self):
conn_class = self.client.get_connection_class('https')
diff --git a/tempest/tests/test_list_tests.py b/tempest/tests/test_list_tests.py
index 19e4c9c..38d4c5c 100644
--- a/tempest/tests/test_list_tests.py
+++ b/tempest/tests/test_list_tests.py
@@ -14,6 +14,7 @@
import os
import re
+import six
import subprocess
from tempest.tests import base
@@ -32,7 +33,7 @@
self.assertEqual(0, p.returncode,
"test discovery failed, one or more files cause an "
"error on import %s" % ids)
- ids = ids.split('\n')
+ ids = six.text_type(ids).split('\n')
for test_id in ids:
if re.match('(\w+\.){3}\w+', test_id):
if not test_id.startswith('tempest.'):
diff --git a/tempest/tests/test_ssh.py b/tempest/tests/test_ssh.py
deleted file mode 100644
index aaacaab..0000000
--- a/tempest/tests/test_ssh.py
+++ /dev/null
@@ -1,189 +0,0 @@
-# Copyright 2014 OpenStack Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import contextlib
-import socket
-import time
-
-import mock
-import testtools
-
-from tempest.common import ssh
-from tempest import exceptions
-from tempest.tests import base
-
-
-class TestSshClient(base.TestCase):
-
- def test_pkey_calls_paramiko_RSAKey(self):
- with contextlib.nested(
- mock.patch('paramiko.RSAKey.from_private_key'),
- mock.patch('six.moves.cStringIO')) as (rsa_mock, cs_mock):
- cs_mock.return_value = mock.sentinel.csio
- pkey = 'mykey'
- ssh.Client('localhost', 'root', pkey=pkey)
- rsa_mock.assert_called_once_with(mock.sentinel.csio)
- cs_mock.assert_called_once_with('mykey')
- rsa_mock.reset_mock()
- cs_mock.reset_mock()
- pkey = mock.sentinel.pkey
- # Shouldn't call out to load a file from RSAKey, since
- # a sentinel isn't a basestring...
- ssh.Client('localhost', 'root', pkey=pkey)
- self.assertEqual(0, rsa_mock.call_count)
- self.assertEqual(0, cs_mock.call_count)
-
- def _set_ssh_connection_mocks(self):
- client_mock = mock.MagicMock()
- client_mock.connect.return_value = True
- return (self.patch('paramiko.SSHClient'),
- self.patch('paramiko.AutoAddPolicy'),
- client_mock)
-
- def test_get_ssh_connection(self):
- c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
- s_mock = self.patch('time.sleep')
-
- c_mock.return_value = client_mock
- aa_mock.return_value = mock.sentinel.aa
-
- # Test normal case for successful connection on first try
- client = ssh.Client('localhost', 'root', timeout=2)
- client._get_ssh_connection(sleep=1)
-
- aa_mock.assert_called_once_with()
- client_mock.set_missing_host_key_policy.assert_called_once_with(
- mock.sentinel.aa)
- expected_connect = [mock.call(
- 'localhost',
- username='root',
- pkey=None,
- key_filename=None,
- look_for_keys=False,
- timeout=10.0,
- password=None
- )]
- self.assertEqual(expected_connect, client_mock.connect.mock_calls)
- self.assertEqual(0, s_mock.call_count)
-
- def test_get_ssh_connection_two_attemps(self):
- c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
-
- c_mock.return_value = client_mock
- client_mock.connect.side_effect = [
- socket.error,
- mock.MagicMock()
- ]
-
- client = ssh.Client('localhost', 'root', timeout=1)
- start_time = int(time.time())
- client._get_ssh_connection(sleep=1)
- end_time = int(time.time())
- self.assertLess((end_time - start_time), 4)
- self.assertGreater((end_time - start_time), 1)
-
- def test_get_ssh_connection_timeout(self):
- c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
-
- c_mock.return_value = client_mock
- client_mock.connect.side_effect = [
- socket.error,
- socket.error,
- socket.error,
- ]
-
- client = ssh.Client('localhost', 'root', timeout=2)
- start_time = int(time.time())
- with testtools.ExpectedException(exceptions.SSHTimeout):
- client._get_ssh_connection()
- end_time = int(time.time())
- self.assertLess((end_time - start_time), 5)
- self.assertGreaterEqual((end_time - start_time), 2)
-
- def test_exec_command(self):
- gsc_mock = self.patch('tempest.common.ssh.Client._get_ssh_connection')
- ito_mock = self.patch('tempest.common.ssh.Client._is_timed_out')
- select_mock = self.patch('select.poll')
-
- client_mock = mock.MagicMock()
- tran_mock = mock.MagicMock()
- chan_mock = mock.MagicMock()
- poll_mock = mock.MagicMock()
-
- def reset_mocks():
- gsc_mock.reset_mock()
- ito_mock.reset_mock()
- select_mock.reset_mock()
- poll_mock.reset_mock()
- client_mock.reset_mock()
- tran_mock.reset_mock()
- chan_mock.reset_mock()
-
- select_mock.return_value = poll_mock
- gsc_mock.return_value = client_mock
- ito_mock.return_value = True
- client_mock.get_transport.return_value = tran_mock
- tran_mock.open_session.return_value = chan_mock
- poll_mock.poll.side_effect = [
- [0, 0, 0]
- ]
-
- # Test for a timeout condition immediately raised
- client = ssh.Client('localhost', 'root', timeout=2)
- with testtools.ExpectedException(exceptions.TimeoutException):
- client.exec_command("test")
-
- chan_mock.fileno.assert_called_once_with()
- chan_mock.exec_command.assert_called_once_with("test")
- chan_mock.shutdown_write.assert_called_once_with()
-
- SELECT_POLLIN = 1
- poll_mock.register.assert_called_once_with(chan_mock, SELECT_POLLIN)
- poll_mock.poll.assert_called_once_with(10)
-
- # Test for proper reading of STDOUT and STDERROR and closing
- # of all file descriptors.
-
- reset_mocks()
-
- select_mock.return_value = poll_mock
- gsc_mock.return_value = client_mock
- ito_mock.return_value = False
- client_mock.get_transport.return_value = tran_mock
- tran_mock.open_session.return_value = chan_mock
- poll_mock.poll.side_effect = [
- [1, 0, 0]
- ]
- closed_prop = mock.PropertyMock(return_value=True)
- type(chan_mock).closed = closed_prop
- chan_mock.recv_exit_status.return_value = 0
- chan_mock.recv.return_value = ''
- chan_mock.recv_stderr.return_value = ''
-
- client = ssh.Client('localhost', 'root', timeout=2)
- client.exec_command("test")
-
- chan_mock.fileno.assert_called_once_with()
- chan_mock.exec_command.assert_called_once_with("test")
- chan_mock.shutdown_write.assert_called_once_with()
-
- SELECT_POLLIN = 1
- poll_mock.register.assert_called_once_with(chan_mock, SELECT_POLLIN)
- poll_mock.poll.assert_called_once_with(10)
- chan_mock.recv_ready.assert_called_once_with()
- chan_mock.recv.assert_called_once_with(1024)
- chan_mock.recv_stderr_ready.assert_called_once_with()
- chan_mock.recv_stderr.assert_called_once_with(1024)
- chan_mock.recv_exit_status.assert_called_once_with()
- closed_prop.assert_called_once_with()
diff --git a/tempest/tests/test_tenant_isolation.py b/tempest/tests/test_tenant_isolation.py
index 1eb33a4..72a63c3 100644
--- a/tempest/tests/test_tenant_isolation.py
+++ b/tempest/tests/test_tenant_isolation.py
@@ -196,6 +196,7 @@
# Assert that the role creation is called with the 2 specified roles
self.assertEqual(len(calls), 2)
args = map(lambda x: x[1], calls)
+ args = list(args)
self.assertIn(('1234', '1234', '1234'), args)
self.assertIn(('1234', '1234', '12345'), args)
self.assertEqual(role_creds.username, 'fake_role_user')
@@ -237,6 +238,7 @@
calls = user_mock.mock_calls
self.assertEqual(len(calls), 3)
args = map(lambda x: x[1][0], calls)
+ args = list(args)
self.assertIn('1234', args)
self.assertIn('12345', args)
self.assertIn('123456', args)
@@ -244,6 +246,7 @@
calls = tenant_mock.mock_calls
self.assertEqual(len(calls), 3)
args = map(lambda x: x[1][0], calls)
+ args = list(args)
self.assertIn('1234', args)
self.assertIn('12345', args)
self.assertIn('123456', args)
@@ -265,6 +268,36 @@
self.assertEqual(alt_creds.user_id, '1234')
@mock.patch('tempest_lib.common.rest_client.RestClient')
+ def test_no_network_creation_with_config_set(self, MockRestClient):
+ cfg.CONF.set_default('create_isolated_networks', False, group='auth')
+ iso_creds = isolated_creds.IsolatedCreds(name='test class',
+ password='fake_password')
+ self._mock_assign_user_role()
+ self._mock_list_role()
+ self._mock_user_create('1234', 'fake_prim_user')
+ self._mock_tenant_create('1234', 'fake_prim_tenant')
+ net = mock.patch.object(iso_creds.network_admin_client,
+ 'delete_network')
+ net_mock = net.start()
+ subnet = mock.patch.object(iso_creds.network_admin_client,
+ 'delete_subnet')
+ subnet_mock = subnet.start()
+ router = mock.patch.object(iso_creds.network_admin_client,
+ 'delete_router')
+ router_mock = router.start()
+
+ primary_creds = iso_creds.get_primary_creds()
+ self.assertEqual(net_mock.mock_calls, [])
+ self.assertEqual(subnet_mock.mock_calls, [])
+ self.assertEqual(router_mock.mock_calls, [])
+ network = primary_creds.network
+ subnet = primary_creds.subnet
+ router = primary_creds.router
+ self.assertIsNone(network)
+ self.assertIsNone(subnet)
+ self.assertIsNone(router)
+
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_network_creation(self, MockRestClient):
iso_creds = isolated_creds.IsolatedCreds(name='test class',
password='fake_password')
@@ -381,6 +414,7 @@
calls = remove_secgroup_mock.mock_calls
self.assertEqual(len(calls), 3)
args = map(lambda x: x[1][0], calls)
+ args = list(args)
self.assertIn('v2.0/security-groups/sg-1234', args)
self.assertIn('v2.0/security-groups/sg-12345', args)
self.assertIn('v2.0/security-groups/sg-123456', args)
@@ -388,6 +422,7 @@
calls = remove_router_interface_mock.mock_calls
self.assertEqual(len(calls), 3)
args = map(lambda x: x[1], calls)
+ args = list(args)
self.assertIn(('1234', '1234'), args)
self.assertIn(('12345', '12345'), args)
self.assertIn(('123456', '123456'), args)
@@ -395,6 +430,7 @@
calls = net_mock.mock_calls
self.assertEqual(len(calls), 3)
args = map(lambda x: x[1][0], calls)
+ args = list(args)
self.assertIn('1234', args)
self.assertIn('12345', args)
self.assertIn('123456', args)
@@ -402,6 +438,7 @@
calls = subnet_mock.mock_calls
self.assertEqual(len(calls), 3)
args = map(lambda x: x[1][0], calls)
+ args = list(args)
self.assertIn('1234', args)
self.assertIn('12345', args)
self.assertIn('123456', args)
@@ -409,6 +446,7 @@
calls = router_mock.mock_calls
self.assertEqual(len(calls), 3)
args = map(lambda x: x[1][0], calls)
+ args = list(args)
self.assertIn('1234', args)
self.assertIn('12345', args)
self.assertIn('123456', args)
diff --git a/tempest/tests/test_waiters.py b/tempest/tests/test_waiters.py
index cdf5362..329d610 100644
--- a/tempest/tests/test_waiters.py
+++ b/tempest/tests/test_waiters.py
@@ -29,7 +29,7 @@
self.client.build_interval = 1
def test_wait_for_image_status(self):
- self.client.get_image.return_value = ({'status': 'active'})
+ self.client.show_image.return_value = ({'status': 'active'})
start_time = int(time.time())
waiters.wait_for_image_status(self.client, 'fake_image_id', 'active')
end_time = int(time.time())
@@ -37,13 +37,13 @@
self.assertTrue((end_time - start_time) < 10)
def test_wait_for_image_status_timeout(self):
- self.client.get_image.return_value = ({'status': 'saving'})
+ self.client.show_image.return_value = ({'status': 'saving'})
self.assertRaises(exceptions.TimeoutException,
waiters.wait_for_image_status,
self.client, 'fake_image_id', 'active')
def test_wait_for_image_status_error_on_image_create(self):
- self.client.get_image.return_value = ({'status': 'ERROR'})
+ self.client.show_image.return_value = ({'status': 'ERROR'})
self.assertRaises(exceptions.AddImageException,
waiters.wait_for_image_status,
self.client, 'fake_image_id', 'active')
diff --git a/tempest/thirdparty/boto/test.py b/tempest/thirdparty/boto/test.py
index 4485972..1ff4dee 100644
--- a/tempest/thirdparty/boto/test.py
+++ b/tempest/thirdparty/boto/test.py
@@ -252,9 +252,9 @@
except exception.BotoServerError as exc:
error_msg = excMatcher.match(exc)
if error_msg is not None:
- raise self.failureException, error_msg
+ raise self.failureException(error_msg)
else:
- raise self.failureException, "BotoServerError not raised"
+ raise self.failureException("BotoServerError not raised")
@classmethod
def resource_cleanup(cls):
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index 19a77dc..b7f0e81 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -283,7 +283,17 @@
CONF.compute.ssh_user,
pkey=self.keypair.material)
text = data_utils.rand_name("Pattern text for console output")
- resp = ssh.write_to_console(text)
+ try:
+ resp = ssh.write_to_console(text)
+ except Exception:
+ if not CONF.compute_feature_enabled.console_output:
+ LOG.debug('Console output not supported, cannot log')
+ else:
+ console_output = instance.get_console_output().output
+ LOG.debug('Console output for %s\nbody=\n%s',
+ instance.id, console_output)
+ raise
+
self.assertFalse(resp)
def _output():
diff --git a/test-requirements.txt b/test-requirements.txt
index 76ae521..32f33bc 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -5,9 +5,9 @@
# needed for doc build
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
python-subunit>=0.0.18
-oslosphinx>=2.5.0,<2.6.0 # Apache-2.0
+oslosphinx>=2.5.0 # Apache-2.0
mox>=0.5.3
mock>=1.0
coverage>=3.6
-oslotest>=1.5.1,<1.6.0 # Apache-2.0
-stevedore>=1.3.0,<1.4.0 # Apache-2.0
+oslotest>=1.5.1 # Apache-2.0
+stevedore>=1.3.0 # Apache-2.0
diff --git a/tox.ini b/tox.ini
index 2f0aa99..4bb5df6 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = pep8,py27
+envlist = pep8,py27,py34
minversion = 1.6
skipsdist = True
@@ -47,7 +47,7 @@
# See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
+ bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty)) {posargs}'
[testenv:full-serial]
sitepackages = {[tempestenv]sitepackages}
@@ -57,17 +57,7 @@
# See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
-
-[testenv:heat-slow]
-sitepackages = {[tempestenv]sitepackages}
-setenv = {[tempestenv]setenv}
- OS_TEST_TIMEOUT=1200
-deps = {[tempestenv]deps}
-# The regex below is used to select heat api/scenario tests tagged as slow.
-commands =
- find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox.sh '(?=.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)\.orchestration) {posargs}'
+ bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty)) {posargs}'
[testenv:large-ops]
sitepackages = {[tempestenv]sitepackages}