Merge pull request #989 from ekholabs/fix/cleanup_vr_ips-CLOUDSTACK-8991

CLOUDSTACK-8991 - IP address is not removed from VR even after disabling static NATThis PR fixes the Public IP removal form the virtual routers. It also improves the existing test_network.py.

* pr/989:
  CLOUDSTACK-8991 - Process the IPs that have been removed
  CLOUDSTACK-8991 - Remove public IP form interface in case add = false
  CLOUDSTACK-8991 - Make sure the public IP is removed form the router before checking

Signed-off-by: Remi Bergsma <github@remi.nl>
This commit is contained in:
Remi Bergsma 2015-10-28 22:24:40 +01:00
commit 1f6781babc
3 changed files with 65 additions and 49 deletions

View File

@ -103,6 +103,7 @@ class CsAddress(CsDataBag):
for address in self.dbag[dev]: for address in self.dbag[dev]:
ip.setAddress(address) ip.setAddress(address)
logging.info("Address found in DataBag ==> %s" % address)
if ip.configured(): if ip.configured():
logging.info( logging.info(
@ -263,10 +264,17 @@ class CsIP:
return self.address return self.address
def configure(self, address): def configure(self, address):
logging.info( # When "add" is false, it means that the IP has to be removed.
"Configuring address %s on device %s", self.ip(), self.dev) if address["add"]:
cmd = "ip addr add dev %s %s brd +" % (self.dev, self.ip()) try:
subprocess.call(cmd, shell=True) logging.info("Configuring address %s on device %s", self.ip(), self.dev)
cmd = "ip addr add dev %s %s brd +" % (self.dev, self.ip())
subprocess.call(cmd, shell=True)
except Exception as e:
logging.info("Exception occurred ==> %s" % e)
else:
self.delete(self.ip())
self.post_configure(address) self.post_configure(address)
def post_configure(self, address): def post_configure(self, address):
@ -602,9 +610,8 @@ class CsIP:
if self.dev in bag.keys(): if self.dev in bag.keys():
for address in bag[self.dev]: for address in bag[self.dev]:
self.setAddress(address) self.setAddress(address)
if self.hasIP(ip): if (self.hasIP(ip) or self.is_guest_gateway(address, ip)) and address["add"]:
found = True logging.debug("The IP address in '%s' will be configured" % address)
if self.is_guest_gateway(address, ip):
found = True found = True
if not found: if not found:
self.delete(ip) self.delete(ip)
@ -620,7 +627,7 @@ class CsIP:
gw = interface.get_gateway() gw = interface.get_gateway()
logging.info("Interface has the following gateway ==> %s", gw) logging.info("Interface has the following gateway ==> %s", gw)
if bag['nw_type'] == "guest" and rip == gw: if bag['nw_type'] == "guest" and rip == gw:
return True return True
return False return False

View File

@ -27,17 +27,18 @@ def merge(dbag, ip):
for address in dbag[dev]: for address in dbag[dev]:
if address['public_ip'] == ip['public_ip']: if address['public_ip'] == ip['public_ip']:
dbag[dev].remove(address) dbag[dev].remove(address)
if ip['add']:
ipo = IPNetwork(ip['public_ip'] + '/' + ip['netmask']) ipo = IPNetwork(ip['public_ip'] + '/' + ip['netmask'])
ip['device'] = 'eth' + str(ip['nic_dev_id']) ip['device'] = 'eth' + str(ip['nic_dev_id'])
ip['broadcast'] = str(ipo.broadcast) ip['broadcast'] = str(ipo.broadcast)
ip['cidr'] = str(ipo.ip) + '/' + str(ipo.prefixlen) ip['cidr'] = str(ipo.ip) + '/' + str(ipo.prefixlen)
ip['size'] = str(ipo.prefixlen) ip['size'] = str(ipo.prefixlen)
ip['network'] = str(ipo.network) + '/' + str(ipo.prefixlen) ip['network'] = str(ipo.network) + '/' + str(ipo.prefixlen)
if 'nw_type' not in ip.keys(): if 'nw_type' not in ip.keys():
ip['nw_type'] = 'public' ip['nw_type'] = 'public'
if ip['nw_type'] == 'control': if ip['nw_type'] == 'control':
dbag['eth' + str(ip['nic_dev_id'])] = [ip] dbag['eth' + str(ip['nic_dev_id'])] = [ip]
else: else:
dbag.setdefault('eth' + str(ip['nic_dev_id']), []).append(ip) dbag.setdefault('eth' + str(ip['nic_dev_id']), []).append(ip)
return dbag return dbag

View File

@ -50,9 +50,14 @@ from nose.plugins.attrib import attr
from ddt import ddt, data from ddt import ddt, data
# Import System modules # Import System modules
import time import time
import logging
_multiprocess_shared_ = True _multiprocess_shared_ = True
logger = logging.getLogger('TestNetworkOps')
stream_handler = logging.StreamHandler()
logger.setLevel(logging.DEBUG)
logger.addHandler(stream_handler)
class TestPublicIP(cloudstackTestCase): class TestPublicIP(cloudstackTestCase):
@ -390,7 +395,7 @@ class TestPortForwarding(cloudstackTestCase):
) )
# SSH virtual machine to test port forwarding # SSH virtual machine to test port forwarding
try: try:
self.debug("SSHing into VM with IP address %s with NAT IP %s" % logger.debug("SSHing into VM with IP address %s with NAT IP %s" %
( (
self.virtual_machine.ipaddress, self.virtual_machine.ipaddress,
src_nat_ip_addr.ipaddress src_nat_ip_addr.ipaddress
@ -424,7 +429,7 @@ class TestPortForwarding(cloudstackTestCase):
# Check if the Public SSH port is inaccessible # Check if the Public SSH port is inaccessible
with self.assertRaises(Exception): with self.assertRaises(Exception):
self.debug( logger.debug(
"SSHing into VM with IP address %s after NAT rule deletion" % "SSHing into VM with IP address %s after NAT rule deletion" %
self.virtual_machine.ipaddress) self.virtual_machine.ipaddress)
@ -518,7 +523,7 @@ class TestPortForwarding(cloudstackTestCase):
) )
try: try:
self.debug("SSHing into VM with IP address %s with NAT IP %s" % logger.debug("SSHing into VM with IP address %s with NAT IP %s" %
( (
self.virtual_machine.ipaddress, self.virtual_machine.ipaddress,
ip_address.ipaddress.ipaddress ip_address.ipaddress.ipaddress
@ -538,11 +543,11 @@ class TestPortForwarding(cloudstackTestCase):
id=nat_rule.id id=nat_rule.id
) )
except CloudstackAPIException: except CloudstackAPIException:
self.debug("Nat Rule is deleted") logger.debug("Nat Rule is deleted")
# Check if the Public SSH port is inaccessible # Check if the Public SSH port is inaccessible
with self.assertRaises(Exception): with self.assertRaises(Exception):
self.debug( logger.debug(
"SSHing into VM with IP address %s after NAT rule deletion" % "SSHing into VM with IP address %s after NAT rule deletion" %
self.virtual_machine.ipaddress) self.virtual_machine.ipaddress)
@ -673,8 +678,8 @@ class TestRebootRouter(cloudstackTestCase):
# Retrieve router for the user account # Retrieve router for the user account
self.debug("Public IP: %s" % self.vm_1.ssh_ip) logger.debug("Public IP: %s" % self.vm_1.ssh_ip)
self.debug("Public IP: %s" % self.public_ip.ipaddress.ipaddress) logger.debug("Public IP: %s" % self.public_ip.ipaddress.ipaddress)
routers = list_routers( routers = list_routers(
self.apiclient, self.apiclient,
account=self.account.name, account=self.account.name,
@ -688,7 +693,7 @@ class TestRebootRouter(cloudstackTestCase):
router = routers[0] router = routers[0]
self.debug("Rebooting the router (ID: %s)" % router.id) logger.debug("Rebooting the router (ID: %s)" % router.id)
cmd = rebootRouter.rebootRouterCmd() cmd = rebootRouter.rebootRouterCmd()
cmd.id = router.id cmd.id = router.id
@ -710,7 +715,7 @@ class TestRebootRouter(cloudstackTestCase):
vm = list_vm_response[0] vm = list_vm_response[0]
if vm.state == 'Running': if vm.state == 'Running':
self.debug("VM state: %s" % vm.state) logger.debug("VM state: %s" % vm.state)
break break
if timeout == 0: if timeout == 0:
@ -722,7 +727,7 @@ class TestRebootRouter(cloudstackTestCase):
# we should be able to SSH after successful reboot # we should be able to SSH after successful reboot
try: try:
self.debug("SSH into VM (ID : %s ) after reboot" % self.vm_1.id) logger.debug("SSH into VM (ID : %s ) after reboot" % self.vm_1.id)
SshClient( SshClient(
self.public_ip.ipaddress.ipaddress, self.public_ip.ipaddress.ipaddress,
@ -825,7 +830,7 @@ class TestReleaseIP(cloudstackTestCase):
def test_releaseIP(self): def test_releaseIP(self):
"""Test for release public IP address""" """Test for release public IP address"""
self.debug("Deleting Public IP : %s" % self.ip_addr.id) logger.debug("Deleting Public IP : %s" % self.ip_addr.id)
self.ip_address.delete(self.apiclient) self.ip_address.delete(self.apiclient)
@ -854,9 +859,9 @@ class TestReleaseIP(cloudstackTestCase):
self.apiclient, self.apiclient,
id=self.nat_rule.id id=self.nat_rule.id
) )
self.debug("List NAT Rule response" + str(list_nat_rule)) logger.debug("List NAT Rule response" + str(list_nat_rule))
except CloudstackAPIException: except CloudstackAPIException:
self.debug("Port Forwarding Rule is deleted") logger.debug("Port Forwarding Rule is deleted")
# listLoadBalancerRules should not list # listLoadBalancerRules should not list
# associated rules with Public IP address # associated rules with Public IP address
@ -865,9 +870,9 @@ class TestReleaseIP(cloudstackTestCase):
self.apiclient, self.apiclient,
id=self.lb_rule.id id=self.lb_rule.id
) )
self.debug("List LB Rule response" + str(list_lb_rule)) logger.debug("List LB Rule response" + str(list_lb_rule))
except CloudstackAPIException: except CloudstackAPIException:
self.debug("Port Forwarding Rule is deleted") logger.debug("Port Forwarding Rule is deleted")
# SSH Attempt though public IP should fail # SSH Attempt though public IP should fail
with self.assertRaises(Exception): with self.assertRaises(Exception):
@ -982,7 +987,7 @@ class TestDeleteAccount(cloudstackTestCase):
domainid=self.account.domainid domainid=self.account.domainid
) )
except CloudstackAPIException: except CloudstackAPIException:
self.debug("Port Forwarding Rule is deleted") logger.debug("Port Forwarding Rule is deleted")
# ListPortForwardingRules should not # ListPortForwardingRules should not
# list associated rules with deleted account # list associated rules with deleted account
@ -993,7 +998,7 @@ class TestDeleteAccount(cloudstackTestCase):
domainid=self.account.domainid domainid=self.account.domainid
) )
except CloudstackAPIException: except CloudstackAPIException:
self.debug("NATRule is deleted") logger.debug("NATRule is deleted")
# Retrieve router for the user account # Retrieve router for the user account
try: try:
@ -1008,7 +1013,7 @@ class TestDeleteAccount(cloudstackTestCase):
"Check routers are properly deleted." "Check routers are properly deleted."
) )
except CloudstackAPIException: except CloudstackAPIException:
self.debug("Router is deleted") logger.debug("Router is deleted")
except Exception as e: except Exception as e:
raise Exception( raise Exception(
@ -1172,7 +1177,7 @@ class TestRouterRules(cloudstackTestCase):
) )
return return
def removeNetworkRules(self, rule, ipaddressobj): def removeNetworkRules(self, rule):
""" Remove specified rule on acquired public IP and """ Remove specified rule on acquired public IP and
default network of virtual machine default network of virtual machine
""" """
@ -1181,12 +1186,16 @@ class TestRouterRules(cloudstackTestCase):
if rule == STATIC_NAT_RULE: if rule == STATIC_NAT_RULE:
StaticNATRule.disable( StaticNATRule.disable(
self.apiclient, self.apiclient,
ipaddressobj.ipaddress.id) self.ipaddress.ipaddress.id)
elif rule == LB_RULE: elif rule == LB_RULE:
self.lb_rule.delete(self.apiclient) self.lb_rule.delete(self.apiclient)
else: else:
self.nat_rule.delete(self.apiclient) self.nat_rule.delete(self.apiclient)
logger.debug("Releasing IP %s from account %s" % (self.ipaddress.ipaddress.ipaddress, self.account.name))
self.ipaddress.delete(self.apiclient)
return return
@data(STATIC_NAT_RULE, NAT_RULE, LB_RULE) @data(STATIC_NAT_RULE, NAT_RULE, LB_RULE)
@ -1205,7 +1214,6 @@ class TestRouterRules(cloudstackTestCase):
domainid=self.account.domainid, domainid=self.account.domainid,
networkid=self.defaultNetworkId networkid=self.defaultNetworkId
) )
self.cleanup.append(self.ipaddress)
self.createNetworkRules(rule=value, self.createNetworkRules(rule=value,
ipaddressobj=self.ipaddress, ipaddressobj=self.ipaddress,
@ -1216,13 +1224,13 @@ class TestRouterRules(cloudstackTestCase):
listall=True)[0] listall=True)[0]
response = self.getCommandResultFromRouter(router, "ip addr") response = self.getCommandResultFromRouter(router, "ip addr")
self.debug(response) logger.debug(response)
stringToMatch = "inet %s" % self.ipaddress.ipaddress.ipaddress stringToMatch = "inet %s" % self.ipaddress.ipaddress.ipaddress
self.assertTrue(stringToMatch in str(response), "IP address is\ self.assertTrue(stringToMatch in str(response), "IP address is\
not removed from VR even after disabling statin NAT") not added to the VR!")
try: try:
self.debug("SSHing into VM with IP address %s with NAT IP %s" % logger.debug("SSHing into VM with IP address %s with NAT IP %s" %
( (
self.virtual_machine.ipaddress, self.virtual_machine.ipaddress,
self.ipaddress.ipaddress.ipaddress self.ipaddress.ipaddress.ipaddress
@ -1239,17 +1247,17 @@ class TestRouterRules(cloudstackTestCase):
# 1. listIpForwardingRules should not return the deleted rule anymore # 1. listIpForwardingRules should not return the deleted rule anymore
# 2. attempt to do ssh should now fail # 2. attempt to do ssh should now fail
self.removeNetworkRules(rule=value, ipaddressobj=self.ipaddress) self.removeNetworkRules(rule=value)
response = self.getCommandResultFromRouter(router, "ip addr") response = self.getCommandResultFromRouter(router, "ip addr")
self.debug(response) logger.debug(response)
stringToMatch = "inet %s" % self.ipaddress.ipaddress.ipaddress stringToMatch = "inet %s" % self.ipaddress.ipaddress.ipaddress
self.assertFalse(stringToMatch in str(response), "IP address is\ self.assertFalse(stringToMatch in str(response), "IP address is\
not removed from VR even after disabling statin NAT") not removed from VR even after disabling stat in NAT")
# Check if the Public SSH port is inaccessible # Check if the Public SSH port is inaccessible
with self.assertRaises(Exception): with self.assertRaises(Exception):
self.debug( logger.debug(
"SSHing into VM with IP address %s after NAT rule deletion" % "SSHing into VM with IP address %s after NAT rule deletion" %
self.virtual_machine.ipaddress) self.virtual_machine.ipaddress)