Merge "Security Group ICMP validation for icmp-code"
diff --git a/HACKING.rst b/HACKING.rst
index 83d67a9..7363e7f 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -8,7 +8,8 @@
Tempest Specific Commandments
------------------------------
-- [T102] Cannot import OpenStack python clients in tempest/api tests
+- [T102] Cannot import OpenStack python clients in tempest/api &
+ tempest/scenario tests
- [T104] Scenario tests require a services decorator
- [T105] Unit tests cannot use setUpClass
- [T106] vim configuration should not be kept in source files.
@@ -36,11 +37,11 @@
In most cases the very first issue is the most important information.
-Try to avoid using ``try`` blocks in the test cases, both the ``except``
-and ``finally`` block could replace the original exception,
+Try to avoid using ``try`` blocks in the test cases, as both the ``except``
+and ``finally`` blocks could replace the original exception,
when the additional operations leads to another exception.
-Just letting an exception to propagate, is not bad idea in a test case,
+Just letting an exception to propagate, is not a bad idea in a test case,
at all.
Try to avoid using any exception handling construct which can hide the errors
@@ -54,10 +55,10 @@
exceptions and still ensure resources are correctly cleaned up if the
test fails part way through.
-Use the ``self.assert*`` methods provided by the unit test framework
-the signal failures early.
+Use the ``self.assert*`` methods provided by the unit test framework.
+This signals the failures early on.
-Avoid using the ``self.fail`` alone, it's stack trace will signal
+Avoid using the ``self.fail`` alone, its stack trace will signal
the ``self.fail`` line as the origin of the error.
Avoid constructing complex boolean expressions for assertion.
@@ -69,7 +70,7 @@
Most other assert method can include more information by default.
For example ``self.assertIn`` can include the whole set.
-Recommended to use testtools matcher for more tricky assertion.
+It is recommended to use testtools matcher for the more tricky assertions.
`[doc] <http://testtools.readthedocs.org/en/latest/for-test-authors.html#matchers>`_
You can implement your own specific matcher as well.
@@ -77,8 +78,8 @@
If the test case fails you can see the related logs and the information
carried by the exception (exception class, backtrack and exception info).
-This and the service logs are your only guide to find the root cause of flaky
-issue.
+This and the service logs are your only guide to finding the root cause of flaky
+issues.
Test cases are independent
--------------------------
@@ -87,7 +88,7 @@
Test cases MAY depend on commonly initialized resources/facilities, like
credentials management, testresources and so on. These facilities, MUST be able
-to work even if just one ``test_method`` selected for execution.
+to work even if just one ``test_method`` is selected for execution.
Service Tagging
---------------
@@ -110,9 +111,9 @@
Negative Tests
--------------
Newly added negative tests should use the negative test framework. First step
-is to create an interface description in a json file under `etc/schemas`.
-These descriptions consists of two important sections for the test
-(one of those is mandatory):
+is to create an interface description in a python file under
+`tempest/api_schema/request/`. These descriptions consists of two important
+sections for the test (one of those is mandatory):
- A resource (part of the URL of the request): Resources needed for a test
must be created in `setUpClass` and registered with `set_resource` e.g.:
@@ -125,21 +126,17 @@
load_tests = test.NegativeAutoTest.load_tests
- class SampeTestNegativeTestJSON(<your base class>, test.NegativeAutoTest):
- _interface = 'json'
+ @test.SimpleNegativeAutoTest
+ class SampleTestNegativeTestJSON(<your base class>, test.NegativeAutoTest):
_service = 'compute'
- _schema_file = <your Schema file>
+ _schema = <your schema file>
-Negative tests must be marked with a negative attribute::
-
- @test.attr(type=['negative', 'gate'])
- def test_get_console_output(self):
- self.execute(self._schema_file)
+The class decorator `SimpleNegativeAutoTest` will automatically generate test
+cases out of the given schema in the attribute `_schema`.
All negative tests should be added into a separate negative test file.
If such a file doesn't exist for the particular resource being tested a new
-test file should be added. Old XML based negative tests can be kept but should
-be renamed to `_xml.py`.
+test file should be added.
Test skips because of Known Bugs
--------------------------------
@@ -213,8 +210,10 @@
Sample Configuration File
-------------------------
The sample config file is autogenerated using a script. If any changes are made
-to the config variables in tempest then the sample config file must be
-regenerated. This can be done running the script: tools/generate_sample.sh
+to the config variables in tempest/config.py then the sample config file must be
+regenerated. This can be done running::
+
+ tox -egenconfig
Unit Tests
----------
@@ -260,15 +259,15 @@
example of this would be::
class TestVolumeBootPattern(manager.ScenarioTest):
- """
- This test case attempts to reproduce the following steps:
+ """
+ This test case attempts to reproduce the following steps:
- * Create in Cinder some bootable volume importing a Glance image
- * Boot an instance from the bootable volume
- * Write content to the volume
- * Delete an instance and Boot a new instance from the volume
- * Check written content in the instance
- * Create a volume snapshot while the instance is running
- * Boot an additional instance from the new snapshot based volume
- * Check written content in the instance booted from snapshot
- """
+ * Create in Cinder some bootable volume importing a Glance image
+ * Boot an instance from the bootable volume
+ * Write content to the volume
+ * Delete an instance and Boot a new instance from the volume
+ * Check written content in the instance
+ * Create a volume snapshot while the instance is running
+ * Boot an additional instance from the new snapshot based volume
+ * Check written content in the instance booted from snapshot
+ """
diff --git a/README.rst b/README.rst
index ea36619..5284bbf 100644
--- a/README.rst
+++ b/README.rst
@@ -79,8 +79,10 @@
document. The etc/tempest.conf.sample attempts to be a self
documenting version of the configuration.
-The sample config file is auto generated using the script:
-tools/generate_sample.sh
+To generate the sample tempest.conf file, run the following
+command from the top level of the tempest directory:
+
+ tox -egenconfig
The most important pieces that are needed are the user ids, openstack
endpoints, and basic flavors and images needed to run tests.
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 1cccacc..b70b446 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -78,7 +78,7 @@
#
# List of logger=LEVEL pairs. (list value)
-#default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN
+#default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN
# Enables or disables fatal status of deprecations. (boolean value)
#fatal_deprecations = false
@@ -260,7 +260,8 @@
# The endpoint type to use for the compute service. (string value)
#endpoint_type = publicURL
-# Visible fixed network name (string value)
+# Name of the fixed network that is visible to all test tenants.
+# (string value)
#fixed_network_name = private
# Valid primary flavor to use in tests. (string value)
@@ -270,7 +271,8 @@
#flavor_ref_alt = 2
# Unallocated floating IP range, which will be used to test the
-# floating IP bulk feature for CRUD operation. (string value)
+# floating IP bulk feature for CRUD operation. This block must not
+# overlap an existing floating IP pool. (string value)
#floating_ip_range = 10.0.0.0/29
# Password used to authenticate to an instance using the alternate
@@ -299,7 +301,8 @@
# IP version used for SSH connections. (integer value)
#ip_version_for_ssh = 4
-# Network used for SSH connections. (string value)
+# Network used for SSH connections. Ignored if
+# use_floatingip_for_ssh=true or run_ssh=false. (string value)
#network_for_ssh = public
# Path to a private key file for SSH access to remote hosts (string
@@ -429,7 +432,7 @@
# Does the test environment support live migration available? (boolean
# value)
-#live_migration = false
+#live_migration = true
# Does the test environment support pausing? (boolean value)
#pause = true
@@ -464,9 +467,6 @@
# [nova.vnc]->vnc_enabled in nova.conf (boolean value)
#vnc_console = false
-# If false skip all v2 api tests with xml (boolean value)
-#xml_api_v2 = true
-
[dashboard]
@@ -758,8 +758,10 @@
# value)
#public_network_id =
-# Id of the public router that provides external connectivity (string
-# value)
+# Id of the public router that provides external connectivity. This
+# should only be used when Neutron's 'allow_overlapping_ips' is set to
+# 'False' in neutron.conf. usually not needed past 'Grizzly' release
+# (string value)
#public_router_id =
# The network region name to use. If empty, the value of
diff --git a/requirements.txt b/requirements.txt
index 708ede3..ce5886e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,25 +5,24 @@
anyjson>=0.3.3
httplib2>=0.7.5
jsonschema>=2.0.0,<3.0.0
-testtools>=0.9.34
-lxml>=2.3
+testtools>=0.9.36,!=1.2.0
boto>=2.32.1
paramiko>=1.13.0
netaddr>=0.7.12
python-ceilometerclient>=1.0.6
python-glanceclient>=0.14.0
-python-keystoneclient>=0.10.0
+python-keystoneclient>=0.11.1
python-novaclient>=2.18.0
python-neutronclient>=2.3.6,<3
python-cinderclient>=1.1.0
python-heatclient>=0.2.9
python-ironicclient>=0.2.1
-python-saharaclient>=0.7.3
+python-saharaclient>=0.7.5
python-swiftclient>=2.2.0
-testresources>=0.2.4
testrepository>=0.0.18
oslo.config>=1.4.0 # Apache-2.0
six>=1.7.0
iso8601>=0.1.9
fixtures>=0.3.14
testscenarios>=0.4
+tempest-lib
diff --git a/setup.cfg b/setup.cfg
index d010ccc..90ea944 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = tempest
-version = 2
+version = 3
summary = OpenStack Integration Testing
description-file =
README.rst
diff --git a/tempest/README.rst b/tempest/README.rst
index fb25151..d28c3f9 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -55,7 +55,8 @@
functionality. They are typically a series of steps where complicated
state requiring multiple services is set up exercised, and torn down.
-Scenario tests can and should use the OpenStack python clients.
+Scenario tests should not use the existing python clients for OpenStack,
+but should instead use the tempest implementations of clients.
:ref:`stress_field_guide`
diff --git a/tempest/api/baremetal/admin/test_nodes.py b/tempest/api/baremetal/admin/test_nodes.py
index 8ccd36b..41c12c6 100644
--- a/tempest/api/baremetal/admin/test_nodes.py
+++ b/tempest/api/baremetal/admin/test_nodes.py
@@ -130,9 +130,7 @@
@test.attr(type='smoke')
def test_set_node_boot_device(self):
- body = self.client.set_node_boot_device(self.node['uuid'], 'pxe')
- # No content
- self.assertEqual('', body)
+ self.client.set_node_boot_device(self.node['uuid'], 'pxe')
@test.attr(type='smoke')
def test_get_node_boot_device(self):
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index f33089c..7c2e604 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -221,9 +221,3 @@
wait_until='ACTIVE')
resp, body = admin_servers_client.get_server(server['id'])
self.assertEqual(self.host, body[self._host_key])
-
-
-class AggregatesAdminTestXML(AggregatesAdminTestJSON):
- _host_key = (
- '{http://docs.openstack.org/compute/ext/extended_status/api/v1.1}host')
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
index ef6752b..219d12e 100644
--- a/tempest/api/compute/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -186,7 +186,3 @@
self.assertRaises(exceptions.NotFound, self.client.remove_host,
aggregate['id'], non_exist_host)
-
-
-class AggregatesAdminNegativeTestXML(AggregatesAdminNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index 0a040d7..068a710 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -46,7 +46,3 @@
class AZAdminV2TestJSON(AZAdminV3Test):
_api_version = 2
-
-
-class AZAdminV2TestXML(AZAdminV2TestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_availability_zone_negative.py b/tempest/api/compute/admin/test_availability_zone_negative.py
index ea157b3..d062b0c 100644
--- a/tempest/api/compute/admin/test_availability_zone_negative.py
+++ b/tempest/api/compute/admin/test_availability_zone_negative.py
@@ -35,7 +35,3 @@
self.assertRaises(
exceptions.Unauthorized,
self.non_adm_client.get_availability_zone_list_detail)
-
-
-class AZAdminNegativeTestXML(AZAdminNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index e7f269d..d1d13a0 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -58,7 +58,3 @@
body = {"unreserve": "None"}
resp, body = self.client.reserve_fixed_ip(self.ip, body)
self.assertEqual(resp.status, 202)
-
-
-class FixedIPsTestXml(FixedIPsTestJson):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py
index 8d6a7fc..e7022db 100644
--- a/tempest/api/compute/admin/test_fixed_ips_negative.py
+++ b/tempest/api/compute/admin/test_fixed_ips_negative.py
@@ -82,7 +82,3 @@
self.assertRaises(exceptions.BadRequest,
self.client.reserve_fixed_ip,
self.ip, body)
-
-
-class FixedIPsNegativeTestXml(FixedIPsNegativeTestJson):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index d365f3a..1953040 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -296,7 +296,7 @@
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
new_flavor_id = data_utils.rand_int_id(start=1000)
- ram = " 1024 "
+ ram = "1024"
resp, flavor = self.client.create_flavor(flavor_name,
ram, self.vcpus,
self.disk,
@@ -308,7 +308,3 @@
self.assertEqual(flavor['disk'], self.disk)
self.assertEqual(flavor['ram'], int(ram))
self.assertEqual(int(flavor['id']), new_flavor_id)
-
-
-class FlavorsAdminTestXML(FlavorsAdminTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index 176a134..19707d0 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -96,7 +96,3 @@
resp, flavors = self.flavors_client.list_flavors_with_detail()
self.assertEqual(resp.status, 200)
self.assertNotIn(new_flavor['id'], map(lambda x: x['id'], flavors))
-
-
-class FlavorsAdminTestXML(FlavorsAccessTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_flavors_access_negative.py b/tempest/api/compute/admin/test_flavors_access_negative.py
index 9cc2a92..c49652d 100644
--- a/tempest/api/compute/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/admin/test_flavors_access_negative.py
@@ -135,7 +135,3 @@
self.client.remove_flavor_access,
new_flavor['id'],
str(uuid.uuid4()))
-
-
-class FlavorsAdminNegativeTestXML(FlavorsAccessNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index c05abe2..5157d2e 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -121,7 +121,3 @@
self.assertEqual(resp.status, 200)
self.assertEqual(body['key1'], 'value1')
self.assertNotIn('key2', body)
-
-
-class FlavorsExtraSpecsTestXML(FlavorsExtraSpecsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
index 30adf73..20860c8 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
@@ -125,7 +125,3 @@
"key1",
key1="value",
key2="value")
-
-
-class FlavorsExtraSpecsNegativeTestXML(FlavorsExtraSpecsNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_flavors_negative.py b/tempest/api/compute/admin/test_flavors_negative.py
index 3389aee..fb27360 100644
--- a/tempest/api/compute/admin/test_flavors_negative.py
+++ b/tempest/api/compute/admin/test_flavors_negative.py
@@ -18,9 +18,13 @@
from tempest.api.compute import base
from tempest.api_schema.request.compute.v2 import flavors
from tempest.common.utils import data_utils
+from tempest import config
from tempest import exceptions
from tempest import test
+
+CONF = config.CONF
+
load_tests = test.NegativeAutoTest.load_tests
@@ -58,7 +62,7 @@
resp, flavor = self.client.create_flavor(flavor_name,
self.ram,
self.vcpus, self.disk,
- '',
+ None,
ephemeral=self.ephemeral,
swap=self.swap,
rxtx=self.rxtx)
@@ -106,5 +110,5 @@
class FlavorCreateNegativeTestJSON(base.BaseV2ComputeAdminTest,
test.NegativeAutoTest):
_interface = 'json'
- _service = 'compute'
+ _service = CONF.compute.catalog_type
_schema = flavors.flavor_create
diff --git a/tempest/api/compute/admin/test_flavors_negative_xml.py b/tempest/api/compute/admin/test_flavors_negative_xml.py
deleted file mode 100644
index a06b0e6..0000000
--- a/tempest/api/compute/admin/test_flavors_negative_xml.py
+++ /dev/null
@@ -1,268 +0,0 @@
-# Copyright 2012 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 uuid
-
-from tempest.api.compute.admin import test_flavors_negative
-from tempest.common.utils import data_utils
-from tempest import exceptions
-from tempest import test
-
-
-class FlavorsAdminNegativeTestXML(test_flavors_negative.
- FlavorsAdminNegativeTestJSON):
-
- """
- Tests Flavors API Create and Delete that require admin privileges
- """
-
- _interface = 'xml'
-
- def flavor_clean_up(self, flavor_id):
- resp, body = self.client.delete_flavor(flavor_id)
- self.assertEqual(resp.status, 202)
- self.client.wait_for_resource_deletion(flavor_id)
-
- @test.attr(type=['negative', 'gate'])
- def test_invalid_is_public_string(self):
- # the 'is_public' parameter can be 'none/true/false' if it exists
- self.assertRaises(exceptions.BadRequest,
- self.client.list_flavors_with_detail,
- {'is_public': 'invalid'})
-
- @test.attr(type=['negative', 'gate'])
- def test_create_flavor_using_invalid_ram(self):
- # the 'ram' attribute must be positive integer
- flavor_name = data_utils.rand_name(self.flavor_name_prefix)
- new_flavor_id = str(uuid.uuid4())
-
- self.assertRaises(exceptions.BadRequest,
- self.client.create_flavor,
- flavor_name, -1, self.vcpus,
- self.disk, new_flavor_id)
-
- @test.attr(type=['negative', 'gate'])
- def test_create_flavor_using_invalid_vcpus(self):
- # the 'vcpu' attribute must be positive integer
- flavor_name = data_utils.rand_name(self.flavor_name_prefix)
- new_flavor_id = str(uuid.uuid4())
-
- self.assertRaises(exceptions.BadRequest,
- self.client.create_flavor,
- flavor_name, self.ram, -1,
- self.disk, new_flavor_id)
-
- @test.attr(type=['negative', 'gate'])
- def test_create_flavor_with_name_length_less_than_1(self):
- # ensure name length >= 1
- new_flavor_id = str(uuid.uuid4())
-
- self.assertRaises(exceptions.BadRequest,
- self.client.create_flavor,
- '',
- self.ram, self.vcpus,
- self.disk,
- new_flavor_id,
- ephemeral=self.ephemeral,
- swap=self.swap,
- rxtx=self.rxtx,
- is_public='False')
-
- @test.attr(type=['negative', 'gate'])
- def test_create_flavor_with_name_length_exceeds_255(self):
- # ensure name do not exceed 255 characters
- new_flavor_name = 'a' * 256
- new_flavor_id = str(uuid.uuid4())
-
- self.assertRaises(exceptions.BadRequest,
- self.client.create_flavor,
- new_flavor_name,
- self.ram, self.vcpus,
- self.disk,
- new_flavor_id,
- ephemeral=self.ephemeral,
- swap=self.swap,
- rxtx=self.rxtx,
- is_public='False')
-
- @test.attr(type=['negative', 'gate'])
- def test_create_flavor_with_invalid_name(self):
- # the regex of flavor_name is '^[\w\.\- ]*$'
- invalid_flavor_name = data_utils.rand_name('invalid-!@#$%-')
- new_flavor_id = str(uuid.uuid4())
-
- self.assertRaises(exceptions.BadRequest,
- self.client.create_flavor,
- invalid_flavor_name,
- self.ram, self.vcpus,
- self.disk,
- new_flavor_id,
- ephemeral=self.ephemeral,
- swap=self.swap,
- rxtx=self.rxtx,
- is_public='False')
-
- @test.attr(type=['negative', 'gate'])
- def test_create_flavor_with_invalid_flavor_id(self):
- # the regex of flavor_id is '^[\w\.\- ]*$', and it cannot contain
- # leading and/or trailing whitespace
- new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
- invalid_flavor_id = '!@#$%'
-
- self.assertRaises(exceptions.BadRequest,
- self.client.create_flavor,
- new_flavor_name,
- self.ram, self.vcpus,
- self.disk,
- invalid_flavor_id,
- ephemeral=self.ephemeral,
- swap=self.swap,
- rxtx=self.rxtx,
- is_public='False')
-
- @test.attr(type=['negative', 'gate'])
- def test_create_flavor_with_id_length_exceeds_255(self):
- # the length of flavor_id should not exceed 255 characters
- new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
- invalid_flavor_id = 'a' * 256
-
- self.assertRaises(exceptions.BadRequest,
- self.client.create_flavor,
- new_flavor_name,
- self.ram, self.vcpus,
- self.disk,
- invalid_flavor_id,
- ephemeral=self.ephemeral,
- swap=self.swap,
- rxtx=self.rxtx,
- is_public='False')
-
- @test.attr(type=['negative', 'gate'])
- def test_create_flavor_with_invalid_root_gb(self):
- # root_gb attribute should be non-negative ( >= 0) integer
- new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
- new_flavor_id = str(uuid.uuid4())
-
- self.assertRaises(exceptions.BadRequest,
- self.client.create_flavor,
- new_flavor_name,
- self.ram, self.vcpus,
- -1,
- new_flavor_id,
- ephemeral=self.ephemeral,
- swap=self.swap,
- rxtx=self.rxtx,
- is_public='False')
-
- @test.attr(type=['negative', 'gate'])
- def test_create_flavor_with_invalid_ephemeral_gb(self):
- # ephemeral_gb attribute should be non-negative ( >= 0) integer
- new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
- new_flavor_id = str(uuid.uuid4())
-
- self.assertRaises(exceptions.BadRequest,
- self.client.create_flavor,
- new_flavor_name,
- self.ram, self.vcpus,
- self.disk,
- new_flavor_id,
- ephemeral=-1,
- swap=self.swap,
- rxtx=self.rxtx,
- is_public='False')
-
- @test.attr(type=['negative', 'gate'])
- def test_create_flavor_with_invalid_swap(self):
- # swap attribute should be non-negative ( >= 0) integer
- new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
- new_flavor_id = str(uuid.uuid4())
-
- self.assertRaises(exceptions.BadRequest,
- self.client.create_flavor,
- new_flavor_name,
- self.ram, self.vcpus,
- self.disk,
- new_flavor_id,
- ephemeral=self.ephemeral,
- swap=-1,
- rxtx=self.rxtx,
- is_public='False')
-
- @test.attr(type=['negative', 'gate'])
- def test_create_flavor_with_invalid_rxtx_factor(self):
- # rxtx_factor attribute should be a positive float
- new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
- new_flavor_id = str(uuid.uuid4())
-
- self.assertRaises(exceptions.BadRequest,
- self.client.create_flavor,
- new_flavor_name,
- self.ram, self.vcpus,
- self.disk,
- new_flavor_id,
- ephemeral=self.ephemeral,
- swap=self.swap,
- rxtx=-1.5,
- is_public='False')
-
- @test.attr(type=['negative', 'gate'])
- def test_create_flavor_with_invalid_is_public(self):
- # is_public attribute should be boolean
- new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
- new_flavor_id = str(uuid.uuid4())
-
- self.assertRaises(exceptions.BadRequest,
- self.client.create_flavor,
- new_flavor_name,
- self.ram, self.vcpus,
- self.disk,
- new_flavor_id,
- ephemeral=self.ephemeral,
- swap=self.swap,
- rxtx=self.rxtx,
- is_public='Invalid')
-
- @test.attr(type=['negative', 'gate'])
- def test_create_flavor_already_exists(self):
- flavor_name = data_utils.rand_name(self.flavor_name_prefix)
- new_flavor_id = str(uuid.uuid4())
-
- resp, flavor = self.client.create_flavor(flavor_name,
- self.ram, self.vcpus,
- self.disk,
- new_flavor_id,
- ephemeral=self.ephemeral,
- swap=self.swap,
- rxtx=self.rxtx)
- self.assertEqual(200, resp.status)
- self.addCleanup(self.flavor_clean_up, flavor['id'])
-
- self.assertRaises(exceptions.Conflict,
- self.client.create_flavor,
- flavor_name,
- self.ram, self.vcpus,
- self.disk,
- new_flavor_id,
- ephemeral=self.ephemeral,
- swap=self.swap,
- rxtx=self.rxtx)
-
- @test.attr(type=['negative', 'gate'])
- def test_delete_nonexistent_flavor(self):
- nonexistent_flavor_id = str(uuid.uuid4())
-
- self.assertRaises(exceptions.NotFound,
- self.client.delete_flavor,
- nonexistent_flavor_id)
diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py
index bcae492..25965fd 100644
--- a/tempest/api/compute/admin/test_hosts.py
+++ b/tempest/api/compute/admin/test_hosts.py
@@ -84,7 +84,3 @@
self.assertIsNotNone(host_resource['memory_mb'])
self.assertIsNotNone(host_resource['project'])
self.assertEqual(hostname, host_resource['host'])
-
-
-class HostsAdminTestXML(HostsAdminTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py
index 4111aba..055219f 100644
--- a/tempest/api/compute/admin/test_hosts_negative.py
+++ b/tempest/api/compute/admin/test_hosts_negative.py
@@ -66,7 +66,6 @@
status='enable',
maintenance_mode='enable')
- @test.skip_because(bug="1261964", interface="xml")
@test.attr(type=['negative', 'gate'])
def test_update_host_with_extra_param(self):
# only 'status' and 'maintenance_mode' are the valid params.
@@ -167,7 +166,3 @@
self.assertRaises(exceptions.Unauthorized,
self.non_admin_client.reboot_host,
hostname)
-
-
-class HostsAdminNegativeTestXML(HostsAdminNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index c51d0a5..de3debb 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -128,7 +128,3 @@
hypers[0]['hypervisor_hostname'])
self.assertEqual(200, resp.status)
self.assertHypervisors(hypers)
-
-
-class HypervisorAdminTestXML(HypervisorAdminTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index d3804e8..b1f2351 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -134,7 +134,3 @@
exceptions.Unauthorized,
self.non_adm_client.search_hypervisor,
hypers[0]['hypervisor_hostname'])
-
-
-class HypervisorAdminNegativeTestXML(HypervisorAdminNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log.py b/tempest/api/compute/admin/test_instance_usage_audit_log.py
index 91f0b02..f7b5e43 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log.py
@@ -54,7 +54,3 @@
'period_beginning', 'num_hosts_not_run']
for item in expected_items:
self.assertIn(item, body)
-
-
-class InstanceUsageAuditLogTestXML(InstanceUsageAuditLogTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
index 1af340d..c4905d9 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
@@ -45,8 +45,3 @@
self.assertRaises(exceptions.BadRequest,
self.adm_client.get_instance_usage_audit_log,
"invalid_time")
-
-
-class InstanceUsageAuditLogNegativeTestXML(
- InstanceUsageAuditLogNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 701e1c2..7c666a2 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -152,10 +152,6 @@
self.assertEqual(ram_default, quota_set_new['ram'])
-class QuotasAdminTestXML(QuotasAdminTestJSON):
- _interface = 'xml'
-
-
class QuotaClassesAdminTestJSON(base.BaseV2ComputeAdminTest):
"""Tests the os-quota-class-sets API to update default quotas.
"""
@@ -202,7 +198,3 @@
LOG.debug("assert that the response has all of the changed values")
self.assertThat(update_body.items(),
matchers.ContainsAll(body.items()))
-
-
-class QuotaClassesAdminTestXML(QuotaClassesAdminTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py
index a9ed7ce..532f195 100644
--- a/tempest/api/compute/admin/test_quotas_negative.py
+++ b/tempest/api/compute/admin/test_quotas_negative.py
@@ -156,7 +156,3 @@
self.assertRaises((exceptions.OverLimit, exceptions.Unauthorized),
self.sg_client.create_security_group_rule,
secgroup_id, ip_protocol, 1025, 1025)
-
-
-class QuotasAdminNegativeTestXML(QuotasAdminNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_security_groups.py b/tempest/api/compute/admin/test_security_groups.py
index 40ae236..b4615f2 100644
--- a/tempest/api/compute/admin/test_security_groups.py
+++ b/tempest/api/compute/admin/test_security_groups.py
@@ -90,7 +90,3 @@
self.assertEqual(sec_group['tenant_id'], client_tenant_id,
"Failed to get all security groups for "
"non admin user.")
-
-
-class SecurityGroupsTestAdminXML(SecurityGroupsTestAdminJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 47aaee3..e3477f1 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -182,9 +182,3 @@
resp, server = self.create_test_server(sched_hints=hints,
wait_until='ACTIVE')
self.assertEqual('202', resp['status'])
-
-
-class ServersAdminTestXML(ServersAdminTestJSON):
- _host_key = (
- '{http://docs.openstack.org/compute/ext/extended_status/api/v1.1}host')
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index 9aa489c..2f0af72 100644
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -148,7 +148,3 @@
self.assertRaises(exceptions.Conflict,
self.client.migrate_server,
server_id)
-
-
-class ServersAdminNegativeTestXML(ServersAdminNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index 76153e7..e7a39f8 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -76,7 +76,3 @@
self.assertEqual(1, len(services))
self.assertEqual(host_name, services[0]['host'])
self.assertEqual(binary_name, services[0]['binary'])
-
-
-class ServicesAdminTestXML(ServicesAdminTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py
index 5331097..534afc5 100644
--- a/tempest/api/compute/admin/test_services_negative.py
+++ b/tempest/api/compute/admin/test_services_negative.py
@@ -60,7 +60,3 @@
resp, services = self.client.list_services(params)
self.assertEqual(200, resp.status)
self.assertEqual(0, len(services))
-
-
-class ServicesAdminNegativeTestXML(ServicesAdminNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage.py b/tempest/api/compute/admin/test_simple_tenant_usage.py
index 5d596ba..f6553b3 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage.py
@@ -73,7 +73,3 @@
self.assertEqual(200, resp.status)
self.assertEqual(len(tenant_usage), 8)
-
-
-class TenantUsagesTestXML(TenantUsagesTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
index 5e2c593..8c31d7c 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
@@ -63,7 +63,3 @@
'detailed': int(bool(True))}
self.assertRaises(exceptions.Unauthorized,
self.client.list_tenant_usages, params)
-
-
-class TenantUsagesNegativeTestXML(TenantUsagesNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 6507ce1..6a3ee44 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -38,9 +38,6 @@
def resource_setup(cls):
cls.set_network_resources()
super(BaseComputeTest, cls).resource_setup()
- if getattr(cls, '_interface', None) == 'xml' and cls._api_version == 2:
- if not CONF.compute_feature_enabled.xml_api_v2:
- raise cls.skipException('XML API is not enabled')
# TODO(andreaf) WE should care also for the alt_manager here
# but only once client lazy load in the manager is done
@@ -72,6 +69,8 @@
cls.quotas_client = cls.os.quotas_client
# NOTE(mriedem): os-quota-class-sets is v2 API only
cls.quota_classes_client = cls.os.quota_classes_client
+ # NOTE(mriedem): os-networks is v2 API only
+ cls.networks_client = cls.os.networks_client
cls.limits_client = cls.os.limits_client
cls.volumes_extensions_client = cls.os.volumes_extensions_client
cls.volumes_client = cls.os.volumes_client
diff --git a/tempest/api/compute/certificates/test_certificates.py b/tempest/api/compute/certificates/test_certificates.py
index 0f921c5..5c55eec 100644
--- a/tempest/api/compute/certificates/test_certificates.py
+++ b/tempest/api/compute/certificates/test_certificates.py
@@ -39,7 +39,3 @@
class CertificatesV2TestJSON(CertificatesV3Test):
_api_version = 2
-
-
-class CertificatesV2TestXML(CertificatesV2TestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index 7beef23..86eeba3 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -132,7 +132,3 @@
_api_version = 2
_min_disk = 'minDisk'
_min_ram = 'minRam'
-
-
-class FlavorsV2TestXML(FlavorsV2TestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py
index cae1ac4..83f8e19 100644
--- a/tempest/api/compute/flavors/test_flavors_negative.py
+++ b/tempest/api/compute/flavors/test_flavors_negative.py
@@ -15,23 +15,26 @@
from tempest.api.compute import base
from tempest.api_schema.request.compute.v2 import flavors
+from tempest import config
from tempest import test
+CONF = config.CONF
+
load_tests = test.NegativeAutoTest.load_tests
@test.SimpleNegativeAutoTest
class FlavorsListWithDetailsNegativeTestJSON(base.BaseV2ComputeTest,
test.NegativeAutoTest):
- _service = 'compute'
+ _service = CONF.compute.catalog_type
_schema = flavors.flavor_list
@test.SimpleNegativeAutoTest
class FlavorDetailsNegativeTestJSON(base.BaseV2ComputeTest,
test.NegativeAutoTest):
- _service = 'compute'
+ _service = CONF.compute.catalog_type
_schema = flavors.flavors_details
@classmethod
diff --git a/tempest/api/compute/flavors/test_flavors_negative_xml.py b/tempest/api/compute/flavors/test_flavors_negative_xml.py
deleted file mode 100644
index 299b18a..0000000
--- a/tempest/api/compute/flavors/test_flavors_negative_xml.py
+++ /dev/null
@@ -1,48 +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 uuid
-
-from tempest.api.compute import base
-from tempest import exceptions
-from tempest import test
-
-
-class FlavorsNegativeTestXML(base.BaseV2ComputeTest):
- _interface = 'xml'
-
- @classmethod
- def resource_setup(cls):
- super(FlavorsNegativeTestXML, cls).resource_setup()
- cls.client = cls.flavors_client
-
- @test.attr(type=['negative', 'gate'])
- def test_invalid_minRam_filter(self):
- self.assertRaises(exceptions.BadRequest,
- self.client.list_flavors_with_detail,
- {'minRam': 'invalid'})
-
- @test.attr(type=['negative', 'gate'])
- def test_invalid_minDisk_filter(self):
- self.assertRaises(exceptions.BadRequest,
- self.client.list_flavors_with_detail,
- {'minDisk': 'invalid'})
-
- @test.attr(type=['negative', 'gate'])
- def test_non_existent_flavor_id(self):
- # flavor details are not returned for non-existent flavors
- nonexistent_flavor_id = str(uuid.uuid4())
- self.assertRaises(exceptions.NotFound, self.client.get_flavor_details,
- nonexistent_flavor_id)
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index ba66ab9..db382eb 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -130,10 +130,7 @@
# Make sure no longer associated with old server
self.assertRaises((exceptions.NotFound,
- exceptions.UnprocessableEntity),
+ exceptions.UnprocessableEntity,
+ exceptions.Conflict),
self.client.disassociate_floating_ip_from_server,
self.floating_ip, self.server_id)
-
-
-class FloatingIPsTestXML(FloatingIPsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
index 104d130..2b0f268 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
@@ -93,7 +93,3 @@
self.assertRaises(exceptions.NotFound,
self.client.associate_floating_ip_to_server,
'', self.server_id)
-
-
-class FloatingIPsNegativeTestXML(FloatingIPsNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index cb93177..7af9ca7 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -79,7 +79,3 @@
self.assertEqual(200, resp.status)
self.assertNotEqual(0, len(floating_ip_pools),
"Expected floating IP Pools. Got zero.")
-
-
-class FloatingIPDetailsTestXML(FloatingIPDetailsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
index 08819c2..c343018 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
@@ -43,7 +43,3 @@
non_exist_id = data_utils.rand_int_id(start=999)
self.assertRaises(exceptions.NotFound,
self.client.get_floating_ip_details, non_exist_id)
-
-
-class FloatingIPDetailsNegativeTestXML(FloatingIPDetailsNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py
index 1fa591f..5105e2f 100644
--- a/tempest/api/compute/images/test_image_metadata.py
+++ b/tempest/api/compute/images/test_image_metadata.py
@@ -107,7 +107,3 @@
resp, resp_metadata = self.client.list_image_metadata(self.image_id)
expected = {'key2': 'value2'}
self.assertEqual(expected, resp_metadata)
-
-
-class ImagesMetadataTestXML(ImagesMetadataTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/images/test_image_metadata_negative.py b/tempest/api/compute/images/test_image_metadata_negative.py
index 7f0bc4e..615b5d0 100644
--- a/tempest/api/compute/images/test_image_metadata_negative.py
+++ b/tempest/api/compute/images/test_image_metadata_negative.py
@@ -72,7 +72,3 @@
self.assertRaises(exceptions.NotFound,
self.client.delete_image_metadata_item,
data_utils.rand_uuid(), 'key1')
-
-
-class ImagesMetadataTestXML(ImagesMetadataTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index 68f793a..51dae65 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -47,7 +47,3 @@
wait_until='SAVING')
resp, body = self.client.delete_image(image['id'])
self.assertEqual('204', resp['status'])
-
-
-class ImagesTestXML(ImagesTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py
index e406374..9570ca5 100644
--- a/tempest/api/compute/images/test_images_negative.py
+++ b/tempest/api/compute/images/test_images_negative.py
@@ -131,7 +131,3 @@
# Return an error while trying to delete image with id over limit
self.assertRaises(exceptions.NotFound, self.client.delete_image,
'11a22b9-12a9-5555-cc11-00ab112223fa-3fac')
-
-
-class ImagesNegativeTestXML(ImagesNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 459d78b..91e0423 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -99,10 +99,6 @@
@test.attr(type=['gate'])
def test_create_image_specify_multibyte_character_image_name(self):
- if self.__class__._interface == "xml":
- # NOTE(sdague): not entirely accurage, but we'd need a ton of work
- # in our XML client to make this good
- raise self.skipException("Not testable in XML")
# prefix character is:
# http://www.fileformat.info/info/unicode/char/1F4A9/index.htm
@@ -114,7 +110,3 @@
image_id = data_utils.parse_image_id(resp['location'])
self.addCleanup(self.client.delete_image, image_id)
self.assertEqual('202', resp['status'])
-
-
-class ImagesOneServerTestXML(ImagesOneServerTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index dc3d6bc..ae6e712 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -131,7 +131,3 @@
self.image_ids.remove(image_id)
self.assertRaises(exceptions.NotFound, self.client.get_image, image_id)
-
-
-class ImagesOneServerNegativeTestXML(ImagesOneServerNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index 30a99dd..ceab4f9 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -263,7 +263,3 @@
params = {'changes-since': self.image1['created']}
resp, images = self.client.list_images_with_detail(params)
self.assertTrue(any([i for i in images if i['id'] == self.image1_id]))
-
-
-class ListImageFiltersTestXML(ListImageFiltersTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/images/test_list_image_filters_negative.py b/tempest/api/compute/images/test_list_image_filters_negative.py
index 53a21a0..a8f2ae7 100644
--- a/tempest/api/compute/images/test_list_image_filters_negative.py
+++ b/tempest/api/compute/images/test_list_image_filters_negative.py
@@ -37,7 +37,3 @@
nonexistent_image = data_utils.rand_uuid()
self.assertRaises(exceptions.NotFound, self.client.get_image,
nonexistent_image)
-
-
-class ListImageFiltersNegativeTestXML(ListImageFiltersNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/images/test_list_images.py b/tempest/api/compute/images/test_list_images.py
index eceac82..22d64e9 100644
--- a/tempest/api/compute/images/test_list_images.py
+++ b/tempest/api/compute/images/test_list_images.py
@@ -49,7 +49,3 @@
resp, images = self.client.list_images_with_detail()
found = any([i for i in images if i['id'] == self.image_ref])
self.assertTrue(found)
-
-
-class ListImagesTestXML(ListImagesTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index 2f0febf..de8cab9 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -117,7 +117,3 @@
class KeyPairsV2TestJSON(KeyPairsV3Test):
_api_version = 2
-
-
-class KeyPairsV2TestXML(KeyPairsV2TestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py
index 0da449b..2cc6f00 100644
--- a/tempest/api/compute/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/keypairs/test_keypairs_negative.py
@@ -93,7 +93,3 @@
k_name = 'key_/.\@:'
self.assertRaises(exceptions.BadRequest, self._create_keypair,
k_name)
-
-
-class KeyPairsNegativeTestXML(KeyPairsNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/limits/test_absolute_limits.py b/tempest/api/compute/limits/test_absolute_limits.py
index bac1a39..4420ac7 100644
--- a/tempest/api/compute/limits/test_absolute_limits.py
+++ b/tempest/api/compute/limits/test_absolute_limits.py
@@ -43,7 +43,3 @@
self.assertEqual(0, len(missing_elements),
"Failed to find element %s in absolute limits list"
% ', '.join(ele for ele in missing_elements))
-
-
-class AbsoluteLimitsTestXML(AbsoluteLimitsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/limits/test_absolute_limits_negative.py b/tempest/api/compute/limits/test_absolute_limits_negative.py
index 2b41ea0..f729436 100644
--- a/tempest/api/compute/limits/test_absolute_limits_negative.py
+++ b/tempest/api/compute/limits/test_absolute_limits_negative.py
@@ -46,7 +46,3 @@
name='test', meta=meta_data,
flavor_ref=self.flavor_ref,
image_ref=self.image_ref)
-
-
-class AbsoluteLimitsNegativeTestXML(AbsoluteLimitsNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 4fd5c02..be06213 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import six
-
from tempest.api.compute.security_groups import base
from tempest import config
from tempest import test
@@ -40,13 +38,6 @@
to_port = cls.to_port
group = {}
ip_range = {}
- if cls._interface == 'xml':
- # NOTE: An XML response is different from the one of JSON
- # like the following.
- from_port = six.text_type(from_port)
- to_port = six.text_type(to_port)
- group = {'tenant_id': 'None', 'name': 'None'}
- ip_range = {'cidr': 'None'}
cls.expected = {
'id': None,
'parent_group_id': None,
@@ -195,7 +186,3 @@
self.client.list_security_group_rules(sg1_id)
# The group1 has no rules because group2 has deleted
self.assertEqual(0, len(rules))
-
-
-class SecurityGroupRulesTestXML(SecurityGroupRulesTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
index 7850909..88a99b9 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -162,7 +162,3 @@
self.assertRaises(exceptions.NotFound,
self.client.delete_security_group_rule,
non_existent_rule_id)
-
-
-class SecurityGroupRulesNegativeTestXML(SecurityGroupRulesNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index 82dd4f0..1cfb16b 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -155,7 +155,3 @@
self.client.get_security_group(securitygroup_id)
self.assertEqual(s_new_name, fetched_group['name'])
self.assertEqual(s_new_des, fetched_group['description'])
-
-
-class SecurityGroupsTestXML(SecurityGroupsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py
index 3101052..ce06180 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -201,7 +201,3 @@
self.client.update_security_group,
non_exist_id, name=s_name,
description=s_description)
-
-
-class SecurityGroupsNegativeTestXML(SecurityGroupsNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index d62d19f..049736c 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -157,7 +157,3 @@
resp, body = self.client.remove_fixed_ip(server['id'],
fixed_ip)
self.assertEqual(202, resp.status)
-
-
-class AttachInterfacesTestXML(AttachInterfacesTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_availability_zone.py b/tempest/api/compute/servers/test_availability_zone.py
index 44bd7d3..28eb274 100644
--- a/tempest/api/compute/servers/test_availability_zone.py
+++ b/tempest/api/compute/servers/test_availability_zone.py
@@ -38,7 +38,3 @@
class AZV2TestJSON(AZV3Test):
_api_version = 2
-
-
-class AZV2TestXML(AZV2TestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index bc452aa..b561b4e 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -103,7 +103,6 @@
self.password)
self.assertTrue(linux_client.hostname_equals_servername(self.name))
- @test.skip_because(bug="1306367", interface="xml")
@test.attr(type='gate')
def test_create_server_with_scheduler_hint_group(self):
# Create a server with the scheduler hint "group".
@@ -276,11 +275,3 @@
msg = "DiskConfig extension not enabled."
raise cls.skipException(msg)
super(ServersTestManualDisk, cls).resource_setup()
-
-
-class ServersTestXML(ServersTestJSON):
- _interface = 'xml'
-
-
-class ServersWithSpecificFlavorTestXML(ServersWithSpecificFlavorTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index 6a5da58..9d1ea9e 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -116,6 +116,7 @@
self.assertEqual('204', resp['status'])
self.client.wait_for_server_termination(server['id'])
+ @test.services('volume')
@test.attr(type='gate')
def test_delete_server_while_in_attached_volume(self):
# Delete a server while a volume is attached to it
@@ -168,11 +169,3 @@
resp, _ = self.admin_client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
self.servers_client.wait_for_server_termination(server['id'])
-
-
-class DeleteServersTestXML(DeleteServersTestJSON):
- _interface = 'xml'
-
-
-class DeleteServersAdminTestXML(DeleteServersAdminTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_disk_config.py b/tempest/api/compute/servers/test_disk_config.py
index 51f2eb4..eeef0e5 100644
--- a/tempest/api/compute/servers/test_disk_config.py
+++ b/tempest/api/compute/servers/test_disk_config.py
@@ -132,7 +132,3 @@
# Verify the disk_config attribute is set correctly
resp, server = self.client.get_server(server['id'])
self.assertEqual('MANUAL', server['OS-DCF:diskConfig'])
-
-
-class ServerDiskConfigTestXML(ServerDiskConfigTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_instance_actions.py b/tempest/api/compute/servers/test_instance_actions.py
index d11ce25..80b2a69 100644
--- a/tempest/api/compute/servers/test_instance_actions.py
+++ b/tempest/api/compute/servers/test_instance_actions.py
@@ -47,7 +47,3 @@
self.assertEqual(200, resp.status)
self.assertEqual(self.server_id, body['instance_uuid'])
self.assertEqual('create', body['action'])
-
-
-class InstanceActionsTestXML(InstanceActionsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_instance_actions_negative.py b/tempest/api/compute/servers/test_instance_actions_negative.py
index c706ad5..e92f04c 100644
--- a/tempest/api/compute/servers/test_instance_actions_negative.py
+++ b/tempest/api/compute/servers/test_instance_actions_negative.py
@@ -41,7 +41,3 @@
# Get the action details of the provided server with invalid request
self.assertRaises(exceptions.NotFound, self.client.get_instance_action,
self.server_id, '999')
-
-
-class InstanceActionsNegativeTestXML(InstanceActionsNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index e660f00..5ff39df 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -143,7 +143,6 @@
# Verify only the expected number of servers are returned
params = {'limit': 1}
resp, servers = self.client.list_servers(params)
- # when _interface='xml', one element for servers_links in servers
self.assertEqual(1, len([x for x in servers['servers'] if 'id' in x]))
@test.attr(type='gate')
@@ -293,7 +292,3 @@
params = {'limit': 1}
resp, servers = self.client.list_servers_with_detail(params)
self.assertEqual(1, len(servers['servers']))
-
-
-class ListServerFiltersTestXML(ListServerFiltersTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index f4d8dda..fd66d2b 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -147,7 +147,3 @@
if srv['id'] in deleted_ids]
self.assertEqual('200', resp['status'])
self.assertEqual([], actual)
-
-
-class ListServersNegativeTestXML(ListServersNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_multiple_create.py b/tempest/api/compute/servers/test_multiple_create.py
index 40b9c16..6fd2a75 100644
--- a/tempest/api/compute/servers/test_multiple_create.py
+++ b/tempest/api/compute/servers/test_multiple_create.py
@@ -53,7 +53,3 @@
return_reservation_id=True)
self.assertEqual(resp['status'], '202')
self.assertIn('reservation_id', body)
-
-
-class MultipleCreateTestXML(MultipleCreateTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_multiple_create_negative.py b/tempest/api/compute/servers/test_multiple_create_negative.py
index 3dea521..55db605 100644
--- a/tempest/api/compute/servers/test_multiple_create_negative.py
+++ b/tempest/api/compute/servers/test_multiple_create_negative.py
@@ -66,7 +66,3 @@
self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
min_count=min_count,
max_count=max_count)
-
-
-class MultipleCreateNegativeTestXML(MultipleCreateNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index b51b46e..28deaa7 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -498,7 +498,3 @@
self.assertEqual(console_type, body['type'])
self.assertNotEqual('', body['url'])
self._validate_url(body['url'])
-
-
-class ServerActionsTestXML(ServerActionsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index 6c29f51..3d1d964 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -14,11 +14,8 @@
# under the License.
from tempest.api.compute import base
-from tempest import config
from tempest import test
-CONF = config.CONF
-
class ServerAddressesTestJSON(base.BaseV2ComputeTest):
@@ -31,8 +28,6 @@
resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
- @test.skip_because(bug="1210483",
- condition=CONF.service_available.neutron)
@test.attr(type='smoke')
@test.services('network')
def test_list_server_addresses(self):
@@ -70,7 +65,3 @@
addr = addr[addr_type]
for address in addresses[addr_type]:
self.assertTrue(any([a for a in addr if a == address]))
-
-
-class ServerAddressesTestXML(ServerAddressesTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_server_addresses_negative.py b/tempest/api/compute/servers/test_server_addresses_negative.py
index c7e4c89..3087e59 100644
--- a/tempest/api/compute/servers/test_server_addresses_negative.py
+++ b/tempest/api/compute/servers/test_server_addresses_negative.py
@@ -42,7 +42,3 @@
self.assertRaises(exceptions.NotFound,
self.client.list_addresses_by_network,
self.server['id'], 'invalid')
-
-
-class ServerAddressesNegativeTestXML(ServerAddressesNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py
index c265352..6fd6a6d 100644
--- a/tempest/api/compute/servers/test_server_metadata.py
+++ b/tempest/api/compute/servers/test_server_metadata.py
@@ -113,7 +113,3 @@
resp, resp_metadata = self.client.list_server_metadata(self.server_id)
expected = {'key2': 'value2'}
self.assertEqual(expected, resp_metadata)
-
-
-class ServerMetadataTestXML(ServerMetadataTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_server_metadata_negative.py b/tempest/api/compute/servers/test_server_metadata_negative.py
index 497b94b..8b074fd 100644
--- a/tempest/api/compute/servers/test_server_metadata_negative.py
+++ b/tempest/api/compute/servers/test_server_metadata_negative.py
@@ -40,7 +40,7 @@
for sz in [256, 257, 511, 1023]:
key = "k" * sz
meta = {key: 'data1'}
- self.assertRaises(exceptions.OverLimit,
+ self.assertRaises((exceptions.BadRequest, exceptions.OverLimit),
self.create_test_server,
meta=meta)
@@ -155,7 +155,3 @@
self.assertRaises(exceptions.BadRequest,
self.client.set_server_metadata,
self.server_id, meta=meta, no_metadata_field=True)
-
-
-class ServerMetadataNegativeTestXML(ServerMetadataNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_server_password.py b/tempest/api/compute/servers/test_server_password.py
index aba9bb6..994caa4 100644
--- a/tempest/api/compute/servers/test_server_password.py
+++ b/tempest/api/compute/servers/test_server_password.py
@@ -35,7 +35,3 @@
def test_delete_server_password(self):
resp, body = self.client.delete_password(self.server['id'])
self.assertEqual(204, resp.status)
-
-
-class ServerPasswordTestXML(ServerPasswordTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index effb52f..de5b6c1 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -61,7 +61,3 @@
})
resp, server = self.create_test_server(personality=person)
self.assertEqual('202', resp['status'])
-
-
-class ServerPersonalityTestXML(ServerPersonalityTestJSON):
- _interface = "xml"
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index a984ade..ee1e268 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -45,12 +45,6 @@
cls.sg_desc)
cls.sg_id = cls.sg['id']
- # Create a volume and wait for it to become ready for attach
- resp, cls.volume = cls.volumes_extensions_client.create_volume(
- 1, display_name=data_utils.rand_name(cls.__name__ + '_volume'))
- cls.volumes_extensions_client.wait_for_volume_status(
- cls.volume['id'], 'available')
-
# Server for positive tests
resp, server = cls.create_test_server(wait_until='BUILD')
cls.server_id = server['id']
@@ -64,8 +58,6 @@
def resource_cleanup(cls):
# Deleting the floating IP which is created in this method
cls.floating_ips_client.delete_floating_ip(cls.floating_ip_id)
- if getattr(cls, 'volume', None):
- cls.delete_volume(cls.volume['id'])
resp, cls.sg = cls.security_groups_client.delete_security_group(
cls.sg_id)
super(ServerRescueTestJSON, cls).resource_cleanup()
@@ -125,7 +117,3 @@
resp, body = self.servers_client.remove_security_group(self.server_id,
self.sg_name)
self.assertEqual(202, resp.status)
-
-
-class ServerRescueTestXML(ServerRescueTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index 0d29968..f1e2f7f 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -35,12 +35,6 @@
super(ServerRescueNegativeTestJSON, cls).resource_setup()
cls.device = CONF.compute.volume_device_name
- # Create a volume and wait for it to become ready for attach
- resp, cls.volume = cls.volumes_extensions_client.create_volume(
- 1, display_name=data_utils.rand_name(cls.__name__ + '_volume'))
- cls.volumes_extensions_client.wait_for_volume_status(
- cls.volume['id'], 'available')
-
# Server for negative tests
resp, server = cls.create_test_server(wait_until='BUILD')
resp, resc_server = cls.create_test_server(wait_until='ACTIVE')
@@ -54,11 +48,14 @@
cls.servers_client.wait_for_server_status(cls.rescue_id, 'RESCUE')
cls.servers_client.wait_for_server_status(cls.server_id, 'ACTIVE')
- @classmethod
- def resource_cleanup(cls):
- if getattr(cls, 'volume', None):
- cls.delete_volume(cls.volume['id'])
- super(ServerRescueNegativeTestJSON, cls).resource_cleanup()
+ def _create_volume(self):
+ resp, volume = self.volumes_extensions_client.create_volume(
+ 1, display_name=data_utils.rand_name(
+ self.__class__.__name__ + '_volume'))
+ self.addCleanup(self.delete_volume, volume['id'])
+ self.volumes_extensions_client.wait_for_volume_status(
+ volume['id'], 'available')
+ return volume
def _detach(self, server_id, volume_id):
self.servers_client.detach_volume(server_id, volume_id)
@@ -108,8 +105,11 @@
self.rescue_id,
self.image_ref_alt)
+ @test.services('volume')
@test.attr(type=['negative', 'gate'])
def test_rescued_vm_attach_volume(self):
+ volume = self._create_volume()
+
# Rescue the server
self.servers_client.rescue_server(self.server_id,
adminPass=self.password)
@@ -120,32 +120,31 @@
self.assertRaises(exceptions.Conflict,
self.servers_client.attach_volume,
self.server_id,
- self.volume['id'],
+ volume['id'],
device='/dev/%s' % self.device)
+ @test.services('volume')
@test.attr(type=['negative', 'gate'])
def test_rescued_vm_detach_volume(self):
+ volume = self._create_volume()
+
# Attach the volume to the server
self.servers_client.attach_volume(self.server_id,
- self.volume['id'],
+ volume['id'],
device='/dev/%s' % self.device)
self.volumes_extensions_client.wait_for_volume_status(
- self.volume['id'], 'in-use')
+ volume['id'], 'in-use')
# Rescue the server
self.servers_client.rescue_server(self.server_id,
adminPass=self.password)
self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
# addCleanup is a LIFO queue
- self.addCleanup(self._detach, self.server_id, self.volume['id'])
+ self.addCleanup(self._detach, self.server_id, volume['id'])
self.addCleanup(self._unrescue, self.server_id)
# Detach the volume from the server expecting failure
self.assertRaises(exceptions.Conflict,
self.servers_client.detach_volume,
self.server_id,
- self.volume['id'])
-
-
-class ServerRescueNegativeTestXML(ServerRescueNegativeTestJSON):
- _interface = 'xml'
+ volume['id'])
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index d501839..aba6dff 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -124,7 +124,3 @@
self.client.wait_for_server_status(server['id'], 'ACTIVE')
resp, server = self.client.get_server(server['id'])
self.assertEqual('2001:2001::3', server['accessIPv6'])
-
-
-class ServersTestXML(ServersTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 0349260..4e6dcda 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -181,10 +181,6 @@
@test.attr(type=['negative', 'gate'])
def test_create_numeric_server_name(self):
- # Create a server with a numeric name
- if self.__class__._interface == "xml":
- raise self.skipException("Not testable in XML")
-
server_name = 12345
self.assertRaises(exceptions.BadRequest,
self.create_test_server,
@@ -223,7 +219,7 @@
# Pass really long metadata while creating a server
metadata = {'a': 'b' * 260}
- self.assertRaises(exceptions.OverLimit,
+ self.assertRaises((exceptions.BadRequest, exceptions.OverLimit),
self.create_test_server,
meta=metadata)
@@ -471,7 +467,3 @@
self.assertRaises(exceptions.Conflict,
self.client.unshelve_server,
self.server_id)
-
-
-class ServersNegativeTestXML(ServersNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_servers_negative_new.py b/tempest/api/compute/servers/test_servers_negative_new.py
deleted file mode 100644
index 7fc2d4f..0000000
--- a/tempest/api/compute/servers/test_servers_negative_new.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2014 Red Hat, Inc & Deutsche Telekom AG
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-from tempest.api.compute import base
-from tempest.api_schema.request.compute.v2 import servers
-from tempest import test
-
-
-load_tests = test.NegativeAutoTest.load_tests
-
-
-@test.SimpleNegativeAutoTest
-class GetConsoleOutputNegativeTestJSON(base.BaseV2ComputeTest,
- test.NegativeAutoTest):
- _service = 'compute'
- _schema = servers.get_console_output
-
- @classmethod
- def resource_setup(cls):
- super(GetConsoleOutputNegativeTestJSON, cls).resource_setup()
- _resp, server = cls.create_test_server()
- cls.set_resource("server", server['id'])
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index f205761..48af084 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -50,7 +50,3 @@
mac_address = virt_iface['mac_address']
self.assertTrue(netaddr.valid_mac(mac_address),
"Invalid mac address detected.")
-
-
-class VirtualInterfacesTestXML(VirtualInterfacesTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_virtual_interfaces_negative.py b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
index 1f4a20e..e81ccc6 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces_negative.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
@@ -38,7 +38,3 @@
self.assertRaises(exceptions.NotFound,
self.client.list_virtual_interfaces,
invalid_server_id)
-
-
-class VirtualInterfacesNegativeTestXML(VirtualInterfacesNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index 175f008..1f4f124 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -379,7 +379,3 @@
self.assertRaises(exceptions.NotFound,
self.alt_client.get_console_output,
self.server['id'], 10)
-
-
-class AuthorizationTestXML(AuthorizationTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index 674ca9a..25e14a8 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -52,7 +52,3 @@
resp, extension = self.extensions_client.get_extension('os-consoles')
self.assertEqual(200, resp.status)
self.assertEqual('os-consoles', extension['alias'])
-
-
-class ExtensionsTestXML(ExtensionsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/test_live_block_migration.py b/tempest/api/compute/test_live_block_migration.py
index 86b8395..cb75d07 100644
--- a/tempest/api/compute/test_live_block_migration.py
+++ b/tempest/api/compute/test_live_block_migration.py
@@ -130,9 +130,3 @@
self._migrate_server_to(server_id, target_host)
self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
self.assertEqual(target_host, self._get_host_for_server(server_id))
-
-
-class LiveBlockMigrationTestXML(LiveBlockMigrationTestJSON):
- _host_key = (
- '{http://docs.openstack.org/compute/ext/extended_status/api/v1.1}host')
- _interface = 'xml'
diff --git a/tempest/api/compute/test_live_block_migration_negative.py b/tempest/api/compute/test_live_block_migration_negative.py
index 95eea19..281b2b3 100644
--- a/tempest/api/compute/test_live_block_migration_negative.py
+++ b/tempest/api/compute/test_live_block_migration_negative.py
@@ -51,9 +51,3 @@
self.assertRaises(exceptions.BadRequest, self._migrate_server_to,
server_id, target_host)
self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
-
-
-class LiveBlockMigrationNegativeTestXML(LiveBlockMigrationNegativeTestJSON):
- _host_key = (
- '{http://docs.openstack.org/compute/ext/extended_status/api/v1.1}host')
- _interface = 'xml'
diff --git a/tempest/api/compute/test_networks.py b/tempest/api/compute/test_networks.py
new file mode 100644
index 0000000..86779b3
--- /dev/null
+++ b/tempest/api/compute/test_networks.py
@@ -0,0 +1,33 @@
+# Copyright 2014 IBM Corp.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.compute import base
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
+
+
+class NetworksTestJSON(base.BaseV2ComputeTest):
+ @classmethod
+ def resource_setup(cls):
+ if CONF.service_available.neutron:
+ raise cls.skipException('nova-network is not available.')
+ super(NetworksTestJSON, cls).resource_setup()
+ cls.client = cls.os.networks_client
+
+ @test.attr(type='gate')
+ def test_list_networks(self):
+ _, networks = self.client.list_networks()
+ self.assertNotEmpty(networks, "No networks found.")
diff --git a/tempest/api/compute/test_quotas.py b/tempest/api/compute/test_quotas.py
index e66b652..4177751 100644
--- a/tempest/api/compute/test_quotas.py
+++ b/tempest/api/compute/test_quotas.py
@@ -76,7 +76,3 @@
resp, tenant_quota_set = self.client.get_quota_set(self.tenant_id)
self.assertEqual(200, resp.status)
self.assertEqual(defualt_quota_set, tenant_quota_set)
-
-
-class QuotasTestXML(QuotasTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_server_addresses.py b/tempest/api/compute/v3/servers/test_server_addresses.py
index 0590146..7b41d71 100644
--- a/tempest/api/compute/v3/servers/test_server_addresses.py
+++ b/tempest/api/compute/v3/servers/test_server_addresses.py
@@ -14,11 +14,8 @@
# under the License.
from tempest.api.compute import base
-from tempest import config
from tempest import test
-CONF = config.CONF
-
class ServerAddressesV3Test(base.BaseV3ComputeTest):
@@ -31,8 +28,6 @@
resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
- @test.skip_because(bug="1210483",
- condition=CONF.service_available.neutron)
@test.attr(type='smoke')
def test_list_server_addresses(self):
# All public and private addresses for
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 484c34d..1d22fbd 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -27,9 +27,7 @@
def __init__(self, *args, **kwargs):
super(AttachVolumeTestJSON, self).__init__(*args, **kwargs)
- self.server = None
- self.volume = None
- self.attached = False
+ self.attachment = None
@classmethod
def resource_setup(cls):
@@ -41,13 +39,15 @@
raise cls.skipException(skip_msg)
def _detach(self, server_id, volume_id):
- if self.attached:
+ if self.attachment:
self.servers_client.detach_volume(server_id, volume_id)
self.volumes_client.wait_for_volume_status(volume_id, 'available')
def _delete_volume(self):
+ # Delete the created Volumes
if self.volume:
self.volumes_client.delete_volume(self.volume['id'])
+ self.volumes_client.wait_for_resource_deletion(self.volume['id'])
self.volume = None
def _create_and_attach(self):
@@ -57,8 +57,8 @@
adminPass=admin_pass)
# Record addresses so that we can ssh later
- _, self.server['addresses'] = \
- self.servers_client.list_addresses(self.server['id'])
+ _, self.server['addresses'] = (
+ self.servers_client.list_addresses(self.server['id']))
# Create a volume and wait for it to become ready
_, self.volume = self.volumes_client.create_volume(
@@ -68,12 +68,12 @@
'available')
# Attach the volume to the server
- self.servers_client.attach_volume(self.server['id'],
- self.volume['id'],
- device='/dev/%s' % self.device)
+ _, self.attachment = self.servers_client.attach_volume(
+ self.server['id'],
+ self.volume['id'],
+ device='/dev/%s' % self.device)
self.volumes_client.wait_for_volume_status(self.volume['id'], 'in-use')
- self.attached = True
self.addCleanup(self._detach, self.server['id'], self.volume['id'])
@testtools.skipUnless(CONF.compute.run_ssh, 'SSH required for this test')
@@ -97,8 +97,7 @@
self.assertIn(self.device, partitions)
self._detach(self.server['id'], self.volume['id'])
- self.attached = False
-
+ self.attachment = None
self.servers_client.stop(self.server['id'])
self.servers_client.wait_for_server_status(self.server['id'],
'SHUTOFF')
@@ -112,6 +111,20 @@
partitions = linux_client.get_partitions()
self.assertNotIn(self.device, partitions)
+ @test.attr(type='gate')
+ def test_list_get_volume_attachments(self):
+ # Create Server, Volume and attach that Volume to Server
+ self._create_and_attach()
+ # List Volume attachment of the server
+ _, body = self.servers_client.list_volume_attachments(
+ self.server['id'])
+ self.assertEqual(1, len(body))
+ self.assertIn(self.attachment, body)
-class AttachVolumeTestXML(AttachVolumeTestJSON):
- _interface = 'xml'
+ # Get Volume attachment of the server
+ _, body = self.servers_client.get_volume_attachment(
+ self.server['id'],
+ self.attachment['id'])
+ self.assertEqual(self.server['id'], body['serverId'])
+ self.assertEqual(self.volume['id'], body['volumeId'])
+ self.assertEqual(self.attachment['id'], body['id'])
diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py
index 4f77fa7..d441427 100644
--- a/tempest/api/compute/volumes/test_volumes_get.py
+++ b/tempest/api/compute/volumes/test_volumes_get.py
@@ -71,7 +71,3 @@
matchers.ContainsAll(metadata.items()),
'The fetched Volume metadata misses data '
'from the created Volume')
-
-
-class VolumesGetTestXML(VolumesGetTestJSON):
- _interface = "xml"
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index dc54c67..6bf9519 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -165,7 +165,3 @@
all_vol_list[index + params['offset']]['id'],
"Failed to list volume details by "
"offset and limit")
-
-
-class VolumesTestXML(VolumesTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py
index ad94ea7..f0f9879 100644
--- a/tempest/api/compute/volumes/test_volumes_negative.py
+++ b/tempest/api/compute/volumes/test_volumes_negative.py
@@ -98,7 +98,3 @@
def test_delete_volume_without_passing_volume_id(self):
# Negative: Should not be able to delete volume when empty ID is passed
self.assertRaises(exceptions.NotFound, self.client.delete_volume, '')
-
-
-class VolumesNegativeTestXML(VolumesNegativeTest):
- _interface = "xml"
diff --git a/tempest/api/identity/admin/test_roles.py b/tempest/api/identity/admin/test_roles.py
index d87d5c1..fabc0ed 100644
--- a/tempest/api/identity/admin/test_roles.py
+++ b/tempest/api/identity/admin/test_roles.py
@@ -105,7 +105,3 @@
self.client.assign_user_role(tenant['id'], user['id'], role['id'])
_, roles = self.client.list_user_roles(tenant['id'], user['id'])
self.assert_role_in_role_list(role, roles)
-
-
-class RolesTestXML(RolesTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/test_roles_negative.py b/tempest/api/identity/admin/test_roles_negative.py
index 37a981e..d0eb334 100644
--- a/tempest/api/identity/admin/test_roles_negative.py
+++ b/tempest/api/identity/admin/test_roles_negative.py
@@ -223,7 +223,3 @@
user['id'])
finally:
self.client.auth_provider.clear_auth()
-
-
-class RolesTestXML(RolesNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/test_services.py b/tempest/api/identity/admin/test_services.py
index a9782a9..b8f09ad 100644
--- a/tempest/api/identity/admin/test_services.py
+++ b/tempest/api/identity/admin/test_services.py
@@ -98,7 +98,3 @@
_, body = self.client.list_services()
found = [serv for serv in body if serv['id'] in service_ids]
self.assertEqual(len(found), len(services), 'Services not found')
-
-
-class ServicesTestXML(ServicesTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/test_tenant_negative.py b/tempest/api/identity/admin/test_tenant_negative.py
index dcfacee..57a2fec 100644
--- a/tempest/api/identity/admin/test_tenant_negative.py
+++ b/tempest/api/identity/admin/test_tenant_negative.py
@@ -135,7 +135,3 @@
self.assertRaises(exceptions.Unauthorized, self.client.update_tenant,
tenant['id'])
self.client.auth_provider.clear_auth()
-
-
-class TenantsNegativeTestXML(TenantsNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/test_tenants.py b/tempest/api/identity/admin/test_tenants.py
index 8d3b402..778bd5c 100644
--- a/tempest/api/identity/admin/test_tenants.py
+++ b/tempest/api/identity/admin/test_tenants.py
@@ -178,7 +178,3 @@
self.client.delete_tenant(t_id)
self.data.tenants.remove(tenant)
-
-
-class TenantsTestXML(TenantsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/test_tokens.py b/tempest/api/identity/admin/test_tokens.py
index 2c5fb74..bfdc7d6 100644
--- a/tempest/api/identity/admin/test_tokens.py
+++ b/tempest/api/identity/admin/test_tokens.py
@@ -104,7 +104,3 @@
# Use the unscoped token to get a token scoped to tenant2
_, body = self.token_client.auth_token(token_id,
tenant=tenant2_name)
-
-
-class TokensTestXML(TokensTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/test_users.py b/tempest/api/identity/admin/test_users.py
index 66a1737..84a8103 100644
--- a/tempest/api/identity/admin/test_users.py
+++ b/tempest/api/identity/admin/test_users.py
@@ -206,7 +206,3 @@
_, body = self.token_client.auth(self.data.test_user, new_pass,
self.data.test_tenant)
self.assertTrue('id' in body['token'])
-
-
-class UsersTestXML(UsersTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/test_users_negative.py b/tempest/api/identity/admin/test_users_negative.py
index bad2b89..c039da6 100644
--- a/tempest/api/identity/admin/test_users_negative.py
+++ b/tempest/api/identity/admin/test_users_negative.py
@@ -227,7 +227,3 @@
for invalid in invalid_id:
self.assertRaises(exceptions.NotFound,
self.client.list_users_for_tenant, invalid)
-
-
-class UsersNegativeTestXML(UsersNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_credentials.py b/tempest/api/identity/admin/v3/test_credentials.py
index 7a0edb0..9b30166 100644
--- a/tempest/api/identity/admin/v3/test_credentials.py
+++ b/tempest/api/identity/admin/v3/test_credentials.py
@@ -105,7 +105,3 @@
self.assertEqual(0, len(missing_creds),
"Failed to find cred %s in fetched list" %
', '.join(m_cred for m_cred in missing_creds))
-
-
-class CredentialsTestXML(CredentialsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index 5b73df1..286ef97 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -85,7 +85,3 @@
self.assertEqual(new_name, fetched_domain['name'])
self.assertEqual(new_desc, fetched_domain['description'])
self.assertEqual('true', str(fetched_domain['enabled']).lower())
-
-
-class DomainsTestXML(DomainsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index f1f1eb6..6044d2b 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -81,8 +81,7 @@
fetched_endpoints_id = [e['id'] for e in fetched_endpoints]
self.assertIn(endpoint['id'], fetched_endpoints_id)
# Deleting the endpoint created in this method
- _, body = self.client.delete_endpoint(endpoint['id'])
- self.assertEqual(body, '')
+ self.client.delete_endpoint(endpoint['id'])
# Checking whether endpoint is deleted successfully
resp, fetched_endpoints = self.client.list_endpoints()
fetched_endpoints_id = [e['id'] for e in fetched_endpoints]
@@ -123,7 +122,3 @@
self.assertEqual(url2, endpoint['url'])
self.assertEqual(region2, endpoint['region'])
self.assertEqual('false', str(endpoint['enabled']).lower())
-
-
-class EndPointsTestXML(EndPointsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_endpoints_negative.py b/tempest/api/identity/admin/v3/test_endpoints_negative.py
index b987d12..4308d44 100644
--- a/tempest/api/identity/admin/v3/test_endpoints_negative.py
+++ b/tempest/api/identity/admin/v3/test_endpoints_negative.py
@@ -88,7 +88,3 @@
def test_update_with_enabled_True(self):
# Enabled should be a boolean, not a string like 'True'
self._assert_update_raises_bad_request('True')
-
-
-class EndpointsNegativeTestXML(EndpointsNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_groups.py b/tempest/api/identity/admin/v3/test_groups.py
index 987a9d5..3f2069d 100644
--- a/tempest/api/identity/admin/v3/test_groups.py
+++ b/tempest/api/identity/admin/v3/test_groups.py
@@ -91,7 +91,3 @@
_, user_groups = self.client.list_user_groups(user['id'])
self.assertEqual(sorted(groups), sorted(user_groups))
self.assertEqual(2, len(user_groups))
-
-
-class GroupsV3TestXML(GroupsV3TestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_list_projects.py b/tempest/api/identity/admin/v3/test_list_projects.py
index be06c7f..2065de3 100644
--- a/tempest/api/identity/admin/v3/test_list_projects.py
+++ b/tempest/api/identity/admin/v3/test_list_projects.py
@@ -67,7 +67,3 @@
resp, body = self.client.list_projects(params)
self.assertIn(self.p1[key], map(lambda x: x[key], body))
self.assertNotIn(self.p2[key], map(lambda x: x[key], body))
-
-
-class ListProjectsTestXML(ListProjectsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_list_users.py b/tempest/api/identity/admin/v3/test_list_users.py
index 903ad5c..70c8ec6 100644
--- a/tempest/api/identity/admin/v3/test_list_users.py
+++ b/tempest/api/identity/admin/v3/test_list_users.py
@@ -94,7 +94,3 @@
self.assertEqual(self.data.v3_users[0]['name'], user['name'])
self.assertEqual(self.alt_email, user['email'])
self.assertEqual(self.data.domain['id'], user['domain_id'])
-
-
-class UsersV3TestXML(UsersV3TestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_policies.py b/tempest/api/identity/admin/v3/test_policies.py
index 65c5230..23df13d 100644
--- a/tempest/api/identity/admin/v3/test_policies.py
+++ b/tempest/api/identity/admin/v3/test_policies.py
@@ -32,13 +32,13 @@
for _ in range(3):
blob = data_utils.rand_name('BlobName-')
policy_type = data_utils.rand_name('PolicyType-')
- resp, policy = self.policy_client.create_policy(blob,
- policy_type)
+ policy = self.policy_client.create_policy(blob,
+ policy_type)
# Delete the Policy at the end of this method
self.addCleanup(self._delete_policy, policy['id'])
policy_ids.append(policy['id'])
# List and Verify Policies
- _, body = self.policy_client.list_policies()
+ body = self.policy_client.list_policies()
for p in body:
fetched_ids.append(p['id'])
missing_pols = [p for p in policy_ids if p not in fetched_ids]
@@ -49,7 +49,7 @@
# Test to update policy
blob = data_utils.rand_name('BlobName-')
policy_type = data_utils.rand_name('PolicyType-')
- _, policy = self.policy_client.create_policy(blob, policy_type)
+ policy = self.policy_client.create_policy(blob, policy_type)
self.addCleanup(self._delete_policy, policy['id'])
self.assertIn('id', policy)
self.assertIn('type', policy)
@@ -59,18 +59,14 @@
self.assertEqual(policy_type, policy['type'])
# Update policy
update_type = data_utils.rand_name('UpdatedPolicyType-')
- _, data = self.policy_client.update_policy(
+ data = self.policy_client.update_policy(
policy['id'], type=update_type)
self.assertIn('type', data)
# Assertion for updated value with fetched value
- _, fetched_policy = self.policy_client.get_policy(policy['id'])
+ fetched_policy = self.policy_client.get_policy(policy['id'])
self.assertIn('id', fetched_policy)
self.assertIn('blob', fetched_policy)
self.assertIn('type', fetched_policy)
self.assertEqual(fetched_policy['id'], policy['id'])
self.assertEqual(fetched_policy['blob'], policy['blob'])
self.assertEqual(update_type, fetched_policy['type'])
-
-
-class PoliciesTestXML(PoliciesTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py
index 5890eab..e7fd2b5 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -176,7 +176,3 @@
self.assertEqual(project['id'],
new_user_get['project_id'])
self.assertEqual(u_email, new_user_get['email'])
-
-
-class ProjectsTestXML(ProjectsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_projects_negative.py b/tempest/api/identity/admin/v3/test_projects_negative.py
index 9e8f613..da35ace 100644
--- a/tempest/api/identity/admin/v3/test_projects_negative.py
+++ b/tempest/api/identity/admin/v3/test_projects_negative.py
@@ -74,7 +74,3 @@
# Attempt to delete a non existent project should fail
self.assertRaises(exceptions.NotFound, self.client.delete_project,
data_utils.rand_uuid_hex())
-
-
-class ProjectsNegativeTestXML(ProjectsNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_regions.py b/tempest/api/identity/admin/v3/test_regions.py
index c5d5824..4305060 100644
--- a/tempest/api/identity/admin/v3/test_regions.py
+++ b/tempest/api/identity/admin/v3/test_regions.py
@@ -89,7 +89,3 @@
self.assertEqual(0, len(missing_regions),
"Failed to find region %s in fetched list" %
', '.join(str(e) for e in missing_regions))
-
-
-class RegionsTestXML(RegionsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index 5e14a04..3c0a180 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -173,7 +173,3 @@
_, body = self.client.list_roles()
found = [role for role in body if role in self.data.v3_roles]
self.assertEqual(len(found), len(self.data.v3_roles))
-
-
-class RolesV3TestXML(RolesV3TestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_services.py b/tempest/api/identity/admin/v3/test_services.py
index 7e21cc3..a871f17 100644
--- a/tempest/api/identity/admin/v3/test_services.py
+++ b/tempest/api/identity/admin/v3/test_services.py
@@ -91,7 +91,3 @@
fetched_ids = [service['id'] for service in services]
found = [s for s in fetched_ids if s in service_ids]
self.assertEqual(len(found), len(service_ids))
-
-
-class ServicesTestXML(ServicesTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index 230e09f..aef8239 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -145,7 +145,3 @@
token_auth['token']['project']['id'])
self.assertEqual(project2['name'],
token_auth['token']['project']['name'])
-
-
-class TokensV3TestXML(TokensV3TestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index 898bcd0..1b003c3 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -144,7 +144,3 @@
self.data.setup_test_v3_user()
_, user = self.client.get_user(self.data.v3_user['id'])
self.assertEqual(self.data.v3_user['id'], user['id'])
-
-
-class UsersV3TestXML(UsersV3TestJSON):
- _interface = 'xml'
diff --git a/tempest/api/identity/test_extension.py b/tempest/api/identity/test_extension.py
index a06ee53..829628a 100644
--- a/tempest/api/identity/test_extension.py
+++ b/tempest/api/identity/test_extension.py
@@ -30,7 +30,3 @@
for value in body:
for key in keys:
self.assertIn(key, value)
-
-
-class ExtensionTestXML(ExtensionTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 74baba6..76b6f17 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -15,7 +15,7 @@
import cStringIO as StringIO
from tempest import clients
-from tempest.common import isolated_creds
+from tempest.common import credentials
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
@@ -36,7 +36,7 @@
super(BaseImageTest, cls).resource_setup()
cls.created_images = []
cls._interface = 'json'
- cls.isolated_creds = isolated_creds.IsolatedCreds(
+ cls.isolated_creds = credentials.get_isolated_credentials(
cls.__name__, network_resources=cls.network_resources)
if not CONF.service_available.glance:
skip_msg = ("%s skipped as glance is not available" % cls.__name__)
diff --git a/tempest/api/messaging/test_queues.py b/tempest/api/messaging/test_queues.py
index 8f9ac20..accbd17 100644
--- a/tempest/api/messaging/test_queues.py
+++ b/tempest/api/messaging/test_queues.py
@@ -20,6 +20,7 @@
from tempest.api.messaging import base
from tempest.common.utils import data_utils
+from tempest import exceptions
from tempest import test
@@ -29,15 +30,22 @@
class TestQueues(base.BaseMessagingTest):
@test.attr(type='smoke')
- def test_create_queue(self):
- # Create Queue
+ def test_create_delete_queue(self):
+ # Create & Delete Queue
queue_name = data_utils.rand_name('test-')
_, body = self.create_queue(queue_name)
self.addCleanup(self.client.delete_queue, queue_name)
-
+ # NOTE(gmann): create_queue returns response status code as 201
+ # so specifically checking the expected empty response body as
+ # this is not going to be checked in response_checker().
self.assertEqual('', body)
+ self.delete_queue(queue_name)
+ self.assertRaises(exceptions.NotFound,
+ self.client.get_queue,
+ queue_name)
+
class TestManageQueue(base.BaseMessagingTest):
_interface = 'json'
@@ -53,25 +61,16 @@
cls.client.create_queue(queue_name)
@test.attr(type='smoke')
- def test_delete_queue(self):
- # Delete Queue
- queue_name = self.queues.pop()
- _, body = self.delete_queue(queue_name)
- self.assertEqual('', body)
-
- @test.attr(type='smoke')
def test_check_queue_existence(self):
# Checking Queue Existence
for queue_name in self.queues:
- _, body = self.check_queue_exists(queue_name)
- self.assertEqual('', body)
+ self.check_queue_exists(queue_name)
@test.attr(type='smoke')
def test_check_queue_head(self):
# Checking Queue Existence by calling HEAD
for queue_name in self.queues:
- _, body = self.check_queue_exists_head(queue_name)
- self.assertEqual('', body)
+ self.check_queue_exists_head(queue_name)
@test.attr(type='smoke')
def test_list_queues(self):
@@ -111,8 +110,8 @@
req_body = dict()
req_body[data_utils.rand_name('key1')] = req_body1
# Set Queue Metadata
- _, body = self.set_queue_metadata(queue_name, req_body)
- self.assertEqual('', body)
+ self.set_queue_metadata(queue_name, req_body)
+
# Get Queue Metadata
_, body = self.get_queue_metadata(queue_name)
self.assertThat(body, matchers.Equals(req_body))
diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py
index 0d27afa..53b9ddd 100644
--- a/tempest/api/network/admin/test_agent_management.py
+++ b/tempest/api/network/admin/test_agent_management.py
@@ -83,7 +83,3 @@
origin_agent = {'description': description}
self.admin_client.update_agent(agent_id=self.agent['id'],
agent_info=origin_agent)
-
-
-class AgentManagementTestXML(AgentManagementTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/network/admin/test_dhcp_agent_scheduler.py b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
index 78f211d..a938fa6 100644
--- a/tempest/api/network/admin/test_dhcp_agent_scheduler.py
+++ b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
@@ -93,7 +93,3 @@
network_id)
self.assertTrue(self._check_network_in_dhcp_agent(
network_id, agent))
-
-
-class DHCPAgentSchedulersTestXML(DHCPAgentSchedulersTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/network/admin/test_external_network_extension.py b/tempest/api/network/admin/test_external_network_extension.py
index 2e58dae..75ee217 100644
--- a/tempest/api/network/admin/test_external_network_extension.py
+++ b/tempest/api/network/admin/test_external_network_extension.py
@@ -84,6 +84,37 @@
self.assertEqual(self.network['id'], show_net['id'])
self.assertFalse(show_net['router:external'])
+ def test_delete_external_networks_with_floating_ip(self):
+ """Verifies external network can be deleted while still holding
+ (unassociated) floating IPs
-class ExternalNetworksTestXML(ExternalNetworksTestJSON):
- _interface = 'xml'
+ """
+ # Set cls.client to admin to use base.create_subnet()
+ client = self.admin_client
+ _, body = client.create_network(**{'router:external': True})
+ external_network = body['network']
+ self.addCleanup(self._try_delete_resource,
+ client.delete_network,
+ external_network['id'])
+ subnet = self.create_subnet(external_network, client=client)
+ _, body = client.create_floatingip(
+ floating_network_id=external_network['id'])
+ created_floating_ip = body['floatingip']
+ self.addCleanup(self._try_delete_resource,
+ client.delete_floatingip,
+ created_floating_ip['id'])
+ _, floatingip_list = client.list_floatingips(
+ network=external_network['id'])
+ self.assertIn(created_floating_ip['id'],
+ (f['id'] for f in floatingip_list['floatingips']))
+ client.delete_network(external_network['id'])
+ # Verifies floating ip is deleted
+ _, floatingip_list = client.list_floatingips()
+ self.assertNotIn(created_floating_ip['id'],
+ (f['id'] for f in floatingip_list['floatingips']))
+ # Verifies subnet is deleted
+ _, subnet_list = client.list_subnets()
+ self.assertNotIn(subnet['id'],
+ (s['id'] for s in subnet_list))
+ # Removes subnet from the cleanup list
+ self.subnets.remove(subnet)
diff --git a/tempest/api/network/admin/test_floating_ips_admin_actions.py b/tempest/api/network/admin/test_floating_ips_admin_actions.py
index 46c5e76..2fe7bf8 100644
--- a/tempest/api/network/admin/test_floating_ips_admin_actions.py
+++ b/tempest/api/network/admin/test_floating_ips_admin_actions.py
@@ -63,7 +63,3 @@
self.assertNotIn(floating_ip_admin['floatingip']['id'],
floating_ip_ids)
self.assertNotIn(floating_ip_alt['id'], floating_ip_ids)
-
-
-class FloatingIPAdminTestXML(FloatingIPAdminTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index 567af24..8fccb1f 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -76,7 +76,3 @@
router['router']['id'])
# NOTE(afazekas): The deletion not asserted, because neutron
# is not forbidden to reschedule the router to the same agent
-
-
-class L3AgentSchedulerTestXML(L3AgentSchedulerTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/network/admin/test_lbaas_agent_scheduler.py b/tempest/api/network/admin/test_lbaas_agent_scheduler.py
index 1476f30..03296a4 100644
--- a/tempest/api/network/admin/test_lbaas_agent_scheduler.py
+++ b/tempest/api/network/admin/test_lbaas_agent_scheduler.py
@@ -69,7 +69,3 @@
_, body = self.admin_client.show_lbaas_agent_hosting_pool(
self.pool['id'])
self.assertEqual('Loadbalancer agent', body['agent']['agent_type'])
-
-
-class LBaaSAgentSchedulerTestXML(LBaaSAgentSchedulerTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/network/admin/test_load_balancer_admin_actions.py b/tempest/api/network/admin/test_load_balancer_admin_actions.py
index 6d115e8..15d06e3 100644
--- a/tempest/api/network/admin/test_load_balancer_admin_actions.py
+++ b/tempest/api/network/admin/test_load_balancer_admin_actions.py
@@ -109,7 +109,3 @@
self.addCleanup(self.admin_client.delete_member, member['id'])
self.assertIsNotNone(member['id'])
self.assertEqual(self.tenant_id, member['tenant_id'])
-
-
-class LoadBalancerAdminTestXML(LoadBalancerAdminTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 91e3e14..b13dd22 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -62,6 +62,8 @@
super(BaseNetworkTest, cls).resource_setup()
if not CONF.service_available.neutron:
raise cls.skipException("Neutron support is required")
+ if cls._ip_version == 6 and not CONF.network_feature_enabled.ipv6:
+ raise cls.skipException("IPv6 Tests are disabled.")
os = cls.get_client_manager()
@@ -90,58 +92,95 @@
if CONF.service_available.neutron:
# Clean up ipsec policies
for ipsecpolicy in cls.ipsecpolicies:
- cls.client.delete_ipsecpolicy(ipsecpolicy['id'])
+ cls._try_delete_resource(cls.client.delete_ipsecpolicy,
+ ipsecpolicy['id'])
# Clean up firewall policies
for fw_policy in cls.fw_policies:
- cls.client.delete_firewall_policy(fw_policy['id'])
+ cls._try_delete_resource(cls.client.delete_firewall_policy,
+ fw_policy['id'])
# Clean up firewall rules
for fw_rule in cls.fw_rules:
- cls.client.delete_firewall_rule(fw_rule['id'])
+ cls._try_delete_resource(cls.client.delete_firewall_rule,
+ fw_rule['id'])
# Clean up ike policies
for ikepolicy in cls.ikepolicies:
- cls.client.delete_ikepolicy(ikepolicy['id'])
+ cls._try_delete_resource(cls.client.delete_ikepolicy,
+ ikepolicy['id'])
# Clean up vpn services
for vpnservice in cls.vpnservices:
- cls.client.delete_vpnservice(vpnservice['id'])
+ cls._try_delete_resource(cls.client.delete_vpnservice,
+ vpnservice['id'])
# Clean up floating IPs
for floating_ip in cls.floating_ips:
- cls.client.delete_floatingip(floating_ip['id'])
+ cls._try_delete_resource(cls.client.delete_floatingip,
+ floating_ip['id'])
# Clean up routers
for router in cls.routers:
- cls.delete_router(router)
+ cls._try_delete_resource(cls.delete_router,
+ router)
# Clean up health monitors
for health_monitor in cls.health_monitors:
- cls.client.delete_health_monitor(health_monitor['id'])
+ cls._try_delete_resource(cls.client.delete_health_monitor,
+ health_monitor['id'])
# Clean up members
for member in cls.members:
- cls.client.delete_member(member['id'])
+ cls._try_delete_resource(cls.client.delete_member,
+ member['id'])
# Clean up vips
for vip in cls.vips:
- cls.client.delete_vip(vip['id'])
+ cls._try_delete_resource(cls.client.delete_vip,
+ vip['id'])
# Clean up pools
for pool in cls.pools:
- cls.client.delete_pool(pool['id'])
+ cls._try_delete_resource(cls.client.delete_pool,
+ pool['id'])
# Clean up metering label rules
for metering_label_rule in cls.metering_label_rules:
- cls.admin_client.delete_metering_label_rule(
+ cls._try_delete_resource(
+ cls.admin_client.delete_metering_label_rule,
metering_label_rule['id'])
# Clean up metering labels
for metering_label in cls.metering_labels:
- cls.admin_client.delete_metering_label(metering_label['id'])
+ cls._try_delete_resource(
+ cls.admin_client.delete_metering_label,
+ metering_label['id'])
# Clean up ports
for port in cls.ports:
- cls.client.delete_port(port['id'])
+ cls._try_delete_resource(cls.client.delete_port,
+ port['id'])
# Clean up subnets
for subnet in cls.subnets:
- cls.client.delete_subnet(subnet['id'])
+ cls._try_delete_resource(cls.client.delete_subnet,
+ subnet['id'])
# Clean up networks
for network in cls.networks:
- cls.client.delete_network(network['id'])
+ cls._try_delete_resource(cls.client.delete_network,
+ network['id'])
cls.clear_isolated_creds()
super(BaseNetworkTest, cls).resource_cleanup()
@classmethod
+ def _try_delete_resource(self, delete_callable, *args, **kwargs):
+ """Cleanup resources in case of test-failure
+
+ Some resources are explicitly deleted by the test.
+ If the test failed to delete a resource, this method will execute
+ the appropriate delete methods. Otherwise, the method ignores NotFound
+ exceptions thrown for resources that were correctly deleted by the
+ test.
+
+ :param delete_callable: delete method
+ :param args: arguments for delete method
+ :param kwargs: keyword arguments for delete method
+ """
+ try:
+ delete_callable(*args, **kwargs)
+ # if resource is not found, this means it was deleted in the test
+ except exceptions.NotFound:
+ pass
+
+ @classmethod
def create_network(cls, network_name=None):
"""Wrapper utility that returns a test network."""
network_name = network_name or data_utils.rand_name('test-network-')
@@ -152,33 +191,40 @@
return network
@classmethod
- def create_subnet(cls, network, gateway=None, cidr=None, mask_bits=None,
- **kwargs):
+ def create_subnet(cls, network, gateway='', cidr=None, mask_bits=None,
+ ip_version=None, client=None, **kwargs):
"""Wrapper utility that returns a test subnet."""
+
+ # allow tests to use admin client
+ if not client:
+ client = cls.client
+
# The cidr and mask_bits depend on the ip version.
- if cls._ip_version == 4:
+ ip_version = ip_version if ip_version is not None else cls._ip_version
+ gateway_not_set = gateway == ''
+ if ip_version == 4:
cidr = cidr or netaddr.IPNetwork(CONF.network.tenant_network_cidr)
mask_bits = mask_bits or CONF.network.tenant_network_mask_bits
- elif cls._ip_version == 6:
+ elif ip_version == 6:
cidr = (
cidr or netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr))
mask_bits = mask_bits or CONF.network.tenant_network_v6_mask_bits
# Find a cidr that is not in use yet and create a subnet with it
for subnet_cidr in cidr.subnet(mask_bits):
- if not gateway:
- gateway = str(netaddr.IPAddress(subnet_cidr) + 1)
+ if gateway_not_set:
+ gateway_ip = str(netaddr.IPAddress(subnet_cidr) + 1)
+ else:
+ gateway_ip = gateway
try:
- resp, body = cls.client.create_subnet(
+ resp, body = client.create_subnet(
network_id=network['id'],
cidr=str(subnet_cidr),
- ip_version=cls._ip_version,
- gateway_ip=gateway,
+ ip_version=ip_version,
+ gateway_ip=gateway_ip,
**kwargs)
break
except exceptions.BadRequest as e:
is_overlapping_cidr = 'overlaps with another subnet' in str(e)
- # Unset gateway value if there is an overlapping subnet
- gateway = None
if not is_overlapping_cidr:
raise
else:
@@ -266,9 +312,11 @@
return vip
@classmethod
- def create_member(cls, protocol_port, pool):
+ def create_member(cls, protocol_port, pool, ip_version=None):
"""Wrapper utility that returns a test member."""
- resp, body = cls.client.create_member(address="10.0.9.46",
+ ip_version = ip_version if ip_version is not None else cls._ip_version
+ member_address = "fd00::abcd" if ip_version == 6 else "10.0.9.46"
+ resp, body = cls.client.create_member(address=member_address,
protocol_port=protocol_port,
pool_id=pool['id'])
member = body['member']
diff --git a/tempest/api/network/test_allowed_address_pair.py b/tempest/api/network/test_allowed_address_pair.py
index c085c39..7b7a5db 100644
--- a/tempest/api/network/test_allowed_address_pair.py
+++ b/tempest/api/network/test_allowed_address_pair.py
@@ -13,9 +13,14 @@
# License for the specific language governing permissions and limitations
# under the License.
+import netaddr
+
from tempest.api.network import base
+from tempest import config
from tempest import test
+CONF = config.CONF
+
class AllowedAddressPairTestJSON(base.BaseNetworkTest):
_interface = 'json'
@@ -68,22 +73,50 @@
self._confirm_allowed_address_pair(port[0], self.ip_address)
@test.attr(type='smoke')
- def test_update_port_with_address_pair(self):
+ def _update_port_with_address(self, address, mac_address=None, **kwargs):
# Create a port without allowed address pair
_, body = self.client.create_port(network_id=self.network['id'])
port_id = body['port']['id']
self.addCleanup(self.client.delete_port, port_id)
-
- # Confirm port is created
- _, body = self.client.show_port(port_id)
+ if mac_address is None:
+ mac_address = self.mac_address
# Update allowed address pair attribute of port
- allowed_address_pairs = [{'ip_address': self.ip_address,
- 'mac_address': self.mac_address}]
+ allowed_address_pairs = [{'ip_address': address,
+ 'mac_address': mac_address}]
+ if kwargs:
+ allowed_address_pairs.append(kwargs['allowed_address_pairs'])
_, body = self.client.update_port(
port_id, allowed_address_pairs=allowed_address_pairs)
- newport = body['port']
- self._confirm_allowed_address_pair(newport, self.ip_address)
+ allowed_address_pair = body['port']['allowed_address_pairs']
+ self.assertEqual(allowed_address_pair, allowed_address_pairs)
+
+ @test.attr(type='smoke')
+ def test_update_port_with_address_pair(self):
+ # Update port with allowed address pair
+ self._update_port_with_address(self.ip_address)
+
+ @test.attr(type='smoke')
+ def test_update_port_with_cidr_address_pair(self):
+ # Update allowed address pair with cidr
+ cidr = str(netaddr.IPNetwork(CONF.network.tenant_network_cidr))
+ self._update_port_with_address(cidr)
+
+ @test.attr(type='smoke')
+ def test_update_port_with_multiple_ip_mac_address_pair(self):
+ # Create an ip _address and mac_address through port create
+ _, resp = self.client.create_port(network_id=self.network['id'])
+ newportid = resp['port']['id']
+ self.addCleanup(self.client.delete_port, newportid)
+ ipaddress = resp['port']['fixed_ips'][0]['ip_address']
+ macaddress = resp['port']['mac_address']
+
+ # Update allowed address pair port with multiple ip and mac
+ allowed_address_pairs = {'ip_address': ipaddress,
+ 'mac_address': macaddress}
+ self._update_port_with_address(
+ self.ip_address, self.mac_address,
+ allowed_address_pairs=allowed_address_pairs)
def _confirm_allowed_address_pair(self, port, ip):
msg = 'Port allowed address pairs should not be empty'
@@ -94,5 +127,5 @@
self.assertEqual(mac_address, self.mac_address)
-class AllowedAddressPairTestXML(AllowedAddressPairTestJSON):
- _interface = 'xml'
+class AllowedAddressPairIpV6TestJSON(AllowedAddressPairTestJSON):
+ _ip_version = 6
diff --git a/tempest/api/network/test_extensions.py b/tempest/api/network/test_extensions.py
index 715136c..1c7feb3 100644
--- a/tempest/api/network/test_extensions.py
+++ b/tempest/api/network/test_extensions.py
@@ -73,7 +73,3 @@
for e in expected_alias:
if test.is_extension_enabled(e, 'network'):
self.assertIn(e, actual_alias)
-
-
-class ExtensionsTestXML(ExtensionsTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/network/test_extra_dhcp_options.py b/tempest/api/network/test_extra_dhcp_options.py
index 86da9b7..6d083b3 100644
--- a/tempest/api/network/test_extra_dhcp_options.py
+++ b/tempest/api/network/test_extra_dhcp_options.py
@@ -44,17 +44,22 @@
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network)
cls.port = cls.create_port(cls.network)
+ cls.ip_tftp = ('123.123.123.123' if cls._ip_version == 4
+ else '2015::dead')
+ cls.ip_server = ('123.123.123.45' if cls._ip_version == 4
+ else '2015::badd')
+ cls.extra_dhcp_opts = [
+ {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'},
+ {'opt_value': cls.ip_tftp, 'opt_name': 'tftp-server'},
+ {'opt_value': cls.ip_server, 'opt_name': 'server-ip-address'}
+ ]
@test.attr(type='smoke')
def test_create_list_port_with_extra_dhcp_options(self):
# Create a port with Extra DHCP Options
- extra_dhcp_opts = [
- {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'},
- {'opt_value': '123.123.123.123', 'opt_name': 'tftp-server'},
- {'opt_value': '123.123.123.45', 'opt_name': 'server-ip-address'}
- ]
- _, body = self.client.create_port(network_id=self.network['id'],
- extra_dhcp_opts=extra_dhcp_opts)
+ _, body = self.client.create_port(
+ network_id=self.network['id'],
+ extra_dhcp_opts=self.extra_dhcp_opts)
port_id = body['port']['id']
self.addCleanup(self.client.delete_port, port_id)
@@ -63,23 +68,19 @@
ports = body['ports']
port = [p for p in ports if p['id'] == port_id]
self.assertTrue(port)
- self._confirm_extra_dhcp_options(port[0], extra_dhcp_opts)
+ self._confirm_extra_dhcp_options(port[0], self.extra_dhcp_opts)
@test.attr(type='smoke')
def test_update_show_port_with_extra_dhcp_options(self):
# Update port with extra dhcp options
- extra_dhcp_opts = [
- {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'},
- {'opt_value': '123.123.123.123', 'opt_name': 'tftp-server'},
- {'opt_value': '123.123.123.45', 'opt_name': 'server-ip-address'}
- ]
name = data_utils.rand_name('new-port-name')
- _, body = self.client.update_port(self.port['id'], name=name,
- extra_dhcp_opts=extra_dhcp_opts)
-
+ _, body = self.client.update_port(
+ self.port['id'],
+ name=name,
+ extra_dhcp_opts=self.extra_dhcp_opts)
# Confirm extra dhcp options were added to the port
_, body = self.client.show_port(self.port['id'])
- self._confirm_extra_dhcp_options(body['port'], extra_dhcp_opts)
+ self._confirm_extra_dhcp_options(body['port'], self.extra_dhcp_opts)
def _confirm_extra_dhcp_options(self, port, extra_dhcp_opts):
retrieved = port['extra_dhcp_opts']
@@ -92,3 +93,7 @@
else:
self.fail('Extra DHCP option not found in port %s' %
str(retrieved_option))
+
+
+class ExtraDHCPOptionsIpV6TestJSON(ExtraDHCPOptionsTestJSON):
+ _ip_version = 6
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index 52672ea..9beae0a 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -213,7 +213,3 @@
update_floating_ip = body['floatingip']
self.assertEqual(update_floating_ip['fixed_ip_address'],
list_ips[1])
-
-
-class FloatingIPTestXML(FloatingIPTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/network/test_fwaas_extensions.py b/tempest/api/network/test_fwaas_extensions.py
index 8e2b7f5..12b8887 100644
--- a/tempest/api/network/test_fwaas_extensions.py
+++ b/tempest/api/network/test_fwaas_extensions.py
@@ -254,7 +254,3 @@
fw_policy_id)
return [ruleid for ruleid in fw_policy['firewall_policy']
['firewall_rules']]
-
-
-class FWaaSExtensionTestXML(FWaaSExtensionTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/network/test_load_balancer.py b/tempest/api/network/test_load_balancer.py
index baa8cad..41294f6 100644
--- a/tempest/api/network/test_load_balancer.py
+++ b/tempest/api/network/test_load_balancer.py
@@ -55,7 +55,9 @@
protocol_port=80,
subnet=cls.subnet,
pool=cls.pool)
- cls.member = cls.create_member(80, cls.pool)
+ cls.member = cls.create_member(80, cls.pool, cls._ip_version)
+ cls.member_address = ("10.0.9.47" if cls._ip_version == 4
+ else "2015::beef")
cls.health_monitor = cls.create_health_monitor(delay=4,
max_retries=3,
Type="TCP",
@@ -213,13 +215,14 @@
def test_list_members_with_filters(self):
attr_exceptions = ['status', 'status_description']
self._check_list_with_filter('member', attr_exceptions,
- address="10.0.9.47", protocol_port=80,
+ address=self.member_address,
+ protocol_port=80,
pool_id=self.pool['id'])
@test.attr(type='smoke')
def test_create_update_delete_member(self):
# Creates a member
- _, body = self.client.create_member(address="10.0.9.47",
+ _, body = self.client.create_member(address=self.member_address,
protocol_port=80,
pool_id=self.pool['id'])
member = body['member']
@@ -419,5 +422,5 @@
self.assertEqual(2, member['weight'])
-class LoadBalancerTestXML(LoadBalancerTestJSON):
- _interface = 'xml'
+class LoadBalancerIpV6TestJSON(LoadBalancerTestJSON):
+ _ip_version = 6
diff --git a/tempest/api/network/test_metering_extensions.py b/tempest/api/network/test_metering_extensions.py
index 2cfb841..daf9948 100644
--- a/tempest/api/network/test_metering_extensions.py
+++ b/tempest/api/network/test_metering_extensions.py
@@ -43,7 +43,8 @@
description = "metering label created by tempest"
name = data_utils.rand_name("metering-label")
cls.metering_label = cls.create_metering_label(name, description)
- remote_ip_prefix = "10.0.0.0/24"
+ remote_ip_prefix = ("10.0.0.0/24" if cls._ip_version == 4
+ else "fd02::/64")
direction = "ingress"
cls.metering_label_rule = cls.create_metering_label_rule(
remote_ip_prefix, direction,
@@ -112,8 +113,10 @@
@test.attr(type='smoke')
def test_create_delete_metering_label_rule_with_filters(self):
# Creates a rule
+ remote_ip_prefix = ("10.0.1.0/24" if self._ip_version == 4
+ else "fd03::/64")
_, body = (self.admin_client.create_metering_label_rule(
- remote_ip_prefix="10.0.1.0/24",
+ remote_ip_prefix=remote_ip_prefix,
direction="ingress",
metering_label_id=self.metering_label['id']))
metering_label_rule = body['metering_label_rule']
@@ -142,5 +145,5 @@
self.assertFalse(metering_label_rule['excluded'])
-class MeteringXML(MeteringJSON):
- interface = 'xml'
+class MeteringIpV6JSON(MeteringJSON):
+ _ip_version = 6
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 986a2c8..ccc489e 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -12,6 +12,7 @@
# 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 itertools
import netaddr
import testtools
@@ -42,6 +43,7 @@
network update
subnet update
delete a network also deletes its subnets
+ list external networks
All subnet tests are run once with ipv4 and once with ipv6.
@@ -280,6 +282,10 @@
self.subnets.pop()
@test.attr(type='smoke')
+ def test_create_delete_subnet_without_gateway(self):
+ self._create_verify_delete_subnet()
+
+ @test.attr(type='smoke')
def test_create_delete_subnet_with_gw(self):
self._create_verify_delete_subnet(
**self.subnet_dict(['gateway']))
@@ -341,9 +347,27 @@
enable_dhcp=True,
**self.subnet_dict(['gateway', 'host_routes', 'dns_nameservers']))
+ @test.attr(type='smoke')
+ def test_external_network_visibility(self):
+ """Verifies user can see external networks but not subnets."""
+ _, body = self.client.list_networks(**{'router:external': True})
+ networks = [network['id'] for network in body['networks']]
+ self.assertNotEmpty(networks, "No external networks found")
-class NetworksTestXML(NetworksTestJSON):
- _interface = 'xml'
+ nonexternal = [net for net in body['networks'] if
+ not net['router:external']]
+ self.assertEmpty(nonexternal, "Found non-external networks"
+ " in filtered list (%s)." % nonexternal)
+ self.assertIn(CONF.network.public_network_id, networks)
+
+ subnets_iter = (network['subnets'] for network in body['networks'])
+ # subnets_iter is a list (iterator) of lists. This flattens it to a
+ # list of UUIDs
+ public_subnets_iter = itertools.chain(*subnets_iter)
+ _, body = self.client.list_subnets()
+ subnets = [sub['id'] for sub in body['subnets']
+ if sub['id'] in public_subnets_iter]
+ self.assertEmpty(subnets, "Public subnets visible")
class BulkNetworkOpsTestJSON(base.BaseNetworkTest):
@@ -467,20 +491,9 @@
self.assertIn(n['id'], ports_list)
-class BulkNetworkOpsTestXML(BulkNetworkOpsTestJSON):
- _interface = 'xml'
-
-
class NetworksIpV6TestJSON(NetworksTestJSON):
_ip_version = 6
- @classmethod
- def resource_setup(cls):
- if not CONF.network_feature_enabled.ipv6:
- skip_msg = "IPv6 Tests are disabled."
- raise cls.skipException(skip_msg)
- super(NetworksIpV6TestJSON, cls).resource_setup()
-
@test.attr(type='smoke')
def test_create_delete_subnet_with_gw(self):
net = netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr)
@@ -492,7 +505,7 @@
self.assertEqual(subnet['gateway_ip'], gateway)
@test.attr(type='smoke')
- def test_create_delete_subnet_without_gw(self):
+ def test_create_delete_subnet_with_default_gw(self):
net = netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr)
gateway_ip = str(netaddr.IPAddress(net.first + 1))
name = data_utils.rand_name('network-')
@@ -501,16 +514,58 @@
# Verifies Subnet GW in IPv6
self.assertEqual(subnet['gateway_ip'], gateway_ip)
+ @test.attr(type='smoke')
+ def test_create_list_subnet_with_no_gw64_one_network(self):
+ name = data_utils.rand_name('network-')
+ network = self.create_network(name)
+ ipv6_gateway = self.subnet_dict(['gateway'])['gateway']
+ subnet1 = self.create_subnet(network,
+ ip_version=6,
+ gateway=ipv6_gateway)
+ self.assertEqual(netaddr.IPNetwork(subnet1['cidr']).version, 6,
+ 'The created subnet is not IPv6')
+ subnet2 = self.create_subnet(network,
+ gateway=None,
+ ip_version=4)
+ self.assertEqual(netaddr.IPNetwork(subnet2['cidr']).version, 4,
+ 'The created subnet is not IPv4')
+ # Verifies Subnet GW is set in IPv6
+ self.assertEqual(subnet1['gateway_ip'], ipv6_gateway)
+ # Verifies Subnet GW is None in IPv4
+ self.assertEqual(subnet2['gateway_ip'], None)
+ # Verifies all 2 subnets in the same network
+ _, body = self.client.list_subnets()
+ subnets = [sub['id'] for sub in body['subnets']
+ if sub['network_id'] == network['id']]
+ test_subnet_ids = [sub['id'] for sub in (subnet1, subnet2)]
+ self.assertItemsEqual(subnets,
+ test_subnet_ids,
+ 'Subnet are not in the same network')
+
@testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
"IPv6 extended attributes for subnets not "
"available")
@test.attr(type='smoke')
- def test_create_delete_subnet_with_v6_attributes(self):
+ def test_create_delete_subnet_with_v6_attributes_stateful(self):
self._create_verify_delete_subnet(
gateway=self._subnet_data[self._ip_version]['gateway'],
+ ipv6_ra_mode='dhcpv6-stateful',
+ ipv6_address_mode='dhcpv6-stateful')
+
+ @testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
+ "IPv6 extended attributes for subnets not "
+ "available")
+ @test.attr(type='smoke')
+ def test_create_delete_subnet_with_v6_attributes_slaac(self):
+ self._create_verify_delete_subnet(
ipv6_ra_mode='slaac',
ipv6_address_mode='slaac')
-
-class NetworksIpV6TestXML(NetworksIpV6TestJSON):
- _interface = 'xml'
+ @testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
+ "IPv6 extended attributes for subnets not "
+ "available")
+ @test.attr(type='smoke')
+ def test_create_delete_subnet_with_v6_attributes_stateless(self):
+ self._create_verify_delete_subnet(
+ ipv6_ra_mode='dhcpv6-stateless',
+ ipv6_address_mode='dhcpv6-stateless')
diff --git a/tempest/api/network/test_networks_negative.py b/tempest/api/network/test_networks_negative.py
index 53dfc52..bc3ab68 100644
--- a/tempest/api/network/test_networks_negative.py
+++ b/tempest/api/network/test_networks_negative.py
@@ -52,7 +52,3 @@
non_exist_id = data_utils.rand_name('network')
self.assertRaises(exceptions.NotFound, self.client.delete_network,
non_exist_id)
-
-
-class NetworksNegativeTestXML(NetworksNegativeTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index d6db64d..d30c7dc 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -187,10 +187,6 @@
data_utils.rand_name('secgroup')])
-class PortsTestXML(PortsTestJSON):
- _interface = 'xml'
-
-
class PortsAdminExtendedAttrsTestJSON(base.BaseAdminNetworkTest):
_interface = 'json'
@@ -267,39 +263,13 @@
show_port['binding:vif_details'])
-class PortsAdminExtendedAttrsTestXML(PortsAdminExtendedAttrsTestJSON):
- _interface = 'xml'
-
-
class PortsIpV6TestJSON(PortsTestJSON):
_ip_version = 6
_tenant_network_cidr = CONF.network.tenant_network_v6_cidr
_tenant_network_mask_bits = CONF.network.tenant_network_v6_mask_bits
- @classmethod
- def resource_setup(cls):
- super(PortsIpV6TestJSON, cls).resource_setup()
- if not CONF.network_feature_enabled.ipv6:
- skip_msg = "IPv6 Tests are disabled."
- raise cls.skipException(skip_msg)
-
-
-class PortsIpV6TestXML(PortsIpV6TestJSON):
- _interface = 'xml'
-
class PortsAdminExtendedAttrsIpV6TestJSON(PortsAdminExtendedAttrsTestJSON):
_ip_version = 6
_tenant_network_cidr = CONF.network.tenant_network_v6_cidr
_tenant_network_mask_bits = CONF.network.tenant_network_v6_mask_bits
-
- @classmethod
- def resource_setup(cls):
- if not CONF.network_feature_enabled.ipv6:
- skip_msg = "IPv6 Tests are disabled."
- raise cls.skipException(skip_msg)
- super(PortsAdminExtendedAttrsIpV6TestJSON, cls).resource_setup()
-
-
-class PortsAdminExtendedAttrsIpV6TestXML(PortsAdminExtendedAttrsIpV6TestJSON):
- _interface = 'xml'
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index f3f25ac..2b4e60a 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -35,6 +35,9 @@
raise cls.skipException(msg)
admin_manager = clients.AdminManager()
cls.identity_admin_client = admin_manager.identity_client
+ cls.tenant_cidr = (CONF.network.tenant_network_cidr
+ if cls._ip_version == 4 else
+ CONF.network.tenant_network_v6_cidr)
def _cleanup_router(self, router):
self.delete_router(router)
@@ -319,7 +322,7 @@
network02 = self.create_network(
network_name=data_utils.rand_name('router-network02-'))
subnet01 = self.create_subnet(network01)
- sub02_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr).next()
+ sub02_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
subnet02 = self.create_subnet(network02, cidr=sub02_cidr)
router = self._create_router(data_utils.rand_name('router-'))
interface01 = self._add_router_interface_with_subnet_id(router['id'],
@@ -337,3 +340,7 @@
self.assertEqual(router_id, interface_port['device_id'])
self.assertEqual(subnet_id,
interface_port['fixed_ips'][0]['subnet_id'])
+
+
+class RoutersIpV6Test(RoutersTest):
+ _ip_version = 6
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index 4c226af..88aa3c9 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -36,6 +36,9 @@
cls.router = cls.create_router(data_utils.rand_name('router-'))
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network)
+ cls.tenant_cidr = (CONF.network.tenant_network_cidr
+ if cls._ip_version == 4 else
+ CONF.network.tenant_network_v6_cidr)
@test.attr(type=['negative', 'smoke'])
def test_router_add_gateway_invalid_network_returns_404(self):
@@ -49,7 +52,7 @@
def test_router_add_gateway_net_not_external_returns_400(self):
alt_network = self.create_network(
network_name=data_utils.rand_name('router-negative-'))
- sub_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr).next()
+ sub_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
self.create_subnet(alt_network, cidr=sub_cidr)
self.assertRaises(exceptions.BadRequest,
self.client.update_router,
@@ -79,3 +82,7 @@
self.assertRaises(exceptions.Conflict,
self.client.delete_router,
self.router['id'])
+
+
+class RoutersNegativeIpV6Test(RoutersNegativeTest):
+ _ip_version = 6
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index e20b58e..b995b1d 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -212,22 +212,25 @@
port_range_max,
remote_ip_prefix=ip_prefix)
-
-class SecGroupTestXML(SecGroupTest):
- _interface = 'xml'
+ @test.attr(type='smoke')
+ def test_create_security_group_rule_with_protocol_integer_value(self):
+ # Verify creating security group rule with the
+ # protocol as integer value
+ # arguments : "protocol": 17
+ group_create_body, _ = self._create_security_group()
+ direction = 'ingress'
+ protocol = 17
+ security_group_id = group_create_body['security_group']['id']
+ _, rule_create_body = self.client.create_security_group_rule(
+ security_group_id=security_group_id,
+ direction=direction,
+ protocol=protocol
+ )
+ sec_group_rule = rule_create_body['security_group_rule']
+ self.assertEqual(sec_group_rule['direction'], direction)
+ self.assertEqual(int(sec_group_rule['protocol']), protocol)
class SecGroupIPv6Test(SecGroupTest):
_ip_version = 6
_tenant_network_cidr = CONF.network.tenant_network_v6_cidr
-
- @classmethod
- def resource_setup(cls):
- if not CONF.network_feature_enabled.ipv6:
- skip_msg = "IPv6 Tests are disabled."
- raise cls.skipException(skip_msg)
- super(SecGroupIPv6Test, cls).resource_setup()
-
-
-class SecGroupIPv6TestXML(SecGroupIPv6Test):
- _interface = 'xml'
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index 87267d6..b9e8666 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -190,21 +190,6 @@
direction='ingress', ethertype=self.ethertype)
-class NegativeSecGroupTestXML(NegativeSecGroupTest):
- _interface = 'xml'
-
-
class NegativeSecGroupIPv6Test(NegativeSecGroupTest):
_ip_version = 6
_tenant_network_cidr = CONF.network.tenant_network_v6_cidr
-
- @classmethod
- def resource_setup(cls):
- if not CONF.network_feature_enabled.ipv6:
- skip_msg = "IPv6 Tests are disabled."
- raise cls.skipException(skip_msg)
- super(NegativeSecGroupIPv6Test, cls).resource_setup()
-
-
-class NegativeSecGroupIPv6TestXML(NegativeSecGroupIPv6Test):
- _interface = 'xml'
diff --git a/tempest/api/network/test_service_type_management.py b/tempest/api/network/test_service_type_management.py
index 302069f..6695f47 100644
--- a/tempest/api/network/test_service_type_management.py
+++ b/tempest/api/network/test_service_type_management.py
@@ -28,7 +28,3 @@
def test_service_provider_list(self):
_, body = self.client.list_service_providers()
self.assertIsInstance(body['service_providers'], list)
-
-
-class ServiceTypeManagementTestXML(ServiceTypeManagementTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/network/test_vpnaas_extensions.py b/tempest/api/network/test_vpnaas_extensions.py
index c61bf41..46f10c4 100644
--- a/tempest/api/network/test_vpnaas_extensions.py
+++ b/tempest/api/network/test_vpnaas_extensions.py
@@ -39,6 +39,7 @@
msg = "vpnaas extension not enabled."
raise cls.skipException(msg)
super(VPNaaSTestJSON, cls).resource_setup()
+ cls.ext_net_id = CONF.network.public_network_id
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network)
cls.router = cls.create_router(
@@ -121,17 +122,21 @@
tenant_id = self._get_tenant_id()
# Create vpn service for the newly created tenant
+ network2 = self.create_network()
+ subnet2 = self.create_subnet(network2)
+ router2 = self.create_router(data_utils.rand_name('router-'),
+ external_network_id=self.ext_net_id)
+ self.create_router_interface(router2['id'], subnet2['id'])
name = data_utils.rand_name('vpn-service')
_, body = self.admin_client.create_vpnservice(
- subnet_id=self.subnet['id'],
- router_id=self.router['id'],
+ subnet_id=subnet2['id'],
+ router_id=router2['id'],
name=name,
admin_state_up=True,
tenant_id=tenant_id)
vpnservice = body['vpnservice']
self.assertIsNotNone(vpnservice['id'])
self.addCleanup(self.admin_client.delete_vpnservice, vpnservice['id'])
-
# Assert that created vpnservice is found in API list call
_, body = self.client.list_vpnservices()
vpn_services = [vs['id'] for vs in body['vpnservices']]
@@ -167,9 +172,14 @@
@test.attr(type='smoke')
def test_create_update_delete_vpn_service(self):
# Creates a VPN service and sets up deletion
- name = data_utils.rand_name('vpn-service')
- _, body = self.client.create_vpnservice(subnet_id=self.subnet['id'],
- router_id=self.router['id'],
+ network1 = self.create_network()
+ subnet1 = self.create_subnet(network1)
+ router1 = self.create_router(data_utils.rand_name('router-'),
+ external_network_id=self.ext_net_id)
+ self.create_router_interface(router1['id'], subnet1['id'])
+ name = data_utils.rand_name('vpn-service1')
+ _, body = self.client.create_vpnservice(subnet_id=subnet1['id'],
+ router_id=router1['id'],
name=name,
admin_state_up=True)
vpnservice = body['vpnservice']
@@ -303,7 +313,3 @@
_, body = self.client.show_ipsecpolicy(self.ipsecpolicy['id'])
ipsecpolicy = body['ipsecpolicy']
self._assertExpected(self.ipsecpolicy, ipsecpolicy)
-
-
-class VPNaaSTestXML(VPNaaSTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 2e39cf9..7fabb7d 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -16,8 +16,8 @@
from tempest.api.identity import base
from tempest import clients
+from tempest.common import credentials
from tempest.common import custom_matchers
-from tempest.common import isolated_creds
from tempest import config
from tempest import exceptions
import tempest.test
@@ -34,7 +34,7 @@
if not CONF.service_available.swift:
skip_msg = ("%s skipped as swift is not available" % cls.__name__)
raise cls.skipException(skip_msg)
- cls.isolated_creds = isolated_creds.IsolatedCreds(
+ cls.isolated_creds = credentials.get_isolated_credentials(
cls.__name__, network_resources=cls.network_resources)
# Get isolated creds for normal user
cls.os = clients.Manager(cls.isolated_creds.get_primary_creds())
diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py
index 743f1aa..31a80cf 100644
--- a/tempest/api/object_storage/test_account_bulk.py
+++ b/tempest/api/object_storage/test_account_bulk.py
@@ -74,8 +74,6 @@
self.containers.append(container_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
-
# When uploading an archived file with the bulk operation, the response
# does not contain 'content-length' header. This is the special case,
# therefore the existence of response headers is checked without
@@ -91,7 +89,6 @@
param = {'format': 'json'}
resp, body = self.account_client.list_account_containers(param)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'GET')
self.assertIn(container_name, [b['name'] for b in body])
@@ -100,7 +97,6 @@
resp, contents_list = self.container_client.list_container_contents(
container_name, param)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertIn(object_name, [c['name'] for c in contents_list])
diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py
index 97e9195..e75e971 100644
--- a/tempest/api/object_storage/test_account_quotas.py
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -83,7 +83,6 @@
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
- self.assertEqual(resp["status"], "201")
self.assertHeaders(resp, 'Object', 'PUT')
@test.attr(type=["smoke"])
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index a0436ee..2bc4f59 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -67,7 +67,6 @@
resp, container_list = \
os_test_user.account_client.list_account_containers()
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
# When sending a request to an account which has not received a PUT
# container request, the response does not contain 'accept-ranges'
@@ -93,7 +92,6 @@
params = {'format': 'json'}
resp, container_list = self.account_client.list_account_containers(
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'GET')
self.assertIsNotNone(container_list)
self.assertTrue([c['name'] for c in container_list])
@@ -106,7 +104,6 @@
params = {'format': 'xml'}
resp, container_list = self.account_client.list_account_containers(
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'GET')
self.assertIsNotNone(container_list)
self.assertEqual(container_list.tag, 'account')
@@ -123,7 +120,6 @@
def test_list_extensions(self):
resp, extensions = self.account_client.list_extensions()
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertThat(resp, custom_matchers.AreAllWellFormatted())
@test.attr(type='smoke')
@@ -182,7 +178,6 @@
'end_marker': self.containers[self.containers_count - 1]}
resp, container_list = self.account_client.list_account_containers(
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'GET')
self.assertEqual(len(container_list), self.containers_count - 2)
@@ -208,7 +203,6 @@
'end_marker': self.containers[self.containers_count / 2]}
resp, container_list = self.account_client.list_account_containers(
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'GET')
self.assertEqual(len(container_list),
min(limit, self.containers_count / 2))
@@ -222,7 +216,6 @@
'end_marker': self.containers[self.containers_count - 1]}
resp, container_list = self.account_client.list_account_containers(
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'GET')
self.assertEqual(len(container_list),
min(limit, self.containers_count - 2))
@@ -237,7 +230,6 @@
resp, _ = self.account_client.create_account_metadata(metadata)
resp, _ = self.account_client.list_account_metadata()
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'HEAD')
self.assertIn('x-account-meta-test-account-meta1', resp)
self.assertIn('x-account-meta-test-account-meta2', resp)
@@ -247,7 +239,6 @@
def test_list_no_account_metadata(self):
# list no account metadata
resp, _ = self.account_client.list_account_metadata()
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'HEAD')
self.assertNotIn('x-account-meta-', str(resp))
@@ -256,7 +247,6 @@
# add metadata to account
metadata = {'test-account-meta1': 'Meta1'}
resp, _ = self.account_client.create_account_metadata(metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'POST')
resp, body = self.account_client.list_account_metadata()
@@ -272,7 +262,6 @@
metadata = {'test-account-meta1': 'Meta1'}
self.account_client.create_account_metadata(metadata)
resp, _ = self.account_client.delete_account_metadata(metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'POST')
resp, _ = self.account_client.list_account_metadata()
@@ -284,7 +273,6 @@
# registered at a server
metadata = {'test-account-meta1': ''}
resp, _ = self.account_client.create_account_metadata(metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'POST')
resp, _ = self.account_client.list_account_metadata()
@@ -298,7 +286,6 @@
self.account_client.create_account_metadata(metadata_1)
metadata_2 = {'test-account-meta1': ''}
resp, _ = self.account_client.delete_account_metadata(metadata_2)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'POST')
resp, _ = self.account_client.list_account_metadata()
@@ -313,7 +300,6 @@
resp, body = self.account_client.create_and_delete_account_metadata(
metadata_2,
metadata_1)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'POST')
resp, _ = self.account_client.list_account_metadata()
diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py
index e816a9f..2244900 100644
--- a/tempest/api/object_storage/test_container_acl.py
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -45,13 +45,11 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')
resp, _ = self.object_client.create_object(self.container_name,
object_name, 'data')
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
# Trying to read the object with rights
self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -60,7 +58,6 @@
)
resp, _ = self.custom_object_client.get_object(
self.container_name, object_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
@test.attr(type='smoke')
@@ -72,7 +69,6 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# Trying to write the object with rights
self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -83,5 +79,4 @@
resp, _ = self.custom_object_client.create_object(
self.container_name,
object_name, 'data')
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'PUT')
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index 9b49db3..fed4549 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -88,7 +88,6 @@
object_name = data_utils.rand_name(name='Object')
resp, _ = self.object_client.create_object(
self.container_name, object_name, 'data')
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
# trying to get object with non authorized user token
self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -106,7 +105,6 @@
object_name = data_utils.rand_name(name='Object')
resp, _ = self.object_client.create_object(
self.container_name, object_name, 'data')
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
# trying to delete object with non-authorized user token
self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -125,13 +123,11 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')
resp, _ = self.object_client.create_object(self.container_name,
object_name, 'data')
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
# Trying to read the object without rights
self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -150,7 +146,6 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# Trying to write the object without rights
self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -173,7 +168,6 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# Trying to write the object without write rights
self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -196,13 +190,11 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')
resp, _ = self.object_client.create_object(self.container_name,
object_name, 'data')
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
# Trying to delete the object without write rights
self.custom_object_client.auth_provider.set_alt_auth_data(
diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py
index 59b84d9..46944ed 100644
--- a/tempest/api/object_storage/test_container_quotas.py
+++ b/tempest/api/object_storage/test_container_quotas.py
@@ -61,7 +61,6 @@
resp, _ = self.object_client.create_object(
self.container_name, object_name, data)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'PUT')
nafter = self._get_bytes_used()
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 8689d10..fe06fd0 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -51,7 +51,6 @@
container_name = data_utils.rand_name(name='TestContainer')
resp, body = self.container_client.create_container(container_name)
self.containers.append(container_name)
- self.assertIn(resp['status'], ('202', '201'))
self.assertHeaders(resp, 'Container', 'PUT')
@test.attr(type='smoke')
@@ -62,7 +61,6 @@
self.containers.append(container_name)
resp, _ = self.container_client.create_container(container_name)
- self.assertIn(resp['status'], ('202', '201'))
self.assertHeaders(resp, 'Container', 'PUT')
@test.attr(type='smoke')
@@ -74,7 +72,6 @@
container_name,
metadata=metadata)
self.containers.append(container_name)
- self.assertIn(resp['status'], ('201', '202'))
self.assertHeaders(resp, 'Container', 'PUT')
resp, _ = self.container_client.list_container_metadata(
@@ -93,7 +90,6 @@
container_name,
metadata=metadata)
self.containers.append(container_name)
- self.assertIn(resp['status'], ('201', '202'))
self.assertHeaders(resp, 'Container', 'PUT')
resp, _ = self.container_client.list_container_metadata(
@@ -116,7 +112,6 @@
resp, _ = self.container_client.create_container(
container_name,
remove_metadata=metadata_2)
- self.assertIn(resp['status'], ('201', '202'))
self.assertHeaders(resp, 'Container', 'PUT')
resp, _ = self.container_client.list_container_metadata(
@@ -135,7 +130,6 @@
resp, _ = self.container_client.create_container(
container_name,
remove_metadata=metadata)
- self.assertIn(resp['status'], ('201', '202'))
self.assertHeaders(resp, 'Container', 'PUT')
resp, _ = self.container_client.list_container_metadata(
@@ -146,11 +140,9 @@
def test_delete_container(self):
# create a container
container_name = self._create_container()
- # delete container
+ # delete container, success asserted within
resp, _ = self.container_client.delete_container(container_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'DELETE')
-
self.containers.remove(container_name)
@test.attr(type='smoke')
@@ -161,7 +153,6 @@
resp, object_list = self.container_client.list_container_contents(
container_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
@@ -172,7 +163,6 @@
resp, object_list = self.container_client.list_container_contents(
container_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual('', object_list.strip('\n'))
@@ -187,7 +177,6 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name.split('/')[0], object_list.strip('/\n'))
@@ -201,7 +190,6 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
@@ -215,7 +203,6 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertIsNotNone(object_list)
@@ -235,7 +222,6 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertIsNotNone(object_list)
@@ -260,7 +246,6 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
@@ -274,7 +259,6 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
@@ -289,7 +273,6 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
@@ -304,7 +287,6 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
@@ -320,7 +302,6 @@
resp, _ = self.container_client.list_container_metadata(
container_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'HEAD')
self.assertIn('x-container-meta-name', resp)
self.assertEqual(resp['x-container-meta-name'], metadata['name'])
@@ -332,7 +313,6 @@
resp, _ = self.container_client.list_container_metadata(
container_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'HEAD')
self.assertNotIn('x-container-meta-', str(resp))
@@ -350,7 +330,6 @@
container_name,
metadata=metadata_2,
remove_metadata=metadata_1)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(
@@ -369,7 +348,6 @@
resp, _ = self.container_client.update_container_metadata(
container_name,
metadata=metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(
@@ -390,7 +368,6 @@
resp, _ = self.container_client.delete_container_metadata(
container_name,
metadata=metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(
@@ -406,7 +383,6 @@
resp, _ = self.container_client.update_container_metadata(
container_name,
metadata=metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(
@@ -426,7 +402,6 @@
resp, _ = self.container_client.delete_container_metadata(
container_name,
metadata=metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(container_name)
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 966a08d..5c4e0bf 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -67,7 +67,6 @@
# we should retrieve the self.object_name file
resp, body = self.custom_account_client.request("GET",
self.container_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
# This request is equivalent to GET object
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, self.object_data)
@@ -92,7 +91,6 @@
# we should retrieve a listing of objects
resp, body = self.custom_account_client.request("GET",
self.container_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
# The target of the request is not any Swift resource. Therefore, the
# existence of response header is checked without a custom matcher.
self.assertIn('content-length', resp)
@@ -131,7 +129,6 @@
# we should retrieve a listing of objects
resp, body = self.custom_account_client.request("GET",
self.container_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertIn(self.object_name, body)
css = '<link rel="stylesheet" type="text/css" href="listings.css" />'
self.assertIn(css, body)
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index aebcb5c..a50e392 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -90,12 +90,10 @@
(client_base_url, str(cont[1]))}
resp, body = \
cont_client[0].put(str(cont[0]), body=None, headers=headers)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
# create object in container
object_name = data_utils.rand_name(name='TestSyncObject')
data = object_name[::-1] # data_utils.arbitrary_string()
resp, _ = obj_client[0].create_object(cont[0], object_name, data)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.objects.append(object_name)
# wait until container contents list is not empty
@@ -108,7 +106,6 @@
cont_client[client_index].\
list_container_contents(self.containers[client_index],
params=params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
object_lists.append(dict(
(obj['name'], obj) for obj in object_list))
# check that containers are not empty and have equal keys()
@@ -128,5 +125,4 @@
for obj_client, cont in obj_clients:
for obj_name in object_lists[0]:
resp, object_content = obj_client.get_object(cont, obj_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertEqual(object_content, obj_name[::-1])
diff --git a/tempest/api/object_storage/test_crossdomain.py b/tempest/api/object_storage/test_crossdomain.py
index f6d1fb9..66e8176 100644
--- a/tempest/api/object_storage/test_crossdomain.py
+++ b/tempest/api/object_storage/test_crossdomain.py
@@ -43,7 +43,6 @@
def test_get_crossdomain_policy(self):
resp, body = self.account_client.get("crossdomain.xml", {})
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertTrue(body.startswith(self.xml_start) and
body.endswith(self.xml_end))
diff --git a/tempest/api/object_storage/test_healthcheck.py b/tempest/api/object_storage/test_healthcheck.py
index a1138e6..53c0347 100644
--- a/tempest/api/object_storage/test_healthcheck.py
+++ b/tempest/api/object_storage/test_healthcheck.py
@@ -36,9 +36,6 @@
resp, _ = self.account_client.get("healthcheck", {})
- # The status is expected to be 200
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
-
# The target of the request is not any Swift resource. Therefore, the
# existence of response header is checked without a custom matcher.
self.assertIn('content-length', resp)
diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py
index 8cec2fc..5fa209d 100644
--- a/tempest/api/object_storage/test_object_expiry.py
+++ b/tempest/api/object_storage/test_object_expiry.py
@@ -51,7 +51,6 @@
resp, _ = \
self.object_client.list_object_metadata(self.container_name,
self.object_name)
- self.assertEqual(resp['status'], '200')
self.assertHeaders(resp, 'Object', 'HEAD')
self.assertIn('x-delete-at', resp)
# we want to ensure that we will sleep long enough for things to
@@ -60,7 +59,6 @@
resp, body = self.object_client.get_object(self.container_name,
self.object_name)
- self.assertEqual(resp['status'], '200')
self.assertHeaders(resp, 'Object', 'GET')
self.assertIn('x-delete-at', resp)
diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py
index 05c8ff2..7a9fcf6 100644
--- a/tempest/api/object_storage/test_object_formpost.py
+++ b/tempest/api/object_storage/test_object_formpost.py
@@ -117,12 +117,10 @@
url = "%s/%s" % (self.container_name, self.object_name)
resp, body = self.object_client.post(url, body, headers=headers)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, "Object", "POST")
# Ensure object is available
resp, body = self.object_client.get("%s/%s%s" % (
self.container_name, self.object_name, "testfile"))
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, "Object", "GET")
self.assertEqual(body, "hello world")
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 56ab1fb..f78220c 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -60,7 +60,6 @@
for i in six.moves.xrange(segments):
resp, _ = self.object_client.create_object_segments(
self.container_name, object_name, i, data_segments[i])
- self.assertEqual(resp['status'], '201')
return object_name, data_segments
@@ -97,7 +96,6 @@
data = data_utils.arbitrary_string()
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
# check uploaded content
@@ -117,7 +115,6 @@
object_name,
data,
metadata=metadata)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
resp, body = self.object_client.get_object(
@@ -144,7 +141,6 @@
object_name,
data,
metadata=metadata)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
# download compressed object
@@ -168,7 +164,6 @@
object_name,
data,
metadata=metadata)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
# check uploaded content
@@ -212,7 +207,6 @@
name=object_name,
contents=StringIO.StringIO(data),
chunk_size=512)
- self.assertEqual(status, 201)
self.assertHeaders(resp_headers, 'Object', 'PUT')
# check uploaded content
@@ -239,7 +233,6 @@
object_name,
'',
metadata=metadata_2)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
resp, body = self.object_client.get_object(self.container_name,
@@ -258,7 +251,6 @@
object_name,
data,
metadata=metadata)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
resp, body = self.object_client.get_object(self.container_name,
@@ -278,7 +270,6 @@
object_name,
data,
metadata=metadata)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
resp, body = self.object_client.get_object(self.container_name,
@@ -303,7 +294,6 @@
object_name,
data,
metadata=metadata_remove)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
resp, body = self.object_client.get_object(self.container_name,
@@ -327,7 +317,6 @@
object_name,
data,
metadata=metadata_remove)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
resp, body = self.object_client.get_object(self.container_name,
@@ -345,7 +334,6 @@
# delete object
resp, _ = self.object_client.delete_object(self.container_name,
object_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'DELETE')
@test.attr(type='smoke')
@@ -359,7 +347,6 @@
object_name,
metadata,
metadata_prefix='')
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'POST')
resp, _ = self.object_client.list_object_metadata(
@@ -384,7 +371,6 @@
object_name,
update_metadata,
metadata_prefix='')
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'POST')
resp, _ = self.object_client.list_object_metadata(
@@ -410,7 +396,6 @@
object_name,
update_metadata,
metadata_prefix='')
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'POST')
resp, _ = self.object_client.list_object_metadata(
@@ -439,7 +424,6 @@
object_name,
update_metadata,
metadata_prefix='')
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'POST')
resp, _ = self.object_client.list_object_metadata(
@@ -458,7 +442,6 @@
object_name,
update_metadata,
metadata_prefix='')
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'POST')
resp, _ = self.object_client.list_object_metadata(
@@ -484,7 +467,6 @@
object_name,
update_metadata,
metadata_prefix='')
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'POST')
resp, _ = self.object_client.list_object_metadata(
@@ -506,7 +488,6 @@
resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'HEAD')
self.assertIn('x-object-meta-test-meta', resp)
self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
@@ -519,7 +500,6 @@
resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'HEAD')
self.assertNotIn('x-object-meta-', str(resp))
@@ -542,7 +522,6 @@
resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
# Check only the existence of common headers with custom matcher
self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders(
@@ -573,7 +552,6 @@
# get object
resp, body = self.object_client.get_object(self.container_name,
object_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
@@ -592,7 +570,6 @@
self.container_name,
object_name,
metadata=None)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
self.assertIn('x-object-meta-test-meta', resp)
self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
@@ -613,7 +590,6 @@
self.container_name,
object_name,
metadata=metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data[rand_num - 3: rand_num])
@@ -637,7 +613,6 @@
self.container_name,
object_name,
metadata=None)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
# Check only the existence of common headers with custom matcher
self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders(
@@ -678,7 +653,6 @@
self.container_name,
object_name,
metadata=list_metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
@@ -699,7 +673,6 @@
self.container_name,
object_name,
metadata=list_metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
@@ -721,7 +694,6 @@
self.container_name,
object_name,
metadata=list_metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
@@ -737,7 +709,6 @@
self.container_name,
object_name,
metadata=list_metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
@@ -751,7 +722,6 @@
self.container_name,
object_name,
metadata=list_metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
@@ -774,7 +744,6 @@
# copy source object to destination
resp, _ = self.object_client.copy_object_in_same_container(
self.container_name, src_object_name, dst_object_name)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
# check data
@@ -796,7 +765,6 @@
self.assertNotEqual(resp_tmp['content-type'], metadata['content-type'])
resp, _ = self.object_client.copy_object_in_same_container(
self.container_name, object_name, object_name, metadata)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
# check the content type
@@ -822,7 +790,6 @@
resp, _ = self.object_client.copy_object_2d_way(self.container_name,
src_object_name,
dst_object_name)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'COPY')
self.assertEqual(
resp['x-copied-from'],
@@ -855,14 +822,12 @@
resp, _ = self.object_client.update_object_metadata(src_container_name,
object_name,
orig_metadata)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'POST')
# copy object from source container to destination container
resp, _ = self.object_client.copy_object_across_containers(
src_container_name, object_name, dst_container_name,
object_name)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
# check if object is present in destination container
@@ -884,7 +849,6 @@
dst_object_name, resp = self._copy_object_2d(src_object_name,
metadata)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'COPY')
self.assertNotIn('x-object-meta-src', resp)
@@ -904,7 +868,6 @@
metadata = {'x-object-meta-test': ''}
dst_obj_name, resp = self._copy_object_2d(src_obj_name, metadata)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'COPY')
expected = {'x-object-meta-test': '',
@@ -927,7 +890,6 @@
metadata = {'x-object-meta-test': 'value'}
dst_obj_name, resp = self._copy_object_2d(src_obj_name, metadata)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'COPY')
expected = {'x-object-meta-test': 'value',
@@ -951,7 +913,6 @@
for i in six.moves.xrange(segments):
resp, _ = self.object_client.create_object_segments(
self.container_name, object_name, i, data_segments[i])
- self.assertEqual(resp['status'], '201')
# creating a manifest file
metadata = {'X-Object-Manifest': '%s/%s/'
% (self.container_name, object_name)}
@@ -1012,7 +973,6 @@
md5 = hashlib.md5(local_data).hexdigest()
headers = {'If-None-Match': md5}
resp, body = self.object_client.get(url, headers=headers)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
@@ -1035,7 +995,6 @@
cont_headers = {'X-Container-Read': '.r:*,.rlistings'}
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers, metadata_prefix='')
- self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
@@ -1044,13 +1003,11 @@
base_text=object_name)
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
# list container metadata
resp_meta, _ = self.container_client.list_container_metadata(
self.container_name)
- self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'HEAD')
self.assertIn('x-container-read', resp_meta)
@@ -1075,7 +1032,6 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
@@ -1084,13 +1040,11 @@
base_text=object_name)
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
- self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
# list container metadata
resp, _ = self.container_client.list_container_metadata(
self.container_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'HEAD')
self.assertIn('x-container-read', resp)
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
index 159ad5c..6622349 100644
--- a/tempest/api/object_storage/test_object_slo.py
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -120,7 +120,6 @@
manifest,
params)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self._assertHeadersSLO(resp, 'PUT')
@test.attr(type='gate')
@@ -132,7 +131,6 @@
self.container_name,
object_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self._assertHeadersSLO(resp, 'HEAD')
@test.attr(type='gate')
@@ -144,7 +142,6 @@
self.container_name,
object_name)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self._assertHeadersSLO(resp, 'GET')
sum_data = self.content + self.content
@@ -161,8 +158,6 @@
object_name,
params=params_del)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
-
# When deleting SLO using multipart manifest, the response contains
# not 'content-length' but 'transfer-encoding' header. This is the
# special case, therefore the existence of response headers is checked
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index e70bd9a..dd4fd17 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -105,13 +105,11 @@
# trying to get object using temp url within expiry time
resp, body = self.object_client.get(url)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, self.content)
# Testing a HEAD on this Temp URL
resp, body = self.object_client.head(url)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'HEAD')
@test.attr(type='gate')
@@ -136,7 +134,6 @@
self.object_name, "GET",
expires, key2)
resp, body = self.object_client.get(url)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertEqual(body, self.content)
@test.attr(type='gate')
@@ -153,12 +150,10 @@
# trying to put random data in the object using temp url
resp, body = self.object_client.put(url, new_data, None)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'PUT')
# Testing a HEAD on this Temp URL
resp, body = self.object_client.head(url)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'HEAD')
# Validate that the content of the object has been modified
@@ -181,7 +176,6 @@
# Testing a HEAD on this Temp URL
resp, body = self.object_client.head(url)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'HEAD')
@test.attr(type='gate')
@@ -196,7 +190,6 @@
# trying to get object using temp url within expiry time
resp, body = self.object_client.get(url)
- self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, self.content)
self.assertEqual(resp['content-disposition'], 'inline')
diff --git a/tempest/api/object_storage/test_object_version.py b/tempest/api/object_storage/test_object_version.py
index 5fe4fc8..da40e5a 100644
--- a/tempest/api/object_storage/test_object_version.py
+++ b/tempest/api/object_storage/test_object_version.py
@@ -36,7 +36,6 @@
def assertContainer(self, container, count, byte, versioned):
resp, _ = self.container_client.list_container_metadata(container)
- self.assertEqual(resp['status'], ('204'))
self.assertHeaders(resp, 'Container', 'HEAD')
header_value = resp.get('x-container-object-count', 'Missing Header')
self.assertEqual(header_value, count)
@@ -55,7 +54,6 @@
resp, body = self.container_client.create_container(
vers_container_name)
self.containers.append(vers_container_name)
- self.assertIn(resp['status'], ('202', '201'))
self.assertHeaders(resp, 'Container', 'PUT')
self.assertContainer(vers_container_name, '0', '0', 'Missing Header')
@@ -66,7 +64,6 @@
metadata=headers,
metadata_prefix='')
self.containers.append(base_container_name)
- self.assertIn(resp['status'], ('202', '201'))
self.assertHeaders(resp, 'Container', 'PUT')
self.assertContainer(base_container_name, '0', '0',
vers_container_name)
diff --git a/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml b/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml
index 8690941..4f9df91 100644
--- a/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml
+++ b/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml
@@ -7,6 +7,8 @@
Default: not_yet
image:
Type: String
+ flavor:
+ Type: String
Resources:
fluffy:
Type: AWS::AutoScaling::LaunchConfiguration
@@ -16,7 +18,7 @@
- Stinky
Properties:
ImageId: {Ref: image}
- InstanceType: not_used
+ InstanceType: {Ref: flavor}
UserData:
Fn::Replace:
- variable_a: {Ref: trigger}
diff --git a/tempest/api/orchestration/stacks/test_non_empty_stack.py b/tempest/api/orchestration/stacks/test_non_empty_stack.py
index 759cbbe..bf6c79c 100644
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ b/tempest/api/orchestration/stacks/test_non_empty_stack.py
@@ -31,13 +31,15 @@
template = cls.read_template('non_empty_stack')
image_id = (CONF.orchestration.image_ref or
cls._create_image()['id'])
+ flavor = CONF.orchestration.instance_type
# create the stack
cls.stack_identifier = cls.create_stack(
cls.stack_name,
template,
parameters={
'trigger': 'start',
- 'image': image_id
+ 'image': image_id,
+ 'flavor': flavor
})
cls.stack_id = cls.stack_identifier.split('/')[1]
cls.resource_name = 'fluffy'
diff --git a/tempest/api/telemetry/test_telemetry_notification_api.py b/tempest/api/telemetry/test_telemetry_notification_api.py
index 42e2a2d..7267183 100644
--- a/tempest/api/telemetry/test_telemetry_notification_api.py
+++ b/tempest/api/telemetry/test_telemetry_notification_api.py
@@ -73,7 +73,3 @@
for metric in self.glance_v2_notifications:
self.await_samples(metric, query)
-
-
-class TelemetryNotificationAPITestXML(TelemetryNotificationAPITestJSON):
- _interface = 'xml'
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index 042cde9..9e24993 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -66,13 +66,14 @@
params = {self.name_field: vol_name, 'volume_type': type_name}
- _, self.volume = self.volume_client.create_volume(size=1, **params)
+ _, self.volume = self.admin_volume_client.create_volume(size=1,
+ **params)
if with_prefix:
self.volume_id_list_with_prefix.append(self.volume['id'])
else:
self.volume_id_list_without_prefix.append(
self.volume['id'])
- self.volume_client.wait_for_volume_status(
+ self.admin_volume_client.wait_for_volume_status(
self.volume['id'], 'available')
@classmethod
@@ -80,13 +81,13 @@
# volumes deletion
vid_prefix = getattr(cls, 'volume_id_list_with_prefix', [])
for volume_id in vid_prefix:
- cls.volume_client.delete_volume(volume_id)
- cls.volume_client.wait_for_resource_deletion(volume_id)
+ cls.admin_volume_client.delete_volume(volume_id)
+ cls.admin_volume_client.wait_for_resource_deletion(volume_id)
vid_no_pre = getattr(cls, 'volume_id_list_without_prefix', [])
for volume_id in vid_no_pre:
- cls.volume_client.delete_volume(volume_id)
- cls.volume_client.wait_for_resource_deletion(volume_id)
+ cls.admin_volume_client.delete_volume(volume_id)
+ cls.admin_volume_client.wait_for_resource_deletion(volume_id)
# volume types deletion
volume_type_id_list = getattr(cls, 'volume_type_id_list', [])
@@ -130,7 +131,7 @@
# the multi backend feature has been enabled
# if multi-backend is enabled: os-vol-attr:host should be like:
# host@backend_name
- _, volume = self.volume_client.get_volume(volume_id)
+ _, volume = self.admin_volume_client.get_volume(volume_id)
volume1_host = volume['os-vol-host-attr:host']
msg = ("multi-backend reporting incorrect values for volume %s" %
@@ -141,10 +142,10 @@
# this test checks that the two volumes created at setUp don't
# belong to the same backend (if they are, than the
# volume backend distinction is not working properly)
- _, volume = self.volume_client.get_volume(volume1_id)
+ _, volume = self.admin_volume_client.get_volume(volume1_id)
volume1_host = volume['os-vol-host-attr:host']
- _, volume = self.volume_client.get_volume(volume2_id)
+ _, volume = self.admin_volume_client.get_volume(volume2_id)
volume2_host = volume['os-vol-host-attr:host']
msg = ("volumes %s and %s were created in the same backend" %
diff --git a/tempest/api/volume/admin/test_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py
index 720734b..31dc09f 100644
--- a/tempest/api/volume/admin/test_snapshots_actions.py
+++ b/tempest/api/volume/admin/test_snapshots_actions.py
@@ -18,29 +18,28 @@
from tempest import test
-class SnapshotsActionsTest(base.BaseVolumeV1AdminTest):
+class SnapshotsActionsV2Test(base.BaseVolumeAdminTest):
_interface = "json"
@classmethod
def resource_setup(cls):
- super(SnapshotsActionsTest, cls).resource_setup()
+ super(SnapshotsActionsV2Test, cls).resource_setup()
cls.client = cls.snapshots_client
- # Create admin volume client
- cls.admin_snapshots_client = cls.os_adm.snapshots_client
-
# Create a test shared volume for tests
vol_name = data_utils.rand_name(cls.__name__ + '-Volume-')
+ cls.name_field = cls.special_fields['name_field']
+ params = {cls.name_field: vol_name}
_, cls.volume = \
- cls.volumes_client.create_volume(size=1, display_name=vol_name)
+ cls.volumes_client.create_volume(size=1, **params)
cls.volumes_client.wait_for_volume_status(cls.volume['id'],
'available')
# Create a test shared snapshot for tests
snap_name = data_utils.rand_name(cls.__name__ + '-Snapshot-')
+ params = {cls.name_field: snap_name}
_, cls.snapshot = \
- cls.client.create_snapshot(cls.volume['id'],
- display_name=snap_name)
+ cls.client.create_snapshot(cls.volume['id'], **params)
cls.client.wait_for_snapshot_status(cls.snapshot['id'],
'available')
@@ -54,7 +53,7 @@
cls.volumes_client.delete_volume(cls.volume['id'])
cls.volumes_client.wait_for_resource_deletion(cls.volume['id'])
- super(SnapshotsActionsTest, cls).resource_cleanup()
+ super(SnapshotsActionsV2Test, cls).resource_cleanup()
def tearDown(self):
# Set snapshot's status to available after test
@@ -62,7 +61,7 @@
snapshot_id = self.snapshot['id']
self.admin_snapshots_client.reset_snapshot_status(snapshot_id,
status)
- super(SnapshotsActionsTest, self).tearDown()
+ super(SnapshotsActionsV2Test, self).tearDown()
def _create_reset_and_force_delete_temp_snapshot(self, status=None):
# Create snapshot, reset snapshot status,
@@ -127,9 +126,5 @@
self._create_reset_and_force_delete_temp_snapshot('error_deleting')
-class SnapshotsActionsTestXML(SnapshotsActionsTest):
- _interface = "xml"
-
- def _get_progress_alias(self):
- return '{http://docs.openstack.org/volume/ext' \
- '/extended_snapshot_attributes/api/v1}progress'
+class SnapshotsActionsV1Test(SnapshotsActionsV2Test):
+ _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
index 017363d..e966613 100644
--- a/tempest/api/volume/admin/test_volume_hosts.py
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -17,7 +17,7 @@
from tempest import test
-class VolumeHostsAdminTestsJSON(base.BaseVolumeV1AdminTest):
+class VolumeHostsAdminV2TestsJSON(base.BaseVolumeAdminTest):
_interface = "json"
@test.attr(type='gate')
@@ -27,5 +27,5 @@
"response of list hosts is: % s" % hosts)
-class VolumeHostsAdminTestsXML(VolumeHostsAdminTestsJSON):
- _interface = 'xml'
+class VolumeHostsAdminV1TestsJSON(VolumeHostsAdminV2TestsJSON):
+ _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index ece4299..50bab56 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -22,14 +22,13 @@
QUOTA_USAGE_KEYS = ['reserved', 'limit', 'in_use']
-class VolumeQuotasAdminTestJSON(base.BaseVolumeV1AdminTest):
+class BaseVolumeQuotasAdminV2TestJSON(base.BaseVolumeAdminTest):
_interface = "json"
force_tenant_isolation = True
@classmethod
def resource_setup(cls):
- super(VolumeQuotasAdminTestJSON, cls).resource_setup()
- cls.admin_volume_client = cls.os_adm.volumes_client
+ super(BaseVolumeQuotasAdminV2TestJSON, cls).resource_setup()
cls.demo_tenant_id = cls.isolated_creds.get_primary_creds().tenant_id
@test.attr(type='gate')
@@ -72,7 +71,7 @@
@test.attr(type='gate')
def test_show_quota_usage(self):
_, quota_usage = self.quotas_client.get_quota_usage(
- self.os_adm.credentials.tenant_name)
+ self.os_adm.credentials.tenant_id)
for key in QUOTA_KEYS:
self.assertIn(key, quota_usage)
for usage_key in QUOTA_USAGE_KEYS:
@@ -116,5 +115,5 @@
self.assertEqual(volume_default, quota_set_new['volumes'])
-class VolumeQuotasAdminTestXML(VolumeQuotasAdminTestJSON):
- _interface = "xml"
+class VolumeQuotasAdminV1TestJSON(BaseVolumeQuotasAdminV2TestJSON):
+ _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py
index 60a0adb..c367ebb 100644
--- a/tempest/api/volume/admin/test_volume_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_quotas_negative.py
@@ -18,13 +18,13 @@
from tempest import test
-class VolumeQuotasNegativeTestJSON(base.BaseVolumeV1AdminTest):
+class BaseVolumeQuotasNegativeV2TestJSON(base.BaseVolumeAdminTest):
_interface = "json"
force_tenant_isolation = True
@classmethod
def resource_setup(cls):
- super(VolumeQuotasNegativeTestJSON, cls).resource_setup()
+ super(BaseVolumeQuotasNegativeV2TestJSON, cls).resource_setup()
demo_user = cls.isolated_creds.get_primary_creds()
cls.demo_tenant_id = demo_user.tenant_id
cls.shared_quota_set = {'gigabytes': 3, 'volumes': 1, 'snapshots': 1}
@@ -78,5 +78,5 @@
self.volume['id'])
-class VolumeQuotasNegativeTestXML(VolumeQuotasNegativeTestJSON):
- _interface = "xml"
+class VolumeQuotasNegativeV1TestJSON(BaseVolumeQuotasNegativeV2TestJSON):
+ _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index a0792f1..a481224 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -21,7 +21,7 @@
CONF = config.CONF
-class VolumeTypesTest(base.BaseVolumeV1AdminTest):
+class VolumeTypesV2Test(base.BaseVolumeAdminTest):
_interface = "json"
def _delete_volume(self, volume_id):
@@ -43,6 +43,7 @@
volume = {}
vol_name = data_utils.rand_name("volume-")
vol_type_name = data_utils.rand_name("volume-type-")
+ self.name_field = self.special_fields['name_field']
proto = CONF.volume.storage_protocol
vendor = CONF.volume.vendor_name
extra_specs = {"storage_protocol": proto,
@@ -54,21 +55,20 @@
self.assertIn('id', body)
self.addCleanup(self._delete_volume_type, body['id'])
self.assertIn('name', body)
+ params = {self.name_field: vol_name, 'volume_type': vol_type_name}
_, volume = self.volumes_client.create_volume(
- size=1, display_name=vol_name,
- volume_type=vol_type_name)
+ size=1, **params)
self.assertIn('id', volume)
self.addCleanup(self._delete_volume, volume['id'])
- self.assertIn('display_name', volume)
- self.assertEqual(volume['display_name'], vol_name,
+ self.assertIn(self.name_field, volume)
+ self.assertEqual(volume[self.name_field], vol_name,
"The created volume name is not equal "
"to the requested name")
self.assertTrue(volume['id'] is not None,
"Field volume id is empty or not found.")
- self.volumes_client.wait_for_volume_status(volume['id'],
- 'available')
+ self.volumes_client.wait_for_volume_status(volume['id'], 'available')
_, fetched_volume = self.volumes_client.get_volume(volume['id'])
- self.assertEqual(vol_name, fetched_volume['display_name'],
+ self.assertEqual(vol_name, fetched_volume[self.name_field],
'The fetched Volume is different '
'from the created Volume')
self.assertEqual(volume['id'], fetched_volume['id'],
@@ -154,3 +154,7 @@
self.volume_types_client.get_encryption_type(
encryption_type['volume_type_id']))
self.assertEmpty(deleted_encryption_type)
+
+
+class VolumeTypesV1Test(VolumeTypesV2Test):
+ _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs.py b/tempest/api/volume/admin/test_volume_types_extra_specs.py
index a154821..3b9f6bb 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs.py
@@ -18,12 +18,12 @@
from tempest import test
-class VolumeTypesExtraSpecsTest(base.BaseVolumeV1AdminTest):
+class VolumeTypesExtraSpecsV2Test(base.BaseVolumeAdminTest):
_interface = "json"
@classmethod
def resource_setup(cls):
- super(VolumeTypesExtraSpecsTest, cls).resource_setup()
+ super(VolumeTypesExtraSpecsV2Test, cls).resource_setup()
vol_type_name = data_utils.rand_name('Volume-type-')
_, cls.volume_type = cls.volume_types_client.create_volume_type(
vol_type_name)
@@ -31,7 +31,7 @@
@classmethod
def resource_cleanup(cls):
cls.volume_types_client.delete_volume_type(cls.volume_type['id'])
- super(VolumeTypesExtraSpecsTest, cls).resource_cleanup()
+ super(VolumeTypesExtraSpecsV2Test, cls).resource_cleanup()
@test.attr(type='smoke')
def test_volume_type_extra_specs_list(self):
@@ -83,3 +83,7 @@
self.volume_types_client.delete_volume_type_extra_specs(
self.volume_type['id'],
extra_specs.keys()[0])
+
+
+class VolumeTypesExtraSpecsV1Test(VolumeTypesExtraSpecsV2Test):
+ _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
index 8734b16..40af37e 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
@@ -21,12 +21,12 @@
from tempest import test
-class ExtraSpecsNegativeTest(base.BaseVolumeV1AdminTest):
+class ExtraSpecsNegativeV2Test(base.BaseVolumeAdminTest):
_interface = 'json'
@classmethod
def resource_setup(cls):
- super(ExtraSpecsNegativeTest, cls).resource_setup()
+ super(ExtraSpecsNegativeV2Test, cls).resource_setup()
vol_type_name = data_utils.rand_name('Volume-type-')
cls.extra_specs = {"spec1": "val1"}
_, cls.volume_type = cls.volume_types_client.create_volume_type(
@@ -36,7 +36,7 @@
@classmethod
def resource_cleanup(cls):
cls.volume_types_client.delete_volume_type(cls.volume_type['id'])
- super(ExtraSpecsNegativeTest, cls).resource_cleanup()
+ super(ExtraSpecsNegativeV2Test, cls).resource_cleanup()
@test.attr(type='gate')
def test_update_no_body(self):
@@ -140,5 +140,5 @@
self.volume_type['id'], str(uuid.uuid4()))
-class ExtraSpecsNegativeTestXML(ExtraSpecsNegativeTest):
- _interface = 'xml'
+class ExtraSpecsNegativeV1Test(ExtraSpecsNegativeV2Test):
+ _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py
index a4d6431..4144270 100644
--- a/tempest/api/volume/admin/test_volume_types_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_negative.py
@@ -20,16 +20,18 @@
from tempest import test
-class VolumeTypesNegativeTest(base.BaseVolumeV1AdminTest):
+class VolumeTypesNegativeV2Test(base.BaseVolumeAdminTest):
_interface = 'json'
@test.attr(type='gate')
def test_create_with_nonexistent_volume_type(self):
# Should not be able to create volume with nonexistent volume_type.
+ self.name_field = self.special_fields['name_field']
+ params = {self.name_field: str(uuid.uuid4()),
+ 'volume_type': str(uuid.uuid4())}
self.assertRaises(exceptions.NotFound,
self.volumes_client.create_volume, size=1,
- display_name=str(uuid.uuid4()),
- volume_type=str(uuid.uuid4()))
+ **params)
@test.attr(type='gate')
def test_create_with_empty_name(self):
@@ -52,5 +54,5 @@
str(uuid.uuid4()))
-class VolumesTypesNegativeTestXML(VolumeTypesNegativeTest):
- _interface = 'xml'
+class VolumeTypesNegativeV1Test(VolumeTypesNegativeV2Test):
+ _api_version = 1
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index f85718b..8db6106 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -18,22 +18,21 @@
from tempest import test
-class VolumesActionsTest(base.BaseVolumeV1AdminTest):
+class VolumesActionsV2Test(base.BaseVolumeAdminTest):
_interface = "json"
@classmethod
def resource_setup(cls):
- super(VolumesActionsTest, cls).resource_setup()
+ super(VolumesActionsV2Test, cls).resource_setup()
cls.client = cls.volumes_client
- # Create admin volume client
- cls.admin_volume_client = cls.os_adm.volumes_client
-
# Create a test shared volume for tests
vol_name = utils.rand_name(cls.__name__ + '-Volume-')
+ cls.name_field = cls.special_fields['name_field']
+ params = {cls.name_field: vol_name}
_, cls.volume = cls.client.create_volume(size=1,
- display_name=vol_name)
+ **params)
cls.client.wait_for_volume_status(cls.volume['id'], 'available')
@classmethod
@@ -42,7 +41,7 @@
cls.client.delete_volume(cls.volume['id'])
cls.client.wait_for_resource_deletion(cls.volume['id'])
- super(VolumesActionsTest, cls).resource_cleanup()
+ super(VolumesActionsV2Test, cls).resource_cleanup()
def _reset_volume_status(self, volume_id, status):
# Reset the volume status
@@ -53,13 +52,14 @@
def tearDown(self):
# Set volume's status to available after test
self._reset_volume_status(self.volume['id'], 'available')
- super(VolumesActionsTest, self).tearDown()
+ super(VolumesActionsV2Test, self).tearDown()
def _create_temp_volume(self):
# Create a temp volume for force delete tests
vol_name = utils.rand_name('Volume')
+ params = {self.name_field: vol_name}
_, temp_volume = self.client.create_volume(size=1,
- display_name=vol_name)
+ **params)
self.client.wait_for_volume_status(temp_volume['id'], 'available')
return temp_volume
@@ -95,5 +95,5 @@
self._create_reset_and_force_delete_temp_volume('error')
-class VolumesActionsTestXML(VolumesActionsTest):
- _interface = "xml"
+class VolumesActionsV1Test(VolumesActionsV2Test):
+ _api_version = 1
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index 8b90b07..1357d31 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -23,18 +23,16 @@
LOG = logging.getLogger(__name__)
-class VolumesBackupsTest(base.BaseVolumeV1AdminTest):
+class VolumesBackupsV2Test(base.BaseVolumeAdminTest):
_interface = "json"
@classmethod
def resource_setup(cls):
- super(VolumesBackupsTest, cls).resource_setup()
+ super(VolumesBackupsV2Test, cls).resource_setup()
if not CONF.volume_feature_enabled.backup:
raise cls.skipException("Cinder backup feature disabled")
- cls.volumes_adm_client = cls.os_adm.volumes_client
- cls.backups_adm_client = cls.os_adm.backups_client
cls.volume = cls.create_volume()
@test.attr(type='smoke')
@@ -47,8 +45,8 @@
self.addCleanup(self.backups_adm_client.delete_backup,
backup['id'])
self.assertEqual(backup_name, backup['name'])
- self.volumes_adm_client.wait_for_volume_status(self.volume['id'],
- 'available')
+ self.admin_volume_client.wait_for_volume_status(
+ self.volume['id'], 'available')
self.backups_adm_client.wait_for_backup_status(backup['id'],
'available')
@@ -65,10 +63,14 @@
_, restore = self.backups_adm_client.restore_backup(backup['id'])
# Delete backup
- self.addCleanup(self.volumes_adm_client.delete_volume,
+ self.addCleanup(self.admin_volume_client.delete_volume,
restore['volume_id'])
self.assertEqual(backup['id'], restore['backup_id'])
self.backups_adm_client.wait_for_backup_status(backup['id'],
'available')
- self.volumes_adm_client.wait_for_volume_status(restore['volume_id'],
- 'available')
+ self.admin_volume_client.wait_for_volume_status(
+ restore['volume_id'], 'available')
+
+
+class VolumesBackupsV1Test(VolumesBackupsV2Test):
+ _api_version = 1
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index d78ddb6..2a52e55 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -165,23 +165,28 @@
cls.qos_specs = []
- cls.hosts_client = cls.os_adm.volume_hosts_client
- cls.quotas_client = cls.os_adm.volume_quotas_client
-
if cls._api_version == 1:
if not CONF.volume_feature_enabled.api_v1:
msg = "Volume API v1 is disabled"
raise cls.skipException(msg)
cls.volume_qos_client = cls.os_adm.volume_qos_client
cls.volume_types_client = cls.os_adm.volume_types_client
- cls.volume_client = cls.os_adm.volumes_client
+ cls.admin_volume_client = cls.os_adm.volumes_client
+ cls.hosts_client = cls.os_adm.volume_hosts_client
+ cls.admin_snapshots_client = cls.os_adm.snapshots_client
+ cls.backups_adm_client = cls.os_adm.backups_client
+ cls.quotas_client = cls.os_adm.volume_quotas_client
elif cls._api_version == 2:
if not CONF.volume_feature_enabled.api_v2:
msg = "Volume API v2 is disabled"
raise cls.skipException(msg)
cls.volume_qos_client = cls.os_adm.volume_qos_v2_client
cls.volume_types_client = cls.os_adm.volume_types_v2_client
- cls.volume_client = cls.os_adm.volumes_v2_client
+ cls.admin_volume_client = cls.os_adm.volumes_v2_client
+ cls.hosts_client = cls.os_adm.volume_hosts_v2_client
+ cls.admin_snapshots_client = cls.os_adm.snapshots_v2_client
+ cls.backups_adm_client = cls.os_adm.backups_v2_client
+ cls.quotas_client = cls.os_adm.volume_quotas_v2_client
@classmethod
def resource_cleanup(cls):
diff --git a/tempest/api/volume/test_availability_zone.py b/tempest/api/volume/test_availability_zone.py
index 648bd8b..c3d5d02 100644
--- a/tempest/api/volume/test_availability_zone.py
+++ b/tempest/api/volume/test_availability_zone.py
@@ -35,13 +35,5 @@
self.assertTrue(len(availability_zone) > 0)
-class AvailabilityZoneV2TestXML(AvailabilityZoneV2TestJSON):
- _interface = 'xml'
-
-
class AvailabilityZoneV1TestJSON(AvailabilityZoneV2TestJSON):
_api_version = 1
-
-
-class AvailabilityZoneV1TestXML(AvailabilityZoneV1TestJSON):
- _interface = 'xml'
diff --git a/tempest/api/volume/test_extensions.py b/tempest/api/volume/test_extensions.py
index 4fc6ee4..66ea9b7 100644
--- a/tempest/api/volume/test_extensions.py
+++ b/tempest/api/volume/test_extensions.py
@@ -44,13 +44,5 @@
raise self.skipException('There are not any extensions configured')
-class ExtensionsV2TestXML(ExtensionsV2TestJSON):
- _interface = 'xml'
-
-
class ExtensionsV1TestJSON(ExtensionsV2TestJSON):
_api_version = 1
-
-
-class ExtensionsV1TestXML(ExtensionsV1TestJSON):
- _interface = 'xml'
diff --git a/tempest/api/volume/test_snapshot_metadata.py b/tempest/api/volume/test_snapshot_metadata.py
index 777d3de..0dceb3d 100644
--- a/tempest/api/volume/test_snapshot_metadata.py
+++ b/tempest/api/volume/test_snapshot_metadata.py
@@ -98,13 +98,5 @@
self.assertEqual(expect, body)
-class SnapshotV2MetadataTestXML(SnapshotV2MetadataTestJSON):
- _interface = "xml"
-
-
class SnapshotV1MetadataTestJSON(SnapshotV2MetadataTestJSON):
_api_version = 1
-
-
-class SnapshotV1MetadataTestXML(SnapshotV1MetadataTestJSON):
- _interface = "xml"
diff --git a/tempest/api/volume/test_volume_metadata.py b/tempest/api/volume/test_volume_metadata.py
index 2ec8667..ac5d016 100644
--- a/tempest/api/volume/test_volume_metadata.py
+++ b/tempest/api/volume/test_volume_metadata.py
@@ -99,13 +99,5 @@
self.assertThat(body.items(), matchers.ContainsAll(expect.items()))
-class VolumesV2MetadataTestXML(VolumesV2MetadataTest):
- _interface = "xml"
-
-
class VolumesV1MetadataTest(VolumesV2MetadataTest):
_api_version = 1
-
-
-class VolumesV1MetadataTestXML(VolumesV1MetadataTest):
- _interface = "xml"
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index fe217c1..2011c1b 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -102,13 +102,5 @@
self.client.wait_for_volume_status(volume['id'], 'available')
-class VolumesV2TransfersTestXML(VolumesV2TransfersTest):
- _interface = "xml"
-
-
class VolumesV1TransfersTest(VolumesV2TransfersTest):
_api_version = 1
-
-
-class VolumesV1TransfersTestXML(VolumesV1TransfersTest):
- _interface = "xml"
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index a9bc70a..4fd27b1 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -142,13 +142,5 @@
self.assertEqual(False, bool_flag)
-class VolumesV2ActionsTestXML(VolumesV2ActionsTest):
- _interface = "xml"
-
-
class VolumesV1ActionsTest(VolumesV2ActionsTest):
_api_version = 1
-
-
-class VolumesV1ActionsTestXML(VolumesV1ActionsTest):
- _interface = "xml"
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index edd497c..2b816ef 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -38,13 +38,5 @@
self.assertEqual(int(volume['size']), extend_size)
-class VolumesV2ExtendTestXML(VolumesV2ExtendTest):
- _interface = "xml"
-
-
class VolumesV1ExtendTest(VolumesV2ExtendTest):
_api_version = 1
-
-
-class VolumesV1ExtendTestXML(VolumesV1ExtendTest):
- _interface = "xml"
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 033beb4..a9c10aa 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -149,13 +149,5 @@
self._volume_create_get_update_delete(source_volid=origin['id'])
-class VolumesV2GetTestXML(VolumesV2GetTest):
- _interface = "xml"
-
-
class VolumesV1GetTest(VolumesV2GetTest):
_api_version = 1
-
-
-class VolumesV1GetTestXML(VolumesV1GetTest):
- _interface = "xml"
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 016e9ab..9c0d238 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -205,14 +205,6 @@
self._list_by_param_value_and_assert(params, with_detail=True)
-class VolumesV2ListTestXML(VolumesV2ListTestJSON):
- _interface = 'xml'
-
-
class VolumesV1ListTestJSON(VolumesV2ListTestJSON):
_api_version = 1
VOLUME_FIELDS = ('id', 'display_name')
-
-
-class VolumesV1ListTestXML(VolumesV1ListTestJSON):
- _interface = 'xml'
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index 2b43c63..5d3fdef 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -259,14 +259,6 @@
self.assertEqual(0, len(fetched_volume))
-class VolumesV2NegativeTestXML(VolumesV2NegativeTest):
- _interface = 'xml'
-
-
class VolumesV1NegativeTest(VolumesV2NegativeTest):
_api_version = 1
_name = 'display_name'
-
-
-class VolumesV1NegativeTestXML(VolumesV1NegativeTest):
- _interface = 'xml'
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 78df1df..21d0a86 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -178,13 +178,5 @@
self.clear_snapshots()
-class VolumesV2SnapshotTestXML(VolumesV2SnapshotTestJSON):
- _interface = "xml"
-
-
class VolumesV1SnapshotTestJSON(VolumesV2SnapshotTestJSON):
_api_version = 1
-
-
-class VolumesV1SnapshotTestXML(VolumesV1SnapshotTestJSON):
- _interface = "xml"
diff --git a/tempest/api/volume/test_volumes_snapshots_negative.py b/tempest/api/volume/test_volumes_snapshots_negative.py
index 75a62a8..2d7b6de 100644
--- a/tempest/api/volume/test_volumes_snapshots_negative.py
+++ b/tempest/api/volume/test_volumes_snapshots_negative.py
@@ -47,13 +47,5 @@
None, display_name=s_name)
-class VolumesV2SnapshotNegativeTestXML(VolumesV2SnapshotNegativeTestJSON):
- _interface = "xml"
-
-
class VolumesV1SnapshotNegativeTestJSON(VolumesV2SnapshotNegativeTestJSON):
_api_version = 1
-
-
-class VolumesV1SnapshotNegativeTestXML(VolumesV1SnapshotNegativeTestJSON):
- _interface = "xml"
diff --git a/tempest/api/volume/v2/test_volumes_list.py b/tempest/api/volume/v2/test_volumes_list.py
index cc56873..c20f3d8 100644
--- a/tempest/api/volume/v2/test_volumes_list.py
+++ b/tempest/api/volume/v2/test_volumes_list.py
@@ -82,7 +82,3 @@
_list_details_with_multiple_params()
_list_details_with_multiple_params(sort_dir='desc')
-
-
-class VolumesV2ListTestXML(VolumesV2ListTestJSON):
- _interface = 'xml'
diff --git a/tempest/api_schema/response/compute/availability_zone.py b/tempest/api_schema/response/compute/availability_zone.py
index c1abc64..ab3e2ea 100644
--- a/tempest/api_schema/response/compute/availability_zone.py
+++ b/tempest/api_schema/response/compute/availability_zone.py
@@ -27,7 +27,7 @@
'properties': {
'available': {'type': 'boolean'},
'active': {'type': 'boolean'},
- 'updated_at': {'type': 'string'}
+ 'updated_at': {'type': ['string', 'null']}
},
'required': ['available', 'active', 'updated_at']
}
diff --git a/tempest/api_schema/response/compute/services.py b/tempest/api_schema/response/compute/services.py
index eaba129..6f361ef 100644
--- a/tempest/api_schema/response/compute/services.py
+++ b/tempest/api_schema/response/compute/services.py
@@ -22,13 +22,14 @@
'items': {
'type': 'object',
'properties': {
- 'id': {'type': 'integer'},
+ 'id': {'type': ['integer', 'string'],
+ 'pattern': '^[a-zA-Z!]*@[0-9]+$'},
'zone': {'type': 'string'},
'host': {'type': 'string'},
'state': {'type': 'string'},
'binary': {'type': 'string'},
'status': {'type': 'string'},
- 'updated_at': {'type': 'string'},
+ 'updated_at': {'type': ['string', 'null']},
'disabled_reason': {'type': ['string', 'null']}
},
'required': ['id', 'zone', 'host', 'state', 'binary',
diff --git a/tempest/api_schema/response/compute/v2/servers.py b/tempest/api_schema/response/compute/v2/servers.py
index 5fc2008..09abaed 100644
--- a/tempest/api_schema/response/compute/v2/servers.py
+++ b/tempest/api_schema/response/compute/v2/servers.py
@@ -117,21 +117,23 @@
}
}
+common_attach_volume_info = {
+ 'type': 'object',
+ 'properties': {
+ 'id': {'type': 'string'},
+ 'device': {'type': 'string'},
+ 'volumeId': {'type': 'string'},
+ 'serverId': {'type': ['integer', 'string']}
+ },
+ 'required': ['id', 'device', 'volumeId', 'serverId']
+}
+
attach_volume = {
'status_code': [200],
'response_body': {
'type': 'object',
'properties': {
- 'volumeAttachment': {
- 'type': 'object',
- 'properties': {
- 'id': {'type': 'string'},
- 'device': {'type': 'string'},
- 'volumeId': {'type': 'string'},
- 'serverId': {'type': ['integer', 'string']}
- },
- 'required': ['id', 'device', 'volumeId', 'serverId']
- }
+ 'volumeAttachment': common_attach_volume_info
},
'required': ['volumeAttachment']
}
@@ -141,6 +143,27 @@
'status_code': [202]
}
+get_volume_attachment = copy.deepcopy(attach_volume)
+get_volume_attachment['response_body']['properties'][
+ 'volumeAttachment']['properties'].update({'serverId': {'type': 'string'}})
+
+list_volume_attachments = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'volumeAttachments': {
+ 'type': 'array',
+ 'items': common_attach_volume_info
+ }
+ },
+ 'required': ['volumeAttachments']
+ }
+}
+list_volume_attachments['response_body']['properties'][
+ 'volumeAttachments']['items']['properties'].update(
+ {'serverId': {'type': 'string'}})
+
set_get_server_metadata_item = {
'status_code': [200],
'response_body': {
diff --git a/tempest/auth.py b/tempest/auth.py
index b1ead29..022a450 100644
--- a/tempest/auth.py
+++ b/tempest/auth.py
@@ -26,8 +26,6 @@
from tempest.openstack.common import log as logging
from tempest.services.identity.json import identity_client as json_id
from tempest.services.identity.v3.json import identity_client as json_v3id
-from tempest.services.identity.v3.xml import identity_client as xml_v3id
-from tempest.services.identity.xml import identity_client as xml_id
CONF = config.CONF
@@ -44,15 +42,14 @@
"""
:param credentials: credentials for authentication
:param interface: 'json' or 'xml'. Applicable for tempest client only
+ (deprecated: only json now supported)
"""
credentials = self._convert_credentials(credentials)
if self.check_credentials(credentials):
self.credentials = credentials
else:
raise TypeError("Invalid credentials")
- self.interface = interface
- if self.interface is None:
- self.interface = 'json'
+ self.interface = 'json'
self.cache = None
self.alt_auth_data = None
self.alt_part = None
@@ -255,10 +252,7 @@
EXPIRY_DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
def _auth_client(self):
- if self.interface == 'json':
- return json_id.TokenClientJSON()
- else:
- return xml_id.TokenClientXML()
+ return json_id.TokenClientJSON()
def _auth_params(self):
return dict(
@@ -336,10 +330,7 @@
EXPIRY_DATE_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
def _auth_client(self):
- if self.interface == 'json':
- return json_v3id.V3TokenClientJSON()
- else:
- return xml_v3id.V3TokenClientXML()
+ return json_v3id.V3TokenClientJSON()
def _auth_params(self):
return dict(
diff --git a/tempest/cli/__init__.py b/tempest/cli/__init__.py
index ca6d7fe..4782129 100644
--- a/tempest/cli/__init__.py
+++ b/tempest/cli/__init__.py
@@ -14,46 +14,21 @@
# under the License.
import functools
-import os
-import shlex
-import subprocess
+from tempest_lib.cli import base
+from tempest_lib.cli import output_parser
import testtools
-import tempest.cli.output_parser
+from tempest.common import credentials
from tempest import config
from tempest import exceptions
-from tempest.openstack.common import log as logging
from tempest.openstack.common import versionutils
-import tempest.test
+from tempest import test
-LOG = logging.getLogger(__name__)
-
CONF = config.CONF
-def execute(cmd, action, flags='', params='', fail_ok=False,
- merge_stderr=False):
- """Executes specified command for the given action."""
- cmd = ' '.join([os.path.join(CONF.cli.cli_dir, cmd),
- flags, action, params])
- LOG.info("running: '%s'" % cmd)
- cmd = shlex.split(cmd.encode('utf-8'))
- result = ''
- result_err = ''
- stdout = subprocess.PIPE
- stderr = subprocess.STDOUT if merge_stderr else subprocess.PIPE
- proc = subprocess.Popen(cmd, stdout=stdout, stderr=stderr)
- result, result_err = proc.communicate()
- if not fail_ok and proc.returncode != 0:
- raise exceptions.CommandFailed(proc.returncode,
- cmd,
- result,
- result_err)
- return result
-
-
def check_client_version(client, version):
"""Checks if the client's version is compatible with the given version
@@ -62,8 +37,8 @@
@return: True if the client version is compatible with the given version
parameter, False otherwise.
"""
- current_version = execute(client, '', params='--version',
- merge_stderr=True)
+ current_version = base.execute(client, '', params='--version',
+ merge_stderr=True, cli_dir=CONF.cli.cli_dir)
if not current_version.strip():
raise exceptions.TempestException('"%s --version" output was empty' %
@@ -92,100 +67,52 @@
return decorator
-class ClientTestBase(tempest.test.BaseTestCase):
+class ClientTestBase(test.BaseTestCase):
@classmethod
def resource_setup(cls):
if not CONF.cli.enabled:
msg = "cli testing disabled"
raise cls.skipException(msg)
super(ClientTestBase, cls).resource_setup()
+ cls.cred_prov = credentials.get_isolated_credentials(cls.__name__)
+ cls.creds = cls.cred_prov.get_admin_creds()
- def __init__(self, *args, **kwargs):
- self.parser = tempest.cli.output_parser
- super(ClientTestBase, self).__init__(*args, **kwargs)
+ def _get_clients(self):
+ clients = base.CLIClient(self.creds.username,
+ self.creds.password,
+ self.creds.tenant_name,
+ CONF.identity.uri, CONF.cli.cli_dir)
+ return clients
- def nova(self, action, flags='', params='', admin=True, fail_ok=False):
- """Executes nova command for the given action."""
- flags += ' --endpoint-type %s' % CONF.compute.endpoint_type
- return self.cmd_with_auth(
- 'nova', action, flags, params, admin, fail_ok)
-
- def nova_manage(self, action, flags='', params='', fail_ok=False,
- merge_stderr=False):
- """Executes nova-manage command for the given action."""
- return execute(
- 'nova-manage', action, flags, params, fail_ok, merge_stderr)
-
- def keystone(self, action, flags='', params='', admin=True, fail_ok=False):
- """Executes keystone command for the given action."""
- return self.cmd_with_auth(
- 'keystone', action, flags, params, admin, fail_ok)
-
- def glance(self, action, flags='', params='', admin=True, fail_ok=False):
- """Executes glance command for the given action."""
- flags += ' --os-endpoint-type %s' % CONF.image.endpoint_type
- return self.cmd_with_auth(
- 'glance', action, flags, params, admin, fail_ok)
-
- def ceilometer(self, action, flags='', params='', admin=True,
- fail_ok=False):
- """Executes ceilometer command for the given action."""
- flags += ' --os-endpoint-type %s' % CONF.telemetry.endpoint_type
- return self.cmd_with_auth(
- 'ceilometer', action, flags, params, admin, fail_ok)
-
- def heat(self, action, flags='', params='', admin=True,
- fail_ok=False):
- """Executes heat command for the given action."""
- flags += ' --os-endpoint-type %s' % CONF.orchestration.endpoint_type
- return self.cmd_with_auth(
- 'heat', action, flags, params, admin, fail_ok)
-
- def cinder(self, action, flags='', params='', admin=True, fail_ok=False):
- """Executes cinder command for the given action."""
- flags += ' --endpoint-type %s' % CONF.volume.endpoint_type
- return self.cmd_with_auth(
- 'cinder', action, flags, params, admin, fail_ok)
-
- def swift(self, action, flags='', params='', admin=True, fail_ok=False):
- """Executes swift command for the given action."""
- flags += ' --os-endpoint-type %s' % CONF.object_storage.endpoint_type
- return self.cmd_with_auth(
- 'swift', action, flags, params, admin, fail_ok)
-
- def neutron(self, action, flags='', params='', admin=True, fail_ok=False):
- """Executes neutron command for the given action."""
- flags += ' --endpoint-type %s' % CONF.network.endpoint_type
- return self.cmd_with_auth(
- 'neutron', action, flags, params, admin, fail_ok)
-
- def sahara(self, action, flags='', params='', admin=True,
- fail_ok=False, merge_stderr=True):
- """Executes sahara command for the given action."""
- flags += ' --endpoint-type %s' % CONF.data_processing.endpoint_type
- return self.cmd_with_auth(
- 'sahara', action, flags, params, admin, fail_ok, merge_stderr)
-
- def cmd_with_auth(self, cmd, action, flags='', params='',
- admin=True, fail_ok=False, merge_stderr=False):
- """Executes given command with auth attributes appended."""
- # TODO(jogo) make admin=False work
- creds = ('--os-username %s --os-tenant-name %s --os-password %s '
- '--os-auth-url %s' %
- (CONF.identity.admin_username,
- CONF.identity.admin_tenant_name,
- CONF.identity.admin_password,
- CONF.identity.uri))
- flags = creds + ' ' + flags
- return execute(cmd, action, flags, params, fail_ok, merge_stderr)
+ # TODO(mtreinish): The following code is basically copied from tempest-lib.
+ # The base cli test class in tempest-lib 0.0.1 doesn't work as a mixin like
+ # is needed here. The code below should be removed when tempest-lib
+ # provides a way to provide this functionality
+ def setUp(self):
+ super(ClientTestBase, self).setUp()
+ self.clients = self._get_clients()
+ self.parser = output_parser
def assertTableStruct(self, items, field_names):
- """Verify that all items has keys listed in field_names."""
+ """Verify that all items has keys listed in field_names.
+
+ :param items: items to assert are field names in the output table
+ :type items: list
+ :param field_names: field names from the output table of the cmd
+ :type field_names: list
+ """
for item in items:
for field in field_names:
self.assertIn(field, item)
def assertFirstLineStartsWith(self, lines, beginning):
+ """Verify that the first line starts with a string
+
+ :param lines: strings for each line of output
+ :type lines: list
+ :param beginning: verify this is at the beginning of the first line
+ :type beginning: string
+ """
self.assertTrue(lines[0].startswith(beginning),
msg=('Beginning of first line has invalid content: %s'
% lines[:3]))
diff --git a/tempest/cli/output_parser.py b/tempest/cli/output_parser.py
deleted file mode 100644
index 80234a3..0000000
--- a/tempest/cli/output_parser.py
+++ /dev/null
@@ -1,171 +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.
-
-"""Collection of utilities for parsing CLI clients output."""
-
-import re
-
-from tempest import exceptions
-from tempest.openstack.common import log as logging
-
-
-LOG = logging.getLogger(__name__)
-
-
-delimiter_line = re.compile('^\+\-[\+\-]+\-\+$')
-
-
-def details_multiple(output_lines, with_label=False):
- """Return list of dicts with item details from cli output tables.
-
- If with_label is True, key '__label' is added to each items dict.
- For more about 'label' see OutputParser.tables().
- """
- items = []
- tables_ = tables(output_lines)
- for table_ in tables_:
- if 'Property' not in table_['headers'] \
- or 'Value' not in table_['headers']:
- raise exceptions.InvalidStructure()
- item = {}
- for value in table_['values']:
- item[value[0]] = value[1]
- if with_label:
- item['__label'] = table_['label']
- items.append(item)
- return items
-
-
-def details(output_lines, with_label=False):
- """Return dict with details of first item (table) found in output."""
- items = details_multiple(output_lines, with_label)
- return items[0]
-
-
-def listing(output_lines):
- """Return list of dicts with basic item info parsed from cli output.
- """
-
- items = []
- table_ = table(output_lines)
- for row in table_['values']:
- item = {}
- for col_idx, col_key in enumerate(table_['headers']):
- item[col_key] = row[col_idx]
- items.append(item)
- return items
-
-
-def tables(output_lines):
- """Find all ascii-tables in output and parse them.
-
- Return list of tables parsed from cli output as dicts.
- (see OutputParser.table())
-
- And, if found, label key (separated line preceding the table)
- is added to each tables dict.
- """
- tables_ = []
-
- table_ = []
- label = None
-
- start = False
- header = False
-
- if not isinstance(output_lines, list):
- output_lines = output_lines.split('\n')
-
- for line in output_lines:
- if delimiter_line.match(line):
- if not start:
- start = True
- elif not header:
- # we are after head area
- header = True
- else:
- # table ends here
- start = header = None
- table_.append(line)
-
- parsed = table(table_)
- parsed['label'] = label
- tables_.append(parsed)
-
- table_ = []
- label = None
- continue
- if start:
- table_.append(line)
- else:
- if label is None:
- label = line
- else:
- LOG.warn('Invalid line between tables: %s' % line)
- if len(table_) > 0:
- LOG.warn('Missing end of table')
-
- return tables_
-
-
-def table(output_lines):
- """Parse single table from cli output.
-
- Return dict with list of column names in 'headers' key and
- rows in 'values' key.
- """
- table_ = {'headers': [], 'values': []}
- columns = None
-
- if not isinstance(output_lines, list):
- output_lines = output_lines.split('\n')
-
- if not output_lines[-1]:
- # skip last line if empty (just newline at the end)
- output_lines = output_lines[:-1]
-
- for line in output_lines:
- if delimiter_line.match(line):
- columns = _table_columns(line)
- continue
- if '|' not in line:
- LOG.warn('skipping invalid table line: %s' % line)
- continue
- row = []
- for col in columns:
- row.append(line[col[0]:col[1]].strip())
- if table_['headers']:
- table_['values'].append(row)
- else:
- table_['headers'] = row
-
- return table_
-
-
-def _table_columns(first_table_row):
- """Find column ranges in output line.
-
- Return list of tuples (start,end) for each column
- detected by plus (+) characters in delimiter line.
- """
- positions = []
- start = 1 # there is '+' at 0
- while start < len(first_table_row):
- end = first_table_row.find('+', start)
- if end == -1:
- break
- positions.append((start, end))
- start = end + 1
- return positions
diff --git a/tempest/cli/simple_read_only/compute/test_nova.py b/tempest/cli/simple_read_only/compute/test_nova.py
index 6e5e077..4fe4982 100644
--- a/tempest/cli/simple_read_only/compute/test_nova.py
+++ b/tempest/cli/simple_read_only/compute/test_nova.py
@@ -13,11 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest_lib import exceptions
import testtools
from tempest import cli
from tempest import config
-from tempest import exceptions
from tempest.openstack.common import log as logging
import tempest.test
@@ -47,6 +47,11 @@
raise cls.skipException(msg)
super(SimpleReadOnlyNovaClientTest, cls).resource_setup()
+ def nova(self, *args, **kwargs):
+ return self.clients.nova(*args,
+ endpoint_type=CONF.compute.endpoint_type,
+ **kwargs)
+
def test_admin_fake_action(self):
self.assertRaises(exceptions.CommandFailed,
self.nova,
diff --git a/tempest/cli/simple_read_only/compute/test_nova_manage.py b/tempest/cli/simple_read_only/compute/test_nova_manage.py
index cff543f..34ec671 100644
--- a/tempest/cli/simple_read_only/compute/test_nova_manage.py
+++ b/tempest/cli/simple_read_only/compute/test_nova_manage.py
@@ -13,9 +13,10 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest_lib import exceptions
+
from tempest import cli
from tempest import config
-from tempest import exceptions
from tempest.openstack.common import log as logging
@@ -46,6 +47,9 @@
raise cls.skipException(msg)
super(SimpleReadOnlyNovaManageTest, cls).resource_setup()
+ def nova_manage(self, *args, **kwargs):
+ return self.clients.nova_manage(*args, **kwargs)
+
def test_admin_fake_action(self):
self.assertRaises(exceptions.CommandFailed,
self.nova_manage,
diff --git a/tempest/cli/simple_read_only/data_processing/test_sahara.py b/tempest/cli/simple_read_only/data_processing/test_sahara.py
index 751a4ad..1f2403c 100644
--- a/tempest/cli/simple_read_only/data_processing/test_sahara.py
+++ b/tempest/cli/simple_read_only/data_processing/test_sahara.py
@@ -15,9 +15,10 @@
import logging
import re
+from tempest_lib import exceptions
+
from tempest import cli
from tempest import config
-from tempest import exceptions
from tempest import test
CONF = config.CONF
@@ -40,6 +41,10 @@
raise cls.skipException(msg)
super(SimpleReadOnlySaharaClientTest, cls).resource_setup()
+ def sahara(self, *args, **kwargs):
+ return self.clients.sahara(
+ *args, endpoint_type=CONF.data_processing.endpoint_type, **kwargs)
+
@test.attr(type='negative')
def test_sahara_fake_action(self):
self.assertRaises(exceptions.CommandFailed,
diff --git a/tempest/cli/simple_read_only/identity/test_keystone.py b/tempest/cli/simple_read_only/identity/test_keystone.py
index 9218fcd..1fc7908 100644
--- a/tempest/cli/simple_read_only/identity/test_keystone.py
+++ b/tempest/cli/simple_read_only/identity/test_keystone.py
@@ -15,9 +15,10 @@
import re
+from tempest_lib import exceptions
+
from tempest import cli
from tempest import config
-from tempest import exceptions
from tempest.openstack.common import log as logging
CONF = config.CONF
@@ -34,6 +35,9 @@
their own. They only verify the structure of output if present.
"""
+ def keystone(self, *args, **kwargs):
+ return self.clients.keystone(*args, **kwargs)
+
def test_admin_fake_action(self):
self.assertRaises(exceptions.CommandFailed,
self.keystone,
diff --git a/tempest/cli/simple_read_only/image/test_glance.py b/tempest/cli/simple_read_only/image/test_glance.py
index a9cbadb..03e00d7 100644
--- a/tempest/cli/simple_read_only/image/test_glance.py
+++ b/tempest/cli/simple_read_only/image/test_glance.py
@@ -15,9 +15,10 @@
import re
+from tempest_lib import exceptions
+
from tempest import cli
from tempest import config
-from tempest import exceptions
from tempest.openstack.common import log as logging
CONF = config.CONF
@@ -40,6 +41,11 @@
raise cls.skipException(msg)
super(SimpleReadOnlyGlanceClientTest, cls).resource_setup()
+ def glance(self, *args, **kwargs):
+ return self.clients.glance(*args,
+ endpoint_type=CONF.image.endpoint_type,
+ **kwargs)
+
def test_glance_fake_action(self):
self.assertRaises(exceptions.CommandFailed,
self.glance,
diff --git a/tempest/cli/simple_read_only/network/test_neutron.py b/tempest/cli/simple_read_only/network/test_neutron.py
index f9f8906..6cf0640 100644
--- a/tempest/cli/simple_read_only/network/test_neutron.py
+++ b/tempest/cli/simple_read_only/network/test_neutron.py
@@ -15,9 +15,10 @@
import re
+from tempest_lib import exceptions
+
from tempest import cli
from tempest import config
-from tempest import exceptions
from tempest.openstack.common import log as logging
from tempest import test
@@ -41,6 +42,11 @@
raise cls.skipException(msg)
super(SimpleReadOnlyNeutronClientTest, cls).resource_setup()
+ def neutron(self, *args, **kwargs):
+ return self.clients.neutron(*args,
+ endpoint_type=CONF.network.endpoint_type,
+ **kwargs)
+
@test.attr(type='smoke')
def test_neutron_fake_action(self):
self.assertRaises(exceptions.CommandFailed,
@@ -156,6 +162,67 @@
'allocation_pools'])
@test.attr(type='smoke')
+ @test.requires_ext(extension='vpnaas', service='network')
+ def test_neutron_vpn_ikepolicy_list(self):
+ ikepolicy = self.parser.listing(self.neutron('vpn-ikepolicy-list'))
+ self.assertTableStruct(ikepolicy, ['id', 'name',
+ 'auth_algorithm',
+ 'encryption_algorithm',
+ 'ike_version', 'pfs'])
+
+ @test.attr(type='smoke')
+ @test.requires_ext(extension='vpnaas', service='network')
+ def test_neutron_vpn_ipsecpolicy_list(self):
+ ipsecpolicy = self.parser.listing(self.neutron('vpn-ipsecpolicy-list'))
+ self.assertTableStruct(ipsecpolicy, ['id', 'name',
+ 'auth_algorithm',
+ 'encryption_algorithm',
+ 'pfs'])
+
+ @test.attr(type='smoke')
+ @test.requires_ext(extension='vpnaas', service='network')
+ def test_neutron_vpn_service_list(self):
+ vpn_list = self.parser.listing(self.neutron('vpn-service-list'))
+ self.assertTableStruct(vpn_list, ['id', 'name',
+ 'router_id', 'status'])
+
+ @test.attr(type='smoke')
+ @test.requires_ext(extension='vpnaas', service='network')
+ def test_neutron_ipsec_site_connection_list(self):
+ ipsec_site = self.parser.listing(self.neutron
+ ('ipsec-site-connection-list'))
+ self.assertTableStruct(ipsec_site, ['id', 'name',
+ 'peer_address',
+ 'peer_cidrs',
+ 'route_mode',
+ 'auth_mode', 'status'])
+
+ @test.attr(type='smoke')
+ @test.requires_ext(extension='fwaas', service='network')
+ def test_neutron_firewall_list(self):
+ firewall_list = self.parser.listing(self.neutron
+ ('firewall-list'))
+ self.assertTableStruct(firewall_list, ['id', 'name',
+ 'firewall_policy_id'])
+
+ @test.attr(type='smoke')
+ @test.requires_ext(extension='fwaas', service='network')
+ def test_neutron_firewall_policy_list(self):
+ firewall_policy = self.parser.listing(self.neutron
+ ('firewall-policy-list'))
+ self.assertTableStruct(firewall_policy, ['id', 'name',
+ 'firewall_rules'])
+
+ @test.attr(type='smoke')
+ @test.requires_ext(extension='fwaas', service='network')
+ def test_neutron_firewall_rule_list(self):
+ firewall_rule = self.parser.listing(self.neutron
+ ('firewall-rule-list'))
+ self.assertTableStruct(firewall_rule, ['id', 'name',
+ 'firewall_policy_id',
+ 'summary', 'enabled'])
+
+ @test.attr(type='smoke')
def test_neutron_help(self):
help_text = self.neutron('help')
lines = help_text.split('\n')
diff --git a/tempest/cli/simple_read_only/object_storage/test_swift.py b/tempest/cli/simple_read_only/object_storage/test_swift.py
index a162660..40c4c15 100644
--- a/tempest/cli/simple_read_only/object_storage/test_swift.py
+++ b/tempest/cli/simple_read_only/object_storage/test_swift.py
@@ -15,9 +15,10 @@
import re
+from tempest_lib import exceptions
+
from tempest import cli
from tempest import config
-from tempest import exceptions
CONF = config.CONF
@@ -37,6 +38,10 @@
raise cls.skipException(msg)
super(SimpleReadOnlySwiftClientTest, cls).resource_setup()
+ def swift(self, *args, **kwargs):
+ return self.clients.swift(
+ *args, endpoint_type=CONF.object_storage.endpoint_type, **kwargs)
+
def test_swift_fake_action(self):
self.assertRaises(exceptions.CommandFailed,
self.swift,
diff --git a/tempest/cli/simple_read_only/orchestration/test_heat.py b/tempest/cli/simple_read_only/orchestration/test_heat.py
index 7d7f8c9..d3a9b01 100644
--- a/tempest/cli/simple_read_only/orchestration/test_heat.py
+++ b/tempest/cli/simple_read_only/orchestration/test_heat.py
@@ -42,6 +42,10 @@
os.path.dirname(os.path.realpath(__file__))),
'heat_templates/heat_minimal.yaml')
+ def heat(self, *args, **kwargs):
+ return self.clients.heat(
+ *args, endpoint_type=CONF.orchestration.endpoint_type, **kwargs)
+
def test_heat_stack_list(self):
self.heat('stack-list')
diff --git a/tempest/cli/simple_read_only/telemetry/test_ceilometer.py b/tempest/cli/simple_read_only/telemetry/test_ceilometer.py
index 45b793b..f9bf8b2 100644
--- a/tempest/cli/simple_read_only/telemetry/test_ceilometer.py
+++ b/tempest/cli/simple_read_only/telemetry/test_ceilometer.py
@@ -39,6 +39,10 @@
raise cls.skipException(msg)
super(SimpleReadOnlyCeilometerClientTest, cls).resource_setup()
+ def ceilometer(self, *args, **kwargs):
+ return self.clients.ceilometer(
+ *args, endpoint_type=CONF.telemetry.endpoint_type, **kwargs)
+
def test_ceilometer_meter_list(self):
self.ceilometer('meter-list')
diff --git a/tempest/cli/simple_read_only/volume/test_cinder.py b/tempest/cli/simple_read_only/volume/test_cinder.py
index 45f6c41..c2e0a42 100644
--- a/tempest/cli/simple_read_only/volume/test_cinder.py
+++ b/tempest/cli/simple_read_only/volume/test_cinder.py
@@ -16,11 +16,13 @@
import logging
import re
+from tempest_lib import exceptions
import testtools
from tempest import cli
+from tempest import clients
from tempest import config
-from tempest import exceptions
+
CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -40,6 +42,14 @@
msg = ("%s skipped as Cinder is not available" % cls.__name__)
raise cls.skipException(msg)
super(SimpleReadOnlyCinderClientTest, cls).resource_setup()
+ id_cl = clients.AdminManager().identity_client
+ tenant = id_cl.get_tenant_by_name(CONF.identity.admin_tenant_name)
+ cls.admin_tenant_id = tenant['id']
+
+ def cinder(self, *args, **kwargs):
+ return self.clients.cinder(*args,
+ endpoint_type=CONF.volume.endpoint_type,
+ **kwargs)
def test_cinder_fake_action(self):
self.assertRaises(exceptions.CommandFailed,
@@ -81,15 +91,13 @@
def test_cinder_quota_defaults(self):
"""This CLI can accept and string as param."""
roles = self.parser.listing(self.cinder('quota-defaults',
- params=CONF.identity.
- admin_tenant_name))
+ params=self.admin_tenant_id))
self.assertTableStruct(roles, ['Property', 'Value'])
def test_cinder_quota_show(self):
"""This CLI can accept and string as param."""
roles = self.parser.listing(self.cinder('quota-show',
- params=CONF.identity.
- admin_tenant_name))
+ params=self.admin_tenant_id))
self.assertTableStruct(roles, ['Property', 'Value'])
def test_cinder_rate_limits(self):
@@ -131,8 +139,7 @@
def test_cinder_service_list(self):
service_list = self.parser.listing(self.cinder('service-list'))
self.assertTableStruct(service_list, ['Binary', 'Host', 'Zone',
- 'Status', 'State', 'Updated_at',
- 'Disabled Reason'])
+ 'Status', 'State', 'Updated_at'])
def test_cinder_transfer_list(self):
transfer_list = self.parser.listing(self.cinder('transfer-list'))
diff --git a/tempest/clients.py b/tempest/clients.py
index cf04929..5873a85 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -16,7 +16,6 @@
from tempest import auth
from tempest.common import rest_client
from tempest import config
-from tempest import exceptions
from tempest import manager
from tempest.openstack.common import log as logging
from tempest.services.baremetal.v1.client_json import BaremetalClientJSON
@@ -87,35 +86,6 @@
ServicesV3ClientJSON
from tempest.services.compute.v3.json.version_client import \
VersionV3ClientJSON
-from tempest.services.compute.xml.aggregates_client import AggregatesClientXML
-from tempest.services.compute.xml.availability_zone_client import \
- AvailabilityZoneClientXML
-from tempest.services.compute.xml.certificates_client import \
- CertificatesClientXML
-from tempest.services.compute.xml.extensions_client import ExtensionsClientXML
-from tempest.services.compute.xml.fixed_ips_client import FixedIPsClientXML
-from tempest.services.compute.xml.flavors_client import FlavorsClientXML
-from tempest.services.compute.xml.floating_ips_client import \
- FloatingIPsClientXML
-from tempest.services.compute.xml.hosts_client import HostsClientXML
-from tempest.services.compute.xml.hypervisor_client import HypervisorClientXML
-from tempest.services.compute.xml.images_client import ImagesClientXML
-from tempest.services.compute.xml.instance_usage_audit_log_client import \
- InstanceUsagesAuditLogClientXML
-from tempest.services.compute.xml.interfaces_client import \
- InterfacesClientXML
-from tempest.services.compute.xml.keypairs_client import KeyPairsClientXML
-from tempest.services.compute.xml.limits_client import LimitsClientXML
-from tempest.services.compute.xml.quotas_client import QuotaClassesClientXML
-from tempest.services.compute.xml.quotas_client import QuotasClientXML
-from tempest.services.compute.xml.security_groups_client \
- import SecurityGroupsClientXML
-from tempest.services.compute.xml.servers_client import ServersClientXML
-from tempest.services.compute.xml.services_client import ServicesClientXML
-from tempest.services.compute.xml.tenant_usages_client import \
- TenantUsagesClientXML
-from tempest.services.compute.xml.volumes_extensions_client import \
- VolumesExtensionsClientXML
from tempest.services.data_processing.v1_1.client import DataProcessingClient
from tempest.services.database.json.flavors_client import \
DatabaseFlavorsClientJSON
@@ -134,24 +104,11 @@
from tempest.services.identity.v3.json.region_client import RegionClientJSON
from tempest.services.identity.v3.json.service_client import \
ServiceClientJSON
-from tempest.services.identity.v3.xml.credentials_client import \
- CredentialsClientXML
-from tempest.services.identity.v3.xml.endpoints_client import EndPointClientXML
-from tempest.services.identity.v3.xml.identity_client import \
- IdentityV3ClientXML
-from tempest.services.identity.v3.xml.identity_client import V3TokenClientXML
-from tempest.services.identity.v3.xml.policy_client import PolicyClientXML
-from tempest.services.identity.v3.xml.region_client import RegionClientXML
-from tempest.services.identity.v3.xml.service_client import \
- ServiceClientXML
-from tempest.services.identity.xml.identity_client import IdentityClientXML
-from tempest.services.identity.xml.identity_client import TokenClientXML
from tempest.services.image.v1.json.image_client import ImageClientJSON
from tempest.services.image.v2.json.image_client import ImageClientV2JSON
from tempest.services.messaging.json.messaging_client import \
MessagingClientJSON
from tempest.services.network.json.network_client import NetworkClientJSON
-from tempest.services.network.xml.network_client import NetworkClientXML
from tempest.services.object_storage.account_client import AccountClient
from tempest.services.object_storage.account_client import \
AccountClientCustomizedHeader
@@ -163,8 +120,6 @@
OrchestrationClient
from tempest.services.telemetry.json.telemetry_client import \
TelemetryClientJSON
-from tempest.services.telemetry.xml.telemetry_client import \
- TelemetryClientXML
from tempest.services.volume.json.admin.volume_hosts_client import \
VolumeHostsClientJSON
from tempest.services.volume.json.admin.volume_quotas_client import \
@@ -181,38 +136,21 @@
from tempest.services.volume.json.qos_client import QosSpecsClientJSON
from tempest.services.volume.json.snapshots_client import SnapshotsClientJSON
from tempest.services.volume.json.volumes_client import VolumesClientJSON
+from tempest.services.volume.v2.json.admin.volume_hosts_client import \
+ VolumeHostsV2ClientJSON
+from tempest.services.volume.v2.json.admin.volume_quotas_client import \
+ VolumeQuotasV2Client
from tempest.services.volume.v2.json.admin.volume_types_client import \
VolumeTypesV2ClientJSON
from tempest.services.volume.v2.json.availability_zone_client import \
VolumeV2AvailabilityZoneClientJSON
+from tempest.services.volume.v2.json.backups_client import BackupsClientV2JSON
from tempest.services.volume.v2.json.extensions_client import \
ExtensionsV2ClientJSON as VolumeV2ExtensionClientJSON
from tempest.services.volume.v2.json.qos_client import QosSpecsV2ClientJSON
from tempest.services.volume.v2.json.snapshots_client import \
SnapshotsV2ClientJSON
from tempest.services.volume.v2.json.volumes_client import VolumesV2ClientJSON
-from tempest.services.volume.v2.xml.availability_zone_client import \
- VolumeV2AvailabilityZoneClientXML
-from tempest.services.volume.v2.xml.extensions_client import \
- ExtensionsV2ClientXML as VolumeV2ExtensionClientXML
-from tempest.services.volume.v2.xml.snapshots_client import \
- SnapshotsV2ClientXML
-from tempest.services.volume.v2.xml.volumes_client import VolumesV2ClientXML
-from tempest.services.volume.xml.admin.volume_hosts_client import \
- VolumeHostsClientXML
-from tempest.services.volume.xml.admin.volume_quotas_client import \
- VolumeQuotasClientXML
-from tempest.services.volume.xml.admin.volume_services_client import \
- VolumesServicesClientXML
-from tempest.services.volume.xml.admin.volume_types_client import \
- VolumeTypesClientXML
-from tempest.services.volume.xml.availability_zone_client import \
- VolumeAvailabilityZoneClientXML
-from tempest.services.volume.xml.backups_client import BackupsClientXML
-from tempest.services.volume.xml.extensions_client import \
- ExtensionsClientXML as VolumeExtensionClientXML
-from tempest.services.volume.xml.snapshots_client import SnapshotsClientXML
-from tempest.services.volume.xml.volumes_client import VolumesClientXML
CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -230,185 +168,23 @@
# super cares for credentials validation
super(Manager, self).__init__(credentials=credentials)
- if self.interface == 'xml':
- self.certificates_client = CertificatesClientXML(
- self.auth_provider)
- self.servers_client = ServersClientXML(self.auth_provider)
- self.limits_client = LimitsClientXML(self.auth_provider)
- self.images_client = ImagesClientXML(self.auth_provider)
- self.keypairs_client = KeyPairsClientXML(self.auth_provider)
- self.quotas_client = QuotasClientXML(self.auth_provider)
- self.quota_classes_client = QuotaClassesClientXML(
- self.auth_provider)
- self.flavors_client = FlavorsClientXML(self.auth_provider)
- self.extensions_client = ExtensionsClientXML(self.auth_provider)
- self.volumes_extensions_client = VolumesExtensionsClientXML(
- self.auth_provider)
- self.floating_ips_client = FloatingIPsClientXML(
- self.auth_provider)
- self.backups_client = BackupsClientXML(self.auth_provider)
- self.snapshots_client = SnapshotsClientXML(self.auth_provider)
- self.snapshots_v2_client = SnapshotsV2ClientXML(self.auth_provider)
- self.volumes_client = VolumesClientXML(self.auth_provider)
- self.volumes_v2_client = VolumesV2ClientXML(self.auth_provider)
- self.volume_types_client = VolumeTypesClientXML(
- self.auth_provider)
- self.identity_client = IdentityClientXML(self.auth_provider)
- self.identity_v3_client = IdentityV3ClientXML(
- self.auth_provider)
- self.security_groups_client = SecurityGroupsClientXML(
- self.auth_provider)
- self.interfaces_client = InterfacesClientXML(self.auth_provider)
- self.endpoints_client = EndPointClientXML(self.auth_provider)
- self.fixed_ips_client = FixedIPsClientXML(self.auth_provider)
- self.availability_zone_client = AvailabilityZoneClientXML(
- self.auth_provider)
- self.service_client = ServiceClientXML(self.auth_provider)
- self.volume_services_client = VolumesServicesClientXML(
- self.auth_provider)
- self.aggregates_client = AggregatesClientXML(self.auth_provider)
- self.services_client = ServicesClientXML(self.auth_provider)
- self.tenant_usages_client = TenantUsagesClientXML(
- self.auth_provider)
- self.policy_client = PolicyClientXML(self.auth_provider)
- self.region_client = RegionClientXML(self.auth_provider)
- self.hosts_client = HostsClientXML(self.auth_provider)
- self.hypervisor_client = HypervisorClientXML(self.auth_provider)
- self.network_client = NetworkClientXML(self.auth_provider)
- self.credentials_client = CredentialsClientXML(
- self.auth_provider)
- self.instance_usages_audit_log_client = \
- InstanceUsagesAuditLogClientXML(self.auth_provider)
- self.volume_hosts_client = VolumeHostsClientXML(
- self.auth_provider)
- self.volume_quotas_client = VolumeQuotasClientXML(
- self.auth_provider)
- self.volumes_extension_client = VolumeExtensionClientXML(
- self.auth_provider)
- self.volumes_v2_extension_client = VolumeV2ExtensionClientXML(
- self.auth_provider)
- if CONF.service_available.ceilometer:
- self.telemetry_client = TelemetryClientXML(
- self.auth_provider)
- self.token_client = TokenClientXML()
- self.token_v3_client = V3TokenClientXML()
- self.volume_availability_zone_client = \
- VolumeAvailabilityZoneClientXML(self.auth_provider)
- self.volume_v2_availability_zone_client = \
- VolumeV2AvailabilityZoneClientXML(self.auth_provider)
+ self._set_compute_clients(self.interface)
+ self._set_identity_clients(self.interface)
+ self._set_volume_clients(self.interface)
- elif self.interface == 'json':
- self.certificates_client = CertificatesClientJSON(
+ self.baremetal_client = BaremetalClientJSON(self.auth_provider)
+ self.network_client = NetworkClientJSON(self.auth_provider)
+ self.database_flavors_client = DatabaseFlavorsClientJSON(
+ self.auth_provider)
+ self.database_versions_client = DatabaseVersionsClientJSON(
+ self.auth_provider)
+ self.messaging_client = MessagingClientJSON(self.auth_provider)
+ if CONF.service_available.ceilometer:
+ self.telemetry_client = TelemetryClientJSON(
self.auth_provider)
- self.certificates_v3_client = CertificatesV3ClientJSON(
- self.auth_provider)
- self.baremetal_client = BaremetalClientJSON(self.auth_provider)
- self.servers_client = ServersClientJSON(self.auth_provider)
- self.servers_v3_client = ServersV3ClientJSON(self.auth_provider)
- self.limits_client = LimitsClientJSON(self.auth_provider)
- self.images_client = ImagesClientJSON(self.auth_provider)
- self.keypairs_v3_client = KeyPairsV3ClientJSON(
- self.auth_provider)
- self.keypairs_client = KeyPairsClientJSON(self.auth_provider)
- self.keypairs_v3_client = KeyPairsV3ClientJSON(
- self.auth_provider)
- self.quotas_client = QuotasClientJSON(self.auth_provider)
- self.quota_classes_client = QuotaClassesClientJSON(
- self.auth_provider)
- self.quotas_v3_client = QuotasV3ClientJSON(self.auth_provider)
- self.flavors_client = FlavorsClientJSON(self.auth_provider)
- self.flavors_v3_client = FlavorsV3ClientJSON(self.auth_provider)
- self.extensions_v3_client = ExtensionsV3ClientJSON(
- self.auth_provider)
- self.extensions_client = ExtensionsClientJSON(
- self.auth_provider)
- self.volumes_extensions_client = VolumesExtensionsClientJSON(
- self.auth_provider)
- self.floating_ips_client = FloatingIPsClientJSON(
- self.auth_provider)
- self.backups_client = BackupsClientJSON(self.auth_provider)
- self.snapshots_client = SnapshotsClientJSON(self.auth_provider)
- self.snapshots_v2_client = SnapshotsV2ClientJSON(
- self.auth_provider)
- self.volumes_client = VolumesClientJSON(self.auth_provider)
- self.volumes_v2_client = VolumesV2ClientJSON(self.auth_provider)
- self.volume_types_client = VolumeTypesClientJSON(
- self.auth_provider)
- self.volume_types_v2_client = VolumeTypesV2ClientJSON(
- self.auth_provider)
- self.identity_client = IdentityClientJSON(self.auth_provider)
- self.identity_v3_client = IdentityV3ClientJSON(
- self.auth_provider)
- self.security_groups_client = SecurityGroupsClientJSON(
- self.auth_provider)
- self.interfaces_v3_client = InterfacesV3ClientJSON(
- self.auth_provider)
- self.interfaces_client = InterfacesClientJSON(
- self.auth_provider)
- self.endpoints_client = EndPointClientJSON(self.auth_provider)
- self.fixed_ips_client = FixedIPsClientJSON(self.auth_provider)
- self.availability_zone_v3_client = AvailabilityZoneV3ClientJSON(
- self.auth_provider)
- self.availability_zone_client = AvailabilityZoneClientJSON(
- self.auth_provider)
- self.services_v3_client = ServicesV3ClientJSON(
- self.auth_provider)
- self.service_client = ServiceClientJSON(self.auth_provider)
- self.volume_services_client = VolumesServicesClientJSON(
- self.auth_provider)
- self.agents_v3_client = AgentsV3ClientJSON(self.auth_provider)
- self.aggregates_v3_client = AggregatesV3ClientJSON(
- self.auth_provider)
- self.aggregates_client = AggregatesClientJSON(
- self.auth_provider)
- self.services_client = ServicesClientJSON(self.auth_provider)
- self.tenant_usages_client = TenantUsagesClientJSON(
- self.auth_provider)
- self.version_v3_client = VersionV3ClientJSON(self.auth_provider)
- self.migrations_v3_client = MigrationsV3ClientJSON(
- self.auth_provider)
- self.policy_client = PolicyClientJSON(self.auth_provider)
- self.region_client = RegionClientJSON(self.auth_provider)
- self.hosts_client = HostsClientJSON(self.auth_provider)
- self.hypervisor_v3_client = HypervisorV3ClientJSON(
- self.auth_provider)
- self.hypervisor_client = HypervisorClientJSON(
- self.auth_provider)
- self.network_client = NetworkClientJSON(self.auth_provider)
- self.credentials_client = CredentialsClientJSON(
- self.auth_provider)
- self.instance_usages_audit_log_client = \
- InstanceUsagesAuditLogClientJSON(self.auth_provider)
- self.volume_hosts_client = VolumeHostsClientJSON(
- self.auth_provider)
- self.volume_quotas_client = VolumeQuotasClientJSON(
- self.auth_provider)
- self.volumes_extension_client = VolumeExtensionClientJSON(
- self.auth_provider)
- self.volumes_v2_extension_client = VolumeV2ExtensionClientJSON(
- self.auth_provider)
- self.hosts_v3_client = HostsV3ClientJSON(self.auth_provider)
- self.database_flavors_client = DatabaseFlavorsClientJSON(
- self.auth_provider)
- self.database_versions_client = DatabaseVersionsClientJSON(
- self.auth_provider)
- self.messaging_client = MessagingClientJSON(self.auth_provider)
- if CONF.service_available.ceilometer:
- self.telemetry_client = TelemetryClientJSON(
- self.auth_provider)
- self.token_client = TokenClientJSON()
- self.token_v3_client = V3TokenClientJSON()
- self.negative_client = rest_client.NegativeRestClient(
- self.auth_provider)
- self.negative_client.service = service
- self.volume_availability_zone_client = \
- VolumeAvailabilityZoneClientJSON(self.auth_provider)
- self.volume_v2_availability_zone_client = \
- VolumeV2AvailabilityZoneClientJSON(self.auth_provider)
-
- else:
- msg = "Unsupported interface type `%s'" % interface
- raise exceptions.InvalidConfiguration(msg)
+ self.negative_client = rest_client.NegativeRestClient(
+ self.auth_provider)
+ self.negative_client.service = service
# TODO(andreaf) EC2 client still do their auth, v2 only
ec2_client_args = (self.credentials.username,
@@ -418,7 +194,6 @@
# common clients
self.account_client = AccountClient(self.auth_provider)
- self.agents_client = AgentsClientJSON(self.auth_provider)
if CONF.service_available.glance:
self.image_client = ImageClientJSON(self.auth_provider)
self.image_client_v2 = ImageClientV2JSON(self.auth_provider)
@@ -434,10 +209,79 @@
AccountClientCustomizedHeader(self.auth_provider)
self.data_processing_client = DataProcessingClient(
self.auth_provider)
+
+ def _set_compute_clients(self, type):
+ self._set_compute_json_clients()
+
+ # Common compute clients
+ self.agents_client = AgentsClientJSON(self.auth_provider)
+ self.networks_client = NetworksClientJSON(self.auth_provider)
self.migrations_client = MigrationsClientJSON(self.auth_provider)
self.security_group_default_rules_client = (
SecurityGroupDefaultRulesClientJSON(self.auth_provider))
- self.networks_client = NetworksClientJSON(self.auth_provider)
+
+ def _set_compute_json_clients(self):
+ self.certificates_client = CertificatesClientJSON(self.auth_provider)
+ self.certificates_v3_client = CertificatesV3ClientJSON(
+ self.auth_provider)
+ self.servers_client = ServersClientJSON(self.auth_provider)
+ self.servers_v3_client = ServersV3ClientJSON(self.auth_provider)
+ self.limits_client = LimitsClientJSON(self.auth_provider)
+ self.images_client = ImagesClientJSON(self.auth_provider)
+ self.keypairs_client = KeyPairsClientJSON(self.auth_provider)
+ self.keypairs_v3_client = KeyPairsV3ClientJSON(self.auth_provider)
+ self.quotas_client = QuotasClientJSON(self.auth_provider)
+ self.quota_classes_client = QuotaClassesClientJSON(self.auth_provider)
+ self.quotas_v3_client = QuotasV3ClientJSON(self.auth_provider)
+ self.flavors_client = FlavorsClientJSON(self.auth_provider)
+ self.flavors_v3_client = FlavorsV3ClientJSON(self.auth_provider)
+ self.extensions_client = ExtensionsClientJSON(self.auth_provider)
+ self.extensions_v3_client = ExtensionsV3ClientJSON(self.auth_provider)
+ self.volumes_extensions_client = VolumesExtensionsClientJSON(
+ self.auth_provider)
+ self.floating_ips_client = FloatingIPsClientJSON(self.auth_provider)
+ self.security_groups_client = SecurityGroupsClientJSON(
+ self.auth_provider)
+ self.interfaces_client = InterfacesClientJSON(self.auth_provider)
+ self.interfaces_v3_client = InterfacesV3ClientJSON(self.auth_provider)
+ self.fixed_ips_client = FixedIPsClientJSON(self.auth_provider)
+ self.availability_zone_client = AvailabilityZoneClientJSON(
+ self.auth_provider)
+ self.availability_zone_v3_client = AvailabilityZoneV3ClientJSON(
+ self.auth_provider)
+ self.services_v3_client = ServicesV3ClientJSON(self.auth_provider)
+ self.agents_v3_client = AgentsV3ClientJSON(self.auth_provider)
+ self.aggregates_client = AggregatesClientJSON(self.auth_provider)
+ self.aggregates_v3_client = AggregatesV3ClientJSON(self.auth_provider)
+ self.services_client = ServicesClientJSON(self.auth_provider)
+ self.tenant_usages_client = TenantUsagesClientJSON(self.auth_provider)
+ self.version_v3_client = VersionV3ClientJSON(self.auth_provider)
+ self.migrations_v3_client = MigrationsV3ClientJSON(self.auth_provider)
+ self.hosts_client = HostsClientJSON(self.auth_provider)
+ self.hosts_v3_client = HostsV3ClientJSON(self.auth_provider)
+ self.hypervisor_client = HypervisorClientJSON(self.auth_provider)
+ self.hypervisor_v3_client = HypervisorV3ClientJSON(self.auth_provider)
+ self.instance_usages_audit_log_client = \
+ InstanceUsagesAuditLogClientJSON(self.auth_provider)
+
+ def _set_identity_clients(self, type):
+ self._set_identity_json_clients()
+
+ def _set_identity_json_clients(self):
+ self.identity_client = IdentityClientJSON(self.auth_provider)
+ self.identity_v3_client = IdentityV3ClientJSON(self.auth_provider)
+ self.endpoints_client = EndPointClientJSON(self.auth_provider)
+ self.service_client = ServiceClientJSON(self.auth_provider)
+ self.policy_client = PolicyClientJSON(self.auth_provider)
+ self.region_client = RegionClientJSON(self.auth_provider)
+ self.token_client = TokenClientJSON()
+ if CONF.identity_feature_enabled.api_v3:
+ self.token_v3_client = V3TokenClientJSON()
+ self.credentials_client = CredentialsClientJSON(self.auth_provider)
+
+ def _set_volume_clients(self, type):
+ self._set_volume_json_clients()
+ # Common volume clients
# NOTE : As XML clients are not implemented for Qos-specs.
# So, setting the qos_client here. Once client are implemented,
# qos_client would be moved to its respective if/else.
@@ -446,19 +290,31 @@
self.volume_qos_v2_client = QosSpecsV2ClientJSON(
self.auth_provider)
-
-class AltManager(Manager):
-
- """
- Manager object that uses the alt_XXX credentials for its
- managed client objects
- """
-
- def __init__(self, interface='json', service=None):
- super(AltManager, self).__init__(
- credentials=auth.get_default_credentials('alt_user'),
- interface=interface,
- service=service)
+ def _set_volume_json_clients(self):
+ self.backups_client = BackupsClientJSON(self.auth_provider)
+ self.backups_v2_client = BackupsClientV2JSON(self.auth_provider)
+ self.snapshots_client = SnapshotsClientJSON(self.auth_provider)
+ self.snapshots_v2_client = SnapshotsV2ClientJSON(self.auth_provider)
+ self.volumes_client = VolumesClientJSON(self.auth_provider)
+ self.volumes_v2_client = VolumesV2ClientJSON(self.auth_provider)
+ self.volume_types_client = VolumeTypesClientJSON(self.auth_provider)
+ self.volume_services_client = VolumesServicesClientJSON(
+ self.auth_provider)
+ self.volume_hosts_client = VolumeHostsClientJSON(self.auth_provider)
+ self.volume_hosts_v2_client = VolumeHostsV2ClientJSON(
+ self.auth_provider)
+ self.volume_quotas_client = VolumeQuotasClientJSON(self.auth_provider)
+ self.volume_quotas_v2_client = VolumeQuotasV2Client(self.auth_provider)
+ self.volumes_extension_client = VolumeExtensionClientJSON(
+ self.auth_provider)
+ self.volumes_v2_extension_client = VolumeV2ExtensionClientJSON(
+ self.auth_provider)
+ self.volume_availability_zone_client = \
+ VolumeAvailabilityZoneClientJSON(self.auth_provider)
+ self.volume_v2_availability_zone_client = \
+ VolumeV2AvailabilityZoneClientJSON(self.auth_provider)
+ self.volume_types_v2_client = VolumeTypesV2ClientJSON(
+ self.auth_provider)
class AdminManager(Manager):
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
old mode 100644
new mode 100755
index a305e42..f36ef56
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -9,7 +9,7 @@
#
# 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
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
@@ -36,14 +36,14 @@
**NOTE**: The _tenants_to_clean array in dry-run.json lists the
tenants that cleanup will loop through and delete child objects, not
delete the tenant itself. This may differ from the tenants array as you
-can clean the tempest and alternate tempest tenants but not delete the
-tenants themselves. This is actually the default behavior.
+can clean the tempest and alternate tempest tenants but by default,
+cleanup deletes the objects in the tempest and alternate tempest tenants
+but does not delete those tenants unless the --delete-tempest-conf-objects
+flag is used to force their deletion.
**Normal mode**: running with no arguments, will query your deployment and
-build a list of objects to delete after filtering out out the objects
-found in saved_state.json and based on the
---preserve-tempest-conf-objects and
---delete-tempest-conf-objects flags.
+build a list of objects to delete after filtering out the objects found in
+saved_state.json and based on the --delete-tempest-conf-objects flag.
By default the tempest and alternate tempest users and tenants are not
deleted and the admin user specified in tempest.conf is never deleted.
@@ -84,7 +84,6 @@
# available services
self.tenant_services = cleanup_service.get_tenant_cleanup_services()
self.global_services = cleanup_service.get_global_cleanup_services()
- cleanup_service.init_conf()
def run(self):
opts = self.options
@@ -98,7 +97,7 @@
def _cleanup(self):
LOG.debug("Begin cleanup")
is_dry_run = self.options.dry_run
- is_preserve = self.options.preserve_tempest_conf_objects
+ is_preserve = not self.options.delete_tempest_conf_objects
is_save_state = False
if is_dry_run:
@@ -149,7 +148,7 @@
LOG.debug("Cleaning tenant: %s " % tenant['name'])
is_dry_run = self.options.dry_run
dry_run_data = self.dry_run_data
- is_preserve = self.options.preserve_tempest_conf_objects
+ is_preserve = not self.options.delete_tempest_conf_objects
tenant_id = tenant['id']
tenant_name = tenant['name']
tenant_data = None
@@ -194,23 +193,16 @@
dest='init_saved_state', default=False,
help="Creates JSON file: " + SAVED_STATE_JSON +
", representing the current state of your "
- "deployment, specifically objects types "
- "Tempest creates and destroys during a run. "
+ "deployment, specifically object types "
+ "tempest creates and destroys during a run. "
"You must run with this flag prior to "
- "executing cleanup.")
- parser.add_argument('--preserve-tempest-conf-objects',
- action="store_true",
- dest='preserve_tempest_conf_objects',
- default=True, help="Do not delete the "
- "tempest and alternate tempest users and "
- "tenants, so they may be used for future "
- "tempest runs. By default this is argument "
- "is true.")
+ "executing cleanup in normal mode, which is with "
+ "no arguments.")
parser.add_argument('--delete-tempest-conf-objects',
- action="store_false",
- dest='preserve_tempest_conf_objects',
+ action="store_true",
+ dest='delete_tempest_conf_objects',
default=False,
- help="Delete the tempest and "
+ help="Force deletion of the tempest and "
"alternate tempest users and tenants.")
parser.add_argument('--dry-run', action="store_true",
dest='dry_run', default=False,
@@ -291,6 +283,7 @@
def main():
+ cleanup_service.init_conf()
cleanup = Cleanup()
cleanup.run()
LOG.info('Cleanup finished!')
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 0d3c6c6..67843e6 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -14,6 +14,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest import clients
from tempest import config
from tempest.openstack.common import log as logging
from tempest import test
@@ -21,13 +22,14 @@
LOG = logging.getLogger(__name__)
CONF = config.CONF
-CONF_USERS = None
-CONF_TENANTS = None
-CONF_PUB_NETWORK = None
-CONF_PRIV_NETWORK_NAME = None
-CONF_PUB_ROUTER = None
CONF_FLAVORS = None
CONF_IMAGES = None
+CONF_NETWORKS = []
+CONF_PRIV_NETWORK_NAME = None
+CONF_PUB_NETWORK = None
+CONF_PUB_ROUTER = None
+CONF_TENANTS = None
+CONF_USERS = None
IS_CEILOMETER = None
IS_CINDER = None
@@ -38,14 +40,15 @@
def init_conf():
- global CONF_USERS
- global CONF_TENANTS
- global CONF_PUB_NETWORK
- global CONF_PRIV_NETWORK_NAME
- global CONF_PUB_ROUTER
global CONF_FLAVORS
global CONF_IMAGES
-
+ global CONF_NETWORKS
+ global CONF_PRIV_NETWORK
+ global CONF_PRIV_NETWORK_NAME
+ global CONF_PUB_NETWORK
+ global CONF_PUB_ROUTER
+ global CONF_TENANTS
+ global CONF_USERS
global IS_CEILOMETER
global IS_CINDER
global IS_GLANCE
@@ -53,17 +56,6 @@
global IS_NEUTRON
global IS_NOVA
- CONF_USERS = [CONF.identity.admin_username, CONF.identity.username,
- CONF.identity.alt_username]
- CONF_TENANTS = [CONF.identity.admin_tenant_name,
- CONF.identity.tenant_name,
- CONF.identity.alt_tenant_name]
- CONF_PUB_NETWORK = CONF.network.public_network_id
- CONF_PRIV_NETWORK_NAME = CONF.compute.fixed_network_name
- CONF_PUB_ROUTER = CONF.network.public_router_id
- CONF_FLAVORS = [CONF.compute.flavor_ref, CONF.compute.flavor_ref_alt]
- CONF_IMAGES = [CONF.compute.image_ref, CONF.compute.image_ref_alt]
-
IS_CEILOMETER = CONF.service_available.ceilometer
IS_CINDER = CONF.service_available.cinder
IS_GLANCE = CONF.service_available.glance
@@ -71,6 +63,38 @@
IS_NEUTRON = CONF.service_available.neutron
IS_NOVA = CONF.service_available.nova
+ CONF_FLAVORS = [CONF.compute.flavor_ref, CONF.compute.flavor_ref_alt]
+ CONF_IMAGES = [CONF.compute.image_ref, CONF.compute.image_ref_alt]
+ 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.identity.admin_tenant_name,
+ CONF.identity.tenant_name,
+ CONF.identity.alt_tenant_name]
+ CONF_USERS = [CONF.identity.admin_username, CONF.identity.username,
+ CONF.identity.alt_username]
+
+ if IS_NEUTRON:
+ CONF_PRIV_NETWORK = _get_priv_net_id(CONF.compute.fixed_network_name,
+ CONF.identity.tenant_name)
+ CONF_NETWORKS = [CONF_PUB_NETWORK, CONF_PRIV_NETWORK]
+
+
+def _get_priv_net_id(prv_net_name, tenant_name):
+ am = clients.AdminManager()
+ net_cl = am.network_client
+ id_cl = am.identity_client
+
+ _, networks = net_cl.list_networks()
+ tenant = id_cl.get_tenant_by_name(tenant_name)
+ t_id = tenant['id']
+ n_id = None
+ for net in networks['networks']:
+ if (net['tenant_id'] == t_id and net['name'] == prv_net_name):
+ n_id = net['id']
+ break
+ return n_id
+
class BaseService(object):
def __init__(self, kwargs):
@@ -86,11 +110,8 @@
or 'tenant_id' not in item_list[0]):
return item_list
- _filtered_list = []
- for item in item_list:
- if item['tenant_id'] == self.tenant_id:
- _filtered_list.append(item)
- return _filtered_list
+ return [item for item in item_list
+ if item['tenant_id'] == self.tenant_id]
def list(self):
pass
@@ -327,6 +348,13 @@
super(NetworkService, self).__init__(kwargs)
self.client = manager.network_client
+ def _filter_by_conf_networks(self, item_list):
+ if not item_list or not all(('network_id' in i for i in item_list)):
+ return item_list
+
+ return [item for item in item_list if item['network_id']
+ not in CONF_NETWORKS]
+
def list(self):
client = self.client
_, networks = client.list_networks()
@@ -334,8 +362,7 @@
# filter out networks declared in tempest.conf
if self.is_preserve:
networks = [network for network in networks
- if (network['name'] != CONF_PRIV_NETWORK_NAME
- and network['id'] != CONF_PUB_NETWORK)]
+ if network['id'] not in CONF_NETWORKS]
LOG.debug("List count, %s Networks" % networks)
return networks
@@ -529,7 +556,7 @@
for port in ports:
subid = port['fixed_ips'][0]['subnet_id']
client.remove_router_interface_with_subnet_id(rid, subid)
- client.delete_router(rid)
+ client.delete_router(rid)
except Exception as e:
LOG.exception("Delete Router exception: %s" % e)
pass
@@ -696,6 +723,8 @@
_, ports = client.list_ports()
ports = ports['ports']
ports = self._filter_by_tenant_id(ports)
+ if self.is_preserve:
+ ports = self._filter_by_conf_networks(ports)
LOG.debug("List count, %s Ports" % len(ports))
return ports
@@ -721,6 +750,8 @@
_, subnets = client.list_subnets()
subnets = subnets['subnets']
subnets = self._filter_by_tenant_id(subnets)
+ if self.is_preserve:
+ subnets = self._filter_by_conf_networks(subnets)
LOG.debug("List count, %s Subnets" % len(subnets))
return subnets
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index 0adc7e0..6879db9 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -26,6 +26,7 @@
import sys
import unittest
+import netaddr
import yaml
import tempest.auth
@@ -34,14 +35,17 @@
from tempest.openstack.common import log as logging
from tempest.openstack.common import timeutils
from tempest.services.compute.json import flavors_client
+from tempest.services.compute.json import security_groups_client
from tempest.services.compute.json import servers_client
from tempest.services.identity.json import identity_client
from tempest.services.image.v2.json import image_client
+from tempest.services.network.json import network_client
from tempest.services.object_storage import container_client
from tempest.services.object_storage import object_client
from tempest.services.telemetry.json import telemetry_client
from tempest.services.volume.json import volumes_client
+CONF = config.CONF
OPTS = {}
USERS = {}
RES = collections.defaultdict(list)
@@ -69,7 +73,9 @@
self.images = image_client.ImageClientV2JSON(_auth)
self.flavors = flavors_client.FlavorsClientJSON(_auth)
self.telemetry = telemetry_client.TelemetryClientJSON(_auth)
+ self.secgroups = security_groups_client.SecurityGroupsClientJSON(_auth)
self.volumes = volumes_client.VolumesClientJSON(_auth)
+ self.networks = network_client.NetworkClientJSON(_auth)
def load_resources(fname):
@@ -90,6 +96,10 @@
else:
LOG.error("%s not found in USERS: %s" % (name, USERS))
+
+def resp_ok(response):
+ return 200 >= int(response['status']) < 300
+
###################
#
# TENANTS
@@ -212,12 +222,36 @@
def runTest(self, *args):
pass
+ def _ping_ip(self, ip_addr, count, namespace=None):
+ if namespace is None:
+ ping_cmd = "ping -c1 " + ip_addr
+ else:
+ ping_cmd = "sudo ip netns exec %s ping -c1 %s" % (namespace,
+ ip_addr)
+ for current in range(count):
+ return_code = os.system(ping_cmd)
+ if return_code is 0:
+ break
+ self.assertNotEqual(current, count - 1,
+ "Server is not pingable at %s" % ip_addr)
+
def check(self):
self.check_users()
self.check_objects()
self.check_servers()
self.check_volumes()
self.check_telemetry()
+ self.check_secgroups()
+
+ # validate neutron is enabled and ironic disabled:
+ # Tenant network isolation is not supported when using ironic.
+ # "admin" has set up a neutron flat network environment within a shared
+ # fixed network for all tenants to use.
+ # In this case, network/subnet/router creation can be skipped and the
+ # server booted the same as nova network.
+ if (CONF.service_available.neutron and
+ not CONF.baremetal.driver_enabled):
+ self.check_networking()
def check_users(self):
"""Check that the users we expect to exist, do.
@@ -264,15 +298,32 @@
"Couldn't find expected server %s" % server['name'])
r, found = client.servers.get_server(found['id'])
- # get the ipv4 address
- addr = found['addresses']['private'][0]['addr']
- for count in range(60):
- return_code = os.system("ping -c1 " + addr)
- if return_code is 0:
- break
- self.assertNotEqual(count, 59,
- "Server %s is not pingable at %s" % (
- server['name'], addr))
+ # validate neutron is enabled and ironic disabled:
+ if (CONF.service_available.neutron and
+ not CONF.baremetal.driver_enabled):
+ for network_name, body in found['addresses'].items():
+ for addr in body:
+ ip = addr['addr']
+ if addr.get('OS-EXT-IPS:type', 'fixed') == 'fixed':
+ namespace = _get_router_namespace(client,
+ network_name)
+ self._ping_ip(ip, 60, namespace)
+ else:
+ self._ping_ip(ip, 60)
+ else:
+ addr = found['addresses']['private'][0]['addr']
+ self._ping_ip(addr, 60)
+
+ def check_secgroups(self):
+ """Check that the security groups are still existing."""
+ LOG.info("Checking security groups")
+ for secgroup in self.res['secgroups']:
+ client = client_for_user(secgroup['owner'])
+ found = _get_resource_by_name(client.secgroups, 'security_groups',
+ secgroup['name'])
+ self.assertIsNotNone(
+ found,
+ "Couldn't find expected secgroup %s" % secgroup['name'])
def check_telemetry(self):
"""Check that ceilometer provides a sane sample.
@@ -334,6 +385,17 @@
'timestamp should come before start of second javelin run'
)
+ def check_networking(self):
+ """Check that the networks are still there."""
+ for res_type in ('networks', 'subnets', 'routers'):
+ for res in self.res[res_type]:
+ client = client_for_user(res['owner'])
+ found = _get_resource_by_name(client.networks, res_type,
+ res['name'])
+ self.assertIsNotNone(
+ found,
+ "Couldn't find expected resource %s" % res['name'])
+
#######################
#
@@ -440,6 +502,147 @@
#######################
#
+# NETWORKS
+#
+#######################
+
+def _get_router_namespace(client, network):
+ network_id = _get_resource_by_name(client.networks,
+ 'networks', network)['id']
+ resp, n_body = client.networks.list_routers()
+ if not resp_ok(resp):
+ raise ValueError("unable to routers list: [%s] %s" % (resp, n_body))
+ for router in n_body['routers']:
+ router_id = router['id']
+ resp, r_body = client.networks.list_router_interfaces(router_id)
+ if not resp_ok(resp):
+ raise ValueError("unable to router interfaces list: [%s] %s" %
+ (resp, r_body))
+ for port in r_body['ports']:
+ if port['network_id'] == network_id:
+ return "qrouter-%s" % router_id
+
+
+def _get_resource_by_name(client, resource, name):
+ get_resources = getattr(client, 'list_%s' % resource)
+ if get_resources is None:
+ raise AttributeError("client doesn't have method list_%s" % resource)
+ r, body = get_resources()
+ if not resp_ok(r):
+ raise ValueError("unable to list %s: [%s] %s" % (resource, r, body))
+ if isinstance(body, dict):
+ body = body[resource]
+ for res in body:
+ if name == res['name']:
+ return res
+ raise ValueError('%s not found in %s resources' % (name, resource))
+
+
+def create_networks(networks):
+ LOG.info("Creating networks")
+ for network in networks:
+ client = client_for_user(network['owner'])
+
+ # only create a network if the name isn't here
+ r, body = client.networks.list_networks()
+ if any(item['name'] == network['name'] for item in body['networks']):
+ LOG.warning("Dupplicated network name: %s" % network['name'])
+ continue
+
+ client.networks.create_network(name=network['name'])
+
+
+def destroy_networks(networks):
+ LOG.info("Destroying subnets")
+ for network in networks:
+ client = client_for_user(network['owner'])
+ network_id = _get_resource_by_name(client.networks, 'networks',
+ network['name'])['id']
+ client.networks.delete_network(network_id)
+
+
+def create_subnets(subnets):
+ LOG.info("Creating subnets")
+ for subnet in subnets:
+ client = client_for_user(subnet['owner'])
+
+ network = _get_resource_by_name(client.networks, 'networks',
+ subnet['network'])
+ ip_version = netaddr.IPNetwork(subnet['range']).version
+ # ensure we don't overlap with another subnet in the network
+ try:
+ client.networks.create_subnet(network_id=network['id'],
+ cidr=subnet['range'],
+ name=subnet['name'],
+ ip_version=ip_version)
+ except exceptions.BadRequest as e:
+ is_overlapping_cidr = 'overlaps with another subnet' in str(e)
+ if not is_overlapping_cidr:
+ raise
+
+
+def destroy_subnets(subnets):
+ LOG.info("Destroying subnets")
+ for subnet in subnets:
+ client = client_for_user(subnet['owner'])
+ subnet_id = _get_resource_by_name(client.networks,
+ 'subnets', subnet['name'])['id']
+ client.networks.delete_subnet(subnet_id)
+
+
+def create_routers(routers):
+ LOG.info("Creating routers")
+ for router in routers:
+ client = client_for_user(router['owner'])
+
+ # only create a router if the name isn't here
+ r, body = client.networks.list_routers()
+ if any(item['name'] == router['name'] for item in body['routers']):
+ LOG.warning("Dupplicated router name: %s" % router['name'])
+ continue
+
+ client.networks.create_router(router['name'])
+
+
+def destroy_routers(routers):
+ LOG.info("Destroying routers")
+ for router in routers:
+ client = client_for_user(router['owner'])
+ router_id = _get_resource_by_name(client.networks,
+ 'routers', router['name'])['id']
+ for subnet in router['subnet']:
+ subnet_id = _get_resource_by_name(client.networks,
+ 'subnets', subnet)['id']
+ client.networks.remove_router_interface_with_subnet_id(router_id,
+ subnet_id)
+ client.networks.delete_router(router_id)
+
+
+def add_router_interface(routers):
+ for router in routers:
+ client = client_for_user(router['owner'])
+ router_id = _get_resource_by_name(client.networks,
+ 'routers', router['name'])['id']
+
+ for subnet in router['subnet']:
+ subnet_id = _get_resource_by_name(client.networks,
+ 'subnets', subnet)['id']
+ # connect routers to their subnets
+ client.networks.add_router_interface_with_subnet_id(router_id,
+ subnet_id)
+ # connect routers to exteral network if set to "gateway"
+ if router['gateway']:
+ if CONF.network.public_network_id:
+ ext_net = CONF.network.public_network_id
+ client.networks._update_router(
+ router_id, set_enable_snat=True,
+ external_gateway_info={"network_id": ext_net})
+ else:
+ raise ValueError('public_network_id is not configured.')
+
+
+#######################
+#
# SERVERS
#
#######################
@@ -473,10 +676,21 @@
image_id = _get_image_by_name(client, server['image'])['id']
flavor_id = _get_flavor_by_name(client, server['flavor'])['id']
- resp, body = client.servers.create_server(server['name'], image_id,
- flavor_id)
+ # validate neutron is enabled and ironic disabled
+ kwargs = dict()
+ if (CONF.service_available.neutron and
+ not CONF.baremetal.driver_enabled and server.get('networks')):
+ get_net_id = lambda x: (_get_resource_by_name(
+ client.networks, 'networks', x)['id'])
+ kwargs['networks'] = [{'uuid': get_net_id(network)}
+ for network in server['networks']]
+ resp, body = client.servers.create_server(
+ server['name'], image_id, flavor_id, **kwargs)
server_id = body['id']
client.servers.wait_for_server_status(server_id, 'ACTIVE')
+ # create to security group(s) after server spawning
+ for secgroup in server['secgroups']:
+ client.servers.add_security_group(server_id, secgroup)
def destroy_servers(servers):
@@ -496,6 +710,44 @@
ignore_error=True)
+def create_secgroups(secgroups):
+ LOG.info("Creating security groups")
+ for secgroup in secgroups:
+ client = client_for_user(secgroup['owner'])
+
+ # only create a security group if the name isn't here
+ # i.e. a security group may be used by another server
+ # only create a router if the name isn't here
+ r, body = client.secgroups.list_security_groups()
+ if any(item['name'] == secgroup['name'] for item in body):
+ LOG.warning("Security group '%s' already exists" %
+ secgroup['name'])
+ continue
+
+ resp, body = client.secgroups.create_security_group(
+ secgroup['name'], secgroup['description'])
+ if not resp_ok(resp):
+ raise ValueError("Failed to create security group: [%s] %s" %
+ (resp, body))
+ secgroup_id = body['id']
+ # for each security group, create the rules
+ for rule in secgroup['rules']:
+ ip_proto, from_port, to_port, cidr = rule.split()
+ client.secgroups.create_security_group_rule(
+ secgroup_id, ip_proto, from_port, to_port, cidr=cidr)
+
+
+def destroy_secgroups(secgroups):
+ LOG.info("Destroying security groups")
+ for secgroup in secgroups:
+ client = client_for_user(secgroup['owner'])
+ sg_id = _get_resource_by_name(client.secgroups,
+ 'security_groups',
+ secgroup['name'])
+ # sg rules are deleted automatically
+ client.secgroups.delete_security_group(sg_id['id'])
+
+
#######################
#
# VOLUMES
@@ -563,6 +815,15 @@
# next create resources in a well known order
create_objects(RES['objects'])
create_images(RES['images'])
+
+ # validate neutron is enabled and ironic is disabled
+ if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
+ create_networks(RES['networks'])
+ create_subnets(RES['subnets'])
+ create_routers(RES['routers'])
+ add_router_interface(RES['routers'])
+
+ create_secgroups(RES['secgroups'])
create_servers(RES['servers'])
create_volumes(RES['volumes'])
attach_volumes(RES['volumes'])
@@ -575,6 +836,11 @@
destroy_images(RES['images'])
destroy_objects(RES['objects'])
destroy_volumes(RES['volumes'])
+ if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
+ destroy_routers(RES['routers'])
+ destroy_subnets(RES['subnets'])
+ destroy_networks(RES['networks'])
+ destroy_secgroups(RES['secgroups'])
destroy_users(RES['users'])
destroy_tenants(RES['tenants'])
LOG.warn("Destroy mode incomplete")
diff --git a/tempest/cmd/resources.yaml b/tempest/cmd/resources.yaml
index 2d5e686..2d6664c 100644
--- a/tempest/cmd/resources.yaml
+++ b/tempest/cmd/resources.yaml
@@ -17,11 +17,17 @@
tenant: discuss
secgroups:
- - angon:
+ - name: angon
owner: javelin
+ description: angon
rules:
- 'icmp -1 -1 0.0.0.0/0'
- 'tcp 22 22 0.0.0.0/0'
+ - name: baobab
+ owner: javelin
+ description: baobab
+ rules:
+ - 'tcp 80 80 0.0.0.0/0'
# resources that we want to create
images:
@@ -43,15 +49,45 @@
owner: javelin
gb: 2
device: /dev/vdb
+networks:
+ - name: world1
+ owner: javelin
+ - name: world2
+ owner: javelin
+subnets:
+ - name: subnet1
+ range: 10.1.0.0/24
+ network: world1
+ owner: javelin
+ - name: subnet2
+ range: 192.168.1.0/24
+ network: world2
+ owner: javelin
+routers:
+ - name: connector
+ owner: javelin
+ gateway: true
+ subnet:
+ - subnet1
+ - subnet2
servers:
- name: peltast
owner: javelin
flavor: m1.small
image: javelin_cirros
+ networks:
+ - world1
+ secgroups:
+ - angon
+ - baobab
- name: hoplite
owner: javelin
flavor: m1.medium
image: javelin_cirros
+ networks:
+ - world2
+ secgroups:
+ - angon
objects:
- container: jc1
name: javelin1
diff --git a/tempest/cmd/run_stress.py b/tempest/cmd/run_stress.py
index a3f185c..d21a441 100755
--- a/tempest/cmd/run_stress.py
+++ b/tempest/cmd/run_stress.py
@@ -102,9 +102,11 @@
call_inherited=ns.call_inherited)
if ns.serial:
+ # Duration is total time
+ duration = ns.duration / len(tests)
for test in tests:
step_result = driver.stress_openstack([test],
- ns.duration,
+ duration,
ns.number,
ns.stop)
# NOTE(mkoderer): we just save the last result code
diff --git a/tempest/common/accounts.py b/tempest/common/accounts.py
index 88e8ced..66285e4 100644
--- a/tempest/common/accounts.py
+++ b/tempest/common/accounts.py
@@ -65,6 +65,9 @@
else:
return len(self.hash_dict) > 1
+ def is_multi_tenant(self):
+ return self.is_multi_user()
+
def _create_hash_file(self, hash_string):
path = os.path.join(os.path.join(self.accounts_dir, hash_string))
if not os.path.isfile(path):
@@ -149,13 +152,13 @@
to preserve the current behaviour of the serial tempest run.
"""
- def is_multi_user(self):
+ def _unique_creds(self, cred_arg=None):
+ """Verify that the configured credentials are valid and distinct """
if self.use_default_creds:
- # Verify that the configured users are valid and distinct
try:
user = self.get_primary_creds()
alt_user = self.get_alt_creds()
- return user.username != alt_user.username
+ return getattr(user, cred_arg) != getattr(alt_user, cred_arg)
except exceptions.InvalidCredentials as ic:
msg = "At least one of the configured credentials is " \
"not valid: %s" % ic.message
@@ -164,6 +167,12 @@
# TODO(andreaf) Add a uniqueness check here
return len(self.hash_dict) > 1
+ def is_multi_user(self):
+ return self._unique_creds('username')
+
+ def is_multi_tenant(self):
+ return self._unique_creds('tenant_id')
+
def get_creds(self, id):
try:
# No need to sort the dict as within the same python process
diff --git a/tempest/common/cred_provider.py b/tempest/common/cred_provider.py
index b09c964..c5be0c0 100644
--- a/tempest/common/cred_provider.py
+++ b/tempest/common/cred_provider.py
@@ -48,3 +48,7 @@
@abc.abstractmethod
def is_multi_user(self):
return
+
+ @abc.abstractmethod
+ def is_multi_tenant(self):
+ return
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index 2d16107..1ce1e39 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -203,9 +203,8 @@
if 'overlaps with another subnet' not in str(e):
raise
else:
- e = exceptions.BuildErrorException()
- e.message = 'Available CIDR for subnet creation could not be found'
- raise e
+ message = 'Available CIDR for subnet creation could not be found'
+ raise Exception(message)
return resp_body['subnet']
def _create_router(self, router_name, tenant_id):
@@ -354,3 +353,6 @@
def is_multi_user(self):
return True
+
+ def is_multi_tenant(self):
+ return True
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 42e4f56..ac1217c 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -16,16 +16,15 @@
import collections
import json
+import logging as real_logging
import re
import time
import jsonschema
-from lxml import etree
import six
from tempest.common import http
from tempest.common.utils import misc as misc_utils
-from tempest.common import xml_utils as common
from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
@@ -36,12 +35,12 @@
MAX_RECURSION_DEPTH = 2
TOKEN_CHARS_RE = re.compile('^[-A-Za-z0-9+/=]*$')
-# All the successful HTTP status codes from RFC 2616
-HTTP_SUCCESS = (200, 201, 202, 203, 204, 205, 206)
+# All the successful HTTP status codes from RFC 7231 & 4918
+HTTP_SUCCESS = (200, 201, 202, 203, 204, 205, 206, 207)
# convert a structure into a string safely
-def safe_body(body, maxlen=2048):
+def safe_body(body, maxlen=4096):
try:
text = six.text_type(body)
except UnicodeDecodeError:
@@ -53,6 +52,40 @@
return text
+class ResponseBody(dict):
+ """Class that wraps an http response and dict body into a single value.
+
+ Callers that receive this object will normally use it as a dict but
+ can extract the response if needed.
+ """
+
+ def __init__(self, response, body=None):
+ body_data = body or {}
+ self.update(body_data)
+ self.response = response
+
+ def __str__(self):
+ body = super.__str__(self)
+ return "response: %s\nBody: %s" % (self.response, body)
+
+
+class ResponseBodyList(list):
+ """Class that wraps an http response and list body into a single value.
+
+ Callers that receive this object will normally use it as a list but
+ can extract the response if needed.
+ """
+
+ def __init__(self, response, body=None):
+ body_data = body or []
+ self.extend(body_data)
+ self.response = response
+
+ def __str__(self):
+ body = super.__str__(self)
+ return "response: %s\nBody: %s" % (self.response, body)
+
+
class RestClient(object):
TYPE = "json"
@@ -208,8 +241,9 @@
@classmethod
def expected_success(cls, expected_code, read_code):
assert_msg = ("This function only allowed to use for HTTP status"
- "codes which explicitly defined in the RFC 2616. {0}"
- " is not a defined Success Code!").format(expected_code)
+ "codes which explicitly defined in the RFC 7231 & 4918."
+ "{0} is not a defined Success Code!"
+ ).format(expected_code)
if isinstance(expected_code, list):
for code in expected_code:
assert code in HTTP_SUCCESS, assert_msg
@@ -310,14 +344,15 @@
caller_name = misc_utils.find_test_caller()
if secs:
secs = " %.3fs" % secs
- self.LOG.info(
- 'Request (%s): %s %s %s%s' % (
- caller_name,
- resp['status'],
- method,
- req_url,
- secs),
- extra=extra)
+ if not self.LOG.isEnabledFor(real_logging.DEBUG):
+ self.LOG.info(
+ 'Request (%s): %s %s %s%s' % (
+ caller_name,
+ resp['status'],
+ method,
+ req_url,
+ secs),
+ extra=extra)
# Also look everything at DEBUG if you want to filter this
# out, don't run at debug.
@@ -325,48 +360,30 @@
req_body, resp_body, caller_name, extra)
def _parse_resp(self, body):
- if self._get_type() is "json":
- body = json.loads(body)
+ body = json.loads(body)
- # We assume, that if the first value of the deserialized body's
- # item set is a dict or a list, that we just return the first value
- # of deserialized body.
- # Essentially "cutting out" the first placeholder element in a body
- # that looks like this:
- #
- # {
- # "users": [
- # ...
- # ]
- # }
- try:
- # Ensure there are not more than one top-level keys
- if len(body.keys()) > 1:
- return body
- # Just return the "wrapped" element
- first_key, first_item = body.items()[0]
- if isinstance(first_item, (dict, list)):
- return first_item
- except (ValueError, IndexError):
- pass
- return body
- elif self._get_type() is "xml":
- element = etree.fromstring(body)
- if any(s in element.tag for s in self.dict_tags):
- # Parse dictionary-like xmls (metadata, etc)
- dictionary = {}
- for el in element.getchildren():
- dictionary[u"%s" % el.get("key")] = u"%s" % el.text
- return dictionary
- if any(s in element.tag for s in self.list_tags):
- # Parse list-like xmls (users, roles, etc)
- array = []
- for child in element.getchildren():
- array.append(common.xml_to_json(child))
- return array
-
- # Parse one-item-like xmls (user, role, etc)
- return common.xml_to_json(element)
+ # We assume, that if the first value of the deserialized body's
+ # item set is a dict or a list, that we just return the first value
+ # of deserialized body.
+ # Essentially "cutting out" the first placeholder element in a body
+ # that looks like this:
+ #
+ # {
+ # "users": [
+ # ...
+ # ]
+ # }
+ try:
+ # Ensure there are not more than one top-level keys
+ if len(body.keys()) > 1:
+ return body
+ # Just return the "wrapped" element
+ first_key, first_item = body.items()[0]
+ if isinstance(first_item, (dict, list)):
+ return first_item
+ except (ValueError, IndexError):
+ pass
+ return body
def response_checker(self, method, resp, resp_body):
if (resp.status in set((204, 205, 304)) or resp.status < 200 or
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 89904b2..6a238d0 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -91,7 +91,7 @@
return self.exec_command(cmd)
def get_mac_address(self):
- cmd = "/sbin/ifconfig | awk '/HWaddr/ {print $5}'"
+ cmd = "/bin/ip addr | awk '/ether/ {print $2}'"
return self.exec_command(cmd)
def get_ip_list(self):
diff --git a/tempest/common/xml_utils.py b/tempest/common/xml_utils.py
deleted file mode 100644
index 7d460a4..0000000
--- a/tempest/common/xml_utils.py
+++ /dev/null
@@ -1,173 +0,0 @@
-# Copyright 2012 IBM Corp.
-# 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 collections
-import copy
-
-XMLNS_11 = "http://docs.openstack.org/compute/api/v1.1"
-XMLNS_V3 = "http://docs.openstack.org/compute/api/v1.1"
-
-NEUTRON_NAMESPACES = {
- 'binding': "http://docs.openstack.org/ext/binding/api/v1.0",
- 'router': "http://docs.openstack.org/ext/neutron/router/api/v1.0",
- 'provider': 'http://docs.openstack.org/ext/provider/api/v1.0',
-}
-
-
-# NOTE(danms): This is just a silly implementation to help make generating
-# XML faster for prototyping. Could be replaced with proper etree gorp
-# if desired
-class Element(object):
- def __init__(self, element_name, *args, **kwargs):
- self.element_name = element_name
- self._attrs = kwargs
- self._elements = list(args)
-
- def add_attr(self, name, value):
- self._attrs[name] = value
-
- def append(self, element):
- self._elements.append(element)
-
- def __str__(self):
- args = " ".join(['%s="%s"' %
- (k, v if v is not None else "")
- for k, v in self._attrs.items()])
- string = '<%s %s' % (self.element_name, args)
- if not self._elements:
- string += '/>'
- return string
-
- string += '>'
-
- for element in self._elements:
- string += str(element)
-
- string += '</%s>' % self.element_name
-
- return string
-
- def __getitem__(self, name):
- for element in self._elements:
- if element.element_name == name:
- return element
- raise KeyError("No such element `%s'" % name)
-
- def __getattr__(self, name):
- if name in self._attrs:
- return self._attrs[name]
- return object.__getattr__(self, name)
-
- def attributes(self):
- return self._attrs.items()
-
- def children(self):
- return self._elements
-
-
-class Document(Element):
- def __init__(self, *args, **kwargs):
- Element.__init__(self, '?xml', *args, **kwargs)
-
- def __str__(self):
- attrs = copy.copy(self._attrs)
- # pop the required standard attrs out and render in required
- # order.
- vers = attrs.pop('version', '1.0')
- enc = attrs.pop('encoding', 'UTF-8')
- args = 'version="%s" encoding="%s"' % (vers, enc)
- if attrs:
- args = " ".join([args] + ['%s="%s"' %
- (k, v if v is not None else "")
- for k, v in attrs.items()])
- string = '<?xml %s?>\n' % args
- for element in self._elements:
- string += str(element)
- return string
-
-
-class Text(Element):
- def __init__(self, content=""):
- Element.__init__(self, None)
- self.__content = content
-
- def __str__(self):
- return self.__content
-
-
-def parse_array(node, plurals=None):
- array = []
- for child in node.getchildren():
- array.append(xml_to_json(child,
- plurals))
- return array
-
-
-def xml_to_json(node, plurals=None):
- """This does a really braindead conversion of an XML tree to
- something that looks like a json dump. In cases where the XML
- and json structures are the same, then this "just works". In
- others, it requires a little hand-editing of the result.
- """
- json = {}
- bool_flag = False
- int_flag = False
- long_flag = False
- for attr in node.keys():
- if not attr.startswith("xmlns"):
- json[attr] = node.get(attr)
- if json[attr] == 'bool':
- bool_flag = True
- elif json[attr] == 'int':
- int_flag = True
- elif json[attr] == 'long':
- long_flag = True
- if not node.getchildren():
- if bool_flag:
- return node.text == 'True'
- elif int_flag:
- return int(node.text)
- elif long_flag:
- return long(node.text)
- else:
- return node.text or json
- for child in node.getchildren():
- tag = child.tag
- if tag.startswith("{"):
- ns, tag = tag.split("}", 1)
- for key, uri in NEUTRON_NAMESPACES.iteritems():
- if uri == ns[1:]:
- tag = key + ":" + tag
- if plurals is not None and tag in plurals:
- json[tag] = parse_array(child, plurals)
- else:
- json[tag] = xml_to_json(child, plurals)
- return json
-
-
-def deep_dict_to_xml(dest, source):
- """Populates the ``dest`` xml element with the ``source`` ``Mapping``
- elements, if the source Mapping's value is also a ``Mapping``
- they will be recursively added as a child elements.
- :param source: A python ``Mapping`` (dict)
- :param dest: XML child element will be added to the ``dest``
- """
- for element, content in source.iteritems():
- if isinstance(content, collections.Mapping):
- xml_element = Element(element)
- deep_dict_to_xml(xml_element, content)
- dest.append(xml_element)
- else:
- dest.append(Element(element, content))
diff --git a/tempest/config.py b/tempest/config.py
index d8f22d4..b467f83 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -219,10 +219,12 @@
"channel."),
cfg.StrOpt('fixed_network_name',
default='private',
- help="Visible fixed network name "),
+ help="Name of the fixed network that is visible to all test "
+ "tenants."),
cfg.StrOpt('network_for_ssh',
default='public',
- help="Network used for SSH connections."),
+ help="Network used for SSH connections. Ignored if "
+ "use_floatingip_for_ssh=true or run_ssh=false."),
cfg.IntOpt('ip_version_for_ssh',
default=4,
help="IP version used for SSH connections."),
@@ -263,7 +265,9 @@
cfg.StrOpt('floating_ip_range',
default='10.0.0.0/29',
help='Unallocated floating IP range, which will be used to '
- 'test the floating IP bulk feature for CRUD operation.')
+ 'test the floating IP bulk feature for CRUD operation. '
+ 'This block must not overlap an existing floating IP '
+ 'pool.')
]
compute_features_group = cfg.OptGroup(name='compute-feature-enabled',
@@ -273,9 +277,6 @@
cfg.BoolOpt('api_v3',
default=False,
help="If false, skip all nova v3 tests."),
- cfg.BoolOpt('xml_api_v2',
- default=True,
- help="If false skip all v2 api tests with xml"),
cfg.BoolOpt('disk_config',
default=True,
help="If false, skip disk config tests"),
@@ -312,7 +313,7 @@
default=True,
help="Does the test environment support suspend/resume?"),
cfg.BoolOpt('live_migration',
- default=False,
+ default=True,
help="Does the test environment support live migration "
"available?"),
cfg.BoolOpt('block_migration_for_live_migration',
@@ -449,7 +450,9 @@
cfg.StrOpt('public_router_id',
default="",
help="Id of the public router that provides external "
- "connectivity"),
+ "connectivity. This should only be used when Neutron's "
+ "'allow_overlapping_ips' is set to 'False' in "
+ "neutron.conf. usually not needed past 'Grizzly' release"),
cfg.IntOpt('build_timeout',
default=300,
help="Timeout in seconds to wait for network operation to "
@@ -481,7 +484,7 @@
help="Allow the execution of IPv6 subnet tests that use "
"the extended IPv6 attributes ipv6_ra_mode "
"and ipv6_address_mode"
- )
+ ),
]
messaging_group = cfg.OptGroup(name='messaging',
@@ -967,7 +970,14 @@
baremetal_group = cfg.OptGroup(name='baremetal',
- title='Baremetal provisioning service options')
+ title='Baremetal provisioning service options',
+ help='When enabling baremetal tests, Nova '
+ 'must be configured to use the Ironic '
+ 'driver. The following paremeters for the '
+ '[compute] section must be disabled: '
+ 'console_output, interface_attach, '
+ 'live_migration, pause, rescue, resize '
+ 'shelve, snapshot, and suspend')
BaremetalGroup = [
cfg.StrOpt('catalog_type',
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 6014cff..29898a9 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -30,18 +30,18 @@
mutable_default_args = re.compile(r"^\s*def .+\((.+=\{\}|.+=\[\])")
-def import_no_clients_in_api(physical_line, filename):
- """Check for client imports from tempest/api tests
+def import_no_clients_in_api_and_scenario_tests(physical_line, filename):
+ """Check for client imports from tempest/api & tempest/scenario tests
T102: Cannot import OpenStack python clients
"""
- if "tempest/api" in filename:
+ if "tempest/api" in filename or "tempest/scenario" in filename:
res = PYTHON_CLIENT_RE.match(physical_line)
if res:
return (physical_line.find(res.group(1)),
("T102: python clients import not allowed"
- " in tempest/api/* tests"))
+ " in tempest/api/* or tempest/scenario/* tests"))
def scenario_tests_need_service_tags(physical_line, filename,
@@ -117,7 +117,7 @@
def factory(register):
- register(import_no_clients_in_api)
+ register(import_no_clients_in_api_and_scenario_tests)
register(scenario_tests_need_service_tags)
register(no_setup_teardown_class_for_tests)
register(no_vi_headers)
diff --git a/tempest/openstack/common/__init__.py b/tempest/openstack/common/__init__.py
index d1223ea..e69de29 100644
--- a/tempest/openstack/common/__init__.py
+++ b/tempest/openstack/common/__init__.py
@@ -1,17 +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 six
-
-
-six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox'))
diff --git a/tempest/openstack/common/_i18n.py b/tempest/openstack/common/_i18n.py
new file mode 100644
index 0000000..fdc8327
--- /dev/null
+++ b/tempest/openstack/common/_i18n.py
@@ -0,0 +1,45 @@
+# 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.
+
+"""oslo.i18n integration module.
+
+See http://docs.openstack.org/developer/oslo.i18n/usage.html
+
+"""
+
+try:
+ import oslo.i18n
+
+ # NOTE(dhellmann): This reference to o-s-l-o will be replaced by the
+ # application name when this module is synced into the separate
+ # repository. It is OK to have more than one translation function
+ # using the same domain, since there will still only be one message
+ # catalog.
+ _translators = oslo.i18n.TranslatorFactory(domain='tempest')
+
+ # The primary translation function using the well-known name "_"
+ _ = _translators.primary
+
+ # Translators for log levels.
+ #
+ # The abbreviated names are meant to reflect the usual use of a short
+ # name like '_'. The "L" is for "log" and the other letter comes from
+ # the level.
+ _LI = _translators.log_info
+ _LW = _translators.log_warning
+ _LE = _translators.log_error
+ _LC = _translators.log_critical
+except ImportError:
+ # NOTE(dims): Support for cases where a project wants to use
+ # code from tempest-incubator, but is not ready to be internationalized
+ # (like tempest)
+ _ = _LI = _LW = _LE = _LC = lambda x: x
diff --git a/tempest/openstack/common/log.py b/tempest/openstack/common/log.py
index 44102c0..26cd6ad 100644
--- a/tempest/openstack/common/log.py
+++ b/tempest/openstack/common/log.py
@@ -33,20 +33,20 @@
import logging.config
import logging.handlers
import os
+import socket
import sys
import traceback
from oslo.config import cfg
+from oslo.serialization import jsonutils
+from oslo.utils import importutils
import six
from six import moves
-from tempest.openstack.common.gettextutils import _
-from tempest.openstack.common import importutils
-from tempest.openstack.common import jsonutils
+_PY26 = sys.version_info[0:2] == (2, 6)
+
+from tempest.openstack.common._i18n import _
from tempest.openstack.common import local
-# NOTE(flaper87): Pls, remove when graduating this module
-# from the incubator.
-from tempest.openstack.common.strutils import mask_password # noqa
_DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
@@ -124,7 +124,9 @@
'qpid=WARN', 'sqlalchemy=WARN', 'suds=INFO',
'oslo.messaging=INFO', 'iso8601=WARN',
'requests.packages.urllib3.connectionpool=WARN',
- 'urllib3.connectionpool=WARN']
+ 'urllib3.connectionpool=WARN', 'websocket=WARN',
+ "keystonemiddleware=WARN", "routes.middleware=WARN",
+ "stevedore=WARN"]
log_opts = [
cfg.StrOpt('logging_context_format_string',
@@ -227,6 +229,15 @@
def audit(self, msg, *args, **kwargs):
self.log(logging.AUDIT, msg, *args, **kwargs)
+ def isEnabledFor(self, level):
+ if _PY26:
+ # This method was added in python 2.7 (and it does the exact
+ # same logic, so we need to do the exact same logic so that
+ # python 2.6 has this capability as well).
+ return self.logger.isEnabledFor(level)
+ else:
+ return super(BaseLoggerAdapter, self).isEnabledFor(level)
+
class LazyAdapter(BaseLoggerAdapter):
def __init__(self, name='unknown', version='unknown'):
@@ -289,11 +300,10 @@
self.warn(stdmsg, *args, **kwargs)
def process(self, msg, kwargs):
- # NOTE(mrodden): catch any Message/other object and
- # coerce to unicode before they can get
- # to the python logging and possibly
- # cause string encoding trouble
- if not isinstance(msg, six.string_types):
+ # NOTE(jecarey): If msg is not unicode, coerce it into unicode
+ # before it can get to the python logging and
+ # possibly cause string encoding trouble
+ if not isinstance(msg, six.text_type):
msg = six.text_type(msg)
if 'extra' not in kwargs:
@@ -410,18 +420,20 @@
sys.excepthook = _create_logging_excepthook(product_name)
-def set_defaults(logging_context_format_string,
+def set_defaults(logging_context_format_string=None,
default_log_levels=None):
# Just in case the caller is not setting the
# default_log_level. This is insurance because
# we introduced the default_log_level parameter
# later in a backwards in-compatible change
- if default_log_levels is None:
- default_log_levels = DEFAULT_LOG_LEVELS
- cfg.set_defaults(
+ if default_log_levels is not None:
+ cfg.set_defaults(
log_opts,
- logging_context_format_string=logging_context_format_string,
default_log_levels=default_log_levels)
+ if logging_context_format_string is not None:
+ cfg.set_defaults(
+ log_opts,
+ logging_context_format_string=logging_context_format_string)
def _find_facility_from_conf():
@@ -470,18 +482,6 @@
for handler in log_root.handlers:
log_root.removeHandler(handler)
- if CONF.use_syslog:
- facility = _find_facility_from_conf()
- # TODO(bogdando) use the format provided by RFCSysLogHandler
- # after existing syslog format deprecation in J
- if CONF.use_syslog_rfc_format:
- syslog = RFCSysLogHandler(address='/dev/log',
- facility=facility)
- else:
- syslog = logging.handlers.SysLogHandler(address='/dev/log',
- facility=facility)
- log_root.addHandler(syslog)
-
logpath = _get_log_file_path()
if logpath:
filelog = logging.handlers.WatchedFileHandler(logpath)
@@ -540,6 +540,20 @@
else:
logger.setLevel(level_name)
+ if CONF.use_syslog:
+ try:
+ facility = _find_facility_from_conf()
+ # TODO(bogdando) use the format provided by RFCSysLogHandler
+ # after existing syslog format deprecation in J
+ if CONF.use_syslog_rfc_format:
+ syslog = RFCSysLogHandler(facility=facility)
+ else:
+ syslog = logging.handlers.SysLogHandler(facility=facility)
+ log_root.addHandler(syslog)
+ except socket.error:
+ log_root.error('Unable to add syslog handler. Verify that syslog '
+ 'is running.')
+
_loggers = {}
@@ -609,6 +623,12 @@
def format(self, record):
"""Uses contextstring if request_id is set, otherwise default."""
+ # NOTE(jecarey): If msg is not unicode, coerce it into unicode
+ # before it can get to the python logging and
+ # possibly cause string encoding trouble
+ if not isinstance(record.msg, six.text_type):
+ record.msg = six.text_type(record.msg)
+
# store project info
record.project = self.project
record.version = self.version
diff --git a/tempest/scenario/README.rst b/tempest/scenario/README.rst
index 5a287d6..38e0de9 100644
--- a/tempest/scenario/README.rst
+++ b/tempest/scenario/README.rst
@@ -29,9 +29,9 @@
Scope of these tests
--------------------
-Scenario tests should use the official python client libraries for
-OpenStack, as they provide a more realistic approach in how people
-will interact with the services.
+Scenario tests should always use the Tempest implementation of the
+OpenStack API, as we want to ensure that bugs aren't hidden by the
+official clients.
Tests should be tagged with which services they exercise, as
determined by which client libraries are used directly by the test.
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 928a8e1..522aa43 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -411,9 +411,8 @@
def nova_volume_attach(self):
# TODO(andreaf) Device should be here CONF.compute.volume_device_name
- _, volume_attachment = self.servers_client.attach_volume(
+ _, volume = self.servers_client.attach_volume(
self.server['id'], self.volume['id'], '/dev/vdb')
- volume = volume_attachment['volumeAttachment']
self.assertEqual(self.volume['id'], volume['id'])
self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
# Refresh the volume after the attachment
@@ -457,6 +456,68 @@
return tempest.test.call_until_true(ping, timeout, 1)
+ def check_vm_connectivity(self, ip_address,
+ username=None,
+ private_key=None,
+ should_connect=True):
+ """
+ :param ip_address: server to test against
+ :param username: server's ssh username
+ :param private_key: server's ssh private key to be used
+ :param should_connect: True/False indicates positive/negative test
+ positive - attempt ping and ssh
+ negative - attempt ping and fail if succeed
+
+ :raises: AssertError if the result of the connectivity check does
+ not match the value of the should_connect param
+ """
+ if should_connect:
+ msg = "Timed out waiting for %s to become reachable" % ip_address
+ else:
+ msg = "ip address %s is reachable" % ip_address
+ self.assertTrue(self.ping_ip_address(ip_address,
+ should_succeed=should_connect),
+ msg=msg)
+ if should_connect:
+ # no need to check ssh for negative connectivity
+ self.get_remote_client(ip_address, username, private_key)
+
+ def check_public_network_connectivity(self, ip_address, username,
+ private_key, should_connect=True,
+ msg=None, servers=None):
+ # The target login is assumed to have been configured for
+ # key-based authentication by cloud-init.
+ LOG.debug('checking network connections to IP %s with user: %s' %
+ (ip_address, username))
+ try:
+ self.check_vm_connectivity(ip_address,
+ username,
+ private_key,
+ should_connect=should_connect)
+ except Exception as e:
+ ex_msg = 'Public network connectivity check failed'
+ if msg:
+ ex_msg += ": " + msg
+ LOG.exception(ex_msg)
+ self._log_console_output(servers)
+ # network debug is called as part of ssh init
+ if not isinstance(e, exceptions.SSHTimeout):
+ debug.log_net_debug()
+ raise
+
+ def create_floating_ip(self, thing, pool_name=None):
+ """Creates a floating IP and associates to a server using
+ Nova clients
+ """
+
+ _, floating_ip = self.floating_ips_client.create_floating_ip(pool_name)
+ self.addCleanup(self.delete_wrapper,
+ self.floating_ips_client.delete_floating_ip,
+ floating_ip['id'])
+ self.floating_ips_client.associate_floating_ip_to_server(
+ floating_ip['ip'], thing['id'])
+ return floating_ip
+
class NetworkScenarioTest(ScenarioTest):
"""Base class for network scenario tests.
@@ -476,9 +537,9 @@
@classmethod
def resource_setup(cls):
+ cls.check_preconditions()
super(NetworkScenarioTest, cls).resource_setup()
cls.tenant_id = cls.manager.identity_client.tenant_id
- cls.check_preconditions()
def _create_network(self, client=None, tenant_id=None,
namestart='network-smoke-'):
@@ -592,8 +653,13 @@
net = self._list_networks(name=network_name)
return net_resources.AttributeDict(net[0])
- def _create_floating_ip(self, thing, external_network_id, port_id=None,
- client=None):
+ def create_floating_ip(self, thing, external_network_id=None,
+ port_id=None, client=None):
+ """Creates a floating IP and associates to a resource/port using
+ Neutron client
+ """
+ if not external_network_id:
+ external_network_id = CONF.network.public_network_id
if not client:
client = self.network_client
if not port_id:
@@ -624,14 +690,20 @@
return floating_ip
def check_floating_ip_status(self, floating_ip, status):
- """Verifies floatingip has reached given status. without waiting
+ """Verifies floatingip reaches the given status
:param floating_ip: net_resources.DeletableFloatingIp floating IP to
to check status
:param status: target status
:raises: AssertionError if status doesn't match
"""
- floating_ip.refresh()
+ def refresh():
+ floating_ip.refresh()
+ return status == floating_ip.status
+
+ tempest.test.call_until_true(refresh,
+ CONF.network.build_timeout,
+ CONF.network.build_interval)
self.assertEqual(status, floating_ip.status,
message="FloatingIP: {fp} is at status: {cst}. "
"failed to reach status: {st}"
@@ -640,53 +712,6 @@
LOG.info("FloatingIP: {fp} is at status: {st}"
.format(fp=floating_ip, st=status))
- def _check_vm_connectivity(self, ip_address,
- username=None,
- private_key=None,
- should_connect=True):
- """
- :param ip_address: server to test against
- :param username: server's ssh username
- :param private_key: server's ssh private key to be used
- :param should_connect: True/False indicates positive/negative test
- positive - attempt ping and ssh
- negative - attempt ping and fail if succeed
-
- :raises: AssertError if the result of the connectivity check does
- not match the value of the should_connect param
- """
- if should_connect:
- msg = "Timed out waiting for %s to become reachable" % ip_address
- else:
- msg = "ip address %s is reachable" % ip_address
- self.assertTrue(self.ping_ip_address(ip_address,
- should_succeed=should_connect),
- msg=msg)
- if should_connect:
- # no need to check ssh for negative connectivity
- self.get_remote_client(ip_address, username, private_key)
-
- def _check_public_network_connectivity(self, ip_address, username,
- private_key, should_connect=True,
- msg=None, servers=None):
- # The target login is assumed to have been configured for
- # key-based authentication by cloud-init.
- LOG.debug('checking network connections to IP %s with user: %s' %
- (ip_address, username))
- try:
- self._check_vm_connectivity(ip_address,
- username,
- private_key,
- should_connect=should_connect)
- except Exception as e:
- ex_msg = 'Public network connectivity check failed'
- if msg:
- ex_msg += ": " + msg
- LOG.exception(ex_msg)
- self._log_console_output(servers)
- self._log_net_info(e)
- raise
-
def _check_tenant_network_connectivity(self, server,
username,
private_key,
@@ -701,10 +726,10 @@
try:
for net_name, ip_addresses in server['networks'].iteritems():
for ip_address in ip_addresses:
- self._check_vm_connectivity(ip_address,
- username,
- private_key,
- should_connect=should_connect)
+ self.check_vm_connectivity(ip_address,
+ username,
+ private_key,
+ should_connect=should_connect)
except Exception as e:
LOG.exception('Tenant network connectivity check failed')
self._log_console_output(servers_for_debug)
@@ -1017,12 +1042,11 @@
class BaremetalScenarioTest(ScenarioTest):
@classmethod
def resource_setup(cls):
- super(BaremetalScenarioTest, cls).resource_setup()
-
if (not CONF.service_available.ironic or
not CONF.baremetal.driver_enabled):
msg = 'Ironic not available or Ironic compute driver not enabled'
raise cls.skipException(msg)
+ super(BaremetalScenarioTest, cls).resource_setup()
# use an admin client manager for baremetal client
manager = clients.Manager(
@@ -1196,9 +1220,9 @@
@classmethod
def resource_setup(cls):
- super(OrchestrationScenarioTest, cls).resource_setup()
if not CONF.service_available.heat:
raise cls.skipException("Heat support is required")
+ super(OrchestrationScenarioTest, cls).resource_setup()
@classmethod
def credentials(cls):
@@ -1241,12 +1265,12 @@
@classmethod
def resource_setup(cls):
- cls.set_network_resources()
- super(SwiftScenarioTest, cls).resource_setup()
if not CONF.service_available.swift:
skip_msg = ("%s skipped as swift is not available" %
cls.__name__)
raise cls.skipException(skip_msg)
+ cls.set_network_resources()
+ super(SwiftScenarioTest, cls).resource_setup()
# Clients for Swift
cls.account_client = cls.manager.account_client
cls.container_client = cls.manager.container_client
@@ -1264,6 +1288,9 @@
# look for the container to assure it is created
self.list_and_check_container_objects(name)
LOG.debug('Container %s created' % (name))
+ self.addCleanup(self.delete_wrapper,
+ self.container_client.delete_container,
+ name)
return name
def delete_container(self, container_name):
@@ -1274,6 +1301,10 @@
obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
obj_data = data_utils.arbitrary_string()
self.object_client.create_object(container_name, obj_name, obj_data)
+ self.addCleanup(self.delete_wrapper,
+ self.object_client.delete_object,
+ container_name,
+ obj_name)
return obj_name, obj_data
def delete_object(self, container_name, filename):
diff --git a/tempest/scenario/orchestration/test_server_cfn_init.py b/tempest/scenario/orchestration/test_server_cfn_init.py
index 791c564..ddfabe4 100644
--- a/tempest/scenario/orchestration/test_server_cfn_init.py
+++ b/tempest/scenario/orchestration/test_server_cfn_init.py
@@ -129,6 +129,7 @@
raise e
@test.attr(type='slow')
+ @test.skip_because(bug='1374175')
@test.services('orchestration', 'compute')
def test_server_cfn_init(self):
self.assign_keypair()
diff --git a/tempest/scenario/test_baremetal_basic_ops.py b/tempest/scenario/test_baremetal_basic_ops.py
index 35571c6..ea10140 100644
--- a/tempest/scenario/test_baremetal_basic_ops.py
+++ b/tempest/scenario/test_baremetal_basic_ops.py
@@ -132,7 +132,6 @@
# We expect the ephemeral partition to be mounted on /mnt and to have
# the same size as our flavor definition.
eph_size = self.get_flavor_ephemeral_size()
- self.assertIsNotNone(eph_size)
if eph_size > 0:
preserve_ephemeral = True
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
index f218fb2..2014293 100644
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -12,11 +12,10 @@
# License for the specific language governing permissions and limitations
# under the License.
+import HTMLParser
import urllib
import urllib2
-from lxml import html
-
from tempest import config
from tempest.scenario import manager
from tempest import test
@@ -24,6 +23,30 @@
CONF = config.CONF
+class HorizonHTMLParser(HTMLParser.HTMLParser):
+ csrf_token = None
+ region = None
+
+ def _find_name(self, attrs, name):
+ for attrpair in attrs:
+ if attrpair[0] == 'name' and attrpair[1] == name:
+ return True
+ return False
+
+ def _find_value(self, attrs):
+ for attrpair in attrs:
+ if attrpair[0] == 'value':
+ return attrpair[1]
+ return None
+
+ def handle_starttag(self, tag, attrs):
+ if tag == 'input':
+ if self._find_name(attrs, 'csrfmiddlewaretoken'):
+ self.csrf_token = self._find_value(attrs)
+ if self._find_name(attrs, 'region'):
+ self.region = self._find_value(attrs)
+
+
class TestDashboardBasicOps(manager.ScenarioTest):
"""
@@ -35,25 +58,22 @@
@classmethod
def resource_setup(cls):
+ if not CONF.service_available.horizon:
+ raise cls.skipException("Horizon support is required")
cls.set_network_resources()
super(TestDashboardBasicOps, cls).resource_setup()
- if not CONF.service_available.horizon:
- raise cls.skipException("Horizon support is required")
-
def check_login_page(self):
response = urllib2.urlopen(CONF.dashboard.dashboard_url)
- self.assertIn("<h3>Log In</h3>", response.read())
+ self.assertIn("Log In", response.read())
def user_login(self):
self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
response = self.opener.open(CONF.dashboard.dashboard_url).read()
# Grab the CSRF token and default region
- csrf_token = html.fromstring(response).xpath(
- '//input[@name="csrfmiddlewaretoken"]/@value')[0]
- region = html.fromstring(response).xpath(
- '//input[@name="region"]/@value')[0]
+ parser = HorizonHTMLParser()
+ parser.feed(response)
# Prepare login form request
req = urllib2.Request(CONF.dashboard.login_url)
@@ -61,8 +81,8 @@
req.add_header('Referer', CONF.dashboard.dashboard_url)
params = {'username': CONF.identity.username,
'password': CONF.identity.password,
- 'region': region,
- 'csrfmiddlewaretoken': csrf_token}
+ 'region': parser.region,
+ 'csrfmiddlewaretoken': parser.csrf_token}
self.opener.open(req, urllib.urlencode(params))
def check_home_page(self):
diff --git a/tempest/scenario/test_large_ops.py b/tempest/scenario/test_large_ops.py
index b111939..e9fa960 100644
--- a/tempest/scenario/test_large_ops.py
+++ b/tempest/scenario/test_large_ops.py
@@ -12,6 +12,7 @@
# 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 import exceptions
from tempest.common.utils import data_utils
from tempest import config
@@ -44,15 +45,40 @@
"instances")
cls.set_network_resources()
super(TestLargeOpsScenario, cls).resource_setup()
+ # list of cleanup calls to be executed in reverse order
+ cls._cleanup_resources = []
+
+ @classmethod
+ def resource_cleanup(cls):
+ while cls._cleanup_resources:
+ function, args, kwargs = cls._cleanup_resources.pop(-1)
+ try:
+ function(*args, **kwargs)
+ except exceptions.NotFound:
+ pass
+ super(TestLargeOpsScenario, cls).resource_cleanup()
+
+ @classmethod
+ def addCleanupClass(cls, function, *arguments, **keywordArguments):
+ cls._cleanup_resources.append((function, arguments, keywordArguments))
def _wait_for_server_status(self, status):
for server in self.servers:
+ # Make sure nova list keeps working throughout the build process
+ self.servers_client.list_servers()
self.servers_client.wait_for_server_status(server['id'], status)
def nova_boot(self):
name = data_utils.rand_name('scenario-server-')
flavor_id = CONF.compute.flavor_ref
- secgroup = self._create_security_group()
+ # Explicitly create secgroup to avoid cleanup at the end of testcases.
+ # Since no traffic is tested, we don't need to actually add rules to
+ # secgroup
+ _, secgroup = self.security_groups_client.create_security_group(
+ 'secgroup-%s' % name, 'secgroup-desc-%s' % name)
+ self.addCleanupClass(self.security_groups_client.delete_security_group,
+ secgroup['id'])
+
self.servers_client.create_server(
name,
self.image,
@@ -66,15 +92,12 @@
for server in self.servers:
# after deleting all servers - wait for all servers to clear
# before cleanup continues
- self.addCleanup(self.servers_client.wait_for_server_termination,
- server['id'])
+ self.addCleanupClass(self.servers_client.
+ wait_for_server_termination,
+ server['id'])
for server in self.servers:
- self.addCleanup_with_wait(
- waiter_callable=(self.servers_client.
- wait_for_server_termination),
- thing_id=server['id'], thing_id_param='server_id',
- cleanup_callable=self.delete_wrapper,
- cleanup_args=[self.servers_client.delete_server, server['id']])
+ self.addCleanupClass(self.servers_client.delete_server,
+ server['id'])
self._wait_for_server_status('ACTIVE')
def _large_ops_scenario(self):
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index 9e404c8..d061406 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -137,7 +137,7 @@
if (config.network.public_network_id and not
config.network.tenant_networks_reachable):
public_network_id = config.network.public_network_id
- floating_ip = self._create_floating_ip(
+ floating_ip = self.create_floating_ip(
server, public_network_id)
self.floating_ips[floating_ip] = server
self.server_ips[server['id']] = floating_ip.floating_ip_address
@@ -257,8 +257,8 @@
def _assign_floating_ip_to_vip(self, vip):
public_network_id = config.network.public_network_id
port_id = vip.port_id
- floating_ip = self._create_floating_ip(vip, public_network_id,
- port_id=port_id)
+ floating_ip = self.create_floating_ip(vip, public_network_id,
+ port_id=port_id)
self.floating_ips.setdefault(vip.id, [])
self.floating_ips[vip.id].append(floating_ip)
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 8a8e387..59af6b3 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -16,6 +16,7 @@
from tempest.common import custom_matchers
from tempest.common import debug
from tempest import config
+from tempest import exceptions
from tempest.openstack.common import log as logging
from tempest.scenario import manager
from tempest import test
@@ -77,9 +78,8 @@
def nova_volume_attach(self):
volume_device_path = '/dev/' + CONF.compute.volume_device_name
- _, volume_attachment = self.servers_client.attach_volume(
+ _, volume = self.servers_client.attach_volume(
self.server['id'], self.volume['id'], volume_device_path)
- volume = volume_attachment['volumeAttachment']
self.assertEqual(self.volume['id'], volume['id'])
self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
# Refresh the volume after the attachment
@@ -89,16 +89,6 @@
self.servers_client.reboot(self.server['id'], 'SOFT')
self._wait_for_server_status('ACTIVE')
- def nova_floating_ip_create(self):
- _, self.floating_ip = self.floating_ips_client.create_floating_ip()
- self.addCleanup(self.delete_wrapper,
- self.floating_ips_client.delete_floating_ip,
- self.floating_ip['id'])
-
- def nova_floating_ip_add(self):
- self.floating_ips_client.associate_floating_ip_to_server(
- self.floating_ip['ip'], self.server['id'])
-
def ssh_to_server(self):
try:
self.linux_client = self.get_remote_client(self.floating_ip['ip'])
@@ -130,6 +120,17 @@
self.addCleanup(self.servers_client.remove_security_group,
self.server['id'], secgroup['name'])
+ def wait_for_secgroup_add():
+ _, body = self.servers_client.get_server(self.server['id'])
+ return {'name': secgroup['name']} in body['security_groups']
+
+ if not test.call_until_true(wait_for_secgroup_add,
+ CONF.compute.build_timeout,
+ CONF.compute.build_interval):
+ msg = ('Timed out waiting for adding security group %s to server '
+ '%s' % (secgroup['id'], self.server['id']))
+ raise exceptions.TimeoutException(msg)
+
@test.services('compute', 'volume', 'image', 'network')
def test_minimum_basic_scenario(self):
self.glance_image_create()
@@ -144,8 +145,7 @@
self.addCleanup(self.nova_volume_detach)
self.cinder_show()
- self.nova_floating_ip_create()
- self.nova_floating_ip_add()
+ self.floating_ip = self.create_floating_ip(self.server)
self.create_and_add_security_group()
self.ssh_to_server()
self.nova_reboot()
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index 0c48334..ad7f18c 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -70,8 +70,8 @@
server_name = data_utils.rand_name('server-smoke')
self.server = self.create_server(name=server_name,
create_kwargs=create_kwargs)
- self.floating_ip = self._create_floating_ip(self.server,
- public_network_id)
+ self.floating_ip = self.create_floating_ip(self.server,
+ public_network_id)
# Verify that we can indeed connect to the server before we mess with
# it's state
self._wait_server_status_and_check_network_connectivity()
@@ -84,9 +84,9 @@
should_connect=should_connect,
servers_for_debug=[self.server])
floating_ip = self.floating_ip.floating_ip_address
- self._check_public_network_connectivity(floating_ip, username,
- private_key, should_connect,
- servers=[self.server])
+ self.check_public_network_connectivity(floating_ip, username,
+ private_key, should_connect,
+ servers=[self.server])
self.check_floating_ip_status(self.floating_ip, 'ACTIVE')
def _wait_server_status_and_check_network_connectivity(self):
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 5d75b64..bac955d 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -89,13 +89,13 @@
@classmethod
def resource_setup(cls):
- # Create no network resources for these tests.
- cls.set_network_resources()
- super(TestNetworkBasicOps, cls).resource_setup()
for ext in ['router', 'security-group']:
if not test.is_extension_enabled(ext, 'network'):
msg = "%s extension not enabled." % ext
raise cls.skipException(msg)
+ # Create no network resources for these tests.
+ cls.set_network_resources()
+ super(TestNetworkBasicOps, cls).resource_setup()
def setUp(self):
super(TestNetworkBasicOps, self).setUp()
@@ -112,7 +112,8 @@
server = self._create_server(name, self.network)
self._check_tenant_network_connectivity()
- self._create_and_associate_floating_ips(server)
+ floating_ip = self.create_floating_ip(server)
+ self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
def check_networks(self):
"""
@@ -169,19 +170,11 @@
server, ssh_login, self._get_server_key(server),
servers_for_debug=self.servers)
- def _create_and_associate_floating_ips(self, server):
- public_network_id = CONF.network.public_network_id
- floating_ip = self._create_floating_ip(server, public_network_id)
- self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
-
- def _check_public_network_connectivity(self, should_connect=True,
- msg=None):
+ def check_public_network_connectivity(self, should_connect=True,
+ msg=None):
"""Verifies connectivty to a VM via public network and floating IP,
and verifies floating IP has resource status is correct.
- Floating IP status is verified after connectivity test in order to
- not add extra waiting and mask racing conditions.
-
:param should_connect: bool. determines if connectivity check is
negative or positive.
:param msg: Failure message to add to Error message. Should describe
@@ -197,7 +190,7 @@
private_key = self._get_server_key(server)
floatingip_status = 'ACTIVE'
# call the common method in the parent class
- super(TestNetworkBasicOps, self)._check_public_network_connectivity(
+ super(TestNetworkBasicOps, self).check_public_network_connectivity(
ip_address, ssh_login, private_key, should_connect, msg,
self.servers)
self.check_floating_ip_status(floating_ip, floatingip_status)
@@ -370,17 +363,17 @@
"""
self._setup_network_and_servers()
- self._check_public_network_connectivity(should_connect=True)
+ self.check_public_network_connectivity(should_connect=True)
self._check_network_internal_connectivity(network=self.network)
self._check_network_external_connectivity()
self._disassociate_floating_ips()
- self._check_public_network_connectivity(should_connect=False,
- msg="after disassociate "
- "floating ip")
+ self.check_public_network_connectivity(should_connect=False,
+ msg="after disassociate "
+ "floating ip")
self._reassociate_floating_ips()
- self._check_public_network_connectivity(should_connect=True,
- msg="after re-associate "
- "floating ip")
+ self.check_public_network_connectivity(should_connect=True,
+ msg="after re-associate "
+ "floating ip")
@testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
'NIC hotplug not available')
@@ -396,7 +389,7 @@
"""
self._setup_network_and_servers()
- self._check_public_network_connectivity(should_connect=True)
+ self.check_public_network_connectivity(should_connect=True)
self._create_new_network()
self._hotplug_server()
self._check_network_internal_connectivity(network=self.new_net)
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 6c36034..747850b 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -120,16 +120,6 @@
cls.enabled = False
raise cls.skipException(msg)
super(TestSecurityGroupsBasicOps, cls).check_preconditions()
- # need alt_creds here to check preconditions
- cls.alt_creds = cls.alt_credentials()
- cls.alt_manager = clients.Manager(cls.alt_creds)
- # Credentials from the manager are filled with both IDs and Names
- cls.alt_creds = cls.alt_manager.credentials
- if (cls.alt_creds is None) or \
- (cls.tenant_id is cls.alt_creds.tenant_id):
- msg = 'No alt_tenant defined'
- cls.enabled = False
- raise cls.skipException(msg)
if not (CONF.network.tenant_networks_reachable or
CONF.network.public_network_id):
msg = ('Either tenant_networks_reachable must be "true", or '
@@ -144,6 +134,13 @@
super(TestSecurityGroupsBasicOps, cls).resource_setup()
# TODO(mnewby) Consider looking up entities as needed instead
# of storing them as collections on the class.
+
+ # get credentials for secondary tenant
+ cls.alt_creds = cls.isolated_creds.get_alt_creds()
+ cls.alt_manager = clients.Manager(cls.alt_creds)
+ # Credentials from the manager are filled with both IDs and Names
+ cls.alt_creds = cls.alt_manager.credentials
+
cls.floating_ips = {}
cls.tenants = {}
creds = cls.credentials()
@@ -274,7 +271,7 @@
def _assign_floating_ips(self, tenant, server):
public_network_id = CONF.network.public_network_id
- floating_ip = self._create_floating_ip(
+ floating_ip = self.create_floating_ip(
server, public_network_id,
client=tenant.manager.network_client)
self.floating_ips.setdefault(server['id'], floating_ip)
@@ -437,6 +434,8 @@
@test.attr(type='smoke')
@test.services('compute', 'network')
def test_cross_tenant_traffic(self):
+ if not self.isolated_creds.is_multi_tenant():
+ raise self.skipException("No secondary tenant defined")
try:
# deploy new tenant
self._deploy_tenant(self.alt_tenant)
diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
index c53e22b..d10fcce 100644
--- a/tempest/scenario/test_server_advanced_ops.py
+++ b/tempest/scenario/test_server_advanced_ops.py
@@ -36,12 +36,11 @@
@classmethod
def resource_setup(cls):
- cls.set_network_resources()
- super(TestServerAdvancedOps, cls).resource_setup()
-
if CONF.compute.flavor_ref_alt == CONF.compute.flavor_ref:
msg = "Skipping test - flavor_ref and flavor_ref_alt are identical"
raise cls.skipException(msg)
+ cls.set_network_resources()
+ super(TestServerAdvancedOps, cls).resource_setup()
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
'Resize is not available.')
diff --git a/tempest/scenario/test_shelve_instance.py b/tempest/scenario/test_shelve_instance.py
new file mode 100644
index 0000000..3ee71dd
--- /dev/null
+++ b/tempest/scenario/test_shelve_instance.py
@@ -0,0 +1,96 @@
+# Copyright 2014 Scality
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import testtools
+
+from tempest import config
+from tempest.openstack.common import log
+from tempest.scenario import manager
+from tempest import test
+
+CONF = config.CONF
+
+LOG = log.getLogger(__name__)
+
+
+class TestShelveInstance(manager.ScenarioTest):
+ """
+ This test shelves then unshelves a Nova instance
+ The following is the scenario outline:
+ * boot a instance and create a timestamp file in it
+ * shelve the instance
+ * unshelve the instance
+ * check the existence of the timestamp file in the unshelved instance
+
+ """
+
+ def _write_timestamp(self, server_or_ip):
+ ssh_client = self.get_remote_client(server_or_ip)
+ ssh_client.exec_command('date > /tmp/timestamp; sync')
+ self.timestamp = ssh_client.exec_command('cat /tmp/timestamp')
+
+ def _check_timestamp(self, server_or_ip):
+ ssh_client = self.get_remote_client(server_or_ip)
+ got_timestamp = ssh_client.exec_command('cat /tmp/timestamp')
+ self.assertEqual(self.timestamp, got_timestamp)
+
+ def _shelve_then_unshelve_server(self, server):
+ self.servers_client.shelve_server(server['id'])
+ offload_time = CONF.compute.shelved_offload_time
+ if offload_time >= 0:
+ self.servers_client.wait_for_server_status(
+ server['id'], 'SHELVED_OFFLOADED', extra_timeout=offload_time)
+ else:
+ self.servers_client.wait_for_server_status(server['id'], 'SHELVED')
+ self.servers_client.shelve_offload_server(server['id'])
+ self.servers_client.wait_for_server_status(server['id'],
+ 'SHELVED_OFFLOADED')
+ self.servers_client.unshelve_server(server['id'])
+ self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
+
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
+ @test.services('compute', 'network', 'image')
+ def test_shelve_instance(self):
+ self.keypair = self.create_keypair()
+
+ self.security_group = self._create_security_group()
+
+ create_kwargs = {
+ 'key_name': self.keypair['name'],
+ 'security_groups': [self.security_group]
+ }
+ server = self.create_server(image=CONF.compute.image_ref,
+ create_kwargs=create_kwargs)
+
+ if CONF.compute.use_floatingip_for_ssh:
+ _, floating_ip = self.floating_ips_client.create_floating_ip()
+ self.addCleanup(self.delete_wrapper,
+ self.floating_ips_client.delete_floating_ip,
+ floating_ip['id'])
+ self.floating_ips_client.associate_floating_ip_to_server(
+ floating_ip['ip'], server['id'])
+ self._write_timestamp(floating_ip['ip'])
+ else:
+ self._write_timestamp(server)
+
+ # Prevent bug #1257594 from coming back
+ # Unshelve used to boot the instance with the original image, not
+ # with the instance snapshot
+ self._shelve_then_unshelve_server(server)
+ if CONF.compute.use_floatingip_for_ssh:
+ self._check_timestamp(floating_ip['ip'])
+ else:
+ self._check_timestamp(server)
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index dc32edc..9a99da4 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -65,17 +65,6 @@
got_timestamp = ssh_client.exec_command('cat /tmp/timestamp')
self.assertEqual(self.timestamp, got_timestamp)
- def _create_floating_ip(self):
- _, floating_ip = self.floating_ips_client.create_floating_ip()
- self.addCleanup(self.delete_wrapper,
- self.floating_ips_client.delete_floating_ip,
- floating_ip['id'])
- return floating_ip
-
- def _set_floating_ip_to_server(self, server, floating_ip):
- self.floating_ips_client.associate_floating_ip_to_server(
- floating_ip['ip'], server['id'])
-
@testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
'Snapshotting is not available.')
@test.services('compute', 'network', 'image')
@@ -87,8 +76,7 @@
# boot a instance and create a timestamp file in it
server = self._boot_image(CONF.compute.image_ref)
if CONF.compute.use_floatingip_for_ssh:
- fip_for_server = self._create_floating_ip()
- self._set_floating_ip_to_server(server, fip_for_server)
+ fip_for_server = self.create_floating_ip(server)
self._write_timestamp(fip_for_server['ip'])
else:
self._write_timestamp(server)
@@ -101,9 +89,7 @@
# check the existence of the timestamp file in the second instance
if CONF.compute.use_floatingip_for_ssh:
- fip_for_snapshot = self._create_floating_ip()
- self._set_floating_ip_to_server(server_from_snapshot,
- fip_for_snapshot)
+ fip_for_snapshot = self.create_floating_ip(server_from_snapshot)
self._check_timestamp(fip_for_snapshot['ip'])
else:
self._check_timestamp(server_from_snapshot)
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 8ea2814..ee2c737 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -52,10 +52,9 @@
@classmethod
def resource_setup(cls):
- super(TestStampPattern, cls).resource_setup()
-
if not CONF.volume_feature_enabled.snapshot:
raise cls.skipException("Cinder volume snapshots are disabled")
+ super(TestStampPattern, cls).resource_setup()
def _wait_for_volume_snapshot_status(self, volume_snapshot, status):
self.snapshots_client.wait_for_snapshot_status(volume_snapshot['id'],
@@ -72,17 +71,6 @@
def _add_keypair(self):
self.keypair = self.create_keypair()
- def _create_floating_ip(self):
- _, floating_ip = self.floating_ips_client.create_floating_ip()
- self.addCleanup(self.delete_wrapper,
- self.floating_ips_client.delete_floating_ip,
- floating_ip['id'])
- return floating_ip
-
- def _add_floating_ip(self, server, floating_ip):
- self.floating_ips_client.associate_floating_ip_to_server(
- floating_ip['ip'], server['id'])
-
def _ssh_to_server(self, server_or_ip):
return self.get_remote_client(server_or_ip)
@@ -115,7 +103,6 @@
# TODO(andreaf) we should use device from config instead if vdb
_, attached_volume = self.servers_client.attach_volume(
server['id'], volume['id'], device='/dev/vdb')
- attached_volume = attached_volume['volumeAttachment']
self.assertEqual(volume['id'], attached_volume['id'])
self._wait_for_volume_status(attached_volume, 'in-use')
@@ -165,8 +152,7 @@
# create and add floating IP to server1
if CONF.compute.use_floatingip_for_ssh:
- floating_ip_for_server = self._create_floating_ip()
- self._add_floating_ip(server, floating_ip_for_server)
+ floating_ip_for_server = self.create_floating_ip(server)
ip_for_server = floating_ip_for_server['ip']
else:
ip_for_server = server
@@ -191,9 +177,8 @@
# create and add floating IP to server_from_snapshot
if CONF.compute.use_floatingip_for_ssh:
- floating_ip_for_snapshot = self._create_floating_ip()
- self._add_floating_ip(server_from_snapshot,
- floating_ip_for_snapshot)
+ floating_ip_for_snapshot = self.create_floating_ip(
+ server_from_snapshot)
ip_for_snapshot = floating_ip_for_snapshot['ip']
else:
ip_for_snapshot = server_from_snapshot
diff --git a/tempest/scenario/test_swift_basic_ops.py b/tempest/scenario/test_swift_basic_ops.py
index 9e0fee0..fcb9505 100644
--- a/tempest/scenario/test_swift_basic_ops.py
+++ b/tempest/scenario/test_swift_basic_ops.py
@@ -44,9 +44,12 @@
self.get_swift_stat()
container_name = self.create_container()
obj_name, obj_data = self.upload_object_to_container(container_name)
- self.list_and_check_container_objects(container_name, [obj_name])
+ self.list_and_check_container_objects(container_name,
+ present_obj=[obj_name])
self.download_and_verify(container_name, obj_name, obj_data)
self.delete_object(container_name, obj_name)
+ self.list_and_check_container_objects(container_name,
+ not_present_obj=[obj_name])
self.delete_container(container_name)
@test.services('object_storage')
@@ -68,5 +71,3 @@
self.change_container_acl(container_name, '.r:*')
resp, _ = http_client.request(obj_url, 'GET')
self.assertEqual(resp.status, 200)
- self.delete_object(container_name, obj_name)
- self.delete_container(container_name)
diff --git a/tempest/scenario/test_swift_telemetry_middleware.py b/tempest/scenario/test_swift_telemetry_middleware.py
new file mode 100644
index 0000000..e8eb45c
--- /dev/null
+++ b/tempest/scenario/test_swift_telemetry_middleware.py
@@ -0,0 +1,103 @@
+#
+# Copyright 2014 Red Hat
+#
+# Author: Chris Dent <chdent@redhat.com>
+# 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 import config
+from tempest.openstack.common import log as logging
+from tempest.scenario import manager
+from tempest import test
+
+CONF = config.CONF
+
+LOG = logging.getLogger(__name__)
+
+# Loop for up to 120 seconds waiting on notifications
+# NOTE(chdent): The choice of 120 seconds is fairly
+# arbitrary: Long enough to give the notifications the
+# chance to travel across a highly latent bus but not
+# so long as to allow excessive latency to never be visible.
+# TODO(chdent): Ideally this value would come from configuration.
+NOTIFICATIONS_WAIT = 120
+NOTIFICATIONS_SLEEP = 1
+
+
+class TestSwiftTelemetry(manager.SwiftScenarioTest):
+ """
+ Test that swift uses the ceilometer middleware.
+ * create container.
+ * upload a file to the created container.
+ * retrieve the file from the created container.
+ * wait for notifications from ceilometer.
+ """
+
+ @classmethod
+ def resource_setup(cls):
+ if not CONF.service_available.ceilometer:
+ skip_msg = ("%s skipped as ceilometer is not available" %
+ cls.__name__)
+ raise cls.skipException(skip_msg)
+ elif CONF.telemetry.too_slow_to_test:
+ skip_msg = "Ceilometer feature for fast work mysql is disabled"
+ raise cls.skipException(skip_msg)
+ super(TestSwiftTelemetry, cls).resource_setup()
+ cls.telemetry_client = cls.manager.telemetry_client
+
+ def _confirm_notifications(self, container_name, obj_name):
+ """
+ Loop seeking for appropriate notifications about the containers
+ and objects sent to swift.
+ """
+
+ def _check_samples():
+ """
+ Return True only if we have notifications about some
+ containers and some objects and the notifications are about
+ the expected containers and objects.
+ Otherwise returning False will case _check_samples to be
+ called again.
+ """
+ _, results = self.telemetry_client.list_samples(
+ 'storage.api.request')
+ LOG.debug('got samples %s', results)
+
+ # Extract container info from samples.
+ containers = [sample['resource_metadata']['container']
+ for sample in results
+ if sample['resource_metadata']['container']
+ != 'None']
+ # Extract object info from samples.
+ objects = [sample['resource_metadata']['object']
+ for sample in results
+ if sample['resource_metadata']['object'] != 'None']
+
+ return (containers
+ and objects
+ and container_name in containers
+ and obj_name in objects)
+
+ self.assertTrue(test.call_until_true(_check_samples,
+ NOTIFICATIONS_WAIT,
+ NOTIFICATIONS_SLEEP),
+ 'Correct notifications were not received after '
+ '%s seconds.' % NOTIFICATIONS_WAIT)
+
+ @test.services('object_storage', 'telemetry')
+ def test_swift_middleware_notifies(self):
+ container_name = self.create_container()
+ obj_name, _ = self.upload_object_to_container(container_name)
+ self._confirm_notifications(container_name, obj_name)
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index a20db5c..dd115e7 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -37,10 +37,9 @@
"""
@classmethod
def resource_setup(cls):
- super(TestVolumeBootPattern, cls).resource_setup()
-
if not CONF.volume_feature_enabled.snapshot:
raise cls.skipException("Cinder volume snapshots are disabled")
+ super(TestVolumeBootPattern, cls).resource_setup()
def _create_volume_from_image(self):
img_uuid = CONF.compute.image_ref
@@ -137,6 +136,7 @@
actual = self._get_content(ssh_client)
self.assertEqual(expected, actual)
+ @test.skip_because(bug='1373513')
@test.services('compute', 'volume', 'image')
def test_volume_boot_pattern(self):
keypair = self.create_keypair()
diff --git a/tempest/scenario/utils.py b/tempest/scenario/utils.py
index c20f20c..e6624a3 100644
--- a/tempest/scenario/utils.py
+++ b/tempest/scenario/utils.py
@@ -25,6 +25,7 @@
from tempest import clients
from tempest.common.utils import misc
from tempest import config
+from tempest import exceptions
CONF = config.CONF
@@ -151,9 +152,12 @@
loader, standard_tests, pattern = args
else:
standard_tests, module, loader = args
- scenario_utils = InputScenarioUtils()
- scenario_flavor = scenario_utils.scenario_flavors
- scenario_image = scenario_utils.scenario_images
+ try:
+ scenario_utils = InputScenarioUtils()
+ scenario_flavor = scenario_utils.scenario_flavors
+ scenario_image = scenario_utils.scenario_images
+ except exceptions.InvalidConfiguration:
+ return standard_tests
for test in testtools.iterate_tests(standard_tests):
setattr(test, 'scenarios', testscenarios.multiply_scenarios(
scenario_image,
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 947ba7a..4268b1a 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -369,7 +369,7 @@
post_body)
body = json.loads(body)
self.validate_response(schema.attach_volume, resp, body)
- return resp, body
+ return resp, body['volumeAttachment']
def detach_volume(self, server_id, volume_id):
"""Detaches a volume from a server instance."""
@@ -378,6 +378,22 @@
self.validate_response(schema.detach_volume, resp, body)
return resp, body
+ def get_volume_attachment(self, server_id, attach_id):
+ """Return details about the given volume attachment."""
+ resp, body = self.get('servers/%s/os-volume_attachments/%s' % (
+ str(server_id), attach_id))
+ body = json.loads(body)
+ self.validate_response(schema.get_volume_attachment, resp, body)
+ return resp, body['volumeAttachment']
+
+ def list_volume_attachments(self, server_id):
+ """Returns the list of volume attachments for a given instance."""
+ resp, body = self.get('servers/%s/os-volume_attachments' % (
+ str(server_id)))
+ body = json.loads(body)
+ self.validate_response(schema.list_volume_attachments, resp, body)
+ return resp, body['volumeAttachments']
+
def add_security_group(self, server_id, name):
"""Adds a security group to the server."""
return self.action(server_id, 'addSecurityGroup', None, name=name)
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index 309dc5b..b23b20b 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -73,10 +73,9 @@
metadata: A dictionary of values to be used as metadata.
"""
post_body = {
- 'size': size,
- 'display_name': kwargs.get('display_name'),
- 'metadata': kwargs.get('metadata'),
+ 'size': size
}
+ post_body.update(kwargs)
post_body = json.dumps({'volume': post_body})
resp, body = self.post('os-volumes', post_body)
@@ -93,7 +92,6 @@
def wait_for_volume_status(self, volume_id, status):
"""Waits for a Volume to reach a given status."""
resp, body = self.get_volume(volume_id)
- volume_name = body['displayName']
volume_status = body['status']
start = int(time.time())
@@ -107,7 +105,7 @@
if int(time.time()) - start >= self.build_timeout:
message = ('Volume %s failed to reach %s status within '
'the required time (%s s).' %
- (volume_name, status, self.build_timeout))
+ (volume_id, status, self.build_timeout))
raise exceptions.TimeoutException(message)
def is_resource_deleted(self, id):
diff --git a/tempest/services/compute/xml/__init__.py b/tempest/services/compute/xml/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/compute/xml/__init__.py
+++ /dev/null
diff --git a/tempest/services/compute/xml/aggregates_client.py b/tempest/services/compute/xml/aggregates_client.py
deleted file mode 100644
index 47cde65..0000000
--- a/tempest/services/compute/xml/aggregates_client.py
+++ /dev/null
@@ -1,130 +0,0 @@
-# Copyright 2013 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 lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
-
-
-class AggregatesClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(AggregatesClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def _format_aggregate(self, g):
- agg = xml_utils.xml_to_json(g)
- aggregate = {}
- for key, value in agg.items():
- if key == 'hosts':
- aggregate['hosts'] = []
- for k, v in value.items():
- aggregate['hosts'].append(v)
- elif key == 'availability_zone':
- aggregate[key] = None if value == 'None' else value
- else:
- aggregate[key] = value
- return aggregate
-
- def _parse_array(self, node):
- return [self._format_aggregate(x) for x in node]
-
- def list_aggregates(self):
- """Get aggregate list."""
- resp, body = self.get("os-aggregates")
- aggregates = self._parse_array(etree.fromstring(body))
- return resp, aggregates
-
- def get_aggregate(self, aggregate_id):
- """Get details of the given aggregate."""
- resp, body = self.get("os-aggregates/%s" % str(aggregate_id))
- aggregate = self._format_aggregate(etree.fromstring(body))
- return resp, aggregate
-
- def create_aggregate(self, name, availability_zone=None):
- """Creates a new aggregate."""
- if availability_zone is not None:
- post_body = xml_utils.Element("aggregate", name=name,
- availability_zone=availability_zone)
- else:
- post_body = xml_utils.Element("aggregate", name=name)
- resp, body = self.post('os-aggregates',
- str(xml_utils.Document(post_body)))
- aggregate = self._format_aggregate(etree.fromstring(body))
- return resp, aggregate
-
- def update_aggregate(self, aggregate_id, name, availability_zone=None):
- """Update a aggregate."""
- if availability_zone is not None:
- put_body = xml_utils.Element("aggregate", name=name,
- availability_zone=availability_zone)
- else:
- put_body = xml_utils.Element("aggregate", name=name)
- resp, body = self.put('os-aggregates/%s' % str(aggregate_id),
- str(xml_utils.Document(put_body)))
- aggregate = self._format_aggregate(etree.fromstring(body))
- return resp, aggregate
-
- def delete_aggregate(self, aggregate_id):
- """Deletes the given aggregate."""
- return self.delete("os-aggregates/%s" % str(aggregate_id))
-
- def is_resource_deleted(self, id):
- try:
- self.get_aggregate(id)
- except exceptions.NotFound:
- return True
- return False
-
- @property
- def resource_type(self):
- """Returns the primary type of resource this client works with."""
- return 'aggregate'
-
- def add_host(self, aggregate_id, host):
- """Adds a host to the given aggregate."""
- post_body = xml_utils.Element("add_host", host=host)
- resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
- str(xml_utils.Document(post_body)))
- aggregate = self._format_aggregate(etree.fromstring(body))
- return resp, aggregate
-
- def remove_host(self, aggregate_id, host):
- """Removes a host from the given aggregate."""
- post_body = xml_utils.Element("remove_host", host=host)
- resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
- str(xml_utils.Document(post_body)))
- aggregate = self._format_aggregate(etree.fromstring(body))
- return resp, aggregate
-
- def set_metadata(self, aggregate_id, meta):
- """Replaces the aggregate's existing metadata with new metadata."""
- post_body = xml_utils.Element("set_metadata")
- metadata = xml_utils.Element("metadata")
- post_body.append(metadata)
- for k, v in meta.items():
- meta = xml_utils.Element(k)
- meta.append(xml_utils.Text(v))
- metadata.append(meta)
- resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
- str(xml_utils.Document(post_body)))
- aggregate = self._format_aggregate(etree.fromstring(body))
- return resp, aggregate
diff --git a/tempest/services/compute/xml/availability_zone_client.py b/tempest/services/compute/xml/availability_zone_client.py
deleted file mode 100644
index 38446b8..0000000
--- a/tempest/services/compute/xml/availability_zone_client.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright 2013 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 lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-
-CONF = config.CONF
-
-
-class AvailabilityZoneClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(AvailabilityZoneClientXML, self).__init__(
- auth_provider)
- self.service = CONF.compute.catalog_type
-
- def _parse_array(self, node):
- return [xml_utils.xml_to_json(x) for x in node]
-
- def get_availability_zone_list(self):
- resp, body = self.get('os-availability-zone')
- availability_zone = self._parse_array(etree.fromstring(body))
- return resp, availability_zone
-
- def get_availability_zone_list_detail(self):
- resp, body = self.get('os-availability-zone/detail')
- availability_zone = self._parse_array(etree.fromstring(body))
- return resp, availability_zone
diff --git a/tempest/services/compute/xml/certificates_client.py b/tempest/services/compute/xml/certificates_client.py
deleted file mode 100644
index 24ffca8..0000000
--- a/tempest/services/compute/xml/certificates_client.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2013 IBM Corp
-# 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 CertificatesClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(CertificatesClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def get_certificate(self, id):
- url = "os-certificates/%s" % (id)
- resp, body = self.get(url)
- body = self._parse_resp(body)
- return resp, body
-
- def create_certificate(self):
- """create certificates."""
- url = "os-certificates"
- resp, body = self.post(url, None)
- body = self._parse_resp(body)
- return resp, body
diff --git a/tempest/services/compute/xml/extensions_client.py b/tempest/services/compute/xml/extensions_client.py
deleted file mode 100644
index d924dff..0000000
--- a/tempest/services/compute/xml/extensions_client.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-
-CONF = config.CONF
-
-
-class ExtensionsClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(ExtensionsClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def _parse_array(self, node):
- array = []
- for child in node:
- array.append(xml_utils.xml_to_json(child))
- return array
-
- def list_extensions(self):
- url = 'extensions'
- resp, body = self.get(url)
- body = self._parse_array(etree.fromstring(body))
- return resp, body
-
- def is_enabled(self, extension):
- _, extensions = self.list_extensions()
- exts = extensions['extensions']
- return any([e for e in exts if e['name'] == extension])
-
- def get_extension(self, extension_alias):
- resp, body = self.get('extensions/%s' % extension_alias)
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
diff --git a/tempest/services/compute/xml/fixed_ips_client.py b/tempest/services/compute/xml/fixed_ips_client.py
deleted file mode 100644
index e14ced6..0000000
--- a/tempest/services/compute/xml/fixed_ips_client.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 2013 IBM Corp
-# 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.common import xml_utils
-from tempest import config
-
-CONF = config.CONF
-
-
-class FixedIPsClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(FixedIPsClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def get_fixed_ip_details(self, fixed_ip):
- url = "os-fixed-ips/%s" % (fixed_ip)
- resp, body = self.get(url)
- body = self._parse_resp(body)
- return resp, body
-
- def reserve_fixed_ip(self, ip, body):
- """This reserves and unreserves fixed ips."""
- url = "os-fixed-ips/%s/action" % (ip)
- # NOTE(maurosr): First converts the dict body to a json string then
- # accept any action key value here to permit tests to cover cases with
- # invalid actions raising badrequest.
- key, value = body.popitem()
- xml_body = xml_utils.Element(key)
- xml_body.append(xml_utils.Text(value))
- resp, body = self.post(url, str(xml_utils.Document(xml_body)))
- return resp, body
diff --git a/tempest/services/compute/xml/flavors_client.py b/tempest/services/compute/xml/flavors_client.py
deleted file mode 100644
index 63d1a4d..0000000
--- a/tempest/services/compute/xml/flavors_client.py
+++ /dev/null
@@ -1,216 +0,0 @@
-# Copyright 2012 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 urllib
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-
-CONF = config.CONF
-
-XMLNS_OS_FLV_EXT_DATA = \
- "http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1"
-XMLNS_OS_FLV_ACCESS = \
- "http://docs.openstack.org/compute/ext/flavor_access/api/v2"
-
-
-class FlavorsClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(FlavorsClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def _format_flavor(self, f):
- flavor = {'links': []}
- for k, v in f.items():
- if k == 'id':
- flavor['id'] = v
- continue
-
- if k == 'link':
- flavor['links'].append(v)
- continue
-
- if k == '{%s}ephemeral' % XMLNS_OS_FLV_EXT_DATA:
- k = 'OS-FLV-EXT-DATA:ephemeral'
-
- if k == '{%s}is_public' % XMLNS_OS_FLV_ACCESS:
- k = 'os-flavor-access:is_public'
- v = True if v == 'True' else False
-
- if k == 'extra_specs':
- k = 'OS-FLV-WITH-EXT-SPECS:extra_specs'
- flavor[k] = dict(v)
- continue
-
- try:
- v = int(v)
- except ValueError:
- try:
- v = float(v)
- except ValueError:
- pass
-
- flavor[k] = v
-
- return flavor
-
- def _parse_array(self, node):
- return [self._format_flavor(xml_utils.xml_to_json(x)) for x in node]
-
- def _list_flavors(self, url, params):
- if params:
- url += "?%s" % urllib.urlencode(params)
-
- resp, body = self.get(url)
- flavors = self._parse_array(etree.fromstring(body))
- return resp, flavors
-
- def list_flavors(self, params=None):
- url = 'flavors'
- return self._list_flavors(url, params)
-
- def list_flavors_with_detail(self, params=None):
- url = 'flavors/detail'
- return self._list_flavors(url, params)
-
- def get_flavor_details(self, flavor_id):
- resp, body = self.get("flavors/%s" % str(flavor_id))
- body = xml_utils.xml_to_json(etree.fromstring(body))
- flavor = self._format_flavor(body)
- return resp, flavor
-
- def create_flavor(self, name, ram, vcpus, disk, flavor_id, **kwargs):
- """Creates a new flavor or instance type."""
- flavor = xml_utils.Element("flavor",
- xmlns=xml_utils.XMLNS_11,
- ram=ram,
- vcpus=vcpus,
- disk=disk,
- id=flavor_id,
- name=name)
- if kwargs.get('rxtx'):
- flavor.add_attr('rxtx_factor', kwargs.get('rxtx'))
- if kwargs.get('swap'):
- flavor.add_attr('swap', kwargs.get('swap'))
- if kwargs.get('ephemeral'):
- flavor.add_attr('OS-FLV-EXT-DATA:ephemeral',
- kwargs.get('ephemeral'))
- if kwargs.get('is_public'):
- flavor.add_attr('os-flavor-access:is_public',
- kwargs.get('is_public'))
- flavor.add_attr('xmlns:OS-FLV-EXT-DATA', XMLNS_OS_FLV_EXT_DATA)
- flavor.add_attr('xmlns:os-flavor-access', XMLNS_OS_FLV_ACCESS)
- resp, body = self.post('flavors', str(xml_utils.Document(flavor)))
- body = xml_utils.xml_to_json(etree.fromstring(body))
- flavor = self._format_flavor(body)
- return resp, flavor
-
- def delete_flavor(self, flavor_id):
- """Deletes the given flavor."""
- return self.delete("flavors/%s" % str(flavor_id))
-
- def is_resource_deleted(self, id):
- # Did not use get_flavor_details(id) for verification as it gives
- # 200 ok even for deleted id. LP #981263
- # we can remove the loop here and use get by ID when bug gets sortedout
- resp, flavors = self.list_flavors_with_detail()
- for flavor in flavors:
- if flavor['id'] == id:
- return False
- return True
-
- @property
- def resource_type(self):
- """Returns the primary type of resource this client works with."""
- return 'flavor'
-
- def set_flavor_extra_spec(self, flavor_id, specs):
- """Sets extra Specs to the mentioned flavor."""
- extra_specs = xml_utils.Element("extra_specs")
- for key in specs.keys():
- extra_specs.add_attr(key, specs[key])
- resp, body = self.post('flavors/%s/os-extra_specs' % flavor_id,
- str(xml_utils.Document(extra_specs)))
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def get_flavor_extra_spec(self, flavor_id):
- """Gets extra Specs of the mentioned flavor."""
- resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id)
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def get_flavor_extra_spec_with_key(self, flavor_id, key):
- """Gets extra Specs key-value of the mentioned flavor and key."""
- resp, xml_body = self.get('flavors/%s/os-extra_specs/%s' %
- (str(flavor_id), key))
- body = {}
- element = etree.fromstring(xml_body)
- key = element.get('key')
- body[key] = xml_utils.xml_to_json(element)
- return resp, body
-
- def update_flavor_extra_spec(self, flavor_id, key, **kwargs):
- """Update extra Specs details of the mentioned flavor and key."""
- doc = xml_utils.Document()
- for (k, v) in kwargs.items():
- element = xml_utils.Element(k)
- doc.append(element)
- value = xml_utils.Text(v)
- element.append(value)
-
- resp, body = self.put('flavors/%s/os-extra_specs/%s' %
- (flavor_id, key), str(doc))
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, {key: body}
-
- def unset_flavor_extra_spec(self, flavor_id, key):
- """Unsets an extra spec based on the mentioned flavor and key."""
- return self.delete('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
- key))
-
- def _parse_array_access(self, node):
- return [xml_utils.xml_to_json(x) for x in node]
-
- def list_flavor_access(self, flavor_id):
- """Gets flavor access information given the flavor id."""
- resp, body = self.get('flavors/%s/os-flavor-access' % str(flavor_id))
- body = self._parse_array(etree.fromstring(body))
- return resp, body
-
- def add_flavor_access(self, flavor_id, tenant_id):
- """Add flavor access for the specified tenant."""
- doc = xml_utils.Document()
- server = xml_utils.Element("addTenantAccess")
- doc.append(server)
- server.add_attr("tenant", tenant_id)
- resp, body = self.post('flavors/%s/action' % str(flavor_id), str(doc))
- body = self._parse_array_access(etree.fromstring(body))
- return resp, body
-
- def remove_flavor_access(self, flavor_id, tenant_id):
- """Remove flavor access from the specified tenant."""
- doc = xml_utils.Document()
- server = xml_utils.Element("removeTenantAccess")
- doc.append(server)
- server.add_attr("tenant", tenant_id)
- resp, body = self.post('flavors/%s/action' % str(flavor_id), str(doc))
- body = self._parse_array_access(etree.fromstring(body))
- return resp, body
diff --git a/tempest/services/compute/xml/floating_ips_client.py b/tempest/services/compute/xml/floating_ips_client.py
deleted file mode 100644
index 84f06ab..0000000
--- a/tempest/services/compute/xml/floating_ips_client.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# Copyright 2012 IBM Corp.
-# 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 urllib
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
-
-
-class FloatingIPsClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(FloatingIPsClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def _parse_array(self, node):
- array = []
- for child in node.getchildren():
- array.append(xml_utils.xml_to_json(child))
- return array
-
- def _parse_floating_ip(self, body):
- json = xml_utils.xml_to_json(body)
- return json
-
- def list_floating_ips(self, params=None):
- """Returns a list of all floating IPs filtered by any parameters."""
- url = 'os-floating-ips'
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = self._parse_array(etree.fromstring(body))
- return resp, body
-
- def get_floating_ip_details(self, floating_ip_id):
- """Get the details of a floating IP."""
- url = "os-floating-ips/%s" % str(floating_ip_id)
- resp, body = self.get(url)
- body = self._parse_floating_ip(etree.fromstring(body))
- if resp.status == 404:
- raise exceptions.NotFound(body)
- return resp, body
-
- def create_floating_ip(self, pool_name=None):
- """Allocate a floating IP to the project."""
- url = 'os-floating-ips'
- if pool_name:
- doc = xml_utils.Document()
- pool = xml_utils.Element("pool")
- pool.append(xml_utils.Text(pool_name))
- doc.append(pool)
- resp, body = self.post(url, str(doc))
- else:
- resp, body = self.post(url, None)
- body = self._parse_floating_ip(etree.fromstring(body))
- return resp, body
-
- def delete_floating_ip(self, floating_ip_id):
- """Deletes the provided floating IP from the project."""
- url = "os-floating-ips/%s" % str(floating_ip_id)
- resp, body = self.delete(url)
- return resp, body
-
- def associate_floating_ip_to_server(self, floating_ip, server_id):
- """Associate the provided floating IP to a specific server."""
- url = "servers/%s/action" % str(server_id)
- doc = xml_utils.Document()
- server = xml_utils.Element("addFloatingIp")
- doc.append(server)
- server.add_attr("address", floating_ip)
- resp, body = self.post(url, str(doc))
- return resp, body
-
- def disassociate_floating_ip_from_server(self, floating_ip, server_id):
- """Disassociate the provided floating IP from a specific server."""
- url = "servers/%s/action" % str(server_id)
- doc = xml_utils.Document()
- server = xml_utils.Element("removeFloatingIp")
- doc.append(server)
- server.add_attr("address", floating_ip)
- resp, body = self.post(url, str(doc))
- return resp, body
-
- def is_resource_deleted(self, id):
- try:
- self.get_floating_ip_details(id)
- except exceptions.NotFound:
- return True
- return False
-
- @property
- def resource_type(self):
- """Returns the primary type of resource this client works with."""
- return 'floating_ip'
-
- def list_floating_ip_pools(self, params=None):
- """Returns a list of all floating IP Pools."""
- url = 'os-floating-ip-pools'
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = self._parse_array(etree.fromstring(body))
- return resp, body
diff --git a/tempest/services/compute/xml/hosts_client.py b/tempest/services/compute/xml/hosts_client.py
deleted file mode 100644
index ddb92b6..0000000
--- a/tempest/services/compute/xml/hosts_client.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# Copyright 2013 IBM Corp.
-#
-# 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 urllib
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-
-CONF = config.CONF
-
-
-class HostsClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(HostsClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def list_hosts(self, params=None):
- """Lists all hosts."""
-
- url = 'os-hosts'
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- node = etree.fromstring(body)
- body = [xml_utils.xml_to_json(x) for x in node.getchildren()]
- return resp, body
-
- def show_host_detail(self, hostname):
- """Show detail information for the host."""
-
- resp, body = self.get("os-hosts/%s" % str(hostname))
- node = etree.fromstring(body)
- body = [xml_utils.xml_to_json(node)]
- return resp, body
-
- def update_host(self, hostname, **kwargs):
- """Update a host."""
-
- request_body = xml_utils.Element("updates")
- if kwargs:
- for k, v in kwargs.iteritems():
- request_body.append(xml_utils.Element(k, v))
- resp, body = self.put("os-hosts/%s" % str(hostname),
- str(xml_utils.Document(request_body)))
- node = etree.fromstring(body)
- body = [xml_utils.xml_to_json(x) for x in node.getchildren()]
- return resp, body
-
- def startup_host(self, hostname):
- """Startup a host."""
-
- resp, body = self.get("os-hosts/%s/startup" % str(hostname))
- node = etree.fromstring(body)
- body = [xml_utils.xml_to_json(x) for x in node.getchildren()]
- return resp, body
-
- def shutdown_host(self, hostname):
- """Shutdown a host."""
-
- resp, body = self.get("os-hosts/%s/shutdown" % str(hostname))
- node = etree.fromstring(body)
- body = [xml_utils.xml_to_json(x) for x in node.getchildren()]
- return resp, body
-
- def reboot_host(self, hostname):
- """Reboot a host."""
-
- resp, body = self.get("os-hosts/%s/reboot" % str(hostname))
- node = etree.fromstring(body)
- body = [xml_utils.xml_to_json(x) for x in node.getchildren()]
- return resp, body
diff --git a/tempest/services/compute/xml/hypervisor_client.py b/tempest/services/compute/xml/hypervisor_client.py
deleted file mode 100644
index 1452708..0000000
--- a/tempest/services/compute/xml/hypervisor_client.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright 2013 IBM 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 lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-
-CONF = config.CONF
-
-
-class HypervisorClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(HypervisorClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def _parse_array(self, node):
- return [xml_utils.xml_to_json(x) for x in node]
-
- def get_hypervisor_list(self):
- """List hypervisors information."""
- resp, body = self.get('os-hypervisors')
- hypervisors = self._parse_array(etree.fromstring(body))
- return resp, hypervisors
-
- def get_hypervisor_list_details(self):
- """Show detailed hypervisors information."""
- resp, body = self.get('os-hypervisors/detail')
- hypervisors = self._parse_array(etree.fromstring(body))
- return resp, hypervisors
-
- def get_hypervisor_show_details(self, hyper_id):
- """Display the details of the specified hypervisor."""
- resp, body = self.get('os-hypervisors/%s' % hyper_id)
- hypervisor = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, hypervisor
-
- def get_hypervisor_servers(self, hyper_name):
- """List instances belonging to the specified hypervisor."""
- resp, body = self.get('os-hypervisors/%s/servers' % hyper_name)
- hypervisors = self._parse_array(etree.fromstring(body))
- return resp, hypervisors
-
- def get_hypervisor_stats(self):
- """Get hypervisor statistics over all compute nodes."""
- resp, body = self.get('os-hypervisors/statistics')
- stats = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, stats
-
- def get_hypervisor_uptime(self, hyper_id):
- """Display the uptime of the specified hypervisor."""
- resp, body = self.get('os-hypervisors/%s/uptime' % hyper_id)
- uptime = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, uptime
-
- def search_hypervisor(self, hyper_name):
- """Search specified hypervisor."""
- resp, body = self.get('os-hypervisors/%s/search' % hyper_name)
- hypervisors = self._parse_array(etree.fromstring(body))
- return resp, hypervisors
diff --git a/tempest/services/compute/xml/images_client.py b/tempest/services/compute/xml/images_client.py
deleted file mode 100644
index ce37b07..0000000
--- a/tempest/services/compute/xml/images_client.py
+++ /dev/null
@@ -1,211 +0,0 @@
-# Copyright 2012 IBM Corp.
-# 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 urllib
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import waiters
-from tempest.common import xml_utils
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
-
-
-class ImagesClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(ImagesClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
- self.build_interval = CONF.compute.build_interval
- self.build_timeout = CONF.compute.build_timeout
-
- def _parse_server(self, node):
- data = xml_utils.xml_to_json(node)
- return self._parse_links(node, data)
-
- def _parse_image(self, node):
- """Parses detailed XML image information into dictionary."""
- data = xml_utils.xml_to_json(node)
-
- self._parse_links(node, data)
-
- # parse all metadata
- if 'metadata' in data:
- tag = node.find('{%s}metadata' % xml_utils.XMLNS_11)
- data['metadata'] = dict((x.get('key'), x.text)
- for x in tag.getchildren())
-
- # parse server information
- if 'server' in data:
- tag = node.find('{%s}server' % xml_utils.XMLNS_11)
- data['server'] = self._parse_server(tag)
- return data
-
- def _parse_links(self, node, data):
- """Append multiple links under a list."""
- # look for links
- if 'link' in data:
- # remove single link element
- del data['link']
- data['links'] = [xml_utils.xml_to_json(x) for x in
- node.findall('{http://www.w3.org/2005/Atom}link')]
- return data
-
- def _parse_images(self, xml):
- data = {'images': []}
- images = xml.getchildren()
- for image in images:
- data['images'].append(self._parse_image(image))
- return data
-
- def _parse_key_value(self, node):
- """Parse <foo key='key'>value</foo> data into {'key': 'value'}."""
- data = {}
- for node in node.getchildren():
- data[node.get('key')] = node.text
- return data
-
- def _parse_metadata(self, node):
- """Parse the response body without children."""
- data = {}
- data[node.get('key')] = node.text
- return data
-
- def create_image(self, server_id, name, meta=None):
- """Creates an image of the original server."""
- post_body = xml_utils.Element('createImage', name=name)
-
- if meta:
- metadata = xml_utils.Element('metadata')
- post_body.append(metadata)
- for k, v in meta.items():
- data = xml_utils.Element('meta', key=k)
- data.append(xml_utils.Text(v))
- metadata.append(data)
- resp, body = self.post('servers/%s/action' % str(server_id),
- str(xml_utils.Document(post_body)))
- return resp, body
-
- def list_images(self, params=None):
- """Returns a list of all images filtered by any parameters."""
- url = 'images'
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = self._parse_images(etree.fromstring(body))
- return resp, body['images']
-
- def list_images_with_detail(self, params=None):
- """Returns a detailed list of images filtered by any parameters."""
- url = 'images/detail'
- if params:
- param_list = urllib.urlencode(params)
-
- url = "images/detail?" + param_list
-
- resp, body = self.get(url)
- body = self._parse_images(etree.fromstring(body))
- return resp, body['images']
-
- def get_image(self, image_id):
- """Returns the details of a single image."""
- resp, body = self.get("images/%s" % str(image_id))
- self.expected_success(200, resp.status)
- body = self._parse_image(etree.fromstring(body))
- return resp, body
-
- def delete_image(self, image_id):
- """Deletes the provided image."""
- return self.delete("images/%s" % str(image_id))
-
- def wait_for_image_status(self, image_id, status):
- """Waits for an image to reach a given status."""
- waiters.wait_for_image_status(self, image_id, status)
-
- def _metadata_body(self, meta):
- post_body = xml_utils.Element('metadata')
- for k, v in meta.items():
- data = xml_utils.Element('meta', key=k)
- data.append(xml_utils.Text(v))
- post_body.append(data)
- return post_body
-
- def list_image_metadata(self, image_id):
- """Lists all metadata items for an image."""
- resp, body = self.get("images/%s/metadata" % str(image_id))
- body = self._parse_key_value(etree.fromstring(body))
- return resp, body
-
- def set_image_metadata(self, image_id, meta):
- """Sets the metadata for an image."""
- post_body = self._metadata_body(meta)
- resp, body = self.put('images/%s/metadata' % image_id,
- str(xml_utils.Document(post_body)))
- body = self._parse_key_value(etree.fromstring(body))
- return resp, body
-
- def update_image_metadata(self, image_id, meta):
- """Updates the metadata for an image."""
- post_body = self._metadata_body(meta)
- resp, body = self.post('images/%s/metadata' % str(image_id),
- str(xml_utils.Document(post_body)))
- body = self._parse_key_value(etree.fromstring(body))
- return resp, body
-
- def get_image_metadata_item(self, image_id, key):
- """Returns the value for a specific image metadata key."""
- resp, body = self.get("images/%s/metadata/%s.xml" %
- (str(image_id), key))
- body = self._parse_metadata(etree.fromstring(body))
- return resp, body
-
- def set_image_metadata_item(self, image_id, key, meta):
- """Sets the value for a specific image metadata key."""
- for k, v in meta.items():
- post_body = xml_utils.Element('meta', key=key)
- post_body.append(xml_utils.Text(v))
- resp, body = self.put('images/%s/metadata/%s' % (str(image_id), key),
- str(xml_utils.Document(post_body)))
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def update_image_metadata_item(self, image_id, key, meta):
- """Sets the value for a specific image metadata key."""
- post_body = xml_utils.Document('meta', xml_utils.Text(meta), key=key)
- resp, body = self.put('images/%s/metadata/%s' % (str(image_id), key),
- post_body)
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body['meta']
-
- def delete_image_metadata_item(self, image_id, key):
- """Deletes a single image metadata key/value pair."""
- return self.delete("images/%s/metadata/%s" % (str(image_id), key))
-
- def is_resource_deleted(self, id):
- try:
- self.get_image(id)
- except exceptions.NotFound:
- return True
- return False
-
- @property
- def resource_type(self):
- """Returns the primary type of resource this client works with."""
- return 'image'
diff --git a/tempest/services/compute/xml/instance_usage_audit_log_client.py b/tempest/services/compute/xml/instance_usage_audit_log_client.py
deleted file mode 100644
index b139db1..0000000
--- a/tempest/services/compute/xml/instance_usage_audit_log_client.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2013 IBM 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 lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-
-CONF = config.CONF
-
-
-class InstanceUsagesAuditLogClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(InstanceUsagesAuditLogClientXML, self).__init__(
- auth_provider)
- self.service = CONF.compute.catalog_type
-
- def list_instance_usage_audit_logs(self):
- url = 'os-instance_usage_audit_log'
- resp, body = self.get(url)
- instance_usage_audit_logs = xml_utils.xml_to_json(
- etree.fromstring(body))
- return resp, instance_usage_audit_logs
-
- def get_instance_usage_audit_log(self, time_before):
- url = 'os-instance_usage_audit_log/%s' % time_before
- resp, body = self.get(url)
- instance_usage_audit_log = xml_utils.xml_to_json(
- etree.fromstring(body))
- return resp, instance_usage_audit_log
diff --git a/tempest/services/compute/xml/interfaces_client.py b/tempest/services/compute/xml/interfaces_client.py
deleted file mode 100644
index e30a97c..0000000
--- a/tempest/services/compute/xml/interfaces_client.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# Copyright 2013 IBM Corp.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import time
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
-
-
-class InterfacesClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(InterfacesClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def _process_xml_interface(self, node):
- iface = xml_utils.xml_to_json(node)
- # NOTE(danms): if multiple addresses per interface is ever required,
- # xml_utils.xml_to_json will need to be fixed or replaced in this case
- iface['fixed_ips'] = [dict(iface['fixed_ips']['fixed_ip'].items())]
- return iface
-
- def list_interfaces(self, server):
- resp, body = self.get('servers/%s/os-interface' % server)
- node = etree.fromstring(body)
- interfaces = [self._process_xml_interface(x)
- for x in node.getchildren()]
- return resp, interfaces
-
- def create_interface(self, server, port_id=None, network_id=None,
- fixed_ip=None):
- doc = xml_utils.Document()
- iface = xml_utils.Element('interfaceAttachment')
- if port_id:
- _port_id = xml_utils.Element('port_id')
- _port_id.append(xml_utils.Text(port_id))
- iface.append(_port_id)
- if network_id:
- _network_id = xml_utils.Element('net_id')
- _network_id.append(xml_utils.Text(network_id))
- iface.append(_network_id)
- if fixed_ip:
- _fixed_ips = xml_utils.Element('fixed_ips')
- _fixed_ip = xml_utils.Element('fixed_ip')
- _ip_address = xml_utils.Element('ip_address')
- _ip_address.append(xml_utils.Text(fixed_ip))
- _fixed_ip.append(_ip_address)
- _fixed_ips.append(_fixed_ip)
- iface.append(_fixed_ips)
- doc.append(iface)
- resp, body = self.post('servers/%s/os-interface' % server,
- body=str(doc))
- body = self._process_xml_interface(etree.fromstring(body))
- return resp, body
-
- def show_interface(self, server, port_id):
- resp, body = self.get('servers/%s/os-interface/%s' % (server, port_id))
- body = self._process_xml_interface(etree.fromstring(body))
- return resp, body
-
- def delete_interface(self, server, port_id):
- resp, body = self.delete('servers/%s/os-interface/%s' % (server,
- port_id))
- return resp, body
-
- def wait_for_interface_status(self, server, port_id, status):
- """Waits for a interface to reach a given status."""
- resp, body = self.show_interface(server, port_id)
- interface_status = body['port_state']
- start = int(time.time())
-
- while(interface_status != status):
- time.sleep(self.build_interval)
- resp, body = self.show_interface(server, port_id)
- interface_status = body['port_state']
-
- timed_out = int(time.time()) - start >= self.build_timeout
-
- if interface_status != status and timed_out:
- message = ('Interface %s failed to reach %s status within '
- 'the required time (%s s).' %
- (port_id, status, self.build_timeout))
- raise exceptions.TimeoutException(message)
- return resp, body
-
- def add_fixed_ip(self, server_id, network_id):
- """Add a fixed IP to input server instance."""
- post_body = xml_utils.Element("addFixedIp",
- xmlns=xml_utils.XMLNS_11,
- networkId=network_id)
- resp, body = self.post('servers/%s/action' % str(server_id),
- str(xml_utils.Document(post_body)))
- return resp, body
-
- def remove_fixed_ip(self, server_id, ip_address):
- """Remove input fixed IP from input server instance."""
- post_body = xml_utils.Element("removeFixedIp",
- xmlns=xml_utils.XMLNS_11,
- address=ip_address)
- resp, body = self.post('servers/%s/action' % str(server_id),
- str(xml_utils.Document(post_body)))
- return resp, body
diff --git a/tempest/services/compute/xml/keypairs_client.py b/tempest/services/compute/xml/keypairs_client.py
deleted file mode 100644
index 8ff37ac..0000000
--- a/tempest/services/compute/xml/keypairs_client.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright 2012 IBM Corp.
-# 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 lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-
-CONF = config.CONF
-
-
-class KeyPairsClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(KeyPairsClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def list_keypairs(self):
- resp, body = self.get("os-keypairs")
- node = etree.fromstring(body)
- body = [{'keypair': xml_utils.xml_to_json(x)} for x in
- node.getchildren()]
- return resp, body
-
- def get_keypair(self, key_name):
- resp, body = self.get("os-keypairs/%s" % str(key_name))
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def create_keypair(self, name, pub_key=None):
- doc = xml_utils.Document()
-
- keypair_element = xml_utils.Element("keypair")
-
- if pub_key:
- public_key_element = xml_utils.Element("public_key")
- public_key_text = xml_utils.Text(pub_key)
- public_key_element.append(public_key_text)
- keypair_element.append(public_key_element)
-
- name_element = xml_utils.Element("name")
- name_text = xml_utils.Text(name)
- name_element.append(name_text)
- keypair_element.append(name_element)
-
- doc.append(keypair_element)
-
- resp, body = self.post("os-keypairs", body=str(doc))
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def delete_keypair(self, key_name):
- return self.delete("os-keypairs/%s" % str(key_name))
diff --git a/tempest/services/compute/xml/limits_client.py b/tempest/services/compute/xml/limits_client.py
deleted file mode 100644
index 2327626..0000000
--- a/tempest/services/compute/xml/limits_client.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright 2012 IBM Corp.
-# 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 lxml import objectify
-
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
-
-NS = "{http://docs.openstack.org/common/api/v1.0}"
-
-
-class LimitsClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(LimitsClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def get_absolute_limits(self):
- resp, body = self.get("limits")
- body = objectify.fromstring(body)
- lim = NS + 'absolute'
- ret = {}
-
- for el in body[lim].iterchildren():
- attributes = el.attrib
- ret[attributes['name']] = attributes['value']
- return resp, ret
-
- def get_specific_absolute_limit(self, absolute_limit):
- resp, body = self.get("limits")
- body = objectify.fromstring(body)
- lim = NS + 'absolute'
- ret = {}
-
- for el in body[lim].iterchildren():
- attributes = el.attrib
- ret[attributes['name']] = attributes['value']
- if absolute_limit not in ret:
- return None
- else:
- return ret[absolute_limit]
diff --git a/tempest/services/compute/xml/quotas_client.py b/tempest/services/compute/xml/quotas_client.py
deleted file mode 100644
index 7f87248..0000000
--- a/tempest/services/compute/xml/quotas_client.py
+++ /dev/null
@@ -1,165 +0,0 @@
-# Copyright 2012 NTT Data
-# 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 lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-
-CONF = config.CONF
-
-
-def format_quota(q):
- quota = {}
- for k, v in q.items():
- try:
- v = int(v)
- except ValueError:
- pass
-
- quota[k] = v
-
- return quota
-
-
-class QuotasClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(QuotasClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def get_quota_set(self, tenant_id, user_id=None):
- """List the quota set for a tenant."""
-
- url = 'os-quota-sets/%s' % str(tenant_id)
- if user_id:
- url += '?user_id=%s' % str(user_id)
- resp, body = self.get(url)
- body = xml_utils.xml_to_json(etree.fromstring(body))
- body = format_quota(body)
- return resp, body
-
- def get_default_quota_set(self, tenant_id):
- """List the default quota set for a tenant."""
-
- url = 'os-quota-sets/%s/defaults' % str(tenant_id)
- resp, body = self.get(url)
- body = xml_utils.xml_to_json(etree.fromstring(body))
- body = format_quota(body)
- return resp, body
-
- def update_quota_set(self, tenant_id, user_id=None,
- force=None, injected_file_content_bytes=None,
- metadata_items=None, ram=None, floating_ips=None,
- fixed_ips=None, key_pairs=None, instances=None,
- security_group_rules=None, injected_files=None,
- cores=None, injected_file_path_bytes=None,
- security_groups=None):
- """
- Updates the tenant's quota limits for one or more resources
- """
- post_body = xml_utils.Element("quota_set",
- xmlns=xml_utils.XMLNS_11)
-
- if force is not None:
- post_body.add_attr('force', force)
-
- if injected_file_content_bytes is not None:
- post_body.add_attr('injected_file_content_bytes',
- injected_file_content_bytes)
-
- if metadata_items is not None:
- post_body.add_attr('metadata_items', metadata_items)
-
- if ram is not None:
- post_body.add_attr('ram', ram)
-
- if floating_ips is not None:
- post_body.add_attr('floating_ips', floating_ips)
-
- if fixed_ips is not None:
- post_body.add_attr('fixed_ips', fixed_ips)
-
- if key_pairs is not None:
- post_body.add_attr('key_pairs', key_pairs)
-
- if instances is not None:
- post_body.add_attr('instances', instances)
-
- if security_group_rules is not None:
- post_body.add_attr('security_group_rules', security_group_rules)
-
- if injected_files is not None:
- post_body.add_attr('injected_files', injected_files)
-
- if cores is not None:
- post_body.add_attr('cores', cores)
-
- if injected_file_path_bytes is not None:
- post_body.add_attr('injected_file_path_bytes',
- injected_file_path_bytes)
-
- if security_groups is not None:
- post_body.add_attr('security_groups', security_groups)
-
- if user_id:
- resp, body = self.put('os-quota-sets/%s?user_id=%s' %
- (str(tenant_id), str(user_id)),
- str(xml_utils.Document(post_body)))
- else:
- resp, body = self.put('os-quota-sets/%s' % str(tenant_id),
- str(xml_utils.Document(post_body)))
-
- body = xml_utils.xml_to_json(etree.fromstring(body))
- body = format_quota(body)
- return resp, body
-
- def delete_quota_set(self, tenant_id):
- """Delete the tenant's quota set."""
- return self.delete('os-quota-sets/%s' % str(tenant_id))
-
-
-class QuotaClassesClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(QuotaClassesClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def get_quota_class_set(self, quota_class_id):
- """List the quota class set for a quota class."""
-
- url = 'os-quota-class-sets/%s' % str(quota_class_id)
- resp, body = self.get(url)
- body = xml_utils.xml_to_json(etree.fromstring(body))
- body = format_quota(body)
- return resp, body
-
- def update_quota_class_set(self, quota_class_id, **kwargs):
- """
- Updates the quota class's limits for one or more resources.
- """
- post_body = xml_utils.Element("quota_class_set",
- xmlns=xml_utils.XMLNS_11,
- **kwargs)
-
- resp, body = self.put('os-quota-class-sets/%s' % str(quota_class_id),
- str(xml_utils.Document(post_body)))
-
- body = xml_utils.xml_to_json(etree.fromstring(body))
- body = format_quota(body)
- return resp, body
diff --git a/tempest/services/compute/xml/security_groups_client.py b/tempest/services/compute/xml/security_groups_client.py
deleted file mode 100644
index e529623..0000000
--- a/tempest/services/compute/xml/security_groups_client.py
+++ /dev/null
@@ -1,166 +0,0 @@
-# Copyright 2012 IBM Corp.
-# 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 urllib
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
-
-
-class SecurityGroupsClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(SecurityGroupsClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def _parse_array(self, node):
- array = []
- for child in node.getchildren():
- array.append(xml_utils.xml_to_json(child))
- return array
-
- def _parse_body(self, body):
- json = xml_utils.xml_to_json(body)
- return json
-
- def list_security_groups(self, params=None):
- """List all security groups for a user."""
-
- url = 'os-security-groups'
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = self._parse_array(etree.fromstring(body))
- return resp, body
-
- def get_security_group(self, security_group_id):
- """Get the details of a Security Group."""
- url = "os-security-groups/%s" % str(security_group_id)
- resp, body = self.get(url)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def create_security_group(self, name, description):
- """
- Creates a new security group.
- name (Required): Name of security group.
- description (Required): Description of security group.
- """
- security_group = xml_utils.Element("security_group", name=name)
- des = xml_utils.Element("description")
- des.append(xml_utils.Text(content=description))
- security_group.append(des)
- resp, body = self.post('os-security-groups',
- str(xml_utils.Document(security_group)))
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def update_security_group(self, security_group_id, name=None,
- description=None):
- """
- Update a security group.
- security_group_id: a security_group to update
- name: new name of security group
- description: new description of security group
- """
- security_group = xml_utils.Element("security_group")
- if name:
- sg_name = xml_utils.Element("name")
- sg_name.append(xml_utils.Text(content=name))
- security_group.append(sg_name)
- if description:
- des = xml_utils.Element("description")
- des.append(xml_utils.Text(content=description))
- security_group.append(des)
- resp, body = self.put('os-security-groups/%s' %
- str(security_group_id),
- str(xml_utils.Document(security_group)))
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def delete_security_group(self, security_group_id):
- """Deletes the provided Security Group."""
- return self.delete('os-security-groups/%s' % str(security_group_id))
-
- def create_security_group_rule(self, parent_group_id, ip_proto, from_port,
- to_port, **kwargs):
- """
- Creating a new security group rules.
- parent_group_id :ID of Security group
- ip_protocol : ip_proto (icmp, tcp, udp).
- from_port: Port at start of range.
- to_port : Port at end of range.
- Following optional keyword arguments are accepted:
- cidr : CIDR for address range.
- group_id : ID of the Source group
- """
- group_rule = xml_utils.Element("security_group_rule")
-
- elements = dict()
- elements['cidr'] = kwargs.get('cidr')
- elements['group_id'] = kwargs.get('group_id')
- elements['parent_group_id'] = parent_group_id
- elements['ip_protocol'] = ip_proto
- elements['from_port'] = from_port
- elements['to_port'] = to_port
-
- for k, v in elements.items():
- if v is not None:
- element = xml_utils.Element(k)
- element.append(xml_utils.Text(content=str(v)))
- group_rule.append(element)
-
- url = 'os-security-group-rules'
- resp, body = self.post(url, str(xml_utils.Document(group_rule)))
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def delete_security_group_rule(self, group_rule_id):
- """Deletes the provided Security Group rule."""
- return self.delete('os-security-group-rules/%s' %
- str(group_rule_id))
-
- def list_security_group_rules(self, security_group_id):
- """List all rules for a security group."""
- url = "os-security-groups"
- resp, body = self.get(url)
- body = etree.fromstring(body)
- secgroups = body.getchildren()
- for secgroup in secgroups:
- if secgroup.get('id') == security_group_id:
- node = secgroup.find('{%s}rules' % xml_utils.XMLNS_11)
- rules = [xml_utils.xml_to_json(x) for x in node.getchildren()]
- return resp, rules
- raise exceptions.NotFound('No such Security Group')
-
- def is_resource_deleted(self, id):
- try:
- self.get_security_group(id)
- except exceptions.NotFound:
- return True
- return False
-
- @property
- def resource_type(self):
- """Returns the primary type of resource this client works with."""
- return 'security_group'
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
deleted file mode 100644
index 06f1b83..0000000
--- a/tempest/services/compute/xml/servers_client.py
+++ /dev/null
@@ -1,673 +0,0 @@
-# Copyright 2012 IBM Corp.
-# Copyright 2013 Hewlett-Packard Development Company, L.P.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import time
-import urllib
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import waiters
-from tempest.common import xml_utils
-from tempest import config
-from tempest import exceptions
-from tempest.openstack.common import log as logging
-
-CONF = config.CONF
-
-LOG = logging.getLogger(__name__)
-
-
-def _translate_ip_xml_json(ip):
- """
- Convert the address version to int.
- """
- ip = dict(ip)
- version = ip.get('version')
- if version:
- ip['version'] = int(version)
- # NOTE(maurosr): just a fast way to avoid the xml version with the
- # expanded xml namespace.
- type_ns_prefix = ('{http://docs.openstack.org/compute/ext/extended_ips/'
- 'api/v1.1}type')
- mac_ns_prefix = ('{http://docs.openstack.org/compute/ext/extended_ips_mac'
- '/api/v1.1}mac_addr')
-
- if type_ns_prefix in ip:
- ip['OS-EXT-IPS:type'] = ip.pop(type_ns_prefix)
-
- if mac_ns_prefix in ip:
- ip['OS-EXT-IPS-MAC:mac_addr'] = ip.pop(mac_ns_prefix)
- return ip
-
-
-def _translate_network_xml_to_json(network):
- return [_translate_ip_xml_json(ip.attrib)
- for ip in network.findall('{%s}ip' % xml_utils.XMLNS_11)]
-
-
-def _translate_addresses_xml_to_json(xml_addresses):
- return dict((network.attrib['id'], _translate_network_xml_to_json(network))
- for network in xml_addresses.findall('{%s}network' %
- xml_utils.XMLNS_11))
-
-
-def _translate_server_xml_to_json(xml_dom):
- """Convert server XML to server JSON.
-
- The addresses collection does not convert well by the dumb xml_to_json.
- This method does some pre and post-processing to deal with that.
-
- Translate XML addresses subtree to JSON.
-
- Having xml_doc similar to
- <api:server xmlns:api="http://docs.openstack.org/compute/api/v1.1">
- <api:addresses>
- <api:network id="foo_novanetwork">
- <api:ip version="4" addr="192.168.0.4"/>
- </api:network>
- <api:network id="bar_novanetwork">
- <api:ip version="4" addr="10.1.0.4"/>
- <api:ip version="6" addr="2001:0:0:1:2:3:4:5"/>
- </api:network>
- </api:addresses>
- </api:server>
-
- the _translate_server_xml_to_json(etree.fromstring(xml_doc)) should produce
- something like
-
- {'addresses': {'bar_novanetwork': [{'addr': '10.1.0.4', 'version': 4},
- {'addr': '2001:0:0:1:2:3:4:5',
- 'version': 6}],
- 'foo_novanetwork': [{'addr': '192.168.0.4', 'version': 4}]}}
- """
- nsmap = {'api': xml_utils.XMLNS_11}
- addresses = xml_dom.xpath('/api:server/api:addresses', namespaces=nsmap)
- if addresses:
- if len(addresses) > 1:
- raise ValueError('Expected only single `addresses` element.')
- json_addresses = _translate_addresses_xml_to_json(addresses[0])
- json = xml_utils.xml_to_json(xml_dom)
- json['addresses'] = json_addresses
- else:
- json = xml_utils.xml_to_json(xml_dom)
- diskConfig = ('{http://docs.openstack.org'
- '/compute/ext/disk_config/api/v1.1}diskConfig')
- terminated_at = ('{http://docs.openstack.org/'
- 'compute/ext/server_usage/api/v1.1}terminated_at')
- launched_at = ('{http://docs.openstack.org'
- '/compute/ext/server_usage/api/v1.1}launched_at')
- power_state = ('{http://docs.openstack.org'
- '/compute/ext/extended_status/api/v1.1}power_state')
- availability_zone = ('{http://docs.openstack.org'
- '/compute/ext/extended_availability_zone/api/v2}'
- 'availability_zone')
- vm_state = ('{http://docs.openstack.org'
- '/compute/ext/extended_status/api/v1.1}vm_state')
- task_state = ('{http://docs.openstack.org'
- '/compute/ext/extended_status/api/v1.1}task_state')
- if 'tenantId' in json:
- json['tenant_id'] = json.pop('tenantId')
- if 'userId' in json:
- json['user_id'] = json.pop('userId')
- if diskConfig in json:
- json['OS-DCF:diskConfig'] = json.pop(diskConfig)
- if terminated_at in json:
- json['OS-SRV-USG:terminated_at'] = json.pop(terminated_at)
- if launched_at in json:
- json['OS-SRV-USG:launched_at'] = json.pop(launched_at)
- if power_state in json:
- json['OS-EXT-STS:power_state'] = json.pop(power_state)
- if availability_zone in json:
- json['OS-EXT-AZ:availability_zone'] = json.pop(availability_zone)
- if vm_state in json:
- json['OS-EXT-STS:vm_state'] = json.pop(vm_state)
- if task_state in json:
- json['OS-EXT-STS:task_state'] = json.pop(task_state)
- return json
-
-
-class ServersClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(ServersClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def _parse_key_value(self, node):
- """Parse <foo key='key'>value</foo> data into {'key': 'value'}."""
- data = {}
- for node in node.getchildren():
- data[node.get('key')] = node.text
- return data
-
- def _parse_links(self, node, json):
- del json['link']
- json['links'] = []
- for linknode in node.findall('{http://www.w3.org/2005/Atom}link'):
- json['links'].append(xml_utils.xml_to_json(linknode))
-
- def _parse_server(self, body):
- json = _translate_server_xml_to_json(body)
-
- if 'metadata' in json and json['metadata']:
- # NOTE(danms): if there was metadata, we need to re-parse
- # that as a special type
- metadata_tag = body.find('{%s}metadata' % xml_utils.XMLNS_11)
- json["metadata"] = self._parse_key_value(metadata_tag)
- if 'link' in json:
- self._parse_links(body, json)
- for sub in ['image', 'flavor']:
- if sub in json and 'link' in json[sub]:
- self._parse_links(body, json[sub])
- return json
-
- def _parse_xml_virtual_interfaces(self, xml_dom):
- """
- Return server's virtual interfaces XML as JSON.
- """
- data = {"virtual_interfaces": []}
- for iface in xml_dom.getchildren():
- data["virtual_interfaces"].append(
- {"id": iface.get("id"),
- "mac_address": iface.get("mac_address")})
- return data
-
- def get_server(self, server_id):
- """Returns the details of an existing server."""
- resp, body = self.get("servers/%s" % str(server_id))
- server = self._parse_server(etree.fromstring(body))
- return resp, server
-
- def migrate_server(self, server_id, **kwargs):
- """Migrates the given server ."""
- return self.action(server_id, 'migrate', None, **kwargs)
-
- def lock_server(self, server_id, **kwargs):
- """Locks the given server."""
- return self.action(server_id, 'lock', None, **kwargs)
-
- def unlock_server(self, server_id, **kwargs):
- """Unlocks the given server."""
- return self.action(server_id, 'unlock', None, **kwargs)
-
- def suspend_server(self, server_id, **kwargs):
- """Suspends the provided server."""
- return self.action(server_id, 'suspend', None, **kwargs)
-
- def resume_server(self, server_id, **kwargs):
- """Un-suspends the provided server."""
- return self.action(server_id, 'resume', None, **kwargs)
-
- def pause_server(self, server_id, **kwargs):
- """Pauses the provided server."""
- return self.action(server_id, 'pause', None, **kwargs)
-
- def unpause_server(self, server_id, **kwargs):
- """Un-pauses the provided server."""
- return self.action(server_id, 'unpause', None, **kwargs)
-
- def shelve_server(self, server_id, **kwargs):
- """Shelves the provided server."""
- return self.action(server_id, 'shelve', None, **kwargs)
-
- def unshelve_server(self, server_id, **kwargs):
- """Un-shelves the provided server."""
- return self.action(server_id, 'unshelve', None, **kwargs)
-
- def shelve_offload_server(self, server_id, **kwargs):
- """Shelve-offload the provided server."""
- return self.action(server_id, 'shelveOffload', None, **kwargs)
-
- def reset_state(self, server_id, state='error'):
- """Resets the state of a server to active/error."""
- return self.action(server_id, 'os-resetState', None, state=state)
-
- def delete_server(self, server_id):
- """Deletes the given server."""
- return self.delete("servers/%s" % str(server_id))
-
- def _parse_array(self, node):
- array = []
- for child in node.getchildren():
- array.append(xml_utils.xml_to_json(child))
- return array
-
- def _parse_server_array(self, node):
- array = []
- for child in node.getchildren():
- array.append(self._parse_server(child))
- return array
-
- def list_servers(self, params=None):
- url = 'servers'
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- servers = self._parse_server_array(etree.fromstring(body))
- return resp, {"servers": servers}
-
- def list_servers_with_detail(self, params=None):
- url = 'servers/detail'
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- servers = self._parse_server_array(etree.fromstring(body))
- return resp, {"servers": servers}
-
- def update_server(self, server_id, name=None, meta=None, accessIPv4=None,
- accessIPv6=None, disk_config=None):
- doc = xml_utils.Document()
- server = xml_utils.Element("server")
- doc.append(server)
-
- if name is not None:
- server.add_attr("name", name)
- if accessIPv4 is not None:
- server.add_attr("accessIPv4", accessIPv4)
- if accessIPv6 is not None:
- server.add_attr("accessIPv6", accessIPv6)
- if disk_config is not None:
- server.add_attr('xmlns:OS-DCF', "http://docs.openstack.org/"
- "compute/ext/disk_config/api/v1.1")
- server.add_attr("OS-DCF:diskConfig", disk_config)
- if meta is not None:
- metadata = xml_utils.Element("metadata")
- server.append(metadata)
- for k, v in meta:
- meta = xml_utils.Element("meta", key=k)
- meta.append(xml_utils.Text(v))
- metadata.append(meta)
-
- resp, body = self.put('servers/%s' % str(server_id), str(doc))
- return resp, xml_utils.xml_to_json(etree.fromstring(body))
-
- def create_server(self, name, image_ref, flavor_ref, **kwargs):
- """
- Creates an instance of a server.
- name (Required): The name of the server.
- image_ref (Required): Reference to the image used to build the server.
- flavor_ref (Required): The flavor used to build the server.
- Following optional keyword arguments are accepted:
- adminPass: Sets the initial root password.
- key_name: Key name of keypair that was created earlier.
- meta: A dictionary of values to be used as metadata.
- personality: A list of dictionaries for files to be injected into
- the server.
- security_groups: A list of security group dicts.
- networks: A list of network dicts with UUID and fixed_ip.
- user_data: User data for instance.
- availability_zone: Availability zone in which to launch instance.
- accessIPv4: The IPv4 access address for the server.
- accessIPv6: The IPv6 access address for the server.
- min_count: Count of minimum number of instances to launch.
- max_count: Count of maximum number of instances to launch.
- disk_config: Determines if user or admin controls disk configuration.
- block_device_mapping: Block device mapping for the server.
- """
- server = xml_utils.Element("server",
- xmlns=xml_utils.XMLNS_11,
- imageRef=image_ref,
- flavorRef=flavor_ref,
- name=name)
-
- for attr in ["adminPass", "accessIPv4", "accessIPv6", "key_name",
- "user_data", "availability_zone", "min_count",
- "max_count", "return_reservation_id",
- "block_device_mapping"]:
- if attr in kwargs:
- server.add_attr(attr, kwargs[attr])
-
- if 'disk_config' in kwargs:
- server.add_attr('xmlns:OS-DCF', "http://docs.openstack.org/"
- "compute/ext/disk_config/api/v1.1")
- server.add_attr('OS-DCF:diskConfig', kwargs['disk_config'])
-
- if 'security_groups' in kwargs:
- secgroups = xml_utils.Element("security_groups")
- server.append(secgroups)
- for secgroup in kwargs['security_groups']:
- s = xml_utils.Element("security_group", name=secgroup['name'])
- secgroups.append(s)
-
- if 'networks' in kwargs:
- networks = xml_utils.Element("networks")
- server.append(networks)
- for network in kwargs['networks']:
- if 'fixed_ip' in network:
- s = xml_utils.Element("network", uuid=network['uuid'],
- fixed_ip=network['fixed_ip'])
- else:
- s = xml_utils.Element("network", uuid=network['uuid'])
- networks.append(s)
-
- if 'meta' in kwargs:
- metadata = xml_utils.Element("metadata")
- server.append(metadata)
- for k, v in kwargs['meta'].items():
- meta = xml_utils.Element("meta", key=k)
- meta.append(xml_utils.Text(v))
- metadata.append(meta)
-
- if 'personality' in kwargs:
- personality = xml_utils.Element('personality')
- server.append(personality)
- for k in kwargs['personality']:
- temp = xml_utils.Element('file', path=k['path'])
- temp.append(xml_utils.Text(k['contents']))
- personality.append(temp)
-
- if 'sched_hints' in kwargs:
- sched_hints = kwargs.get('sched_hints')
- hints = xml_utils.Element("os:scheduler_hints")
- hints.add_attr('xmlns:os', xml_utils.XMLNS_11)
- for attr in sched_hints:
- p1 = xml_utils.Element(attr)
- p1.append(sched_hints[attr])
- hints.append(p1)
- server.append(hints)
- resp, body = self.post('servers', str(xml_utils.Document(server)))
- server = self._parse_server(etree.fromstring(body))
- return resp, server
-
- def wait_for_server_status(self, server_id, status, extra_timeout=0,
- raise_on_error=True):
- """Waits for a server to reach a given status."""
- return waiters.wait_for_server_status(self, server_id, status,
- extra_timeout=extra_timeout,
- raise_on_error=raise_on_error)
-
- def wait_for_server_termination(self, server_id, ignore_error=False):
- """Waits for server to reach termination."""
- start_time = int(time.time())
- while True:
- try:
- resp, body = self.get_server(server_id)
- except exceptions.NotFound:
- return
-
- server_status = body['status']
- if server_status == 'ERROR' and not ignore_error:
- raise exceptions.BuildErrorException(server_id=server_id)
-
- if int(time.time()) - start_time >= self.build_timeout:
- raise exceptions.TimeoutException
-
- time.sleep(self.build_interval)
-
- def _parse_network(self, node):
- addrs = []
- for child in node.getchildren():
- addrs.append({'version': int(child.get('version')),
- 'addr': child.get('addr')})
- return {node.get('id'): addrs}
-
- def list_addresses(self, server_id):
- """Lists all addresses for a server."""
- resp, body = self.get("servers/%s/ips" % str(server_id))
-
- networks = {}
- xml_list = etree.fromstring(body)
- for child in xml_list.getchildren():
- network = self._parse_network(child)
- networks.update(**network)
-
- return resp, networks
-
- def list_addresses_by_network(self, server_id, network_id):
- """Lists all addresses of a specific network type for a server."""
- resp, body = self.get("servers/%s/ips/%s" % (str(server_id),
- network_id))
- network = self._parse_network(etree.fromstring(body))
-
- return resp, network
-
- def action(self, server_id, action_name, response_key, **kwargs):
- if 'xmlns' not in kwargs:
- kwargs['xmlns'] = xml_utils.XMLNS_11
- doc = xml_utils.Document((xml_utils.Element(action_name, **kwargs)))
- resp, body = self.post("servers/%s/action" % server_id, str(doc))
- if response_key is not None:
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def create_backup(self, server_id, backup_type, rotation, name):
- """Backup a server instance."""
- return self.action(server_id, "createBackup", None,
- backup_type=backup_type,
- rotation=rotation,
- name=name)
-
- def change_password(self, server_id, password):
- return self.action(server_id, "changePassword", None,
- adminPass=password)
-
- def get_password(self, server_id):
- resp, body = self.get("servers/%s/os-server-password" % str(server_id))
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def delete_password(self, server_id):
- """
- Removes the encrypted server password from the metadata server
- Note that this does not actually change the instance server
- password.
- """
- return self.delete("servers/%s/os-server-password" % str(server_id))
-
- def reboot(self, server_id, reboot_type):
- return self.action(server_id, "reboot", None, type=reboot_type)
-
- def rebuild(self, server_id, image_ref, **kwargs):
- kwargs['imageRef'] = image_ref
- if 'disk_config' in kwargs:
- kwargs['OS-DCF:diskConfig'] = kwargs['disk_config']
- del kwargs['disk_config']
- kwargs['xmlns:OS-DCF'] = "http://docs.openstack.org/"\
- "compute/ext/disk_config/api/v1.1"
- kwargs['xmlns:atom'] = "http://www.w3.org/2005/Atom"
- if 'xmlns' not in kwargs:
- kwargs['xmlns'] = xml_utils.XMLNS_11
-
- attrs = kwargs.copy()
- if 'metadata' in attrs:
- del attrs['metadata']
- rebuild = xml_utils.Element("rebuild", **attrs)
-
- if 'metadata' in kwargs:
- metadata = xml_utils.Element("metadata")
- rebuild.append(metadata)
- for k, v in kwargs['metadata'].items():
- meta = xml_utils.Element("meta", key=k)
- meta.append(xml_utils.Text(v))
- metadata.append(meta)
-
- resp, body = self.post('servers/%s/action' % server_id,
- str(xml_utils.Document(rebuild)))
- server = self._parse_server(etree.fromstring(body))
- return resp, server
-
- def resize(self, server_id, flavor_ref, **kwargs):
- if 'disk_config' in kwargs:
- kwargs['OS-DCF:diskConfig'] = kwargs['disk_config']
- del kwargs['disk_config']
- kwargs['xmlns:OS-DCF'] = "http://docs.openstack.org/"\
- "compute/ext/disk_config/api/v1.1"
- kwargs['xmlns:atom'] = "http://www.w3.org/2005/Atom"
- kwargs['flavorRef'] = flavor_ref
- return self.action(server_id, 'resize', None, **kwargs)
-
- def confirm_resize(self, server_id, **kwargs):
- return self.action(server_id, 'confirmResize', None, **kwargs)
-
- def revert_resize(self, server_id, **kwargs):
- return self.action(server_id, 'revertResize', None, **kwargs)
-
- def stop(self, server_id, **kwargs):
- return self.action(server_id, 'os-stop', None, **kwargs)
-
- def start(self, server_id, **kwargs):
- return self.action(server_id, 'os-start', None, **kwargs)
-
- def create_image(self, server_id, name):
- return self.action(server_id, 'createImage', None, name=name)
-
- def add_security_group(self, server_id, name):
- return self.action(server_id, 'addSecurityGroup', None, name=name)
-
- def remove_security_group(self, server_id, name):
- return self.action(server_id, 'removeSecurityGroup', None, name=name)
-
- def live_migrate_server(self, server_id, dest_host, use_block_migration):
- """This should be called with administrator privileges ."""
-
- req_body = xml_utils.Element("os-migrateLive",
- xmlns=xml_utils.XMLNS_11,
- disk_over_commit=False,
- block_migration=use_block_migration,
- host=dest_host)
-
- resp, body = self.post("servers/%s/action" % str(server_id),
- str(xml_utils.Document(req_body)))
- return resp, body
-
- def list_server_metadata(self, server_id):
- resp, body = self.get("servers/%s/metadata" % str(server_id))
- body = self._parse_key_value(etree.fromstring(body))
- return resp, body
-
- def set_server_metadata(self, server_id, meta, no_metadata_field=False):
- doc = xml_utils.Document()
- if not no_metadata_field:
- metadata = xml_utils.Element("metadata")
- doc.append(metadata)
- for k, v in meta.items():
- meta_element = xml_utils.Element("meta", key=k)
- meta_element.append(xml_utils.Text(v))
- metadata.append(meta_element)
- resp, body = self.put('servers/%s/metadata' % str(server_id), str(doc))
- return resp, xml_utils.xml_to_json(etree.fromstring(body))
-
- def update_server_metadata(self, server_id, meta):
- doc = xml_utils.Document()
- metadata = xml_utils.Element("metadata")
- doc.append(metadata)
- for k, v in meta.items():
- meta_element = xml_utils.Element("meta", key=k)
- meta_element.append(xml_utils.Text(v))
- metadata.append(meta_element)
- resp, body = self.post("/servers/%s/metadata" % str(server_id),
- str(doc))
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def get_server_metadata_item(self, server_id, key):
- resp, body = self.get("servers/%s/metadata/%s" % (str(server_id), key))
- return resp, dict([(etree.fromstring(body).attrib['key'],
- xml_utils.xml_to_json(etree.fromstring(body)))])
-
- def set_server_metadata_item(self, server_id, key, meta):
- doc = xml_utils.Document()
- for k, v in meta.items():
- meta_element = xml_utils.Element("meta", key=k)
- meta_element.append(xml_utils.Text(v))
- doc.append(meta_element)
- resp, body = self.put('servers/%s/metadata/%s' % (str(server_id), key),
- str(doc))
- return resp, xml_utils.xml_to_json(etree.fromstring(body))
-
- def delete_server_metadata_item(self, server_id, key):
- resp, body = self.delete("servers/%s/metadata/%s" %
- (str(server_id), key))
- return resp, body
-
- def get_console_output(self, server_id, length):
- kwargs = {'length': length} if length else {}
- return self.action(server_id, 'os-getConsoleOutput', 'output',
- **kwargs)
-
- def list_virtual_interfaces(self, server_id):
- """
- List the virtual interfaces used in an instance.
- """
- resp, body = self.get('/'.join(['servers', server_id,
- 'os-virtual-interfaces']))
- virt_int = self._parse_xml_virtual_interfaces(etree.fromstring(body))
- return resp, virt_int
-
- def rescue_server(self, server_id, **kwargs):
- """Rescue the provided server."""
- return self.action(server_id, 'rescue', None, **kwargs)
-
- def unrescue_server(self, server_id):
- """Unrescue the provided server."""
- return self.action(server_id, 'unrescue', None)
-
- def attach_volume(self, server_id, volume_id, device='/dev/vdz'):
- post_body = xml_utils.Element("volumeAttachment", volumeId=volume_id,
- device=device)
- resp, body = self.post('servers/%s/os-volume_attachments' % server_id,
- str(xml_utils.Document(post_body)))
- return resp, body
-
- def detach_volume(self, server_id, volume_id):
- headers = {'Content-Type': 'application/xml',
- 'Accept': 'application/xml'}
- resp, body = self.delete('servers/%s/os-volume_attachments/%s' %
- (server_id, volume_id), headers)
- return resp, body
-
- def get_server_diagnostics(self, server_id):
- """Get the usage data for a server."""
- resp, body = self.get("servers/%s/diagnostics" % server_id)
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def list_instance_actions(self, server_id):
- """List the provided server action."""
- resp, body = self.get("servers/%s/os-instance-actions" % server_id)
- body = self._parse_array(etree.fromstring(body))
- return resp, body
-
- def get_instance_action(self, server_id, request_id):
- """Returns the action details of the provided server."""
- resp, body = self.get("servers/%s/os-instance-actions/%s" %
- (server_id, request_id))
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def force_delete_server(self, server_id, **kwargs):
- """Force delete a server."""
- return self.action(server_id, 'forceDelete', None, **kwargs)
-
- def restore_soft_deleted_server(self, server_id, **kwargs):
- """Restore a soft-deleted server."""
- return self.action(server_id, 'restore', None, **kwargs)
-
- def reset_network(self, server_id, **kwargs):
- """Resets the Network of a server"""
- return self.action(server_id, 'resetNetwork', None, **kwargs)
-
- def inject_network_info(self, server_id, **kwargs):
- """Inject the Network Info into server"""
- return self.action(server_id, 'injectNetworkInfo', None, **kwargs)
-
- def get_vnc_console(self, server_id, console_type):
- """Get URL of VNC console."""
- return self.action(server_id, "os-getVNCConsole",
- "console", type=console_type)
diff --git a/tempest/services/compute/xml/services_client.py b/tempest/services/compute/xml/services_client.py
deleted file mode 100644
index e1e78d0..0000000
--- a/tempest/services/compute/xml/services_client.py
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright 2013 NEC Corporation
-# Copyright 2013 IBM Corp.
-# 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 urllib
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-
-CONF = config.CONF
-
-
-class ServicesClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(ServicesClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def list_services(self, params=None):
- url = 'os-services'
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- node = etree.fromstring(body)
- body = [xml_utils.xml_to_json(x) for x in node.getchildren()]
- return resp, body
-
- def enable_service(self, host_name, binary):
- """
- Enable service on a host
- host_name: Name of host
- binary: Service binary
- """
- post_body = xml_utils.Element("service")
- post_body.add_attr('binary', binary)
- post_body.add_attr('host', host_name)
-
- resp, body = self.put('os-services/enable', str(
- xml_utils.Document(post_body)))
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def disable_service(self, host_name, binary):
- """
- Disable service on a host
- host_name: Name of host
- binary: Service binary
- """
- post_body = xml_utils.Element("service")
- post_body.add_attr('binary', binary)
- post_body.add_attr('host', host_name)
-
- resp, body = self.put('os-services/disable', str(
- xml_utils.Document(post_body)))
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
diff --git a/tempest/services/compute/xml/tenant_usages_client.py b/tempest/services/compute/xml/tenant_usages_client.py
deleted file mode 100644
index 0b19f63..0000000
--- a/tempest/services/compute/xml/tenant_usages_client.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright 2013 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 urllib
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-
-CONF = config.CONF
-
-
-class TenantUsagesClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(TenantUsagesClientXML, self).__init__(auth_provider)
- self.service = CONF.compute.catalog_type
-
- def _parse_array(self, node):
- json = xml_utils.xml_to_json(node)
- return json
-
- def list_tenant_usages(self, params=None):
- url = 'os-simple-tenant-usage'
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- tenant_usage = self._parse_array(etree.fromstring(body))
- return resp, tenant_usage['tenant_usage']
-
- def get_tenant_usage(self, tenant_id, params=None):
- url = 'os-simple-tenant-usage/%s' % tenant_id
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- tenant_usage = self._parse_array(etree.fromstring(body))
- return resp, tenant_usage
diff --git a/tempest/services/compute/xml/volumes_extensions_client.py b/tempest/services/compute/xml/volumes_extensions_client.py
deleted file mode 100644
index da1764a..0000000
--- a/tempest/services/compute/xml/volumes_extensions_client.py
+++ /dev/null
@@ -1,148 +0,0 @@
-# Copyright 2012 IBM Corp.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import time
-import urllib
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
-
-
-class VolumesExtensionsClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(VolumesExtensionsClientXML, self).__init__(
- auth_provider)
- self.service = CONF.compute.catalog_type
- self.build_interval = CONF.compute.build_interval
- self.build_timeout = CONF.compute.build_timeout
-
- def _parse_volume(self, body):
- vol = dict((attr, body.get(attr)) for attr in body.keys())
-
- for child in body.getchildren():
- tag = child.tag
- if tag.startswith("{"):
- ns, tag = tag.split("}", 1)
- if tag == 'metadata':
- vol['metadata'] = dict((meta.get('key'),
- meta.text) for meta in list(child))
- else:
- vol[tag] = xml_utils.xml_to_json(child)
- return vol
-
- def list_volumes(self, params=None):
- """List all the volumes created."""
- url = 'os-volumes'
-
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = etree.fromstring(body)
- volumes = []
- if body is not None:
- volumes += [self._parse_volume(vol) for vol in list(body)]
- return resp, volumes
-
- def list_volumes_with_detail(self, params=None):
- """List all the details of volumes."""
- url = 'os-volumes/detail'
-
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = etree.fromstring(body)
- volumes = []
- if body is not None:
- volumes += [self._parse_volume(vol) for vol in list(body)]
- return resp, volumes
-
- def get_volume(self, volume_id):
- """Returns the details of a single volume."""
- url = "os-volumes/%s" % str(volume_id)
- resp, body = self.get(url)
- body = etree.fromstring(body)
- return resp, self._parse_volume(body)
-
- def create_volume(self, size, display_name=None, metadata=None):
- """Creates a new Volume.
-
- :param size: Size of volume in GB. (Required)
- :param display_name: Optional Volume Name.
- :param metadata: An optional dictionary of values for metadata.
- """
- volume = xml_utils.Element("volume",
- xmlns=xml_utils.XMLNS_11,
- size=size)
- if display_name:
- volume.add_attr('display_name', display_name)
-
- if metadata:
- _metadata = xml_utils.Element('metadata')
- volume.append(_metadata)
- for key, value in metadata.items():
- meta = xml_utils.Element('meta')
- meta.add_attr('key', key)
- meta.append(xml_utils.Text(value))
- _metadata.append(meta)
-
- resp, body = self.post('os-volumes', str(xml_utils.Document(volume)))
- body = xml_utils.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def delete_volume(self, volume_id):
- """Deletes the Specified Volume."""
- return self.delete("os-volumes/%s" % str(volume_id))
-
- def wait_for_volume_status(self, volume_id, status):
- """Waits for a Volume to reach a given status."""
- resp, body = self.get_volume(volume_id)
- volume_name = body['displayName']
- volume_status = body['status']
- start = int(time.time())
-
- while volume_status != status:
- time.sleep(self.build_interval)
- resp, body = self.get_volume(volume_id)
- volume_status = body['status']
- if volume_status == 'error':
- raise exceptions.VolumeBuildErrorException(volume_id=volume_id)
-
- if int(time.time()) - start >= self.build_timeout:
- message = 'Volume %s failed to reach %s status within '\
- 'the required time (%s s).' % (volume_name, status,
- self.build_timeout)
- raise exceptions.TimeoutException(message)
-
- def is_resource_deleted(self, id):
- try:
- self.get_volume(id)
- except exceptions.NotFound:
- return True
- return False
-
- @property
- def resource_type(self):
- """Returns the primary type of resource this client works with."""
- return 'volume'
diff --git a/tempest/services/identity/v3/json/policy_client.py b/tempest/services/identity/v3/json/policy_client.py
index e093260..579243c 100644
--- a/tempest/services/identity/v3/json/policy_client.py
+++ b/tempest/services/identity/v3/json/policy_client.py
@@ -39,14 +39,14 @@
resp, body = self.post('policies', post_body)
self.expected_success(201, resp.status)
body = json.loads(body)
- return resp, body['policy']
+ return rest_client.ResponseBody(resp, body['policy'])
def list_policies(self):
"""Lists the policies."""
resp, body = self.get('policies')
self.expected_success(200, resp.status)
body = json.loads(body)
- return resp, body['policies']
+ return rest_client.ResponseBodyList(resp, body['policies'])
def get_policy(self, policy_id):
"""Lists out the given policy."""
@@ -54,7 +54,7 @@
resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
- return resp, body['policy']
+ return rest_client.ResponseBody(resp, body['policy'])
def update_policy(self, policy_id, **kwargs):
"""Updates a policy."""
@@ -67,11 +67,11 @@
resp, body = self.patch(url, post_body)
self.expected_success(200, resp.status)
body = json.loads(body)
- return resp, body['policy']
+ return rest_client.ResponseBody(resp, body['policy'])
def delete_policy(self, policy_id):
"""Deletes the policy."""
url = "policies/%s" % policy_id
resp, body = self.delete(url)
self.expected_success(204, resp.status)
- return resp, body
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/v3/xml/__init__.py b/tempest/services/identity/v3/xml/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/identity/v3/xml/__init__.py
+++ /dev/null
diff --git a/tempest/services/identity/v3/xml/credentials_client.py b/tempest/services/identity/v3/xml/credentials_client.py
deleted file mode 100644
index 37513d0..0000000
--- a/tempest/services/identity/v3/xml/credentials_client.py
+++ /dev/null
@@ -1,111 +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 json
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils as common
-from tempest import config
-
-CONF = config.CONF
-
-XMLNS = "http://docs.openstack.org/identity/api/v3"
-
-
-class CredentialsClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(CredentialsClientXML, self).__init__(auth_provider)
- self.service = CONF.identity.catalog_type
- self.endpoint_url = 'adminURL'
- self.api_version = "v3"
-
- def _parse_body(self, body):
- data = common.xml_to_json(body)
- return data
-
- def _parse_creds(self, node):
- array = []
- for child in node.getchildren():
- tag_list = child.tag.split('}', 1)
- if tag_list[1] == "credential":
- array.append(common.xml_to_json(child))
- return array
-
- def create_credential(self, access_key, secret_key, user_id, project_id):
- """Creates a credential."""
- cred_type = 'ec2'
- access = ""access": "%s"" % access_key
- secret = ""secret": "%s"" % secret_key
- blob = common.Element('blob',
- xmlns=XMLNS)
- blob.append(common.Text("{%s , %s}"
- % (access, secret)))
- credential = common.Element('credential', project_id=project_id,
- type=cred_type, user_id=user_id)
- credential.append(blob)
- resp, body = self.post('credentials', str(common.Document(credential)))
- self.expected_success(201, resp.status)
- body = self._parse_body(etree.fromstring(body))
- body['blob'] = json.loads(body['blob'])
- return resp, body
-
- def update_credential(self, credential_id, **kwargs):
- """Updates a credential."""
- _, body = self.get_credential(credential_id)
- cred_type = kwargs.get('type', body['type'])
- access_key = kwargs.get('access_key', body['blob']['access'])
- secret_key = kwargs.get('secret_key', body['blob']['secret'])
- project_id = kwargs.get('project_id', body['project_id'])
- user_id = kwargs.get('user_id', body['user_id'])
- access = ""access": "%s"" % access_key
- secret = ""secret": "%s"" % secret_key
- blob = common.Element('blob',
- xmlns=XMLNS)
- blob.append(common.Text("{%s , %s}"
- % (access, secret)))
- credential = common.Element('credential', project_id=project_id,
- type=cred_type, user_id=user_id)
- credential.append(blob)
- resp, body = self.patch('credentials/%s' % credential_id,
- str(common.Document(credential)))
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- body['blob'] = json.loads(body['blob'])
- return resp, body
-
- def get_credential(self, credential_id):
- """To GET Details of a credential."""
- resp, body = self.get('credentials/%s' % credential_id)
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- body['blob'] = json.loads(body['blob'])
- return resp, body
-
- def list_credentials(self):
- """Lists out all the available credentials."""
- resp, body = self.get('credentials')
- self.expected_success(200, resp.status)
- body = self._parse_creds(etree.fromstring(body))
- return resp, body
-
- def delete_credential(self, credential_id):
- """Deletes a credential."""
- resp, body = self.delete('credentials/%s' % credential_id)
- self.expected_success(204, resp.status)
- return resp, body
diff --git a/tempest/services/identity/v3/xml/endpoints_client.py b/tempest/services/identity/v3/xml/endpoints_client.py
deleted file mode 100644
index 892fb58..0000000
--- a/tempest/services/identity/v3/xml/endpoints_client.py
+++ /dev/null
@@ -1,133 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from lxml import etree
-
-from tempest.common import http
-from tempest.common import rest_client
-from tempest.common import xml_utils as common
-from tempest import config
-
-CONF = config.CONF
-
-XMLNS = "http://docs.openstack.org/identity/api/v3"
-
-
-class EndPointClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(EndPointClientXML, self).__init__(auth_provider)
- self.service = CONF.identity.catalog_type
- self.endpoint_url = 'adminURL'
- self.api_version = "v3"
-
- def _parse_array(self, node):
- array = []
- for child in node.getchildren():
- tag_list = child.tag.split('}', 1)
- if tag_list[1] == "endpoint":
- array.append(common.xml_to_json(child))
- return array
-
- def _parse_body(self, body):
- json = common.xml_to_json(body)
- return json
-
- def request(self, method, url, extra_headers=False, headers=None,
- body=None, wait=None):
- """Overriding the existing HTTP request in super class RestClient."""
- if extra_headers:
- try:
- headers.update(self.get_headers())
- except (ValueError, TypeError):
- headers = self.get_headers()
- dscv = CONF.identity.disable_ssl_certificate_validation
- self.http_obj = http.ClosingHttp(
- disable_ssl_certificate_validation=dscv)
- return super(EndPointClientXML, self).request(method, url,
- extra_headers,
- headers=headers,
- body=body)
-
- def list_endpoints(self):
- """Get the list of endpoints."""
- resp, body = self.get("endpoints")
- self.expected_success(200, resp.status)
- body = self._parse_array(etree.fromstring(body))
- return resp, body
-
- def create_endpoint(self, service_id, interface, url, **kwargs):
- """Create endpoint.
-
- Normally this function wouldn't allow setting values that are not
- allowed for 'enabled'. Use `force_enabled` to set a non-boolean.
-
- """
- region = kwargs.get('region', None)
- if 'force_enabled' in kwargs:
- enabled = kwargs['force_enabled']
- else:
- enabled = kwargs.get('enabled', None)
- if enabled is not None:
- enabled = str(enabled).lower()
- create_endpoint = common.Element("endpoint",
- xmlns=XMLNS,
- service_id=service_id,
- interface=interface,
- url=url, region=region,
- enabled=enabled)
- resp, body = self.post('endpoints',
- str(common.Document(create_endpoint)))
- self.expected_success(201, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def update_endpoint(self, endpoint_id, service_id=None, interface=None,
- url=None, region=None, enabled=None, **kwargs):
- """Updates an endpoint with given parameters.
-
- Normally this function wouldn't allow setting values that are not
- allowed for 'enabled'. Use `force_enabled` to set a non-boolean.
-
- """
- doc = common.Document()
- endpoint = common.Element("endpoint")
- doc.append(endpoint)
-
- if service_id:
- endpoint.add_attr("service_id", service_id)
- if interface:
- endpoint.add_attr("interface", interface)
- if url:
- endpoint.add_attr("url", url)
- if region:
- endpoint.add_attr("region", region)
-
- if 'force_enabled' in kwargs:
- endpoint.add_attr("enabled", kwargs['force_enabled'])
- elif enabled is not None:
- endpoint.add_attr("enabled", str(enabled).lower())
-
- resp, body = self.patch('endpoints/%s' % str(endpoint_id), str(doc))
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def delete_endpoint(self, endpoint_id):
- """Delete endpoint."""
- resp_header, resp_body = self.delete('endpoints/%s' % endpoint_id)
- self.expected_success(204, resp_header.status)
- return resp_header, resp_body
diff --git a/tempest/services/identity/v3/xml/identity_client.py b/tempest/services/identity/v3/xml/identity_client.py
deleted file mode 100644
index fdc0a0a..0000000
--- a/tempest/services/identity/v3/xml/identity_client.py
+++ /dev/null
@@ -1,632 +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 json
-import urllib
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils as common
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
-
-XMLNS = "http://docs.openstack.org/identity/api/v3"
-
-
-class IdentityV3ClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(IdentityV3ClientXML, self).__init__(auth_provider)
- self.service = CONF.identity.catalog_type
- self.endpoint_url = 'adminURL'
- self.api_version = "v3"
-
- def _parse_projects(self, node):
- array = []
- for child in node.getchildren():
- tag_list = child.tag.split('}', 1)
- if tag_list[1] == "project":
- array.append(common.xml_to_json(child))
- return array
-
- def _parse_domains(self, node):
- array = []
- for child in node.getchildren():
- tag_list = child.tag.split('}', 1)
- if tag_list[1] == "domain":
- array.append(common.xml_to_json(child))
- return array
-
- def _parse_groups(self, node):
- array = []
- for child in node.getchildren():
- tag_list = child.tag.split('}', 1)
- if tag_list[1] == "group":
- array.append(common.xml_to_json(child))
- return array
-
- def _parse_group_users(self, node):
- array = []
- for child in node.getchildren():
- tag_list = child.tag.split('}', 1)
- if tag_list[1] == "user":
- array.append(common.xml_to_json(child))
- return array
-
- def _parse_roles(self, node):
- array = []
- for child in node.getchildren():
- tag_list = child.tag.split('}', 1)
- if tag_list[1] == "role":
- array.append(common.xml_to_json(child))
- return array
-
- def _parse_users(self, node):
- array = []
- for child in node.getchildren():
- tag_list = child.tag.split('}', 1)
- if tag_list[1] == "user":
- array.append(common.xml_to_json(child))
- return array
-
- def _parse_array(self, node):
- array = []
- for child in node.getchildren():
- array.append(common.xml_to_json(child))
- return array
-
- def _parse_body(self, body):
- _json = common.xml_to_json(body)
- return _json
-
- def create_user(self, user_name, password=None, project_id=None,
- email=None, domain_id='default', **kwargs):
- """Creates a user."""
- en = kwargs.get('enabled', 'true')
- description = kwargs.get('description', None)
- post_body = common.Element("user",
- xmlns=XMLNS,
- name=user_name,
- password=password,
- description=description,
- email=email,
- enabled=str(en).lower(),
- project_id=project_id,
- domain_id=domain_id)
- resp, body = self.post('users', str(common.Document(post_body)))
- self.expected_success(201, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def update_user(self, user_id, name, **kwargs):
- """Updates a user."""
- _, body = self.get_user(user_id)
- email = kwargs.get('email', body['email'])
- en = kwargs.get('enabled', body['enabled'])
- project_id = kwargs.get('project_id', body['project_id'])
- description = kwargs.get('description', body['description'])
- domain_id = kwargs.get('domain_id', body['domain_id'])
- update_user = common.Element("user",
- xmlns=XMLNS,
- name=name,
- email=email,
- project_id=project_id,
- domain_id=domain_id,
- description=description,
- enabled=str(en).lower())
- resp, body = self.patch('users/%s' % user_id,
- str(common.Document(update_user)))
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def update_user_password(self, user_id, password, original_password):
- """Updates a user password."""
- update_user = common.Element("user",
- xmlns=XMLNS,
- password=password,
- original_password=original_password)
- resp, _ = self.post('users/%s/password' % user_id,
- str(common.Document(update_user)))
- self.expected_success(204, resp.status)
- return resp
-
- def list_user_projects(self, user_id):
- """Lists the projects on which a user has roles assigned."""
- resp, body = self.get('users/%s/projects' % user_id)
- self.expected_success(200, resp.status)
- body = self._parse_projects(etree.fromstring(body))
- return resp, body
-
- def get_users(self, params=None):
- """Get the list of users."""
- url = 'users'
- if params:
- url += '?%s' % urllib.urlencode(params)
- resp, body = self.get(url)
- self.expected_success(200, resp.status)
- body = self._parse_users(etree.fromstring(body))
- return resp, body
-
- def get_user(self, user_id):
- """GET a user."""
- resp, body = self.get("users/%s" % user_id)
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def delete_user(self, user_id):
- """Deletes a User."""
- resp, body = self.delete("users/%s" % user_id)
- self.expected_success(204, resp.status)
- return resp, body
-
- def create_project(self, name, **kwargs):
- """Creates a project."""
- description = kwargs.get('description', None)
- en = kwargs.get('enabled', 'true')
- domain_id = kwargs.get('domain_id', 'default')
- post_body = common.Element("project",
- xmlns=XMLNS,
- description=description,
- domain_id=domain_id,
- enabled=str(en).lower(),
- name=name)
- resp, body = self.post('projects',
- str(common.Document(post_body)))
- self.expected_success(201, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def list_projects(self, params=None):
- """Get the list of projects."""
- url = 'projects'
- if params:
- url += '?%s' % urllib.urlencode(params)
- resp, body = self.get(url)
- self.expected_success(200, resp.status)
- body = self._parse_projects(etree.fromstring(body))
- return resp, body
-
- def update_project(self, project_id, **kwargs):
- """Updates a Project."""
- resp, body = self.get_project(project_id)
- name = kwargs.get('name', body['name'])
- desc = kwargs.get('description', body['description'])
- en = kwargs.get('enabled', body['enabled'])
- domain_id = kwargs.get('domain_id', body['domain_id'])
- post_body = common.Element("project",
- xmlns=XMLNS,
- name=name,
- description=desc,
- enabled=str(en).lower(),
- domain_id=domain_id)
- resp, body = self.patch('projects/%s' % project_id,
- str(common.Document(post_body)))
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def get_project(self, project_id):
- """GET a Project."""
- resp, body = self.get("projects/%s" % project_id)
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def delete_project(self, project_id):
- """Delete a project."""
- resp, body = self.delete('projects/%s' % str(project_id))
- self.expected_success(204, resp.status)
- return resp, body
-
- def create_role(self, name):
- """Create a Role."""
- post_body = common.Element("role",
- xmlns=XMLNS,
- name=name)
- resp, body = self.post('roles', str(common.Document(post_body)))
- self.expected_success(201, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def get_role(self, role_id):
- """GET a Role."""
- resp, body = self.get('roles/%s' % str(role_id))
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def list_roles(self):
- """Get the list of Roles."""
- resp, body = self.get("roles")
- self.expected_success(200, resp.status)
- body = self._parse_roles(etree.fromstring(body))
- return resp, body
-
- def update_role(self, name, role_id):
- """Updates a Role."""
- post_body = common.Element("role",
- xmlns=XMLNS,
- name=name)
- resp, body = self.patch('roles/%s' % str(role_id),
- str(common.Document(post_body)))
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def delete_role(self, role_id):
- """Delete a role."""
- resp, body = self.delete('roles/%s' % str(role_id))
- self.expected_success(204, resp.status)
- return resp, body
-
- def assign_user_role(self, project_id, user_id, role_id):
- """Add roles to a user on a tenant."""
- resp, body = self.put('projects/%s/users/%s/roles/%s' %
- (project_id, user_id, role_id), '')
- self.expected_success(204, resp.status)
- return resp, body
-
- def create_domain(self, name, **kwargs):
- """Creates a domain."""
- description = kwargs.get('description', None)
- en = kwargs.get('enabled', True)
- post_body = common.Element("domain",
- xmlns=XMLNS,
- name=name,
- description=description,
- enabled=str(en).lower())
- resp, body = self.post('domains', str(common.Document(post_body)))
- self.expected_success(201, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def list_domains(self):
- """Get the list of domains."""
- resp, body = self.get("domains")
- self.expected_success(200, resp.status)
- body = self._parse_domains(etree.fromstring(body))
- return resp, body
-
- def delete_domain(self, domain_id):
- """Delete a domain."""
- resp, body = self.delete('domains/%s' % domain_id)
- self.expected_success(204, resp.status)
- return resp, body
-
- def update_domain(self, domain_id, **kwargs):
- """Updates a domain."""
- _, body = self.get_domain(domain_id)
- description = kwargs.get('description', body['description'])
- en = kwargs.get('enabled', body['enabled'])
- name = kwargs.get('name', body['name'])
- post_body = common.Element("domain",
- xmlns=XMLNS,
- name=name,
- description=description,
- enabled=str(en).lower())
- resp, body = self.patch('domains/%s' % domain_id,
- str(common.Document(post_body)))
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def get_domain(self, domain_id):
- """Get Domain details."""
- resp, body = self.get('domains/%s' % domain_id)
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def get_token(self, resp_token):
- """GET a Token Details."""
- headers = {'Content-Type': 'application/xml',
- 'Accept': 'application/xml',
- 'X-Subject-Token': resp_token}
- resp, body = self.get("auth/tokens", headers=headers)
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def delete_token(self, resp_token):
- """Delete a Given Token."""
- headers = {'X-Subject-Token': resp_token}
- resp, body = self.delete("auth/tokens", headers=headers)
- self.expected_success(204, resp.status)
- return resp, body
-
- def create_group(self, name, **kwargs):
- """Creates a group."""
- description = kwargs.get('description', None)
- domain_id = kwargs.get('domain_id', 'default')
- project_id = kwargs.get('project_id', None)
- post_body = common.Element("group",
- xmlns=XMLNS,
- name=name,
- description=description,
- domain_id=domain_id,
- project_id=project_id)
- resp, body = self.post('groups', str(common.Document(post_body)))
- self.expected_success(201, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def get_group(self, group_id):
- """Get group details."""
- resp, body = self.get('groups/%s' % group_id)
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def update_group(self, group_id, **kwargs):
- """Updates a group."""
- _, body = self.get_group(group_id)
- name = kwargs.get('name', body['name'])
- description = kwargs.get('description', body['description'])
- post_body = common.Element("group",
- xmlns=XMLNS,
- name=name,
- description=description)
- resp, body = self.patch('groups/%s' % group_id,
- str(common.Document(post_body)))
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def delete_group(self, group_id):
- """Delete a group."""
- resp, body = self.delete('groups/%s' % group_id)
- self.expected_success(204, resp.status)
- return resp, body
-
- def add_group_user(self, group_id, user_id):
- """Add user into group."""
- resp, body = self.put('groups/%s/users/%s' % (group_id, user_id), '')
- self.expected_success(204, resp.status)
- return resp, body
-
- def list_group_users(self, group_id):
- """List users in group."""
- resp, body = self.get('groups/%s/users' % group_id)
- self.expected_success(200, resp.status)
- body = self._parse_group_users(etree.fromstring(body))
- return resp, body
-
- def list_user_groups(self, user_id):
- """Lists the groups which a user belongs to."""
- resp, body = self.get('users/%s/groups' % user_id)
- self.expected_success(200, resp.status)
- body = self._parse_groups(etree.fromstring(body))
- return resp, body
-
- def delete_group_user(self, group_id, user_id):
- """Delete user in group."""
- resp, body = self.delete('groups/%s/users/%s' % (group_id, user_id))
- self.expected_success(204, resp.status)
- return resp, body
-
- def assign_user_role_on_project(self, project_id, user_id, role_id):
- """Add roles to a user on a project."""
- resp, body = self.put('projects/%s/users/%s/roles/%s' %
- (project_id, user_id, role_id), '')
- self.expected_success(204, resp.status)
- return resp, body
-
- def assign_user_role_on_domain(self, domain_id, user_id, role_id):
- """Add roles to a user on a domain."""
- resp, body = self.put('domains/%s/users/%s/roles/%s' %
- (domain_id, user_id, role_id), '')
- self.expected_success(204, resp.status)
- return resp, body
-
- def list_user_roles_on_project(self, project_id, user_id):
- """list roles of a user on a project."""
- resp, body = self.get('projects/%s/users/%s/roles' %
- (project_id, user_id))
- self.expected_success(200, resp.status)
- body = self._parse_roles(etree.fromstring(body))
- return resp, body
-
- def list_user_roles_on_domain(self, domain_id, user_id):
- """list roles of a user on a domain."""
- resp, body = self.get('domains/%s/users/%s/roles' %
- (domain_id, user_id))
- self.expected_success(200, resp.status)
- body = self._parse_roles(etree.fromstring(body))
- return resp, body
-
- def revoke_role_from_user_on_project(self, project_id, user_id, role_id):
- """Delete role of a user on a project."""
- resp, body = self.delete('projects/%s/users/%s/roles/%s' %
- (project_id, user_id, role_id))
- self.expected_success(204, resp.status)
- return resp, body
-
- def revoke_role_from_user_on_domain(self, domain_id, user_id, role_id):
- """Delete role of a user on a domain."""
- resp, body = self.delete('domains/%s/users/%s/roles/%s' %
- (domain_id, user_id, role_id))
- self.expected_success(204, resp.status)
- return resp, body
-
- def assign_group_role_on_project(self, project_id, group_id, role_id):
- """Add roles to a user on a project."""
- resp, body = self.put('projects/%s/groups/%s/roles/%s' %
- (project_id, group_id, role_id), '')
- self.expected_success(204, resp.status)
- return resp, body
-
- def assign_group_role_on_domain(self, domain_id, group_id, role_id):
- """Add roles to a user on a domain."""
- resp, body = self.put('domains/%s/groups/%s/roles/%s' %
- (domain_id, group_id, role_id), '')
- self.expected_success(204, resp.status)
- return resp, body
-
- def list_group_roles_on_project(self, project_id, group_id):
- """list roles of a user on a project."""
- resp, body = self.get('projects/%s/groups/%s/roles' %
- (project_id, group_id))
- self.expected_success(200, resp.status)
- body = self._parse_roles(etree.fromstring(body))
- return resp, body
-
- def list_group_roles_on_domain(self, domain_id, group_id):
- """list roles of a user on a domain."""
- resp, body = self.get('domains/%s/groups/%s/roles' %
- (domain_id, group_id))
- self.expected_success(200, resp.status)
- body = self._parse_roles(etree.fromstring(body))
- return resp, body
-
- def revoke_role_from_group_on_project(self, project_id, group_id, role_id):
- """Delete role of a user on a project."""
- resp, body = self.delete('projects/%s/groups/%s/roles/%s' %
- (project_id, group_id, role_id))
- self.expected_success(204, resp.status)
- return resp, body
-
- def revoke_role_from_group_on_domain(self, domain_id, group_id, role_id):
- """Delete role of a user on a domain."""
- resp, body = self.delete('domains/%s/groups/%s/roles/%s' %
- (domain_id, group_id, role_id))
- self.expected_success(204, resp.status)
- return resp, body
-
-
-class V3TokenClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self):
- super(V3TokenClientXML, self).__init__(None)
- auth_url = CONF.identity.uri_v3
- if not auth_url:
- raise exceptions.InvalidConfiguration('you must specify a v3 uri '
- 'if using the v3 identity '
- 'api')
- if 'auth/tokens' not in auth_url:
- auth_url = auth_url.rstrip('/') + '/auth/tokens'
-
- self.auth_url = auth_url
-
- def auth(self, user=None, password=None, tenant=None, user_type='id',
- domain=None, token=None):
- """
- :param user: user id or name, as specified in user_type
- :param domain: the user and tenant domain
- :param token: a token to re-scope.
-
- Accepts different combinations of credentials. Restrictions:
- - tenant and domain are only name (no id)
- - user domain and tenant domain are assumed identical
- - domain scope is not supported here
- Sample sample valid combinations:
- - token
- - token, tenant, domain
- - user_id, password
- - username, password, domain
- - username, password, tenant, domain
- Validation is left to the server side.
- """
-
- methods = common.Element('methods')
- identity = common.Element('identity')
-
- if token:
- method = common.Element('method')
- method.append(common.Text('token'))
- methods.append(method)
-
- token = common.Element('token', id=token)
- identity.append(token)
-
- if user and password:
- if user_type == 'id':
- _user = common.Element('user', id=user, password=password)
- else:
- _user = common.Element('user', name=user, password=password)
- if domain is not None:
- _domain = common.Element('domain', name=domain)
- _user.append(_domain)
-
- password = common.Element('password')
- password.append(_user)
- method = common.Element('method')
- method.append(common.Text('password'))
- methods.append(method)
- identity.append(password)
-
- identity.append(methods)
-
- auth = common.Element('auth')
- auth.append(identity)
-
- if tenant is not None:
- project = common.Element('project', name=tenant)
- _domain = common.Element('domain', name=domain)
- project.append(_domain)
- scope = common.Element('scope')
- scope.append(project)
- auth.append(scope)
-
- resp, body = self.post(self.auth_url, body=str(common.Document(auth)))
- self.expected_success(201, resp.status)
- return resp, body
-
- def request(self, method, url, extra_headers=False, headers=None,
- body=None):
- """A simple HTTP request interface."""
- if headers is None:
- # Always accept 'json', for xml token client too.
- # Because XML response is not easily
- # converted to the corresponding JSON one
- headers = self.get_headers(accept_type="json")
- elif extra_headers:
- try:
- headers.update(self.get_headers(accept_type="json"))
- except (ValueError, TypeError):
- headers = self.get_headers(accept_type="json")
- resp, resp_body = self.http_obj.request(url, method,
- headers=headers, body=body)
- self._log_request(method, url, resp)
-
- if resp.status in [401, 403]:
- resp_body = json.loads(resp_body)
- raise exceptions.Unauthorized(resp_body['error']['message'])
- elif resp.status not in [200, 201, 204]:
- raise exceptions.IdentityError(
- 'Unexpected status code {0}'.format(resp.status))
-
- return resp, json.loads(resp_body)
-
- def get_token(self, user, password, tenant, domain='Default',
- auth_data=False):
- """
- :param user: username
- Returns (token id, token data) for supplied credentials
- """
- resp, body = self.auth(user, password, tenant, user_type='name',
- domain=domain)
-
- token = resp.get('x-subject-token')
- if auth_data:
- return token, body['token']
- else:
- return token
diff --git a/tempest/services/identity/v3/xml/policy_client.py b/tempest/services/identity/v3/xml/policy_client.py
deleted file mode 100644
index 41bbfe5..0000000
--- a/tempest/services/identity/v3/xml/policy_client.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from lxml import etree
-
-from tempest.common import http
-from tempest.common import rest_client
-from tempest.common import xml_utils as common
-from tempest import config
-
-CONF = config.CONF
-
-XMLNS = "http://docs.openstack.org/identity/api/v3"
-
-
-class PolicyClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(PolicyClientXML, self).__init__(auth_provider)
- self.service = CONF.identity.catalog_type
- self.endpoint_url = 'adminURL'
- self.api_version = "v3"
-
- def _parse_array(self, node):
- array = []
- for child in node.getchildren():
- tag_list = child.tag.split('}', 1)
- if tag_list[1] == "policy":
- array.append(common.xml_to_json(child))
- return array
-
- def _parse_body(self, body):
- json = common.xml_to_json(body)
- return json
-
- def request(self, method, url, extra_headers=False, headers=None,
- body=None, wait=None):
- """Overriding the existing HTTP request in super class RestClient."""
- if extra_headers:
- try:
- headers.update(self.get_headers())
- except (ValueError, TypeError):
- headers = self.get_headers()
- dscv = CONF.identity.disable_ssl_certificate_validation
- self.http_obj = http.ClosingHttp(
- disable_ssl_certificate_validation=dscv)
- return super(PolicyClientXML, self).request(method, url,
- extra_headers,
- headers=headers,
- body=body)
-
- def create_policy(self, blob, type):
- """Creates a Policy."""
- create_policy = common.Element("policy", xmlns=XMLNS,
- blob=blob, type=type)
- resp, body = self.post('policies', str(common.Document(create_policy)))
- self.expected_success(201, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def list_policies(self):
- """Lists the policies."""
- resp, body = self.get('policies')
- self.expected_success(200, resp.status)
- body = self._parse_array(etree.fromstring(body))
- return resp, body
-
- def get_policy(self, policy_id):
- """Lists out the given policy."""
- url = 'policies/%s' % policy_id
- resp, body = self.get(url)
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def update_policy(self, policy_id, **kwargs):
- """Updates a policy."""
- type = kwargs.get('type')
- update_policy = common.Element("policy", xmlns=XMLNS, type=type)
- url = 'policies/%s' % policy_id
- resp, body = self.patch(url, str(common.Document(update_policy)))
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def delete_policy(self, policy_id):
- """Deletes the policy."""
- url = "policies/%s" % policy_id
- resp, body = self.delete(url)
- self.expected_success(204, resp.status)
- return resp, body
diff --git a/tempest/services/identity/v3/xml/region_client.py b/tempest/services/identity/v3/xml/region_client.py
deleted file mode 100644
index 7669678..0000000
--- a/tempest/services/identity/v3/xml/region_client.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# Copyright 2014 Hewlett-Packard Development Company, L.P
-# 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 urllib
-
-from lxml import etree
-
-from tempest.common import http
-from tempest.common import rest_client
-from tempest.common import xml_utils as common
-from tempest import config
-
-CONF = config.CONF
-
-XMLNS = "http://docs.openstack.org/identity/api/v3"
-
-
-class RegionClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(RegionClientXML, self).__init__(auth_provider)
- self.service = CONF.identity.catalog_type
- self.region_url = 'adminURL'
- self.api_version = "v3"
-
- def _parse_array(self, node):
- array = []
- for child in node.getchildren():
- tag_list = child.tag.split('}', 1)
- if tag_list[1] == "region":
- array.append(common.xml_to_json(child))
- return array
-
- def _parse_body(self, body):
- json = common.xml_to_json(body)
- return json
-
- def request(self, method, url, extra_headers=False, headers=None,
- body=None, wait=None):
- """Overriding the existing HTTP request in super class RestClient."""
- if extra_headers:
- try:
- headers.update(self.get_headers())
- except (ValueError, TypeError):
- headers = self.get_headers()
- dscv = CONF.identity.disable_ssl_certificate_validation
- self.http_obj = http.ClosingHttp(
- disable_ssl_certificate_validation=dscv)
- return super(RegionClientXML, self).request(method, url,
- extra_headers,
- headers=headers,
- body=body)
-
- def create_region(self, description, **kwargs):
- """Create region."""
- create_region = common.Element("region",
- xmlns=XMLNS,
- description=description)
- if 'parent_region_id' in kwargs:
- create_region.append(common.Element(
- 'parent_region_id', kwargs.get('parent_region_id')))
- if 'unique_region_id' in kwargs:
- resp, body = self.put(
- 'regions/%s' % kwargs.get('unique_region_id'),
- str(common.Document(create_region)))
- else:
- resp, body = self.post('regions',
- str(common.Document(create_region)))
- self.expected_success(201, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def update_region(self, region_id, **kwargs):
- """Updates an region with given parameters.
- """
- description = kwargs.get('description', None)
- update_region = common.Element("region",
- xmlns=XMLNS,
- description=description)
- if 'parent_region_id' in kwargs:
- update_region.append(common.Element('parent_region_id',
- kwargs.get('parent_region_id')))
-
- resp, body = self.patch('regions/%s' % str(region_id),
- str(common.Document(update_region)))
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def get_region(self, region_id):
- """Get Region."""
- url = 'regions/%s' % region_id
- resp, body = self.get(url)
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def list_regions(self, params=None):
- """Get the list of regions."""
- url = 'regions'
- if params:
- url += '?%s' % urllib.urlencode(params)
- resp, body = self.get(url)
- self.expected_success(200, resp.status)
- body = self._parse_array(etree.fromstring(body))
- return resp, body
-
- def delete_region(self, region_id):
- """Delete region."""
- resp, body = self.delete('regions/%s' % region_id)
- self.expected_success(204, resp.status)
- return resp, body
diff --git a/tempest/services/identity/v3/xml/service_client.py b/tempest/services/identity/v3/xml/service_client.py
deleted file mode 100644
index 14adfac..0000000
--- a/tempest/services/identity/v3/xml/service_client.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils as common
-from tempest import config
-
-CONF = config.CONF
-
-XMLNS = "http://docs.openstack.org/identity/api/v3"
-
-
-class ServiceClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(ServiceClientXML, self).__init__(auth_provider)
- self.service = CONF.identity.catalog_type
- self.endpoint_url = 'adminURL'
- self.api_version = "v3"
-
- def _parse_body(self, body):
- data = common.xml_to_json(body)
- return data
-
- def _parse_array(self, node):
- array = []
- for child in node.getchildren():
- tag_list = child.tag.split('}', 1)
- if tag_list[1] == "service":
- array.append(common.xml_to_json(child))
- return array
-
- def update_service(self, service_id, **kwargs):
- """Updates a service_id."""
- resp, body = self.get_service(service_id)
- name = kwargs.get('name', body['name'])
- description = kwargs.get('description', body['description'])
- type = kwargs.get('type', body['type'])
- update_service = common.Element("service",
- xmlns=XMLNS,
- id=service_id,
- name=name,
- description=description,
- type=type)
- resp, body = self.patch('services/%s' % service_id,
- str(common.Document(update_service)))
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def get_service(self, service_id):
- """Get Service."""
- url = 'services/%s' % service_id
- resp, body = self.get(url)
- self.expected_success(200, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def create_service(self, serv_type, name=None, description=None):
- post_body = common.Element("service",
- xmlns=XMLNS,
- name=name,
- description=description,
- type=serv_type)
- resp, body = self.post("services", str(common.Document(post_body)))
- self.expected_success(201, resp.status)
- body = self._parse_body(etree.fromstring(body))
- return resp, body
-
- def delete_service(self, serv_id):
- url = "services/" + serv_id
- resp, body = self.delete(url)
- self.expected_success(204, resp.status)
- return resp, body
-
- def list_services(self):
- resp, body = self.get('services')
- self.expected_success(200, resp.status)
- body = self._parse_array(etree.fromstring(body))
- return resp, body
diff --git a/tempest/services/identity/xml/__init__.py b/tempest/services/identity/xml/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/identity/xml/__init__.py
+++ /dev/null
diff --git a/tempest/services/identity/xml/identity_client.py b/tempest/services/identity/xml/identity_client.py
deleted file mode 100644
index eaf9390..0000000
--- a/tempest/services/identity/xml/identity_client.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# Copyright 2012 IBM Corp.
-# 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 xml_utils as xml
-from tempest import config
-from tempest.services.identity.json import identity_client
-
-CONF = config.CONF
-
-XMLNS = "http://docs.openstack.org/identity/api/v2.0"
-
-
-class IdentityClientXML(identity_client.IdentityClientJSON):
- TYPE = "xml"
-
- def create_role(self, name):
- """Create a role."""
- create_role = xml.Element("role", xmlns=XMLNS, name=name)
- resp, body = self.post('OS-KSADM/roles',
- str(xml.Document(create_role)))
- self.expected_success(200, resp.status)
- return resp, self._parse_resp(body)
-
- def get_role(self, role_id):
- """Get a role by its id."""
- resp, body = self.get('OS-KSADM/roles/%s' % role_id)
- self.expected_success(200, resp.status)
- return resp, self._parse_resp(body)
-
- def create_tenant(self, name, **kwargs):
- """
- Create a tenant
- name (required): New tenant name
- description: Description of new tenant (default is none)
- enabled <true|false>: Initial tenant status (default is true)
- """
- en = kwargs.get('enabled', 'true')
- create_tenant = xml.Element("tenant",
- xmlns=XMLNS,
- name=name,
- description=kwargs.get('description', ''),
- enabled=str(en).lower())
- resp, body = self.post('tenants', str(xml.Document(create_tenant)))
- self.expected_success(200, resp.status)
- return resp, self._parse_resp(body)
-
- def list_tenants(self):
- """Returns tenants."""
- resp, body = self.get('tenants')
- self.expected_success(200, resp.status)
- return resp, self._parse_resp(body)
-
- def update_tenant(self, tenant_id, **kwargs):
- """Updates a tenant."""
- _, body = self.get_tenant(tenant_id)
- name = kwargs.get('name', body['name'])
- desc = kwargs.get('description', body['description'])
- en = kwargs.get('enabled', body['enabled'])
- update_tenant = xml.Element("tenant",
- xmlns=XMLNS,
- id=tenant_id,
- name=name,
- description=desc,
- enabled=str(en).lower())
-
- resp, body = self.post('tenants/%s' % tenant_id,
- str(xml.Document(update_tenant)))
- self.expected_success(200, resp.status)
- return resp, self._parse_resp(body)
-
- def create_user(self, name, password, tenant_id, email, **kwargs):
- """Create a user."""
- create_user = xml.Element("user",
- xmlns=XMLNS,
- name=name,
- password=password,
- email=email)
- if tenant_id:
- create_user.add_attr('tenantId', tenant_id)
- if 'enabled' in kwargs:
- create_user.add_attr('enabled', str(kwargs['enabled']).lower())
-
- resp, body = self.post('users', str(xml.Document(create_user)))
- self.expected_success(200, resp.status)
- return resp, self._parse_resp(body)
-
- def update_user(self, user_id, **kwargs):
- """Updates a user."""
- if 'enabled' in kwargs:
- kwargs['enabled'] = str(kwargs['enabled']).lower()
- update_user = xml.Element("user", xmlns=XMLNS, **kwargs)
-
- resp, body = self.put('users/%s' % user_id,
- str(xml.Document(update_user)))
- self.expected_success(200, resp.status)
- return resp, self._parse_resp(body)
-
- def enable_disable_user(self, user_id, enabled):
- """Enables or disables a user."""
- enable_user = xml.Element("user", enabled=str(enabled).lower())
- resp, body = self.put('users/%s/enabled' % user_id,
- str(xml.Document(enable_user)))
- self.expected_success(200, resp.status)
- return resp, self._parse_resp(body)
-
- def create_service(self, name, service_type, **kwargs):
- """Create a service."""
- OS_KSADM = "http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0"
- create_service = xml.Element("service",
- xmlns=OS_KSADM,
- name=name,
- type=service_type,
- description=kwargs.get('description'))
- resp, body = self.post('OS-KSADM/services',
- str(xml.Document(create_service)))
- self.expected_success(200, resp.status)
- return resp, self._parse_resp(body)
-
- def update_user_password(self, user_id, new_pass):
- """Update User Password."""
- put_body = xml.Element("user",
- id=user_id,
- password=new_pass)
- resp, body = self.put('users/%s/OS-KSADM/password' % user_id,
- str(xml.Document(put_body)))
- self.expected_success(200, resp.status)
- return resp, self._parse_resp(body)
-
- def list_extensions(self):
- """List all the extensions."""
- resp, body = self.get('/extensions')
- self.expected_success(200, resp.status)
- return resp, self._parse_resp(body)
-
-
-class TokenClientXML(identity_client.TokenClientJSON):
- TYPE = "xml"
-
- def auth(self, user, password, tenant=None):
- passwordCreds = xml.Element('passwordCredentials',
- username=user,
- password=password)
- auth_kwargs = {}
- if tenant:
- auth_kwargs['tenantName'] = tenant
- auth = xml.Element('auth', **auth_kwargs)
- auth.append(passwordCreds)
- resp, body = self.post(self.auth_url, body=str(xml.Document(auth)))
- self.expected_success(200, resp.status)
- return resp, body['access']
-
- def auth_token(self, token_id, tenant=None):
- tokenCreds = xml.Element('token', id=token_id)
- auth_kwargs = {}
- if tenant:
- auth_kwargs['tenantName'] = tenant
- auth = xml.Element('auth', **auth_kwargs)
- auth.append(tokenCreds)
- resp, body = self.post(self.auth_url, body=str(xml.Document(auth)))
- self.expected_success(200, resp.status)
- return resp, body['access']
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 78ed56f..46475f0 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -85,8 +85,14 @@
update_body['admin_state_up'] = kwargs.get(
'admin_state_up', body['router']['admin_state_up'])
cur_gw_info = body['router']['external_gateway_info']
- if cur_gw_info and not set_enable_snat:
- cur_gw_info.pop('enable_snat', None)
+ if cur_gw_info:
+ # TODO(kevinbenton): setting the external gateway info is not
+ # allowed for a regular tenant. If the ability to update is also
+ # merged, a test case for this will need to be added similar to
+ # the SNAT case.
+ cur_gw_info.pop('external_fixed_ips', None)
+ if not set_enable_snat:
+ cur_gw_info.pop('enable_snat', None)
update_body['external_gateway_info'] = kwargs.get(
'external_gateway_info', body['router']['external_gateway_info'])
update_body = dict(router=update_body)
diff --git a/tempest/services/network/xml/__init__.py b/tempest/services/network/xml/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/network/xml/__init__.py
+++ /dev/null
diff --git a/tempest/services/network/xml/network_client.py b/tempest/services/network/xml/network_client.py
deleted file mode 100644
index 4a8dddc..0000000
--- a/tempest/services/network/xml/network_client.py
+++ /dev/null
@@ -1,320 +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 xml.etree.ElementTree as ET
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils as common
-from tempest.services.network import network_client_base as client_base
-
-
-class NetworkClientXML(client_base.NetworkClientBase):
- TYPE = "xml"
-
- # list of plurals used for xml serialization
- PLURALS = ['dns_nameservers', 'host_routes', 'allocation_pools',
- 'fixed_ips', 'extensions', 'extra_dhcp_opts', 'pools',
- 'health_monitors', 'vips', 'members', 'allowed_address_pairs',
- 'firewall_rules', 'security_groups']
-
- def get_rest_client(self, auth_provider):
- rc = rest_client.RestClient(auth_provider)
- rc.TYPE = self.TYPE
- return rc
-
- def deserialize_list(self, body):
- return common.parse_array(etree.fromstring(body), self.PLURALS)
-
- def deserialize_single(self, body):
- return _root_tag_fetcher_and_xml_to_json_parse(body)
-
- def serialize(self, body):
- # TODO(enikanorov): implement better json to xml conversion
- # expecting the dict with single key
- root = body.keys()[0]
- post_body = common.Element(root)
- post_body.add_attr('xmlns:xsi',
- 'http://www.w3.org/2001/XMLSchema-instance')
- elements = set()
- for name, attr in body[root].items():
- elt = self._get_element(name, attr)
- post_body.append(elt)
- if ":" in name:
- elements.add(name.split(":")[0])
- if elements:
- self._add_namespaces(post_body, elements)
- return str(common.Document(post_body))
-
- def serialize_list(self, body, root_name=None, item_name=None):
- # expecting dict in form
- # body = {'resources': [res_dict1, res_dict2, ...]
- post_body = common.Element(root_name)
- post_body.add_attr('xmlns:xsi',
- 'http://www.w3.org/2001/XMLSchema-instance')
- for item in body[body.keys()[0]]:
- elt = common.Element(item_name)
- for name, attr in item.items():
- elt_content = self._get_element(name, attr)
- elt.append(elt_content)
- post_body.append(elt)
- return str(common.Document(post_body))
-
- def _get_element(self, name, value):
- if value is None:
- xml_elem = common.Element(name)
- xml_elem.add_attr("xsi:nil", "true")
- return xml_elem
- elif isinstance(value, dict):
- dict_element = common.Element(name)
- for key, value in value.iteritems():
- elem = self._get_element(key, value)
- dict_element.append(elem)
- return dict_element
- elif isinstance(value, list):
- list_element = common.Element(name)
- for element in value:
- elem = self._get_element(name[:-1], element)
- list_element.append(elem)
- return list_element
- else:
- return common.Element(name, value)
-
- def _add_namespaces(self, root, elements):
- for element in elements:
- root.add_attr('xmlns:%s' % element,
- common.NEUTRON_NAMESPACES[element])
-
- def associate_health_monitor_with_pool(self, health_monitor_id,
- pool_id):
- uri = '%s/lb/pools/%s/health_monitors' % (self.uri_prefix,
- pool_id)
- post_body = common.Element("health_monitor")
- p1 = common.Element("id", health_monitor_id,)
- post_body.append(p1)
- resp, body = self.post(uri, str(common.Document(post_body)))
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- self.rest_client.expected_success(201, resp.status)
- return resp, body
-
- def disassociate_health_monitor_with_pool(self, health_monitor_id,
- pool_id):
- 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)
- return resp, body
-
- def show_extension_details(self, ext_alias):
- uri = '%s/extensions/%s' % (self.uri_prefix, str(ext_alias))
- resp, body = self.get(uri)
- self.rest_client.expected_success(200, resp.status)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
-
- def create_router(self, name, **kwargs):
- uri = '%s/routers' % (self.uri_prefix)
- router = common.Element("router")
- router.append(common.Element("name", name))
- common.deep_dict_to_xml(router, kwargs)
- resp, body = self.post(uri, str(common.Document(router)))
- self.rest_client.expected_success(201, resp.status)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
-
- def update_router(self, router_id, **kwargs):
- uri = '%s/routers/%s' % (self.uri_prefix, router_id)
- router = common.Element("router")
- for element, content in kwargs.iteritems():
- router.append(common.Element(element, content))
- resp, body = self.put(uri, str(common.Document(router)))
- self.rest_client.expected_success(200, resp.status)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
-
- def add_router_interface_with_subnet_id(self, router_id, subnet_id):
- uri = '%s/routers/%s/add_router_interface' % (self.uri_prefix,
- router_id)
- subnet = common.Element("subnet_id", subnet_id)
- resp, body = self.put(uri, str(common.Document(subnet)))
- self.rest_client.expected_success(200, resp.status)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
-
- def add_router_interface_with_port_id(self, router_id, port_id):
- uri = '%s/routers/%s/add_router_interface' % (self.uri_prefix,
- router_id)
- port = common.Element("port_id", port_id)
- resp, body = self.put(uri, str(common.Document(port)))
- self.rest_client.expected_success(200, resp.status)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
-
- def remove_router_interface_with_subnet_id(self, router_id, subnet_id):
- uri = '%s/routers/%s/remove_router_interface' % (self.uri_prefix,
- router_id)
- subnet = common.Element("subnet_id", subnet_id)
- resp, body = self.put(uri, str(common.Document(subnet)))
- self.rest_client.expected_success(200, resp.status)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
-
- def remove_router_interface_with_port_id(self, router_id, port_id):
- uri = '%s/routers/%s/remove_router_interface' % (self.uri_prefix,
- router_id)
- port = common.Element("port_id", port_id)
- resp, body = self.put(uri, str(common.Document(port)))
- self.rest_client.expected_success(200, resp.status)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return 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)
- ports = common.parse_array(etree.fromstring(body), self.PLURALS)
- ports = {"ports": ports}
- return resp, ports
-
- def update_agent(self, agent_id, agent_info):
- uri = '%s/agents/%s' % (self.uri_prefix, agent_id)
- agent = common.Element('agent')
- for (key, value) in agent_info.items():
- p = common.Element(key, value)
- agent.append(p)
- resp, body = self.put(uri, str(common.Document(agent)))
- self.rest_client.expected_success(200, resp.status)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return 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)
- pools = common.parse_array(etree.fromstring(body))
- body = {'pools': pools}
- return resp, body
-
- def show_lbaas_agent_hosting_pool(self, pool_id):
- 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)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return 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)
- routers = common.parse_array(etree.fromstring(body))
- body = {'routers': routers}
- return 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)
- agents = common.parse_array(etree.fromstring(body))
- body = {'agents': agents}
- return resp, body
-
- def add_router_to_l3_agent(self, agent_id, router_id):
- uri = '%s/agents/%s/l3-routers' % (self.uri_prefix, agent_id)
- router = (common.Element("router_id", router_id))
- resp, body = self.post(uri, str(common.Document(router)))
- self.rest_client.expected_success(201, resp.status)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
-
- def remove_router_from_l3_agent(self, agent_id, router_id):
- 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)
- return 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)
- agents = common.parse_array(etree.fromstring(body))
- body = {'agents': agents}
- return 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)
- networks = common.parse_array(etree.fromstring(body))
- body = {'networks': networks}
- return resp, body
-
- def remove_network_from_dhcp_agent(self, agent_id, network_id):
- 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)
- return 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)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
-
- def add_dhcp_agent_to_network(self, agent_id, network_id):
- uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
- network = common.Element("network_id", network_id)
- resp, body = self.post(uri, str(common.Document(network)))
- self.rest_client.expected_success(201, resp.status)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
-
- def insert_firewall_rule_in_policy(self, firewall_policy_id,
- firewall_rule_id, insert_after="",
- insert_before=""):
- uri = '%s/fw/firewall_policies/%s/insert_rule' % (self.uri_prefix,
- firewall_policy_id)
- rule = common.Element("firewall_rule_id", firewall_rule_id)
- resp, body = self.put(uri, str(common.Document(rule)))
- self.rest_client.expected_success(200, resp.status)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
-
- def remove_firewall_rule_from_policy(self, firewall_policy_id,
- firewall_rule_id):
- uri = '%s/fw/firewall_policies/%s/remove_rule' % (self.uri_prefix,
- firewall_policy_id)
- rule = common.Element("firewall_rule_id", firewall_rule_id)
- resp, body = self.put(uri, str(common.Document(rule)))
- self.rest_client.expected_success(200, resp.status)
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
-
-
-def _root_tag_fetcher_and_xml_to_json_parse(xml_returned_body):
- body = ET.fromstring(xml_returned_body)
- root_tag = body.tag
- if root_tag.startswith("{"):
- ns, root_tag = root_tag.split("}", 1)
- body = common.xml_to_json(etree.fromstring(xml_returned_body),
- NetworkClientXML.PLURALS)
- nil = '{http://www.w3.org/2001/XMLSchema-instance}nil'
- for key, val in body.iteritems():
- if isinstance(val, dict):
- if (nil in val and val[nil] == 'true'):
- body[key] = None
- body = {root_tag: body}
- return body
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index 4dc588f..4417e3b 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -52,6 +52,7 @@
headers[remove_metadata_prefix + key] = remove_metadata[key]
resp, body = self.put(url, data, headers)
+ self.expected_success(200, resp.status)
return resp, body
def delete_account(self, data=None, params=None):
@@ -61,6 +62,7 @@
url = '?%s%s' % (url, urllib.urlencode(params))
resp, body = self.delete(url, headers={}, body=data)
+ self.expected_success(200, resp.status)
return resp, body
def list_account_metadata(self):
@@ -69,6 +71,7 @@
Returns all account metadata headers
"""
resp, body = self.head('')
+ self.expected_success(204, resp.status)
return resp, body
def create_account_metadata(self, metadata,
@@ -85,6 +88,7 @@
url = '?%s%s' % (url, urllib.urlencode(params))
resp, body = self.post(url, headers=headers, body=data)
+ self.expected_success([200, 204], resp.status)
return resp, body
def delete_account_metadata(self, metadata,
@@ -97,6 +101,7 @@
for item in metadata:
headers[metadata_prefix + item] = metadata[item]
resp, body = self.post('', headers=headers, body=None)
+ self.expected_success(204, resp.status)
return resp, body
def create_and_delete_account_metadata(
@@ -115,6 +120,7 @@
headers[delete_metadata_prefix + key] = delete_metadata[key]
resp, body = self.post('', headers=headers, body=None)
+ self.expected_success(204, resp.status)
return resp, body
def list_account_containers(self, params=None):
@@ -147,6 +153,7 @@
body = etree.fromstring(body)
else:
body = body.strip().splitlines()
+ self.expected_success([200, 204], resp.status)
return resp, body
def list_extensions(self):
@@ -156,6 +163,7 @@
finally:
self.reset_path()
body = json.loads(body)
+ self.expected_success(200, resp.status)
return resp, body
@@ -222,7 +230,7 @@
url = '?format=%s' % self.format
if params:
- url += '&%s' + urllib.urlencode(params)
+ url += '&%s' % urllib.urlencode(params)
headers = {}
if metadata:
@@ -230,4 +238,5 @@
headers[str(key)] = metadata[key]
resp, body = self.get(url, headers=headers)
+ self.expected_success(200, resp.status)
return resp, body
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index ffc1326..182c4d0 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -53,12 +53,14 @@
headers[remove_metadata_prefix + key] = remove_metadata[key]
resp, body = self.put(url, body=None, headers=headers)
+ self.expected_success([201, 202], resp.status)
return resp, body
def delete_container(self, container_name):
"""Deletes the container (if it's empty)."""
url = str(container_name)
resp, body = self.delete(url)
+ self.expected_success(204, resp.status)
return resp, body
def update_container_metadata(
@@ -79,6 +81,7 @@
headers[remove_metadata_prefix + key] = remove_metadata[key]
resp, body = self.post(url, body=None, headers=headers)
+ self.expected_success(204, resp.status)
return resp, body
def delete_container_metadata(self, container_name, metadata,
@@ -92,6 +95,7 @@
headers[metadata_prefix + item] = metadata[item]
resp, body = self.post(url, body=None, headers=headers)
+ self.expected_success(204, resp.status)
return resp, body
def list_container_metadata(self, container_name):
@@ -100,6 +104,7 @@
"""
url = str(container_name)
resp, body = self.head(url)
+ self.expected_success(204, resp.status)
return resp, body
def list_all_container_objects(self, container, params=None):
@@ -121,6 +126,7 @@
resp, objlist = self.list_container_contents(
container,
params={'limit': limit, 'format': 'json'})
+ self.expected_success(200, resp.status)
return objlist
"""tmp = []
for obj in objlist:
@@ -186,4 +192,5 @@
body = json.loads(body)
elif params and params.get('format') == 'xml':
body = etree.fromstring(body)
+ self.expected_success([200, 204], resp.status)
return resp, body
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index b2f8205..2231407 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -46,11 +46,14 @@
url += '?%s' % urllib.urlencode(params)
resp, body = self.put(url, data, headers)
+ self.expected_success(201, resp.status)
return resp, body
def update_object(self, container, object_name, data):
"""Upload data to replace current storage object."""
- return self.create_object(container, object_name, data)
+ resp, body = self.create_object(container, object_name, data)
+ self.expected_success(201, resp.status)
+ return resp, body
def delete_object(self, container, object_name, params=None):
"""Delete storage object."""
@@ -58,6 +61,7 @@
if params:
url += '?%s' % urllib.urlencode(params)
resp, body = self.delete(url, headers={})
+ self.expected_success([200, 204], resp.status)
return resp, body
def update_object_metadata(self, container, object_name, metadata,
@@ -70,6 +74,7 @@
url = "%s/%s" % (str(container), str(object_name))
resp, body = self.post(url, None, headers=headers)
+ self.expected_success(202, resp.status)
return resp, body
def list_object_metadata(self, container, object_name):
@@ -77,6 +82,7 @@
url = "%s/%s" % (str(container), str(object_name))
resp, body = self.head(url)
+ self.expected_success(200, resp.status)
return resp, body
def get_object(self, container, object_name, metadata=None):
@@ -89,6 +95,7 @@
url = "{0}/{1}".format(container, object_name)
resp, body = self.get(url, headers=headers)
+ self.expected_success([200, 206], resp.status)
return resp, body
def copy_object_in_same_container(self, container, src_object_name,
@@ -105,6 +112,7 @@
headers[str(key)] = metadata[key]
resp, body = self.put(url, None, headers=headers)
+ self.expected_success(201, resp.status)
return resp, body
def copy_object_across_containers(self, src_container, src_object_name,
@@ -122,6 +130,7 @@
headers[str(key)] = metadata[key]
resp, body = self.put(url, None, headers=headers)
+ self.expected_success(201, resp.status)
return resp, body
def copy_object_2d_way(self, container, src_object_name, dest_object_name,
@@ -137,12 +146,14 @@
headers[str(key)] = metadata[key]
resp, body = self.copy(url, headers=headers)
+ self.expected_success(201, resp.status)
return resp, body
def create_object_segments(self, container, object_name, segment, data):
"""Creates object segments."""
url = "{0}/{1}/{2}".format(container, object_name, segment)
resp, body = self.put(url, data)
+ self.expected_success(201, resp.status)
return resp, body
def put_object_with_chunk(self, container, name, contents, chunk_size):
@@ -167,7 +178,7 @@
resp_headers[header.lower()] = value
self._error_checker('PUT', None, headers, contents, resp, body)
-
+ self.expected_success(201, resp.status)
return resp.status, resp.reason, resp_headers
@@ -220,6 +231,7 @@
url = "{0}/{1}".format(container, object_name)
resp, body = self.get(url, headers=headers)
+ self.expected_success(200, resp.status)
return resp, body
def create_object(self, container, object_name, data, metadata=None):
@@ -234,6 +246,7 @@
headers['content-length'] = '0'
url = "%s/%s" % (str(container), str(object_name))
resp, body = self.put(url, data, headers=headers)
+ self.expected_success(201, resp.status)
return resp, body
def delete_object(self, container, object_name, metadata=None):
@@ -246,6 +259,7 @@
url = "%s/%s" % (str(container), str(object_name))
resp, body = self.delete(url, headers=headers)
+ self.expected_success(200, resp.status)
return resp, body
def create_object_continue(self, container, object_name,
diff --git a/tempest/services/telemetry/xml/__init__.py b/tempest/services/telemetry/xml/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/telemetry/xml/__init__.py
+++ /dev/null
diff --git a/tempest/services/telemetry/xml/telemetry_client.py b/tempest/services/telemetry/xml/telemetry_client.py
deleted file mode 100644
index 3bee8bf..0000000
--- a/tempest/services/telemetry/xml/telemetry_client.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2014 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils as common
-import tempest.services.telemetry.telemetry_client_base as client
-
-
-class TelemetryClientXML(client.TelemetryClientBase):
- TYPE = "xml"
-
- def get_rest_client(self, auth_provider):
- rc = rest_client.RestClient(auth_provider)
- rc.TYPE = self.TYPE
- return rc
-
- def _parse_array(self, body):
- array = []
- for child in body.getchildren():
- array.append(common.xml_to_json(child))
- return array
-
- def serialize(self, body):
- return str(common.Document(body))
-
- def deserialize(self, body):
- return self._parse_array(etree.fromstring(body))
diff --git a/tempest/services/volume/json/admin/volume_hosts_client.py b/tempest/services/volume/json/admin/volume_hosts_client.py
index b3a22b5..10cb0be 100644
--- a/tempest/services/volume/json/admin/volume_hosts_client.py
+++ b/tempest/services/volume/json/admin/volume_hosts_client.py
@@ -22,13 +22,13 @@
CONF = config.CONF
-class VolumeHostsClientJSON(rest_client.RestClient):
+class BaseVolumeHostsClientJSON(rest_client.RestClient):
"""
Client class to send CRUD Volume Hosts API requests to a Cinder endpoint
"""
def __init__(self, auth_provider):
- super(VolumeHostsClientJSON, self).__init__(auth_provider)
+ super(BaseVolumeHostsClientJSON, self).__init__(auth_provider)
self.service = CONF.volume.catalog_type
self.build_interval = CONF.volume.build_interval
@@ -45,3 +45,9 @@
body = json.loads(body)
self.expected_success(200, resp.status)
return resp, body['hosts']
+
+
+class VolumeHostsClientJSON(BaseVolumeHostsClientJSON):
+ """
+ Client class to send CRUD Volume Host API V1 requests to a Cinder endpoint
+ """
diff --git a/tempest/services/volume/json/admin/volume_quotas_client.py b/tempest/services/volume/json/admin/volume_quotas_client.py
index 90790e3..5b49040 100644
--- a/tempest/services/volume/json/admin/volume_quotas_client.py
+++ b/tempest/services/volume/json/admin/volume_quotas_client.py
@@ -23,7 +23,7 @@
CONF = config.CONF
-class VolumeQuotasClientJSON(rest_client.RestClient):
+class BaseVolumeQuotasClientJSON(rest_client.RestClient):
"""
Client class to send CRUD Volume Quotas API requests to a Cinder endpoint
"""
@@ -31,7 +31,7 @@
TYPE = "json"
def __init__(self, auth_provider):
- super(VolumeQuotasClientJSON, self).__init__(auth_provider)
+ super(BaseVolumeQuotasClientJSON, self).__init__(auth_provider)
self.service = CONF.volume.catalog_type
self.build_interval = CONF.volume.build_interval
@@ -85,3 +85,9 @@
"""Delete the tenant's quota set."""
resp, body = self.delete('os-quota-sets/%s' % tenant_id)
self.expected_success(200, resp.status)
+
+
+class VolumeQuotasClientJSON(BaseVolumeQuotasClientJSON):
+ """
+ Client class to send CRUD Volume Type API V1 requests to a Cinder endpoint
+ """
diff --git a/tempest/services/volume/json/backups_client.py b/tempest/services/volume/json/backups_client.py
index 63fc646..da47639 100644
--- a/tempest/services/volume/json/backups_client.py
+++ b/tempest/services/volume/json/backups_client.py
@@ -23,13 +23,13 @@
CONF = config.CONF
-class BackupsClientJSON(rest_client.RestClient):
+class BaseBackupsClientJSON(rest_client.RestClient):
"""
Client class to send CRUD Volume backup API requests to a Cinder endpoint
"""
def __init__(self, auth_provider):
- super(BackupsClientJSON, self).__init__(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
@@ -99,3 +99,7 @@
'the required time (%s s).' %
(backup_id, status, self.build_timeout))
raise exceptions.TimeoutException(message)
+
+
+class BackupsClientJSON(BaseBackupsClientJSON):
+ """Volume V1 Backups client"""
diff --git a/tempest/services/volume/v2/xml/extensions_client.py b/tempest/services/volume/v2/json/admin/volume_hosts_client.py
similarity index 66%
rename from tempest/services/volume/v2/xml/extensions_client.py
rename to tempest/services/volume/v2/json/admin/volume_hosts_client.py
index 13f333c..d631570 100644
--- a/tempest/services/volume/v2/xml/extensions_client.py
+++ b/tempest/services/volume/v2/json/admin/volume_hosts_client.py
@@ -1,4 +1,4 @@
-# Copyright 2014 IBM Corp.
+# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -13,12 +13,16 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.services.volume.xml import extensions_client
+
+from tempest.services.volume.json.admin import volume_hosts_client
-class ExtensionsV2ClientXML(extensions_client.BaseExtensionsClientXML):
+class VolumeHostsV2ClientJSON(volume_hosts_client.BaseVolumeHostsClientJSON):
+ """
+ Client class to send CRUD Volume V2 API requests to a Cinder endpoint
+ """
def __init__(self, auth_provider):
- super(ExtensionsV2ClientXML, self).__init__(auth_provider)
+ super(VolumeHostsV2ClientJSON, self).__init__(auth_provider)
self.api_version = "v2"
diff --git a/tempest/services/volume/v2/xml/extensions_client.py b/tempest/services/volume/v2/json/admin/volume_quotas_client.py
similarity index 66%
copy from tempest/services/volume/v2/xml/extensions_client.py
copy to tempest/services/volume/v2/json/admin/volume_quotas_client.py
index 13f333c..64f4f33 100644
--- a/tempest/services/volume/v2/xml/extensions_client.py
+++ b/tempest/services/volume/v2/json/admin/volume_quotas_client.py
@@ -1,4 +1,4 @@
-# Copyright 2014 IBM Corp.
+# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -13,12 +13,15 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.services.volume.xml import extensions_client
+from tempest.services.volume.json.admin import volume_quotas_client
-class ExtensionsV2ClientXML(extensions_client.BaseExtensionsClientXML):
+class VolumeQuotasV2Client(volume_quotas_client.BaseVolumeQuotasClientJSON):
+ """
+ Client class to send CRUD Volume V2 API requests to a Cinder endpoint
+ """
def __init__(self, auth_provider):
- super(ExtensionsV2ClientXML, self).__init__(auth_provider)
+ super(VolumeQuotasV2Client, self).__init__(auth_provider)
self.api_version = "v2"
diff --git a/tempest/services/volume/xml/backups_client.py b/tempest/services/volume/v2/json/backups_client.py
similarity index 72%
rename from tempest/services/volume/xml/backups_client.py
rename to tempest/services/volume/v2/json/backups_client.py
index a691a25..9698075 100644
--- a/tempest/services/volume/xml/backups_client.py
+++ b/tempest/services/volume/v2/json/backups_client.py
@@ -16,11 +16,11 @@
from tempest.services.volume.json import backups_client
-class BackupsClientXML(backups_client.BackupsClientJSON):
+class BackupsClientV2JSON(backups_client.BaseBackupsClientJSON):
"""
- Client class to send CRUD Volume Backup API requests to a Cinder endpoint
+ Client class to send CRUD Volume V2 API requests to a Cinder endpoint
"""
- TYPE = "xml"
- # TODO(gfidente): XML client isn't yet implemented because of bug 1270589
- pass
+ def __init__(self, auth_provider):
+ super(BackupsClientV2JSON, self).__init__(auth_provider)
+ self.api_version = "v2"
diff --git a/tempest/services/volume/v2/xml/__init__.py b/tempest/services/volume/v2/xml/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/volume/v2/xml/__init__.py
+++ /dev/null
diff --git a/tempest/services/volume/v2/xml/availability_zone_client.py b/tempest/services/volume/v2/xml/availability_zone_client.py
deleted file mode 100644
index 68ca39b..0000000
--- a/tempest/services/volume/v2/xml/availability_zone_client.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2014 IBM Corp.
-# 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.services.volume.xml import availability_zone_client
-
-
-class VolumeV2AvailabilityZoneClientXML(
- availability_zone_client.BaseVolumeAvailabilityZoneClientXML):
-
- def __init__(self, auth_provider):
- super(VolumeV2AvailabilityZoneClientXML, self).__init__(
- auth_provider)
-
- self.api_version = "v2"
diff --git a/tempest/services/volume/v2/xml/snapshots_client.py b/tempest/services/volume/v2/xml/snapshots_client.py
deleted file mode 100644
index b29d86c..0000000
--- a/tempest/services/volume/v2/xml/snapshots_client.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.services.volume.xml import snapshots_client
-
-
-class SnapshotsV2ClientXML(snapshots_client.BaseSnapshotsClientXML):
- """Client class to send CRUD Volume V2 API requests."""
-
- def __init__(self, auth_provider):
- super(SnapshotsV2ClientXML, self).__init__(auth_provider)
-
- self.api_version = "v2"
- self.create_resp = 202
diff --git a/tempest/services/volume/v2/xml/volumes_client.py b/tempest/services/volume/v2/xml/volumes_client.py
deleted file mode 100644
index b3133af..0000000
--- a/tempest/services/volume/v2/xml/volumes_client.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright 2012 IBM Corp.
-# 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 urllib
-
-from lxml import etree
-
-from tempest.common import xml_utils as common
-from tempest.services.volume.xml import volumes_client
-
-
-class VolumesV2ClientXML(volumes_client.BaseVolumesClientXML):
- """
- Client class to send CRUD Volume API V2 requests to a Cinder endpoint
- """
-
- def __init__(self, auth_provider):
- super(VolumesV2ClientXML, self).__init__(auth_provider)
-
- self.api_version = "v2"
- self.create_resp = 202
-
- def _parse_volume(self, body):
- vol = dict((attr, body.get(attr)) for attr in body.keys())
-
- for child in body.getchildren():
- tag = child.tag
- if tag.startswith("{"):
- ns, tag = tag.split("}", 1)
- if tag == 'metadata':
- vol['metadata'] = dict((meta.get('key'),
- meta.text) for meta in
- child.getchildren())
- else:
- vol[tag] = common.xml_to_json(child)
- self._translate_attributes_to_json(vol)
- return vol
-
- def list_volumes_with_detail(self, params=None):
- """List all the details of volumes."""
- url = 'volumes/detail'
-
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = etree.fromstring(body)
- volumes = []
- if body is not None:
- volumes += [self._parse_volume(vol) for vol in list(body)]
- for v in volumes:
- v = self._check_if_bootable(v)
- self.expected_success(200, resp.status)
- return resp, volumes
-
- def get_volume(self, volume_id):
- """Returns the details of a single volume."""
- url = "volumes/%s" % str(volume_id)
- resp, body = self.get(url)
- body = self._parse_volume(etree.fromstring(body))
- body = self._check_if_bootable(body)
- self.expected_success(200, resp.status)
- return resp, body
diff --git a/tempest/services/volume/xml/__init__.py b/tempest/services/volume/xml/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/volume/xml/__init__.py
+++ /dev/null
diff --git a/tempest/services/volume/xml/admin/__init__.py b/tempest/services/volume/xml/admin/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/volume/xml/admin/__init__.py
+++ /dev/null
diff --git a/tempest/services/volume/xml/admin/volume_hosts_client.py b/tempest/services/volume/xml/admin/volume_hosts_client.py
deleted file mode 100644
index 98a7c58..0000000
--- a/tempest/services/volume/xml/admin/volume_hosts_client.py
+++ /dev/null
@@ -1,74 +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 urllib
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils as common
-from tempest import config
-
-CONF = config.CONF
-
-
-class VolumeHostsClientXML(rest_client.RestClient):
- """
- Client class to send CRUD Volume Hosts API requests to a Cinder endpoint
- """
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(VolumeHostsClientXML, self).__init__(auth_provider)
- self.service = CONF.volume.catalog_type
- self.build_interval = CONF.compute.build_interval
- self.build_timeout = CONF.compute.build_timeout
-
- def _parse_array(self, node):
- """
- This method is to parse the "list" response body
- Eg:
-
- <?xml version='1.0' encoding='UTF-8'?>
- <hosts>
- <host service-status="available" service="cinder-scheduler"/>
- <host service-status="available" service="cinder-volume"/>
- </hosts>
-
- This method will append the details of specified tag,
- here it is "host"
- Return value would be list of hosts as below
-
- [{'service-status': 'available', 'service': 'cinder-scheduler'},
- {'service-status': 'available', 'service': 'cinder-volume'}]
- """
- array = []
- for child in node.getchildren():
- tag_list = child.tag.split('}', 1)
- if tag_list[0] == "host":
- array.append(common.xml_to_json(child))
- return array
-
- def list_hosts(self, params=None):
- """List all the hosts."""
- url = 'os-hosts'
-
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- self.expected_success(200, resp.status)
- body = self._parse_array(etree.fromstring(body))
- return resp, body
diff --git a/tempest/services/volume/xml/admin/volume_quotas_client.py b/tempest/services/volume/xml/admin/volume_quotas_client.py
deleted file mode 100644
index acf9102..0000000
--- a/tempest/services/volume/xml/admin/volume_quotas_client.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
-#
-# Author: Sylvain Baubeau <sylvain.baubeau@enovance.com>
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import ast
-
-from lxml import etree
-
-from tempest.common import xml_utils as xml
-from tempest import config
-from tempest.services.volume.json.admin import volume_quotas_client
-
-CONF = config.CONF
-
-
-class VolumeQuotasClientXML(volume_quotas_client.VolumeQuotasClientJSON):
- """
- Client class to send CRUD Volume Quotas API requests to a Cinder endpoint
- """
-
- TYPE = "xml"
-
- def _format_quota(self, q):
- quota = {}
- for k, v in q.items():
- try:
- v = ast.literal_eval(v)
- except (ValueError, SyntaxError):
- pass
-
- quota[k] = v
-
- return quota
-
- def get_quota_usage(self, tenant_id):
- """List the quota set for a tenant."""
-
- resp, body = self.get_quota_set(tenant_id, params={'usage': True})
- self.expected_success(200, resp.status)
- return resp, self._format_quota(body)
-
- def update_quota_set(self, tenant_id, gigabytes=None, volumes=None,
- snapshots=None):
- post_body = {}
- element = xml.Element("quota_set")
-
- if gigabytes is not None:
- post_body['gigabytes'] = gigabytes
-
- if volumes is not None:
- post_body['volumes'] = volumes
-
- if snapshots is not None:
- post_body['snapshots'] = snapshots
-
- xml.deep_dict_to_xml(element, post_body)
- resp, body = self.put('os-quota-sets/%s' % tenant_id,
- str(xml.Document(element)))
- body = xml.xml_to_json(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, self._format_quota(body)
-
- def delete_quota_set(self, tenant_id):
- """Delete the tenant's quota set."""
- resp, body = self.delete('os-quota-sets/%s' % tenant_id)
- self.expected_success(200, resp.status)
diff --git a/tempest/services/volume/xml/admin/volume_services_client.py b/tempest/services/volume/xml/admin/volume_services_client.py
deleted file mode 100644
index 2ecb590..0000000
--- a/tempest/services/volume/xml/admin/volume_services_client.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2014 NEC Corporation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import urllib
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-
-CONF = config.CONF
-
-
-class VolumesServicesClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(VolumesServicesClientXML, self).__init__(auth_provider)
- self.service = CONF.volume.catalog_type
-
- def list_services(self, params=None):
- url = 'os-services'
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- node = etree.fromstring(body)
- body = [xml_utils.xml_to_json(x) for x in node.getchildren()]
- self.expected_success(200, resp.status)
- return resp, body
diff --git a/tempest/services/volume/xml/admin/volume_types_client.py b/tempest/services/volume/xml/admin/volume_types_client.py
deleted file mode 100644
index 2464016..0000000
--- a/tempest/services/volume/xml/admin/volume_types_client.py
+++ /dev/null
@@ -1,212 +0,0 @@
-# Copyright 2012 IBM Corp.
-# 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 urllib
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils as common
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
-
-
-class VolumeTypesClientXML(rest_client.RestClient):
- """
- Client class to send CRUD Volume Types API requests to a Cinder endpoint
- """
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(VolumeTypesClientXML, self).__init__(auth_provider)
- self.service = CONF.volume.catalog_type
- self.build_interval = CONF.compute.build_interval
- self.build_timeout = CONF.compute.build_timeout
-
- def _parse_volume_type(self, body):
- vol_type = dict((attr, body.get(attr)) for attr in body.keys())
-
- for child in body.getchildren():
- tag = child.tag
- if tag.startswith("{"):
- ns, tag = tag.split("}", 1)
- if tag == 'extra_specs':
- vol_type['extra_specs'] = dict((meta.get('key'),
- meta.text)
- for meta in list(child))
- else:
- vol_type[tag] = common.xml_to_json(child)
- return vol_type
-
- def _parse_volume_type_extra_specs(self, body):
- extra_spec = dict((attr, body.get(attr)) for attr in body.keys())
-
- for child in body.getchildren():
- tag = child.tag
- if tag.startswith("{"):
- ns, tag = tag.split("}", 1)
- else:
- extra_spec[tag] = common.xml_to_json(child)
- return extra_spec
-
- def list_volume_types(self, params=None):
- """List all the volume_types created."""
- url = 'types'
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = etree.fromstring(body)
- volume_types = []
- if body is not None:
- volume_types += [self._parse_volume_type(vol)
- for vol in list(body)]
- self.expected_success(200, resp.status)
- return resp, volume_types
-
- def get_volume_type(self, type_id):
- """Returns the details of a single volume_type."""
- url = "types/%s" % str(type_id)
- resp, body = self.get(url)
- body = etree.fromstring(body)
- self.expected_success(200, resp.status)
- return resp, self._parse_volume_type(body)
-
- def create_volume_type(self, name, **kwargs):
- """
- Creates a new Volume_type.
- name(Required): Name of volume_type.
- Following optional keyword arguments are accepted:
- extra_specs: A dictionary of values to be used as extra_specs.
- """
- vol_type = common.Element("volume_type", xmlns=common.XMLNS_11)
- if name:
- vol_type.add_attr('name', name)
-
- extra_specs = kwargs.get('extra_specs')
- if extra_specs:
- _extra_specs = common.Element('extra_specs')
- vol_type.append(_extra_specs)
- for key, value in extra_specs.items():
- spec = common.Element('extra_spec')
- spec.add_attr('key', key)
- spec.append(common.Text(value))
- _extra_specs.append(spec)
-
- resp, body = self.post('types', str(common.Document(vol_type)))
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
- def delete_volume_type(self, type_id):
- """Deletes the Specified Volume_type."""
- resp, body = self.delete("types/%s" % str(type_id))
- self.expected_success(202, resp.status)
-
- def list_volume_types_extra_specs(self, vol_type_id, params=None):
- """List all the volume_types extra specs created."""
- url = 'types/%s/extra_specs' % str(vol_type_id)
-
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = etree.fromstring(body)
- extra_specs = []
- if body is not None:
- extra_specs += [self._parse_volume_type_extra_specs(spec)
- for spec in list(body)]
- self.expected_success(200, resp.status)
- return resp, extra_specs
-
- def get_volume_type_extra_specs(self, vol_type_id, extra_spec_name):
- """Returns the details of a single volume_type extra spec."""
- url = "types/%s/extra_specs/%s" % (str(vol_type_id),
- str(extra_spec_name))
- resp, body = self.get(url)
- body = etree.fromstring(body)
- self.expected_success(200, resp.status)
- return resp, self._parse_volume_type_extra_specs(body)
-
- def create_volume_type_extra_specs(self, vol_type_id, extra_spec):
- """
- Creates a new Volume_type extra spec.
- vol_type_id: Id of volume_type.
- extra_specs: A dictionary of values to be used as extra_specs.
- """
- url = "types/%s/extra_specs" % str(vol_type_id)
- extra_specs = common.Element("extra_specs", xmlns=common.XMLNS_11)
- if extra_spec:
- if isinstance(extra_spec, list):
- extra_specs.append(extra_spec)
- else:
- for key, value in extra_spec.items():
- spec = common.Element('extra_spec')
- spec.add_attr('key', key)
- spec.append(common.Text(value))
- extra_specs.append(spec)
- else:
- extra_specs = None
-
- resp, body = self.post(url, str(common.Document(extra_specs)))
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
- def delete_volume_type_extra_specs(self, vol_id, extra_spec_name):
- """Deletes the Specified Volume_type extra spec."""
- resp, body = self.delete("types/%s/extra_specs/%s" % (
- (str(vol_id)), str(extra_spec_name)))
- self.expected_success(202, resp.status)
- return resp, body
-
- def update_volume_type_extra_specs(self, vol_type_id, extra_spec_name,
- extra_spec):
- """
- Update a volume_type extra spec.
- vol_type_id: Id of volume_type.
- 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.
- """
- url = "types/%s/extra_specs/%s" % (str(vol_type_id),
- str(extra_spec_name))
- extra_specs = common.Element("extra_specs", xmlns=common.XMLNS_11)
-
- if extra_spec is not None:
- for key, value in extra_spec.items():
- spec = common.Element('extra_spec')
- spec.add_attr('key', key)
- spec.append(common.Text(value))
- extra_specs.append(spec)
-
- resp, body = self.put(url, str(common.Document(extra_specs)))
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
- def is_resource_deleted(self, id):
- try:
- self.get_volume_type(id)
- except exceptions.NotFound:
- return True
- return False
-
- @property
- def resource_type(self):
- """Returns the primary type of resource this client works with."""
- return 'volume-type'
diff --git a/tempest/services/volume/xml/availability_zone_client.py b/tempest/services/volume/xml/availability_zone_client.py
deleted file mode 100644
index b956d3f..0000000
--- a/tempest/services/volume/xml/availability_zone_client.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright 2014 NEC Corporation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils
-from tempest import config
-
-CONF = config.CONF
-
-
-class BaseVolumeAvailabilityZoneClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(BaseVolumeAvailabilityZoneClientXML, self).__init__(
- auth_provider)
- self.service = CONF.volume.catalog_type
-
- def _parse_array(self, node):
- return [xml_utils.xml_to_json(x) for x in node]
-
- def get_availability_zone_list(self):
- resp, body = self.get('os-availability-zone')
- availability_zone = self._parse_array(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, availability_zone
-
-
-class VolumeAvailabilityZoneClientXML(BaseVolumeAvailabilityZoneClientXML):
- """
- Volume V1 availability zone client.
- """
diff --git a/tempest/services/volume/xml/extensions_client.py b/tempest/services/volume/xml/extensions_client.py
deleted file mode 100644
index f2b2e02..0000000
--- a/tempest/services/volume/xml/extensions_client.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils as common
-from tempest import config
-
-CONF = config.CONF
-
-
-class BaseExtensionsClientXML(rest_client.RestClient):
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(BaseExtensionsClientXML, self).__init__(auth_provider)
- self.service = CONF.volume.catalog_type
-
- def _parse_array(self, node):
- array = []
- for child in node:
- array.append(common.xml_to_json(child))
- return array
-
- def list_extensions(self):
- url = 'extensions'
- resp, body = self.get(url)
- body = self._parse_array(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
-
-class ExtensionsClientXML(BaseExtensionsClientXML):
- """
- Volume V1 extensions client.
- """
diff --git a/tempest/services/volume/xml/snapshots_client.py b/tempest/services/volume/xml/snapshots_client.py
deleted file mode 100644
index fb591b1..0000000
--- a/tempest/services/volume/xml/snapshots_client.py
+++ /dev/null
@@ -1,255 +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 lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils as common
-from tempest import config
-from tempest import exceptions
-from tempest.openstack.common import log as logging
-
-CONF = config.CONF
-
-LOG = logging.getLogger(__name__)
-
-
-class BaseSnapshotsClientXML(rest_client.RestClient):
- """Base Client class to send CRUD Volume API requests."""
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(BaseSnapshotsClientXML, 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
-
- def list_snapshots(self, params=None):
- """List all snapshot."""
- url = 'snapshots'
-
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = etree.fromstring(body)
- snapshots = []
- for snap in body:
- snapshots.append(common.xml_to_json(snap))
- self.expected_success(200, resp.status)
- return resp, snapshots
-
- def list_snapshots_with_detail(self, params=None):
- """List all the details of snapshot."""
- url = 'snapshots/detail'
-
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = etree.fromstring(body)
- snapshots = []
- for snap in body:
- snapshots.append(common.xml_to_json(snap))
- self.expected_success(200, resp.status)
- return resp, snapshots
-
- def get_snapshot(self, snapshot_id):
- """Returns the details of a single snapshot."""
- url = "snapshots/%s" % str(snapshot_id)
- resp, body = self.get(url)
- body = etree.fromstring(body)
- self.expected_success(200, resp.status)
- return resp, common.xml_to_json(body)
-
- def create_snapshot(self, volume_id, **kwargs):
- """Creates a new snapshot.
- volume_id(Required): id of the volume.
- force: Create a snapshot even if the volume attached (Default=False)
- display_name: Optional snapshot Name.
- display_description: User friendly snapshot description.
- """
- # NOTE(afazekas): it should use the volume namespace
- snapshot = common.Element("snapshot", xmlns=common.XMLNS_11,
- volume_id=volume_id)
- for key, value in kwargs.items():
- snapshot.add_attr(key, value)
- resp, body = self.post('snapshots',
- str(common.Document(snapshot)))
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(self.create_resp, resp.status)
- return resp, body
-
- def update_snapshot(self, snapshot_id, **kwargs):
- """Updates a snapshot."""
- put_body = common.Element("snapshot", xmlns=common.XMLNS_11, **kwargs)
-
- resp, body = self.put('snapshots/%s' % snapshot_id,
- str(common.Document(put_body)))
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
- # NOTE(afazekas): just for the wait function
- def _get_snapshot_status(self, snapshot_id):
- resp, body = self.get_snapshot(snapshot_id)
- status = body['status']
- # NOTE(afazekas): snapshot can reach an "error"
- # state in a "normal" lifecycle
- if (status == 'error'):
- raise exceptions.SnapshotBuildErrorException(
- snapshot_id=snapshot_id)
-
- return status
-
- # NOTE(afazkas): Wait reinvented again. It is not in the correct layer
- def wait_for_snapshot_status(self, snapshot_id, status):
- """Waits for a Snapshot to reach a given status."""
- start_time = time.time()
- old_value = value = self._get_snapshot_status(snapshot_id)
- while True:
- dtime = time.time() - start_time
- time.sleep(self.build_interval)
- if value != old_value:
- LOG.info('Value transition from "%s" to "%s"'
- 'in %d second(s).', old_value,
- value, dtime)
- if (value == status):
- return value
-
- if dtime > self.build_timeout:
- message = ('Time Limit Exceeded! (%ds)'
- 'while waiting for %s, '
- 'but we got %s.' %
- (self.build_timeout, status, value))
- raise exceptions.TimeoutException(message)
- time.sleep(self.build_interval)
- old_value = value
- value = self._get_snapshot_status(snapshot_id)
-
- def delete_snapshot(self, snapshot_id):
- """Delete Snapshot."""
- resp, body = self.delete("snapshots/%s" % str(snapshot_id))
- self.expected_success(202, resp.status)
-
- def is_resource_deleted(self, id):
- try:
- self.get_snapshot(id)
- except exceptions.NotFound:
- return True
- return False
-
- @property
- def resource_type(self):
- """Returns the primary type of resource this client works with."""
- return 'volume-snapshot'
-
- def reset_snapshot_status(self, snapshot_id, status):
- """Reset the specified snapshot's status."""
- post_body = common.Element("os-reset_status", status=status)
- url = 'snapshots/%s/action' % str(snapshot_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- if body:
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, body
-
- def update_snapshot_status(self, snapshot_id, status, progress):
- """Update the specified snapshot's status."""
- post_body = common.Element("os-update_snapshot_status",
- status=status,
- progress=progress
- )
- url = 'snapshots/%s/action' % str(snapshot_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- if body:
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, body
-
- def _metadata_body(self, meta):
- post_body = common.Element('metadata')
- for k, v in meta.items():
- data = common.Element('meta', key=k)
- data.append(common.Text(v))
- post_body.append(data)
- return post_body
-
- def _parse_key_value(self, node):
- """Parse <foo key='key'>value</foo> data into {'key': 'value'}."""
- data = {}
- for node in node.getchildren():
- data[node.get('key')] = node.text
- return data
-
- def create_snapshot_metadata(self, snapshot_id, metadata):
- """Create metadata for the snapshot."""
- post_body = self._metadata_body(metadata)
- resp, body = self.post('snapshots/%s/metadata' % snapshot_id,
- str(common.Document(post_body)))
- body = self._parse_key_value(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
- def get_snapshot_metadata(self, snapshot_id):
- """Get metadata of the snapshot."""
- url = "snapshots/%s/metadata" % str(snapshot_id)
- resp, body = self.get(url)
- body = self._parse_key_value(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
- def update_snapshot_metadata(self, snapshot_id, metadata):
- """Update metadata for the snapshot."""
- put_body = self._metadata_body(metadata)
- url = "snapshots/%s/metadata" % str(snapshot_id)
- resp, body = self.put(url, str(common.Document(put_body)))
- body = self._parse_key_value(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
- def update_snapshot_metadata_item(self, snapshot_id, id, meta_item):
- """Update metadata item for the snapshot."""
- for k, v in meta_item.items():
- put_body = common.Element('meta', key=k)
- put_body.append(common.Text(v))
- url = "snapshots/%s/metadata/%s" % (str(snapshot_id), str(id))
- resp, body = self.put(url, str(common.Document(put_body)))
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
- def delete_snapshot_metadata_item(self, snapshot_id, id):
- """Delete metadata item for the snapshot."""
- url = "snapshots/%s/metadata/%s" % (str(snapshot_id), str(id))
- resp, body = self.delete(url)
- self.expected_success(200, resp.status)
- return resp, body
-
- def force_delete_snapshot(self, snapshot_id):
- """Force Delete Snapshot."""
- post_body = common.Element("os-force_delete")
- url = 'snapshots/%s/action' % str(snapshot_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- if body:
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, body
-
-
-class SnapshotsClientXML(BaseSnapshotsClientXML):
- """Client class to send CRUD Volume V1 API requests."""
diff --git a/tempest/services/volume/xml/volumes_client.py b/tempest/services/volume/xml/volumes_client.py
deleted file mode 100644
index 0fe7e0d..0000000
--- a/tempest/services/volume/xml/volumes_client.py
+++ /dev/null
@@ -1,472 +0,0 @@
-# Copyright 2012 IBM Corp.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import time
-import urllib
-from xml.sax import saxutils
-
-from lxml import etree
-
-from tempest.common import rest_client
-from tempest.common import xml_utils as common
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
-
-VOLUME_NS_BASE = 'http://docs.openstack.org/volume/ext/'
-VOLUME_HOST_NS = VOLUME_NS_BASE + 'volume_host_attribute/api/v1'
-VOLUME_MIG_STATUS_NS = VOLUME_NS_BASE + 'volume_mig_status_attribute/api/v1'
-VOLUMES_TENANT_NS = VOLUME_NS_BASE + 'volume_tenant_attribute/api/v1'
-
-
-class BaseVolumesClientXML(rest_client.RestClient):
- """
- Base client class to send CRUD Volume API requests to a Cinder endpoint
- """
- TYPE = "xml"
-
- def __init__(self, auth_provider):
- super(BaseVolumesClientXML, self).__init__(auth_provider)
- self.service = CONF.volume.catalog_type
- self.build_interval = CONF.compute.build_interval
- self.build_timeout = CONF.compute.build_timeout
- self.create_resp = 200
-
- def _translate_attributes_to_json(self, volume):
- volume_host_attr = '{' + VOLUME_HOST_NS + '}host'
- volume_mig_stat_attr = '{' + VOLUME_MIG_STATUS_NS + '}migstat'
- volume_mig_name_attr = '{' + VOLUME_MIG_STATUS_NS + '}name_id'
- volume_tenant_id_attr = '{' + VOLUMES_TENANT_NS + '}tenant_id'
- if volume_host_attr in volume:
- volume['os-vol-host-attr:host'] = volume.pop(volume_host_attr)
- if volume_mig_stat_attr in volume:
- volume['os-vol-mig-status-attr:migstat'] = volume.pop(
- volume_mig_stat_attr)
- if volume_mig_name_attr in volume:
- volume['os-vol-mig-status-attr:name_id'] = volume.pop(
- volume_mig_name_attr)
- if volume_tenant_id_attr in volume:
- volume['os-vol-tenant-attr:tenant_id'] = volume.pop(
- volume_tenant_id_attr)
-
- def _parse_volume(self, body):
- vol = dict((attr, body.get(attr)) for attr in body.keys())
-
- for child in body.getchildren():
- tag = child.tag
- if tag.startswith("{"):
- ns, tag = tag.split("}", 1)
- if tag == 'metadata':
- vol['metadata'] = dict((meta.get('key'),
- meta.text) for meta in
- child.getchildren())
- else:
- vol[tag] = common.xml_to_json(child)
- self._translate_attributes_to_json(vol)
- self._check_if_bootable(vol)
- return vol
-
- def get_attachment_from_volume(self, volume):
- """Return the element 'attachment' from input volumes."""
- return volume['attachments']['attachment']
-
- def _check_if_bootable(self, volume):
- """
- Check if the volume is bootable, also change the value
- of 'bootable' from string to boolean.
- """
-
- # NOTE(jdg): Version 1 of Cinder API uses lc strings
- # We should consider being explicit in this check to
- # avoid introducing bugs like: LP #1227837
-
- if volume['bootable'].lower() == 'true':
- volume['bootable'] = True
- elif volume['bootable'].lower() == 'false':
- volume['bootable'] = False
- else:
- raise ValueError(
- 'bootable flag is supposed to be either True or False,'
- 'it is %s' % volume['bootable'])
- return volume
-
- def list_volumes(self, params=None):
- """List all the volumes created."""
- url = 'volumes'
-
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = etree.fromstring(body)
- volumes = []
- if body is not None:
- volumes += [self._parse_volume(vol) for vol in list(body)]
- self.expected_success(200, resp.status)
- return resp, volumes
-
- def list_volumes_with_detail(self, params=None):
- """List all the details of volumes."""
- url = 'volumes/detail'
-
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = etree.fromstring(body)
- volumes = []
- if body is not None:
- volumes += [self._parse_volume(vol) for vol in list(body)]
- self.expected_success(200, resp.status)
- return resp, volumes
-
- def get_volume(self, volume_id):
- """Returns the details of a single volume."""
- url = "volumes/%s" % str(volume_id)
- resp, body = self.get(url)
- body = self._parse_volume(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
- def create_volume(self, size=None, **kwargs):
- """Creates a new Volume.
-
- :param size: Size of volume in GB.
- :param display_name: Optional Volume Name(only for V1).
- :param name: Optional Volume Name(only for V2).
- :param display_name: Optional Volume Name.
- :param metadata: An optional dictionary of values for metadata.
- :param volume_type: Optional Name of volume_type for the volume
- :param snapshot_id: When specified the volume is created from
- this snapshot
- :param imageRef: When specified the volume is created from this
- image
- """
- # for bug #1293885:
- # If no size specified, read volume size from CONF
- if size is None:
- size = CONF.volume.volume_size
- # NOTE(afazekas): it should use a volume namespace
- volume = common.Element("volume", xmlns=common.XMLNS_11, size=size)
-
- if 'metadata' in kwargs:
- _metadata = common.Element('metadata')
- volume.append(_metadata)
- for key, value in kwargs['metadata'].items():
- meta = common.Element('meta')
- meta.add_attr('key', key)
- meta.append(common.Text(value))
- _metadata.append(meta)
- attr_to_add = kwargs.copy()
- del attr_to_add['metadata']
- else:
- attr_to_add = kwargs
-
- for key, value in attr_to_add.items():
- volume.add_attr(key, value)
-
- resp, body = self.post('volumes', str(common.Document(volume)))
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(self.create_resp, resp.status)
- return resp, body
-
- def update_volume(self, volume_id, **kwargs):
- """Updates the Specified Volume."""
- put_body = common.Element("volume", xmlns=common.XMLNS_11, **kwargs)
-
- resp, body = self.put('volumes/%s' % volume_id,
- str(common.Document(put_body)))
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
- def delete_volume(self, volume_id):
- """Deletes the Specified Volume."""
- resp, body = self.delete("volumes/%s" % str(volume_id))
- self.expected_success(202, resp.status)
- return resp, body
-
- def wait_for_volume_status(self, volume_id, status):
- """Waits for a Volume to reach a given status."""
- resp, body = self.get_volume(volume_id)
- volume_status = body['status']
- start = int(time.time())
-
- while volume_status != status:
- time.sleep(self.build_interval)
- resp, body = self.get_volume(volume_id)
- volume_status = body['status']
- if volume_status == 'error':
- raise exceptions.VolumeBuildErrorException(volume_id=volume_id)
-
- if int(time.time()) - start >= self.build_timeout:
- message = 'Volume %s failed to reach %s status within '\
- 'the required time (%s s).' % (volume_id,
- status,
- self.build_timeout)
- raise exceptions.TimeoutException(message)
-
- def is_resource_deleted(self, id):
- try:
- self.get_volume(id)
- except exceptions.NotFound:
- return True
- return False
-
- @property
- def resource_type(self):
- """Returns the primary type of resource this client works with."""
- return 'volume'
-
- def attach_volume(self, volume_id, instance_uuid, mountpoint):
- """Attaches a volume to a given instance on a given mountpoint."""
- post_body = common.Element("os-attach",
- instance_uuid=instance_uuid,
- mountpoint=mountpoint
- )
- url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- if body:
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, body
-
- def detach_volume(self, volume_id):
- """Detaches a volume from an instance."""
- post_body = common.Element("os-detach")
- url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- if body:
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, body
-
- def upload_volume(self, volume_id, image_name, disk_format):
- """Uploads a volume in Glance."""
- post_body = common.Element("os-volume_upload_image",
- image_name=image_name,
- disk_format=disk_format)
- url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- volume = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, volume
-
- def extend_volume(self, volume_id, extend_size):
- """Extend a volume."""
- post_body = common.Element("os-extend",
- new_size=extend_size)
- url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- if body:
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, body
-
- def reset_volume_status(self, volume_id, status):
- """Reset the Specified Volume's Status."""
- post_body = common.Element("os-reset_status",
- status=status
- )
- url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- if body:
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, body
-
- def volume_begin_detaching(self, volume_id):
- """Volume Begin Detaching."""
- post_body = common.Element("os-begin_detaching")
- url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- if body:
- body = common.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def volume_roll_detaching(self, volume_id):
- """Volume Roll Detaching."""
- post_body = common.Element("os-roll_detaching")
- url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- if body:
- body = common.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def reserve_volume(self, volume_id):
- """Reserves a volume."""
- post_body = common.Element("os-reserve")
- url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- if body:
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, body
-
- def unreserve_volume(self, volume_id):
- """Restore a reserved volume ."""
- post_body = common.Element("os-unreserve")
- url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- if body:
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, body
-
- def create_volume_transfer(self, vol_id, display_name=None):
- """Create a volume transfer."""
- post_body = common.Element("transfer",
- volume_id=vol_id)
- if display_name:
- post_body.add_attr('name', display_name)
- resp, body = self.post('os-volume-transfer',
- str(common.Document(post_body)))
- volume = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, volume
-
- def get_volume_transfer(self, transfer_id):
- """Returns the details of a volume transfer."""
- url = "os-volume-transfer/%s" % str(transfer_id)
- resp, body = self.get(url)
- volume = common.xml_to_json(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, volume
-
- def list_volume_transfers(self, params=None):
- """List all the volume transfers created."""
- url = 'os-volume-transfer'
- if params:
- url += '?%s' % urllib.urlencode(params)
-
- resp, body = self.get(url)
- body = etree.fromstring(body)
- volumes = []
- if body is not None:
- volumes += [self._parse_volume_transfer(vol) for vol in list(body)]
- self.expected_success(200, resp.status)
- return resp, volumes
-
- def _parse_volume_transfer(self, body):
- vol = dict((attr, body.get(attr)) for attr in body.keys())
- for child in body.getchildren():
- tag = child.tag
- if tag.startswith("{"):
- tag = tag.split("}", 1)
- vol[tag] = common.xml_to_json(child)
- return vol
-
- def delete_volume_transfer(self, transfer_id):
- """Delete a volume transfer."""
- resp, body = self.delete("os-volume-transfer/%s" % str(transfer_id))
- self.expected_success(202, resp.status)
- return resp, body
-
- def accept_volume_transfer(self, transfer_id, transfer_auth_key):
- """Accept a volume transfer."""
- post_body = common.Element("accept", auth_key=transfer_auth_key)
- url = 'os-volume-transfer/%s/accept' % transfer_id
- resp, body = self.post(url, str(common.Document(post_body)))
- volume = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, volume
-
- def update_volume_readonly(self, volume_id, readonly):
- """Update the Specified Volume readonly."""
- post_body = common.Element("os-update_readonly_flag",
- readonly=readonly)
- url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- if body:
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, body
-
- def force_delete_volume(self, volume_id):
- """Force Delete Volume."""
- post_body = common.Element("os-force_delete")
- url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(common.Document(post_body)))
- if body:
- body = common.xml_to_json(etree.fromstring(body))
- self.expected_success(202, resp.status)
- return resp, body
-
- def _metadata_body(self, meta):
- post_body = common.Element('metadata')
- for k, v in meta.items():
- data = common.Element('meta', key=k)
- # Escape value to allow for special XML chars
- data.append(common.Text(saxutils.escape(v)))
- post_body.append(data)
- return post_body
-
- def _parse_key_value(self, node):
- """Parse <foo key='key'>value</foo> data into {'key': 'value'}."""
- data = {}
- for node in node.getchildren():
- data[node.get('key')] = node.text
- return data
-
- def create_volume_metadata(self, volume_id, metadata):
- """Create metadata for the volume."""
- post_body = self._metadata_body(metadata)
- resp, body = self.post('volumes/%s/metadata' % volume_id,
- str(common.Document(post_body)))
- body = self._parse_key_value(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
- def get_volume_metadata(self, volume_id):
- """Get metadata of the volume."""
- url = "volumes/%s/metadata" % str(volume_id)
- resp, body = self.get(url)
- body = self._parse_key_value(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
- def update_volume_metadata(self, volume_id, metadata):
- """Update metadata for the volume."""
- put_body = self._metadata_body(metadata)
- url = "volumes/%s/metadata" % str(volume_id)
- resp, body = self.put(url, str(common.Document(put_body)))
- body = self._parse_key_value(etree.fromstring(body))
- self.expected_success(200, resp.status)
- return resp, body
-
- def update_volume_metadata_item(self, volume_id, id, meta_item):
- """Update metadata item for the volume."""
- for k, v in meta_item.items():
- put_body = common.Element('meta', key=k)
- put_body.append(common.Text(v))
- url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
- resp, body = self.put(url, str(common.Document(put_body)))
- self.expected_success(200, resp.status)
- body = common.xml_to_json(etree.fromstring(body))
- return resp, body
-
- def delete_volume_metadata_item(self, volume_id, id):
- """Delete metadata item for the volume."""
- url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
- resp, body = self.delete(url)
- self.expected_success(200, resp.status)
- return resp, body
-
-
-class VolumesClientXML(BaseVolumesClientXML):
- """
- Client class to send CRUD Volume API V1 requests to a Cinder endpoint
- """
diff --git a/tempest/test.py b/tempest/test.py
index 1c6265d..7db0376 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -24,7 +24,6 @@
import uuid
import fixtures
-import testresources
import testscenarios
import testtools
@@ -222,23 +221,9 @@
atexit.register(validate_tearDownClass)
-if sys.version_info >= (2, 7):
- class BaseDeps(testtools.TestCase,
- testtools.testcase.WithAttributes,
- testresources.ResourcedTestCase):
- pass
-else:
- # Define asserts for py26
- import unittest2
- class BaseDeps(testtools.TestCase,
- testtools.testcase.WithAttributes,
- testresources.ResourcedTestCase,
- unittest2.TestCase):
- pass
-
-
-class BaseTestCase(BaseDeps):
+class BaseTestCase(testtools.testcase.WithAttributes,
+ testtools.TestCase):
setUpClassCalled = False
_service = None
@@ -342,10 +327,12 @@
"""
force_tenant_isolation = getattr(cls, 'force_tenant_isolation', None)
- cls.isolated_creds = credentials.get_isolated_credentials(
- name=cls.__name__, network_resources=cls.network_resources,
- force_tenant_isolation=force_tenant_isolation,
- )
+ if (not hasattr(cls, 'isolated_creds') or
+ not cls.isolated_creds.name == cls.__name__):
+ cls.isolated_creds = credentials.get_isolated_credentials(
+ name=cls.__name__, network_resources=cls.network_resources,
+ force_tenant_isolation=force_tenant_isolation,
+ )
creds = cls.isolated_creds.get_primary_creds()
params = dict(credentials=creds, service=cls._service)
@@ -427,12 +414,8 @@
else:
standard_tests, module, loader = args
for test in testtools.iterate_tests(standard_tests):
- schema_file = getattr(test, '_schema_file', None)
schema = getattr(test, '_schema', None)
- if schema_file is not None:
- setattr(test, 'scenarios',
- NegativeAutoTest.generate_scenario(schema_file))
- elif schema is not None:
+ if schema is not None:
setattr(test, 'scenarios',
NegativeAutoTest.generate_scenario(schema))
return testscenarios.load_tests_apply_scenarios(*args)
diff --git a/tempest/tests/cli/test_cli.py b/tempest/tests/cli/test_cli.py
index 1fd5ccb..8f18dfc 100644
--- a/tempest/tests/cli/test_cli.py
+++ b/tempest/tests/cli/test_cli.py
@@ -13,17 +13,25 @@
# under the License.
import mock
+from tempest_lib.cli import base as cli_base
import testtools
from tempest import cli
+from tempest import config
from tempest import exceptions
from tempest.tests import base
+from tempest.tests import fake_config
class TestMinClientVersion(base.TestCase):
"""Tests for the min_client_version decorator.
"""
+ def setUp(self):
+ super(TestMinClientVersion, self).setUp()
+ self.useFixture(fake_config.ConfigFixture())
+ self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+
def _test_min_version(self, required, installed, expect_skip):
@cli.min_client_version(client='nova', version=required)
@@ -33,7 +41,7 @@
# expected so we need to fail.
self.fail('Should not have gotten past the decorator.')
- with mock.patch.object(cli, 'execute',
+ with mock.patch.object(cli_base, 'execute',
return_value=installed) as mock_cmd:
if expect_skip:
self.assertRaises(testtools.TestCase.skipException, fake,
@@ -41,6 +49,7 @@
else:
fake(self, expect_skip)
mock_cmd.assert_called_once_with('nova', '', params='--version',
+ cli_dir='/usr/local/bin',
merge_stderr=True)
def test_min_client_version(self):
@@ -52,7 +61,7 @@
for case in cases:
self._test_min_version(*case)
- @mock.patch.object(cli, 'execute', return_value=' ')
+ @mock.patch.object(cli_base, 'execute', return_value=' ')
def test_check_client_version_empty_output(self, mock_execute):
# Tests that an exception is raised if the command output is empty.
self.assertRaises(exceptions.TempestException,
diff --git a/tempest/tests/cli/test_command_failed.py b/tempest/tests/cli/test_command_failed.py
deleted file mode 100644
index 36a4fc8..0000000
--- a/tempest/tests/cli/test_command_failed.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest import exceptions
-from tempest.tests import base
-
-
-class TestOutputParser(base.TestCase):
-
- def test_command_failed_exception(self):
- returncode = 1
- cmd = "foo"
- stdout = "output"
- stderr = "error"
- try:
- raise exceptions.CommandFailed(returncode, cmd, stdout, stderr)
- except exceptions.CommandFailed as e:
- self.assertIn(str(returncode), str(e))
- self.assertIn(cmd, str(e))
- self.assertIn(stdout, str(e))
- self.assertIn(stderr, str(e))
diff --git a/tempest/tests/cli/test_output_parser.py b/tempest/tests/cli/test_output_parser.py
deleted file mode 100644
index 7ad270c..0000000
--- a/tempest/tests/cli/test_output_parser.py
+++ /dev/null
@@ -1,177 +0,0 @@
-# Copyright 2014 NEC Corporation.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-from tempest.cli import output_parser
-from tempest import exceptions
-from tempest.tests import base
-
-
-class TestOutputParser(base.TestCase):
- OUTPUT_LINES = """
-+----+------+---------+
-| ID | Name | Status |
-+----+------+---------+
-| 11 | foo | BUILD |
-| 21 | bar | ERROR |
-| 31 | bee | None |
-+----+------+---------+
-"""
- OUTPUT_LINES2 = """
-+----+-------+---------+
-| ID | Name2 | Status2 |
-+----+-------+---------+
-| 41 | aaa | SSSSS |
-| 51 | bbb | TTTTT |
-| 61 | ccc | AAAAA |
-+----+-------+---------+
-"""
-
- EXPECTED_TABLE = {'headers': ['ID', 'Name', 'Status'],
- 'values': [['11', 'foo', 'BUILD'],
- ['21', 'bar', 'ERROR'],
- ['31', 'bee', 'None']]}
- EXPECTED_TABLE2 = {'headers': ['ID', 'Name2', 'Status2'],
- 'values': [['41', 'aaa', 'SSSSS'],
- ['51', 'bbb', 'TTTTT'],
- ['61', 'ccc', 'AAAAA']]}
-
- def test_table_with_normal_values(self):
- actual = output_parser.table(self.OUTPUT_LINES)
- self.assertIsInstance(actual, dict)
- self.assertEqual(self.EXPECTED_TABLE, actual)
-
- def test_table_with_list(self):
- output_lines = self.OUTPUT_LINES.split('\n')
- actual = output_parser.table(output_lines)
- self.assertIsInstance(actual, dict)
- self.assertEqual(self.EXPECTED_TABLE, actual)
-
- def test_table_with_invalid_line(self):
- output_lines = self.OUTPUT_LINES + "aaaa"
- actual = output_parser.table(output_lines)
- self.assertIsInstance(actual, dict)
- self.assertEqual(self.EXPECTED_TABLE, actual)
-
- def test_tables_with_normal_values(self):
- output_lines = 'test' + self.OUTPUT_LINES +\
- 'test2' + self.OUTPUT_LINES2
- expected = [{'headers': self.EXPECTED_TABLE['headers'],
- 'label': 'test',
- 'values': self.EXPECTED_TABLE['values']},
- {'headers': self.EXPECTED_TABLE2['headers'],
- 'label': 'test2',
- 'values': self.EXPECTED_TABLE2['values']}]
- actual = output_parser.tables(output_lines)
- self.assertIsInstance(actual, list)
- self.assertEqual(expected, actual)
-
- def test_tables_with_invalid_values(self):
- output_lines = 'test' + self.OUTPUT_LINES +\
- 'test2' + self.OUTPUT_LINES2 + '\n'
- expected = [{'headers': self.EXPECTED_TABLE['headers'],
- 'label': 'test',
- 'values': self.EXPECTED_TABLE['values']},
- {'headers': self.EXPECTED_TABLE2['headers'],
- 'label': 'test2',
- 'values': self.EXPECTED_TABLE2['values']}]
- actual = output_parser.tables(output_lines)
- self.assertIsInstance(actual, list)
- self.assertEqual(expected, actual)
-
- def test_tables_with_invalid_line(self):
- output_lines = 'test' + self.OUTPUT_LINES +\
- 'test2' + self.OUTPUT_LINES2 +\
- '+----+-------+---------+'
- expected = [{'headers': self.EXPECTED_TABLE['headers'],
- 'label': 'test',
- 'values': self.EXPECTED_TABLE['values']},
- {'headers': self.EXPECTED_TABLE2['headers'],
- 'label': 'test2',
- 'values': self.EXPECTED_TABLE2['values']}]
-
- actual = output_parser.tables(output_lines)
- self.assertIsInstance(actual, list)
- self.assertEqual(expected, actual)
-
- LISTING_OUTPUT = """
-+----+
-| ID |
-+----+
-| 11 |
-| 21 |
-| 31 |
-+----+
-"""
-
- def test_listing(self):
- expected = [{'ID': '11'}, {'ID': '21'}, {'ID': '31'}]
- actual = output_parser.listing(self.LISTING_OUTPUT)
- self.assertIsInstance(actual, list)
- self.assertEqual(expected, actual)
-
- def test_details_multiple_with_invalid_line(self):
- self.assertRaises(exceptions.InvalidStructure,
- output_parser.details_multiple,
- self.OUTPUT_LINES)
-
- DETAILS_LINES1 = """First Table
-+----------+--------+
-| Property | Value |
-+----------+--------+
-| foo | BUILD |
-| bar | ERROR |
-| bee | None |
-+----------+--------+
-"""
- DETAILS_LINES2 = """Second Table
-+----------+--------+
-| Property | Value |
-+----------+--------+
-| aaa | VVVVV |
-| bbb | WWWWW |
-| ccc | XXXXX |
-+----------+--------+
-"""
-
- def test_details_with_normal_line_label_false(self):
- expected = {'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'}
- actual = output_parser.details(self.DETAILS_LINES1)
- self.assertEqual(expected, actual)
-
- def test_details_with_normal_line_label_true(self):
- expected = {'__label': 'First Table',
- 'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'}
- actual = output_parser.details(self.DETAILS_LINES1, with_label=True)
- self.assertEqual(expected, actual)
-
- def test_details_multiple_with_normal_line_label_false(self):
- expected = [{'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'},
- {'aaa': 'VVVVV', 'bbb': 'WWWWW', 'ccc': 'XXXXX'}]
- actual = output_parser.details_multiple(self.DETAILS_LINES1 +
- self.DETAILS_LINES2)
- self.assertIsInstance(actual, list)
- self.assertEqual(expected, actual)
-
- def test_details_multiple_with_normal_line_label_true(self):
- expected = [{'__label': 'First Table',
- 'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'},
- {'__label': 'Second Table',
- 'aaa': 'VVVVV', 'bbb': 'WWWWW', 'ccc': 'XXXXX'}]
- actual = output_parser.details_multiple(self.DETAILS_LINES1 +
- self.DETAILS_LINES2,
- with_label=True)
- self.assertIsInstance(actual, list)
- self.assertEqual(expected, actual)
diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py
index 0db4cfa..e8650c5 100644
--- a/tempest/tests/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/common/utils/linux/test_remote_client.py
@@ -117,7 +117,7 @@
self.assertEqual(self.conn.get_mac_address(), macs)
self._assert_exec_called_with(
- "/sbin/ifconfig | awk '/HWaddr/ {print $5}'")
+ "/bin/ip addr | awk '/ether/ {print $2}'")
def test_get_ip_list(self):
ips = """1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue
diff --git a/tempest/tests/stress/test_stress.py b/tempest/tests/stress/test_stress.py
index 3dc2199..9c3533d 100644
--- a/tempest/tests/stress/test_stress.py
+++ b/tempest/tests/stress/test_stress.py
@@ -16,7 +16,8 @@
import shlex
import subprocess
-import tempest.cli as cli
+from tempest_lib import exceptions
+
from tempest.openstack.common import log as logging
from tempest.tests import base
@@ -43,9 +44,9 @@
result, result_err = proc.communicate()
if proc.returncode != 0:
LOG.debug('error of %s:\n%s' % (cmd_str, result_err))
- raise cli.CommandFailed(proc.returncode,
- cmd,
- result)
+ raise exceptions.CommandFailed(proc.returncode,
+ cmd,
+ result)
finally:
LOG.debug('output of %s:\n%s' % (cmd_str, result))
return proc.returncode
diff --git a/tempest/tests/test_compute_xml_common.py b/tempest/tests/test_compute_xml_common.py
deleted file mode 100644
index 1561931..0000000
--- a/tempest/tests/test_compute_xml_common.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright 2013 IBM Corp.
-#
-# 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 lxml import etree
-
-from tempest.common import xml_utils as common
-from tempest.tests import base
-
-
-class TestXMLParser(base.TestCase):
-
- def test_xml_to_json_parser_bool_value(self):
- node = etree.fromstring('''<health_monitor
- xmlns="http://openstack.org/quantum/api/v2.0"
- xmlns:quantum="http://openstack.org/quantum/api/v2.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <admin_state_up quantum:type="bool">False</admin_state_up>
- <fake_state_up quantum:type="bool">True</fake_state_up>
- </health_monitor>''')
- body = common.xml_to_json(node)
- self.assertEqual(body['admin_state_up'], False)
- self.assertEqual(body['fake_state_up'], True)
-
- def test_xml_to_json_parser_int_value(self):
- node = etree.fromstring('''<health_monitor
- xmlns="http://openstack.org/quantum/api/v2.0"
- xmlns:quantum="http://openstack.org/quantum/api/v2.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <delay quantum:type="long">4</delay>
- <max_retries quantum:type="int">3</max_retries>
- </health_monitor>''')
- body = common.xml_to_json(node)
- self.assertEqual(body['delay'], 4L)
- self.assertEqual(body['max_retries'], 3)
-
- def test_xml_to_json_parser_text_value(self):
- node = etree.fromstring('''<health_monitor
- xmlns="http://openstack.org/quantum/api/v2.0"
- xmlns:quantum="http://openstack.org/quantum/api/v2.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <status>ACTIVE</status>
- </health_monitor>''')
- body = common.xml_to_json(node)
- self.assertEqual(body['status'], 'ACTIVE')
-
- def test_xml_to_json_parser_list_as_value(self):
- node = etree.fromstring('''<health_monitor
- xmlns="http://openstack.org/quantum/api/v2.0"
- xmlns:quantum="http://openstack.org/quantum/api/v2.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <elements>
- <element>first_element</element>
- <element>second_element</element>
- </elements>
- </health_monitor>''')
- body = common.xml_to_json(node, 'elements')
- self.assertEqual(body['elements'], ['first_element', 'second_element'])
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index 6857461..fd01887 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -69,13 +69,18 @@
self.assertFalse(checks.no_setup_teardown_class_for_tests(
" def tearDownClass(cls):", './tempest/test.py'))
- def test_import_no_clients_in_api(self):
+ def test_import_no_clients_in_api_and_scenario_tests(self):
for client in checks.PYTHON_CLIENTS:
string = "import " + client + "client"
- self.assertTrue(checks.import_no_clients_in_api(
- string, './tempest/api/fake_test.py'))
- self.assertFalse(checks.import_no_clients_in_api(
- string, './tempest/scenario/fake_test.py'))
+ self.assertTrue(
+ checks.import_no_clients_in_api_and_scenario_tests(
+ string, './tempest/api/fake_test.py'))
+ self.assertTrue(
+ checks.import_no_clients_in_api_and_scenario_tests(
+ string, './tempest/scenario/fake_test.py'))
+ self.assertFalse(
+ checks.import_no_clients_in_api_and_scenario_tests(
+ string, './tempest/test.py'))
def test_scenario_tests_need_service_tags(self):
self.assertFalse(checks.scenario_tests_need_service_tags(
diff --git a/tempest/tests/test_list_tests.py b/tempest/tests/test_list_tests.py
index 157fc5f..efdb413 100644
--- a/tempest/tests/test_list_tests.py
+++ b/tempest/tests/test_list_tests.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import os
import re
import subprocess
@@ -20,16 +21,23 @@
class TestTestList(base.TestCase):
- def test_no_import_errors(self):
+ def test_testr_list_tests_no_errors(self):
+ # Remove unit test discover path from env to test tempest tests
+ test_env = os.environ.copy()
+ test_env.pop('OS_TEST_PATH')
import_failures = []
- p = subprocess.Popen(['testr', 'list-tests'], stdout=subprocess.PIPE)
- ids = p.stdout.read()
+ p = subprocess.Popen(['testr', 'list-tests'], stdout=subprocess.PIPE,
+ env=test_env)
+ ids, err = p.communicate()
+ self.assertEqual(0, p.returncode,
+ "test discovery failed, one or more files cause an "
+ "error on import")
ids = ids.split('\n')
for test_id in ids:
if re.match('(\w+\.){3}\w+', test_id):
if not test_id.startswith('tempest.'):
- fail_id = test_id.split('unittest.loader.ModuleImport'
- 'Failure.')[1]
+ parts = test_id.partition('tempest')
+ fail_id = parts[1] + parts[2]
import_failures.append(fail_id)
error_message = ("The following tests have import failures and aren't"
" being run with test filters %s" % import_failures)
diff --git a/tempest/tests/test_rest_client.py b/tempest/tests/test_rest_client.py
index 5f55ca2..bb463e5 100644
--- a/tempest/tests/test_rest_client.py
+++ b/tempest/tests/test_rest_client.py
@@ -18,7 +18,6 @@
from oslotest import mockpatch
from tempest.common import rest_client
-from tempest.common import xml_utils as xml
from tempest import config
from tempest import exceptions
from tempest.tests import base
@@ -236,29 +235,8 @@
)
-class TestRestClientHeadersXML(TestRestClientHeadersJSON):
- TYPE = "xml"
-
- # These two tests are needed in one exemplar
- def test_send_json_accept_xml(self):
- resp, __ = self.rest_client.get(self.url,
- self.rest_client.get_headers("xml",
- "json"))
- resp = dict((k.lower(), v) for k, v in resp.iteritems())
- self.assertEqual("application/json", resp["content-type"])
- self.assertEqual("application/xml", resp["accept"])
-
- def test_send_xml_accept_json(self):
- resp, __ = self.rest_client.get(self.url,
- self.rest_client.get_headers("json",
- "xml"))
- resp = dict((k.lower(), v) for k, v in resp.iteritems())
- self.assertEqual("application/json", resp["accept"])
- self.assertEqual("application/xml", resp["content-type"])
-
-
-class TestRestClientParseRespXML(BaseRestClientTestClass):
- TYPE = "xml"
+class TestRestClientParseRespJSON(BaseRestClientTestClass):
+ TYPE = "json"
keys = ["fake_key1", "fake_key2"]
values = ["fake_value1", "fake_value2"]
@@ -274,39 +252,10 @@
def setUp(self):
self.fake_http = fake_http.fake_httplib2()
- super(TestRestClientParseRespXML, self).setUp()
+ super(TestRestClientParseRespJSON, self).setUp()
self.rest_client.TYPE = self.TYPE
def test_parse_resp_body_item(self):
- body_item = xml.Element("item", **self.item_expected)
- body = self.rest_client._parse_resp(str(xml.Document(body_item)))
- self.assertEqual(self.item_expected, body)
-
- def test_parse_resp_body_list(self):
- self.rest_client.list_tags = ["fake_list", ]
- body_list = xml.Element(self.rest_client.list_tags[0])
- for i in range(2):
- body_list.append(xml.Element("fake_item",
- **self.list_expected["body_list"][i]))
- body = self.rest_client._parse_resp(str(xml.Document(body_list)))
- self.assertEqual(self.list_expected["body_list"], body)
-
- def test_parse_resp_body_dict(self):
- self.rest_client.dict_tags = ["fake_dict", ]
- body_dict = xml.Element(self.rest_client.dict_tags[0])
-
- for i in range(2):
- body_dict.append(xml.Element("fake_item", xml.Text(self.values[i]),
- key=self.keys[i]))
-
- body = self.rest_client._parse_resp(str(xml.Document(body_dict)))
- self.assertEqual(self.dict_expected["body_dict"], body)
-
-
-class TestRestClientParseRespJSON(TestRestClientParseRespXML):
- TYPE = "json"
-
- def test_parse_resp_body_item(self):
body = self.rest_client._parse_resp(json.dumps(self.item_expected))
self.assertEqual(self.item_expected, body)
@@ -426,10 +375,6 @@
**self.set_data("402"))
-class TestRestClientErrorCheckerXML(TestRestClientErrorCheckerJSON):
- c_type = "application/xml"
-
-
class TestRestClientErrorCheckerTEXT(TestRestClientErrorCheckerJSON):
c_type = "text/plain"
diff --git a/tempest/tests/test_tenant_isolation.py b/tempest/tests/test_tenant_isolation.py
index 27c45c2..df9719b 100644
--- a/tempest/tests/test_tenant_isolation.py
+++ b/tempest/tests/test_tenant_isolation.py
@@ -21,9 +21,7 @@
from tempest import exceptions
from tempest.openstack.common.fixture import mockpatch
from tempest.services.identity.json import identity_client as json_iden_client
-from tempest.services.identity.xml import identity_client as xml_iden_client
from tempest.services.network.json import network_client as json_network_client
-from tempest.services.network.xml import network_client as xml_network_client
from tempest.tests import base
from tempest.tests import fake_config
from tempest.tests import fake_http
@@ -49,14 +47,6 @@
self.assertTrue(isinstance(iso_creds.network_admin_client,
json_network_client.NetworkClientJSON))
- def test_tempest_client_xml(self):
- iso_creds = isolated_creds.IsolatedCreds('test class', interface='xml')
- self.assertEqual(iso_creds.interface, 'xml')
- self.assertTrue(isinstance(iso_creds.identity_admin_client,
- xml_iden_client.IdentityClientXML))
- self.assertTrue(isinstance(iso_creds.network_admin_client,
- xml_network_client.NetworkClientXML))
-
def _mock_user_create(self, id, name):
user_fix = self.useFixture(mockpatch.PatchObject(
json_iden_client.IdentityClientJSON,
diff --git a/tempest/tests/test_wrappers.py b/tempest/tests/test_wrappers.py
index 0fd41f9..ae7860d 100644
--- a/tempest/tests/test_wrappers.py
+++ b/tempest/tests/test_wrappers.py
@@ -34,7 +34,6 @@
# Setup Test files
self.testr_conf_file = os.path.join(self.directory, '.testr.conf')
self.setup_cfg_file = os.path.join(self.directory, 'setup.cfg')
- self.subunit_trace = os.path.join(self.directory, 'subunit-trace.py')
self.passing_file = os.path.join(self.test_dir, 'test_passing.py')
self.failing_file = os.path.join(self.test_dir, 'test_failing.py')
self.init_file = os.path.join(self.test_dir, '__init__.py')
@@ -45,7 +44,6 @@
shutil.copy('setup.py', self.setup_py)
shutil.copy('tempest/tests/files/setup.cfg', self.setup_cfg_file)
shutil.copy('tempest/tests/files/__init__.py', self.init_file)
- shutil.copy('tools/subunit-trace.py', self.subunit_trace)
# copy over the pretty_tox scripts
shutil.copy('tools/pretty_tox.sh',
os.path.join(self.directory, 'pretty_tox.sh'))
diff --git a/tempest/tests/test_xml_utils.py b/tempest/tests/test_xml_utils.py
deleted file mode 100644
index 53e31c4..0000000
--- a/tempest/tests/test_xml_utils.py
+++ /dev/null
@@ -1,35 +0,0 @@
-#
-# Copyright 2014 Hewlett-Packard Development Company, L.P.
-#
-# 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 xml_utils
-from tempest.tests import base
-
-
-class TestDocumentXML(base.TestCase):
- def test_xml_document_ordering_version_encoding(self):
- expected = '<?xml version="1.0" encoding="UTF-8"?>'
- xml_out = str(xml_utils.Document())
- self.assertEqual(expected, xml_out.strip())
-
- xml_out = str(xml_utils.Document(encoding='UTF-8', version='1.0'))
- self.assertEqual(expected, xml_out.strip())
-
- xml_out = str(xml_utils.Document(version='1.0', encoding='UTF-8'))
- self.assertEqual(expected, xml_out.strip())
-
- def test_xml_document_additonal_attrs(self):
- expected = '<?xml version="1.0" encoding="UTF-8" foo="bar"?>'
- xml_out = str(xml_utils.Document(foo='bar'))
- self.assertEqual(expected, xml_out.strip())
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index f3f11fd..00b17d9 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -306,8 +306,7 @@
volume.detach()
- self.assertVolumeStatusWait(_volume_state, "available")
- wait.re_search_wait(_volume_state, "available")
+ self.assertVolumeStatusWait(volume, "available")
wait.state_wait(_part_state, 'DECREASE')
diff --git a/tempest/thirdparty/boto/test_ec2_network.py b/tempest/thirdparty/boto/test_ec2_network.py
index a75fb7b..132a5a8 100644
--- a/tempest/thirdparty/boto/test_ec2_network.py
+++ b/tempest/thirdparty/boto/test_ec2_network.py
@@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest import test
from tempest.thirdparty.boto import test as boto_test
@@ -22,21 +21,22 @@
@classmethod
def resource_setup(cls):
super(EC2NetworkTest, cls).resource_setup()
- cls.client = cls.os.ec2api_client
+ cls.ec2_client = cls.os.ec2api_client
# Note(afazekas): these tests for things duable without an instance
- @test.skip_because(bug="1080406")
def test_disassociate_not_associated_floating_ip(self):
# EC2 disassociate not associated floating ip
ec2_codes = self.ec2_error_code
- address = self.client.allocate_address()
+ address = self.ec2_client.allocate_address()
public_ip = address.public_ip
- rcuk = self.addResourceCleanUp(self.client.release_address, public_ip)
- addresses_get = self.client.get_all_addresses(addresses=(public_ip,))
+ rcuk = self.addResourceCleanUp(self.ec2_client.release_address,
+ public_ip)
+ addresses_get = self.ec2_client.get_all_addresses(
+ addresses=(public_ip,))
self.assertEqual(len(addresses_get), 1)
self.assertEqual(addresses_get[0].public_ip, public_ip)
self.assertBotoError(ec2_codes.client.InvalidAssociationID.NotFound,
address.disassociate)
- self.client.release_address(public_ip)
- self.cancelResourceCleanUp(rcuk)
+ self.ec2_client.release_address(public_ip)
self.assertAddressReleasedWait(address)
+ self.cancelResourceCleanUp(rcuk)
diff --git a/test-requirements.txt b/test-requirements.txt
index ba70259..6eefeee 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -3,11 +3,11 @@
# process, which may cause wedges in the gate later.
hacking>=0.9.2,<0.10
# needed for doc build
-sphinx>=1.1.2,!=1.2.0,<1.3
+sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
python-subunit>=0.0.18
oslosphinx>=2.2.0 # Apache-2.0
mox>=0.5.3
mock>=1.0
coverage>=3.6
-oslotest>=1.1.0 # Apache-2.0
-stevedore>=1.0.0 # Apache-2.0
+oslotest>=1.2.0 # Apache-2.0
+stevedore>=1.1.0 # Apache-2.0
diff --git a/tools/check_logs.py b/tools/check_logs.py
index 7cf9d85..c8d3a1a 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -31,7 +31,7 @@
is_grenade = os.environ.get('DEVSTACK_GATE_GRENADE') is not None
dump_all_errors = True
-# As logs are made clean, add to this set
+# As logs are made clean, remove from this set
allowed_dirty = set([
'c-api',
'ceilometer-acentral',
diff --git a/tools/pretty_tox.sh b/tools/pretty_tox.sh
index 0a04ce6..ff554c5 100755
--- a/tools/pretty_tox.sh
+++ b/tools/pretty_tox.sh
@@ -3,4 +3,4 @@
set -o pipefail
TESTRARGS=$1
-python setup.py testr --slowest --testr-args="--subunit $TESTRARGS" | $(dirname $0)/subunit-trace.py --no-failure-debug -f
+python setup.py testr --slowest --testr-args="--subunit $TESTRARGS" | subunit-trace --no-failure-debug -f
diff --git a/tools/pretty_tox_serial.sh b/tools/pretty_tox_serial.sh
index db70890..e0fca0f 100755
--- a/tools/pretty_tox_serial.sh
+++ b/tools/pretty_tox_serial.sh
@@ -7,7 +7,7 @@
if [ ! -d .testrepository ]; then
testr init
fi
-testr run --subunit $TESTRARGS | $(dirname $0)/subunit-trace.py -f -n
+testr run --subunit $TESTRARGS | subunit-trace -f -n
retval=$?
testr slowest
diff --git a/tools/subunit-trace.py b/tools/subunit-trace.py
deleted file mode 100755
index 57e58f2..0000000
--- a/tools/subunit-trace.py
+++ /dev/null
@@ -1,247 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2014 Hewlett-Packard Development Company, L.P.
-# Copyright 2014 Samsung Electronics
-# 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.
-
-"""Trace a subunit stream in reasonable detail and high accuracy."""
-
-import argparse
-import functools
-import re
-import sys
-
-import subunit
-import testtools
-
-DAY_SECONDS = 60 * 60 * 24
-FAILS = []
-RESULTS = {}
-
-
-def cleanup_test_name(name, strip_tags=True, strip_scenarios=False):
- """Clean up the test name for display.
-
- By default we strip out the tags in the test because they don't help us
- in identifying the test that is run to it's result.
-
- Make it possible to strip out the testscenarios information (not to
- be confused with tempest scenarios) however that's often needed to
- indentify generated negative tests.
- """
- if strip_tags:
- tags_start = name.find('[')
- tags_end = name.find(']')
- if tags_start > 0 and tags_end > tags_start:
- newname = name[:tags_start]
- newname += name[tags_end + 1:]
- name = newname
-
- if strip_scenarios:
- tags_start = name.find('(')
- tags_end = name.find(')')
- if tags_start > 0 and tags_end > tags_start:
- newname = name[:tags_start]
- newname += name[tags_end + 1:]
- name = newname
-
- return name
-
-
-def get_duration(timestamps):
- start, end = timestamps
- if not start or not end:
- duration = ''
- else:
- delta = end - start
- duration = '%d.%06ds' % (
- delta.days * DAY_SECONDS + delta.seconds, delta.microseconds)
- return duration
-
-
-def find_worker(test):
- for tag in test['tags']:
- if tag.startswith('worker-'):
- return int(tag[7:])
- return 'NaN'
-
-
-# Print out stdout/stderr if it exists, always
-def print_attachments(stream, test, all_channels=False):
- """Print out subunit attachments.
-
- Print out subunit attachments that contain content. This
- runs in 2 modes, one for successes where we print out just stdout
- and stderr, and an override that dumps all the attachments.
- """
- channels = ('stdout', 'stderr')
- for name, detail in test['details'].items():
- # NOTE(sdague): the subunit names are a little crazy, and actually
- # are in the form pythonlogging:'' (with the colon and quotes)
- name = name.split(':')[0]
- if detail.content_type.type == 'test':
- detail.content_type.type = 'text'
- if (all_channels or name in channels) and detail.as_text():
- title = "Captured %s:" % name
- stream.write("\n%s\n%s\n" % (title, ('~' * len(title))))
- # indent attachment lines 4 spaces to make them visually
- # offset
- for line in detail.as_text().split('\n'):
- stream.write(" %s\n" % line)
-
-
-def show_outcome(stream, test, print_failures=False):
- global RESULTS
- status = test['status']
- # TODO(sdague): ask lifeless why on this?
- if status == 'exists':
- return
-
- worker = find_worker(test)
- name = cleanup_test_name(test['id'])
- duration = get_duration(test['timestamps'])
-
- if worker not in RESULTS:
- RESULTS[worker] = []
- RESULTS[worker].append(test)
-
- # don't count the end of the return code as a fail
- if name == 'process-returncode':
- return
-
- if status == 'success':
- stream.write('{%s} %s [%s] ... ok\n' % (
- worker, name, duration))
- print_attachments(stream, test)
- elif status == 'fail':
- FAILS.append(test)
- stream.write('{%s} %s [%s] ... FAILED\n' % (
- worker, name, duration))
- if not print_failures:
- print_attachments(stream, test, all_channels=True)
- elif status == 'skip':
- stream.write('{%s} %s ... SKIPPED: %s\n' % (
- worker, name, test['details']['reason'].as_text()))
- else:
- stream.write('{%s} %s [%s] ... %s\n' % (
- worker, name, duration, test['status']))
- if not print_failures:
- print_attachments(stream, test, all_channels=True)
-
- stream.flush()
-
-
-def print_fails(stream):
- """Print summary failure report.
-
- Currently unused, however there remains debate on inline vs. at end
- reporting, so leave the utility function for later use.
- """
- if not FAILS:
- return
- stream.write("\n==============================\n")
- stream.write("Failed %s tests - output below:" % len(FAILS))
- stream.write("\n==============================\n")
- for f in FAILS:
- stream.write("\n%s\n" % f['id'])
- stream.write("%s\n" % ('-' * len(f['id'])))
- print_attachments(stream, f, all_channels=True)
- stream.write('\n')
-
-
-def count_tests(key, value):
- count = 0
- for k, v in RESULTS.items():
- for item in v:
- if key in item:
- if re.search(value, item[key]):
- count += 1
- return count
-
-
-def run_time():
- runtime = 0.0
- for k, v in RESULTS.items():
- for test in v:
- runtime += float(get_duration(test['timestamps']).strip('s'))
- return runtime
-
-
-def worker_stats(worker):
- tests = RESULTS[worker]
- num_tests = len(tests)
- delta = tests[-1]['timestamps'][1] - tests[0]['timestamps'][0]
- return num_tests, delta
-
-
-def print_summary(stream):
- stream.write("\n======\nTotals\n======\n")
- stream.write("Run: %s in %s sec.\n" % (count_tests('status', '.*'),
- run_time()))
- stream.write(" - Passed: %s\n" % count_tests('status', 'success'))
- stream.write(" - Skipped: %s\n" % count_tests('status', 'skip'))
- stream.write(" - Failed: %s\n" % count_tests('status', 'fail'))
-
- # we could have no results, especially as we filter out the process-codes
- if RESULTS:
- stream.write("\n==============\nWorker Balance\n==============\n")
-
- for w in range(max(RESULTS.keys()) + 1):
- if w not in RESULTS:
- stream.write(
- " - WARNING: missing Worker %s! "
- "Race in testr accounting.\n" % w)
- else:
- num, time = worker_stats(w)
- stream.write(" - Worker %s (%s tests) => %ss\n" %
- (w, num, time))
-
-
-def parse_args():
- parser = argparse.ArgumentParser()
- parser.add_argument('--no-failure-debug', '-n', action='store_true',
- dest='print_failures', help='Disable printing failure '
- 'debug information in realtime')
- parser.add_argument('--fails', '-f', action='store_true',
- dest='post_fails', help='Print failure debug '
- 'information after the stream is proccesed')
- return parser.parse_args()
-
-
-def main():
- args = parse_args()
- stream = subunit.ByteStreamToStreamResult(
- sys.stdin, non_subunit_name='stdout')
- outcomes = testtools.StreamToDict(
- functools.partial(show_outcome, sys.stdout,
- print_failures=args.print_failures))
- summary = testtools.StreamSummary()
- result = testtools.CopyStreamResult([outcomes, summary])
- result.startTestRun()
- try:
- stream.run(result)
- finally:
- result.stopTestRun()
- if count_tests('status', '.*') == 0:
- print("The test run didn't actually run any tests")
- return 1
- if args.post_fails:
- print_fails(sys.stdout)
- print_summary(sys.stdout)
- return (0 if summary.wasSuccessful() else 1)
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/tox.ini b/tox.ini
index e575b4f..edfee15 100644
--- a/tox.ini
+++ b/tox.ini
@@ -17,7 +17,9 @@
whitelist_externals = *
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
-commands = bash tools/pretty_tox.sh '{posargs}'
+commands =
+ find . -type f -name "*.pyc" -delete
+ bash tools/pretty_tox.sh '{posargs}'
[testenv:genconfig]
commands = oslo-config-generator --config-file tools/config/config-generator.tempest.conf
@@ -28,9 +30,12 @@
[testenv:all]
sitepackages = {[tempestenv]sitepackages}
+# 'all' includes slow tests
setenv = {[tempestenv]setenv}
+ OS_TEST_TIMEOUT=1200
deps = {[tempestenv]deps}
commands =
+ find . -type f -name "*.pyc" -delete
bash tools/pretty_tox.sh '{posargs}'
[testenv:full]
@@ -40,6 +45,7 @@
# The regex below is used to select which tests to run and exclude the slow tag:
# See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
+ find . -type f -name "*.pyc" -delete
bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
[testenv:full-serial]
@@ -49,6 +55,7 @@
# The regex below is used to select which tests to run and exclude the slow tag:
# See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
+ find . -type f -name "*.pyc" -delete
bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
[testenv:heat-slow]
@@ -58,6 +65,7 @@
deps = {[tempestenv]deps}
# The regex below is used to select heat api/scenario tests tagged as slow.
commands =
+ find . -type f -name "*.pyc" -delete
bash tools/pretty_tox.sh '(?=.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)\.orchestration) {posargs}'
[testenv:large-ops]
@@ -65,6 +73,7 @@
setenv = {[tempestenv]setenv}
deps = {[tempestenv]deps}
commands =
+ find . -type f -name "*.pyc" -delete
python setup.py testr --slowest --testr-args='tempest.scenario.test_large_ops {posargs}'
[testenv:smoke]
@@ -72,6 +81,7 @@
setenv = {[tempestenv]setenv}
deps = {[tempestenv]deps}
commands =
+ find . -type f -name "*.pyc" -delete
bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
[testenv:smoke-serial]
@@ -82,6 +92,7 @@
# https://bugs.launchpad.net/tempest/+bug/1216076 so the neutron smoke
# job would fail if we moved it to parallel.
commands =
+ find . -type f -name "*.pyc" -delete
bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
[testenv:stress]
@@ -89,7 +100,7 @@
setenv = {[tempestenv]setenv}
deps = {[tempestenv]deps}
commands =
- run-tempest-stress '{posargs}'
+ run-tempest-stress {posargs}
[testenv:venv]
commands = {posargs}