Merge "Shared images test create with default visibility"
diff --git a/.gitignore b/.gitignore
index 9292dbb..287db4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
ChangeLog
*.pyc
__pycache__/
+etc/accounts.yaml
etc/tempest.conf
etc/tempest.conf.sample
etc/logging.conf
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 2edaddb..04ddfdf 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-#
# Tempest documentation build configuration file, created by
# sphinx-quickstart on Tue May 21 17:43:32 2013.
#
diff --git a/releasenotes/notes/add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml b/releasenotes/notes/14.0.0-add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml
similarity index 100%
rename from releasenotes/notes/add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml
rename to releasenotes/notes/14.0.0-add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml
diff --git a/releasenotes/notes/add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml b/releasenotes/notes/14.0.0-add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml
similarity index 100%
rename from releasenotes/notes/add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml
rename to releasenotes/notes/14.0.0-add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml
diff --git a/releasenotes/notes/add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml b/releasenotes/notes/14.0.0-add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml
similarity index 100%
rename from releasenotes/notes/add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml
rename to releasenotes/notes/14.0.0-add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml
diff --git a/releasenotes/notes/add-image-clients-af94564fb34ddca6.yaml b/releasenotes/notes/14.0.0-add-image-clients-af94564fb34ddca6.yaml
similarity index 100%
rename from releasenotes/notes/add-image-clients-af94564fb34ddca6.yaml
rename to releasenotes/notes/14.0.0-add-image-clients-af94564fb34ddca6.yaml
diff --git a/releasenotes/notes/add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml b/releasenotes/notes/14.0.0-add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml
similarity index 100%
rename from releasenotes/notes/add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml
rename to releasenotes/notes/14.0.0-add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml
diff --git a/releasenotes/notes/add-service-provider-client-cbba77d424a30dd3.yaml b/releasenotes/notes/14.0.0-add-service-provider-client-cbba77d424a30dd3.yaml
similarity index 100%
rename from releasenotes/notes/add-service-provider-client-cbba77d424a30dd3.yaml
rename to releasenotes/notes/14.0.0-add-service-provider-client-cbba77d424a30dd3.yaml
diff --git a/releasenotes/notes/add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml b/releasenotes/notes/14.0.0-add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml
similarity index 100%
rename from releasenotes/notes/add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml
rename to releasenotes/notes/14.0.0-add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml
diff --git a/releasenotes/notes/deprecate-nova-api-extensions-df16b02485dae203.yaml b/releasenotes/notes/14.0.0-deprecate-nova-api-extensions-df16b02485dae203.yaml
similarity index 100%
rename from releasenotes/notes/deprecate-nova-api-extensions-df16b02485dae203.yaml
rename to releasenotes/notes/14.0.0-deprecate-nova-api-extensions-df16b02485dae203.yaml
diff --git a/releasenotes/notes/move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml b/releasenotes/notes/14.0.0-move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml
similarity index 100%
rename from releasenotes/notes/move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml
rename to releasenotes/notes/14.0.0-move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml
diff --git a/releasenotes/notes/new-volume-limit-client-517c17d9090f4df4.yaml b/releasenotes/notes/14.0.0-new-volume-limit-client-517c17d9090f4df4.yaml
similarity index 100%
rename from releasenotes/notes/new-volume-limit-client-517c17d9090f4df4.yaml
rename to releasenotes/notes/14.0.0-new-volume-limit-client-517c17d9090f4df4.yaml
diff --git a/releasenotes/notes/remo-stress-tests-81052b211ad95d2e.yaml b/releasenotes/notes/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml
similarity index 100%
rename from releasenotes/notes/remo-stress-tests-81052b211ad95d2e.yaml
rename to releasenotes/notes/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml
diff --git a/releasenotes/notes/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml b/releasenotes/notes/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml
new file mode 100644
index 0000000..ca2635e
--- /dev/null
+++ b/releasenotes/notes/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml
@@ -0,0 +1,4 @@
+---
+upgrade:
+ - All tests for the Ironic project have been removed from Tempest. Those
+ exist as a Tempest plugin in the Ironic project.
diff --git a/releasenotes/notes/remove-bootable-option-024f8944c056a3e0.yaml b/releasenotes/notes/14.0.0-remove-bootable-option-024f8944c056a3e0.yaml
similarity index 100%
rename from releasenotes/notes/remove-bootable-option-024f8944c056a3e0.yaml
rename to releasenotes/notes/14.0.0-remove-bootable-option-024f8944c056a3e0.yaml
diff --git a/releasenotes/notes/remove-negative-test-generator-1653f4c0f86ccf75.yaml b/releasenotes/notes/14.0.0-remove-negative-test-generator-1653f4c0f86ccf75.yaml
similarity index 100%
rename from releasenotes/notes/remove-negative-test-generator-1653f4c0f86ccf75.yaml
rename to releasenotes/notes/14.0.0-remove-negative-test-generator-1653f4c0f86ccf75.yaml
diff --git a/releasenotes/notes/remove-sahara-tests-1532c47c7df80e3a.yaml b/releasenotes/notes/14.0.0-remove-sahara-tests-1532c47c7df80e3a.yaml
similarity index 100%
rename from releasenotes/notes/remove-sahara-tests-1532c47c7df80e3a.yaml
rename to releasenotes/notes/14.0.0-remove-sahara-tests-1532c47c7df80e3a.yaml
diff --git a/releasenotes/notes/13.1.0-volume-clients-as-library-309030c7a16e62ab.yaml b/releasenotes/notes/14.0.0-volume-clients-as-library-309030c7a16e62ab.yaml
similarity index 100%
rename from releasenotes/notes/13.1.0-volume-clients-as-library-309030c7a16e62ab.yaml
rename to releasenotes/notes/14.0.0-volume-clients-as-library-309030c7a16e62ab.yaml
diff --git a/releasenotes/notes/add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml b/releasenotes/notes/add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml
new file mode 100644
index 0000000..1af1939
--- /dev/null
+++ b/releasenotes/notes/add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - Define the identity v3 service client domains_client as a library.
+ Add domains_client to the library interface so the other
+ projects can use this module as a stable library without any
+ maintenance changes.
diff --git a/releasenotes/notes/add-image-clients-tests-49dbc0a0a4281a77.yaml b/releasenotes/notes/add-image-clients-tests-49dbc0a0a4281a77.yaml
new file mode 100644
index 0000000..9d1a003
--- /dev/null
+++ b/releasenotes/notes/add-image-clients-tests-49dbc0a0a4281a77.yaml
@@ -0,0 +1,9 @@
+---
+features:
+ - |
+ As in the [doc]:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html,
+ there are some apis are not included, add them.
+
+ * namespace_objects_client(v2)
+
diff --git a/releasenotes/notes/add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml b/releasenotes/notes/add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml
new file mode 100644
index 0000000..9a4e6b1
--- /dev/null
+++ b/releasenotes/notes/add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml
@@ -0,0 +1,8 @@
+---
+features:
+ - |
+ Define v2 snapshot_manage_client client for the volume service as
+ library interfaces, allowing other projects to use this module as
+ stable libraries without maintenance changes.
+
+ * snapshot_manage_client(v2)
diff --git a/releasenotes/notes/deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml b/releasenotes/notes/deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml
new file mode 100644
index 0000000..4acdc6d
--- /dev/null
+++ b/releasenotes/notes/deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml
@@ -0,0 +1,8 @@
+---
+upgrade:
+ - The default value for the ``allow_port_security_disabled`` option in the
+ ``compute-feature-enabled`` section has been changed from ``False``
+ to ``True``.
+deprecations:
+ - The ``allow_port_security_disabled`` option in the
+ ``compute-feature-enabled`` section is now deprecated.
diff --git a/releasenotes/notes/deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml b/releasenotes/notes/deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml
new file mode 100644
index 0000000..c0a06d1
--- /dev/null
+++ b/releasenotes/notes/deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml
@@ -0,0 +1,8 @@
+---
+upgrade:
+ - The default value for the ``reseller`` option in the
+ ``identity-feature-enabled`` section has been changed from ``False``
+ to ``True``.
+deprecations:
+ - The ``reseller`` option in the ``identity-feature-enabled`` section is now
+ deprecated.
diff --git a/releasenotes/notes/deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml b/releasenotes/notes/deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml
new file mode 100644
index 0000000..c80f159
--- /dev/null
+++ b/releasenotes/notes/deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml
@@ -0,0 +1,8 @@
+---
+upgrade:
+ - The default value for the ``volume_services`` option in the
+ ``volume_feature_enabled`` section has been changed from ``False``
+ to ``True``.
+deprecations:
+ - The ``volume_services`` option in the ``volume_feature_enabled`` section
+ is now deprecated.
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index 140263c..eec42cd 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
diff --git a/tempest/api/compute/admin/test_auto_allocate_network.py b/tempest/api/compute/admin/test_auto_allocate_network.py
index 8e481fd..08e4072 100644
--- a/tempest/api/compute/admin/test_auto_allocate_network.py
+++ b/tempest/api/compute/admin/test_auto_allocate_network.py
@@ -17,7 +17,6 @@
from tempest.api.compute import base
from tempest.common import compute
from tempest.common import credentials_factory as credentials
-from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import test_utils
from tempest.lib import exceptions as lib_excs
@@ -152,9 +151,7 @@
# create the server with no networking
server, _ = compute.create_test_server(
self.os, networks='none', wait_until='ACTIVE')
- self.addCleanup(waiters.wait_for_server_termination,
- self.servers_client, server['id'])
- self.addCleanup(self.servers_client.delete_server, server['id'])
+ self.addCleanup(self.delete_server, server['id'])
# get the server ips
addresses = self.servers_client.list_addresses(
server['id'])['addresses']
@@ -182,9 +179,7 @@
min_count=3)
server_nets = set()
for server in servers:
- self.addCleanup(waiters.wait_for_server_termination,
- self.servers_client, server['id'])
- self.addCleanup(self.servers_client.delete_server, server['id'])
+ self.addCleanup(self.delete_server, server['id'])
# get the server ips
addresses = self.servers_client.list_addresses(
server['id'])['addresses']
diff --git a/tempest/api/compute/admin/test_keypairs_v210.py b/tempest/api/compute/admin/test_keypairs_v210.py
index dfa7c39..9011433 100644
--- a/tempest/api/compute/admin/test_keypairs_v210.py
+++ b/tempest/api/compute/admin/test_keypairs_v210.py
@@ -32,9 +32,9 @@
key_list = list()
for i in range(2):
k_name = data_utils.rand_name('keypair')
- keypair = self._create_keypair(k_name,
- keypair_type='ssh',
- user_id=user_id)
+ keypair = self.create_keypair(k_name,
+ keypair_type='ssh',
+ user_id=user_id)
self.assertEqual(k_name, keypair['name'],
"The created keypair name is not equal "
"to the requested name!")
@@ -56,8 +56,7 @@
self.assertEqual(user_id, keypair_detail['user_id'],
"The fetched keypair is not for requested user!")
# Create a admin keypair
- admin_k_name = data_utils.rand_name('keypair')
- admin_keypair = self._create_keypair(admin_k_name, keypair_type='ssh')
+ admin_keypair = self.create_keypair(keypair_type='ssh')
admin_keypair.pop('private_key', None)
admin_keypair.pop('user_id')
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 72d5b18..ff84945 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -72,10 +72,9 @@
block_migration = (CONF.compute_feature_enabled.
block_migration_for_live_migration and
not volume_backed)
- body = self.admin_servers_client.live_migrate_server(
+ self.admin_servers_client.live_migrate_server(
server_id, host=dest_host, block_migration=block_migration,
**kwargs)
- return body
def _get_host_other_than(self, host):
for target_host in self._get_compute_hostnames():
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index ce0adb4..33b9bef 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -14,7 +14,6 @@
# under the License.
from oslo_log import log as logging
-import six
from testtools import matchers
from tempest.api.compute import base
@@ -175,7 +174,7 @@
# restore the defaults when the test is done
self.addCleanup(self._restore_default_quotas, body.copy())
# increment all of the values for updating the default quota class
- for quota, default in six.iteritems(body):
+ for quota, default in body.items():
# NOTE(sdague): we need to increment a lot, otherwise
# there is a real chance that we go from -1 (unlimited)
# to a very small number which causes issues.
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index 23b16e7..206260f 100644
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -72,8 +72,8 @@
raise self.skipException("ram quota set is -1,"
" cannot test overlimit")
ram += 1
- vcpus = 8
- disk = 10
+ vcpus = 1
+ disk = 5
flavor_ref = self.flavors_client.create_flavor(name=flavor_name,
ram=ram, vcpus=vcpus,
disk=disk,
@@ -93,7 +93,6 @@
self.useFixture(fixtures.LockFixture('compute_quotas'))
flavor_name = data_utils.rand_name("flavor")
flavor_id = self._get_unused_flavor_id()
- ram = 512
quota_set = self.quotas_client.show_quota_set(
self.tenant_id)['quota_set']
vcpus = int(quota_set['cores'])
@@ -101,7 +100,8 @@
raise self.skipException("cores quota set is -1,"
" cannot test overlimit")
vcpus += 1
- disk = 10
+ ram = 512
+ disk = 5
flavor_ref = self.flavors_client.create_flavor(name=flavor_name,
ram=ram, vcpus=vcpus,
disk=disk,
diff --git a/tempest/api/compute/admin/test_volumes_negative.py b/tempest/api/compute/admin/test_volumes_negative.py
index b9dac6f..26b8742 100644
--- a/tempest/api/compute/admin/test_volumes_negative.py
+++ b/tempest/api/compute/admin/test_volumes_negative.py
@@ -49,6 +49,7 @@
self.server['id'], nonexistent_volume,
volumeId=volume['id'])
+ @test.related_bug('1629110', status_code=400)
@test.idempotent_id('7dcac15a-b107-46d3-a5f6-cb863f4e454a')
def test_update_attached_volume_with_nonexistent_volume_in_body(self):
volume = self.create_volume()
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index d7e01f0..d77ea90 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -139,15 +139,15 @@
test_utils.call_and_ignore_notfound_exc(
cls.servers_client.delete_server, server['id'])
except Exception:
- LOG.exception('Deleting server %s failed' % server['id'])
+ LOG.exception('Deleting server %s failed', server['id'])
for server in cls.servers:
try:
waiters.wait_for_server_termination(cls.servers_client,
server['id'])
except Exception:
- LOG.exception('Waiting for deletion of server %s failed'
- % server['id'])
+ LOG.exception('Waiting for deletion of server %s failed',
+ server['id'])
@classmethod
def server_check_teardown(cls):
@@ -179,7 +179,7 @@
test_utils.call_and_ignore_notfound_exc(
cls.compute_images_client.delete_image, image_id)
except Exception:
- LOG.exception('Exception raised deleting image %s' % image_id)
+ LOG.exception('Exception raised deleting image %s', image_id)
@classmethod
def clear_security_groups(cls):
@@ -283,7 +283,7 @@
volumes_client.wait_for_resource_deletion(volume_id)
except lib_exc.NotFound:
LOG.warning("Unable to delete volume '%s' since it was not found. "
- "Maybe it was already deleted?" % volume_id)
+ "Maybe it was already deleted?", volume_id)
@classmethod
def prepare_instance_network(cls):
@@ -336,7 +336,7 @@
waiters.wait_for_server_termination(cls.servers_client,
server_id)
except Exception:
- LOG.exception('Failed to delete server %s' % server_id)
+ LOG.exception('Failed to delete server %s', server_id)
@classmethod
def resize_server(cls, server_id, new_flavor_id, **kwargs):
diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py
index 549262e..6c97072 100644
--- a/tempest/api/compute/images/test_images_negative.py
+++ b/tempest/api/compute/images/test_images_negative.py
@@ -50,21 +50,19 @@
self.servers_client.delete_server(server['id'])
waiters.wait_for_server_termination(self.servers_client, server['id'])
# Create a new image after server is deleted
- name = data_utils.rand_name('image')
meta = {'image_type': 'test'}
self.assertRaises(lib_exc.NotFound,
self.create_image_from_server,
- server['id'], name=name, meta=meta)
+ server['id'], meta=meta)
@test.attr(type=['negative'])
@test.idempotent_id('82c5b0c4-9dbd-463c-872b-20c4755aae7f')
def test_create_image_from_invalid_server(self):
# An image should not be created with invalid server id
# Create a new image with invalid server id
- name = data_utils.rand_name('image')
meta = {'image_type': 'test'}
self.assertRaises(lib_exc.NotFound, self.create_image_from_server,
- '!@$^&*()', name=name, meta=meta)
+ data_utils.rand_name('invalid'), meta=meta)
@test.attr(type=['negative'])
@test.idempotent_id('ec176029-73dc-4037-8d72-2e4ff60cf538')
@@ -89,7 +87,7 @@
def test_delete_image_with_invalid_image_id(self):
# An image should not be deleted with invalid image id
self.assertRaises(lib_exc.NotFound, self.client.delete_image,
- '!@$^&*()')
+ data_utils.rand_name('invalid'))
@test.attr(type=['negative'])
@test.idempotent_id('137aef61-39f7-44a1-8ddf-0adf82511701')
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index 1c9b3f1..cd71de7 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -47,8 +47,8 @@
waiters.wait_for_server_status(self.servers_client, self.server_id,
'ACTIVE')
except Exception:
- LOG.exception('server %s timed out to become ACTIVE. rebuilding'
- % self.server_id)
+ LOG.exception('server %s timed out to become ACTIVE. rebuilding',
+ self.server_id)
# Rebuild server if cannot reach the ACTIVE state
# Usually it means the server had a serious accident
self._reset_server()
diff --git a/tempest/api/compute/keypairs/base.py b/tempest/api/compute/keypairs/base.py
index ad7f958..21f504b 100644
--- a/tempest/api/compute/keypairs/base.py
+++ b/tempest/api/compute/keypairs/base.py
@@ -14,6 +14,7 @@
# under the License.
from tempest.api.compute import base
+from tempest.common.utils import data_utils
class BaseKeypairTest(base.BaseV2ComputeTest):
@@ -27,9 +28,12 @@
def _delete_keypair(self, keypair_name, **params):
self.client.delete_keypair(keypair_name, **params)
- def _create_keypair(self, keypair_name,
- pub_key=None, keypair_type=None,
- user_id=None):
+ def create_keypair(self, keypair_name=None,
+ pub_key=None, keypair_type=None,
+ user_id=None):
+ if keypair_name is None:
+ keypair_name = data_utils.rand_name(
+ self.__class__.__name__ + '-keypair')
kwargs = {'name': keypair_name}
delete_params = {}
if pub_key:
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index 562a508..8acc25a 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -27,8 +27,7 @@
# Create 3 keypairs
key_list = list()
for i in range(3):
- k_name = data_utils.rand_name('keypair')
- keypair = self._create_keypair(k_name)
+ keypair = self.create_keypair()
# Need to pop these keys so that our compare doesn't fail later,
# as the keypair dicts from list API doesn't have them.
keypair.pop('private_key')
@@ -51,7 +50,7 @@
def test_keypair_create_delete(self):
# Keypair should be created, verified and deleted
k_name = data_utils.rand_name('keypair')
- keypair = self._create_keypair(k_name)
+ keypair = self.create_keypair(k_name)
private_key = keypair['private_key']
key_name = keypair['name']
self.assertEqual(key_name, k_name,
@@ -64,7 +63,7 @@
def test_get_keypair_detail(self):
# Keypair should be created, Got details by name and deleted
k_name = data_utils.rand_name('keypair')
- self._create_keypair(k_name)
+ self.create_keypair(k_name)
keypair_detail = self.client.show_keypair(k_name)['keypair']
self.assertIn('name', keypair_detail)
self.assertIn('public_key', keypair_detail)
@@ -88,7 +87,7 @@
"LOeB1kYMOBaiUPLQTWXR3JpckqFIQwhIH0zoHlJvZE8hh90"
"XcPojYN56tI0OlrGqojbediJYD0rUsJu4weZpbn8vilb3JuDY+jws"
"snSA8wzBx3A/8y9Pp1B nova@ubuntu")
- keypair = self._create_keypair(k_name, pub_key)
+ keypair = self.create_keypair(k_name, pub_key)
self.assertNotIn('private_key', keypair,
"Field private_key is not empty!")
key_name = keypair['name']
diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py
index 2a6139b..f5ffa19 100644
--- a/tempest/api/compute/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/keypairs/test_keypairs_negative.py
@@ -25,10 +25,9 @@
@test.idempotent_id('29cca892-46ae-4d48-bc32-8fe7e731eb81')
def test_keypair_create_with_invalid_pub_key(self):
# Keypair should not be created with a non RSA public key
- k_name = data_utils.rand_name('keypair')
pub_key = "ssh-rsa JUNK nova@ubuntu"
self.assertRaises(lib_exc.BadRequest,
- self._create_keypair, k_name, pub_key)
+ self.create_keypair, pub_key=pub_key)
@test.attr(type=['negative'])
@test.idempotent_id('7cc32e47-4c42-489d-9623-c5e2cb5a2fa5')
@@ -42,19 +41,17 @@
@test.idempotent_id('dade320e-69ca-42a9-ba4a-345300f127e0')
def test_create_keypair_with_empty_public_key(self):
# Keypair should not be created with an empty public key
- k_name = data_utils.rand_name("keypair")
pub_key = ' '
- self.assertRaises(lib_exc.BadRequest, self._create_keypair,
- k_name, pub_key)
+ self.assertRaises(lib_exc.BadRequest, self.create_keypair,
+ pub_key=pub_key)
@test.attr(type=['negative'])
@test.idempotent_id('fc100c19-2926-4b9c-8fdc-d0589ee2f9ff')
def test_create_keypair_when_public_key_bits_exceeds_maximum(self):
# Keypair should not be created when public key bits are too long
- k_name = data_utils.rand_name("keypair")
pub_key = 'ssh-rsa ' + 'A' * 2048 + ' openstack@ubuntu'
- self.assertRaises(lib_exc.BadRequest, self._create_keypair,
- k_name, pub_key)
+ self.assertRaises(lib_exc.BadRequest, self.create_keypair,
+ pub_key=pub_key)
@test.attr(type=['negative'])
@test.idempotent_id('0359a7f1-f002-4682-8073-0c91e4011b7c')
@@ -63,7 +60,7 @@
k_name = data_utils.rand_name('keypair')
self.client.create_keypair(name=k_name)
# Now try the same keyname to create another key
- self.assertRaises(lib_exc.Conflict, self._create_keypair,
+ self.assertRaises(lib_exc.Conflict, self.create_keypair,
k_name)
self.client.delete_keypair(k_name)
@@ -71,7 +68,7 @@
@test.idempotent_id('1398abe1-4a84-45fb-9294-89f514daff00')
def test_create_keypair_with_empty_name_string(self):
# Keypairs with name being an empty string should not be created
- self.assertRaises(lib_exc.BadRequest, self._create_keypair,
+ self.assertRaises(lib_exc.BadRequest, self.create_keypair,
'')
@test.attr(type=['negative'])
@@ -79,7 +76,7 @@
def test_create_keypair_with_long_keynames(self):
# Keypairs with name longer than 255 chars should not be created
k_name = 'keypair-'.ljust(260, '0')
- self.assertRaises(lib_exc.BadRequest, self._create_keypair,
+ self.assertRaises(lib_exc.BadRequest, self.create_keypair,
k_name)
@test.attr(type=['negative'])
@@ -87,5 +84,5 @@
def test_create_keypair_invalid_name(self):
# Keypairs with name being an invalid name should not be created
k_name = 'key_/.\@:'
- self.assertRaises(lib_exc.BadRequest, self._create_keypair,
+ self.assertRaises(lib_exc.BadRequest, self.create_keypair,
k_name)
diff --git a/tempest/api/compute/keypairs/test_keypairs_v22.py b/tempest/api/compute/keypairs/test_keypairs_v22.py
index 997ef9b..4bd1a40 100644
--- a/tempest/api/compute/keypairs/test_keypairs_v22.py
+++ b/tempest/api/compute/keypairs/test_keypairs_v22.py
@@ -28,7 +28,7 @@
def _test_keypairs_create_list_show(self, keypair_type=None):
k_name = data_utils.rand_name('keypair')
- keypair = self._create_keypair(k_name, keypair_type=keypair_type)
+ keypair = self.create_keypair(k_name, keypair_type=keypair_type)
# Verify whether 'type' is present in keypair create response of
# version 2.2 and it is with default value 'ssh'.
self._check_keypair_type(keypair, keypair_type)
diff --git a/tempest/api/compute/security_groups/base.py b/tempest/api/compute/security_groups/base.py
index f70f6d3..cb18775 100644
--- a/tempest/api/compute/security_groups/base.py
+++ b/tempest/api/compute/security_groups/base.py
@@ -14,6 +14,11 @@
# under the License.
from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
class BaseSecurityGroupsTest(base.BaseV2ComputeTest):
@@ -23,3 +28,11 @@
# A network and a subnet will be created for these tests
cls.set_network_resources(network=True, subnet=True)
super(BaseSecurityGroupsTest, cls).setup_credentials()
+
+ @staticmethod
+ def generate_random_security_group_id():
+ if (CONF.service_available.neutron and
+ test.is_extension_enabled('security-group', 'network')):
+ return data_utils.rand_uuid()
+ else:
+ return data_utils.rand_int_id(start=999)
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 38c294b..60caa19 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -43,7 +43,6 @@
group = {}
ip_range = {}
cls.expected = {
- 'id': None,
'parent_group_id': None,
'ip_protocol': cls.ip_protocol,
'from_port': from_port,
@@ -54,8 +53,6 @@
def _check_expected_response(self, actual_rule):
for key in self.expected:
- if key == 'id':
- continue
self.assertEqual(self.expected[key], actual_rule[key],
"Miss-matched key is %s" % key)
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
index 32b3ea3..78c19ca 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -15,20 +15,9 @@
from tempest.api.compute.security_groups import base
from tempest.common.utils import data_utils
-from tempest import config
from tempest.lib import exceptions as lib_exc
from tempest import test
-CONF = config.CONF
-
-
-def not_existing_id():
- if (CONF.service_available.neutron and
- test.is_extension_enabled('security-group', 'network')):
- return data_utils.rand_uuid()
- else:
- return data_utils.rand_int_id(start=999)
-
class SecurityGroupRulesNegativeTestJSON(base.BaseSecurityGroupsTest):
@@ -44,7 +33,7 @@
# Negative test: Creation of Security Group rule should FAIL
# with non existent Parent group id
# Adding rules to the non existent Security Group id
- parent_group_id = not_existing_id()
+ parent_group_id = self.generate_random_security_group_id()
ip_protocol = 'tcp'
from_port = 22
to_port = 22
@@ -179,7 +168,7 @@
def test_delete_security_group_rule_with_non_existent_id(self):
# Negative test: Deletion of Security Group rule should be FAIL
# with non existent id
- non_existent_rule_id = not_existing_id()
+ non_existent_rule_id = self.generate_random_security_group_id()
self.assertRaises(lib_exc.NotFound,
self.rules_client.delete_security_group_rule,
non_existent_rule_id)
diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py
index e6abf28..bcada1e 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -37,29 +37,13 @@
super(SecurityGroupsNegativeTestJSON, cls).resource_setup()
cls.neutron_available = CONF.service_available.neutron
- def _generate_a_non_existent_security_group_id(self):
- security_group_id = []
- body = self.client.list_security_groups()['security_groups']
- for i in range(len(body)):
- security_group_id.append(body[i]['id'])
- # Generate a non-existent security group id
- while True:
- if (self.neutron_available and
- test.is_extension_enabled('security-group', 'network')):
- non_exist_id = data_utils.rand_uuid()
- else:
- non_exist_id = data_utils.rand_int_id(start=999)
- if non_exist_id not in security_group_id:
- break
- return non_exist_id
-
@test.attr(type=['negative'])
@test.idempotent_id('673eaec1-9b3e-48ed-bdf1-2786c1b9661c')
@test.services('network')
def test_security_group_get_nonexistent_group(self):
# Negative test:Should not be able to GET the details
# of non-existent Security Group
- non_exist_id = self._generate_a_non_existent_security_group_id()
+ non_exist_id = self.generate_random_security_group_id()
self.assertRaises(lib_exc.NotFound, self.client.show_security_group,
non_exist_id)
@@ -139,7 +123,7 @@
@test.services('network')
def test_delete_nonexistent_security_group(self):
# Negative test:Deletion of a non-existent Security Group should fail
- non_exist_id = self._generate_a_non_existent_security_group_id()
+ non_exist_id = self.generate_random_security_group_id()
self.assertRaises(lib_exc.NotFound,
self.client.delete_security_group, non_exist_id)
@@ -204,7 +188,7 @@
@test.services('network')
def test_update_non_existent_security_group(self):
# Update a non-existent Security Group should Fail
- non_exist_id = self._generate_a_non_existent_security_group_id()
+ non_exist_id = self.generate_random_security_group_id()
s_name = data_utils.rand_name('sg')
s_description = data_utils.rand_name('description')
self.assertRaises(lib_exc.NotFound,
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index a21ce94..1731bf3 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -268,9 +268,7 @@
self.os, tenant_network=network, wait_until='ACTIVE', min_count=2)
# add our cleanups for the servers since we bypassed the base class
for server in servers:
- self.addCleanup(waiters.wait_for_server_termination,
- self.servers_client, server['id'])
- self.addCleanup(self.servers_client.delete_server, server['id'])
+ self.addCleanup(self.delete_server, server['id'])
for server in servers:
# attach the port to the server
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index d2e31ad..2dcacb7 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -253,24 +253,18 @@
self.flavor_ref)['flavor']
def create_flavor_with_ephemeral(ephem_disk):
- flavor_with_eph_disk_id = data_utils.rand_int_id(start=1000)
+ flavor_id = data_utils.rand_int_id(start=1000)
+ name = 'flavor_with_ephemeral_%s' % ephem_disk
+ flavor_name = data_utils.rand_name(name)
ram = flavor_base['ram']
vcpus = flavor_base['vcpus']
disk = flavor_base['disk']
- if ephem_disk > 0:
- # Create a flavor with ephemeral disk
- flavor_name = data_utils.rand_name('eph_flavor')
- flavor = self.flavor_client.create_flavor(
- name=flavor_name, ram=ram, vcpus=vcpus, disk=disk,
- id=flavor_with_eph_disk_id, ephemeral=ephem_disk)['flavor']
- else:
- # Create a flavor without ephemeral disk
- flavor_name = data_utils.rand_name('no_eph_flavor')
- flavor = self.flavor_client.create_flavor(
- name=flavor_name, ram=ram, vcpus=vcpus, disk=disk,
- id=flavor_with_eph_disk_id)['flavor']
+ # Create a flavor with ephemeral disk
+ flavor = self.flavor_client.create_flavor(
+ name=flavor_name, ram=ram, vcpus=vcpus, disk=disk,
+ id=flavor_id, ephemeral=ephem_disk)['flavor']
self.addCleanup(flavor_clean_up, flavor['id'])
return flavor['id']
diff --git a/tempest/api/compute/servers/test_device_tagging.py b/tempest/api/compute/servers/test_device_tagging.py
index b2d5ae7..1d502be 100644
--- a/tempest/api/compute/servers/test_device_tagging.py
+++ b/tempest/api/compute/servers/test_device_tagging.py
@@ -19,7 +19,6 @@
from tempest.api.compute import base
from tempest.common.utils import data_utils
from tempest.common.utils.linux import remote_client
-from tempest.common import waiters
from tempest import config
from tempest.lib import exceptions
from tempest import test
@@ -196,9 +195,7 @@
}
])
- self.addCleanup(waiters.wait_for_server_termination,
- self.servers_client, server['id'])
- self.addCleanup(self.servers_client.delete_server, server['id'])
+ self.addCleanup(self.delete_server, server['id'])
self.ssh_client = remote_client.RemoteClient(
self.get_server_ip(server),
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 0a94d5e..0334eff 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -350,7 +350,7 @@
else:
LOG.warning("Deletion of oldest backup %s should not have "
"been successful as it should have been "
- "deleted during rotation." % oldest_backup)
+ "deleted during rotation.", oldest_backup)
image1_id = data_utils.parse_image_id(resp['location'])
self.addCleanup(_clean_oldest_backup, image1_id)
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index d31b6f8..549ba03 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
-
from tempest.api.compute import base
from tempest import test
@@ -50,7 +48,7 @@
# We do not know the exact network configuration, but an instance
# should at least have a single public or private address
self.assertGreaterEqual(len(addresses), 1)
- for network_name, network_addresses in six.iteritems(addresses):
+ for network_name, network_addresses in addresses.items():
self.assertGreaterEqual(len(network_addresses), 1)
for address in network_addresses:
self.assertTrue(address['addr'])
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 1b1b339..2b4cee7 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -209,7 +209,7 @@
@test.attr(type=['negative'])
@test.idempotent_id('c3e0fb12-07fc-4d76-a22e-37409887afe8')
def test_create_server_name_length_exceeds_256(self):
- # Create a server with name length exceeding 256 characters
+ # Create a server with name length exceeding 255 characters
server_name = 'a' * 256
self.assertRaises(lib_exc.BadRequest,
@@ -217,6 +217,26 @@
name=server_name)
@test.attr(type=['negative'])
+ @test.related_bug('1651064', status_code=500)
+ @test.idempotent_id('12146ac1-d7df-4928-ad25-b1f99e5286cd')
+ def test_create_server_invalid_bdm_in_2nd_dict(self):
+ volume = self.create_volume()
+ bdm_1st = {"source_type": "image",
+ "delete_on_termination": True,
+ "boot_index": 0,
+ "uuid": self.image_ref,
+ "destination_type": "local"}
+ bdm_2nd = {"source_type": "volume",
+ "uuid": volume["id"],
+ "destination_type": "invalid"}
+ bdm = [bdm_1st, bdm_2nd]
+
+ self.assertRaises(lib_exc.BadRequest,
+ self.create_test_server,
+ image_id=self.image_ref,
+ block_device_mapping_v2=bdm)
+
+ @test.attr(type=['negative'])
@test.idempotent_id('4e72dc2d-44c5-4336-9667-f7972e95c402')
def test_create_with_invalid_network_uuid(self):
# Pass invalid network uuid while creating a server
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index 6e57aff..d171cd5 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -42,7 +42,7 @@
raise self.skipException('There are not any extensions configured')
# Log extensions list
extension_list = map(lambda x: x['alias'], extensions)
- LOG.debug("Nova extensions: %s" % ','.join(extension_list))
+ LOG.debug("Nova extensions: %s", ','.join(extension_list))
@test.idempotent_id('05762f39-bdfa-4cdb-9b46-b78f8e78e2fd')
@test.requires_ext(extension='os-consoles', service='compute')
diff --git a/tempest/api/compute/test_live_block_migration_negative.py b/tempest/api/compute/test_live_block_migration_negative.py
index f072b81..7853962 100644
--- a/tempest/api/compute/test_live_block_migration_negative.py
+++ b/tempest/api/compute/test_live_block_migration_negative.py
@@ -37,10 +37,9 @@
def _migrate_server_to(self, server_id, dest_host):
bmflm = CONF.compute_feature_enabled.block_migration_for_live_migration
- body = self.admin_servers_client.live_migrate_server(
+ self.admin_servers_client.live_migrate_server(
server_id, host=dest_host, block_migration=bmflm,
disk_over_commit=False)
- return body
@test.attr(type=['negative'])
@test.idempotent_id('7fb7856e-ae92-44c9-861a-af62d7830bcb')
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 1edadef..fa465af 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import logging
+from oslo_log import log as logging
import testtools
from tempest.api.compute import base
@@ -68,8 +68,8 @@
volume_id, 'available')
except lib_exc.NotFound:
LOG.warning("Unable to detach volume %s from server %s "
- "possibly it was already detached" % (volume_id,
- server_id))
+ "possibly it was already detached", volume_id,
+ server_id)
def _attach_volume(self, server_id, volume_id, device=None):
# Attach the volume to the server
diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py
index c4041cb..0e1fef2 100644
--- a/tempest/api/compute/volumes/test_volumes_negative.py
+++ b/tempest/api/compute/volumes/test_volumes_negative.py
@@ -95,7 +95,8 @@
# Negative: Should not be able to delete volume when invalid ID is
# passed
self.assertRaises(lib_exc.NotFound,
- self.client.delete_volume, '!@#$%^&*()')
+ self.client.delete_volume,
+ data_utils.rand_name('invalid'))
@test.attr(type=['negative'])
@test.idempotent_id('0d1417c5-4ae8-4c2c-adc5-5f0b864253e5')
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index fd2683e..3ec4ff1 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -15,11 +15,17 @@
import time
+import testtools
+
from tempest.api.identity import base
from tempest.common.utils import data_utils
+from tempest import config
from tempest import test
+CONF = config.CONF
+
+
class UsersV3TestJSON(base.BaseIdentityV3AdminTest):
@test.idempotent_id('b537d090-afb9-4519-b95d-270b0708e87e')
@@ -152,3 +158,30 @@
user = self.setup_test_user()
fetched_user = self.users_client.show_user(user['id'])['user']
self.assertEqual(user['id'], fetched_user['id'])
+
+ @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance,
+ 'Security compliance not available.')
+ @test.idempotent_id('568cd46c-ee6c-4ab4-a33a-d3791931979e')
+ def test_password_history_not_enforced_in_admin_reset(self):
+ old_password = self.os.credentials.password
+ user_id = self.os.credentials.user_id
+
+ new_password = data_utils.rand_password()
+ self.users_client.update_user(user_id, password=new_password)
+ # To be safe, we add this cleanup to restore the original password in
+ # case something goes wrong before it is restored later.
+ self.addCleanup(
+ self.users_client.update_user, user_id, password=old_password)
+
+ # Check authorization with new password
+ self.token.auth(user_id=user_id, password=new_password)
+
+ if CONF.identity.user_unique_last_password_count > 1:
+ # The password history is not enforced via the admin reset route.
+ # We can set the same password.
+ self.users_client.update_user(user_id, password=new_password)
+
+ # Restore original password
+ self.users_client.update_user(user_id, password=old_password)
+ # Check authorization with old password
+ self.token.auth(user_id=user_id, password=old_password)
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 14bf4f8..9515788 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -105,6 +105,15 @@
credentials = ['primary', 'admin']
+ # NOTE(andreaf) Identity tests work with credentials, so it is safer
+ # for them to always use disposable credentials. Forcing dynamic creds
+ # on regular identity tests would be however to restrictive, since it
+ # would prevent any identity test from being executed against clouds where
+ # admin credentials are not available.
+ # Since All admin tests require admin credentials to be
+ # executed, so this will not impact the ability to execute tests.
+ force_tenant_isolation = True
+
@classmethod
def setup_clients(cls):
super(BaseIdentityV2AdminTest, cls).setup_clients()
@@ -165,6 +174,15 @@
credentials = ['primary', 'admin']
+ # NOTE(andreaf) Identity tests work with credentials, so it is safer
+ # for them to always use disposable credentials. Forcing dynamic creds
+ # on regular identity tests would be however to restrictive, since it
+ # would prevent any identity test from being executed against clouds where
+ # admin credentials are not available.
+ # Since All admin tests require admin credentials to be
+ # executed, so this will not impact the ability to execute tests.
+ force_tenant_isolation = True
+
@classmethod
def setup_clients(cls):
super(BaseIdentityV3AdminTest, cls).setup_clients()
diff --git a/tempest/api/identity/v2/test_users.py b/tempest/api/identity/v2/test_users.py
index 33d212c..bafb1f2 100644
--- a/tempest/api/identity/v2/test_users.py
+++ b/tempest/api/identity/v2/test_users.py
@@ -16,11 +16,15 @@
import time
from tempest.api.identity import base
+from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions
from tempest import test
+CONF = config.CONF
+
+
class IdentityUsersTest(base.BaseIdentityV2Test):
@classmethod
@@ -31,36 +35,10 @@
cls.password = cls.creds.password
cls.tenant_name = cls.creds.tenant_name
- @test.idempotent_id('165859c9-277f-4124-9479-a7d1627b0ca7')
- def test_user_update_own_password(self):
-
- def _restore_password(client, user_id, old_pass, new_pass):
- # Reset auth to get a new token with the new password
- client.auth_provider.clear_auth()
- client.auth_provider.credentials.password = new_pass
- client.update_user_own_password(user_id, password=old_pass,
- original_password=new_pass)
- # Reset auth again to verify the password restore does work.
- # Clear auth restores the original credentials and deletes
- # cached auth data
- client.auth_provider.clear_auth()
- # NOTE(lbragstad): Fernet tokens are not subsecond aware and
- # Keystone should only be precise to the second. Sleep to ensure we
- # are passing the second boundary before attempting to
- # authenticate.
- time.sleep(1)
- client.auth_provider.set_auth()
-
- old_pass = self.creds.password
- new_pass = data_utils.rand_password()
- user_id = self.creds.user_id
- # to change password back. important for allow_tenant_isolation = false
- self.addCleanup(_restore_password, self.non_admin_users_client,
- user_id, old_pass=old_pass, new_pass=new_pass)
-
- # user updates own password
+ def _update_password(self, user_id, original_password, password):
self.non_admin_users_client.update_user_own_password(
- user_id, password=new_pass, original_password=old_pass)
+ user_id, password=password, original_password=original_password)
+
# NOTE(morganfainberg): Fernet tokens are not subsecond aware and
# Keystone should only be precise to the second. Sleep to ensure
# we are passing the second boundary.
@@ -68,13 +46,55 @@
# check authorization with new password
self.non_admin_token_client.auth(self.username,
- new_pass,
+ password,
self.tenant_name)
+ # Reset auth to get a new token with the new password
+ self.non_admin_users_client.auth_provider.clear_auth()
+ self.non_admin_users_client.auth_provider.credentials.password = (
+ password)
+
+ def _restore_password(self, user_id, old_pass, new_pass):
+ if CONF.identity_feature_enabled.security_compliance:
+ # First we need to clear the password history
+ unique_count = CONF.identity.user_unique_last_password_count
+ for i in range(unique_count):
+ random_pass = data_utils.rand_password()
+ self._update_password(
+ user_id, original_password=new_pass, password=random_pass)
+ new_pass = random_pass
+
+ self._update_password(
+ user_id, original_password=new_pass, password=old_pass)
+ # Reset auth again to verify the password restore does work.
+ # Clear auth restores the original credentials and deletes
+ # cached auth data
+ self.non_admin_users_client.auth_provider.clear_auth()
+ # NOTE(lbragstad): Fernet tokens are not subsecond aware and
+ # Keystone should only be precise to the second. Sleep to ensure we
+ # are passing the second boundary before attempting to
+ # authenticate.
+ time.sleep(1)
+ self.non_admin_users_client.auth_provider.set_auth()
+
+ @test.idempotent_id('165859c9-277f-4124-9479-a7d1627b0ca7')
+ def test_user_update_own_password(self):
+ old_pass = self.creds.password
+ old_token = self.non_admin_users_client.token
+ new_pass = data_utils.rand_password()
+ user_id = self.creds.user_id
+
+ # to change password back. important for allow_tenant_isolation = false
+ self.addCleanup(self._restore_password, user_id, old_pass, new_pass)
+
+ # user updates own password
+ self._update_password(
+ user_id, original_password=old_pass, password=new_pass)
+
# authorize with old token should lead to Unauthorized
self.assertRaises(exceptions.Unauthorized,
self.non_admin_token_client.auth_token,
- self.non_admin_users_client.token)
+ old_token)
# authorize with old password should lead to Unauthorized
self.assertRaises(exceptions.Unauthorized,
diff --git a/tempest/api/identity/v3/test_users.py b/tempest/api/identity/v3/test_users.py
index 1a38f3a..f389a8f 100644
--- a/tempest/api/identity/v3/test_users.py
+++ b/tempest/api/identity/v3/test_users.py
@@ -15,12 +15,18 @@
import time
+import testtools
+
from tempest.api.identity import base
+from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions
from tempest import test
+CONF = config.CONF
+
+
class IdentityV3UsersTest(base.BaseIdentityV3Test):
@classmethod
@@ -31,36 +37,11 @@
cls.username = cls.creds.username
cls.password = cls.creds.password
- @test.idempotent_id('ad71bd23-12ad-426b-bb8b-195d2b635f27')
- def test_user_update_own_password(self):
-
- def _restore_password(client, user_id, old_pass, new_pass):
- # Reset auth to get a new token with the new password
- client.auth_provider.clear_auth()
- client.auth_provider.credentials.password = new_pass
- client.update_user_password(user_id, password=old_pass,
- original_password=new_pass)
- # Reset auth again to verify the password restore does work.
- # Clear auth restores the original credentials and deletes
- # cached auth data
- client.auth_provider.clear_auth()
- # NOTE(lbragstad): Fernet tokens are not subsecond aware and
- # Keystone should only be precise to the second. Sleep to ensure we
- # are passing the second boundary before attempting to
- # authenticate.
- time.sleep(1)
- client.auth_provider.set_auth()
-
- old_pass = self.creds.password
- new_pass = data_utils.rand_password()
- user_id = self.creds.user_id
- # to change password back. important for allow_tenant_isolation = false
- self.addCleanup(_restore_password, self.non_admin_users_client,
- user_id, old_pass=old_pass, new_pass=new_pass)
-
- # user updates own password
+ def _update_password(self, original_password, password):
self.non_admin_users_client.update_user_password(
- user_id, password=new_pass, original_password=old_pass)
+ self.user_id,
+ password=password,
+ original_password=original_password)
# NOTE(morganfainberg): Fernet tokens are not subsecond aware and
# Keystone should only be precise to the second. Sleep to ensure
@@ -68,15 +49,112 @@
time.sleep(1)
# check authorization with new password
- self.non_admin_token.auth(user_id=self.user_id, password=new_pass)
+ self.non_admin_token.auth(user_id=self.user_id, password=password)
+
+ # Reset auth to get a new token with the new password
+ self.non_admin_users_client.auth_provider.clear_auth()
+ self.non_admin_users_client.auth_provider.credentials.password = (
+ password)
+
+ def _restore_password(self, old_pass, new_pass):
+ if CONF.identity_feature_enabled.security_compliance:
+ # First we need to clear the password history
+ unique_count = CONF.identity.user_unique_last_password_count
+ for i in range(unique_count):
+ random_pass = data_utils.rand_password()
+ self._update_password(
+ original_password=new_pass, password=random_pass)
+ new_pass = random_pass
+
+ self._update_password(original_password=new_pass, password=old_pass)
+ # Reset auth again to verify the password restore does work.
+ # Clear auth restores the original credentials and deletes
+ # cached auth data
+ self.non_admin_users_client.auth_provider.clear_auth()
+ # NOTE(lbragstad): Fernet tokens are not subsecond aware and
+ # Keystone should only be precise to the second. Sleep to ensure we
+ # are passing the second boundary before attempting to
+ # authenticate.
+ time.sleep(1)
+ self.non_admin_users_client.auth_provider.set_auth()
+
+ @test.idempotent_id('ad71bd23-12ad-426b-bb8b-195d2b635f27')
+ def test_user_update_own_password(self):
+ old_pass = self.creds.password
+ old_token = self.non_admin_client.token
+ new_pass = data_utils.rand_password()
+
+ # to change password back. important for allow_tenant_isolation = false
+ self.addCleanup(self._restore_password, old_pass, new_pass)
+
+ # user updates own password
+ self._update_password(original_password=old_pass, password=new_pass)
# authorize with old token should lead to IdentityError (404 code)
self.assertRaises(exceptions.IdentityError,
self.non_admin_token.auth,
- token=self.non_admin_client.token)
+ token=old_token)
# authorize with old password should lead to Unauthorized
self.assertRaises(exceptions.Unauthorized,
self.non_admin_token.auth,
user_id=self.user_id,
password=old_pass)
+
+ @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance,
+ 'Security compliance not available.')
+ @test.idempotent_id('941784ee-5342-4571-959b-b80dd2cea516')
+ def test_password_history_check_self_service_api(self):
+ old_pass = self.creds.password
+ new_pass1 = data_utils.rand_password()
+ new_pass2 = data_utils.rand_password()
+
+ self.addCleanup(self._restore_password, old_pass, new_pass2)
+
+ # Update password
+ self._update_password(original_password=old_pass, password=new_pass1)
+
+ if CONF.identity.user_unique_last_password_count > 1:
+ # Can not reuse a previously set password
+ self.assertRaises(exceptions.BadRequest,
+ self.non_admin_users_client.update_user_password,
+ self.user_id,
+ password=new_pass1,
+ original_password=new_pass1)
+
+ self.assertRaises(exceptions.BadRequest,
+ self.non_admin_users_client.update_user_password,
+ self.user_id,
+ password=old_pass,
+ original_password=new_pass1)
+
+ # A different password can be set
+ self._update_password(original_password=new_pass1, password=new_pass2)
+
+ @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance,
+ 'Security compliance not available.')
+ @test.idempotent_id('a7ad8bbf-2cff-4520-8c1d-96332e151658')
+ def test_user_account_lockout(self):
+ password = self.creds.password
+
+ # First, we login using the correct credentials
+ self.non_admin_token.auth(user_id=self.user_id, password=password)
+
+ # Lock user account by using the wrong password to login
+ bad_password = data_utils.rand_password()
+ for i in range(CONF.identity.user_lockout_failure_attempts):
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_token.auth,
+ user_id=self.user_id,
+ password=bad_password)
+
+ # The user account must be locked, so now it is not possible to login
+ # even using the correct password
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_token.auth,
+ user_id=self.user_id,
+ password=password)
+
+ # If we wait the required time, the user account will be unlocked
+ time.sleep(CONF.identity.user_lockout_duration + 1)
+ self.non_admin_token.auth(user_id=self.user_id, password=password)
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 812c436..23bd628 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -142,6 +142,7 @@
cls.namespaces_client = cls.os.namespaces_client
cls.resource_types_client = cls.os.resource_types_client
cls.namespace_properties_client = cls.os.namespace_properties_client
+ cls.namespace_objects_client = cls.os.namespace_objects_client
cls.schemas_client = cls.os.schemas_client
def create_namespace(cls, namespace_name=None, visibility='public',
diff --git a/tempest/api/image/v1/test_image_members.py b/tempest/api/image/v1/test_image_members.py
index 50f0926..9c211ef 100644
--- a/tempest/api/image/v1/test_image_members.py
+++ b/tempest/api/image/v1/test_image_members.py
@@ -14,6 +14,7 @@
from tempest.api.image import base
+from tempest.lib import exceptions as lib_exc
from tempest import test
@@ -54,3 +55,5 @@
body = self.image_member_client.list_image_members(image_id)
members = body['members']
self.assertEqual(0, len(members), str(members))
+ self.assertRaises(
+ lib_exc.NotFound, self.alt_img_cli.show_image, image_id)
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index 9fbdcd7..b22ceed 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -30,13 +30,23 @@
a_formats = ['ami', 'ari', 'aki']
container_format = CONF.image.container_formats[0]
- disk_format = CONF.image.disk_formats[0]
- if container_format in a_formats and container_format != disk_format:
- msg = ("The container format and the disk format don't match. "
- "Container format: %(container)s, Disk format: %(disk)s." %
- {'container': container_format, 'disk': disk_format})
- raise exceptions.InvalidConfiguration(message=msg)
+ # In v1, If container_format is one of ['ami', 'ari', 'aki'], then
+ # disk_format must be same with container_format.
+ # If they are of different item sequence in tempest.conf, such as:
+ # container_formats = ami,ari,aki,bare
+ # disk_formats = ari,ami,aki,vhd
+ # we can select one in disk_format list that is same with container_format.
+ if container_format in a_formats:
+ if container_format in CONF.image.disk_formats:
+ disk_format = container_format
+ else:
+ msg = ("The container format and the disk format don't match. "
+ "Container format: %(container)s, Disk format: %(disk)s." %
+ {'container': container_format, 'disk': disk_format})
+ raise exceptions.InvalidConfiguration(msg)
+ else:
+ disk_format = CONF.image.disk_formats[0]
return container_format, disk_format
@@ -54,7 +64,6 @@
disk_format=disk_format,
is_public=False,
properties=properties)
- self.assertIn('id', image)
self.assertEqual('New Name', image.get('name'))
self.assertFalse(image.get('is_public'))
self.assertEqual('queued', image.get('status'))
@@ -77,7 +86,6 @@
location=CONF.image.http_image,
properties={'key1': 'value1',
'key2': 'value2'})
- self.assertIn('id', body)
self.assertEqual('New Remote Image', body.get('name'))
self.assertFalse(body.get('is_public'))
self.assertEqual('active', body.get('status'))
@@ -92,7 +100,6 @@
container_format=container_format,
disk_format=disk_format, is_public=False,
copy_from=CONF.image.http_image)
- self.assertIn('id', image)
self.assertEqual('New Http Image', image.get('name'))
self.assertFalse(image.get('is_public'))
waiters.wait_for_image_status(self.client, image['id'], 'active')
@@ -109,7 +116,6 @@
is_public=False,
min_ram=40,
properties=properties)
- self.assertIn('id', body)
self.assertEqual('New_image_with_min_ram', body.get('name'))
self.assertFalse(body.get('is_public'))
self.assertEqual('queued', body.get('status'))
diff --git a/tempest/api/image/v1/test_images_negative.py b/tempest/api/image/v1/test_images_negative.py
index d8f103a..3493cc2 100644
--- a/tempest/api/image/v1/test_images_negative.py
+++ b/tempest/api/image/v1/test_images_negative.py
@@ -15,6 +15,7 @@
from tempest.api.image import base
+from tempest.common.utils import data_utils
from tempest.lib import exceptions as lib_exc
from tempest import test
@@ -44,7 +45,7 @@
def test_delete_non_existent_image(self):
# Return an error while trying to delete a non-existent image
- non_existent_image_id = '11a22b9-12a9-5555-cc11-00ab112223fa'
+ non_existent_image_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound, self.client.delete_image,
non_existent_image_id)
@@ -58,9 +59,9 @@
@test.idempotent_id('950e5054-a3c7-4dee-ada5-e576f1087abd')
def test_delete_image_non_hex_string_id(self):
# Return an error while trying to delete an image with non hex id
- image_id = '11a22b9-120q-5555-cc11-00ab112223gj'
+ invalid_image_id = data_utils.rand_uuid()[:-1] + "j"
self.assertRaises(lib_exc.NotFound, self.client.delete_image,
- image_id)
+ invalid_image_id)
@test.attr(type=['negative'])
@test.idempotent_id('4ed757cd-450c-44b1-9fd1-c819748c650d')
@@ -70,7 +71,8 @@
@test.attr(type=['negative'])
@test.idempotent_id('a4a448ab-3db2-4d2d-b9b2-6a1271241dfe')
- def test_delete_image_id_is_over_35_character_limit(self):
+ def test_delete_image_id_over_character_limit(self):
# Return an error while trying to delete image with id over limit
+ overlimit_image_id = data_utils.rand_uuid() + "1"
self.assertRaises(lib_exc.NotFound, self.client.delete_image,
- '11a22b9-12a9-5555-cc11-00ab112223fa-3fac')
+ overlimit_image_id)
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index e7a10f3..cdf0b23 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -49,7 +49,6 @@
disk_format=disk_format,
visibility='private',
ramdisk_id=uuid)
- self.assertIn('id', image)
self.assertIn('name', image)
self.assertEqual(image_name, image['name'])
self.assertIn('visibility', image)
diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_objects.py b/tempest/api/image/v2/test_images_metadefs_namespace_objects.py
new file mode 100644
index 0000000..95d1521
--- /dev/null
+++ b/tempest/api/image/v2/test_images_metadefs_namespace_objects.py
@@ -0,0 +1,73 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.image import base
+from tempest.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest import test
+
+
+class MetadataNamespaceObjectsTest(base.BaseV2ImageTest):
+ """Test the Metadata definition namespace objects basic functionality"""
+
+ def _create_namespace_object(self, namespace):
+ object_name = data_utils.rand_name(self.__class__.__name__ + '-object')
+ namespace_object = self.namespace_objects_client.\
+ create_namespace_object(namespace['namespace'], name=object_name)
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.namespace_objects_client.delete_namespace_object,
+ namespace['namespace'], object_name)
+ return namespace_object
+
+ @test.idempotent_id('b1a3775e-3b5c-4f6a-a3b4-1ba3574ae718')
+ def test_create_update_delete_meta_namespace_objects(self):
+ # Create a namespace
+ namespace = self.create_namespace()
+ # Create a namespace object
+ body = self._create_namespace_object(namespace)
+ # Update a namespace object
+ up_object_name = data_utils.rand_name('update-object')
+ body = self.namespace_objects_client.update_namespace_object(
+ namespace['namespace'], body['name'],
+ name=up_object_name)
+ self.assertEqual(up_object_name, body['name'])
+ # Delete a namespace object
+ self.namespace_objects_client.delete_namespace_object(
+ namespace['namespace'], up_object_name)
+ # List namespace objects and validate deletion
+ namespace_objects = [
+ namespace_object['name'] for namespace_object in
+ self.namespace_objects_client.list_namespace_objects(
+ namespace['namespace'])['objects']]
+ self.assertNotIn(up_object_name, namespace_objects)
+
+ @test.idempotent_id('a2a3615e-3b5c-3f6a-a2b1-1ba3574ae738')
+ def test_list_meta_namespace_objects(self):
+ # Create a namespace object
+ namespace = self.create_namespace()
+ meta_namespace_object = self._create_namespace_object(namespace)
+ # List namespace objects
+ namespace_objects = [
+ namespace_object['name'] for namespace_object in
+ self.namespace_objects_client.list_namespace_objects(
+ namespace['namespace'])['objects']]
+ self.assertIn(meta_namespace_object['name'], namespace_objects)
+
+ @test.idempotent_id('b1a3674e-3b4c-3f6a-a3b4-1ba3573ca768')
+ def test_show_meta_namespace_objects(self):
+ # Create a namespace object
+ namespace = self.create_namespace()
+ namespace_object = self._create_namespace_object(namespace)
+ # Show a namespace object
+ body = self.namespace_objects_client.show_namespace_object(
+ namespace['namespace'], namespace_object['name'])
+ self.assertEqual(namespace_object['name'], body['name'])
diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py
index c256b5b..beb6ce6 100644
--- a/tempest/api/network/admin/test_negative_quotas.py
+++ b/tempest/api/network/admin/test_negative_quotas.py
@@ -57,8 +57,7 @@
# Try to create a third network while the quota is two
with self.assertRaisesRegex(
lib_exc.Conflict,
- "An object with that identifier already exists\\n" +
- "Details.*Quota exceeded for resources: \['network'\].*"):
+ "Quota exceeded for resources: \['network'\].*"):
n3 = self.networks_client.create_network()
self.addCleanup(self.networks_client.delete_network,
n3['network']['id'])
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 978fb8f..8695ebd 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
-
from tempest.api.network import base
from tempest.common.utils import data_utils
from tempest.lib.common.utils import test_utils
@@ -57,7 +55,7 @@
project_id, **new_quotas)['quota']
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.admin_quotas_client.reset_quotas, project_id)
- for key, value in six.iteritems(new_quotas):
+ for key, value in new_quotas.items():
self.assertEqual(value, quota_set[key])
# Confirm our project is listed among projects with non default quotas
@@ -71,7 +69,7 @@
# Confirm from API quotas were changed as requested for project
quota_set = self.admin_quotas_client.show_quotas(project_id)
quota_set = quota_set['quota']
- for key, value in six.iteritems(new_quotas):
+ for key, value in new_quotas.items():
self.assertEqual(value, quota_set[key])
# Reset quotas to default and confirm
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index 84c48ec..3c96a93 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -16,8 +16,6 @@
import netaddr
import random
-import six
-
from tempest.api.network import base
from tempest.common.utils import data_utils
from tempest.common.utils import net_info
@@ -126,7 +124,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = dict((k, v) for k, v in six.iteritems(kwargs) if v)
+ kwargs = dict((k, v) for k, v in kwargs.items() if v)
real_ip, eui_ip = self._get_ips_from_subnet(**kwargs)
self._clean_network()
self.assertEqual(eui_ip, real_ip,
@@ -269,7 +267,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = dict((k, v) for k, v in six.iteritems(kwargs) if v)
+ kwargs = dict((k, v) for k, v in kwargs.items() if v)
subnet = self.create_subnet(self.network, **kwargs)
port = self.create_port(self.network)
port_ip = next(iter(port['fixed_ips']), None)['ip_address']
@@ -291,7 +289,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = dict((k, v) for k, v in six.iteritems(kwargs) if v)
+ kwargs = dict((k, v) for k, v in kwargs.items() if v)
subnet = self.create_subnet(self.network, **kwargs)
ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
subnet["allocation_pools"][0]["end"])
@@ -340,7 +338,7 @@
{'subnet_id': subnet['id'],
'ip_address': ip}])
self.assertRaisesRegex(lib_exc.Conflict,
- "object with that identifier already exists",
+ "IpAddressAlreadyAllocated|IpAddressInUse",
self.create_port,
self.network,
fixed_ips=[{'subnet_id': subnet['id'],
@@ -364,7 +362,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = dict((k, v) for k, v in six.iteritems(kwargs) if v)
+ kwargs = dict((k, v) for k, v in kwargs.items() if v)
subnet, port = self._create_subnet_router(kwargs)
port_ip = next(iter(port['fixed_ips']), None)['ip_address']
self._clean_network()
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index acac22b..8e2f3f6 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -130,7 +130,7 @@
**kwargs)
compare_args_full = dict(gateway_ip=gateway, cidr=cidr,
mask_bits=mask_bits, **kwargs)
- compare_args = dict((k, v) for k, v in six.iteritems(compare_args_full)
+ compare_args = dict((k, v) for k, v in compare_args_full.items()
if v is not None)
if 'dns_nameservers' in set(subnet).intersection(compare_args):
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 5b46088..e7153f0 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -108,7 +108,7 @@
if ((address.version == 4 and address.prefixlen >= 30) or
(address.version == 6 and address.prefixlen >= 126)):
msg = ("Subnet %s isn't large enough for the test" % address.cidr)
- raise exceptions.InvalidConfiguration(message=msg)
+ raise exceptions.InvalidConfiguration(msg)
allocation_pools = {'allocation_pools': [{'start': str(address[2]),
'end': str(address[-2])}]}
subnet = self.create_subnet(network, cidr=address,
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index f2170ad..101e4dd 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -14,7 +14,6 @@
# under the License.
import netaddr
-import six
from tempest.api.network import base_routers as base
from tempest.common.utils import data_utils
@@ -163,7 +162,7 @@
self.assertIsNone(actual_ext_gw_info)
return
# Verify only keys passed in exp_ext_gw_info
- for k, v in six.iteritems(exp_ext_gw_info):
+ for k, v in exp_ext_gw_info.items():
self.assertEqual(v, actual_ext_gw_info[k])
def _verify_gateway_port(self, router_id):
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 1031ab8..be01852 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
-
from tempest.api.network import base_security_groups as base
from tempest.common.utils import data_utils
from tempest import config
@@ -62,7 +60,7 @@
'port_range_max': port_range_max,
'remote_group_id': remote_group_id,
'remote_ip_prefix': remote_ip_prefix}
- for key, value in six.iteritems(expected):
+ for key, value in expected.items():
self.assertEqual(value, sec_group_rule[key],
"Field %s of the created security group "
"rule does not match with %s." %
@@ -131,7 +129,7 @@
rule_create_body['security_group_rule']['id']
)
create_dict = rule_create_body['security_group_rule']
- for key, value in six.iteritems(create_dict):
+ for key, value in create_dict.items():
self.assertEqual(value,
show_rule_body['security_group_rule'][key],
"%s does not match." % key)
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index eb313d2..535137e 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -25,6 +25,38 @@
CONF = config.CONF
+def delete_containers(containers, container_client, object_client):
+ """Remove containers and all objects in them.
+
+ The containers should be visible from the container_client given.
+ Will not throw any error if the containers don't exist.
+ Will not check that object and container deletions succeed.
+ After delete all the objects from a container, it will wait 2
+ seconds before delete the container itself, in order to deployments
+ using HA proxy sync the deletion properly, otherwise, the container
+ might fail to be deleted because it's not empty.
+
+ :param containers: List of containers to be deleted
+ :param container_client: Client to be used to delete containers
+ :param object_client: Client to be used to delete objects
+ """
+ for cont in containers:
+ try:
+ params = {'limit': 9999, 'format': 'json'}
+ resp, objlist = container_client.list_container_contents(
+ cont, params)
+ # delete every object in the container
+ for obj in objlist:
+ test_utils.call_and_ignore_notfound_exc(
+ object_client.delete_object, cont, obj['name'])
+ # sleep 2 seconds to sync the deletion of the objects
+ # in HA deployment
+ time.sleep(2)
+ container_client.delete_container(cont)
+ except lib_exc.NotFound:
+ pass
+
+
class BaseObjectTest(tempest.test.BaseTestCase):
credentials = [['operator', CONF.object_storage.operator_role]]
@@ -98,42 +130,12 @@
return object_name, data
@classmethod
- def delete_containers(cls, container_client=None,
- object_client=None):
- """Remove containers and all objects in them.
-
- The containers should be visible from the container_client given.
- Will not throw any error if the containers don't exist.
- Will not check that object and container deletions succeed.
- After delete all the objects from a container, it will wait 2
- seconds before delete the container itself, in order to deployments
- using HA proxy sync the deletion properly, otherwise, the container
- might fail to be deleted because it's not empty.
-
- :param container_client: if None, use cls.container_client, this means
- that the default testing user will be used (see 'username' in
- 'etc/tempest.conf')
- :param object_client: if None, use cls.object_client
- """
+ def delete_containers(cls, container_client=None, object_client=None):
if container_client is None:
container_client = cls.container_client
if object_client is None:
object_client = cls.object_client
- for cont in cls.containers:
- try:
- params = {'limit': 9999, 'format': 'json'}
- resp, objlist = container_client.list_container_contents(
- cont, params)
- # delete every object in the container
- for obj in objlist:
- test_utils.call_and_ignore_notfound_exc(
- object_client.delete_object, cont, obj['name'])
- # sleep 2 seconds to sync the deletion of the objects
- # in HA deployment
- time.sleep(2)
- container_client.delete_container(cont)
- except lib_exc.NotFound:
- pass
+ delete_containers(cls.containers, container_client, object_client)
def assertHeaders(self, resp, target, method):
"""Check the existence and the format of response headers"""
diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py
index a75ed98..1eda49a 100644
--- a/tempest/api/object_storage/test_account_bulk.py
+++ b/tempest/api/object_storage/test_account_bulk.py
@@ -27,7 +27,10 @@
self.containers = []
def tearDown(self):
- self.delete_containers()
+ # NOTE(andreaf) BulkTests needs to cleanup containers after each
+ # test is executed.
+ base.delete_containers(self.containers, self.container_client,
+ self.object_client)
super(BulkTest, self).tearDown()
def _create_archive(self):
diff --git a/tempest/api/object_storage/test_container_services_negative.py b/tempest/api/object_storage/test_container_services_negative.py
index f63c518..2856fab 100644
--- a/tempest/api/object_storage/test_container_services_negative.py
+++ b/tempest/api/object_storage/test_container_services_negative.py
@@ -173,5 +173,5 @@
ex = self.assertRaises(exceptions.Conflict,
self.container_client.delete_container,
container_name)
- self.assertIn('An object with that identifier already exists',
- str(ex))
+ self.assertIn('There was a conflict when trying to complete your '
+ 'request.', str(ex))
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 8736f9a..e2e9919 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -19,8 +19,6 @@
import time
import zlib
-import six
-
from tempest.api.object_storage import base
from tempest.common import custom_matchers
from tempest.common.utils import data_utils
@@ -865,7 +863,7 @@
expected = {'x-object-meta-test': '',
'x-object-meta-src': 'src_value',
'x-copied-from': self.container_name + "/" + src_obj_name}
- for key, value in six.iteritems(expected):
+ for key, value in expected.items():
self.assertIn(key, resp)
self.assertEqual(value, resp[key])
@@ -888,7 +886,7 @@
expected = {'x-object-meta-test': 'value',
'x-object-meta-src': 'src_value',
'x-copied-from': self.container_name + "/" + src_obj_name}
- for key, value in six.iteritems(expected):
+ for key, value in expected.items():
self.assertIn(key, resp)
self.assertEqual(value, resp[key])
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index 6d27502..5d680d2 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -28,8 +28,6 @@
@classmethod
def skip_checks(cls):
- msg = "Skipped until Bug: 1547261 is resolved."
- raise cls.skipException(msg)
super(NeutronResourcesTestJSON, cls).skip_checks()
if not CONF.service_available.neutron:
raise cls.skipException("Neutron support is required")
@@ -44,6 +42,7 @@
super(NeutronResourcesTestJSON, cls).setup_clients()
cls.subnets_client = cls.os.subnets_client
cls.ports_client = cls.os.ports_client
+ cls.routers_client = cls.os.routers_client
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/orchestration/stacks/test_swift_resources.py b/tempest/api/orchestration/stacks/test_swift_resources.py
index c0f1c4b..3672526 100644
--- a/tempest/api/orchestration/stacks/test_swift_resources.py
+++ b/tempest/api/orchestration/stacks/test_swift_resources.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index b47a5f0..7d8c94d 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
from tempest.api.volume import base
from tempest.common.utils import data_utils
from tempest.common import waiters
@@ -63,7 +62,7 @@
**new_quota_set)['quota_set']
cleanup_quota_set = dict(
- (k, v) for k, v in six.iteritems(default_quota_set)
+ (k, v) for k, v in default_quota_set.items()
if k in QUOTA_KEYS)
self.addCleanup(self.admin_quotas_client.update_quota_set,
self.demo_tenant_id, **cleanup_quota_set)
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 3098cab..6b2acc6 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -93,7 +93,6 @@
"vendor_name": vendor}
body = self.create_volume_type(description=description, name=name,
extra_specs=extra_specs)
- self.assertIn('id', body)
self.assertIn('name', body)
self.assertEqual(name, body['name'],
"The created volume_type name is not equal "
diff --git a/tempest/api/volume/admin/v2/test_snapshot_manage.py b/tempest/api/volume/admin/v2/test_snapshot_manage.py
new file mode 100644
index 0000000..6a3f9ee
--- /dev/null
+++ b/tempest/api/volume/admin/v2/test_snapshot_manage.py
@@ -0,0 +1,73 @@
+# Copyright 2016 Red Hat, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import testtools
+
+from tempest.api.volume import base
+from tempest.common import waiters
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
+
+
+class SnapshotManageAdminV2Test(base.BaseVolumeAdminTest):
+ """Unmanage & manage snapshots
+
+ This feature provides the ability to import/export volume snapshot
+ from one Cinder to another and to import snapshots that have not been
+ managed by Cinder from a storage back end to Cinder
+ """
+
+ @test.idempotent_id('0132f42d-0147-4b45-8501-cc504bbf7810')
+ @testtools.skipUnless(CONF.volume_feature_enabled.manage_snapshot,
+ "Manage snapshot tests are disabled")
+ def test_unmanage_manage_snapshot(self):
+ # Create a volume
+ volume = self.create_volume()
+
+ # Create a snapshot
+ snapshot = self.create_snapshot(volume_id=volume['id'])
+
+ # Unmanage the snapshot
+ # Unmanage snapshot function works almost the same as delete snapshot,
+ # but it does not delete the snapshot data
+ self.admin_snapshots_client.unmanage_snapshot(snapshot['id'])
+ self.admin_snapshots_client.wait_for_resource_deletion(snapshot['id'])
+
+ # Fetch snapshot ids
+ snapshot_list = [
+ snap['id'] for snap in
+ self.snapshots_client.list_snapshots()['snapshots']
+ ]
+
+ # Verify snapshot does not exist in snapshot list
+ self.assertNotIn(snapshot['id'], snapshot_list)
+
+ # Manage the snapshot
+ snapshot_ref = '_snapshot-%s' % snapshot['id']
+ new_snapshot = self.admin_snapshot_manage_client.manage_snapshot(
+ volume_id=volume['id'],
+ ref={'source-name': snapshot_ref})['snapshot']
+ self.addCleanup(self.delete_snapshot,
+ self.admin_snapshots_client, new_snapshot['id'])
+
+ # Wait for the snapshot to be available after manage operation
+ waiters.wait_for_snapshot_status(self.admin_snapshots_client,
+ new_snapshot['id'],
+ 'available')
+
+ # Verify the managed snapshot has the expected parent volume
+ self.assertEqual(new_snapshot['volume_id'], volume['id'])
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 9f522bd..98e050e 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -51,7 +51,7 @@
raise cls.skipException(msg)
else:
msg = ("Invalid Cinder API version (%s)" % cls._api_version)
- raise exceptions.InvalidConfiguration(message=msg)
+ raise exceptions.InvalidConfiguration(msg)
@classmethod
def setup_credentials(cls):
@@ -165,14 +165,20 @@
# NOTE(afazekas): these create_* and clean_* could be defined
# only in a single location in the source, and could be more general.
- @classmethod
- def delete_volume(cls, client, volume_id):
+ @staticmethod
+ def delete_volume(client, volume_id):
"""Delete volume by the given client"""
client.delete_volume(volume_id)
client.wait_for_resource_deletion(volume_id)
+ @staticmethod
+ def delete_snapshot(client, snapshot_id):
+ """Delete snapshot by the given client"""
+ client.delete_snapshot(snapshot_id)
+ client.wait_for_resource_deletion(snapshot_id)
+
def attach_volume(self, server_id, volume_id):
- """Attachs a volume to a server"""
+ """Attach a volume to a server"""
self.servers_client.attach_volume(
server_id, volumeId=volume_id,
device='/dev/%s' % CONF.compute.volume_device_name)
@@ -200,16 +206,13 @@
@classmethod
def clear_snapshots(cls):
for snapshot in cls.snapshots:
- try:
- cls.snapshots_client.delete_snapshot(snapshot['id'])
- except Exception:
- pass
+ test_utils.call_and_ignore_notfound_exc(
+ cls.snapshots_client.delete_snapshot, snapshot['id'])
for snapshot in cls.snapshots:
- try:
- cls.snapshots_client.wait_for_resource_deletion(snapshot['id'])
- except Exception:
- pass
+ test_utils.call_and_ignore_notfound_exc(
+ cls.snapshots_client.wait_for_resource_deletion,
+ snapshot['id'])
def create_server(self, **kwargs):
name = kwargs.pop(
@@ -260,6 +263,8 @@
cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
cls.admin_volume_client = cls.os_adm.volumes_v2_client
cls.admin_hosts_client = cls.os_adm.volume_hosts_v2_client
+ cls.admin_snapshot_manage_client = \
+ cls.os_adm.snapshot_manage_v2_client
cls.admin_snapshots_client = cls.os_adm.snapshots_v2_client
cls.admin_backups_client = cls.os_adm.backups_v2_client
cls.admin_encryption_types_client = \
diff --git a/tempest/api/volume/test_extensions.py b/tempest/api/volume/test_extensions.py
index cce9ace..f044124 100644
--- a/tempest/api/volume/test_extensions.py
+++ b/tempest/api/volume/test_extensions.py
@@ -35,7 +35,7 @@
if len(CONF.volume_feature_enabled.api_extensions) == 0:
raise self.skipException('There are not any extensions configured')
extension_list = [extension.get('alias') for extension in extensions]
- LOG.debug("Cinder extensions: %s" % ','.join(extension_list))
+ LOG.debug("Cinder extensions: %s", ','.join(extension_list))
ext = CONF.volume_feature_enabled.api_extensions[0]
if ext == 'all':
self.assertIn('Hosts', map(lambda x: x['name'], extensions))
diff --git a/tempest/api/volume/test_volume_absolute_limits.py b/tempest/api/volume/test_volume_absolute_limits.py
index bc7694a..35e0d56 100644
--- a/tempest/api/volume/test_volume_absolute_limits.py
+++ b/tempest/api/volume/test_volume_absolute_limits.py
@@ -23,6 +23,9 @@
class AbsoluteLimitsV2Tests(base.BaseVolumeTest):
+ # avoid existing volumes of pre-defined tenant
+ force_tenant_isolation = True
+
@classmethod
def resource_setup(cls):
super(AbsoluteLimitsV2Tests, cls).resource_setup()
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 0091027..6dcde08 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -30,6 +30,22 @@
if not CONF.volume_feature_enabled.backup:
raise cls.skipException("Cinder backup feature disabled")
+ def restore_backup(self, backup_id):
+ # Restore a backup
+ restored_volume = self.backups_client.restore_backup(
+ backup_id)['restore']
+
+ # Delete backup
+ self.addCleanup(self.volumes_client.delete_volume,
+ restored_volume['volume_id'])
+ self.assertEqual(backup_id, restored_volume['backup_id'])
+ waiters.wait_for_backup_status(self.backups_client,
+ backup_id, 'available')
+ waiters.wait_for_volume_status(self.volumes_client,
+ restored_volume['volume_id'],
+ 'available')
+ return restored_volume
+
@test.idempotent_id('a66eb488-8ee1-47d4-8e9f-575a095728c6')
def test_volume_backup_create_get_detailed_list_restore_delete(self):
# Create backup
@@ -57,18 +73,7 @@
self.assertIn((backup['name'], backup['id']),
[(m['name'], m['id']) for m in backups])
- # Restore backup
- restore = self.backups_client.restore_backup(
- backup['id'])['restore']
-
- # Delete backup
- self.addCleanup(self.volumes_client.delete_volume,
- restore['volume_id'])
- self.assertEqual(backup['id'], restore['backup_id'])
- waiters.wait_for_backup_status(self.backups_client,
- backup['id'], 'available')
- waiters.wait_for_volume_status(self.volumes_client,
- restore['volume_id'], 'available')
+ self.restore_backup(backup['id'])
@test.idempotent_id('07af8f6d-80af-44c9-a5dc-c8427b1b62e6')
@test.services('compute')
@@ -84,14 +89,7 @@
volume['id'])
server = self.create_server(wait_until='ACTIVE')
# Attach volume to instance
- self.servers_client.attach_volume(server['id'],
- volumeId=volume['id'])
- waiters.wait_for_volume_status(self.volumes_client,
- volume['id'], 'in-use')
- self.addCleanup(waiters.wait_for_volume_status, self.volumes_client,
- volume['id'], 'available')
- self.addCleanup(self.servers_client.detach_volume, server['id'],
- volume['id'])
+ self.attach_volume(server['id'], volume['id'])
# Create backup using force flag
backup_name = data_utils.rand_name(
self.__class__.__name__ + '-Backup')
@@ -99,6 +97,28 @@
name=backup_name, force=True)
self.assertEqual(backup_name, backup['name'])
+ @test.idempotent_id('2a8ba340-dff2-4511-9db7-646f07156b15')
+ def test_bootable_volume_backup_and_restore(self):
+ # Create volume from image
+ img_uuid = CONF.compute.image_ref
+ volume = self.create_volume(imageRef=img_uuid)
+
+ volume_details = self.volumes_client.show_volume(
+ volume['id'])['volume']
+ self.assertEqual('true', volume_details['bootable'])
+
+ # Create a backup
+ backup = self.create_backup(volume_id=volume['id'])
+
+ # Restore the backup
+ restored_volume_id = self.restore_backup(backup['id'])['volume_id']
+
+ # Verify the restored backup volume is bootable
+ restored_volume_info = self.volumes_client.show_volume(
+ restored_volume_id)['volume']
+
+ self.assertEqual('true', restored_volume_info['bootable'])
+
class VolumesBackupsV1Test(VolumesBackupsV2Test):
_api_version = 1
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index c45ace6..bcdbd22 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -133,7 +133,8 @@
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
metadata = {'Type': 'work'}
self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume,
- volume_id='#$%%&^&^', display_name=v_name,
+ volume_id=data_utils.rand_name('invalid'),
+ display_name=v_name,
metadata=metadata)
@test.attr(type=['negative'])
@@ -150,7 +151,7 @@
def test_get_invalid_volume_id(self):
# Should not be able to get volume with invalid id
self.assertRaises(lib_exc.NotFound, self.volumes_client.show_volume,
- '#$%%&^&^')
+ data_utils.rand_name('invalid'))
@test.attr(type=['negative'])
@test.idempotent_id('c6c3db06-29ad-4e91-beb0-2ab195fe49e3')
@@ -164,7 +165,7 @@
def test_delete_invalid_volume_id(self):
# Should not be able to delete volume when invalid ID is passed
self.assertRaises(lib_exc.NotFound, self.volumes_client.delete_volume,
- '!@#$%^&*()')
+ data_utils.rand_name('invalid'))
@test.attr(type=['negative'])
@test.idempotent_id('441a1550-5d44-4b30-af0f-a6d402f52026')
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 3c7a2c8..6f85891 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -140,6 +140,14 @@
# Destination volume bigger than source snapshot
dst_vol = self.create_volume(snapshot_id=src_snap['id'],
size=src_size + 1)
+ # NOTE(zhufl): dst_vol is created based on snapshot, so dst_vol
+ # should be deleted before deleting snapshot, otherwise deleting
+ # snapshot will end with status 'error-deleting'. This depends on
+ # the implementation mechanism of vendors, generally speaking,
+ # some verdors will use "virtual disk clone" which will promote
+ # disk clone speed, and in this situation the "disk clone"
+ # is just a relationship between volume and snapshot.
+ self.addCleanup(self.delete_volume, self.volumes_client, dst_vol['id'])
volume = self.volumes_client.show_volume(dst_vol['id'])['volume']
# Should allow
diff --git a/tempest/clients.py b/tempest/clients.py
index 1ab7cfe..b76e3fd 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -13,15 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-import copy
-
from oslo_log import log as logging
from tempest import config
from tempest.lib import auth
from tempest.lib import exceptions as lib_exc
from tempest.lib.services import clients
-from tempest.services import identity
from tempest.services import object_storage
from tempest.services import orchestration
@@ -34,12 +31,19 @@
default_params = config.service_client_config()
- def __init__(self, credentials, service=None, scope='project'):
+ # TODO(jordanP): remove this once no Tempest plugin use that class
+ # variable.
+ default_params_with_timeout_values = {
+ 'build_interval': CONF.compute.build_interval,
+ 'build_timeout': CONF.compute.build_timeout
+ }
+ default_params_with_timeout_values.update(default_params)
+
+ def __init__(self, credentials, scope='project'):
"""Initialization of Manager class.
Setup all services clients and make them available for tests cases.
:param credentials: type Credentials or TestResources
- :param service: Service name
:param scope: default scope for tokens produced by the auth provider
"""
_, identity_uri = get_auth_provider_class(credentials)
@@ -91,7 +95,7 @@
config.service_client_config(service_for_config))
except lib_exc.UnknownServiceClient:
LOG.warning(
- 'Could not load configuration for service %s' % service)
+ 'Could not load configuration for service %s', service)
return configuration
@@ -122,6 +126,8 @@
self.image_member_client_v2 = self.image_v2.ImageMembersClient()
self.namespaces_client = self.image_v2.NamespacesClient()
self.resource_types_client = self.image_v2.ResourceTypesClient()
+ self.namespace_objects_client = \
+ self.image_v2.NamespaceObjectsClient()
self.schemas_client = self.image_v2.SchemasClient()
self.namespace_properties_client = \
self.image_v2.NamespacePropertiesClient()
@@ -157,6 +163,7 @@
self.aggregates_client = self.compute.AggregatesClient()
self.services_client = self.compute.ServicesClient()
self.tenant_usages_client = self.compute.TenantUsagesClient()
+ self.baremetal_nodes_client = self.compute.BaremetalNodesClient()
self.hosts_client = self.compute.HostsClient()
self.hypervisor_client = self.compute.HypervisorClient()
self.instance_usages_audit_log_client = (
@@ -178,82 +185,67 @@
**params_volume)
def _set_identity_clients(self):
- params = self.parameters['identity']
-
# Clients below use the admin endpoint type of Keystone API v2
- params_v2_admin = copy.copy(params)
- params_v2_admin['endpoint_type'] = CONF.identity.v2_admin_endpoint_type
- self.endpoints_client = identity.v2.EndpointsClient(self.auth_provider,
- **params_v2_admin)
- self.identity_client = identity.v2.IdentityClient(self.auth_provider,
- **params_v2_admin)
- self.tenants_client = identity.v2.TenantsClient(self.auth_provider,
- **params_v2_admin)
- self.roles_client = identity.v2.RolesClient(self.auth_provider,
- **params_v2_admin)
- self.users_client = identity.v2.UsersClient(self.auth_provider,
- **params_v2_admin)
- self.identity_services_client = identity.v2.ServicesClient(
- self.auth_provider, **params_v2_admin)
+ params_v2_admin = {
+ 'endpoint_type': CONF.identity.v2_admin_endpoint_type}
+ self.endpoints_client = self.identity_v2.EndpointsClient(
+ **params_v2_admin)
+ self.identity_client = self.identity_v2.IdentityClient(
+ **params_v2_admin)
+ self.tenants_client = self.identity_v2.TenantsClient(
+ **params_v2_admin)
+ self.roles_client = self.identity_v2.RolesClient(**params_v2_admin)
+ self.users_client = self.identity_v2.UsersClient(**params_v2_admin)
+ self.identity_services_client = self.identity_v2.ServicesClient(
+ **params_v2_admin)
# Clients below use the public endpoint type of Keystone API v2
- params_v2_public = copy.copy(params)
- params_v2_public['endpoint_type'] = (
- CONF.identity.v2_public_endpoint_type)
- self.identity_public_client = identity.v2.IdentityClient(
- self.auth_provider, **params_v2_public)
- self.tenants_public_client = identity.v2.TenantsClient(
- self.auth_provider, **params_v2_public)
- self.users_public_client = identity.v2.UsersClient(
- self.auth_provider, **params_v2_public)
+ params_v2_public = {
+ 'endpoint_type': CONF.identity.v2_public_endpoint_type}
+ self.identity_public_client = self.identity_v2.IdentityClient(
+ **params_v2_public)
+ self.tenants_public_client = self.identity_v2.TenantsClient(
+ **params_v2_public)
+ self.users_public_client = self.identity_v2.UsersClient(
+ **params_v2_public)
# Clients below use the endpoint type of Keystone API v3, which is set
# in endpoint_type
- params_v3 = copy.copy(params)
- params_v3['endpoint_type'] = CONF.identity.v3_endpoint_type
- self.domains_client = identity.v3.DomainsClient(self.auth_provider,
- **params_v3)
- self.identity_v3_client = identity.v3.IdentityClient(
- self.auth_provider, **params_v3)
- self.trusts_client = identity.v3.TrustsClient(self.auth_provider,
- **params_v3)
- self.users_v3_client = identity.v3.UsersClient(self.auth_provider,
- **params_v3)
- self.endpoints_v3_client = identity.v3.EndPointsClient(
- self.auth_provider, **params_v3)
- self.roles_v3_client = identity.v3.RolesClient(self.auth_provider,
- **params_v3)
- self.inherited_roles_client = identity.v3.InheritedRolesClient(
- self.auth_provider, **params_v3)
- self.role_assignments_client = identity.v3.RoleAssignmentsClient(
- self.auth_provider, **params_v3)
- self.identity_services_v3_client = identity.v3.ServicesClient(
- self.auth_provider, **params_v3)
- self.policies_client = identity.v3.PoliciesClient(self.auth_provider,
- **params_v3)
- self.projects_client = identity.v3.ProjectsClient(self.auth_provider,
- **params_v3)
- self.regions_client = identity.v3.RegionsClient(self.auth_provider,
- **params_v3)
- self.credentials_client = identity.v3.CredentialsClient(
- self.auth_provider, **params_v3)
- self.groups_client = identity.v3.GroupsClient(self.auth_provider,
- **params_v3)
+ params_v3 = {'endpoint_type': CONF.identity.v3_endpoint_type}
+ self.domains_client = self.identity_v3.DomainsClient(**params_v3)
+ self.identity_v3_client = self.identity_v3.IdentityClient(**params_v3)
+ self.trusts_client = self.identity_v3.TrustsClient(**params_v3)
+ self.users_v3_client = self.identity_v3.UsersClient(**params_v3)
+ self.endpoints_v3_client = self.identity_v3.EndPointsClient(
+ **params_v3)
+ self.roles_v3_client = self.identity_v3.RolesClient(**params_v3)
+ self.inherited_roles_client = self.identity_v3.InheritedRolesClient(
+ **params_v3)
+ self.role_assignments_client = self.identity_v3.RoleAssignmentsClient(
+ **params_v3)
+ self.identity_services_v3_client = self.identity_v3.ServicesClient(
+ **params_v3)
+ self.policies_client = self.identity_v3.PoliciesClient(**params_v3)
+ self.projects_client = self.identity_v3.ProjectsClient(**params_v3)
+ self.regions_client = self.identity_v3.RegionsClient(**params_v3)
+ self.credentials_client = self.identity_v3.CredentialsClient(
+ **params_v3)
+ self.groups_client = self.identity_v3.GroupsClient(**params_v3)
# Token clients do not use the catalog. They only need default_params.
# They read auth_url, so they should only be set if the corresponding
# API version is marked as enabled
if CONF.identity_feature_enabled.api_v2:
if CONF.identity.uri:
- self.token_client = identity.v2.TokenClient(
- CONF.identity.uri, **self.default_params)
+ self.token_client = self.identity_v2.TokenClient(
+ auth_url=CONF.identity.uri)
else:
msg = 'Identity v2 API enabled, but no identity.uri set'
raise lib_exc.InvalidConfiguration(msg)
if CONF.identity_feature_enabled.api_v3:
if CONF.identity.uri_v3:
- self.token_v3_client = identity.v3.V3TokenClient(
- CONF.identity.uri_v3, **self.default_params)
+ self.token_v3_client = self.identity_v3.V3TokenClient(
+ auth_url=CONF.identity.uri_v3)
else:
msg = 'Identity v3 API enabled, but no identity.uri_v3 set'
raise lib_exc.InvalidConfiguration(msg)
@@ -269,6 +261,7 @@
self.encryption_types_client = self.volume_v1.EncryptionTypesClient()
self.encryption_types_v2_client = \
self.volume_v2.EncryptionTypesClient()
+ self.snapshot_manage_v2_client = self.volume_v2.SnapshotManageClient()
self.snapshots_client = self.volume_v1.SnapshotsClient()
self.snapshots_v2_client = self.volume_v2.SnapshotsClient()
self.volumes_client = self.volume_v1.VolumesClient()
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index 3d38e25..172d9e1 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -205,7 +205,7 @@
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)
+ LOG.info('%s generated successfully!', account_file)
def _parser_add_args(parser):
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index af86fe3..ec76103 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -149,8 +149,8 @@
def _remove_admin_user_roles(self):
tenant_ids = self.admin_role_added
- LOG.debug("Removing admin user roles where needed for tenants: %s"
- % tenant_ids)
+ LOG.debug("Removing admin user roles where needed for tenants: %s",
+ tenant_ids)
for tenant_id in tenant_ids:
self._remove_admin_role(tenant_id)
@@ -236,13 +236,13 @@
needs_role = False
LOG.debug("User already had admin privilege for this tenant")
if needs_role:
- LOG.debug("Adding admin privilege for : %s" % tenant_id)
+ LOG.debug("Adding admin privilege for : %s", tenant_id)
rl_cl.create_user_role_on_project(tenant_id, self.admin_id,
self.admin_role_id)
self.admin_role_added.append(tenant_id)
def _remove_admin_role(self, tenant_id):
- LOG.debug("Remove admin user role for tenant: %s" % tenant_id)
+ LOG.debug("Remove admin user role for tenant: %s", tenant_id)
# Must initialize AdminManager for each user role
# Otherwise authentication exception is thrown, weird
id_cl = credentials.AdminManager().identity_client
@@ -253,16 +253,16 @@
self.admin_role_id)
except Exception as ex:
LOG.exception("Failed removing role from tenant which still"
- "exists, exception: %s" % ex)
+ "exists, exception: %s", ex)
def _tenant_exists(self, tenant_id):
tn_cl = self.admin_mgr.tenants_client
try:
t = tn_cl.show_tenant(tenant_id)
- LOG.debug("Tenant is: %s" % str(t))
+ LOG.debug("Tenant is: %s", str(t))
return True
except Exception as ex:
- LOG.debug("Tenant no longer exists? %s" % ex)
+ LOG.debug("Tenant no longer exists? %s", ex)
return False
def _init_state(self):
@@ -290,8 +290,8 @@
except IOError as ex:
LOG.exception("Failed loading saved state, please be sure you"
" have first run cleanup with --init-saved-state "
- "flag prior to running tempest. Exception: %s" % ex)
+ "flag prior to running tempest. Exception: %s", ex)
sys.exit(ex)
except Exception as ex:
- LOG.exception("Exception parsing saved state json : %s" % ex)
+ LOG.exception("Exception parsing saved state json : %s", ex)
sys.exit(ex)
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 32b0ebb..a632726 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -144,7 +144,7 @@
def list(self):
client = self.client
snaps = client.list_snapshots()['snapshots']
- LOG.debug("List count, %s Snapshots" % len(snaps))
+ LOG.debug("List count, %s Snapshots", len(snaps))
return snaps
def delete(self):
@@ -171,7 +171,7 @@
client = self.client
servers_body = client.list_servers()
servers = servers_body['servers']
- LOG.debug("List count, %s Servers" % len(servers))
+ LOG.debug("List count, %s Servers", len(servers))
return servers
def delete(self):
@@ -193,7 +193,7 @@
def list(self):
client = self.server_groups_client
sgs = client.list_server_groups()['server_groups']
- LOG.debug("List count, %s Server Groups" % len(sgs))
+ LOG.debug("List count, %s Server Groups", len(sgs))
return sgs
def delete(self):
@@ -218,7 +218,7 @@
def list(self):
client = self.client
stacks = client.list_stacks()['stacks']
- LOG.debug("List count, %s Stacks" % len(stacks))
+ LOG.debug("List count, %s Stacks", len(stacks))
return stacks
def delete(self):
@@ -243,7 +243,7 @@
def list(self):
client = self.client
keypairs = client.list_keypairs()['keypairs']
- LOG.debug("List count, %s Keypairs" % len(keypairs))
+ LOG.debug("List count, %s Keypairs", len(keypairs))
return keypairs
def delete(self):
@@ -270,7 +270,7 @@
client = self.client
secgrps = client.list_security_groups()['security_groups']
secgrp_del = [grp for grp in secgrps if grp['name'] != 'default']
- LOG.debug("List count, %s Security Groups" % len(secgrp_del))
+ LOG.debug("List count, %s Security Groups", len(secgrp_del))
return secgrp_del
def delete(self):
@@ -295,7 +295,7 @@
def list(self):
client = self.client
floating_ips = client.list_floating_ips()['floating_ips']
- LOG.debug("List count, %s Floating IPs" % len(floating_ips))
+ LOG.debug("List count, %s Floating IPs", len(floating_ips))
return floating_ips
def delete(self):
@@ -320,7 +320,7 @@
def list(self):
client = self.client
vols = client.list_volumes()['volumes']
- LOG.debug("List count, %s Volumes" % len(vols))
+ LOG.debug("List count, %s Volumes", len(vols))
return vols
def delete(self):
@@ -402,7 +402,7 @@
if self.is_preserve:
networks = [network for network in networks
if network['id'] not in CONF_NETWORKS]
- LOG.debug("List count, %s Networks" % networks)
+ LOG.debug("List count, %s Networks", networks)
return networks
def delete(self):
@@ -425,7 +425,7 @@
client = self.floating_ips_client
flips = client.list_floatingips(**self.tenant_filter)
flips = flips['floatingips']
- LOG.debug("List count, %s Network Floating IPs" % len(flips))
+ LOG.debug("List count, %s Network Floating IPs", len(flips))
return flips
def delete(self):
@@ -452,7 +452,7 @@
routers = [router for router in routers
if router['id'] != CONF_PUB_ROUTER]
- LOG.debug("List count, %s Routers" % len(routers))
+ LOG.debug("List count, %s Routers", len(routers))
return routers
def delete(self):
@@ -483,7 +483,7 @@
hms = client.list_health_monitors()
hms = hms['health_monitors']
hms = self._filter_by_tenant_id(hms)
- LOG.debug("List count, %s Health Monitors" % len(hms))
+ LOG.debug("List count, %s Health Monitors", len(hms))
return hms
def delete(self):
@@ -507,7 +507,7 @@
members = client.list_members()
members = members['members']
members = self._filter_by_tenant_id(members)
- LOG.debug("List count, %s Members" % len(members))
+ LOG.debug("List count, %s Members", len(members))
return members
def delete(self):
@@ -531,7 +531,7 @@
vips = client.list_vips()
vips = vips['vips']
vips = self._filter_by_tenant_id(vips)
- LOG.debug("List count, %s VIPs" % len(vips))
+ LOG.debug("List count, %s VIPs", len(vips))
return vips
def delete(self):
@@ -555,7 +555,7 @@
pools = client.list_pools()
pools = pools['pools']
pools = self._filter_by_tenant_id(pools)
- LOG.debug("List count, %s Pools" % len(pools))
+ LOG.debug("List count, %s Pools", len(pools))
return pools
def delete(self):
@@ -579,7 +579,7 @@
rules = client.list_metering_label_rules()
rules = rules['metering_label_rules']
rules = self._filter_by_tenant_id(rules)
- LOG.debug("List count, %s Metering Label Rules" % len(rules))
+ LOG.debug("List count, %s Metering Label Rules", len(rules))
return rules
def delete(self):
@@ -603,7 +603,7 @@
labels = client.list_metering_labels()
labels = labels['metering_labels']
labels = self._filter_by_tenant_id(labels)
- LOG.debug("List count, %s Metering Labels" % len(labels))
+ LOG.debug("List count, %s Metering Labels", len(labels))
return labels
def delete(self):
@@ -632,7 +632,7 @@
if self.is_preserve:
ports = self._filter_by_conf_networks(ports)
- LOG.debug("List count, %s Ports" % len(ports))
+ LOG.debug("List count, %s Ports", len(ports))
return ports
def delete(self):
@@ -660,7 +660,7 @@
if self.is_preserve:
secgroups = self._filter_by_conf_networks(secgroups)
- LOG.debug("List count, %s security_groups" % len(secgroups))
+ LOG.debug("List count, %s security_groups", len(secgroups))
return secgroups
def delete(self):
@@ -685,7 +685,7 @@
subnets = subnets['subnets']
if self.is_preserve:
subnets = self._filter_by_conf_networks(subnets)
- LOG.debug("List count, %s Subnets" % len(subnets))
+ LOG.debug("List count, %s Subnets", len(subnets))
return subnets
def delete(self):
@@ -719,7 +719,7 @@
if self.is_preserve:
flavors = [flavor for flavor in flavors
if flavor['id'] not in CONF_FLAVORS]
- LOG.debug("List count, %s Flavors after reconcile" % len(flavors))
+ LOG.debug("List count, %s Flavors after reconcile", len(flavors))
return flavors
def delete(self):
@@ -756,7 +756,7 @@
if self.is_preserve:
images = [image for image in images
if image['id'] not in CONF_IMAGES]
- LOG.debug("List count, %s Images after reconcile" % len(images))
+ LOG.debug("List count, %s Images after reconcile", len(images))
return images
def delete(self):
@@ -806,7 +806,7 @@
users = [user for user in users if user['name'] !=
CONF.auth.admin_username]
- LOG.debug("List count, %s Users after reconcile" % len(users))
+ LOG.debug("List count, %s Users after reconcile", len(users))
return users
def delete(self):
@@ -843,7 +843,7 @@
(role['id'] not in
self.saved_state_json['roles'].keys()
and role['name'] != CONF.identity.admin_role)]
- LOG.debug("List count, %s Roles after reconcile" % len(roles))
+ LOG.debug("List count, %s Roles after reconcile", len(roles))
return roles
except Exception:
LOG.exception("Cannot retrieve Roles.")
@@ -885,7 +885,7 @@
tenants = [tenant for tenant in tenants if tenant['name']
not in CONF_TENANTS]
- LOG.debug("List count, %s Tenants after reconcile" % len(tenants))
+ LOG.debug("List count, %s Tenants after reconcile", len(tenants))
return tenants
def delete(self):
@@ -920,7 +920,7 @@
domains = [domain for domain in domains if domain['id']
not in self.saved_state_json['domains'].keys()]
- LOG.debug("List count, %s Domains after reconcile" % len(domains))
+ LOG.debug("List count, %s Domains after reconcile", len(domains))
return domains
def delete(self):
diff --git a/tempest/cmd/init.py b/tempest/cmd/init.py
index 99185d2..7634d9e 100644
--- a/tempest/cmd/init.py
+++ b/tempest/cmd/init.py
@@ -120,7 +120,7 @@
if os.path.isdir(config_dir):
shutil.copytree(config_dir, etc_dir)
else:
- LOG.warning("Global config dir %s can't be found" % config_dir)
+ LOG.warning("Global config dir %s can't be found", config_dir)
def generate_sample_config(self, local_dir):
conf_generator = os.path.join(os.path.dirname(__file__),
@@ -131,14 +131,14 @@
output_file])
else:
LOG.warning("Skipping sample config generation because global "
- "config file %s can't be found" % conf_generator)
+ "config file %s can't be found", conf_generator)
def create_working_dir(self, local_dir, config_dir):
# make sure we are working with abspath however tempest init is called
local_dir = os.path.abspath(local_dir)
# Create local dir if missing
if not os.path.isdir(local_dir):
- LOG.debug('Creating local working dir: %s' % local_dir)
+ LOG.debug('Creating local working dir: %s', local_dir)
os.mkdir(local_dir)
elif not os.listdir(local_dir) == []:
raise OSError("Directory you are trying to initialize already "
@@ -151,11 +151,11 @@
testr_dir = os.path.join(local_dir, '.testrepository')
# Create lock dir
if not os.path.isdir(lock_dir):
- LOG.debug('Creating lock dir: %s' % lock_dir)
+ LOG.debug('Creating lock dir: %s', lock_dir)
os.mkdir(lock_dir)
# Create log dir
if not os.path.isdir(log_dir):
- LOG.debug('Creating log dir: %s' % log_dir)
+ LOG.debug('Creating log dir: %s', log_dir)
os.mkdir(log_dir)
# Create and copy local etc dir
self.copy_config(etc_dir, config_dir)
diff --git a/tempest/cmd/run.py b/tempest/cmd/run.py
index 5fa8b74..54b844a 100644
--- a/tempest/cmd/run.py
+++ b/tempest/cmd/run.py
@@ -21,7 +21,7 @@
* **--regex/-r**: This is a selection regex like what testr uses. It will run
any tests that match on re.match() with the regex
- * **--smoke**: Run all the tests tagged as smoke
+ * **--smoke/-s**: Run all the tests tagged as smoke
There are also the **--blacklist-file** and **--whitelist-file** options that
let you pass a filepath to tempest run with the file format being a line
@@ -52,7 +52,7 @@
There are several options to control how the tests are executed. By default
tempest will run in parallel with a worker for each CPU present on the machine.
If you want to adjust the number of workers use the **--concurrency** option
-and if you want to run tests serially use **--serial**
+and if you want to run tests serially use **--serial/-t**
Running with Workspaces
-----------------------
@@ -88,6 +88,7 @@
from cliff import command
from os_testr import regex_builder
from os_testr import subunit_trace
+import six
from testrepository.commands import run_argv
from tempest.cmd import init
@@ -109,6 +110,12 @@
return
else:
os.environ["TESTR_PDB"] = ""
+ # NOTE(dims): most of our .testr.conf try to test for PYTHON
+ # environment variable and fall back to "python", under python3
+ # if it does not exist. we should set it to the python3 executable
+ # to deal with this situation better for now.
+ if six.PY3 and 'PYTHON' not in os.environ:
+ os.environ['PYTHON'] = sys.executable
def _create_testrepository(self):
if not os.path.isdir('.testrepository'):
@@ -191,7 +198,7 @@
help='Configuration file to run tempest with')
# test selection args
regex = parser.add_mutually_exclusive_group()
- regex.add_argument('--smoke', action='store_true',
+ regex.add_argument('--smoke', '-s', action='store_true',
help="Run the smoke tests only")
regex.add_argument('--regex', '-r', default='',
help='A normal testr selection regex used to '
@@ -218,7 +225,7 @@
action='store_true',
help='Run tests in parallel (this is the'
' default)')
- parallel.add_argument('--serial', dest='parallel',
+ parallel.add_argument('--serial', '-t', dest='parallel',
action='store_false',
help='Run tests serially')
# output args
diff --git a/tempest/cmd/workspace.py b/tempest/cmd/workspace.py
index 3c58648..d2dc00d 100644
--- a/tempest/cmd/workspace.py
+++ b/tempest/cmd/workspace.py
@@ -151,7 +151,7 @@
if not os.path.isfile(self.path):
return
with open(self.path, 'r') as f:
- self.workspaces = yaml.load(f) or {}
+ self.workspaces = yaml.safe_load(f) or {}
class TempestWorkspace(command.Command):
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 64543fb..4f2fe67 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -163,8 +163,8 @@
clients.servers_client.delete_server(
server['id'])
except Exception:
- LOG.exception('Deleting server %s failed'
- % server['id'])
+ LOG.exception('Deleting server %s failed',
+ server['id'])
return body, servers
diff --git a/tempest/common/credentials_factory.py b/tempest/common/credentials_factory.py
index bf8d30e..e6b46ed 100644
--- a/tempest/common/credentials_factory.py
+++ b/tempest/common/credentials_factory.py
@@ -233,7 +233,6 @@
class AdminManager(clients.Manager):
"""Manager that uses admin credentials for its managed client objects"""
- def __init__(self, service=None):
+ def __init__(self):
super(AdminManager, self).__init__(
- credentials=get_configured_admin_credentials(),
- service=service)
+ credentials=get_configured_admin_credentials())
diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py
index 8410541..ed11b21 100644
--- a/tempest/common/custom_matchers.py
+++ b/tempest/common/custom_matchers.py
@@ -14,7 +14,6 @@
import re
-import six
from testtools import helpers
@@ -217,7 +216,7 @@
"""
def match(self, actual):
- for key, value in six.iteritems(actual):
+ for key, value in actual.items():
if key in ('content-length', 'x-account-bytes-used',
'x-account-container-count', 'x-account-object-count',
'x-container-bytes-used', 'x-container-object-count')\
diff --git a/tempest/common/dynamic_creds.py b/tempest/common/dynamic_creds.py
index 2763d16..632a876 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -254,7 +254,7 @@
msg = "There was an exception trying to setup network " \
"resources for tenant %s, and this error happened " \
"trying to clean them up: %s"
- LOG.warning(msg % (tenant_id, cleanup_exception))
+ LOG.warning(msg, tenant_id, cleanup_exception)
raise
return network, subnet, router
@@ -316,8 +316,7 @@
credentials = self._create_creds(roles=credential_type)
self._creds[str(credential_type)] = credentials
# Maintained until tests are ported
- LOG.info("Acquired dynamic creds:\n credentials: %s"
- % credentials)
+ LOG.info("Acquired dynamic creds:\n credentials: %s", credentials)
if (self.neutron_available and
self.create_networks):
network, subnet, router = self._create_network_resources(
@@ -325,7 +324,7 @@
credentials.set_resources(network=network, subnet=subnet,
router=router)
LOG.info("Created isolated network resources for : \n"
- + " credentials: %s" % credentials)
+ + " credentials: %s", credentials)
return credentials
def get_primary_creds(self):
@@ -356,7 +355,7 @@
try:
client.delete_router(router_id)
except lib_exc.NotFound:
- LOG.warning('router with name: %s not found for delete' %
+ LOG.warning('router with name: %s not found for delete',
router_name)
def _clear_isolated_subnet(self, subnet_id, subnet_name):
@@ -364,7 +363,7 @@
try:
client.delete_subnet(subnet_id)
except lib_exc.NotFound:
- LOG.warning('subnet with name: %s not found for delete' %
+ LOG.warning('subnet with name: %s not found for delete',
subnet_name)
def _clear_isolated_network(self, network_id, network_name):
@@ -372,7 +371,7 @@
try:
net_client.delete_network(network_id)
except lib_exc.NotFound:
- LOG.warning('network with name: %s not found for delete' %
+ LOG.warning('network with name: %s not found for delete',
network_name)
def _cleanup_default_secgroup(self, tenant):
@@ -384,8 +383,8 @@
try:
nsg_client.delete_security_group(secgroup['id'])
except lib_exc.NotFound:
- LOG.warning('Security group %s, id %s not found for clean-up' %
- (secgroup['name'], secgroup['id']))
+ LOG.warning('Security group %s, id %s not found for clean-up',
+ secgroup['name'], secgroup['id'])
def _clear_isolated_net_resources(self):
client = self.routers_admin_client
@@ -405,7 +404,7 @@
creds.router['id'],
subnet_id=creds.subnet['id'])
except lib_exc.NotFound:
- LOG.warning('router with name: %s not found for delete' %
+ LOG.warning('router with name: %s not found for delete',
creds.router['name'])
self._clear_isolated_router(creds.router['id'],
creds.router['name'])
@@ -426,7 +425,7 @@
try:
self.creds_client.delete_user(creds.user_id)
except lib_exc.NotFound:
- LOG.warning("user with name: %s not found for delete" %
+ LOG.warning("user with name: %s not found for delete",
creds.username)
# NOTE(zhufl): Only when neutron's security_group ext is
# enabled, _cleanup_default_secgroup will not raise error. But
@@ -437,12 +436,12 @@
if self.neutron_available:
self._cleanup_default_secgroup(creds.tenant_id)
except lib_exc.NotFound:
- LOG.warning("failed to cleanup tenant %s's secgroup" %
+ LOG.warning("failed to cleanup tenant %s's secgroup",
creds.tenant_name)
try:
self.creds_client.delete_project(creds.tenant_id)
except lib_exc.NotFound:
- LOG.warning("tenant with name: %s not found for delete" %
+ LOG.warning("tenant with name: %s not found for delete",
creds.tenant_name)
self._creds = {}
diff --git a/tempest/common/fixed_network.py b/tempest/common/fixed_network.py
index f57c18a..f50edbd 100644
--- a/tempest/common/fixed_network.py
+++ b/tempest/common/fixed_network.py
@@ -122,5 +122,5 @@
params.update({"networks": [{'uuid': network['id']}]})
else:
LOG.warning('The provided network dict: %s was invalid and did '
- 'not contain an id' % network)
+ 'not contain an id', network)
return params
diff --git a/tempest/common/image.py b/tempest/common/image.py
index 95a7d1a..3618f7e 100644
--- a/tempest/common/image.py
+++ b/tempest/common/image.py
@@ -15,8 +15,6 @@
import copy
-import six
-
def get_image_meta_from_headers(resp):
meta = {'properties': {}}
@@ -55,13 +53,13 @@
if copy_from is not None:
headers['x-glance-api-copy-from'] = copy_from
- for key, value in six.iteritems(fields_copy.pop('properties', {})):
+ for key, value in fields_copy.pop('properties', {}).items():
headers['x-image-meta-property-%s' % key] = str(value)
- for key, value in six.iteritems(fields_copy.pop('api', {})):
+ for key, value in fields_copy.pop('api', {}).items():
headers['x-glance-api-property-%s' % key] = str(value)
- for key, value in six.iteritems(fields_copy):
+ for key, value in fields_copy.items():
headers['x-image-meta-%s' % key] = str(value)
return headers
diff --git a/tempest/common/preprov_creds.py b/tempest/common/preprov_creds.py
index 3f68ae8..a92d16a 100644
--- a/tempest/common/preprov_creds.py
+++ b/tempest/common/preprov_creds.py
@@ -33,7 +33,7 @@
def read_accounts_yaml(path):
try:
with open(path, 'r') as yaml_file:
- accounts = yaml.load(yaml_file)
+ accounts = yaml.safe_load(yaml_file)
except IOError:
raise lib_exc.InvalidConfiguration(
'The path for the test accounts file: %s '
@@ -120,7 +120,7 @@
if 'resources' in account:
resources = account.pop('resources')
temp_hash = hashlib.md5()
- account_for_hash = dict((k, v) for (k, v) in six.iteritems(account)
+ account_for_hash = dict((k, v) for (k, v) in account.items()
if k in cls.HASH_CRED_FIELDS)
temp_hash.update(six.text_type(account_for_hash).encode('utf-8'))
temp_hash_key = temp_hash.hexdigest()
@@ -158,8 +158,10 @@
if resource == 'network':
hash_dict['networks'][temp_hash_key] = resources[resource]
else:
- LOG.warning('Unknown resource type %s, ignoring this field'
- % resource)
+ LOG.warning(
+ 'Unknown resource type %s, ignoring this field',
+ resource
+ )
return hash_dict
def is_multi_user(self):
@@ -245,7 +247,7 @@
free_hash = self._get_free_hash(useable_hashes)
clean_creds = self._sanitize_creds(
self.hash_dict['creds'][free_hash])
- LOG.info('%s allocated creds:\n%s' % (self.name, clean_creds))
+ LOG.info('%s allocated creds:\n%s', self.name, clean_creds)
return self._wrap_creds_with_network(free_hash)
@lockutils.synchronized('test_accounts_io', external=True)
@@ -253,7 +255,7 @@
hash_path = os.path.join(self.accounts_dir, hash_string)
if not os.path.isfile(hash_path):
LOG.warning('Expected an account lock file %s to remove, but '
- 'one did not exist' % hash_path)
+ 'one did not exist', hash_path)
else:
os.remove(hash_path)
if not os.listdir(self.accounts_dir):
@@ -278,7 +280,7 @@
_hash = self.get_hash(creds)
clean_creds = self._sanitize_creds(self.hash_dict['creds'][_hash])
self.remove_hash(_hash)
- LOG.info("%s returned allocated creds:\n%s" % (self.name, clean_creds))
+ LOG.info("%s returned allocated creds:\n%s", self.name, clean_creds)
def get_primary_creds(self):
if self._creds.get('primary'):
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index d8993bb..009812e 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -87,7 +87,7 @@
# Shell options below add more clearness on failures,
# path is extended for some non-cirros guest oses (centos7)
cmd = CONF.validation.ssh_shell_prologue + " " + cmd
- LOG.debug("Remote command: %s" % cmd)
+ LOG.debug("Remote command: %s", cmd)
return self.ssh_client.exec_command(cmd)
@debug_ssh
@@ -248,5 +248,5 @@
except tempest.lib.exceptions.SSHExecCommandFailed:
LOG.error("Couldn't mke2fs")
cmd_why = 'sudo ls -lR /dev'
- LOG.info("Contents of /dev: %s" % self.exec_command(cmd_why))
+ LOG.info("Contents of /dev: %s", self.exec_command(cmd_why))
raise
diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py
index a55ee32..88697c4 100644
--- a/tempest/common/validation_resources.py
+++ b/tempest/common/validation_resources.py
@@ -60,8 +60,7 @@
parent_group_id=security_group['id'], ip_protocol='icmp',
from_port=-1, to_port=-1)
LOG.debug("SSH Validation resource security group with tcp and icmp "
- "rules %s created"
- % sg_name)
+ "rules %s created", sg_name)
return security_group
@@ -73,7 +72,7 @@
keypair_name = data_utils.rand_name('keypair')
validation_data.update(os.keypairs_client.create_keypair(
name=keypair_name))
- LOG.debug("Validation resource key %s created" % keypair_name)
+ LOG.debug("Validation resource key %s created", keypair_name)
add_rule = False
if validation_resources['security_group']:
if validation_resources['security_group_rules']:
@@ -98,11 +97,13 @@
try:
keypair_client.delete_keypair(keypair_name)
except lib_exc.NotFound:
- LOG.warning("Keypair %s is not found when attempting to delete"
- % keypair_name)
+ LOG.warning(
+ "Keypair %s is not found when attempting to delete",
+ keypair_name
+ )
except Exception as exc:
- LOG.exception('Exception raised while deleting key %s'
- % keypair_name)
+ LOG.exception('Exception raised while deleting key %s',
+ keypair_name)
if not has_exception:
has_exception = exc
if 'security_group' in validation_data:
@@ -113,15 +114,15 @@
security_group_client.wait_for_resource_deletion(sec_id)
except lib_exc.NotFound:
LOG.warning("Security group %s is not found when attempting "
- "to delete" % sec_id)
+ "to delete", sec_id)
except lib_exc.Conflict as exc:
LOG.exception('Conflict while deleting security '
- 'group %s VM might not be deleted ' % sec_id)
+ 'group %s VM might not be deleted', sec_id)
if not has_exception:
has_exception = exc
except Exception as exc:
LOG.exception('Exception raised while deleting security '
- 'group %s ' % sec_id)
+ 'group %s', sec_id)
if not has_exception:
has_exception = exc
if 'floating_ip' in validation_data:
@@ -131,10 +132,9 @@
floating_client.delete_floating_ip(fip_id)
except lib_exc.NotFound:
LOG.warning('Floating ip %s not found while attempting to '
- 'delete' % fip_id)
+ 'delete', fip_id)
except Exception as exc:
- LOG.exception('Exception raised while deleting ip %s '
- % fip_id)
+ LOG.exception('Exception raised while deleting ip %s', fip_id)
if not has_exception:
has_exception = exc
if has_exception:
diff --git a/tempest/config.py b/tempest/config.py
index 9e03b7f..fe8c175 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -16,7 +16,6 @@
from __future__ import print_function
import functools
-import logging as std_logging
import os
import tempfile
@@ -171,7 +170,20 @@
cfg.BoolOpt('admin_domain_scope',
default=False,
help="Whether keystone identity v3 policy required "
- "a domain scoped token to use admin APIs")
+ "a domain scoped token to use admin APIs"),
+ # Security Compliance (PCI-DSS)
+ cfg.IntOpt('user_lockout_failure_attempts',
+ default=2,
+ help="The number of unsuccessful login attempts the user is "
+ "allowed before having the account locked."),
+ cfg.IntOpt('user_lockout_duration',
+ default=5,
+ help="The number of seconds a user account will remain "
+ "locked."),
+ cfg.IntOpt('user_unique_last_password_count',
+ default=2,
+ help="The number of passwords for a user that must be unique "
+ "before an old password can be reused."),
]
service_clients_group = cfg.OptGroup(name='service-clients',
@@ -207,8 +219,15 @@
# TODO(rodrigods): Remove the reseller flag when Kilo and Liberty is end
# of life.
cfg.BoolOpt('reseller',
+ default=True,
+ help='Does the environment support reseller?',
+ deprecated_for_removal=True,
+ deprecated_reason="All supported version of OpenStack now "
+ "supports the 'reseller' feature"),
+ cfg.BoolOpt('security_compliance',
default=False,
- help='Does the environment support reseller?')
+ help='Does the environment have the security compliance '
+ 'settings enabled?')
]
compute_group = cfg.OptGroup(name='compute',
@@ -312,9 +331,12 @@
# NOTE(mriedem): This is a feature toggle for bug 1175464 which is fixed in
# mitaka and newton. This option can be removed after liberty-eol.
cfg.BoolOpt('allow_port_security_disabled',
- default=False,
+ default=True,
help='Does the test environment support creating ports in a '
- 'network where port security is disabled?'),
+ 'network where port security is disabled?',
+ deprecated_for_removal=True,
+ deprecated_reason='This config switch was added for Liberty '
+ 'which is not supported anymore.'),
cfg.BoolOpt('disk_config',
default=True,
help="If false, skip disk config tests"),
@@ -784,6 +806,9 @@
cfg.BoolOpt('clone',
default=True,
help='Runs Cinder volume clone test'),
+ cfg.BoolOpt('manage_snapshot',
+ default=False,
+ help='Runs Cinder manage snapshot tests'),
cfg.ListOpt('api_extensions',
default=['all'],
help='A list of enabled volume extensions with a special '
@@ -800,8 +825,11 @@
help="Is the v3 volume API enabled"),
# TODO(ynesenenko): Remove volume_services once liberty-eol happens.
cfg.BoolOpt('volume_services',
- default=False,
- help='Extract correct host info from host@backend')
+ default=True,
+ help='Extract correct host info from host@backend',
+ deprecated_for_removal=True,
+ deprecated_reason='This config switch was added for Liberty '
+ 'which is not supported anymore.')
]
@@ -1166,11 +1194,11 @@
logging.setup(_CONF, 'tempest')
LOG = logging.getLogger('tempest')
- LOG.info("Using tempest config file %s" % path)
+ LOG.info("Using tempest config file %s", path)
register_opts()
self._set_attrs()
if parse_conf:
- _CONF.log_opt_values(LOG, std_logging.DEBUG)
+ _CONF.log_opt_values(LOG, logging.DEBUG)
class TempestConfigProxy(object):
@@ -1178,14 +1206,14 @@
_path = None
_extra_log_defaults = [
- ('paramiko.transport', std_logging.INFO),
- ('requests.packages.urllib3.connectionpool', std_logging.WARN),
+ ('paramiko.transport', logging.INFO),
+ ('requests.packages.urllib3.connectionpool', logging.WARN),
]
def _fix_log_levels(self):
"""Tweak the oslo log defaults."""
for name, level in self._extra_log_defaults:
- std_logging.getLogger(name).setLevel(level)
+ logging.getLogger(name).logger.setLevel(level)
def __getattr__(self, attr):
if not self._config:
diff --git a/tempest/lib/api_schema/response/compute/v2_1/servers.py b/tempest/lib/api_schema/response/compute/v2_1/servers.py
index 63e8467..1264416 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/servers.py
@@ -238,14 +238,17 @@
'status_code': [200],
'response_body': {
'type': 'object',
- 'properties': {
- 'adminPass': {'type': 'string'}
- },
'additionalProperties': False,
- 'required': ['adminPass']
}
}
+rescue_server_with_admin_pass = copy.deepcopy(rescue_server)
+rescue_server_with_admin_pass['response_body'].update(
+ {'properties': {'adminPass': {'type': 'string'}}})
+rescue_server_with_admin_pass['response_body'].update(
+ {'required': ['adminPass']})
+
+
list_virtual_interfaces = {
'status_code': [200],
'response_body': {
diff --git a/tempest/lib/cli/base.py b/tempest/lib/cli/base.py
index 72a15b5..5468a7b 100644
--- a/tempest/lib/cli/base.py
+++ b/tempest/lib/cli/base.py
@@ -13,11 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-import logging
import os
import shlex
import subprocess
+from oslo_log import log as logging
import six
from tempest.lib import base
@@ -54,7 +54,7 @@
cmd = ' '.join([prefix, os.path.join(cli_dir, cmd),
flags, action, params])
cmd = cmd.strip()
- LOG.info("running: '%s'" % cmd)
+ LOG.info("running: '%s'", cmd)
if six.PY2:
cmd = cmd.encode('utf-8')
cmd = shlex.split(cmd)
diff --git a/tempest/lib/cli/output_parser.py b/tempest/lib/cli/output_parser.py
index 0313505..716f374 100644
--- a/tempest/lib/cli/output_parser.py
+++ b/tempest/lib/cli/output_parser.py
@@ -15,9 +15,10 @@
"""Collection of utilities for parsing CLI clients output."""
-import logging
import re
+from oslo_log import log as logging
+
from tempest.lib import exceptions
@@ -112,7 +113,7 @@
if label is None:
label = line
else:
- LOG.warning('Invalid line between tables: %s' % line)
+ LOG.warning('Invalid line between tables: %s', line)
if len(table_) > 0:
LOG.warning('Missing end of table')
@@ -140,7 +141,7 @@
columns = _table_columns(line)
continue
if '|' not in line:
- LOG.warning('skipping invalid table line: %s' % line)
+ LOG.warning('skipping invalid table line: %s', line)
continue
row = []
for col in columns:
diff --git a/tempest/lib/common/cred_client.py b/tempest/lib/common/cred_client.py
index 3f10dee..ea06011 100644
--- a/tempest/lib/common/cred_client.py
+++ b/tempest/lib/common/cred_client.py
@@ -78,8 +78,8 @@
user['id'],
role['id'])
except lib_exc.Conflict:
- LOG.debug("Role %s already assigned on project %s for user %s" % (
- role['id'], project['id'], user['id']))
+ LOG.debug("Role %s already assigned on project %s for user %s",
+ role['id'], project['id'], user['id'])
@abc.abstractmethod
def get_credentials(self, user, project, password):
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index 2d2771f..2c36f55 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -16,7 +16,6 @@
import collections
import email.utils
-import logging as real_logging
import re
import time
@@ -248,8 +247,8 @@
# NOTE(afazekas): the http status code above 400 is processed by
# the _error_checker method
if read_code < 400:
- pattern = """Unexpected http success status code {0},
- The expected status code is {1}"""
+ pattern = ("Unexpected http success status code {0}, "
+ "The expected status code is {1}")
if ((not isinstance(expected_code, list) and
(read_code != expected_code)) or
(isinstance(expected_code, list) and
@@ -406,8 +405,8 @@
def _log_request_start(self, method, req_url):
caller_name = test_utils.find_test_caller()
if self.trace_requests and re.search(self.trace_requests, caller_name):
- self.LOG.debug('Starting Request (%s): %s %s' %
- (caller_name, method, req_url))
+ self.LOG.debug('Starting Request (%s): %s %s', caller_name,
+ method, req_url)
def _log_request_full(self, resp, req_headers=None, req_body=None,
resp_body=None, extra=None):
@@ -423,11 +422,11 @@
Body: %s"""
self.LOG.debug(
- log_fmt % (
- str(req_headers),
- self._safe_body(req_body),
- str(resp_log),
- self._safe_body(resp_body)),
+ log_fmt,
+ str(req_headers),
+ self._safe_body(req_body),
+ str(resp_log),
+ self._safe_body(resp_body),
extra=extra)
def _log_request(self, method, req_url, resp,
@@ -445,17 +444,17 @@
if secs:
secs = " %.3fs" % secs
self.LOG.info(
- 'Request (%s): %s %s %s%s' % (
- caller_name,
- resp['status'],
- method,
- req_url,
- secs),
+ 'Request (%s): %s %s %s%s',
+ caller_name,
+ resp['status'],
+ method,
+ req_url,
+ secs,
extra=extra)
# Also look everything at DEBUG if you want to filter this
# out, don't run at debug.
- if self.LOG.isEnabledFor(real_logging.DEBUG):
+ if self.LOG.isEnabledFor(logging.DEBUG):
self._log_request_full(resp, req_headers, req_body,
resp_body, extra)
diff --git a/tempest/lib/common/utils/test_utils.py b/tempest/lib/common/utils/test_utils.py
index 3b28701..bd0db7c 100644
--- a/tempest/lib/common/utils/test_utils.py
+++ b/tempest/lib/common/utils/test_utils.py
@@ -74,7 +74,7 @@
# prevents frame leaks
del frame
if caller_name is None:
- LOG.debug("Sane call name not found in %s" % names)
+ LOG.debug("Sane call name not found in %s", names)
return caller_name
diff --git a/tempest/lib/services/clients.py b/tempest/lib/services/clients.py
index 0e8e3c6..445e8bd 100644
--- a/tempest/lib/services/clients.py
+++ b/tempest/lib/services/clients.py
@@ -17,7 +17,8 @@
import copy
import importlib
import inspect
-import logging
+
+from oslo_log import log as logging
from tempest.lib import auth
from tempest.lib.common.utils import misc
@@ -41,6 +42,7 @@
return {
'compute': compute,
'identity.v2': identity.v2,
+ 'identity.v3': identity.v3,
'image.v1': image.v1,
'image.v2': image.v2,
'network': network,
@@ -55,7 +57,7 @@
# NOTE(andreaf) This list will exists only as long the remain clients
# are migrated to tempest.lib, and it will then be deleted without
# deprecation or advance notice
- return set(['identity.v3', 'object-storage'])
+ return set(['object-storage'])
def available_modules():
@@ -278,7 +280,7 @@
a dictionary ready to be injected in kwargs.
Exceptions are:
- - Token clients for 'identity' have a very different interface
+ - Token clients for 'identity' must be given an 'auth_url' parameter
- Volume client for 'volume' accepts 'default_volume_size'
- Servers client from 'compute' accepts 'enable_instance_password'
@@ -373,7 +375,7 @@
except Exception:
LOG.exception(
'Failed to register service client from plugin %s '
- 'with parameters %s' % (plugin, service_client))
+ 'with parameters %s', plugin, service_client)
raise
def register_service_client_module(self, name, service_version,
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index 24557d8..50ce32e 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -100,7 +100,7 @@
any changes.
:param disk_config: The name is changed to OS-DCF:diskConfig
"""
- if kwargs.get('disk_config'):
+ if 'disk_config' in kwargs:
kwargs['OS-DCF:diskConfig'] = kwargs.pop('disk_config')
post_body = json.dumps({'server': kwargs})
@@ -616,7 +616,11 @@
API reference:
http://developer.openstack.org/api-ref-compute-v2.1.html#rescue
"""
- return self.action(server_id, 'rescue', schema.rescue_server, **kwargs)
+ if self.enable_instance_password:
+ rescue_schema = schema.rescue_server_with_admin_pass
+ else:
+ rescue_schema = schema.rescue_server
+ return self.action(server_id, 'rescue', rescue_schema, **kwargs)
def unrescue_server(self, server_id):
"""Unrescue the provided server.
diff --git a/tempest/lib/services/identity/__init__.py b/tempest/lib/services/identity/__init__.py
index e69de29..941a10e 100644
--- a/tempest/lib/services/identity/__init__.py
+++ b/tempest/lib/services/identity/__init__.py
@@ -0,0 +1,18 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+from tempest.lib.services.identity import v2
+from tempest.lib.services.identity import v3
+
+__all__ = ['v2', 'v3']
diff --git a/tempest/lib/services/identity/v2/token_client.py b/tempest/lib/services/identity/v2/token_client.py
index a5d7c86..458c862 100644
--- a/tempest/lib/services/identity/v2/token_client.py
+++ b/tempest/lib/services/identity/v2/token_client.py
@@ -23,7 +23,22 @@
def __init__(self, auth_url, disable_ssl_certificate_validation=None,
ca_certs=None, trace_requests=None, **kwargs):
+ """Initialises the Token client
+
+ :param auth_url: URL to which the token request is sent
+ :param disable_ssl_certificate_validation: pass-through to rest client
+ :param ca_certs: pass-through to rest client
+ :param trace_requests: pass-through to rest client
+ :param kwargs: any extra parameter to pass through the rest client.
+ region, service and auth_provider will be ignored, if passed,
+ as they are not meaningful for token client
+ """
dscv = disable_ssl_certificate_validation
+ # NOTE(andreaf) region, service and auth_provider are passed
+ # positionally with None. Having them in kwargs would raise a
+ # "multiple values for keyword arguments" error
+ for unwanted_kwargs in ['region', 'service', 'auth_provider']:
+ kwargs.pop(unwanted_kwargs, None)
super(TokenClient, self).__init__(
None, None, None, disable_ssl_certificate_validation=dscv,
ca_certs=ca_certs, trace_requests=trace_requests, **kwargs)
@@ -117,8 +132,8 @@
LOG = logging.getLogger(__name__)
def _warn(self):
- self.LOG.warning("%s class was deprecated and renamed to %s" %
- (self.__class__.__name__, 'TokenClient'))
+ self.LOG.warning("%s class was deprecated and renamed to %s",
+ self.__class__.__name__, 'TokenClient')
def __init__(self, *args, **kwargs):
self._warn()
diff --git a/tempest/lib/services/identity/v3/__init__.py b/tempest/lib/services/identity/v3/__init__.py
index e69de29..8058d51 100644
--- a/tempest/lib/services/identity/v3/__init__.py
+++ b/tempest/lib/services/identity/v3/__init__.py
@@ -0,0 +1,38 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+from tempest.lib.services.identity.v3.credentials_client import \
+ CredentialsClient
+from tempest.lib.services.identity.v3.domains_client import DomainsClient
+from tempest.lib.services.identity.v3.endpoints_client import EndPointsClient
+from tempest.lib.services.identity.v3.groups_client import GroupsClient
+from tempest.lib.services.identity.v3.identity_client import IdentityClient
+from tempest.lib.services.identity.v3.inherited_roles_client import \
+ InheritedRolesClient
+from tempest.lib.services.identity.v3.policies_client import PoliciesClient
+from tempest.lib.services.identity.v3.projects_client import ProjectsClient
+from tempest.lib.services.identity.v3.regions_client import RegionsClient
+from tempest.lib.services.identity.v3.role_assignments_client import \
+ RoleAssignmentsClient
+from tempest.lib.services.identity.v3.roles_client import RolesClient
+from tempest.lib.services.identity.v3.services_client import ServicesClient
+from tempest.lib.services.identity.v3.token_client import V3TokenClient
+from tempest.lib.services.identity.v3.trusts_client import TrustsClient
+from tempest.lib.services.identity.v3.users_client import UsersClient
+
+__all__ = ['CredentialsClient', 'DomainsClient', 'EndPointsClient',
+ 'GroupsClient', 'IdentityClient', 'InheritedRolesClient',
+ 'PoliciesClient', 'ProjectsClient', 'RegionsClient',
+ 'RoleAssignmentsClient', 'RolesClient', 'ServicesClient',
+ 'V3TokenClient', 'TrustsClient', 'UsersClient', ]
diff --git a/tempest/services/identity/v3/json/domains_client.py b/tempest/lib/services/identity/v3/domains_client.py
similarity index 100%
rename from tempest/services/identity/v3/json/domains_client.py
rename to tempest/lib/services/identity/v3/domains_client.py
diff --git a/tempest/lib/services/identity/v3/token_client.py b/tempest/lib/services/identity/v3/token_client.py
index c1f7e7b..33f6f16 100644
--- a/tempest/lib/services/identity/v3/token_client.py
+++ b/tempest/lib/services/identity/v3/token_client.py
@@ -23,7 +23,19 @@
def __init__(self, auth_url, disable_ssl_certificate_validation=None,
ca_certs=None, trace_requests=None, **kwargs):
+ """Initialises the Token client
+
+ :param auth_url: URL to which the token request is sent
+ :param disable_ssl_certificate_validation: pass-through to rest client
+ :param ca_certs: pass-through to rest client
+ :param trace_requests: pass-through to rest client
+ :param kwargs: any extra parameter to pass through the rest client.
+ Three kwargs are forbidden: region, service and auth_provider
+ as they are not meaningful for token client
+ """
dscv = disable_ssl_certificate_validation
+ for unwanted_kwargs in ['region', 'service', 'auth_provider']:
+ kwargs.pop(unwanted_kwargs, None)
super(V3TokenClient, self).__init__(
None, None, None, disable_ssl_certificate_validation=dscv,
ca_certs=ca_certs, trace_requests=trace_requests, **kwargs)
@@ -179,8 +191,8 @@
LOG = logging.getLogger(__name__)
def _warn(self):
- self.LOG.warning("%s class was deprecated and renamed to %s" %
- (self.__class__.__name__, 'V3TokenClient'))
+ self.LOG.warning("%s class was deprecated and renamed to %s",
+ self.__class__.__name__, 'V3TokenClient')
def __init__(self, *args, **kwargs):
self._warn()
diff --git a/tempest/lib/services/image/v1/images_client.py b/tempest/lib/services/image/v1/images_client.py
index e67a547..03f4c4b 100644
--- a/tempest/lib/services/image/v1/images_client.py
+++ b/tempest/lib/services/image/v1/images_client.py
@@ -115,7 +115,7 @@
if detail:
url += '/detail'
- if kwargs.get('changes_since'):
+ if 'changes_since' in kwargs:
kwargs['changes-since'] = kwargs.pop('changes_since')
if len(kwargs) > 0:
diff --git a/tempest/lib/services/image/v2/__init__.py b/tempest/lib/services/image/v2/__init__.py
index d359d4b..a35ce17 100644
--- a/tempest/lib/services/image/v2/__init__.py
+++ b/tempest/lib/services/image/v2/__init__.py
@@ -15,6 +15,8 @@
from tempest.lib.services.image.v2.image_members_client import \
ImageMembersClient
from tempest.lib.services.image.v2.images_client import ImagesClient
+from tempest.lib.services.image.v2.namespace_objects_client import \
+ NamespaceObjectsClient
from tempest.lib.services.image.v2.namespace_properties_client import \
NamespacePropertiesClient
from tempest.lib.services.image.v2.namespaces_client import NamespacesClient
@@ -22,5 +24,6 @@
ResourceTypesClient
from tempest.lib.services.image.v2.schemas_client import SchemasClient
-__all__ = ['ImageMembersClient', 'ImagesClient', 'NamespacePropertiesClient',
- 'NamespacesClient', 'ResourceTypesClient', 'SchemasClient']
+__all__ = ['ImageMembersClient', 'ImagesClient', 'NamespaceObjectsClient',
+ 'NamespacePropertiesClient', 'NamespacesClient',
+ 'ResourceTypesClient', 'SchemasClient']
diff --git a/tempest/lib/services/image/v2/namespace_objects_client.py b/tempest/lib/services/image/v2/namespace_objects_client.py
new file mode 100644
index 0000000..ac2e63e
--- /dev/null
+++ b/tempest/lib/services/image/v2/namespace_objects_client.py
@@ -0,0 +1,91 @@
+# Copyright 2016 EasyStack.
+# 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 six.moves.urllib import parse as urllib
+
+from tempest.lib.common import rest_client
+
+
+class NamespaceObjectsClient(rest_client.RestClient):
+ api_version = "v2"
+
+ def list_namespace_objects(self, namespace, **kwargs):
+ """Lists all namespace objects.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-objects
+ """
+ url = 'metadefs/namespaces/%s/objects' % namespace
+ if kwargs:
+ url += '?%s' % urllib.urlencode(kwargs)
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def create_namespace_object(self, namespace, **kwargs):
+ """Create a namespace object
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-object
+ """
+ url = 'metadefs/namespaces/%s/objects' % namespace
+ data = json.dumps(kwargs)
+ resp, body = self.post(url, data)
+ self.expected_success(201, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def update_namespace_object(self, namespace, object_name, **kwargs):
+ """Update a namespace object
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-object
+ """
+ url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name)
+ 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_namespace_object(self, namespace, object_name):
+ """Show a namespace object
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#show-object
+ """
+ url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name)
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_namespace_object(self, namespace, object_name):
+ """Delete a namespace object
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-object
+ """
+ url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name)
+ resp, _ = self.delete(url)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp)
diff --git a/tempest/lib/services/volume/v2/__init__.py b/tempest/lib/services/volume/v2/__init__.py
index 837b4f6..8acad0f 100644
--- a/tempest/lib/services/volume/v2/__init__.py
+++ b/tempest/lib/services/volume/v2/__init__.py
@@ -27,6 +27,8 @@
from tempest.lib.services.volume.v2.scheduler_stats_client import \
SchedulerStatsClient
from tempest.lib.services.volume.v2.services_client import ServicesClient
+from tempest.lib.services.volume.v2.snapshot_manage_client import \
+ SnapshotManageClient
from tempest.lib.services.volume.v2.snapshots_client import SnapshotsClient
from tempest.lib.services.volume.v2.types_client import TypesClient
from tempest.lib.services.volume.v2.volumes_client import VolumesClient
@@ -34,4 +36,5 @@
__all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient',
'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient',
'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient',
- 'LimitsClient', 'CapabilitiesClient', 'SchedulerStatsClient']
+ 'LimitsClient', 'CapabilitiesClient', 'SchedulerStatsClient',
+ 'SnapshotManageClient']
diff --git a/tempest/lib/services/volume/v2/snapshot_manage_client.py b/tempest/lib/services/volume/v2/snapshot_manage_client.py
new file mode 100644
index 0000000..aecd30b
--- /dev/null
+++ b/tempest/lib/services/volume/v2/snapshot_manage_client.py
@@ -0,0 +1,33 @@
+# Copyright 2016 Red Hat, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class SnapshotManageClient(rest_client.RestClient):
+ """Snapshot manage V2 client."""
+
+ api_version = "v2"
+
+ def manage_snapshot(self, **kwargs):
+ """Manage a snapshot."""
+ post_body = json.dumps({'snapshot': kwargs})
+ url = 'os-snapshot-manage'
+ resp, body = self.post(url, post_body)
+ self.expected_success(202, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v2/snapshots_client.py b/tempest/lib/services/volume/v2/snapshots_client.py
index 6f51b51..2bdf1b1 100644
--- a/tempest/lib/services/volume/v2/snapshots_client.py
+++ b/tempest/lib/services/volume/v2/snapshots_client.py
@@ -184,3 +184,11 @@
resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body)
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
+
+ def unmanage_snapshot(self, snapshot_id):
+ """Unmanage a snapshot."""
+ post_body = json.dumps({'os-unmanage': {}})
+ url = 'snapshots/%s/action' % (snapshot_id)
+ resp, body = self.post(url, post_body)
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 376dd19..a3a0100 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -20,7 +20,6 @@
from oslo_log import log
from oslo_serialization import jsonutils as json
from oslo_utils import netutils
-import six
from tempest.common import compute
from tempest.common import image as common_image
@@ -380,9 +379,9 @@
img_disk_format = CONF.scenario.img_disk_format
img_properties = CONF.scenario.img_properties
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))
+ "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)
try:
image = self._image_create('scenario-img',
img_container_format,
@@ -397,7 +396,7 @@
image = self._image_create('scenario-ami', 'ami',
path=ami_img_path,
properties=properties)
- LOG.debug("image:%s" % image)
+ LOG.debug("image:%s", image)
return image
@@ -530,14 +529,14 @@
caller = test_utils.find_test_caller()
LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
- ' expected result is %(should_succeed)s' % {
+ ' expected result is %(should_succeed)s', {
'caller': caller, 'ip': ip_address, 'timeout': timeout,
'should_succeed':
'reachable' if should_succeed else 'unreachable'
})
result = test_utils.call_until_true(ping, timeout, 1)
LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
- 'ping result is %(result)s' % {
+ 'ping result is %(result)s', {
'caller': caller, 'ip': ip_address, 'timeout': timeout,
'result': 'expected' if result else 'unexpected'
})
@@ -578,8 +577,8 @@
msg=None, servers=None, mtu=None):
# The target login is assumed to have been configured for
# key-based authentication by cloud-init.
- LOG.debug('checking network connections to IP %s with user: %s' %
- (ip_address, username))
+ LOG.debug('checking network connections to IP %s with user: %s',
+ ip_address, username)
try:
self.check_vm_connectivity(ip_address,
username,
@@ -920,7 +919,7 @@
# The target login is assumed to have been configured for
# key-based authentication by cloud-init.
try:
- for net_name, ip_addresses in six.iteritems(server['addresses']):
+ for net_name, ip_addresses in server['addresses'].items():
for ip_address in ip_addresses:
self.check_vm_connectivity(ip_address['addr'],
username,
@@ -948,7 +947,7 @@
source.ping_host(dest, nic=nic)
except lib_exc.SSHExecCommandFailed:
LOG.warning('Failed to ping IP: %s via a ssh connection '
- 'from: %s.' % (dest, source.ssh_client.host))
+ 'from: %s.', dest, source.ssh_client.host)
return not should_succeed
return should_succeed
@@ -1315,7 +1314,7 @@
self.container_client.create_container(name)
# look for the container to assure it is created
self.list_and_check_container_objects(name)
- LOG.debug('Container %s created' % (name))
+ LOG.debug('Container %s created', name)
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.container_client.delete_container,
name)
@@ -1323,7 +1322,7 @@
def delete_container(self, container_name):
self.container_client.delete_container(container_name)
- LOG.debug('Container %s deleted' % (container_name))
+ LOG.debug('Container %s deleted', container_name)
def upload_object_to_container(self, container_name, obj_name=None):
obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index 0605902..1279484 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -198,12 +198,11 @@
@test.idempotent_id('a4858f6c-401e-4155-9a49-d5cd053d1a2f')
@testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
'Cold migration is not available.')
+ @testtools.skipUnless(CONF.compute.min_compute_nodes > 1,
+ 'Less than 2 compute nodes, skipping multinode '
+ 'tests.')
@test.services('compute', 'network')
def test_server_connectivity_cold_migration(self):
- if CONF.compute.min_compute_nodes < 2:
- msg = "Less than 2 compute nodes, skipping multinode tests."
- raise self.skipException(msg)
-
keypair = self.create_keypair()
server = self._setup_server(keypair)
floating_ip = self._setup_network(server, keypair)
@@ -220,3 +219,28 @@
dst_host = self._get_host_for_server(server['id'])
self.assertNotEqual(src_host, dst_host)
+
+ @test.idempotent_id('25b188d7-0183-4b1e-a11d-15840c8e2fd6')
+ @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
+ 'Cold migration is not available.')
+ @testtools.skipUnless(CONF.compute.min_compute_nodes > 1,
+ 'Less than 2 compute nodes, skipping multinode '
+ 'tests.')
+ @test.services('compute', 'network')
+ def test_server_connectivity_cold_migration_revert(self):
+ keypair = self.create_keypair()
+ server = self._setup_server(keypair)
+ floating_ip = self._setup_network(server, keypair)
+ src_host = self._get_host_for_server(server['id'])
+ self._wait_server_status_and_check_network_connectivity(
+ server, keypair, floating_ip)
+
+ self.admin_servers_client.migrate_server(server['id'])
+ waiters.wait_for_server_status(self.servers_client, server['id'],
+ 'VERIFY_RESIZE')
+ self.servers_client.revert_resize_server(server['id'])
+ self._wait_server_status_and_check_network_connectivity(
+ server, keypair, floating_ip)
+ dst_host = self._get_host_for_server(server['id'])
+
+ self.assertEqual(src_host, dst_host)
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 4bbe4eb..f9aa3e7 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -615,29 +615,44 @@
def test_update_instance_port_admin_state(self):
"""Test to update admin_state_up attribute of instance port
- 1. Check public connectivity before updating
+ 1. Check public and project connectivity before updating
admin_state_up attribute of instance port to False
- 2. Check public connectivity after updating
+ 2. Check public and project connectivity after updating
admin_state_up attribute of instance port to False
- 3. Check public connectivity after updating
+ 3. Check public and project connectivity after updating
admin_state_up attribute of instance port to True
"""
self._setup_network_and_servers()
floating_ip, server = self.floating_ip_tuple
server_id = server['id']
port_id = self._list_ports(device_id=server_id)[0]['id']
+ server_pip = server['addresses'][self.network['name']][0]['addr']
+
+ server2 = self._create_server(self.network)
+ server2_fip = self.create_floating_ip(server2)
+
+ private_key = self._get_server_key(server2)
+ ssh_client = self.get_remote_client(server2_fip['floating_ip_address'],
+ private_key=private_key)
+
self.check_public_network_connectivity(
should_connect=True, msg="before updating "
"admin_state_up of instance port to False")
+ self._check_remote_connectivity(ssh_client, dest=server_pip,
+ should_succeed=True)
self.ports_client.update_port(port_id, admin_state_up=False)
self.check_public_network_connectivity(
should_connect=False, msg="after updating "
"admin_state_up of instance port to False",
should_check_floating_ip_status=False)
+ self._check_remote_connectivity(ssh_client, dest=server_pip,
+ should_succeed=False)
self.ports_client.update_port(port_id, admin_state_up=True)
self.check_public_network_connectivity(
should_connect=True, msg="after updating "
"admin_state_up of instance port to True")
+ self._check_remote_connectivity(ssh_client, dest=server_pip,
+ should_succeed=True)
@test.idempotent_id('759462e1-8535-46b0-ab3a-33aa45c55aaa')
@test.services('compute', 'network')
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 40b3317..7acf107 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -14,8 +14,6 @@
# under the License.
import functools
-import six
-
from tempest import config
from tempest.lib.common.utils import test_utils
from tempest.scenario import manager
@@ -112,7 +110,7 @@
@staticmethod
def define_server_ips(srv):
ips = {'4': None, '6': []}
- for net_name, nics in six.iteritems(srv['addresses']):
+ for net_name, nics in srv['addresses'].items():
for nic in nics:
if nic['version'] == 6:
ips['6'].append(nic['addr'])
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index dff00e7..b10be11 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -86,7 +86,7 @@
def _func():
disks = ssh.get_disks()
- LOG.debug("Disks: %s" % disks)
+ LOG.debug("Disks: %s", disks)
return CONF.compute.volume_device_name in disks
if not test_utils.call_until_true(_func,
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 46aebfe..2c8b618 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -118,36 +118,36 @@
volume_origin = self._create_volume_from_image()
instance_1st = self._boot_instance_from_volume(volume_origin['id'],
keypair, security_group)
- LOG.info("Booted first instance: %s" % instance_1st)
+ LOG.info("Booted first instance: %s", instance_1st)
# write content to volume on instance
- LOG.info("Setting timestamp in instance %s" % instance_1st)
+ LOG.info("Setting timestamp in instance %s", instance_1st)
ip_instance_1st = self.get_server_ip(instance_1st)
timestamp = self.create_timestamp(ip_instance_1st,
private_key=keypair['private_key'])
# delete instance
- LOG.info("Deleting first instance: %s" % instance_1st)
+ LOG.info("Deleting first instance: %s", instance_1st)
self._delete_server(instance_1st)
# create a 2nd instance from volume
instance_2nd = self._boot_instance_from_volume(volume_origin['id'],
keypair, security_group)
- LOG.info("Booted second instance %s" % instance_2nd)
+ LOG.info("Booted second instance %s", instance_2nd)
# check the content of written file
- LOG.info("Getting timestamp in instance %s" % instance_2nd)
+ LOG.info("Getting timestamp in instance %s", instance_2nd)
ip_instance_2nd = self.get_server_ip(instance_2nd)
timestamp2 = self.get_timestamp(ip_instance_2nd,
private_key=keypair['private_key'])
self.assertEqual(timestamp, timestamp2)
# snapshot a volume
- LOG.info("Creating snapshot from volume: %s" % volume_origin['id'])
+ LOG.info("Creating snapshot from volume: %s", volume_origin['id'])
snapshot = self._create_snapshot_from_volume(volume_origin['id'])
# create a 3rd instance from snapshot
- LOG.info("Creating third instance from snapshot: %s" % snapshot['id'])
+ LOG.info("Creating third instance from snapshot: %s", snapshot['id'])
volume = self.create_volume(snapshot_id=snapshot['id'],
size=snapshot['size'])
LOG.info("Booting third instance from snapshot")
@@ -157,7 +157,7 @@
LOG.info("Booted third instance %s", server_from_snapshot)
# check the content of written file
- LOG.info("Logging into third instance to get timestamp: %s" %
+ LOG.info("Logging into third instance to get timestamp: %s",
server_from_snapshot)
server_from_snapshot_ip = self.get_server_ip(server_from_snapshot)
timestamp3 = self.get_timestamp(server_from_snapshot_ip,
diff --git a/tempest/services/identity/__init__.py b/tempest/services/identity/__init__.py
deleted file mode 100644
index 53c223f..0000000
--- a/tempest/services/identity/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not
-# use this file except in compliance with the License. You may obtain a copy of
-# the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations under
-# the License.
-
-from tempest.lib.services.identity import v2
-from tempest.services.identity import v3
-
-__all__ = ['v2', 'v3']
diff --git a/tempest/services/identity/v3/__init__.py b/tempest/services/identity/v3/__init__.py
deleted file mode 100644
index 6e64a7d..0000000
--- a/tempest/services/identity/v3/__init__.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not
-# use this file except in compliance with the License. You may obtain a copy of
-# the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations under
-# the License.
-
-from tempest.lib.services.identity.v3.credentials_client import \
- CredentialsClient
-from tempest.lib.services.identity.v3.endpoints_client import EndPointsClient
-from tempest.lib.services.identity.v3.groups_client import GroupsClient
-from tempest.lib.services.identity.v3.identity_client import IdentityClient
-from tempest.lib.services.identity.v3.inherited_roles_client import \
- InheritedRolesClient
-from tempest.lib.services.identity.v3.policies_client import PoliciesClient
-from tempest.lib.services.identity.v3.projects_client import ProjectsClient
-from tempest.lib.services.identity.v3.regions_client import RegionsClient
-from tempest.lib.services.identity.v3.role_assignments_client import \
- RoleAssignmentsClient
-from tempest.lib.services.identity.v3.roles_client import RolesClient
-from tempest.lib.services.identity.v3.services_client import ServicesClient
-from tempest.lib.services.identity.v3.token_client import V3TokenClient
-from tempest.lib.services.identity.v3.trusts_client import TrustsClient
-from tempest.lib.services.identity.v3.users_client import UsersClient
-from tempest.services.identity.v3.json.domains_client import DomainsClient
-
-__all__ = ['CredentialsClient', 'EndPointsClient', 'GroupsClient',
- 'IdentityClient', 'InheritedRolesClient', 'PoliciesClient',
- 'ProjectsClient', 'RegionsClient', 'RoleAssignmentsClient',
- 'RolesClient', 'ServicesClient', 'V3TokenClient', 'TrustsClient',
- 'UsersClient', 'DomainsClient', ]
diff --git a/tempest/services/identity/v3/json/__init__.py b/tempest/services/identity/v3/json/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/identity/v3/json/__init__.py
+++ /dev/null
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 9445e34..6d656ec 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
from six.moves import http_client as httplib
from six.moves.urllib import parse as urlparse
@@ -189,7 +188,7 @@
# Send the PUT request and the headers including the "Expect" header
conn.putrequest('PUT', path)
- for header, value in six.iteritems(headers):
+ for header, value in headers.items():
conn.putheader(header, value)
conn.endheaders()
diff --git a/tempest/test.py b/tempest/test.py
index 4cc2a2b..039afa1 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -156,7 +156,7 @@
if status_code is None or status_code == exc_status_code:
LOG.error('Hints: This test was made for the bug %s. '
'The failure could be related to '
- 'https://launchpad.net/bugs/%s' % (bug, bug))
+ 'https://launchpad.net/bugs/%s', bug, bug)
raise exc
return wrapper
return decorator
@@ -219,7 +219,6 @@
"""
setUpClassCalled = False
- _service = None
# NOTE(andreaf) credentials holds a list of the credentials to be allocated
# at class setup time. Credential types can be 'primary', 'alt', 'admin' or
@@ -263,8 +262,8 @@
cls.resource_setup()
except Exception:
etype, value, trace = sys.exc_info()
- LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass." % (
- etype, cls.__name__))
+ LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass.",
+ etype, cls.__name__)
cls.tearDownClass()
try:
six.reraise(etype, value, trace)
@@ -296,9 +295,9 @@
# resources that were successfully setup in resource_cleanup,
# log AttributeError as info instead of exception.
if tetype is AttributeError and name == 'resources':
- LOG.info("tearDownClass of %s failed: %s" % (name, te))
+ LOG.info("tearDownClass of %s failed: %s", name, te)
else:
- LOG.exception("teardown of %s failed: %s" % (name, te))
+ LOG.exception("teardown of %s failed: %s", name, te)
if not etype:
etype, value, trace = sys_exec_info
# If exceptions were raised during teardown, and not before, re-raise
@@ -533,8 +532,7 @@
else:
raise lib_exc.InvalidCredentials(
"Invalid credentials type %s" % credential_type)
- manager = cls.client_manager(credentials=creds.credentials,
- service=cls._service)
+ manager = cls.client_manager(credentials=creds.credentials)
# NOTE(andreaf) Ensure credentials have user and project id fields.
# It may not be the case when using pre-provisioned credentials.
manager.auth_provider.set_auth()
diff --git a/tempest/test_discover/plugins.py b/tempest/test_discover/plugins.py
index f8d5d9d..abe2b73 100644
--- a/tempest/test_discover/plugins.py
+++ b/tempest/test_discover/plugins.py
@@ -13,8 +13,8 @@
# under the License.
import abc
-import logging
+from oslo_log import log as logging
import six
import stevedore
@@ -143,7 +143,7 @@
plug.obj.register_opts(conf)
except Exception:
LOG.exception('Plugin %s raised an exception trying to run '
- 'register_opts' % plug.name)
+ 'register_opts', plug.name)
def get_plugin_options_list(self):
plugin_options = []
@@ -163,4 +163,4 @@
plug.name, service_clients)
except Exception:
LOG.exception('Plugin %s raised an exception trying to run '
- 'get_service_clients' % plug.name)
+ 'get_service_clients', plug.name)
diff --git a/tempest/tests/cmd/test_account_generator.py b/tempest/tests/cmd/test_account_generator.py
index b08954f..6773b2f 100644
--- a/tempest/tests/cmd/test_account_generator.py
+++ b/tempest/tests/cmd/test_account_generator.py
@@ -75,7 +75,7 @@
fake_domain_list = {'domains': [{'id': 'fake_domain',
'name': 'Fake_Domain'}]}
self.useFixture(fixtures.MockPatch(''.join([
- 'tempest.services.identity.v3.json.domains_client.'
+ 'tempest.lib.services.identity.v3.domains_client.'
'DomainsClient.list_domains']),
return_value=fake_domain_list))
self.useFixture(fixtures.MockPatch(
@@ -121,7 +121,7 @@
super(TestAccountGeneratorV3, self).setUp()
fake_domain_list = {'domains': [{'id': 'fake_domain'}]}
self.useFixture(fixtures.MockPatch(''.join([
- 'tempest.services.identity.v3.json.domains_client.'
+ 'tempest.lib.services.identity.v3.domains_client.'
'DomainsClient.list_domains']),
return_value=fake_domain_list))
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index a90ca8a..b4fbd50 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -27,6 +27,7 @@
v2_tenants_client
from tempest.lib.services.identity.v2 import token_client as v2_token_client
from tempest.lib.services.identity.v2 import users_client as v2_users_client
+from tempest.lib.services.identity.v3 import domains_client
from tempest.lib.services.identity.v3 import identity_client as v3_iden_client
from tempest.lib.services.identity.v3 import projects_client as \
v3_projects_client
@@ -35,7 +36,6 @@
from tempest.lib.services.identity.v3 import users_client as \
v3_users_client
from tempest.lib.services.network import routers_client
-from tempest.services.identity.v3.json import domains_client
from tempest.tests import base
from tempest.tests import fake_config
from tempest.tests.lib import fake_http
diff --git a/tempest/tests/common/test_preprov_creds.py b/tempest/tests/common/test_preprov_creds.py
index f824b6c..1c9982c 100644
--- a/tempest/tests/common/test_preprov_creds.py
+++ b/tempest/tests/common/test_preprov_creds.py
@@ -101,7 +101,7 @@
preprov_creds.PreProvisionedCredentialProvider.HASH_CRED_FIELDS)
for account in accounts_list:
hash = hashlib.md5()
- account_for_hash = dict((k, v) for (k, v) in six.iteritems(account)
+ account_for_hash = dict((k, v) for (k, v) in account.items()
if k in hash_fields)
hash.update(six.text_type(account_for_hash).encode('utf-8'))
temp_hash = hash.hexdigest()
diff --git a/tempest/tests/lib/services/identity/v3/test_domains_client.py b/tempest/tests/lib/services/identity/v3/test_domains_client.py
new file mode 100644
index 0000000..f89ced7
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_domains_client.py
@@ -0,0 +1,138 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from tempest.lib.services.identity.v3 import domains_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestDomainsClient(base.BaseServiceTest):
+ FAKE_CREATE_DOMAIN = {
+ "domain": {
+ "description": "Domain description",
+ "enabled": True,
+ "name": "myDomain"
+ }
+ }
+
+ FAKE_DOMAIN_INFO = {
+ "domain": {
+ "description": "Used for swift functional testing",
+ "enabled": True,
+ "id": "5a75994a3",
+ "links": {
+ "self": "http://example.com/identity/v3/domains/5a75994a3"
+ },
+ "name": "swift_test"
+ }
+ }
+
+ FAKE_LIST_DOMAINS = {
+ "domains": [
+ {
+ "description": "Used for swift functional testing",
+ "enabled": True,
+ "id": "5a75994a3",
+ "links": {
+ "self": "http://example.com/identity/v3/domains/5a75994a3"
+ },
+ "name": "swift_test"
+ },
+ {
+ "description": "Owns users and tenants available on " +
+ "Identity API",
+ "enabled": True,
+ "id": "default",
+ "links": {
+ "self": "http://example.com/identity/v3/domains/default"
+ },
+ "name": "Default"
+ }
+ ],
+ "links": {
+ "next": None,
+ "previous": None,
+ "self": "http://example.com/identity/v3/domains"
+ }
+ }
+
+ def setUp(self):
+ super(TestDomainsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = domains_client.DomainsClient(fake_auth,
+ 'identity',
+ 'regionOne')
+
+ def _test_create_domain(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_domain,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_DOMAIN,
+ bytes_body,
+ status=201)
+
+ def _test_show_domain(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_domain,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_DOMAIN_INFO,
+ bytes_body,
+ domain_id="5a75994a3")
+
+ def _test_list_domains(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_domains,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_DOMAINS,
+ bytes_body)
+
+ def _test_update_domain(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_domain,
+ 'tempest.lib.common.rest_client.RestClient.patch',
+ self.FAKE_DOMAIN_INFO,
+ bytes_body,
+ domain_id="5a75994a3")
+
+ def test_create_domain_with_str_body(self):
+ self._test_create_domain()
+
+ def test_create_domain_with_bytes_body(self):
+ self._test_create_domain(bytes_body=True)
+
+ def test_show_domain_with_str_body(self):
+ self._test_show_domain()
+
+ def test_show_domain_with_bytes_body(self):
+ self._test_show_domain(bytes_body=True)
+
+ def test_list_domain_with_str_body(self):
+ self._test_list_domains()
+
+ def test_list_domain_with_bytes_body(self):
+ self._test_list_domains(bytes_body=True)
+
+ def test_update_domain_with_str_body(self):
+ self._test_update_domain()
+
+ def test_update_domain_with_bytes_body(self):
+ self._test_update_domain(bytes_body=True)
+
+ def test_delete_domain(self):
+ self.check_service_client_function(
+ self.client.delete_domain,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ domain_id="5a75994a3",
+ status=204)
diff --git a/tempest/tests/lib/services/image/v2/test_namespace_object_client.py b/tempest/tests/lib/services/image/v2/test_namespace_object_client.py
new file mode 100644
index 0000000..8d29660
--- /dev/null
+++ b/tempest/tests/lib/services/image/v2/test_namespace_object_client.py
@@ -0,0 +1,210 @@
+# Copyright 2016 EasyStack. 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.image.v2 import namespace_objects_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestNamespaceObjectClient(base.BaseServiceTest):
+ FAKE_CREATE_SHOW_OBJECTS = {
+ "created_at": "2016-09-19T18:20:56Z",
+ "description": "You can configure the CPU limits.",
+ "name": "CPU Limits",
+ "properties": {
+ "quota:cpu_period": {
+ "description": "Specifies the enforcement interval",
+ "maximum": 1000000,
+ "minimum": 1000,
+ "title": "Quota: CPU Period",
+ "type": "integer"
+ },
+ "quota:cpu_quota": {
+ "description": "Specifies the maximum allowed bandwidth ",
+ "title": "Quota: CPU Quota",
+ "type": "integer"
+ },
+ "quota:cpu_shares": {
+ "description": "Specifies the proportional weighted share.",
+ "title": "Quota: CPU Shares",
+ "type": "integer"
+ }
+ },
+ "required": [],
+ "schema": "/v2/schemas/metadefs/object",
+ "self": "/v2/metadefs/namespaces/OS::Compute::Quota/objects/CPU",
+ "updated_at": "2016-09-19T18:20:56Z"
+ }
+
+ FAKE_LIST_OBJECTS = {
+ "objects": [
+ {
+ "created_at": "2016-09-18T18:16:35Z",
+ "description": "You can configure the CPU limits.",
+ "name": "CPU Limits",
+ "properties": {
+ "quota:cpu_period": {
+ "description": "Specifies the enforcement interval ",
+ "maximum": 1000000,
+ "minimum": 1000,
+ "title": "Quota: CPU Period",
+ "type": "integer"
+ },
+ "quota:cpu_quota": {
+ "description": "Specifies the maximum.",
+ "title": "Quota: CPU Quota",
+ "type": "integer"
+ },
+ "quota:cpu_shares": {
+ "description": " Desc.",
+ "title": "Quota: CPU Shares",
+ "type": "integer"
+ }
+ },
+ "required": [],
+ "schema": "/v2/schemas/metadefs/object",
+ "self":
+ "/v2/metadefs/namespaces/OS::Compute::Quota/objects/CPU"
+ },
+ {
+ "created_at": "2016-09-18T18:16:35Z",
+ "description": "Using disk I/O quotas.",
+ "name": "Disk QoS",
+ "properties": {
+ "quota:disk_read_bytes_sec": {
+ "description": "Sets disk I/O quota.",
+ "title": "Quota: Disk read bytes / sec",
+ "type": "integer"
+ },
+ "quota:disk_read_iops_sec": {
+ "description": "Sets disk I/O quota",
+ "title": "Quota: Disk read IOPS / sec",
+ "type": "integer"
+ },
+ "quota:disk_total_bytes_sec": {
+ "description": "Sets disk I/O quota.",
+ "title": "Quota: Disk Total Bytes / sec",
+ "type": "integer"
+ },
+ "quota:disk_total_iops_sec": {
+ "description": "Sets disk I/O quota.",
+ "title": "Quota: Disk Total IOPS / sec",
+ "type": "integer"
+ },
+ "quota:disk_write_bytes_sec": {
+ "description": "Sets disk I/O quota.",
+ "title": "Quota: Disk Write Bytes / sec",
+ "type": "integer"
+ },
+ "quota:disk_write_iops_sec": {
+ "description": "Sets disk I/O quota.",
+ "title": "Quota: Disk Write IOPS / sec",
+ "type": "integer"
+ }
+ },
+ "required": [],
+ "schema": "/v2/schemas/metadefs/object",
+ "self":
+ "/v2/metadefs/namespaces/OS::Compute::Quota/objects/Disk QoS"
+ },
+ ],
+ "schema": "v2/schemas/metadefs/objects"
+ }
+
+ FAKE_UPDATE_OBJECTS = {
+ "description": "You can configure the CPU limits.",
+ "name": "CPU",
+ "properties": {
+ "quota:cpu_shares": {
+ "description": "Specify.",
+ "title": "Quota: CPU Shares",
+ "type": "integer"
+ }
+ },
+ "required": []
+ }
+
+ def setUp(self):
+ super(TestNamespaceObjectClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = namespace_objects_client.NamespaceObjectsClient(
+ fake_auth, 'image', 'regionOne')
+
+ def _test_create_namespace_objects(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_namespace_object,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_SHOW_OBJECTS,
+ bytes_body, status=201,
+ namespace="OS::Compute::Hypervisor",
+ object_name="OS::Glance::Image")
+
+ def _test_list_namespace_objects(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_namespace_objects,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_OBJECTS,
+ bytes_body,
+ namespace="OS::Compute::Hypervisor")
+
+ def _test_show_namespace_objects(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_namespace_object,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_CREATE_SHOW_OBJECTS,
+ bytes_body,
+ namespace="OS::Compute::Hypervisor",
+ object_name="OS::Glance::Image")
+
+ def _test_update_namespace_objects(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_namespace_object,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_UPDATE_OBJECTS,
+ bytes_body,
+ namespace="OS::Compute::Hypervisor",
+ object_name="OS::Glance::Image",
+ name="CPU")
+
+ def test_create_namespace_object_with_str_body(self):
+ self._test_create_namespace_objects()
+
+ def test_create_namespace_object_with_bytes_body(self):
+ self._test_create_namespace_objects(bytes_body=True)
+
+ def test_list_namespace_object_with_str_body(self):
+ self._test_list_namespace_objects()
+
+ def test_list_namespace_object_with_bytes_body(self):
+ self._test_list_namespace_objects(bytes_body=True)
+
+ def test_show_namespace_object_with_str_body(self):
+ self._test_show_namespace_objects()
+
+ def test_show_namespace_object_with_bytes_body(self):
+ self._test_show_namespace_objects(bytes_body=True)
+
+ def test_update_namespace_object_with_str_body(self):
+ self._test_update_namespace_objects()
+
+ def test_update_namespace_object_with_bytes_body(self):
+ self._test_update_namespace_objects(bytes_body=True)
+
+ def test_delete_namespace_objects(self):
+ self.check_service_client_function(
+ self.client.delete_namespace_object,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {}, namespace="OS::Compute::Hypervisor",
+ object_name="OS::Glance::Image",
+ status=204)
diff --git a/tempest/tests/lib/test_tempest_lib.py b/tempest/tests/lib/test_tempest_lib.py
index d70e53d..4d9f099 100644
--- a/tempest/tests/lib/test_tempest_lib.py
+++ b/tempest/tests/lib/test_tempest_lib.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
diff --git a/tempest/tests/negative/__init__.py b/tempest/tests/negative/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/tests/negative/__init__.py
+++ /dev/null
diff --git a/tempest/tests/services/object_storage/test_object_client.py b/tempest/tests/services/object_storage/test_object_client.py
index cc1dc1a..748614c 100644
--- a/tempest/tests/services/object_storage/test_object_client.py
+++ b/tempest/tests/services/object_storage/test_object_client.py
@@ -15,7 +15,6 @@
import mock
-import six
from tempest.lib import exceptions
from tempest.services.object_storage import object_client
@@ -85,7 +84,7 @@
# Verify that headers were written, including "Expect:100-continue"
calls = []
- for header, value in six.iteritems(expected_hdrs):
+ for header, value in expected_hdrs.items():
calls.append(mock.call(header, value))
mock_poc.return_value.putheader.assert_has_calls(calls, False)
diff --git a/tox.ini b/tox.ini
index 7a36e84..46823d8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -146,7 +146,7 @@
ignore = E125,E123,E129
show-source = True
exclude = .git,.venv,.tox,dist,doc,*egg
-enable-extensions = H106,H203
+enable-extensions = H106,H203,H904
[testenv:releasenotes]
commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html