CLOUDSTACK-9075 - Adds VPC static routes test

- Adds redundant VPC tests
   - Adds support to Static Routes on VPC private gatways
   - Removes the route configuration in case static route is deleted.
This commit is contained in:
Wilder Rodrigues 2015-11-19 12:28:32 +01:00
parent 3e02b8999b
commit a17fa48de1
5 changed files with 344 additions and 78 deletions

View File

@ -2417,10 +2417,9 @@ Configurable, StateListener<State, VirtualMachine.Event, VirtualMachine> {
for (final Nic routerNic : routerNics) {
final Network network = _networkModel.getNetwork(routerNic.getNetworkId());
// Send network usage command for public nic in VPC VR
// Send network usage command for isolated guest nic of non VPC
// VR
if (forVpc && network.getTrafficType() == TrafficType.Public || !forVpc && network.getTrafficType() == TrafficType.Guest
&& network.getGuestType() == Network.GuestType.Isolated) {
// Send network usage command for isolated guest nic of non VPC VR
if (network != null && (forVpc && network.getTrafficType() == TrafficType.Public || !forVpc && network.getTrafficType() == TrafficType.Guest
&& network.getGuestType() == Network.GuestType.Isolated)) {
final NetworkUsageCommand usageCmd = new NetworkUsageCommand(privateIP, router.getHostName(), forVpc, routerNic.getIPv4Address());
final String routerType = router.getType().toString();
final UserStatisticsVO previousStats = _userStatsDao.findBy(router.getAccountId(), router.getDataCenterId(), network.getId(),

View File

@ -74,6 +74,27 @@ class CsPassword(CsDataBag):
logging.debug("Update password server result ==> %s" % result)
class CsStaticRoutes(CsDataBag):
def process(self):
logging.debug("Processing CsStaticRoutes file ==> %s" % self.dbag)
for item in self.dbag:
if item == "id":
continue
self.__update(self.dbag[item])
def __update(self, route):
if route['revoke']:
command = "route del -net %s gw %s" % (route['network'], route['gateway'])
result = CsHelper.execute(command)
else:
command = "ip route show | grep %s | awk '{print $1, $3}'" % route['network']
result = CsHelper.execute(command)
if not result:
route_command = "route add -net %s gw %s" % (route['network'], route['gateway'])
result = CsHelper.execute(route_command)
class CsAcl(CsDataBag):
"""
Deal with Network acls
@ -932,13 +953,17 @@ def main(argv):
mon = CsMonitor("monitorservice", config)
mon.process()
logging.debug("Configuring iptables rules .....")
logging.debug("Configuring iptables rules")
nf = CsNetfilters()
nf.compare(config.get_fw())
red = CsRedundant(config)
red.set()
logging.debug("Configuring static routes")
static_routes = CsStaticRoutes("staticroutes", config)
static_routes.process()
logging.debug("Configuring iptables rules done ...saving rules")
# Save iptables configuration - will be loaded on reboot by the iptables-restore that is configured on /etc/rc.local

View File

@ -0,0 +1,30 @@
# -- coding: utf-8 --
# 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 pprint import pprint
def merge(dbag, staticroutes):
for route in staticroutes['routes']:
key = route['ip_address']
revoke = route['revoke']
if revoke:
del dbag[key]
else:
dbag[key] = route
return dbag

View File

@ -34,6 +34,7 @@ import cs_forwardingrules
import cs_site2sitevpn
import cs_remoteaccessvpn
import cs_vpnusers
import cs_staticroutes
from pprint import pprint
@ -126,6 +127,8 @@ class updateDataBag:
dbag = self.process_remoteaccessvpn(self.db.getDataBag())
elif self.qFile.type == 'vpnuserlist':
dbag = self.process_vpnusers(self.db.getDataBag())
elif self.qFile.type == 'staticroutes':
dbag = self.process_staticroutes(self.db.getDataBag())
else:
logging.error("Error I do not know what to do with file of type %s", self.qFile.type)
return
@ -172,6 +175,9 @@ class updateDataBag:
def process_monitorservice(self, dbag):
return cs_monitorservice.merge(dbag, self.qFile.data)
def process_staticroutes(self, dbag):
return cs_staticroutes.merge(dbag, self.qFile.data)
def processVMpassword(self, dbag):
return cs_vmp.merge(dbag, self.qFile.data)

View File

@ -14,6 +14,7 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from marvin.cloudstackAPI.createStaticRoute import createStaticRouteCmd
""" Tests for Network ACLs in VPC
"""
#Import Local Modules
@ -87,7 +88,7 @@ class Services:
"NetworkACL": 'VpcVirtualRouter'
},
},
"redundsnt_vpc_offering": {
"redundant_vpc_offering": {
"name": 'Redundant VPC off',
"displaytext": 'Redundant VPC off',
"supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding,Vpn,Lb,UserData,StaticNat',
@ -133,11 +134,19 @@ class Services:
"publicport": 22,
"protocol": 'TCP',
},
"natrule": {
"privateport": 22,
"publicport": 22,
"startport": 22,
"endport": 22,
"protocol": "TCP",
"cidrlist": '0.0.0.0/0',
},
"ostype": 'CentOS 5.3 (64-bit)',
"timeout": 10,
}
class TestPrivateGWACL(cloudstackTestCase):
class TestPrivateGwACL(cloudstackTestCase):
@classmethod
def setUpClass(cls):
@ -163,7 +172,7 @@ class TestPrivateGWACL(cloudstackTestCase):
cls.services["service_offering"])
cls._cleanup = [cls.service_offering]
cls.logger = logging.getLogger('TestPrivateGWACL')
cls.logger = logging.getLogger('TestPrivateGwACL')
cls.stream_handler = logging.StreamHandler()
cls.logger.setLevel(logging.DEBUG)
cls.logger.addHandler(cls.stream_handler)
@ -179,13 +188,14 @@ class TestPrivateGWACL(cloudstackTestCase):
def setUp(self):
self.apiclient = self.testClient.getApiClient()
self.logger.debug("Creating Admin Account for Domain ID ==> %s" %self.domain.id)
self.logger.debug("Creating Admin Account for Domain ID ==> %s" % self.domain.id)
self.account = Account.create(
self.apiclient,
self.services["account"],
admin=True,
domainid=self.domain.id)
self.cleanup = []
return
def tearDown(self):
@ -195,89 +205,203 @@ class TestPrivateGWACL(cloudstackTestCase):
raise Exception("Warning: Exception during cleanup : %s" % e)
return
def _replaceAcl(self, command):
try:
successResponse = self.apiclient.replaceNetworkACLList(command);
except Exception as e:
self.fail("Failed to replace ACL list due to %s" % e)
self.assertTrue(successResponse.success, "Failed to replace ACL list.")
@attr(tags=["advanced"], required_hardware="true")
def test_01_vpc_privategw_acl(self):
self.logger.debug("Creating a VPC offering..")
self.vpc_off = VpcOffering.create(
vpc_off = VpcOffering.create(
self.apiclient,
self.services["vpc_offering"])
self.logger.debug("Enabling the VPC offering created")
self.vpc_off.update(self.apiclient, state='Enabled')
vpc_off.update(self.apiclient, state='Enabled')
self.logger.debug("Creating a VPC network in the account: %s" % self.account.name)
self.services["vpc"]["cidr"] = '10.1.1.1/16'
self.vpc = VPC.create(
self.apiclient,
self.services["vpc"],
vpcofferingid=self.vpc_off.id,
zoneid=self.zone.id,
account=self.account.name,
domainid=self.account.domainid)
vpc = self.createVPC(vpc_off)
self.cleanup = [self.vpc, self.vpc_off, self.account]
self.cleanup = [vpc, vpc_off, self.account]
self.createACL(self.vpc)
self.createACLItem()
self.createNetwork(self.vpc)
self.createPvtGw(self.vpc)
self.replaceacl()
physical_networks = get_physical_networks(self.apiclient, self.zone.id)
if not physical_networks:
self.fail("No Physical Networks found!")
vlans = physical_networks[0].vlan.split('-')
vlan_1 = int(vlans[0])
acl = self.createACL(vpc)
self.createACLItem(acl.id)
self.createNetwork(vpc)
privateGw = self.createPvtGw(vpc, "10.0.3.99", acl.id, vlan_1)
self.replacePvtGwACL(acl.id, privateGw.id)
@attr(tags=["advanced"], required_hardware="true")
def test_02_rvpc_privategw_acl(self):
def test_02_vpc_privategw_static_routes(self):
self.logger.debug("Creating a VPC offering..")
vpc_off = VpcOffering.create(
self.apiclient,
self.services["vpc_offering"])
self.logger.debug("Enabling the VPC offering created")
vpc_off.update(self.apiclient, state='Enabled')
self.performVPCTests(vpc_off)
@attr(tags=["advanced"], required_hardware="true")
def test_03_rvpc_privategw_static_routes(self):
self.skipTest("Redundant VPC Routers have to be fixed. Private Gateway not working yet.")
self.logger.debug("Creating a Redundant VPC offering..")
self.rvpc_off = VpcOffering.create(
vpc_off = VpcOffering.create(
self.apiclient,
self.services["redundant_vpc_offering"])
self.logger.debug("Enabling the Redundant VPC offering created")
self.rvpc_off.update(self.apiclient, state='Enabled')
vpc_off.update(self.apiclient, state='Enabled')
self.logger.debug("Creating a VPC network in the account: %s" % self.account.name)
self.services["vpc"]["cidr"] = '10.1.1.1/16'
self.rvpc = VPC.create(
self.apiclient,
self.services["vpc"],
vpcofferingid=self.rvpc_off.id,
zoneid=self.zone.id,
account=self.account.name,
domainid=self.account.domainid)
self.performVPCTests(vpc_off)
def performVPCTests(self, vpc_off):
self.logger.debug("Creating VPCs with offering ID %s" % vpc_off.id)
vpc_1 = self.createVPC(vpc_off, cidr = '10.0.1.0/24')
vpc_2 = self.createVPC(vpc_off, cidr = '10.0.2.0/24')
self.cleanup = [vpc_1, vpc_2, vpc_off, self.account]
physical_networks = get_physical_networks(self.apiclient, self.zone.id)
if not physical_networks:
self.fail("No Physical Networks found!")
vlans = physical_networks[0].vlan.split('-')
vlan_1 = int(vlans[0]) + 1
network_1 = self.createNetwork(vpc_1, gateway = '10.0.1.1')
network_2 = self.createNetwork(vpc_2, gateway = '10.0.2.1')
vm1 = self.createVM(network_1)
vm2 = self.createVM(network_2)
self.cleanup.insert(0, vm1)
self.cleanup.insert(0, vm2)
self.cleanup = [self.rvpc, self.rvpc_off, self.account]
self.createACL(self.rvpc)
self.createACLItem()
self.createNetwork(self.rvpc)
self.createPvtGw(self.rvpc)
self.replaceacl()
acl1 = self.createACL(vpc_1)
self.createACLItem(acl1.id, cidr = "0.0.0.0/0")
privateGw_1 = self.createPvtGw(vpc_1, "10.0.3.100", "10.0.3.101", acl1.id, vlan_1)
self.replacePvtGwACL(acl1.id, privateGw_1.id)
acl2 = self.createACL(vpc_2)
self.createACLItem(acl2.id, cidr = "0.0.0.0/0")
privateGw_2 = self.createPvtGw(vpc_2, "10.0.3.101", "10.0.3.100", acl2.id, vlan_1)
self.replacePvtGwACL(acl2.id, privateGw_2.id)
self.replaceNetworkAcl(acl1.id, network_1)
self.replaceNetworkAcl(acl2.id, network_2)
staticRoute_1 = self.createStaticRoute(privateGw_1.id, cidr = '10.0.2.0/24')
staticRoute_2 = self.createStaticRoute(privateGw_2.id, cidr = '10.0.1.0/24')
public_ip_1 = self.acquire_publicip(vpc_1, network_1)
public_ip_2 = self.acquire_publicip(vpc_2, network_2)
nat_rule_1 = self.create_natrule(vpc_1, vm1, public_ip_1, network_1)
nat_rule_2 = self.create_natrule(vpc_2, vm2, public_ip_2, network_2)
self.check_pvt_gw_connectivity(vm1, public_ip_1, vm2.nic[0].ipaddress)
self.check_pvt_gw_connectivity(vm2, public_ip_2, vm1.nic[0].ipaddress)
def createVPC(self, vpc_offering, cidr = '10.1.1.1/16'):
try:
self.logger.debug("Creating a VPC network in the account: %s" % self.account.name)
self.services["vpc"]["cidr"] = cidr
vpc = VPC.create(
self.apiclient,
self.services["vpc"],
vpcofferingid=vpc_offering.id,
zoneid=self.zone.id,
account=self.account.name,
domainid=self.account.domainid)
self.logger.debug("Created VPC with ID: %s" % vpc.id)
except Exception, e:
self.fail('Unable to create VPC due to %s ' % e)
return vpc
def createVM(self, network):
try:
self.logger.debug('Creating VM in network=%s' % network.name)
vm = 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("Created VM with ID: %s" % vm.id)
except Exception, e:
self.fail('Unable to create virtual machine due to %s ' % e)
return vm
def createStaticRoute(self, privateGwId, cidr = '10.0.0.0/16'):
staticRouteCmd = createStaticRoute.createStaticRouteCmd()
staticRouteCmd.cidr = cidr
staticRouteCmd.gatewayid = privateGwId
try:
staticRoute = self.apiclient.createStaticRoute(staticRouteCmd)
self.assertIsNotNone(staticRoute.id, "Failed to create static route.")
self.logger.debug("Created staticRoute with ID: %s" % staticRoute.id)
except Exception, e:
self.fail('Unable to create static route due to %s ' % e)
return staticRoute
def createACL(self, vpc):
createAclCmd = createNetworkACLList.createNetworkACLListCmd()
createAclCmd.name = "acl1"
createAclCmd.description = "new acl"
createAclCmd.name = "ACL-Test-%s" % vpc.id
createAclCmd.description = createAclCmd.name
createAclCmd.vpcid = vpc.id
createAclResponse = self.apiclient.createNetworkACLList(createAclCmd)
try:
acl = self.apiclient.createNetworkACLList(createAclCmd)
self.assertIsNotNone(acl.id, "Failed to create ACL.")
self.aclId = createAclResponse.id
self.logger.debug("Created ACL with ID: %s" % acl.id)
except Exception, e:
self.fail('Unable to create ACL due to %s ' % e)
self.assertIsNotNone(self.aclId, "Failed to create ACL.")
return acl
def createACLItem(self):
def createACLItem(self, aclId, cidr = "0.0.0.0/0"):
createAclItemCmd = createNetworkACL.createNetworkACLCmd()
createAclItemCmd.cidr = "0.0.0.0/0"
createAclItemCmd.protocol = "TCP"
createAclItemCmd.cidr = cidr
createAclItemCmd.protocol = "All"
createAclItemCmd.number = "1"
createAclItemCmd.action = "Deny"
createAclItemCmd.aclid = self.aclId
createAclItemResponse = self.apiclient.createNetworkACL(createAclItemCmd)
createAclItemCmd.action = "Allow"
createAclItemCmd.aclid = aclId
try:
aclItem = self.apiclient.createNetworkACL(createAclItemCmd)
self.assertIsNotNone(aclItem.id, "Failed to create ACL item.")
self.assertIsNotNone(createAclItemResponse.id, "Failed to create ACL item.")
self.logger.debug("Created ACL Item ID: %s" % aclItem.id)
except Exception, e:
self.fail('Unable to create ACL Item due to %s ' % e)
def createNetwork(self, vpc):
def createNetwork(self, vpc, gateway = '10.1.1.1'):
try:
self.logger.debug('Create NetworkOffering')
net_offerring = self.services["network_offering"]
net_offerring["name"] = "NET_OFF-10.1.1.1"
net_offerring["name"] = "NET_OFF-%s" % gateway
nw_off = NetworkOffering.create(
self.apiclient,
net_offerring,
@ -287,7 +411,7 @@ class TestPrivateGWACL(cloudstackTestCase):
self.logger.debug('Created and Enabled NetworkOffering')
self.services["network"]["name"] = "NETWORK-10.1.1.1"
self.services["network"]["name"] = "NETWORK-%s" % gateway
self.logger.debug('Adding Network=%s' % self.services["network"])
obj_network = Network.create(
@ -297,7 +421,7 @@ class TestPrivateGWACL(cloudstackTestCase):
domainid=self.account.domainid,
networkofferingid=nw_off.id,
zoneid=self.zone.id,
gateway="10.1.1.1",
gateway=gateway,
vpcid=vpc.id
)
@ -305,35 +429,117 @@ class TestPrivateGWACL(cloudstackTestCase):
except Exception, e:
self.fail('Unable to create a Network with offering=%s because of %s ' % (net_offerring, e))
self.network = obj_network
self.cleanup.insert(0, nw_off)
self.cleanup.insert(0, obj_network)
def createPvtGw(self, vpc):
return obj_network
def createPvtGw(self, vpc, ip_address, gateway, aclId, vlan):
physical_networks = get_physical_networks(self.apiclient, self.zone.id)
if not physical_networks:
self.fail("No Physical Networks found!")
self.logger.debug('::: Physical Networks ::: ==> %s' % physical_networks)
createPrivateGatewayCmd = createPrivateGateway.createPrivateGatewayCmd()
createPrivateGatewayCmd.physicalnetworkid = get_physical_networks(self.apiclient, self.zone.id)
createPrivateGatewayCmd.gateway = "10.147.30.1"
createPrivateGatewayCmd.physicalnetworkid = physical_networks[0].id
createPrivateGatewayCmd.gateway = gateway
createPrivateGatewayCmd.netmask = "255.255.255.0"
createPrivateGatewayCmd.ipaddress = "10.147.30.200"
createPrivateGatewayCmd.vlan = "30"
createPrivateGatewayCmd.ipaddress = ip_address
createPrivateGatewayCmd.vlan = vlan
createPrivateGatewayCmd.vpcid = vpc.id
createPrivateGatewayCmd.sourcenatsupported = "true"
createPrivateGatewayCmd.aclid = self.aclId
createPrivateGatewayCmd.sourcenatsupported = "false"
createPrivateGatewayCmd.aclid = aclId
try:
privateGatewayResponse = self.apiclient.createPrivateGateway(createPrivateGatewayCmd)
privateGw = self.apiclient.createPrivateGateway(createPrivateGatewayCmd)
except Exception as e:
self.fail("Failed to create Private Gateway ==> %s" % e)
self.privateGwId = privateGatewayResponse.id
self.assertIsNotNone(privateGw.id, "Failed to create ACL.")
return privateGw
self.assertIsNotNone(self.privateGwId, "Failed to create ACL.")
def replaceNetworkAcl(self, aclId, network):
self.logger.debug("Replacing Network ACL with ACL ID ==> %s" % aclId)
def replaceacl(self):
replaceNetworkACLListCmd = replaceNetworkACLList.replaceNetworkACLListCmd()
replaceNetworkACLListCmd.aclid = self.aclId
replaceNetworkACLListCmd.gatewayid = self.privateGwId
successResponse = self.apiclient.replaceNetworkACLList(replaceNetworkACLListCmd);
replaceNetworkACLListCmd.aclid = aclId
replaceNetworkACLListCmd.networkid = network.id
self.assertTrue(successResponse.success, "Failed to replace ACL list.")
self._replaceAcl(replaceNetworkACLListCmd)
def replacePvtGwACL(self, aclId, privateGwId):
self.logger.debug("Replacing Private GW ACL with ACL ID ==> %s" % aclId)
replaceNetworkACLListCmd = replaceNetworkACLList.replaceNetworkACLListCmd()
replaceNetworkACLListCmd.aclid = aclId
replaceNetworkACLListCmd.gatewayid = privateGwId
self._replaceAcl(replaceNetworkACLListCmd)
def acquire_publicip(self, vpc, network):
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,
vpcid=vpc.id
)
self.logger.debug("Associated %s with network %s" % (
public_ip.ipaddress.ipaddress,
network.id
))
return public_ip
def create_natrule(self, vpc, virtual_machine, public_ip, network):
self.logger.debug("Creating NAT rule in network for vm with public IP")
nat_service = self.services["natrule"]
nat_rule = NATRule.create(
self.apiclient,
virtual_machine,
nat_service,
ipaddressid=public_ip.ipaddress.id,
openfirewall=False,
networkid=network.id,
vpcid=vpc.id)
self.logger.debug("Adding NetworkACL rules to make NAT rule accessible")
nwacl_nat = NetworkACL.create(
self.apiclient,
networkid=network.id,
services=nat_service,
traffictype='Ingress'
)
self.logger.debug('nwacl_nat=%s' % nwacl_nat.__dict__)
return nat_rule
def check_pvt_gw_connectivity(self, virtual_machine, public_ip, vm_ip):
ssh_command = "ping -c 3 %s" % vm_ip
# Should be able to SSH VM
result = 'failed'
try:
self.logger.debug("SSH into VM: %s" % public_ip.ipaddress.ipaddress)
ssh = virtual_machine.get_ssh_client(ipaddress=public_ip.ipaddress.ipaddress)
self.logger.debug("Ping to VM inside another VPC")
result = str(ssh.execute(ssh_command))
self.logger.debug("SSH result: %s; COUNT is ==> %s" % (result, result.count("3 packets received")))
except Exception as e:
self.fail("SSH Access failed for %s: %s" % \
(vmObj.get_ip(), e)
)
self.assertEqual(
result.count("3 packets received"),
1,
"Ping to outside world from VM should be successful"
)