Merge release branch 4.7 to master

* 4.7:
  CLOUDSTACK-9154 - Sets the pub interface down when all guest nets are gone
  CLOUDSTACK-9187 - Makes code ready for more something like ethXXXX, if we ever get that far
  CLOUDSTACK-9188 -  Reads network GC interval and wait from configDao
  CLOUDSTACK-9187 - Fixes interface allocation to VRRP instances
  CLOUDSTACK-9187 - Adds test to cover multiple nics and nic removal
  CLOUDSTACK-9154 - Adds test to cover nics state after GC
  CLOUDSTACK-9154 - Returns the guest iterface that is marked as added

 Conflicts:
	engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
This commit is contained in:
Daan Hoogland 2016-01-17 20:04:11 +01:00
commit addb26455a
4 changed files with 646 additions and 541 deletions

View File

@ -48,15 +48,19 @@ class CsAddress(CsDataBag):
def get_guest_if(self): def get_guest_if(self):
""" """
Return CsInterface object for the lowest guest interface Return CsInterface object for the lowest in use guest interface
""" """
ipr = [] guest_interface = None
lowest_device = 1000
for ip in self.get_ips(): for ip in self.get_ips():
if ip.is_guest(): if ip.is_guest() and ip.is_added():
ipr.append(ip) device = ip.get_device()
if len(ipr) > 0: device_suffix = int(''.join([digit for digit in device if digit.isdigit()]))
return sorted(ipr)[-1] if device_suffix < lowest_device:
return None lowest_device = device_suffix
guest_interface = ip
logging.debug("Guest interface will be set on device '%s' and IP '%s'" % (guest_interface.get_device(), guest_interface.get_ip()))
return guest_interface
def get_guest_ip(self): def get_guest_ip(self):
""" """
@ -190,6 +194,9 @@ class CsInterface:
return True return True
return False return False
def is_added(self):
return self.get_attr("add")
def to_str(self): def to_str(self):
pprint(self.address) pprint(self.address)

View File

@ -81,8 +81,10 @@ class CsRedundant(object):
def _redundant_on(self): def _redundant_on(self):
guest = self.address.get_guest_if() guest = self.address.get_guest_if()
# No redundancy if there is no guest network # No redundancy if there is no guest network
if guest is None: if guest is None:
self.set_backup()
self._redundant_off() self._redundant_off()
return return
@ -108,7 +110,6 @@ class CsRedundant(object):
CsHelper.service("keepalived", "stop") CsHelper.service("keepalived", "stop")
return return
CsHelper.mkdir(self.CS_RAMDISK_DIR, 0755, False) CsHelper.mkdir(self.CS_RAMDISK_DIR, 0755, False)
CsHelper.mount_tmpfs(self.CS_RAMDISK_DIR) CsHelper.mount_tmpfs(self.CS_RAMDISK_DIR)
CsHelper.mkdir(self.CS_ROUTER_DIR, 0755, False) CsHelper.mkdir(self.CS_ROUTER_DIR, 0755, False)
@ -164,10 +165,14 @@ class CsRedundant(object):
conntrackd_conf = CsFile(self.CONNTRACKD_CONF) conntrackd_conf = CsFile(self.CONNTRACKD_CONF)
is_equals = conntrackd_tmpl.compare(conntrackd_conf) is_equals = conntrackd_tmpl.compare(conntrackd_conf)
force_keepalived_restart = False
proc = CsProcess(['/etc/conntrackd/conntrackd.conf']) proc = CsProcess(['/etc/conntrackd/conntrackd.conf'])
if not proc.find() or not is_equals:
if not proc.find() and not is_equals:
CsHelper.copy(conntrackd_template_conf, self.CONNTRACKD_CONF) CsHelper.copy(conntrackd_template_conf, self.CONNTRACKD_CONF)
CsHelper.service("conntrackd", "restart") CsHelper.service("conntrackd", "restart")
force_keepalived_restart = True
# Restore the template file and remove the backup. # Restore the template file and remove the backup.
CsHelper.copy(conntrackd_temp_bkp, conntrackd_template_conf) CsHelper.copy(conntrackd_temp_bkp, conntrackd_template_conf)
@ -185,7 +190,7 @@ class CsRedundant(object):
heartbeat_cron.commit() heartbeat_cron.commit()
proc = CsProcess(['/usr/sbin/keepalived']) proc = CsProcess(['/usr/sbin/keepalived'])
if not proc.find() or keepalived_conf.is_changed(): if not proc.find() or keepalived_conf.is_changed() or force_keepalived_restart:
keepalived_conf.commit() keepalived_conf.commit()
CsHelper.service("keepalived", "restart") CsHelper.service("keepalived", "restart")
@ -222,17 +227,21 @@ class CsRedundant(object):
self.set_lock() self.set_lock()
logging.info("Router switched to fault mode") logging.info("Router switched to fault mode")
ads = [o for o in self.address.get_ips() if o.is_public()]
for o in ads: ips = [ip for ip in self.address.get_ips() if ip.is_public()]
CsHelper.execute("ifconfig %s down" % o.get_device()) for ip in ips:
CsHelper.execute("ifconfig %s down" % ip.get_device())
cmd = "%s -C %s" % (self.CONNTRACKD_BIN, self.CONNTRACKD_CONF) cmd = "%s -C %s" % (self.CONNTRACKD_BIN, self.CONNTRACKD_CONF)
CsHelper.execute("%s -s" % cmd) CsHelper.execute("%s -s" % cmd)
CsHelper.service("ipsec", "stop") CsHelper.service("ipsec", "stop")
CsHelper.service("xl2tpd", "stop") CsHelper.service("xl2tpd", "stop")
CsHelper.service("dnsmasq", "stop") CsHelper.service("dnsmasq", "stop")
ads = [o for o in self.address.get_ips() if o.needs_vrrp()]
for o in ads: ips = [ip for ip in self.address.get_ips() if ip.needs_vrrp()]
CsPasswdSvc(o.get_gateway()).stop() for ip in ips:
CsPasswdSvc(ip.get_gateway()).stop()
self.cl.set_fault_state() self.cl.set_fault_state()
self.cl.save() self.cl.save()
self.release_lock() self.release_lock()
@ -246,22 +255,25 @@ class CsRedundant(object):
self.set_lock() self.set_lock()
logging.debug("Setting router to backup") logging.debug("Setting router to backup")
ads = [o for o in self.address.get_ips() if o.is_public()]
dev = '' dev = ''
for o in ads: ips = [ip for ip in self.address.get_ips() if ip.is_public()]
if dev == o.get_device(): for ip in ips:
if dev == ip.get_device():
continue continue
logging.info("Bringing public interface %s down" % o.get_device()) logging.info("Bringing public interface %s down" % ip.get_device())
cmd2 = "ip link set %s down" % o.get_device() cmd2 = "ip link set %s down" % ip.get_device()
CsHelper.execute(cmd2) CsHelper.execute(cmd2)
dev = o.get_device() dev = ip.get_device()
cmd = "%s -C %s" % (self.CONNTRACKD_BIN, self.CONNTRACKD_CONF) cmd = "%s -C %s" % (self.CONNTRACKD_BIN, self.CONNTRACKD_CONF)
CsHelper.execute("%s -d" % cmd) CsHelper.execute("%s -d" % cmd)
CsHelper.service("ipsec", "stop") CsHelper.service("ipsec", "stop")
CsHelper.service("xl2tpd", "stop") CsHelper.service("xl2tpd", "stop")
ads = [o for o in self.address.get_ips() if o.needs_vrrp()]
for o in ads: ips = [ip for ip in self.address.get_ips() if ip.needs_vrrp()]
CsPasswdSvc(o.get_gateway()).stop() for ip in ips:
CsPasswdSvc(ip.get_gateway()).stop()
CsHelper.service("dnsmasq", "stop") CsHelper.service("dnsmasq", "stop")
self.cl.set_master_state(False) self.cl.set_master_state(False)
@ -278,13 +290,13 @@ class CsRedundant(object):
self.set_lock() self.set_lock()
logging.debug("Setting router to master") logging.debug("Setting router to master")
ads = [o for o in self.address.get_ips() if o.is_public()]
dev = '' dev = ''
ips = [ip for ip in self.address.get_ips() if ip.is_public()]
route = CsRoute() route = CsRoute()
for o in ads: for ip in ips:
if dev == o.get_device(): if dev == ip.get_device():
continue continue
dev = o.get_device() dev = ip.get_device()
logging.info("Will proceed configuring device ==> %s" % dev) logging.info("Will proceed configuring device ==> %s" % dev)
cmd2 = "ip link set %s up" % dev cmd2 = "ip link set %s up" % dev
if CsDevice(dev, self.config).waitfordevice(): if CsDevice(dev, self.config).waitfordevice():
@ -292,7 +304,7 @@ class CsRedundant(object):
logging.info("Bringing public interface %s up" % dev) logging.info("Bringing public interface %s up" % dev)
try: try:
gateway = o.get_gateway() gateway = ip.get_gateway()
logging.info("Adding gateway ==> %s to device ==> %s" % (gateway, dev)) logging.info("Adding gateway ==> %s to device ==> %s" % (gateway, dev))
route.add_defaultroute(gateway) route.add_defaultroute(gateway)
except: except:
@ -341,13 +353,15 @@ class CsRedundant(object):
that could function as a router and VPC router at the same time that could function as a router and VPC router at the same time
""" """
lines = [] lines = []
for o in self.address.get_ips(): for ip in self.address.get_ips():
if o.needs_vrrp(): if ip.needs_vrrp():
cmdline=self.config.get_cmdline_instance() cmdline=self.config.get_cmdline_instance()
if not ip.is_added():
continue
if(cmdline.get_type()=='router'): if(cmdline.get_type()=='router'):
str = " %s brd %s dev %s\n" % (cmdline.get_guest_gw(), o.get_broadcast(), o.get_device()) str = " %s brd %s dev %s\n" % (cmdline.get_guest_gw(), ip.get_broadcast(), ip.get_device())
else: else:
str = " %s brd %s dev %s\n" % (o.get_gateway_cidr(), o.get_broadcast(), o.get_device()) str = " %s brd %s dev %s\n" % (ip.get_gateway_cidr(), ip.get_broadcast(), ip.get_device())
lines.append(str) lines.append(str)
return lines return lines

View File

@ -34,7 +34,8 @@ from marvin.lib.base import (stopRouter,
NetworkOffering, NetworkOffering,
Network, Network,
VirtualMachine, VirtualMachine,
LoadBalancerRule) LoadBalancerRule,
Configurations)
from marvin.lib.common import (get_domain, from marvin.lib.common import (get_domain,
get_zone, get_zone,
get_template, get_template,
@ -134,7 +135,7 @@ class Services:
"vpc": { "vpc": {
"name": "TestVPC", "name": "TestVPC",
"displaytext": "TestVPC", "displaytext": "TestVPC",
"cidr": '10.0.0.1/24' "cidr": '10.0.0.0/16'
}, },
"network": { "network": {
"name": "Test Network", "name": "Test Network",
@ -295,7 +296,7 @@ class TestVPCRedundancy(cloudstackTestCase):
len(self.routers), count, len(self.routers), count,
"Check that %s routers were indeed created" % count) "Check that %s routers were indeed created" % count)
def check_master_status(self,count=2, showall=False): def check_routers_state(self,count=2, status_to_check="MASTER", expected_count=1, showall=False):
vals = ["MASTER", "BACKUP", "UNKNOWN"] vals = ["MASTER", "BACKUP", "UNKNOWN"]
cnts = [0, 0, 0] cnts = [0, 0, 0]
@ -345,11 +346,11 @@ class TestVPCRedundancy(cloudstackTestCase):
"Marvin configuration has no host credentials to\ "Marvin configuration has no host credentials to\
check router services") check router services")
if result.count(vals[0]) == 1: if result.count(status_to_check) == 1:
cnts[vals.index(vals[0])] += 1 cnts[vals.index(status_to_check)] += 1
if cnts[vals.index('MASTER')] != 1: if cnts[vals.index(status_to_check)] != expected_count:
self.fail("No Master or too many master routers found %s" % cnts[vals.index('MASTER')]) self.fail("Expected '%s' routers at state '%s', but found '%s'!" % (expected_count, status_to_check, cnts[vals.index(status_to_check)]))
def stop_router(self, router): def stop_router(self, router):
self.logger.debug('Stopping router %s' % router.id) self.logger.debug('Stopping router %s' % router.id)
@ -364,14 +365,14 @@ class TestVPCRedundancy(cloudstackTestCase):
self.apiclient.rebootRouter(cmd) self.apiclient.rebootRouter(cmd)
def stop_router_by_type(self, type): def stop_router_by_type(self, type):
self.check_master_status(2) self.check_routers_state()
self.logger.debug('Stopping %s router' % type) self.logger.debug('Stopping %s router' % type)
for router in self.routers: for router in self.routers:
if router.redundantstate == type: if router.redundantstate == type:
self.stop_router(router) self.stop_router(router)
def reboot_router_by_type(self, type): def reboot_router_by_type(self, type):
self.check_master_status(2) self.check_routers_state()
self.logger.debug('Rebooting %s router' % type) self.logger.debug('Rebooting %s router' % type)
for router in self.routers: for router in self.routers:
if router.redundantstate == type: if router.redundantstate == type:
@ -387,7 +388,7 @@ class TestVPCRedundancy(cloudstackTestCase):
self.routers = [] self.routers = []
def start_routers(self): def start_routers(self):
self.check_master_status(2, showall=True) self.check_routers_state(showall=True)
self.logger.debug('Starting stopped routers') self.logger.debug('Starting stopped routers')
for router in self.routers: for router in self.routers:
self.logger.debug('Router %s has state %s' % (router.id, router.state)) self.logger.debug('Router %s has state %s' % (router.id, router.state))
@ -397,7 +398,9 @@ class TestVPCRedundancy(cloudstackTestCase):
cmd.id = router.id cmd.id = router.id
self.apiclient.startRouter(cmd) self.apiclient.startRouter(cmd)
def create_network(self, net_offerring, gateway='10.1.1.1', vpc=None): def create_network(self, net_offerring, gateway='10.1.1.1', vpc=None, nr_vms=2, mark_net_cleanup=True):
if not nr_vms or nr_vms <= 0:
self.fail("At least 1 VM has to be created. You informed nr_vms < 1")
try: try:
self.logger.debug('Create NetworkOffering') self.logger.debug('Create NetworkOffering')
net_offerring["name"] = "NET_OFF-" + str(gateway) net_offerring["name"] = "NET_OFF-" + str(gateway)
@ -428,16 +431,17 @@ class TestVPCRedundancy(cloudstackTestCase):
self.fail('Unable to create a Network with offering=%s because of %s ' % (net_offerring, e)) self.fail('Unable to create a Network with offering=%s because of %s ' % (net_offerring, e))
o = networkO(obj_network) o = networkO(obj_network)
vm1 = self.deployvm_in_network(obj_network) self.cleanup.insert(0, nw_off)
vm2 = self.deployvm_in_network(obj_network) if mark_net_cleanup:
self.cleanup.insert(2, obj_network) self.cleanup.insert(0, obj_network)
self.cleanup.insert(3, nw_off)
for i in range(0, nr_vms):
vm1 = self.deployvm_in_network(obj_network, mark_vm_cleanup=mark_net_cleanup)
o.add_vm(vm1) o.add_vm(vm1)
o.add_vm(vm2)
return o return o
def deployvm_in_network(self, network, host_id=None): def deployvm_in_network(self, network, host_id=None, mark_vm_cleanup=True):
try: try:
self.logger.debug('Creating VM in network=%s' % network.name) self.logger.debug('Creating VM in network=%s' % network.name)
vm = VirtualMachine.create( vm = VirtualMachine.create(
@ -451,6 +455,7 @@ class TestVPCRedundancy(cloudstackTestCase):
) )
self.logger.debug('Created VM=%s in network=%s' % (vm.id, network.name)) self.logger.debug('Created VM=%s in network=%s' % (vm.id, network.name))
if mark_vm_cleanup:
self.cleanup.insert(0, vm) self.cleanup.insert(0, vm)
return vm return vm
except: except:
@ -524,22 +529,22 @@ class TestVPCRedundancy(cloudstackTestCase):
self.query_routers() self.query_routers()
self.networks.append(self.create_network(self.services["network_offering"], "10.1.1.1")) self.networks.append(self.create_network(self.services["network_offering"], "10.1.1.1"))
self.networks.append(self.create_network(self.services["network_offering_no_lb"], "10.1.2.1")) self.networks.append(self.create_network(self.services["network_offering_no_lb"], "10.1.2.1"))
self.check_master_status(2) self.check_routers_state()
self.add_nat_rules() self.add_nat_rules()
self.do_vpc_test(False) self.do_vpc_test(False)
self.stop_router_by_type("MASTER") self.stop_router_by_type("MASTER")
self.check_master_status(1) self.check_routers_state(1)
self.do_vpc_test(False) self.do_vpc_test(False)
self.delete_nat_rules() self.delete_nat_rules()
self.check_master_status(1) self.check_routers_state(count=1)
self.do_vpc_test(True) self.do_vpc_test(True)
self.delete_public_ip() self.delete_public_ip()
self.start_routers() self.start_routers()
self.add_nat_rules() self.add_nat_rules()
self.check_master_status(2) self.check_routers_state()
self.do_vpc_test(False) self.do_vpc_test(False)
@attr(tags=["advanced", "intervlan"], required_hardware="true") @attr(tags=["advanced", "intervlan"], required_hardware="true")
@ -549,7 +554,7 @@ class TestVPCRedundancy(cloudstackTestCase):
self.query_routers() self.query_routers()
self.networks.append(self.create_network(self.services["network_offering"], "10.1.1.1")) self.networks.append(self.create_network(self.services["network_offering"], "10.1.1.1"))
self.networks.append(self.create_network(self.services["network_offering_no_lb"], "10.1.2.1")) self.networks.append(self.create_network(self.services["network_offering_no_lb"], "10.1.2.1"))
self.check_master_status(2) self.check_routers_state()
self.add_nat_rules() self.add_nat_rules()
self.do_default_routes_test() self.do_default_routes_test()
@ -559,18 +564,89 @@ class TestVPCRedundancy(cloudstackTestCase):
self.logger.debug("Starting test_01_create_redundant_VPC_2tiers_4VMs_4IPs_4PF_ACL") self.logger.debug("Starting test_01_create_redundant_VPC_2tiers_4VMs_4IPs_4PF_ACL")
self.query_routers() self.query_routers()
self.networks.append(self.create_network(self.services["network_offering"], "10.1.1.1")) self.networks.append(self.create_network(self.services["network_offering"], "10.1.1.1"))
self.check_master_status(2) self.check_routers_state()
self.add_nat_rules() self.add_nat_rules()
self.do_vpc_test(False) self.do_vpc_test(False)
self.reboot_router_by_type("MASTER") self.reboot_router_by_type("MASTER")
self.check_master_status(2) self.check_routers_state()
self.do_vpc_test(False) self.do_vpc_test(False)
self.reboot_router_by_type("MASTER") self.reboot_router_by_type("MASTER")
self.check_master_status(2) self.check_routers_state()
self.do_vpc_test(False) self.do_vpc_test(False)
@attr(tags=["advanced", "intervlan"], required_hardware="true")
def test_04_rvpc_network_garbage_collector_nics(self):
""" Create a redundant VPC with 1 Tier, 1 VM, 1 ACL, 1 PF and test Network GC Nics"""
self.logger.debug("Starting test_04_rvpc_network_garbage_collector_nics")
self.query_routers()
self.networks.append(self.create_network(self.services["network_offering"], "10.1.1.1", nr_vms=1))
self.check_routers_state()
self.add_nat_rules()
self.do_vpc_test(False)
self.stop_vm()
gc_wait = Configurations.list(self.apiclient, name="network.gc.wait")
gc_interval = Configurations.list(self.apiclient, name="network.gc.interval")
self.logger.debug("network.gc.wait is ==> %s" % gc_wait)
self.logger.debug("network.gc.interval is ==> %s" % gc_wait)
total_sleep = 120
if gc_wait and gc_interval:
total_sleep = int(gc_wait[0].value) + int(gc_interval[0].value)
else:
self.logger.debug("Could not retrieve the keys 'network.gc.interval' and 'network.gc.wait'. Sleeping for 2 minutes.")
time.sleep(total_sleep * 3)
self.check_routers_state(status_to_check="BACKUP", expected_count=2)
self.start_vm()
self.check_routers_state(status_to_check="MASTER")
@attr(tags=["advanced", "intervlan"], required_hardware="true")
def test_05_rvpc_multi_tiers(self):
""" Create a redundant VPC with 1 Tier, 1 VM, 1 ACL, 1 PF and test Network GC Nics"""
self.logger.debug("Starting test_04_rvpc_network_garbage_collector_nics")
self.query_routers()
network = self.create_network(self.services["network_offering"], "10.1.1.1", nr_vms=1, mark_net_cleanup=False)
self.networks.append(network)
self.networks.append(self.create_network(self.services["network_offering_no_lb"], "10.1.2.1", nr_vms=1))
self.networks.append(self.create_network(self.services["network_offering_no_lb"], "10.1.3.1", nr_vms=1))
self.check_routers_state()
self.add_nat_rules()
self.do_vpc_test(False)
self.destroy_vm(network)
network.get_net().delete(self.apiclient)
self.networks.remove(network)
self.check_routers_state(status_to_check="MASTER")
self.do_vpc_test(False)
def destroy_vm(self, network):
vms_to_delete = []
for vm in network.get_vms():
vm.get_vm().delete(self.apiclient, expunge=True)
vms_to_delete.append(vm)
all_vms = network.get_vms()
[all_vms.remove(vm) for vm in vms_to_delete]
def stop_vm(self):
for o in self.networks:
for vm in o.get_vms():
vm.get_vm().stop(self.apiclient)
def start_vm(self):
for o in self.networks:
for vm in o.get_vms():
vm.get_vm().start(self.apiclient)
def delete_nat_rules(self): def delete_nat_rules(self):
for o in self.networks: for o in self.networks:
for vm in o.get_vms(): for vm in o.get_vms():