Merge "Remove a redundant wait_for_backup_deletion()"
diff --git a/requirements.txt b/requirements.txt
index 0f8e94d..d698cda 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,7 +9,7 @@
netaddr!=0.7.16,>=0.7.12 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
oslo.concurrency>=3.8.0 # Apache-2.0
-oslo.config>=3.12.0 # Apache-2.0
+oslo.config>=3.14.0 # Apache-2.0
oslo.i18n>=2.1.0 # Apache-2.0
oslo.log>=1.14.0 # Apache-2.0
oslo.serialization>=1.10.0 # Apache-2.0
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 05c23ee..a5c303c 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -84,19 +84,21 @@
self.volume['id'], 'available')
if shelve_server:
- # NOTE(andreaf) If we are going to shelve a server, we should
- # check first whether the server is ssh-able. Otherwise we won't
- # be able to distinguish failures introduced by shelve from
- # pre-existing ones. Also it's good to wait for cloud-init to be
- # done and sshd server to be running before shelving to avoid
- # breaking the VM
- linux_client = remote_client.RemoteClient(
- self.get_server_ip(self.server),
- self.image_ssh_user,
- self.admin_pass,
- self.validation_resources['keypair']['private_key'])
- linux_client.validate_authentication()
- # If validation went ok, shelve the server
+ if CONF.validation.run_validation:
+ # NOTE(andreaf) If we are going to shelve a server, we should
+ # check first whether the server is ssh-able. Otherwise we
+ # won't be able to distinguish failures introduced by shelve
+ # from pre-existing ones. Also it's good to wait for cloud-init
+ # to be done and sshd server to be running before shelving to
+ # avoid breaking the VM
+ linux_client = remote_client.RemoteClient(
+ self.get_server_ip(self.server),
+ self.image_ssh_user,
+ self.admin_pass,
+ self.validation_resources['keypair']['private_key'])
+ linux_client.validate_authentication()
+
+ # If validation went ok, or it was skipped, shelve the server
compute.shelve_server(self.servers_client, self.server['id'])
# Attach the volume to the server
@@ -110,8 +112,6 @@
self.addCleanup(self._detach, self.server['id'], self.volume['id'])
@test.idempotent_id('52e9045a-e90d-4c0d-9087-79d657faffff')
- @testtools.skipUnless(CONF.validation.run_validation,
- 'SSH required for this test')
def test_attach_detach_volume(self):
# Stop and Start a server with an attached volume, ensuring that
# the volume remains attached.
@@ -125,16 +125,17 @@
waiters.wait_for_server_status(self.servers_client, self.server['id'],
'ACTIVE')
- linux_client = remote_client.RemoteClient(
- self.get_server_ip(self.server),
- self.image_ssh_user,
- self.admin_pass,
- self.validation_resources['keypair']['private_key'],
- server=self.server,
- servers_client=self.servers_client)
+ if CONF.validation.run_validation:
+ linux_client = remote_client.RemoteClient(
+ self.get_server_ip(self.server),
+ self.image_ssh_user,
+ self.admin_pass,
+ self.validation_resources['keypair']['private_key'],
+ server=self.server,
+ servers_client=self.servers_client)
- partitions = linux_client.get_partitions()
- self.assertIn(self.device, partitions)
+ partitions = linux_client.get_partitions()
+ self.assertIn(self.device, partitions)
self._detach(self.server['id'], self.volume['id'])
self.attachment = None
@@ -146,16 +147,17 @@
waiters.wait_for_server_status(self.servers_client, self.server['id'],
'ACTIVE')
- linux_client = remote_client.RemoteClient(
- self.get_server_ip(self.server),
- self.image_ssh_user,
- self.admin_pass,
- self.validation_resources['keypair']['private_key'],
- server=self.server,
- servers_client=self.servers_client)
+ if CONF.validation.run_validation:
+ linux_client = remote_client.RemoteClient(
+ self.get_server_ip(self.server),
+ self.image_ssh_user,
+ self.admin_pass,
+ self.validation_resources['keypair']['private_key'],
+ server=self.server,
+ servers_client=self.servers_client)
- partitions = linux_client.get_partitions()
- self.assertNotIn(self.device, partitions)
+ partitions = linux_client.get_partitions()
+ self.assertNotIn(self.device, partitions)
@test.idempotent_id('7fa563fe-f0f7-43eb-9e22-a1ece036b513')
def test_list_get_volume_attachments(self):
@@ -192,23 +194,22 @@
waiters.wait_for_server_status(self.servers_client,
self.server['id'],
'ACTIVE')
- linux_client = remote_client.RemoteClient(
- self.get_server_ip(self.server['id']),
- self.image_ssh_user,
- self.admin_pass,
- self.validation_resources['keypair']['private_key'],
- server=self.server,
- servers_client=self.servers_client)
+ if CONF.validation.run_validation:
+ linux_client = remote_client.RemoteClient(
+ self.get_server_ip(self.server['id']),
+ self.image_ssh_user,
+ self.admin_pass,
+ self.validation_resources['keypair']['private_key'],
+ server=self.server,
+ servers_client=self.servers_client)
- command = 'grep [vs]d /proc/partitions | wc -l'
- nb_partitions = linux_client.exec_command(command).strip()
- self.assertEqual(number_of_partition, nb_partitions)
+ command = 'grep [vs]d /proc/partitions | wc -l'
+ nb_partitions = linux_client.exec_command(command).strip()
+ self.assertEqual(number_of_partition, nb_partitions)
@test.idempotent_id('13a940b6-3474-4c3c-b03f-29b89112bfee')
@testtools.skipUnless(CONF.compute_feature_enabled.shelve,
'Shelve is not available.')
- @testtools.skipUnless(CONF.validation.run_validation,
- 'SSH required for this test')
def test_attach_volume_shelved_or_offload_server(self):
self._create_and_attach(shelve_server=True)
@@ -228,8 +229,6 @@
@test.idempotent_id('b54e86dd-a070-49c4-9c07-59ae6dae15aa')
@testtools.skipUnless(CONF.compute_feature_enabled.shelve,
'Shelve is not available.')
- @testtools.skipUnless(CONF.validation.run_validation,
- 'SSH required for this test')
def test_detach_volume_shelved_or_offload_server(self):
self._create_and_attach(shelve_server=True)
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index 7e1a442..4e851b0 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -64,7 +64,7 @@
certificate validation
:param str ca_certs: File containing the CA Bundle to use in verifying a
TLS server cert
- :param str trace_request: Regex to use for specifying logging the entirety
+ :param str trace_requests: Regex to use for specifying logging the entirety
of the request and response payload
:param str http_timeout: Timeout in seconds to wait for the http request to
return
diff --git a/tempest/lib/services/compute/agents_client.py b/tempest/lib/services/compute/agents_client.py
old mode 100644
new mode 100755
index 6d3a817..3f05d3b
--- a/tempest/lib/services/compute/agents_client.py
+++ b/tempest/lib/services/compute/agents_client.py
@@ -24,7 +24,11 @@
"""Tests Agents API"""
def list_agents(self, **params):
- """List all agent builds."""
+ """List all agent builds.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#listbuilds
+ """
url = 'os-agents'
if params:
url += '?%s' % urllib.urlencode(params)
@@ -46,7 +50,11 @@
return rest_client.ResponseBody(resp, body)
def delete_agent(self, agent_id):
- """Delete an existing agent build."""
+ """Delete an existing agent build.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#deleteBuild
+ """
resp, body = self.delete("os-agents/%s" % agent_id)
self.validate_response(schema.delete_agent, resp, body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/flavors_client.py b/tempest/lib/services/compute/flavors_client.py
old mode 100644
new mode 100755
index 5be8272..ae1700c
--- a/tempest/lib/services/compute/flavors_client.py
+++ b/tempest/lib/services/compute/flavors_client.py
@@ -28,6 +28,11 @@
class FlavorsClient(base_compute_client.BaseComputeClient):
def list_flavors(self, detail=False, **params):
+ """Lists flavors.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#listFlavors
+ """
url = 'flavors'
_schema = schema.list_flavors
@@ -43,6 +48,11 @@
return rest_client.ResponseBody(resp, body)
def show_flavor(self, flavor_id):
+ """Shows details for a flavor.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#showFlavor
+ """
resp, body = self.get("flavors/%s" % flavor_id)
body = json.loads(body)
self.validate_response(schema.create_get_flavor_details, resp, body)
@@ -67,7 +77,11 @@
return rest_client.ResponseBody(resp, body)
def delete_flavor(self, flavor_id):
- """Delete the given flavor."""
+ """Delete the given flavor.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#deleteFlavor
+ """
resp, body = self.delete("flavors/{0}".format(flavor_id))
self.validate_response(schema.delete_flavor, resp, body)
return rest_client.ResponseBody(resp, body)
@@ -102,7 +116,11 @@
return rest_client.ResponseBody(resp, body)
def list_flavor_extra_specs(self, flavor_id):
- """Get extra Specs details of the mentioned flavor."""
+ """Get extra Specs details of the mentioned flavor.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#listFlavorExtraSpecs
+ """
resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id)
body = json.loads(body)
self.validate_response(schema_extra_specs.set_get_flavor_extra_specs,
@@ -110,7 +128,11 @@
return rest_client.ResponseBody(resp, body)
def show_flavor_extra_spec(self, flavor_id, key):
- """Get extra Specs key-value of the mentioned flavor and key."""
+ """Get extra Specs key-value of the mentioned flavor and key.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#showFlavorExtraSpec
+ """
resp, body = self.get('flavors/%s/os-extra_specs/%s' % (flavor_id,
key))
body = json.loads(body)
@@ -136,14 +158,22 @@
def unset_flavor_extra_spec(self, flavor_id, key): # noqa
# NOTE: This noqa is for passing T111 check and we cannot rename
# to keep backwards compatibility.
- """Unset extra Specs from the mentioned flavor."""
+ """Unset extra Specs from the mentioned flavor.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#deleteFlavorExtraSpec
+ """
resp, body = self.delete('flavors/%s/os-extra_specs/%s' %
(flavor_id, key))
self.validate_response(schema.unset_flavor_extra_specs, resp, body)
return rest_client.ResponseBody(resp, body)
def list_flavor_access(self, flavor_id):
- """Get flavor access information given the flavor id."""
+ """Get flavor access information given the flavor id.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#listFlavorAccess
+ """
resp, body = self.get('flavors/%s/os-flavor-access' % flavor_id)
body = json.loads(body)
self.validate_response(schema_access.add_remove_list_flavor_access,
@@ -151,7 +181,11 @@
return rest_client.ResponseBody(resp, body)
def add_flavor_access(self, flavor_id, tenant_id):
- """Add flavor access for the specified tenant."""
+ """Add flavor access for the specified tenant.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#addFlavorAccess
+ """
post_body = {
'addTenantAccess': {
'tenant': tenant_id
@@ -165,7 +199,11 @@
return rest_client.ResponseBody(resp, body)
def remove_flavor_access(self, flavor_id, tenant_id):
- """Remove flavor access from the specified tenant."""
+ """Remove flavor access from the specified tenant.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#removeFlavorAccess
+ """
post_body = {
'removeTenantAccess': {
'tenant': tenant_id
diff --git a/tempest/lib/services/compute/floating_ips_client.py b/tempest/lib/services/compute/floating_ips_client.py
old mode 100644
new mode 100755
index 03e4894..6922c48
--- a/tempest/lib/services/compute/floating_ips_client.py
+++ b/tempest/lib/services/compute/floating_ips_client.py
@@ -25,7 +25,11 @@
class FloatingIPsClient(base_compute_client.BaseComputeClient):
def list_floating_ips(self, **params):
- """Returns a list of all floating IPs filtered by any parameters."""
+ """Returns a list of all floating IPs filtered by any parameters.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#listfloatingipsObject
+ """
url = 'os-floating-ips'
if params:
url += '?%s' % urllib.urlencode(params)
@@ -36,7 +40,11 @@
return rest_client.ResponseBody(resp, body)
def show_floating_ip(self, floating_ip_id):
- """Get the details of a floating IP."""
+ """Get the details of a floating IP.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#showFloatingIP
+ """
url = "os-floating-ips/%s" % floating_ip_id
resp, body = self.get(url)
body = json.loads(body)
@@ -57,7 +65,11 @@
return rest_client.ResponseBody(resp, body)
def delete_floating_ip(self, floating_ip_id):
- """Deletes the provided floating IP from the project."""
+ """Deletes the provided floating IP from the project.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#deleteFloatingIP
+ """
url = "os-floating-ips/%s" % floating_ip_id
resp, body = self.delete(url)
self.validate_response(schema.add_remove_floating_ip, resp, body)
diff --git a/tempest/lib/services/compute/keypairs_client.py b/tempest/lib/services/compute/keypairs_client.py
old mode 100644
new mode 100755
index 7b8e6b2..2246739
--- a/tempest/lib/services/compute/keypairs_client.py
+++ b/tempest/lib/services/compute/keypairs_client.py
@@ -28,6 +28,11 @@
{'min': '2.2', 'max': None, 'schema': schemav22}]
def list_keypairs(self, **params):
+ """Lists keypairs that are associated with the account.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#listKeypairs
+ """
url = 'os-keypairs'
if params:
url += '?%s' % urllib.urlencode(params)
@@ -38,6 +43,11 @@
return rest_client.ResponseBody(resp, body)
def show_keypair(self, keypair_name, **params):
+ """Shows details for a keypair that is associated with the account.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#showKeypair
+ """
url = "os-keypairs/%s" % keypair_name
if params:
url += '?%s' % urllib.urlencode(params)
@@ -61,6 +71,11 @@
return rest_client.ResponseBody(resp, body)
def delete_keypair(self, keypair_name, **params):
+ """Deletes a keypair.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#deleteKeypair
+ """
url = "os-keypairs/%s" % keypair_name
if params:
url += '?%s' % urllib.urlencode(params)
diff --git a/tempest/lib/services/compute/security_groups_client.py b/tempest/lib/services/compute/security_groups_client.py
old mode 100644
new mode 100755
index 6b9c7e1..386c214
--- a/tempest/lib/services/compute/security_groups_client.py
+++ b/tempest/lib/services/compute/security_groups_client.py
@@ -26,7 +26,11 @@
class SecurityGroupsClient(base_compute_client.BaseComputeClient):
def list_security_groups(self, **params):
- """List all security groups for a user."""
+ """List all security groups for a user.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#listSecGroups
+ """
url = 'os-security-groups'
if params:
@@ -38,7 +42,11 @@
return rest_client.ResponseBody(resp, body)
def show_security_group(self, security_group_id):
- """Get the details of a Security Group."""
+ """Get the details of a Security Group.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#showSecGroup
+ """
url = "os-security-groups/%s" % security_group_id
resp, body = self.get(url)
body = json.loads(body)
@@ -71,7 +79,11 @@
return rest_client.ResponseBody(resp, body)
def delete_security_group(self, security_group_id):
- """Delete the provided Security Group."""
+ """Delete the provided Security Group.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#deleteSecGroup
+ """
resp, body = self.delete(
'os-security-groups/%s' % security_group_id)
self.validate_response(schema.delete_security_group, resp, body)
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
old mode 100644
new mode 100755
index 9444e20..24c0be9
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -103,7 +103,11 @@
return rest_client.ResponseBody(resp, body)
def show_server(self, server_id):
- """Get server details."""
+ """Get server details.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#showServer
+ """
resp, body = self.get("servers/%s" % server_id)
body = json.loads(body)
schema = self.get_schema(self.schema_versions_info)
@@ -111,7 +115,11 @@
return rest_client.ResponseBody(resp, body)
def delete_server(self, server_id):
- """Delete server."""
+ """Delete server.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#deleteServer
+ """
resp, body = self.delete("servers/%s" % server_id)
self.validate_response(schema.delete_server, resp, body)
return rest_client.ResponseBody(resp, body)
@@ -141,7 +149,11 @@
return rest_client.ResponseBody(resp, body)
def list_addresses(self, server_id):
- """Lists all addresses for a server."""
+ """Lists all addresses for a server.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#list-ips
+ """
resp, body = self.get("servers/%s/ips" % server_id)
body = json.loads(body)
self.validate_response(schema.list_addresses, resp, body)
@@ -264,12 +276,22 @@
return self.action(server_id, 'revertResize', **kwargs)
def list_server_metadata(self, server_id):
+ """Lists all metadata for a server.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#listServerMetadata
+ """
resp, body = self.get("servers/%s/metadata" % server_id)
body = json.loads(body)
self.validate_response(schema.list_server_metadata, resp, body)
return rest_client.ResponseBody(resp, body)
def set_server_metadata(self, server_id, meta, no_metadata_field=False):
+ """Sets one or more metadata items for a server.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#createServerMetadata
+ """
if no_metadata_field:
post_body = ""
else:
@@ -281,6 +303,11 @@
return rest_client.ResponseBody(resp, body)
def update_server_metadata(self, server_id, meta):
+ """Updates one or more metadata items for a server.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#updateServerMetadata
+ """
post_body = json.dumps({'metadata': meta})
resp, body = self.post('servers/%s/metadata' % server_id,
post_body)
@@ -290,6 +317,11 @@
return rest_client.ResponseBody(resp, body)
def show_server_metadata_item(self, server_id, key):
+ """Shows details for a metadata item, by key, for a server.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#showServerMetadataItem
+ """
resp, body = self.get("servers/%s/metadata/%s" % (server_id, key))
body = json.loads(body)
self.validate_response(schema.set_show_server_metadata_item,
@@ -297,6 +329,11 @@
return rest_client.ResponseBody(resp, body)
def set_server_metadata_item(self, server_id, key, meta):
+ """Sets a metadata item, by key, for a server.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#setServerMetadataItem
+ """
post_body = json.dumps({'meta': meta})
resp, body = self.put('servers/%s/metadata/%s' % (server_id, key),
post_body)
@@ -306,6 +343,11 @@
return rest_client.ResponseBody(resp, body)
def delete_server_metadata_item(self, server_id, key):
+ """Deletes a metadata item, by key, from a server.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#deleteServerMetadataItem
+ """
resp, body = self.delete("servers/%s/metadata/%s" %
(server_id, key))
self.validate_response(schema.delete_server_metadata_item,
@@ -313,9 +355,19 @@
return rest_client.ResponseBody(resp, body)
def stop_server(self, server_id, **kwargs):
+ """Stops a running server and changes its status to SHUTOFF.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#stop
+ """
return self.action(server_id, 'os-stop', **kwargs)
def start_server(self, server_id, **kwargs):
+ """Starts a stopped server and changes its status to ACTIVE.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#start
+ """
return self.action(server_id, 'os-start', **kwargs)
def attach_volume(self, server_id, **kwargs):
@@ -341,14 +393,23 @@
return rest_client.ResponseBody(resp, body)
def detach_volume(self, server_id, volume_id): # noqa
- """Detaches a volume from a server instance."""
+ """Detaches a volume from a server instance.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#deleteVolumeAttachment
+ """
resp, body = self.delete('servers/%s/os-volume_attachments/%s' %
(server_id, volume_id))
self.validate_response(schema.detach_volume, resp, body)
return rest_client.ResponseBody(resp, body)
def show_volume_attachment(self, server_id, volume_id):
- """Return details about the given volume attachment."""
+ """Return details about the given volume attachment.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#
+ getVolumeAttachmentDetails
+ """
resp, body = self.get('servers/%s/os-volume_attachments/%s' % (
server_id, volume_id))
body = json.loads(body)
@@ -356,7 +417,11 @@
return rest_client.ResponseBody(resp, body)
def list_volume_attachments(self, server_id):
- """Returns the list of volume attachments for a given instance."""
+ """Returns the list of volume attachments for a given instance.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#listVolumeAttachments
+ """
resp, body = self.get('servers/%s/os-volume_attachments' % (
server_id))
body = json.loads(body)
@@ -366,7 +431,8 @@
def add_security_group(self, server_id, **kwargs):
"""Add a security group to the server.
- Available params: TODO
+ Available params: http://developer.openstack.org/
+ api-ref-compute-v2.1.html#addSecurityGroup
"""
# TODO(oomichi): The api-site doesn't contain this API description.
# So the above should be changed to the api-site link after
@@ -377,7 +443,8 @@
def remove_security_group(self, server_id, **kwargs):
"""Remove a security group from the server.
- Available params: TODO
+ Available params: http://developer.openstack.org/
+ api-ref-compute-v2.1.html#removeSecurityGroup
"""
# TODO(oomichi): The api-site doesn't contain this API description.
# So the above should be changed to the api-site link after
@@ -507,7 +574,11 @@
return self.action(server_id, 'rescue', schema.rescue_server, **kwargs)
def unrescue_server(self, server_id):
- """Unrescue the provided server."""
+ """Unrescue the provided server.
+
+ Available params: http://developer.openstack.org/
+ api-ref-compute-v2.1.html#unrescue
+ """
return self.action(server_id, 'unrescue')
def show_server_diagnostics(self, server_id):
diff --git a/tempest/lib/services/compute/services_client.py b/tempest/lib/services/compute/services_client.py
old mode 100644
new mode 100755
index a190e5f..b6dbe28
--- a/tempest/lib/services/compute/services_client.py
+++ b/tempest/lib/services/compute/services_client.py
@@ -25,6 +25,11 @@
class ServicesClient(base_compute_client.BaseComputeClient):
def list_services(self, **params):
+ """Lists all running Compute services for a tenant.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#listServices
+ """
url = 'os-services'
if params:
url += '?%s' % urllib.urlencode(params)
diff --git a/tempest/lib/services/compute/volumes_client.py b/tempest/lib/services/compute/volumes_client.py
old mode 100644
new mode 100755
index 41d9af2..2787779
--- a/tempest/lib/services/compute/volumes_client.py
+++ b/tempest/lib/services/compute/volumes_client.py
@@ -25,7 +25,11 @@
class VolumesClient(base_compute_client.BaseComputeClient):
def list_volumes(self, detail=False, **params):
- """List all the volumes created."""
+ """List all the volumes created.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#listVolumes
+ """
url = 'os-volumes'
if detail:
@@ -39,7 +43,11 @@
return rest_client.ResponseBody(resp, body)
def show_volume(self, volume_id):
- """Return the details of a single volume."""
+ """Return the details of a single volume.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#showVolume
+ """
url = "os-volumes/%s" % volume_id
resp, body = self.get(url)
body = json.loads(body)
@@ -59,7 +67,11 @@
return rest_client.ResponseBody(resp, body)
def delete_volume(self, volume_id):
- """Delete the Specified Volume."""
+ """Delete the Specified Volume.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-compute-v2.1.html#deleteVolume
+ """
resp, body = self.delete("os-volumes/%s" % volume_id)
self.validate_response(schema.delete_volume, resp, body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/service_clients.py b/tempest/service_clients.py
index a5bc86e..136ad65 100644
--- a/tempest/service_clients.py
+++ b/tempest/service_clients.py
@@ -149,14 +149,34 @@
setattr(self, class_name, self._get_partial_class(
klass, auth_provider, final_kwargs))
- @classmethod
- def _get_partial_class(cls, klass, auth_provider, kwargs):
+ def _get_partial_class(self, klass, auth_provider, kwargs):
# Define a function that returns a new class instance by
# combining default kwargs with extra ones
- def partial_class(**later_kwargs):
+ def partial_class(alias=None, **later_kwargs):
+ """Returns a callable the initialises a service client
+
+ Builds a callable that accepts kwargs, which are passed through
+ to the __init__ of the service client, along with a set of defaults
+ set in factory at factory __init__ time.
+ Original args in the service client can only be passed as kwargs.
+
+ It accepts one extra parameter 'alias' compared to the original
+ service client. When alias is provided, the returned callable will
+ also set an attribute called with a name defined in 'alias', which
+ contains the instance of the service client.
+
+ :param alias: str Name of the attribute set on the factory once
+ the callable is invoked which contains the initialised
+ service client. If None, no attribute is set.
+ :param later_kwargs: kwargs passed through to the service client
+ __init__ on top of defaults set at factory level.
+ """
kwargs.update(later_kwargs)
- return klass(auth_provider=auth_provider, **kwargs)
+ _client = klass(auth_provider=auth_provider, **kwargs)
+ if alias:
+ setattr(self, alias, _client)
+ return _client
return partial_class
diff --git a/tempest/services/identity/v3/json/services_client.py b/tempest/services/identity/v3/json/services_client.py
index e863016..95caf7d 100644
--- a/tempest/services/identity/v3/json/services_client.py
+++ b/tempest/services/identity/v3/json/services_client.py
@@ -18,6 +18,7 @@
"""
from oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
from tempest.lib.common import rest_client
@@ -57,13 +58,21 @@
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
- def delete_service(self, serv_id):
- url = "services/" + serv_id
+ def delete_service(self, service_id):
+ url = "services/" + service_id
resp, body = self.delete(url)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
- def list_services(self):
+ def list_services(self, **params):
+ """List services.
+
+ Available params: see http://developer.openstack.org/
+ api-ref/identity/v3/#list-services
+ """
+ url = 'services'
+ if params:
+ url += '?%s' % urllib.urlencode(params)
resp, body = self.get('services')
self.expected_success(200, resp.status)
body = json.loads(body)
diff --git a/tempest/tests/lib/common/utils/test_data_utils.py b/tempest/tests/lib/common/utils/test_data_utils.py
index 399c4af..94a4847 100644
--- a/tempest/tests/lib/common/utils/test_data_utils.py
+++ b/tempest/tests/lib/common/utils/test_data_utils.py
@@ -59,7 +59,7 @@
def test_rand_password(self):
actual = data_utils.rand_password()
self.assertIsInstance(actual, str)
- self.assertRegex(actual, "[A-Za-z0-9~!@#$%^&*_=+]{15,}")
+ self.assertRegex(actual, "[A-Za-z0-9~!@#%^&*_=+]{15,}")
actual2 = data_utils.rand_password()
self.assertNotEqual(actual, actual2)
@@ -67,7 +67,7 @@
actual = data_utils.rand_password(8)
self.assertIsInstance(actual, str)
self.assertEqual(len(actual), 8)
- self.assertRegex(actual, "[A-Za-z0-9~!@#$%^&*_=+]{8}")
+ self.assertRegex(actual, "[A-Za-z0-9~!@#%^&*_=+]{8}")
actual2 = data_utils.rand_password(8)
self.assertNotEqual(actual, actual2)
@@ -75,7 +75,7 @@
actual = data_utils.rand_password(2)
self.assertIsInstance(actual, str)
self.assertEqual(len(actual), 3)
- self.assertRegex(actual, "[A-Za-z0-9~!@#$%^&*_=+]{3}")
+ self.assertRegex(actual, "[A-Za-z0-9~!@#%^&*_=+]{3}")
actual2 = data_utils.rand_password(2)
self.assertNotEqual(actual, actual2)
diff --git a/tempest/tests/test_service_clients.py b/tempest/tests/test_service_clients.py
index 3d8b360..b0aa456 100644
--- a/tempest/tests/test_service_clients.py
+++ b/tempest/tests/test_service_clients.py
@@ -160,6 +160,28 @@
klass_mock.assert_called_once_with(auth_provider=auth_provider,
**params)
+ def test__get_partial_class_with_alias(self):
+ expected_fake_client = 'not_really_a_client'
+ client_alias = 'fake_client'
+ self._setup_fake_module(class_names=[])
+ auth_provider = fake_auth_provider.FakeAuthProvider()
+ params = {'k1': 'v1', 'k2': 'v2'}
+ later_params = {'k2': 'v4', 'k3': 'v3'}
+ factory = service_clients.ClientsFactory(
+ 'fake_path', [], auth_provider, **params)
+ klass_mock = mock.Mock(return_value=expected_fake_client)
+ partial = factory._get_partial_class(klass_mock, auth_provider, params)
+ # Class has not be initialised yet
+ klass_mock.assert_not_called()
+ # Use partial and assert on parameters
+ client = partial(alias=client_alias, **later_params)
+ params.update(later_params)
+ self.assertEqual(expected_fake_client, client)
+ klass_mock.assert_called_once_with(auth_provider=auth_provider,
+ **params)
+ self.assertThat(factory, has_attribute(client_alias))
+ self.assertEqual(expected_fake_client, getattr(factory, client_alias))
+
class TestServiceClients(base.TestCase):