Adds status check for FloatingIP in network scenarios
Verifies FloatingIP changes status correctly on association and dis-association
Scenarios:
test_network_basic_op
test_network_advanced_server_ops
Status is verified after connectivity check and without a waiter in order to
not mask unknown races in Neutron
Changes show() to refresh() to keep consistency
Partially Implements: blueprint fip-op-status (this is a Neutron bp:
https://blueprints.launchpad.net/neutron/+spec/fip-op-status)
Partially Implements: blueprint neutron-advanced-scenarios
Change-Id: Ibd45f3092cebc8f9fd0d16a3a543c2ef72156409
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 79207cd..4cde415 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -622,6 +622,23 @@
self.assertIsNone(floating_ip.port_id)
return floating_ip
+ def check_floating_ip_status(self, floating_ip, status):
+ """Verifies floatingip has reached given status. without waiting
+
+ :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()
+ self.assertEqual(status, floating_ip.status,
+ message="FloatingIP: {fp} is at status: {cst}. "
+ "failed to reach status: {st}"
+ .format(fp=floating_ip, cst=floating_ip.status,
+ st=status))
+ 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,
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index 58a028f..0c48334 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -87,6 +87,7 @@
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):
self.servers_client.wait_for_server_status(self.server['id'], 'ACTIVE')
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index de60745..5d75b64 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -176,16 +176,31 @@
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
+ the place in the test scenario where the method was called,
+ to indicate the context of the failure
+ """
ssh_login = CONF.compute.image_ssh_user
floating_ip, server = self.floating_ip_tuple
ip_address = floating_ip.floating_ip_address
private_key = None
+ floatingip_status = 'DOWN'
if should_connect:
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(
ip_address, ssh_login, private_key, should_connect, msg,
self.servers)
+ self.check_floating_ip_status(floating_ip, floatingip_status)
def _disassociate_floating_ips(self):
floating_ip, server = self.floating_ip_tuple
@@ -350,6 +365,8 @@
VMs are created with unique keypair so connectivity also asserts that
floating IP is associated with the new VM instead of the old one
+ Verifies that floating IP status is updated correctly after each change
+
"""
self._setup_network_and_servers()
diff --git a/tempest/services/network/resources.py b/tempest/services/network/resources.py
index 2b182d0..a84b4d5 100644
--- a/tempest/services/network/resources.py
+++ b/tempest/services/network/resources.py
@@ -52,7 +52,7 @@
return
@abc.abstractmethod
- def show(self):
+ def refresh(self):
return
def __hash__(self):
@@ -62,7 +62,11 @@
if not hasattr(self, 'status'):
return
- return self.client.wait_for_resource_status(self.show, status)
+ def helper_get():
+ self.refresh()
+ return self
+
+ return self.client.wait_for_resource_status(helper_get, status)
class DeletableNetwork(DeletableResource):
@@ -116,6 +120,12 @@
class DeletableFloatingIp(DeletableResource):
+ def refresh(self, *args, **kwargs):
+ _, result = self.client.show_floatingip(self.id,
+ *args,
+ **kwargs)
+ super(DeletableFloatingIp, self).update(**result['floatingip'])
+
def update(self, *args, **kwargs):
_, result = self.client.update_floatingip(self.id,
*args,
@@ -172,7 +182,6 @@
def delete(self):
self.client.delete_vip(self.id)
- def show(self):
+ def refresh(self):
_, result = self.client.show_vip(self.id)
- super(DeletableVip, self).update(**result['vip'])
- return self
+ super(DeletableVip, self).update(**result['vip'])
\ No newline at end of file