From 45642b83821ce0ecd6d4cddb76a77a2481e54d9a Mon Sep 17 00:00:00 2001 From: Wilder Rodrigues Date: Thu, 8 Oct 2015 14:19:26 +0200 Subject: [PATCH 1/4] CLOUDSTACK-8934 - Add default gateway when the public interface is up again --- .../config/opt/cloud/bin/cs/CsAddress.py | 8 +++--- .../config/opt/cloud/bin/cs/CsRedundant.py | 21 +++++++++++---- .../debian/config/opt/cloud/bin/ian.py | 27 ------------------- .../component/test_vpc_redundant.py | 5 ++-- 4 files changed, 23 insertions(+), 38 deletions(-) delete mode 100644 systemvm/patches/debian/config/opt/cloud/bin/ian.py diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py index 78ccb3a1fef..074a63f5823 100755 --- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py @@ -155,7 +155,7 @@ class CsInterface: return self.get_attr("netmask") def get_gateway(self): - if self.config.is_vpc(): + if self.config.is_vpc() or self.config.cmdline().is_redundant(): return self.get_attr("gateway") else: return self.config.cmdline().get_guest_gw() @@ -308,7 +308,7 @@ class CsIP: if not self.config.is_vpc(): self.setup_router_control() - if self.config.is_vpc(): + if self.config.is_vpc() or self.cl.is_redundant(): # The code looks redundant here, but we actually have to cater for routers and # VPC routers in a different manner. Please do not remove this block otherwise # The VPC default route will be broken. @@ -329,10 +329,10 @@ class CsIP: cmd2 = "ip link set %s up" % self.getDevice() # If redundant do not bring up public interfaces # master.py and keepalived deal with tham - if self.config.cmdline().is_redundant() and not self.is_public(): + if self.cl.is_redundant() and not self.is_public(): CsHelper.execute(cmd2) # if not redundant bring everything up - if not self.config.cmdline().is_redundant(): + if not self.cl.is_redundant(): CsHelper.execute(cmd2) def set_mark(self): diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsRedundant.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsRedundant.py index 0f71673e307..abe997c36fc 100755 --- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsRedundant.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsRedundant.py @@ -37,6 +37,7 @@ from CsFile import CsFile from CsProcess import CsProcess from CsApp import CsPasswdSvc from CsAddress import CsDevice +from CsRoute import CsRoute import socket from time import sleep @@ -267,16 +268,26 @@ class CsRedundant(object): ads = [o for o in self.address.get_ips() if o.is_public()] dev = '' + route = CsRoute() for o in ads: if dev == o.get_device(): continue - cmd2 = "ip link set %s up" % o.get_device() - if CsDevice(o.get_device(), self.config).waitfordevice(): + dev = o.get_device() + logging.info("Will proceed configuring device ==> %s" % dev) + cmd2 = "ip link set %s up" % dev + if CsDevice(dev, self.config).waitfordevice(): CsHelper.execute(cmd2) - dev = o.get_device() - logging.info("Bringing public interface %s up" % o.get_device()) + logging.info("Bringing public interface %s up" % dev) + + try: + gateway = o.get_gateway() + logging.info("Adding gateway ==> %s to device ==> %s" % (gateway, dev)) + route.add_defaultroute(gateway) + except: + logging.error("ERROR getting gateway from device %s" % dev) + else: - logging.error("Device %s was not ready could not bring it up" % o.get_device()) + logging.error("Device %s was not ready could not bring it up" % dev) # ip route add default via $gw table Table_$dev proto static cmd = "%s -C %s" % (self.CONNTRACKD_BIN, self.CONNTRACKD_CONF) diff --git a/systemvm/patches/debian/config/opt/cloud/bin/ian.py b/systemvm/patches/debian/config/opt/cloud/bin/ian.py deleted file mode 100644 index 186c5942b32..00000000000 --- a/systemvm/patches/debian/config/opt/cloud/bin/ian.py +++ /dev/null @@ -1,27 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -from cs.CsGuestNetwork import CsGuestNetwork -import merge - -merge.DataBag.DPATH = "." -csguestnetwork = CsGuestNetwork({}, {}) -csguestnetwork.guest = True -csguestnetwork.set_dns("1.1.1.1,2.2.2.2") -csguestnetwork.set_router("3.3.3.3") -dns = csguestnetwork.get_dns() -print dns diff --git a/test/integration/component/test_vpc_redundant.py b/test/integration/component/test_vpc_redundant.py index 11fabf697c8..6f82aece9ec 100644 --- a/test/integration/component/test_vpc_redundant.py +++ b/test/integration/component/test_vpc_redundant.py @@ -462,7 +462,8 @@ class TestVPCRedundancy(cloudstackTestCase): self.check_master_status(2) self.add_nat_rules() self.do_vpc_test(False) - + time.sleep(30) + self.stop_router_by_type("MASTER") # wait for the backup router to transit to master state time.sleep(30) @@ -476,7 +477,7 @@ class TestVPCRedundancy(cloudstackTestCase): self.start_routers() self.add_nat_rules() - time.sleep(45) + time.sleep(30) self.check_master_status(2) self.do_vpc_test(False) From 5d1cdc64409caed239f6814a8f73266c8e5eb6fe Mon Sep 17 00:00:00 2001 From: Wilder Rodrigues Date: Fri, 9 Oct 2015 13:31:32 +0200 Subject: [PATCH 2/4] CLOUDSTACK-8934 - Adding tests to cover default routes on IsoNest and RVR nets --- .../component/test_routers_network_ops.py | 827 ++++++------------ 1 file changed, 279 insertions(+), 548 deletions(-) diff --git a/test/integration/component/test_routers_network_ops.py b/test/integration/component/test_routers_network_ops.py index 7f1e4aa4434..95ede49baf2 100644 --- a/test/integration/component/test_routers_network_ops.py +++ b/test/integration/component/test_routers_network_ops.py @@ -26,9 +26,13 @@ from marvin.lib.utils import (cleanup_resources, from marvin.lib.base import (ServiceOffering, VirtualMachine, Account, - LoadBalancerRule, + ServiceOffering, + NATRule, + NetworkACL, FireWallRule, - NATRule) + PublicIPAddress, + NetworkOffering, + Network) from marvin.lib.common import (get_zone, get_template, get_domain, @@ -38,7 +42,6 @@ from marvin.lib.common import (get_zone, list_routers, list_nat_rules, list_publicIP, - list_lb_rules, list_firewall_rules, list_hosts) @@ -46,12 +49,12 @@ from marvin.lib.common import (get_zone, import time import logging -class TestCreatePFOnStoppedRouter(cloudstackTestCase): +class TestRedundantIsolateNetworks(cloudstackTestCase): @classmethod def setUpClass(cls): - cls.testClient = super(TestCreatePFOnStoppedRouter, cls).getClsTestClient() + cls.testClient = super(TestRedundantIsolateNetworks, cls).getClsTestClient() cls.api_client = cls.testClient.getApiClient() cls.services = cls.testClient.getParsedTestDataConfig() @@ -77,20 +80,22 @@ class TestCreatePFOnStoppedRouter(cloudstackTestCase): cls.api_client, cls.services["service_offering"] ) - cls.vm_1 = VirtualMachine.create( - cls.api_client, - cls.services["virtual_machine"], - templateid=template.id, - accountid=cls.account.name, - domainid=cls.account.domainid, - serviceofferingid=cls.service_offering.id - ) - cls._cleanup = [ - cls.account, - cls.service_offering - ] - cls.logger = logging.getLogger('TestCreatePFOnStoppedRouter') + cls.services["nw_off_persistent_RVR"]["egress_policy"] = "true" + + cls.network_offering = NetworkOffering.create( + cls.api_client, + cls.services["nw_off_persistent_RVR"], + conservemode=True + ) + cls.network_offering.update(cls.api_client, state='Enabled') + + cls._cleanup = [ + cls.service_offering, + cls.network_offering, + ] + + cls.logger = logging.getLogger('TestRedundantIsolateNetworks') cls.stream_handler = logging.StreamHandler() cls.logger.setLevel(logging.DEBUG) cls.logger.addHandler(cls.stream_handler) @@ -100,35 +105,263 @@ class TestCreatePFOnStoppedRouter(cloudstackTestCase): @classmethod def tearDownClass(cls): try: - cls.api_client = super( - TestCreatePFOnStoppedRouter, - cls).getClsTestClient().getApiClient() - # Clean up, terminate the created resources cleanup_resources(cls.api_client, cls._cleanup) - except Exception as e: raise Exception("Warning: Exception during cleanup : %s" % e) return def setUp(self): self.apiclient = self.testClient.getApiClient() + self.account = Account.create( + self.apiclient, + self.services["account"], + admin=True, + domainid=self.domain.id + ) self.cleanup = [] + self.cleanup.insert(0, self.account) return def tearDown(self): try: - # Clean up, terminate the created resources - cleanup_resources(self.apiclient, self.cleanup) + cleanup_resources(self.api_client, self.cleanup) except Exception as e: raise Exception("Warning: Exception during cleanup : %s" % e) return + @attr(tags=["advanced", "advancedns", "ssh"], required_hardware="true") + def test_RVR_Network_FW_PF_SSH_default_routes(self): + """ Test redundant router internals """ + self.logger.debug("Starting test_RVR_Network_FW_PF_SSH_default_routes...") - @attr(tags=["advanced", "advancedns"], required_hardware="true") - def test_01_CreatePFOnStoppedRouter(self): + self.logger.debug("Creating network with network offering: %s" % self.network_offering.id) + network = Network.create( + self.apiclient, + self.services["network"], + accountid=self.account.name, + domainid=self.account.domainid, + networkofferingid=self.network_offering.id, + zoneid=self.zone.id + ) + self.logger.debug("Created network with ID: %s" % network.id) + + networks = Network.list( + self.apiclient, + id=network.id, + listall=True + ) + self.assertEqual( + isinstance(networks, list), + True, + "List networks should return a valid response for created network" + ) + nw_response = networks[0] + + self.logger.debug("Network state: %s" % nw_response.state) + self.assertEqual( + nw_response.state, + "Allocated", + "The network should be in allocated state after creation" + ) + + self.logger.debug("Listing routers for network: %s" % network.name) + routers = Router.list( + self.apiclient, + networkid=network.id, + listall=True + ) + self.assertEqual( + routers, + None, + "Routers should not be spawned when network is in allocated state" + ) + + self.logger.debug("Deploying VM in account: %s" % self.account.name) + virtual_machine = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + networkids=[str(network.id)] + ) + self.logger.debug("Deployed VM in network: %s" % network.id) + + vms = VirtualMachine.list( + self.apiclient, + id=virtual_machine.id, + listall=True + ) + self.assertEqual( + isinstance(vms, list), + True, + "List Vms should return a valid list" + ) + vm = vms[0] + self.assertEqual( + vm.state, + "Running", + "VM should be in running state after deployment" + ) + + self.logger.debug("Listing routers for network: %s" % network.name) + routers = Router.list( + self.apiclient, + networkid=network.id, + listall=True + ) + self.assertEqual( + isinstance(routers, list), + True, + "list router should return Master and backup routers" + ) + self.assertEqual( + len(routers), + 2, + "Length of the list router should be 2 (Backup & master)" + ) + + self.logger.debug("Associating public IP for network: %s" % network.name) + public_ip = PublicIPAddress.create( + self.apiclient, + accountid=self.account.name, + zoneid=self.zone.id, + domainid=self.account.domainid, + networkid=network.id + ) + self.logger.debug("Associated %s with network %s" % ( + public_ip.ipaddress.ipaddress, + network.id + )) + + self.logger.debug("Creating Firewall rule for VM ID: %s" % virtual_machine.id) + FireWallRule.create( + self.apiclient, + ipaddressid=public_ip.id, + protocol=self.services["natrule"]["protocol"], + cidrlist=['0.0.0.0/0'], + startport=self.services["natrule"]["publicport"], + endport=self.services["natrule"]["publicport"] + ) + + self.logger.debug("Creating NAT rule for VM ID: %s" % virtual_machine.id) + nat_rule = NATRule.create( + self.apiclient, + virtual_machine, + self.services["natrule"], + public_ip.id + ) + + self.cleanup.insert(0, network) + self.cleanup.insert(0, virtual_machine) + + result = 'failed' + try: + ssh_command = "ping -c 3 8.8.8.8" + ssh = virtual_machine.get_ssh_client(ipaddress=public_ip.ipaddress.ipaddress, retries=5) + self.logger.debug("Ping to google.com from VM") + + result = str(ssh.execute(ssh_command)) + self.logger.debug("SSH result: %s; COUNT is ==> %s" % (result, result.count("3 packets received"))) + except: + self.fail("Failed to SSH into VM - %s" % (public_ip.ipaddress.ipaddress)) + + self.assertEqual( + result.count("3 packets received"), + 1, + "Ping to outside world from VM should be successful" + ) + + return + + +class TestIsolatedNetworks(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + + cls.testClient = super(TestIsolatedNetworks, cls).getClsTestClient() + cls.api_client = cls.testClient.getApiClient() + + cls.services = cls.testClient.getParsedTestDataConfig() + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client) + cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) + cls.services['mode'] = cls.zone.networktype + template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + + # Create an account, network, VM and IP addresses + cls.account = Account.create( + cls.api_client, + cls.services["account"], + admin=True, + domainid=cls.domain.id + ) + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) + + cls.services["network_offering"]["egress_policy"] = "true" + + cls.network_offering = NetworkOffering.create(cls.api_client, + cls.services["network_offering"], + conservemode=True) + + cls.network_offering.update(cls.api_client, state='Enabled') + + cls.network = Network.create(cls.api_client, + cls.services["network"], + accountid=cls.account.name, + domainid=cls.account.domainid, + networkofferingid=cls.network_offering.id, + zoneid=cls.zone.id) + + cls.vm_1 = VirtualMachine.create(cls.api_client, + cls.services["virtual_machine"], + templateid=template.id, + accountid=cls.account.name, + domainid=cls.domain.id, + serviceofferingid=cls.service_offering.id, + networkids=[str(cls.network.id)]) + + cls._cleanup = [ + cls.vm_1, + cls.network, + cls.network_offering, + cls.service_offering, + cls.account + ] + + cls.logger = logging.getLogger('TestIsolatedNetworks') + cls.stream_handler = logging.StreamHandler() + cls.logger.setLevel(logging.DEBUG) + cls.logger.addHandler(cls.stream_handler) + + return + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + return + + @attr(tags=["advanced", "advancedns", "ssh"], required_hardware="true") + def test_isolate_network_FW_PF_default_routes(self): """Stop existing router, add a PF rule and check we can access the VM """ - # Get router details associated for that account + self.logger.debug("Starting test_isolate_network_FW_PF_default_routes...") routers = list_routers( self.apiclient, account=self.account.name, @@ -140,35 +373,18 @@ class TestCreatePFOnStoppedRouter(cloudstackTestCase): True, "Check for list routers response return valid data" ) + self.assertNotEqual( len(routers), 0, "Check list router response" ) - router = routers[0] - self.logger.debug("Stopping router ID: %s" % router.id) - - # Stop the router - cmd = stopRouter.stopRouterCmd() - cmd.id = router.id - self.apiclient.stopRouter(cmd) - - routers = list_routers( - self.apiclient, - account=self.account.name, - domainid=self.account.domainid - ) - self.assertEqual( - isinstance(routers, list), - True, - "Check for list routers response return valid data" - ) router = routers[0] self.assertEqual( router.state, - 'Stopped', + 'Running', "Check list router response for router state" ) @@ -178,6 +394,7 @@ class TestCreatePFOnStoppedRouter(cloudstackTestCase): domainid=self.account.domainid, zoneid=self.zone.id ) + self.assertEqual( isinstance(public_ips, list), True, @@ -186,7 +403,7 @@ class TestCreatePFOnStoppedRouter(cloudstackTestCase): public_ip = public_ips[0] - # Open up firewall port for SSH + self.logger.debug("Creating Firewall rule for VM ID: %s" % self.vm_1.id) FireWallRule.create( self.apiclient, ipaddressid=public_ip.id, @@ -205,31 +422,6 @@ class TestCreatePFOnStoppedRouter(cloudstackTestCase): public_ip.id ) - self.logger.debug("Starting router ID: %s" % router.id) - # Start the router - cmd = startRouter.startRouterCmd() - cmd.id = router.id - self.apiclient.startRouter(cmd) - - routers = list_routers( - self.apiclient, - account=self.account.name, - domainid=self.account.domainid, - zoneid=self.zone.id - ) - self.assertEqual( - isinstance(routers, list), - True, - "Check for list routers response return valid data" - ) - router = routers[0] - - self.assertEqual( - router.state, - 'Running', - "Check list router response for router state" - ) - # NAT Rule should be in Active state after router start nat_rules = list_nat_rules( self.apiclient, id=nat_rule.id @@ -244,482 +436,21 @@ class TestCreatePFOnStoppedRouter(cloudstackTestCase): 'Active', "Check list port forwarding rules" ) + + result = 'failed' try: - + ssh_command = "ping -c 3 8.8.8.8" self.logger.debug("SSH into VM with ID: %s" % nat_rule.ipaddress) - self.vm_1.get_ssh_client( - ipaddress=nat_rule.ipaddress, - port=self.services["natrule"]["publicport"]) - except Exception as e: - self.fail( - "SSH Access failed for %s: %s" % - (nat_rule.ipaddress, e) - ) - return - - -class TestCreateLBOnStoppedRouter(cloudstackTestCase): - - @classmethod - def setUpClass(cls): - - cls.testClient = super(TestCreateLBOnStoppedRouter, cls).getClsTestClient() - cls.api_client = cls.testClient.getApiClient() - - cls.services = cls.testClient.getParsedTestDataConfig() - # Get Zone, Domain and templates - cls.domain = get_domain(cls.api_client) - cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) - cls.services['mode'] = cls.zone.networktype - template = get_template( - cls.api_client, - cls.zone.id, - cls.services["ostype"] - ) - cls.services["virtual_machine"]["zoneid"] = cls.zone.id - - # Create an account, network, VM and IP addresses - cls.account = Account.create( - cls.api_client, - cls.services["account"], - admin=True, - domainid=cls.domain.id - ) - cls.service_offering = ServiceOffering.create( - cls.api_client, - cls.services["service_offering"] - ) - cls.vm_1 = VirtualMachine.create( - cls.api_client, - cls.services["virtual_machine"], - templateid=template.id, - accountid=cls.account.name, - domainid=cls.account.domainid, - serviceofferingid=cls.service_offering.id - ) - cls._cleanup = [ - cls.account, - cls.service_offering - ] - - cls.logger = logging.getLogger('TestCreateLBOnStoppedRouter') - cls.stream_handler = logging.StreamHandler() - cls.logger.setLevel(logging.DEBUG) - cls.logger.addHandler(cls.stream_handler) - - return - - @classmethod - def tearDownClass(cls): - try: - cls.api_client = super( - TestCreateLBOnStoppedRouter, - cls).getClsTestClient().getApiClient() - # Clean up, terminate the created resources - cleanup_resources(cls.api_client, cls._cleanup) - - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return - - def setUp(self): - self.apiclient = self.testClient.getApiClient() - self.cleanup = [] - return - - def tearDown(self): - try: - cleanup_resources(self.apiclient, self.cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return - - @attr(tags=["advanced", "advancedns"], required_hardware="true") - def test_01_CreateLBOnStoppedRouter(self): - """Stop existing Router, add LB rule and check we can reach the VM""" - - # Get router details associated for that account - routers = list_routers( - self.apiclient, - account=self.account.name, - domainid=self.account.domainid - ) - - self.assertEqual( - isinstance(routers, list), - True, - "Check for list routers response return valid data" - ) - - self.assertNotEqual( - len(routers), - 0, - "Check list router response" - ) - - router = routers[0] - - self.logger.debug("Stopping router with ID: %s" % router.id) - # Stop the router - cmd = stopRouter.stopRouterCmd() - cmd.id = router.id - self.apiclient.stopRouter(cmd) - - routers = list_routers( - self.apiclient, - account=self.account.name, - domainid=self.account.domainid - ) - self.assertEqual( - isinstance(routers, list), - True, - "Check for list routers response return valid data" - ) - router = routers[0] - - self.assertEqual( - router.state, - 'Stopped', - "Check list router response for router state" - ) - - public_ips = list_publicIP( - self.apiclient, - account=self.account.name, - domainid=self.account.domainid - ) - self.assertEqual( - isinstance(public_ips, list), - True, - "Check for list public IPs response return valid data" - ) - public_ip = public_ips[0] - - # Open up firewall port for SSH - FireWallRule.create( - self.apiclient, - ipaddressid=public_ip.id, - protocol=self.services["lbrule"]["protocol"], - cidrlist=['0.0.0.0/0'], - startport=self.services["lbrule"]["publicport"], - endport=self.services["lbrule"]["publicport"] - ) - self.logger.debug("Creating LB rule for public IP: %s" % public_ip.id) - # Create Load Balancer rule and assign VMs to rule - lb_rule = LoadBalancerRule.create( - self.apiclient, - self.services["lbrule"], - public_ip.id, - accountid=self.account.name - ) - self.logger.debug("Assigning VM %s to LB rule: %s" % ( - self.vm_1.id, - lb_rule.id - )) - lb_rule.assign(self.apiclient, [self.vm_1]) - - # Start the router - cmd = startRouter.startRouterCmd() - cmd.id = router.id - self.apiclient.startRouter(cmd) - - routers = list_routers( - self.apiclient, - account=self.account.name, - domainid=self.account.domainid - ) - self.assertEqual( - isinstance(routers, list), - True, - "Check for list routers response return valid data" - ) - router = routers[0] - - self.assertEqual( - router.state, - 'Running', - "Check list router response for router state" - ) - # After router start, LB RUle should be in Active state - lb_rules = list_lb_rules( - self.apiclient, - id=lb_rule.id - ) - self.assertEqual( - isinstance(lb_rules, list), - True, - "Check for list LB rules response return valid data" - ) - self.assertEqual( - lb_rules[0].state, - 'Active', - "Check list load balancing rules" - ) - self.assertEqual( - lb_rules[0].publicport, - str(self.services["lbrule"]["publicport"]), - "Check list load balancing rules" - ) - - try: - self.logger.debug("SSH into VM with IP: %s" % public_ip.ipaddress) - self.vm_1.ssh_port = self.services["lbrule"]["publicport"] - self.vm_1.get_ssh_client(public_ip.ipaddress) - except Exception as e: - self.fail( - "SSH Access failed for %s: %s" % - (self.vm_1.ipaddress, e) - ) - return - - -class TestCreateFWOnStoppedRouter(cloudstackTestCase): - - @classmethod - def setUpClass(cls): - - cls.testClient = super(TestCreateFWOnStoppedRouter, cls).getClsTestClient() - cls.api_client = cls.testClient.getApiClient() - - cls.services = cls.testClient.getParsedTestDataConfig() - # Get Zone, Domain and templates - cls.domain = get_domain(cls.api_client) - cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) - cls.services['mode'] = cls.zone.networktype - template = get_template( - cls.api_client, - cls.zone.id, - cls.services["ostype"] - ) - cls.services["virtual_machine"]["zoneid"] = cls.zone.id - - # Create an account, network, VM and IP addresses - cls.account = Account.create( - cls.api_client, - cls.services["account"], - domainid=cls.domain.id - ) - cls.service_offering = ServiceOffering.create( - cls.api_client, - cls.services["service_offering"] - ) - cls.vm_1 = VirtualMachine.create( - cls.api_client, - cls.services["virtual_machine"], - templateid=template.id, - accountid=cls.account.name, - domainid=cls.account.domainid, - serviceofferingid=cls.service_offering.id - ) - cls._cleanup = [ - cls.account, - cls.service_offering - ] - - cls.logger = logging.getLogger('TestCreateFWOnStoppedRouter') - cls.stream_handler = logging.StreamHandler() - cls.logger.setLevel(logging.DEBUG) - cls.logger.addHandler(cls.stream_handler) - - return - - @classmethod - def tearDownClass(cls): - try: - cls.api_client = super( - TestCreateFWOnStoppedRouter, - cls).getClsTestClient().getApiClient() - # Clean up, terminate the created templates - cleanup_resources(cls.api_client, cls._cleanup) - - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return - - def tearDown(self): - try: - cleanup_resources(self.apiclient, self.cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return - - def setUp(self): - self.apiclient = self.testClient.getApiClient() - self.hypervisor = self.testClient.getHypervisorInfo() - self.cleanup = [] - return - - @attr(tags=["advanced", "advancedns"], required_hardware="true") - def test_01_CreateFWOnStoppedRouter(self): - """Stop existing Router, create Firewall rules and check that the rules are applied to the router""" - - # Get the router details associated with account - routers = list_routers( - self.apiclient, - account=self.account.name, - domainid=self.account.domainid - ) - - self.assertEqual( - isinstance(routers, list), - True, - "Check for list routers response return valid data" - ) - - self.assertNotEqual( - len(routers), - 0, - "Check list router response" - ) - - router = routers[0] - - self.logger.debug("Stopping the router: %s" % router.id) - # Stop the router - cmd = stopRouter.stopRouterCmd() - cmd.id = router.id - self.apiclient.stopRouter(cmd) - - routers = list_routers( - self.apiclient, - account=self.account.name, - domainid=self.account.domainid - ) - self.assertEqual( - isinstance(routers, list), - True, - "Check for list routers response return valid data" - ) - router = routers[0] - - self.assertEqual( - router.state, - 'Stopped', - "Check list router response for router state" - ) - - public_ips = list_publicIP( - self.apiclient, - account=self.account.name, - domainid=self.account.domainid - ) - self.assertEqual( - isinstance(public_ips, list), - True, - "Check for list public IP response return valid data" - ) - public_ip = public_ips[0] - - # Create Firewall rule with configurations from settings file - fw_rule = FireWallRule.create( - self.apiclient, - ipaddressid=public_ip.id, - protocol='TCP', - cidrlist=[self.services["fwrule"]["cidr"]], - startport=self.services["fwrule"]["startport"], - endport=self.services["fwrule"]["endport"] - ) - self.logger.debug("Created firewall rule: %s" % fw_rule.id) - - self.logger.debug("Starting the router: %s" % router.id) - # Start the router - cmd = startRouter.startRouterCmd() - cmd.id = router.id - self.apiclient.startRouter(cmd) - - routers = list_routers( - self.apiclient, - account=self.account.name, - domainid=self.account.domainid - ) - self.assertEqual( - isinstance(routers, list), - True, - "Check for list routers response return valid data" - ) - - router = routers[0] - - self.assertEqual( - router.state, - 'Running', - "Check list router response for router state" - ) - # After Router start, FW rule should be in Active state - fw_rules = list_firewall_rules( - self.apiclient, - id=fw_rule.id, - ) - self.assertEqual( - isinstance(fw_rules, list), - True, - "Check for list FW rules response return valid data" - ) - - self.assertEqual( - fw_rules[0].state, - 'Active', - "Check list load balancing rules" - ) - self.assertEqual( - fw_rules[0].startport, - str(self.services["fwrule"]["startport"]), - "Check start port of firewall rule" - ) - - self.assertEqual( - fw_rules[0].endport, - str(self.services["fwrule"]["endport"]), - "Check end port of firewall rule" - ) - # For DNS and DHCP check 'dnsmasq' process status - if (self.hypervisor.lower() == 'vmware' - or self.hypervisor.lower() == 'hyperv'): - result = get_process_status( - self.apiclient.connection.mgtSvr, - 22, - self.apiclient.connection.user, - self.apiclient.connection.passwd, - router.linklocalip, - 'iptables -t nat -L', - hypervisor=self.hypervisor - ) - else: - hosts = list_hosts( - self.apiclient, - id=router.hostid, - ) - self.assertEqual( - isinstance(hosts, list), - True, - "Check for list hosts response return valid data" - ) - host = hosts[0] - host.user = self.services["configurableData"]["host"]["username"] - host.passwd = self.services["configurableData"]["host"]["password"] - try: - result = get_process_status( - host.ipaddress, - 22, - host.user, - host.passwd, - router.linklocalip, - 'iptables -t nat -L' - ) - except KeyError: - self.skipTest( - "Provide a marvin config file with host\ - credentials to run %s" % - self._testMethodName) - - self.logger.debug("iptables -t nat -L: %s" % result) - self.logger.debug("Public IP: %s" % public_ip.ipaddress) - res = str(result) - self.assertEqual( - res.count(str(public_ip.ipaddress)), - 1, - "Check public IP address" - ) - + ssh = self.vm_1.get_ssh_client(ipaddress=nat_rule.ipaddress, port=self.services["natrule"]["publicport"], retries=5) + result = str(ssh.execute(ssh_command)) + self.logger.debug("SSH result: %s; COUNT is ==> %s" % (result, result.count("3 packets received"))) + except: + self.fail("Failed to SSH into VM - %s" % (public_ip.ipaddress.ipaddress)) + + self.assertEqual( + result.count("3 packets received"), + 1, + "Ping to outside world from VM should be successful" + ) return From b4dc392bfdf4fb93e1652203b7d4027651cca5ac Mon Sep 17 00:00:00 2001 From: Wilder Rodrigues Date: Fri, 9 Oct 2015 14:32:35 +0200 Subject: [PATCH 3/4] CLOUDSTACK-8934 - Fix default EGRESS rules for isolated networks - The default is Accept and will be changed based on the configuration of the offering. CLOUDSTACK-8934 - The default egress is set as Deny in the router. - We had to change it on the Java side in order to make the apply it once the default is defined as allowed on the net offering --- .../VirtualNetworkApplianceManagerImpl.java | 26 +++++++------------ .../debian/config/opt/cloud/bin/configure.py | 11 +++++--- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index c32aeba1a35..9eda2a2cdab 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -629,7 +629,7 @@ Configurable, StateListener { _agentMgr.registerForHostEvents(new SshKeysDistriMonitor(_agentMgr, _hostDao, _configDao), true, false, false); - List offerings = _serviceOfferingDao.createSystemServiceOfferings("System Offering For Software Router", + final List offerings = _serviceOfferingDao.createSystemServiceOfferings("System Offering For Software Router", ServiceOffering.routerDefaultOffUniqueName, 1, _routerRamSize, _routerCpuMHz, null, null, true, null, ProvisioningType.THIN, true, null, true, VirtualMachine.Type.DomainRouter, true); // this can sometimes happen, if DB is manually or programmatically manipulated @@ -1971,18 +1971,12 @@ Configurable, StateListener { } private void createDefaultEgressFirewallRule(final List rules, final long networkId) { - String systemRule = null; - - Boolean defaultEgressPolicy = false; final NetworkVO network = _networkDao.findById(networkId); final NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); - defaultEgressPolicy = offering.getEgressDefaultPolicy(); - - - // construct rule when egress policy is true. In true case for VR we default allow rule need to be added - if (!defaultEgressPolicy) { - systemRule = String.valueOf(FirewallRule.FirewallRuleType.System); + final Boolean defaultEgressPolicy = offering.getEgressDefaultPolicy(); + // The default on the router is set to Deny all. So, if the default configuration in the offering is set to treu (Allow), we change the Egress here + if (defaultEgressPolicy) { final List sourceCidr = new ArrayList(); sourceCidr.add(NetUtils.ALL_CIDRS); @@ -1991,12 +1985,10 @@ Configurable, StateListener { rules.add(rule); } else { - s_logger.debug(" Egress policy for the Network "+ networkId +" is "+defaultEgressPolicy + " So no need"+ - " of default rule is needed. "); + s_logger.debug("Egress policy for the Network " + networkId + " is already defined as Deny. So, no need to default the rule to Allow. "); } } - private void removeRevokedIpAliasFromDb(final List revokedIpAliasVOs) { for (final NicIpAliasVO ipalias : revokedIpAliasVOs) { _nicIpAliasDao.expunge(ipalias.getId()); @@ -2616,10 +2608,10 @@ Configurable, StateListener { final State newState = transition.getToState(); final VirtualMachine.Event event = transition.getEvent(); if (vo.getType() == VirtualMachine.Type.DomainRouter && - event == VirtualMachine.Event.FollowAgentPowerOnReport && - newState == State.Running && - isOutOfBandMigrated(opaque)) { - s_logger.debug("Virtual router " + vo.getInstanceName() + " is powered-on out-of-band"); + event == VirtualMachine.Event.FollowAgentPowerOnReport && + newState == State.Running && + isOutOfBandMigrated(opaque)) { + s_logger.debug("Virtual router " + vo.getInstanceName() + " is powered-on out-of-band"); } return true; diff --git a/systemvm/patches/debian/config/opt/cloud/bin/configure.py b/systemvm/patches/debian/config/opt/cloud/bin/configure.py index ae24ac56d8a..c3c4cae11e0 100755 --- a/systemvm/patches/debian/config/opt/cloud/bin/configure.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/configure.py @@ -123,24 +123,29 @@ class CsAcl(CsDataBag): " -p %s " % rule['protocol'] + " -m %s " % rule['protocol'] + " --dport %s -j RETURN" % rnge]) + + logging.debug("Current ACL IP direction is ==> %s", self.direction) if self.direction == 'egress': - self.fw.append(["filter", "", " -A FW_OUTBOUND -j FIREWALL_EGRESS_RULES"]) + self.fw.append(["filter", "", " -A FW_OUTBOUND -j FW_EGRESS_RULES"]) if rule['protocol'] == "icmp": self.fw.append(["filter", "front", - " -A FIREWALL_EGRESS_RULES" + + " -A FW_EGRESS_RULES" + " -s %s " % cidr + " -p %s " % rule['protocol'] + " -m %s " % rule['protocol'] + " --icmp-type %s -j %s" % (icmp_type, self.rule['action'])]) else: - fwr = " -A FIREWALL_EGRESS_RULES" + \ + fwr = " -A FW_EGRESS_RULES" + \ " -s %s " % cidr if rule['protocol'] != "all": fwr += "-p %s " % rule['protocol'] + \ " -m %s " % rule['protocol'] + \ " --dport %s" % rnge + self.fw.append(["filter", "front", "%s -j %s" % (fwr, rule['action'])]) + logging.debug("EGRESS rule configured for protocol ==> %s, action ==> %s", rule['protocol'], rule['action']) + class AclDevice(): """ A little class for each list of acls per device """ From cd8c3e97f594639292075d9a704dc7c382a103ca Mon Sep 17 00:00:00 2001 From: Wilder Rodrigues Date: Sat, 10 Oct 2015 12:02:47 +0200 Subject: [PATCH 4/4] CLOUDSTACK-8934 - Fix the AclIP class to make it configure the default FW policy --- .../VirtualNetworkApplianceManagerImpl.java | 2 +- .../debian/config/opt/cloud/bin/configure.py | 8 +++- .../component/test_routers_network_ops.py | 45 +++++++++---------- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 9eda2a2cdab..f0e5f0916b9 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -1975,7 +1975,7 @@ Configurable, StateListener { final NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); final Boolean defaultEgressPolicy = offering.getEgressDefaultPolicy(); - // The default on the router is set to Deny all. So, if the default configuration in the offering is set to treu (Allow), we change the Egress here + // The default on the router is set to Deny all. So, if the default configuration in the offering is set to true (Allow), we change the Egress here if (defaultEgressPolicy) { final List sourceCidr = new ArrayList(); diff --git a/systemvm/patches/debian/config/opt/cloud/bin/configure.py b/systemvm/patches/debian/config/opt/cloud/bin/configure.py index c3c4cae11e0..55a4b942bd0 100755 --- a/systemvm/patches/debian/config/opt/cloud/bin/configure.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/configure.py @@ -86,8 +86,14 @@ class CsAcl(CsDataBag): self.rule['first_port'] = obj['src_port_range'][0] self.rule['last_port'] = obj['src_port_range'][1] self.rule['allowed'] = True - self.rule['cidr'] = obj['source_cidr_list'] + + if self.rule['type'] == 'all' and not obj['source_cidr_list']: + self.rule['cidr'] = ['0.0.0.0/0'] + else: + self.rule['cidr'] = obj['source_cidr_list'] + self.rule['action'] = "ACCEPT" + logging.debug("AclIP created for rule ==> %s", self.rule) def create(self): for cidr in self.rule['cidr']: diff --git a/test/integration/component/test_routers_network_ops.py b/test/integration/component/test_routers_network_ops.py index 95ede49baf2..ba3e5e461f6 100644 --- a/test/integration/component/test_routers_network_ops.py +++ b/test/integration/component/test_routers_network_ops.py @@ -32,7 +32,8 @@ from marvin.lib.base import (ServiceOffering, FireWallRule, PublicIPAddress, NetworkOffering, - Network) + Network, + Router) from marvin.lib.common import (get_zone, get_template, get_domain, @@ -62,7 +63,7 @@ class TestRedundantIsolateNetworks(cloudstackTestCase): cls.domain = get_domain(cls.api_client) cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) cls.services['mode'] = cls.zone.networktype - template = get_template( + cls.template = get_template( cls.api_client, cls.zone.id, cls.services["ostype"] @@ -157,34 +158,17 @@ class TestRedundantIsolateNetworks(cloudstackTestCase): ) nw_response = networks[0] - self.logger.debug("Network state: %s" % nw_response.state) - self.assertEqual( - nw_response.state, - "Allocated", - "The network should be in allocated state after creation" - ) - - self.logger.debug("Listing routers for network: %s" % network.name) - routers = Router.list( - self.apiclient, - networkid=network.id, - listall=True - ) - self.assertEqual( - routers, - None, - "Routers should not be spawned when network is in allocated state" - ) - self.logger.debug("Deploying VM in account: %s" % self.account.name) virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], + templateid=self.template.id, accountid=self.account.name, domainid=self.account.domainid, serviceofferingid=self.service_offering.id, networkids=[str(network.id)] ) + self.logger.debug("Deployed VM in network: %s" % network.id) vms = VirtualMachine.list( @@ -234,10 +218,25 @@ class TestRedundantIsolateNetworks(cloudstackTestCase): network.id )) + public_ips = list_publicIP( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid, + zoneid=self.zone.id + ) + + self.assertEqual( + isinstance(public_ips, list), + True, + "Check for list public IPs response return valid data" + ) + + public_ip_1 = public_ips[0] + self.logger.debug("Creating Firewall rule for VM ID: %s" % virtual_machine.id) FireWallRule.create( self.apiclient, - ipaddressid=public_ip.id, + ipaddressid=public_ip_1.id, protocol=self.services["natrule"]["protocol"], cidrlist=['0.0.0.0/0'], startport=self.services["natrule"]["publicport"], @@ -249,7 +248,7 @@ class TestRedundantIsolateNetworks(cloudstackTestCase): self.apiclient, virtual_machine, self.services["natrule"], - public_ip.id + public_ip_1.id ) self.cleanup.insert(0, network)