From 7e83d0876ddb84a45e130eeba28bc40ef53c074b Mon Sep 17 00:00:00 2001 From: Yaron Yogev Date: Thu, 27 Jul 2017 09:02:54 +0300 Subject: Calipso initial release for OPNFV Change-Id: I7210c244b0c10fa80bfa8c77cb86c9d6ddf8bc88 Signed-off-by: Yaron Yogev --- app/discover/events/event_port_add.py | 309 ++++++++++++++++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 app/discover/events/event_port_add.py (limited to 'app/discover/events/event_port_add.py') diff --git a/app/discover/events/event_port_add.py b/app/discover/events/event_port_add.py new file mode 100644 index 0000000..63a5e80 --- /dev/null +++ b/app/discover/events/event_port_add.py @@ -0,0 +1,309 @@ +############################################################################### +# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) # +# and others # +# # +# All rights reserved. This program and the accompanying materials # +# are made available under the terms of the Apache License, Version 2.0 # +# which accompanies this distribution, and is available at # +# http://www.apache.org/licenses/LICENSE-2.0 # +############################################################################### +import datetime + +from discover.events.event_base import EventBase, EventResult +from discover.fetchers.api.api_fetch_host_instances import ApiFetchHostInstances +from discover.fetchers.cli.cli_fetch_instance_vnics import CliFetchInstanceVnics +from discover.fetchers.cli.cli_fetch_instance_vnics_vpp import CliFetchInstanceVnicsVpp +from discover.fetchers.cli.cli_fetch_vservice_vnics import CliFetchVserviceVnics +from discover.find_links_for_instance_vnics import FindLinksForInstanceVnics +from discover.find_links_for_vedges import FindLinksForVedges +from discover.scanner import Scanner + + +class EventPortAdd(EventBase): + + def get_name_by_id(self, object_id): + item = self.inv.get_by_id(self.env, object_id) + if item: + return item['name'] + return None + + def add_port_document(self, env, project_name, project_id, network_name, network_id, port): + # add other data for port document + port['type'] = 'port' + port['environment'] = env + + port['parent_id'] = port['network_id'] + '-ports' + port['parent_text'] = 'Ports' + port['parent_type'] = 'ports_folder' + + port['name'] = port['mac_address'] + port['object'] = port['name'] + port['project'] = project_name + + port['id_path'] = "{}/{}-projects/{}/{}-networks/{}/{}-ports/{}" \ + .format(env, env, + project_id, project_id, + network_id, network_id, port['id']) + port['name_path'] = "/{}/Projects/{}/Networks/{}/Ports/{}" \ + .format(env, project_name, network_name, port['id']) + + port['show_in_tree'] = True + port['last_scanned'] = datetime.datetime.utcnow() + self.inv.set(port) + self.log.info("add port document for port: {}".format(port['id'])) + + def add_ports_folder(self, env, project_id, network_id, network_name): + port_folder = { + "id": network_id + "-ports", + "create_object": True, + "name": "Ports", + "text": "Ports", + "type": "ports_folder", + "parent_id": network_id, + "parent_type": "network", + 'environment': env, + 'id_path': "{}/{}-projects/{}/{}-networks/{}/{}-ports/" + .format(env, env, project_id, project_id, + network_id, network_id), + 'name_path': "/{}/Projects/{}/Networks/{}/Ports" + .format(env, project_id, network_name), + "show_in_tree": True, + "last_scanned": datetime.datetime.utcnow(), + "object_name": "Ports", + } + self.inv.set(port_folder) + self.log.info("add ports_folder document for network: {}.".format(network_id)) + + def add_network_services_folder(self, env, project_id, network_id, network_name): + network_services_folder = { + "create_object": True, + "environment": env, + "id": network_id + "-network_services", + "id_path": "{}/{}-projects/{}/{}-networks/{}/{}-network_services/" + .format(env, env, project_id, project_id, + network_id, network_id), + "last_scanned": datetime.datetime.utcnow(), + "name": "Network vServices", + "name_path": "/{}/Projects/{}/Networks/{}/Network vServices" + .format(env, project_id, network_name), + "object_name": "Network vServices", + "parent_id": network_id, + "parent_type": "network", + "show_in_tree": True, + "text": "Network vServices", + "type": "network_services_folder" + } + self.inv.set(network_services_folder) + self.log.info("add network services folder for network:{}".format(network_id)) + + def add_dhcp_document(self, env, host, network_id, network_name): + dhcp_document = { + "environment": env, + "host": host['id'], + "id": "qdhcp-" + network_id, + "id_path": "{}/{}-vservices/{}-vservices-dhcps/qdhcp-{}" + .format(host['id_path'], host['id'], + host['id'], network_id), + "last_scanned": datetime.datetime.utcnow(), + "local_service_id": "qdhcp-" + network_id, + "name": "dhcp-" + network_name, + "name_path": host['name_path'] + "/Vservices/DHCP servers/dhcp-" + network_name, + "network": [network_id], + "object_name": "dhcp-" + network_name, + "parent_id": host['id'] + "-vservices-dhcps", + "parent_text": "DHCP servers", + "parent_type": "vservice_dhcps_folder", + "service_type": "dhcp", + "show_in_tree": True, + "type": "vservice" + } + self.inv.set(dhcp_document) + self.log.info("add DHCP document for network: {}.".format(network_id)) + + # This method has dynamic usages, take caution when changing its signature + def add_vnics_folder(self, + env, host, + object_id, network_name='', + object_type="dhcp", router_name=''): + # when vservice is DHCP, id = network_id, + # when vservice is router, id = router_id + type_map = {"dhcp": ('DHCP servers', 'dhcp-' + network_name), + "router": ('Gateways', router_name)} + + vnics_folder = { + "environment": env, + "id": "q{}-{}-vnics".format(object_type, object_id), + "id_path": "{}/{}-vservices/{}-vservices-{}s/q{}-{}/q{}-{}-vnics" + .format(host['id_path'], host['id'], host['id'], + object_type, object_type, object_id, + object_type, object_id), + "last_scanned": datetime.datetime.utcnow(), + "name": "q{}-{}-vnics".format(object_type, object_id), + "name_path": "{}/Vservices/{}/{}/vNICs" + .format(host['name_path'], + type_map[object_type][0], + type_map[object_type][1]), + "object_name": "vNICs", + "parent_id": "q{}-{}".format(object_type, object_id), + "parent_type": "vservice", + "show_in_tree": True, + "text": "vNICs", + "type": "vnics_folder" + } + self.inv.set(vnics_folder) + self.log.info("add vnics_folder document for q{}-{}-vnics" + .format(object_type, object_id)) + + # This method has dynamic usages, take caution when changing its signature + def add_vnic_document(self, + env, host, + object_id, network_name='', + object_type='dhcp', router_name='', + mac_address=None): + # when vservice is DHCP, id = network_id, + # when vservice is router, id = router_id + type_map = {"dhcp": ('DHCP servers', 'dhcp-' + network_name), + "router": ('Gateways', router_name)} + + fetcher = CliFetchVserviceVnics() + fetcher.set_env(env) + namespace = 'q{}-{}'.format(object_type, object_id) + vnic_documents = fetcher.handle_service(host['id'], namespace, enable_cache=False) + if not vnic_documents: + self.log.info("Vnic document not found in namespace.") + return False + + if mac_address is not None: + for doc in vnic_documents: + if doc['mac_address'] == mac_address: + # add a specific vnic document. + doc["environment"] = env + doc["id_path"] = "{}/{}-vservices/{}-vservices-{}s/{}/{}-vnics/{}"\ + .format(host['id_path'], host['id'], + host['id'], object_type, namespace, + namespace, doc["id"]) + doc["name_path"] = "{}/Vservices/{}/{}/vNICs/{}" \ + .format(host['name_path'], + type_map[object_type][0], + type_map[object_type][1], + doc["id"]) + self.inv.set(doc) + self.log.info("add vnic document with mac_address: {}." + .format(mac_address)) + return True + + self.log.info("Can not find vnic document by mac_address: {}" + .format(mac_address)) + return False + else: + for doc in vnic_documents: + # add all vnic documents. + doc["environment"] = env + doc["id_path"] = "{}/{}-vservices/{}-vservices-{}s/{}/{}-vnics/{}" \ + .format(host['id_path'], host['id'], + host['id'], object_type, + namespace, namespace, doc["id"]) + doc["name_path"] = "{}/Vservices/{}/{}/vNICs/{}" \ + .format(host['name_path'], + type_map[object_type][0], + type_map[object_type][1], + doc["id"]) + self.inv.set(doc) + self.log.info("add vnic document with mac_address: {}." + .format(doc["mac_address"])) + return True + + def handle_dhcp_device(self, env, notification, network_id, network_name, mac_address=None): + # add dhcp vservice document. + host_id = notification["publisher_id"].replace("network.", "", 1) + host = self.inv.get_by_id(env, host_id) + + self.add_dhcp_document(env, host, network_id, network_name) + + # add vnics folder. + self.add_vnics_folder(env, host, network_id, network_name) + + # add vnic document. + self.add_vnic_document(env, host, network_id, network_name, mac_address=mac_address) + + def handle(self, env, notification): + project = notification['_context_project_name'] + project_id = notification['_context_project_id'] + payload = notification['payload'] + port = payload['port'] + network_id = port['network_id'] + network_name = self.get_name_by_id(network_id) + mac_address = port['mac_address'] + + # check ports folder document. + ports_folder = self.inv.get_by_id(env, network_id + '-ports') + if not ports_folder: + self.log.info("ports folder not found, add ports folder first.") + self.add_ports_folder(env, project_id, network_id, network_name) + self.add_port_document(env, project, project_id, network_name, network_id, port) + + # update the port related documents. + if 'compute' in port['device_owner']: + # update the instance related document. + host_id = port['binding:host_id'] + instance_id = port['device_id'] + old_instance_doc = self.inv.get_by_id(env, instance_id) + instances_root_id = host_id + '-instances' + instances_root = self.inv.get_by_id(env, instances_root_id) + if not instances_root: + self.log.info('instance document not found, aborting port adding') + return EventResult(result=False, retry=True) + + # update instance + instance_fetcher = ApiFetchHostInstances() + instance_fetcher.set_env(env) + instance_docs = instance_fetcher.get(host_id + '-') + instance = next(filter(lambda i: i['id'] == instance_id, instance_docs), None) + + if instance: + old_instance_doc['network_info'] = instance['network_info'] + old_instance_doc['network'] = instance['network'] + if old_instance_doc.get('mac_address') is None: + old_instance_doc['mac_address'] = mac_address + + self.inv.set(old_instance_doc) + self.log.info("update instance document") + + # add vnic document. + if port['binding:vif_type'] == 'vpp': + vnic_fetcher = CliFetchInstanceVnicsVpp() + else: + # set ovs as default type. + vnic_fetcher = CliFetchInstanceVnics() + + vnic_fetcher.set_env(env) + vnic_docs = vnic_fetcher.get(instance_id + '-') + vnic = next(filter(lambda vnic: vnic['mac_address'] == mac_address, vnic_docs), None) + + if vnic: + vnic['environment'] = env + vnic['type'] = 'vnic' + vnic['name_path'] = old_instance_doc['name_path'] + '/vNICs/' + vnic['name'] + vnic['id_path'] = '{}/{}/{}'.format(old_instance_doc['id_path'], + old_instance_doc['id'], + vnic['name']) + self.inv.set(vnic) + self.log.info("add instance-vnic document, mac_address: {}" + .format(mac_address)) + + self.log.info("scanning for links") + fetchers_implementing_add_links = [FindLinksForInstanceVnics(), FindLinksForVedges()] + for fetcher in fetchers_implementing_add_links: + fetcher.add_links() + scanner = Scanner() + scanner.set_env(env) + scanner.scan_cliques() + + port_document = self.inv.get_by_id(env, port['id']) + if not port_document: + self.log.error("Port {} failed to add".format(port['id'])) + return EventResult(result=False, retry=True) + + return EventResult(result=True, + related_object=port['id'], + display_context=network_id) -- cgit 1.2.3-korg