mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-03 04:12:31 +01:00
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:
commit
be419211ec
@ -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;
|
||||
|
||||
@ -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 """
|
||||
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user