Merge "javelin2: destroy functions above network resources"
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 484c34d..75f9795 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,25 @@
partitions = linux_client.get_partitions()
self.assertNotIn(self.device, partitions)
+ @test.skip_because(bug="1323591", interface="xml")
+ @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)
+
+ # 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'])
+
class AttachVolumeTestXML(AttachVolumeTestJSON):
_interface = 'xml'
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index c6480a1..7ba68f7 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -155,33 +155,35 @@
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, **kwargs):
"""Wrapper utility that returns a test subnet."""
# 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(
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:
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 986a2c8..dd81a09 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -280,6 +280,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']))
@@ -492,7 +496,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 +505,62 @@
# 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')
+ @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')
+
class NetworksIpV6TestXML(NetworksIpV6TestJSON):
_interface = 'xml'
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/scenario/manager.py b/tempest/scenario/manager.py
index 990a392..2ebfdd1 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
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_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 8a8e387..ead021e 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
@@ -130,6 +130,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()
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 8ea2814..7fc1edf 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -115,7 +115,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')
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/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/tox.ini b/tox.ini
index e575b4f..9f52f0d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -28,7 +28,9 @@
[testenv:all]
sitepackages = {[tempestenv]sitepackages}
+# 'all' includes slow tests
setenv = {[tempestenv]setenv}
+ OS_TEST_TIMEOUT=1200
deps = {[tempestenv]deps}
commands =
bash tools/pretty_tox.sh '{posargs}'