예제 #1
0
    def handle(self, env, values):
        # find the host, to serve as parent
        instance_id = values['payload']['instance_id']
        host_id = values['payload']['host']
        instances_root_id = host_id + '-instances'
        instances_root = self.inv.get_by_id(env, instances_root_id)
        if not instances_root:
            self.log.info('instances root not found, aborting instance add')
            return EventResult(result=False, retry=True)

        # scan instance
        scanner = Scanner()
        scanner.set_env(env)
        scanner.scan("ScanInstancesRoot",
                     instances_root,
                     limit_to_child_id=instance_id,
                     limit_to_child_type='instance')
        scanner.scan_from_queue()

        # scan host
        host = self.inv.get_by_id(env, host_id)
        scanner.scan(
            'ScanHost',
            host,
            limit_to_child_type=['vconnectors_folder', 'vedges_folder'])
        scanner.scan_from_queue()
        scanner.scan_links()
        scanner.scan_cliques()

        return EventResult(result=True,
                           related_object=instance_id,
                           display_context=instance_id)
예제 #2
0
    def handle(self, env, notification):
        network = notification['payload']['network']
        network_id = network['id']

        network_document = self.inv.get_by_id(env, network_id)
        if not network_document:
            self.log.info('Network document not found, aborting network update')
            return EventResult(result=False, retry=True)

        # update network document
        name = network['name']
        if name != network_document['name']:
            network_document['name'] = name
            network_document['object_name'] = name

            name_path = network_document['name_path']
            network_document['name_path'] = name_path[:name_path.rindex('/') + 1] + name

            # TBD: fix name_path for descendants
            self.inv.values_replace({"environment": env,
                                     "name_path": {"$regex": r"^" + re.escape(name_path + '/')}},
                                    {"name_path": {"from": name_path, "to": network_document['name_path']}})

        network_document['admin_state_up'] = network['admin_state_up']
        self.inv.set(network_document)
        return EventResult(result=True,
                           related_object=network_id,
                           display_context=network_id)
예제 #3
0
    def delete_port(self, env, port_id):
        port_doc = self.inv.get_by_id(env, port_id)
        if not port_doc:
            self.log.info("Port document not found, aborting port deleting.")
            return EventResult(result=False, retry=False)

        # if port is binding to a instance, instance document needs to be updated.
        if 'compute' in port_doc['device_owner']:
            self.log.info("update instance document to which port is binding.")
            self.update_instance(env, port_doc)

        # delete port document
        self.inv.delete('inventory', {'id': port_id})

        # delete vnic and related document
        vnic_doc = self.inv.get_by_field(env, 'vnic', 'mac_address', port_doc['mac_address'], get_single=True)
        if not vnic_doc:
            self.log.info("Vnic document not found, aborting vnic deleting.")
            return EventResult(result=False, retry=False)

        result = self.delete_handler(env, vnic_doc['id'], 'vnic')
        result.related_object = port_id
        result.display_context = port_doc.get('network_id')
        self.log.info('Finished port deleting')
        return result
예제 #4
0
    def handle(self, env, notification):
        subnet_id = notification['payload']['subnet_id']
        network_document = self.inv.get_by_field(env,
                                                 "network",
                                                 "subnet_ids",
                                                 subnet_id,
                                                 get_single=True)
        if not network_document:
            self.log.info(
                "network document not found, aborting subnet deleting")
            return EventResult(result=False, retry=False)

        # remove subnet_id from subnet_ids array
        network_document["subnet_ids"].remove(subnet_id)

        # find the subnet in network_document by subnet_id
        subnet = next(
            filter(lambda s: s['id'] == subnet_id,
                   network_document['subnets'].values()), None)

        # remove cidr from cidrs and delete subnet document.
        if subnet:
            network_document['cidrs'].remove(subnet['cidr'])
            del network_document['subnets'][subnet['name']]

        self.inv.set(network_document)

        # when network does not have any subnet, delete vservice DHCP, port and vnic documents.
        if not network_document["subnet_ids"]:
            vservice_dhcp_id = 'qdhcp-{}'.format(network_document['id'])
            self.delete_children_documents(env, vservice_dhcp_id)

        return EventResult(result=True,
                           related_object=subnet['id'],
                           display_context=network_document.get('id'))
예제 #5
0
 def handle_event(self, event_type: str, notification: dict) -> EventResult:
     self.log.error("Got notification.\nEvent_type: {}\nNotification:\n{}".
                    format(event_type, notification))
     try:
         result = self.handler.handle(event_name=event_type,
                                      notification=notification)
         return result if result else EventResult(result=False, retry=False)
     except Exception as e:
         self.inv.log.exception(e)
         return EventResult(result=False, retry=False)
예제 #6
0
    def handle(self, env, notification):
        # check for network document.
        subnet = notification['payload']['subnet']
        project_id = subnet['tenant_id']
        network_id = subnet['network_id']
        if 'id' not in subnet:
            self.log.info(
                'Subnet payload doesn\'t have id, aborting subnet add')
            return EventResult(result=False, retry=False)

        network_document = self.inv.get_by_id(env, network_id)
        if not network_document:
            self.log.info(
                'network document does not exist, aborting subnet add')
            return EventResult(result=False, retry=True)
        network_name = network_document['name']

        # build subnet document for adding network
        if subnet['cidr'] not in network_document['cidrs']:
            network_document['cidrs'].append(subnet['cidr'])
        if not network_document.get('subnets'):
            network_document['subnets'] = {}

        network_document['subnets'][subnet['name']] = subnet
        if subnet['id'] not in network_document['subnet_ids']:
            network_document['subnet_ids'].append(subnet['id'])
        self.inv.set(network_document)

        # Check DHCP enable, if true, scan network.
        if subnet['enable_dhcp'] is True:
            # update network
            if not ApiAccess.regions:
                fetcher = ApiFetchRegions()
                fetcher.set_env(env)
                fetcher.get(project_id)

            self.log.info("add new subnet.")
            host_id = notification["publisher_id"].replace("network.", "", 1)
            self.add_children_documents(env, project_id, network_id,
                                        network_name, host_id)

        # scan links and cliques
        self.log.info("scanning for links")
        FindLinksForPnics().add_links()
        FindLinksForVserviceVnics().add_links(
            search={"parent_id": "qdhcp-%s-vnics" % network_id})

        scanner = Scanner()
        scanner.set_env(env)
        scanner.scan_cliques()
        self.log.info("Finished subnet added.")
        return EventResult(result=True,
                           related_object=subnet['id'],
                           display_context=network_id)
예제 #7
0
    def handle(self, env, values):
        router = values['payload']['router']
        host_id = values["publisher_id"].replace("network.", "", 1)
        project_id = values['_context_project_id']
        router_id = encode_router_id(router['id'])
        host = self.inv.get_by_id(env, host_id)

        fetcher = CliFetchHostVservice()
        fetcher.setup(env=env, origin=self.origin)
        router_doc = fetcher.get_vservice(host_id, router_id)
        gateway_info = router['external_gateway_info']

        if gateway_info:
            network_id = gateway_info['network_id']
            self.add_router_document(env, network_id, router_doc, host)
            self.add_children_documents(env, project_id, network_id, host,
                                        router_doc)
        else:
            self.add_router_document(env, None, router_doc, host)

        # scan links and cliques
        FindLinksForVserviceVnics().add_links(search={"parent_id": router_id})
        scanner = Scanner()
        scanner.setup(env=env, origin=self.origin)
        scanner.scan_cliques()
        self.log.info("Finished router added.")

        return EventResult(result=True,
                           related_object=router_id,
                           display_context=router_id)
예제 #8
0
    def test_handle_interface_add(self, subnet_add_class_mock,
                                  port_add_class_mock, fetcher_class_mock,
                                  scanner_class_mock, find_links_class_mock):
        self.values = EVENT_PAYLOAD_INTERFACE_ADD

        self.inv.get_by_field.return_value = NETWORK_DOC
        self.inv.get_by_id.side_effect = self.get_by_id

        subnet_add_mock = subnet_add_class_mock.return_value
        subnet_add_mock.add_port_document.return_value = PORT_DOC

        port_add_mock = port_add_class_mock.return_value
        port_add_mock.add_vnic_document = \
            Mock(return_value=EventResult(result=True))

        fetcher_mock = fetcher_class_mock.return_value
        fetcher_mock.get_vservice.return_value = ROUTER_DOCUMENT
        fetcher_mock.handle_service.return_value = VNIC_DOCS

        scanner_mock = scanner_class_mock.return_value
        find_links_mock = find_links_class_mock.return_value

        with patch("discover.fetcher.FullLogger"):
            with TestRegions(EVENT_PAYLOAD_REGION):
                res = EventInterfaceAdd().handle(self.env, self.values)

        self.assertTrue(res.result)
        self.inv.set.assert_called_with(ROUTER_DOCUMENT)
        self.assertTrue(port_add_mock.add_vnic_document.called)
        self.assertTrue(scanner_mock.scan_cliques.called)
        self.assertTrue(find_links_mock.add_links.called)
예제 #9
0
    def delete_handler(self, env, object_id, object_type) -> EventResult:
        item = self.inv.get_by_id(env, object_id)
        if not item:
            self.log.info(
                '{0} document is not found, aborting {0} delete'.format(
                    object_type))
            return EventResult(result=False, retry=False)

        db_id = ObjectId(item['_id'])
        id_path = item['id_path'] + '/'

        # remove related clique
        clique_finder = CliqueFinder()
        self.inv.delete('cliques', {'focal_point': db_id})

        # keep related links to do rebuild of cliques using them
        matched_links_source = clique_finder.find_links_by_source(db_id)
        matched_links_target = clique_finder.find_links_by_target(db_id)

        links_using_object = []
        links_using_object.extend([l['_id'] for l in matched_links_source])
        links_using_object.extend([l['_id'] for l in matched_links_target])

        # find cliques using these links
        if links_using_object:
            matched_cliques = clique_finder.find_cliques_by_link(
                links_using_object)
            # find cliques using these links and rebuild them
            for clique in matched_cliques:
                clique_finder.rebuild_clique(clique)

        # remove all related links
        self.inv.delete('links', {'source': db_id})
        self.inv.delete('links', {'target': db_id})

        # remove object itself
        self.inv.delete('inventory', {'_id': db_id})

        # remove children
        regexp = re.compile('^' + id_path)
        self.inv.delete('inventory', {'id_path': {'$regex': regexp}})
        return EventResult(result=True,
                           related_object=object_id,
                           display_context=object_id)
예제 #10
0
    def handle(self, env, values):
        payload = values['payload']

        if 'publisher_id' not in values:
            self.log.error(
                "Publisher_id is not in event values. Aborting router delete")
            return EventResult(result=False, retry=False)

        if 'router_id' in payload:
            router_id = payload['router_id']
        elif 'id' in payload:
            router_id = payload['id']
        else:
            router_id = payload.get('router', {}).get('id')

        if not router_id:
            self.log.error(
                "Router id is not in payload. Aborting router delete")
            return EventResult(result=False, retry=False)

        router_full_id = encode_router_id(router_id)
        return self.delete_handler(env, router_full_id, "vservice")
예제 #11
0
    def delete_children_documents(self, env, vservice_id):
        vnic_parent_id = vservice_id + '-vnics'
        vnic = self.inv.get_by_field(env,
                                     'vnic',
                                     'parent_id',
                                     vnic_parent_id,
                                     get_single=True)
        if not vnic:
            self.log.info("Vnic document not found.")
            return EventResult(result=False, retry=False)

        # delete port and vnic together by mac address.
        self.inv.delete('inventory', {"mac_address": vnic.get("mac_address")})
        return self.delete_handler(env, vservice_id, 'vservice')
예제 #12
0
    def handle(self, env, values):
        # find the host, to serve as parent
        payload = values['payload']
        instance_id = payload['instance_id']
        state = payload['state']
        old_state = payload['old_state']

        if state == 'building':
            return EventResult(result=False, retry=False)

        if state == 'active' and old_state == 'building':
            return EventInstanceAdd().handle(env, values)

        if state == 'deleted' and old_state == 'active':
            return EventInstanceDelete().handle(env, values)

        name = payload['display_name']
        instance = self.inv.get_by_id(env, instance_id)
        if not instance:
            self.log.info('instance document not found, aborting instance update')
            return EventResult(result=False, retry=True)

        instance['name'] = name
        instance['object_name'] = name
        name_path = instance['name_path']
        instance['name_path'] = name_path[:name_path.rindex('/') + 1] + name

        # TBD: fix name_path for descendants
        if name_path != instance['name_path']:
            self.inv.values_replace({
                "environment": env,
                "name_path": {"$regex": r"^" + re.escape(name_path + '/')}},
                {"name_path": {"from": name_path, "to": instance['name_path']}})
        self.inv.set(instance)
        return EventResult(result=True,
                           related_object=instance_id,
                           display_context=instance_id)
예제 #13
0
    def handle(self, env, notification):
        network = notification['payload']['network']
        network_id = network['id']
        network_document = self.inv.get_by_id(env, network_id)
        if network_document:
            self.log.info('network already existed, aborting network add')
            return EventResult(result=False, retry=False)

        # build network document for adding network
        project_name = notification['_context_project_name']
        project_id = notification['_context_project_id']
        parent_id = project_id + '-networks'
        network_name = network['name']

        network['environment'] = env
        network['type'] = 'network'
        network['id_path'] = "/%s/%s-projects/%s/%s/%s" \
                             % (env, env, project_id, parent_id, network_id)
        network['cidrs'] = []
        network['subnet_ids'] = []
        network['last_scanned'] = notification['timestamp']
        network['name_path'] = "/%s/Projects/%s/Networks/%s" \
                               % (env, project_name, network_name)
        network['network'] = network_id
        network['object_name'] = network_name
        network['parent_id'] = parent_id
        network['parent_text'] = "Networks"
        network['parent_type'] = "networks_folder"
        network['project'] = project_name
        network["show_in_tree"] = True
        network['subnets'] = {}

        self.inv.set(network)
        return EventResult(result=True,
                           related_object=network_id,
                           display_context=network_id)
예제 #14
0
    def handle(self, env, notification):
        # check port document.
        port = notification['payload']['port']
        port_id = port['id']
        port_document = self.inv.get_by_id(env, port_id)
        if not port_document:
            self.log.info('port document does not exist, aborting port update')
            return EventResult(result=False, retry=True)

        # build port document
        port_document['name'] = port['name']
        port_document['admin_state_up'] = port['admin_state_up']
        if port_document['admin_state_up']:
            port_document['status'] = 'ACTIVE'
        else:
            port_document['status'] = 'DOWN'

        port_document['binding:vnic_type'] = port['binding:vnic_type']

        # update port document.
        self.inv.set(port_document)
        return EventResult(result=True,
                           related_object=port_id,
                           display_context=port_document.get('network_id'))
예제 #15
0
    def test_handle_interface_delete(self, port_delete_class_mock):
        self.values = EVENT_PAYLOAD_INTERFACE_DELETE
        self.payload = self.values['payload']
        self.interface = self.payload['router_interface']
        self.port_id = self.interface['port_id']
        self.router_id = encode_router_id(self.interface['id'])

        port_delete_mock = port_delete_class_mock.return_value
        port_delete_mock.delete_port.return_value = EventResult(result=True)

        self.inv.get_by_id.side_effect = self.get_by_id

        res = EventInterfaceDelete().handle(self.env, self.values)

        self.assertTrue(res.result)
        self.assertTrue(port_delete_mock.delete_port.called)
        self.inv.set.assert_called_with(ROUTER_DOCUMENT)
예제 #16
0
class TestSubnetDelete(TestEvent):
    def get_by_field(self,
                     environment,
                     item_type,
                     field_name,
                     field_value,
                     get_single=False):
        if item_type == "network":
            return NETWORK_DOC
        elif item_type == "vnic":
            return VNIC_DOC
        else:
            return None

    @patch.object(EventDeleteBase,
                  "delete_handler",
                  return_value=EventResult(result=True))
    def test_handle_subnet_delete(self, delete_handler_mock):
        self.values = EVENT_PAYLOAD_SUBNET_DELETE
        self.subnet_id = self.values['payload']['subnet_id']
        self.network_doc = NETWORK_DOC
        self.network_id = self.network_doc['id']
        self.vnic_id = VNIC_DOC['id']
        self.vnic_folder_id = 'qdhcp-{}'.format(self.network_id)

        self.inv.get_by_field.side_effect = self.get_by_field

        res = EventSubnetDelete().handle(self.env, self.values)

        self.assertTrue(res.result)
        delete_handler_mock.assert_called_with(self.env, self.vnic_folder_id,
                                               "vservice")

        updated_network = [
            call[0][0] for call in self.inv.set.call_args_list
            if call[0][0]['type'] == 'network'
        ]
        self.assertTrue(updated_network)
        self.assertTrue(
            self.subnet_id not in updated_network[0].get('subnet_ids'))
        self.assertTrue(self.inv.delete.called)
예제 #17
0
    def handle(self, env, values):
        interface = values['payload']['router_interface']
        port_id = interface['port_id']
        router_id = encode_router_id(interface['id'])

        # update router document
        port_doc = self.inv.get_by_id(env, port_id)
        if not port_doc:
            self.log.info("Interface deleting handler: port document not found.")
            return EventResult(result=False, retry=False)
        network_id = port_doc['network_id']

        router_doc = self.inv.get_by_id(env, router_id)
        if router_doc and network_id in router_doc.get('network', []):
            router_doc['network'].remove(network_id)
            self.inv.set(router_doc)

        # delete port document
        result = EventPortDelete().delete_port(env, port_id)
        result.related_object = interface['id']
        result.display_context = network_id
        return result
예제 #18
0
    def handle(self, env, values):
        payload = values['payload']
        router = payload['router']

        project_id = values['_context_project_id']
        host_id = values["publisher_id"].replace("network.", "", 1)
        router_id = payload['id'] if 'id' in payload else router['id']

        router_full_id = encode_router_id(router_id)
        router_doc = self.inv.get_by_id(env, router_full_id)
        if not router_doc:
            self.log.info(
                "Router document not found, aborting router updating")
            return EventResult(result=False, retry=True)

        router_doc['admin_state_up'] = router['admin_state_up']
        router_doc['name'] = router['name']
        gateway_info = router.get('external_gateway_info')
        if gateway_info is None:
            # when delete gateway, need to delete the port relate document.
            port_doc = {}
            if router_doc.get('gw_port_id'):
                port_doc = self.inv.get_by_id(env, router_doc['gw_port_id'])
                EventPortDelete().delete_port(env, router_doc['gw_port_id'])

            if router_doc.get('network'):
                if port_doc:
                    router_doc['network'].remove(port_doc['network_id'])
                router_doc['gw_port_id'] = None

                # remove related links
                self.inv.delete('links', {'source_id': router_full_id})
        else:
            if 'network' in router_doc:
                if gateway_info['network_id'] not in router_doc['network']:
                    router_doc['network'].append(gateway_info['network_id'])
            else:
                router_doc['network'] = [gateway_info['network_id']]
            # update static route
            router_doc['routes'] = router['routes']

            # add gw_port_id info and port document.
            fetcher = CliFetchHostVservice()
            fetcher.setup(env=env, origin=self.origin)
            router_vservice = fetcher.get_vservice(host_id, router_full_id)
            if router_vservice.get('gw_port_id'):
                router_doc['gw_port_id'] = router_vservice['gw_port_id']

            host = self.inv.get_by_id(env, host_id)
            EventRouterAdd().add_children_documents(env, project_id,
                                                    gateway_info['network_id'],
                                                    host, router_doc)

            # rescan the vnic links.
            FindLinksForVserviceVnics().add_links(
                search={'parent_id': router_full_id + '-vnics'})
        self.inv.set(router_doc)

        # update the cliques.
        scanner = Scanner()
        scanner.setup(env=env, origin=self.origin)
        scanner.scan_cliques()
        self.log.info("Finished router update.")
        return EventResult(result=True,
                           related_object=router_full_id,
                           display_context=router_full_id)
예제 #19
0
    def handle(self, env, values):
        interface = values['payload']['router_interface']
        project_id = values['_context_project_id']
        project = values['_context_project_name']
        host_id = values["publisher_id"].replace("network.", "", 1)
        port_id = interface['port_id']
        subnet_id = interface['subnet_id']
        router_id = encode_router_id(interface['id'])

        network_document = self.inv.get_by_field(env,
                                                 "network",
                                                 "subnet_ids",
                                                 subnet_id,
                                                 get_single=True)
        if not network_document:
            self.log.info(
                "network document not found, aborting interface adding")
            return EventResult(result=False, retry=True)
        network_name = network_document['name']
        network_id = network_document['id']

        # add router-interface port document.
        if not ApiAccess.regions:
            fetcher = ApiFetchRegions()
            fetcher.setup(env=env, origin=self.origin)
            fetcher.get(project_id)
        port_doc = EventSubnetAdd().add_port_document(
            env, port_id, network_name=network_name)

        mac_address = port_doc['mac_address'] if port_doc else None

        # add vnic document
        host = self.inv.get_by_id(env, host_id)
        router_doc = self.inv.get_by_id(env, router_id)

        add_vnic_document = partial(EventPortAdd().add_vnic_document,
                                    env=env,
                                    host=host,
                                    object_id=interface['id'],
                                    object_type='router',
                                    network_name=network_name,
                                    router_name=router_doc['name'],
                                    mac_address=mac_address)

        ret = add_vnic_document()
        if ret is False:
            # try it again to fetch vnic document, vnic will be created a little bit late before CLI fetch.
            time.sleep(self.delay)
            self.log.info(
                "Wait {} seconds, and then fetch vnic document again.".format(
                    self.delay))
            add_vnic_document()

        # update the router document: gw_port_id, network.
        self.update_router(env, project, network_id, network_name, router_doc,
                           host_id)

        # update vservice-vnic, vnic-network,
        FindLinksForVserviceVnics().add_links(search={"parent_id": router_id})
        scanner = Scanner()
        scanner.setup(env=env, origin=self.origin)

        scanner.scan_cliques()
        self.log.info("Finished router-interface added.")

        return EventResult(result=True,
                           related_object=interface['id'],
                           display_context=network_id)
예제 #20
0
    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.setup(env=env, origin=self.origin)
            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.setup(env=env, origin=self.origin)
            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.setup(env=env, origin=self.origin)
            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)
예제 #21
0
    def handle(self, env, notification):
        # check for network document.
        subnet = notification['payload']['subnet']
        project_id = notification['_context_project_id']
        project = notification['_context_project_name']
        host_id = notification['publisher_id'].replace('network.', '', 1)
        subnet_id = subnet['id']
        network_id = subnet['network_id']
        network_document = self.inv.get_by_id(env, network_id)
        if not network_document:
            self.log.info(
                'network document does not exist, aborting subnet update')
            return EventResult(result=False, retry=True)

        # update network document.
        subnets = network_document['subnets']
        key = next(filter(lambda k: subnets[k]['id'] == subnet_id, subnets),
                   None)

        if key:
            if subnet['enable_dhcp'] and subnets[key]['enable_dhcp'] is False:
                # scan DHCP namespace to add related document.
                # add dhcp vservice document.
                host = self.inv.get_by_id(env, host_id)
                port_handler = EventPortAdd()
                port_handler.add_dhcp_document(env, host, network_id,
                                               network_document['name'])

                # make sure that self.regions is not empty.
                if not ApiAccess.regions:
                    fetcher = ApiFetchRegions()
                    fetcher.setup(env=env, origin=self.origin)
                    fetcher.get(project_id)

                self.log.info("add port binding to DHCP server.")
                port_id = DbFetchPort(). \
                    get_id_by_field(network_id,
                                    """device_owner LIKE "%dhcp" """)
                port = EventSubnetAdd(). \
                    add_port_document(env, port_id,
                                      network_name=network_document['name'],
                                      project_name=project)
                if port:
                    port_handler. \
                        add_vnic_document(env, host, network_id,
                                          network_name=network_document['name'],
                                          mac_address=port['mac_address'])
                    # add link for vservice - vnic
                    FindLinksForVserviceVnics().add_links(
                        search={"id": "qdhcp-%s" % network_id})
                    scanner = Scanner()
                    scanner.setup(env=env, origin=self.origin)
                    scanner.scan_cliques()
                    FindLinksForVserviceVnics(). \
                        add_links(search={"id": "qdhcp-%s" % network_id})
                    scanner = Scanner()
                    scanner.setup(env=env, origin=self.origin)
                    scanner.scan_cliques()

            if subnet['enable_dhcp'] is False and subnets[key]['enable_dhcp']:
                # delete existed related DHCP documents.
                self.inv.delete("inventory",
                                {'id': "qdhcp-%s" % subnet['network_id']})
                self.log.info("delete DHCP document: qdhcp-%s" %
                              subnet['network_id'])

                port = self.inv.find_items(
                    {
                        'network_id': subnet['network_id'],
                        'device_owner': 'network:dhcp'
                    },
                    get_single=True)
                if 'id' in port:
                    EventPortDelete().delete_port(env, port['id'])
                    self.log.info("delete port binding to DHCP server.")

            if subnet['name'] == subnets[key]['name']:
                subnets[key] = subnet
            else:
                del subnets[key]
                subnets[subnet['name']] = subnet

            self.inv.set(network_document)
            return EventResult(result=True,
                               related_object=subnet['id'],
                               display_context=network_id)
        else:
            self.log.info('subnet not in network, aborting subnet update')
            return EventResult(result=False, retry=False)