Merge "Fix volume attach tests failing when using FIP as ssh method"
diff --git a/doc/source/conf.py b/doc/source/conf.py
index cbfcc09..f11d96a 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -27,6 +27,8 @@
import subprocess
import warnings
+import openstackdocstheme
+
# Build the plugin registry
def build_plugin_registry(app):
root_dir = os.path.dirname(
@@ -117,7 +119,7 @@
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'nature'
+html_theme = 'openstackdocs'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@@ -125,7 +127,7 @@
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+html_theme_path = [openstackdocstheme.get_html_theme_path()]
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 1264ecc..c4affd2 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -2,18 +2,16 @@
Tempest Testing Project
=======================
---------
Overview
---------
+========
.. toctree::
:maxdepth: 2
overview
-------------
Field Guides
-------------
+============
Tempest contains tests of many different types, the field guides
attempt to explain these in a way that makes it easy to understand
where your test contributions should go.
@@ -26,11 +24,9 @@
field_guide/scenario
field_guide/unit_tests
-=========
For users
=========
----------------------------
Tempest Configuration Guide
---------------------------
@@ -40,7 +36,6 @@
configuration
sampleconf
----------------------
Command Documentation
---------------------
@@ -53,11 +48,9 @@
workspace
run
-==============
For developers
==============
------------
Development
-----------
@@ -70,7 +63,6 @@
test_removal
write_tests
--------
Plugins
-------
@@ -80,7 +72,6 @@
plugin
plugin-registry
--------
Library
-------
@@ -89,7 +80,6 @@
library
-==================
Indices and tables
==================
diff --git a/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml b/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml
new file mode 100644
index 0000000..0de1803
--- /dev/null
+++ b/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Add show host API to the volume v2 hosts_client library.
+ This feature enables the possibility to show details for a host.
diff --git a/releasenotes/notes/add-show-volume-summary-api-to-v3-volumes-client-96e7b01abdb5c9c3.yaml b/releasenotes/notes/add-show-volume-summary-api-to-v3-volumes-client-96e7b01abdb5c9c3.yaml
new file mode 100644
index 0000000..361e387
--- /dev/null
+++ b/releasenotes/notes/add-show-volume-summary-api-to-v3-volumes-client-96e7b01abdb5c9c3.yaml
@@ -0,0 +1,10 @@
+---
+features:
+ - |
+ Define v3 volumes_client for the volume service as a library interface,
+ allowing other projects to use this module as a stable library without
+ maintenance changes.
+ Add show volume summary API to v3 volumes_client library, min_microversion
+ of this API is 3.12.
+
+ * volumes_client(v3)
diff --git a/releasenotes/notes/add-volume-backup-force-delete-af0156651a0cbf7f.yaml b/releasenotes/notes/add-volume-backup-force-delete-af0156651a0cbf7f.yaml
deleted file mode 100644
index 71bbfcb..0000000
--- a/releasenotes/notes/add-volume-backup-force-delete-af0156651a0cbf7f.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
----
-features:
- - |
- As in the [doc]:
- https://developer.openstack.org/api-ref/block-storage/v3/
- #force-delete-a-backup.
-
- * Force-deletes a backup(v2)
-
diff --git a/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml b/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml
index dc4ed27..1ae251c 100644
--- a/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml
+++ b/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml
@@ -6,5 +6,5 @@
compute_images_client and Glance v1 APIs are removed in volume tests.
upgrade:
- |
- Swith to use Glance v2 APIs in volume tests, by adding the Glance v2 client
- images_client.
+ Switch to use Glance v2 APIs in volume tests, by adding the Glance v2
+ client images_client.
diff --git a/releasenotes/notes/remove-heat-tests-9efb42cac3e0b306.yaml b/releasenotes/notes/remove-heat-tests-9efb42cac3e0b306.yaml
new file mode 100644
index 0000000..4d0f3ce
--- /dev/null
+++ b/releasenotes/notes/remove-heat-tests-9efb42cac3e0b306.yaml
@@ -0,0 +1,4 @@
+---
+upgrade:
+ - The Heat API tests have been removed from tempest, they were unmaintained.
+ The future direction of api test for heat is their in-tree Gabbi tests
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index 97e3a4d..d240467 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -111,7 +111,7 @@
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'default'
+html_theme = 'openstackdocs'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@@ -119,7 +119,9 @@
# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-# html_theme_path = []
+import openstackdocstheme
+
+html_theme_path = [openstackdocstheme.get_html_theme_path()]
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index adec7a7..d2be814 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -1,5 +1,5 @@
===========================
- tempest Release Notes
+ Tempest Release Notes
===========================
.. toctree::
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 79d03f4..902ea9a 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -59,15 +59,20 @@
msg += " for hypervisor_type %s" % CONF.compute.hypervisor_type
raise testtools.TestCase.failureException(msg)
+ def _create_test_aggregate(self, **kwargs):
+ if 'name' not in kwargs:
+ kwargs['name'] = data_utils.rand_name(self.aggregate_name_prefix)
+ aggregate = self.client.create_aggregate(**kwargs)['aggregate']
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.client.delete_aggregate, aggregate['id'])
+ self.assertEqual(kwargs['name'], aggregate['name'])
+
+ return aggregate
+
@decorators.idempotent_id('0d148aa3-d54c-4317-aa8d-42040a475e20')
def test_aggregate_create_delete(self):
# Create and delete an aggregate.
- aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- aggregate = (self.client.create_aggregate(name=aggregate_name)
- ['aggregate'])
- self.addCleanup(test_utils.call_and_ignore_notfound_exc,
- self.client.delete_aggregate, aggregate['id'])
- self.assertEqual(aggregate_name, aggregate['name'])
+ aggregate = self._create_test_aggregate()
self.assertIsNone(aggregate['availability_zone'])
self.client.delete_aggregate(aggregate['id'])
@@ -76,13 +81,8 @@
@decorators.idempotent_id('5873a6f8-671a-43ff-8838-7ce430bb6d0b')
def test_aggregate_create_delete_with_az(self):
# Create and delete an aggregate.
- aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
az_name = data_utils.rand_name(self.az_name_prefix)
- aggregate = self.client.create_aggregate(
- name=aggregate_name, availability_zone=az_name)['aggregate']
- self.addCleanup(test_utils.call_and_ignore_notfound_exc,
- self.client.delete_aggregate, aggregate['id'])
- self.assertEqual(aggregate_name, aggregate['name'])
+ aggregate = self._create_test_aggregate(availability_zone=az_name)
self.assertEqual(az_name, aggregate['availability_zone'])
self.client.delete_aggregate(aggregate['id'])
@@ -91,11 +91,7 @@
@decorators.idempotent_id('68089c38-04b1-4758-bdf0-cf0daec4defd')
def test_aggregate_create_verify_entry_in_list(self):
# Create an aggregate and ensure it is listed.
- aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- aggregate = (self.client.create_aggregate(name=aggregate_name)
- ['aggregate'])
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-
+ aggregate = self._create_test_aggregate()
aggregates = self.client.list_aggregates()['aggregates']
self.assertIn((aggregate['id'], aggregate['availability_zone']),
map(lambda x: (x['id'], x['availability_zone']),
@@ -104,11 +100,7 @@
@decorators.idempotent_id('36ec92ca-7a73-43bc-b920-7531809e8540')
def test_aggregate_create_update_metadata_get_details(self):
# Create an aggregate and ensure its details are returned.
- aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- aggregate = (self.client.create_aggregate(name=aggregate_name)
- ['aggregate'])
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-
+ aggregate = self._create_test_aggregate()
body = self.client.show_aggregate(aggregate['id'])['aggregate']
self.assertEqual(aggregate['name'], body['name'])
self.assertEqual(aggregate['availability_zone'],
@@ -129,11 +121,9 @@
# Update an aggregate and ensure properties are updated correctly
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
az_name = data_utils.rand_name(self.az_name_prefix)
- aggregate = self.client.create_aggregate(
- name=aggregate_name, availability_zone=az_name)['aggregate']
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+ aggregate = self._create_test_aggregate(
+ name=aggregate_name, availability_zone=az_name)
- self.assertEqual(aggregate_name, aggregate['name'])
self.assertEqual(az_name, aggregate['availability_zone'])
self.assertIsNotNone(aggregate['id'])
@@ -159,9 +149,7 @@
# Add a host to the given aggregate and remove.
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- aggregate = (self.client.create_aggregate(name=aggregate_name)
- ['aggregate'])
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+ aggregate = self._create_test_aggregate(name=aggregate_name)
body = (self.client.add_host(aggregate['id'], host=self.host)
['aggregate'])
@@ -182,9 +170,8 @@
# Add a host to the given aggregate and list.
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- aggregate = (self.client.create_aggregate(name=aggregate_name)
- ['aggregate'])
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+ aggregate = self._create_test_aggregate(name=aggregate_name)
+
self.client.add_host(aggregate['id'], host=self.host)
self.addCleanup(self.client.remove_host, aggregate['id'],
host=self.host)
@@ -202,9 +189,8 @@
# Add a host to the given aggregate and get details.
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- aggregate = (self.client.create_aggregate(name=aggregate_name)
- ['aggregate'])
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+ aggregate = self._create_test_aggregate(name=aggregate_name)
+
self.client.add_host(aggregate['id'], host=self.host)
self.addCleanup(self.client.remove_host, aggregate['id'],
host=self.host)
@@ -218,11 +204,9 @@
def test_aggregate_add_host_create_server_with_az(self):
# Add a host to the given aggregate and create a server.
self.useFixture(fixtures.LockFixture('availability_zone'))
- aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
az_name = data_utils.rand_name(self.az_name_prefix)
- aggregate = self.client.create_aggregate(
- name=aggregate_name, availability_zone=az_name)['aggregate']
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+ aggregate = self._create_test_aggregate(availability_zone=az_name)
+
self.client.add_host(aggregate['id'], host=self.host)
self.addCleanup(self.client.remove_host, aggregate['id'],
host=self.host)
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index b0f18d7..ca53696 100644
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -124,8 +124,8 @@
data_utils.rand_uuid())
@decorators.idempotent_id('b0b17f83-d14e-4fc4-8f31-bcc9f3cfa629')
- @testtools.skipUnless(CONF.compute_feature_enabled.resize,
- 'Resize not available.')
+ @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
+ 'Cold migration not available.')
@testtools.skipUnless(CONF.compute_feature_enabled.suspend,
'Suspend is not available.')
@decorators.attr(type=['negative'])
diff --git a/tempest/api/compute/admin/test_servers_on_multinodes.py b/tempest/api/compute/admin/test_servers_on_multinodes.py
index 6a2e5e9..858998a 100644
--- a/tempest/api/compute/admin/test_servers_on_multinodes.py
+++ b/tempest/api/compute/admin/test_servers_on_multinodes.py
@@ -25,6 +25,12 @@
class ServersOnMultiNodesTest(base.BaseV2ComputeAdminTest):
@classmethod
+ def resource_setup(cls):
+ super(ServersOnMultiNodesTest, cls).resource_setup()
+ cls.server01 = cls.create_test_server(wait_until='ACTIVE')['id']
+ cls.host01 = cls._get_host(cls.server01)
+
+ @classmethod
def skip_checks(cls):
super(ServersOnMultiNodesTest, cls).skip_checks()
@@ -32,8 +38,9 @@
raise cls.skipException(
"Less than 2 compute nodes, skipping multi-nodes test.")
- def _get_host(self, server_id):
- return self.os_admin.servers_client.show_server(
+ @classmethod
+ def _get_host(cls, server_id):
+ return cls.os_admin.servers_client.show_server(
server_id)['server']['OS-EXT-SRV-ATTR:host']
@decorators.idempotent_id('26a9d5df-6890-45f2-abc4-a659290cb130')
@@ -41,40 +48,31 @@
test.is_scheduler_filter_enabled("SameHostFilter"),
'SameHostFilter is not available.')
def test_create_servers_on_same_host(self):
- server01 = self.create_test_server(wait_until='ACTIVE')['id']
-
- hints = {'same_host': server01}
+ hints = {'same_host': self.server01}
server02 = self.create_test_server(scheduler_hints=hints,
wait_until='ACTIVE')['id']
- host01 = self._get_host(server01)
host02 = self._get_host(server02)
- self.assertEqual(host01, host02)
+ self.assertEqual(self.host01, host02)
@decorators.idempotent_id('cc7ca884-6e3e-42a3-a92f-c522fcf25e8e')
@testtools.skipUnless(
test.is_scheduler_filter_enabled("DifferentHostFilter"),
'DifferentHostFilter is not available.')
def test_create_servers_on_different_hosts(self):
- server01 = self.create_test_server(wait_until='ACTIVE')['id']
-
- hints = {'different_host': server01}
+ hints = {'different_host': self.server01}
server02 = self.create_test_server(scheduler_hints=hints,
wait_until='ACTIVE')['id']
- host01 = self._get_host(server01)
host02 = self._get_host(server02)
- self.assertNotEqual(host01, host02)
+ self.assertNotEqual(self.host01, host02)
@decorators.idempotent_id('7869cc84-d661-4e14-9f00-c18cdc89cf57')
@testtools.skipUnless(
test.is_scheduler_filter_enabled("DifferentHostFilter"),
'DifferentHostFilter is not available.')
def test_create_servers_on_different_hosts_with_list_of_servers(self):
- server01 = self.create_test_server(wait_until='ACTIVE')['id']
-
# This scheduler-hint supports list of servers also.
- hints = {'different_host': [server01]}
+ hints = {'different_host': [self.server01]}
server02 = self.create_test_server(scheduler_hints=hints,
wait_until='ACTIVE')['id']
- host01 = self._get_host(server01)
host02 = self._get_host(server02)
- self.assertNotEqual(host01, host02)
+ self.assertNotEqual(self.host01, host02)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index a5ee716..141b9f3 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -123,10 +123,13 @@
@classmethod
def resource_cleanup(cls):
- cls.clear_images()
+ cls.clear_resources('images', cls.images,
+ cls.compute_images_client.delete_image)
cls.clear_servers()
- cls.clear_security_groups()
- cls.clear_server_groups()
+ cls.clear_resources('security groups', cls.security_groups,
+ cls.security_groups_client.delete_security_group)
+ cls.clear_resources('server groups', cls.server_groups,
+ cls.server_groups_client.delete_server_group)
cls.clear_volumes()
super(BaseV2ComputeTest, cls).resource_cleanup()
@@ -172,42 +175,19 @@
raise
@classmethod
- def clear_images(cls):
- LOG.debug('Clearing images: %s', ','.join(cls.images))
- for image_id in cls.images:
+ def clear_resources(cls, resource_name, resources, resource_del_func):
+ LOG.debug('Clearing %s: %s', resource_name,
+ ','.join(map(str, resources)))
+ for res_id in resources:
try:
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)
-
- @classmethod
- def clear_security_groups(cls):
- LOG.debug('Clearing security groups: %s', ','.join(
- str(sg['id']) for sg in cls.security_groups))
- for sg in cls.security_groups:
- try:
- test_utils.call_and_ignore_notfound_exc(
- cls.security_groups_client.delete_security_group, sg['id'])
+ resource_del_func, res_id)
except Exception as exc:
- LOG.info('Exception raised deleting security group %s',
- sg['id'])
+ LOG.exception('Exception raised deleting %s: %s',
+ resource_name, res_id)
LOG.exception(exc)
@classmethod
- def clear_server_groups(cls):
- LOG.debug('Clearing server groups: %s', ','.join(cls.server_groups))
- for server_group_id in cls.server_groups:
- try:
- test_utils.call_and_ignore_notfound_exc(
- cls.server_groups_client.delete_server_group,
- server_group_id
- )
- except Exception:
- LOG.exception('Exception raised deleting server-group %s',
- server_group_id)
-
- @classmethod
def create_test_server(cls, validatable=False, volume_backed=False,
**kwargs):
"""Wrapper utility that returns a test server.
@@ -243,7 +223,7 @@
description = data_utils.rand_name('description')
body = cls.security_groups_client.create_security_group(
name=name, description=description)['security_group']
- cls.security_groups.append(body)
+ cls.security_groups.append(body['id'])
return body
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index db24174..83447b6 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -24,6 +24,11 @@
class ImagesOneServerTestJSON(base.BaseV2ComputeTest):
@classmethod
+ def resource_setup(cls):
+ super(ImagesOneServerTestJSON, cls).resource_setup()
+ cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id']
+
+ @classmethod
def skip_checks(cls):
super(ImagesOneServerTestJSON, cls).skip_checks()
if not CONF.service_available.glance:
@@ -46,12 +51,10 @@
@decorators.idempotent_id('3731d080-d4c5-4872-b41a-64d0d0021314')
def test_create_delete_image(self):
- server_id = self.create_test_server(wait_until='ACTIVE')['id']
-
# Create a new image
name = data_utils.rand_name('image')
meta = {'image_type': 'test'}
- image = self.create_image_from_server(server_id, name=name,
+ image = self.create_image_from_server(self.server_id, name=name,
metadata=meta,
wait_until='ACTIVE')
@@ -76,8 +79,6 @@
@decorators.idempotent_id('3b7c6fe4-dfe7-477c-9243-b06359db51e6')
def test_create_image_specify_multibyte_character_image_name(self):
- server_id = self.create_test_server(wait_until='ACTIVE')['id']
-
# prefix character is:
# http://www.fileformat.info/info/unicode/char/1F4A9/index.htm
@@ -85,6 +86,6 @@
# #1370954 in glance which will 500 if mysql is used as the
# backend and it attempts to store a 4 byte utf-8 character
utf8_name = data_utils.rand_name(b'\xe2\x82\xa1'.decode('utf-8'))
- body = self.client.create_image(server_id, name=utf8_name)
+ body = self.client.create_image(self.server_id, name=utf8_name)
image_id = data_utils.parse_image_id(body.response['location'])
self.addCleanup(self.client.delete_image, image_id)
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index d89f44c..527f4bd 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -34,13 +34,12 @@
# by the test methods in this class. These
# servers are cleaned up automatically in the
# tearDownClass method of the super-class.
- cls.deleted_fixtures = []
- cls.create_test_server(wait_until='ACTIVE', min_count=2)
+ body = cls.create_test_server(wait_until='ACTIVE', min_count=3)
- srv = cls.create_test_server(wait_until='ACTIVE')
- cls.client.delete_server(srv['id'])
- waiters.wait_for_server_termination(cls.client, srv['id'])
- cls.deleted_fixtures.append(srv)
+ # delete one of the created servers
+ cls.deleted_id = body['server']['id']
+ cls.client.delete_server(cls.deleted_id)
+ waiters.wait_for_server_termination(cls.client, cls.deleted_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('24a26f1a-1ddc-4eea-b0d7-a90cc874ad8f')
@@ -49,9 +48,8 @@
# List servers and verify server not returned
body = self.client.list_servers()
servers = body['servers']
- deleted_ids = [s['id'] for s in self.deleted_fixtures]
actual = [srv for srv in servers
- if srv['id'] in deleted_ids]
+ if srv['id'] == self.deleted_id]
self.assertEqual([], actual)
@decorators.attr(type=['negative'])
@@ -136,9 +134,8 @@
@decorators.idempotent_id('93055106-2d34-46fe-af68-d9ddbf7ee570')
def test_list_servers_detail_server_is_deleted(self):
# Server details are not listed for a deleted server
- deleted_ids = [s['id'] for s in self.deleted_fixtures]
body = self.client.list_servers(detail=True)
servers = body['servers']
actual = [srv for srv in servers
- if srv['id'] in deleted_ids]
+ if srv['id'] == self.deleted_id]
self.assertEqual([], actual)
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 8808510..76b9c44 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -168,6 +168,9 @@
@decorators.idempotent_id('aaa6cdf3-55a7-461a-add9-1c8596b9a07c')
def test_rebuild_server(self):
+ # Get the IPs the server has before rebuilding it
+ original_addresses = (self.client.show_server(self.server_id)['server']
+ ['addresses'])
# The server should be rebuilt using the provided image and data
meta = {'rebuild': 'server'}
new_name = data_utils.rand_name(self.__class__.__name__ + '-server')
@@ -197,6 +200,7 @@
rebuilt_image_id = server['image']['id']
self.assertTrue(self.image_ref_alt.endswith(rebuilt_image_id))
self.assertEqual(new_name, server['name'])
+ self.assertEqual(original_addresses, server['addresses'])
if CONF.validation.run_validation:
# Authentication is attempted in the following order of priority:
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index 8760af6..83151b3 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -42,81 +42,50 @@
def resource_setup(cls):
super(ServerRescueTestJSON, cls).resource_setup()
- # Floating IP creation
- body = cls.floating_ips_client.create_floating_ip(
- pool=CONF.network.floating_network_name)['floating_ip']
- cls.floating_ip_id = str(body['id']).strip()
- cls.floating_ip = str(body['ip']).strip()
-
- # Security group creation
- cls.sg_name = data_utils.rand_name('sg')
- sg_desc = data_utils.rand_name('sg-desc')
- cls.sg = cls.security_groups_client.create_security_group(
- name=cls.sg_name, description=sg_desc)['security_group']
- cls.sg_id = cls.sg['id']
-
- cls.password = data_utils.rand_password()
- # Server for positive tests
- server = cls.create_test_server(adminPass=cls.password,
+ password = data_utils.rand_password()
+ server = cls.create_test_server(adminPass=password,
wait_until='ACTIVE')
- cls.server_id = server['id']
-
- @classmethod
- def resource_cleanup(cls):
- # Deleting the floating IP which is created in this method
- cls.floating_ips_client.delete_floating_ip(cls.floating_ip_id)
- cls.sg = cls.security_groups_client.delete_security_group(
- cls.sg_id)
- super(ServerRescueTestJSON, cls).resource_cleanup()
-
- def _unrescue(self, server_id):
- self.servers_client.unrescue_server(server_id)
- waiters.wait_for_server_status(self.servers_client, server_id,
- 'ACTIVE')
+ cls.servers_client.rescue_server(server['id'], adminPass=password)
+ waiters.wait_for_server_status(cls.servers_client, server['id'],
+ 'RESCUE')
+ cls.rescued_server_id = server['id']
@decorators.idempotent_id('fd032140-714c-42e4-a8fd-adcd8df06be6')
def test_rescue_unrescue_instance(self):
- self.servers_client.rescue_server(
- self.server_id, adminPass=self.password)
- waiters.wait_for_server_status(self.servers_client, self.server_id,
+ password = data_utils.rand_password()
+ server = self.create_test_server(adminPass=password,
+ wait_until='ACTIVE')
+ self.servers_client.rescue_server(server['id'], adminPass=password)
+ waiters.wait_for_server_status(self.servers_client, server['id'],
'RESCUE')
- self.servers_client.unrescue_server(self.server_id)
- waiters.wait_for_server_status(self.servers_client, self.server_id,
+ self.servers_client.unrescue_server(server['id'])
+ waiters.wait_for_server_status(self.servers_client, server['id'],
'ACTIVE')
@decorators.idempotent_id('4842e0cf-e87d-4d9d-b61f-f4791da3cacc')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_rescued_vm_associate_dissociate_floating_ip(self):
- # Rescue the server
- self.servers_client.rescue_server(
- self.server_id, adminPass=self.password)
- waiters.wait_for_server_status(self.servers_client, self.server_id,
- 'RESCUE')
- self.addCleanup(self._unrescue, self.server_id)
-
# Association of floating IP to a rescued vm
- client = self.floating_ips_client
- client.associate_floating_ip_to_server(self.floating_ip,
- self.server_id)
+ floating_ip_body = self.floating_ips_client.create_floating_ip(
+ pool=CONF.network.floating_network_name)['floating_ip']
+ self.addCleanup(self.floating_ips_client.delete_floating_ip,
+ floating_ip_body['id'])
+
+ self.floating_ips_client.associate_floating_ip_to_server(
+ str(floating_ip_body['ip']).strip(), self.rescued_server_id)
# Disassociation of floating IP that was associated in this method
- client.disassociate_floating_ip_from_server(self.floating_ip,
- self.server_id)
+ self.floating_ips_client.disassociate_floating_ip_from_server(
+ str(floating_ip_body['ip']).strip(), self.rescued_server_id)
@decorators.idempotent_id('affca41f-7195-492d-8065-e09eee245404')
def test_rescued_vm_add_remove_security_group(self):
- # Rescue the server
- self.servers_client.rescue_server(
- self.server_id, adminPass=self.password)
- waiters.wait_for_server_status(self.servers_client, self.server_id,
- 'RESCUE')
- self.addCleanup(self._unrescue, self.server_id)
-
# Add Security group
- self.servers_client.add_security_group(self.server_id,
- name=self.sg_name)
+ sg = self.create_security_group()
+ self.servers_client.add_security_group(self.rescued_server_id,
+ name=sg['name'])
# Delete Security group
- self.servers_client.remove_security_group(self.server_id,
- name=self.sg_name)
+ self.servers_client.remove_security_group(self.rescued_server_id,
+ name=sg['name'])
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index a480a15..7943b37 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -551,7 +551,7 @@
def setUp(self):
super(ServersNegativeTestMultiTenantJSON, self).setUp()
try:
- waiters.wait_for_server_status(self.client, self.server_id,
+ waiters.wait_for_server_status(self.servers_client, self.server_id,
'ACTIVE')
except Exception:
self.__class__.server_id = self.rebuild_server(self.server_id)
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index 3b41775..42e13bd 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -35,16 +35,18 @@
raise self.skipException('There are not any extensions configured')
extensions = self.extensions_client.list_extensions()['extensions']
ext = CONF.compute_feature_enabled.api_extensions[0]
- if ext == 'all':
- self.assertIn('Hosts', map(lambda x: x['name'], extensions))
- elif ext:
- self.assertIn(ext, map(lambda x: x['alias'], extensions))
- else:
- 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))
+ if ext == 'all':
+ self.assertIn('Hosts', map(lambda x: x['name'], extensions))
+ elif ext:
+ self.assertIn(ext, extension_list)
+ else:
+ raise self.skipException('There are not any extensions configured')
+
@decorators.idempotent_id('05762f39-bdfa-4cdb-9b46-b78f8e78e2fd')
@test.requires_ext(extension='os-consoles', service='compute')
def test_get_extension(self):
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 4665eb1..ed5f9a6 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -114,51 +114,35 @@
def test_list_get_volume_attachments(self):
# List volume attachment of the server
server = self._create_server()
- volume = self.create_volume()
- attachment = self.attach_volume(server, volume,
- device=('/dev/%s' % self.device))
+ volume_1st = self.create_volume()
+ attachment_1st = self.attach_volume(server, volume_1st,
+ device=('/dev/%s' % self.device))
body = self.servers_client.list_volume_attachments(
server['id'])['volumeAttachments']
self.assertEqual(1, len(body))
- self.assertIn(attachment, body)
+ self.assertIn(attachment_1st, body)
# Get volume attachment of the server
body = self.servers_client.show_volume_attachment(
server['id'],
- attachment['id'])['volumeAttachment']
+ attachment_1st['id'])['volumeAttachment']
self.assertEqual(server['id'], body['serverId'])
- self.assertEqual(volume['id'], body['volumeId'])
- self.assertEqual(attachment['id'], body['id'])
+ self.assertEqual(volume_1st['id'], body['volumeId'])
+ self.assertEqual(attachment_1st['id'], body['id'])
- @decorators.idempotent_id('757d488b-a951-4bc7-b3cd-f417028da08a')
- def test_list_get_two_volume_attachments(self):
- # NOTE: This test is using the volume device auto-assignment
- # without specifying the device ("/dev/sdb", etc). The feature
- # is supported since Nova Liberty release or later. So this should
- # be skipped on older clouds.
- server = self._create_server()
- volume_1st = self.create_volume()
+ # attach one more volume to server
volume_2nd = self.create_volume()
- attachment_1st = self.attach_volume(server, volume_1st)
attachment_2nd = self.attach_volume(server, volume_2nd)
-
body = self.servers_client.list_volume_attachments(
server['id'])['volumeAttachments']
self.assertEqual(2, len(body))
- body = self.servers_client.show_volume_attachment(
- server['id'],
- attachment_1st['id'])['volumeAttachment']
- self.assertEqual(server['id'], body['serverId'])
- self.assertEqual(attachment_1st['volumeId'], body['volumeId'])
- self.assertEqual(attachment_1st['id'], body['id'])
-
- body = self.servers_client.show_volume_attachment(
- server['id'],
- attachment_2nd['id'])['volumeAttachment']
- self.assertEqual(server['id'], body['serverId'])
- self.assertEqual(attachment_2nd['volumeId'], body['volumeId'])
- self.assertEqual(attachment_2nd['id'], body['id'])
+ for attachment in [attachment_1st, attachment_2nd]:
+ body = self.servers_client.show_volume_attachment(
+ server['id'], attachment['id'])['volumeAttachment']
+ self.assertEqual(server['id'], body['serverId'])
+ self.assertEqual(attachment['volumeId'], body['volumeId'])
+ self.assertEqual(attachment['id'], body['id'])
class AttachVolumeShelveTestJSON(AttachVolumeTestJSON):
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index adb467c..6d42b2a 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -215,7 +215,7 @@
implies_role_id)
@decorators.idempotent_id('c90c316c-d706-4728-bcba-eb1912081b69')
- def test_implied_roles_create_delete(self):
+ def test_implied_roles_create_check_show_delete(self):
prior_role_id = self.roles[0]['id']
implies_role_id = self.roles[1]['id']
@@ -224,9 +224,19 @@
ignore_not_found=True)
# Check if the inference rule exists
- self.roles_client.show_role_inference_rule(
+ self.roles_client.check_role_inference_rule(
prior_role_id, implies_role_id)
+ # Show the inference rule and check its elements
+ resp_body = self.roles_client.show_role_inference_rule(
+ prior_role_id, implies_role_id)
+ self.assertIn('role_inference', resp_body)
+ role_inference = resp_body['role_inference']
+ for key1 in ['prior_role', 'implies']:
+ self.assertIn(key1, role_inference)
+ for key2 in ['id', 'links', 'name']:
+ self.assertIn(key2, role_inference[key1])
+
# Delete the inference rule
self.roles_client.delete_role_inference_rule(
prior_role_id, implies_role_id)
diff --git a/tempest/api/network/test_metering_extensions.py b/tempest/api/network/admin/test_metering_extensions.py
similarity index 87%
rename from tempest/api/network/test_metering_extensions.py
rename to tempest/api/network/admin/test_metering_extensions.py
index 18dccc3..3f94868 100644
--- a/tempest/api/network/test_metering_extensions.py
+++ b/tempest/api/network/admin/test_metering_extensions.py
@@ -45,6 +45,28 @@
remote_ip_prefix, direction,
metering_label_id=cls.metering_label['id'])
+ @classmethod
+ def create_metering_label(cls, name, description):
+ """Wrapper utility that returns a test metering label."""
+ body = cls.admin_metering_labels_client.create_metering_label(
+ description=description,
+ name=name)
+ metering_label = body['metering_label']
+ cls.metering_labels.append(metering_label)
+ return metering_label
+
+ @classmethod
+ def create_metering_label_rule(cls, remote_ip_prefix, direction,
+ metering_label_id):
+ """Wrapper utility that returns a test metering label rule."""
+ client = cls.admin_metering_label_rules_client
+ body = client.create_metering_label_rule(
+ remote_ip_prefix=remote_ip_prefix, direction=direction,
+ metering_label_id=metering_label_id)
+ metering_label_rule = body['metering_label_rule']
+ cls.metering_label_rules.append(metering_label_rule)
+ return metering_label_rule
+
def _delete_metering_label(self, metering_label_id):
# Deletes a label and verifies if it is deleted or not
self.admin_metering_labels_client.delete_metering_label(
diff --git a/tempest/api/network/admin/test_ports.py b/tempest/api/network/admin/test_ports.py
new file mode 100644
index 0000000..807994b
--- /dev/null
+++ b/tempest/api/network/admin/test_ports.py
@@ -0,0 +1,99 @@
+# Copyright 2014 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import socket
+
+from tempest.api.network import base
+from tempest import config
+from tempest.lib import decorators
+
+CONF = config.CONF
+
+
+class PortsAdminExtendedAttrsTestJSON(base.BaseAdminNetworkTest):
+
+ @classmethod
+ def resource_setup(cls):
+ super(PortsAdminExtendedAttrsTestJSON, cls).resource_setup()
+ cls.network = cls.create_network()
+ cls.host_id = socket.gethostname()
+
+ @decorators.idempotent_id('8e8569c1-9ac7-44db-8bc1-f5fb2814f29b')
+ def test_create_port_binding_ext_attr(self):
+ post_body = {"network_id": self.network['id'],
+ "binding:host_id": self.host_id}
+ body = self.admin_ports_client.create_port(**post_body)
+ port = body['port']
+ self.addCleanup(self.admin_ports_client.delete_port, port['id'])
+ host_id = port['binding:host_id']
+ self.assertIsNotNone(host_id)
+ self.assertEqual(self.host_id, host_id)
+
+ @decorators.idempotent_id('6f6c412c-711f-444d-8502-0ac30fbf5dd5')
+ def test_update_port_binding_ext_attr(self):
+ post_body = {"network_id": self.network['id']}
+ body = self.admin_ports_client.create_port(**post_body)
+ port = body['port']
+ self.addCleanup(self.admin_ports_client.delete_port, port['id'])
+ update_body = {"binding:host_id": self.host_id}
+ body = self.admin_ports_client.update_port(port['id'], **update_body)
+ updated_port = body['port']
+ host_id = updated_port['binding:host_id']
+ self.assertIsNotNone(host_id)
+ self.assertEqual(self.host_id, host_id)
+
+ @decorators.idempotent_id('1c82a44a-6c6e-48ff-89e1-abe7eaf8f9f8')
+ def test_list_ports_binding_ext_attr(self):
+ # Create a new port
+ post_body = {"network_id": self.network['id']}
+ body = self.admin_ports_client.create_port(**post_body)
+ port = body['port']
+ self.addCleanup(self.admin_ports_client.delete_port, port['id'])
+
+ # Update the port's binding attributes so that is now 'bound'
+ # to a host
+ update_body = {"binding:host_id": self.host_id}
+ self.admin_ports_client.update_port(port['id'], **update_body)
+
+ # List all ports, ensure new port is part of list and its binding
+ # attributes are set and accurate
+ body = self.admin_ports_client.list_ports()
+ ports_list = body['ports']
+ pids_list = [p['id'] for p in ports_list]
+ self.assertIn(port['id'], pids_list)
+ listed_port = [p for p in ports_list if p['id'] == port['id']]
+ self.assertEqual(1, len(listed_port),
+ 'Multiple ports listed with id %s in ports listing: '
+ '%s' % (port['id'], ports_list))
+ self.assertEqual(self.host_id, listed_port[0]['binding:host_id'])
+
+ @decorators.idempotent_id('b54ac0ff-35fc-4c79-9ca3-c7dbd4ea4f13')
+ def test_show_port_binding_ext_attr(self):
+ body = self.admin_ports_client.create_port(
+ network_id=self.network['id'])
+ port = body['port']
+ self.addCleanup(self.admin_ports_client.delete_port, port['id'])
+ body = self.admin_ports_client.show_port(port['id'])
+ show_port = body['port']
+ self.assertEqual(port['binding:host_id'],
+ show_port['binding:host_id'])
+ self.assertEqual(port['binding:vif_type'],
+ show_port['binding:vif_type'])
+ self.assertEqual(port['binding:vif_details'],
+ show_port['binding:vif_details'])
+
+
+class PortsAdminExtendedAttrsIpV6TestJSON(PortsAdminExtendedAttrsTestJSON):
+ _ip_version = 6
diff --git a/tempest/api/network/admin/test_routers_dvr.py b/tempest/api/network/admin/test_routers_dvr.py
index 4ccad30..f9a0cfb 100644
--- a/tempest/api/network/admin/test_routers_dvr.py
+++ b/tempest/api/network/admin/test_routers_dvr.py
@@ -15,13 +15,13 @@
import testtools
-from tempest.api.network import base_routers as base
+from tempest.api.network import base
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest import test
-class RoutersTestDVR(base.BaseRouterTest):
+class RoutersTestDVR(base.BaseAdminNetworkTest):
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/network/admin/test_routers_negative.py b/tempest/api/network/admin/test_routers_negative.py
new file mode 100644
index 0000000..f350a15
--- /dev/null
+++ b/tempest/api/network/admin/test_routers_negative.py
@@ -0,0 +1,63 @@
+# Copyright 2013 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import testtools
+
+from tempest.api.network import base
+from tempest import config
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from tempest import test
+
+CONF = config.CONF
+
+
+class RoutersAdminNegativeTest(base.BaseAdminNetworkTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(RoutersAdminNegativeTest, cls).skip_checks()
+ if not test.is_extension_enabled('router', 'network'):
+ msg = "router extension not enabled."
+ raise cls.skipException(msg)
+
+ @decorators.attr(type=['negative'])
+ @decorators.idempotent_id('7101cc02-058a-11e7-93e1-fa163e4fa634')
+ @test.requires_ext(extension='ext-gw-mode', service='network')
+ @testtools.skipUnless(CONF.network.public_network_id,
+ 'The public_network_id option must be specified.')
+ def test_router_set_gateway_used_ip_returns_409(self):
+ # At first create a address from public_network_id
+ port = self.admin_ports_client.create_port(
+ network_id=CONF.network.public_network_id)['port']
+ self.addCleanup(self.admin_ports_client.delete_port,
+ port_id=port['id'])
+ # Add used ip and subnet_id in external_fixed_ips
+ fixed_ip = {
+ 'subnet_id': port['fixed_ips'][0]['subnet_id'],
+ 'ip_address': port['fixed_ips'][0]['ip_address']
+ }
+ external_gateway_info = {
+ 'network_id': CONF.network.public_network_id,
+ 'external_fixed_ips': [fixed_ip]
+ }
+ # Create a router and set gateway to used ip
+ self.assertRaises(lib_exc.Conflict,
+ self.admin_routers_client.create_router,
+ external_gateway_info=external_gateway_info)
+
+
+class RoutersAdminNegativeIpV6Test(RoutersAdminNegativeTest):
+ _ip_version = 6
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 359a444..8775495 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -269,25 +269,3 @@
cls.admin_metering_labels_client = cls.os_admin.metering_labels_client
cls.admin_metering_label_rules_client = (
cls.os_admin.metering_label_rules_client)
-
- @classmethod
- def create_metering_label(cls, name, description):
- """Wrapper utility that returns a test metering label."""
- body = cls.admin_metering_labels_client.create_metering_label(
- description=description,
- name=name)
- metering_label = body['metering_label']
- cls.metering_labels.append(metering_label)
- return metering_label
-
- @classmethod
- def create_metering_label_rule(cls, remote_ip_prefix, direction,
- metering_label_id):
- """Wrapper utility that returns a test metering label rule."""
- client = cls.admin_metering_label_rules_client
- body = client.create_metering_label_rule(
- remote_ip_prefix=remote_ip_prefix, direction=direction,
- metering_label_id=metering_label_id)
- metering_label_rule = body['metering_label_rule']
- cls.metering_label_rules.append(metering_label_rule)
- return metering_label_rule
diff --git a/tempest/api/network/base_routers.py b/tempest/api/network/base_routers.py
deleted file mode 100644
index f6fd871..0000000
--- a/tempest/api/network/base_routers.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.network import base
-
-
-class BaseRouterTest(base.BaseAdminNetworkTest):
- # NOTE(salv-orlando): This class inherits from BaseAdminNetworkTest
- # as some router operations, such as enabling or disabling SNAT
- # require admin credentials by default
-
- def _cleanup_router(self, router):
- self.delete_router(router)
- self.routers.remove(router)
-
- def _create_router(self, name=None, admin_state_up=False,
- external_network_id=None, enable_snat=None):
- # associate a cleanup with created routers to avoid quota limits
- router = self.create_router(name, admin_state_up,
- external_network_id, enable_snat)
- self.addCleanup(self._cleanup_router, router)
- return router
-
- def _delete_router(self, router_id, routers_client=None):
- client = routers_client or self.routers_client
- client.delete_router(router_id)
- # Asserting that the router is not found in the list
- # after deletion
- list_body = client.list_routers()
- routers_list = [router['id'] for router in list_body['routers']]
- self.assertNotIn(router_id, routers_list)
-
- def _add_router_interface_with_subnet_id(self, router_id, subnet_id):
- interface = self.routers_client.add_router_interface(
- router_id, subnet_id=subnet_id)
- self.addCleanup(self._remove_router_interface_with_subnet_id,
- router_id, subnet_id)
- self.assertEqual(subnet_id, interface['subnet_id'])
- return interface
-
- def _remove_router_interface_with_subnet_id(self, router_id, subnet_id):
- body = self.routers_client.remove_router_interface(router_id,
- subnet_id=subnet_id)
- self.assertEqual(subnet_id, body['subnet_id'])
-
- def _remove_router_interface_with_port_id(self, router_id, port_id):
- body = self.routers_client.remove_router_interface(router_id,
- port_id=port_id)
- self.assertEqual(port_id, body['port_id'])
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 69a1441..f81927d 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -13,12 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-import socket
-
import netaddr
import testtools
-from tempest.api.network import base
from tempest.api.network import base_security_groups as sec_base
from tempest.common import custom_matchers
from tempest import config
@@ -358,82 +355,5 @@
self.assertEmpty(port['security_groups'])
-class PortsAdminExtendedAttrsTestJSON(base.BaseAdminNetworkTest):
-
- @classmethod
- def resource_setup(cls):
- super(PortsAdminExtendedAttrsTestJSON, cls).resource_setup()
- cls.network = cls.create_network()
- cls.host_id = socket.gethostname()
-
- @decorators.idempotent_id('8e8569c1-9ac7-44db-8bc1-f5fb2814f29b')
- def test_create_port_binding_ext_attr(self):
- post_body = {"network_id": self.network['id'],
- "binding:host_id": self.host_id}
- body = self.admin_ports_client.create_port(**post_body)
- port = body['port']
- self.addCleanup(self.admin_ports_client.delete_port, port['id'])
- host_id = port['binding:host_id']
- self.assertIsNotNone(host_id)
- self.assertEqual(self.host_id, host_id)
-
- @decorators.idempotent_id('6f6c412c-711f-444d-8502-0ac30fbf5dd5')
- def test_update_port_binding_ext_attr(self):
- post_body = {"network_id": self.network['id']}
- body = self.admin_ports_client.create_port(**post_body)
- port = body['port']
- self.addCleanup(self.admin_ports_client.delete_port, port['id'])
- update_body = {"binding:host_id": self.host_id}
- body = self.admin_ports_client.update_port(port['id'], **update_body)
- updated_port = body['port']
- host_id = updated_port['binding:host_id']
- self.assertIsNotNone(host_id)
- self.assertEqual(self.host_id, host_id)
-
- @decorators.idempotent_id('1c82a44a-6c6e-48ff-89e1-abe7eaf8f9f8')
- def test_list_ports_binding_ext_attr(self):
- # Create a new port
- post_body = {"network_id": self.network['id']}
- body = self.admin_ports_client.create_port(**post_body)
- port = body['port']
- self.addCleanup(self.admin_ports_client.delete_port, port['id'])
-
- # Update the port's binding attributes so that is now 'bound'
- # to a host
- update_body = {"binding:host_id": self.host_id}
- self.admin_ports_client.update_port(port['id'], **update_body)
-
- # List all ports, ensure new port is part of list and its binding
- # attributes are set and accurate
- body = self.admin_ports_client.list_ports()
- ports_list = body['ports']
- pids_list = [p['id'] for p in ports_list]
- self.assertIn(port['id'], pids_list)
- listed_port = [p for p in ports_list if p['id'] == port['id']]
- self.assertEqual(1, len(listed_port),
- 'Multiple ports listed with id %s in ports listing: '
- '%s' % (port['id'], ports_list))
- self.assertEqual(self.host_id, listed_port[0]['binding:host_id'])
-
- @decorators.idempotent_id('b54ac0ff-35fc-4c79-9ca3-c7dbd4ea4f13')
- def test_show_port_binding_ext_attr(self):
- body = self.admin_ports_client.create_port(
- network_id=self.network['id'])
- port = body['port']
- self.addCleanup(self.admin_ports_client.delete_port, port['id'])
- body = self.admin_ports_client.show_port(port['id'])
- show_port = body['port']
- self.assertEqual(port['binding:host_id'],
- show_port['binding:host_id'])
- self.assertEqual(port['binding:vif_type'],
- show_port['binding:vif_type'])
- self.assertEqual(port['binding:vif_details'],
- show_port['binding:vif_details'])
-
-
class PortsIpV6TestJSON(PortsTestJSON):
_ip_version = 6
-
-
-class PortsAdminExtendedAttrsIpV6TestJSON(PortsAdminExtendedAttrsTestJSON):
- _ip_version = 6
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 97ad4d4..0466d3a 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -16,7 +16,7 @@
import netaddr
import testtools
-from tempest.api.network import base_routers as base
+from tempest.api.network import base
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
@@ -25,7 +25,35 @@
CONF = config.CONF
-class RoutersTest(base.BaseRouterTest):
+class RoutersTest(base.BaseAdminNetworkTest):
+ # NOTE(salv-orlando): This class inherits from BaseAdminNetworkTest
+ # as some router operations, such as enabling or disabling SNAT
+ # require admin credentials by default
+
+ def _cleanup_router(self, router):
+ self.delete_router(router)
+ self.routers.remove(router)
+
+ def _create_router(self, name=None, admin_state_up=False,
+ external_network_id=None, enable_snat=None):
+ # associate a cleanup with created routers to avoid quota limits
+ router = self.create_router(name, admin_state_up,
+ external_network_id, enable_snat)
+ self.addCleanup(self._cleanup_router, router)
+ return router
+
+ def _add_router_interface_with_subnet_id(self, router_id, subnet_id):
+ interface = self.routers_client.add_router_interface(
+ router_id, subnet_id=subnet_id)
+ self.addCleanup(self._remove_router_interface_with_subnet_id,
+ router_id, subnet_id)
+ self.assertEqual(subnet_id, interface['subnet_id'])
+ return interface
+
+ def _remove_router_interface_with_subnet_id(self, router_id, subnet_id):
+ body = self.routers_client.remove_router_interface(router_id,
+ subnet_id=subnet_id)
+ self.assertEqual(subnet_id, body['subnet_id'])
@classmethod
def skip_checks(cls):
@@ -153,8 +181,8 @@
interface = self.routers_client.add_router_interface(
router['id'],
port_id=port_body['port']['id'])
- self.addCleanup(self._remove_router_interface_with_port_id,
- router['id'], port_body['port']['id'])
+ self.addCleanup(self.routers_client.remove_router_interface,
+ router['id'], port_id=port_body['port']['id'])
self.assertIn('subnet_id', interface.keys())
self.assertIn('port_id', interface.keys())
# Verify router id is equal to device id in port details
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index fdd8dd8..72face8 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -14,9 +14,8 @@
# under the License.
import netaddr
-import testtools
-from tempest.api.network import base_routers as base
+from tempest.api.network import base
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
@@ -26,7 +25,7 @@
CONF = config.CONF
-class RoutersNegativeTest(base.BaseRouterTest):
+class RoutersNegativeTest(base.BaseNetworkTest):
@classmethod
def skip_checks(cls):
@@ -75,37 +74,15 @@
network_name=data_utils.rand_name('router-network02-'))
subnet01 = self.create_subnet(network01)
subnet02 = self.create_subnet(network02)
- self._add_router_interface_with_subnet_id(self.router['id'],
- subnet01['id'])
+ interface = self.routers_client.add_router_interface(
+ self.router['id'], subnet_id=subnet01['id'])
+ self.addCleanup(self.routers_client.remove_router_interface,
+ self.router['id'], subnet_id=subnet01['id'])
+ self.assertEqual(subnet01['id'], interface['subnet_id'])
self.assertRaises(lib_exc.BadRequest,
- self._add_router_interface_with_subnet_id,
+ self.routers_client.add_router_interface,
self.router['id'],
- subnet02['id'])
-
- @decorators.attr(type=['negative'])
- @decorators.idempotent_id('7101cc02-058a-11e7-93e1-fa163e4fa634')
- @test.requires_ext(extension='ext-gw-mode', service='network')
- @testtools.skipUnless(CONF.network.public_network_id,
- 'The public_network_id option must be specified.')
- def test_router_set_gateway_used_ip_returns_409(self):
- # At first create a address from public_network_id
- port = self.admin_ports_client.create_port(
- network_id=CONF.network.public_network_id)['port']
- self.addCleanup(self.admin_ports_client.delete_port,
- port_id=port['id'])
- # Add used ip and subnet_id in external_fixed_ips
- fixed_ip = {
- 'subnet_id': port['fixed_ips'][0]['subnet_id'],
- 'ip_address': port['fixed_ips'][0]['ip_address']
- }
- external_gateway_info = {
- 'network_id': CONF.network.public_network_id,
- 'external_fixed_ips': [fixed_ip]
- }
- # Create a router and set gateway to used ip
- self.assertRaises(lib_exc.Conflict,
- self.admin_routers_client.create_router,
- external_gateway_info=external_gateway_info)
+ subnet_id=subnet02['id'])
@decorators.attr(type=['negative'])
@decorators.idempotent_id('04df80f9-224d-47f5-837a-bf23e33d1c20')
@@ -142,7 +119,7 @@
_ip_version = 6
-class DvrRoutersNegativeTest(base.BaseRouterTest):
+class DvrRoutersNegativeTest(base.BaseNetworkTest):
@classmethod
def skip_checks(cls):
diff --git a/tempest/api/orchestration/__init__.py b/tempest/api/orchestration/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api/orchestration/__init__.py
+++ /dev/null
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
deleted file mode 100644
index d9d8017..0000000
--- a/tempest/api/orchestration/base.py
+++ /dev/null
@@ -1,169 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import os.path
-
-import yaml
-
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
-import tempest.test
-
-CONF = config.CONF
-
-
-class BaseOrchestrationTest(tempest.test.BaseTestCase):
- """Base test case class for all Orchestration API tests."""
-
- credentials = ['primary']
-
- @classmethod
- def skip_checks(cls):
- super(BaseOrchestrationTest, cls).skip_checks()
- if not CONF.service_available.heat:
- raise cls.skipException("Heat support is required")
-
- @classmethod
- def setup_credentials(cls):
- super(BaseOrchestrationTest, cls).setup_credentials()
- stack_owner_role = CONF.orchestration.stack_owner_role
- cls.os = cls.get_client_manager(roles=[stack_owner_role])
-
- @classmethod
- def setup_clients(cls):
- super(BaseOrchestrationTest, cls).setup_clients()
- cls.orchestration_client = cls.os_primary.orchestration_client
- cls.client = cls.orchestration_client
- cls.servers_client = cls.os_primary.servers_client
- cls.keypairs_client = cls.os_primary.keypairs_client
- cls.networks_client = cls.os_primary.networks_client
- cls.images_v2_client = cls.os_primary.image_client_v2
- cls.volumes_client = cls.os_primary.volumes_v2_client
-
- @classmethod
- def resource_setup(cls):
- super(BaseOrchestrationTest, cls).resource_setup()
- cls.build_timeout = CONF.orchestration.build_timeout
- cls.build_interval = CONF.orchestration.build_interval
- cls.stacks = []
- cls.keypairs = []
- cls.images = []
-
- @classmethod
- def create_stack(cls, stack_name, template_data, parameters=None,
- environment=None, files=None):
- if parameters is None:
- parameters = {}
- body = cls.client.create_stack(
- stack_name,
- template=template_data,
- parameters=parameters,
- environment=environment,
- files=files)
- stack_id = body.response['location'].split('/')[-1]
- stack_identifier = '%s/%s' % (stack_name, stack_id)
- cls.stacks.append(stack_identifier)
- return stack_identifier
-
- @classmethod
- def _clear_stacks(cls):
- for stack_identifier in cls.stacks:
- test_utils.call_and_ignore_notfound_exc(
- cls.client.delete_stack, stack_identifier)
-
- for stack_identifier in cls.stacks:
- test_utils.call_and_ignore_notfound_exc(
- cls.client.wait_for_stack_status, stack_identifier,
- 'DELETE_COMPLETE')
-
- @classmethod
- def _create_keypair(cls, name_start='keypair-heat-'):
- kp_name = data_utils.rand_name(name_start)
- body = cls.keypairs_client.create_keypair(name=kp_name)['keypair']
- cls.keypairs.append(kp_name)
- return body
-
- @classmethod
- def _clear_keypairs(cls):
- for kp_name in cls.keypairs:
- try:
- cls.keypairs_client.delete_keypair(kp_name)
- except Exception:
- pass
-
- @classmethod
- def _create_image(cls, name_start='image-heat-', container_format='bare',
- disk_format='iso'):
- image_name = data_utils.rand_name(name_start)
- body = cls.images_v2_client.create_image(image_name,
- container_format,
- disk_format)
- image_id = body['id']
- cls.images.append(image_id)
- return body
-
- @classmethod
- def _clear_images(cls):
- for image_id in cls.images:
- test_utils.call_and_ignore_notfound_exc(
- cls.images_v2_client.delete_image, image_id)
-
- @classmethod
- def read_template(cls, name, ext='yaml'):
- loc = ["stacks", "templates", "%s.%s" % (name, ext)]
- fullpath = os.path.join(os.path.dirname(__file__), *loc)
-
- with open(fullpath, "r") as f:
- content = f.read()
- return content
-
- @classmethod
- def load_template(cls, name, ext='yaml'):
- loc = ["stacks", "templates", "%s.%s" % (name, ext)]
- fullpath = os.path.join(os.path.dirname(__file__), *loc)
-
- with open(fullpath, "r") as f:
- return yaml.safe_load(f)
-
- @classmethod
- def resource_cleanup(cls):
- cls._clear_stacks()
- cls._clear_keypairs()
- cls._clear_images()
- super(BaseOrchestrationTest, cls).resource_cleanup()
-
- @staticmethod
- def stack_output(stack, output_key):
- """Return a stack output value for a given key."""
- return next((o['output_value'] for o in stack['outputs']
- if o['output_key'] == output_key), None)
-
- def assert_fields_in_dict(self, obj, *fields):
- for field in fields:
- self.assertIn(field, obj)
-
- def list_resources(self, stack_identifier):
- """Get a dict mapping of resource names to types."""
- resources = self.client.list_resources(stack_identifier)['resources']
- self.assertIsInstance(resources, list)
- for res in resources:
- self.assert_fields_in_dict(res, 'logical_resource_id',
- 'resource_type', 'resource_status',
- 'updated_time')
-
- return dict((r['resource_name'], r['resource_type'])
- for r in resources)
-
- def get_stack_output(self, stack_identifier, output_key):
- body = self.client.show_stack(stack_identifier)['stack']
- return self.stack_output(body, output_key)
diff --git a/tempest/api/orchestration/stacks/__init__.py b/tempest/api/orchestration/stacks/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api/orchestration/stacks/__init__.py
+++ /dev/null
diff --git a/tempest/api/orchestration/stacks/templates/cinder_basic.yaml b/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
deleted file mode 100644
index 61c271c..0000000
--- a/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
+++ /dev/null
@@ -1,33 +0,0 @@
-heat_template_version: 2013-05-23
-
-parameters:
- volume_size:
- type: number
- default: 1
-
-resources:
- volume:
- type: OS::Cinder::Volume
- properties:
- size: { get_param: volume_size }
- description: a descriptive description
- name: volume_name
-
-outputs:
- status:
- description: status
- value: { get_attr: ['volume', 'status'] }
-
- size:
- description: size
- value: { get_attr: ['volume', 'size'] }
-
- display_description:
- description: display_description
- value: { get_attr: ['volume', 'display_description'] }
-
- display_name:
- value: { get_attr: ['volume', 'display_name'] }
-
- volume_id:
- value: { get_resource: volume }
diff --git a/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml b/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
deleted file mode 100644
index 0bc6d69..0000000
--- a/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
+++ /dev/null
@@ -1,34 +0,0 @@
-heat_template_version: 2013-05-23
-
-parameters:
- volume_size:
- type: number
- default: 1
-
-resources:
- volume:
- deletion_policy: 'Retain'
- type: OS::Cinder::Volume
- properties:
- size: { get_param: volume_size }
- description: a descriptive description
- name: volume_name
-
-outputs:
- status:
- description: status
- value: { get_attr: ['volume', 'status'] }
-
- size:
- description: size
- value: { get_attr: ['volume', 'size'] }
-
- display_description:
- description: display_description
- value: { get_attr: ['volume', 'display_description'] }
-
- display_name:
- value: { get_attr: ['volume', 'display_name'] }
-
- volume_id:
- value: { get_resource: volume }
diff --git a/tempest/api/orchestration/stacks/templates/neutron_basic.yaml b/tempest/api/orchestration/stacks/templates/neutron_basic.yaml
deleted file mode 100644
index ccb1b54..0000000
--- a/tempest/api/orchestration/stacks/templates/neutron_basic.yaml
+++ /dev/null
@@ -1,72 +0,0 @@
-heat_template_version: '2013-05-23'
-description: |
- Template which creates single EC2 instance
-parameters:
- KeyName:
- type: string
- InstanceType:
- type: string
- ImageId:
- type: string
- SubNetCidr:
- type: string
- ExternalNetworkId:
- type: string
- DNSServers:
- type: comma_delimited_list
- timeout:
- type: number
-resources:
- Network:
- type: OS::Neutron::Net
- properties:
- name: NewNetwork
- Subnet:
- type: OS::Neutron::Subnet
- properties:
- network_id: {Ref: Network}
- name: NewSubnet
- ip_version: 4
- cidr: { get_param: SubNetCidr }
- dns_nameservers: { get_param: DNSServers }
- Router:
- type: OS::Neutron::Router
- properties:
- name: NewRouter
- admin_state_up: true
- external_gateway_info:
- network: {get_param: ExternalNetworkId}
- RouterInterface:
- type: OS::Neutron::RouterInterface
- properties:
- router_id: {get_resource: Router}
- subnet_id: {get_resource: Subnet}
- Server:
- type: OS::Nova::Server
- metadata:
- Name: SmokeServerNeutron
- properties:
- image: {get_param: ImageId}
- flavor: {get_param: InstanceType}
- key_name: {get_param: KeyName}
- networks:
- - network: {get_resource: Network}
- user_data_format: RAW
- user_data:
- str_replace:
- template: |
- #!/bin/sh -v
-
- SIGNAL_DATA='{"Status": "SUCCESS", "Reason": "SmokeServerNeutron created", "Data": "Application has completed configuration.", "UniqueId": "00000"}'
- while ! curl --insecure --fail -X PUT -H 'Content-Type:' --data-binary "$SIGNAL_DATA" \
- 'wait_handle' ; do sleep 3; done
- params:
- wait_handle: {get_resource: WaitHandleNeutron}
- WaitHandleNeutron:
- type: AWS::CloudFormation::WaitConditionHandle
- WaitCondition:
- type: AWS::CloudFormation::WaitCondition
- depends_on: Server
- properties:
- Handle: {get_resource: WaitHandleNeutron}
- Timeout: {get_param: timeout}
diff --git a/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml b/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml
deleted file mode 100644
index 4f9df91..0000000
--- a/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml
+++ /dev/null
@@ -1,36 +0,0 @@
-HeatTemplateFormatVersion: '2012-12-12'
-Description: |
- Template which creates some simple resources
-Parameters:
- trigger:
- Type: String
- Default: not_yet
- image:
- Type: String
- flavor:
- Type: String
-Resources:
- fluffy:
- Type: AWS::AutoScaling::LaunchConfiguration
- Metadata:
- kittens:
- - Tom
- - Stinky
- Properties:
- ImageId: {Ref: image}
- InstanceType: {Ref: flavor}
- UserData:
- Fn::Replace:
- - variable_a: {Ref: trigger}
- variable_b: bee
- - |
- A == variable_a
- B == variable_b
-Outputs:
- fluffy:
- Description: "fluffies irc nick"
- Value:
- Fn::Replace:
- - nick: {Ref: fluffy}
- - |
- #nick
diff --git a/tempest/api/orchestration/stacks/templates/nova_keypair.json b/tempest/api/orchestration/stacks/templates/nova_keypair.json
deleted file mode 100644
index 63d3817..0000000
--- a/tempest/api/orchestration/stacks/templates/nova_keypair.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "AWSTemplateFormatVersion" : "2010-09-09",
- "Description" : "Template which create two key pairs.",
- "Parameters" : {
- "KeyPairName1": {
- "Type": "String",
- "Default": "testkey1"
- },
- "KeyPairName2": {
- "Type": "String",
- "Default": "testkey2"
- }
- },
- "Resources" : {
- "KeyPairSavePrivate": {
- "Type": "OS::Nova::KeyPair",
- "Properties": {
- "name" : { "Ref" : "KeyPairName1" },
- "save_private_key": true
- }
- },
- "KeyPairDontSavePrivate": {
- "Type": "OS::Nova::KeyPair",
- "Properties": {
- "name" : { "Ref" : "KeyPairName2" },
- "save_private_key": false
- }
- }
- },
- "Outputs": {
- "KeyPair_PublicKey": {
- "Description": "Public Key of generated keypair.",
- "Value": { "Fn::GetAtt" : ["KeyPairSavePrivate", "public_key"] }
- },
- "KeyPair_PrivateKey": {
- "Description": "Private Key of generated keypair.",
- "Value": { "Fn::GetAtt" : ["KeyPairSavePrivate", "private_key"] }
- },
- "KeyPairDontSavePrivate_PublicKey": {
- "Description": "Public Key of generated keypair.",
- "Value": { "Fn::GetAtt" : ["KeyPairDontSavePrivate", "public_key"] }
- },
- "KeyPairDontSavePrivate_PrivateKey": {
- "Description": "Private Key of generated keypair.",
- "Value": { "Fn::GetAtt" : ["KeyPairDontSavePrivate", "private_key"] }
- }
- }
-}
diff --git a/tempest/api/orchestration/stacks/templates/nova_keypair.yaml b/tempest/api/orchestration/stacks/templates/nova_keypair.yaml
deleted file mode 100644
index 81ad99c..0000000
--- a/tempest/api/orchestration/stacks/templates/nova_keypair.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-heat_template_version: 2013-05-23
-
-description: >
- Template which creates two key pairs.
-
-parameters:
- KeyPairName1:
- type: string
- default: testkey
-
- KeyPairName2:
- type: string
- default: testkey2
-
-resources:
- KeyPairSavePrivate:
- type: OS::Nova::KeyPair
- properties:
- name: { get_param: KeyPairName1 }
- save_private_key: true
-
- KeyPairDontSavePrivate:
- type: OS::Nova::KeyPair
- properties:
- name: { get_param: KeyPairName2 }
- save_private_key: false
-
-outputs:
- KeyPair_PublicKey:
- description: Public Key of generated keypair
- value: { get_attr: [KeyPairSavePrivate, public_key] }
-
- KeyPair_PrivateKey:
- description: Private Key of generated keypair
- value: { get_attr: [KeyPairSavePrivate, private_key] }
-
- KeyPairDontSavePrivate_PublicKey:
- description: Public Key of generated keypair
- value: { get_attr: [KeyPairDontSavePrivate, public_key] }
-
- KeyPairDontSavePrivate_PrivateKey:
- description: Private Key of generated keypair
- value: { get_attr: [KeyPairDontSavePrivate, private_key] }
diff --git a/tempest/api/orchestration/stacks/templates/random_string.yaml b/tempest/api/orchestration/stacks/templates/random_string.yaml
deleted file mode 100644
index dfd2342..0000000
--- a/tempest/api/orchestration/stacks/templates/random_string.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-heat_template_version: 2013-05-23
-
-parameters:
- random_length:
- type: number
- default: 10
-
-resources:
- random:
- type: OS::Heat::RandomString
- properties:
- length: {get_param: random_length}
-
-outputs:
- random_length:
- value: {get_param: random_length}
- random_value:
- value: {get_attr: [random, value]}
diff --git a/tempest/api/orchestration/stacks/templates/swift_basic.yaml b/tempest/api/orchestration/stacks/templates/swift_basic.yaml
deleted file mode 100644
index 713f8bc..0000000
--- a/tempest/api/orchestration/stacks/templates/swift_basic.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-heat_template_version: 2013-05-23
-description: Template which creates a Swift container resource
-
-resources:
- SwiftContainerWebsite:
- deletion_policy: "Delete"
- type: OS::Swift::Container
- properties:
- X-Container-Read: ".r:*"
- X-Container-Meta:
- web-index: "index.html"
- web-error: "error.html"
-
- SwiftContainer:
- type: OS::Swift::Container
-
-outputs:
- WebsiteURL:
- description: "URL for website hosted on S3"
- value: { get_attr: [SwiftContainer, WebsiteURL] }
- DomainName:
- description: "Domain of Swift host"
- value: { get_attr: [SwiftContainer, DomainName] }
diff --git a/tempest/api/orchestration/stacks/test_environment.py b/tempest/api/orchestration/stacks/test_environment.py
deleted file mode 100644
index c8a9aa7..0000000
--- a/tempest/api/orchestration/stacks/test_environment.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-
-class StackEnvironmentTest(base.BaseOrchestrationTest):
-
- @decorators.idempotent_id('37d4346b-1abd-4442-b7b1-2a4e5749a1e3')
- def test_environment_parameter(self):
- """Test passing a stack parameter via the environment."""
- stack_name = data_utils.rand_name('heat')
- template = self.read_template('random_string')
- environment = {'parameters': {'random_length': 20}}
-
- stack_identifier = self.create_stack(stack_name, template,
- environment=environment)
- self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-
- random_len = self.get_stack_output(stack_identifier, 'random_length')
- self.assertEqual(20, random_len)
-
- random_value = self.get_stack_output(stack_identifier, 'random_value')
- self.assertEqual(20, len(random_value))
-
- @decorators.idempotent_id('73bce717-ad22-4853-bbef-6ed89b632701')
- def test_environment_provider_resource(self):
- """Test passing resource_registry defining a provider resource."""
- stack_name = data_utils.rand_name('heat')
- template = '''
-heat_template_version: 2013-05-23
-resources:
- random:
- type: My:Random::String
-outputs:
- random_value:
- value: {get_attr: [random, random_value]}
-'''
- environment = {'resource_registry':
- {'My:Random::String': 'my_random.yaml'}}
- files = {'my_random.yaml': self.read_template('random_string')}
-
- stack_identifier = self.create_stack(stack_name, template,
- environment=environment,
- files=files)
- self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-
- # random_string.yaml specifies a length of 10
- random_value = self.get_stack_output(stack_identifier, 'random_value')
- random_string_template = self.load_template('random_string')
- expected_length = random_string_template['parameters'][
- 'random_length']['default']
- self.assertEqual(expected_length, len(random_value))
-
- @decorators.idempotent_id('9d682e5a-f4bb-47d5-8472-9d3cacb855df')
- def test_files_provider_resource(self):
- """Test untyped defining of a provider resource via "files"."""
- # It's also possible to specify the filename directly in the template.
- # without adding the type alias to resource_registry
- stack_name = data_utils.rand_name('heat')
- template = '''
-heat_template_version: 2013-05-23
-resources:
- random:
- type: my_random.yaml
-outputs:
- random_value:
- value: {get_attr: [random, random_value]}
-'''
- files = {'my_random.yaml': self.read_template('random_string')}
-
- stack_identifier = self.create_stack(stack_name, template,
- files=files)
- self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-
- # random_string.yaml specifies a length of 10
- random_value = self.get_stack_output(stack_identifier, 'random_value')
- random_string_template = self.load_template('random_string')
- expected_length = random_string_template['parameters'][
- 'random_length']['default']
- self.assertEqual(expected_length, len(random_value))
diff --git a/tempest/api/orchestration/stacks/test_limits.py b/tempest/api/orchestration/stacks/test_limits.py
deleted file mode 100644
index 9c9d4f9..0000000
--- a/tempest/api/orchestration/stacks/test_limits.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-from tempest.lib import exceptions as lib_exc
-
-CONF = config.CONF
-
-
-class TestServerStackLimits(base.BaseOrchestrationTest):
-
- @decorators.idempotent_id('ec9bed71-c460-45c9-ab98-295caa9fd76b')
- def test_exceed_max_template_size_fails(self):
- stack_name = data_utils.rand_name('heat')
- fill = 'A' * CONF.orchestration.max_template_size
- template = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Description: '%s'
-Outputs:
- Foo: bar''' % fill
- ex = self.assertRaises(lib_exc.BadRequest, self.create_stack,
- stack_name, template)
- self.assertIn('exceeds maximum allowed size', str(ex))
-
- @decorators.idempotent_id('d1b83e73-7cad-4a22-9839-036548c5387c')
- def test_exceed_max_resources_per_stack(self):
- stack_name = data_utils.rand_name('heat')
- # Create a big template, one resource more than the limit
- template = 'heat_template_version: \'2013-05-23\'\nresources:\n'
- rsrc_snippet = ' random%s:\n type: \'OS::Heat::RandomString\'\n'
- num_resources = CONF.orchestration.max_resources_per_stack + 1
- for i in range(num_resources):
- template += rsrc_snippet % i
-
- ex = self.assertRaises(lib_exc.BadRequest, self.create_stack,
- stack_name, template)
- self.assertIn('Maximum resources per stack exceeded', str(ex))
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
deleted file mode 100644
index 36881bf..0000000
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ /dev/null
@@ -1,196 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import netaddr
-from oslo_log import log as logging
-
-from tempest.api.orchestration import base
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-from tempest.lib import exceptions
-from tempest import test
-
-CONF = config.CONF
-
-LOG = logging.getLogger(__name__)
-
-
-class NeutronResourcesTestJSON(base.BaseOrchestrationTest):
-
- @classmethod
- def skip_checks(cls):
- super(NeutronResourcesTestJSON, cls).skip_checks()
- if not CONF.service_available.neutron:
- raise cls.skipException("Neutron support is required")
-
- @classmethod
- def setup_credentials(cls):
- cls.set_network_resources()
- super(NeutronResourcesTestJSON, cls).setup_credentials()
-
- @classmethod
- def setup_clients(cls):
- super(NeutronResourcesTestJSON, cls).setup_clients()
- cls.subnets_client = cls.os_primary.subnets_client
- cls.ports_client = cls.os_primary.ports_client
- cls.routers_client = cls.os_primary.routers_client
-
- @classmethod
- def resource_setup(cls):
- super(NeutronResourcesTestJSON, cls).resource_setup()
- cls.neutron_basic_template = cls.load_template('neutron_basic')
- cls.stack_name = data_utils.rand_name('heat')
- template = cls.read_template('neutron_basic')
- cls.keypair_name = (CONF.orchestration.keypair_name or
- cls._create_keypair()['name'])
- cls.external_network_id = CONF.network.public_network_id
-
- tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
- mask_bits = CONF.network.project_network_mask_bits
- cls.subnet_cidr = tenant_cidr.subnet(mask_bits).next()
-
- # create the stack
- cls.stack_identifier = cls.create_stack(
- cls.stack_name,
- template,
- parameters={
- 'KeyName': cls.keypair_name,
- 'InstanceType': CONF.orchestration.instance_type,
- 'ImageId': CONF.compute.image_ref,
- 'ExternalNetworkId': cls.external_network_id,
- 'timeout': CONF.orchestration.build_timeout,
- 'DNSServers': CONF.network.dns_servers,
- 'SubNetCidr': str(cls.subnet_cidr)
- })
- cls.stack_id = cls.stack_identifier.split('/')[1]
- try:
- cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
- resources = (cls.client.list_resources(cls.stack_identifier)
- ['resources'])
- except exceptions.TimeoutException:
- if CONF.compute_feature_enabled.console_output:
- # attempt to log the server console to help with debugging
- # the cause of the server not signalling the waitcondition
- # to heat.
- body = cls.client.show_resource(cls.stack_identifier,
- 'Server')
- server_id = body.get('physical_resource_id')
- if server_id:
- LOG.debug('Console output for %s', server_id)
- output = cls.servers_client.get_console_output(
- server_id)['output']
- LOG.debug(output)
- else:
- LOG.debug('Server resource is %s', body)
- raise # original exception
-
- cls.test_resources = {}
- for resource in resources:
- cls.test_resources[resource['logical_resource_id']] = resource
-
- @decorators.idempotent_id('f9e2664c-bc44-4eef-98b6-495e4f9d74b3')
- def test_created_resources(self):
- """Verifies created neutron resources."""
- resources = [('Network', self.neutron_basic_template['resources'][
- 'Network']['type']),
- ('Subnet', self.neutron_basic_template['resources'][
- 'Subnet']['type']),
- ('RouterInterface', self.neutron_basic_template[
- 'resources']['RouterInterface']['type']),
- ('Server', self.neutron_basic_template['resources'][
- 'Server']['type'])]
- for resource_name, resource_type in resources:
- resource = self.test_resources.get(resource_name, None)
- self.assertIsInstance(resource, dict)
- self.assertEqual(resource_name, resource['logical_resource_id'])
- self.assertEqual(resource_type, resource['resource_type'])
- self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
-
- @decorators.idempotent_id('c572b915-edb1-4e90-b196-c7199a6848c0')
- @test.services('network')
- def test_created_network(self):
- """Verifies created network."""
- network_id = self.test_resources.get('Network')['physical_resource_id']
- body = self.networks_client.show_network(network_id)
- network = body['network']
- self.assertIsInstance(network, dict)
- self.assertEqual(network_id, network['id'])
- self.assertEqual(self.neutron_basic_template['resources'][
- 'Network']['properties']['name'], network['name'])
-
- @decorators.idempotent_id('e8f84b96-f9d7-4684-ad5f-340203e9f2c2')
- @test.services('network')
- def test_created_subnet(self):
- """Verifies created subnet."""
- subnet_id = self.test_resources.get('Subnet')['physical_resource_id']
- body = self.subnets_client.show_subnet(subnet_id)
- subnet = body['subnet']
- network_id = self.test_resources.get('Network')['physical_resource_id']
- self.assertEqual(subnet_id, subnet['id'])
- self.assertEqual(network_id, subnet['network_id'])
- self.assertEqual(self.neutron_basic_template['resources'][
- 'Subnet']['properties']['name'], subnet['name'])
- self.assertEqual(sorted(CONF.network.dns_servers),
- sorted(subnet['dns_nameservers']))
- self.assertEqual(self.neutron_basic_template['resources'][
- 'Subnet']['properties']['ip_version'], subnet['ip_version'])
- self.assertEqual(str(self.subnet_cidr), subnet['cidr'])
-
- @decorators.idempotent_id('96af4c7f-5069-44bc-bdcf-c0390f8a67d1')
- @test.services('network')
- def test_created_router(self):
- """Verifies created router."""
- router_id = self.test_resources.get('Router')['physical_resource_id']
- body = self.routers_client.show_router(router_id)
- router = body['router']
- self.assertEqual(self.neutron_basic_template['resources'][
- 'Router']['properties']['name'], router['name'])
- self.assertEqual(self.external_network_id,
- router['external_gateway_info']['network_id'])
- self.assertEqual(True, router['admin_state_up'])
-
- @decorators.idempotent_id('89f605bd-153e-43ee-a0ed-9919b63423c5')
- @test.services('network')
- def test_created_router_interface(self):
- """Verifies created router interface."""
- router_id = self.test_resources.get('Router')['physical_resource_id']
- network_id = self.test_resources.get('Network')['physical_resource_id']
- subnet_id = self.test_resources.get('Subnet')['physical_resource_id']
- body = self.ports_client.list_ports()
- ports = body['ports']
- router_ports = filter(lambda port: port['device_id'] ==
- router_id, ports)
- created_network_ports = filter(lambda port: port['network_id'] ==
- network_id, router_ports)
- self.assertEqual(1, len(created_network_ports))
- router_interface = created_network_ports[0]
- fixed_ips = router_interface['fixed_ips']
- subnet_fixed_ips = filter(lambda port: port['subnet_id'] ==
- subnet_id, fixed_ips)
- self.assertEqual(1, len(subnet_fixed_ips))
- router_interface_ip = subnet_fixed_ips[0]['ip_address']
- self.assertEqual(str(self.subnet_cidr.iter_hosts().next()),
- router_interface_ip)
-
- @decorators.idempotent_id('75d85316-4ac2-4c0e-a1a9-edd2148fc10e')
- @test.services('compute', 'network')
- def test_created_server(self):
- """Verifies created sever."""
- server_id = self.test_resources.get('Server')['physical_resource_id']
- server = self.servers_client.show_server(server_id)['server']
- self.assertEqual(self.keypair_name, server['key_name'])
- self.assertEqual('ACTIVE', server['status'])
- network = server['addresses'][self.neutron_basic_template['resources'][
- 'Network']['properties']['name']][0]
- self.assertEqual(4, network['version'])
- self.assertIn(netaddr.IPAddress(network['addr']), self.subnet_cidr)
diff --git a/tempest/api/orchestration/stacks/test_non_empty_stack.py b/tempest/api/orchestration/stacks/test_non_empty_stack.py
deleted file mode 100644
index 6b9c88b..0000000
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-CONF = config.CONF
-
-
-class StacksTestJSON(base.BaseOrchestrationTest):
-
- @classmethod
- def resource_setup(cls):
- super(StacksTestJSON, cls).resource_setup()
- cls.stack_name = data_utils.rand_name('heat')
- template = cls.read_template('non_empty_stack')
- image_id = (CONF.compute.image_ref or
- cls._create_image()['id'])
- flavor = CONF.orchestration.instance_type
- # create the stack
- cls.stack_identifier = cls.create_stack(
- cls.stack_name,
- template,
- parameters={
- 'trigger': 'start',
- 'image': image_id,
- 'flavor': flavor
- })
- cls.stack_id = cls.stack_identifier.split('/')[1]
- cls.resource_name = 'fluffy'
- cls.resource_type = 'AWS::AutoScaling::LaunchConfiguration'
- cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
-
- def _list_stacks(self, expected_num=None, **filter_kwargs):
- stacks = self.client.list_stacks(params=filter_kwargs)['stacks']
- self.assertIsInstance(stacks, list)
- if expected_num is not None:
- self.assertEqual(expected_num, len(stacks))
- return stacks
-
- @decorators.idempotent_id('065c652a-720d-4760-9132-06aedeb8e3ab')
- def test_stack_list(self):
- """Created stack should be in the list of existing stacks."""
- stacks = self._list_stacks()
- stacks_names = map(lambda stack: stack['stack_name'], stacks)
- self.assertIn(self.stack_name, stacks_names)
-
- @decorators.idempotent_id('992f96e3-41ee-4ff6-91c7-bcfb670c0919')
- def test_stack_show(self):
- """Getting details about created stack should be possible."""
- stack = self.client.show_stack(self.stack_name)['stack']
- self.assertIsInstance(stack, dict)
- self.assert_fields_in_dict(stack, 'stack_name', 'id', 'links',
- 'parameters', 'outputs', 'disable_rollback',
- 'stack_status_reason', 'stack_status',
- 'creation_time', 'updated_time',
- 'capabilities', 'notification_topics',
- 'timeout_mins', 'template_description')
- self.assert_fields_in_dict(stack['parameters'], 'AWS::StackId',
- 'trigger', 'AWS::Region', 'AWS::StackName')
- self.assertEqual(True, stack['disable_rollback'],
- 'disable_rollback should default to True')
- self.assertEqual(self.stack_name, stack['stack_name'])
- self.assertEqual(self.stack_id, stack['id'])
- self.assertEqual('fluffy', stack['outputs'][0]['output_key'])
-
- @decorators.idempotent_id('fe719f7a-305a-44d8-bbb5-c91e93d9da17')
- def test_suspend_resume_stack(self):
- """Suspend and resume a stack."""
- self.client.suspend_stack(self.stack_identifier)
- self.client.wait_for_stack_status(self.stack_identifier,
- 'SUSPEND_COMPLETE')
- self.client.resume_stack(self.stack_identifier)
- self.client.wait_for_stack_status(self.stack_identifier,
- 'RESUME_COMPLETE')
-
- @decorators.idempotent_id('c951d55e-7cce-4c1f-83a0-bad735437fa6')
- def test_list_resources(self):
- """Get list of created resources for the stack should be possible."""
- resources = self.list_resources(self.stack_identifier)
- self.assertEqual({self.resource_name: self.resource_type}, resources)
-
- @decorators.idempotent_id('2aba03b3-392f-4237-900b-1f5a5e9bd962')
- def test_show_resource(self):
- """Getting details about created resource should be possible."""
- resource = self.client.show_resource(self.stack_identifier,
- self.resource_name)['resource']
- self.assertIsInstance(resource, dict)
- self.assert_fields_in_dict(resource, 'resource_name', 'description',
- 'links', 'logical_resource_id',
- 'resource_status', 'updated_time',
- 'required_by', 'resource_status_reason',
- 'physical_resource_id', 'resource_type')
- self.assertEqual(self.resource_name, resource['logical_resource_id'])
- self.assertEqual(self.resource_type, resource['resource_type'])
-
- @decorators.idempotent_id('898070a9-eba5-4fae-b7d6-cf3ffa03090f')
- def test_resource_metadata(self):
- """Getting metadata for created resources should be possible."""
- metadata = self.client.show_resource_metadata(
- self.stack_identifier,
- self.resource_name)['metadata']
- self.assertIsInstance(metadata, dict)
- self.assertEqual(['Tom', 'Stinky'], metadata.get('kittens', None))
-
- @decorators.idempotent_id('46567533-0a7f-483b-8942-fa19e0f17839')
- def test_list_events(self):
- """Getting list of created events for the stack should be possible."""
- events = self.client.list_events(self.stack_identifier)['events']
- self.assertIsInstance(events, list)
-
- for event in events:
- self.assert_fields_in_dict(event, 'logical_resource_id', 'id',
- 'resource_status_reason',
- 'resource_status', 'event_time')
-
- resource_statuses = [event['resource_status'] for event in events]
- self.assertIn('CREATE_IN_PROGRESS', resource_statuses)
- self.assertIn('CREATE_COMPLETE', resource_statuses)
-
- @decorators.idempotent_id('92465723-1673-400a-909d-4773757a3f21')
- def test_show_event(self):
- """Getting details about an event should be possible."""
- events = self.client.list_resource_events(self.stack_identifier,
- self.resource_name)['events']
- self.assertNotEqual([], events)
- events.sort(key=lambda event: event['event_time'])
- event_id = events[0]['id']
- event = self.client.show_event(self.stack_identifier,
- self.resource_name, event_id)['event']
- self.assertIsInstance(event, dict)
- self.assert_fields_in_dict(event, 'resource_name', 'event_time',
- 'links', 'logical_resource_id',
- 'resource_status', 'resource_status_reason',
- 'physical_resource_id', 'id',
- 'resource_properties', 'resource_type')
- self.assertEqual(self.resource_name, event['resource_name'])
- self.assertEqual('state changed', event['resource_status_reason'])
- self.assertEqual(self.resource_name, event['logical_resource_id'])
diff --git a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
deleted file mode 100644
index a51648f..0000000
--- a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-
-class NovaKeyPairResourcesYAMLTest(base.BaseOrchestrationTest):
- _tpl_type = 'yaml'
- _resource = 'resources'
- _type = 'type'
-
- @classmethod
- def resource_setup(cls):
- super(NovaKeyPairResourcesYAMLTest, cls).resource_setup()
- cls.stack_name = data_utils.rand_name('heat')
- template = cls.read_template('nova_keypair', ext=cls._tpl_type)
-
- # create the stack, avoid any duplicated key.
- cls.stack_identifier = cls.create_stack(
- cls.stack_name,
- template,
- parameters={
- 'KeyPairName1': cls.stack_name + '_1',
- 'KeyPairName2': cls.stack_name + '_2'
- })
-
- cls.stack_id = cls.stack_identifier.split('/')[1]
- cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
- resources = (cls.client.list_resources(cls.stack_identifier)
- ['resources'])
- cls.test_resources = {}
- for resource in resources:
- cls.test_resources[resource['logical_resource_id']] = resource
-
- @decorators.idempotent_id('b476eac2-a302-4815-961f-18c410a2a537')
- def test_created_resources(self):
- """Verifies created keypair resource."""
-
- nova_keypair_template = self.load_template('nova_keypair',
- ext=self._tpl_type)
- resources = [('KeyPairSavePrivate',
- nova_keypair_template[self._resource][
- 'KeyPairSavePrivate'][self._type]),
- ('KeyPairDontSavePrivate',
- nova_keypair_template[self._resource][
- 'KeyPairDontSavePrivate'][self._type])]
-
- for resource_name, resource_type in resources:
- resource = self.test_resources.get(resource_name, None)
- self.assertIsInstance(resource, dict)
- self.assertEqual(resource_name, resource['logical_resource_id'])
- self.assertEqual(resource_type, resource['resource_type'])
- self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
-
- @decorators.idempotent_id('8d77dec7-91fd-45a6-943d-5abd45e338a4')
- def test_stack_keypairs_output(self):
- stack = self.client.show_stack(self.stack_name)['stack']
- self.assertIsInstance(stack, dict)
-
- output_map = {}
- for outputs in stack['outputs']:
- output_map[outputs['output_key']] = outputs['output_value']
- # Test that first key generated public and private keys
- self.assertIn('KeyPair_PublicKey', output_map)
- self.assertIn("Generated", output_map['KeyPair_PublicKey'])
- self.assertIn('KeyPair_PrivateKey', output_map)
- self.assertIn('-----BEGIN', output_map['KeyPair_PrivateKey'])
- # Test that second key generated public key, and private key is not
- # in the output due to save_private_key = false
- self.assertIn('KeyPairDontSavePrivate_PublicKey', output_map)
- self.assertIn('Generated',
- output_map['KeyPairDontSavePrivate_PublicKey'])
- self.assertIn(u'KeyPairDontSavePrivate_PrivateKey', output_map)
- private_key = output_map['KeyPairDontSavePrivate_PrivateKey']
- self.assertEqual(0, len(private_key))
-
-
-class NovaKeyPairResourcesAWSTest(NovaKeyPairResourcesYAMLTest):
- _tpl_type = 'json'
- _resource = 'Resources'
- _type = 'Type'
diff --git a/tempest/api/orchestration/stacks/test_resource_types.py b/tempest/api/orchestration/stacks/test_resource_types.py
deleted file mode 100644
index 6d0707e..0000000
--- a/tempest/api/orchestration/stacks/test_resource_types.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib import decorators
-
-
-class ResourceTypesTest(base.BaseOrchestrationTest):
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('7123d082-3577-4a30-8f00-f805327c4ffd')
- def test_resource_type_list(self):
- """Verify it is possible to list resource types."""
- resource_types = self.client.list_resource_types()['resource_types']
- self.assertIsInstance(resource_types, list)
- self.assertIn('OS::Nova::Server', resource_types)
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('0e85a483-828b-4a28-a0e3-f0a21809192b')
- def test_resource_type_show(self):
- """Verify it is possible to get schema about resource types."""
- resource_types = self.client.list_resource_types()['resource_types']
- self.assertNotEmpty(resource_types)
-
- for resource_type in resource_types:
- type_schema = self.client.show_resource_type(resource_type)
- self.assert_fields_in_dict(type_schema, 'properties',
- 'attributes', 'resource_type')
- self.assertEqual(resource_type, type_schema['resource_type'])
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('8401821d-65fe-4d43-9fa3-57d5ce3a35c7')
- def test_resource_type_template(self):
- """Verify it is possible to get template about resource types."""
- type_template = self.client.show_resource_type_template(
- 'OS::Nova::Server')
- self.assert_fields_in_dict(
- type_template,
- 'Outputs',
- 'Parameters', 'Resources')
diff --git a/tempest/api/orchestration/stacks/test_soft_conf.py b/tempest/api/orchestration/stacks/test_soft_conf.py
deleted file mode 100644
index 8192999..0000000
--- a/tempest/api/orchestration/stacks/test_soft_conf.py
+++ /dev/null
@@ -1,169 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-from tempest.lib import exceptions as lib_exc
-
-
-class TestSoftwareConfig(base.BaseOrchestrationTest):
-
- def setUp(self):
- super(TestSoftwareConfig, self).setUp()
- self.configs = []
- # Add 2 sets of software configuration
- self.configs.append(self._config_create('a'))
- self.configs.append(self._config_create('b'))
- # Create a deployment using config a's id
- self._deployment_create(self.configs[0]['id'])
-
- def _config_create(self, suffix):
- configuration = {'group': 'script',
- 'inputs': [],
- 'outputs': [],
- 'options': {}}
- configuration['name'] = 'heat_soft_config_%s' % suffix
- configuration['config'] = '#!/bin/bash echo init-%s' % suffix
- api_config = self.client.create_software_config(**configuration)
- configuration['id'] = api_config['software_config']['id']
- self.addCleanup(self._config_delete, configuration['id'])
- self._validate_config(configuration, api_config)
- return configuration
-
- def _validate_config(self, configuration, api_config):
- # Assert all expected keys are present with matching data
- for k in configuration:
- self.assertEqual(configuration[k],
- api_config['software_config'][k])
-
- def _deployment_create(self, config_id):
- self.server_id = data_utils.rand_name('dummy-server')
- self.action = 'ACTION_0'
- self.status = 'STATUS_0'
- self.input_values = {}
- self.output_values = []
- self.status_reason = 'REASON_0'
- self.signal_transport = 'NO_SIGNAL'
- self.deployment = self.client.create_software_deploy(
- self.server_id, config_id, self.action, self.status,
- self.input_values, self.output_values, self.status_reason,
- self.signal_transport)
- self.deployment_id = self.deployment['software_deployment']['id']
- self.addCleanup(self._deployment_delete, self.deployment_id)
-
- def _deployment_delete(self, deploy_id):
- self.client.delete_software_deploy(deploy_id)
- # Testing that it is really gone
- self.assertRaises(
- lib_exc.NotFound, self.client.show_software_deployment,
- self.deployment_id)
-
- def _config_delete(self, config_id):
- self.client.delete_software_config(config_id)
- # Testing that it is really gone
- self.assertRaises(
- lib_exc.NotFound, self.client.show_software_config, config_id)
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('136162ed-9445-4b9c-b7fc-306af8b5da99')
- def test_get_software_config(self):
- """Testing software config get."""
- for conf in self.configs:
- api_config = self.client.show_software_config(conf['id'])
- self._validate_config(conf, api_config)
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('1275c835-c967-4a2c-8d5d-ad533447ed91')
- def test_get_deployment_list(self):
- """Getting a list of all deployments"""
- deploy_list = self.client.list_software_deployments()
- deploy_ids = [deploy['id'] for deploy in
- deploy_list['software_deployments']]
- self.assertIn(self.deployment_id, deploy_ids)
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('fe7cd9f9-54b1-429c-a3b7-7df8451db913')
- def test_get_deployment_metadata(self):
- """Testing deployment metadata get"""
- metadata = self.client.show_software_deployment_metadata(
- self.server_id)
- conf_ids = [conf['id'] for conf in metadata['metadata']]
- self.assertIn(self.configs[0]['id'], conf_ids)
-
- def _validate_deployment(self, action, status, reason, config_id):
- deployment = self.client.show_software_deployment(self.deployment_id)
- self.assertEqual(action, deployment['software_deployment']['action'])
- self.assertEqual(status, deployment['software_deployment']['status'])
- self.assertEqual(reason,
- deployment['software_deployment']['status_reason'])
- self.assertEqual(config_id,
- deployment['software_deployment']['config_id'])
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('f29d21f3-ed75-47cf-8cdc-ef1bdeb4c674')
- def test_software_deployment_create_validate(self):
- """Testing software deployment was created as expected."""
- # Asserting that all fields were created
- self.assert_fields_in_dict(
- self.deployment['software_deployment'], 'action', 'config_id',
- 'id', 'input_values', 'output_values', 'server_id', 'status',
- 'status_reason')
- # Testing get for this deployment and verifying parameters
- self._validate_deployment(self.action, self.status,
- self.status_reason, self.configs[0]['id'])
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('2ac43ab3-34f2-415d-be2e-eabb4d14ee32')
- def test_software_deployment_update_no_metadata_change(self):
- """Testing software deployment update without metadata change."""
- metadata = self.client.show_software_deployment_metadata(
- self.server_id)
- # Updating values without changing the configuration ID
- new_action = 'ACTION_1'
- new_status = 'STATUS_1'
- new_reason = 'REASON_1'
- self.client.update_software_deploy(
- self.deployment_id, self.server_id, self.configs[0]['id'],
- new_action, new_status, self.input_values, self.output_values,
- new_reason, self.signal_transport)
- # Verifying get and that the deployment was updated as expected
- self._validate_deployment(new_action, new_status,
- new_reason, self.configs[0]['id'])
-
- # Metadata should not be changed at this point
- test_metadata = self.client.show_software_deployment_metadata(
- self.server_id)
- for key in metadata['metadata'][0]:
- self.assertEqual(
- metadata['metadata'][0][key],
- test_metadata['metadata'][0][key])
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('92c48944-d79d-4595-a840-8e1a581c1a72')
- def test_software_deployment_update_with_metadata_change(self):
- """Testing software deployment update with metadata change."""
- metadata = self.client.show_software_deployment_metadata(
- self.server_id)
- self.client.update_software_deploy(
- self.deployment_id, self.server_id, self.configs[1]['id'],
- self.action, self.status, self.input_values,
- self.output_values, self.status_reason, self.signal_transport)
- self._validate_deployment(self.action, self.status,
- self.status_reason, self.configs[1]['id'])
- # Metadata should now be changed
- new_metadata = self.client.show_software_deployment_metadata(
- self.server_id)
- # Its enough to test the ID in this case
- meta_id = metadata['metadata'][0]['id']
- test_id = new_metadata['metadata'][0]['id']
- self.assertNotEqual(meta_id, test_id)
diff --git a/tempest/api/orchestration/stacks/test_stacks.py b/tempest/api/orchestration/stacks/test_stacks.py
deleted file mode 100644
index dc1bb4f..0000000
--- a/tempest/api/orchestration/stacks/test_stacks.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-
-class StacksTestJSON(base.BaseOrchestrationTest):
- empty_template = "HeatTemplateFormatVersion: '2012-12-12'\n"
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('d35d628c-07f6-4674-85a1-74db9919e986')
- def test_stack_list_responds(self):
- stacks = self.client.list_stacks()['stacks']
- self.assertIsInstance(stacks, list)
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('10498bd5-a83e-4b62-a817-ce24afe938fe')
- def test_stack_crud_no_resources(self):
- stack_name = data_utils.rand_name('heat')
-
- # create the stack
- stack_identifier = self.create_stack(
- stack_name, self.empty_template)
- stack_id = stack_identifier.split('/')[1]
-
- # wait for create complete (with no resources it should be instant)
- self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-
- # check for stack in list
- stacks = self.client.list_stacks()['stacks']
- list_ids = list([stack['id'] for stack in stacks])
- self.assertIn(stack_id, list_ids)
-
- # fetch the stack
- stack = self.client.show_stack(stack_identifier)['stack']
- self.assertEqual('CREATE_COMPLETE', stack['stack_status'])
-
- # fetch the stack by name
- stack = self.client.show_stack(stack_name)['stack']
- self.assertEqual('CREATE_COMPLETE', stack['stack_status'])
-
- # fetch the stack by id
- stack = self.client.show_stack(stack_id)['stack']
- self.assertEqual('CREATE_COMPLETE', stack['stack_status'])
-
- # delete the stack
- self.client.delete_stack(stack_identifier)
- self.client.wait_for_stack_status(stack_identifier, 'DELETE_COMPLETE')
diff --git a/tempest/api/orchestration/stacks/test_swift_resources.py b/tempest/api/orchestration/stacks/test_swift_resources.py
deleted file mode 100644
index d63cde8..0000000
--- a/tempest/api/orchestration/stacks/test_swift_resources.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# 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.orchestration import base
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-from tempest import test
-
-
-CONF = config.CONF
-
-
-class SwiftResourcesTestJSON(base.BaseOrchestrationTest):
- @classmethod
- def skip_checks(cls):
- super(SwiftResourcesTestJSON, cls).skip_checks()
- if not CONF.service_available.swift:
- raise cls.skipException("Swift support is required")
-
- @classmethod
- def setup_credentials(cls):
- super(SwiftResourcesTestJSON, cls).setup_credentials()
- stack_owner_role = CONF.orchestration.stack_owner_role
- operator_role = CONF.object_storage.operator_role
- cls.os = cls.get_client_manager(
- roles=[stack_owner_role, operator_role])
-
- @classmethod
- def setup_clients(cls):
- super(SwiftResourcesTestJSON, cls).setup_clients()
- cls.account_client = cls.os_primary.account_client
- cls.container_client = cls.os_primary.container_client
-
- @classmethod
- def resource_setup(cls):
- super(SwiftResourcesTestJSON, cls).resource_setup()
- cls.stack_name = data_utils.rand_name('heat')
- template = cls.read_template('swift_basic')
- # create the stack
- cls.stack_identifier = cls.create_stack(
- cls.stack_name,
- template)
- cls.stack_id = cls.stack_identifier.split('/')[1]
- cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
- cls.test_resources = {}
- resources = (cls.client.list_resources(cls.stack_identifier)
- ['resources'])
- for resource in resources:
- cls.test_resources[resource['logical_resource_id']] = resource
-
- @decorators.idempotent_id('1a6fe69e-4be4-4990-9a7a-84b6f18019cb')
- def test_created_resources(self):
- """Created stack should be in the list of existing stacks."""
- swift_basic_template = self.load_template('swift_basic')
- resources = [('SwiftContainer', swift_basic_template['resources'][
- 'SwiftContainer']['type']),
- ('SwiftContainerWebsite', swift_basic_template[
- 'resources']['SwiftContainerWebsite']['type'])]
- for resource_name, resource_type in resources:
- resource = self.test_resources.get(resource_name)
- self.assertIsInstance(resource, dict)
- self.assertEqual(resource_type, resource['resource_type'])
- self.assertEqual(resource_name, resource['logical_resource_id'])
- self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
-
- @decorators.idempotent_id('bd438b18-5494-4d5a-9ce6-d2a942ec5060')
- @test.services('object_storage')
- def test_created_containers(self):
- params = {'format': 'json'}
- _, container_list = \
- self.account_client.list_account_containers(params=params)
- created_containers = [cont for cont in container_list
- if cont['name'].startswith(self.stack_name)]
- self.assertEqual(2, len(created_containers))
-
- @decorators.idempotent_id('73d0c093-9922-44a0-8b1d-1fc092dee367')
- @test.services('object_storage')
- def test_acl(self):
- acl_headers = ('x-container-meta-web-index', 'x-container-read')
-
- swcont = self.test_resources.get(
- 'SwiftContainer')['physical_resource_id']
- swcont_website = self.test_resources.get(
- 'SwiftContainerWebsite')['physical_resource_id']
-
- headers, _ = self.container_client.list_container_metadata(swcont)
- for h in acl_headers:
- self.assertNotIn(h, headers)
- headers, _ = self.container_client.list_container_metadata(
- swcont_website)
- for h in acl_headers:
- self.assertIn(h, headers)
-
- @decorators.idempotent_id('fda06135-6777-4594-aefa-0f6107169698')
- @test.services('object_storage')
- def test_metadata(self):
- swift_basic_template = self.load_template('swift_basic')
- metadatas = swift_basic_template['resources']['SwiftContainerWebsite'][
- 'properties']['X-Container-Meta']
- swcont_website = self.test_resources.get(
- 'SwiftContainerWebsite')['physical_resource_id']
- headers, _ = self.container_client.list_container_metadata(
- swcont_website)
-
- for meta in metadatas:
- header_meta = "x-container-meta-%s" % meta
- self.assertIn(header_meta, headers)
- self.assertEqual(headers[header_meta], metadatas[meta])
diff --git a/tempest/api/orchestration/stacks/test_templates.py b/tempest/api/orchestration/stacks/test_templates.py
deleted file mode 100644
index 4ff951d..0000000
--- a/tempest/api/orchestration/stacks/test_templates.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-
-class TemplateYAMLTestJSON(base.BaseOrchestrationTest):
- template = """
-HeatTemplateFormatVersion: '2012-12-12'
-Description: |
- Template which creates only a new user
-Resources:
- CfnUser:
- Type: AWS::IAM::User
-"""
-
- @classmethod
- def resource_setup(cls):
- super(TemplateYAMLTestJSON, cls).resource_setup()
- cls.stack_name = data_utils.rand_name('heat')
- cls.stack_identifier = cls.create_stack(cls.stack_name, cls.template)
- cls.client.wait_for_stack_status(cls.stack_identifier,
- 'CREATE_COMPLETE')
- cls.stack_id = cls.stack_identifier.split('/')[1]
- cls.parameters = {}
-
- @decorators.idempotent_id('47430699-c368-495e-a1db-64c26fd967d7')
- def test_show_template(self):
- """Getting template used to create the stack."""
- self.client.show_template(self.stack_identifier)
-
- @decorators.idempotent_id('ed53debe-8727-46c5-ab58-eba6090ec4de')
- def test_validate_template(self):
- """Validating template passing it content."""
- self.client.validate_template(self.template,
- self.parameters)
-
-
-class TemplateAWSTestJSON(TemplateYAMLTestJSON):
- template = """
-{
- "AWSTemplateFormatVersion" : "2010-09-09",
- "Description" : "Template which creates only a new user",
- "Resources" : {
- "CfnUser" : {
- "Type" : "AWS::IAM::User"
- }
- }
-}
-"""
diff --git a/tempest/api/orchestration/stacks/test_templates_negative.py b/tempest/api/orchestration/stacks/test_templates_negative.py
deleted file mode 100644
index eb93d95..0000000
--- a/tempest/api/orchestration/stacks/test_templates_negative.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2014 NEC Corporation. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib import decorators
-from tempest.lib import exceptions as lib_exc
-
-
-class TemplateYAMLNegativeTestJSON(base.BaseOrchestrationTest):
- template = """
-HeatTemplateFormatVersion: '2012-12-12'
-Description: |
- Template which creates only a new user
-Resources:
- CfnUser:
- Type: AWS::IAM::User
-"""
-
- invalid_template_url = 'http:///template.yaml'
-
- @classmethod
- def resource_setup(cls):
- super(TemplateYAMLNegativeTestJSON, cls).resource_setup()
- cls.parameters = {}
-
- @decorators.attr(type=['negative'])
- @decorators.idempotent_id('5586cbca-ddc4-4152-9db8-fa1ce5fc1876')
- def test_validate_template_url(self):
- """Validating template passing url to it."""
- self.assertRaises(lib_exc.BadRequest,
- self.client.validate_template_url,
- template_url=self.invalid_template_url,
- parameters=self.parameters)
-
-
-class TemplateAWSNegativeTestJSON(TemplateYAMLNegativeTestJSON):
- template = """
-{
- "AWSTemplateFormatVersion" : "2010-09-09",
- "Description" : "Template which creates only a new user",
- "Resources" : {
- "CfnUser" : {
- "Type" : "AWS::IAM::User"
- }
- }
-}
-"""
-
- invalid_template_url = 'http:///template.template'
diff --git a/tempest/api/orchestration/stacks/test_volumes.py b/tempest/api/orchestration/stacks/test_volumes.py
deleted file mode 100644
index 7ddf7af..0000000
--- a/tempest/api/orchestration/stacks/test_volumes.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-from tempest.lib import exceptions as lib_exc
-from tempest import test
-
-
-CONF = config.CONF
-
-
-class CinderResourcesTest(base.BaseOrchestrationTest):
-
- @classmethod
- def skip_checks(cls):
- super(CinderResourcesTest, cls).skip_checks()
- if not CONF.service_available.cinder:
- raise cls.skipException('Cinder support is required')
-
- def _cinder_verify(self, volume_id, template):
- self.assertIsNotNone(volume_id)
- volume = self.volumes_client.show_volume(volume_id)['volume']
- self.assertEqual('available', volume.get('status'))
- self.assertEqual(CONF.volume.volume_size, volume.get('size'))
-
- self.assertEqual(template['resources']['volume']['properties'][
- 'description'], volume.get('description'))
- self.assertEqual(template['resources']['volume']['properties'][
- 'name'], volume.get('name'))
-
- def _outputs_verify(self, stack_identifier, template):
- self.assertEqual('available',
- self.get_stack_output(stack_identifier, 'status'))
- self.assertEqual(str(CONF.volume.volume_size),
- self.get_stack_output(stack_identifier, 'size'))
- self.assertEqual(template['resources']['volume']['properties'][
- 'description'], self.get_stack_output(stack_identifier,
- 'display_description'))
- self.assertEqual(template['resources']['volume']['properties'][
- 'name'], self.get_stack_output(stack_identifier, 'display_name'))
-
- @decorators.idempotent_id('c3243329-7bdd-4730-b402-4d19d50c41d8')
- @test.services('volume')
- def test_cinder_volume_create_delete(self):
- """Create and delete a volume via OS::Cinder::Volume."""
- stack_name = data_utils.rand_name('heat')
- template = self.read_template('cinder_basic')
- stack_identifier = self.create_stack(
- stack_name,
- template,
- parameters={
- 'volume_size': CONF.volume.volume_size
- })
- self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-
- # Verify with cinder that the volume exists, with matching details
- volume_id = self.get_stack_output(stack_identifier, 'volume_id')
- cinder_basic_template = self.load_template('cinder_basic')
- self._cinder_verify(volume_id, cinder_basic_template)
-
- # Verify the stack outputs are as expected
- self._outputs_verify(stack_identifier, cinder_basic_template)
-
- # Delete the stack and ensure the volume is gone
- self.client.delete_stack(stack_identifier)
- self.client.wait_for_stack_status(stack_identifier, 'DELETE_COMPLETE')
- self.assertRaises(lib_exc.NotFound,
- self.volumes_client.show_volume,
- volume_id)
-
- def _cleanup_volume(self, volume_id):
- """Cleanup the volume direct with cinder."""
- self.volumes_client.delete_volume(volume_id)
- self.volumes_client.wait_for_resource_deletion(volume_id)
-
- @decorators.idempotent_id('ea8b3a46-b932-4c18-907a-fe23f00b33f8')
- @test.services('volume')
- def test_cinder_volume_create_delete_retain(self):
- """Ensure the 'Retain' deletion policy is respected."""
- stack_name = data_utils.rand_name('heat')
- template = self.read_template('cinder_basic_delete_retain')
- stack_identifier = self.create_stack(
- stack_name,
- template,
- parameters={
- 'volume_size': CONF.volume.volume_size
- })
- self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-
- # Verify with cinder that the volume exists, with matching details
- volume_id = self.get_stack_output(stack_identifier, 'volume_id')
- self.addCleanup(self._cleanup_volume, volume_id)
- retain_template = self.load_template('cinder_basic_delete_retain')
- self._cinder_verify(volume_id, retain_template)
-
- # Verify the stack outputs are as expected
- self._outputs_verify(stack_identifier, retain_template)
-
- # Delete the stack and ensure the volume is *not* gone
- self.client.delete_stack(stack_identifier)
- self.client.wait_for_stack_status(stack_identifier, 'DELETE_COMPLETE')
- self._cinder_verify(volume_id, retain_template)
-
- # Volume cleanup happens via addCleanup calling _cleanup_volume
diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
index 04d6cf9..e4ec442 100644
--- a/tempest/api/volume/admin/test_volume_hosts.py
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import random
+
from tempest.api.volume import base
from tempest.lib import decorators
@@ -22,5 +24,38 @@
@decorators.idempotent_id('d5f3efa2-6684-4190-9ced-1c2f526352ad')
def test_list_hosts(self):
hosts = self.admin_hosts_client.list_hosts()['hosts']
- self.assertGreaterEqual(len(hosts), 2, "No. of hosts are < 2,"
- "response of list hosts is: % s" % hosts)
+ self.assertGreaterEqual(len(hosts), 2,
+ "The count of volume hosts is < 2, "
+ "response of list hosts is: %s" % hosts)
+
+ # Check elements in volume hosts list
+ host_list_keys = ['service', 'host_name', 'last-update',
+ 'zone', 'service-status', 'service-state']
+ for host in hosts:
+ for key in host_list_keys:
+ self.assertIn(key, host)
+
+ @decorators.idempotent_id('21168d57-b373-4b71-a3ac-f2c88f0c5d31')
+ def test_show_host(self):
+ hosts = self.admin_hosts_client.list_hosts()['hosts']
+ self.assertGreaterEqual(len(hosts), 2,
+ "The count of volume hosts is < 2, "
+ "response of list hosts is: %s" % hosts)
+
+ # Note(jeremyZ): Host in volume is always presented in two formats:
+ # <host-name> or <host-name>@<driver-name>. Since Mitaka is EOL,
+ # both formats can be chosen for test.
+ host_names = [host['host_name'] for host in hosts]
+ self.assertNotEmpty(host_names, "No available volume host is found, "
+ "all hosts that found are: %s" % hosts)
+
+ # Choose a random host to get and check its elements
+ host_details = self.admin_hosts_client.show_host(
+ random.choice(host_names))['host']
+ self.assertNotEmpty(host_details)
+ host_detail_keys = ['project', 'volume_count', 'snapshot_count',
+ 'host', 'total_volume_gb', 'total_snapshot_gb']
+ for detail in host_details:
+ self.assertIn('resource', detail)
+ for key in host_detail_keys:
+ self.assertIn(key, detail['resource'])
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index a6f9246..afc3281 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -121,7 +121,7 @@
'available')
@decorators.idempotent_id('47a35425-a891-4e13-961c-c45deea21e94')
- def test_volume_backup_reset_status_force_delete(self):
+ def test_volume_backup_reset_status(self):
# Create a volume
volume = self.create_volume()
# Create a backup
@@ -136,6 +136,3 @@
status="error")
waiters.wait_for_volume_resource_status(self.admin_backups_client,
backup['id'], 'error')
- # Force delete a backup volume when backup is in error state.
- self.admin_backups_client.force_delete_backup(backup['id'])
- self.admin_backups_client.wait_for_resource_deletion(backup['id'])
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index c877969..3f33c7b 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -80,6 +80,9 @@
cls.messages_client = cls.os_primary.volume_v3_messages_client
cls.versions_client = cls.os_primary.volume_v3_versions_client
+ if cls._api_version == 3:
+ cls.volumes_client = cls.os_primary.volumes_v3_client
+
def setUp(self):
super(BaseVolumeTest, self).setUp()
self.useFixture(api_microversion_fixture.APIMicroversionFixture(
@@ -144,8 +147,7 @@
snapshot['id'], 'available')
return snapshot
- def create_backup(self, volume_id, backup_client=None,
- wait_until="available", **kwargs):
+ def create_backup(self, volume_id, backup_client=None, **kwargs):
"""Wrapper utility that returns a test backup."""
if backup_client is None:
backup_client = self.backups_client
@@ -155,12 +157,9 @@
backup = backup_client.create_backup(
volume_id=volume_id, **kwargs)['backup']
-
- self.addCleanup(test_utils.call_and_ignore_notfound_exc,
- backup_client.delete_backup, backup['id'])
- waiters.wait_for_volume_resource_status(backup_client,
- backup['id'],
- wait_until)
+ self.addCleanup(backup_client.delete_backup, backup['id'])
+ waiters.wait_for_volume_resource_status(backup_client, backup['id'],
+ 'available')
return backup
# NOTE(afazekas): these create_* and clean_* could be defined
@@ -270,6 +269,9 @@
cls.os_admin.volume_scheduler_stats_v2_client
cls.admin_messages_client = cls.os_admin.volume_v3_messages_client
+ if cls._api_version == 3:
+ cls.admin_volume_client = cls.os_admin.volumes_v3_client
+
@classmethod
def resource_setup(cls):
super(BaseVolumeAdminTest, cls).resource_setup()
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index 5fd1904..5a192ac 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -63,6 +63,12 @@
transfer_id, auth_key=auth_key)['transfer']
waiters.wait_for_volume_resource_status(self.alt_volumes_client,
volume['id'], 'available')
+ accepted_volume = self.alt_volumes_client.show_volume(
+ volume['id'])['volume']
+ self.assertEqual(self.os_alt.credentials.user_id,
+ accepted_volume['user_id'])
+ self.assertEqual(self.os_alt.credentials.project_id,
+ accepted_volume['os-vol-tenant-attr:tenant_id'])
@decorators.idempotent_id('ab526943-b725-4c07-b875-8e8ef87a2c30')
def test_create_list_delete_volume_transfer(self):
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index 84ecb22..1eb76a0 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -13,10 +13,15 @@
# 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.lib import decorators
+CONF = config.CONF
+
class VolumesExtendTest(base.BaseVolumeTest):
@@ -31,3 +36,20 @@
volume['id'], 'available')
volume = self.volumes_client.show_volume(volume['id'])['volume']
self.assertEqual(volume['size'], extend_size)
+
+ @decorators.idempotent_id('86be1cba-2640-11e5-9c82-635fb964c912')
+ @testtools.skipUnless(CONF.volume_feature_enabled.snapshot,
+ "Cinder volume snapshots are disabled")
+ @decorators.skip_because(bug='1687044')
+ def test_volume_extend_when_volume_has_snapshot(self):
+ volume = self.create_volume()
+ self.create_snapshot(volume['id'])
+
+ extend_size = volume['size'] + 1
+ self.volumes_client.extend_volume(volume['id'], new_size=extend_size)
+
+ waiters.wait_for_volume_resource_status(self.volumes_client,
+ volume['id'], 'available')
+ resized_volume = self.volumes_client.show_volume(
+ volume['id'])['volume']
+ self.assertEqual(extend_size, resized_volume['size'])
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 712254e..ec9a0dd 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -137,3 +137,17 @@
origin = self.create_volume()
self._volume_create_get_update_delete(source_volid=origin['id'],
size=CONF.volume.volume_size)
+
+
+class VolumesSummaryTest(base.BaseVolumeTest):
+
+ _api_version = 3
+ min_microversion = '3.12'
+ max_microversion = 'latest'
+
+ @decorators.idempotent_id('c4f2431e-4920-4736-9e00-4040386b6feb')
+ def test_show_volume_summary(self):
+ volume_summary = \
+ self.volumes_client.show_volume_summary()['volume-summary']
+ for key in ['total_size', 'total_count']:
+ self.assertIn(key, volume_summary)
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index be3f1f2..99918eb 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -35,10 +35,9 @@
super(VolumesSnapshotTestJSON, cls).resource_setup()
cls.volume_origin = cls.create_volume()
- @decorators.idempotent_id('b467b54c-07a4-446d-a1cf-651dedcc3ff1')
+ @decorators.idempotent_id('8567b54c-4455-446d-a1cf-651ddeaa3ff2')
@test.services('compute')
- def test_snapshot_create_with_volume_in_use(self):
- # Create a snapshot when volume status is in-use
+ def test_snapshot_create_delete_with_volume_in_use(self):
# Create a test instance
server = self.create_server(wait_until='ACTIVE')
self.attach_volume(server['id'], self.volume_origin['id'])
@@ -47,19 +46,6 @@
self.assertRaises(lib_exc.BadRequest, self.create_snapshot,
self.volume_origin['id'], force=False)
- # Snapshot a volume even if it's attached to an instance
- snapshot = self.create_snapshot(self.volume_origin['id'],
- force=True)
- # Delete the snapshot
- self.delete_snapshot(snapshot['id'])
-
- @decorators.idempotent_id('8567b54c-4455-446d-a1cf-651ddeaa3ff2')
- @test.services('compute')
- def test_snapshot_delete_with_volume_in_use(self):
- # Create a test instance
- server = self.create_server(wait_until='ACTIVE')
- self.attach_volume(server['id'], self.volume_origin['id'])
-
# Snapshot a volume attached to an instance
snapshot1 = self.create_snapshot(self.volume_origin['id'], force=True)
snapshot2 = self.create_snapshot(self.volume_origin['id'], force=True)
diff --git a/tempest/clients.py b/tempest/clients.py
index 73a4b20..4baa31d 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -269,6 +269,7 @@
self.volume_manage_v2_client = self.volume_v2.VolumeManageClient()
self.volumes_client = self.volume_v1.VolumesClient()
self.volumes_v2_client = self.volume_v2.VolumesClient()
+ self.volumes_v3_client = self.volume_v3.VolumesClient()
self.volume_v3_messages_client = self.volume_v3.MessagesClient()
self.volume_v3_versions_client = self.volume_v3.VersionsClient()
self.volume_types_client = self.volume_v1.TypesClient()
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 9587ffe..9110c4a 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -15,6 +15,7 @@
import base64
import socket
+import ssl
import struct
import textwrap
@@ -236,7 +237,11 @@
def create_websocket(url):
url = urlparse.urlparse(url)
- client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ if url.scheme == 'https':
+ client_socket = ssl.wrap_socket(socket.socket(socket.AF_INET,
+ socket.SOCK_STREAM))
+ else:
+ client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
client_socket.connect((url.hostname, url.port))
# Turn the Socket into a WebSocket to do the communication
diff --git a/tempest/config.py b/tempest/config.py
index f5b2f0d..a5225e6 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -899,38 +899,58 @@
OrchestrationGroup = [
cfg.StrOpt('catalog_type',
default='orchestration',
- help="Catalog type of the Orchestration service."),
+ help="Catalog type of the Orchestration service.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.StrOpt('region',
default='',
help="The orchestration region name to use. If empty, the "
"value of identity.region is used instead. If no such "
"region is found in the service catalog, the first found "
- "one is used."),
+ "one is used.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.StrOpt('endpoint_type',
default='publicURL',
choices=['public', 'admin', 'internal',
'publicURL', 'adminURL', 'internalURL'],
- help="The endpoint type to use for the orchestration service."),
+ help="The endpoint type to use for the orchestration service.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.StrOpt('stack_owner_role', default='heat_stack_owner',
- help='Role required for users to be able to manage stacks'),
+ help='Role required for users to be able to manage stacks',
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.IntOpt('build_interval',
default=1,
- help="Time in seconds between build status checks."),
+ help="Time in seconds between build status checks.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.IntOpt('build_timeout',
default=1200,
- help="Timeout in seconds to wait for a stack to build."),
+ help="Timeout in seconds to wait for a stack to build.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.StrOpt('instance_type',
default='m1.micro',
help="Instance type for tests. Needs to be big enough for a "
- "full OS plus the test workload"),
+ "full OS plus the test workload",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.StrOpt('keypair_name',
- help="Name of existing keypair to launch servers with."),
+ help="Name of existing keypair to launch servers with.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.IntOpt('max_template_size',
default=524288,
- help="Value must match heat configuration of the same name."),
+ help="Value must match heat configuration of the same name.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.IntOpt('max_resources_per_stack',
default=1000,
- help="Value must match heat configuration of the same name."),
+ help="Value must match heat configuration of the same name.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
]
@@ -996,7 +1016,9 @@
help="Whether or not nova is expected to be available"),
cfg.BoolOpt('heat',
default=False,
- help="Whether or not Heat is expected to be available"),
+ help="Whether or not Heat is expected to be available",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
]
debug_group = cfg.OptGroup(name="debug",
diff --git a/tempest/lib/services/volume/v2/backups_client.py b/tempest/lib/services/volume/v2/backups_client.py
index 197d57e..2b5e82d 100644
--- a/tempest/lib/services/volume/v2/backups_client.py
+++ b/tempest/lib/services/volume/v2/backups_client.py
@@ -55,14 +55,6 @@
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
- def force_delete_backup(self, backup_id):
- """Force delete a backup volume."""
- post_body = json.dumps({'os-force_delete': {}})
- url = 'backups/%s/action' % backup_id
- resp, body = self.post(url, post_body)
- self.expected_success(202, resp.status)
- return rest_client.ResponseBody(resp)
-
def show_backup(self, backup_id):
"""Returns the details of a single backup."""
url = "backups/%s" % backup_id
diff --git a/tempest/lib/services/volume/v2/hosts_client.py b/tempest/lib/services/volume/v2/hosts_client.py
index dd7c482..8fcf4d0 100644
--- a/tempest/lib/services/volume/v2/hosts_client.py
+++ b/tempest/lib/services/volume/v2/hosts_client.py
@@ -34,3 +34,11 @@
body = json.loads(body)
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
+
+ def show_host(self, host_name):
+ """Show host details."""
+ url = 'os-hosts/%s' % host_name
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v3/__init__.py b/tempest/lib/services/volume/v3/__init__.py
index 72ab785..07ae917 100644
--- a/tempest/lib/services/volume/v3/__init__.py
+++ b/tempest/lib/services/volume/v3/__init__.py
@@ -15,5 +15,6 @@
from tempest.lib.services.volume.v3.base_client import BaseClient
from tempest.lib.services.volume.v3.messages_client import MessagesClient
from tempest.lib.services.volume.v3.versions_client import VersionsClient
+from tempest.lib.services.volume.v3.volumes_client import VolumesClient
-__all__ = ['MessagesClient', 'BaseClient', 'VersionsClient']
+__all__ = ['MessagesClient', 'BaseClient', 'VersionsClient', 'VolumesClient']
diff --git a/tempest/lib/services/volume/v3/volumes_client.py b/tempest/lib/services/volume/v3/volumes_client.py
new file mode 100644
index 0000000..aec0205
--- /dev/null
+++ b/tempest/lib/services/volume/v3/volumes_client.py
@@ -0,0 +1,42 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# 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
+from tempest.lib.services.volume.v2 import volumes_client
+from tempest.lib.services.volume.v3 import base_client
+
+
+class VolumesClient(base_client.BaseClient,
+ volumes_client.VolumesClient):
+ """Client class to send CRUD Volume V3 API requests"""
+ api_version = "v3"
+
+ def show_volume_summary(self, **params):
+ """Get volumes summary.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/block-storage/v3/#get-volumes-summary
+ """
+ url = 'volumes/summary'
+ if params:
+ url += '?%s' % urllib.urlencode(params)
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/test.py b/tempest/test.py
index f6b17ad..e8108f4 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -339,24 +339,24 @@
if credentials_type == 'primary':
cls.os = debtcollector.moves.moved_read_only_property(
'os', 'os_primary', version='Pike',
- removal_version='Ocata')
+ removal_version='Queens')
cls.manager =\
debtcollector.moves.moved_read_only_property(
'manager', 'os_primary', version='Pike',
- removal_version='Ocata')
+ removal_version='Queens')
if credentials_type == 'admin':
cls.os_adm = debtcollector.moves.moved_read_only_property(
'os_adm', 'os_admin', version='Pike',
- removal_version='Ocata')
+ removal_version='Queens')
cls.admin_manager =\
debtcollector.moves.moved_read_only_property(
'admin_manager', 'os_admin', version='Pike',
- removal_version='Ocata')
+ removal_version='Queens')
if credentials_type == 'alt':
cls.alt_manager =\
debtcollector.moves.moved_read_only_property(
'alt_manager', 'os_alt', version='Pike',
- removal_version='Ocata')
+ removal_version='Queens')
elif isinstance(credentials_type, list):
manager = cls.get_client_manager(roles=credentials_type[1:],
force_new=True)
diff --git a/tempest/tests/lib/services/base.py b/tempest/tests/lib/services/base.py
index a244aa2..71b7f2d 100644
--- a/tempest/tests/lib/services/base.py
+++ b/tempest/tests/lib/services/base.py
@@ -12,8 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import fixtures
from oslo_serialization import jsonutils as json
-from oslotest import mockpatch
from tempest.tests import base
from tempest.tests.lib import fake_http
@@ -33,7 +33,7 @@
body, to_utf=False, status=200,
headers=None, **kwargs):
mocked_response = self.create_response(body, to_utf, status, headers)
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
function2mock, return_value=mocked_response))
if kwargs:
resp = function(**kwargs)
diff --git a/tempest/tests/lib/services/compute/test_flavors_client.py b/tempest/tests/lib/services/compute/test_flavors_client.py
index 445ee22..cbd17c6 100644
--- a/tempest/tests/lib/services/compute/test_flavors_client.py
+++ b/tempest/tests/lib/services/compute/test_flavors_client.py
@@ -14,8 +14,8 @@
import copy
+import fixtures
from oslo_serialization import jsonutils as json
-from oslotest import mockpatch
from tempest.lib.services.compute import flavors_client
from tempest.tests.lib import fake_auth_provider
@@ -118,7 +118,7 @@
if bytes_body:
body = body.encode('utf-8')
response = fake_http.fake_http_response({}, status=200), body
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.lib.common.rest_client.RestClient.get',
return_value=response))
self.assertEqual(is_deleted,
diff --git a/tempest/tests/lib/services/compute/test_floating_ips_client.py b/tempest/tests/lib/services/compute/test_floating_ips_client.py
index 92737f2..950f9ce 100644
--- a/tempest/tests/lib/services/compute/test_floating_ips_client.py
+++ b/tempest/tests/lib/services/compute/test_floating_ips_client.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from oslotest import mockpatch
+import fixtures
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import floating_ips_client
@@ -99,14 +99,14 @@
server_id='c782b7a9-33cd-45f0-b795-7f87f456408b')
def test_is_resource_deleted_true(self):
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.lib.services.compute.floating_ips_client.'
'FloatingIPsClient.show_floating_ip',
side_effect=lib_exc.NotFound()))
self.assertTrue(self.client.is_resource_deleted('fake-id'))
def test_is_resource_deleted_false(self):
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.lib.services.compute.floating_ips_client.'
'FloatingIPsClient.show_floating_ip',
return_value={"floating_ip": TestFloatingIpsClient.floating_ip}))
diff --git a/tempest/tests/lib/services/compute/test_images_client.py b/tempest/tests/lib/services/compute/test_images_client.py
index a9a570d..c2c3b76 100644
--- a/tempest/tests/lib/services/compute/test_images_client.py
+++ b/tempest/tests/lib/services/compute/test_images_client.py
@@ -14,8 +14,7 @@
import copy
-from oslotest import mockpatch
-
+import fixtures
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import images_client
from tempest.tests.lib import fake_auth_provider
@@ -187,15 +186,15 @@
def _test_resource_deleted(self, bytes_body=False):
params = {"id": self.FAKE_IMAGE_ID}
expected_op = self.FAKE_IMAGE_DATA['show']
- self.useFixture(mockpatch.Patch('tempest.lib.services.compute'
+ self.useFixture(fixtures.MockPatch('tempest.lib.services.compute'
'.images_client.ImagesClient.show_image',
- side_effect=lib_exc.NotFound))
+ side_effect=lib_exc.NotFound))
self.assertEqual(True, self.client.is_resource_deleted(**params))
tempdata = copy.deepcopy(self.FAKE_IMAGE_DATA['show'])
tempdata['image']['id'] = None
- self.useFixture(mockpatch.Patch('tempest.lib.services.compute'
+ self.useFixture(fixtures.MockPatch('tempest.lib.services.compute'
'.images_client.ImagesClient.show_image',
- return_value=expected_op))
+ return_value=expected_op))
self.assertEqual(False, self.client.is_resource_deleted(**params))
def test_list_images_with_str_body(self):
diff --git a/tempest/tests/lib/services/compute/test_security_groups_client.py b/tempest/tests/lib/services/compute/test_security_groups_client.py
index d293a08..7bbf20e 100644
--- a/tempest/tests/lib/services/compute/test_security_groups_client.py
+++ b/tempest/tests/lib/services/compute/test_security_groups_client.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from oslotest import mockpatch
+import fixtures
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import security_groups_client
@@ -103,11 +103,11 @@
def test_is_resource_deleted_true(self):
mod = ('tempest.lib.services.compute.security_groups_client.'
'SecurityGroupsClient.show_security_group')
- self.useFixture(mockpatch.Patch(mod, side_effect=lib_exc.NotFound))
+ self.useFixture(fixtures.MockPatch(mod, side_effect=lib_exc.NotFound))
self.assertTrue(self.client.is_resource_deleted('fake-id'))
def test_is_resource_deleted_false(self):
mod = ('tempest.lib.services.compute.security_groups_client.'
'SecurityGroupsClient.show_security_group')
- self.useFixture(mockpatch.Patch(mod, return_value='success'))
+ self.useFixture(fixtures.MockPatch(mod, return_value='success'))
self.assertFalse(self.client.is_resource_deleted('fake-id'))
diff --git a/tempest/tests/lib/services/compute/test_server_groups_client.py b/tempest/tests/lib/services/compute/test_server_groups_client.py
index bf03b84..1c535ca 100644
--- a/tempest/tests/lib/services/compute/test_server_groups_client.py
+++ b/tempest/tests/lib/services/compute/test_server_groups_client.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from oslotest import mockpatch
+import fixtures
from tempest.tests.lib import fake_auth_provider
from tempest.lib.services.compute import server_groups_client
@@ -50,7 +50,7 @@
def test_delete_server_group(self):
response = fake_http.fake_http_response({}, status=204), ''
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.lib.common.rest_client.RestClient.delete',
return_value=response))
self.client.delete_server_group('fake-group')
diff --git a/tempest/tests/lib/services/compute/test_snapshots_client.py b/tempest/tests/lib/services/compute/test_snapshots_client.py
index 1629943..1e2902c 100644
--- a/tempest/tests/lib/services/compute/test_snapshots_client.py
+++ b/tempest/tests/lib/services/compute/test_snapshots_client.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from oslotest import mockpatch
+import fixtures
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import snapshots_client
@@ -91,13 +91,13 @@
def test_is_resource_deleted_true(self):
module = ('tempest.lib.services.compute.snapshots_client.'
'SnapshotsClient.show_snapshot')
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
module, side_effect=lib_exc.NotFound))
self.assertTrue(self.client.is_resource_deleted('fake-id'))
def test_is_resource_deleted_false(self):
module = ('tempest.lib.services.compute.snapshots_client.'
'SnapshotsClient.show_snapshot')
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
module, return_value={}))
self.assertFalse(self.client.is_resource_deleted('fake-id'))
diff --git a/tempest/tests/lib/services/compute/test_versions_client.py b/tempest/tests/lib/services/compute/test_versions_client.py
index 255a0a3..40d424f 100644
--- a/tempest/tests/lib/services/compute/test_versions_client.py
+++ b/tempest/tests/lib/services/compute/test_versions_client.py
@@ -14,7 +14,7 @@
import copy
-from oslotest import mockpatch
+import fixtures
from tempest.lib.services.compute import versions_client
from tempest.tests.lib import fake_auth_provider
@@ -73,7 +73,7 @@
200)
def _test_get_version_by_url(self, bytes_body=False):
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
"tempest.lib.common.rest_client.RestClient.token",
return_value="Dummy Token"))
params = {"version_url": self.versions_client._get_base_version_url()}
diff --git a/tempest/tests/lib/services/compute/test_volumes_client.py b/tempest/tests/lib/services/compute/test_volumes_client.py
index b81cdbb..4b4f02e 100644
--- a/tempest/tests/lib/services/compute/test_volumes_client.py
+++ b/tempest/tests/lib/services/compute/test_volumes_client.py
@@ -14,7 +14,7 @@
import copy
-from oslotest import mockpatch
+import fixtures
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import volumes_client
@@ -102,13 +102,13 @@
def test_is_resource_deleted_true(self):
module = ('tempest.lib.services.compute.volumes_client.'
'VolumesClient.show_volume')
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
module, side_effect=lib_exc.NotFound))
self.assertTrue(self.client.is_resource_deleted('fake-id'))
def test_is_resource_deleted_false(self):
module = ('tempest.lib.services.compute.volumes_client.'
'VolumesClient.show_volume')
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
module, return_value={}))
self.assertFalse(self.client.is_resource_deleted('fake-id'))
diff --git a/tempest/tests/lib/services/volume/v2/test_hosts_client.py b/tempest/tests/lib/services/volume/v2/test_hosts_client.py
new file mode 100644
index 0000000..e107910
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v2/test_hosts_client.py
@@ -0,0 +1,97 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# 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.volume.v2 import hosts_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestQuotasClient(base.BaseServiceTest):
+ FAKE_LIST_HOSTS = {
+ "hosts": [
+ {
+ "service-status": "available",
+ "service": "cinder-scheduler",
+ "zone": "nova",
+ "service-state": "enabled",
+ "host_name": "fake-host",
+ "last-update": "2017-04-12T04:26:03.000000"
+ },
+ {
+ "service-status": "available",
+ "service": "cinder-volume",
+ "zone": "nova",
+ "service-state": "enabled",
+ "host_name": "fake-host@rbd",
+ "last-update": "2017-04-12T04:26:07.000000"
+ }
+ ]
+ }
+
+ FAKE_HOST_INFO = {
+ "host": [
+ {
+ "resource": {
+ "volume_count": "2",
+ "total_volume_gb": "2",
+ "total_snapshot_gb": "0",
+ "project": "(total)",
+ "host": "fake-host",
+ "snapshot_count": "0"
+ }
+ },
+ {
+ "resource": {
+ "volume_count": "2",
+ "total_volume_gb": "2",
+ "total_snapshot_gb": "0",
+ "project": "f21a9c86d7114bf99c711f4874d80474",
+ "host": "fake-host",
+ "snapshot_count": "0"
+ }
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestQuotasClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = hosts_client.HostsClient(fake_auth,
+ 'volume',
+ 'regionOne')
+
+ def _test_list_hosts(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_hosts,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_HOSTS, bytes_body)
+
+ def _test_show_host(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_host,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_HOST_INFO, bytes_body, host_name='fake-host')
+
+ def test_list_hosts_with_str_body(self):
+ self._test_list_hosts()
+
+ def test_list_hosts_with_bytes_body(self):
+ self._test_list_hosts(bytes_body=True)
+
+ def test_show_host_with_str_body(self):
+ self._test_show_host()
+
+ def test_show_host_with_bytes_body(self):
+ self._test_show_host(bytes_body=True)
diff --git a/tempest/tests/lib/services/volume/v3/test_volumes_client.py b/tempest/tests/lib/services/volume/v3/test_volumes_client.py
new file mode 100644
index 0000000..a515fd3
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v3/test_volumes_client.py
@@ -0,0 +1,48 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# 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.volume.v3 import volumes_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestVolumesClient(base.BaseServiceTest):
+
+ FAKE_VOLUME_SUMMARY = {
+ "volume-summary": {
+ "total_size": 20,
+ "total_count": 5
+ }
+ }
+
+ def setUp(self):
+ super(TestVolumesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = volumes_client.VolumesClient(fake_auth,
+ 'volume',
+ 'regionOne')
+
+ def _test_show_volume_summary(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_volume_summary,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_VOLUME_SUMMARY,
+ bytes_body)
+
+ def test_show_volume_summary_with_str_body(self):
+ self._test_show_volume_summary()
+
+ def test_show_volume_summary_with_bytes_body(self):
+ self._test_show_volume_summary(bytes_body=True)
diff --git a/test-requirements.txt b/test-requirements.txt
index 13950bd..beb456d 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -10,3 +10,4 @@
coverage>=4.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
flake8-import-order==0.11 # LGPLv3
+openstackdocstheme>=1.5.0 # Apache-2.0