Merge "Check Floating ip status before load balancer check"
diff --git a/README.rst b/README.rst
index 5284bbf..7af0025 100644
--- a/README.rst
+++ b/README.rst
@@ -124,14 +124,14 @@
Python 2.6
----------
-Tempest can be run with Python 2.6 however the unit tests and the gate
-currently only run with Python 2.7, so there are no guarantees about the state
-of tempest when running with Python 2.6. Additionally, to enable testr to work
-with tempest using python 2.6 the discover module from the unittest-ext
-project has to be patched to switch the unittest.TestSuite to use
-unittest2.TestSuite instead. See:
-
-https://code.google.com/p/unittest-ext/issues/detail?id=79
+Starting in the kilo release the OpenStack services dropped all support for
+python 2.6. This change has been mirrored in tempest, starting after the
+tempest-2 tag. This means that proposed changes to tempest which only fix
+python 2.6 compatibility will be rejected, and moving forward more features not
+present in python 2.6 will be used. If you're running you're OpenStack services
+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)
Branchless Tempest Considerations
---------------------------------
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
new file mode 100644
index 0000000..08f37cc
--- /dev/null
+++ b/doc/source/configuration.rst
@@ -0,0 +1,115 @@
+Tempest Configuration Guide
+===========================
+
+Auth/Credentials
+----------------
+
+Tempest currently has 2 different ways in configuration to provide credentials
+to use when running tempest. One is a traditional set of configuration options
+in the tempest.conf file. These options are in the identity section and let you
+specify a regular user, a global admin user, and a alternate user set of
+credentials. (which consist of a username, password, and project/tenant name)
+These options should be clearly labelled in the sample config file in the
+identity section.
+
+The other method to provide credentials is using the accounts.yaml file. This
+file is used to specify an arbitrary number of users available to run tests
+with. You can specify the location of the file in the
+auth section in the tempest.conf file. To see the specific format used in
+the file please refer to the accounts.yaml.sample file included in tempest.
+Currently users that are specified in the accounts.yaml file are assumed to
+have the same set of roles which can be used for executing all the tests you
+are running. This will be addressed in the future, but is a current limitation.
+Eventually the config options for providing credentials to tempest will be
+deprecated and removed in favor of the accounts.yaml file.
+
+Credential Provider Mechanisms
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Tempest currently also has 3 different internal methods for providing
+authentication to tests. Tenant isolation, locking test accounts, and
+non-locking test accounts. Depending on which one is in use the configuration
+of tempest is slightly different.
+
+Tenant Isolation
+""""""""""""""""
+Tenant isolation was originally create to enable running tempest in parallel.
+For each test class it creates a unique set of user credentials to use for the
+tests in the class. It can create up to 3 sets of username, password, and
+tenant/project names for a primary user, an admin user, and an alternate user.
+To enable and use tenant isolation you only need to configure 2 things:
+
+ #. A set of admin credentials with permissions to create users and
+ tenants/projects. This is specified in the identity section with the
+ admin_username, admin_tenant_name, and admin_password options
+ #. To enable tenant_isolation in the auth section with the
+ allow_tenant_isolation option.
+
+
+Locking Test Accounts
+"""""""""""""""""""""
+For a long time using tenant isolation was the only method available if you
+wanted to enable parallel execution of tempest tests. However this was
+insufficient for certain use cases because of the admin credentials requirement
+to create the credential sets on demand. To get around that the accounts.yaml
+file was introduced and with that a new internal credential provider to enable
+using the list of credentials instead of creating them on demand. With locking
+test accounts each test class will reserve a set of credentials from the
+accounts.yaml before executing any of its tests so that each class is isolated
+like in tenant isolation.
+
+Currently, this mechanism has some limitations, first only non-admin users with
+the same role set can be used at one time. The second limitation is around
+networking, locking test accounts will only work with a single flat network as
+the default for each tenant/project. If another network configuration is used
+in your cloud you might face unexpected failures.
+
+To enable and use locking test accounts you need do a few things:
+
+ #. Enable the locking test account provider with the
+ locking_credentials_provider option in the auth section
+ #. Create a accounts.yaml file which contains the set of pre-existing
+ credentials to use for testing. To make sure you don't have a credentials
+ starvation issue when running in parallel make sure you have at least 2
+ times the number of parallel workers you are using to execute tempest
+ available in the file.
+ #. Provide tempest with the location of you accounts.yaml file with the
+ test_accounts_file option in the auth section
+
+
+Non-locking test accounts
+"""""""""""""""""""""""""
+When tempest was refactored to allow for locking test accounts, the original
+non-tenant isolated case was converted to support the new accounts.yaml file.
+This mechanism is the non-locking test accounts provider. It only makes sense
+to use it if parallel execution isn't needed. If the role restrictions were too
+limiting with the locking accounts provider and tenant isolation is not wanted
+then you can use the non-locking test accounts credential provider without the
+accounts.yaml file. This is also the currently the default configuration for
+tempest, since it doesn't require elevated permissions or the extra file.
+
+To use the non-locking test accounts provider you have 2 ways to configure it.
+First you can specify the sets of credentials in the configuration file like
+detailed above with following 9 options in the identity section:
+
+ #. username
+ #. password
+ #. tenant_name
+ #. admin_username
+ #. admin_password
+ #. admin_tenant_name
+ #. alt_username
+ #. alt_password
+ #. alt_tenant_name
+
+You should use this if you need to specify credentials with different roles.
+(i.e. you want to use admin credentials) However, this isn't a requirement for
+its usage.
+
+You also can use the accounts.yaml file to specify the credentials used for
+testing. This will just allocate them serially so you only need to provide
+a pair of credentials. Do note that all the restrictions associated with
+locking test accounts applies to using the accounts.yaml file this way too.
+The procedure for doing this is very similar to with the locking accounts
+provider just don't set the locking_credentials_provider to true and you
+only should need a single pair of credentials.
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 1f06bc5..cb1c504 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -29,6 +29,15 @@
field_guide/thirdparty
field_guide/unit_tests
+---------------------------
+Tempest Configuration Guide
+---------------------------
+
+.. toctree::
+ :maxdepth: 2
+
+ configuration
+
---------------------
Command Documentation
---------------------
diff --git a/etc/accounts.yaml.sample b/etc/accounts.yaml.sample
index 54fdcad..64ff8a7 100644
--- a/etc/accounts.yaml.sample
+++ b/etc/accounts.yaml.sample
@@ -9,3 +9,27 @@
- username: 'user_2'
tenant_name: 'test_tenant_2'
password: 'test_password'
+
+# To specify which roles a user has list them under the roles field
+- username: 'multi_role_user'
+ tenant_name: 'test_tenant_42'
+ password: 'test_password'
+ roles:
+ - 'fun_role'
+ - 'not_an_admin'
+ - 'an_admin'
+
+# To specify a user has a role specified in the config file you can use the
+# type field to specify it, valid values are admin, operator, and reseller_admin
+- username: 'swift_pseudo_admin_user_1'
+ tenant_name: 'admin_tenant_1'
+ password: 'test_password'
+ types:
+ - 'reseller_admin'
+ - 'operator'
+
+- username: 'admin_user_1'
+ tenant_name: 'admin_tenant_1'
+ password: 'test_password'
+ types:
+ - 'admin'
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index bc4198f..d81d3bb 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -125,7 +125,7 @@
# achieved configuring a list of test accounts (boolean value)
# Deprecated group/name - [compute]/allow_tenant_isolation
# Deprecated group/name - [orchestration]/allow_tenant_isolation
-#allow_tenant_isolation = false
+#allow_tenant_isolation = true
# If set to True it enables the Accounts provider, which locks
# credentials to allow for parallel execution with pre-provisioned
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index 8842899..6155958 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -123,7 +123,7 @@
device = '/dev/%s' % CONF.compute.volume_device_name
server = self.create_test_server(wait_until='ACTIVE')
- volume = volumes_client.create_volume(1)
+ volume = volumes_client.create_volume()
self.addCleanup(volumes_client.delete_volume, volume['id'])
volumes_client.wait_for_volume_status(volume['id'], 'available')
self.client.attach_volume(server['id'],
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index 6e23334..7564758 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -58,7 +58,7 @@
def _create_volume(self):
volume = self.volumes_extensions_client.create_volume(
- 1, display_name=data_utils.rand_name(
+ CONF.volume.volume_size, display_name=data_utils.rand_name(
self.__class__.__name__ + '_volume'))
self.addCleanup(self.delete_volume, volume['id'])
self.volumes_extensions_client.wait_for_volume_status(
diff --git a/tempest/api/compute/test_live_block_migration.py b/tempest/api/compute/test_live_block_migration.py
index a933f81..d2221e1 100644
--- a/tempest/api/compute/test_live_block_migration.py
+++ b/tempest/api/compute/test_live_block_migration.py
@@ -115,7 +115,7 @@
actual_host = self._get_host_for_server(server_id)
target_host = self._get_host_other_than(actual_host)
- volume = self.volumes_client.create_volume(1, display_name='test')
+ volume = self.volumes_client.create_volume(display_name='test')
self.volumes_client.wait_for_volume_status(volume['id'],
'available')
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 43d2302..12d5b0e 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -70,7 +70,7 @@
# Create a volume and wait for it to become ready
self.volume = self.volumes_client.create_volume(
- 1, display_name='test')
+ CONF.volume.volume_size, display_name='test')
self.addCleanup(self._delete_volume)
self.volumes_client.wait_for_volume_status(self.volume['id'],
'available')
diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py
index 207476d..5f84c73 100644
--- a/tempest/api/compute/volumes/test_volumes_get.py
+++ b/tempest/api/compute/volumes/test_volumes_get.py
@@ -46,8 +46,7 @@
v_name = data_utils.rand_name('Volume')
metadata = {'Type': 'work'}
# Create volume
- volume = self.client.create_volume(size=1,
- display_name=v_name,
+ volume = self.client.create_volume(display_name=v_name,
metadata=metadata)
self.addCleanup(self.delete_volume, volume['id'])
self.assertIn('id', volume)
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index 501e9ed..bd126d8 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -53,8 +53,7 @@
v_name = data_utils.rand_name('volume')
metadata = {'Type': 'work'}
try:
- volume = cls.client.create_volume(size=1,
- display_name=v_name,
+ volume = cls.client.create_volume(display_name=v_name,
metadata=metadata)
cls.client.wait_for_volume_status(volume['id'], 'available')
volume = cls.client.get_volume(volume['id'])
diff --git a/tempest/services/identity/json/__init__.py b/tempest/api/identity/admin/v2/__init__.py
similarity index 100%
copy from tempest/services/identity/json/__init__.py
copy to tempest/api/identity/admin/v2/__init__.py
diff --git a/tempest/api/identity/admin/test_roles.py b/tempest/api/identity/admin/v2/test_roles.py
similarity index 100%
rename from tempest/api/identity/admin/test_roles.py
rename to tempest/api/identity/admin/v2/test_roles.py
diff --git a/tempest/api/identity/admin/test_roles_negative.py b/tempest/api/identity/admin/v2/test_roles_negative.py
similarity index 100%
rename from tempest/api/identity/admin/test_roles_negative.py
rename to tempest/api/identity/admin/v2/test_roles_negative.py
diff --git a/tempest/api/identity/admin/test_services.py b/tempest/api/identity/admin/v2/test_services.py
similarity index 100%
rename from tempest/api/identity/admin/test_services.py
rename to tempest/api/identity/admin/v2/test_services.py
diff --git a/tempest/api/identity/admin/test_tenant_negative.py b/tempest/api/identity/admin/v2/test_tenant_negative.py
similarity index 100%
rename from tempest/api/identity/admin/test_tenant_negative.py
rename to tempest/api/identity/admin/v2/test_tenant_negative.py
diff --git a/tempest/api/identity/admin/test_tenants.py b/tempest/api/identity/admin/v2/test_tenants.py
similarity index 100%
rename from tempest/api/identity/admin/test_tenants.py
rename to tempest/api/identity/admin/v2/test_tenants.py
diff --git a/tempest/api/identity/admin/test_tokens.py b/tempest/api/identity/admin/v2/test_tokens.py
similarity index 100%
rename from tempest/api/identity/admin/test_tokens.py
rename to tempest/api/identity/admin/v2/test_tokens.py
diff --git a/tempest/api/identity/admin/test_users.py b/tempest/api/identity/admin/v2/test_users.py
similarity index 100%
rename from tempest/api/identity/admin/test_users.py
rename to tempest/api/identity/admin/v2/test_users.py
diff --git a/tempest/api/identity/admin/test_users_negative.py b/tempest/api/identity/admin/v2/test_users_negative.py
similarity index 100%
rename from tempest/api/identity/admin/test_users_negative.py
rename to tempest/api/identity/admin/v2/test_users_negative.py
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index 6c634b8..0441f6d 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -83,3 +83,16 @@
self.assertEqual(new_name, fetched_domain['name'])
self.assertEqual(new_desc, fetched_domain['description'])
self.assertEqual('true', str(fetched_domain['enabled']).lower())
+
+ @test.attr(type='smoke')
+ @test.idempotent_id('036df86e-bb5d-42c0-a7c2-66b9db3a6046')
+ def test_create_domain_with_disabled_status(self):
+ # Create domain with enabled status as false
+ 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, enabled=False)
+ self.addCleanup(self.client.delete_domain, domain['id'])
+ self.assertEqual(d_name, domain['name'])
+ self.assertFalse(domain['enabled'])
+ self.assertEqual(d_desc, domain['description'])
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index 4b5075c..db64a5b 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -120,7 +120,7 @@
self.assertIsNotNone(trust['id'])
self.assertEqual(impersonate, trust['impersonation'])
if expires is not None:
- # Omit microseconds of the expiry time
+ # Omit microseconds component of the expiry time
trust_expires_at = re.sub(r'\.([0-9]){6}', '', trust['expires_at'])
self.assertEqual(expires, trust_expires_at)
else:
@@ -220,11 +220,14 @@
# with an expiry specified
expires_at = timeutils.utcnow() + datetime.timedelta(hours=1)
# NOTE(ylobankov) In some cases the expiry time may be rounded up
- # because of microseconds. For example, we have the following expiry
- # time for a trust: 2015-02-17T17:34:01.907051Z. However, if we make
- # a GET request on the trust, the response may contain the time
- # rounded up to 2015-02-17T17:34:02.000000Z. That is why we should
- # omit microseconds when creating a trust.
+ # because of microseconds. In fact, it depends on database and its
+ # version. At least MySQL 5.6.16 does this.
+ # For example, when creating a trust, we will set the expiry time of
+ # the trust to 2015-02-17T17:34:01.907051Z. However, if we make a GET
+ # request on the trust, the response will contain the time rounded up
+ # to 2015-02-17T17:34:02.000000Z. That is why we shouldn't set flag
+ # "subsecond" to True when we invoke timeutils.isotime(...) to avoid
+ # problems with rounding.
expires_str = timeutils.isotime(at=expires_at)
trust = self.create_trust(expires=expires_str)
diff --git a/tempest/api/network/admin/test_external_network_extension.py b/tempest/api/network/admin/test_external_network_extension.py
index 20b4e31..d942641 100644
--- a/tempest/api/network/admin/test_external_network_extension.py
+++ b/tempest/api/network/admin/test_external_network_extension.py
@@ -101,7 +101,8 @@
self.addCleanup(self._try_delete_resource,
client.delete_network,
external_network['id'])
- subnet = self.create_subnet(external_network, client=client)
+ subnet = self.create_subnet(external_network, client=client,
+ enable_dhcp=False)
body = client.create_floatingip(
floating_network_id=external_network['id'])
created_floating_ip = body['floatingip']
diff --git a/tempest/api/network/test_metering_extensions.py b/tempest/api/network/test_metering_extensions.py
index f794f5a..8e4ee87 100644
--- a/tempest/api/network/test_metering_extensions.py
+++ b/tempest/api/network/test_metering_extensions.py
@@ -1,7 +1,5 @@
# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
#
-# Author: Emilien Macchi <emilien.macchi@enovance.com>
-#
# 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
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 8479013..79d2046 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -176,7 +176,7 @@
sg_id = group_create_body['security_group']['id']
direction = 'ingress'
protocol = 'icmp'
- icmp_type_codes = [(3, 2), (2, 3), (3, 0), (2, None)]
+ icmp_type_codes = [(3, 2), (3, 0), (8, 0), (0, 0), (11, None)]
for icmp_type, icmp_code in icmp_type_codes:
self._create_verify_security_group_rule(sg_id, direction,
self.ethertype, protocol,
diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py
index 29f314d..9b379f4 100644
--- a/tempest/api/object_storage/test_account_quotas.py
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -1,7 +1,5 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
-# Author: Joe H. Rahme <joe.hakim.rahme@enovance.com>
-#
# 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
diff --git a/tempest/api/object_storage/test_account_quotas_negative.py b/tempest/api/object_storage/test_account_quotas_negative.py
index 548c619..7d4008c 100644
--- a/tempest/api/object_storage/test_account_quotas_negative.py
+++ b/tempest/api/object_storage/test_account_quotas_negative.py
@@ -1,7 +1,5 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
-# Author: Joe H. Rahme <joe.hakim.rahme@enovance.com>
-#
# 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
diff --git a/tempest/api/object_storage/test_account_services_negative.py b/tempest/api/object_storage/test_account_services_negative.py
index a913bd7..f329675 100644
--- a/tempest/api/object_storage/test_account_services_negative.py
+++ b/tempest/api/object_storage/test_account_services_negative.py
@@ -1,7 +1,5 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
-# Author: Joe H. Rahme <joe.hakim.rahme@enovance.com>
-#
# 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
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index 644c3b1..5892340 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -1,7 +1,5 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
-# Author: Joe H. Rahme <joe.hakim.rahme@enovance.com>
-#
# 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
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 102c9cd..45ecfec 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -1,7 +1,5 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
-# Author: Joe H. Rahme <joe.hakim.rahme@enovance.com>
-#
# 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
diff --git a/tempest/api/object_storage/test_crossdomain.py b/tempest/api/object_storage/test_crossdomain.py
index 16ff95e..9d49a73 100644
--- a/tempest/api/object_storage/test_crossdomain.py
+++ b/tempest/api/object_storage/test_crossdomain.py
@@ -1,7 +1,5 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
-# Author: Joe H. Rahme <joe.hakim.rahme@enovance.com>
-#
# 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
diff --git a/tempest/api/object_storage/test_healthcheck.py b/tempest/api/object_storage/test_healthcheck.py
index a2a4497..2ca0a9f 100644
--- a/tempest/api/object_storage/test_healthcheck.py
+++ b/tempest/api/object_storage/test_healthcheck.py
@@ -1,7 +1,5 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
-# Author: Joe H. Rahme <joe.hakim.rahme@enovance.com>
-#
# 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
diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py
index 5425eaa..3e0fc7b 100644
--- a/tempest/api/object_storage/test_object_formpost.py
+++ b/tempest/api/object_storage/test_object_formpost.py
@@ -1,7 +1,5 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
-# Author: Christian Schwede <christian.schwede@enovance.com>
-#
# 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
diff --git a/tempest/api/object_storage/test_object_formpost_negative.py b/tempest/api/object_storage/test_object_formpost_negative.py
index d8fc077..d92a2e5 100644
--- a/tempest/api/object_storage/test_object_formpost_negative.py
+++ b/tempest/api/object_storage/test_object_formpost_negative.py
@@ -1,5 +1,4 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
-# Author: Joe H. Rahme <joe.hakim.rahme@enovance.com>
#
# 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
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index 4563bfd..e6b0b05 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -1,7 +1,5 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
-# Author: Joe H. Rahme <joe.hakim.rahme@enovance.com>
-#
# 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
diff --git a/tempest/api/object_storage/test_object_temp_url_negative.py b/tempest/api/object_storage/test_object_temp_url_negative.py
index af927a8..343749e 100644
--- a/tempest/api/object_storage/test_object_temp_url_negative.py
+++ b/tempest/api/object_storage/test_object_temp_url_negative.py
@@ -1,7 +1,5 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
-# Author: Joe H. Rahme <joe.hakim.rahme@enovance.com>
-#
# 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
diff --git a/tempest/api/orchestration/stacks/test_resource_types.py b/tempest/api/orchestration/stacks/test_resource_types.py
index 33d2f9e..32b0b8e 100644
--- a/tempest/api/orchestration/stacks/test_resource_types.py
+++ b/tempest/api/orchestration/stacks/test_resource_types.py
@@ -43,5 +43,7 @@
"""Verify it is possible to get template about resource types."""
type_template = self.client.get_resource_type_template(
'OS::Nova::Server')
- self.assert_fields_in_dict(type_template, 'Outputs',
- 'Parameters', 'Resources')
\ No newline at end of file
+ self.assert_fields_in_dict(
+ type_template,
+ 'Outputs',
+ 'Parameters', 'Resources')
diff --git a/tempest/api/orchestration/stacks/test_swift_resources.py b/tempest/api/orchestration/stacks/test_swift_resources.py
index efbf695..1290dfe 100644
--- a/tempest/api/orchestration/stacks/test_swift_resources.py
+++ b/tempest/api/orchestration/stacks/test_swift_resources.py
@@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
-# Author: Chmouel Boudjnah <chmouel@enovance.com>
-#
# 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
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index 97dd104..2e4b614 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -70,8 +70,7 @@
params = {self.name_field: vol_name, 'volume_type': type_name}
- self.volume = self.admin_volume_client.create_volume(size=1,
- **params)
+ self.volume = self.admin_volume_client.create_volume(**params)
if with_prefix:
self.volume_id_list_with_prefix.append(self.volume['id'])
else:
diff --git a/tempest/api/volume/admin/test_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py
index 469f13e..4834be1 100644
--- a/tempest/api/volume/admin/test_snapshots_actions.py
+++ b/tempest/api/volume/admin/test_snapshots_actions.py
@@ -34,7 +34,7 @@
cls.name_field = cls.special_fields['name_field']
params = {cls.name_field: vol_name}
cls.volume = \
- cls.volumes_client.create_volume(size=1, **params)
+ cls.volumes_client.create_volume(**params)
cls.volumes_client.wait_for_volume_status(cls.volume['id'],
'available')
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index 9b436aa..cd91552 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -1,7 +1,5 @@
# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
#
-# Author: Sylvain Baubeau <sylvain.baubeau@enovance.com>
-#
# 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
@@ -86,7 +84,7 @@
quota_usage = self.quotas_client.get_quota_usage(
self.demo_tenant_id)
- volume = self.create_volume(size=1)
+ volume = self.create_volume()
self.addCleanup(self.admin_volume_client.delete_volume,
volume['id'])
diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py
index 67edd09..98b7143 100644
--- a/tempest/api/volume/admin/test_volume_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_quotas_negative.py
@@ -48,8 +48,7 @@
@test.idempotent_id('bf544854-d62a-47f2-a681-90f7a47d86b6')
def test_quota_volumes(self):
self.assertRaises(lib_exc.OverLimit,
- self.volumes_client.create_volume,
- size=1)
+ self.volumes_client.create_volume)
@test.attr(type='negative')
@test.idempotent_id('02bbf63f-6c05-4357-9d98-2926a94064ff')
@@ -73,8 +72,7 @@
self.demo_tenant_id,
**new_quota_set)
self.assertRaises(lib_exc.OverLimit,
- self.volumes_client.create_volume,
- size=1)
+ self.volumes_client.create_volume)
new_quota_set = {'gigabytes': 2, 'volumes': 1, 'snapshots': 2}
self.quotas_client.update_quota_set(
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 8705f6f..01242f9 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -60,7 +60,7 @@
'volume_type': volume_types[0]['id']}
# Create volume
- volume = self.volumes_client.create_volume(size=1, **params)
+ volume = self.volumes_client.create_volume(**params)
self.addCleanup(self._delete_volume, volume['id'])
self.assertEqual(volume_types[0]['name'], volume["volume_type"])
self.assertEqual(volume[self.name_field], vol_name,
diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py
index eb46a54..d2bf777 100644
--- a/tempest/api/volume/admin/test_volume_types_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_negative.py
@@ -31,8 +31,7 @@
params = {self.name_field: str(uuid.uuid4()),
'volume_type': str(uuid.uuid4())}
self.assertRaises(lib_exc.NotFound,
- self.volumes_client.create_volume, size=1,
- **params)
+ self.volumes_client.create_volume, **params)
@test.attr(type='gate')
@test.idempotent_id('878b4e57-faa2-4659-b0d1-ce740a06ae81')
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index b0013e6..dc96839 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -34,8 +34,7 @@
cls.name_field = cls.special_fields['name_field']
params = {cls.name_field: vol_name}
- cls.volume = cls.client.create_volume(size=1,
- **params)
+ cls.volume = cls.client.create_volume(**params)
cls.client.wait_for_volume_status(cls.volume['id'], 'available')
@classmethod
@@ -61,8 +60,7 @@
# Create a temp volume for force delete tests
vol_name = utils.rand_name('Volume')
params = {self.name_field: vol_name}
- temp_volume = self.client.create_volume(size=1,
- **params)
+ temp_volume = self.client.create_volume(**params)
self.client.wait_for_volume_status(temp_volume['id'], 'available')
return temp_volume
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index c672607..4f94f34 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -106,7 +106,7 @@
super(BaseVolumeTest, cls).resource_cleanup()
@classmethod
- def create_volume(cls, size=1, **kwargs):
+ def create_volume(cls, size=None, **kwargs):
"""Wrapper utility that returns a test volume."""
name = data_utils.rand_name('Volume')
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 007b0db..d03bd8d 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -108,7 +108,7 @@
new_v_desc = data_utils.rand_name('@#$%^* description')
params = {self.descrip_field: new_v_desc,
'availability_zone': volume['availability_zone']}
- new_volume = self.client.create_volume(size=1, **params)
+ new_volume = self.client.create_volume(**params)
self.assertIn('id', new_volume)
self.addCleanup(self._delete_volume, new_volume['id'])
self.client.wait_for_volume_status(new_volume['id'], 'available')
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 3c1cce3..b6cdd6b 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -181,7 +181,6 @@
snapshot = self.create_snapshot(self.volume_origin['id'])
# NOTE(gfidente): size is required also when passing snapshot_id
volume = self.volumes_client.create_volume(
- size=1,
snapshot_id=snapshot['id'])
self.volumes_client.wait_for_volume_status(volume['id'], 'available')
self.volumes_client.delete_volume(volume['id'])
diff --git a/tempest/api_schema/response/compute/flavors.py b/tempest/api_schema/response/compute/flavors.py
index 44020d2..65f2c28 100644
--- a/tempest/api_schema/response/compute/flavors.py
+++ b/tempest/api_schema/response/compute/flavors.py
@@ -30,8 +30,11 @@
},
'required': ['name', 'links', 'id']
}
- }
+ },
+ 'flavors_links': parameter_types.links
},
+ # NOTE(gmann): flavors_links attribute is not necessary
+ # to be present always So it is not 'required'.
'required': ['flavors']
}
}
diff --git a/tempest/api_schema/response/compute/v2/flavors.py b/tempest/api_schema/response/compute/v2/flavors.py
index 811ea84..76c4cee 100644
--- a/tempest/api_schema/response/compute/v2/flavors.py
+++ b/tempest/api_schema/response/compute/v2/flavors.py
@@ -15,6 +15,7 @@
import copy
from tempest.api_schema.response.compute import flavors
+from tempest.api_schema.response.compute import parameter_types
list_flavors_details = copy.deepcopy(flavors.common_flavor_list_details)
@@ -23,6 +24,12 @@
list_flavors_details['response_body']['properties']['flavors']['items'][
'properties']['swap'] = {'type': ['string', 'integer']}
+# Defining 'flavors_links' attributes for V2 flavor schema
+list_flavors_details['response_body'][
+ 'properties'].update({'flavors_links': parameter_types.links})
+# NOTE(gmann): flavors_links attribute is not necessary to be
+# present always So it is not 'required'.
+
# Defining extra attributes for V2 flavor schema
list_flavors_details['response_body']['properties']['flavors']['items'][
'properties'].update({'OS-FLV-DISABLED:disabled': {'type': 'boolean'},
diff --git a/tempest/api_schema/response/compute/v2/floating_ips.py b/tempest/api_schema/response/compute/v2/floating_ips.py
index def0a78..7250773 100644
--- a/tempest/api_schema/response/compute/v2/floating_ips.py
+++ b/tempest/api_schema/response/compute/v2/floating_ips.py
@@ -146,8 +146,14 @@
'instance_uuid': {'type': ['string', 'null']},
'interface': {'type': ['string', 'null']},
'pool': {'type': ['string', 'null']},
- 'project_id': {'type': ['string', 'null']}
+ 'project_id': {'type': ['string', 'null']},
+ 'fixed_ip': {
+ 'type': ['string', 'null'],
+ 'format': 'ip-address'
+ }
},
+ # NOTE: fixed_ip is introduced after JUNO release,
+ # So it is not defined as 'required'.
'required': ['address', 'instance_uuid', 'interface',
'pool', 'project_id']
}
diff --git a/tempest/api_schema/response/compute/v2/limits.py b/tempest/api_schema/response/compute/v2/limits.py
index b9857f1..a7decb7 100644
--- a/tempest/api_schema/response/compute/v2/limits.py
+++ b/tempest/api_schema/response/compute/v2/limits.py
@@ -38,8 +38,15 @@
'maxSecurityGroupRules': {'type': 'integer'},
'maxTotalKeypairs': {'type': 'integer'},
'totalRAMUsed': {'type': 'integer'},
- 'totalInstancesUsed': {'type': 'integer'}
+ 'totalInstancesUsed': {'type': 'integer'},
+ 'maxServerGroupMembers': {'type': 'integer'},
+ 'maxServerGroups': {'type': 'integer'},
+ 'totalServerGroupsUsed': {'type': 'integer'}
},
+ # NOTE(gmann): maxServerGroupMembers, maxServerGroups
+ # and totalServerGroupsUsed are API extension,
+ # and some environments return a response without these
+ # attributes.So they are not 'required'.
'required': ['maxImageMeta',
'maxPersonality',
'maxPersonalitySize',
diff --git a/tempest/api_schema/response/compute/v2/servers.py b/tempest/api_schema/response/compute/v2/servers.py
index 09abaed..0132350 100644
--- a/tempest/api_schema/response/compute/v2/servers.py
+++ b/tempest/api_schema/response/compute/v2/servers.py
@@ -30,10 +30,10 @@
'links': parameter_types.links,
'OS-DCF:diskConfig': {'type': 'string'}
},
- # NOTE: OS-DCF:diskConfig is API extension, and some
- # environments return a response without the attribute.
- # So it is not 'required'.
- 'required': ['id', 'security_groups', 'links']
+ # NOTE: OS-DCF:diskConfig & security_groups are API extension,
+ # and some environments return a response without these
+ # attributes.So they are not 'required'.
+ 'required': ['id', 'links']
}
},
'required': ['server']
@@ -64,6 +64,7 @@
get_server['response_body']['properties']['server']['properties'].update({
'key_name': {'type': ['string', 'null']},
'hostId': {'type': 'string'},
+ 'security_groups': {'type': 'array'},
# NOTE: Non-admin users also can see "OS-SRV-USG" and "OS-EXT-AZ"
# attributes.
@@ -288,10 +289,11 @@
'properties'].update({
'hostId': {'type': 'string'},
'OS-DCF:diskConfig': {'type': 'string'},
+ 'security_groups': {'type': 'array'},
'accessIPv4': parameter_types.access_ip_v4,
'accessIPv6': parameter_types.access_ip_v6
})
-# NOTE(GMann): OS-DCF:diskConfig and accessIPv4/v6 are API
+# NOTE(GMann): OS-DCF:diskConfig, security_groups and accessIPv4/v6 are API
# extensions, and some environments return a response
# without these attributes. So they are not 'required'.
list_servers_detail['response_body']['properties']['servers']['items'][
diff --git a/tempest/auth.py b/tempest/auth.py
index 5e76a88..9d8341c 100644
--- a/tempest/auth.py
+++ b/tempest/auth.py
@@ -23,7 +23,7 @@
import six
from tempest.openstack.common import log as logging
-from tempest.services.identity.json import token_client as json_id
+from tempest.services.identity.v2.json import token_client as json_v2id
from tempest.services.identity.v3.json import token_client as json_v3id
@@ -242,7 +242,7 @@
EXPIRY_DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
def _auth_client(self, auth_url):
- return json_id.TokenClientJSON(
+ return json_v2id.TokenClientJSON(
auth_url, disable_ssl_certificate_validation=self.dsvm,
ca_certs=self.ca_certs, trace_requests=self.trace_requests)
diff --git a/tempest/cli/__init__.py b/tempest/cli/__init__.py
index 4782129..6733204 100644
--- a/tempest/cli/__init__.py
+++ b/tempest/cli/__init__.py
@@ -68,14 +68,22 @@
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.cred_prov = credentials.get_isolated_credentials(cls.__name__)
- cls.creds = cls.cred_prov.get_admin_creds()
+ 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,
diff --git a/tempest/cli/simple_read_only/identity/__init__.py b/tempest/cli/simple_read_only/identity/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/cli/simple_read_only/identity/__init__.py
+++ /dev/null
diff --git a/tempest/cli/simple_read_only/identity/test_keystone.py b/tempest/cli/simple_read_only/identity/test_keystone.py
deleted file mode 100644
index 10a26d5..0000000
--- a/tempest/cli/simple_read_only/identity/test_keystone.py
+++ /dev/null
@@ -1,155 +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 tempest_lib import exceptions
-
-from tempest import cli
-from tempest import config
-from tempest.openstack.common import log as logging
-from tempest import test
-
-CONF = config.CONF
-
-
-LOG = logging.getLogger(__name__)
-
-
-class SimpleReadOnlyKeystoneClientTest(cli.ClientTestBase):
- """Basic, read-only tests for Keystone 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.
- """
-
- def keystone(self, *args, **kwargs):
- return self.clients.keystone(*args, **kwargs)
-
- @test.idempotent_id('19c3ae95-3c19-4bba-8ba3-48ad19939b71')
- def test_admin_fake_action(self):
- self.assertRaises(exceptions.CommandFailed,
- self.keystone,
- 'this-does-not-exist')
-
- @test.idempotent_id('a1100917-c7c5-4887-a4da-f7d7f13194f5')
- def test_admin_catalog_list(self):
- out = self.keystone('catalog')
- catalog = self.parser.details_multiple(out, with_label=True)
- for svc in catalog:
- if svc.get('__label'):
- self.assertTrue(svc['__label'].startswith('Service:'),
- msg=('Invalid beginning of service block: '
- '%s' % svc['__label']))
- # check that region and publicURL exists. One might also
- # check for adminURL and internalURL. id seems to be optional
- # and is missing in the catalog backend
- self.assertIn('publicURL', svc.keys())
- self.assertIn('region', svc.keys())
-
- @test.idempotent_id('35c73506-eab6-4abc-956e-42da90aba8ec')
- def test_admin_endpoint_list(self):
- out = self.keystone('endpoint-list')
- endpoints = self.parser.listing(out)
- self.assertTableStruct(endpoints, [
- 'id', 'region', 'publicurl', 'internalurl',
- 'adminurl', 'service_id'])
-
- @test.idempotent_id('f17cb155-bd16-4f32-9956-1b073752fc07')
- def test_admin_endpoint_service_match(self):
- endpoints = self.parser.listing(self.keystone('endpoint-list'))
- services = self.parser.listing(self.keystone('service-list'))
- svc_by_id = {}
- for svc in services:
- svc_by_id[svc['id']] = svc
- for endpoint in endpoints:
- self.assertIn(endpoint['service_id'], svc_by_id)
-
- @test.idempotent_id('be7176f2-9c34-4d84-bb7d-b4bc85d06a33')
- def test_admin_role_list(self):
- roles = self.parser.listing(self.keystone('role-list'))
- self.assertTableStruct(roles, ['id', 'name'])
-
- @test.idempotent_id('96a4de8d-aa9e-4ca5-89f0-985809eccd66')
- def test_admin_service_list(self):
- services = self.parser.listing(self.keystone('service-list'))
- self.assertTableStruct(services, ['id', 'name', 'type', 'description'])
-
- @test.idempotent_id('edb45480-0f7b-49eb-8f95-7562cbba96da')
- def test_admin_tenant_list(self):
- tenants = self.parser.listing(self.keystone('tenant-list'))
- self.assertTableStruct(tenants, ['id', 'name', 'enabled'])
-
- @test.idempotent_id('25a2753d-6bd1-40c0-addc-32864b00cb2d')
- def test_admin_user_list(self):
- users = self.parser.listing(self.keystone('user-list'))
- self.assertTableStruct(users, [
- 'id', 'name', 'enabled', 'email'])
-
- @test.idempotent_id('f92bf8d4-b27b-47c9-8450-e27c57758de9')
- def test_admin_user_role_list(self):
- user_roles = self.parser.listing(self.keystone('user-role-list'))
- self.assertTableStruct(user_roles, [
- 'id', 'name', 'user_id', 'tenant_id'])
-
- @test.idempotent_id('14a2687b-3ce1-404c-9f78-a0e28e2f8f7b')
- def test_admin_discover(self):
- discovered = self.keystone('discover')
- self.assertIn('Keystone found at http', discovered)
- self.assertIn('supports version', discovered)
-
- @test.idempotent_id('9a567c8c-3787-4e5f-9c30-bed55f2b75c0')
- def test_admin_help(self):
- help_text = self.keystone('help')
- lines = help_text.split('\n')
- self.assertFirstLineStartsWith(lines, 'usage: keystone')
-
- 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(('catalog', 'endpoint-list', 'help',
- 'token-get', 'discover', 'bootstrap'))
- self.assertFalse(wanted_commands - commands)
-
- @test.idempotent_id('a7b9e1fe-db31-4846-82c5-52a7aa9863c3')
- def test_admin_bashcompletion(self):
- self.keystone('bash-completion')
-
- @test.idempotent_id('5328c681-df8b-4874-a65c-8fa278f0af8f')
- def test_admin_ec2_credentials_list(self):
- creds = self.keystone('ec2-credentials-list')
- creds = self.parser.listing(creds)
- self.assertTableStruct(creds, ['tenant', 'access', 'secret'])
-
- # Optional arguments:
-
- @test.idempotent_id('af95e809-ce95-4505-8627-170d803b1d13')
- def test_admin_version(self):
- self.keystone('', flags='--version')
-
- @test.idempotent_id('9e26521f-7bfa-4d8e-9d61-fd364f0c20c0')
- def test_admin_debug_list(self):
- self.keystone('catalog', flags='--debug')
-
- @test.idempotent_id('097b3a52-725f-4df7-84b6-277a2b6f6e38')
- def test_admin_timeout(self):
- self.keystone('catalog', flags='--timeout %d' % CONF.cli.timeout)
diff --git a/tempest/clients.py b/tempest/clients.py
index 7a41f32..e5f41eb 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -74,8 +74,9 @@
DatabaseLimitsClientJSON
from tempest.services.database.json.versions_client import \
DatabaseVersionsClientJSON
-from tempest.services.identity.json.identity_client import IdentityClientJSON
-from tempest.services.identity.json.token_client import TokenClientJSON
+from tempest.services.identity.v2.json.identity_client import \
+ IdentityClientJSON
+from tempest.services.identity.v2.json.token_client import TokenClientJSON
from tempest.services.identity.v3.json.credentials_client import \
CredentialsClientJSON
from tempest.services.identity.v3.json.endpoints_client import \
@@ -194,8 +195,22 @@
endpoint_type=CONF.telemetry.endpoint_type,
**self.default_params_with_timeout_values)
if CONF.service_available.glance:
- self.image_client = ImageClientJSON(self.auth_provider)
- self.image_client_v2 = ImageClientV2JSON(self.auth_provider)
+ self.image_client = ImageClientJSON(
+ self.auth_provider,
+ CONF.image.catalog_type,
+ CONF.image.region or CONF.identity.region,
+ endpoint_type=CONF.image.endpoint_type,
+ build_interval=CONF.image.build_interval,
+ build_timeout=CONF.image.build_timeout,
+ **self.default_params)
+ self.image_client_v2 = ImageClientV2JSON(
+ self.auth_provider,
+ CONF.image.catalog_type,
+ CONF.image.region or CONF.identity.region,
+ endpoint_type=CONF.image.endpoint_type,
+ build_interval=CONF.image.build_interval,
+ build_timeout=CONF.image.build_timeout,
+ **self.default_params)
self.orchestration_client = OrchestrationClient(
self.auth_provider,
CONF.orchestration.catalog_type,
@@ -239,7 +254,11 @@
SecurityGroupDefaultRulesClientJSON(self.auth_provider, **params))
self.certificates_client = CertificatesClientJSON(self.auth_provider,
**params)
- self.servers_client = ServersClientJSON(self.auth_provider, **params)
+ self.servers_client = ServersClientJSON(
+ self.auth_provider,
+ enable_instance_password=CONF.compute_feature_enabled
+ .enable_instance_password,
+ **params)
self.limits_client = LimitsClientJSON(self.auth_provider, **params)
self.images_client = ImagesClientJSON(self.auth_provider, **params)
self.keypairs_client = KeyPairsClientJSON(self.auth_provider, **params)
@@ -282,7 +301,8 @@
'build_timeout': CONF.volume.build_timeout
})
self.volumes_extensions_client = VolumesExtensionsClientJSON(
- self.auth_provider, **params_volume)
+ self.auth_provider, default_volume_size=CONF.volume.volume_size,
+ **params_volume)
def _set_database_clients(self):
self.database_flavors_client = DatabaseFlavorsClientJSON(
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index aff4087..4c09bd2 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -120,7 +120,7 @@
from tempest.services.compute.json import flavors_client
from tempest.services.compute.json import security_groups_client
from tempest.services.compute.json import servers_client
-from tempest.services.identity.json import identity_client
+from tempest.services.identity.v2.json import identity_client
from tempest.services.image.v2.json import image_client
from tempest.services.network.json import network_client
from tempest.services.object_storage import container_client
@@ -200,7 +200,14 @@
**object_storage_params)
self.containers = container_client.ContainerClient(
_auth, **object_storage_params)
- self.images = image_client.ImageClientV2JSON(_auth)
+ self.images = image_client.ImageClientV2JSON(
+ _auth,
+ CONF.image.catalog_type,
+ CONF.image.region or CONF.identity.region,
+ endpoint_type=CONF.image.endpoint_type,
+ build_interval=CONF.image.build_interval,
+ build_timeout=CONF.image.build_timeout,
+ **default_params)
self.telemetry = telemetry_client.TelemetryClientJSON(
_auth,
CONF.telemetry.catalog_type,
diff --git a/tempest/common/accounts.py b/tempest/common/accounts.py
index 9ecf596..89de69b 100644
--- a/tempest/common/accounts.py
+++ b/tempest/common/accounts.py
@@ -37,6 +37,7 @@
def __init__(self, name):
super(Accounts, self).__init__(name)
+ self.name = name
if os.path.isfile(CONF.auth.test_accounts_file):
accounts = read_accounts_yaml(CONF.auth.test_accounts_file)
self.use_default_creds = False
@@ -48,12 +49,46 @@
self.isolated_creds = {}
@classmethod
+ def _append_role(cls, role, account_hash, hash_dict):
+ if role in hash_dict['roles']:
+ hash_dict['roles'][role].append(account_hash)
+ else:
+ hash_dict['roles'][role] = [account_hash]
+ return hash_dict
+
+ @classmethod
def get_hash_dict(cls, accounts):
- hash_dict = {}
+ hash_dict = {'roles': {}, 'creds': {}}
+ # Loop over the accounts read from the yaml file
for account in accounts:
+ roles = []
+ types = []
+ if 'roles' in account:
+ roles = account.pop('roles')
+ if 'types' in account:
+ types = account.pop('types')
temp_hash = hashlib.md5()
temp_hash.update(str(account))
- hash_dict[temp_hash.hexdigest()] = account
+ temp_hash_key = temp_hash.hexdigest()
+ hash_dict['creds'][temp_hash_key] = account
+ for role in roles:
+ hash_dict = cls._append_role(role, temp_hash_key,
+ hash_dict)
+ # If types are set for the account append the matching role
+ # subdict with the hash
+ for type in types:
+ if type == 'admin':
+ hash_dict = cls._append_role(CONF.identity.admin_role,
+ temp_hash_key, hash_dict)
+ elif type == 'operator':
+ hash_dict = cls._append_role(
+ CONF.object_storage.operator_role, temp_hash_key,
+ hash_dict)
+ elif type == 'reseller_admin':
+ hash_dict = cls._append_role(
+ CONF.object_storage.reseller_admin_role,
+ temp_hash_key,
+ hash_dict)
return hash_dict
def is_multi_user(self):
@@ -62,7 +97,7 @@
raise exceptions.InvalidConfiguration(
"Account file %s doesn't exist" % CONF.auth.test_accounts_file)
else:
- return len(self.hash_dict) > 1
+ return len(self.hash_dict['creds']) > 1
def is_multi_tenant(self):
return self.is_multi_user()
@@ -70,30 +105,74 @@
def _create_hash_file(self, hash_string):
path = os.path.join(os.path.join(self.accounts_dir, hash_string))
if not os.path.isfile(path):
- open(path, 'w').close()
+ with open(path, 'w') as fd:
+ fd.write(self.name)
return True
return False
@lockutils.synchronized('test_accounts_io', external=True)
def _get_free_hash(self, hashes):
+ # Cast as a list because in some edge cases a set will be passed in
+ hashes = list(hashes)
if not os.path.isdir(self.accounts_dir):
os.mkdir(self.accounts_dir)
# Create File from first hash (since none are in use)
self._create_hash_file(hashes[0])
return hashes[0]
+ names = []
for _hash in hashes:
res = self._create_hash_file(_hash)
if res:
return _hash
- msg = 'Insufficient number of users provided'
+ else:
+ path = os.path.join(os.path.join(self.accounts_dir,
+ _hash))
+ with open(path, 'r') as fd:
+ names.append(fd.read())
+ msg = ('Insufficient number of users provided. %s have allocated all '
+ 'the credentials for this allocation request' % ','.join(names))
raise exceptions.InvalidConfiguration(msg)
- def _get_creds(self):
+ def _get_match_hash_list(self, roles=None):
+ hashes = []
+ if roles:
+ # Loop over all the creds for each role in the subdict and generate
+ # a list of cred lists for each role
+ for role in roles:
+ temp_hashes = self.hash_dict['roles'].get(role, None)
+ if not temp_hashes:
+ raise exceptions.InvalidConfiguration(
+ "No credentials with role: %s specified in the "
+ "accounts ""file" % role)
+ hashes.append(temp_hashes)
+ # Take the list of lists and do a boolean and between each list to
+ # find the creds which fall under all the specified roles
+ temp_list = set(hashes[0])
+ for hash_list in hashes[1:]:
+ temp_list = temp_list & set(hash_list)
+ hashes = temp_list
+ else:
+ hashes = self.hash_dict['creds'].keys()
+ # NOTE(mtreinish): admin is a special case because of the increased
+ # privlege set which could potentially cause issues on tests where that
+ # is not expected. So unless the admin role isn't specified do not
+ # allocate admin.
+ admin_hashes = self.hash_dict['roles'].get(CONF.identity.admin_role,
+ None)
+ if ((not roles or CONF.identity.admin_role not in roles) and
+ admin_hashes):
+ useable_hashes = [x for x in hashes if x not in admin_hashes]
+ else:
+ useable_hashes = hashes
+ return useable_hashes
+
+ def _get_creds(self, roles=None):
if self.use_default_creds:
raise exceptions.InvalidConfiguration(
"Account file %s doesn't exist" % CONF.auth.test_accounts_file)
- free_hash = self._get_free_hash(self.hash_dict.keys())
- return self.hash_dict[free_hash]
+ useable_hashes = self._get_match_hash_list(roles)
+ free_hash = self._get_free_hash(useable_hashes)
+ return self.hash_dict['creds'][free_hash]
@lockutils.synchronized('test_accounts_io', external=True)
def remove_hash(self, hash_string):
@@ -107,10 +186,10 @@
os.rmdir(self.accounts_dir)
def get_hash(self, creds):
- for _hash in self.hash_dict:
- # Comparing on the attributes that were read from the YAML
- if all([getattr(creds, k) == self.hash_dict[_hash][k] for k in
- creds.get_init_attributes()]):
+ for _hash in self.hash_dict['creds']:
+ # Comparing on the attributes that are expected in the YAML
+ if all([getattr(creds, k) == self.hash_dict['creds'][_hash][k] for
+ k in creds.get_init_attributes()]):
return _hash
raise AttributeError('Invalid credentials %s' % creds)
@@ -134,14 +213,33 @@
self.isolated_creds['alt'] = alt_credential
return alt_credential
+ def get_creds_by_roles(self, roles, force_new=False):
+ roles = list(set(roles))
+ exist_creds = self.isolated_creds.get(str(roles), 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))
+ self.isolated_creds[new_index] = exist_creds
+ creds = self._get_creds(roles=roles)
+ role_credential = cred_provider.get_credentials(**creds)
+ self.isolated_creds[str(roles)] = role_credential
+ return role_credential
+
def clear_isolated_creds(self):
for creds in self.isolated_creds.values():
self.remove_credentials(creds)
def get_admin_creds(self):
- msg = ('If admin credentials are available tenant_isolation should be'
- ' used instead')
- raise NotImplementedError(msg)
+ return self.get_creds_by_roles([CONF.identity.admin_role])
+
+ def admin_available(self):
+ if not self.hash_dict['roles'].get(CONF.identity.admin_role):
+ return False
+ return True
class NotLockingAccounts(Accounts):
@@ -164,7 +262,7 @@
raise exceptions.InvalidConfiguration(msg)
else:
# TODO(andreaf) Add a uniqueness check here
- return len(self.hash_dict) > 1
+ return len(self.hash_dict['creds']) > 1
def is_multi_user(self):
return self._unique_creds('username')
@@ -172,16 +270,17 @@
def is_multi_tenant(self):
return self._unique_creds('tenant_id')
- def get_creds(self, id):
+ def get_creds(self, id, roles=None):
try:
+ hashes = self._get_match_hash_list(roles)
# No need to sort the dict as within the same python process
# the HASH seed won't change, so subsequent calls to keys()
# will return the same result
- _hash = self.hash_dict.keys()[id]
+ _hash = hashes[id]
except IndexError:
msg = 'Insufficient number of users provided'
raise exceptions.InvalidConfiguration(msg)
- return self.hash_dict[_hash]
+ return self.hash_dict['creds'][_hash]
def get_primary_creds(self):
if self.isolated_creds.get('primary'):
@@ -211,5 +310,35 @@
self.isolated_creds = {}
def get_admin_creds(self):
- return cred_provider.get_configured_credentials(
- "identity_admin", fill_in=False)
+ if not self.use_default_creds:
+ return self.get_creds_by_roles([CONF.identity.admin_role])
+ else:
+ creds = cred_provider.get_configured_credentials(
+ "identity_admin", fill_in=False)
+ self.isolated_creds['admin'] = creds
+ return creds
+
+ def get_creds_by_roles(self, roles, force_new=False):
+ roles = list(set(roles))
+ exist_creds = self.isolated_creds.get(str(roles), None)
+ index = 0
+ 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))
+ self.isolated_creds[new_index] = exist_creds
+ # Figure out how many existing creds for this roles set are present
+ # use this as the index the returning hash list to ensure separate
+ # creds are returned with force_new being True
+ for creds_names in self.isolated_creds:
+ if str(roles) in creds_names:
+ index = index + 1
+ if not self.use_default_creds:
+ creds = self.get_creds(index, roles=roles)
+ role_credential = cred_provider.get_credentials(**creds)
+ self.isolated_creds[str(roles)] = role_credential
+ else:
+ msg = "Default credentials can not be used with specifying "\
+ "credentials by roles"
+ raise exceptions.InvalidConfiguration(msg)
+ return role_credential
diff --git a/tempest/common/cred_provider.py b/tempest/common/cred_provider.py
index 033410e..c22dc1f 100644
--- a/tempest/common/cred_provider.py
+++ b/tempest/common/cred_provider.py
@@ -113,3 +113,7 @@
@abc.abstractmethod
def is_multi_tenant(self):
return
+
+ @abc.abstractmethod
+ def get_creds_by_roles(self, roles, force_new=False):
+ return
diff --git a/tempest/common/credentials.py b/tempest/common/credentials.py
index 40761c8..3794b66 100644
--- a/tempest/common/credentials.py
+++ b/tempest/common/credentials.py
@@ -11,6 +11,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
+
from tempest.common import accounts
from tempest.common import cred_provider
from tempest.common import isolated_creds
@@ -46,24 +48,17 @@
# creds area vailable.
def is_admin_available():
is_admin = True
- # In the case of a pre-provisioned account, if even if creds were
- # configured, the admin credentials won't be available
- if (CONF.auth.locking_credentials_provider and
- not CONF.auth.allow_tenant_isolation):
- is_admin = False
+ # If tenant isolation is enabled admin will be available
+ if CONF.auth.allow_tenant_isolation:
+ return is_admin
+ # Check whether test accounts file has the admin specified or not
+ elif os.path.isfile(CONF.auth.test_accounts_file):
+ check_accounts = accounts.Accounts(name='check_admin')
+ if not check_accounts.admin_available():
+ is_admin = False
else:
try:
cred_provider.get_configured_credentials('identity_admin')
- # NOTE(mtreinish) This should never be caught because of the if above.
- # NotImplementedError is only raised if admin credentials are requested
- # and the locking test accounts cred provider is being used.
- except NotImplementedError:
- is_admin = False
- # NOTE(mtreinish): This will be raised by the non-locking accounts
- # provider if there aren't admin credentials provided in the config
- # file. This exception originates from the auth call to get configured
- # credentials
except exceptions.InvalidConfiguration:
is_admin = False
-
return is_admin
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index 3eed689..b0531fd 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -90,7 +90,7 @@
self._cleanup_default_secgroup(tenant)
self.identity_admin_client.delete_tenant(tenant)
- def _create_creds(self, suffix="", admin=False):
+ def _create_creds(self, suffix="", admin=False, roles=None):
"""Create random credentials under the following schema.
If the name contains a '.' is the full class path of something, and
@@ -121,8 +121,13 @@
self._assign_user_role(tenant, user, swift_operator_role)
if admin:
self._assign_user_role(tenant, user, CONF.identity.admin_role)
- for role in CONF.auth.tempest_roles:
- self._assign_user_role(tenant, user, role)
+ # Add roles specified in config file
+ for conf_role in CONF.auth.tempest_roles:
+ self._assign_user_role(tenant, user, conf_role)
+ # Add roles requested by caller
+ if roles:
+ for role in roles:
+ self._assign_user_role(tenant, user, role)
return self._get_credentials(user, tenant)
def _get_credentials(self, user, tenant):
@@ -247,12 +252,15 @@
return self.isolated_net_resources.get('alt')[2]
def get_credentials(self, credential_type):
- if self.isolated_creds.get(credential_type):
- credentials = self.isolated_creds[credential_type]
+ if self.isolated_creds.get(str(credential_type)):
+ credentials = self.isolated_creds[str(credential_type)]
else:
- is_admin = (credential_type == 'admin')
- credentials = self._create_creds(admin=is_admin)
- self.isolated_creds[credential_type] = credentials
+ if credential_type in ['primary', 'alt', 'admin']:
+ is_admin = (credential_type == 'admin')
+ credentials = self._create_creds(admin=is_admin)
+ else:
+ credentials = self._create_creds(roles=credential_type)
+ self.isolated_creds[str(credential_type)] = credentials
# Maintained until tests are ported
LOG.info("Acquired isolated creds:\n credentials: %s"
% credentials)
@@ -260,7 +268,7 @@
not CONF.baremetal.driver_enabled):
network, subnet, router = self._create_network_resources(
credentials.tenant_id)
- self.isolated_net_resources[credential_type] = (
+ self.isolated_net_resources[str(credential_type)] = (
network, subnet, router,)
LOG.info("Created isolated network resources for : \n"
+ " credentials: %s" % credentials)
@@ -275,6 +283,26 @@
def get_alt_creds(self):
return self.get_credentials('alt')
+ def get_creds_by_roles(self, roles, force_new=False):
+ roles = list(set(roles))
+ # The roles list as a str will become the index as the dict key for
+ # the created credentials set in the isolated_creds dict.
+ exist_creds = self.isolated_creds.get(str(roles))
+ # If force_new flag is True 2 cred sets with the same roles are needed
+ # handle this by creating a separate index for old one to store it
+ # separately for cleanup
+ if exist_creds and force_new:
+ new_index = str(roles) + '-' + str(len(self.isolated_creds))
+ self.isolated_creds[new_index] = exist_creds
+ del self.isolated_creds[str(roles)]
+ # Handle isolated neutron resouces if they exist too
+ if CONF.service_available.neutron:
+ exist_net = self.isolated_net_resources.get(str(roles))
+ if exist_net:
+ self.isolated_net_resources[new_index] = exist_net
+ del self.isolated_net_resources[str(roles)]
+ return self.get_credentials(roles)
+
def _clear_isolated_router(self, router_id, router_name):
net_client = self.network_admin_client
try:
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 6e61c55..1f1414f 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -23,7 +23,7 @@
CONF = config.CONF
-class RemoteClient():
+class RemoteClient(object):
# NOTE(afazekas): It should always get an address instead of server
def __init__(self, server, username, password=None, pkey=None):
@@ -163,4 +163,4 @@
% dhcp_client)
if dhcp_client == 'udhcpc' and not fixed_ip:
raise ValueError("need to set 'fixed_ip' for udhcpc client")
- return getattr(self, '_renew_lease_' + dhcp_client)(fixed_ip=fixed_ip)
\ No newline at end of file
+ return getattr(self, '_renew_lease_' + dhcp_client)(fixed_ip=fixed_ip)
diff --git a/tempest/config.py b/tempest/config.py
index 4588b20..a66aa9b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -40,7 +40,7 @@
help="Path to the yaml file that contains the list of "
"credentials to use for running tests"),
cfg.BoolOpt('allow_tenant_isolation',
- default=False,
+ default=True,
help="Allows test cases to create/destroy tenants and "
"users. This option requires that OpenStack Identity "
"API admin credentials are known. If false, isolated "
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 968c8ca..f24a22a 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -207,7 +207,7 @@
self.assertEqual(server['name'], name)
return server
- def create_volume(self, size=1, name=None, snapshot_id=None,
+ def create_volume(self, size=None, name=None, snapshot_id=None,
imageRef=None, volume_type=None, wait_on_delete=True):
if name is None:
name = data_utils.rand_name(self.__class__.__name__)
diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py
index 1069908..eed3d0b 100644
--- a/tempest/scenario/test_encrypted_cinder_volumes.py
+++ b/tempest/scenario/test_encrypted_cinder_volumes.py
@@ -62,4 +62,4 @@
self.launch_instance()
self.create_encrypted_volume('nova.volume.encryptors.'
'cryptsetup.CryptsetupEncryptor')
- self.attach_detach_volume()
\ No newline at end of file
+ self.attach_detach_volume()
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index f29fecf..4199b2c 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -435,13 +435,15 @@
"admin_state_up of router to True")
@test.idempotent_id('d8bb918e-e2df-48b2-97cd-b73c95450980')
+ @testtools.skipIf(CONF.baremetal.driver_enabled,
+ 'network isolation not available for baremetal nodes')
@testtools.skipUnless(CONF.scenario.dhcp_client,
"DHCP client is not available.")
@test.attr(type='smoke')
@test.services('compute', 'network')
def test_subnet_details(self):
"""Tests that subnet's extra configuration details are affecting
- the VMs
+ the VMs. This test relies on non-shared, isolated tenant networks.
NOTE: Neutron subnets push data to servers via dhcp-agent, so any
update in subnet requires server to actively renew its DHCP lease.
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 979953f..d5d2d77 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -12,6 +12,7 @@
# 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
import netaddr
from tempest import config
from tempest.openstack.common import log as logging
@@ -118,14 +119,28 @@
ssh1, srv1 = self.prepare_server()
ssh2, srv2 = self.prepare_server()
+ def guest_has_address(ssh, addr):
+ return addr in ssh.get_ip_list()
+
+ srv1_v6_addr_assigned = functools.partial(
+ guest_has_address, ssh1, srv1['accessIPv6'])
+ srv2_v6_addr_assigned = functools.partial(
+ guest_has_address, ssh2, srv2['accessIPv6'])
+
result = ssh1.get_ip_list()
self.assertIn(srv1['accessIPv4'], result)
# v6 should be configured since the image supports it
- self.assertIn(srv1['accessIPv6'], result)
+ # It can take time for ipv6 automatic address to get assigned
+ self.assertTrue(
+ test.call_until_true(srv1_v6_addr_assigned,
+ CONF.compute.ping_timeout, 1))
result = ssh2.get_ip_list()
self.assertIn(srv2['accessIPv4'], result)
# v6 should be configured since the image supports it
- self.assertIn(srv2['accessIPv6'], result)
+ # It can take time for ipv6 automatic address to get assigned
+ self.assertTrue(
+ test.call_until_true(srv2_v6_addr_assigned,
+ CONF.compute.ping_timeout, 1))
result = ssh1.ping_host(srv2['accessIPv4'])
self.assertIn('0% packet loss', result)
result = ssh2.ping_host(srv1['accessIPv4'])
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index f3c1f85..4fbadb0 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -91,7 +91,7 @@
its own router connected to the public network
"""
- class TenantProperties():
+ class TenantProperties(object):
"""
helper class to save tenant details
id
diff --git a/tempest/scenario/test_swift_telemetry_middleware.py b/tempest/scenario/test_swift_telemetry_middleware.py
index 2427f0f..8305641 100644
--- a/tempest/scenario/test_swift_telemetry_middleware.py
+++ b/tempest/scenario/test_swift_telemetry_middleware.py
@@ -1,7 +1,5 @@
-#
# Copyright 2014 Red Hat
#
-# Author: Chris Dent <chdent@redhat.com>
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index b01fbf1..bd4fd0e 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -24,14 +24,17 @@
from tempest.api_schema.response.compute.v2 import servers as schema
from tempest.common import service_client
from tempest.common import waiters
-from tempest import config
from tempest import exceptions
-CONF = config.CONF
-
class ServersClientJSON(service_client.ServiceClient):
+ def __init__(self, auth_provider, service, region,
+ enable_instance_password=True, **kwargs):
+ super(ServersClientJSON, self).__init__(
+ auth_provider, service, region, **kwargs)
+ self.enable_instance_password = enable_instance_password
+
def create_server(self, name, image_ref, flavor_ref, **kwargs):
"""
Creates an instance of a server.
@@ -93,7 +96,7 @@
# with return reservation id set True
if 'reservation_id' in body:
return service_client.ResponseBody(resp, body)
- if CONF.compute_feature_enabled.enable_instance_password:
+ if self.enable_instance_password:
create_schema = schema.create_server_with_admin_pass
else:
create_schema = schema.create_server
@@ -275,7 +278,7 @@
if 'disk_config' in kwargs:
kwargs['OS-DCF:diskConfig'] = kwargs['disk_config']
del kwargs['disk_config']
- if CONF.compute_feature_enabled.enable_instance_password:
+ if self.enable_instance_password:
rebuild_schema = schema.rebuild_server_with_admin_pass
else:
rebuild_schema = schema.rebuild_server
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index a9cada8..b2d5cf9 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -26,6 +26,12 @@
class VolumesExtensionsClientJSON(service_client.ServiceClient):
+ def __init__(self, auth_provider, service, region,
+ default_volume_size=1, **kwargs):
+ super(VolumesExtensionsClientJSON, self).__init__(
+ auth_provider, service, region, **kwargs)
+ self.default_volume_size = default_volume_size
+
def list_volumes(self, params=None):
"""List all the volumes created."""
url = 'os-volumes'
@@ -56,7 +62,7 @@
self.validate_response(schema.create_get_volume, resp, body)
return service_client.ResponseBody(resp, body['volume'])
- def create_volume(self, size, **kwargs):
+ def create_volume(self, size=None, **kwargs):
"""
Creates a new Volume.
size(Required): Size of volume in GB.
@@ -64,6 +70,8 @@
display_name: Optional Volume Name.
metadata: A dictionary of values to be used as metadata.
"""
+ if size is None:
+ size = self.default_volume_size
post_body = {
'size': size
}
diff --git a/tempest/services/identity/json/__init__.py b/tempest/services/identity/v2/__init__.py
similarity index 100%
copy from tempest/services/identity/json/__init__.py
copy to tempest/services/identity/v2/__init__.py
diff --git a/tempest/services/identity/json/__init__.py b/tempest/services/identity/v2/json/__init__.py
similarity index 100%
rename from tempest/services/identity/json/__init__.py
rename to tempest/services/identity/v2/json/__init__.py
diff --git a/tempest/services/identity/json/identity_client.py b/tempest/services/identity/v2/json/identity_client.py
similarity index 100%
rename from tempest/services/identity/json/identity_client.py
rename to tempest/services/identity/v2/json/identity_client.py
diff --git a/tempest/services/identity/json/token_client.py b/tempest/services/identity/v2/json/token_client.py
similarity index 100%
rename from tempest/services/identity/json/token_client.py
rename to tempest/services/identity/v2/json/token_client.py
diff --git a/tempest/services/image/v1/json/image_client.py b/tempest/services/image/v1/json/image_client.py
index 4ea710f..50f75b3 100644
--- a/tempest/services/image/v1/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -25,26 +25,32 @@
from tempest.common import glance_http
from tempest.common import service_client
from tempest.common.utils import misc as misc_utils
-from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
-CONF = config.CONF
-
LOG = logging.getLogger(__name__)
class ImageClientJSON(service_client.ServiceClient):
- def __init__(self, auth_provider):
+ def __init__(self, auth_provider, catalog_type, region, endpoint_type=None,
+ build_interval=None, build_timeout=None,
+ disable_ssl_certificate_validation=None,
+ ca_certs=None, **kwargs):
super(ImageClientJSON, self).__init__(
auth_provider,
- CONF.image.catalog_type,
- CONF.image.region or CONF.identity.region,
- endpoint_type=CONF.image.endpoint_type,
- build_interval=CONF.image.build_interval,
- build_timeout=CONF.image.build_timeout)
+ catalog_type,
+ region,
+ endpoint_type=endpoint_type,
+ build_interval=build_interval,
+ build_timeout=build_timeout,
+ disable_ssl_certificate_validation=(
+ disable_ssl_certificate_validation),
+ ca_certs=ca_certs,
+ **kwargs)
self._http = None
+ self.dscv = disable_ssl_certificate_validation
+ self.ca_certs = ca_certs
def _image_meta_from_headers(self, headers):
meta = {'properties': {}}
@@ -112,11 +118,10 @@
return None
def _get_http(self):
- dscv = CONF.identity.disable_ssl_certificate_validation
- ca_certs = CONF.identity.ca_certificates_file
return glance_http.HTTPClient(auth_provider=self.auth_provider,
filters=self.filters,
- insecure=dscv, ca_certs=ca_certs)
+ insecure=self.dscv,
+ ca_certs=self.ca_certs)
def _create_with_data(self, headers, data):
resp, body_iter = self.http.raw_request('POST', '/v1/images',
@@ -138,8 +143,7 @@
@property
def http(self):
if self._http is None:
- if CONF.service_available.glance:
- self._http = self._get_http()
+ self._http = self._get_http()
return self._http
def create_image(self, name, container_format, disk_format, **kwargs):
diff --git a/tempest/services/image/v2/json/image_client.py b/tempest/services/image/v2/json/image_client.py
index 50f273c..e55a824 100644
--- a/tempest/services/image/v2/json/image_client.py
+++ b/tempest/services/image/v2/json/image_client.py
@@ -21,29 +21,34 @@
from tempest.common import glance_http
from tempest.common import service_client
-from tempest import config
-
-CONF = config.CONF
class ImageClientV2JSON(service_client.ServiceClient):
- def __init__(self, auth_provider):
+ def __init__(self, auth_provider, catalog_type, region, endpoint_type=None,
+ build_interval=None, build_timeout=None,
+ disable_ssl_certificate_validation=None, ca_certs=None,
+ **kwargs):
super(ImageClientV2JSON, self).__init__(
auth_provider,
- CONF.image.catalog_type,
- CONF.image.region or CONF.identity.region,
- endpoint_type=CONF.image.endpoint_type,
- build_interval=CONF.image.build_interval,
- build_timeout=CONF.image.build_timeout)
+ catalog_type,
+ region,
+ endpoint_type=endpoint_type,
+ build_interval=build_interval,
+ build_timeout=build_timeout,
+ disable_ssl_certificate_validation=(
+ disable_ssl_certificate_validation),
+ ca_certs=ca_certs,
+ **kwargs)
self._http = None
+ self.dscv = disable_ssl_certificate_validation
+ self.ca_certs = ca_certs
def _get_http(self):
- dscv = CONF.identity.disable_ssl_certificate_validation
- ca_certs = CONF.identity.ca_certificates_file
return glance_http.HTTPClient(auth_provider=self.auth_provider,
filters=self.filters,
- insecure=dscv, ca_certs=ca_certs)
+ insecure=self.dscv,
+ ca_certs=self.ca_certs)
def _validate_schema(self, body, type='image'):
if type in ['image', 'images']:
@@ -56,8 +61,7 @@
@property
def http(self):
if self._http is None:
- if CONF.service_available.glance:
- self._http = self._get_http()
+ self._http = self._get_http()
return self._http
def update_image(self, image_id, patch):
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index ba069e8..87f1332 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -262,9 +262,8 @@
# expecting response in form
# {'resources': [ res1, res2] } => when pagination disabled
# {'resources': [..], 'resources_links': {}} => if pagination enabled
- pagination_suffix = "_links"
for k in res.keys():
- if k[-len(pagination_suffix):] == pagination_suffix:
+ if k.endswith("_links"):
continue
return res[k]
diff --git a/tempest/services/volume/json/admin/volume_quotas_client.py b/tempest/services/volume/json/admin/volume_quotas_client.py
index 19d320f..616f8e4 100644
--- a/tempest/services/volume/json/admin/volume_quotas_client.py
+++ b/tempest/services/volume/json/admin/volume_quotas_client.py
@@ -1,7 +1,5 @@
# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
#
-# Author: Sylvain Baubeau <sylvain.baubeau@enovance.com>
-#
# 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
diff --git a/tempest/stress/actions/volume_attach_delete.py b/tempest/stress/actions/volume_attach_delete.py
index 2e1d623..a5e393f 100644
--- a/tempest/stress/actions/volume_attach_delete.py
+++ b/tempest/stress/actions/volume_attach_delete.py
@@ -29,7 +29,6 @@
name = data_utils.rand_name("volume")
self.logger.info("creating volume: %s" % name)
volume = self.manager.volumes_client.create_volume(
- size=1,
display_name=name)
self.manager.volumes_client.wait_for_volume_status(volume['id'],
'available')
diff --git a/tempest/stress/actions/volume_attach_verify.py b/tempest/stress/actions/volume_attach_verify.py
index c013af3..a6abd82 100644
--- a/tempest/stress/actions/volume_attach_verify.py
+++ b/tempest/stress/actions/volume_attach_verify.py
@@ -78,7 +78,6 @@
self.logger.info("creating volume: %s" % name)
volumes_client = self.manager.volumes_client
self.volume = volumes_client.create_volume(
- size=1,
display_name=name)
volumes_client.wait_for_volume_status(self.volume['id'],
'available')
diff --git a/tempest/stress/actions/volume_create_delete.py b/tempest/stress/actions/volume_create_delete.py
index 93402d9..4870055 100644
--- a/tempest/stress/actions/volume_create_delete.py
+++ b/tempest/stress/actions/volume_create_delete.py
@@ -20,8 +20,7 @@
name = data_utils.rand_name("volume")
self.logger.info("creating %s" % name)
volumes_client = self.manager.volumes_client
- volume = volumes_client.create_volume(size=1,
- display_name=name)
+ volume = volumes_client.create_volume(display_name=name)
vol_id = volume['id']
volumes_client.wait_for_volume_status(vol_id, 'available')
self.logger.info("created %s" % volume['id'])
diff --git a/tempest/tests/common/test_accounts.py b/tempest/tests/common/test_accounts.py
index a836a20..58e3c0c 100644
--- a/tempest/tests/common/test_accounts.py
+++ b/tempest/tests/common/test_accounts.py
@@ -24,7 +24,7 @@
from tempest.common import accounts
from tempest import config
from tempest import exceptions
-from tempest.services.identity.json import token_client
+from tempest.services.identity.v2.json import token_client
from tempest.tests import base
from tempest.tests import fake_config
from tempest.tests import fake_identity
@@ -51,7 +51,19 @@
{'username': 'test_user5', 'tenant_name': 'test_tenant5',
'password': 'p'},
{'username': 'test_user6', 'tenant_name': 'test_tenant6',
- 'password': 'p'},
+ 'password': 'p', 'roles': ['role1', 'role2']},
+ {'username': 'test_user7', 'tenant_name': 'test_tenant7',
+ 'password': 'p', 'roles': ['role2', 'role3']},
+ {'username': 'test_user8', 'tenant_name': 'test_tenant8',
+ 'password': 'p', 'roles': ['role4', 'role1']},
+ {'username': 'test_user9', 'tenant_name': 'test_tenant9',
+ 'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']},
+ {'username': 'test_user10', 'tenant_name': 'test_tenant10',
+ 'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']},
+ {'username': 'test_user11', 'tenant_name': 'test_tenant11',
+ 'password': 'p', 'roles': [cfg.CONF.identity.admin_role]},
+ {'username': 'test_user12', 'tenant_name': 'test_tenant12',
+ 'password': 'p', 'roles': [cfg.CONF.identity.admin_role]},
]
self.useFixture(mockpatch.Patch(
'tempest.common.accounts.read_accounts_yaml',
@@ -64,7 +76,8 @@
for account in accounts_list:
hash = hashlib.md5()
hash.update(str(account))
- hash_list.append(hash.hexdigest())
+ temp_hash = hash.hexdigest()
+ hash_list.append(temp_hash)
return hash_list
def test_get_hash(self):
@@ -83,8 +96,8 @@
hash_dict = test_account_class.get_hash_dict(self.test_accounts)
hash_list = self._get_hash_list(self.test_accounts)
for hash in hash_list:
- self.assertIn(hash, hash_dict.keys())
- self.assertIn(hash_dict[hash], self.test_accounts)
+ self.assertIn(hash, hash_dict['creds'].keys())
+ self.assertIn(hash_dict['creds'][hash], self.test_accounts)
def test_create_hash_file_previous_file(self):
# Emulate the lock existing on the filesystem
@@ -129,8 +142,9 @@
# Emulate all lcoks in list are in use
self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
test_account_class = accounts.Accounts('test_name')
- self.assertRaises(exceptions.InvalidConfiguration,
- test_account_class._get_free_hash, hash_list)
+ with mock.patch('__builtin__.open', mock.mock_open(), create=True):
+ self.assertRaises(exceptions.InvalidConfiguration,
+ test_account_class._get_free_hash, hash_list)
@mock.patch('tempest.openstack.common.lockutils.lock')
def test_get_free_hash_some_in_use_accounts(self, lock_mock):
@@ -152,7 +166,7 @@
test_account_class._get_free_hash(hash_list)
lock_path = os.path.join(accounts.CONF.lock_path, 'test_accounts',
hash_list[3])
- open_mock.assert_called_once_with(lock_path, 'w')
+ open_mock.assert_has_calls([mock.call(lock_path, 'w')])
@mock.patch('tempest.openstack.common.lockutils.lock')
def test_remove_hash_last_account(self, lock_mock):
@@ -200,6 +214,62 @@
test_accounts_class = accounts.Accounts('test_name')
self.assertFalse(test_accounts_class.is_multi_user())
+ def test__get_creds_by_roles_one_role(self):
+ self.useFixture(mockpatch.Patch(
+ 'tempest.common.accounts.read_accounts_yaml',
+ return_value=self.test_accounts))
+ test_accounts_class = accounts.Accounts('test_name')
+ hashes = test_accounts_class.hash_dict['roles']['role4']
+ temp_hash = hashes[0]
+ get_free_hash_mock = self.useFixture(mockpatch.PatchObject(
+ test_accounts_class, '_get_free_hash', return_value=temp_hash))
+ # Test a single role returns all matching roles
+ test_accounts_class._get_creds(roles=['role4'])
+ calls = get_free_hash_mock.mock.mock_calls
+ self.assertEqual(len(calls), 1)
+ args = calls[0][1][0]
+ for i in hashes:
+ self.assertIn(i, args)
+
+ def test__get_creds_by_roles_list_role(self):
+ self.useFixture(mockpatch.Patch(
+ 'tempest.common.accounts.read_accounts_yaml',
+ return_value=self.test_accounts))
+ test_accounts_class = accounts.Accounts('test_name')
+ hashes = test_accounts_class.hash_dict['roles']['role4']
+ hashes2 = test_accounts_class.hash_dict['roles']['role2']
+ hashes = list(set(hashes) & set(hashes2))
+ temp_hash = hashes[0]
+ get_free_hash_mock = self.useFixture(mockpatch.PatchObject(
+ test_accounts_class, '_get_free_hash', return_value=temp_hash))
+ # Test an intersection of multiple roles
+ test_accounts_class._get_creds(roles=['role2', 'role4'])
+ calls = get_free_hash_mock.mock.mock_calls
+ self.assertEqual(len(calls), 1)
+ args = calls[0][1][0]
+ for i in hashes:
+ self.assertIn(i, args)
+
+ def test__get_creds_by_roles_no_admin(self):
+ self.useFixture(mockpatch.Patch(
+ 'tempest.common.accounts.read_accounts_yaml',
+ return_value=self.test_accounts))
+ test_accounts_class = accounts.Accounts('test_name')
+ hashes = test_accounts_class.hash_dict['creds'].keys()
+ admin_hashes = test_accounts_class.hash_dict['roles'][
+ cfg.CONF.identity.admin_role]
+ temp_hash = hashes[0]
+ get_free_hash_mock = self.useFixture(mockpatch.PatchObject(
+ test_accounts_class, '_get_free_hash', return_value=temp_hash))
+ # Test an intersection of multiple roles
+ test_accounts_class._get_creds()
+ calls = get_free_hash_mock.mock.mock_calls
+ self.assertEqual(len(calls), 1)
+ args = calls[0][1][0]
+ self.assertEqual(len(args), 10)
+ for i in admin_hashes:
+ self.assertNotIn(i, args)
+
class TestNotLockingAccount(base.TestCase):
diff --git a/tempest/tests/common/test_cred_provider.py b/tempest/tests/common/test_cred_provider.py
index 160ecaa..3f7c0f8 100644
--- a/tempest/tests/common/test_cred_provider.py
+++ b/tempest/tests/common/test_cred_provider.py
@@ -17,7 +17,7 @@
from tempest import auth
from tempest.common import cred_provider
from tempest.common import tempest_fixtures as fixtures
-from tempest.services.identity.json import token_client as v2_client
+from tempest.services.identity.v2.json import token_client as v2_client
from tempest.services.identity.v3.json import token_client as v3_client
from tempest.tests import fake_identity
# Note: eventually the auth module will move to tempest-lib, and so wil its
diff --git a/tempest/tests/common/test_custom_matchers.py b/tempest/tests/common/test_custom_matchers.py
index 57217e3..2656a47 100644
--- a/tempest/tests/common/test_custom_matchers.py
+++ b/tempest/tests/common/test_custom_matchers.py
@@ -63,4 +63,4 @@
" b: expected 2, actual None\n",
{'a': 1, 'b': None, 'foo': 1},
matches_matcher)
- ]
\ No newline at end of file
+ ]
diff --git a/tempest/tests/common/test_service_clients.py b/tempest/tests/common/test_service_clients.py
index afe4abc..9bb58b0 100644
--- a/tempest/tests/common/test_service_clients.py
+++ b/tempest/tests/common/test_service_clients.py
@@ -46,7 +46,7 @@
from tempest.services.data_processing.v1_1 import data_processing_client
from tempest.services.database.json import flavors_client as db_flavor_client
from tempest.services.database.json import versions_client as db_version_client
-from tempest.services.identity.json import identity_client as \
+from tempest.services.identity.v2.json import identity_client as \
identity_v2_identity_client
from tempest.services.identity.v3.json import credentials_client
from tempest.services.identity.v3.json import endpoints_client
@@ -55,6 +55,8 @@
from tempest.services.identity.v3.json import policy_client
from tempest.services.identity.v3.json import region_client
from tempest.services.identity.v3.json import service_client
+from tempest.services.image.v1.json import image_client
+from tempest.services.image.v2.json import image_client as image_v2_client
from tempest.services.messaging.json import messaging_client
from tempest.services.network.json import network_client
from tempest.services.object_storage import account_client
@@ -163,7 +165,9 @@
identity_v3_identity_client.IdentityV3ClientJSON,
policy_client.PolicyClientJSON,
region_client.RegionClientJSON,
- service_client.ServiceClientJSON
+ service_client.ServiceClientJSON,
+ image_client.ImageClientJSON,
+ image_v2_client.ImageClientV2JSON
]
for client in test_clients:
diff --git a/tempest/tests/test_auth.py b/tempest/tests/test_auth.py
index c236dbe..f54ff4f 100644
--- a/tempest/tests/test_auth.py
+++ b/tempest/tests/test_auth.py
@@ -21,7 +21,7 @@
from tempest import auth
from tempest import config
from tempest import exceptions
-from tempest.services.identity.json import token_client as v2_client
+from tempest.services.identity.v2.json import token_client as v2_client
from tempest.services.identity.v3.json import token_client as v3_client
from tempest.tests import base
from tempest.tests import fake_config
diff --git a/tempest/tests/test_credentials.py b/tempest/tests/test_credentials.py
index 54a3360..350b190 100644
--- a/tempest/tests/test_credentials.py
+++ b/tempest/tests/test_credentials.py
@@ -19,7 +19,7 @@
from tempest.common import tempest_fixtures as fixtures
from tempest import config
from tempest import exceptions
-from tempest.services.identity.json import token_client as v2_client
+from tempest.services.identity.v2.json import token_client as v2_client
from tempest.services.identity.v3.json import token_client as v3_client
from tempest.tests import base
from tempest.tests import fake_config
diff --git a/tempest/tests/test_tenant_isolation.py b/tempest/tests/test_tenant_isolation.py
index 6c80496..a18ad46 100644
--- a/tempest/tests/test_tenant_isolation.py
+++ b/tempest/tests/test_tenant_isolation.py
@@ -20,8 +20,9 @@
from tempest import config
from tempest import exceptions
from tempest.openstack.common.fixture import mockpatch
-from tempest.services.identity.json import identity_client as json_iden_client
-from tempest.services.identity.json import token_client as json_token_client
+from tempest.services.identity.v2.json import identity_client as \
+ json_iden_client
+from tempest.services.identity.v2.json import token_client as json_token_client
from tempest.services.network.json import network_client as json_network_client
from tempest.tests import base
from tempest.tests import fake_config
@@ -74,6 +75,17 @@
{'id': '1', 'name': 'FakeRole'}]))))
return roles_fix
+ def _mock_list_2_roles(self):
+ roles_fix = self.useFixture(mockpatch.PatchObject(
+ json_iden_client.IdentityClientJSON,
+ 'list_roles',
+ return_value=(service_client.ResponseBodyList
+ (200,
+ [{'id': '1234', 'name': 'role1'},
+ {'id': '1', 'name': 'FakeRole'},
+ {'id': '12345', 'name': 'role2'}]))))
+ return roles_fix
+
def _mock_assign_user_role(self):
tenant_fix = self.useFixture(mockpatch.PatchObject(
json_iden_client.IdentityClientJSON,
@@ -153,6 +165,35 @@
self.assertEqual(admin_creds.user_id, '1234')
@mock.patch('tempest_lib.common.rest_client.RestClient')
+ def test_role_creds(self, MockRestClient):
+ cfg.CONF.set_default('neutron', False, 'service_available')
+ iso_creds = isolated_creds.IsolatedCreds('test class',
+ password='fake_password')
+ self._mock_list_2_roles()
+ self._mock_user_create('1234', 'fake_role_user')
+ self._mock_tenant_create('1234', 'fake_role_tenant')
+
+ user_mock = mock.patch.object(json_iden_client.IdentityClientJSON,
+ 'assign_user_role')
+ user_mock.start()
+ self.addCleanup(user_mock.stop)
+ with mock.patch.object(json_iden_client.IdentityClientJSON,
+ 'assign_user_role') as user_mock:
+ role_creds = iso_creds.get_creds_by_roles(roles=['role1', 'role2'])
+ calls = user_mock.mock_calls
+ # Assert that the role creation is called with the 2 specified roles
+ self.assertEqual(len(calls), 3)
+ args = map(lambda x: x[1], calls)
+ self.assertIn(('1234', '1234', '1'), args)
+ self.assertIn(('1234', '1234', '1234'), args)
+ self.assertIn(('1234', '1234', '12345'), args)
+ self.assertEqual(role_creds.username, 'fake_role_user')
+ self.assertEqual(role_creds.tenant_name, 'fake_role_tenant')
+ # Verify IDs
+ self.assertEqual(role_creds.tenant_id, '1234')
+ self.assertEqual(role_creds.user_id, '1234')
+
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_all_cred_cleanup(self, MockRestClient):
cfg.CONF.set_default('neutron', False, 'service_available')
iso_creds = isolated_creds.IsolatedCreds('test class',
@@ -175,10 +216,10 @@
self._mock_list_roles('123456', 'admin')
iso_creds.get_admin_creds()
user_mock = self.patch(
- 'tempest.services.identity.json.identity_client.'
+ 'tempest.services.identity.v2.json.identity_client.'
'IdentityClientJSON.delete_user')
tenant_mock = self.patch(
- 'tempest.services.identity.json.identity_client.'
+ 'tempest.services.identity.v2.json.identity_client.'
'IdentityClientJSON.delete_tenant')
iso_creds.clear_isolated_creds()
# Verify user delete calls
@@ -293,9 +334,9 @@
router_fix = self._mock_router_create('123456', 'fake_admin_router')
self._mock_list_roles('123456', 'admin')
iso_creds.get_admin_creds()
- self.patch('tempest.services.identity.json.identity_client.'
+ self.patch('tempest.services.identity.v2.json.identity_client.'
'IdentityClientJSON.delete_user')
- self.patch('tempest.services.identity.json.identity_client.'
+ self.patch('tempest.services.identity.v2.json.identity_client.'
'IdentityClientJSON.delete_tenant')
net = mock.patch.object(iso_creds.network_admin_client,
'delete_network')
diff --git a/tempest/thirdparty/boto/test.py b/tempest/thirdparty/boto/test.py
index edd9de1..5b2ed70 100644
--- a/tempest/thirdparty/boto/test.py
+++ b/tempest/thirdparty/boto/test.py
@@ -201,10 +201,14 @@
raise cls.skipException("The EC2 API is not available")
@classmethod
+ def setup_credentials(cls):
+ super(BotoTestCase, cls).setup_credentials()
+ cls.os = cls.get_client_manager()
+
+ @classmethod
def resource_setup(cls):
super(BotoTestCase, cls).resource_setup()
cls.conclusion = decision_maker()
- cls.os = cls.get_client_manager()
# The trash contains cleanup functions and paramaters in tuples
# (function, *args, **kwargs)
cls._resource_trash_bin = {}
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index 822bf34..4a2bd23 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -31,13 +31,17 @@
class InstanceRunTest(boto_test.BotoTestCase):
@classmethod
+ def setup_clients(cls):
+ super(InstanceRunTest, cls).setup_clients()
+ cls.s3_client = cls.os.s3_client
+ cls.ec2_client = cls.os.ec2api_client
+
+ @classmethod
def resource_setup(cls):
super(InstanceRunTest, cls).resource_setup()
if not cls.conclusion['A_I_IMAGES_READY']:
raise cls.skipException("".join(("EC2 ", cls.__name__,
": requires ami/aki/ari manifest")))
- cls.s3_client = cls.os.s3_client
- cls.ec2_client = cls.os.ec2api_client
cls.zone = CONF.boto.aws_zone
cls.materials_path = CONF.boto.s3_materials_path
ami_manifest = CONF.boto.ami_manifest
@@ -245,7 +249,8 @@
self.addResourceCleanUp(self.destroy_reservation,
reservation)
- volume = self.ec2_client.create_volume(1, self.zone)
+ volume = self.ec2_client.create_volume(CONF.volume.volume_size,
+ self.zone)
LOG.debug("Volume created - status: %s", volume.status)
self.addResourceCleanUp(self.destroy_volume_wait, volume)
diff --git a/tempest/thirdparty/boto/test_ec2_keys.py b/tempest/thirdparty/boto/test_ec2_keys.py
index 36c3386..acf797a 100644
--- a/tempest/thirdparty/boto/test_ec2_keys.py
+++ b/tempest/thirdparty/boto/test_ec2_keys.py
@@ -26,9 +26,13 @@
class EC2KeysTest(boto_test.BotoTestCase):
@classmethod
+ def setup_clients(cls):
+ super(EC2KeysTest, cls).setup_clients()
+ cls.client = cls.os.ec2api_client
+
+ @classmethod
def resource_setup(cls):
super(EC2KeysTest, cls).resource_setup()
- cls.client = cls.os.ec2api_client
cls.ec = cls.ec2_error_code
# TODO(afazekas): merge create, delete, get test cases
diff --git a/tempest/thirdparty/boto/test_ec2_network.py b/tempest/thirdparty/boto/test_ec2_network.py
index c7ed00d..ce20156 100644
--- a/tempest/thirdparty/boto/test_ec2_network.py
+++ b/tempest/thirdparty/boto/test_ec2_network.py
@@ -20,8 +20,8 @@
class EC2NetworkTest(boto_test.BotoTestCase):
@classmethod
- def resource_setup(cls):
- super(EC2NetworkTest, cls).resource_setup()
+ def setup_clients(cls):
+ super(EC2NetworkTest, cls).setup_clients()
cls.ec2_client = cls.os.ec2api_client
# Note(afazekas): these tests for things duable without an instance
diff --git a/tempest/thirdparty/boto/test_ec2_security_groups.py b/tempest/thirdparty/boto/test_ec2_security_groups.py
index 92fe59d..7f9568b 100644
--- a/tempest/thirdparty/boto/test_ec2_security_groups.py
+++ b/tempest/thirdparty/boto/test_ec2_security_groups.py
@@ -21,8 +21,8 @@
class EC2SecurityGroupTest(boto_test.BotoTestCase):
@classmethod
- def resource_setup(cls):
- super(EC2SecurityGroupTest, cls).resource_setup()
+ def setup_clients(cls):
+ super(EC2SecurityGroupTest, cls).setup_clients()
cls.client = cls.os.ec2api_client
@test.idempotent_id('519b566e-0c38-4629-905e-7d6b6355f524')
diff --git a/tempest/thirdparty/boto/test_ec2_volumes.py b/tempest/thirdparty/boto/test_ec2_volumes.py
index 4616851..9a6d13f 100644
--- a/tempest/thirdparty/boto/test_ec2_volumes.py
+++ b/tempest/thirdparty/boto/test_ec2_volumes.py
@@ -30,20 +30,26 @@
class EC2VolumesTest(boto_test.BotoTestCase):
@classmethod
- def resource_setup(cls):
- super(EC2VolumesTest, cls).resource_setup()
-
+ def skip_checks(cls):
+ super(EC2VolumesTest, cls).skip_checks()
if not CONF.service_available.cinder:
skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
raise cls.skipException(skip_msg)
+ @classmethod
+ def setup_clients(cls):
+ super(EC2VolumesTest, cls).setup_clients()
cls.client = cls.os.ec2api_client
+
+ @classmethod
+ def resource_setup(cls):
+ super(EC2VolumesTest, cls).resource_setup()
cls.zone = CONF.boto.aws_zone
@test.idempotent_id('663f0077-c743-48ad-8ae0-46821cbc0918')
def test_create_get_delete(self):
# EC2 Create, get, delete Volume
- volume = self.client.create_volume(1, self.zone)
+ volume = self.client.create_volume(CONF.volume.volume_size, self.zone)
cuk = self.addResourceCleanUp(self.client.delete_volume, volume.id)
self.assertIn(volume.status, self.valid_volume_status)
retrieved = self.client.get_all_volumes((volume.id,))
@@ -56,14 +62,15 @@
@test.idempotent_id('c6b60d7a-1af7-4f8e-af21-d539d9496149')
def test_create_volume_from_snapshot(self):
# EC2 Create volume from snapshot
- volume = self.client.create_volume(1, self.zone)
+ volume = self.client.create_volume(CONF.volume.volume_size, self.zone)
self.addResourceCleanUp(self.client.delete_volume, volume.id)
self.assertVolumeStatusWait(volume, "available")
snap = self.client.create_snapshot(volume.id)
self.addResourceCleanUp(self.destroy_snapshot_wait, snap)
self.assertSnapshotStatusWait(snap, "completed")
- svol = self.client.create_volume(1, self.zone, snapshot=snap)
+ svol = self.client.create_volume(CONF.volume.volume_size, self.zone,
+ snapshot=snap)
cuk = self.addResourceCleanUp(svol.delete)
self.assertVolumeStatusWait(svol, "available")
svol.delete()
diff --git a/tempest/thirdparty/boto/test_s3_buckets.py b/tempest/thirdparty/boto/test_s3_buckets.py
index e3a265e..bf04803 100644
--- a/tempest/thirdparty/boto/test_s3_buckets.py
+++ b/tempest/thirdparty/boto/test_s3_buckets.py
@@ -21,8 +21,8 @@
class S3BucketsTest(boto_test.BotoTestCase):
@classmethod
- def resource_setup(cls):
- super(S3BucketsTest, cls).resource_setup()
+ def setup_clients(cls):
+ super(S3BucketsTest, cls).setup_clients()
cls.client = cls.os.s3_client
@test.idempotent_id('4678525d-8da0-4518-81c1-f1f67d595b00')
diff --git a/tempest/thirdparty/boto/test_s3_ec2_images.py b/tempest/thirdparty/boto/test_s3_ec2_images.py
index 773a193..21ea984 100644
--- a/tempest/thirdparty/boto/test_s3_ec2_images.py
+++ b/tempest/thirdparty/boto/test_s3_ec2_images.py
@@ -27,13 +27,17 @@
class S3ImagesTest(boto_test.BotoTestCase):
@classmethod
+ def setup_clients(cls):
+ super(S3ImagesTest, cls).setup_clients()
+ cls.s3_client = cls.os.s3_client
+ cls.images_client = cls.os.ec2api_client
+
+ @classmethod
def resource_setup(cls):
super(S3ImagesTest, cls).resource_setup()
if not cls.conclusion['A_I_IMAGES_READY']:
raise cls.skipException("".join(("EC2 ", cls.__name__,
": requires ami/aki/ari manifest")))
- cls.s3_client = cls.os.s3_client
- cls.images_client = cls.os.ec2api_client
cls.materials_path = CONF.boto.s3_materials_path
cls.ami_manifest = CONF.boto.ami_manifest
cls.aki_manifest = CONF.boto.aki_manifest
diff --git a/tempest/thirdparty/boto/test_s3_objects.py b/tempest/thirdparty/boto/test_s3_objects.py
index bc32686..2d8152d 100644
--- a/tempest/thirdparty/boto/test_s3_objects.py
+++ b/tempest/thirdparty/boto/test_s3_objects.py
@@ -25,8 +25,8 @@
class S3BucketsTest(boto_test.BotoTestCase):
@classmethod
- def resource_setup(cls):
- super(S3BucketsTest, cls).resource_setup()
+ def setup_clients(cls):
+ super(S3BucketsTest, cls).setup_clients()
cls.client = cls.os.s3_client
@test.idempotent_id('4eea567a-b46a-405b-a475-6097e1faebde')
diff --git a/test-requirements.txt b/test-requirements.txt
index 6eefeee..6a9111e 100644
--- a/test-requirements.txt
+++ b/test-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.
-hacking>=0.9.2,<0.10
+hacking<0.11,>=0.10.0
# needed for doc build
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
python-subunit>=0.0.18
diff --git a/tox.ini b/tox.ini
index f3fc8b7..ef98e90 100644
--- a/tox.ini
+++ b/tox.ini
@@ -125,11 +125,9 @@
[flake8]
# E125 is a won't fix until https://github.com/jcrocholl/pep8/issues/126 is resolved. For further detail see https://review.openstack.org/#/c/36788/
-# H402 skipped because some docstrings aren't sentences
# E123 skipped because it is ignored by default in the default pep8
# E129 skipped because it is too limiting when combined with other rules
-# H305 skipped because it is inconsistent between python versions
-# Skipped because of new hacking 0.9: H405,H904
-ignore = E125,H402,E123,E129,H404,H405,H904,H305
+# Skipped because of new hacking 0.9: H405
+ignore = E125,E123,E129,H404,H405
show-source = True
exclude = .git,.venv,.tox,dist,doc,openstack,*egg