Merge "Add test case for update volume encryption type"
diff --git a/HACKING.rst b/HACKING.rst
index 910a977..f97f97a 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -170,7 +170,7 @@
All negative tests should be based on `API-WG guideline`_ . Such negative
tests can block any changes from accurate failure code to invalid one.
-.. _API-WG guideline: https://github.com/openstack/api-wg/blob/master/guidelines/http.rst#failure-code-clarifications
+.. _API-WG guideline: http://specs.openstack.org/openstack/api-wg/guidelines/http.html#failure-code-clarifications
If facing some gray area which is not clarified on the above guideline, propose
a new guideline to the API-WG. With a proposal to the API-WG we will be able to
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 04ddfdf..2597f04 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -140,9 +140,8 @@
git_cmd = ["git", "log", "--pretty=format:'%ad, commit %h'", "--date=local",
"-n1"]
try:
- html_last_updated_fmt = subprocess.Popen(git_cmd,
- stdout=subprocess.PIPE).\
- communicate()[0]
+ html_last_updated_fmt = str(
+ subprocess.Popen(git_cmd, stdout=subprocess.PIPE).communicate()[0])
except Exception:
warnings.warn('Cannot get last updated time from git repository. '
'Not setting "html_last_updated_fmt".')
@@ -184,123 +183,5 @@
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'Tempestdoc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
-
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
-
-# Additional stuff for the LaTeX preamble.
-#'preamble': '',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
- ('index', 'Tempest.tex', u'Tempest Documentation',
- u'OpenStack QA Team', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# If true, show page references after internal links.
-#latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-#latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_domain_indices = True
-
-
-# -- Options for manual page output --------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('index', 'tempest', u'Tempest Documentation',
- [u'OpenStack QA Team'], 1)
-]
-
-# If true, show URL addresses after external links.
-#man_show_urls = False
-
-
-# -- Options for Texinfo output ------------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-# dir menu entry, description, category)
-texinfo_documents = [
- ('index', 'Tempest', u'Tempest Documentation',
- u'OpenStack QA Team', 'Tempest', 'One line description of project.',
- 'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
-
-# If false, no module index is generated.
-#texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
-
-
-# -- Options for Epub output ---------------------------------------------------
-
-# Bibliographic Dublin Core info.
-epub_title = u'Tempest'
-epub_author = u'Sean Dague'
-epub_publisher = u'OpenStack QA Team'
-epub_copyright = u'2013, OpenStack QA Team'
-
-# The language of the text. It defaults to the language option
-# or en if the language is not set.
-#epub_language = ''
-
-# The scheme of the identifier. Typical schemes are ISBN or URL.
-#epub_scheme = ''
-
-# The unique identifier of the text. This can be a ISBN number
-# or the project homepage.
-#epub_identifier = ''
-
-# A unique identification for the text.
-#epub_uid = ''
-
-# A tuple containing the cover image and cover page html template filenames.
-#epub_cover = ()
-
-# HTML files that should be inserted before the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-#epub_pre_files = []
-
-# HTML files shat should be inserted after the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-#epub_post_files = []
-
-# A list of files that should not be packed into the epub file.
-#epub_exclude_files = []
-
-# The depth of the table of contents in toc.ncx.
-#epub_tocdepth = 3
-
-# Allow duplicate toc entries.
-#epub_tocdup = True
+# A list of warning types to suppress arbitrary warning messages.
+suppress_warnings = ['image.nonlocal_uri']
diff --git a/releasenotes/notes/add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml b/releasenotes/notes/add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml
new file mode 100644
index 0000000..848a21b
--- /dev/null
+++ b/releasenotes/notes/add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml
@@ -0,0 +1,3 @@
+---
+features:
+ - Define the compute server evacuate client method in the servers_client library.
diff --git a/releasenotes/notes/add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml b/releasenotes/notes/add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml
new file mode 100644
index 0000000..233cc28
--- /dev/null
+++ b/releasenotes/notes/add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Add versions_client module for volume service.
+ This new module provides list_versions() method which shows API versions
+ from Volume service.
diff --git a/releasenotes/notes/deprecate-deactivate_image-config-7a282c471937bbcb.yaml b/releasenotes/notes/deprecate-deactivate_image-config-7a282c471937bbcb.yaml
new file mode 100644
index 0000000..69c6bb6
--- /dev/null
+++ b/releasenotes/notes/deprecate-deactivate_image-config-7a282c471937bbcb.yaml
@@ -0,0 +1,6 @@
+---
+deprecations:
+ - |
+ The ``deactivate_image`` configuration switch from the ``config`` module
+ is deprecated. It was added to support the older-than-kilo releases
+ which we don't support anymore.
diff --git a/releasenotes/notes/deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml b/releasenotes/notes/deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml
new file mode 100644
index 0000000..c3e43ee
--- /dev/null
+++ b/releasenotes/notes/deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml
@@ -0,0 +1,7 @@
+---
+deprecations:
+ - |
+ The ``dvr_extra_resources`` configuration switch from the ``config`` module
+ is deprecated. It was added to support the Liberty Release which we don't
+ support anymore.
+
diff --git a/releasenotes/notes/deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml b/releasenotes/notes/deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml
new file mode 100644
index 0000000..0660d9c
--- /dev/null
+++ b/releasenotes/notes/deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml
@@ -0,0 +1,12 @@
+---
+deprecations:
+ - |
+ Volume v1 API is deprecated and the v3 are CURRENT.
+ Tempest doesn't need to test the v1 API as the default.
+ The volume config option 'api_v1' has been marked as
+ deprecated.
+upgrade:
+ - |
+ The volume config option 'api_v1' default is changed to
+ ``False`` because the volume v1 API has been deprecated
+ since Juno release.
diff --git a/setup.cfg b/setup.cfg
index 96313fd..b2035bc 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -45,12 +45,10 @@
tempest.config = tempest.config:list_opts
[build_sphinx]
-all_files = 1
+all-files = 1
+warning-is-error = 1
build-dir = doc/build
source-dir = doc/source
-[pbr]
-warnerrors = True
-
[wheel]
universal = 1
diff --git a/tempest/api/compute/admin/test_volume_swap.py b/tempest/api/compute/admin/test_volume_swap.py
index 984f1a9..22a5bc4 100644
--- a/tempest/api/compute/admin/test_volume_swap.py
+++ b/tempest/api/compute/admin/test_volume_swap.py
@@ -10,10 +10,13 @@
# License for the specific language governing permissions and limitations
# under the License.
+import time
+
from tempest.api.compute import base
from tempest.common import waiters
from tempest import config
from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
from tempest import test
CONF = config.CONF
@@ -41,6 +44,41 @@
if not CONF.compute_feature_enabled.swap_volume:
raise cls.skipException("Swapping volumes is not supported.")
+ def _wait_for_server_volume_swap(self, server_id, old_volume_id,
+ new_volume_id):
+ """Waits for a server to swap the old volume to a new one."""
+ volume_attachments = self.servers_client.list_volume_attachments(
+ server_id)['volumeAttachments']
+ attached_volume_ids = [attachment['volumeId']
+ for attachment in volume_attachments]
+ start = int(time.time())
+
+ while (old_volume_id in attached_volume_ids) \
+ or (new_volume_id not in attached_volume_ids):
+ time.sleep(self.servers_client.build_interval)
+ volume_attachments = self.servers_client.list_volume_attachments(
+ server_id)['volumeAttachments']
+ attached_volume_ids = [attachment['volumeId']
+ for attachment in volume_attachments]
+
+ if int(time.time()) - start >= self.servers_client.build_timeout:
+ old_vol_bdm_status = 'in BDM' \
+ if old_volume_id in attached_volume_ids else 'not in BDM'
+ new_vol_bdm_status = 'in BDM' \
+ if new_volume_id in attached_volume_ids else 'not in BDM'
+ message = ('Failed to swap old volume %(old_volume_id)s '
+ '(current %(old_vol_bdm_status)s) to new volume '
+ '%(new_volume_id)s (current %(new_vol_bdm_status)s)'
+ ' on server %(server_id)s within the required time '
+ '(%(timeout)s s)' %
+ {'old_volume_id': old_volume_id,
+ 'old_vol_bdm_status': old_vol_bdm_status,
+ 'new_volume_id': new_volume_id,
+ 'new_vol_bdm_status': new_vol_bdm_status,
+ 'server_id': server_id,
+ 'timeout': self.servers_client.build_timeout})
+ raise lib_exc.TimeoutException(message)
+
@decorators.idempotent_id('1769f00d-a693-4d67-a631-6a3496773813')
@test.services('volume')
def test_volume_swap(self):
@@ -61,6 +99,8 @@
volume1['id'], 'available')
waiters.wait_for_volume_resource_status(self.volumes_client,
volume2['id'], 'in-use')
+ self._wait_for_server_volume_swap(server['id'], volume1['id'],
+ volume2['id'])
# Verify "volume2" is attached to the server
vol_attachments = self.servers_client.list_volume_attachments(
server['id'])['volumeAttachments']
@@ -74,6 +114,8 @@
volume2['id'], 'available')
waiters.wait_for_volume_resource_status(self.volumes_client,
volume1['id'], 'in-use')
+ self._wait_for_server_volume_swap(server['id'], volume2['id'],
+ volume1['id'])
# Verify "volume1" is attached to the server
vol_attachments = self.servers_client.list_volume_attachments(
server['id'])['volumeAttachments']
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index ceac56b..29bd6da 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -17,6 +17,7 @@
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
+import testtools
CONF = config.CONF
@@ -66,6 +67,8 @@
self.assertEqual(snapshot_name, image['name'])
@decorators.idempotent_id('71bcb732-0261-11e7-9086-fa163e4fa634')
+ @testtools.skipUnless(CONF.compute_feature_enabled.pause,
+ 'Pause is not available.')
def test_create_image_from_paused_server(self):
server = self.create_test_server(wait_until='ACTIVE')
self.servers_client.pause_server(server['id'])
@@ -82,6 +85,8 @@
self.assertEqual(snapshot_name, image['name'])
@decorators.idempotent_id('8ca07fec-0262-11e7-907e-fa163e4fa634')
+ @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
+ 'Suspend is not available.')
def test_create_image_from_suspended_server(self):
server = self.create_test_server(wait_until='ACTIVE')
self.servers_client.suspend_server(server['id'])
diff --git a/tempest/api/compute/servers/test_multiple_create.py b/tempest/api/compute/servers/test_multiple_create.py
index 87265ec..7cbb513 100644
--- a/tempest/api/compute/servers/test_multiple_create.py
+++ b/tempest/api/compute/servers/test_multiple_create.py
@@ -22,9 +22,12 @@
@decorators.idempotent_id('61e03386-89c3-449c-9bb1-a06f423fd9d1')
def test_multiple_create(self):
- body, servers = compute.create_test_server(self.os,
- wait_until='ACTIVE',
- min_count=2)
+ tenant_network = self.get_tenant_network()
+ body, servers = compute.create_test_server(
+ self.os,
+ wait_until='ACTIVE',
+ min_count=2,
+ tenant_network=tenant_network)
for server in servers:
self.addCleanup(self.servers_client.delete_server, server['id'])
# NOTE(maurosr): do status response check and also make sure that
diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
index 3f6abab..a72df5e 100644
--- a/tempest/api/compute/servers/test_novnc.py
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -87,29 +87,48 @@
'Token must be invalid because the connection '
'closed.')
# Parse the RFB version from the data to make sure it is valid
- # and greater than or equal to 3.3
+ # and belong to the known supported RFB versions.
version = float("%d.%d" % (int(data[4:7], base=10),
int(data[8:11], base=10)))
- self.assertTrue(version >= 3.3, 'Bad RFB Version: ' + str(version))
- # Send our RFB version to the server, which we will just go with 3.3
+ # Add the max RFB versions supported
+ supported_versions = [3.3, 3.8]
+ self.assertIn(version, supported_versions,
+ 'Bad RFB Version: ' + str(version))
+ # Send our RFB version to the server
self._websocket.send_frame(data)
# Get the sever authentication type and make sure None is supported
data = self._websocket.receive_frame()
self.assertIsNotNone(data, 'Expected authentication type None.')
- self.assertGreaterEqual(
- len(data), 2, 'Expected authentication type None.')
- self.assertIn(
- 1, [ord_func(data[i + 1]) for i in range(ord_func(data[0]))],
- 'Expected authentication type None.')
- # Send to the server that we only support authentication type None
- self._websocket.send_frame(six.int2byte(1))
- # The server should send 4 bytes of 0's if security handshake succeeded
- data = self._websocket.receive_frame()
- self.assertEqual(
- len(data), 4, 'Server did not think security was successful.')
- self.assertEqual(
- [ord_func(i) for i in data], [0, 0, 0, 0],
- 'Server did not think security was successful.')
+ data_length = len(data)
+ if version == 3.3:
+ # For RFB 3.3: in the security handshake, rather than a two-way
+ # negotiation, the server decides the security type and sends a
+ # single word(4 bytes).
+ self.assertEqual(
+ data_length, 4, 'Expected authentication type None.')
+ self.assertIn(1, [ord_func(data[i]) for i in (0, 3)],
+ 'Expected authentication type None.')
+ else:
+ self.assertGreaterEqual(
+ len(data), 2, 'Expected authentication type None.')
+ self.assertIn(
+ 1,
+ [ord_func(data[i + 1]) for i in range(ord_func(data[0]))],
+ 'Expected authentication type None.')
+ # Send to the server that we only support authentication
+ # type None
+ self._websocket.send_frame(six.int2byte(1))
+
+ # The server should send 4 bytes of 0's if security
+ # handshake succeeded
+ data = self._websocket.receive_frame()
+ self.assertEqual(
+ len(data), 4,
+ 'Server did not think security was successful.')
+ self.assertEqual(
+ [ord_func(i) for i in data], [0, 0, 0, 0],
+ 'Server did not think security was successful.')
+
# Say to leave the desktop as shared as part of client initialization
self._websocket.send_frame(six.int2byte(1))
# Get the server initialization packet back and make sure it is the
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index 5230708..eea918a 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -36,7 +36,6 @@
# read backend name from a list .
backend_names = set(CONF.volume.backend_names)
- cls.name_field = cls.special_fields['name_field']
cls.volume_id_list_with_prefix = []
cls.volume_id_list_without_prefix = []
@@ -65,7 +64,7 @@
cls.create_volume_type(name=type_name,
extra_specs=extra_specs)
- params = {cls.name_field: vol_name, 'volume_type': type_name,
+ params = {'name': vol_name, 'volume_type': type_name,
'size': CONF.volume.volume_size}
cls.volume = cls.admin_volume_client.create_volume(
**params)['volume']
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 19cb476..ae57540 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -36,7 +36,6 @@
# Create/update/get/delete volume with volume_type and extra spec.
volume_types = list()
vol_name = data_utils.rand_name(self.__class__.__name__ + '-volume')
- name_field = self.special_fields['name_field']
proto = CONF.volume.storage_protocol
vendor = CONF.volume.vendor_name
extra_specs = {"storage_protocol": proto,
@@ -46,14 +45,14 @@
vol_type = self.create_volume_type(
extra_specs=extra_specs)
volume_types.append(vol_type)
- params = {name_field: vol_name,
+ params = {'name': vol_name,
'volume_type': volume_types[0]['id'],
'size': CONF.volume.volume_size}
# Create volume
volume = self.create_volume(**params)
self.assertEqual(volume_types[0]['name'], volume["volume_type"])
- self.assertEqual(volume[name_field], vol_name,
+ self.assertEqual(volume['name'], vol_name,
"The created volume name is not equal "
"to the requested name")
self.assertIsNotNone(volume['id'],
@@ -74,7 +73,7 @@
fetched_volume['volume_type'],
'The fetched Volume type is different '
'from updated volume type')
- self.assertEqual(vol_name, fetched_volume[name_field],
+ self.assertEqual(vol_name, fetched_volume['name'],
'The fetched Volume is different '
'from the created Volume')
self.assertEqual(volume['id'], fetched_volume['id'],
diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py
index 8d0bf4a..4017de6 100644
--- a/tempest/api/volume/admin/test_volume_types_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_negative.py
@@ -26,8 +26,7 @@
@decorators.idempotent_id('b48c98f2-e662-4885-9b71-032256906314')
def test_create_with_nonexistent_volume_type(self):
# Should not be able to create volume with nonexistent volume_type.
- name_field = self.special_fields['name_field']
- params = {name_field: data_utils.rand_uuid(),
+ params = {'name': data_utils.rand_uuid(),
'volume_type': data_utils.rand_uuid()}
self.assertRaises(lib_exc.NotFound,
self.volumes_client.create_volume, **params)
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index f794920..5e4fada 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -80,9 +80,6 @@
cls.build_interval = CONF.volume.build_interval
cls.build_timeout = CONF.volume.build_timeout
- cls.special_fields = {'name_field': 'name',
- 'descrip_field': 'description'}
-
@classmethod
def resource_cleanup(cls):
cls.clear_snapshots()
@@ -104,10 +101,9 @@
min_disk = image.get('minDisk')
kwargs['size'] = max(kwargs['size'], min_disk)
- name_field = cls.special_fields['name_field']
- if name_field not in kwargs:
+ if 'name' not in kwargs:
name = data_utils.rand_name(cls.__name__ + '-Volume')
- kwargs[name_field] = name
+ kwargs['name'] = name
volume = cls.volumes_client.create_volume(**kwargs)['volume']
cls.volumes.append(volume)
@@ -118,10 +114,9 @@
@classmethod
def create_snapshot(cls, volume_id=1, **kwargs):
"""Wrapper utility that returns a test snapshot."""
- name_field = cls.special_fields['name_field']
- if name_field not in kwargs:
+ if 'name' not in kwargs:
name = data_utils.rand_name(cls.__name__ + '-Snapshot')
- kwargs[name_field] = name
+ kwargs['name'] = name
snapshot = cls.snapshots_client.create_snapshot(
volume_id=volume_id, **kwargs)['snapshot']
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 8014e62..9eff97a 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -29,22 +29,19 @@
class VolumesV2GetTest(base.BaseVolumeTest):
def _volume_create_get_update_delete(self, **kwargs):
- name_field = self.special_fields['name_field']
- descrip_field = self.special_fields['descrip_field']
-
# Create a volume, Get it's details and Delete the volume
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
metadata = {'Type': 'Test'}
# Create a volume
- kwargs[name_field] = v_name
+ kwargs['name'] = v_name
kwargs['metadata'] = metadata
volume = self.volumes_client.create_volume(**kwargs)['volume']
self.assertIn('id', volume)
self.addCleanup(self.delete_volume, self.volumes_client, volume['id'])
waiters.wait_for_volume_resource_status(self.volumes_client,
volume['id'], 'available')
- self.assertIn(name_field, volume)
- self.assertEqual(volume[name_field], v_name,
+ self.assertIn('name', volume)
+ self.assertEqual(volume['name'], v_name,
"The created volume name is not equal "
"to the requested name")
@@ -52,7 +49,7 @@
fetched_volume = self.volumes_client.show_volume(
volume['id'])['volume']
self.assertEqual(v_name,
- fetched_volume[name_field],
+ fetched_volume['name'],
'The fetched Volume name is different '
'from the created Volume')
self.assertEqual(volume['id'],
@@ -71,25 +68,25 @@
# Update Volume
# Test volume update when display_name is same with original value
- params = {name_field: v_name}
+ params = {'name': v_name}
self.volumes_client.update_volume(volume['id'], **params)
# Test volume update when display_name is new
new_v_name = data_utils.rand_name(
self.__class__.__name__ + '-new-Volume')
new_desc = 'This is the new description of volume'
- params = {name_field: new_v_name,
- descrip_field: new_desc}
+ params = {'name': new_v_name,
+ 'description': new_desc}
update_volume = self.volumes_client.update_volume(
volume['id'], **params)['volume']
# Assert response body for update_volume method
- self.assertEqual(new_v_name, update_volume[name_field])
- self.assertEqual(new_desc, update_volume[descrip_field])
+ self.assertEqual(new_v_name, update_volume['name'])
+ self.assertEqual(new_desc, update_volume['description'])
# Assert response body for show_volume method
updated_volume = self.volumes_client.show_volume(
volume['id'])['volume']
self.assertEqual(volume['id'], updated_volume['id'])
- self.assertEqual(new_v_name, updated_volume[name_field])
- self.assertEqual(new_desc, updated_volume[descrip_field])
+ self.assertEqual(new_v_name, updated_volume['name'])
+ self.assertEqual(new_desc, updated_volume['description'])
self.assertThat(updated_volume['metadata'].items(),
matchers.ContainsAll(metadata.items()),
'The fetched Volume metadata misses data '
@@ -99,7 +96,7 @@
# contains specific characters,
# then test volume update if display_name is duplicated
new_v_desc = data_utils.rand_name('@#$%^* description')
- params = {descrip_field: new_v_desc,
+ params = {'description': new_v_desc,
'availability_zone': volume['availability_zone'],
'size': CONF.volume.volume_size}
new_volume = self.volumes_client.create_volume(**params)['volume']
@@ -109,8 +106,8 @@
waiters.wait_for_volume_resource_status(self.volumes_client,
new_volume['id'], 'available')
- params = {name_field: volume[name_field],
- descrip_field: volume[descrip_field]}
+ params = {'name': volume['name'],
+ 'description': volume['description']}
self.volumes_client.update_volume(new_volume['id'], **params)
if 'imageRef' in kwargs:
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index da11ed9..8990a15 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -26,8 +26,6 @@
def resource_setup(cls):
super(VolumesV2NegativeTest, cls).resource_setup()
- cls.name_field = cls.special_fields['name_field']
-
# Create a test shared instance and volume for attach/detach tests
cls.volume = cls.create_volume()
cls.mountpoint = "/dev/vdc"
@@ -52,7 +50,7 @@
# Should not be able to create volume with invalid size
# in request
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: v_name}
+ params = {'name': v_name}
self.assertRaises(lib_exc.BadRequest,
self.volumes_client.create_volume,
size='#$%', params=params)
@@ -63,7 +61,7 @@
# Should not be able to create volume without passing size
# in request
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: v_name}
+ params = {'name': v_name}
self.assertRaises(lib_exc.BadRequest,
self.volumes_client.create_volume,
size='', params=params)
@@ -73,7 +71,7 @@
def test_create_volume_with_size_zero(self):
# Should not be able to create volume with size zero
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: v_name}
+ params = {'name': v_name}
self.assertRaises(lib_exc.BadRequest,
self.volumes_client.create_volume,
size='0', params=params)
@@ -83,7 +81,7 @@
def test_create_volume_with_size_negative(self):
# Should not be able to create volume with size negative
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: v_name}
+ params = {'name': v_name}
self.assertRaises(lib_exc.BadRequest,
self.volumes_client.create_volume,
size='-1', params=params)
@@ -93,7 +91,7 @@
def test_create_volume_with_nonexistent_volume_type(self):
# Should not be able to create volume with non-existent volume type
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: v_name}
+ params = {'name': v_name}
self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
size='1', volume_type=data_utils.rand_uuid(),
params=params)
@@ -103,7 +101,7 @@
def test_create_volume_with_nonexistent_snapshot_id(self):
# Should not be able to create volume with non-existent snapshot
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: v_name}
+ params = {'name': v_name}
self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
size='1', snapshot_id=data_utils.rand_uuid(),
params=params)
@@ -113,7 +111,7 @@
def test_create_volume_with_nonexistent_source_volid(self):
# Should not be able to create volume with non-existent source volume
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: v_name}
+ params = {'name': v_name}
self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
size='1', source_volid=data_utils.rand_uuid(),
params=params)
@@ -122,7 +120,7 @@
@decorators.idempotent_id('0186422c-999a-480e-a026-6a665744c30c')
def test_update_volume_with_nonexistent_volume_id(self):
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: v_name}
+ params = {'name': v_name}
self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume,
volume_id=data_utils.rand_uuid(), params=params)
@@ -130,7 +128,7 @@
@decorators.idempotent_id('e66e40d6-65e6-4e75-bdc7-636792fa152d')
def test_update_volume_with_invalid_volume_id(self):
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: v_name}
+ params = {'name': v_name}
self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume,
volume_id=data_utils.rand_name('invalid'),
params=params)
@@ -139,7 +137,7 @@
@decorators.idempotent_id('72aeca85-57a5-4c1f-9057-f320f9ea575b')
def test_update_volume_with_empty_volume_id(self):
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: v_name}
+ params = {'name': v_name}
self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume,
volume_id='', params=params)
@@ -263,7 +261,7 @@
@decorators.idempotent_id('0f4aa809-8c7b-418f-8fb3-84c7a5dfc52f')
def test_list_volumes_with_nonexistent_name(self):
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: v_name}
+ params = {'name': v_name}
fetched_volume = self.volumes_client.list_volumes(
params=params)['volumes']
self.assertEqual(0, len(fetched_volume))
@@ -272,7 +270,7 @@
@decorators.idempotent_id('9ca17820-a0e7-4cbd-a7fa-f4468735e359')
def test_list_volumes_detail_with_nonexistent_name(self):
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {self.name_field: v_name}
+ params = {'name': v_name}
fetched_volume = \
self.volumes_client.list_volumes(
detail=True, params=params)['volumes']
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index ce93512..82f456b 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -33,8 +33,6 @@
def resource_setup(cls):
super(VolumesV2SnapshotTestJSON, cls).resource_setup()
cls.volume_origin = cls.create_volume()
- cls.name_field = cls.special_fields['name_field']
- cls.descrip_field = cls.special_fields['descrip_field']
@decorators.idempotent_id('b467b54c-07a4-446d-a1cf-651dedcc3ff1')
@test.services('compute')
@@ -110,27 +108,27 @@
matchers.ContainsAll(metadata.items()))
# Compare also with the output from the list action
- tracking_data = (snapshot['id'], snapshot[self.name_field])
+ tracking_data = (snapshot['id'], snapshot['name'])
snaps_list = self.snapshots_client.list_snapshots()['snapshots']
- snaps_data = [(f['id'], f[self.name_field]) for f in snaps_list]
+ snaps_data = [(f['id'], f['name']) for f in snaps_list]
self.assertIn(tracking_data, snaps_data)
# Updates snapshot with new values
new_s_name = data_utils.rand_name(
self.__class__.__name__ + '-new-snap')
new_desc = 'This is the new description of snapshot.'
- params = {self.name_field: new_s_name,
- self.descrip_field: new_desc}
+ params = {'name': new_s_name,
+ 'description': new_desc}
update_snapshot = self.snapshots_client.update_snapshot(
snapshot['id'], **params)['snapshot']
# Assert response body for update_snapshot method
- self.assertEqual(new_s_name, update_snapshot[self.name_field])
- self.assertEqual(new_desc, update_snapshot[self.descrip_field])
+ self.assertEqual(new_s_name, update_snapshot['name'])
+ self.assertEqual(new_desc, update_snapshot['description'])
# Assert response body for show_snapshot method
updated_snapshot = self.snapshots_client.show_snapshot(
snapshot['id'])['snapshot']
- self.assertEqual(new_s_name, updated_snapshot[self.name_field])
- self.assertEqual(new_desc, updated_snapshot[self.descrip_field])
+ self.assertEqual(new_s_name, updated_snapshot['name'])
+ self.assertEqual(new_desc, updated_snapshot['description'])
# Delete the snapshot
self.delete_snapshot(snapshot['id'])
diff --git a/tempest/api/volume/test_volumes_snapshots_list.py b/tempest/api/volume/test_volumes_snapshots_list.py
index 237b276..0ea8ec7 100644
--- a/tempest/api/volume/test_volumes_snapshots_list.py
+++ b/tempest/api/volume/test_volumes_snapshots_list.py
@@ -29,7 +29,6 @@
def resource_setup(cls):
super(VolumesV2SnapshotListTestJSON, cls).resource_setup()
volume_origin = cls.create_volume()
- cls.name_field = cls.special_fields['name_field']
# Create snapshots with params
for _ in range(2):
cls.snapshot = cls.create_snapshot(volume_origin['id'])
@@ -59,7 +58,7 @@
def test_snapshots_list_with_params(self):
"""list snapshots with params."""
# Verify list snapshots by display_name filter
- params = {self.name_field: self.snapshot[self.name_field]}
+ params = {'name': self.snapshot['name']}
self._list_by_param_values_and_assert(**params)
# Verify list snapshots by status filter
@@ -68,21 +67,21 @@
# Verify list snapshots by status and display name filter
params = {'status': 'available',
- self.name_field: self.snapshot[self.name_field]}
+ 'name': self.snapshot['name']}
self._list_by_param_values_and_assert(**params)
@decorators.idempotent_id('220a1022-1fcd-4a74-a7bd-6b859156cda2')
def test_snapshots_list_details_with_params(self):
"""list snapshot details with params."""
# Verify list snapshot details by display_name filter
- params = {self.name_field: self.snapshot[self.name_field]}
+ params = {'name': self.snapshot['name']}
self._list_by_param_values_and_assert(with_detail=True, **params)
# Verify list snapshot details by status filter
params = {'status': 'available'}
self._list_by_param_values_and_assert(with_detail=True, **params)
# Verify list snapshot details by status and display name filter
params = {'status': 'available',
- self.name_field: self.snapshot[self.name_field]}
+ 'name': self.snapshot['name']}
self._list_by_param_values_and_assert(with_detail=True, **params)
@decorators.idempotent_id('db4d8e0a-7a2e-41cc-a712-961f6844e896')
diff --git a/tempest/api/volume/v3/base.py b/tempest/api/volume/v3/base.py
index 31fc1eb..7f76e6f 100644
--- a/tempest/api/volume/v3/base.py
+++ b/tempest/api/volume/v3/base.py
@@ -45,6 +45,7 @@
def setup_clients(cls):
super(VolumesV3Test, cls).setup_clients()
cls.messages_client = cls.os.volume_v3_messages_client
+ cls.versions_client = cls.os.volume_v3_versions_client
def setUp(self):
super(VolumesV3Test, self).setUp()
diff --git a/tempest/api/volume/v3/test_versions.py b/tempest/api/volume/v3/test_versions.py
new file mode 100644
index 0000000..20f1657
--- /dev/null
+++ b/tempest/api/volume/v3/test_versions.py
@@ -0,0 +1,28 @@
+# Copyright 2017 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.volume.v3 import base
+from tempest.lib import decorators
+from tempest import test
+
+
+class VersionsTest(base.VolumesV3Test):
+
+ @decorators.idempotent_id('77838fc4-b49b-4c64-9533-166762517369')
+ @test.attr(type='smoke')
+ def test_list_versions(self):
+ # NOTE: The version data is checked on service client side
+ # with JSON-Schema validation. It is enough to just call
+ # the API here.
+ self.versions_client.list_versions()['versions']
diff --git a/tempest/clients.py b/tempest/clients.py
index e75fa79..0654110 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -265,6 +265,7 @@
self.volumes_client = self.volume_v1.VolumesClient()
self.volumes_v2_client = self.volume_v2.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()
self.volume_types_v2_client = self.volume_v2.TypesClient()
self.volume_hosts_client = self.volume_v1.HostsClient()
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 9a483bb..b2667e5 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -13,6 +13,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import base64
+import textwrap
+
from oslo_log import log as logging
from oslo_utils import excutils
@@ -113,6 +116,19 @@
if wait_until is None:
wait_until = 'ACTIVE'
+ if 'user_data' not in kwargs:
+ # If nothing overrides the default user data script then run
+ # a simple script on the host to print networking info. This is
+ # to aid in debugging ssh failures.
+ script = '''
+ #!/bin/sh
+ echo "Printing {user} user authorized keys"
+ cat ~{user}/.ssh/authorized_keys || true
+ '''.format(user=CONF.validation.image_ssh_user)
+ script_clean = textwrap.dedent(script).lstrip().encode('utf8')
+ script_b64 = base64.b64encode(script_clean)
+ kwargs['user_data'] = script_b64
+
if volume_backed:
volume_name = data_utils.rand_name(__name__ + '-volume')
volumes_client = clients.volumes_v2_client
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 6dfc579..414c016 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -50,6 +50,8 @@
ping_count=CONF.validation.ping_count,
ping_size=CONF.validation.ping_size)
+ # Note that this method will not work on SLES11 guests, as they do
+ # not support the TYPE column on lsblk
def get_disks(self):
# Select root disk devices as shown by lsblk
command = 'lsblk -lb --nodeps'
diff --git a/tempest/config.py b/tempest/config.py
index d5c8ea9..a8d0355 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -223,8 +223,8 @@
default=True,
help='Does the environment support reseller?',
deprecated_for_removal=True,
- deprecated_reason="All supported version of OpenStack now "
- "supports the 'reseller' feature"),
+ deprecated_reason="All supported versions of OpenStack now "
+ "support the 'reseller' feature"),
# TODO(rodrigods): This is a feature flag for bug 1590578 which is fixed
# in Newton and Ocata. This option can be removed after Mitaka is end of
# life.
@@ -531,7 +531,10 @@
cfg.BoolOpt('deactivate_image',
default=False,
help="Is the deactivate-image feature enabled."
- " The feature has been integrated since Kilo."),
+ " The feature has been integrated since Kilo.",
+ deprecated_for_removal=True,
+ deprecated_reason="All supported versions of OpenStack now "
+ "support the 'deactivate_image' feature"),
]
network_group = cfg.OptGroup(name='network',
@@ -616,7 +619,10 @@
"in L3 agent scheduler test. Extra resources need to be "
"provisioned in order to bind router to L3 agent in the "
"Liberty release or older, and are not required since "
- "the Mitaka release.")
+ "the Mitaka release.",
+ deprecated_for_removal=True,
+ deprecated_reason='This config switch was added for Liberty '
+ 'which is not supported anymore.')
]
network_feature_group = cfg.OptGroup(name='network-feature-enabled',
@@ -812,8 +818,12 @@
'entry all which indicates every extension is enabled. '
'Empty list indicates all extensions are disabled'),
cfg.BoolOpt('api_v1',
- default=True,
- help="Is the v1 volume API enabled"),
+ default=False,
+ help="Is the v1 volume API enabled",
+ deprecated_for_removal=True,
+ deprecated_reason="The v1 volume API has been deprecated "
+ "since Juno release, and the API will be "
+ "removed."),
cfg.BoolOpt('api_v2',
default=True,
help="Is the v2 volume API enabled"),
diff --git a/tempest/lib/api_schema/response/compute/v2_1/servers.py b/tempest/lib/api_schema/response/compute/v2_1/servers.py
index 4ccca6f..4c4b5eb 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/servers.py
@@ -564,3 +564,19 @@
update_attached_volume = {
'status_code': [202]
}
+
+evacuate_server = {
+ 'status_code': [200]
+}
+
+evacuate_server_with_admin_pass = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'adminPass': {'type': 'string'}
+ },
+ 'additionalProperties': False,
+ 'required': ['adminPass']
+ }
+}
diff --git a/tempest/lib/api_schema/response/volume/__init__.py b/tempest/lib/api_schema/response/volume/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/__init__.py
diff --git a/tempest/lib/api_schema/response/volume/versions.py b/tempest/lib/api_schema/response/volume/versions.py
new file mode 100644
index 0000000..2391a8c
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/versions.py
@@ -0,0 +1,60 @@
+# Copyright 2015 NEC Corporation. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+list_versions = {
+ 'status_code': [300],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'versions': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'status': {'type': 'string'},
+ 'updated': {'type': 'string'},
+ 'id': {'type': 'string'},
+ 'links': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'href': {'type': 'string',
+ 'format': 'uri'},
+ 'rel': {'type': 'string'},
+ 'type': {'type': 'string'},
+ },
+ 'required': ['href', 'rel']
+ }
+ },
+ 'min_version': {'type': 'string'},
+ 'version': {'type': 'string'},
+ 'media-types': {
+ 'type': 'array',
+ 'properties': {
+ 'base': {'type': 'string'},
+ 'type': {'type': 'string'}
+ },
+ 'required': ['base', 'type']
+ }
+ },
+ 'required': ['status', 'updated', 'id', 'links',
+ 'min_version', 'version', 'media-types']
+ }
+ }
+ },
+ 'required': ['versions'],
+ }
+}
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index b37afb3..0d355a1 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -814,3 +814,19 @@
schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.delete_tag, resp, body)
return rest_client.ResponseBody(resp, body)
+
+ def evacuate_server(self, server_id, **kwargs):
+ """Evacuate the given server.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/compute/#evacuate-server-evacuate-action
+ """
+ if self.enable_instance_password:
+ evacuate_schema = schema.evacuate_server_with_admin_pass
+ else:
+ evacuate_schema = schema.evacuate_server
+
+ return self.action(server_id, 'evacuate',
+ evacuate_schema,
+ **kwargs)
diff --git a/tempest/lib/services/volume/v3/__init__.py b/tempest/lib/services/volume/v3/__init__.py
index a4600a8..72ab785 100644
--- a/tempest/lib/services/volume/v3/__init__.py
+++ b/tempest/lib/services/volume/v3/__init__.py
@@ -14,5 +14,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
-__all__ = ['MessagesClient', 'BaseClient']
+__all__ = ['MessagesClient', 'BaseClient', 'VersionsClient']
diff --git a/tempest/lib/services/volume/v3/versions_client.py b/tempest/lib/services/volume/v3/versions_client.py
new file mode 100644
index 0000000..e2941c4
--- /dev/null
+++ b/tempest/lib/services/volume/v3/versions_client.py
@@ -0,0 +1,47 @@
+# Copyright 2017 NEC Corporation. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import time
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.api_schema.response.volume import versions as schema
+from tempest.lib.common import rest_client
+from tempest.lib.services.volume.v3 import base_client
+
+
+class VersionsClient(base_client.BaseClient):
+
+ def list_versions(self):
+ """List API versions
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/block-storage/v3/#list-all-api-versions
+ """
+ version_url = self._get_base_version_url()
+
+ start = time.time()
+ resp, body = self.raw_request(version_url, 'GET')
+ end = time.time()
+ # NOTE: We need a raw_request() here instead of request() call because
+ # "list API versions" API doesn't require an authentication and we can
+ # skip it with raw_request() call.
+ self._log_request('GET', version_url, resp, secs=(end - start),
+ resp_body=body)
+ self._error_checker(resp, body)
+
+ body = json.loads(body)
+ self.validate_response(schema.list_versions, resp, body)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 727afd6..d4f0e13 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -79,13 +79,8 @@
cls.security_groups_client = cls.manager.security_groups_client
cls.security_group_rules_client = (
cls.manager.security_group_rules_client)
-
- if CONF.volume_feature_enabled.api_v2:
- cls.volumes_client = cls.manager.volumes_v2_client
- cls.snapshots_client = cls.manager.snapshots_v2_client
- else:
- cls.volumes_client = cls.manager.volumes_client
- cls.snapshots_client = cls.manager.snapshots_client
+ cls.volumes_client = cls.manager.volumes_v2_client
+ cls.snapshots_client = cls.manager.snapshots_v2_client
# ## Test functions library
#
@@ -235,12 +230,7 @@
volume['id'])
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.volumes_client.delete_volume, volume['id'])
-
- # NOTE(e0ne): Cinder API v2 uses name instead of display_name
- if 'display_name' in volume:
- self.assertEqual(name, volume['display_name'])
- else:
- self.assertEqual(name, volume['name'])
+ self.assertEqual(name, volume['name'])
waiters.wait_for_volume_resource_status(self.volumes_client,
volume['id'], 'available')
# The volume retrieved on creation has a non-up-to-date status.
diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
index 1960e9a..cc3687f 100644
--- a/tempest/scenario/test_server_advanced_ops.py
+++ b/tempest/scenario/test_server_advanced_ops.py
@@ -37,13 +37,6 @@
"""
@classmethod
- def skip_checks(cls):
- super(TestServerAdvancedOps, cls).skip_checks()
- if CONF.compute.flavor_ref_alt == CONF.compute.flavor_ref:
- msg = "Skipping test - flavor_ref and flavor_ref_alt are identical"
- raise cls.skipException(msg)
-
- @classmethod
def setup_credentials(cls):
cls.set_network_resources()
super(TestServerAdvancedOps, cls).setup_credentials()
@@ -52,6 +45,11 @@
@decorators.idempotent_id('e6c28180-7454-4b59-b188-0257af08a63b')
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
'Resize is not available.')
+ @testtools.skipUnless(CONF.compute.flavor_ref !=
+ CONF.compute.flavor_ref_alt
+ and CONF.compute.flavor_ref_alt != "",
+ 'The flavor_ref_alt option should not be empty and '
+ 'should not be identical with flavor_ref')
@test.services('compute', 'volume')
def test_resize_volume_backed_server_confirm(self):
# We create an instance for use in this test
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 96b423d..5f5d701 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -68,10 +68,7 @@
volume['id'], 'available')
waiters.wait_for_volume_resource_status(self.snapshots_client,
snapshot['id'], 'available')
- if 'display_name' in snapshot:
- self.assertEqual(snapshot_name, snapshot['display_name'])
- else:
- self.assertEqual(snapshot_name, snapshot['name'])
+ self.assertEqual(snapshot_name, snapshot['name'])
return snapshot
def _wait_for_volume_available_on_the_system(self, ip_address,
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index ae0230e..888bff2 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -81,13 +81,7 @@
self.addCleanup(self.snapshots_client.delete_snapshot, snap['id'])
waiters.wait_for_volume_resource_status(self.snapshots_client,
snap['id'], 'available')
-
- # NOTE(e0ne): Cinder API v2 uses name instead of display_name
- if 'display_name' in snap:
- self.assertEqual(snap_name, snap['display_name'])
- else:
- self.assertEqual(snap_name, snap['name'])
-
+ self.assertEqual(snap_name, snap['name'])
return snap
def _delete_server(self, server):
diff --git a/tempest/test_discover/plugins.py b/tempest/test_discover/plugins.py
index 276cf3c..613ab92 100644
--- a/tempest/test_discover/plugins.py
+++ b/tempest/test_discover/plugins.py
@@ -102,11 +102,10 @@
in any ServiceClients object instantiated by tests.
The default implementation returns an empty list.
- :return list of dictionaries. Each element of the list represents
- the service client for an API. Each dict must define all
- parameters required for the invocation of
- `service_clients.ServiceClients.register_service_client_module`.
- :rtype: list
+ :returns: Each element of the list represents the service client for an
+ API. Each dict must define all parameters required for the invocation
+ of `service_clients.ServiceClients.register_service_client_module`.
+ :rtype: list of dictionaries
Example:
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index 1af0d95..98bf145 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -192,7 +192,7 @@
self.useFixture(mockpatch.PatchObject(
verify_tempest_config, '_get_unversioned_endpoint',
return_value='http://fake_endpoint:5000'))
- fake_resp = {'versions': [{'id': 'v1.0'}, {'id': 'v2.0'}]}
+ fake_resp = {'versions': [{'id': 'v2.0'}]}
fake_resp = json.dumps(fake_resp)
mock_request.return_value = (None, fake_resp)
fake_os = mock.MagicMock()
@@ -206,7 +206,7 @@
self.useFixture(mockpatch.PatchObject(
verify_tempest_config, '_get_unversioned_endpoint',
return_value='http://fake_endpoint:5000'))
- fake_resp = {'versions': [{'id': 'v1.0'}, {'id': 'v3.0'}]}
+ fake_resp = {'versions': [{'id': 'v3.0'}]}
fake_resp = json.dumps(fake_resp)
mock_request.return_value = (None, fake_resp)
fake_os = mock.MagicMock()
@@ -231,11 +231,9 @@
with mock.patch.object(verify_tempest_config,
'print_and_or_update') as print_mock:
verify_tempest_config.verify_cinder_api_versions(fake_os, True)
- print_mock.assert_any_call('api_v1', 'volume-feature-enabled',
- False, True)
print_mock.assert_any_call('api_v3', 'volume-feature-enabled',
True, True)
- self.assertEqual(2, print_mock.call_count)
+ self.assertEqual(1, print_mock.call_count)
def test_verify_glance_version_no_v2_with_v1_1(self):
def fake_get_versions():
diff --git a/tempest/tests/lib/services/compute/test_servers_client.py b/tempest/tests/lib/services/compute/test_servers_client.py
index 8d391c1..a277dfe 100644
--- a/tempest/tests/lib/services/compute/test_servers_client.py
+++ b/tempest/tests/lib/services/compute/test_servers_client.py
@@ -168,6 +168,10 @@
"url": "http://os.co/v2/616fb98f-46ca-475e-917e-2563e5a8cd19"
}
+ FAKE_SERVER_PASSWORD = {
+ "adminPass": "fake-password",
+ }
+
FAKE_INSTANCE_ACTION_EVENTS = {
"event": "fake-event",
"start_time": "2016-10-02T10:00:00-05:00",
@@ -322,6 +326,21 @@
name='fake-name'
)
+ def test_evacuate_server_with_str_body(self):
+ self._test_evacuate_server()
+
+ def test_evacuate_server_with_bytes_body(self):
+ self._test_evacuate_server(bytes_body=True)
+
+ def _test_evacuate_server(self, bytes_body=False):
+ kwargs = {'server_id': self.server_id,
+ 'host': 'fake-target-host'}
+ self.check_service_client_function(
+ self.client.evacuate_server,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_SERVER_PASSWORD,
+ **kwargs)
+
def test_change_password_with_str_body(self):
self._test_change_password()
diff --git a/tempest/tests/lib/services/volume/v3/test_versions_client.py b/tempest/tests/lib/services/volume/v3/test_versions_client.py
new file mode 100644
index 0000000..9627b9a
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v3/test_versions_client.py
@@ -0,0 +1,91 @@
+# Copyright 2017 NEC Corporation. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.volume.v3 import versions_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestVersionsClient(base.BaseServiceTest):
+
+ FAKE_VERSIONS_INFO = {
+ "versions": [
+ {
+ "status": "DEPRECATED", "updated": "2016-05-02T20:25:19Z",
+ "links": [
+ {"href": "http://docs.openstack.org/", "type": "text/html",
+ "rel": "describedby"},
+ {"href": "https://10.30.197.39:8776/v1/", "rel": "self"}
+ ],
+ "min_version": "",
+ "version": "",
+ "media-types": [
+ {"base": "application/json",
+ "type": "application/vnd.openstack.volume+json;version=1"}
+ ],
+ "id": "v1.0"
+ },
+ {
+ "status": "DEPRECATED", "updated": "2017-02-25T12:00:00Z",
+ "links": [
+ {"href": "http://docs.openstack.org/", "type": "text/html",
+ "rel": "describedby"},
+ {"href": "https://10.30.197.39:8776/v2/", "rel": "self"}
+ ],
+ "min_version": "",
+ "version": "",
+ "media-types": [
+ {"base": "application/json",
+ "type": "application/vnd.openstack.volume+json;version=1"}
+ ],
+ "id": "v2.0"
+ },
+ {
+ "status": "CURRENT", "updated": "2016-02-08T12:20:21Z",
+ "links": [
+ {"href": "http://docs.openstack.org/", "type": "text/html",
+ "rel": "describedby"},
+ {"href": "https://10.30.197.39:8776/v3/", "rel": "self"}
+ ],
+ "min_version": "3.0",
+ "version": "3.28",
+ "media-types": [
+ {"base": "application/json",
+ "type": "application/vnd.openstack.volume+json;version=1"}
+ ],
+ "id": "v3.0"
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestVersionsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = versions_client.VersionsClient(fake_auth,
+ 'volume',
+ 'regionOne')
+
+ def _test_list_versions(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_versions,
+ 'tempest.lib.common.rest_client.RestClient.raw_request',
+ self.FAKE_VERSIONS_INFO,
+ bytes_body,
+ 300)
+
+ def test_list_versions_with_str_body(self):
+ self._test_list_versions()
+
+ def test_list_versions_with_bytes_body(self):
+ self._test_list_versions(bytes_body=True)
diff --git a/tox.ini b/tox.ini
index dfa8332..e2a9b3f 100644
--- a/tox.ini
+++ b/tox.ini
@@ -11,7 +11,6 @@
BRANCH_NAME=master
CLIENT_NAME=tempest
deps =
- setuptools
-r{toxinidir}/requirements.txt
[testenv]