Merge "Introduce the ClientsFactory"
diff --git a/README.rst b/README.rst
index 53c7de5..d109a2d 100644
--- a/README.rst
+++ b/README.rst
@@ -178,9 +178,8 @@
is OS_TEST_PATH=./tempest/test_discover which will only run test discover on the
Tempest suite.
-Alternatively, you can use the run_tests.sh script which will create a venv and
-run the unit tests. There are also the py27 and py34 tox jobs which will run
-the unit tests with the corresponding version of python.
+Alternatively, there are the py27 and py34 tox jobs which will run the unit
+tests with the corresponding version of python.
Python 2.6
----------
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index 17059e4..5263fdd 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -217,3 +217,7 @@
* `2.20`_
.. _2.20: http://docs.openstack.org/developer/nova/api_microversion_history.html#id18
+
+ * `2.25`_
+
+ .. _2.25: http://docs.openstack.org/developer/nova/api_microversion_history.html#maximum-in-mitaka
diff --git a/releasenotes/notes/add-new-identity-clients-3c3afd674a395bde.yaml b/releasenotes/notes/add-new-identity-clients-3c3afd674a395bde.yaml
new file mode 100644
index 0000000..b8dcfce
--- /dev/null
+++ b/releasenotes/notes/add-new-identity-clients-3c3afd674a395bde.yaml
@@ -0,0 +1,10 @@
+---
+features:
+ - |
+ Define identity service clients as libraries
+ The following identity service clients are defined as library interface,
+ so the other projects can use these modules as stable libraries without
+ any maintenance changes.
+
+ * endpoints_client(v3)
+ * policies_client (v3)
diff --git a/requirements.txt b/requirements.txt
index fdcb3d5..058ea00 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -18,7 +18,7 @@
fixtures>=3.0.0 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
PyYAML>=3.1.0 # MIT
-stevedore>=1.10.0 # Apache-2.0
+stevedore>=1.16.0 # Apache-2.0
PrettyTable<0.8,>=0.7 # BSD
os-testr>=0.7.0 # Apache-2.0
urllib3>=1.15.1 # MIT
diff --git a/run_tests.sh b/run_tests.sh
index 22314b6..a856bb4 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -17,6 +17,44 @@
echo " -- [TESTROPTIONS] After the first '--' you can pass arbitrary arguments to testr "
}
+function deprecation_warning {
+ cat <<EOF
+-------------------------------------------------------------------------
+WARNING: run_tests.sh is deprecated and this script will be removed after
+the Newton release. All tests should be run through testr/ostestr or tox.
+
+To run style checks:
+
+ tox -e pep8
+
+To run python 2.7 unit tests
+
+ tox -e py27
+
+To run unit tests and generate coverage report
+
+ tox -e cover
+
+To run a subset of any of these tests:
+
+ tox -e py27 someregex
+
+ i.e.: tox -e py27 test_servers
+
+Additional tox targets are available in tox.ini. For more information
+see:
+http://docs.openstack.org/project-team-guide/project-setup/python.html
+
+NOTE: if you want to use testr to run tests, you can instead use:
+
+ OS_TEST_PATH=./tempest/tests testr run
+
+Documentation on using testr directly can be found at
+http://testrepository.readthedocs.org/en/latest/MANUAL.html
+-------------------------------------------------------------------------
+EOF
+}
+
testrargs=""
just_pep8=0
venv=${VENV:-.venv}
@@ -32,6 +70,8 @@
config_file=""
update=0
+deprecation_warning
+
if ! options=$(getopt -o VNnfuctphd -l virtual-env,no-virtual-env,no-site-packages,force,update,serial,coverage,pep8,help,debug -- "$@")
then
# parse error
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 84b00a7..ac1bfee 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -181,7 +181,7 @@
host=self.host)
aggregates = self.client.list_aggregates()['aggregates']
- aggs = filter(lambda x: x['id'] == aggregate['id'], aggregates)
+ aggs = [agg for agg in aggregates if agg['id'] == aggregate['id']]
self.assertEqual(1, len(aggs))
agg = aggs[0]
self.assertEqual(aggregate_name, agg['name'])
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
index 6b75aee..3c4e313 100644
--- a/tempest/api/compute/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -36,8 +36,8 @@
cls.az_name_prefix = 'test_az'
hosts_all = cls.os_adm.hosts_client.list_hosts()['hosts']
- hosts = map(lambda x: x['host_name'],
- filter(lambda y: y['service'] == 'compute', hosts_all))
+ hosts = ([host['host_name']
+ for host in hosts_all if host['service'] == 'compute'])
cls.host = hosts[0]
@test.attr(type=['negative'])
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 94635ff..dd7beaa 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -27,6 +27,8 @@
class LiveBlockMigrationTestJSON(base.BaseV2ComputeAdminTest):
_host_key = 'OS-EXT-SRV-ATTR:host'
+ max_microversion = '2.24'
+ block_migration = None
@classmethod
def skip_checks(cls):
@@ -64,12 +66,16 @@
return self._get_server_details(server_id)[self._host_key]
def _migrate_server_to(self, server_id, dest_host, volume_backed=False):
- block_migration = (CONF.compute_feature_enabled.
- block_migration_for_live_migration and
- not volume_backed)
+ kwargs = dict()
+ block_migration = getattr(self, 'block_migration', None)
+ if self.block_migration is None:
+ kwargs['disk_over_commit'] = False
+ block_migration = (CONF.compute_feature_enabled.
+ block_migration_for_live_migration and
+ not volume_backed)
body = self.admin_servers_client.live_migrate_server(
server_id, host=dest_host, block_migration=block_migration,
- disk_over_commit=False)
+ **kwargs)
return body
def _get_host_other_than(self, host):
@@ -167,3 +173,9 @@
waiters.wait_for_server_status(self.servers_client,
server_id, 'ACTIVE')
self.assertEqual(target_host, self._get_host_for_server(server_id))
+
+
+class LiveAutoBlockMigrationV225TestJSON(LiveBlockMigrationTestJSON):
+ min_microversion = '2.25'
+ max_microversion = 'latest'
+ block_migration = 'auto'
diff --git a/tempest/api/compute/admin/test_security_groups.py b/tempest/api/compute/admin/test_security_groups.py
index 1494745..58da8b9 100644
--- a/tempest/api/compute/admin/test_security_groups.py
+++ b/tempest/api/compute/admin/test_security_groups.py
@@ -65,7 +65,7 @@
# Fetch all security groups based on 'all_tenants' search filter
fetched_list = self.adm_client.list_security_groups(
all_tenants='true')['security_groups']
- sec_group_id_list = map(lambda sg: sg['id'], fetched_list)
+ sec_group_id_list = [sg['id'] for sg in fetched_list]
# Now check if all created Security Groups are present in fetched list
for sec_group in security_group_list:
self.assertIn(sec_group['id'], sec_group_id_list)
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 3eb6d94..09253b0 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -77,7 +77,7 @@
params = {'all_tenants': ''}
body = self.client.list_servers(detail=True, **params)
servers = body['servers']
- servers_name = map(lambda x: x['name'], servers)
+ servers_name = [server['name'] for server in servers]
self.assertIn(self.s1_name, servers_name)
self.assertIn(self.s2_name, servers_name)
diff --git a/tempest/api/identity/admin/v2/test_services.py b/tempest/api/identity/admin/v2/test_services.py
index 6c9b564..94291f8 100644
--- a/tempest/api/identity/admin/v2/test_services.py
+++ b/tempest/api/identity/admin/v2/test_services.py
@@ -93,7 +93,7 @@
name=name, type=s_type,
description=description)['OS-KSADM:service']
services.append(service)
- service_ids = map(lambda x: x['id'], services)
+ service_ids = [svc['id'] for svc in services]
def delete_services():
for service_id in service_ids:
diff --git a/tempest/api/identity/admin/v2/test_tenants.py b/tempest/api/identity/admin/v2/test_tenants.py
index 583fa8e..4faf184 100644
--- a/tempest/api/identity/admin/v2/test_tenants.py
+++ b/tempest/api/identity/admin/v2/test_tenants.py
@@ -35,7 +35,7 @@
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.tenants_client.delete_tenant, tenant['id'])
tenants.append(tenant)
- tenant_ids = map(lambda x: x['id'], tenants)
+ tenant_ids = [tn['id'] for tn in tenants]
body = self.tenants_client.list_tenants()['tenants']
found = [t for t in body if t['id'] in tenant_ids]
self.assertEqual(len(found), len(tenants), 'Tenants not created')
diff --git a/tempest/api/image/v1/test_image_members.py b/tempest/api/image/v1/test_image_members.py
index 94edb6c..50f0926 100644
--- a/tempest/api/image/v1/test_image_members.py
+++ b/tempest/api/image/v1/test_image_members.py
@@ -25,7 +25,7 @@
self.image_member_client.create_image_member(image, self.alt_tenant_id)
body = self.image_member_client.list_image_members(image)
members = body['members']
- members = map(lambda x: x['member_id'], members)
+ members = [member['member_id'] for member in members]
self.assertIn(self.alt_tenant_id, members)
# get image as alt user
self.alt_img_cli.show_image(image)
@@ -40,7 +40,7 @@
body = self.image_member_client.list_shared_images(
self.alt_tenant_id)
images = body['shared_images']
- images = map(lambda x: x['image_id'], images)
+ images = [img['image_id'] for img in images]
self.assertIn(share_image, images)
self.assertIn(image, images)
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index def7750..e4fbbe3 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -212,7 +212,7 @@
def test_index_no_params(self):
# Simple test to see all fixture images returned
images_list = self.client.list_images()['images']
- image_list = map(lambda x: x['id'], images_list)
+ image_list = [image['id'] for image in images_list]
for image_id in self.created_images:
self.assertIn(image_id, image_list)
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 1fb9c52..42a4352 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -185,7 +185,7 @@
def test_list_no_params(self):
# Simple test to see all fixture images returned
images_list = self.client.list_images()['images']
- image_list = map(lambda x: x['id'], images_list)
+ image_list = [image['id'] for image in images_list]
for image in self.created_images:
self.assertIn(image, image_list)
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index 2abbf93..c64b01e 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -54,7 +54,7 @@
# Create network, subnet, router and add interface
cls.network = cls.create_network()
- cls.subnet = cls.create_subnet(cls.network)
+ cls.subnet = cls.create_subnet(cls.network, enable_dhcp=False)
cls.router = cls.create_router(data_utils.rand_name('router-'),
external_network_id=cls.ext_net_id)
cls.create_router_interface(cls.router['id'], cls.subnet['id'])
diff --git a/tempest/api/orchestration/stacks/test_non_empty_stack.py b/tempest/api/orchestration/stacks/test_non_empty_stack.py
index 3be5bb6..4ead084 100644
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ b/tempest/api/orchestration/stacks/test_non_empty_stack.py
@@ -125,7 +125,7 @@
'resource_status_reason',
'resource_status', 'event_time')
- resource_statuses = map(lambda event: event['resource_status'], events)
+ resource_statuses = [event['resource_status'] for event in events]
self.assertIn('CREATE_IN_PROGRESS', resource_statuses)
self.assertIn('CREATE_COMPLETE', resource_statuses)
diff --git a/tempest/api/volume/admin/test_volumes_list.py b/tempest/api/volume/admin/test_volumes_list.py
index 64041b8..70c16f3 100644
--- a/tempest/api/volume/admin/test_volumes_list.py
+++ b/tempest/api/volume/admin/test_volumes_list.py
@@ -53,7 +53,7 @@
self.assertEqual(sorted(expected_list_ids), sorted(fetched_list_ids))
# Verifying tenant id of volumes fetched list is related to
# primary tenant
- fetched_tenant_id = map(operator.itemgetter(
- 'os-vol-tenant-attr:tenant_id'), fetched_list)
+ fetched_tenant_id = [operator.itemgetter(
+ 'os-vol-tenant-attr:tenant_id')(item) for item in fetched_list]
expected_tenant_id = [self.volumes_client.tenant_id] * 3
self.assertEqual(expected_tenant_id, fetched_tenant_id)
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index a93025d..f7176f4 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -33,8 +33,9 @@
def assertVolumesIn(self, fetched_list, expected_list, fields=None):
if fields:
- expected_list = map(operator.itemgetter(*fields), expected_list)
- fetched_list = map(operator.itemgetter(*fields), fetched_list)
+ fieldsgetter = operator.itemgetter(*fields)
+ expected_list = map(fieldsgetter, expected_list)
+ fetched_list = [fieldsgetter(item) for item in fetched_list]
missing_vols = [v for v in expected_list if v not in fetched_list]
if len(missing_vols) == 0:
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 8d2cfdc..426571f 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -67,11 +67,8 @@
CONF_PRIV_NETWORK_NAME = CONF.compute.fixed_network_name
CONF_PUB_NETWORK = CONF.network.public_network_id
CONF_PUB_ROUTER = CONF.network.public_router_id
- CONF_TENANTS = [CONF.auth.admin_project_name,
- CONF.identity.project_name,
- CONF.identity.alt_project_name]
- CONF_USERS = [CONF.auth.admin_username, CONF.identity.username,
- CONF.identity.alt_username]
+ CONF_TENANTS = [CONF.auth.admin_project_name]
+ CONF_USERS = [CONF.auth.admin_username]
if IS_NEUTRON:
CONF_PRIV_NETWORK = _get_network_id(CONF.compute.fixed_network_name,
diff --git a/tempest/cmd/subunit_describe_calls.py b/tempest/cmd/subunit_describe_calls.py
index da7f426..9391823 100644
--- a/tempest/cmd/subunit_describe_calls.py
+++ b/tempest/cmd/subunit_describe_calls.py
@@ -203,7 +203,7 @@
desc = "Outputs all HTTP calls a given test made that were logged."
super(ArgumentParser, self).__init__(description=desc)
- self.prog = "Argument Parser"
+ self.prog = "subunit-describe-calls"
self.add_argument(
"-s", "--subunit", metavar="<subunit file>", required=True,
diff --git a/tempest/common/utils/net_utils.py b/tempest/common/utils/net_utils.py
index d98fb32..fd0391d 100644
--- a/tempest/common/utils/net_utils.py
+++ b/tempest/common/utils/net_utils.py
@@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import itertools
import netaddr
from tempest.lib import exceptions as lib_exc
@@ -39,10 +38,11 @@
alloc_set.add(fixed_ip['ip_address'])
av_set = subnet_set - alloc_set
- ip_list = [str(ip) for ip in itertools.islice(av_set, count)]
-
- if len(ip_list) != count:
- msg = "Insufficient IP addresses available"
- raise lib_exc.BadRequest(message=msg)
-
- return ip_list
+ addrs = []
+ for cidr in reversed(av_set.iter_cidrs()):
+ for ip in reversed(cidr):
+ addrs.append(str(ip))
+ if len(addrs) == count:
+ return addrs
+ msg = "Insufficient IP addresses available"
+ raise lib_exc.BadRequest(message=msg)
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index f534f30..67faad5 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -70,7 +70,7 @@
# of get_network_from_name and preprov_creds to tempest.lib, and it should
# be migrated along with them
class InvalidTestResource(exceptions.TempestException):
- message = "%(name) is not a valid %(type), or the name is ambiguous"
+ message = "%(name)s is not a valid %(type)s, or the name is ambiguous"
class RFCViolation(exceptions.RestClientException):
diff --git a/tempest/lib/api_schema/response/compute/v2_16/__init__.py b/tempest/lib/api_schema/response/compute/v2_16/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_16/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_16/servers.py b/tempest/lib/api_schema/response/compute/v2_16/servers.py
new file mode 100644
index 0000000..6868110
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_16/servers.py
@@ -0,0 +1,160 @@
+# 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.
+import copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+from tempest.lib.api_schema.response.compute.v2_9 import servers
+
+# Compute microversion 2.16:
+# 1. New attributes in 'server' dict.
+# 'host_status'
+
+server_detail = {
+ 'type': 'object',
+ 'properties': {
+ 'id': {'type': 'string'},
+ 'name': {'type': 'string'},
+ 'status': {'type': 'string'},
+ 'image': {'oneOf': [
+ {'type': 'object',
+ 'properties': {
+ 'id': {'type': 'string'},
+ 'links': parameter_types.links
+ },
+ 'additionalProperties': False,
+ 'required': ['id', 'links']},
+ {'type': ['string', 'null']}
+ ]},
+ 'flavor': {
+ 'type': 'object',
+ 'properties': {
+ 'id': {'type': 'string'},
+ 'links': parameter_types.links
+ },
+ 'additionalProperties': False,
+ 'required': ['id', 'links']
+ },
+ 'fault': {
+ 'type': 'object',
+ 'properties': {
+ 'code': {'type': 'integer'},
+ 'created': {'type': 'string'},
+ 'message': {'type': 'string'},
+ 'details': {'type': 'string'},
+ },
+ 'additionalProperties': False,
+ # NOTE(gmann): 'details' is not necessary to be present
+ # in the 'fault'. So it is not defined as 'required'.
+ 'required': ['code', 'created', 'message']
+ },
+ 'user_id': {'type': 'string'},
+ 'tenant_id': {'type': 'string'},
+ 'created': {'type': 'string'},
+ 'updated': {'type': 'string'},
+ 'progress': {'type': 'integer'},
+ 'metadata': {'type': 'object'},
+ 'links': parameter_types.links,
+ 'addresses': parameter_types.addresses,
+ 'hostId': {'type': 'string'},
+ 'OS-DCF:diskConfig': {'type': 'string'},
+ 'accessIPv4': parameter_types.access_ip_v4,
+ 'accessIPv6': parameter_types.access_ip_v6,
+ 'key_name': {'type': ['string', 'null']},
+ 'security_groups': {'type': 'array'},
+ 'OS-SRV-USG:launched_at': {'type': ['string', 'null']},
+ 'OS-SRV-USG:terminated_at': {'type': ['string', 'null']},
+ 'OS-EXT-AZ:availability_zone': {'type': 'string'},
+ 'OS-EXT-STS:task_state': {'type': ['string', 'null']},
+ 'OS-EXT-STS:vm_state': {'type': 'string'},
+ 'OS-EXT-STS:power_state': {'type': 'integer'},
+ 'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']},
+ 'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
+ 'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']},
+ 'config_drive': {'type': 'string'},
+ 'os-extended-volumes:volumes_attached': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'id': {'type': 'string'},
+ 'delete_on_termination': {'type': 'boolean'}
+ },
+ 'additionalProperties': False,
+ },
+ },
+ 'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']},
+ 'OS-EXT-SRV-ATTR:launch_index': {'type': 'integer'},
+ 'OS-EXT-SRV-ATTR:kernel_id': {'type': ['string', 'null']},
+ 'OS-EXT-SRV-ATTR:ramdisk_id': {'type': ['string', 'null']},
+ 'OS-EXT-SRV-ATTR:hostname': {'type': 'string'},
+ 'OS-EXT-SRV-ATTR:root_device_name': {'type': ['string', 'null']},
+ 'OS-EXT-SRV-ATTR:user_data': {'type': ['string', 'null']},
+ 'locked': {'type': 'boolean'},
+ # NOTE(gmann): new attributes in version 2.16
+ 'host_status': {'type': 'string'}
+ },
+ 'additionalProperties': False,
+ # NOTE(gmann): 'progress' attribute is present in the response
+ # only when server's status is one of the progress statuses
+ # ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE")
+ # 'fault' attribute is present in the response
+ # only when server's status is one of the "ERROR", "DELETED".
+ # OS-DCF:diskConfig and accessIPv4/v6 are API
+ # extensions, and some environments return a response
+ # without these attributes.So these are not defined as 'required'.
+ 'required': ['id', 'name', 'status', 'image', 'flavor',
+ 'user_id', 'tenant_id', 'created', 'updated',
+ 'metadata', 'links', 'addresses', 'hostId']
+}
+
+server_detail['properties']['addresses']['patternProperties'][
+ '^[a-zA-Z0-9-_.]+$']['items']['properties'].update({
+ 'OS-EXT-IPS:type': {'type': 'string'},
+ 'OS-EXT-IPS-MAC:mac_addr': parameter_types.mac_address})
+# NOTE(gmann)dd: Update OS-EXT-IPS:type and OS-EXT-IPS-MAC:mac_addr
+# attributes in server address. Those are API extension,
+# and some environments return a response without
+# these attributes. So they are not 'required'.
+
+get_server = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'server': server_detail
+ },
+ 'additionalProperties': False,
+ 'required': ['server']
+ }
+}
+
+list_servers_detail = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'servers': {
+ 'type': 'array',
+ 'items': server_detail
+ },
+ 'servers_links': parameter_types.links
+ },
+ 'additionalProperties': False,
+ # NOTE(gmann): servers_links attribute is not necessary to be
+ # present always So it is not 'required'.
+ 'required': ['servers']
+ }
+}
+
+list_servers = copy.deepcopy(servers.list_servers)
diff --git a/tempest/lib/api_schema/response/compute/v2_19/servers.py b/tempest/lib/api_schema/response/compute/v2_19/servers.py
index 883839e..05cc32c 100644
--- a/tempest/lib/api_schema/response/compute/v2_19/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_19/servers.py
@@ -15,15 +15,18 @@
import copy
from tempest.lib.api_schema.response.compute.v2_1 import servers as serversv21
-from tempest.lib.api_schema.response.compute.v2_9 import servers as serversv29
+from tempest.lib.api_schema.response.compute.v2_16 import servers \
+ as serversv216
-get_server = copy.deepcopy(serversv29.get_server)
+list_servers = copy.deepcopy(serversv216.list_servers)
+
+get_server = copy.deepcopy(serversv216.get_server)
get_server['response_body']['properties']['server'][
'properties'].update({'description': {'type': ['string', 'null']}})
get_server['response_body']['properties']['server'][
'required'].append('description')
-list_servers_detail = copy.deepcopy(serversv29.list_servers_detail)
+list_servers_detail = copy.deepcopy(serversv216.list_servers_detail)
list_servers_detail['response_body']['properties']['servers']['items'][
'properties'].update({'description': {'type': ['string', 'null']}})
list_servers_detail['response_body']['properties']['servers']['items'][
diff --git a/tempest/lib/api_schema/response/compute/v2_23/__init__.py b/tempest/lib/api_schema/response/compute/v2_23/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_23/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_23/migrations.py b/tempest/lib/api_schema/response/compute/v2_23/migrations.py
new file mode 100644
index 0000000..3cd0f6e
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_23/migrations.py
@@ -0,0 +1,62 @@
+# 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.lib.api_schema.response.compute.v2_1 import parameter_types
+
+# Compute microversion 2.23:
+# New attributes in 'migrations' list.
+# 'migration_type'
+# 'links'
+
+list_migrations = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'migrations': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'id': {'type': 'integer'},
+ 'status': {'type': ['string', 'null']},
+ 'instance_uuid': {'type': ['string', 'null']},
+ 'source_node': {'type': ['string', 'null']},
+ 'source_compute': {'type': ['string', 'null']},
+ 'dest_node': {'type': ['string', 'null']},
+ 'dest_compute': {'type': ['string', 'null']},
+ 'dest_host': {'type': ['string', 'null']},
+ 'old_instance_type_id': {'type': ['integer', 'null']},
+ 'new_instance_type_id': {'type': ['integer', 'null']},
+ 'created_at': {'type': 'string'},
+ 'updated_at': {'type': ['string', 'null']},
+ # New attributes in version 2.23
+ 'migration_type': {'type': ['string', 'null']},
+ 'links': parameter_types.links
+ },
+ 'additionalProperties': False,
+ 'required': [
+ 'id', 'status', 'instance_uuid', 'source_node',
+ 'source_compute', 'dest_node', 'dest_compute',
+ 'dest_host', 'old_instance_type_id',
+ 'new_instance_type_id', 'created_at', 'updated_at',
+ 'migration_type'
+ ]
+ }
+ }
+ },
+ 'additionalProperties': False,
+ 'required': ['migrations']
+ }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_3/__init__.py b/tempest/lib/api_schema/response/compute/v2_3/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_3/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_3/servers.py b/tempest/lib/api_schema/response/compute/v2_3/servers.py
new file mode 100644
index 0000000..ee16333
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_3/servers.py
@@ -0,0 +1,166 @@
+# 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.
+import copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+from tempest.lib.api_schema.response.compute.v2_1 import servers
+
+# Compute microversion 2.3:
+# 1. New attributes in 'os-extended-volumes:volumes_attached' dict.
+# 'delete_on_termination'
+# 2. New attributes in 'server' dict.
+# 'OS-EXT-SRV-ATTR:reservation_id'
+# 'OS-EXT-SRV-ATTR:launch_index'
+# 'OS-EXT-SRV-ATTR:kernel_id'
+# 'OS-EXT-SRV-ATTR:ramdisk_id'
+# 'OS-EXT-SRV-ATTR:hostname'
+# 'OS-EXT-SRV-ATTR:root_device_name'
+# 'OS-EXT-SRV-ATTR:user_data'
+
+server_detail = {
+ 'type': 'object',
+ 'properties': {
+ 'id': {'type': 'string'},
+ 'name': {'type': 'string'},
+ 'status': {'type': 'string'},
+ 'image': {'oneOf': [
+ {'type': 'object',
+ 'properties': {
+ 'id': {'type': 'string'},
+ 'links': parameter_types.links
+ },
+ 'additionalProperties': False,
+ 'required': ['id', 'links']},
+ {'type': ['string', 'null']}
+ ]},
+ 'flavor': {
+ 'type': 'object',
+ 'properties': {
+ 'id': {'type': 'string'},
+ 'links': parameter_types.links
+ },
+ 'additionalProperties': False,
+ 'required': ['id', 'links']
+ },
+ 'fault': {
+ 'type': 'object',
+ 'properties': {
+ 'code': {'type': 'integer'},
+ 'created': {'type': 'string'},
+ 'message': {'type': 'string'},
+ 'details': {'type': 'string'},
+ },
+ 'additionalProperties': False,
+ # NOTE(gmann): 'details' is not necessary to be present
+ # in the 'fault'. So it is not defined as 'required'.
+ 'required': ['code', 'created', 'message']
+ },
+ 'user_id': {'type': 'string'},
+ 'tenant_id': {'type': 'string'},
+ 'created': {'type': 'string'},
+ 'updated': {'type': 'string'},
+ 'progress': {'type': 'integer'},
+ 'metadata': {'type': 'object'},
+ 'links': parameter_types.links,
+ 'addresses': parameter_types.addresses,
+ 'hostId': {'type': 'string'},
+ 'OS-DCF:diskConfig': {'type': 'string'},
+ 'accessIPv4': parameter_types.access_ip_v4,
+ 'accessIPv6': parameter_types.access_ip_v6,
+ 'key_name': {'type': ['string', 'null']},
+ 'security_groups': {'type': 'array'},
+ 'OS-SRV-USG:launched_at': {'type': ['string', 'null']},
+ 'OS-SRV-USG:terminated_at': {'type': ['string', 'null']},
+ 'OS-EXT-AZ:availability_zone': {'type': 'string'},
+ 'OS-EXT-STS:task_state': {'type': ['string', 'null']},
+ 'OS-EXT-STS:vm_state': {'type': 'string'},
+ 'OS-EXT-STS:power_state': {'type': 'integer'},
+ 'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']},
+ 'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
+ 'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']},
+ 'config_drive': {'type': 'string'},
+ # NOTE(gmann): new attributes in version 2.3
+ 'os-extended-volumes:volumes_attached': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'id': {'type': 'string'},
+ 'delete_on_termination': {'type': 'boolean'}
+ },
+ 'additionalProperties': False,
+ },
+ },
+ 'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']},
+ 'OS-EXT-SRV-ATTR:launch_index': {'type': 'integer'},
+ 'OS-EXT-SRV-ATTR:kernel_id': {'type': ['string', 'null']},
+ 'OS-EXT-SRV-ATTR:ramdisk_id': {'type': ['string', 'null']},
+ 'OS-EXT-SRV-ATTR:hostname': {'type': 'string'},
+ 'OS-EXT-SRV-ATTR:root_device_name': {'type': ['string', 'null']},
+ 'OS-EXT-SRV-ATTR:user_data': {'type': ['string', 'null']},
+ },
+ 'additionalProperties': False,
+ # NOTE(gmann): 'progress' attribute is present in the response
+ # only when server's status is one of the progress statuses
+ # ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE")
+ # 'fault' attribute is present in the response
+ # only when server's status is one of the "ERROR", "DELETED".
+ # OS-DCF:diskConfig and accessIPv4/v6 are API
+ # extensions, and some environments return a response
+ # without these attributes.So these are not defined as 'required'.
+ 'required': ['id', 'name', 'status', 'image', 'flavor',
+ 'user_id', 'tenant_id', 'created', 'updated',
+ 'metadata', 'links', 'addresses', 'hostId']
+}
+
+server_detail['properties']['addresses']['patternProperties'][
+ '^[a-zA-Z0-9-_.]+$']['items']['properties'].update({
+ 'OS-EXT-IPS:type': {'type': 'string'},
+ 'OS-EXT-IPS-MAC:mac_addr': parameter_types.mac_address})
+# NOTE(gmann)dd: Update OS-EXT-IPS:type and OS-EXT-IPS-MAC:mac_addr
+# attributes in server address. Those are API extension,
+# and some environments return a response without
+# these attributes. So they are not 'required'.
+
+get_server = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'server': server_detail
+ },
+ 'additionalProperties': False,
+ 'required': ['server']
+ }
+}
+
+list_servers_detail = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'servers': {
+ 'type': 'array',
+ 'items': server_detail
+ },
+ 'servers_links': parameter_types.links
+ },
+ 'additionalProperties': False,
+ # NOTE(gmann): servers_links attribute is not necessary to be
+ # present always So it is not 'required'.
+ 'required': ['servers']
+ }
+}
+
+list_servers = copy.deepcopy(servers.list_servers)
diff --git a/tempest/lib/api_schema/response/compute/v2_9/servers.py b/tempest/lib/api_schema/response/compute/v2_9/servers.py
index e9b7249..470190c 100644
--- a/tempest/lib/api_schema/response/compute/v2_9/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_9/servers.py
@@ -14,7 +14,9 @@
import copy
-from tempest.lib.api_schema.response.compute.v2_1 import servers
+from tempest.lib.api_schema.response.compute.v2_3 import servers
+
+list_servers = copy.deepcopy(servers.list_servers)
get_server = copy.deepcopy(servers.get_server)
get_server['response_body']['properties']['server'][
diff --git a/tempest/lib/common/utils/data_utils.py b/tempest/lib/common/utils/data_utils.py
index 7fcec8c..93382c0 100644
--- a/tempest/lib/common/utils/data_utils.py
+++ b/tempest/lib/common/utils/data_utils.py
@@ -47,8 +47,8 @@
:param str name: The name that you want to include
:param str prefix: The prefix that you want to include
:return: a random name. The format is
- '<prefix>-<random number>-<name>-<random number>'.
- (e.g. 'prefixfoo-1308607012-namebar-154876201')
+ '<prefix>-<name>-<random number>'.
+ (e.g. 'prefixfoo-namebar-154876201')
:rtype: string
"""
randbits = str(random.randint(1, 0x7fffffff))
diff --git a/tempest/lib/services/compute/migrations_client.py b/tempest/lib/services/compute/migrations_client.py
index 62246d3..c3bdba7 100644
--- a/tempest/lib/services/compute/migrations_client.py
+++ b/tempest/lib/services/compute/migrations_client.py
@@ -16,11 +16,16 @@
from six.moves.urllib import parse as urllib
from tempest.lib.api_schema.response.compute.v2_1 import migrations as schema
+from tempest.lib.api_schema.response.compute.v2_23 import migrations \
+ as schemav223
from tempest.lib.common import rest_client
from tempest.lib.services.compute import base_compute_client
class MigrationsClient(base_compute_client.BaseComputeClient):
+ schema_versions_info = [
+ {'min': None, 'max': '2.22', 'schema': schema},
+ {'min': '2.23', 'max': None, 'schema': schemav223}]
def list_migrations(self, **params):
"""List all migrations.
@@ -35,5 +40,6 @@
resp, body = self.get(url)
body = json.loads(body)
+ schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.list_migrations, resp, body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index 0d31ac7..9444e20 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -20,7 +20,9 @@
from six.moves.urllib import parse as urllib
from tempest.lib.api_schema.response.compute.v2_1 import servers as schema
+from tempest.lib.api_schema.response.compute.v2_16 import servers as schemav216
from tempest.lib.api_schema.response.compute.v2_19 import servers as schemav219
+from tempest.lib.api_schema.response.compute.v2_3 import servers as schemav23
from tempest.lib.api_schema.response.compute.v2_9 import servers as schemav29
from tempest.lib.common import rest_client
from tempest.lib.services.compute import base_compute_client
@@ -28,8 +30,10 @@
class ServersClient(base_compute_client.BaseComputeClient):
schema_versions_info = [
- {'min': None, 'max': '2.8', 'schema': schema},
- {'min': '2.9', 'max': '2.18', 'schema': schemav29},
+ {'min': None, 'max': '2.2', 'schema': schema},
+ {'min': '2.3', 'max': '2.8', 'schema': schemav23},
+ {'min': '2.9', 'max': '2.15', 'schema': schemav29},
+ {'min': '2.16', 'max': '2.18', 'schema': schemav216},
{'min': '2.19', 'max': None, 'schema': schemav219}]
def __init__(self, auth_provider, service, region,
diff --git a/tempest/lib/services/identity/v2/services_client.py b/tempest/lib/services/identity/v2/services_client.py
old mode 100644
new mode 100755
index 4a63d56..c26d419
--- a/tempest/lib/services/identity/v2/services_client.py
+++ b/tempest/lib/services/identity/v2/services_client.py
@@ -22,7 +22,11 @@
api_version = "v2.0"
def create_service(self, **kwargs):
- """Create a service."""
+ """Create a service.
+
+ Available params: see http://developer.openstack.org/api-ref/identity/
+ v2-ext/?expanded=#create-service-admin-extension
+ """
post_body = json.dumps({'OS-KSADM:service': kwargs})
resp, body = self.post('/OS-KSADM/services', post_body)
self.expected_success(200, resp.status)
@@ -38,7 +42,11 @@
return rest_client.ResponseBody(resp, body)
def list_services(self, **params):
- """List Service - Returns Services."""
+ """List Service - Returns Services.
+
+ Available params: see http://developer.openstack.org/api-ref/identity/
+ v2-ext/?expanded=#list-services-admin-extension
+ """
url = '/OS-KSADM/services'
if params:
url += '?%s' % urllib.urlencode(params)
diff --git a/tempest/services/identity/v3/json/endpoints_client.py b/tempest/lib/services/identity/v3/endpoints_client.py
similarity index 100%
rename from tempest/services/identity/v3/json/endpoints_client.py
rename to tempest/lib/services/identity/v3/endpoints_client.py
diff --git a/tempest/services/identity/v3/json/policies_client.py b/tempest/lib/services/identity/v3/policies_client.py
similarity index 100%
rename from tempest/services/identity/v3/json/policies_client.py
rename to tempest/lib/services/identity/v3/policies_client.py
diff --git a/tempest/lib/services/network/floating_ips_client.py b/tempest/lib/services/network/floating_ips_client.py
old mode 100644
new mode 100755
index 1968e05..f6cc0ff
--- a/tempest/lib/services/network/floating_ips_client.py
+++ b/tempest/lib/services/network/floating_ips_client.py
@@ -16,16 +16,34 @@
class FloatingIPsClient(base.BaseNetworkClient):
def create_floatingip(self, **kwargs):
+ """Creates a floating IP.
+
+ If you specify port information, associates the floating IP with an
+ internal port.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#createFloatingIp
+ """
uri = '/floatingips'
post_data = {'floatingip': kwargs}
return self.create_resource(uri, post_data)
def update_floatingip(self, floatingip_id, **kwargs):
+ """Updates a floating IP and its association with an internal port.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#updateFloatingIp
+ """
uri = '/floatingips/%s' % floatingip_id
post_data = {'floatingip': kwargs}
return self.update_resource(uri, post_data)
def show_floatingip(self, floatingip_id, **fields):
+ """Shows details for a floating IP.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#showFloatingIp
+ """
uri = '/floatingips/%s' % floatingip_id
return self.show_resource(uri, **fields)
@@ -34,5 +52,10 @@
return self.delete_resource(uri)
def list_floatingips(self, **filters):
+ """Lists floating IPs.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#listFloatingIps
+ """
uri = '/floatingips'
return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/networks_client.py b/tempest/lib/services/network/networks_client.py
index 19fa1db..7d75bf7 100755
--- a/tempest/lib/services/network/networks_client.py
+++ b/tempest/lib/services/network/networks_client.py
@@ -36,6 +36,11 @@
return self.update_resource(uri, post_data)
def show_network(self, network_id, **fields):
+ """Shows details for a network.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2.html#showNetwork
+ """
uri = '/networks/%s' % network_id
return self.show_resource(uri, **fields)
@@ -44,6 +49,11 @@
return self.delete_resource(uri)
def list_networks(self, **filters):
+ """Lists networks to which the tenant has access.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2.html#listNetworks
+ """
uri = '/networks'
return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/routers_client.py b/tempest/lib/services/network/routers_client.py
old mode 100644
new mode 100755
index 2ba1938..23e9c4e
--- a/tempest/lib/services/network/routers_client.py
+++ b/tempest/lib/services/network/routers_client.py
@@ -26,11 +26,21 @@
return self.create_resource(uri, post_body)
def update_router(self, router_id, **kwargs):
+ """Updates a logical router.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#updateRouter
+ """
uri = '/routers/%s' % router_id
update_body = {'router': kwargs}
return self.update_resource(uri, update_body)
def show_router(self, router_id, **fields):
+ """Shows details for a router.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#showRouter
+ """
uri = '/routers/%s' % router_id
return self.show_resource(uri, **fields)
@@ -39,6 +49,11 @@
return self.delete_resource(uri)
def list_routers(self, **filters):
+ """Lists logical routers.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#listRouters
+ """
uri = '/routers'
return self.list_resources(uri, **filters)
@@ -46,7 +61,8 @@
"""Add router interface.
Available params: see http://developer.openstack.org/
- api-ref-networking-v2-ext.html#addRouterInterface
+ api-ref-networking-v2-ext.html#
+ addRouterInterface
"""
uri = '/routers/%s/add_router_interface' % router_id
return self.update_resource(uri, kwargs)
@@ -55,7 +71,8 @@
"""Remove router interface.
Available params: see http://developer.openstack.org/
- api-ref-networking-v2-ext.html#deleteRouterInterface
+ api-ref-networking-v2-ext.html#
+ deleteRouterInterface
"""
uri = '/routers/%s/remove_router_interface' % router_id
return self.update_resource(uri, kwargs)
diff --git a/tempest/lib/services/network/security_group_rules_client.py b/tempest/lib/services/network/security_group_rules_client.py
old mode 100644
new mode 100755
index 944eba6..6cd01e1
--- a/tempest/lib/services/network/security_group_rules_client.py
+++ b/tempest/lib/services/network/security_group_rules_client.py
@@ -16,11 +16,22 @@
class SecurityGroupRulesClient(base.BaseNetworkClient):
def create_security_group_rule(self, **kwargs):
+ """Creates an OpenStack Networking security group rule.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#
+ createSecGroupRule
+ """
uri = '/security-group-rules'
post_data = {'security_group_rule': kwargs}
return self.create_resource(uri, post_data)
def show_security_group_rule(self, security_group_rule_id, **fields):
+ """Shows detailed information for a security group rule.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#showSecGroupRule
+ """
uri = '/security-group-rules/%s' % security_group_rule_id
return self.show_resource(uri, **fields)
@@ -29,5 +40,10 @@
return self.delete_resource(uri)
def list_security_group_rules(self, **filters):
+ """Lists a summary of all OpenStack Networking security group rules.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#listSecGroupRules
+ """
uri = '/security-group-rules'
return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/subnetpools_client.py b/tempest/lib/services/network/subnetpools_client.py
old mode 100644
new mode 100755
index 12349b1..f0a66a0
--- a/tempest/lib/services/network/subnetpools_client.py
+++ b/tempest/lib/services/network/subnetpools_client.py
@@ -18,19 +18,39 @@
class SubnetpoolsClient(base.BaseNetworkClient):
def list_subnetpools(self, **filters):
+ """Lists subnet pools to which the tenant has access.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#listSubnetPools
+ """
uri = '/subnetpools'
return self.list_resources(uri, **filters)
def create_subnetpool(self, **kwargs):
+ """Creates a subnet pool.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#createSubnetPool
+ """
uri = '/subnetpools'
post_data = {'subnetpool': kwargs}
return self.create_resource(uri, post_data)
def show_subnetpool(self, subnetpool_id, **fields):
+ """Shows information for a subnet pool.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#showSubnetPool
+ """
uri = '/subnetpools/%s' % subnetpool_id
return self.show_resource(uri, **fields)
def update_subnetpool(self, subnetpool_id, **kwargs):
+ """Updates a subnet pool.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2-ext.html#updateSubnetPool
+ """
uri = '/subnetpools/%s' % subnetpool_id
post_data = {'subnetpool': kwargs}
return self.update_resource(uri, post_data)
diff --git a/tempest/lib/services/network/subnets_client.py b/tempest/lib/services/network/subnets_client.py
index 9de4a33..0fde3ee 100755
--- a/tempest/lib/services/network/subnets_client.py
+++ b/tempest/lib/services/network/subnets_client.py
@@ -36,6 +36,11 @@
return self.update_resource(uri, post_data)
def show_subnet(self, subnet_id, **fields):
+ """Shows details for a subnet.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2.html#showSubnet
+ """
uri = '/subnets/%s' % subnet_id
return self.show_resource(uri, **fields)
@@ -44,6 +49,11 @@
return self.delete_resource(uri)
def list_subnets(self, **filters):
+ """Lists subnets to which the tenant has access.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-networking-v2.html#listSubnets
+ """
uri = '/subnets'
return self.list_resources(uri, **filters)
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index b58479d..60dca3d 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -16,8 +16,6 @@
import json
import re
-from oslo_log import log as logging
-
from tempest import config
from tempest import exceptions
from tempest.scenario import manager
@@ -25,8 +23,6 @@
CONF = config.CONF
-LOG = logging.getLogger(__name__)
-
class TestServerBasicOps(manager.ScenarioTest):
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index d6528a3..47c6e8d 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import testtools
-
from tempest import config
from tempest.scenario import manager
from tempest import test
@@ -33,9 +31,13 @@
"""
+ @classmethod
+ def skip_checks(cls):
+ super(TestSnapshotPattern, cls).skip_checks()
+ if not CONF.compute_feature_enabled.snapshot:
+ raise cls.skipException("Snapshotting is not available.")
+
@test.idempotent_id('608e604b-1d63-4a82-8e3e-91bc665c90b4')
- @testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
- 'Snapshotting is not available.')
@test.services('compute', 'network', 'image')
def test_snapshot_pattern(self):
# prepare for booting an instance
diff --git a/tempest/services/baremetal/v1/json/baremetal_client.py b/tempest/services/baremetal/v1/json/baremetal_client.py
old mode 100644
new mode 100755
index f24ef68..ede0d90
--- a/tempest/services/baremetal/v1/json/baremetal_client.py
+++ b/tempest/services/baremetal/v1/json/baremetal_client.py
@@ -20,7 +20,11 @@
@base.handle_errors
def list_nodes(self, **kwargs):
- """List all existing nodes."""
+ """List all existing nodes.
+
+ Available params: see http://developer.openstack.org/api-ref/
+ baremetal/index.html#list-nodes
+ """
return self._list_request('nodes', **kwargs)
@base.handle_errors
@@ -35,7 +39,11 @@
@base.handle_errors
def list_ports(self, **kwargs):
- """List all existing ports."""
+ """List all existing ports.
+
+ Available params: see http://developer.openstack.org/api-ref/
+ baremetal/index.html?expanded=#list-ports
+ """
return self._list_request('ports', **kwargs)
@base.handle_errors
@@ -50,7 +58,11 @@
@base.handle_errors
def list_ports_detail(self, **kwargs):
- """Details list all existing ports."""
+ """Details list all existing ports.
+
+ Available params: see http://developer.openstack.org/api-ref/baremetal/
+ index.html?expanded=#list-detailed-ports
+ """
return self._list_request('/ports/detail', **kwargs)
@base.handle_errors
diff --git a/tempest/services/identity/v3/__init__.py b/tempest/services/identity/v3/__init__.py
index 144c5a9..6ad8ef2 100644
--- a/tempest/services/identity/v3/__init__.py
+++ b/tempest/services/identity/v3/__init__.py
@@ -12,14 +12,14 @@
# License for the specific language governing permissions and limitations under
# the License.
+from tempest.lib.services.identity.v3.endpoints_client import EndPointsClient
+from tempest.lib.services.identity.v3.policies_client import PoliciesClient
from tempest.lib.services.identity.v3.token_client import V3TokenClient
from tempest.services.identity.v3.json.credentials_client import \
CredentialsClient
from tempest.services.identity.v3.json.domains_client import DomainsClient
-from tempest.services.identity.v3.json.endpoints_client import EndPointsClient
from tempest.services.identity.v3.json.groups_client import GroupsClient
from tempest.services.identity.v3.json.identity_client import IdentityClient
-from tempest.services.identity.v3.json.policies_client import PoliciesClient
from tempest.services.identity.v3.json.projects_client import ProjectsClient
from tempest.services.identity.v3.json.regions_client import RegionsClient
from tempest.services.identity.v3.json.roles_client import RolesClient
@@ -27,7 +27,7 @@
from tempest.services.identity.v3.json.trusts_client import TrustsClient
from tempest.services.identity.v3.json.users_clients import UsersClient
-__all__ = ['V3TokenClient', 'CredentialsClient', 'DomainsClient',
- 'EndPointsClient', 'GroupsClient', 'IdentityClient',
- 'PoliciesClient', 'ProjectsClient', 'RegionsClient', 'RolesClient',
+__all__ = ['EndPointsClient', 'PoliciesClient', 'V3TokenClient',
+ 'CredentialsClient', 'DomainsClient', 'GroupsClient',
+ 'IdentityClient', 'ProjectsClient', 'RegionsClient', 'RolesClient',
'ServicesClient', 'TrustsClient', 'UsersClient', ]
diff --git a/tempest/services/volume/base/admin/base_types_client.py b/tempest/services/volume/base/admin/base_types_client.py
old mode 100644
new mode 100755
index e4d9014..afca752
--- a/tempest/services/volume/base/admin/base_types_client.py
+++ b/tempest/services/volume/base/admin/base_types_client.py
@@ -48,7 +48,11 @@
return 'volume-type/encryption-type'
def list_volume_types(self, **params):
- """List all the volume_types created."""
+ """List all the volume_types created.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html#showVolumeTypes
+ """
url = 'types'
if params:
url += '?%s' % urllib.urlencode(params)
@@ -59,7 +63,11 @@
return rest_client.ResponseBody(resp, body)
def show_volume_type(self, volume_id):
- """Returns the details of a single volume_type."""
+ """Returns the details of a single volume_type.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html#showVolumeType
+ """
url = "types/%s" % str(volume_id)
resp, body = self.get(url)
body = json.loads(body)
@@ -79,7 +87,11 @@
return rest_client.ResponseBody(resp, body)
def delete_volume_type(self, volume_id):
- """Deletes the Specified Volume_type."""
+ """Deletes the Specified Volume_type.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html#deleteVolumeType
+ """
resp, body = self.delete("types/%s" % str(volume_id))
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
@@ -90,8 +102,6 @@
TODO: Current api-site doesn't contain this API description.
After fixing the api-site, we need to fix here also for putting
the link to api-site.
-
-
"""
url = 'types/%s/extra_specs' % str(vol_type_id)
if params:
@@ -139,6 +149,9 @@
extra_spec_name: Name of the extra spec to be updated.
extra_spec: A dictionary of with key as extra_spec_name and the
updated value.
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html#
+ updateVolumeTypeExtraSpecs
"""
url = "types/%s/extra_specs/%s" % (str(vol_type_id),
str(extra_spec_name))
@@ -207,7 +220,12 @@
return rest_client.ResponseBody(resp, body)
def list_type_access(self, volume_type_id):
- """Print access information about the given volume type."""
+ """Print access information about the given volume type.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html#
+ listVolumeTypeAccessExt
+ """
url = 'types/%s/os-volume-type-access' % (volume_type_id)
resp, body = self.get(url)
body = json.loads(body)
diff --git a/tempest/services/volume/base/base_snapshots_client.py b/tempest/services/volume/base/base_snapshots_client.py
old mode 100644
new mode 100755
index 6d3f03b..7a8e12b
--- a/tempest/services/volume/base/base_snapshots_client.py
+++ b/tempest/services/volume/base/base_snapshots_client.py
@@ -23,7 +23,11 @@
create_resp = 200
def list_snapshots(self, detail=False, **params):
- """List all the snapshot."""
+ """List all the snapshot.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html#listSnapshots
+ """
url = 'snapshots'
if detail:
url += '/detail'
@@ -36,7 +40,11 @@
return rest_client.ResponseBody(resp, body)
def show_snapshot(self, snapshot_id):
- """Returns the details of a single snapshot."""
+ """Returns the details of a single snapshot.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html#showSnapshot
+ """
url = "snapshots/%s" % str(snapshot_id)
resp, body = self.get(url)
body = json.loads(body)
@@ -68,7 +76,11 @@
return rest_client.ResponseBody(resp, body)
def delete_snapshot(self, snapshot_id):
- """Delete Snapshot."""
+ """Delete Snapshot.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html#deleteSnapshot
+ """
resp, body = self.delete("snapshots/%s" % str(snapshot_id))
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
@@ -115,7 +127,12 @@
return rest_client.ResponseBody(resp, body)
def show_snapshot_metadata(self, snapshot_id):
- """Get metadata of the snapshot."""
+ """Get metadata of the snapshot.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html#
+ showSnapshotMetadata
+ """
url = "snapshots/%s/metadata" % str(snapshot_id)
resp, body = self.get(url)
body = json.loads(body)
@@ -126,7 +143,8 @@
"""Update metadata for the snapshot.
Available params: see http://developer.openstack.org/
- api-ref-blockstorage-v2.html#updateSnapshotMetadata
+ api-ref-blockstorage-v2.html#
+ updateSnapshotMetadata
"""
put_body = json.dumps(kwargs)
url = "snapshots/%s/metadata" % str(snapshot_id)
diff --git a/tempest/tests/lib/services/identity/v3/test_endpoints_client.py b/tempest/tests/lib/services/identity/v3/test_endpoints_client.py
new file mode 100644
index 0000000..f8c553f
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_endpoints_client.py
@@ -0,0 +1,100 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from tempest.lib.services.identity.v3 import endpoints_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestEndpointsClient(base.BaseServiceTest):
+ FAKE_CREATE_ENDPOINT = {
+ "endpoint": {
+ "id": 1,
+ "tenantId": 1,
+ "region": "North",
+ "type": "compute",
+ "publicURL": "https://compute.north.public.com/v1",
+ "internalURL": "https://compute.north.internal.com/v1",
+ "adminURL": "https://compute.north.internal.com/v1"
+ }
+ }
+
+ FAKE_LIST_ENDPOINTS = {
+ "endpoints": [
+ {
+ "id": 1,
+ "tenantId": "1",
+ "region": "North",
+ "type": "compute",
+ "publicURL": "https://compute.north.public.com/v1",
+ "internalURL": "https://compute.north.internal.com/v1",
+ "adminURL": "https://compute.north.internal.com/v1"
+ },
+ {
+ "id": 2,
+ "tenantId": "1",
+ "region": "South",
+ "type": "compute",
+ "publicURL": "https://compute.north.public.com/v1",
+ "internalURL": "https://compute.north.internal.com/v1",
+ "adminURL": "https://compute.north.internal.com/v1"
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestEndpointsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = endpoints_client.EndPointsClient(fake_auth,
+ 'identity', 'regionOne')
+
+ def _test_create_endpoint(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_endpoint,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_ENDPOINT,
+ bytes_body,
+ status=201,
+ service_id="b344506af7644f6794d9cb316600b020",
+ region="region-demo",
+ publicurl="https://compute.north.public.com/v1",
+ adminurl="https://compute.north.internal.com/v1",
+ internalurl="https://compute.north.internal.com/v1")
+
+ def _test_list_endpoints(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_endpoints,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_ENDPOINTS,
+ bytes_body)
+
+ def test_create_endpoint_with_str_body(self):
+ self._test_create_endpoint()
+
+ def test_create_endpoint_with_bytes_body(self):
+ self._test_create_endpoint(bytes_body=True)
+
+ def test_list_endpoints_with_str_body(self):
+ self._test_list_endpoints()
+
+ def test_list_endpoints_with_bytes_body(self):
+ self._test_list_endpoints(bytes_body=True)
+
+ def test_delete_endpoint(self):
+ self.check_service_client_function(
+ self.client.delete_endpoint,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ endpoint_id="b344506af7644f6794d9cb316600b020",
+ status=204)
diff --git a/tempest/tests/lib/services/identity/v3/test_policies_client.py b/tempest/tests/lib/services/identity/v3/test_policies_client.py
new file mode 100644
index 0000000..66c3d65
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_policies_client.py
@@ -0,0 +1,152 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from tempest.lib.services.identity.v3 import policies_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestPoliciesClient(base.BaseServiceTest):
+ FAKE_CREATE_POLICY = {
+ "policy": {
+ "blob": "{'foobar_user': 'role:compute-user'}",
+ "project_id": "0426ac1e48f642ef9544c2251e07e261",
+ "type": "application/json",
+ "user_id": "0ffd248c55b443eaac5253b4e9cbf9b5"
+ }
+ }
+
+ FAKE_POLICY_INFO = {
+ "policy": {
+ "blob": {
+ "foobar_user": [
+ "role:compute-user"
+ ]
+ },
+ "id": "717273",
+ "links": {
+ "self": "http://example.com/identity/v3/policies/717273"
+ },
+ "project_id": "456789",
+ "type": "application/json",
+ "user_id": "616263"
+ }
+ }
+
+ FAKE_LIST_POLICIES = {
+ "links": {
+ "next": None,
+ "previous": None,
+ "self": "http://example.com/identity/v3/policies"
+ },
+ "policies": [
+ {
+ "blob": {
+ "foobar_user": [
+ "role:compute-user"
+ ]
+ },
+ "id": "717273",
+ "links": {
+ "self": "http://example.com/identity/v3/policies/717273"
+ },
+ "project_id": "456789",
+ "type": "application/json",
+ "user_id": "616263"
+ },
+ {
+ "blob": {
+ "foobar_user": [
+ "role:compute-user"
+ ]
+ },
+ "id": "717274",
+ "links": {
+ "self": "http://example.com/identity/v3/policies/717274"
+ },
+ "project_id": "456789",
+ "type": "application/json",
+ "user_id": "616263"
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestPoliciesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = policies_client.PoliciesClient(fake_auth,
+ 'identity', 'regionOne')
+
+ def _test_create_policy(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_policy,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_POLICY,
+ bytes_body,
+ status=201)
+
+ def _test_show_policy(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_policy,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_POLICY_INFO,
+ bytes_body,
+ policy_id="717273")
+
+ def _test_list_policies(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_policies,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_POLICIES,
+ bytes_body)
+
+ def _test_update_policy(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_policy,
+ 'tempest.lib.common.rest_client.RestClient.patch',
+ self.FAKE_POLICY_INFO,
+ bytes_body,
+ policy_id="717273")
+
+ def test_create_policy_with_str_body(self):
+ self._test_create_policy()
+
+ def test_create_policy_with_bytes_body(self):
+ self._test_create_policy(bytes_body=True)
+
+ def test_show_policy_with_str_body(self):
+ self._test_show_policy()
+
+ def test_show_policy_with_bytes_body(self):
+ self._test_show_policy(bytes_body=True)
+
+ def test_list_policies_with_str_body(self):
+ self._test_list_policies()
+
+ def test_list_policies_with_bytes_body(self):
+ self._test_list_policies(bytes_body=True)
+
+ def test_update_policy_with_str_body(self):
+ self._test_update_policy()
+
+ def test_update_policy_with_bytes_body(self):
+ self._test_update_policy(bytes_body=True)
+
+ def test_delete_policy(self):
+ self.check_service_client_function(
+ self.client.delete_policy,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ policy_id="717273",
+ status=204)