mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
This PR contains 3 features - IPv4 Static Routing (Routed mode) #9346 Design document: https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=306153967 - AS Numbers Management #9410 Design Document: https://cwiki.apache.org/confluence/display/CLOUDSTACK/BGP+AS+Numbers+Management - Dynamic routing Design Document: https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=315492858 - Document: https://github.com/apache/cloudstack-documentation/pull/419 Rename nsx mode to routing mode by ``` git grep -l nsx_mode |xargs sed -i "s/nsx_mode/routing_mode/g" git grep -l nsxmode |xargs sed -i "s/nsxmode/routingmode/g" git grep -l nsxMode |xargs sed -i "s/nsxMode/routingMode/g" git grep -l NsxMode |xargs sed -i "s/NsxMode/RoutingMode/g" ``` - re-organize sql changes - fix NPE as rules do not have public ip - fix missing destination cidr in ingress rules - disable network usage for routed network - fix DB exception as network_id is -1 during network creation - apply ingress/egress routing rules - VR changes to configure nft rules for isolated network - VR: setup nft rule for control network - VR: flush all iptables rules - fix NPE which is because ingress rules do not have public ip associated - fix dest cidr is missing in nft tables - add ip4 routing and ip4 routes to list network and list vpc response - fix ingress rule is missing when vr is restarted - fix icmp types in nft rules - add tab to manage routing firewall rules - fix ingress rules are not applied when VR is restarted - add default rules in FORWARD chain - fix create vpc offerings - fix public ip is not assigned to vpc - fix network offering is not listed when create vpc tier - add is_routing to boot args of vpc vr - remove table ip4_firewall in vpc vr - release or remove subnet when remove a network - implemenent fw_vpcrouter_routing - fix wrong ip familty when flush ipv4 rules - fix acl rules are not applied due to wrong version (should be 6 which means ip6 rules are removed) - add default rules for vpc tiers so that tcp connections (e.g. ssh) work - append policy rules after default rules - remove /usr/local/cloud/systemvm/ in routers - throw an exception when allocate subnet with cidrsize - fix some TODOs - add new parameters to update API - return type Ipv4GuestSubnetNetworkMap when get or create subnet - fix firewall rules are broken - add domain_id and account_id to db - add domain/account/project to ipv4 subnet response - create ipv4 subnet for domain/account/project - check conflict when update ipv4 subnet - ui changes - add parent subnet to response - add list for ipv4 subnet - implement some methods - fix list subnets for guest networks by zoneid - UI changes - fix delete ipv4 subnet for network - fix ipv4 subnet is set to zone guest network cidr if cidrsize is specified - add zone info to response if parent subnet is null but network is not - fix gateway/cidr is not set when create network with cidrsize - fix order of nft rules in the VRs * Routed v24 - add classes in marvin base.py * Routed v25 - add test_01_subnet_zone - fix dedicate to domain/account failure - list subnets for network by keyword and subnet * Routed v26: implement subnet auto-allocation - add utils for split ip ranges into small subnets - add utils to get start/end ip of a cidr - implement subnet auto-generation - add global settings * Routed 27: add subnet for VPC - add db column for vpc_id - add db record for vpc - remove db record when delete a vpc - add checkConflicts methods - remove duplicated settings - check ipv4 cidr when create subnet * Routed v28: update smoke tests - update test_ipv4_routing.py - search subnets by networkid * Routed 29: fix vpc and add more tests - fix createnetwork in vpc - add vpc id/name to response - fix zone id/name are not displayed in some cases - add smoke test for vpc - add smoke tests for failed cases - add smoke test for connectivity checks - marvin: add "-q" to ssh command * Routed 31: ui and smoke tests - UI: add link to network in list view - add nftables rules check in VRs * Routed 32: add chain OUTPUT and more rules - fix the issue 80/443/8080 is not reachable from VR itself ``` 2024-06-27 10:21:52,121 INFO Executing: systemctl start cloud-password-server@172.31.1.1 2024-06-27 10:21:52,128 INFO Service cloud-password-server@172.31.1.1 start 2024-06-27 10:21:52,129 INFO Executing: ps aux 2024-06-27 10:24:02,175 ERROR Failed to update password server due to: <urlopen error [Errno 110] Connection timed out> ``` * Routed: fix dns search from VMs in Isolated networks * Routed: fix VPC dns issue due to gateway IP is missing in cloud.conf This is caused by NSX integration, and fixed by https://github.com/apache/cloudstack/pull/9102/ * Routed: rename routing_mode to network_mode * Routed: replace centos5.5 template in smoke test as dhclient does not work in the vms // this does not work refer to https://dominikrys.com/posts/disable-udp-checksum-validation/#ignoring-udp-checksums-with-nftables and https://forum.openwrt.org/t/udp-checksum-with-nftables/161522/11 the vm should have checksum offloading disabled * Routed: fix smoke test due to wrong cidrlist of egress rules and missing ingress rule from VR * PR 9346: fix lint error schema-41910to42000.sql * PR 9346: ui polish v1 * PR 9346: create VPC with cidrsize * Routed: fix test failures with test_network_ipv6 and test_vpc_ipv6 due to 'ssh -q' * Routed: fix /usr/local/cloud/systemvm/ are removed after SSVM/CPVM reboot * Routed: fix IP of additional nics of VPC VR is not gateway * PR 9346: fix cidrsize check when create VPC with cidrsize * Routed: fix test/integration/smoke/test_ipv4_routing.py:279:16: E713 test for membership should be 'not in' * PR9346: fix/Update api * PR 9346: set response object name * PR9346: UI refactor and small fixes * PR9346: change return type of getNetworkMode * PR9346: move IPv4 subnet to seperated tab * PR9346: revert IpRangesTabGuest.vue back to original * PR9346: fix remove ipv4 subnet on UI * PR9346: fix test_ipv4_routing.py * AS Number Range Management * Create AS Number Range for a Zone * Fix build * Add ListASNRange and fix create ASN range * Add List AS numbers * Add UI for AS Numbers * Fix UI and filter AS Numbers * Add AS Number on Isolated network creation and refactor UI and response * Release AS Number * Add network offering new columns * Add UI support to view and add AS number and configure network offering * Automatically assign AS Number if not specify AS number * update variable name * Fix routing mode check * UI: Only allow selecting AS number when routing mode is Dynamic and specifyAsNumber is true * UI: Only pass AS number when supported by the network offering * Release AS number on network deletion * Add deleteASNRange command (#81) * API: List ASNumbers by asnumber (#83) --------- Co-authored-by: Pearl Dsilva <pearl1594@gmail.com> * AS number management extensions * Support AS number on VPC tier creation based on the offering * Fix delete AS Range * Fix UI values * UI: Minor fix for releasing AS number * UI: Move management of AS Range to Zone details view * Fix specify_as_number column in network_offering table to set the default false * Add events for AS number operations * Allow users to list AS Numbers and fix network form for Normal users * Add AS number details to list networks response * Fix Allocated time format * Fix Allocated time format * support in details view too * Fix: Do not release AS number if acquired network requires AS number * Fix: Do not release AS number if acquired network requires AS number * Fix typo * Fix allocated release * Fix event type * UI: Add Routing mode and Specify AS to the network offering details * UI: Add Routing mode and Specify AS to the network offering details * Address comment * Fix release AS number of network deletion * Fix release AS number of network deletion * Fix * Restore release to its place based on the boolean * Rename boolean * API: Add networkId as listASNumber parameter * Add Network name to the search view filter for AS numbers * Present allocated time in human readable format - Pubilc IP / AS Numbers * Add account / domain filter for AS numbers * Add support for AS numbers on VPC offerings * Refactor AS number allocation to VPC and non VPC isolated networks * Checkstyle * Add support for AS numbers on VPC offerings * extend vpc offering view and vpcoffering response * merge https://github.com/shapeblue/cloudstack-playtika/pull/115 and change network_id of as_numbers to include vpc_id * Display AS number of VPC tiers as the AS number of the VPC * extend asnumber response and ui support * improve UI and as number response to view VPC details * List only dynamic offerings for vpc tiers with specify as numbers * Fix release AS number * Fix AS number displayed as 0 when no AS number assigned * Fix VPC offering creation without specify AS --------- Co-authored-by: nvazquez <nicovazquez90@gmail.com> * Fix release AS number on VPC deletion * Update server/src/main/java/com/cloud/dc/BGPServiceImpl.java * Update server/src/main/java/com/cloud/dc/BGPServiceImpl.java * Fix missing column on asnumber table * Fix listASNumbers API to support vpcid and obtain AS number from vpc for tiers * Prevent listing 0 AS number for VPC * Fix create Isolated Network form * Update server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java * Update server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java * Dynamic: move routingmode/specifyasn after networkmode in AddNetworkOffering.vue on UI * Dynamic: fix ip4routing in network response * Dynamic/systemvm: add FRR to systemvm template * Dynamic: BGP peers (DB,VO,Dao) * Dynamic: BGP peers (VR/server) * Dynamic: v3 - remove BgpPeer class - fix vpc vr has bgp peers of only 1 tier - rename ip4_cidr to guest_ip4_cidr - rename ip6_cidr to guest_ip6_cidr - generate /etc/frr/frr.conf - apply BGP peers on Dynamic-Routed network even if there is no BGP peers * Dynamic v4: fix vpc vr - fix duplicated guest cidr in frr.conf in vpc vr todo - restart frr / reload frr (reload will cause bgp session to Policy state) - apis for bgp peers - assign/release bgp peer from/to network * Dynamic v5: add apis for bgp peers * Dynamic v6: fix bugs - set response object name - remove required as number when update - fix checks when update - allow regular users to list bgp peers * Dynamic v7: move apis to bgp sub-dir * Dynamic v8: add tab for manage BGP peers on UI * Dynamic v9: fix update bgp with same config * Dynamiv v10: add changeBgpPeersForNetworkCmd * Dynamic v11: create network with bgppeerids - create network with bgppeerids - add marvin classes - add smoke tests - remove uuid from bgp_peer_network_map - fix created/removed in bgp_peer_network_map - remove bgppeers when remove a network - UI: fix delete bgp peer * Dynamic v12: add test for vpc tiers * Dynamic v13: bug fixes - fix change BGP peers for network in Allocated state - fix listing network returns removed record - fix all vpc tiers have the same settings - remove BGP peers as part of network removal - remove FRR settings for vpc tiers without any BGP peers - UI: fix no error msg when change BGP peers * Dynamic v14: assign BGP Peers for VPC instead of VPC tiers - create vpc with bgppeerids - do not allow create/update vpc tier with bgppeerids - apply all bgp peers when create/delete a vpc tier - UI: change bgp peers for vpc - test: update tests on vpc * Dynamic: fix build errors after merging as number PR * Dynamic: fix TODOs * Dynamic: fix smoke test on VPC * Allow creation of networks by users with as numbers * Address review comments * Move BGPService to bgp package and inject it on BaseCmd * Revert changes for CKS and address more comments * Display left side menu option for AS number only for root admin * Dynamic: create/update BGP peer with details refer to https://docs.frrouting.org/en/latest/bgp.html * Dynamic: fix build error and remove access to ListBgpPeers cmd for regular users * Dynamic: assign all zone BGP peers to user networks * Dynamic: show BGP peer info of networks only for root admin * AS number: disable specifyasnumber for non-NSX offerings * Dynamic: pass bgppeer details to command and fix typo with ip6 addr * Dynamic: list BGP peers by isdedicated, and fix change bgppeers for network/vpc * Dynamic: add UI labels * Dynamic: add bgp peers to vpc response * Dynamic: list bgp peers by keyword, fix list by asnumber * Dynamic: fix list bgppeers by keyword and db schema * Dynamic: fix list bgppeers do not return dedicated peers * Dynamic: update UI when create network/vpc offering * Update server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java Co-authored-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * Update tools/marvin/setup.py * Dynamic: network mode must be same when update a network with new offering * Dynamic: add method networkModel.isAnyServiceSupportedInNetwork * Dynamic: rename APIs and classes * Dynamic: fix unit tests due to previous changes * Dynamic: validateNetworkCidrSize when auto-create subnet * Dynamic: check AS number overlap * Dynamic: add ActionEvent * Dynamic: small code optimization * Dynamic: fix ui bugs after api rename * Dynamic: add marvin and test for ASN ranges and AS numbers * Dynamic: add account setting use.system.bgp.peers also - change the default value of routed.ipv4.vpc.max.cidr.size and routed.ipv4.vpc.min.cidr.size - change the category of settings * static: fix ui error when delete zone ipv4 subnets * static: small UI polish * Dynamic: throw exception when as number is required but not passed * Dynamic: fix typo when create FRR directory which causes network deletion failures * Dynamic: connect to ALL (or ALL dedicated) BGP peers if no BGP peer mapping for the network/vpc * Dynamic: throw exception when as number is required for VPC but not passed * Dynamic: list bgp peers by useSystemBgpPeers * Dynamic: fix frr config in VPC VR when change bgp peers * Dynamic: create frr config even if there is no VPC tiers * Dynamic: list bgp peers by zoneid (required for account) and account * Dynamic: only apply FRR config for vpc tiers with dynamic routing * Dynamic: donot send commands to router if commands size is 0 * Dynamic: fix 'new IPv6 address is not valid' when update bgp peer without IPv6 * Dynamic: throw exception if fail to allocate AS number when create network/vpc with dynamic routing * Dynamic: enable ipv6 unicast and 'ip nht resolve-via-default' * Dynamic: delete network/vpc if fail to allocate AS number when create network/vpc with dynamic routing * test: add unit tests for ASN APIs * test: add unit tests for core module * test: add unit tests for API responses * test: add unit tests for BgpPeerTO * test: add minor changes * test: add tests for create/delete/update/list RoutingFirewallRuleCmd * Static: show ip4 routes for vpc tiers * test: fix smoke test failure caused by type change of as number * test: add test for Ipv4SubnetForZoneCmd * test: add test for Ipv4SubnetForGuestNetworkCmd and BgpPeerCmd * UI: do not show redundant router when network mode is ROUTED as RVR is not supported * UI: hide 'Conserve mode' when networkmode is ROUTED * test: add unit tests for ListASNumbersCmdTest * Static: remove allocated IPv4 subnet when delete a network or vpc * test: add unit tests for BgpPeersRules * Dynamic: set ipv4routing from network offering * server: list as numbers and ipv4 subnets by keyword * server: remove dedicated bgp peers and ipv4 subnets when delete an account or domain * server: fix dedicated ipv4 subnet is allocated to other accounts * UI: fix allocated time format * server: ignore project is projectid is -1 so bgppeers/ipv4subnets works in project view * UI: add project column to bgp peers and ipv4 subnets * server: fix list AS numbers by domain admin or normal user * server: fix network creation when ipv4 subnet is dedicated * UI: polish network.js * Dynamic: fix frr config for ipv6 routing * Static routing: support cks cluster * Static: get/create IPv4 subnet from dedicated subnets at first * Dynamic: add BGP peers tab * Static: remove redundant loops * api: add since to api and response * server: add unit tests --------- Co-authored-by: Nicolas Vazquez <nicovazquez90@gmail.com> Co-authored-by: Pearl Dsilva <pearl1594@gmail.com> Co-authored-by: Harikrishna Patnala <harikrishna.patnala@gmail.com> Co-authored-by: Abhishek Kumar <abhishek.mrt22@gmail.com> Co-authored-by: Rohit Yadav <rohit.yadav@shapeblue.com>
1674 lines
68 KiB
Python
1674 lines
68 KiB
Python
# 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.
|
|
|
|
""" Test for IPv4 Routed mode"""
|
|
import datetime
|
|
import logging
|
|
import random
|
|
import time
|
|
|
|
from marvin.cloudstackTestCase import cloudstackTestCase
|
|
from marvin.lib.base import ZoneIpv4Subnet, Domain, Account, ServiceOffering, NetworkOffering, VpcOffering, Network, \
|
|
Ipv4SubnetForGuestNetwork, VirtualMachine, VPC, NetworkACLList, NetworkACL, RoutingFirewallRule, Template, ASNRange, \
|
|
BgpPeer, Router
|
|
from marvin.lib.common import get_domain, get_zone, list_routers, list_hosts
|
|
from marvin.lib.utils import get_host_credentials, get_process_status
|
|
|
|
from nose.plugins.attrib import attr
|
|
|
|
ICMPv4_ALL_TYPES = ("{ echo-reply, destination-unreachable, source-quench, redirect, echo-request, "
|
|
"router-advertisement, router-solicitation, time-exceeded, parameter-problem, timestamp-request, "
|
|
"timestamp-reply, info-request, info-reply, address-mask-request, address-mask-reply }")
|
|
SUBNET_PREFIX = "172.30."
|
|
SUBNET_1_PREFIX = SUBNET_PREFIX + str(random.randrange(100, 150))
|
|
SUBNET_2_PREFIX = SUBNET_PREFIX + str(random.randrange(151, 199))
|
|
|
|
VPC_CIDR_PREFIX = "172.31" # .0 to .16
|
|
NETWORK_CIDR_PREFIX = VPC_CIDR_PREFIX + ".100"
|
|
NETWORK_CIDR_PREFIX_DYNAMIC = VPC_CIDR_PREFIX + ".101"
|
|
|
|
MAX_RETRIES = 30
|
|
WAIT_INTERVAL = 5
|
|
|
|
test_network = None
|
|
test_network_vm = None
|
|
test_vpc = None
|
|
test_vpc_tier = None
|
|
test_vpc_vm = None
|
|
test_network_acl = None
|
|
|
|
START_ASN = 888800
|
|
END_ASN = 888888
|
|
ASN_1 = 900100 + random.randrange(1, 200)
|
|
ASN_2 = 900301 + random.randrange(0, 200)
|
|
IP4_ADDR_1 = "10.0.53.10"
|
|
IP4_ADDR_2 = "10.0.53.11"
|
|
PASSWORD_1 = "testpassword1"
|
|
PASSWORD_2 = "testpassword2"
|
|
|
|
NETWORK_OFFERING = {
|
|
"name": "Test Network offering - Routed mode",
|
|
"displaytext": "Test Network offering - Routed mode",
|
|
"networkmode": "ROUTED",
|
|
"guestiptype": "Isolated",
|
|
"supportedservices":
|
|
"Dhcp,Dns,UserData,Firewall",
|
|
"traffictype": "GUEST",
|
|
"availability": "Optional",
|
|
"egress_policy": "true",
|
|
"serviceProviderList": {
|
|
"Dhcp": "VirtualRouter",
|
|
"Dns": "VirtualRouter",
|
|
"UserData": "VirtualRouter",
|
|
"Firewall": "VirtualRouter"
|
|
}
|
|
}
|
|
|
|
VPC_OFFERING = {
|
|
"name": "Test VPC offering - Routed mode",
|
|
"displaytext": "Test VPC offering - Routed mode",
|
|
"networkmode": "ROUTED",
|
|
"supportedservices":
|
|
"Dhcp,Dns,UserData,NetworkACL"
|
|
}
|
|
|
|
VPC_NETWORK_OFFERING = {
|
|
"name": "Test VPC Network offering - Routed mode",
|
|
"displaytext": "Test VPC Network offering - Routed mode",
|
|
"networkmode": "ROUTED",
|
|
"guestiptype": "Isolated",
|
|
"supportedservices":
|
|
"Dhcp,Dns,UserData,NetworkACL",
|
|
"traffictype": "GUEST",
|
|
"availability": "Optional",
|
|
"serviceProviderList": {
|
|
"Dhcp": "VpcVirtualRouter",
|
|
"Dns": "VpcVirtualRouter",
|
|
"UserData": "VpcVirtualRouter",
|
|
"NetworkACL": "VpcVirtualRouter"
|
|
}
|
|
}
|
|
|
|
NETWORK_OFFERING_DYNAMIC = {
|
|
"name": "Test Network offering - Dynamic Routed mode",
|
|
"displaytext": "Test Network offering - Dynamic Routed mode",
|
|
"networkmode": "ROUTED",
|
|
"routingmode": "Dynamic",
|
|
"guestiptype": "Isolated",
|
|
"supportedservices":
|
|
"Dhcp,Dns,UserData,Firewall",
|
|
"traffictype": "GUEST",
|
|
"availability": "Optional",
|
|
"egress_policy": "true",
|
|
"serviceProviderList": {
|
|
"Dhcp": "VirtualRouter",
|
|
"Dns": "VirtualRouter",
|
|
"UserData": "VirtualRouter",
|
|
"Firewall": "VirtualRouter"
|
|
}
|
|
}
|
|
|
|
VPC_OFFERING_DYNAMIC = {
|
|
"name": "Test VPC offering - Routed mode",
|
|
"displaytext": "Test VPC offering - Routed mode",
|
|
"networkmode": "ROUTED",
|
|
"routingmode": "Dynamic",
|
|
"supportedservices":
|
|
"Dhcp,Dns,UserData,NetworkACL"
|
|
}
|
|
|
|
VPC_NETWORK_OFFERING_DYNAMIC = {
|
|
"name": "Test VPC Network offering - Dynamic Routed mode",
|
|
"displaytext": "Test VPC Network offering - Dynamic Routed mode",
|
|
"networkmode": "ROUTED",
|
|
"routingmode": "Dynamic",
|
|
"guestiptype": "Isolated",
|
|
"supportedservices":
|
|
"Dhcp,Dns,UserData,NetworkACL",
|
|
"traffictype": "GUEST",
|
|
"availability": "Optional",
|
|
"serviceProviderList": {
|
|
"Dhcp": "VpcVirtualRouter",
|
|
"Dns": "VpcVirtualRouter",
|
|
"UserData": "VpcVirtualRouter",
|
|
"NetworkACL": "VpcVirtualRouter"
|
|
}
|
|
}
|
|
class TestIpv4Routing(cloudstackTestCase):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
testdata = super(TestIpv4Routing, cls).getClsTestClient()
|
|
cls.services = testdata.getParsedTestDataConfig()
|
|
cls.apiclient = testdata.getApiClient()
|
|
cls.dbclient = testdata.getDbConnection()
|
|
cls.hypervisor = testdata.getHypervisorInfo()
|
|
cls.domain = get_domain(cls.apiclient)
|
|
cls.zone = get_zone(cls.apiclient)
|
|
|
|
cls._cleanup = []
|
|
|
|
cls.logger = logging.getLogger("TestIpv4Routing")
|
|
cls.stream_handler = logging.StreamHandler()
|
|
cls.logger.setLevel(logging.DEBUG)
|
|
cls.logger.addHandler(cls.stream_handler)
|
|
|
|
# 0. register template
|
|
cls.template = Template.register(cls.apiclient, cls.services["test_templates"][cls.hypervisor.lower()],
|
|
zoneid=cls.zone.id, hypervisor=cls.hypervisor.lower())
|
|
cls.template.download(cls.apiclient)
|
|
cls._cleanup.append(cls.template)
|
|
|
|
# 1.1 create subnet for zone
|
|
cls.subnet_1 = ZoneIpv4Subnet.create(
|
|
cls.apiclient,
|
|
zoneid=cls.zone.id,
|
|
subnet=SUBNET_1_PREFIX + ".0/24"
|
|
)
|
|
cls._cleanup.append(cls.subnet_1)
|
|
|
|
# 1.2 create ASN range for zone
|
|
cls.asnrange = ASNRange.create(
|
|
cls.apiclient,
|
|
zoneid=cls.zone.id,
|
|
startasn=START_ASN,
|
|
endasn=END_ASN
|
|
)
|
|
cls._cleanup.append(cls.asnrange)
|
|
|
|
# 2. Create small service offering
|
|
cls.service_offering = ServiceOffering.create(
|
|
cls.apiclient,
|
|
cls.services["service_offerings"]["small"]
|
|
)
|
|
cls._cleanup.append(cls.service_offering)
|
|
|
|
# 3. Create network and vpc offering with routed mode
|
|
# 3.1 Network offering for static routing
|
|
cls.network_offering_isolated = NetworkOffering.create(
|
|
cls.apiclient,
|
|
NETWORK_OFFERING
|
|
)
|
|
cls._cleanup.append(cls.network_offering_isolated)
|
|
cls.network_offering_isolated.update(cls.apiclient, state='Enabled')
|
|
|
|
# 3.2 VPC offering for static routing
|
|
cls.vpc_offering = VpcOffering.create(
|
|
cls.apiclient,
|
|
VPC_OFFERING
|
|
)
|
|
cls._cleanup.append(cls.vpc_offering)
|
|
cls.vpc_offering.update(cls.apiclient, state='Enabled')
|
|
|
|
# 3.3 VPC tier offering for static routing
|
|
cls.vpc_network_offering = NetworkOffering.create(
|
|
cls.apiclient,
|
|
VPC_NETWORK_OFFERING
|
|
)
|
|
cls._cleanup.append(cls.vpc_network_offering)
|
|
cls.vpc_network_offering.update(cls.apiclient, state='Enabled')
|
|
|
|
# 3.4 Network offering for dynamic routing
|
|
cls.network_offering_dynamic = NetworkOffering.create(
|
|
cls.apiclient,
|
|
NETWORK_OFFERING_DYNAMIC
|
|
)
|
|
cls._cleanup.append(cls.network_offering_dynamic)
|
|
cls.network_offering_dynamic.update(cls.apiclient, state='Enabled')
|
|
|
|
# 3.5 VPC Network offering for dynamic routing
|
|
cls.vpc_network_offering_dynamic = NetworkOffering.create(
|
|
cls.apiclient,
|
|
VPC_NETWORK_OFFERING_DYNAMIC
|
|
)
|
|
cls._cleanup.append(cls.vpc_network_offering_dynamic)
|
|
cls.vpc_network_offering_dynamic.update(cls.apiclient, state='Enabled')
|
|
|
|
# 4. Create sub-domain
|
|
cls.sub_domain = Domain.create(
|
|
cls.apiclient,
|
|
cls.services["acl"]["domain1"]
|
|
)
|
|
cls._cleanup.append(cls.sub_domain)
|
|
|
|
# 5. Create regular user
|
|
cls.regular_user = Account.create(
|
|
cls.apiclient,
|
|
cls.services["acl"]["accountD11A"],
|
|
domainid=cls.sub_domain.id
|
|
)
|
|
cls._cleanup.append(cls.regular_user)
|
|
|
|
# 6. Create api clients for regular user
|
|
cls.regular_user_user = cls.regular_user.user[0]
|
|
cls.regular_user_apiclient = cls.testClient.getUserApiClient(
|
|
cls.regular_user_user.username, cls.sub_domain.name
|
|
)
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
super(TestIpv4Routing, cls).tearDownClass()
|
|
|
|
@classmethod
|
|
def message(cls, msg):
|
|
cls.logger.debug("====== " + str(datetime.datetime.now()) + " " + msg + " ======")
|
|
|
|
def setUp(self):
|
|
self.apiclient = self.testClient.getApiClient()
|
|
self.cleanup = []
|
|
|
|
def tearDown(self):
|
|
super(TestIpv4Routing, self).tearDown()
|
|
|
|
def get_router(self, networkid=None, vpcid=None):
|
|
# list router
|
|
if vpcid:
|
|
list_router_response = list_routers(
|
|
self.apiclient,
|
|
vpcid=vpcid,
|
|
listall="true"
|
|
)
|
|
else:
|
|
list_router_response = list_routers(
|
|
self.apiclient,
|
|
networkid=networkid,
|
|
listall="true"
|
|
)
|
|
self.assertEqual(
|
|
isinstance(list_router_response, list),
|
|
True,
|
|
"list routers response should return a valid list"
|
|
)
|
|
router = list_router_response[0]
|
|
return router
|
|
|
|
def run_command_in_router(self, router, command):
|
|
# get host of router
|
|
hosts = list_hosts(
|
|
self.apiclient,
|
|
zoneid=router.zoneid,
|
|
type='Routing',
|
|
state='Up',
|
|
id=router.hostid
|
|
)
|
|
self.assertEqual(
|
|
isinstance(hosts, list),
|
|
True,
|
|
"Check list host returns a valid list"
|
|
)
|
|
host = hosts[0]
|
|
|
|
# run command
|
|
result = ''
|
|
if router.hypervisor.lower() in ('vmware', 'hyperv'):
|
|
result = get_process_status(
|
|
self.apiclient.connection.mgtSvr,
|
|
22,
|
|
self.apiclient.connection.user,
|
|
self.apiclient.connection.passwd,
|
|
router.linklocalip,
|
|
command,
|
|
hypervisor=router.hypervisor
|
|
)
|
|
else:
|
|
try:
|
|
host.user, host.passwd = get_host_credentials(self.config, host.ipaddress)
|
|
result = get_process_status(
|
|
host.ipaddress,
|
|
22,
|
|
host.user,
|
|
host.passwd,
|
|
router.linklocalip,
|
|
command
|
|
)
|
|
except KeyError:
|
|
self.skipTest("Marvin configuration has no host credentials to check router services")
|
|
res = str(result)
|
|
self.message("VR command (%s) result: (%s)" % (command, res))
|
|
return res
|
|
|
|
def rebootRouter(self, router):
|
|
try:
|
|
Router.reboot(
|
|
self.apiclient,
|
|
id=router.id
|
|
)
|
|
except Exception as e:
|
|
self.fail("Failed to reboot the virtual router: %s, %s" % (router.id, e))
|
|
|
|
def createNetworkAclRule(self, rule):
|
|
return NetworkACL.create(self.apiclient,
|
|
services=rule,
|
|
aclid=test_network_acl.id)
|
|
|
|
def createIpv4RoutingFirewallRule(self, rule):
|
|
return RoutingFirewallRule.create(self.apiclient,
|
|
services=rule,
|
|
networkid=test_network.id)
|
|
|
|
def verifyNftablesRulesInRouter(self, router, rules):
|
|
if router.vpcid:
|
|
table = "ip4_acl"
|
|
else:
|
|
table = "ip4_firewall"
|
|
for rule in rules:
|
|
cmd = "nft list chain ip %s %s" % (table, rule["chain"])
|
|
res = self.run_command_in_router(router, cmd)
|
|
if "exists" not in rule or rule["exists"]:
|
|
exists = True
|
|
else:
|
|
exists = False
|
|
if exists and not rule["rule"] in res:
|
|
self.fail("The nftables rule (%s) should exist but is not found in the VR !!!" % rule["rule"])
|
|
if not exists and rule["rule"] in res:
|
|
self.fail("The nftables rule (%s) should not exist but is found in the VR !!!" % rule["rule"])
|
|
self.message("The nftables rules look good so far.")
|
|
|
|
def verifyPingFromRouter(self, router, vm, expected=True, retries=2):
|
|
while retries > 0:
|
|
cmd_ping_vm = "ping -c1 -W1 %s" % vm.ipaddress
|
|
try:
|
|
result = self.run_command_in_router(router, cmd_ping_vm)
|
|
if "0 packets received" in result:
|
|
retries = retries - 1
|
|
self.message("No packets received, remaining retries %s" % retries)
|
|
if retries > 0:
|
|
time.sleep(WAIT_INTERVAL)
|
|
else:
|
|
self.message("packets are received, looks good")
|
|
return
|
|
except Exception as ex:
|
|
self.fail("Failed to ping vm %s from router %s: %s" % (vm.ipaddress, router.name, ex))
|
|
if retries == 0 and expected:
|
|
self.fail("Failed to ping vm %s from router %s, which is expected to work !!!" % (vm.ipaddress, router.name))
|
|
if retries > 0 and not expected:
|
|
self.fail("ping vm %s from router %s works, however it is unexpected !!!" % (vm.ipaddress, router.name))
|
|
|
|
def verifyFrrConf(self, router, configs):
|
|
cmd = "cat /etc/frr/frr.conf"
|
|
res = self.run_command_in_router(router, cmd)
|
|
for config in configs:
|
|
if "exists" not in config or config["exists"]:
|
|
exists = True
|
|
else:
|
|
exists = False
|
|
if exists and not config["config"] in res:
|
|
self.fail("The frr config (%s) should exist but is not found in the VR !!!" % config["config"])
|
|
if not exists and config["config"] in res:
|
|
self.fail("The frr config (%s) should not exist but is found in the VR !!!" % config["config"])
|
|
self.message("The frr config look good so far.")
|
|
|
|
@attr(tags=['advanced'], required_hardware=False)
|
|
def test_01_zone_subnet(self):
|
|
""" Test for subnet for zone"""
|
|
"""
|
|
# 1. Create subnet
|
|
# 2. List subnet
|
|
# 3. Update subnet
|
|
# 4. dedicate subnet to domain
|
|
# 5. released dedicated subnet
|
|
# 6. dedicate subnet to sub-domain/account
|
|
# 7. released dedicated subnet
|
|
# 8. delete subnet
|
|
"""
|
|
self.message("Running test_01_zone_subnet")
|
|
# 1. Create subnet
|
|
self.subnet_2 = ZoneIpv4Subnet.create(
|
|
self.apiclient,
|
|
zoneid=self.zone.id,
|
|
subnet=SUBNET_2_PREFIX + ".0/24"
|
|
)
|
|
self.cleanup.append(self.subnet_2)
|
|
# 2. List subnet
|
|
subnets = ZoneIpv4Subnet.list(
|
|
self.apiclient,
|
|
id=self.subnet_2.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(subnets, list),
|
|
True,
|
|
"List subnets for zone should return a valid list"
|
|
)
|
|
self.assertEqual(
|
|
len(subnets) == 1,
|
|
True,
|
|
"The number of subnets for zone (%s) should be equal to 1" % (len(subnets))
|
|
)
|
|
self.assertEqual(
|
|
subnets[0].subnet == SUBNET_2_PREFIX + ".0/24",
|
|
True,
|
|
"The subnet of subnet for zone (%s) should be equal to %s" % (subnets[0].subnet, SUBNET_2_PREFIX + ".0/24")
|
|
)
|
|
# 3. Update subnet
|
|
self.subnet_2.update(
|
|
self.apiclient,
|
|
subnet=SUBNET_2_PREFIX + ".0/25"
|
|
)
|
|
subnets = ZoneIpv4Subnet.list(
|
|
self.apiclient,
|
|
id=self.subnet_2.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(subnets, list) and len(subnets) == 1 and subnets[0].subnet == SUBNET_2_PREFIX + ".0/25",
|
|
True,
|
|
"The subnet of subnet for zone should be equal to %s" % (SUBNET_2_PREFIX + ".0/25")
|
|
)
|
|
# 4. dedicate subnet to domain
|
|
ZoneIpv4Subnet.dedicate(
|
|
self.apiclient,
|
|
id=self.subnet_2.id,
|
|
domainid=self.domain.id
|
|
)
|
|
subnets = ZoneIpv4Subnet.list(
|
|
self.apiclient,
|
|
id=self.subnet_2.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(subnets, list) and len(subnets) == 1 and subnets[0].domainid == self.domain.id,
|
|
True,
|
|
"The subnet should be dedicated to domain %s" % self.domain.id
|
|
)
|
|
# 5. released dedicated subnet
|
|
self.subnet_2.release(
|
|
self.apiclient
|
|
)
|
|
subnets = ZoneIpv4Subnet.list(
|
|
self.apiclient,
|
|
id=self.subnet_2.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(subnets, list) and len(subnets) == 1 and not subnets[0].domainid,
|
|
True,
|
|
"The subnet should not be dedicated to domain %s" % self.domain.id
|
|
)
|
|
# 6. dedicate subnet to sub-domain/account
|
|
ZoneIpv4Subnet.dedicate(
|
|
self.apiclient,
|
|
id=self.subnet_2.id,
|
|
domainid=self.sub_domain.id,
|
|
account=self.regular_user.name
|
|
)
|
|
subnets = ZoneIpv4Subnet.list(
|
|
self.apiclient,
|
|
id=self.subnet_2.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(subnets, list) and len(subnets) == 1
|
|
and subnets[0].domainid == self.sub_domain.id and subnets[0].account == self.regular_user.name,
|
|
True,
|
|
"The subnet should be dedicated to account %s" % self.regular_user.name
|
|
)
|
|
# 7. released dedicated subnet
|
|
self.subnet_2.release(
|
|
self.apiclient
|
|
)
|
|
subnets = ZoneIpv4Subnet.list(
|
|
self.apiclient,
|
|
id=self.subnet_2.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(subnets, list) and len(subnets) == 1 and not subnets[0].domainid,
|
|
True,
|
|
"The subnet should not be dedicated to account %s" % self.regular_user.name
|
|
)
|
|
# 8. delete subnet
|
|
self.subnet_2.delete(
|
|
self.apiclient
|
|
)
|
|
self.cleanup.remove(self.subnet_2)
|
|
|
|
@attr(tags=['advanced'], required_hardware=False)
|
|
def test_02_create_network_routed_mode_with_specified_cidr(self):
|
|
""" Test for guest network with specified cidr"""
|
|
"""
|
|
# 1. Create Isolated network
|
|
# 2. List subnet for network by subnet
|
|
# 3. Delete the network
|
|
# 4. List subnet for network by subnet. the subnet should be gone as well
|
|
"""
|
|
self.message("Running test_02_create_network_routed_mode_with_specified_cidr")
|
|
|
|
# 1. Create Isolated network
|
|
isolated_network = Network.create(
|
|
self.apiclient,
|
|
self.services["network"],
|
|
gateway=NETWORK_CIDR_PREFIX + ".1",
|
|
netmask="255.255.255.0",
|
|
networkofferingid=self.network_offering_isolated.id,
|
|
zoneid=self.zone.id
|
|
)
|
|
self.cleanup.append(isolated_network)
|
|
|
|
# 2. List subnet for network by subnet
|
|
subnets = Ipv4SubnetForGuestNetwork.list(
|
|
self.apiclient,
|
|
subnet=NETWORK_CIDR_PREFIX + ".0/24"
|
|
)
|
|
self.assertEqual(
|
|
isinstance(subnets, list) and len(subnets) == 1
|
|
and subnets[0].subnet == NETWORK_CIDR_PREFIX + ".0/24" and subnets[0].state == "Allocated",
|
|
True,
|
|
"The subnet should be added for network %s" % isolated_network.name
|
|
)
|
|
|
|
# 3. Delete the network
|
|
isolated_network.delete(self.apiclient)
|
|
self.cleanup.remove(isolated_network)
|
|
|
|
# 4. List subnet for network by subnet. the subnet should be gone as well
|
|
network_cidr = subnets[0].subnet
|
|
subnets = Ipv4SubnetForGuestNetwork.list(
|
|
self.apiclient,
|
|
subnet=network_cidr
|
|
)
|
|
self.assertEqual(
|
|
not isinstance(subnets, list) or len(subnets) == 0,
|
|
True,
|
|
"The subnet %s should be removed for network %s" % (network_cidr, isolated_network.name)
|
|
)
|
|
|
|
@attr(tags=['advanced'], required_hardware=False)
|
|
def test_03_create_subnets_for_guest_network(self):
|
|
""" Test for subnets for guest network with cidr/cidrsize"""
|
|
"""
|
|
# 1. Create subnet with cidr for guest network
|
|
# 2. List subnets for network
|
|
# 3. delete subnet for network
|
|
|
|
# 4. Create subnet with cidrsize
|
|
# 5. List subnet for network
|
|
# 6. delete subnet for network
|
|
"""
|
|
self.message("Running test_03_create_subnets_for_guest_network")
|
|
|
|
# 1. Create subnet with cidr for guest network
|
|
subnet_network_1 = Ipv4SubnetForGuestNetwork.create(
|
|
self.apiclient,
|
|
parentid=self.subnet_1.id,
|
|
subnet=SUBNET_1_PREFIX + ".0/26"
|
|
)
|
|
self.cleanup.append(subnet_network_1)
|
|
|
|
# 2. List subnets for network
|
|
subnets = Ipv4SubnetForGuestNetwork.list(
|
|
self.apiclient,
|
|
subnet=subnet_network_1.subnet
|
|
)
|
|
self.assertEqual(
|
|
isinstance(subnets, list) and len(subnets) == 1,
|
|
True,
|
|
"The subnet should be created for subnet_network_1 %s" % subnet_network_1.subnet
|
|
)
|
|
|
|
# 3. delete subnet for network
|
|
subnet_network_1.delete(self.apiclient)
|
|
self.cleanup.remove(subnet_network_1)
|
|
|
|
# 4. Create subnet with cidrsize
|
|
subnet_network_2 = Ipv4SubnetForGuestNetwork.create(
|
|
self.apiclient,
|
|
parentid=self.subnet_1.id,
|
|
cidrsize=26
|
|
)
|
|
self.cleanup.append(subnet_network_2)
|
|
# 5. List subnet for network
|
|
subnets = Ipv4SubnetForGuestNetwork.list(
|
|
self.apiclient,
|
|
subnet=subnet_network_2.subnet
|
|
)
|
|
self.assertEqual(
|
|
isinstance(subnets, list) and len(subnets) == 1,
|
|
True,
|
|
"The subnet should be created for subnet_network_2 %s" % subnet_network_2.subnet
|
|
)
|
|
|
|
# 6. delete subnet for network
|
|
subnet_network_2.delete(self.apiclient)
|
|
self.cleanup.remove(subnet_network_2)
|
|
|
|
@attr(tags=['advanced'], required_hardware=False)
|
|
def test_04_create_isolated_network_routed_mode_with_cidrsize(self):
|
|
""" Test for subnet and guest network with cidrsize"""
|
|
"""
|
|
# 1. Create Isolated network with cidrsize
|
|
# 2. List subnet for network by networkid
|
|
# 3. Delete the network
|
|
# 4. List subnet for network by networkid, it should be removed
|
|
"""
|
|
self.message("Running test_04_create_isolated_network_routed_mode_with_cidrsize")
|
|
|
|
# 1. Create Isolated network with cidrsize
|
|
isolated_network = Network.create(
|
|
self.apiclient,
|
|
self.services["network"],
|
|
networkofferingid=self.network_offering_isolated.id,
|
|
zoneid=self.zone.id,
|
|
cidrsize=26
|
|
)
|
|
self.cleanup.append(isolated_network)
|
|
|
|
# 2. List subnet for network by networkid
|
|
subnets = Ipv4SubnetForGuestNetwork.list(
|
|
self.apiclient,
|
|
networkid=isolated_network.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(subnets, list) and len(subnets) == 1
|
|
and subnets[0].networkid == isolated_network.id and subnets[0].state == "Allocated",
|
|
True,
|
|
"The subnet should be created for isolated_network %s" % isolated_network.name
|
|
)
|
|
|
|
# 3. Delete the network
|
|
isolated_network.delete(self.apiclient)
|
|
self.cleanup.remove(isolated_network)
|
|
|
|
# 4. List subnet for network by network cidr, it should be removed
|
|
network_cidr = subnets[0].subnet
|
|
subnets = Ipv4SubnetForGuestNetwork.list(
|
|
self.apiclient,
|
|
subnet=network_cidr
|
|
)
|
|
self.assertEqual(
|
|
not isinstance(subnets, list) or len(subnets) == 0,
|
|
True,
|
|
"The subnet should be removed for isolated_network %s" % isolated_network.name
|
|
)
|
|
|
|
@attr(tags=['advanced'], required_hardware=False)
|
|
def test_05_create_vpc_routed_mode_with_cidrsize(self):
|
|
""" Test for Routed VPC with cidrsize"""
|
|
"""
|
|
# 1. Create VPC with cidrsize
|
|
# 2. List subnet for network by vpcid
|
|
# 3. Delete the VPC
|
|
# 4. List subnet for network by vpcid, it should be removed
|
|
"""
|
|
self.message("Running test_05_create_vpc_routed_mode_with_cidrsize")
|
|
|
|
# 1. Create VPC with cidrsize
|
|
del self.services["vpc"]["cidr"]
|
|
vpc = VPC.create(self.apiclient,
|
|
self.services["vpc"],
|
|
vpcofferingid=self.vpc_offering.id,
|
|
zoneid=self.zone.id,
|
|
cidrsize=26,
|
|
start=False
|
|
)
|
|
self.cleanup.append(vpc)
|
|
|
|
# 2. List subnet for network by networkid
|
|
subnets = Ipv4SubnetForGuestNetwork.list(
|
|
self.apiclient,
|
|
vpcid=vpc.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(subnets, list) and len(subnets) == 1
|
|
and subnets[0].vpcid == vpc.id and subnets[0].state == "Allocated",
|
|
True,
|
|
"The subnet should be created for vpc %s" % vpc.name
|
|
)
|
|
|
|
# 3. Delete the VPC
|
|
vpc.delete(self.apiclient)
|
|
self.cleanup.remove(vpc)
|
|
|
|
# 4. List subnet for network by vpc cidr, it should be removed
|
|
vpc_cidr = subnets[0].subnet
|
|
subnets = Ipv4SubnetForGuestNetwork.list(
|
|
self.apiclient,
|
|
subnet=vpc_cidr
|
|
)
|
|
self.assertEqual(
|
|
not isinstance(subnets, list) or len(subnets) == 0,
|
|
True,
|
|
"The subnet should be removed for vpc %s" % vpc.name
|
|
)
|
|
|
|
@attr(tags=['advanced'], required_hardware=False)
|
|
def test_06_isolated_network_with_routed_mode(self):
|
|
""" Test for Isolated Network with Routed mode"""
|
|
"""
|
|
# 1. Create Isolated network
|
|
# 2. Create VM in the network
|
|
"""
|
|
self.message("Running test_06_isolated_network_with_routed_mode")
|
|
|
|
# 1. Create Isolated network
|
|
global test_network
|
|
test_network = Network.create(
|
|
self.apiclient,
|
|
self.services["network"],
|
|
networkofferingid=self.network_offering_isolated.id,
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
accountid=self.regular_user.name,
|
|
gateway=NETWORK_CIDR_PREFIX + ".1",
|
|
netmask="255.255.255.0"
|
|
)
|
|
self._cleanup.append(test_network)
|
|
|
|
# 2. Create VM in the network
|
|
global test_network_vm
|
|
test_network_vm = VirtualMachine.create(
|
|
self.regular_user_apiclient,
|
|
self.services["virtual_machine"],
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
accountid=self.regular_user.name,
|
|
networkids=test_network.id,
|
|
serviceofferingid=self.service_offering.id,
|
|
templateid=self.template.id)
|
|
self._cleanup.append(test_network_vm)
|
|
|
|
@attr(tags=['advanced'], required_hardware=False)
|
|
def test_07_vpc_and_tier_with_routed_mode(self):
|
|
""" Test for VPC/tier with Routed mode"""
|
|
"""
|
|
# 1. Create VPC
|
|
# 2. Create Network ACL (egress = Deny, ingress = Deny)
|
|
# 3. Create VPC tier with Network ACL in the VPC
|
|
# 4. Create VM in the VPC tier
|
|
"""
|
|
self.message("Running test_07_vpc_and_tier_with_routed_mode")
|
|
|
|
# 1. Create VPC
|
|
self.services["vpc"]["cidr"] = VPC_CIDR_PREFIX + ".0.0/22"
|
|
global test_vpc
|
|
test_vpc = VPC.create(self.apiclient,
|
|
self.services["vpc"],
|
|
vpcofferingid=self.vpc_offering.id,
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
account=self.regular_user.name,
|
|
start=False
|
|
)
|
|
self._cleanup.append(test_vpc)
|
|
|
|
# 2. Create Network ACL (egress = Deny, ingress = Deny)
|
|
global test_network_acl
|
|
test_network_acl = NetworkACLList.create(self.apiclient,
|
|
services={},
|
|
name="test-network-acl",
|
|
description="test-network-acl",
|
|
vpcid=test_vpc.id
|
|
)
|
|
|
|
# 3. Create VPC tier with Network ACL in the VPC
|
|
global test_vpc_tier
|
|
test_vpc_tier = Network.create(self.regular_user_apiclient,
|
|
self.services["network"],
|
|
networkofferingid=self.vpc_network_offering.id,
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
accountid=self.regular_user.name,
|
|
vpcid=test_vpc.id,
|
|
gateway=VPC_CIDR_PREFIX + ".1.1",
|
|
netmask="255.255.255.0",
|
|
aclid=test_network_acl.id
|
|
)
|
|
self._cleanup.append(test_vpc_tier)
|
|
|
|
# 4. Create VM in the VPC tier
|
|
global test_vpc_vm
|
|
test_vpc_vm = VirtualMachine.create(
|
|
self.regular_user_apiclient,
|
|
self.services["virtual_machine"],
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
accountid=self.regular_user.name,
|
|
networkids=test_vpc_tier.id,
|
|
serviceofferingid=self.service_offering.id,
|
|
templateid=self.template.id)
|
|
self._cleanup.append(test_vpc_vm)
|
|
|
|
@attr(tags=['advanced'], required_hardware=False)
|
|
def test_08_vpc_and_tier_failed_cases(self):
|
|
""" Test for VPC/tier with Routed mode (some failed cases)"""
|
|
"""
|
|
# 1. create VPC with Routed mode
|
|
# 2. create network offering with NATTED mode, create vpc tier, it should fail
|
|
# 3. create vpc tier not in the vpc cidr, it should fail
|
|
"""
|
|
|
|
self.message("Running test_08_vpc_and_tier_failed_cases")
|
|
|
|
# 1. Create VPC
|
|
self.services["vpc"]["cidr"] = VPC_CIDR_PREFIX + ".8.0/22"
|
|
test_vpc_2 = VPC.create(self.apiclient,
|
|
self.services["vpc"],
|
|
vpcofferingid=self.vpc_offering.id,
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
account=self.regular_user.name,
|
|
start=False
|
|
)
|
|
self.cleanup.append(test_vpc_2)
|
|
|
|
# 2. create network offering with NATTED mode, create vpc tier, it should fail
|
|
nw_offering_isolated_vpc = NetworkOffering.create(
|
|
self.apiclient,
|
|
self.services["nw_offering_isolated_vpc"]
|
|
)
|
|
self.cleanup.append(nw_offering_isolated_vpc)
|
|
nw_offering_isolated_vpc.update(self.apiclient, state='Enabled')
|
|
try:
|
|
test_vpc_tier_2 = Network.create(self.regular_user_apiclient,
|
|
self.services["network"],
|
|
networkofferingid=nw_offering_isolated_vpc.id,
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
accountid=self.regular_user.name,
|
|
vpcid=test_vpc_2.id,
|
|
gateway=VPC_CIDR_PREFIX + ".1.1",
|
|
netmask="255.255.255.0"
|
|
)
|
|
self.cleanup.append(test_vpc_tier_2)
|
|
self.fail("Created vpc network successfully, but expected to fail")
|
|
except Exception as ex:
|
|
self.message("Failed to create vpc network due to %s, which is expected behaviour" % ex)
|
|
|
|
# 3. create vpc tier not in the vpc cidr, it should fail
|
|
try:
|
|
test_vpc_tier_3 = Network.create(self.regular_user_apiclient,
|
|
self.services["network"],
|
|
networkofferingid=self.vpc_network_offering.id,
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
accountid=self.regular_user.name,
|
|
vpcid=test_vpc_2.id,
|
|
gateway=VPC_CIDR_PREFIX + ".31.1",
|
|
netmask="255.255.255.0"
|
|
)
|
|
self.cleanup.append(test_vpc_tier_3)
|
|
self.fail("Created vpc network successfully, but expected to fail")
|
|
except Exception as ex:
|
|
self.message("Failed to create vpc network due to %s, which is expected behaviour" % ex)
|
|
|
|
@attr(tags=['advanced'], required_hardware=False)
|
|
def test_09_connectivity_between_network_and_vpc_tier(self):
|
|
""" Test for connectivity between VMs in the Isolated Network and VPC/tier"""
|
|
"""
|
|
# 0. Get static routes of Network/VPC
|
|
# 1. Add static routes in VRs manually
|
|
|
|
# 2. Test VM2 in VR1-Network (ping/ssh should fail)
|
|
# 3. Test VM1 in VR2-VPC (ping/ssh should fail)
|
|
|
|
# 4. Create Ingress rules in Network ACL for VPC
|
|
# 5. Create Egress rules in Network ACL for VPC
|
|
# 6. Test VM2 in VR1-Network (ping/ssh should succeed)
|
|
# 7. Test VM1 in VR2-VPC (ping/ssh should fail)
|
|
|
|
# 8. Create IPv4 firewalls for Isolated network
|
|
# 9. Test VM2 in VR1-Network (ping/ssh should succeed)
|
|
# 10. Test VM1 in VR2-VPC (ping/ssh should succeed)
|
|
|
|
# 11. Delete Network ACL rules for VPC
|
|
# 12. Delete IPv4 firewall rules for Network
|
|
# 13. Test VM2 in VR1-Network (ping/ssh should fail)
|
|
# 14. Test VM1 in VR2-VPC (ping/ssh should fail)
|
|
|
|
"""
|
|
self.message("Running test_09_connectivity_between_network_and_vpc_tier")
|
|
|
|
# 0. Get static routes of Network/VPC
|
|
network_ip4routes = []
|
|
if test_network:
|
|
network_ip4routes = Network.list(
|
|
self.apiclient,
|
|
id=test_network.id,
|
|
listall=True
|
|
)[0].ip4routes
|
|
else:
|
|
self.skipTest("test_network is not created")
|
|
|
|
vpc_ip4routes = []
|
|
if test_vpc:
|
|
vpc_ip4routes = VPC.list(
|
|
self.apiclient,
|
|
id=test_vpc.id,
|
|
listall=True
|
|
)[0].ip4routes
|
|
else:
|
|
self.skipTest("test_vpc is not created")
|
|
|
|
network_router = self.get_router(networkid=test_network.id)
|
|
vpc_router = self.get_router(vpcid=test_vpc.id)
|
|
|
|
# Test VM1 in VR1-Network (wait until ping works)
|
|
self.verifyPingFromRouter(network_router, test_network_vm, retries=MAX_RETRIES)
|
|
# Test VM2 in VR2-VPC (wait until ping works)
|
|
self.verifyPingFromRouter(vpc_router, test_vpc_vm, retries=MAX_RETRIES)
|
|
|
|
# 1. Add static routes in VRs manually
|
|
if not network_router or not vpc_router:
|
|
self.skipTest("network_router (%s) or vpc_router (%s) does not exist" % (network_router, vpc_router))
|
|
for ip4route in network_ip4routes:
|
|
self.run_command_in_router(vpc_router, "ip route add %s via %s" % (ip4route.subnet, ip4route.gateway))
|
|
for ip4route in vpc_ip4routes:
|
|
self.run_command_in_router(network_router, "ip route add %s via %s" % (ip4route.subnet, ip4route.gateway))
|
|
|
|
# 2. Test VM2 in VR1-Network (ping/ssh should fail)
|
|
self.verifyPingFromRouter(network_router, test_vpc_vm, expected=False)
|
|
# 3. Test VM1 in VR2-VPC (ping/ssh should fail)
|
|
self.verifyPingFromRouter(vpc_router, test_network_vm, expected=False)
|
|
|
|
vpc_router_rules = [{"chain": "FORWARD",
|
|
"rule": "ip daddr %s jump eth2_ingress_policy" % test_vpc_tier.cidr},
|
|
{"chain": "FORWARD",
|
|
"rule": "ip saddr %s jump eth2_egress_policy" % test_vpc_tier.cidr}]
|
|
vpc_acl_rules = []
|
|
# 4. Create Ingress rules in Network ACL for VPC
|
|
rule = {}
|
|
rule["traffictype"] = "Ingress"
|
|
rule["cidrlist"] = test_network.cidr
|
|
rule["protocol"] = "icmp"
|
|
rule["icmptype"] = -1
|
|
rule["icmpcode"] = -1
|
|
vpc_acl_rules.append(self.createNetworkAclRule(rule))
|
|
vpc_router_rules.append({"chain": "eth2_ingress_policy",
|
|
"rule": "ip saddr %s icmp type %s accept" % (test_network.cidr, ICMPv4_ALL_TYPES)})
|
|
self.verifyNftablesRulesInRouter(vpc_router, vpc_router_rules)
|
|
|
|
rule = {}
|
|
rule["traffictype"] = "Ingress"
|
|
rule["cidrlist"] = test_network.cidr
|
|
rule["protocol"] = "tcp"
|
|
rule["startport"] = 22
|
|
rule["endport"] = 22
|
|
vpc_acl_rules.append(self.createNetworkAclRule(rule))
|
|
vpc_router_rules.append({"chain": "eth2_ingress_policy",
|
|
"rule": "ip saddr %s tcp dport 22 accept" % test_network.cidr})
|
|
self.verifyNftablesRulesInRouter(vpc_router, vpc_router_rules)
|
|
|
|
rule = {}
|
|
rule["traffictype"] = "Ingress"
|
|
rule["cidrlist"] = network_router.publicip + "/32"
|
|
rule["protocol"] = "icmp"
|
|
rule["icmptype"] = -1
|
|
rule["icmpcode"] = -1
|
|
vpc_acl_rules.append(self.createNetworkAclRule(rule))
|
|
vpc_router_rules.append({"chain": "eth2_ingress_policy",
|
|
"rule": "ip saddr %s icmp type %s accept" % (network_router.publicip, ICMPv4_ALL_TYPES)})
|
|
self.verifyNftablesRulesInRouter(vpc_router, vpc_router_rules)
|
|
|
|
# 5. Create Egress rules in Network ACL for VPC
|
|
rule = {}
|
|
rule["traffictype"] = "Egress"
|
|
rule["protocol"] = "icmp"
|
|
rule["icmptype"] = -1
|
|
rule["icmpcode"] = -1
|
|
vpc_acl_rules.append(self.createNetworkAclRule(rule))
|
|
vpc_router_rules.append({"chain": "eth2_egress_policy",
|
|
"rule": "ip daddr 0.0.0.0/0 icmp type %s accept" % ICMPv4_ALL_TYPES})
|
|
self.verifyNftablesRulesInRouter(vpc_router, vpc_router_rules)
|
|
|
|
# 6. Test VM2 in VR1-Network (ping/ssh should succeed)
|
|
self.verifyPingFromRouter(network_router, test_vpc_vm, expected=True)
|
|
# 7. Test VM1 in VR2-VPC (ping/ssh should fail)
|
|
self.verifyPingFromRouter(vpc_router, test_network_vm, expected=False)
|
|
|
|
network_router_rules = [{"chain": "FORWARD",
|
|
"rule": "ip daddr %s jump fw_chain_ingress" % test_network.cidr},
|
|
{"chain": "FORWARD",
|
|
"rule": "ip saddr %s jump fw_chain_egress" % test_network.cidr}]
|
|
network_routing_firewall_rules = []
|
|
# 8. Create IPv4 firewalls for Isolated network
|
|
rule = {}
|
|
rule["traffictype"] = "Ingress"
|
|
rule["cidrlist"] = test_vpc.cidr
|
|
rule["protocol"] = "icmp"
|
|
rule["icmptype"] = -1
|
|
rule["icmpcode"] = -1
|
|
network_routing_firewall_rules.append(self.createIpv4RoutingFirewallRule(rule))
|
|
network_router_rules.append({"chain": "fw_chain_ingress",
|
|
"rule": "ip saddr %s ip daddr 0.0.0.0/0 icmp type %s accept" % (test_vpc.cidr, ICMPv4_ALL_TYPES)})
|
|
self.verifyNftablesRulesInRouter(network_router, network_router_rules)
|
|
|
|
rule = {}
|
|
rule["traffictype"] = "Ingress"
|
|
rule["cidrlist"] = test_vpc.cidr
|
|
rule["protocol"] = "tcp"
|
|
rule["startport"] = 22
|
|
rule["endport"] = 22
|
|
network_routing_firewall_rules.append(self.createIpv4RoutingFirewallRule(rule))
|
|
network_router_rules.append({"chain": "fw_chain_ingress",
|
|
"rule": "ip saddr %s ip daddr 0.0.0.0/0 tcp dport 22 accept" % test_vpc.cidr})
|
|
self.verifyNftablesRulesInRouter(network_router, network_router_rules)
|
|
|
|
rule = {}
|
|
rule["traffictype"] = "Ingress"
|
|
rule["cidrlist"] = vpc_router.publicip + "/32"
|
|
rule["protocol"] = "icmp"
|
|
rule["icmptype"] = -1
|
|
rule["icmpcode"] = -1
|
|
network_routing_firewall_rules.append(self.createIpv4RoutingFirewallRule(rule))
|
|
network_router_rules.append({"chain": "fw_chain_ingress",
|
|
"rule": "ip saddr %s ip daddr 0.0.0.0/0 icmp type %s accept" % (vpc_router.publicip, ICMPv4_ALL_TYPES)})
|
|
self.verifyNftablesRulesInRouter(network_router, network_router_rules)
|
|
|
|
# 9. Test VM2 in VR1-Network (ping/ssh should succeed)
|
|
self.verifyPingFromRouter(network_router, test_vpc_vm, expected=True)
|
|
# 10. Test VM1 in VR2-VPC (ping/ssh should succeed)
|
|
self.verifyPingFromRouter(vpc_router, test_network_vm, expected=True)
|
|
|
|
# 11. Delete Network ACL rules for VPC
|
|
for rule in vpc_acl_rules:
|
|
rule.delete(self.apiclient)
|
|
vpc_router_rules[2] = {"chain": "eth2_ingress_policy",
|
|
"rule": "ip saddr %s icmp type %s accept" % (test_network.cidr, ICMPv4_ALL_TYPES),
|
|
"exists": False}
|
|
vpc_router_rules[3] = {"chain": "eth2_ingress_policy",
|
|
"rule": "ip saddr %s tcp dport 22 accept" % test_network.cidr,
|
|
"exists": False}
|
|
vpc_router_rules[4] = {"chain": "eth2_egress_policy",
|
|
"rule": "ip daddr 0.0.0.0/0 icmp type %s accept" % ICMPv4_ALL_TYPES,
|
|
"exists": False}
|
|
vpc_router_rules[5] = {"chain": "eth2_ingress_policy",
|
|
"rule": "ip saddr %s icmp type %s accept" % (network_router.publicip, ICMPv4_ALL_TYPES),
|
|
"exists": False}
|
|
self.verifyNftablesRulesInRouter(vpc_router, vpc_router_rules)
|
|
|
|
# 12. Delete IPv4 firewall rules for Network
|
|
for rule in network_routing_firewall_rules:
|
|
rule.delete(self.apiclient)
|
|
network_router_rules[2] = {"chain": "fw_chain_ingress",
|
|
"rule": "ip saddr %s ip daddr 0.0.0.0/0 icmp type %s accept" % (test_vpc.cidr, ICMPv4_ALL_TYPES),
|
|
"exists": False}
|
|
network_router_rules[3] = {"chain": "fw_chain_ingress",
|
|
"rule": "ip saddr %s ip daddr 0.0.0.0/0 tcp dport 22 accept" % test_vpc.cidr,
|
|
"exists": False}
|
|
network_router_rules[4] = {"chain": "fw_chain_ingress",
|
|
"rule": "ip saddr %s ip daddr 0.0.0.0/0 icmp type %s accept" % (vpc_router.publicip, ICMPv4_ALL_TYPES),
|
|
"exists": False}
|
|
self.verifyNftablesRulesInRouter(network_router, network_router_rules)
|
|
|
|
# 13. Test VM2 in VR1-Network (ping/ssh should fail)
|
|
self.verifyPingFromRouter(network_router, test_vpc_vm, expected=False)
|
|
# 14. Test VM1 in VR2-VPC (ping/ssh should fail)
|
|
self.verifyPingFromRouter(vpc_router, test_network_vm, expected=False)
|
|
|
|
@attr(tags=['advanced'], required_hardware=False)
|
|
def test_10_bgp_peers(self):
|
|
""" Test for BGP peers"""
|
|
"""
|
|
# 1. Create bgppeer
|
|
# 2. List bgppeer
|
|
# 3. Update bgppeer
|
|
# 4. dedicate bgppeer to domain
|
|
# 5. released dedicated bgppeer
|
|
# 6. dedicate bgppeer to sub-domain/account
|
|
# 7. released dedicated bgppeer
|
|
# 8. delete bgppeer
|
|
"""
|
|
self.message("Running test_10_bgp_peers")
|
|
# 1. Create bgp peer
|
|
bgppeer_1 = BgpPeer.create(
|
|
self.apiclient,
|
|
zoneid=self.zone.id,
|
|
asnumber=ASN_1,
|
|
ipaddress=IP4_ADDR_1
|
|
)
|
|
self.cleanup.append(bgppeer_1)
|
|
# 2. List bgp peer
|
|
bgppeers = BgpPeer.list(
|
|
self.apiclient,
|
|
id=bgppeer_1.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(bgppeers, list),
|
|
True,
|
|
"List bgppeers for zone should return a valid list"
|
|
)
|
|
self.assertEqual(
|
|
len(bgppeers) == 1,
|
|
True,
|
|
"The number of bgp peers (%s) should be equal to 1" % (len(bgppeers))
|
|
)
|
|
self.assertEqual(
|
|
bgppeers[0].asnumber == ASN_1 and bgppeers[0].ipaddress == IP4_ADDR_1,
|
|
True,
|
|
"The asnumber of bgp peer (%s) should be equal to %s, the ip address (%s) should be %s"
|
|
% (bgppeers[0].asnumber, ASN_1, bgppeers[0].ipaddress, IP4_ADDR_1)
|
|
)
|
|
# 3. Update bgp peer
|
|
bgppeer_1.update(
|
|
self.apiclient,
|
|
asnumber=ASN_2,
|
|
ipaddress=IP4_ADDR_2
|
|
)
|
|
bgppeers = BgpPeer.list(
|
|
self.apiclient,
|
|
id=bgppeer_1.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(bgppeers, list) and len(bgppeers) == 1
|
|
and bgppeers[0].asnumber == ASN_2 and bgppeers[0].ipaddress == IP4_ADDR_2,
|
|
True,
|
|
"The asnumber of bgp peer (%s) should be equal to %s, the ip address (%s) should be %s"
|
|
% (bgppeers[0].asnumber, ASN_2, bgppeers[0].ipaddress, IP4_ADDR_2)
|
|
)
|
|
# 4. dedicate bgp peer to domain
|
|
BgpPeer.dedicate(
|
|
self.apiclient,
|
|
id=bgppeer_1.id,
|
|
domainid=self.domain.id
|
|
)
|
|
bgppeers = BgpPeer.list(
|
|
self.apiclient,
|
|
id=bgppeer_1.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(bgppeers, list) and len(bgppeers) == 1 and bgppeers[0].domainid == self.domain.id,
|
|
True,
|
|
"The bgppeer should be dedicated to domain %s" % self.domain.id
|
|
)
|
|
# 5. released dedicated bgp peer
|
|
bgppeer_1.release(
|
|
self.apiclient
|
|
)
|
|
bgppeers = BgpPeer.list(
|
|
self.apiclient,
|
|
id=bgppeer_1.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(bgppeers, list) and len(bgppeers) == 1 and not bgppeers[0].domainid,
|
|
True,
|
|
"The bgp peer should not be dedicated to domain %s" % self.domain.id
|
|
)
|
|
# 6. dedicate bgp peer to sub-domain/account
|
|
BgpPeer.dedicate(
|
|
self.apiclient,
|
|
id=bgppeer_1.id,
|
|
domainid=self.sub_domain.id,
|
|
account=self.regular_user.name
|
|
)
|
|
bgppeers = BgpPeer.list(
|
|
self.apiclient,
|
|
id=bgppeer_1.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(bgppeers, list) and len(bgppeers) == 1
|
|
and bgppeers[0].domainid == self.sub_domain.id and bgppeers[0].account == self.regular_user.name,
|
|
True,
|
|
"The bgp peer should be dedicated to account %s" % self.regular_user.name
|
|
)
|
|
# 7. released dedicated bgp peer
|
|
bgppeer_1.release(
|
|
self.apiclient
|
|
)
|
|
bgppeers = BgpPeer.list(
|
|
self.apiclient,
|
|
id=bgppeer_1.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(bgppeers, list) and len(bgppeers) == 1 and not bgppeers[0].domainid,
|
|
True,
|
|
"The bgppeer should not be dedicated to account %s" % self.regular_user.name
|
|
)
|
|
# 8. delete bgp peer
|
|
bgppeer_1.delete(
|
|
self.apiclient
|
|
)
|
|
self.cleanup.remove(bgppeer_1)
|
|
|
|
@attr(tags=['advanced'], required_hardware=False)
|
|
def test_11_isolated_network_with_dynamic_routed_mode(self):
|
|
""" Test for Isolated Network with Dynamic Routed mode"""
|
|
"""
|
|
# 1. Create Isolated network with bgp_peer_1
|
|
# 2. Create VM in the network
|
|
# 3. Verify frr.conf in network VR
|
|
# 4. Update network BGP peers (to bgp_peer_1 and bgp_peer_2)
|
|
# 5. Verify frr.conf in network VR
|
|
# 6. Reboot VR
|
|
# 7. Verify frr.conf in network VR
|
|
# 8. Update network BGP peers (to bgppeer_2)
|
|
# 9. Verify frr.conf in network VR
|
|
# 10. Update network BGP peers (to null)
|
|
# 11. Verify frr.conf in network VR
|
|
"""
|
|
self.message("Running test_11_isolated_network_with_dynamic_routed_mode")
|
|
|
|
# 1. Create bgp peers
|
|
bgppeer_1 = BgpPeer.create(
|
|
self.apiclient,
|
|
zoneid=self.zone.id,
|
|
asnumber=ASN_1,
|
|
ipaddress=IP4_ADDR_1,
|
|
password=PASSWORD_1
|
|
)
|
|
self.cleanup.append(bgppeer_1)
|
|
|
|
# 1. Create Isolated network with Dynamic routing
|
|
test_network_dynamic = Network.create(
|
|
self.apiclient,
|
|
self.services["network"],
|
|
networkofferingid=self.network_offering_dynamic.id,
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
accountid=self.regular_user.name,
|
|
gateway=NETWORK_CIDR_PREFIX_DYNAMIC + ".1",
|
|
netmask="255.255.255.0",
|
|
bgppeerids=bgppeer_1.id
|
|
)
|
|
self.cleanup.append(test_network_dynamic)
|
|
|
|
# 2. Create VM in the network
|
|
test_network_dynamic_vm = VirtualMachine.create(
|
|
self.regular_user_apiclient,
|
|
self.services["virtual_machine"],
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
accountid=self.regular_user.name,
|
|
networkids=test_network_dynamic.id,
|
|
serviceofferingid=self.service_offering.id,
|
|
templateid=self.template.id)
|
|
self.cleanup.append(test_network_dynamic_vm)
|
|
|
|
network_router = self.get_router(networkid=test_network_dynamic.id)
|
|
|
|
# 3. Verify frr.conf in network VR
|
|
frr_configs = [{"config": "neighbor %s remote-as %s" % (bgppeer_1.ipaddress, bgppeer_1.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_1.ipaddress, PASSWORD_1),
|
|
"exists": True},
|
|
{"config": "network %s" % test_network_dynamic.cidr,
|
|
"exists": True}]
|
|
self.verifyFrrConf(network_router, frr_configs)
|
|
|
|
# 4. Update network BGP peers (to bgp_peer_1 and bgp_peer_2)
|
|
bgppeer_2 = BgpPeer.create(
|
|
self.apiclient,
|
|
zoneid=self.zone.id,
|
|
asnumber=ASN_2,
|
|
ipaddress=IP4_ADDR_2,
|
|
password=PASSWORD_2
|
|
)
|
|
self.cleanup.append(bgppeer_2)
|
|
|
|
test_network_dynamic.changeBgpPeers(
|
|
self.apiclient,
|
|
bgppeerids=[bgppeer_1.id, bgppeer_2.id]
|
|
)
|
|
|
|
# 5. Verify frr.conf in network VR
|
|
frr_configs = [{"config": "neighbor %s remote-as %s" % (bgppeer_1.ipaddress, bgppeer_1.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_1.ipaddress, PASSWORD_1),
|
|
"exists": True},
|
|
{"config": "neighbor %s remote-as %s" % (bgppeer_2.ipaddress, bgppeer_2.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_2.ipaddress, PASSWORD_2),
|
|
"exists": True},
|
|
{"config": "network %s" % test_network_dynamic.cidr,
|
|
"exists": True}]
|
|
self.verifyFrrConf(network_router, frr_configs)
|
|
|
|
# 6. Reboot VR
|
|
self.rebootRouter(network_router)
|
|
|
|
# 7. Verify frr.conf in network VR
|
|
network_router = self.get_router(networkid=test_network_dynamic.id)
|
|
self.verifyFrrConf(network_router, frr_configs)
|
|
|
|
# 8. Update network BGP peers (to bgppeer_2)
|
|
test_network_dynamic.changeBgpPeers(
|
|
self.apiclient,
|
|
bgppeerids=[bgppeer_2.id]
|
|
)
|
|
|
|
# 9. Verify frr.conf in network VR
|
|
frr_configs = [{"config": "neighbor %s remote-as %s" % (bgppeer_1.ipaddress, bgppeer_1.asnumber),
|
|
"exists": False},
|
|
{"config": "neighbor %s password %s" % (bgppeer_1.ipaddress, PASSWORD_1),
|
|
"exists": False},
|
|
{"config": "neighbor %s remote-as %s" % (bgppeer_2.ipaddress, bgppeer_2.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_2.ipaddress, PASSWORD_2),
|
|
"exists": True},
|
|
{"config": "network %s" % test_network_dynamic.cidr,
|
|
"exists": True}]
|
|
self.verifyFrrConf(network_router, frr_configs)
|
|
|
|
# 10. Update network BGP peers (to null)
|
|
test_network_dynamic.changeBgpPeers(
|
|
self.apiclient,
|
|
bgppeerids=[]
|
|
)
|
|
|
|
# 11. Verify frr.conf in network VR
|
|
frr_configs = [{"config": "neighbor %s remote-as %s" % (bgppeer_1.ipaddress, bgppeer_1.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_1.ipaddress, PASSWORD_1),
|
|
"exists": True},
|
|
{"config": "neighbor %s remote-as %s" % (bgppeer_2.ipaddress, bgppeer_2.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_2.ipaddress, PASSWORD_2),
|
|
"exists": True},
|
|
{"config": "network %s" % test_network_dynamic.cidr,
|
|
"exists": True}]
|
|
self.verifyFrrConf(network_router, frr_configs)
|
|
|
|
@attr(tags=['advanced'], required_hardware=False)
|
|
def test_12_vpc_and_tier_with_dynamic_routed_mode(self):
|
|
""" Test for VPC/tier with Dynamic Routed mode"""
|
|
"""
|
|
# 1. Create bgp peers
|
|
# 2. Create VPC
|
|
# 3. Create Network ACL (egress = Deny, ingress = Deny)
|
|
# 4. Create VPC tier with Network ACL in the VPC
|
|
# 5. Create VM in the VPC tier
|
|
# 6. Verify frr.conf in VPC VR
|
|
# 7. Update network BGP peers (to bgp_peer_1 and bgp_peer_2)
|
|
# 8. Verify frr.conf in VPC VR
|
|
# 9. Create VPC tier-2 with Network ACL in the VPC
|
|
# 10. Create VM-2 in the VPC tier-2
|
|
# 11. Verify frr.conf in VPC VR
|
|
# 12. Reboot VPC VR
|
|
# 13. Verify frr.conf in VPC VR
|
|
# 14. Update network BGP peers (to bgppeer_2)
|
|
# 15. Verify frr.conf in VPC VR
|
|
# 16. Update network BGP peers (to null)
|
|
# 17. Verify frr.conf in VPC VR
|
|
"""
|
|
self.message("Running test_12_vpc_and_tier_with_dynamic_routed_mode")
|
|
|
|
# 1. Create bgp peers
|
|
bgppeer_1 = BgpPeer.create(
|
|
self.apiclient,
|
|
zoneid=self.zone.id,
|
|
asnumber=ASN_1,
|
|
ipaddress=IP4_ADDR_1,
|
|
password=PASSWORD_1
|
|
)
|
|
self.cleanup.append(bgppeer_1)
|
|
|
|
# 2.1 VPC offering for static routing
|
|
vpc_offering_dynamic = VpcOffering.create(
|
|
self.apiclient,
|
|
VPC_OFFERING_DYNAMIC
|
|
)
|
|
self.cleanup.append(vpc_offering_dynamic)
|
|
vpc_offering_dynamic.update(self.apiclient, state='Enabled')
|
|
|
|
# 2.2 Create VPC
|
|
self.services["vpc"]["cidr"] = VPC_CIDR_PREFIX + ".8.0/22"
|
|
test_vpc_dynamic = VPC.create(self.apiclient,
|
|
self.services["vpc"],
|
|
vpcofferingid=vpc_offering_dynamic.id,
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
account=self.regular_user.name,
|
|
start=False,
|
|
bgppeerids=bgppeer_1.id
|
|
)
|
|
self.cleanup.append(test_vpc_dynamic)
|
|
|
|
# 3. Create Network ACL (egress = Deny, ingress = Deny)
|
|
test_network_acl_dynamic = NetworkACLList.create(self.apiclient,
|
|
services={},
|
|
name="test-network-acl-dynamic",
|
|
description="test-network-acl-dynamic",
|
|
vpcid=test_vpc_dynamic.id
|
|
)
|
|
|
|
# 4. Create VPC tier with Network ACL in the VPC
|
|
self.services["network"]["name"] = "test_vpc_tier_dynamic_1"
|
|
test_vpc_tier_dynamic_1 = Network.create(self.regular_user_apiclient,
|
|
self.services["network"],
|
|
networkofferingid=self.vpc_network_offering_dynamic.id,
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
accountid=self.regular_user.name,
|
|
vpcid=test_vpc_dynamic.id,
|
|
gateway=VPC_CIDR_PREFIX + ".8.1",
|
|
netmask="255.255.255.0",
|
|
aclid=test_network_acl_dynamic.id
|
|
)
|
|
self.cleanup.append(test_vpc_tier_dynamic_1)
|
|
|
|
# 5. Create VM in the VPC tier
|
|
test_vpc_vm_dynamic_1 = VirtualMachine.create(
|
|
self.regular_user_apiclient,
|
|
self.services["virtual_machine"],
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
accountid=self.regular_user.name,
|
|
networkids=test_vpc_tier_dynamic_1.id,
|
|
serviceofferingid=self.service_offering.id,
|
|
templateid=self.template.id)
|
|
self.cleanup.append(test_vpc_vm_dynamic_1)
|
|
|
|
vpc_router = self.get_router(vpcid=test_vpc_dynamic.id)
|
|
|
|
# 6. Verify frr.conf in VPC VR
|
|
frr_configs = [{"config": "neighbor %s remote-as %s" % (bgppeer_1.ipaddress, bgppeer_1.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_1.ipaddress, PASSWORD_1),
|
|
"exists": True},
|
|
{"config": "network %s" % test_vpc_tier_dynamic_1.cidr,
|
|
"exists": True}]
|
|
self.verifyFrrConf(vpc_router, frr_configs)
|
|
|
|
# 7. Update VPC BGP peers (to bgp_peer_1 and bgp_peer_2)
|
|
bgppeer_2 = BgpPeer.create(
|
|
self.apiclient,
|
|
zoneid=self.zone.id,
|
|
asnumber=ASN_2,
|
|
ipaddress=IP4_ADDR_2,
|
|
password=PASSWORD_2
|
|
)
|
|
self.cleanup.append(bgppeer_2)
|
|
|
|
test_vpc_dynamic.changeBgpPeers(
|
|
self.apiclient,
|
|
bgppeerids=[bgppeer_1.id, bgppeer_2.id]
|
|
)
|
|
|
|
# 8. Verify frr.conf in VPC VR
|
|
frr_configs = [{"config": "neighbor %s remote-as %s" % (bgppeer_1.ipaddress, bgppeer_1.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_1.ipaddress, PASSWORD_1),
|
|
"exists": True},
|
|
{"config": "neighbor %s remote-as %s" % (bgppeer_2.ipaddress, bgppeer_2.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_2.ipaddress, PASSWORD_2),
|
|
"exists": True},
|
|
{"config": "network %s" % test_vpc_tier_dynamic_1.cidr,
|
|
"exists": True}]
|
|
self.verifyFrrConf(vpc_router, frr_configs)
|
|
|
|
# 9. Create VPC tier-2 with Network ACL in the VPC
|
|
self.services["network"]["name"] = "test_vpc_tier_dynamic_2"
|
|
test_vpc_tier_dynamic_2 = Network.create(self.regular_user_apiclient,
|
|
self.services["network"],
|
|
networkofferingid=self.vpc_network_offering_dynamic.id,
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
accountid=self.regular_user.name,
|
|
vpcid=test_vpc_dynamic.id,
|
|
gateway=VPC_CIDR_PREFIX + ".9.1",
|
|
netmask="255.255.255.0",
|
|
aclid=test_network_acl_dynamic.id
|
|
)
|
|
self.cleanup.append(test_vpc_tier_dynamic_2)
|
|
|
|
# 10. Create VM-2 in the VPC tier-2
|
|
test_vpc_vm_dynamic_2 = VirtualMachine.create(
|
|
self.regular_user_apiclient,
|
|
self.services["virtual_machine"],
|
|
zoneid=self.zone.id,
|
|
domainid=self.sub_domain.id,
|
|
accountid=self.regular_user.name,
|
|
networkids=test_vpc_tier_dynamic_2.id,
|
|
serviceofferingid=self.service_offering.id,
|
|
templateid=self.template.id)
|
|
self.cleanup.append(test_vpc_vm_dynamic_2)
|
|
|
|
# 11. Verify frr.conf in VPC VR
|
|
frr_configs = [{"config": "neighbor %s remote-as %s" % (bgppeer_1.ipaddress, bgppeer_1.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_1.ipaddress, PASSWORD_1),
|
|
"exists": True},
|
|
{"config": "neighbor %s remote-as %s" % (bgppeer_2.ipaddress, bgppeer_2.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_2.ipaddress, PASSWORD_2),
|
|
"exists": True},
|
|
{"config": "network %s" % test_vpc_tier_dynamic_1.cidr,
|
|
"exists": True},
|
|
{"config": "network %s" % test_vpc_tier_dynamic_2.cidr,
|
|
"exists": True}]
|
|
self.verifyFrrConf(vpc_router, frr_configs)
|
|
|
|
# 12. Reboot VPC VR
|
|
self.rebootRouter(vpc_router)
|
|
|
|
# 13. Verify frr.conf in VPC VR
|
|
vpc_router = self.get_router(vpcid=test_vpc_dynamic.id)
|
|
self.verifyFrrConf(vpc_router, frr_configs)
|
|
|
|
# 14. Update VPC BGP peers (to bgppeer_2)
|
|
test_vpc_dynamic.changeBgpPeers(
|
|
self.apiclient,
|
|
bgppeerids=[bgppeer_2.id]
|
|
)
|
|
|
|
# 15. Verify frr.conf in VPC VR
|
|
frr_configs = [{"config": "neighbor %s remote-as %s" % (bgppeer_1.ipaddress, bgppeer_1.asnumber),
|
|
"exists": False},
|
|
{"config": "neighbor %s password %s" % (bgppeer_1.ipaddress, PASSWORD_1),
|
|
"exists": False},
|
|
{"config": "neighbor %s remote-as %s" % (bgppeer_2.ipaddress, bgppeer_2.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_2.ipaddress, PASSWORD_2),
|
|
"exists": True},
|
|
{"config": "network %s" % test_vpc_tier_dynamic_1.cidr,
|
|
"exists": True},
|
|
{"config": "network %s" % test_vpc_tier_dynamic_2.cidr,
|
|
"exists": True}]
|
|
self.verifyFrrConf(vpc_router, frr_configs)
|
|
|
|
# 16. Update VPC BGP peers (to null)
|
|
test_vpc_dynamic.changeBgpPeers(
|
|
self.apiclient,
|
|
bgppeerids=[]
|
|
)
|
|
|
|
# 17. Verify frr.conf in VPC VR
|
|
frr_configs = [{"config": "neighbor %s remote-as %s" % (bgppeer_1.ipaddress, bgppeer_1.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_1.ipaddress, PASSWORD_1),
|
|
"exists": True},
|
|
{"config": "neighbor %s remote-as %s" % (bgppeer_2.ipaddress, bgppeer_2.asnumber),
|
|
"exists": True},
|
|
{"config": "neighbor %s password %s" % (bgppeer_2.ipaddress, PASSWORD_2),
|
|
"exists": True},
|
|
{"config": "network %s" % test_vpc_tier_dynamic_1.cidr,
|
|
"exists": True},
|
|
{"config": "network %s" % test_vpc_tier_dynamic_2.cidr,
|
|
"exists": True}]
|
|
self.verifyFrrConf(vpc_router, frr_configs)
|
|
|
|
|
|
@attr(tags=['advanced'], required_hardware=False)
|
|
def test_13_asn_ranges(self):
|
|
""" Test for ASN ranges"""
|
|
"""
|
|
# 1. Create an ASN range without overlap
|
|
# 2. List ASN ranges by zoneid
|
|
# 3. List ASN numbers by ASN range id
|
|
# 4. Create an ASN range with overlap, it should fail
|
|
# 5. Delete ASN range
|
|
"""
|
|
self.message("Running test_13_asn_ranges")
|
|
|
|
# 1. Create an ASN range without overlap
|
|
asnrange_2 = ASNRange.create(
|
|
self.apiclient,
|
|
zoneid=self.zone.id,
|
|
startasn=END_ASN+100,
|
|
endasn=END_ASN+200
|
|
)
|
|
self.cleanup.append(asnrange_2)
|
|
|
|
# 2. List ASN ranges by zoneid
|
|
ranges = ASNRange.list(
|
|
self.apiclient,
|
|
zoneid = self.zone.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(ranges, list),
|
|
True,
|
|
"List ASN ranges by zoneid should return a valid list"
|
|
)
|
|
self.assertEqual(
|
|
len(ranges) >= 1,
|
|
True,
|
|
"The number of ASN ranges (%s) should be at least 1" % (len(ranges))
|
|
)
|
|
asnrange_2_new = None
|
|
for range in ranges:
|
|
if range.startasn == asnrange_2.startasn:
|
|
asnrange_2_new = range
|
|
break
|
|
if asnrange_2_new:
|
|
self.assertEqual(
|
|
asnrange_2_new.endasn == asnrange_2.endasn,
|
|
True,
|
|
"The end ASN of ASN range (%s-%s) should be equal to %s" % (asnrange_2_new.startasn, asnrange_2_new.endasn, asnrange_2.endasn)
|
|
)
|
|
else:
|
|
self.fail("Unable to find ASN range (%s-%s)" % (asnrange_2.startasn, asnrange_2.endasn))
|
|
|
|
# 3. List ASN numbers by ASN range id
|
|
asnumbers = ASNRange.listAsNumbers(
|
|
self.apiclient,
|
|
zoneid = self.zone.id,
|
|
asnrangeid = asnrange_2.id
|
|
)
|
|
self.assertEqual(
|
|
isinstance(asnumbers, list),
|
|
True,
|
|
"List AS numbers should return a valid list"
|
|
)
|
|
self.assertEqual(
|
|
len(asnumbers) == asnrange_2.endasn - asnrange_2.startasn + 1,
|
|
True,
|
|
"The number of asnumbers (%s) should be equal to %s" % (len(asnumbers), (asnrange_2.endasn - asnrange_2.startasn + 1))
|
|
)
|
|
|
|
# 4. Create an ASN range with overlap, it should fail
|
|
try:
|
|
asnrange_3 = ASNRange.create(
|
|
self.apiclient,
|
|
zoneid=self.zone.id,
|
|
startasn=END_ASN+150,
|
|
endasn=END_ASN+250
|
|
)
|
|
self.cleanup.append(asnrange_3)
|
|
self.fail("Succeeded to create ASN range (%s-%s) but it should fail" % (asnrange_3.startasn, asnrange_3.endasn))
|
|
except Exception as e:
|
|
self.message("Failed to create ASN range but it is expected")
|
|
|
|
# 5. Delete ASN range
|
|
asnrange_2.delete(
|
|
self.apiclient
|
|
)
|
|
self.cleanup.remove(asnrange_2)
|