From 5987bd298cc39073364ff168f469dc4c396c2624 Mon Sep 17 00:00:00 2001 From: Sachin Bansal Date: Fri, 4 Dec 2015 16:51:30 -0800 Subject: [PATCH] Schema transformer changes for Bgp as a service Added schema transformer changes and unit test cases for BGP as a service Change-Id: Ia2739bdfcde9e161179463952d0f2cbec6653dca Partial-Bug: 1518047 --- src/config/schema-transformer/config_db.py | 176 +++++++++++++++++- src/config/schema-transformer/db.py | 16 ++ .../schema-transformer/test/test_service.py | 49 +++++ src/config/schema-transformer/to_bgp.py | 15 +- src/schema/bgp_schema.xsd | 3 + src/schema/vnc_cfg.xsd | 1 + 6 files changed, 253 insertions(+), 7 deletions(-) diff --git a/src/config/schema-transformer/config_db.py b/src/config/schema-transformer/config_db.py index 1ebb7bb9f89..6c378bfe29f 100644 --- a/src/config/schema-transformer/config_db.py +++ b/src/config/schema-transformer/config_db.py @@ -2495,21 +2495,33 @@ class BgpRouterST(DBBaseST): def __init__(self, name, obj=None): self.name = name self.asn = None + self.bgp_as_a_service = None self.update(obj) # end __init__ def update(self, obj=None): self.obj = obj or self.read_vnc_obj(fq_name=self.name) self.set_params(self.obj.get_bgp_router_parameters()) + self.update_single_ref('bgp_as_a_service', self.obj) # end update + def delete_obj(self): + self.update_single_ref('bgp_as_a_service', {}) + if self.router_type == 'bgpaas-client': + self._cassandra.free_bgpaas_port(self.source_port) + # end delete_ref + def set_params(self, params): self.vendor = (params.vendor or 'contrail').lower() self.identifier = params.identifier - if self.vendor == 'contrail': - self.update_global_asn(GlobalSystemConfigST.get_autonomous_system()) - else: - self.update_autonomous_system(params.autonomous_system) + self.router_type = params.router_type + self.source_port = params.source_port + if self.router_type not in ('bgpaas-client', 'bgpaas-server'): + if self.vendor == 'contrail': + self.update_global_asn( + GlobalSystemConfigST.get_autonomous_system()) + else: + self.update_autonomous_system(params.autonomous_system) # end set_params def update_global_asn(self, asn): @@ -2531,7 +2543,62 @@ def update_autonomous_system(self, asn): # end update_autonomous_system def evaluate(self): - self.update_peering() + if self.router_type == 'bgpaas-client': + bgpaas = BgpAsAServiceST.get(self.bgp_as_a_service) + ret = self.update_bgpaas_client(bgpaas) + if ret == -1: + if bgpaas: + bgpaas.obj.del_bgp_router(self.obj) + try: + self._vnc_lib.bgp_as_a_service_update(bgpaas.obj) + except NoIdError: + pass + self._vnc_lib.bgp_router_delete(id=self.obj.uuid) + elif ret: + self._vnc_lib.bgp_router_update(self.obj) + elif self.router_type != 'bgpaas-server': + self.update_peering() + # end evaluate + + def update_bgpaas_client(self, bgpaas): + if not bgpaas: + return -1 + for vmi_name, router in bgpaas.bgpaas_clients.items(): + if router == self.name: + break + else: + return -1 + if vmi_name not in bgpaas.virtual_machine_interfaces: + del bgpaas.bgpaas_clients[vmi_name] + return -1 + vmi = VirtualMachineInterfaceST.get(vmi_name) + if vmi is None or vmi.virtual_network is None: + del bgpaas.bgpaas_clients[vmi_name] + return -1 + vn = VirtualNetworkST.get(vmi.virtual_network) + if not vn or self.obj.get_parent_fq_name_str() != vn._default_ri_name: + del bgpaas.bgpaas_clients[vmi_name] + return -1 + update = False + params = self.obj.get_bgp_router_parameters() + if self.asn != bgpaas.asn: + params.autonomous_system = bgpaas.asn + self.asn = bgpaas.asn + update = True + if params.address != bgpaas.ip_address: + params.address = bgpaas.ip_address + update = True + if params.identifier != bgpaas.ip_address: + params.identifier = bgpaas.ip_address + update = True + router_refs = self.obj.get_bgp_router_refs() + peering_attribs = router_refs[0]['attr'] + if peering_attribs != bgpaas.peering_attribs: + self.obj.set_bgp_router_list([router_refs[0]['to']], + [bgpaas.peering_attribs]) + update = True + return update + # end update_bgpaas_client def update_peering(self): if not GlobalSystemConfigST.get_ibgp_auto_mesh(): @@ -2582,6 +2649,102 @@ def handle_st_object_req(self): # end class BgpRouterST +class BgpAsAServiceST(DBBaseST): + _dict = {} + obj_type = 'bgp_as_a_service' + + def __init__(self, name, obj=None): + self.name = name + self.obj = obj or self.read_vnc_obj(fq_name=name) + self.virtual_machine_interfaces = set() + self.bgp_routers = set() + self.bgpaas_clients = {} + self.update(self.obj) + # end __init__ + + def update(self, obj=None): + self.obj = obj or self.read_vnc_obj(fq_name=self.name) + self.ip_address = self.obj.get_bgpaas_ip_address() + self.asn = self.obj.get_autonomous_system() + session_attrib = self.obj.get_bgpaas_session_attributes() + bgp_session = BgpSession() + if session_attrib: + bgp_session.attributes=[self.session_attrib] + self.peering_attribs = BgpPeeringAttributes(session=[bgp_session]) + self.update_multiple_refs('virtual_machine_interface', self.obj) + self.update_multiple_refs('bgp_router', self.obj) + # end update + + def delete_obj(self): + self.update_multiple_refs('virtual_machine_interface', {}) + self.update_multiple_refs('bgp_router', {}) + # end delete_obj + + def evaluate(self): + for name in (self.virtual_machine_interfaces - + set(self.bgpaas_clients.keys())): + self.create_bgp_router(name) + # end evaluate + + def create_bgp_router(self, name): + vmi = VirtualMachineInterfaceST.get(name) + if not vmi: + self.virtual_machine_interfaces.discard(name) + return + vn = VirtualNetworkST.get(vmi.virtual_network) + if not vn: + return + ri = vn.get_primary_routing_instance() + if not ri: + return + router_fq_name = ri.obj.get_fq_name_str() + ':' + vmi.obj.name + if router_fq_name in BgpRouterST: + self.bgp_routers.add(router_fq_name) + self.bgpaas_clients[name] = router_fq_name + return + server_fq_name = ri.obj.get_fq_name_str() + ':bgpaas-server' + server_router = BgpRouterST.get(server_fq_name) + if not server_router: + server_router = BgpRouter('bgpaas-server', parent_obj=ri.obj) + params = BgpRouterParams(router_type='bgpaas-server') + server_router.set_bgp_router_parameters(params) + self._vnc_lib.bgp_router_create(server_router) + BgpRouterST.locate(server_fq_name, server_router) + else: + server_router = server_router.obj + bgp_router = BgpRouter(vmi.obj.name, parent_obj=ri.obj) + params = BgpRouterParams( + autonomous_system=self.asn, + ip_address=self.ip_address, + identifier=self.ip_address, + source_port=self._cassandra.alloc_bgpaas_port(router_fq_name), + router_type='bgpaas-client') + bgp_router.set_bgp_router_parameters(params) + bgp_router.set_bgp_router(server_router, self.peering_attribs) + self._vnc_lib.bgp_router_create(bgp_router) + bgpr = BgpRouterST.locate(router_fq_name, bgp_router) + self.obj.add_bgp_router(bgp_router) + self._vnc_lib.bgp_as_a_service_update(self.obj) + self.bgp_routers.add(router_fq_name) + bgpr.bgp_as_a_service = self.name + self.bgpaas_clients[name] = router_fq_name + # end create_bgp_router + + def handle_st_object_req(self): + resp = DBBaseST.handle_st_object_req() + resp.obj_refs = [ + sandesh.RefsList('virtual_machine_interface', + self.virtual_machine_interfaces), + sandesh.RefsList('bgp_router', self.bgp_routers) + ] + resp.properties = [ + sandesh.PropList('ip_address', self.ip_address), + sandesh.PropList('asn', self.asn) + ] + return resp + # end handle_st_object_req +# end class BgpAsAService + class VirtualMachineInterfaceST(DBBaseST): _dict = {} obj_type = 'virtual_machine_interface' @@ -2593,6 +2756,7 @@ def __init__(self, name, obj=None): self.virtual_network = None self.virtual_machine = None self.logical_router = None + self.bgp_as_a_service = None self.uuid = None self.instance_ips = set() self.floating_ips = set() @@ -2614,6 +2778,7 @@ def update(self, obj=None): else: self.update_single_ref('virtual_machine', self.obj) self.update_single_ref('logical_router', self.obj) + self.update_single_ref('bgp_as_a_service', self.obj) self.set_properties() self.update_routing_instances(self.obj.get_routing_instance_refs()) # end update @@ -2624,6 +2789,7 @@ def delete_obj(self): self.update_single_ref('logical_router', {}) self.update_multiple_refs('instance_ip', {}) self.update_multiple_refs('floating_ip', {}) + self.update_multiple_refs('bgp_as_a_service', {}) self.update_routing_instances([]) # end delete_obj diff --git a/src/config/schema-transformer/db.py b/src/config/schema-transformer/db.py index 5d72cf137de..4f14989c66b 100644 --- a/src/config/schema-transformer/db.py +++ b/src/config/schema-transformer/db.py @@ -35,6 +35,7 @@ class SchemaTransformerDB(VncCassandraClient): _SERVICE_CHAIN_MAX_VLAN = 4093 _SERVICE_CHAIN_VLAN_ALLOC_PATH = "/id/service-chain/vlan/" + _BGPAAS_PORT_ALLOC_PATH = "/id/bgpaas/port/" @classmethod def get_db_info(cls): @@ -99,6 +100,11 @@ def __init__(self, manager, zkclient): zkclient, self._zk_path_pfx+self._BGP_RTGT_ALLOC_PATH, self._BGP_RTGT_MAX_ID, common.BGP_RTGT_MIN_ID) + self._bgpaas_port_allocator = IndexAllocator( + zkclient, self._zk_path_pfx + self._BGPAAS_PORT_ALLOC_PATH, + self._args.bgpaas_port_end - self._args.bgpaas_port_start, + self._args.bgpaas_port_start) + self._sc_vlan_allocator_dict = {} self._upgrade_vlan_alloc_path() # end __init__ @@ -260,3 +266,13 @@ def alloc_vn_id(self, name): def free_vn_id(self, vn_id): self._vn_id_allocator.delete(vn_id) + + def get_bgpaas_port(self, port): + return self._bgpaas_allocator.read(port) + + def alloc_bgpaas_port(self, name): + return self._bgpaas_port_allocator.alloc(name) + + def free_bgpaas_port(self, port): + self._bgpaas_port_allocator.delete(port) + diff --git a/src/config/schema-transformer/test/test_service.py b/src/config/schema-transformer/test/test_service.py index aa2355797ae..21b6b7aed5a 100644 --- a/src/config/schema-transformer/test/test_service.py +++ b/src/config/schema-transformer/test/test_service.py @@ -238,6 +238,16 @@ def check_ri_is_present(self, fq_name): def check_link_in_ifmap_graph(self, fq_name_str, links): self._vnc_lib.routing_instance_read(fq_name) + @retries(5) + def wait_to_get_object(self, obj_class, obj_name): + if obj_name not in obj_class._dict: + raise Exception('%s not found' % obj_name) + + @retries(5) + def wait_to_delete_object(self, obj_class, obj_name): + if obj_name in obj_class._dict: + raise Exception('%s still found' % obj_name) + @retries(5) def wait_to_get_sc(self, left_vn=None, right_vn=None): for sc in to_bgp.ServiceChain.values(): @@ -2157,4 +2167,43 @@ def test_misc(self): #end test_misc + def test_bgpaas(self): + # create vn1 + vn1_name = self.id() + 'vn1' + vn1_obj = self.create_virtual_network(vn1_name, '10.0.0.0/24') + + project_name = ['default-domain', 'default-project'] + project_obj = self._vnc_lib.project_read(fq_name=project_name) + port_name = self.id() + 'p1' + port_obj = VirtualMachineInterface(port_name, parent_obj=project_obj) + port_obj.add_virtual_network(vn1_obj) + self._vnc_lib.virtual_machine_interface_create(port_obj) + + bgpaas_name = self.id() + 'bgp1' + bgpaas = BgpAsAService(bgpaas_name, parent_obj=project_obj) + bgpaas.add_virtual_machine_interface(port_obj) + self._vnc_lib.bgp_as_a_service_create(bgpaas) + + self.wait_to_get_object(config_db.BgpAsAServiceST, + bgpaas.get_fq_name_str()) + self.wait_to_get_object(config_db.BgpRouterST, + vn1_obj.get_fq_name_str() + ':' + vn1_name + ':' + port_name) + + port2_name = self.id() + 'p2' + port2_obj = VirtualMachineInterface(port2_name, parent_obj=project_obj) + port2_obj.add_virtual_network(vn1_obj) + self._vnc_lib.virtual_machine_interface_create(port2_obj) + bgpaas.add_virtual_machine_interface(port2_obj) + self._vnc_lib.bgp_as_a_service_update(bgpaas) + self.wait_to_get_object(config_db.BgpRouterST, + vn1_obj.get_fq_name_str() + ':' + vn1_name + ':' + port2_name) + + bgpaas.del_virtual_machine_interface(port_obj) + self._vnc_lib.bgp_as_a_service_update(bgpaas) + self.wait_to_delete_object(config_db.BgpRouterST, + vn1_obj.get_fq_name_str() + ':' + vn1_name + ':' + port_name) + self._vnc_lib.bgp_as_a_service_delete(id=bgpaas.uuid) + self.wait_to_delete_object(config_db.BgpRouterST, + vn1_obj.get_fq_name_str() + ':' + vn1_name + ':' + port2_name) + # end test_bgpaas # end class TestRouteTable diff --git a/src/config/schema-transformer/to_bgp.py b/src/config/schema-transformer/to_bgp.py index f396f9d5526..9cd683f7dc0 100644 --- a/src/config/schema-transformer/to_bgp.py +++ b/src/config/schema-transformer/to_bgp.py @@ -65,12 +65,13 @@ class SchemaTransformer(object): 'self': ['virtual_network'], }, 'virtual_machine_interface': { - 'self': ['virtual_machine', 'virtual_network'], - 'virtual_network': ['virtual_machine'], + 'self': ['virtual_machine', 'virtual_network', 'bgp_as_a_service'], + 'virtual_network': ['virtual_machine', 'bgp_as_a_service'], 'logical_router': ['virtual_network'], 'instance_ip': ['virtual_machine'], 'floating_ip': ['virtual_machine'], 'virtual_machine': [], + 'bgp_as_a_service': [], }, 'virtual_network': { 'self': ['network_policy'], @@ -112,6 +113,10 @@ class SchemaTransformer(object): 'instance_ip': { 'self': ['virtual_machine_interface'], }, + 'bgp_as_a_service': { + 'self': ['bgp_router'], + 'virtual_machine)interface': ['bgp_router'] + }, 'bgp_router': { 'self': [], }, @@ -605,6 +610,8 @@ def parse_args(args_str): 'logging_conf': '', 'logger_class': None, 'sandesh_send_rate_limit': SandeshSystem.get_sandesh_send_rate_limit(), + 'bgpaas_port_start': '50000', + 'bgpaas_port_end': '50256', } secopts = { 'use_certs': False, @@ -717,6 +724,10 @@ def parse_args(args_str): parser.add_argument("--rabbit_password", help="password for rabbit") parser.add_argument("--rabbit_ha_mode", action='store_true', help="True if the rabbitmq cluster is mirroring all queue") + parser.add_argument("--bgpaas_port_start", + help="Start port for bgp-as-a-service proxy") + parser.add_argument("--bgpaas_port_end", + help="End port for bgp-as-a-service proxy") args = parser.parse_args(remaining_argv) if type(args.cassandra_server_list) is str: diff --git a/src/schema/bgp_schema.xsd b/src/schema/bgp_schema.xsd index 68fec9282ef..26e811260fe 100644 --- a/src/schema/bgp_schema.xsd +++ b/src/schema/bgp_schema.xsd @@ -20,6 +20,9 @@ Link('connection', 'routing-instance', 'routing-instance', ['ref']) --> + + diff --git a/src/schema/vnc_cfg.xsd b/src/schema/vnc_cfg.xsd index 74b437eb21b..ae346c0e085 100644 --- a/src/schema/vnc_cfg.xsd +++ b/src/schema/vnc_cfg.xsd @@ -1290,6 +1290,7 @@ targetNamespace="http://www.contrailsystems.com/2012/VNC-CONFIG/0"> +