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):
"""
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():
if ip.is_guest():
ipr.append(ip)
if len(ipr) > 0:
return sorted(ipr)[-1]
return None
if ip.is_guest() and ip.is_added():
device = ip.get_device()
device_suffix = int(''.join([digit for digit in device if digit.isdigit()]))
if device_suffix < lowest_device:
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):
"""
@ -190,6 +194,9 @@ class CsInterface:
return True
return False
def is_added(self):
return self.get_attr("add")
def to_str(self):
pprint(self.address)

View File

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

View File

@ -34,7 +34,8 @@ from marvin.lib.base import (stopRouter,
NetworkOffering,
Network,
VirtualMachine,
LoadBalancerRule)
LoadBalancerRule,
Configurations)
from marvin.lib.common import (get_domain,
get_zone,
get_template,
@ -134,7 +135,7 @@ class Services:
"vpc": {
"name": "TestVPC",
"displaytext": "TestVPC",
"cidr": '10.0.0.1/24'
"cidr": '10.0.0.0/16'
},
"network": {
"name": "Test Network",
@ -295,7 +296,7 @@ class TestVPCRedundancy(cloudstackTestCase):
len(self.routers), 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"]
cnts = [0, 0, 0]
@ -345,11 +346,11 @@ class TestVPCRedundancy(cloudstackTestCase):
"Marvin configuration has no host credentials to\
check router services")
if result.count(vals[0]) == 1:
cnts[vals.index(vals[0])] += 1
if result.count(status_to_check) == 1:
cnts[vals.index(status_to_check)] += 1
if cnts[vals.index('MASTER')] != 1:
self.fail("No Master or too many master routers found %s" % cnts[vals.index('MASTER')])
if cnts[vals.index(status_to_check)] != expected_count:
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):
self.logger.debug('Stopping router %s' % router.id)
@ -364,14 +365,14 @@ class TestVPCRedundancy(cloudstackTestCase):
self.apiclient.rebootRouter(cmd)
def stop_router_by_type(self, type):
self.check_master_status(2)
self.check_routers_state()
self.logger.debug('Stopping %s router' % type)
for router in self.routers:
if router.redundantstate == type:
self.stop_router(router)
def reboot_router_by_type(self, type):
self.check_master_status(2)
self.check_routers_state()
self.logger.debug('Rebooting %s router' % type)
for router in self.routers:
if router.redundantstate == type:
@ -387,7 +388,7 @@ class TestVPCRedundancy(cloudstackTestCase):
self.routers = []
def start_routers(self):
self.check_master_status(2, showall=True)
self.check_routers_state(showall=True)
self.logger.debug('Starting stopped routers')
for router in self.routers:
self.logger.debug('Router %s has state %s' % (router.id, router.state))
@ -397,7 +398,9 @@ class TestVPCRedundancy(cloudstackTestCase):
cmd.id = router.id
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:
self.logger.debug('Create NetworkOffering')
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))
o = networkO(obj_network)
vm1 = self.deployvm_in_network(obj_network)
vm2 = self.deployvm_in_network(obj_network)
self.cleanup.insert(2, obj_network)
self.cleanup.insert(3, nw_off)
self.cleanup.insert(0, nw_off)
if mark_net_cleanup:
self.cleanup.insert(0, obj_network)
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(vm2)
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:
self.logger.debug('Creating VM in network=%s' % network.name)
vm = VirtualMachine.create(
@ -451,6 +455,7 @@ class TestVPCRedundancy(cloudstackTestCase):
)
self.logger.debug('Created VM=%s in network=%s' % (vm.id, network.name))
if mark_vm_cleanup:
self.cleanup.insert(0, vm)
return vm
except:
@ -524,22 +529,22 @@ class TestVPCRedundancy(cloudstackTestCase):
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_no_lb"], "10.1.2.1"))
self.check_master_status(2)
self.check_routers_state()
self.add_nat_rules()
self.do_vpc_test(False)
self.stop_router_by_type("MASTER")
self.check_master_status(1)
self.check_routers_state(1)
self.do_vpc_test(False)
self.delete_nat_rules()
self.check_master_status(1)
self.check_routers_state(count=1)
self.do_vpc_test(True)
self.delete_public_ip()
self.start_routers()
self.add_nat_rules()
self.check_master_status(2)
self.check_routers_state()
self.do_vpc_test(False)
@attr(tags=["advanced", "intervlan"], required_hardware="true")
@ -549,7 +554,7 @@ class TestVPCRedundancy(cloudstackTestCase):
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_no_lb"], "10.1.2.1"))
self.check_master_status(2)
self.check_routers_state()
self.add_nat_rules()
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.query_routers()
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.do_vpc_test(False)
self.reboot_router_by_type("MASTER")
self.check_master_status(2)
self.check_routers_state()
self.do_vpc_test(False)
self.reboot_router_by_type("MASTER")
self.check_master_status(2)
self.check_routers_state()
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):
for o in self.networks:
for vm in o.get_vms():