Merge "Clean up scenario functions"
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index 18e4452..283a45a 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -29,7 +29,6 @@
def setUpClass(cls):
super(AZAdminTestJSON, cls).setUpClass()
cls.client = cls.os_adm.availability_zone_client
- cls.non_adm_client = cls.availability_zone_client
@attr(type='gate')
def test_get_availability_zone_list(self):
@@ -46,14 +45,6 @@
self.assertEqual(200, resp.status)
self.assertTrue(len(availability_zone) > 0)
- @attr(type='gate')
- def test_get_availability_zone_list_with_non_admin_user(self):
- # List of availability zone with non-administrator user
- resp, availability_zone = \
- self.non_adm_client.get_availability_zone_list()
- self.assertEqual(200, resp.status)
- self.assertTrue(len(availability_zone) > 0)
-
class AZAdminTestXML(AZAdminTestJSON):
_interface = 'xml'
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index 16dcfcc..ac800fb 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -30,7 +30,6 @@
def setUpClass(cls):
super(ServicesAdminTestJSON, cls).setUpClass()
cls.client = cls.os_adm.services_client
- cls.non_admin_client = cls.services_client
@attr(type='gate')
def test_list_services(self):
diff --git a/tempest/api/compute/servers/test_availability_zone.py b/tempest/api/compute/servers/test_availability_zone.py
new file mode 100644
index 0000000..748ba41
--- /dev/null
+++ b/tempest/api/compute/servers/test_availability_zone.py
@@ -0,0 +1,42 @@
+# 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.api.compute import base
+from tempest import test
+
+
+class AZTestJSON(base.BaseV2ComputeTest):
+
+ """
+ Tests Availability Zone API List
+ """
+
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(AZTestJSON, cls).setUpClass()
+ cls.client = cls.availability_zone_client
+
+ @test.attr(type='gate')
+ def test_get_availability_zone_list_with_non_admin_user(self):
+ # List of availability zone with non-administrator user
+ resp, availability_zone = self.client.get_availability_zone_list()
+ self.assertEqual(200, resp.status)
+ self.assertTrue(len(availability_zone) > 0)
+
+
+class AZTestXML(AZTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
new file mode 100644
index 0000000..6a9b996
--- /dev/null
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -0,0 +1,85 @@
+# 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 tempest.api.compute import base
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
+
+
+class DeleteServersTestJSON(base.BaseV2ComputeTest):
+ # NOTE: Server creations of each test class should be under 10
+ # for preventing "Quota exceeded for instances"
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(DeleteServersTestJSON, cls).setUpClass()
+ cls.client = cls.servers_client
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_building_state(self):
+ # Delete a server while it's VM state is Building
+ resp, server = self.create_test_server(wait_until='BUILD')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_active_server(self):
+ # Delete a server while it's VM state is Active
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_shutoff_state(self):
+ # Delete a server while it's VM state is Shutoff
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.stop(server['id'])
+ self.client.wait_for_server_status(server['id'], 'SHUTOFF')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_pause_state(self):
+ # Delete a server while it's VM state is Pause
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.pause_server(server['id'])
+ self.client.wait_for_server_status(server['id'], 'PAUSED')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_shelved_state(self):
+ # Delete a server while it's VM state is Shelved
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.shelve_server(server['id'])
+ self.assertEqual(202, resp.status)
+
+ offload_time = CONF.compute.shelved_offload_time
+ if offload_time >= 0:
+ self.client.wait_for_server_status(server['id'],
+ 'SHELVED_OFFLOADED',
+ extra_timeout=offload_time)
+ else:
+ self.client.wait_for_server_status(server['id'],
+ 'SHELVED')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+
+class DeleteServersTestXML(DeleteServersTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index 203832e..7167a8b 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -104,38 +104,6 @@
self.assertEqual('::babe:202:202', server['accessIPv6'])
@attr(type='gate')
- def test_delete_server_while_in_shutoff_state(self):
- # Delete a server while it's VM state is Shutoff
- resp, server = self.create_test_server(wait_until='ACTIVE')
- resp, body = self.client.stop(server['id'])
- self.client.wait_for_server_status(server['id'], 'SHUTOFF')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @attr(type='gate')
- def test_delete_server_while_in_pause_state(self):
- # Delete a server while it's VM state is Pause
- resp, server = self.create_test_server(wait_until='ACTIVE')
- resp, body = self.client.pause_server(server['id'])
- self.client.wait_for_server_status(server['id'], 'PAUSED')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @attr(type='gate')
- def test_delete_server_while_in_building_state(self):
- # Delete a server while it's VM state is Building
- resp, server = self.create_test_server(wait_until='BUILD')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @attr(type='gate')
- def test_delete_active_server(self):
- # Delete a server while it's VM state is Active
- resp, server = self.create_test_server(wait_until='ACTIVE')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @attr(type='gate')
def test_create_server_with_ipv6_addr_only(self):
# Create a server without an IPv4 address(only IPv6 address).
resp, server = self.create_test_server(accessIPv6='2001:2001::3')
diff --git a/tempest/api/compute/v3/admin/test_aggregates.py b/tempest/api/compute/v3/admin/test_aggregates.py
index b8b478d..20093e4 100644
--- a/tempest/api/compute/v3/admin/test_aggregates.py
+++ b/tempest/api/compute/v3/admin/test_aggregates.py
@@ -32,7 +32,6 @@
def setUpClass(cls):
super(AggregatesAdminV3Test, cls).setUpClass()
cls.client = cls.aggregates_admin_client
- cls.user_client = cls.aggregates_client
cls.aggregate_name_prefix = 'test_aggregate_'
cls.az_name_prefix = 'test_az_'
diff --git a/tempest/api/compute/v3/admin/test_availability_zone.py b/tempest/api/compute/v3/admin/test_availability_zone.py
index 57ac869..176751f 100644
--- a/tempest/api/compute/v3/admin/test_availability_zone.py
+++ b/tempest/api/compute/v3/admin/test_availability_zone.py
@@ -29,7 +29,6 @@
def setUpClass(cls):
super(AZAdminV3Test, cls).setUpClass()
cls.client = cls.availability_zone_admin_client
- cls.non_adm_client = cls.availability_zone_client
@attr(type='gate')
def test_get_availability_zone_list(self):
@@ -45,11 +44,3 @@
self.client.get_availability_zone_list_detail()
self.assertEqual(200, resp.status)
self.assertTrue(len(availability_zone) > 0)
-
- @attr(type='gate')
- def test_get_availability_zone_list_with_non_admin_user(self):
- # List of availability zone with non-administrator user
- resp, availability_zone = \
- self.non_adm_client.get_availability_zone_list()
- self.assertEqual(200, resp.status)
- self.assertTrue(len(availability_zone) > 0)
diff --git a/tempest/api/compute/v3/servers/test_availability_zone.py b/tempest/api/compute/v3/servers/test_availability_zone.py
new file mode 100644
index 0000000..feac9a1
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_availability_zone.py
@@ -0,0 +1,38 @@
+# 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.api.compute import base
+from tempest import test
+
+
+class AZV3Test(base.BaseV3ComputeTest):
+
+ """
+ Tests Availability Zone API List
+ """
+
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(AZV3Test, cls).setUpClass()
+ cls.client = cls.availability_zone_client
+
+ @test.attr(type='gate')
+ def test_get_availability_zone_list_with_non_admin_user(self):
+ # List of availability zone with non-administrator user
+ resp, availability_zone = self.client.get_availability_zone_list()
+ self.assertEqual(200, resp.status)
+ self.assertTrue(len(availability_zone) > 0)
diff --git a/tempest/api/compute/v3/servers/test_delete_server.py b/tempest/api/compute/v3/servers/test_delete_server.py
new file mode 100644
index 0000000..e98e1b7
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_delete_server.py
@@ -0,0 +1,81 @@
+# Copyright 2012 OpenStack Foundation
+#
+# 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 DeleteServersV3Test(base.BaseV3ComputeTest):
+ # NOTE: Server creations of each test class should be under 10
+ # for preventing "Quota exceeded for instances".
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(DeleteServersV3Test, cls).setUpClass()
+ cls.client = cls.servers_client
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_building_state(self):
+ # Delete a server while it's VM state is Building
+ resp, server = self.create_test_server(wait_until='BUILD')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_active_server(self):
+ # Delete a server while it's VM state is Active
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_shutoff_state(self):
+ # Delete a server while it's VM state is Shutoff
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.stop(server['id'])
+ self.client.wait_for_server_status(server['id'], 'SHUTOFF')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_pause_state(self):
+ # Delete a server while it's VM state is Pause
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.pause_server(server['id'])
+ self.client.wait_for_server_status(server['id'], 'PAUSED')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_shelved_state(self):
+ # Delete a server while it's VM state is Shelved
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.shelve_server(server['id'])
+ self.assertEqual(202, resp.status)
+
+ offload_time = CONF.compute.shelved_offload_time
+ if offload_time >= 0:
+ self.client.wait_for_server_status(server['id'],
+ 'SHELVED_OFFLOADED',
+ extra_timeout=offload_time)
+ else:
+ self.client.wait_for_server_status(server['id'],
+ 'SHELVED')
+
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
diff --git a/tempest/api/compute/v3/servers/test_servers.py b/tempest/api/compute/v3/servers/test_servers.py
index dc64c40..5480e31 100644
--- a/tempest/api/compute/v3/servers/test_servers.py
+++ b/tempest/api/compute/v3/servers/test_servers.py
@@ -105,38 +105,6 @@
server['os-access-ips:access_ip_v6'])
@test.attr(type='gate')
- def test_delete_server_while_in_shutoff_state(self):
- # Delete a server while it's VM state is Shutoff
- resp, server = self.create_test_server(wait_until='ACTIVE')
- resp, body = self.client.stop(server['id'])
- self.client.wait_for_server_status(server['id'], 'SHUTOFF')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @test.attr(type='gate')
- def test_delete_server_while_in_pause_state(self):
- # Delete a server while it's VM state is Pause
- resp, server = self.create_test_server(wait_until='ACTIVE')
- resp, body = self.client.pause_server(server['id'])
- self.client.wait_for_server_status(server['id'], 'PAUSED')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @test.attr(type='gate')
- def test_delete_server_while_in_building_state(self):
- # Delete a server while it's VM state is Building
- resp, server = self.create_test_server(wait_until='BUILD')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @test.attr(type='gate')
- def test_delete_active_server(self):
- # Delete a server while it's VM state is Active
- resp, server = self.create_test_server(wait_until='ACTIVE')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @test.attr(type='gate')
def test_create_server_with_ipv6_addr_only(self):
# Create a server without an IPv4 address(only IPv6 address).
resp, server = self.create_test_server(access_ip_v6='2001:2001::3')
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 197e7fa..6c71340 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -49,6 +49,7 @@
cls.data.teardown_all()
super(StaticWebTest, cls).tearDownClass()
+ @test.requires_ext(extension='staticweb', service='object')
@test.attr('gate')
def test_web_index(self):
headers = {'web-index': self.object_name}
@@ -79,6 +80,7 @@
self.container_name)
self.assertNotIn('x-container-meta-web-index', body)
+ @test.requires_ext(extension='staticweb', service='object')
@test.attr('gate')
def test_web_listing(self):
headers = {'web-listings': 'true'}
@@ -110,6 +112,7 @@
self.container_name)
self.assertNotIn('x-container-meta-web-listings', body)
+ @test.requires_ext(extension='staticweb', service='object')
@test.attr('gate')
def test_web_listing_css(self):
headers = {'web-listings': 'true',
@@ -133,6 +136,7 @@
css = '<link rel="stylesheet" type="text/css" href="listings.css" />'
self.assertIn(css, body)
+ @test.requires_ext(extension='staticweb', service='object')
@test.attr('gate')
def test_web_error(self):
headers = {'web-listings': 'true',
diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py
index 98e36b5..e0d15ac 100644
--- a/tempest/api/object_storage/test_object_formpost.py
+++ b/tempest/api/object_storage/test_object_formpost.py
@@ -92,6 +92,7 @@
content_type = 'multipart/form-data; boundary=%s' % boundary
return body, content_type
+ @test.requires_ext(extension='formpost', service='object')
@test.attr(type='gate')
def test_post_object_using_form(self):
body, content_type = self.get_multipart_form()
diff --git a/tempest/api/object_storage/test_object_formpost_negative.py b/tempest/api/object_storage/test_object_formpost_negative.py
index e02a058..a52c248 100644
--- a/tempest/api/object_storage/test_object_formpost_negative.py
+++ b/tempest/api/object_storage/test_object_formpost_negative.py
@@ -20,7 +20,7 @@
from tempest.api.object_storage import base
from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
class ObjectFormPostNegativeTest(base.BaseObjectTest):
@@ -91,7 +91,8 @@
content_type = 'multipart/form-data; boundary=%s' % boundary
return body, content_type
- @attr(type=['gate', 'negative'])
+ @test.requires_ext(extension='formpost', service='object')
+ @test.attr(type=['gate', 'negative'])
def test_post_object_using_form_expired(self):
body, content_type = self.get_multipart_form(expires=1)
time.sleep(2)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index f5dd53a..c1f9df3 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -276,6 +276,41 @@
return cls._get_credentials(cls.isolated_creds.get_admin_creds,
'admin_')
+ @staticmethod
+ def cleanup_resource(resource, test_name):
+
+ LOG.debug("Deleting %r from shared resources of %s" %
+ (resource, test_name))
+ try:
+ # OpenStack resources are assumed to have a delete()
+ # method which destroys the resource...
+ resource.delete()
+ except Exception as e:
+ # If the resource is already missing, mission accomplished.
+ # add status code as workaround for bug 1247568
+ if (e.__class__.__name__ == 'NotFound' or
+ (hasattr(e, 'status_code') and e.status_code == 404)):
+ return
+ raise
+
+ def is_deletion_complete():
+ # Deletion testing is only required for objects whose
+ # existence cannot be checked via retrieval.
+ if isinstance(resource, dict):
+ return True
+ try:
+ resource.get()
+ except Exception as e:
+ # Clients are expected to return an exception
+ # called 'NotFound' if retrieval fails.
+ if e.__class__.__name__ == 'NotFound':
+ return True
+ raise
+ return False
+
+ # Block until resource deletion has completed or timed-out
+ tempest.test.call_until_true(is_deletion_complete, 10, 1)
+
@classmethod
def tearDownClass(cls):
# NOTE(jaypipes): Because scenario tests are typically run in a
@@ -285,38 +320,7 @@
# the scenario test class object
while cls.os_resources:
thing = cls.os_resources.pop()
- LOG.debug("Deleting %r from shared resources of %s" %
- (thing, cls.__name__))
-
- try:
- # OpenStack resources are assumed to have a delete()
- # method which destroys the resource...
- thing.delete()
- except Exception as e:
- # If the resource is already missing, mission accomplished.
- # add status code as workaround for bug 1247568
- if (e.__class__.__name__ == 'NotFound' or
- hasattr(e, 'status_code') and e.status_code == 404):
- continue
- raise
-
- def is_deletion_complete():
- # Deletion testing is only required for objects whose
- # existence cannot be checked via retrieval.
- if isinstance(thing, dict):
- return True
- try:
- thing.get()
- except Exception as e:
- # Clients are expected to return an exception
- # called 'NotFound' if retrieval fails.
- if e.__class__.__name__ == 'NotFound':
- return True
- raise
- return False
-
- # Block until resource deletion has completed or timed-out
- tempest.test.call_until_true(is_deletion_complete, 10, 1)
+ cls.cleanup_resource(thing, cls.__name__)
cls.isolated_creds.clear_isolated_creds()
super(OfficialClientTest, cls).tearDownClass()
@@ -1058,9 +1062,6 @@
router = self._get_router(tenant_id)
subnet = self._create_subnet(network)
subnet.add_to_router(router.id)
- self.networks.append(network)
- self.subnets.append(subnet)
- self.routers.append(router)
return network, subnet, router
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 0c0234f..a4002d4 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -116,46 +116,57 @@
msg = "%s extension not enabled." % ext
raise cls.skipException(msg)
cls.check_preconditions()
- # TODO(mnewby) Consider looking up entities as needed instead
- # of storing them as collections on the class.
- cls.security_groups = {}
- cls.networks = []
- cls.subnets = []
- cls.routers = []
- cls.servers = {}
- cls.floating_ips = {}
- def _create_security_groups(self):
- self.security_groups[self.tenant_id] =\
+ def cleanup_wrapper(self, resource):
+ self.cleanup_resource(resource, self.__class__.__name__)
+
+ def setUp(self):
+ super(TestNetworkBasicOps, self).setUp()
+ self.security_group = \
self._create_security_group_neutron(tenant_id=self.tenant_id)
+ self.addCleanup(self.cleanup_wrapper, self.security_group)
+ self.network, self.subnet, self.router = self._create_networks()
+ for r in [self.network, self.router, self.subnet]:
+ self.addCleanup(self.cleanup_wrapper, r)
+ self.check_networks()
+ self.servers = {}
+ name = data_utils.rand_name('server-smoke')
+ serv_dict = self._create_server(name, self.network)
+ self.servers[serv_dict['server']] = serv_dict['keypair']
+ self._check_tenant_network_connectivity()
+ self.floating_ips = {}
+ self._create_and_associate_floating_ips()
- def _check_networks(self):
- # Checks that we see the newly created network/subnet/router via
- # checking the result of list_[networks,routers,subnets]
+ def check_networks(self):
+ """
+ Checks that we see the newly created network/subnet/router via
+ checking the result of list_[networks,routers,subnets]
+ """
+
seen_nets = self._list_networks()
seen_names = [n['name'] for n in seen_nets]
seen_ids = [n['id'] for n in seen_nets]
- for mynet in self.networks:
- self.assertIn(mynet.name, seen_names)
- self.assertIn(mynet.id, seen_ids)
+ self.assertIn(self.network.name, seen_names)
+ self.assertIn(self.network.id, seen_ids)
+
seen_subnets = self._list_subnets()
seen_net_ids = [n['network_id'] for n in seen_subnets]
seen_subnet_ids = [n['id'] for n in seen_subnets]
- for mynet in self.networks:
- self.assertIn(mynet.id, seen_net_ids)
- for mysubnet in self.subnets:
- self.assertIn(mysubnet.id, seen_subnet_ids)
+ self.assertIn(self.network.id, seen_net_ids)
+ self.assertIn(self.subnet.id, seen_subnet_ids)
+
seen_routers = self._list_routers()
seen_router_ids = [n['id'] for n in seen_routers]
seen_router_names = [n['name'] for n in seen_routers]
- for myrouter in self.routers:
- self.assertIn(myrouter.name, seen_router_names)
- self.assertIn(myrouter.id, seen_router_ids)
+ self.assertIn(self.router.name,
+ seen_router_names)
+ self.assertIn(self.router.id,
+ seen_router_ids)
def _create_server(self, name, network):
- tenant_id = network.tenant_id
keypair = self.create_keypair(name='keypair-%s' % name)
- security_groups = [self.security_groups[tenant_id].name]
+ self.addCleanup(self.cleanup_wrapper, keypair)
+ security_groups = [self.security_group.name]
create_kwargs = {
'nics': [
{'net-id': network.id},
@@ -164,8 +175,8 @@
'security_groups': security_groups,
}
server = self.create_server(name=name, create_kwargs=create_kwargs)
- self.servers[server] = keypair
- return server
+ self.addCleanup(self.cleanup_wrapper, server)
+ return dict(server=server, keypair=keypair)
def _create_servers(self):
for i, network in enumerate(self.networks):
@@ -181,7 +192,7 @@
# key-based authentication by cloud-init.
ssh_login = CONF.compute.image_ssh_user
try:
- for server, key in self.servers.items():
+ for server, key in self.servers.iteritems():
for net_name, ip_addresses in server.networks.iteritems():
for ip_address in ip_addresses:
self._check_vm_connectivity(ip_address, ssh_login,
@@ -197,6 +208,7 @@
for server in self.servers.keys():
floating_ip = self._create_floating_ip(server, public_network_id)
self.floating_ips[floating_ip] = server
+ self.addCleanup(self.cleanup_wrapper, floating_ip)
def _check_public_network_connectivity(self, should_connect=True,
msg=None):
@@ -229,23 +241,17 @@
self.floating_ips[floating_ip] = None
def _reassociate_floating_ips(self):
- network = self.networks[0]
for floating_ip in self.floating_ips.keys():
name = data_utils.rand_name('new_server-smoke-')
# create a new server for the floating ip
- server = self._create_server(name, network)
- self._associate_floating_ip(floating_ip, server)
- self.floating_ips[floating_ip] = server
+ serv_dict = self._create_server(name, self.network)
+ self.servers[serv_dict['server']] = serv_dict['keypair']
+ self._associate_floating_ip(floating_ip, serv_dict['server'])
+ self.floating_ips[floating_ip] = serv_dict['server']
@test.attr(type='smoke')
@test.services('compute', 'network')
def test_network_basic_ops(self):
- self._create_security_groups()
- self._create_networks()
- self._check_networks()
- self._create_servers()
- self._create_and_associate_floating_ips()
- self._check_tenant_network_connectivity()
self._check_public_network_connectivity(should_connect=True)
self._disassociate_floating_ips()
self._check_public_network_connectivity(should_connect=False,
diff --git a/tempest/scenario/test_cross_tenant_connectivity.py b/tempest/scenario/test_security_groups_basic_ops.py
similarity index 80%
rename from tempest/scenario/test_cross_tenant_connectivity.py
rename to tempest/scenario/test_security_groups_basic_ops.py
index edcf091..eabc734 100644
--- a/tempest/scenario/test_cross_tenant_connectivity.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -29,7 +29,7 @@
LOG = logging.getLogger(__name__)
-class TestNetworkCrossTenant(manager.NetworkScenarioTest):
+class TestSecurityGroupsBasicOps(manager.NetworkScenarioTest):
"""
This test suite assumes that Nova has been configured to
@@ -50,7 +50,7 @@
failure - ping_timeout reached
setup:
- for each tenant (demo and alt):
+ for primary tenant:
1. create a network&subnet
2. create a router (if public router isn't configured)
3. connect tenant network to public network via router
@@ -59,8 +59,6 @@
b. a VM with a floating ip
5. create a general empty security group (same as "default", but
without rules allowing in-tenant traffic)
- 6. for demo tenant - create another server to test in-tenant
- connections
tests:
1. _verify_network_details
@@ -80,7 +78,7 @@
been created on source tenant
assumptions:
- 1. alt_tenant/user existed and is different from demo_tenant/user
+ 1. alt_tenant/user existed and is different from primary_tenant/user
2. Public network is defined and reachable from the Tempest host
3. Public router can either be:
* defined, in which case all tenants networks can connect directly
@@ -92,7 +90,7 @@
"""
class TenantProperties():
- '''
+ """
helper class to save tenant details
id
credentials
@@ -101,7 +99,7 @@
security groups
servers
access point
- '''
+ """
def __init__(self, tenant_id, tenant_user, tenant_pass, tenant_name):
self.manager = OfficialClientManager(
@@ -109,6 +107,7 @@
tenant_pass,
tenant_name
)
+ self.keypair = None
self.tenant_id = tenant_id
self.tenant_name = tenant_name
self.tenant_user = tenant_user
@@ -119,7 +118,7 @@
self.security_groups = {}
self.servers = list()
- def _set_network(self, network, subnet, router):
+ def set_network(self, network, subnet, router):
self.network = network
self.subnet = subnet
self.router = router
@@ -129,7 +128,7 @@
@classmethod
def check_preconditions(cls):
- super(TestNetworkCrossTenant, cls).check_preconditions()
+ super(TestSecurityGroupsBasicOps, cls).check_preconditions()
if (cls.alt_tenant_id is None) or (cls.tenant_id is cls.alt_tenant_id):
msg = 'No alt_tenant defined'
cls.enabled = False
@@ -143,7 +142,7 @@
@classmethod
def setUpClass(cls):
- super(TestNetworkCrossTenant, cls).setUpClass()
+ super(TestSecurityGroupsBasicOps, cls).setUpClass()
alt_creds = cls.alt_credentials()
cls.alt_tenant_id = cls.manager._get_identity_client(
*alt_creds
@@ -151,48 +150,47 @@
cls.check_preconditions()
# TODO(mnewby) Consider looking up entities as needed instead
# of storing them as collections on the class.
- cls.keypairs = {}
- cls.security_groups = {}
cls.networks = []
cls.subnets = []
cls.routers = []
- cls.servers = []
cls.floating_ips = {}
cls.tenants = {}
- cls.demo_tenant = cls.TenantProperties(
- cls.tenant_id,
- *cls.credentials()
- )
- cls.alt_tenant = cls.TenantProperties(
- cls.alt_tenant_id,
- *alt_creds
- )
- for tenant in [cls.demo_tenant, cls.alt_tenant]:
+ cls.primary_tenant = cls.TenantProperties(cls.tenant_id,
+ *cls.credentials())
+ cls.alt_tenant = cls.TenantProperties(cls.alt_tenant_id,
+ *alt_creds)
+ for tenant in [cls.primary_tenant, cls.alt_tenant]:
cls.tenants[tenant.tenant_id] = tenant
- if not CONF.network.public_router_id:
- cls.floating_ip_access = True
- else:
- cls.floating_ip_access = False
+ cls.floating_ip_access = not CONF.network.public_router_id
- @classmethod
- def tearDownClass(cls):
- super(TestNetworkCrossTenant, cls).tearDownClass()
+ def cleanup_wrapper(self, resource):
+ self.cleanup_resource(resource, self.__class__.__name__)
+
+ def setUp(self):
+ super(TestSecurityGroupsBasicOps, self).setUp()
+ self._deploy_tenant(self.primary_tenant)
+ self._verify_network_details(self.primary_tenant)
+ self._verify_mac_addr(self.primary_tenant)
def _create_tenant_keypairs(self, tenant_id):
- self.keypairs[tenant_id] = self.create_keypair(
+ keypair = self.create_keypair(
name=data_utils.rand_name('keypair-smoke-'))
+ self.addCleanup(self.cleanup_wrapper, keypair)
+ self.tenants[tenant_id].keypair = keypair
def _create_tenant_security_groups(self, tenant):
- self.security_groups.setdefault(self.tenant_id, [])
access_sg = self._create_empty_security_group(
namestart='secgroup_access-',
tenant_id=tenant.tenant_id
)
+ self.addCleanup(self.cleanup_wrapper, access_sg)
+
# don't use default secgroup since it allows in-tenant traffic
def_sg = self._create_empty_security_group(
namestart='secgroup_general-',
tenant_id=tenant.tenant_id
)
+ self.addCleanup(self.cleanup_wrapper, def_sg)
tenant.security_groups.update(access=access_sg, default=def_sg)
ssh_rule = dict(
protocol='tcp',
@@ -200,9 +198,9 @@
port_range_max=22,
direction='ingress',
)
- self._create_security_group_rule(secgroup=access_sg,
- **ssh_rule
- )
+ rule = self._create_security_group_rule(secgroup=access_sg,
+ **ssh_rule)
+ self.addCleanup(self.cleanup_wrapper, rule)
def _verify_network_details(self, tenant):
# Checks that we see the newly created network/subnet/router via
@@ -245,11 +243,12 @@
'nics': [
{'net-id': tenant.network.id},
],
- 'key_name': self.keypairs[tenant.tenant_id].name,
+ 'key_name': tenant.keypair.name,
'security_groups': security_groups,
'tenant_id': tenant.tenant_id
}
server = self.create_server(name=name, create_kwargs=create_kwargs)
+ self.addCleanup(self.cleanup_wrapper, server)
return server
def _create_tenant_servers(self, tenant, num=1):
@@ -260,7 +259,6 @@
)
name = data_utils.rand_name(name)
server = self._create_server(name, tenant)
- self.servers.append(server)
tenant.servers.append(server)
def _set_access_point(self, tenant):
@@ -275,17 +273,20 @@
name = data_utils.rand_name(name)
server = self._create_server(name, tenant,
security_groups=secgroups)
- self.servers.append(server)
tenant.access_point = server
self._assign_floating_ips(server)
def _assign_floating_ips(self, server):
public_network_id = CONF.network.public_network_id
floating_ip = self._create_floating_ip(server, public_network_id)
+ self.addCleanup(self.cleanup_wrapper, floating_ip)
self.floating_ips.setdefault(server, floating_ip)
def _create_tenant_network(self, tenant):
- tenant._set_network(*self._create_networks(tenant.tenant_id))
+ network, subnet, router = self._create_networks(tenant.tenant_id)
+ for r in [network, router, subnet]:
+ self.addCleanup(self.cleanup_wrapper, r)
+ tenant.set_network(network, subnet, router)
def _set_compute_context(self, tenant):
self.compute_client = tenant.manager.compute_client
@@ -299,8 +300,6 @@
router (if public not defined)
access security group
access-point server
- for demo_tenant:
- creates general server to test against
"""
if not isinstance(tenant_or_id, self.TenantProperties):
tenant = self.tenants[tenant_or_id]
@@ -312,14 +311,12 @@
self._create_tenant_keypairs(tenant_id)
self._create_tenant_network(tenant)
self._create_tenant_security_groups(tenant)
- if tenant is self.demo_tenant:
- self._create_tenant_servers(tenant, num=1)
self._set_access_point(tenant)
def _get_server_ip(self, server, floating=False):
- '''
+ """
returns the ip (floating/internal) of a server
- '''
+ """
if floating:
return self.floating_ips[server].floating_ip_address
else:
@@ -332,7 +329,7 @@
"""
access_point_ssh = \
self.floating_ips[tenant.access_point].floating_ip_address
- private_key = self.keypairs[tenant.tenant_id].private_key
+ private_key = tenant.keypair.private_key
access_point_ssh = self._ssh_to_server(access_point_ssh,
private_key=private_key)
return access_point_ssh
@@ -391,17 +388,17 @@
secgroup=tenant.security_groups['default'],
**ruleset
)
+ self.addCleanup(self.cleanup_wrapper, rule)
access_point_ssh = self._connect_to_access_point(tenant)
for server in tenant.servers:
self._check_connectivity(access_point=access_point_ssh,
ip=self._get_server_ip(server))
- rule.delete()
def _test_cross_tenant_block(self, source_tenant, dest_tenant):
- '''
+ """
if public router isn't defined, then dest_tenant access is via
floating-ip
- '''
+ """
access_point_ssh = self._connect_to_access_point(source_tenant)
ip = self._get_server_ip(dest_tenant.access_point,
floating=self.floating_ip_access)
@@ -409,10 +406,10 @@
should_succeed=False)
def _test_cross_tenant_allow(self, source_tenant, dest_tenant):
- '''
+ """
check for each direction:
creating rule for tenant incoming traffic enables only 1way traffic
- '''
+ """
ruleset = dict(
protocol='icmp',
direction='ingress'
@@ -421,37 +418,26 @@
secgroup=dest_tenant.security_groups['default'],
**ruleset
)
- try:
- access_point_ssh = self._connect_to_access_point(source_tenant)
- ip = self._get_server_ip(dest_tenant.access_point,
- floating=self.floating_ip_access)
- self._check_connectivity(access_point_ssh, ip)
+ self.addCleanup(self.cleanup_wrapper, rule_s2d)
+ access_point_ssh = self._connect_to_access_point(source_tenant)
+ ip = self._get_server_ip(dest_tenant.access_point,
+ floating=self.floating_ip_access)
+ self._check_connectivity(access_point_ssh, ip)
- # test that reverse traffic is still blocked
- self._test_cross_tenant_block(dest_tenant, source_tenant)
+ # test that reverse traffic is still blocked
+ self._test_cross_tenant_block(dest_tenant, source_tenant)
- # allow reverse traffic and check
- rule_d2s = self._create_security_group_rule(
- secgroup=source_tenant.security_groups['default'],
- **ruleset
- )
- try:
- access_point_ssh_2 = self._connect_to_access_point(dest_tenant)
- ip = self._get_server_ip(source_tenant.access_point,
- floating=self.floating_ip_access)
- self._check_connectivity(access_point_ssh_2, ip)
+ # allow reverse traffic and check
+ rule_d2s = self._create_security_group_rule(
+ secgroup=source_tenant.security_groups['default'],
+ **ruleset
+ )
+ self.addCleanup(self.cleanup_wrapper, rule_d2s)
- # clean_rules
- rule_s2d.delete()
- rule_d2s.delete()
-
- except Exception as e:
- rule_d2s.delete()
- raise e
-
- except Exception as e:
- rule_s2d.delete()
- raise e
+ access_point_ssh_2 = self._connect_to_access_point(dest_tenant)
+ ip = self._get_server_ip(source_tenant.access_point,
+ floating=self.floating_ip_access)
+ self._check_connectivity(access_point_ssh_2, ip)
def _verify_mac_addr(self, tenant):
"""
@@ -475,20 +461,32 @@
@services('compute', 'network')
def test_cross_tenant_traffic(self):
try:
- for tenant_id in self.tenants.keys():
- self._deploy_tenant(tenant_id)
- self._verify_network_details(self.tenants[tenant_id])
- self._verify_mac_addr(self.tenants[tenant_id])
-
- # in-tenant check
- self._test_in_tenant_block(self.demo_tenant)
- self._test_in_tenant_allow(self.demo_tenant)
+ # deploy new tenant
+ self._deploy_tenant(self.alt_tenant)
+ self._verify_network_details(self.alt_tenant)
+ self._verify_mac_addr(self.alt_tenant)
# cross tenant check
- source_tenant = self.demo_tenant
+ source_tenant = self.primary_tenant
dest_tenant = self.alt_tenant
self._test_cross_tenant_block(source_tenant, dest_tenant)
self._test_cross_tenant_allow(source_tenant, dest_tenant)
except Exception:
- self._log_console_output(servers=self.servers)
+ for tenant in self.tenants.values():
+ self._log_console_output(servers=tenant.servers)
+ raise
+
+ @attr(type='smoke')
+ @services('compute', 'network')
+ def test_in_tenant_traffic(self):
+ try:
+ self._create_tenant_servers(self.primary_tenant, num=1)
+
+ # in-tenant check
+ self._test_in_tenant_block(self.primary_tenant)
+ self._test_in_tenant_allow(self.primary_tenant)
+
+ except Exception:
+ for tenant in self.tenants.values():
+ self._log_console_output(servers=tenant.servers)
raise
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index 399a3c8..54861be 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -123,15 +123,6 @@
_terminate_reservation(reservation_1, rcuk_1)
_terminate_reservation(reservation_2, rcuk_2)
- reservation_3, rcuk_3 = _run_instance('token_1')
- self.assertIsNotNone(reservation_3)
-
- # make sure we don't get the old reservation back
- self.assertNotEqual(reservation_1.id, reservation_3.id)
-
- # clean up
- _terminate_reservation(reservation_3, rcuk_3)
-
@attr(type='smoke')
def test_run_stop_terminate_instance(self):
# EC2 run, stop and terminate instance