Merge pull request #923 from ekholabs/fix/default_routes_CLOUDSTACK-8934

CLOUDSTACK-8934 - Default routes not configured for rVPC and RVRThis PR fixes the default routes for redundant VPCs and isolated networks. New tests were introduced in order to make sure that the routers are working properly.

During the tests, I found out that the Firewall Egress was not working properly when creating the network offering with default allow. The bug has been fixed and tests for redundant and non-redundant isolated networks were added.

Test reports will follow in a separate comment.

* pr/923:
  CLOUDSTACK-8934 - Fix the AclIP class to make it configure the default FW policy
  CLOUDSTACK-8934 - Fix default EGRESS rules for isolated networks
  CLOUDSTACK-8934 - Adding tests to cover default routes on IsoNest and RVR nets
  CLOUDSTACK-8934 - Add default gateway when the public interface is up again

Signed-off-by: Remi Bergsma <github@remi.nl>
This commit is contained in:
Remi Bergsma 2015-10-13 22:38:34 +02:00
commit be419211ec
7 changed files with 331 additions and 613 deletions

View File

@ -629,7 +629,7 @@ Configurable, StateListener<State, VirtualMachine.Event, VirtualMachine> {
_agentMgr.registerForHostEvents(new SshKeysDistriMonitor(_agentMgr, _hostDao, _configDao), true, false, false);
List<ServiceOfferingVO> offerings = _serviceOfferingDao.createSystemServiceOfferings("System Offering For Software Router",
final List<ServiceOfferingVO> 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<State, VirtualMachine.Event, VirtualMachine> {
}
private void createDefaultEgressFirewallRule(final List<FirewallRule> 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 true (Allow), we change the Egress here
if (defaultEgressPolicy) {
final List<String> sourceCidr = new ArrayList<String>();
sourceCidr.add(NetUtils.ALL_CIDRS);
@ -1991,12 +1985,10 @@ Configurable, StateListener<State, VirtualMachine.Event, VirtualMachine> {
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<NicIpAliasVO> revokedIpAliasVOs) {
for (final NicIpAliasVO ipalias : revokedIpAliasVOs) {
_nicIpAliasDao.expunge(ipalias.getId());
@ -2616,10 +2608,10 @@ Configurable, StateListener<State, VirtualMachine.Event, VirtualMachine> {
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;

View File

@ -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']:
@ -123,24 +129,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 """

View File

@ -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):

View File

@ -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)

View File

@ -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

View File

@ -26,9 +26,14 @@ from marvin.lib.utils import (cleanup_resources,
from marvin.lib.base import (ServiceOffering,
VirtualMachine,
Account,
LoadBalancerRule,
ServiceOffering,
NATRule,
NetworkACL,
FireWallRule,
NATRule)
PublicIPAddress,
NetworkOffering,
Network,
Router)
from marvin.lib.common import (get_zone,
get_template,
get_domain,
@ -38,7 +43,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 +50,236 @@ 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()
# 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
cls.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["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)
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()
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:
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...")
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("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(
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
))
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_1.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_1.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()
@ -77,20 +305,39 @@ 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.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.account,
cls.service_offering
cls.vm_1,
cls.network,
cls.network_offering,
cls.service_offering,
cls.account
]
cls.logger = logging.getLogger('TestCreatePFOnStoppedRouter')
cls.logger = logging.getLogger('TestIsolatedNetworks')
cls.stream_handler = logging.StreamHandler()
cls.logger.setLevel(logging.DEBUG)
cls.logger.addHandler(cls.stream_handler)
@ -100,35 +347,20 @@ 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.cleanup = []
return
def tearDown(self):
try:
# Clean up, terminate the created resources
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_CreatePFOnStoppedRouter(self):
@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 +372,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 +393,7 @@ class TestCreatePFOnStoppedRouter(cloudstackTestCase):
domainid=self.account.domainid,
zoneid=self.zone.id
)
self.assertEqual(
isinstance(public_ips, list),
True,
@ -186,7 +402,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 +421,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 +435,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

View File

@ -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)