Merge "Improves documentation formatting of cleanup.py"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 86dda80..b396503 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -248,7 +248,9 @@
# Time in seconds between build status checks. (integer value)
#build_interval = 1
-# Timeout in seconds to wait for an instance to build. (integer value)
+# Timeout in seconds to wait for an instance to build. Other services
+# that do not define build_timeout will inherit this value, for
+# example the image service. (integer value)
#build_timeout = 300
# Catalog type of the Compute service. (string value)
@@ -748,7 +750,7 @@
# Catalog type of the Neutron service. (string value)
#catalog_type = network
-# List of dns servers whichs hould be used for subnet creation (list
+# List of dns servers which should be used for subnet creation (list
# value)
#dns_servers = 8.8.8.8,8.8.4.4
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index de5b6c1..c6d48bc 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -36,6 +36,8 @@
personality = []
max_file_limit = \
self.user_client.get_specific_absolute_limit("maxPersonality")
+ if max_file_limit == -1:
+ raise self.skipException("No limit for personality files")
for i in range(0, int(max_file_limit) + 1):
path = 'etc/test' + str(i) + '.txt'
personality.append({'path': path,
@@ -52,6 +54,8 @@
file_contents = 'This is a test file.'
max_file_limit = \
self.user_client.get_specific_absolute_limit("maxPersonality")
+ if max_file_limit == -1:
+ raise self.skipException("No limit for personality files")
person = []
for i in range(0, int(max_file_limit)):
path = 'etc/test' + str(i) + '.txt'
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index 15c5421..5643c88 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -60,7 +60,7 @@
body = self.client.list_ports()
ports = body['ports']
for port in ports:
- if (port['device_owner'] == 'network:router_interface'
+ if (port['device_owner'].startswith('network:router_interface')
and port['device_id'] in [r['id'] for r in self.routers]):
self.client.remove_router_interface_with_port_id(
port['device_id'], port['id']
@@ -371,7 +371,6 @@
for ra_mode, add_mode in (
('dhcpv6-stateful', 'dhcpv6-stateful'),
('dhcpv6-stateful', None),
- (None, 'dhcpv6-stateful'),
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index fa1f6ee..fb51e30 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -193,3 +193,22 @@
class NegativeSecGroupIPv6Test(NegativeSecGroupTest):
_ip_version = 6
_tenant_network_cidr = CONF.network.tenant_network_v6_cidr
+
+ @test.attr(type=['negative', 'gate'])
+ def test_create_security_group_rule_wrong_ip_prefix_version(self):
+ group_create_body, _ = self._create_security_group()
+
+ # Create rule with bad remote_ip_prefix
+ pairs = ({'ethertype': 'IPv6',
+ 'ip_prefix': CONF.network.tenant_network_cidr},
+ {'ethertype': 'IPv4',
+ 'ip_prefix': CONF.network.tenant_network_v6_cidr})
+ for pair in pairs:
+ self.assertRaisesRegexp(
+ exceptions.BadRequest,
+ "Conflicting value ethertype",
+ self.client.create_security_group_rule,
+ security_group_id=group_create_body['security_group']['id'],
+ protocol='tcp', direction='ingress',
+ ethertype=pair['ethertype'],
+ remote_ip_prefix=pair['ip_prefix'])
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 21d0a86..b7e9422 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -70,11 +70,14 @@
self.addCleanup(self.servers_client.delete_server, server['id'])
self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
mountpoint = '/dev/%s' % CONF.compute.volume_device_name
- _, body = self.volumes_client.attach_volume(
- self.volume_origin['id'], server['id'], mountpoint)
+ _, body = self.servers_client.attach_volume(
+ server['id'], self.volume_origin['id'], mountpoint)
self.volumes_client.wait_for_volume_status(self.volume_origin['id'],
'in-use')
- self.addCleanup(self._detach, self.volume_origin['id'])
+ self.addCleanup(self.volumes_client.wait_for_volume_status,
+ self.volume_origin['id'], 'available')
+ self.addCleanup(self.servers_client.detach_volume, server['id'],
+ self.volume_origin['id'])
# Snapshot a volume even if it's attached to an instance
snapshot = self.create_snapshot(self.volume_origin['id'],
force=True)
diff --git a/tempest/auth.py b/tempest/auth.py
index 022a450..2550cfb 100644
--- a/tempest/auth.py
+++ b/tempest/auth.py
@@ -561,7 +561,10 @@
raise exceptions.InvalidCredentials()
creds = cls._get_default(credentials_type)
if not creds.is_valid():
- raise exceptions.InvalidConfiguration()
+ msg = ("The %s credentials are incorrectly set in the config file."
+ " Double check that all required values are assigned" %
+ credentials_type)
+ raise exceptions.InvalidConfiguration(msg)
return creds
@classmethod
diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py
index 39e3a67..298a94e 100644
--- a/tempest/common/custom_matchers.py
+++ b/tempest/common/custom_matchers.py
@@ -122,33 +122,21 @@
def match(self, actual):
for key, value in actual.iteritems():
- if key == 'content-length' and not value.isdigit():
+ if key in ('content-length', 'x-account-bytes-used',
+ 'x-account-container-count', 'x-account-object-count',
+ 'x-container-bytes-used', 'x-container-object-count')\
+ and not value.isdigit():
+ return InvalidFormat(key, value)
+ elif key in ('content-type', 'date', 'last-modified',
+ 'x-copied-from-last-modified') and not value:
return InvalidFormat(key, value)
elif key == 'x-timestamp' and not re.match("^\d+\.?\d*\Z", value):
return InvalidFormat(key, value)
- elif key == 'x-account-bytes-used' and not value.isdigit():
- return InvalidFormat(key, value)
- elif key == 'x-account-container-count' and not value.isdigit():
- return InvalidFormat(key, value)
- elif key == 'x-account-object-count' and not value.isdigit():
- return InvalidFormat(key, value)
- elif key == 'x-container-bytes-used' and not value.isdigit():
- return InvalidFormat(key, value)
- elif key == 'x-container-object-count' and not value.isdigit():
- return InvalidFormat(key, value)
- elif key == 'content-type' and not value:
- return InvalidFormat(key, value)
elif key == 'x-copied-from' and not re.match("\S+/\S+", value):
return InvalidFormat(key, value)
- elif key == 'x-copied-from-last-modified' and not value:
- return InvalidFormat(key, value)
elif key == 'x-trans-id' and \
not re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*", value):
return InvalidFormat(key, value)
- elif key == 'date' and not value:
- return InvalidFormat(key, value)
- elif key == 'last-modified' and not value:
- return InvalidFormat(key, value)
elif key == 'accept-ranges' and not value == 'bytes':
return InvalidFormat(key, value)
elif key == 'etag' and not value.isalnum():
diff --git a/tempest/config.py b/tempest/config.py
index cc6d626..bbfe70b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -185,7 +185,9 @@
help="Time in seconds between build status checks."),
cfg.IntOpt('build_timeout',
default=300,
- help="Timeout in seconds to wait for an instance to build."),
+ help="Timeout in seconds to wait for an instance to build. "
+ "Other services that do not define build_timeout will "
+ "inherit this value, for example the image service."),
cfg.BoolOpt('run_ssh',
default=False,
help="Should the tests ssh to instances?"),
@@ -467,7 +469,7 @@
"checks."),
cfg.ListOpt('dns_servers',
default=["8.8.8.8", "8.8.4.4"],
- help="List of dns servers whichs hould be used"
+ help="List of dns servers which should be used"
" for subnet creation")
]
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 61a7d2e..20b95e4 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -556,7 +556,7 @@
if not client:
client = self.network_client
if not tenant_id:
- tenant_id = client.rest_client.tenant_id
+ tenant_id = client.tenant_id
name = data_utils.rand_name(namestart)
result = client.create_network(name=name, tenant_id=tenant_id)
network = net_resources.DeletableNetwork(client=client,
@@ -791,7 +791,7 @@
if client is None:
client = self.network_client
if tenant_id is None:
- tenant_id = client.rest_client.tenant_id
+ tenant_id = client.tenant_id
secgroup = self._create_empty_security_group(namestart=namestart,
client=client,
tenant_id=tenant_id)
@@ -817,7 +817,7 @@
if client is None:
client = self.network_client
if not tenant_id:
- tenant_id = client.rest_client.tenant_id
+ tenant_id = client.tenant_id
sg_name = data_utils.rand_name(namestart)
sg_desc = sg_name + " description"
sg_dict = dict(name=sg_name,
@@ -842,7 +842,7 @@
if client is None:
client = self.network_client
if not tenant_id:
- tenant_id = client.rest_client.tenant_id
+ tenant_id = client.tenant_id
sgs = [
sg for sg in client.list_security_groups().values()[0]
if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
@@ -874,7 +874,7 @@
if client is None:
client = self.network_client
if not tenant_id:
- tenant_id = client.rest_client.tenant_id
+ tenant_id = client.tenant_id
if secgroup is None:
secgroup = self._default_security_group(client=client,
tenant_id=tenant_id)
@@ -986,7 +986,7 @@
if not client:
client = self.network_client
if not tenant_id:
- tenant_id = client.rest_client.tenant_id
+ tenant_id = client.tenant_id
router_id = CONF.network.public_router_id
network_id = CONF.network.public_network_id
if router_id:
@@ -1005,7 +1005,7 @@
if not client:
client = self.network_client
if not tenant_id:
- tenant_id = client.rest_client.tenant_id
+ tenant_id = client.tenant_id
name = data_utils.rand_name(namestart)
result = client.create_router(name=name,
admin_state_up=True,
diff --git a/tempest/services/compute/json/agents_client.py b/tempest/services/compute/json/agents_client.py
index 5b76a56..eacd367 100644
--- a/tempest/services/compute/json/agents_client.py
+++ b/tempest/services/compute/json/agents_client.py
@@ -17,21 +17,14 @@
from tempest.api_schema.response.compute import agents as common_schema
from tempest.api_schema.response.compute.v2 import agents as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class AgentsClientJSON(rest_client.RestClient):
+class AgentsClientJSON(base.ComputeClient):
"""
Tests Agents API
"""
- def __init__(self, auth_provider):
- super(AgentsClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
def list_agents(self, params=None):
"""List all agent builds."""
url = 'os-agents'
diff --git a/tempest/services/compute/json/aggregates_client.py b/tempest/services/compute/json/aggregates_client.py
index 09927d3..1539259 100644
--- a/tempest/services/compute/json/aggregates_client.py
+++ b/tempest/services/compute/json/aggregates_client.py
@@ -17,18 +17,11 @@
from tempest.api_schema.response.compute import aggregates as schema
from tempest.api_schema.response.compute.v2 import aggregates as v2_schema
-from tempest.common import rest_client
-from tempest import config
from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class AggregatesClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(AggregatesClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class AggregatesClientJSON(base.ComputeClient):
def list_aggregates(self):
"""Get aggregate list."""
diff --git a/tempest/services/compute/json/availability_zone_client.py b/tempest/services/compute/json/availability_zone_client.py
index 00f8330..b8bda68 100644
--- a/tempest/services/compute/json/availability_zone_client.py
+++ b/tempest/services/compute/json/availability_zone_client.py
@@ -16,18 +16,10 @@
import json
from tempest.api_schema.response.compute.v2 import availability_zone as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class AvailabilityZoneClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(AvailabilityZoneClientJSON, self).__init__(
- auth_provider)
- self.service = CONF.compute.catalog_type
+class AvailabilityZoneClientJSON(base.ComputeClient):
def get_availability_zone_list(self):
resp, body = self.get('os-availability-zone')
diff --git a/tempest/services/compute/json/base.py b/tempest/services/compute/json/base.py
new file mode 100644
index 0000000..b712452
--- /dev/null
+++ b/tempest/services/compute/json/base.py
@@ -0,0 +1,36 @@
+# 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.common import rest_client
+from tempest import config
+
+CONF = config.CONF
+
+
+class ComputeClient(rest_client.RestClient):
+ """
+ Base compute client class
+ """
+
+ def __init__(self, auth_provider,
+ build_interval=None, build_timeout=None):
+ if build_interval is None:
+ build_interval = CONF.compute.build_interval
+ if build_timeout is None:
+ build_timeout = CONF.compute.build_timeout
+
+ super(ComputeClient, self).__init__(auth_provider)
+ self.service = CONF.compute.catalog_type
+ self.build_interval = build_interval
+ self.build_timeout = build_timeout
diff --git a/tempest/services/compute/json/certificates_client.py b/tempest/services/compute/json/certificates_client.py
index 356ded2..123f0b9 100644
--- a/tempest/services/compute/json/certificates_client.py
+++ b/tempest/services/compute/json/certificates_client.py
@@ -17,17 +17,10 @@
from tempest.api_schema.response.compute import certificates as schema
from tempest.api_schema.response.compute.v2 import certificates as v2schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class CertificatesClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(CertificatesClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class CertificatesClientJSON(base.ComputeClient):
def get_certificate(self, id):
url = "os-certificates/%s" % (id)
diff --git a/tempest/services/compute/json/extensions_client.py b/tempest/services/compute/json/extensions_client.py
index 41d1c4e..69ad7c0 100644
--- a/tempest/services/compute/json/extensions_client.py
+++ b/tempest/services/compute/json/extensions_client.py
@@ -16,17 +16,10 @@
import json
from tempest.api_schema.response.compute.v2 import extensions as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class ExtensionsClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(ExtensionsClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class ExtensionsClientJSON(base.ComputeClient):
def list_extensions(self):
url = 'extensions'
diff --git a/tempest/services/compute/json/fixed_ips_client.py b/tempest/services/compute/json/fixed_ips_client.py
index 5903334..8fd24b6 100644
--- a/tempest/services/compute/json/fixed_ips_client.py
+++ b/tempest/services/compute/json/fixed_ips_client.py
@@ -16,17 +16,10 @@
import json
from tempest.api_schema.response.compute.v2 import fixed_ips as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class FixedIPsClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(FixedIPsClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class FixedIPsClientJSON(base.ComputeClient):
def get_fixed_ip_details(self, fixed_ip):
url = "os-fixed-ips/%s" % (fixed_ip)
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 8faf8a7..6276d3c 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -21,17 +21,10 @@
from tempest.api_schema.response.compute import flavors_extra_specs \
as schema_extra_specs
from tempest.api_schema.response.compute.v2 import flavors as v2schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class FlavorsClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(FlavorsClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class FlavorsClientJSON(base.ComputeClient):
def list_flavors(self, params=None):
url = 'flavors'
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index 0ed1720..788b4d2 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -17,17 +17,11 @@
import urllib
from tempest.api_schema.response.compute.v2 import floating_ips as schema
-from tempest.common import rest_client
-from tempest import config
from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class FloatingIPsClientJSON(rest_client.RestClient):
- def __init__(self, auth_provider):
- super(FloatingIPsClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class FloatingIPsClientJSON(base.ComputeClient):
def list_floating_ips(self, params=None):
"""Returns a list of all floating IPs filtered by any parameters."""
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index 8644173..5d306f9 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -17,17 +17,10 @@
from tempest.api_schema.response.compute import hosts as schema
from tempest.api_schema.response.compute.v2 import hosts as v2_schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class HostsClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(HostsClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class HostsClientJSON(base.ComputeClient):
def list_hosts(self, params=None):
"""Lists all hosts."""
diff --git a/tempest/services/compute/json/hypervisor_client.py b/tempest/services/compute/json/hypervisor_client.py
index 8eacf61..52b50c8 100644
--- a/tempest/services/compute/json/hypervisor_client.py
+++ b/tempest/services/compute/json/hypervisor_client.py
@@ -17,17 +17,10 @@
from tempest.api_schema.response.compute import hypervisors as common_schema
from tempest.api_schema.response.compute.v2 import hypervisors as v2schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class HypervisorClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(HypervisorClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class HypervisorClientJSON(base.ComputeClient):
def get_hypervisor_list(self):
"""List hypervisors information."""
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index 079a91e..a4cfe57 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -17,21 +17,12 @@
import urllib
from tempest.api_schema.response.compute.v2 import images as schema
-from tempest.common import rest_client
from tempest.common import waiters
-from tempest import config
from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class ImagesClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(ImagesClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
- self.build_interval = CONF.compute.build_interval
- self.build_timeout = CONF.compute.build_timeout
+class ImagesClientJSON(base.ComputeClient):
def create_image(self, server_id, name, meta=None):
"""Creates an image of the original server."""
diff --git a/tempest/services/compute/json/instance_usage_audit_log_client.py b/tempest/services/compute/json/instance_usage_audit_log_client.py
index 4b0362b..f79c3de 100644
--- a/tempest/services/compute/json/instance_usage_audit_log_client.py
+++ b/tempest/services/compute/json/instance_usage_audit_log_client.py
@@ -17,18 +17,10 @@
from tempest.api_schema.response.compute.v2 import instance_usage_audit_logs \
as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class InstanceUsagesAuditLogClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(InstanceUsagesAuditLogClientJSON, self).__init__(
- auth_provider)
- self.service = CONF.compute.catalog_type
+class InstanceUsagesAuditLogClientJSON(base.ComputeClient):
def list_instance_usage_audit_logs(self):
url = 'os-instance_usage_audit_log'
diff --git a/tempest/services/compute/json/interfaces_client.py b/tempest/services/compute/json/interfaces_client.py
index 620ed68..f1e2660 100644
--- a/tempest/services/compute/json/interfaces_client.py
+++ b/tempest/services/compute/json/interfaces_client.py
@@ -19,18 +19,11 @@
from tempest.api_schema.response.compute import interfaces as common_schema
from tempest.api_schema.response.compute import servers as servers_schema
from tempest.api_schema.response.compute.v2 import interfaces as schema
-from tempest.common import rest_client
-from tempest import config
from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class InterfacesClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(InterfacesClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class InterfacesClientJSON(base.ComputeClient):
def list_interfaces(self, server):
resp, body = self.get('servers/%s/os-interface' % server)
diff --git a/tempest/services/compute/json/keypairs_client.py b/tempest/services/compute/json/keypairs_client.py
index 31c42a5..c4406f5 100644
--- a/tempest/services/compute/json/keypairs_client.py
+++ b/tempest/services/compute/json/keypairs_client.py
@@ -17,17 +17,10 @@
from tempest.api_schema.response.compute import keypairs as common_schema
from tempest.api_schema.response.compute.v2 import keypairs as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class KeyPairsClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(KeyPairsClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class KeyPairsClientJSON(base.ComputeClient):
def list_keypairs(self):
resp, body = self.get("os-keypairs")
diff --git a/tempest/services/compute/json/limits_client.py b/tempest/services/compute/json/limits_client.py
index 81c602b..66a0649 100644
--- a/tempest/services/compute/json/limits_client.py
+++ b/tempest/services/compute/json/limits_client.py
@@ -16,17 +16,10 @@
import json
from tempest.api_schema.response.compute.v2 import limits as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class LimitsClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(LimitsClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class LimitsClientJSON(base.ComputeClient):
def get_absolute_limits(self):
resp, body = self.get("limits")
diff --git a/tempest/services/compute/json/migrations_client.py b/tempest/services/compute/json/migrations_client.py
index f4abbb2..de183f1 100644
--- a/tempest/services/compute/json/migrations_client.py
+++ b/tempest/services/compute/json/migrations_client.py
@@ -16,17 +16,10 @@
import urllib
from tempest.api_schema.response.compute import migrations as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class MigrationsClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(MigrationsClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class MigrationsClientJSON(base.ComputeClient):
def list_migrations(self, params=None):
"""Lists all migrations."""
diff --git a/tempest/services/compute/json/networks_client.py b/tempest/services/compute/json/networks_client.py
index 40eb1a6..5a2744d 100644
--- a/tempest/services/compute/json/networks_client.py
+++ b/tempest/services/compute/json/networks_client.py
@@ -15,17 +15,10 @@
import json
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class NetworksClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(NetworksClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class NetworksClientJSON(base.ComputeClient):
def list_networks(self):
resp, body = self.get("os-networks")
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index b691529..0fee57a 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -18,17 +18,10 @@
from tempest.api_schema.response.compute.v2\
import quota_classes as classes_schema
from tempest.api_schema.response.compute.v2 import quotas as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class QuotasClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(QuotasClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class QuotasClientJSON(base.ComputeClient):
def get_quota_set(self, tenant_id, user_id=None):
"""List the quota set for a tenant."""
@@ -122,11 +115,7 @@
return resp, body
-class QuotaClassesClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(QuotaClassesClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class QuotaClassesClientJSON(base.ComputeClient):
def get_quota_class_set(self, quota_class_id):
"""List the quota class set for a quota class."""
diff --git a/tempest/services/compute/json/security_group_default_rules_client.py b/tempest/services/compute/json/security_group_default_rules_client.py
index 7743f9c..efaf329 100644
--- a/tempest/services/compute/json/security_group_default_rules_client.py
+++ b/tempest/services/compute/json/security_group_default_rules_client.py
@@ -17,18 +17,10 @@
from tempest.api_schema.response.compute.v2 import \
security_group_default_rule as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class SecurityGroupDefaultRulesClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(SecurityGroupDefaultRulesClientJSON,
- self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class SecurityGroupDefaultRulesClientJSON(base.ComputeClient):
def create_security_default_group_rule(self, ip_protocol, from_port,
to_port, **kwargs):
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index 733a50b..a301a0f 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -17,18 +17,11 @@
import urllib
from tempest.api_schema.response.compute.v2 import security_groups as schema
-from tempest.common import rest_client
-from tempest import config
from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class SecurityGroupsClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(SecurityGroupsClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class SecurityGroupsClientJSON(base.ComputeClient):
def list_security_groups(self, params=None):
"""List all security groups for a user."""
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 4268b1a..400f9a7 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -20,20 +20,15 @@
from tempest.api_schema.response.compute import servers as common_schema
from tempest.api_schema.response.compute.v2 import servers as schema
-from tempest.common import rest_client
from tempest.common import waiters
from tempest import config
from tempest import exceptions
+from tempest.services.compute.json import base
CONF = config.CONF
-class ServersClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(ServersClientJSON, self).__init__(auth_provider)
-
- self.service = CONF.compute.catalog_type
+class ServersClientJSON(base.ComputeClient):
def create_server(self, name, image_ref, flavor_ref, **kwargs):
"""
diff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py
index e56263c..8d73c37 100644
--- a/tempest/services/compute/json/services_client.py
+++ b/tempest/services/compute/json/services_client.py
@@ -18,17 +18,10 @@
import urllib
from tempest.api_schema.response.compute import services as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class ServicesClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(ServicesClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class ServicesClientJSON(base.ComputeClient):
def list_services(self, params=None):
url = 'os-services'
diff --git a/tempest/services/compute/json/tenant_usages_client.py b/tempest/services/compute/json/tenant_usages_client.py
index a0b9b4a..eac23bb 100644
--- a/tempest/services/compute/json/tenant_usages_client.py
+++ b/tempest/services/compute/json/tenant_usages_client.py
@@ -17,17 +17,10 @@
import urllib
from tempest.api_schema.response.compute.v2 import tenant_usages as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
-class TenantUsagesClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(TenantUsagesClientJSON, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
+class TenantUsagesClientJSON(base.ComputeClient):
def list_tenant_usages(self, params=None):
url = 'os-simple-tenant-usage'
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index afa6937..69b9bea 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -18,21 +18,20 @@
import urllib
from tempest.api_schema.response.compute.v2 import volumes as schema
-from tempest.common import rest_client
from tempest import config
from tempest import exceptions
+from tempest.services.compute.json import base
CONF = config.CONF
-class VolumesExtensionsClientJSON(rest_client.RestClient):
+class VolumesExtensionsClientJSON(base.ComputeClient):
def __init__(self, auth_provider):
super(VolumesExtensionsClientJSON, self).__init__(
- auth_provider)
- self.service = CONF.compute.catalog_type
- self.build_interval = CONF.volume.build_interval
- self.build_timeout = CONF.volume.build_timeout
+ auth_provider,
+ build_interval=CONF.volume.build_interval,
+ build_timeout=CONF.volume.build_timeout)
def list_volumes(self, params=None):
"""List all the volumes created."""
diff --git a/tempest/services/identity/v3/json/base.py b/tempest/services/identity/v3/json/base.py
new file mode 100644
index 0000000..3df0dab
--- /dev/null
+++ b/tempest/services/identity/v3/json/base.py
@@ -0,0 +1,30 @@
+# 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.common import rest_client
+from tempest import config
+
+CONF = config.CONF
+
+
+class IdentityV3Client(rest_client.RestClient):
+ """
+ Base identity v3 client class
+ """
+
+ def __init__(self, auth_provider):
+ super(IdentityV3Client, self).__init__(auth_provider)
+ self.service = CONF.identity.catalog_type
+ self.endpoint_url = 'adminURL'
+ self.api_version = "v3"
diff --git a/tempest/services/identity/v3/json/credentials_client.py b/tempest/services/identity/v3/json/credentials_client.py
index d424f4c..42acd2a 100644
--- a/tempest/services/identity/v3/json/credentials_client.py
+++ b/tempest/services/identity/v3/json/credentials_client.py
@@ -15,19 +15,10 @@
import json
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.identity.v3.json import base
-class CredentialsClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(CredentialsClientJSON, self).__init__(auth_provider)
- self.service = CONF.identity.catalog_type
- self.endpoint_url = 'adminURL'
- self.api_version = "v3"
+class CredentialsClientJSON(base.IdentityV3Client):
def create_credential(self, access_key, secret_key, user_id, project_id):
"""Creates a credential."""
diff --git a/tempest/services/identity/v3/json/endpoints_client.py b/tempest/services/identity/v3/json/endpoints_client.py
index c3fedb2..9316a4b 100644
--- a/tempest/services/identity/v3/json/endpoints_client.py
+++ b/tempest/services/identity/v3/json/endpoints_client.py
@@ -15,19 +15,10 @@
import json
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.identity.v3.json import base
-class EndPointClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(EndPointClientJSON, self).__init__(auth_provider)
- self.service = CONF.identity.catalog_type
- self.endpoint_url = 'adminURL'
- self.api_version = "v3"
+class EndPointClientJSON(base.IdentityV3Client):
def list_endpoints(self):
"""GET endpoints."""
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index 6ac4901..4c8d8df 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -19,17 +19,12 @@
from tempest.common import rest_client
from tempest import config
from tempest import exceptions
+from tempest.services.identity.v3.json import base
CONF = config.CONF
-class IdentityV3ClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(IdentityV3ClientJSON, self).__init__(auth_provider)
- self.service = CONF.identity.catalog_type
- self.endpoint_url = 'adminURL'
- self.api_version = "v3"
+class IdentityV3ClientJSON(base.IdentityV3Client):
def create_user(self, user_name, password=None, project_id=None,
email=None, domain_id='default', **kwargs):
diff --git a/tempest/services/identity/v3/json/policy_client.py b/tempest/services/identity/v3/json/policy_client.py
index 579243c..04374a2 100644
--- a/tempest/services/identity/v3/json/policy_client.py
+++ b/tempest/services/identity/v3/json/policy_client.py
@@ -16,18 +16,10 @@
import json
from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.identity.v3.json import base
-class PolicyClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(PolicyClientJSON, self).__init__(auth_provider)
- self.service = CONF.identity.catalog_type
- self.endpoint_url = 'adminURL'
- self.api_version = "v3"
+class PolicyClientJSON(base.IdentityV3Client):
def create_policy(self, blob, type):
"""Creates a Policy."""
diff --git a/tempest/services/identity/v3/json/region_client.py b/tempest/services/identity/v3/json/region_client.py
index becea6b..8545778 100644
--- a/tempest/services/identity/v3/json/region_client.py
+++ b/tempest/services/identity/v3/json/region_client.py
@@ -16,19 +16,10 @@
import json
import urllib
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.identity.v3.json import base
-class RegionClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(RegionClientJSON, self).__init__(auth_provider)
- self.service = CONF.identity.catalog_type
- self.endpoint_url = 'adminURL'
- self.api_version = "v3"
+class RegionClientJSON(base.IdentityV3Client):
def create_region(self, description, **kwargs):
"""Create region."""
diff --git a/tempest/services/identity/v3/json/service_client.py b/tempest/services/identity/v3/json/service_client.py
index 8e89957..b8b2556 100644
--- a/tempest/services/identity/v3/json/service_client.py
+++ b/tempest/services/identity/v3/json/service_client.py
@@ -15,19 +15,10 @@
import json
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.identity.v3.json import base
-class ServiceClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(ServiceClientJSON, self).__init__(auth_provider)
- self.service = CONF.identity.catalog_type
- self.endpoint_url = 'adminURL'
- self.api_version = "v3"
+class ServiceClientJSON(base.IdentityV3Client):
def update_service(self, service_id, **kwargs):
"""Updates a service."""
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 0a9a1fa..c622ee4 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -11,12 +11,18 @@
# under the License.
import json
+import time
+import urllib
from tempest.common import rest_client
-from tempest.services.network import network_client_base
+from tempest.common.utils import misc
+from tempest import config
+from tempest import exceptions
+
+CONF = config.CONF
-class NetworkClientJSON(network_client_base.NetworkClientBase):
+class NetworkClientJSON(rest_client.RestClient):
"""
Tempest REST client for Neutron. Uses v2 of the Neutron API, since the
@@ -31,8 +37,228 @@
quotas
"""
- def get_rest_client(self, auth_provider):
- return rest_client.RestClient(auth_provider)
+ def __init__(self, auth_provider):
+ super(NetworkClientJSON, self).__init__(auth_provider)
+ self.service = CONF.network.catalog_type
+ self.build_timeout = CONF.network.build_timeout
+ self.build_interval = CONF.network.build_interval
+ self.version = '2.0'
+ self.uri_prefix = "v%s" % (self.version)
+
+ def get_uri(self, plural_name):
+ # get service prefix from resource name
+
+ # The following list represents resource names that do not require
+ # changing underscore to a hyphen
+ hyphen_exceptions = ["health_monitors", "firewall_rules",
+ "firewall_policies"]
+ # the following map is used to construct proper URI
+ # for the given neutron resource
+ service_resource_prefix_map = {
+ 'networks': '',
+ 'subnets': '',
+ 'ports': '',
+ 'pools': 'lb',
+ 'vips': 'lb',
+ 'health_monitors': 'lb',
+ 'members': 'lb',
+ 'ipsecpolicies': 'vpn',
+ 'vpnservices': 'vpn',
+ 'ikepolicies': 'vpn',
+ 'ipsecpolicies': 'vpn',
+ 'metering_labels': 'metering',
+ 'metering_label_rules': 'metering',
+ 'firewall_rules': 'fw',
+ 'firewall_policies': 'fw',
+ 'firewalls': 'fw'
+ }
+ service_prefix = service_resource_prefix_map.get(
+ plural_name)
+ if plural_name not in hyphen_exceptions:
+ plural_name = plural_name.replace("_", "-")
+ if service_prefix:
+ uri = '%s/%s/%s' % (self.uri_prefix, service_prefix,
+ plural_name)
+ else:
+ uri = '%s/%s' % (self.uri_prefix, plural_name)
+ return uri
+
+ def pluralize(self, resource_name):
+ # get plural from map or just add 's'
+
+ # map from resource name to a plural name
+ # needed only for those which can't be constructed as name + 's'
+ resource_plural_map = {
+ 'security_groups': 'security_groups',
+ 'security_group_rules': 'security_group_rules',
+ 'ipsecpolicy': 'ipsecpolicies',
+ 'ikepolicy': 'ikepolicies',
+ 'ipsecpolicy': 'ipsecpolicies',
+ 'quotas': 'quotas',
+ 'firewall_policy': 'firewall_policies'
+ }
+ return resource_plural_map.get(resource_name, resource_name + 's')
+
+ def _lister(self, plural_name):
+ def _list(**filters):
+ uri = self.get_uri(plural_name)
+ if filters:
+ uri += '?' + urllib.urlencode(filters, doseq=1)
+ resp, body = self.get(uri)
+ result = {plural_name: self.deserialize_list(body)}
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, result)
+
+ return _list
+
+ def _deleter(self, resource_name):
+ def _delete(resource_id):
+ plural = self.pluralize(resource_name)
+ uri = '%s/%s' % (self.get_uri(plural), resource_id)
+ resp, body = self.delete(uri)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ return _delete
+
+ def _shower(self, resource_name):
+ def _show(resource_id, **fields):
+ # fields is a dict which key is 'fields' and value is a
+ # list of field's name. An example:
+ # {'fields': ['id', 'name']}
+ plural = self.pluralize(resource_name)
+ uri = '%s/%s' % (self.get_uri(plural), resource_id)
+ if fields:
+ uri += '?' + urllib.urlencode(fields, doseq=1)
+ resp, body = self.get(uri)
+ body = self.deserialize_single(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ return _show
+
+ def _creater(self, resource_name):
+ def _create(**kwargs):
+ plural = self.pluralize(resource_name)
+ uri = self.get_uri(plural)
+ post_data = self.serialize({resource_name: kwargs})
+ resp, body = self.post(uri, post_data)
+ body = self.deserialize_single(body)
+ self.expected_success(201, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ return _create
+
+ def _updater(self, resource_name):
+ def _update(res_id, **kwargs):
+ plural = self.pluralize(resource_name)
+ uri = '%s/%s' % (self.get_uri(plural), res_id)
+ post_data = self.serialize({resource_name: kwargs})
+ resp, body = self.put(uri, post_data)
+ body = self.deserialize_single(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ return _update
+
+ def __getattr__(self, name):
+ method_prefixes = ["list_", "delete_", "show_", "create_", "update_"]
+ method_functors = [self._lister,
+ self._deleter,
+ self._shower,
+ self._creater,
+ self._updater]
+ for index, prefix in enumerate(method_prefixes):
+ prefix_len = len(prefix)
+ if name[:prefix_len] == prefix:
+ return method_functors[index](name[prefix_len:])
+ raise AttributeError(name)
+
+ # Common methods that are hard to automate
+ def create_bulk_network(self, names):
+ network_list = [{'name': name} for name in names]
+ post_data = {'networks': network_list}
+ body = self.serialize_list(post_data, "networks", "network")
+ uri = self.get_uri("networks")
+ resp, body = self.post(uri, body)
+ body = {'networks': self.deserialize_list(body)}
+ self.expected_success(201, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def create_bulk_subnet(self, subnet_list):
+ post_data = {'subnets': subnet_list}
+ body = self.serialize_list(post_data, 'subnets', 'subnet')
+ uri = self.get_uri('subnets')
+ resp, body = self.post(uri, body)
+ body = {'subnets': self.deserialize_list(body)}
+ self.expected_success(201, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def create_bulk_port(self, port_list):
+ post_data = {'ports': port_list}
+ body = self.serialize_list(post_data, 'ports', 'port')
+ uri = self.get_uri('ports')
+ resp, body = self.post(uri, body)
+ body = {'ports': self.deserialize_list(body)}
+ self.expected_success(201, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def wait_for_resource_deletion(self, resource_type, id):
+ """Waits for a resource to be deleted."""
+ start_time = int(time.time())
+ while True:
+ if self.is_resource_deleted(resource_type, id):
+ return
+ if int(time.time()) - start_time >= self.build_timeout:
+ raise exceptions.TimeoutException
+ time.sleep(self.build_interval)
+
+ def is_resource_deleted(self, resource_type, id):
+ method = 'show_' + resource_type
+ try:
+ getattr(self, method)(id)
+ except AttributeError:
+ raise Exception("Unknown resource type %s " % resource_type)
+ except exceptions.NotFound:
+ return True
+ return False
+
+ def wait_for_resource_status(self, fetch, status, interval=None,
+ timeout=None):
+ """
+ @summary: Waits for a network resource to reach a status
+ @param fetch: the callable to be used to query the resource status
+ @type fecth: callable that takes no parameters and returns the resource
+ @param status: the status that the resource has to reach
+ @type status: String
+ @param interval: the number of seconds to wait between each status
+ query
+ @type interval: Integer
+ @param timeout: the maximum number of seconds to wait for the resource
+ to reach the desired status
+ @type timeout: Integer
+ """
+ if not interval:
+ interval = self.build_interval
+ if not timeout:
+ timeout = self.build_timeout
+ start_time = time.time()
+
+ while time.time() - start_time <= timeout:
+ resource = fetch()
+ if resource['status'] == status:
+ return
+ time.sleep(interval)
+
+ # At this point, the wait has timed out
+ message = 'Resource %s' % (str(resource))
+ message += ' failed to reach status %s' % status
+ message += ' (current: %s)' % resource['status']
+ message += ' within the required time %s' % timeout
+ caller = misc.find_test_caller()
+ if caller:
+ message = '(%s) %s' % (caller, message)
+ raise exceptions.TimeoutException(message)
def deserialize_single(self, body):
return json.loads(body)
@@ -59,14 +285,14 @@
body = json.dumps(put_body)
uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
resp, body = self.put(uri, body)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body['quota'])
def reset_quotas(self, tenant_id):
uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
resp, body = self.delete(uri)
- self.rest_client.expected_success(204, resp.status)
+ self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
def create_router(self, name, admin_state_up=True, **kwargs):
@@ -76,14 +302,14 @@
body = json.dumps(post_body)
uri = '%s/routers' % (self.uri_prefix)
resp, body = self.post(uri, body)
- self.rest_client.expected_success(201, resp.status)
+ self.expected_success(201, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def _update_router(self, router_id, set_enable_snat, **kwargs):
uri = '%s/routers/%s' % (self.uri_prefix, router_id)
resp, body = self.get(uri)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
update_body = {}
update_body['name'] = kwargs.get('name', body['router']['name'])
@@ -103,7 +329,7 @@
update_body = dict(router=update_body)
update_body = json.dumps(update_body)
resp, body = self.put(uri, update_body)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -130,7 +356,7 @@
update_body = {"subnet_id": subnet_id}
update_body = json.dumps(update_body)
resp, body = self.put(uri, update_body)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -140,7 +366,7 @@
update_body = {"port_id": port_id}
update_body = json.dumps(update_body)
resp, body = self.put(uri, update_body)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -150,7 +376,7 @@
update_body = {"subnet_id": subnet_id}
update_body = json.dumps(update_body)
resp, body = self.put(uri, update_body)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -160,7 +386,7 @@
update_body = {"port_id": port_id}
update_body = json.dumps(update_body)
resp, body = self.put(uri, update_body)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -175,7 +401,7 @@
uri = '%s/lb/pools/%s/health_monitors' % (self.uri_prefix,
pool_id)
resp, body = self.post(uri, body)
- self.rest_client.expected_success(201, resp.status)
+ self.expected_success(201, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -184,13 +410,13 @@
uri = '%s/lb/pools/%s/health_monitors/%s' % (self.uri_prefix, pool_id,
health_monitor_id)
resp, body = self.delete(uri)
- self.rest_client.expected_success(204, resp.status)
+ self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
def list_router_interfaces(self, uuid):
uri = '%s/ports?device_id=%s' % (self.uri_prefix, uuid)
resp, body = self.get(uri)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -203,14 +429,14 @@
agent = {"agent": agent_info}
body = json.dumps(agent)
resp, body = self.put(uri, body)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def list_pools_hosted_by_one_lbaas_agent(self, agent_id):
uri = '%s/agents/%s/loadbalancer-pools' % (self.uri_prefix, agent_id)
resp, body = self.get(uri)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -218,21 +444,21 @@
uri = ('%s/lb/pools/%s/loadbalancer-agent' %
(self.uri_prefix, pool_id))
resp, body = self.get(uri)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def list_routers_on_l3_agent(self, agent_id):
uri = '%s/agents/%s/l3-routers' % (self.uri_prefix, agent_id)
resp, body = self.get(uri)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def list_l3_agents_hosting_router(self, router_id):
uri = '%s/routers/%s/l3-agents' % (self.uri_prefix, router_id)
resp, body = self.get(uri)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -241,7 +467,7 @@
post_body = {"router_id": router_id}
body = json.dumps(post_body)
resp, body = self.post(uri, body)
- self.rest_client.expected_success(201, resp.status)
+ self.expected_success(201, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -249,20 +475,20 @@
uri = '%s/agents/%s/l3-routers/%s' % (
self.uri_prefix, agent_id, router_id)
resp, body = self.delete(uri)
- self.rest_client.expected_success(204, resp.status)
+ self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
def list_dhcp_agent_hosting_network(self, network_id):
uri = '%s/networks/%s/dhcp-agents' % (self.uri_prefix, network_id)
resp, body = self.get(uri)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def list_networks_hosted_by_one_dhcp_agent(self, agent_id):
uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
resp, body = self.get(uri)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -270,7 +496,7 @@
uri = '%s/agents/%s/dhcp-networks/%s' % (self.uri_prefix, agent_id,
network_id)
resp, body = self.delete(uri)
- self.rest_client.expected_success(204, resp.status)
+ self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
def create_ikepolicy(self, name, **kwargs):
@@ -284,7 +510,7 @@
body = json.dumps(post_body)
uri = '%s/vpn/ikepolicies' % (self.uri_prefix)
resp, body = self.post(uri, body)
- self.rest_client.expected_success(201, resp.status)
+ self.expected_success(201, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -298,7 +524,7 @@
}
body = json.dumps(put_body)
resp, body = self.put(uri, body)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -312,14 +538,14 @@
}
body = json.dumps(put_body)
resp, body = self.put(uri, body)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def list_lb_pool_stats(self, pool_id):
uri = '%s/lb/pools/%s/stats' % (self.uri_prefix, pool_id)
resp, body = self.get(uri)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -328,7 +554,7 @@
body = json.dumps(post_body)
uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
resp, body = self.post(uri, body)
- self.rest_client.expected_success(201, resp.status)
+ self.expected_success(201, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -344,7 +570,7 @@
}
body = json.dumps(body)
resp, body = self.put(uri, body)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
@@ -355,6 +581,6 @@
update_body = {"firewall_rule_id": firewall_rule_id}
update_body = json.dumps(update_body)
resp, body = self.put(uri, update_body)
- self.rest_client.expected_success(200, resp.status)
+ self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/network/network_client_base.py b/tempest/services/network/network_client_base.py
deleted file mode 100644
index 53fd222..0000000
--- a/tempest/services/network/network_client_base.py
+++ /dev/null
@@ -1,268 +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 time
-import urllib
-
-from tempest.common import rest_client
-from tempest.common.utils import misc
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
-
-# the following map is used to construct proper URI
-# for the given neutron resource
-service_resource_prefix_map = {
- 'networks': '',
- 'subnets': '',
- 'ports': '',
- 'pools': 'lb',
- 'vips': 'lb',
- 'health_monitors': 'lb',
- 'members': 'lb',
- 'ipsecpolicies': 'vpn',
- 'vpnservices': 'vpn',
- 'ikepolicies': 'vpn',
- 'ipsecpolicies': 'vpn',
- 'metering_labels': 'metering',
- 'metering_label_rules': 'metering',
- 'firewall_rules': 'fw',
- 'firewall_policies': 'fw',
- 'firewalls': 'fw'
-}
-
-# The following list represents resource names that do not require
-# changing underscore to a hyphen
-hyphen_exceptions = ["health_monitors", "firewall_rules", "firewall_policies"]
-
-# map from resource name to a plural name
-# needed only for those which can't be constructed as name + 's'
-resource_plural_map = {
- 'security_groups': 'security_groups',
- 'security_group_rules': 'security_group_rules',
- 'ipsecpolicy': 'ipsecpolicies',
- 'ikepolicy': 'ikepolicies',
- 'ipsecpolicy': 'ipsecpolicies',
- 'quotas': 'quotas',
- 'firewall_policy': 'firewall_policies'
-}
-
-
-class NetworkClientBase(object):
- def __init__(self, auth_provider):
- self.rest_client = self.get_rest_client(
- auth_provider)
- self.rest_client.service = CONF.network.catalog_type
- self.version = '2.0'
- self.uri_prefix = "v%s" % (self.version)
- self.build_timeout = CONF.network.build_timeout
- self.build_interval = CONF.network.build_interval
-
- def get_rest_client(self, auth_provider):
- raise NotImplementedError
-
- def post(self, uri, body, headers=None):
- return self.rest_client.post(uri, body, headers)
-
- def put(self, uri, body, headers=None):
- return self.rest_client.put(uri, body, headers)
-
- def get(self, uri, headers=None):
- return self.rest_client.get(uri, headers)
-
- def delete(self, uri, headers=None):
- return self.rest_client.delete(uri, headers)
-
- def deserialize_list(self, body):
- raise NotImplementedError
-
- def deserialize_single(self, body):
- raise NotImplementedError
-
- def get_uri(self, plural_name):
- # get service prefix from resource name
- service_prefix = service_resource_prefix_map.get(
- plural_name)
- if plural_name not in hyphen_exceptions:
- plural_name = plural_name.replace("_", "-")
- if service_prefix:
- uri = '%s/%s/%s' % (self.uri_prefix, service_prefix,
- plural_name)
- else:
- uri = '%s/%s' % (self.uri_prefix, plural_name)
- return uri
-
- def pluralize(self, resource_name):
- # get plural from map or just add 's'
- return resource_plural_map.get(resource_name, resource_name + 's')
-
- def _lister(self, plural_name):
- def _list(**filters):
- uri = self.get_uri(plural_name)
- if filters:
- uri += '?' + urllib.urlencode(filters, doseq=1)
- resp, body = self.get(uri)
- result = {plural_name: self.deserialize_list(body)}
- self.rest_client.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, result)
-
- return _list
-
- def _deleter(self, resource_name):
- def _delete(resource_id):
- plural = self.pluralize(resource_name)
- uri = '%s/%s' % (self.get_uri(plural), resource_id)
- resp, body = self.delete(uri)
- self.rest_client.expected_success(204, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- return _delete
-
- def _shower(self, resource_name):
- def _show(resource_id, **fields):
- # fields is a dict which key is 'fields' and value is a
- # list of field's name. An example:
- # {'fields': ['id', 'name']}
- plural = self.pluralize(resource_name)
- uri = '%s/%s' % (self.get_uri(plural), resource_id)
- if fields:
- uri += '?' + urllib.urlencode(fields, doseq=1)
- resp, body = self.get(uri)
- body = self.deserialize_single(body)
- self.rest_client.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- return _show
-
- def _creater(self, resource_name):
- def _create(**kwargs):
- plural = self.pluralize(resource_name)
- uri = self.get_uri(plural)
- post_data = self.serialize({resource_name: kwargs})
- resp, body = self.post(uri, post_data)
- body = self.deserialize_single(body)
- self.rest_client.expected_success(201, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- return _create
-
- def _updater(self, resource_name):
- def _update(res_id, **kwargs):
- plural = self.pluralize(resource_name)
- uri = '%s/%s' % (self.get_uri(plural), res_id)
- post_data = self.serialize({resource_name: kwargs})
- resp, body = self.put(uri, post_data)
- body = self.deserialize_single(body)
- self.rest_client.expected_success(200, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- return _update
-
- def __getattr__(self, name):
- method_prefixes = ["list_", "delete_", "show_", "create_", "update_"]
- method_functors = [self._lister,
- self._deleter,
- self._shower,
- self._creater,
- self._updater]
- for index, prefix in enumerate(method_prefixes):
- prefix_len = len(prefix)
- if name[:prefix_len] == prefix:
- return method_functors[index](name[prefix_len:])
- raise AttributeError(name)
-
- # Common methods that are hard to automate
- def create_bulk_network(self, names):
- network_list = [{'name': name} for name in names]
- post_data = {'networks': network_list}
- body = self.serialize_list(post_data, "networks", "network")
- uri = self.get_uri("networks")
- resp, body = self.post(uri, body)
- body = {'networks': self.deserialize_list(body)}
- self.rest_client.expected_success(201, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def create_bulk_subnet(self, subnet_list):
- post_data = {'subnets': subnet_list}
- body = self.serialize_list(post_data, 'subnets', 'subnet')
- uri = self.get_uri('subnets')
- resp, body = self.post(uri, body)
- body = {'subnets': self.deserialize_list(body)}
- self.rest_client.expected_success(201, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def create_bulk_port(self, port_list):
- post_data = {'ports': port_list}
- body = self.serialize_list(post_data, 'ports', 'port')
- uri = self.get_uri('ports')
- resp, body = self.post(uri, body)
- body = {'ports': self.deserialize_list(body)}
- self.rest_client.expected_success(201, resp.status)
- return rest_client.ResponseBody(resp, body)
-
- def wait_for_resource_deletion(self, resource_type, id):
- """Waits for a resource to be deleted."""
- start_time = int(time.time())
- while True:
- if self.is_resource_deleted(resource_type, id):
- return
- if int(time.time()) - start_time >= self.build_timeout:
- raise exceptions.TimeoutException
- time.sleep(self.build_interval)
-
- def is_resource_deleted(self, resource_type, id):
- method = 'show_' + resource_type
- try:
- getattr(self, method)(id)
- except AttributeError:
- raise Exception("Unknown resource type %s " % resource_type)
- except exceptions.NotFound:
- return True
- return False
-
- def wait_for_resource_status(self, fetch, status, interval=None,
- timeout=None):
- """
- @summary: Waits for a network resource to reach a status
- @param fetch: the callable to be used to query the resource status
- @type fecth: callable that takes no parameters and returns the resource
- @param status: the status that the resource has to reach
- @type status: String
- @param interval: the number of seconds to wait between each status
- query
- @type interval: Integer
- @param timeout: the maximum number of seconds to wait for the resource
- to reach the desired status
- @type timeout: Integer
- """
- if not interval:
- interval = self.build_interval
- if not timeout:
- timeout = self.build_timeout
- start_time = time.time()
-
- while time.time() - start_time <= timeout:
- resource = fetch()
- if resource['status'] == status:
- return
- time.sleep(interval)
-
- # At this point, the wait has timed out
- message = 'Resource %s' % (str(resource))
- message += ' failed to reach status %s' % status
- message += ' (current: %s)' % resource['status']
- message += ' within the required time %s' % timeout
- caller = misc.find_test_caller()
- if caller:
- message = '(%s) %s' % (caller, message)
- raise exceptions.TimeoutException(message)
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index a2044ef..23984cd 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -18,17 +18,14 @@
from xml.etree import ElementTree as etree
from tempest.common import http
-from tempest.common import rest_client
from tempest import config
from tempest import exceptions
+from tempest.services.object_storage import base
CONF = config.CONF
-class AccountClient(rest_client.RestClient):
- def __init__(self, auth_provider):
- super(AccountClient, self).__init__(auth_provider)
- self.service = CONF.object_storage.catalog_type
+class AccountClient(base.ObjectStorageClient):
def create_account(self, data=None,
params=None,
@@ -167,17 +164,10 @@
return resp, body
-class AccountClientCustomizedHeader(rest_client.RestClient):
+class AccountClientCustomizedHeader(base.ObjectStorageClient):
# TODO(andreaf) This class is now redundant, to be removed in next patch
- def __init__(self, auth_provider):
- super(AccountClientCustomizedHeader, self).__init__(
- auth_provider)
- # Overwrites json-specific header encoding in rest_client.RestClient
- self.service = CONF.object_storage.catalog_type
- self.format = 'json'
-
def request(self, method, url, extra_headers=False, headers=None,
body=None):
"""A simple HTTP request interface."""
diff --git a/tempest/services/object_storage/base.py b/tempest/services/object_storage/base.py
new file mode 100644
index 0000000..c903ca5
--- /dev/null
+++ b/tempest/services/object_storage/base.py
@@ -0,0 +1,29 @@
+# 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.common import rest_client
+from tempest import config
+
+CONF = config.CONF
+
+
+class ObjectStorageClient(rest_client.RestClient):
+ """
+ Base object storage client class
+ """
+
+ def __init__(self, auth_provider):
+ super(ObjectStorageClient, self).__init__(auth_provider)
+ self.service = CONF.object_storage.catalog_type
+ self.format = 'json'
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index 182c4d0..c55826b 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -17,20 +17,10 @@
import urllib
from xml.etree import ElementTree as etree
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.object_storage import base
-class ContainerClient(rest_client.RestClient):
- def __init__(self, auth_provider):
- super(ContainerClient, self).__init__(auth_provider)
-
- # Overwrites json-specific header encoding in rest_client.RestClient
- self.headers = {}
- self.service = CONF.object_storage.catalog_type
- self.format = 'json'
+class ContainerClient(base.ObjectStorageClient):
def create_container(
self, container_name,
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 7a69fa8..a93a9df 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -18,18 +18,14 @@
import urlparse
from tempest.common import http
-from tempest.common import rest_client
from tempest import config
from tempest import exceptions
+from tempest.services.object_storage import base
CONF = config.CONF
-class ObjectClient(rest_client.RestClient):
- def __init__(self, auth_provider):
- super(ObjectClient, self).__init__(auth_provider)
-
- self.service = CONF.object_storage.catalog_type
+class ObjectClient(base.ObjectStorageClient):
def create_object(self, container, object_name, data,
params=None, metadata=None):
@@ -182,17 +178,10 @@
return resp.status, resp.reason, resp_headers
-class ObjectClientCustomizedHeader(rest_client.RestClient):
+class ObjectClientCustomizedHeader(base.ObjectStorageClient):
# TODO(andreaf) This class is now redundant, to be removed in next patch
- def __init__(self, auth_provider):
- super(ObjectClientCustomizedHeader, self).__init__(
- auth_provider)
- # Overwrites json-specific header encoding in rest_client.RestClient
- self.service = CONF.object_storage.catalog_type
- self.format = 'json'
-
def request(self, method, url, extra_headers=False, headers=None,
body=None):
"""A simple HTTP request interface."""
diff --git a/tempest/services/telemetry/json/telemetry_client.py b/tempest/services/telemetry/json/telemetry_client.py
index 996aceb..d2dd375 100644
--- a/tempest/services/telemetry/json/telemetry_client.py
+++ b/tempest/services/telemetry/json/telemetry_client.py
@@ -13,15 +13,22 @@
# License for the specific language governing permissions and limitations
# under the License.
+import urllib
+
from tempest.common import rest_client
+from tempest import config
from tempest.openstack.common import jsonutils as json
-import tempest.services.telemetry.telemetry_client_base as client
+
+CONF = config.CONF
-class TelemetryClientJSON(client.TelemetryClientBase):
+class TelemetryClientJSON(rest_client.RestClient):
- def get_rest_client(self, auth_provider):
- return rest_client.RestClient(auth_provider)
+ def __init__(self, auth_provider):
+ super(TelemetryClientJSON, self).__init__(auth_provider)
+ self.service = CONF.telemetry.catalog_type
+ self.version = '2'
+ self.uri_prefix = "v%s" % self.version
def deserialize(self, body):
return json.loads(body.replace("\n", ""))
@@ -42,4 +49,87 @@
def create_sample(self, meter_name, sample_list):
uri = "%s/meters/%s" % (self.uri_prefix, meter_name)
- return self.post(uri, str(sample_list))
+ body = self.serialize(sample_list)
+ resp, body = self.post(uri, body)
+ body = self.deserialize(body)
+ return resp, body
+
+ def helper_list(self, uri, query=None, period=None):
+ uri_dict = {}
+ if query:
+ uri_dict = {'q.field': query[0],
+ 'q.op': query[1],
+ 'q.value': query[2]}
+ if period:
+ uri_dict['period'] = period
+ if uri_dict:
+ uri += "?%s" % urllib.urlencode(uri_dict)
+ resp, body = self.get(uri)
+ body = self.deserialize(body)
+ return resp, body
+
+ def list_resources(self, query=None):
+ uri = '%s/resources' % self.uri_prefix
+ return self.helper_list(uri, query)
+
+ def list_meters(self, query=None):
+ uri = '%s/meters' % self.uri_prefix
+ return self.helper_list(uri, query)
+
+ def list_alarms(self, query=None):
+ uri = '%s/alarms' % self.uri_prefix
+ return self.helper_list(uri, query)
+
+ def list_statistics(self, meter, period=None, query=None):
+ uri = "%s/meters/%s/statistics" % (self.uri_prefix, meter)
+ return self.helper_list(uri, query, period)
+
+ def list_samples(self, meter_id, query=None):
+ uri = '%s/meters/%s' % (self.uri_prefix, meter_id)
+ return self.helper_list(uri, query)
+
+ def get_resource(self, resource_id):
+ uri = '%s/resources/%s' % (self.uri_prefix, resource_id)
+ resp, body = self.get(uri)
+ body = self.deserialize(body)
+ return resp, body
+
+ def get_alarm(self, alarm_id):
+ uri = '%s/alarms/%s' % (self.uri_prefix, alarm_id)
+ resp, body = self.get(uri)
+ body = self.deserialize(body)
+ return resp, body
+
+ def delete_alarm(self, alarm_id):
+ uri = "%s/alarms/%s" % (self.uri_prefix, alarm_id)
+ resp, body = self.delete(uri)
+ if body:
+ body = self.deserialize(body)
+ return resp, body
+
+ def create_alarm(self, **kwargs):
+ uri = "%s/alarms" % self.uri_prefix
+ body = self.serialize(kwargs)
+ resp, body = self.post(uri, body)
+ body = self.deserialize(body)
+ return resp, body
+
+ def update_alarm(self, alarm_id, **kwargs):
+ uri = "%s/alarms/%s" % (self.uri_prefix, alarm_id)
+ body = self.serialize(kwargs)
+ resp, body = self.put(uri, body)
+ body = self.deserialize(body)
+ return resp, body
+
+ def alarm_get_state(self, alarm_id):
+ uri = "%s/alarms/%s/state" % (self.uri_prefix, alarm_id)
+ resp, body = self.get(uri)
+ body = self.deserialize(body)
+ return resp, body
+
+ def alarm_set_state(self, alarm_id, state):
+ uri = "%s/alarms/%s/state" % (self.uri_prefix, alarm_id)
+ body = self.serialize(state)
+ resp, body = self.put(uri, body)
+ body = self.deserialize(body)
+ return resp, body
diff --git a/tempest/services/telemetry/telemetry_client_base.py b/tempest/services/telemetry/telemetry_client_base.py
deleted file mode 100644
index a184a77..0000000
--- a/tempest/services/telemetry/telemetry_client_base.py
+++ /dev/null
@@ -1,151 +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.
-
-import abc
-import urllib
-
-import six
-
-from tempest import config
-
-CONF = config.CONF
-
-
-@six.add_metaclass(abc.ABCMeta)
-class TelemetryClientBase(object):
-
- """
- Tempest REST client for Ceilometer V2 API.
- Implements the following basic Ceilometer abstractions:
- resources
- meters
- alarms
- queries
- statistics
- """
-
- def __init__(self, auth_provider):
- self.rest_client = self.get_rest_client(auth_provider)
- self.rest_client.service = CONF.telemetry.catalog_type
- self.version = '2'
- self.uri_prefix = "v%s" % self.version
-
- @abc.abstractmethod
- def get_rest_client(self, auth_provider):
- """
- :param config:
- :param username:
- :param password:
- :param auth_url:
- :param tenant_name:
- :return: RestClient
- """
-
- @abc.abstractmethod
- def deserialize(self, body):
- """
- :param body:
- :return: Deserialize body
- """
-
- @abc.abstractmethod
- def serialize(self, body):
- """
- :param body:
- :return: Serialize body
- """
-
- def post(self, uri, body):
- body = self.serialize(body)
- resp, body = self.rest_client.post(uri, body)
- body = self.deserialize(body)
- return resp, body
-
- def put(self, uri, body):
- body = self.serialize(body)
- resp, body = self.rest_client.put(uri, body)
- body = self.deserialize(body)
- return resp, body
-
- def get(self, uri):
- resp, body = self.rest_client.get(uri)
- body = self.deserialize(body)
- return resp, body
-
- def delete(self, uri):
- resp, body = self.rest_client.delete(uri)
- if body:
- body = self.deserialize(body)
- return resp, body
-
- def helper_list(self, uri, query=None, period=None):
- uri_dict = {}
- if query:
- uri_dict = {'q.field': query[0],
- 'q.op': query[1],
- 'q.value': query[2]}
- if period:
- uri_dict['period'] = period
- if uri_dict:
- uri += "?%s" % urllib.urlencode(uri_dict)
- return self.get(uri)
-
- def list_resources(self, query=None):
- uri = '%s/resources' % self.uri_prefix
- return self.helper_list(uri, query)
-
- def list_meters(self, query=None):
- uri = '%s/meters' % self.uri_prefix
- return self.helper_list(uri, query)
-
- def list_alarms(self, query=None):
- uri = '%s/alarms' % self.uri_prefix
- return self.helper_list(uri, query)
-
- def list_statistics(self, meter, period=None, query=None):
- uri = "%s/meters/%s/statistics" % (self.uri_prefix, meter)
- return self.helper_list(uri, query, period)
-
- def list_samples(self, meter_id, query=None):
- uri = '%s/meters/%s' % (self.uri_prefix, meter_id)
- return self.helper_list(uri, query)
-
- def get_resource(self, resource_id):
- uri = '%s/resources/%s' % (self.uri_prefix, resource_id)
- return self.get(uri)
-
- def get_alarm(self, alarm_id):
- uri = '%s/alarms/%s' % (self.uri_prefix, alarm_id)
- return self.get(uri)
-
- def delete_alarm(self, alarm_id):
- uri = "%s/alarms/%s" % (self.uri_prefix, alarm_id)
- return self.delete(uri)
-
- def create_alarm(self, **kwargs):
- uri = "%s/alarms" % self.uri_prefix
- return self.post(uri, kwargs)
-
- def update_alarm(self, alarm_id, **kwargs):
- uri = "%s/alarms/%s" % (self.uri_prefix, alarm_id)
- return self.put(uri, kwargs)
-
- def alarm_get_state(self, alarm_id):
- uri = "%s/alarms/%s/state" % (self.uri_prefix, alarm_id)
- return self.get(uri)
-
- def alarm_set_state(self, alarm_id, state):
- uri = "%s/alarms/%s/state" % (self.uri_prefix, alarm_id)
- return self.put(uri, state)
diff --git a/tempest/services/volume/json/admin/volume_hosts_client.py b/tempest/services/volume/json/admin/volume_hosts_client.py
index 10cb0be..e7add30 100644
--- a/tempest/services/volume/json/admin/volume_hosts_client.py
+++ b/tempest/services/volume/json/admin/volume_hosts_client.py
@@ -16,24 +16,14 @@
import json
import urllib
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.volume.json import base
-class BaseVolumeHostsClientJSON(rest_client.RestClient):
+class BaseVolumeHostsClientJSON(base.VolumeClient):
"""
Client class to send CRUD Volume Hosts API requests to a Cinder endpoint
"""
- def __init__(self, auth_provider):
- super(BaseVolumeHostsClientJSON, self).__init__(auth_provider)
-
- self.service = CONF.volume.catalog_type
- self.build_interval = CONF.volume.build_interval
- self.build_timeout = CONF.volume.build_timeout
-
def list_hosts(self, params=None):
"""Lists all hosts."""
diff --git a/tempest/services/volume/json/admin/volume_quotas_client.py b/tempest/services/volume/json/admin/volume_quotas_client.py
index 5b49040..f08cb64 100644
--- a/tempest/services/volume/json/admin/volume_quotas_client.py
+++ b/tempest/services/volume/json/admin/volume_quotas_client.py
@@ -16,27 +16,17 @@
import urllib
-from tempest.common import rest_client
-from tempest import config
from tempest.openstack.common import jsonutils
-
-CONF = config.CONF
+from tempest.services.volume.json import base
-class BaseVolumeQuotasClientJSON(rest_client.RestClient):
+class BaseVolumeQuotasClientJSON(base.VolumeClient):
"""
Client class to send CRUD Volume Quotas API requests to a Cinder endpoint
"""
TYPE = "json"
- def __init__(self, auth_provider):
- super(BaseVolumeQuotasClientJSON, self).__init__(auth_provider)
-
- self.service = CONF.volume.catalog_type
- self.build_interval = CONF.volume.build_interval
- self.build_timeout = CONF.volume.build_timeout
-
def get_default_quota_set(self, tenant_id):
"""List the default volume quota set for a tenant."""
diff --git a/tempest/services/volume/json/admin/volume_services_client.py b/tempest/services/volume/json/admin/volume_services_client.py
index 88c6db0..5d4f9db 100644
--- a/tempest/services/volume/json/admin/volume_services_client.py
+++ b/tempest/services/volume/json/admin/volume_services_client.py
@@ -16,17 +16,10 @@
import json
import urllib
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.volume.json import base
-class BaseVolumesServicesClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(BaseVolumesServicesClientJSON, self).__init__(auth_provider)
- self.service = CONF.volume.catalog_type
+class BaseVolumesServicesClientJSON(base.VolumeClient):
def list_services(self, params=None):
url = 'os-services'
diff --git a/tempest/services/volume/json/admin/volume_types_client.py b/tempest/services/volume/json/admin/volume_types_client.py
index eedf880..171ad35 100644
--- a/tempest/services/volume/json/admin/volume_types_client.py
+++ b/tempest/services/volume/json/admin/volume_types_client.py
@@ -16,25 +16,15 @@
import json
import urllib
-from tempest.common import rest_client
-from tempest import config
from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.volume.json import base
-class BaseVolumeTypesClientJSON(rest_client.RestClient):
+class BaseVolumeTypesClientJSON(base.VolumeClient):
"""
Client class to send CRUD Volume Types API requests to a Cinder endpoint
"""
- def __init__(self, auth_provider):
- super(BaseVolumeTypesClientJSON, self).__init__(auth_provider)
-
- self.service = CONF.volume.catalog_type
- self.build_interval = CONF.volume.build_interval
- self.build_timeout = CONF.volume.build_timeout
-
def is_resource_deleted(self, resource):
# to use this method self.resource must be defined to respective value
# Resource is a dictionary containing resource id and type
diff --git a/tempest/services/volume/json/availability_zone_client.py b/tempest/services/volume/json/availability_zone_client.py
index 5ad2287..9f2c570 100644
--- a/tempest/services/volume/json/availability_zone_client.py
+++ b/tempest/services/volume/json/availability_zone_client.py
@@ -15,18 +15,10 @@
import json
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.volume.json import base
-class BaseVolumeAvailabilityZoneClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(BaseVolumeAvailabilityZoneClientJSON, self).__init__(
- auth_provider)
- self.service = CONF.volume.catalog_type
+class BaseVolumeAvailabilityZoneClientJSON(base.VolumeClient):
def get_availability_zone_list(self):
resp, body = self.get('os-availability-zone')
diff --git a/tempest/services/volume/json/backups_client.py b/tempest/services/volume/json/backups_client.py
index 51a017e..e2ba822 100644
--- a/tempest/services/volume/json/backups_client.py
+++ b/tempest/services/volume/json/backups_client.py
@@ -16,24 +16,15 @@
import json
import time
-from tempest.common import rest_client
-from tempest import config
from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.volume.json import base
-class BaseBackupsClientJSON(rest_client.RestClient):
+class BaseBackupsClientJSON(base.VolumeClient):
"""
Client class to send CRUD Volume backup API requests to a Cinder endpoint
"""
- def __init__(self, auth_provider):
- super(BaseBackupsClientJSON, self).__init__(auth_provider)
- self.service = CONF.volume.catalog_type
- self.build_interval = CONF.volume.build_interval
- self.build_timeout = CONF.volume.build_timeout
-
def create_backup(self, volume_id, container=None, name=None,
description=None):
"""Creates a backup of volume."""
diff --git a/tempest/services/volume/json/base.py b/tempest/services/volume/json/base.py
new file mode 100644
index 0000000..8bc2f93
--- /dev/null
+++ b/tempest/services/volume/json/base.py
@@ -0,0 +1,30 @@
+# 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.common import rest_client
+from tempest import config
+
+CONF = config.CONF
+
+
+class VolumeClient(rest_client.RestClient):
+ """
+ Base volume client class
+ """
+
+ def __init__(self, auth_provider):
+ super(VolumeClient, self).__init__(auth_provider)
+ self.service = CONF.volume.catalog_type
+ self.build_interval = CONF.volume.build_interval
+ self.build_timeout = CONF.volume.build_timeout
diff --git a/tempest/services/volume/json/extensions_client.py b/tempest/services/volume/json/extensions_client.py
index c84b186..13b91c3 100644
--- a/tempest/services/volume/json/extensions_client.py
+++ b/tempest/services/volume/json/extensions_client.py
@@ -15,17 +15,10 @@
import json
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.volume.json import base
-class BaseExtensionsClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_provider):
- super(BaseExtensionsClientJSON, self).__init__(auth_provider)
- self.service = CONF.volume.catalog_type
+class BaseExtensionsClientJSON(base.VolumeClient):
def list_extensions(self):
url = 'extensions'
diff --git a/tempest/services/volume/json/qos_client.py b/tempest/services/volume/json/qos_client.py
index b647bc7..9c13cac 100644
--- a/tempest/services/volume/json/qos_client.py
+++ b/tempest/services/volume/json/qos_client.py
@@ -15,22 +15,13 @@
import json
import time
-from tempest.common import rest_client
-from tempest import config
from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.volume.json import base
-class BaseQosSpecsClientJSON(rest_client.RestClient):
+class BaseQosSpecsClientJSON(base.VolumeClient):
"""Client class to send CRUD QoS API requests"""
- def __init__(self, auth_provider):
- super(BaseQosSpecsClientJSON, self).__init__(auth_provider)
- self.service = CONF.volume.catalog_type
- self.build_interval = CONF.volume.build_interval
- self.build_timeout = CONF.volume.build_timeout
-
def is_resource_deleted(self, qos_id):
try:
self.get_qos(qos_id)
diff --git a/tempest/services/volume/json/snapshots_client.py b/tempest/services/volume/json/snapshots_client.py
index e9d5b83..349d1b0 100644
--- a/tempest/services/volume/json/snapshots_client.py
+++ b/tempest/services/volume/json/snapshots_client.py
@@ -14,26 +14,18 @@
import time
import urllib
-from tempest.common import rest_client
-from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
+from tempest.services.volume.json import base
-CONF = config.CONF
LOG = logging.getLogger(__name__)
-class BaseSnapshotsClientJSON(rest_client.RestClient):
+class BaseSnapshotsClientJSON(base.VolumeClient):
"""Base Client class to send CRUD Volume API requests."""
- def __init__(self, auth_provider):
- super(BaseSnapshotsClientJSON, self).__init__(auth_provider)
-
- self.service = CONF.volume.catalog_type
- self.build_interval = CONF.volume.build_interval
- self.build_timeout = CONF.volume.build_timeout
- self.create_resp = 200
+ create_resp = 200
def list_snapshots(self, params=None):
"""List all the snapshot."""
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index 1e49e5a..f19718e 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -17,25 +17,19 @@
import time
import urllib
-from tempest.common import rest_client
from tempest import config
from tempest import exceptions
+from tempest.services.volume.json import base
CONF = config.CONF
-class BaseVolumesClientJSON(rest_client.RestClient):
+class BaseVolumesClientJSON(base.VolumeClient):
"""
Base client class to send CRUD Volume API requests to a Cinder endpoint
"""
- def __init__(self, auth_provider):
- super(BaseVolumesClientJSON, self).__init__(auth_provider)
-
- self.service = CONF.volume.catalog_type
- self.build_interval = CONF.volume.build_interval
- self.build_timeout = CONF.volume.build_timeout
- self.create_resp = 200
+ create_resp = 200
def get_attachment_from_volume(self, volume):
"""Return the element 'attachment' from input volumes."""
diff --git a/tempest/test.py b/tempest/test.py
index 6deb42b..ff829f3 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -274,8 +274,8 @@
cls.resource_setup()
except Exception:
etype, value, trace = sys.exc_info()
- LOG.info("%s in %s.setUpClass. Invoking tearDownClass." % (
- cls.__name__, etype))
+ LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass." % (
+ etype, cls.__name__))
cls.tearDownClass()
try:
raise etype, value, trace
@@ -321,20 +321,6 @@
del trace # to avoid circular refs
@classmethod
- def resource_setup(cls):
- """Class level resource setup for test cases.
- """
- pass
-
- @classmethod
- def resource_cleanup(cls):
- """Class level resource cleanup for test cases.
- Resource cleanup must be able to handle the case of partially setup
- resources, in case a failure during `resource_setup` should happen.
- """
- pass
-
- @classmethod
def skip_checks(cls):
"""Class level skip checks. Subclasses verify in here all
conditions that might prevent the execution of the entire test class.
@@ -362,6 +348,20 @@
# specify which client is `client` and nothing else.
pass
+ @classmethod
+ def resource_setup(cls):
+ """Class level resource setup for test cases.
+ """
+ pass
+
+ @classmethod
+ def resource_cleanup(cls):
+ """Class level resource cleanup for test cases.
+ Resource cleanup must be able to handle the case of partially setup
+ resources, in case a failure during `resource_setup` should happen.
+ """
+ pass
+
def setUp(self):
super(BaseTestCase, self).setUp()
if not self.setUpClassCalled:
diff --git a/tempest/tests/test_tenant_isolation.py b/tempest/tests/test_tenant_isolation.py
index f29ae5a..053dae1 100644
--- a/tempest/tests/test_tenant_isolation.py
+++ b/tempest/tests/test_tenant_isolation.py
@@ -320,8 +320,8 @@
return_values = (fake_http.fake_httplib({}, status=204), {})
remove_secgroup_mock = self.patch(
- 'tempest.services.network.network_client_base.'
- 'NetworkClientBase.delete', return_value=return_values)
+ 'tempest.services.network.json.network_client.'
+ 'NetworkClientJSON.delete', return_value=return_values)
iso_creds.clear_isolated_creds()
# Verify default security group delete
calls = remove_secgroup_mock.mock_calls
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index 00b17d9..707590e 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -157,19 +157,24 @@
instance.add_tag('key1', value='value1')
tags = self.ec2_client.get_all_tags()
- self.assertEqual(tags[0].name, 'key1')
- self.assertEqual(tags[0].value, 'value1')
+ td = {item.name: item.value for item in tags}
+
+ self.assertIn('key1', td)
+ self.assertEqual('value1', td['key1'])
tags = self.ec2_client.get_all_tags(filters={'key': 'key1'})
- self.assertEqual(tags[0].name, 'key1')
- self.assertEqual(tags[0].value, 'value1')
+ td = {item.name: item.value for item in tags}
+ self.assertIn('key1', td)
+ self.assertEqual('value1', td['key1'])
tags = self.ec2_client.get_all_tags(filters={'value': 'value1'})
- self.assertEqual(tags[0].name, 'key1')
- self.assertEqual(tags[0].value, 'value1')
+ td = {item.name: item.value for item in tags}
+ self.assertIn('key1', td)
+ self.assertEqual('value1', td['key1'])
tags = self.ec2_client.get_all_tags(filters={'key': 'value2'})
- self.assertEqual(len(tags), 0, str(tags))
+ td = {item.name: item.value for item in tags}
+ self.assertNotIn('key1', td)
for instance in reservation.instances:
instance.remove_tag('key1', value='value1')