Merge "Make missing global config dir not fatal in tempest init"
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index 9a7ce15..32cd3ef 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -205,6 +205,8 @@
Enabling Remote Access to Created Servers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Network Creation/Usage for Servers
+""""""""""""""""""""""""""""""""""
When Tempest creates servers for testing, some tests require being able to
connect those servers. Depending on the configuration of the cloud, the methods
for doing this can be different. In certain configurations it is required to
@@ -214,23 +216,8 @@
run. This section covers the different methods of configuring Tempest to provide
a network when creating servers.
-The ``validation`` group gathers all the connection options to remotely access the
-created servers.
-
-To enable remote access to servers, at least the three following options need to be
-set:
-
-* The ``run_validation`` option needs be set to ``true``.
-
-* The ``connect_method`` option. Two connect methods are available: ``fixed`` and
- ``floating``, the later being set by default.
-
-* The ``auth_method`` option. Currently, only authentication by keypair is
- available.
-
-
Fixed Network Name
-""""""""""""""""""
+''''''''''''''''''
This is the simplest method of specifying how networks should be used. You can
just specify a single network name/label to use for all server creations. The
limitation with this is that all projects and users must be able to see
@@ -252,7 +239,7 @@
Accounts File
-"""""""""""""
+'''''''''''''
If you are using an accounts file to provide credentials for running Tempest
then you can leverage it to also specify which network should be used with
server creations on a per project and user pair basis. This provides
@@ -277,7 +264,7 @@
With Dynamic Credentials
-""""""""""""""""""""""""
+''''''''''''''''''''''''
With dynamic credentials enabled and using nova-network, your only option for
configuration is to either set a fixed network name or not. However, in most
cases it shouldn't matter because nova-network should have no problem booting a
@@ -302,6 +289,34 @@
network available for the server creation, or use ``fixed_network_name`` to
inform Tempest which network to use.
+SSH Connection Configuration
+""""""""""""""""""""""""""""
+There are also several different ways to actually establish a connection and
+authenticate/login on the server. After a server is booted with a provided
+network there are still details needed to know how to actually connect to
+the server. The ``validation`` group gathers all the options regarding
+connecting to and remotely accessing the created servers.
+
+To enable remote access to servers, there are 3 options at a minimum that are used:
+
+ #. ``run_validation``
+ #. ``connect_method``
+ #. ``auth_method``
+
+The ``run_validation`` is used to enable or disable ssh connectivity for
+all tests (with the exception of scenario tests which do not have a flag for
+enabling or disabling ssh) To enable ssh connectivity this needs be set to ``true``.
+
+The ``connect_method`` option is used to tell tempest what kind of IP to use for
+establishing a connection to the server. Two methods are available: ``fixed``
+and ``floating``, the later being set by default. If this is set to floating
+tempest will create a floating ip for the server before attempted to connect
+to it. The IP for the floating ip is what is used for the connection.
+
+For the ``auth_method`` option there is currently, only one valid option,
+``keypair``. With this set to ``keypair`` tempest will create an ssh keypair
+and use that for authenticating against the created server.
+
Configuring Available Services
------------------------------
OpenStack is really a constellation of several different projects which
diff --git a/releasenotes/notes/routers-client-as-library-25a363379da351f6.yaml b/releasenotes/notes/routers-client-as-library-25a363379da351f6.yaml
new file mode 100644
index 0000000..35cf2c4
--- /dev/null
+++ b/releasenotes/notes/routers-client-as-library-25a363379da351f6.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - Define routers_client as stable library interface.
+ The routers_client module is defined as library interface,
+ so the other projects can use the module as stable library
+ without any maintenance changes.
diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py
index 0724566..427a748 100644
--- a/tempest/api/compute/images/test_image_metadata.py
+++ b/tempest/api/compute/images/test_image_metadata.py
@@ -19,6 +19,7 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
+from tempest import exceptions
from tempest import test
CONF = config.CONF
@@ -36,7 +37,17 @@
@classmethod
def setup_clients(cls):
super(ImagesMetadataTestJSON, cls).setup_clients()
- cls.glance_client = cls.os.image_client
+ # Check if glance v1 is available to determine which client to use. We
+ # prefer glance v1 for the compute API tests since the compute image
+ # API proxy was written for glance v1.
+ if CONF.image_feature_enabled.api_v1:
+ cls.glance_client = cls.os.image_client
+ elif CONF.image_feature_enabled.api_v2:
+ cls.glance_client = cls.os.image_client_v2
+ else:
+ raise exceptions.InvalidConfiguration(
+ 'Either api_v1 or api_v2 must be True in '
+ '[image-feature-enabled].')
cls.client = cls.compute_images_client
@classmethod
@@ -45,14 +56,22 @@
cls.image_id = None
name = data_utils.rand_name('image')
+ if CONF.image_feature_enabled.api_v1:
+ kwargs = dict(is_public=False)
+ else:
+ kwargs = dict(visibility='private')
body = cls.glance_client.create_image(name=name,
container_format='bare',
disk_format='raw',
- is_public=False)['image']
+ **kwargs)
+ body = body['image'] if 'image' in body else body
cls.image_id = body['id']
cls.images.append(cls.image_id)
image_file = six.StringIO(('*' * 1024))
- cls.glance_client.update_image(cls.image_id, data=image_file)
+ if CONF.image_feature_enabled.api_v1:
+ cls.glance_client.update_image(cls.image_id, data=image_file)
+ else:
+ cls.glance_client.store_image_file(cls.image_id, data=image_file)
waiters.wait_for_image_status(cls.client, cls.image_id, 'ACTIVE')
def setUp(self):
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index af840cc..e74ca67 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -22,6 +22,7 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
+from tempest import exceptions
from tempest import test
CONF = config.CONF
@@ -40,7 +41,17 @@
def setup_clients(cls):
super(ListImageFiltersTestJSON, cls).setup_clients()
cls.client = cls.compute_images_client
- cls.glance_client = cls.os.image_client
+ # Check if glance v1 is available to determine which client to use. We
+ # prefer glance v1 for the compute API tests since the compute image
+ # API proxy was written for glance v1.
+ if CONF.image_feature_enabled.api_v1:
+ cls.glance_client = cls.os.image_client
+ elif CONF.image_feature_enabled.api_v2:
+ cls.glance_client = cls.os.image_client_v2
+ else:
+ raise exceptions.InvalidConfiguration(
+ 'Either api_v1 or api_v2 must be True in '
+ '[image-feature-enabled].')
@classmethod
def resource_setup(cls):
@@ -48,17 +59,25 @@
def _create_image():
name = data_utils.rand_name('image')
+ if CONF.image_feature_enabled.api_v1:
+ kwargs = dict(is_public=False)
+ else:
+ kwargs = dict(visibility='private')
body = cls.glance_client.create_image(name=name,
container_format='bare',
disk_format='raw',
- is_public=False)['image']
+ **kwargs)
+ body = body['image'] if 'image' in body else body
image_id = body['id']
cls.images.append(image_id)
# Wait 1 second between creation and upload to ensure a delta
# between created_at and updated_at.
time.sleep(1)
image_file = six.StringIO(('*' * 1024))
- cls.glance_client.update_image(image_id, data=image_file)
+ if CONF.image_feature_enabled.api_v1:
+ cls.glance_client.update_image(image_id, data=image_file)
+ else:
+ cls.glance_client.store_image_file(image_id, data=image_file)
waiters.wait_for_image_status(cls.client, image_id, 'ACTIVE')
body = cls.client.show_image(image_id)['image']
return body
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 66aec84..3a4428a 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -24,6 +24,7 @@
from tempest.common.utils.linux import remote_client
from tempest.common import waiters
from tempest import config
+from tempest import exceptions
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
from tempest import test
@@ -320,6 +321,19 @@
def test_create_backup(self):
# Positive test:create backup successfully and rotate backups correctly
# create the first and the second backup
+
+ # Check if glance v1 is available to determine which client to use. We
+ # prefer glance v1 for the compute API tests since the compute image
+ # API proxy was written for glance v1.
+ if CONF.image_feature_enabled.api_v1:
+ glance_client = self.os.image_client
+ elif CONF.image_feature_enabled.api_v2:
+ glance_client = self.os.image_client_v2
+ else:
+ raise exceptions.InvalidConfiguration(
+ 'Either api_v1 or api_v2 must be True in '
+ '[image-feature-enabled].')
+
backup1 = data_utils.rand_name('backup-1')
resp = self.client.create_backup(self.server_id,
backup_type='daily',
@@ -331,7 +345,7 @@
def _clean_oldest_backup(oldest_backup):
if oldest_backup_exist:
try:
- self.os.image_client.delete_image(oldest_backup)
+ glance_client.delete_image(oldest_backup)
except lib_exc.NotFound:
pass
else:
@@ -341,7 +355,7 @@
image1_id = data_utils.parse_image_id(resp['location'])
self.addCleanup(_clean_oldest_backup, image1_id)
- waiters.wait_for_image_status(self.os.image_client,
+ waiters.wait_for_image_status(glance_client,
image1_id, 'active')
backup2 = data_utils.rand_name('backup-2')
@@ -351,8 +365,8 @@
rotation=2,
name=backup2).response
image2_id = data_utils.parse_image_id(resp['location'])
- self.addCleanup(self.os.image_client.delete_image, image2_id)
- waiters.wait_for_image_status(self.os.image_client,
+ self.addCleanup(glance_client.delete_image, image2_id)
+ waiters.wait_for_image_status(glance_client,
image2_id, 'active')
# verify they have been created
@@ -361,12 +375,20 @@
'backup_type': "daily",
'instance_uuid': self.server_id,
}
- image_list = self.os.image_client.list_images(
- detail=True,
- properties=properties,
- status='active',
- sort_key='created_at',
- sort_dir='asc')['images']
+ if CONF.image_feature_enabled.api_v1:
+ params = dict(
+ properties=properties, status='active',
+ sort_key='created_at', sort_dir='asc',)
+ image_list = glance_client.list_images(
+ detail=True,
+ **params)['images']
+ else:
+ # Additional properties are flattened in glance v2.
+ params = dict(
+ status='active', sort_key='created_at', sort_dir='asc')
+ params.update(properties)
+ image_list = glance_client.list_images(params)['images']
+
self.assertEqual(2, len(image_list))
self.assertEqual((backup1, backup2),
(image_list[0]['name'], image_list[1]['name']))
@@ -380,17 +402,16 @@
rotation=2,
name=backup3).response
image3_id = data_utils.parse_image_id(resp['location'])
- self.addCleanup(self.os.image_client.delete_image, image3_id)
+ self.addCleanup(glance_client.delete_image, image3_id)
# the first back up should be deleted
waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
- self.os.image_client.wait_for_resource_deletion(image1_id)
+ glance_client.wait_for_resource_deletion(image1_id)
oldest_backup_exist = False
- image_list = self.os.image_client.list_images(
- detail=True,
- properties=properties,
- status='active',
- sort_key='created_at',
- sort_dir='asc')['images']
+ if CONF.image_feature_enabled.api_v1:
+ image_list = glance_client.list_images(
+ detail=True, **params)['images']
+ else:
+ image_list = glance_client.list_images(params)['images']
self.assertEqual(2, len(image_list),
'Unexpected number of images for '
'v2:test_create_backup; was the oldest backup not '
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index bd04c0d..6d0fa8e 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -93,12 +93,14 @@
@classmethod
def setup_clients(cls):
super(BaseV1ImageMembersTest, cls).setup_clients()
+ cls.image_member_client = cls.os.image_member_client
+ cls.alt_image_member_client = cls.os_alt.image_member_client
cls.alt_img_cli = cls.os_alt.image_client
@classmethod
def resource_setup(cls):
super(BaseV1ImageMembersTest, cls).resource_setup()
- cls.alt_tenant_id = cls.alt_img_cli.tenant_id
+ cls.alt_tenant_id = cls.alt_image_member_client.tenant_id
def _create_image(self):
image_file = moves.cStringIO(data_utils.random_bytes())
@@ -123,6 +125,8 @@
def setup_clients(cls):
super(BaseV2ImageTest, cls).setup_clients()
cls.client = cls.os.image_client_v2
+ cls.namespaces_client = cls.os.namespaces_client
+ cls.schemas_client = cls.os.schemas_client
class BaseV2MemberImageTest(BaseV2ImageTest):
@@ -132,13 +136,14 @@
@classmethod
def setup_clients(cls):
super(BaseV2MemberImageTest, cls).setup_clients()
- cls.os_img_client = cls.os.image_client_v2
+ cls.os_image_member_client = cls.os.image_member_client_v2
+ cls.alt_image_member_client = cls.os_alt.image_member_client_v2
cls.alt_img_client = cls.os_alt.image_client_v2
@classmethod
def resource_setup(cls):
super(BaseV2MemberImageTest, cls).resource_setup()
- cls.alt_tenant_id = cls.alt_img_client.tenant_id
+ cls.alt_tenant_id = cls.alt_image_member_client.tenant_id
def _list_image_ids_as_alt(self):
image_list = self.alt_img_client.list_images()['images']
@@ -147,11 +152,11 @@
def _create_image(self):
name = data_utils.rand_name('image')
- image = self.os_img_client.create_image(name=name,
- container_format='bare',
- disk_format='raw')
+ image = self.client.create_image(name=name,
+ container_format='bare',
+ disk_format='raw')
image_id = image['id']
- self.addCleanup(self.os_img_client.delete_image, image_id)
+ self.addCleanup(self.client.delete_image, image_id)
return image_id
diff --git a/tempest/api/image/v1/test_image_members.py b/tempest/api/image/v1/test_image_members.py
index eb6969b..0bad96a 100644
--- a/tempest/api/image/v1/test_image_members.py
+++ b/tempest/api/image/v1/test_image_members.py
@@ -22,8 +22,8 @@
@test.idempotent_id('1d6ef640-3a20-4c84-8710-d95828fdb6ad')
def test_add_image_member(self):
image = self._create_image()
- self.client.add_member(self.alt_tenant_id, image)
- body = self.client.list_image_members(image)
+ self.image_member_client.add_member(self.alt_tenant_id, image)
+ body = self.image_member_client.list_image_members(image)
members = body['members']
members = map(lambda x: x['member_id'], members)
self.assertIn(self.alt_tenant_id, members)
@@ -33,10 +33,11 @@
@test.idempotent_id('6a5328a5-80e8-4b82-bd32-6c061f128da9')
def test_get_shared_images(self):
image = self._create_image()
- self.client.add_member(self.alt_tenant_id, image)
+ self.image_member_client.add_member(self.alt_tenant_id, image)
share_image = self._create_image()
- self.client.add_member(self.alt_tenant_id, share_image)
- body = self.client.list_shared_images(self.alt_tenant_id)
+ self.image_member_client.add_member(self.alt_tenant_id, share_image)
+ body = self.image_member_client.list_shared_images(
+ self.alt_tenant_id)
images = body['shared_images']
images = map(lambda x: x['image_id'], images)
self.assertIn(share_image, images)
@@ -45,8 +46,8 @@
@test.idempotent_id('a76a3191-8948-4b44-a9d6-4053e5f2b138')
def test_remove_member(self):
image_id = self._create_image()
- self.client.add_member(self.alt_tenant_id, image_id)
- self.client.delete_member(self.alt_tenant_id, image_id)
- body = self.client.list_image_members(image_id)
+ self.image_member_client.add_member(self.alt_tenant_id, image_id)
+ self.image_member_client.delete_member(self.alt_tenant_id, image_id)
+ body = self.image_member_client.list_image_members(image_id)
members = body['members']
self.assertEqual(0, len(members), str(members))
diff --git a/tempest/api/image/v1/test_image_members_negative.py b/tempest/api/image/v1/test_image_members_negative.py
index 16a4ba6..d46a836 100644
--- a/tempest/api/image/v1/test_image_members_negative.py
+++ b/tempest/api/image/v1/test_image_members_negative.py
@@ -25,7 +25,8 @@
def test_add_member_with_non_existing_image(self):
# Add member with non existing image.
non_exist_image = data_utils.rand_uuid()
- self.assertRaises(lib_exc.NotFound, self.client.add_member,
+ self.assertRaises(lib_exc.NotFound,
+ self.image_member_client.add_member,
self.alt_tenant_id, non_exist_image)
@test.attr(type=['negative'])
@@ -33,7 +34,8 @@
def test_delete_member_with_non_existing_image(self):
# Delete member with non existing image.
non_exist_image = data_utils.rand_uuid()
- self.assertRaises(lib_exc.NotFound, self.client.delete_member,
+ self.assertRaises(lib_exc.NotFound,
+ self.image_member_client.delete_member,
self.alt_tenant_id, non_exist_image)
@test.attr(type=['negative'])
@@ -42,7 +44,8 @@
# Delete member with non existing tenant.
image_id = self._create_image()
non_exist_tenant = data_utils.rand_uuid_hex()
- self.assertRaises(lib_exc.NotFound, self.client.delete_member,
+ self.assertRaises(lib_exc.NotFound,
+ self.image_member_client.delete_member,
non_exist_tenant, image_id)
@test.attr(type=['negative'])
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 04582c6..1fb9c52 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -254,12 +254,12 @@
def test_get_image_schema(self):
# Test to get image schema
schema = "image"
- body = self.client.show_schema(schema)
+ body = self.schemas_client.show_schema(schema)
self.assertEqual("image", body['name'])
@test.idempotent_id('25c8d7b2-df21-460f-87ac-93130bcdc684')
def test_get_images_schema(self):
# Test to get images schema
schema = "images"
- body = self.client.show_schema(schema)
+ body = self.schemas_client.show_schema(schema)
self.assertEqual("images", body['name'])
diff --git a/tempest/api/image/v2/test_images_member.py b/tempest/api/image/v2/test_images_member.py
index bb73318..d8254f5 100644
--- a/tempest/api/image/v2/test_images_member.py
+++ b/tempest/api/image/v2/test_images_member.py
@@ -19,17 +19,17 @@
@test.idempotent_id('5934c6ea-27dc-4d6e-9421-eeb5e045494a')
def test_image_share_accept(self):
image_id = self._create_image()
- member = self.os_img_client.create_image_member(
+ member = self.os_image_member_client.create_image_member(
image_id, member=self.alt_tenant_id)
self.assertEqual(member['member_id'], self.alt_tenant_id)
self.assertEqual(member['image_id'], image_id)
self.assertEqual(member['status'], 'pending')
self.assertNotIn(image_id, self._list_image_ids_as_alt())
- self.alt_img_client.update_image_member(image_id,
- self.alt_tenant_id,
- status='accepted')
+ self.alt_image_member_client.update_image_member(image_id,
+ self.alt_tenant_id,
+ status='accepted')
self.assertIn(image_id, self._list_image_ids_as_alt())
- body = self.os_img_client.list_image_members(image_id)
+ body = self.os_image_member_client.list_image_members(image_id)
members = body['members']
member = members[0]
self.assertEqual(len(members), 1, str(members))
@@ -40,29 +40,29 @@
@test.idempotent_id('d9e83e5f-3524-4b38-a900-22abcb26e90e')
def test_image_share_reject(self):
image_id = self._create_image()
- member = self.os_img_client.create_image_member(
+ member = self.os_image_member_client.create_image_member(
image_id, member=self.alt_tenant_id)
self.assertEqual(member['member_id'], self.alt_tenant_id)
self.assertEqual(member['image_id'], image_id)
self.assertEqual(member['status'], 'pending')
self.assertNotIn(image_id, self._list_image_ids_as_alt())
- self.alt_img_client.update_image_member(image_id,
- self.alt_tenant_id,
- status='rejected')
+ self.alt_image_member_client.update_image_member(image_id,
+ self.alt_tenant_id,
+ status='rejected')
self.assertNotIn(image_id, self._list_image_ids_as_alt())
@test.idempotent_id('a6ee18b9-4378-465e-9ad9-9a6de58a3287')
def test_get_image_member(self):
image_id = self._create_image()
- self.os_img_client.create_image_member(
+ self.os_image_member_client.create_image_member(
image_id, member=self.alt_tenant_id)
- self.alt_img_client.update_image_member(image_id,
- self.alt_tenant_id,
- status='accepted')
+ self.alt_image_member_client.update_image_member(image_id,
+ self.alt_tenant_id,
+ status='accepted')
self.assertIn(image_id, self._list_image_ids_as_alt())
- member = self.os_img_client.show_image_member(image_id,
- self.alt_tenant_id)
+ member = self.os_image_member_client.show_image_member(
+ image_id, self.alt_tenant_id)
self.assertEqual(self.alt_tenant_id, member['member_id'])
self.assertEqual(image_id, member['image_id'])
self.assertEqual('accepted', member['status'])
@@ -70,38 +70,40 @@
@test.idempotent_id('72989bc7-2268-48ed-af22-8821e835c914')
def test_remove_image_member(self):
image_id = self._create_image()
- self.os_img_client.create_image_member(
+ self.os_image_member_client.create_image_member(
image_id, member=self.alt_tenant_id)
- self.alt_img_client.update_image_member(image_id,
- self.alt_tenant_id,
- status='accepted')
+ self.alt_image_member_client.update_image_member(image_id,
+ self.alt_tenant_id,
+ status='accepted')
self.assertIn(image_id, self._list_image_ids_as_alt())
- self.os_img_client.delete_image_member(image_id, self.alt_tenant_id)
+ self.os_image_member_client.delete_image_member(image_id,
+ self.alt_tenant_id)
self.assertNotIn(image_id, self._list_image_ids_as_alt())
@test.idempotent_id('634dcc3f-f6e2-4409-b8fd-354a0bb25d83')
def test_get_image_member_schema(self):
- body = self.os_img_client.show_schema("member")
+ body = self.schemas_client.show_schema("member")
self.assertEqual("member", body['name'])
@test.idempotent_id('6ae916ef-1052-4e11-8d36-b3ae14853cbb')
def test_get_image_members_schema(self):
- body = self.os_img_client.show_schema("members")
+ body = self.schemas_client.show_schema("members")
self.assertEqual("members", body['name'])
@test.idempotent_id('cb961424-3f68-4d21-8e36-30ad66fb6bfb')
def test_get_private_image(self):
image_id = self._create_image()
- member = self.os_img_client.create_image_member(
+ member = self.os_image_member_client.create_image_member(
image_id, member=self.alt_tenant_id)
self.assertEqual(member['member_id'], self.alt_tenant_id)
self.assertEqual(member['image_id'], image_id)
self.assertEqual(member['status'], 'pending')
self.assertNotIn(image_id, self._list_image_ids_as_alt())
- self.alt_img_client.update_image_member(image_id,
- self.alt_tenant_id,
- status='accepted')
+ self.alt_image_member_client.update_image_member(image_id,
+ self.alt_tenant_id,
+ status='accepted')
self.assertIn(image_id, self._list_image_ids_as_alt())
- self.os_img_client.delete_image_member(image_id, self.alt_tenant_id)
+ self.os_image_member_client.delete_image_member(image_id,
+ self.alt_tenant_id)
self.assertNotIn(image_id, self._list_image_ids_as_alt())
diff --git a/tempest/api/image/v2/test_images_member_negative.py b/tempest/api/image/v2/test_images_member_negative.py
index 388eb08..5a08d77 100644
--- a/tempest/api/image/v2/test_images_member_negative.py
+++ b/tempest/api/image/v2/test_images_member_negative.py
@@ -21,11 +21,11 @@
@test.idempotent_id('b79efb37-820d-4cf0-b54c-308b00cf842c')
def test_image_share_invalid_status(self):
image_id = self._create_image()
- member = self.os_img_client.create_image_member(
+ member = self.os_image_member_client.create_image_member(
image_id, member=self.alt_tenant_id)
self.assertEqual(member['status'], 'pending')
self.assertRaises(lib_exc.BadRequest,
- self.alt_img_client.update_image_member,
+ self.alt_image_member_client.update_image_member,
image_id, self.alt_tenant_id,
status='notavalidstatus')
@@ -33,11 +33,11 @@
@test.idempotent_id('27002f74-109e-4a37-acd0-f91cd4597967')
def test_image_share_owner_cannot_accept(self):
image_id = self._create_image()
- member = self.os_img_client.create_image_member(
+ member = self.os_image_member_client.create_image_member(
image_id, member=self.alt_tenant_id)
self.assertEqual(member['status'], 'pending')
self.assertNotIn(image_id, self._list_image_ids_as_alt())
self.assertRaises(lib_exc.Forbidden,
- self.os_img_client.update_image_member,
+ self.os_image_member_client.update_image_member,
image_id, self.alt_tenant_id, status='accepted')
self.assertNotIn(image_id, self._list_image_ids_as_alt())
diff --git a/tempest/api/image/v2/test_images_metadefs_namespaces.py b/tempest/api/image/v2/test_images_metadefs_namespaces.py
index da0f4c1..f6d1bdc 100644
--- a/tempest/api/image/v2/test_images_metadefs_namespaces.py
+++ b/tempest/api/image/v2/test_images_metadefs_namespaces.py
@@ -31,38 +31,42 @@
name = [{'name': resource_name}]
namespace_name = data_utils.rand_name('namespace')
# create the metadef namespace
- body = self.client.create_namespace(namespace=namespace_name,
- visibility='public',
- description='Tempest',
- display_name=namespace_name,
- resource_type_associations=name,
- protected=True)
+ body = self.namespaces_client.create_namespace(
+ namespace=namespace_name,
+ visibility='public',
+ description='Tempest',
+ display_name=namespace_name,
+ resource_type_associations=name,
+ protected=True)
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self._cleanup_namespace, namespace_name)
# get namespace details
- body = self.client.show_namespace(namespace_name)
+ body = self.namespaces_client.show_namespace(namespace_name)
self.assertEqual(namespace_name, body['namespace'])
self.assertEqual('public', body['visibility'])
# unable to delete protected namespace
- self.assertRaises(lib_exc.Forbidden, self.client.delete_namespace,
+ self.assertRaises(lib_exc.Forbidden,
+ self.namespaces_client.delete_namespace,
namespace_name)
# update the visibility to private and protected to False
- body = self.client.update_namespace(namespace=namespace_name,
- description='Tempest',
- visibility='private',
- display_name=namespace_name,
- protected=False)
+ body = self.namespaces_client.update_namespace(
+ namespace=namespace_name,
+ description='Tempest',
+ visibility='private',
+ display_name=namespace_name,
+ protected=False)
self.assertEqual('private', body['visibility'])
self.assertEqual(False, body['protected'])
# now able to delete the non-protected namespace
- self.client.delete_namespace(namespace_name)
+ self.namespaces_client.delete_namespace(namespace_name)
def _cleanup_namespace(self, namespace_name):
- body = self.client.show_namespace(namespace_name)
+ body = self.namespaces_client.show_namespace(namespace_name)
self.assertEqual(namespace_name, body['namespace'])
- body = self.client.update_namespace(namespace=namespace_name,
- description='Tempest',
- visibility='private',
- display_name=namespace_name,
- protected=False)
- self.client.delete_namespace(namespace_name)
+ body = self.namespaces_client.update_namespace(
+ namespace=namespace_name,
+ description='Tempest',
+ visibility='private',
+ display_name=namespace_name,
+ protected=False)
+ self.namespaces_client.delete_namespace(namespace_name)
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index 38913ce..76cd36c 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -18,6 +18,7 @@
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
+from tempest import exceptions
from tempest.lib.common.utils import test_utils
from tempest import test
@@ -30,7 +31,16 @@
def setup_clients(cls):
super(VolumesV2ActionsTest, cls).setup_clients()
cls.client = cls.volumes_client
- cls.image_client = cls.os.image_client
+ if CONF.service_available.glance:
+ # Check if glance v1 is available to determine which client to use.
+ if CONF.image_feature_enabled.api_v1:
+ cls.image_client = cls.os.image_client
+ elif CONF.image_feature_enabled.api_v2:
+ cls.image_client = cls.os.image_client_v2
+ else:
+ raise exceptions.InvalidConfiguration(
+ 'Either api_v1 or api_v2 must be True in '
+ '[image-feature-enabled].')
@classmethod
def resource_setup(cls):
diff --git a/tempest/clients.py b/tempest/clients.py
index 19f1a2a..de9b88a 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -88,6 +88,7 @@
from tempest.lib.services.network.ports_client import PortsClient
from tempest.lib.services.network.quotas_client import QuotasClient \
as NetworkQuotasClient
+from tempest.lib.services.network.routers_client import RoutersClient
from tempest.lib.services.network.security_group_rules_client import \
SecurityGroupRulesClient
from tempest.lib.services.network.security_groups_client import \
@@ -131,9 +132,13 @@
from tempest.services.identity.v3.json.users_clients import \
UsersClient as UsersV3Client
from tempest.services.image.v1.json.images_client import ImagesClient
+from tempest.services.image.v1.json.members_client import MembersClient
from tempest.services.image.v2.json.images_client import \
ImagesClient as ImagesV2Client
-from tempest.services.network.json.routers_client import RoutersClient
+from tempest.services.image.v2.json.members_client import MembersClient \
+ as MembersClientV2
+from tempest.services.image.v2.json.namespaces_client import NamespacesClient
+from tempest.services.image.v2.json.schemas_client import SchemasClient
from tempest.services.object_storage.account_client import AccountClient
from tempest.services.object_storage.container_client import ContainerClient
from tempest.services.object_storage.object_client import ObjectClient
@@ -332,6 +337,14 @@
build_interval=CONF.image.build_interval,
build_timeout=CONF.image.build_timeout,
**self.default_params)
+ self.image_member_client = MembersClient(
+ 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 = ImagesV2Client(
self.auth_provider,
CONF.image.catalog_type,
@@ -340,6 +353,30 @@
build_interval=CONF.image.build_interval,
build_timeout=CONF.image.build_timeout,
**self.default_params)
+ self.image_member_client_v2 = MembersClientV2(
+ 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.namespaces_client = NamespacesClient(
+ 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.schemas_client = SchemasClient(
+ 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,
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index 5fab961..249261b 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -40,13 +40,15 @@
You're probably familiar with these, but just to remind::
- +----------+------------------+----------------------+
- | Param | CLI | Environment Variable |
- +----------+------------------+----------------------+
- | Username | --os-username | OS_USERNAME |
- | Password | --os-password | OS_PASSWORD |
- | Tenant | --os-tenant-name | OS_TENANT_NAME |
- +----------+------------------+----------------------+
+ +----------+---------------------------+----------------------+
+ | Param | CLI | Environment Variable |
+ +----------+---------------------------+----------------------+
+ | Username | --os-username | OS_USERNAME |
+ | Password | --os-password | OS_PASSWORD |
+ | Project | --os-project-name | OS_PROJECT_NAME |
+ | Tenant | --os-tenant-name (depr.) | OS_TENANT_NAME |
+ | Domain | --os-domain-name | OS_DOMAIN_NAME |
+ +----------+---------------------------+----------------------+
Optional Arguments
------------------
@@ -63,8 +65,14 @@
**--os-password <auth-password>** (Optional) Password used for authentication
with the OpenStack Identity service. Defaults to env[OS_PASSWORD].
-**--os-tenant-name <auth-tenant-name>** (Optional) Tenant to request
-authorization on. Defaults to env[OS_TENANT_NAME].
+**--os-project-name <auth-project-name>** (Optional) Project to request
+authorization on. Defaults to env[OS_PROJECT_NAME].
+
+**--os-tenant-name <auth-tenant-name>** (Optional, deprecated) Tenant to
+request authorization on. Defaults to env[OS_TENANT_NAME].
+
+**--os-domain-name <auth-domain-name>** (Optional) Domain the user and project
+belong to. Defaults to env[OS_DOMAIN_NAME].
**--tag TAG** (Optional) Resources tag. Each created resource (user, project)
will have the prefix with the given TAG in its name. Using tag is recommended
@@ -79,11 +87,13 @@
**--with-admin** (Optional) Creates admin for each concurrent group
(default: False).
+**-i VERSION**, **--identity-version VERSION** (Optional) Provisions accounts
+using the specified version of the identity API. (default: '3').
+
To see help on specific argument, please do: ``tempest-account-generator
[OPTIONS] <accounts_file.yaml> -h``.
"""
import argparse
-import netaddr
import os
import traceback
@@ -91,19 +101,10 @@
from oslo_log import log as logging
import yaml
-from tempest.common import identity
+from tempest.common import credentials_factory
+from tempest.common import dynamic_creds
from tempest import config
-from tempest import exceptions as exc
-import tempest.lib.auth
-from tempest.lib.common.utils import data_utils
-import tempest.lib.exceptions
-from tempest.lib.services.network import networks_client
-from tempest.lib.services.network import subnets_client
-from tempest.services.identity.v2.json import identity_client
-from tempest.services.identity.v2.json import roles_client
-from tempest.services.identity.v2.json import tenants_client
-from tempest.services.identity.v2.json import users_client
-from tempest.services.network.json import routers_client
+
LOG = None
CONF = config.CONF
@@ -120,290 +121,83 @@
LOG = logging.getLogger(__name__)
-def get_admin_clients(opts):
- _creds = tempest.lib.auth.KeystoneV2Credentials(
- username=opts.os_username,
- password=opts.os_password,
- tenant_name=opts.os_tenant_name)
- auth_params = {
- 'disable_ssl_certificate_validation':
- CONF.identity.disable_ssl_certificate_validation,
- 'ca_certs': CONF.identity.ca_certificates_file,
- 'trace_requests': CONF.debug.trace_requests
- }
- _auth = tempest.lib.auth.KeystoneV2AuthProvider(
- _creds, CONF.identity.uri, **auth_params)
- params = {
- 'disable_ssl_certificate_validation':
- CONF.identity.disable_ssl_certificate_validation,
- 'ca_certs': CONF.identity.ca_certificates_file,
- 'trace_requests': CONF.debug.trace_requests,
- 'build_interval': CONF.compute.build_interval,
- 'build_timeout': CONF.compute.build_timeout
- }
- identity_admin = identity_client.IdentityClient(
- _auth,
- CONF.identity.catalog_type,
- CONF.identity.region,
- endpoint_type='adminURL',
- **params
- )
- tenants_admin = tenants_client.TenantsClient(
- _auth,
- CONF.identity.catalog_type,
- CONF.identity.region,
- endpoint_type='adminURL',
- **params
- )
- roles_admin = roles_client.RolesClient(
- _auth,
- CONF.identity.catalog_type,
- CONF.identity.region,
- endpoint_type='adminURL',
- **params
- )
- users_admin = users_client.UsersClient(
- _auth,
- CONF.identity.catalog_type,
- CONF.identity.region,
- endpoint_type='adminURL',
- **params
- )
- networks_admin = None
- routers_admin = None
- subnets_admin = None
- neutron_iso_networks = False
- if (CONF.service_available.neutron and
- CONF.auth.create_isolated_networks):
- neutron_iso_networks = True
- networks_admin = networks_client.NetworksClient(
- _auth,
- CONF.network.catalog_type,
- CONF.network.region or CONF.identity.region,
- endpoint_type='adminURL',
- **params)
- routers_admin = routers_client.RoutersClient(
- _auth,
- CONF.network.catalog_type,
- CONF.network.region or CONF.identity.region,
- endpoint_type='adminURL',
- **params)
- subnets_admin = subnets_client.SubnetsClient(
- _auth,
- CONF.network.catalog_type,
- CONF.network.region or CONF.identity.region,
- endpoint_type='adminURL',
- **params)
- return (identity_admin, tenants_admin, roles_admin, users_admin,
- neutron_iso_networks, networks_admin, routers_admin,
- subnets_admin)
+def get_credential_provider(opts):
+ identity_version = "".join(['v', str(opts.identity_version)])
+ # NOTE(andreaf) For now tempest.conf controls whether resources will
+ # actually be created. Once we remove the dependency from tempest.conf
+ # we will need extra CLI option(s) to control this.
+ network_resources = {'router': True,
+ 'network': True,
+ 'subnet': True,
+ 'dhcp': True}
+ admin_creds_dict = {'username': opts.os_username,
+ 'password': opts.os_password}
+ _project_name = opts.os_project_name or opts.os_tenant_name
+ if opts.identity_version == 3:
+ admin_creds_dict['project_name'] = _project_name
+ admin_creds_dict['domain_name'] = opts.os_domain_name or 'Default'
+ elif opts.identity_version == 2:
+ admin_creds_dict['tenant_name'] = _project_name
+ admin_creds = credentials_factory.get_credentials(
+ fill_in=False, identity_version=identity_version, **admin_creds_dict)
+ return dynamic_creds.DynamicCredentialProvider(
+ identity_version=identity_version,
+ name=opts.tag,
+ network_resources=network_resources,
+ admin_creds=admin_creds,
+ **credentials_factory.get_dynamic_provider_params())
-def create_resources(opts, resources):
- (identity_admin, tenants_admin, roles_admin, users_admin,
- neutron_iso_networks, networks_admin, routers_admin,
- subnets_admin) = get_admin_clients(opts)
- roles = roles_admin.list_roles()['roles']
- for u in resources['users']:
- u['role_ids'] = []
- for r in u.get('roles', ()):
- try:
- role = filter(lambda r_: r_['name'] == r, roles)[0]
- except IndexError:
- msg = "Role: %s doesn't exist" % r
- raise exc.InvalidConfiguration(msg)
- u['role_ids'] += [role['id']]
- existing = [x['name'] for x in tenants_admin.list_tenants()['tenants']]
- for tenant in resources['tenants']:
- if tenant not in existing:
- tenants_admin.create_tenant(tenant)
- else:
- LOG.warning("Tenant '%s' already exists in this environment"
- % tenant)
- LOG.info('Tenants created')
- for u in resources['users']:
- try:
- tenant = identity.get_tenant_by_name(tenants_admin, u['tenant'])
- except tempest.lib.exceptions.NotFound:
- LOG.error("Tenant: %s - not found" % u['tenant'])
- continue
- while True:
- try:
- identity.get_user_by_username(tenants_admin,
- tenant['id'], u['name'])
- except tempest.lib.exceptions.NotFound:
- users_admin.create_user(
- u['name'], u['pass'], tenant['id'],
- "%s@%s" % (u['name'], tenant['id']),
- enabled=True)
- break
- else:
- LOG.warning("User '%s' already exists in this environment. "
- "New name generated" % u['name'])
- u['name'] = random_user_name(opts.tag, u['prefix'])
-
- LOG.info('Users created')
- if neutron_iso_networks:
- for u in resources['users']:
- tenant = identity.get_tenant_by_name(tenants_admin, u['tenant'])
- network_name, router_name = create_network_resources(
- networks_admin, routers_admin, subnets_admin,
- tenant['id'], u['name'])
- u['network'] = network_name
- u['router'] = router_name
- LOG.info('Networks created')
- for u in resources['users']:
- try:
- tenant = identity.get_tenant_by_name(tenants_admin, u['tenant'])
- except tempest.lib.exceptions.NotFound:
- LOG.error("Tenant: %s - not found" % u['tenant'])
- continue
- try:
- user = identity.get_user_by_username(tenants_admin,
- tenant['id'], u['name'])
- except tempest.lib.exceptions.NotFound:
- LOG.error("User: %s - not found" % u['name'])
- continue
- for r in u['role_ids']:
- try:
- roles_admin.assign_user_role(tenant['id'], user['id'], r)
- except tempest.lib.exceptions.Conflict:
- # don't care if it's already assigned
- pass
- LOG.info('Roles assigned')
- LOG.info('Resources deployed successfully!')
-
-
-def create_network_resources(networks_admin_client,
- routers_admin_client, subnets_admin_client,
- tenant_id, name):
-
- def _create_network(name):
- resp_body = networks_admin_client.create_network(
- name=name, tenant_id=tenant_id)
- return resp_body['network']
-
- def _create_subnet(subnet_name, network_id):
- base_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
- mask_bits = CONF.network.project_network_mask_bits
- for subnet_cidr in base_cidr.subnet(mask_bits):
- try:
- resp_body = subnets_admin_client.\
- create_subnet(
- network_id=network_id, cidr=str(subnet_cidr),
- name=subnet_name,
- tenant_id=tenant_id,
- enable_dhcp=True,
- ip_version=4)
- break
- except tempest.lib.exceptions.BadRequest as e:
- if 'overlaps with another subnet' not in str(e):
- raise
- else:
- message = 'Available CIDR for subnet creation could not be found'
- raise Exception(message)
- return resp_body['subnet']
-
- def _create_router(router_name):
- external_net_id = dict(
- network_id=CONF.network.public_network_id)
- resp_body = routers_admin_client.create_router(
- name=router_name,
- external_gateway_info=external_net_id,
- tenant_id=tenant_id)
- return resp_body['router']
-
- def _add_router_interface(router_id, subnet_id):
- routers_admin_client.add_router_interface(router_id,
- subnet_id=subnet_id)
-
- network_name = name + "-network"
- network = _create_network(network_name)
- subnet_name = name + "-subnet"
- subnet = _create_subnet(subnet_name, network['id'])
- router_name = name + "-router"
- router = _create_router(router_name)
- _add_router_interface(router['id'], subnet['id'])
- return network_name, router_name
-
-
-def random_user_name(tag, prefix):
- if tag:
- return data_utils.rand_name('-'.join((tag, prefix)))
- else:
- return data_utils.rand_name(prefix)
-
-
-def generate_resources(opts):
- spec = [{'number': 1,
- 'prefix': 'primary',
- 'roles': (CONF.auth.tempest_roles +
- [CONF.object_storage.operator_role])},
- {'number': 1,
- 'prefix': 'alt',
- 'roles': (CONF.auth.tempest_roles +
- [CONF.object_storage.operator_role])}]
+def generate_resources(cred_provider, admin):
+ # Create the list of resources to be provisioned for each process
+ # NOTE(andreaf) get_credentials expects a string for types or a list for
+ # roles. Adding all required inputs to the spec list.
+ spec = ['primary', 'alt']
if CONF.service_available.swift:
- spec.append({'number': 1,
- 'prefix': 'swift_operator',
- 'roles': (CONF.auth.tempest_roles +
- [CONF.object_storage.operator_role])})
- spec.append({'number': 1,
- 'prefix': 'swift_reseller_admin',
- 'roles': (CONF.auth.tempest_roles +
- [CONF.object_storage.reseller_admin_role])})
+ spec.append([CONF.object_storage.operator_role])
+ spec.append([CONF.object_storage.reseller_admin_role])
if CONF.service_available.heat:
- spec.append({'number': 1,
- 'prefix': 'stack_owner',
- 'roles': (CONF.auth.tempest_roles +
- [CONF.orchestration.stack_owner_role])})
- if opts.admin:
- spec.append({
- 'number': 1,
- 'prefix': 'admin',
- 'roles': (CONF.auth.tempest_roles +
- [CONF.identity.admin_role])
- })
- resources = {'tenants': [],
- 'users': []}
- for count in range(opts.concurrency):
- for user_group in spec:
- users = [random_user_name(opts.tag, user_group['prefix'])
- for _ in range(user_group['number'])]
- for user in users:
- tenant = '-'.join((user, 'tenant'))
- resources['tenants'].append(tenant)
- resources['users'].append({
- 'tenant': tenant,
- 'name': user,
- 'pass': data_utils.rand_password(),
- 'prefix': user_group['prefix'],
- 'roles': user_group['roles']
- })
+ spec.append([CONF.orchestration.stack_owner_role])
+ if admin:
+ spec.append('admin')
+ resources = []
+ for cred_type in spec:
+ resources.append((cred_type, cred_provider.get_credentials(
+ credential_type=cred_type)))
return resources
-def dump_accounts(opts, resources):
+def dump_accounts(resources, identity_version, account_file):
accounts = []
- for user in resources['users']:
+ for resource in resources:
+ cred_type, test_resource = resource
account = {
- 'username': user['name'],
- 'tenant_name': user['tenant'],
- 'password': user['pass'],
- 'roles': user['roles']
+ 'username': test_resource.username,
+ 'password': test_resource.password
}
- if 'network' in user or 'router' in user:
+ if identity_version == 3:
+ account['project_name'] = test_resource.project_name
+ account['domain_name'] = test_resource.domain_name
+ else:
+ account['project_name'] = test_resource.tenant_name
+
+ # If the spec includes 'admin' credentials are defined via type,
+ # else they are defined via list of roles.
+ if cred_type == 'admin':
+ account['types'] = [cred_type]
+ elif cred_type not in ['primary', 'alt']:
+ account['roles'] = cred_type
+
+ if test_resource.network:
account['resources'] = {}
- if 'network' in user:
- account['resources']['network'] = user['network']
- if 'router' in user:
- account['resources']['router'] = user['router']
+ if test_resource.network:
+ account['resources']['network'] = test_resource.network['name']
accounts.append(account)
- if os.path.exists(opts.accounts):
- os.rename(opts.accounts, '.'.join((opts.accounts, 'bak')))
- with open(opts.accounts, 'w') as f:
- yaml.dump(accounts, f, default_flow_style=False)
- LOG.info('%s generated successfully!' % opts.accounts)
+ if os.path.exists(account_file):
+ os.rename(account_file, '.'.join((account_file, 'bak')))
+ with open(account_file, 'w') as f:
+ yaml.safe_dump(accounts, f, default_flow_style=False)
+ LOG.info('%s generated successfully!' % account_file)
def _parser_add_args(parser):
@@ -420,10 +214,18 @@
metavar='<auth-password>',
default=os.environ.get('OS_PASSWORD'),
help='Defaults to env[OS_PASSWORD].')
+ parser.add_argument('--os-project-name',
+ metavar='<auth-project-name>',
+ default=os.environ.get('OS_PROJECT_NAME'),
+ help='Defaults to env[OS_PROJECT_NAME].')
parser.add_argument('--os-tenant-name',
metavar='<auth-tenant-name>',
default=os.environ.get('OS_TENANT_NAME'),
help='Defaults to env[OS_TENANT_NAME].')
+ parser.add_argument('--os-domain-name',
+ metavar='<auth-domain-name>',
+ default=os.environ.get('OS_DOMAIN_NAME'),
+ help='Defaults to env[OS_DOMAIN_NAME].')
parser.add_argument('--tag',
default='',
required=False,
@@ -439,6 +241,13 @@
action='store_true',
dest='admin',
help='Creates admin for each concurrent group')
+ parser.add_argument('-i', '--identity-version',
+ default=3,
+ choices=[2, 3],
+ type=int,
+ required=False,
+ dest='identity_version',
+ help='Version of the Identity API to use')
parser.add_argument('accounts',
metavar='accounts_file.yaml',
help='Output accounts yaml file')
@@ -487,9 +296,16 @@
opts = get_options()
if opts.config_file:
config.CONF.set_config_path(opts.config_file)
- resources = generate_resources(opts)
- create_resources(opts, resources)
- dump_accounts(opts, resources)
+ if opts.os_tenant_name:
+ LOG.warning("'os-tenant-name' and 'OS_TENANT_NAME' are both "
+ "deprecated, please use 'os-project-name' or "
+ "'OS_PROJECT_NAME' instead")
+ resources = []
+ for count in range(opts.concurrency):
+ # Use N different cred_providers to obtain different sets of creds
+ cred_provider = get_credential_provider(opts)
+ resources.extend(generate_resources(cred_provider, opts.admin))
+ dump_accounts(resources, opts.identity_version, opts.accounts)
if __name__ == "__main__":
main()
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index f2a69c7..6a65fcb 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -128,13 +128,13 @@
from tempest.lib.services.compute import servers_client
from tempest.lib.services.network import networks_client
from tempest.lib.services.network import ports_client
+from tempest.lib.services.network import routers_client
from tempest.lib.services.network import subnets_client
from tempest.services.identity.v2.json import identity_client
from tempest.services.identity.v2.json import roles_client
from tempest.services.identity.v2.json import tenants_client
from tempest.services.identity.v2.json import users_client
from tempest.services.image.v2.json import images_client
-from tempest.services.network.json import routers_client
from tempest.services.object_storage import container_client
from tempest.services.object_storage import object_client
from tempest.services.volume.v1.json import volumes_client
diff --git a/tempest/common/cred_client.py b/tempest/common/cred_client.py
index b23bc6f..aac036b 100644
--- a/tempest/common/cred_client.py
+++ b/tempest/common/cred_client.py
@@ -155,6 +155,9 @@
def get_credentials(self, user, project, password):
# User, project and domain already include both ID and name here,
# so there's no need to use the fill_in mode.
+ # NOTE(andreaf) We need to set all fields in the returned credentials.
+ # Scope is then used to pick only those relevant for the type of
+ # token needed by each service client.
return auth.get_credentials(
auth_url=None,
fill_in=False,
@@ -163,7 +166,9 @@
project_name=project['name'], project_id=project['id'],
password=password,
project_domain_id=self.creds_domain['id'],
- project_domain_name=self.creds_domain['name'])
+ project_domain_name=self.creds_domain['name'],
+ domain_id=self.creds_domain['id'],
+ domain_name=self.creds_domain['name'])
def _assign_user_role(self, project, user, role):
self.roles_client.assign_user_role_on_project(project['id'],
diff --git a/tempest/common/credentials_factory.py b/tempest/common/credentials_factory.py
index 286e01f..4873fcf 100644
--- a/tempest/common/credentials_factory.py
+++ b/tempest/common/credentials_factory.py
@@ -39,19 +39,19 @@
# Subset of the parameters of credential providers that depend on configuration
-def _get_common_provider_params():
+def get_common_provider_params():
return {
'credentials_domain': CONF.auth.default_credentials_domain_name,
'admin_role': CONF.identity.admin_role
}
-def _get_dynamic_provider_params():
- return _get_common_provider_params()
+def get_dynamic_provider_params():
+ return get_common_provider_params()
-def _get_preprov_provider_params():
- _common_params = _get_common_provider_params()
+def get_preprov_provider_params():
+ _common_params = get_common_provider_params()
reseller_admin_role = CONF.object_storage.reseller_admin_role
return dict(_common_params, **dict([
('accounts_lock_dir', lockutils.get_lock_path(CONF)),
@@ -80,13 +80,13 @@
network_resources=network_resources,
identity_version=identity_version,
admin_creds=admin_creds,
- **_get_dynamic_provider_params())
+ **get_dynamic_provider_params())
else:
if CONF.auth.test_accounts_file:
# Most params are not relevant for pre-created accounts
return preprov_creds.PreProvisionedCredentialProvider(
name=name, identity_version=identity_version,
- **_get_preprov_provider_params())
+ **get_preprov_provider_params())
else:
raise exceptions.InvalidConfiguration(
'A valid credential provider is needed')
@@ -106,7 +106,7 @@
elif CONF.auth.test_accounts_file:
check_accounts = preprov_creds.PreProvisionedCredentialProvider(
identity_version=identity_version, name='check_admin',
- **_get_preprov_provider_params())
+ **get_preprov_provider_params())
if not check_accounts.admin_available():
is_admin = False
else:
@@ -131,7 +131,7 @@
if CONF.auth.test_accounts_file:
check_accounts = preprov_creds.PreProvisionedCredentialProvider(
identity_version=identity_version, name='check_alt',
- **_get_preprov_provider_params())
+ **get_preprov_provider_params())
else:
raise exceptions.InvalidConfiguration(
'A valid credential provider is needed')
diff --git a/tempest/hacking/ignored_list_T110.txt b/tempest/hacking/ignored_list_T110.txt
index 4ef9012..be875ee 100644
--- a/tempest/hacking/ignored_list_T110.txt
+++ b/tempest/hacking/ignored_list_T110.txt
@@ -2,4 +2,3 @@
./tempest/services/volume/base/base_qos_client.py
./tempest/services/volume/base/base_backups_client.py
./tempest/services/baremetal/base.py
-./tempest/services/network/json/routers_client.py
diff --git a/tempest/services/network/json/routers_client.py b/tempest/lib/services/network/routers_client.py
similarity index 100%
rename from tempest/services/network/json/routers_client.py
rename to tempest/lib/services/network/routers_client.py
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 8d0f2f6..1dfa86d 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -50,8 +50,15 @@
cls.compute_floating_ips_client = (
cls.manager.compute_floating_ips_client)
if CONF.service_available.glance:
- # Glance image client v1
- cls.image_client = cls.manager.image_client
+ # Check if glance v1 is available to determine which client to use.
+ if CONF.image_feature_enabled.api_v1:
+ cls.image_client = cls.manager.image_client
+ elif CONF.image_feature_enabled.api_v2:
+ cls.image_client = cls.manager.image_client_v2
+ else:
+ raise exceptions.InvalidConfiguration(
+ 'Either api_v1 or api_v2 must be True in '
+ '[image-feature-enabled].')
# Compute image client
cls.compute_images_client = cls.manager.compute_images_client
cls.keypairs_client = cls.manager.keypairs_client
@@ -376,14 +383,23 @@
'name': name,
'container_format': fmt,
'disk_format': disk_format or fmt,
- 'is_public': 'False',
}
- params['properties'] = properties
- image = self.image_client.create_image(**params)['image']
+ if CONF.image_feature_enabled.api_v1:
+ params['is_public'] = 'False'
+ params['properties'] = properties
+ else:
+ params['visibility'] = 'private'
+ # Additional properties are flattened out in the v2 API.
+ params.update(properties)
+ body = self.image_client.create_image(**params)
+ image = body['image'] if 'image' in body else body
self.addCleanup(self.image_client.delete_image, image['id'])
self.assertEqual("queued", image['status'])
with open(path, 'rb') as image_file:
- self.image_client.update_image(image['id'], data=image_file)
+ if CONF.image_feature_enabled.api_v1:
+ self.image_client.update_image(image['id'], data=image_file)
+ else:
+ self.image_client.store_image_file(image['id'], image_file)
return image['id']
def glance_image_create(self):
@@ -394,7 +410,7 @@
img_container_format = CONF.scenario.img_container_format
img_disk_format = CONF.scenario.img_disk_format
img_properties = CONF.scenario.img_properties
- LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
+ LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
"properties: %s, ami: %s, ari: %s, aki: %s" %
(img_path, img_container_format, img_disk_format,
img_properties, ami_img_path, ari_img_path, aki_img_path))
@@ -450,9 +466,16 @@
thing_id=image_id, thing_id_param='id',
cleanup_callable=test_utils.call_and_ignore_notfound_exc,
cleanup_args=[_image_client.delete_image, image_id])
- snapshot_image = _image_client.check_image(image_id)
+ if CONF.image_feature_enabled.api_v1:
+ # In glance v1 the additional properties are stored in the headers.
+ snapshot_image = _image_client.check_image(image_id)
+ image_props = snapshot_image.get('properties', {})
+ else:
+ # In glance v2 the additional properties are flattened.
+ snapshot_image = _image_client.show_image(image_id)
+ image_props = snapshot_image
- bdm = snapshot_image.get('properties', {}).get('block_device_mapping')
+ bdm = image_props.get('block_device_mapping')
if bdm:
bdm = json.loads(bdm)
if bdm and 'snapshot_id' in bdm[0]:
diff --git a/tempest/services/image/v1/json/images_client.py b/tempest/services/image/v1/json/images_client.py
index 922b626..4ffaf3b 100644
--- a/tempest/services/image/v1/json/images_client.py
+++ b/tempest/services/image/v1/json/images_client.py
@@ -14,9 +14,7 @@
# under the License.
import copy
-import errno
import functools
-import os
from oslo_log import log as logging
from oslo_serialization import jsonutils as json
@@ -31,10 +29,7 @@
class ImagesClient(rest_client.RestClient):
-
- def __init__(self, auth_provider, catalog_type, region, **kwargs):
- super(ImagesClient, self).__init__(
- auth_provider, catalog_type, region, **kwargs)
+ api_version = "v1"
def _image_meta_from_headers(self, headers):
meta = {'properties': {}}
@@ -72,43 +67,14 @@
headers['x-image-meta-%s' % key] = str(value)
return headers
- def _get_file_size(self, obj):
- """Analyze file-like object and attempt to determine its size.
-
- :param obj: file-like object, typically redirected from stdin.
- :retval The file's size or None if it cannot be determined.
- """
- # For large images, we need to supply the size of the
- # image file. See LP Bugs #827660 and #845788.
- if hasattr(obj, 'seek') and hasattr(obj, 'tell'):
- try:
- obj.seek(0, os.SEEK_END)
- obj_size = obj.tell()
- obj.seek(0)
- return obj_size
- except IOError as e:
- if e.errno == errno.ESPIPE:
- # Illegal seek. This means the user is trying
- # to pipe image data to the client, e.g.
- # echo testdata | bin/glance add blah..., or
- # that stdin is empty, or that a file-like
- # object which doesn't support 'seek/tell' has
- # been supplied.
- return None
- else:
- raise
- else:
- # Cannot determine size of input image
- return None
-
def _create_with_data(self, headers, data):
# We are going to do chunked transfert, so split the input data
# info fixed-sized chunks.
headers['Content-Type'] = 'application/octet-stream'
data = iter(functools.partial(data.read, CHUNKSIZE), b'')
- resp, body = self.request('POST', '/v1/images',
+ resp, body = self.request('POST', 'images',
headers=headers, body=data, chunked=True)
- self._error_checker('POST', '/v1/images', headers, data, resp,
+ self._error_checker('POST', 'images', headers, data, resp,
body)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -118,7 +84,7 @@
# info fixed-sized chunks.
headers['Content-Type'] = 'application/octet-stream'
data = iter(functools.partial(data.read, CHUNKSIZE), b'')
- url = '/v1/images/%s' % image_id
+ url = 'images/%s' % image_id
resp, body = self.request('PUT', url, headers=headers,
body=data, chunked=True)
self._error_checker('PUT', url, headers, data,
@@ -140,7 +106,7 @@
if data is not None:
return self._create_with_data(headers, data)
- resp, body = self.post('v1/images', None, headers)
+ resp, body = self.post('images', None, headers)
self.expected_success(201, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -153,14 +119,14 @@
if data is not None:
return self._update_with_data(image_id, headers, data)
- url = 'v1/images/%s' % image_id
+ url = 'images/%s' % image_id
resp, body = self.put(url, None, headers)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def delete_image(self, image_id):
- url = 'v1/images/%s' % image_id
+ url = 'images/%s' % image_id
resp, body = self.delete(url)
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
@@ -175,7 +141,7 @@
any changes.
:param changes_since: The name is changed to changes-since
"""
- url = 'v1/images'
+ url = 'images'
if detail:
url += '/detail'
@@ -197,7 +163,7 @@
def check_image(self, image_id):
"""Check image metadata."""
- url = 'v1/images/%s' % image_id
+ url = 'images/%s' % image_id
resp, __ = self.head(url)
self.expected_success(200, resp.status)
body = self._image_meta_from_headers(resp)
@@ -205,7 +171,7 @@
def show_image(self, image_id):
"""Get image details plus the image itself."""
- url = 'v1/images/%s' % image_id
+ url = 'images/%s' % image_id
resp, body = self.get(url)
self.expected_success(200, resp.status)
return rest_client.ResponseBodyData(resp, body)
@@ -222,36 +188,3 @@
def resource_type(self):
"""Returns the primary type of resource this client works with."""
return 'image_meta'
-
- def list_image_members(self, image_id):
- url = 'v1/images/%s/members' % image_id
- resp, body = self.get(url)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return rest_client.ResponseBody(resp, body)
-
- def list_shared_images(self, tenant_id):
- """List shared images with the specified tenant"""
- url = 'v1/shared-images/%s' % tenant_id
- resp, body = self.get(url)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return rest_client.ResponseBody(resp, body)
-
- def add_member(self, member_id, image_id, **kwargs):
- """Add a member to an image.
-
- Available params: see http://developer.openstack.org/
- api-ref-image-v1.html#addMember-v1
- """
- url = 'v1/images/%s/members/%s' % (image_id, member_id)
- body = json.dumps({'member': kwargs})
- resp, __ = self.put(url, body)
- self.expected_success(204, resp.status)
- return rest_client.ResponseBody(resp)
-
- def delete_member(self, member_id, image_id):
- url = 'v1/images/%s/members/%s' % (image_id, member_id)
- resp, __ = self.delete(url)
- self.expected_success(204, resp.status)
- return rest_client.ResponseBody(resp)
diff --git a/tempest/services/image/v1/json/members_client.py b/tempest/services/image/v1/json/members_client.py
new file mode 100644
index 0000000..95cee1c
--- /dev/null
+++ b/tempest/services/image/v1/json/members_client.py
@@ -0,0 +1,63 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class MembersClient(rest_client.RestClient):
+ api_version = "v1"
+
+ def list_image_members(self, image_id):
+ """List all members of an image."""
+ url = 'images/%s/members' % image_id
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def list_shared_images(self, tenant_id):
+ """List image memberships for the given tenant.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-image-v1.html#listSharedImages-v1
+ """
+
+ url = 'shared-images/%s' % tenant_id
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def add_member(self, member_id, image_id, **kwargs):
+ """Add a member to an image.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-image-v1.html#addMember-v1
+ """
+ url = 'images/%s/members/%s' % (image_id, member_id)
+ body = json.dumps({'member': kwargs})
+ resp, __ = self.put(url, body)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp)
+
+ def delete_member(self, member_id, image_id):
+ """Removes a membership from the image.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-image-v1.html#removeMember-v1
+ """
+ url = 'images/%s/members/%s' % (image_id, member_id)
+ resp, __ = self.delete(url)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp)
diff --git a/tempest/services/image/v2/json/images_client.py b/tempest/services/image/v2/json/images_client.py
index 88eafe1..aae1cd0 100644
--- a/tempest/services/image/v2/json/images_client.py
+++ b/tempest/services/image/v2/json/images_client.py
@@ -25,10 +25,7 @@
class ImagesClient(rest_client.RestClient):
-
- def __init__(self, auth_provider, catalog_type, region, **kwargs):
- super(ImagesClient, self).__init__(
- auth_provider, catalog_type, region, **kwargs)
+ api_version = "v2"
def update_image(self, image_id, patch):
"""Update an image.
@@ -39,7 +36,7 @@
data = json.dumps(patch)
headers = {"Content-Type": "application/openstack-images-v2.0"
"-json-patch"}
- resp, body = self.patch('v2/images/%s' % image_id, data, headers)
+ resp, body = self.patch('images/%s' % image_id, data, headers)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -51,31 +48,31 @@
api-ref-image-v2.html#createImage-v2
"""
data = json.dumps(kwargs)
- resp, body = self.post('v2/images', data)
+ resp, body = self.post('images', data)
self.expected_success(201, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def deactivate_image(self, image_id):
- url = 'v2/images/%s/actions/deactivate' % image_id
+ url = 'images/%s/actions/deactivate' % image_id
resp, body = self.post(url, None)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
def reactivate_image(self, image_id):
- url = 'v2/images/%s/actions/reactivate' % image_id
+ url = 'images/%s/actions/reactivate' % image_id
resp, body = self.post(url, None)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
def delete_image(self, image_id):
- url = 'v2/images/%s' % image_id
+ url = 'images/%s' % image_id
resp, _ = self.delete(url)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp)
def list_images(self, params=None):
- url = 'v2/images'
+ url = 'images'
if params:
url += '?%s' % urllib.urlencode(params)
@@ -86,7 +83,7 @@
return rest_client.ResponseBody(resp, body)
def show_image(self, image_id):
- url = 'v2/images/%s' % image_id
+ url = 'images/%s' % image_id
resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
@@ -105,7 +102,7 @@
return 'image'
def store_image_file(self, image_id, data):
- url = 'v2/images/%s/file' % image_id
+ url = 'images/%s/file' % image_id
# We are going to do chunked transfert, so split the input data
# info fixed-sized chunks.
@@ -118,120 +115,26 @@
return rest_client.ResponseBody(resp, body)
def show_image_file(self, image_id):
- url = 'v2/images/%s/file' % image_id
+ url = 'images/%s/file' % image_id
resp, body = self.get(url)
self.expected_success(200, resp.status)
return rest_client.ResponseBodyData(resp, body)
def add_image_tag(self, image_id, tag):
- url = 'v2/images/%s/tags/%s' % (image_id, tag)
+ url = 'images/%s/tags/%s' % (image_id, tag)
resp, body = self.put(url, body=None)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
def delete_image_tag(self, image_id, tag):
- url = 'v2/images/%s/tags/%s' % (image_id, tag)
+ url = 'images/%s/tags/%s' % (image_id, tag)
resp, _ = self.delete(url)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp)
- def list_image_members(self, image_id):
- url = 'v2/images/%s/members' % image_id
- resp, body = self.get(url)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return rest_client.ResponseBody(resp, body)
-
- def create_image_member(self, image_id, **kwargs):
- """Create an image member.
-
- Available params: see http://developer.openstack.org/
- api-ref-image-v2.html#createImageMember-v2
- """
- url = 'v2/images/%s/members' % image_id
- data = json.dumps(kwargs)
- resp, body = self.post(url, data)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return rest_client.ResponseBody(resp, body)
-
- def update_image_member(self, image_id, member_id, **kwargs):
- """Update an image member.
-
- Available params: see http://developer.openstack.org/
- api-ref-image-v2.html#updateImageMember-v2
- """
- url = 'v2/images/%s/members/%s' % (image_id, member_id)
- data = json.dumps(kwargs)
- resp, body = self.put(url, data)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return rest_client.ResponseBody(resp, body)
-
- def show_image_member(self, image_id, member_id):
- url = 'v2/images/%s/members/%s' % (image_id, member_id)
- resp, body = self.get(url)
- self.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, json.loads(body))
-
- def delete_image_member(self, image_id, member_id):
- url = 'v2/images/%s/members/%s' % (image_id, member_id)
- resp, _ = self.delete(url)
- self.expected_success(204, resp.status)
- return rest_client.ResponseBody(resp)
-
- def show_schema(self, schema):
- url = 'v2/schemas/%s' % schema
- resp, body = self.get(url)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return rest_client.ResponseBody(resp, body)
-
def list_resource_types(self):
- url = '/v2/metadefs/resource_types'
+ url = 'metadefs/resource_types'
resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
-
- def create_namespace(self, **kwargs):
- """Create a namespace.
-
- Available params: see http://developer.openstack.org/
- api-ref-image-v2.html#createNamespace-v2
- """
- data = json.dumps(kwargs)
- resp, body = self.post('/v2/metadefs/namespaces', data)
- self.expected_success(201, resp.status)
- body = json.loads(body)
- return rest_client.ResponseBody(resp, body)
-
- def show_namespace(self, namespace):
- url = '/v2/metadefs/namespaces/%s' % namespace
- resp, body = self.get(url)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return rest_client.ResponseBody(resp, body)
-
- def update_namespace(self, namespace, **kwargs):
- """Update a namespace.
-
- Available params: see http://developer.openstack.org/
- api-ref-image-v2.html#updateNamespace-v2
- """
- # NOTE: On Glance API, we need to pass namespace on both URI
- # and a request body.
- params = {'namespace': namespace}
- params.update(kwargs)
- data = json.dumps(params)
- url = '/v2/metadefs/namespaces/%s' % namespace
- resp, body = self.put(url, body=data)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return rest_client.ResponseBody(resp, body)
-
- def delete_namespace(self, namespace):
- url = '/v2/metadefs/namespaces/%s' % namespace
- resp, _ = self.delete(url)
- self.expected_success(204, resp.status)
- return rest_client.ResponseBody(resp)
diff --git a/tempest/services/image/v2/json/members_client.py b/tempest/services/image/v2/json/members_client.py
new file mode 100644
index 0000000..233a6ec
--- /dev/null
+++ b/tempest/services/image/v2/json/members_client.py
@@ -0,0 +1,64 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class MembersClient(rest_client.RestClient):
+ api_version = "v2"
+
+ def list_image_members(self, image_id):
+ url = 'images/%s/members' % image_id
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def create_image_member(self, image_id, **kwargs):
+ """Create an image member.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-image-v2.html#createImageMember-v2
+ """
+ url = 'images/%s/members' % image_id
+ data = json.dumps(kwargs)
+ resp, body = self.post(url, data)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def update_image_member(self, image_id, member_id, **kwargs):
+ """Update an image member.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-image-v2.html#updateImageMember-v2
+ """
+ url = 'images/%s/members/%s' % (image_id, member_id)
+ data = json.dumps(kwargs)
+ resp, body = self.put(url, data)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def show_image_member(self, image_id, member_id):
+ url = 'images/%s/members/%s' % (image_id, member_id)
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, json.loads(body))
+
+ def delete_image_member(self, image_id, member_id):
+ url = 'images/%s/members/%s' % (image_id, member_id)
+ resp, _ = self.delete(url)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp)
diff --git a/tempest/services/image/v2/json/namespaces_client.py b/tempest/services/image/v2/json/namespaces_client.py
new file mode 100644
index 0000000..97400e1
--- /dev/null
+++ b/tempest/services/image/v2/json/namespaces_client.py
@@ -0,0 +1,64 @@
+# Copyright 2013 IBM Corp.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class NamespacesClient(rest_client.RestClient):
+ api_version = "v2"
+
+ def create_namespace(self, **kwargs):
+ """Create a namespace.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-image-v2.html#createNamespace-v2
+ """
+ data = json.dumps(kwargs)
+ resp, body = self.post('metadefs/namespaces', data)
+ self.expected_success(201, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def show_namespace(self, namespace):
+ url = 'metadefs/namespaces/%s' % namespace
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def update_namespace(self, namespace, **kwargs):
+ """Update a namespace.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-image-v2.html#updateNamespace-v2
+ """
+ # NOTE: On Glance API, we need to pass namespace on both URI
+ # and a request body.
+ params = {'namespace': namespace}
+ params.update(kwargs)
+ data = json.dumps(params)
+ url = 'metadefs/namespaces/%s' % namespace
+ resp, body = self.put(url, body=data)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_namespace(self, namespace):
+ url = 'metadefs/namespaces/%s' % namespace
+ resp, _ = self.delete(url)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp)
diff --git a/tempest/services/image/v2/json/schemas_client.py b/tempest/services/image/v2/json/schemas_client.py
new file mode 100644
index 0000000..0c9db40
--- /dev/null
+++ b/tempest/services/image/v2/json/schemas_client.py
@@ -0,0 +1,29 @@
+# Copyright 2013 IBM Corp.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class SchemasClient(rest_client.RestClient):
+ api_version = "v2"
+
+ def show_schema(self, schema):
+ url = 'schemas/%s' % schema
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/network/json/__init__.py b/tempest/services/network/json/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/network/json/__init__.py
+++ /dev/null
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index f025418..a7a3a22 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -23,6 +23,7 @@
from tempest.lib.common import rest_client
from tempest.lib.services.identity.v2 import token_client as v2_token_client
from tempest.lib.services.identity.v3 import token_client as v3_token_client
+from tempest.lib.services.network import routers_client
from tempest.services.identity.v2.json import identity_client as v2_iden_client
from tempest.services.identity.v2.json import roles_client as v2_roles_client
from tempest.services.identity.v2.json import tenants_client as \
@@ -34,7 +35,6 @@
v3_projects_client
from tempest.services.identity.v3.json import roles_client as v3_roles_client
from tempest.services.identity.v3.json import users_clients as v3_users_client
-from tempest.services.network.json import routers_client
from tempest.tests import base
from tempest.tests import fake_config
from tempest.tests.lib import fake_http
@@ -333,7 +333,7 @@
self._mock_subnet_create(creds, '1234', 'fake_subnet')
self._mock_router_create('1234', 'fake_router')
router_interface_mock = self.patch(
- 'tempest.services.network.json.routers_client.RoutersClient.'
+ 'tempest.lib.services.network.routers_client.RoutersClient.'
'add_router_interface')
primary_creds = creds.get_primary_creds()
router_interface_mock.assert_called_once_with('1234', subnet_id='1234')
@@ -365,7 +365,7 @@
self._mock_subnet_create(creds, '1234', 'fake_subnet')
self._mock_router_create('1234', 'fake_router')
router_interface_mock = self.patch(
- 'tempest.services.network.json.routers_client.RoutersClient.'
+ 'tempest.lib.services.network.routers_client.RoutersClient.'
'add_router_interface')
creds.get_primary_creds()
router_interface_mock.assert_called_once_with('1234', subnet_id='1234')
@@ -397,7 +397,7 @@
router = mock.patch.object(creds.routers_admin_client, 'delete_router')
router_mock = router.start()
remove_router_interface_mock = self.patch(
- 'tempest.services.network.json.routers_client.RoutersClient.'
+ 'tempest.lib.services.network.routers_client.RoutersClient.'
'remove_router_interface')
return_values = ({'status': 200}, {'ports': []})
port_list_mock = mock.patch.object(creds.ports_admin_client,
@@ -468,7 +468,7 @@
self._mock_subnet_create(creds, '1234', 'fake_alt_subnet')
self._mock_router_create('1234', 'fake_alt_router')
router_interface_mock = self.patch(
- 'tempest.services.network.json.routers_client.RoutersClient.'
+ 'tempest.lib.services.network.routers_client.RoutersClient.'
'add_router_interface')
alt_creds = creds.get_alt_creds()
router_interface_mock.assert_called_once_with('1234', subnet_id='1234')
@@ -492,7 +492,7 @@
self._mock_subnet_create(creds, '1234', 'fake_admin_subnet')
self._mock_router_create('1234', 'fake_admin_router')
router_interface_mock = self.patch(
- 'tempest.services.network.json.routers_client.RoutersClient.'
+ 'tempest.lib.services.network.routers_client.RoutersClient.'
'add_router_interface')
self._mock_list_roles('123456', 'admin')
admin_creds = creds.get_admin_creds()
diff --git a/tempest/tests/lib/services/compute/base.py b/tempest/tests/lib/services/base.py
similarity index 97%
rename from tempest/tests/lib/services/compute/base.py
rename to tempest/tests/lib/services/base.py
index e77b436..a244aa2 100644
--- a/tempest/tests/lib/services/compute/base.py
+++ b/tempest/tests/lib/services/base.py
@@ -19,7 +19,7 @@
from tempest.tests.lib import fake_http
-class BaseComputeServiceTest(base.TestCase):
+class BaseServiceTest(base.TestCase):
def create_response(self, body, to_utf=False, status=200, headers=None):
json_body = {}
if body:
diff --git a/tempest/tests/lib/services/compute/test_agents_client.py b/tempest/tests/lib/services/compute/test_agents_client.py
index 3c5043d..880220e 100644
--- a/tempest/tests/lib/services/compute/test_agents_client.py
+++ b/tempest/tests/lib/services/compute/test_agents_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import agents_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestAgentsClient(base.BaseComputeServiceTest):
+class TestAgentsClient(base.BaseServiceTest):
FAKE_CREATE_AGENT = {
"agent": {
"url": "http://foo.com",
diff --git a/tempest/tests/lib/services/compute/test_aggregates_client.py b/tempest/tests/lib/services/compute/test_aggregates_client.py
index a63380e..674d92a 100644
--- a/tempest/tests/lib/services/compute/test_aggregates_client.py
+++ b/tempest/tests/lib/services/compute/test_aggregates_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import aggregates_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestAggregatesClient(base.BaseComputeServiceTest):
+class TestAggregatesClient(base.BaseServiceTest):
FAKE_SHOW_AGGREGATE = {
"aggregate":
{
diff --git a/tempest/tests/lib/services/compute/test_availability_zone_client.py b/tempest/tests/lib/services/compute/test_availability_zone_client.py
index d16cf0a..6608592 100644
--- a/tempest/tests/lib/services/compute/test_availability_zone_client.py
+++ b/tempest/tests/lib/services/compute/test_availability_zone_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import availability_zone_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestAvailabilityZoneClient(base.BaseComputeServiceTest):
+class TestAvailabilityZoneClient(base.BaseServiceTest):
FAKE_AVAILABIRITY_ZONE_INFO = {
"availabilityZoneInfo":
diff --git a/tempest/tests/lib/services/compute/test_baremetal_nodes_client.py b/tempest/tests/lib/services/compute/test_baremetal_nodes_client.py
index a867c06..81c54b5 100644
--- a/tempest/tests/lib/services/compute/test_baremetal_nodes_client.py
+++ b/tempest/tests/lib/services/compute/test_baremetal_nodes_client.py
@@ -16,10 +16,10 @@
from tempest.lib.services.compute import baremetal_nodes_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestBareMetalNodesClient(base.BaseComputeServiceTest):
+class TestBareMetalNodesClient(base.BaseServiceTest):
FAKE_NODE_INFO = {'cpus': '8',
'disk_gb': '64',
diff --git a/tempest/tests/lib/services/compute/test_base_compute_client.py b/tempest/tests/lib/services/compute/test_base_compute_client.py
index 49d29b3..69e8542 100644
--- a/tempest/tests/lib/services/compute/test_base_compute_client.py
+++ b/tempest/tests/lib/services/compute/test_base_compute_client.py
@@ -19,10 +19,10 @@
from tempest.lib.services.compute import base_compute_client
from tempest.tests.lib import fake_auth_provider
from tempest.tests.lib import fake_http
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestMicroversionHeaderCheck(base.BaseComputeServiceTest):
+class TestMicroversionHeaderCheck(base.BaseServiceTest):
def setUp(self):
super(TestMicroversionHeaderCheck, self).setUp()
@@ -72,7 +72,7 @@
return self.get_schema(self.schema_versions_info)
-class TestSchemaVersionsNone(base.BaseComputeServiceTest):
+class TestSchemaVersionsNone(base.BaseServiceTest):
api_microversion = None
expected_schema = 'schemav21'
@@ -130,7 +130,7 @@
return self.get_schema(self.schema_versions_info)
-class TestSchemaVersionsNotFound(base.BaseComputeServiceTest):
+class TestSchemaVersionsNotFound(base.BaseServiceTest):
api_microversion = '2.10'
expected_schema = 'schemav210'
@@ -149,7 +149,7 @@
self.client.return_selected_schema)
-class TestClientWithoutMicroversionHeader(base.BaseComputeServiceTest):
+class TestClientWithoutMicroversionHeader(base.BaseServiceTest):
def setUp(self):
super(TestClientWithoutMicroversionHeader, self).setUp()
@@ -172,7 +172,7 @@
self.client.get('fake_url')
-class TestClientWithMicroversionHeader(base.BaseComputeServiceTest):
+class TestClientWithMicroversionHeader(base.BaseServiceTest):
def setUp(self):
super(TestClientWithMicroversionHeader, self).setUp()
diff --git a/tempest/tests/lib/services/compute/test_certificates_client.py b/tempest/tests/lib/services/compute/test_certificates_client.py
index e8123bb..9faef6f 100644
--- a/tempest/tests/lib/services/compute/test_certificates_client.py
+++ b/tempest/tests/lib/services/compute/test_certificates_client.py
@@ -16,10 +16,10 @@
from tempest.lib.services.compute import certificates_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestCertificatesClient(base.BaseComputeServiceTest):
+class TestCertificatesClient(base.BaseServiceTest):
FAKE_CERTIFICATE = {
"certificate": {
diff --git a/tempest/tests/lib/services/compute/test_extensions_client.py b/tempest/tests/lib/services/compute/test_extensions_client.py
index 7415988..d7e217e 100644
--- a/tempest/tests/lib/services/compute/test_extensions_client.py
+++ b/tempest/tests/lib/services/compute/test_extensions_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import extensions_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestExtensionsClient(base.BaseComputeServiceTest):
+class TestExtensionsClient(base.BaseServiceTest):
FAKE_SHOW_EXTENSION = {
"extension": {
diff --git a/tempest/tests/lib/services/compute/test_fixedIPs_client.py b/tempest/tests/lib/services/compute/test_fixedIPs_client.py
index 6999f24..65bda45 100644
--- a/tempest/tests/lib/services/compute/test_fixedIPs_client.py
+++ b/tempest/tests/lib/services/compute/test_fixedIPs_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import fixed_ips_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestFixedIPsClient(base.BaseComputeServiceTest):
+class TestFixedIPsClient(base.BaseServiceTest):
FIXED_IP_INFO = {"fixed_ip": {"address": "10.0.0.1",
"cidr": "10.11.12.0/24",
"host": "localhost",
diff --git a/tempest/tests/lib/services/compute/test_flavors_client.py b/tempest/tests/lib/services/compute/test_flavors_client.py
index e22b4fe..445ee22 100644
--- a/tempest/tests/lib/services/compute/test_flavors_client.py
+++ b/tempest/tests/lib/services/compute/test_flavors_client.py
@@ -20,10 +20,10 @@
from tempest.lib.services.compute import flavors_client
from tempest.tests.lib import fake_auth_provider
from tempest.tests.lib import fake_http
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestFlavorsClient(base.BaseComputeServiceTest):
+class TestFlavorsClient(base.BaseServiceTest):
FAKE_FLAVOR = {
"disk": 1,
diff --git a/tempest/tests/lib/services/compute/test_floating_ip_pools_client.py b/tempest/tests/lib/services/compute/test_floating_ip_pools_client.py
index f30719e..b0c00f0 100644
--- a/tempest/tests/lib/services/compute/test_floating_ip_pools_client.py
+++ b/tempest/tests/lib/services/compute/test_floating_ip_pools_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import floating_ip_pools_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestFloatingIPPoolsClient(base.BaseComputeServiceTest):
+class TestFloatingIPPoolsClient(base.BaseServiceTest):
FAKE_FLOATING_IP_POOLS = {
"floating_ip_pools":
diff --git a/tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py b/tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py
index c16c985..ace76f8 100644
--- a/tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py
+++ b/tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py
@@ -15,10 +15,10 @@
from tempest.tests.lib import fake_auth_provider
from tempest.lib.services.compute import floating_ips_bulk_client
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestFloatingIPsBulkClient(base.BaseComputeServiceTest):
+class TestFloatingIPsBulkClient(base.BaseServiceTest):
FAKE_FIP_BULK_LIST = {"floating_ip_info": [{
"address": "10.10.10.1",
diff --git a/tempest/tests/lib/services/compute/test_floating_ips_client.py b/tempest/tests/lib/services/compute/test_floating_ips_client.py
index 3844ba8..92737f2 100644
--- a/tempest/tests/lib/services/compute/test_floating_ips_client.py
+++ b/tempest/tests/lib/services/compute/test_floating_ips_client.py
@@ -17,10 +17,10 @@
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import floating_ips_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestFloatingIpsClient(base.BaseComputeServiceTest):
+class TestFloatingIpsClient(base.BaseServiceTest):
floating_ip = {"fixed_ip": None,
"id": "46d61064-13ba-4bf0-9557-69de824c3d6f",
diff --git a/tempest/tests/lib/services/compute/test_hosts_client.py b/tempest/tests/lib/services/compute/test_hosts_client.py
index d9ff513..78537c2 100644
--- a/tempest/tests/lib/services/compute/test_hosts_client.py
+++ b/tempest/tests/lib/services/compute/test_hosts_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import hosts_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestHostsClient(base.BaseComputeServiceTest):
+class TestHostsClient(base.BaseServiceTest):
FAKE_HOST_DATA = {
"host": {
"resource": {
diff --git a/tempest/tests/lib/services/compute/test_hypervisor_client.py b/tempest/tests/lib/services/compute/test_hypervisor_client.py
index fab34da..89eb698 100644
--- a/tempest/tests/lib/services/compute/test_hypervisor_client.py
+++ b/tempest/tests/lib/services/compute/test_hypervisor_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import hypervisor_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestHypervisorClient(base.BaseComputeServiceTest):
+class TestHypervisorClient(base.BaseServiceTest):
hypervisor_id = "1"
hypervisor_name = "hyper.hostname.com"
diff --git a/tempest/tests/lib/services/compute/test_images_client.py b/tempest/tests/lib/services/compute/test_images_client.py
index 3ebc27f..a9a570d 100644
--- a/tempest/tests/lib/services/compute/test_images_client.py
+++ b/tempest/tests/lib/services/compute/test_images_client.py
@@ -19,10 +19,10 @@
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import images_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestImagesClient(base.BaseComputeServiceTest):
+class TestImagesClient(base.BaseServiceTest):
# Data Dictionaries used for testing #
FAKE_IMAGE_METADATA = {
"list":
diff --git a/tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py b/tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py
index e8c22f1..21764ff 100644
--- a/tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py
+++ b/tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py
@@ -16,10 +16,10 @@
from tempest.lib.services.compute import instance_usage_audit_log_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestInstanceUsagesAuditLogClient(base.BaseComputeServiceTest):
+class TestInstanceUsagesAuditLogClient(base.BaseServiceTest):
FAKE_AUDIT_LOG = {
"hosts_not_run": [
diff --git a/tempest/tests/lib/services/compute/test_interfaces_client.py b/tempest/tests/lib/services/compute/test_interfaces_client.py
index de8e268..4d78103 100644
--- a/tempest/tests/lib/services/compute/test_interfaces_client.py
+++ b/tempest/tests/lib/services/compute/test_interfaces_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import interfaces_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestInterfacesClient(base.BaseComputeServiceTest):
+class TestInterfacesClient(base.BaseServiceTest):
# Data Values to be used for testing #
FAKE_INTERFACE_DATA = {
"fixed_ips": [{
diff --git a/tempest/tests/lib/services/compute/test_keypairs_client.py b/tempest/tests/lib/services/compute/test_keypairs_client.py
index 7c595ca..ed3b9dd 100644
--- a/tempest/tests/lib/services/compute/test_keypairs_client.py
+++ b/tempest/tests/lib/services/compute/test_keypairs_client.py
@@ -16,10 +16,10 @@
from tempest.lib.services.compute import keypairs_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestKeyPairsClient(base.BaseComputeServiceTest):
+class TestKeyPairsClient(base.BaseServiceTest):
FAKE_KEYPAIR = {"keypair": {
"public_key": "ssh-rsa foo Generated-by-Nova",
diff --git a/tempest/tests/lib/services/compute/test_limits_client.py b/tempest/tests/lib/services/compute/test_limits_client.py
index d3f0aee..5f3fa5a 100644
--- a/tempest/tests/lib/services/compute/test_limits_client.py
+++ b/tempest/tests/lib/services/compute/test_limits_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import limits_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestLimitsClient(base.BaseComputeServiceTest):
+class TestLimitsClient(base.BaseServiceTest):
def setUp(self):
super(TestLimitsClient, self).setUp()
diff --git a/tempest/tests/lib/services/compute/test_migrations_client.py b/tempest/tests/lib/services/compute/test_migrations_client.py
index 5b1578d..be62c0c 100644
--- a/tempest/tests/lib/services/compute/test_migrations_client.py
+++ b/tempest/tests/lib/services/compute/test_migrations_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import migrations_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestMigrationsClient(base.BaseComputeServiceTest):
+class TestMigrationsClient(base.BaseServiceTest):
FAKE_MIGRATION_INFO = {"migrations": [{
"created_at": "2012-10-29T13:42:02",
"dest_compute": "compute2",
diff --git a/tempest/tests/lib/services/compute/test_networks_client.py b/tempest/tests/lib/services/compute/test_networks_client.py
index 4f5c8b9..1908b57 100644
--- a/tempest/tests/lib/services/compute/test_networks_client.py
+++ b/tempest/tests/lib/services/compute/test_networks_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import networks_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestNetworksClient(base.BaseComputeServiceTest):
+class TestNetworksClient(base.BaseServiceTest):
FAKE_NETWORK = {
"bridge": None,
diff --git a/tempest/tests/lib/services/compute/test_quota_classes_client.py b/tempest/tests/lib/services/compute/test_quota_classes_client.py
index 4b67576..22d8b91 100644
--- a/tempest/tests/lib/services/compute/test_quota_classes_client.py
+++ b/tempest/tests/lib/services/compute/test_quota_classes_client.py
@@ -16,10 +16,10 @@
from tempest.lib.services.compute import quota_classes_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestQuotaClassesClient(base.BaseComputeServiceTest):
+class TestQuotaClassesClient(base.BaseServiceTest):
FAKE_QUOTA_CLASS_SET = {
"injected_file_content_bytes": 10240,
diff --git a/tempest/tests/lib/services/compute/test_quotas_client.py b/tempest/tests/lib/services/compute/test_quotas_client.py
index 9f5d1f6..4c49e8d 100644
--- a/tempest/tests/lib/services/compute/test_quotas_client.py
+++ b/tempest/tests/lib/services/compute/test_quotas_client.py
@@ -16,10 +16,10 @@
from tempest.lib.services.compute import quotas_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestQuotasClient(base.BaseComputeServiceTest):
+class TestQuotasClient(base.BaseServiceTest):
FAKE_QUOTA_SET = {
"quota_set": {
diff --git a/tempest/tests/lib/services/compute/test_security_group_default_rules_client.py b/tempest/tests/lib/services/compute/test_security_group_default_rules_client.py
index 581f7b1..86eee02 100644
--- a/tempest/tests/lib/services/compute/test_security_group_default_rules_client.py
+++ b/tempest/tests/lib/services/compute/test_security_group_default_rules_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import security_group_default_rules_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestSecurityGroupDefaultRulesClient(base.BaseComputeServiceTest):
+class TestSecurityGroupDefaultRulesClient(base.BaseServiceTest):
FAKE_RULE = {
"from_port": 80,
"id": 1,
diff --git a/tempest/tests/lib/services/compute/test_security_group_rules_client.py b/tempest/tests/lib/services/compute/test_security_group_rules_client.py
index 9a7c04d..2b0a94d 100644
--- a/tempest/tests/lib/services/compute/test_security_group_rules_client.py
+++ b/tempest/tests/lib/services/compute/test_security_group_rules_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import security_group_rules_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestSecurityGroupRulesClient(base.BaseComputeServiceTest):
+class TestSecurityGroupRulesClient(base.BaseServiceTest):
FAKE_SECURITY_GROUP_RULE = {
"security_group_rule": {
diff --git a/tempest/tests/lib/services/compute/test_security_groups_client.py b/tempest/tests/lib/services/compute/test_security_groups_client.py
index 6a11c29..d293a08 100644
--- a/tempest/tests/lib/services/compute/test_security_groups_client.py
+++ b/tempest/tests/lib/services/compute/test_security_groups_client.py
@@ -17,10 +17,10 @@
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import security_groups_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestSecurityGroupsClient(base.BaseComputeServiceTest):
+class TestSecurityGroupsClient(base.BaseServiceTest):
FAKE_SECURITY_GROUP_INFO = [{
"description": "default",
diff --git a/tempest/tests/lib/services/compute/test_server_groups_client.py b/tempest/tests/lib/services/compute/test_server_groups_client.py
index cb163a8..bf03b84 100644
--- a/tempest/tests/lib/services/compute/test_server_groups_client.py
+++ b/tempest/tests/lib/services/compute/test_server_groups_client.py
@@ -17,10 +17,10 @@
from tempest.lib.services.compute import server_groups_client
from tempest.tests.lib import fake_http
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestServerGroupsClient(base.BaseComputeServiceTest):
+class TestServerGroupsClient(base.BaseServiceTest):
server_group = {
"id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9",
diff --git a/tempest/tests/lib/services/compute/test_servers_client.py b/tempest/tests/lib/services/compute/test_servers_client.py
index 0078497..93550fd 100644
--- a/tempest/tests/lib/services/compute/test_servers_client.py
+++ b/tempest/tests/lib/services/compute/test_servers_client.py
@@ -16,10 +16,10 @@
from tempest.lib.services.compute import servers_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestServersClient(base.BaseComputeServiceTest):
+class TestServersClient(base.BaseServiceTest):
FAKE_SERVERS = {'servers': [{
"id": "616fb98f-46ca-475e-917e-2563e5a8cd19",
diff --git a/tempest/tests/lib/services/compute/test_services_client.py b/tempest/tests/lib/services/compute/test_services_client.py
index 7add187..41da39c 100644
--- a/tempest/tests/lib/services/compute/test_services_client.py
+++ b/tempest/tests/lib/services/compute/test_services_client.py
@@ -16,10 +16,10 @@
from tempest.lib.services.compute import services_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestServicesClient(base.BaseComputeServiceTest):
+class TestServicesClient(base.BaseServiceTest):
FAKE_SERVICES = {
"services":
diff --git a/tempest/tests/lib/services/compute/test_snapshots_client.py b/tempest/tests/lib/services/compute/test_snapshots_client.py
index b1d8ade..1629943 100644
--- a/tempest/tests/lib/services/compute/test_snapshots_client.py
+++ b/tempest/tests/lib/services/compute/test_snapshots_client.py
@@ -17,10 +17,10 @@
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import snapshots_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestSnapshotsClient(base.BaseComputeServiceTest):
+class TestSnapshotsClient(base.BaseServiceTest):
FAKE_SNAPSHOT = {
"createdAt": "2015-10-02T16:27:54.724209",
diff --git a/tempest/tests/lib/services/compute/test_tenant_networks_client.py b/tempest/tests/lib/services/compute/test_tenant_networks_client.py
index cfb68cc..f71aad9 100644
--- a/tempest/tests/lib/services/compute/test_tenant_networks_client.py
+++ b/tempest/tests/lib/services/compute/test_tenant_networks_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import tenant_networks_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestTenantNetworksClient(base.BaseComputeServiceTest):
+class TestTenantNetworksClient(base.BaseServiceTest):
FAKE_NETWORK = {
"cidr": "None",
diff --git a/tempest/tests/lib/services/compute/test_tenant_usages_client.py b/tempest/tests/lib/services/compute/test_tenant_usages_client.py
index 88d093d..49eae08 100644
--- a/tempest/tests/lib/services/compute/test_tenant_usages_client.py
+++ b/tempest/tests/lib/services/compute/test_tenant_usages_client.py
@@ -14,10 +14,10 @@
from tempest.lib.services.compute import tenant_usages_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestTenantUsagesClient(base.BaseComputeServiceTest):
+class TestTenantUsagesClient(base.BaseServiceTest):
FAKE_SERVER_USAGES = [{
"ended_at": None,
diff --git a/tempest/tests/lib/services/compute/test_versions_client.py b/tempest/tests/lib/services/compute/test_versions_client.py
index fc6c1d2..06ecdc3 100644
--- a/tempest/tests/lib/services/compute/test_versions_client.py
+++ b/tempest/tests/lib/services/compute/test_versions_client.py
@@ -17,10 +17,10 @@
from tempest.lib.services.compute import versions_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestVersionsClient(base.BaseComputeServiceTest):
+class TestVersionsClient(base.BaseServiceTest):
FAKE_INIT_VERSION = {
"version": {
diff --git a/tempest/tests/lib/services/compute/test_volumes_client.py b/tempest/tests/lib/services/compute/test_volumes_client.py
index d16f5b0..b81cdbb 100644
--- a/tempest/tests/lib/services/compute/test_volumes_client.py
+++ b/tempest/tests/lib/services/compute/test_volumes_client.py
@@ -19,10 +19,10 @@
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import volumes_client
from tempest.tests.lib import fake_auth_provider
-from tempest.tests.lib.services.compute import base
+from tempest.tests.lib.services import base
-class TestVolumesClient(base.BaseComputeServiceTest):
+class TestVolumesClient(base.BaseServiceTest):
FAKE_VOLUME = {
"id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
diff --git a/tempest/services/network/__init__.py b/tempest/tests/lib/services/network/__init__.py
similarity index 100%
rename from tempest/services/network/__init__.py
rename to tempest/tests/lib/services/network/__init__.py
diff --git a/tempest/tests/lib/services/network/test_routers_client.py b/tempest/tests/lib/services/network/test_routers_client.py
new file mode 100644
index 0000000..2fa5993
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_routers_client.py
@@ -0,0 +1,109 @@
+# Copyright 2016 NEC Corporation. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.network import routers_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestRoutersClient(base.BaseServiceTest):
+ FAKE_CREATE_ROUTER = {
+ "router": {
+ "name": u'\u2740(*\xb4\u25e1`*)\u2740',
+ "external_gateway_info": {
+ "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b",
+ "enable_snat": True,
+ "external_fixed_ips": [
+ {
+ "subnet_id": "255.255.255.0",
+ "ip": "192.168.10.1"
+ }
+ ]
+ },
+ "admin_state_up": True,
+ "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e"
+ }
+ }
+
+ FAKE_UPDATE_ROUTER = {
+ "router": {
+ "name": u'\u2740(*\xb4\u25e1`*)\u2740',
+ "external_gateway_info": {
+ "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b",
+ "enable_snat": True,
+ "external_fixed_ips": [
+ {
+ "subnet_id": "255.255.255.0",
+ "ip": "192.168.10.1"
+ }
+ ]
+ },
+ "admin_state_up": False,
+ "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e"
+ }
+ }
+
+ def setUp(self):
+ super(TestRoutersClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = routers_client.RoutersClient(fake_auth,
+ 'network', 'regionOne')
+
+ def _test_list_routers(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_routers,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ {"routers": []},
+ bytes_body)
+
+ def _test_create_router(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_router,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_ROUTER,
+ bytes_body,
+ name="another_router", admin_state_up="true", status=201)
+
+ def _test_update_router(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_router,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_UPDATE_ROUTER,
+ bytes_body,
+ router_id="8604a0de-7f6b-409a-a47c-a1cc7bc77b2e",
+ admin_state_up=False)
+
+ def test_list_routers_with_str_body(self):
+ self._test_list_routers()
+
+ def test_list_routers_with_bytes_body(self):
+ self._test_list_routers(bytes_body=True)
+
+ def test_create_router_with_str_body(self):
+ self._test_create_router()
+
+ def test_create_router_with_bytes_body(self):
+ self._test_create_router(bytes_body=True)
+
+ def test_delete_router(self):
+ self.check_service_client_function(
+ self.client.delete_router,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {}, router_id="1", status=204)
+
+ def test_update_router_with_str_body(self):
+ self._test_update_router()
+
+ def test_update_router_with_bytes_body(self):
+ self._test_update_router(bytes_body=True)
diff --git a/tempest/tests/services/compute/__init__.py b/tempest/tests/services/compute/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/tests/services/compute/__init__.py
+++ /dev/null