aboutsummaryrefslogtreecommitdiffstats
path: root/app/discover/events/event_interface_add.py
blob: f0ba5690eec67c7f28dfef66f1f83242b198fee6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
###############################################################################
# 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 time
from functools import partial

from discover.events.event_base import EventBase, EventResult
from discover.events.event_port_add import EventPortAdd
from discover.events.event_subnet_add import EventSubnetAdd
from discover.fetchers.api.api_access import ApiAccess
from discover.fetchers.api.api_fetch_regions import ApiFetchRegions
from discover.fetchers.cli.cli_fetch_host_vservice import CliFetchHostVservice
from discover.link_finders.find_links_for_vservice_vnics import \
    FindLinksForVserviceVnics
from discover.scanner import Scanner
from utils.util import decode_router_id, encode_router_id


class EventInterfaceAdd(EventBase):

    def __init__(self):
        super().__init__()
        self.delay = 2

    def add_gateway_port(self, env, project, network_name, router_doc, host_id):
        fetcher = CliFetchHostVservice()
        fetcher.setup(env=env, origin=self.origin)
        router_id = router_doc['id']
        router = fetcher.get_vservice(host_id, router_id)
        device_id = decode_router_id(router_id)
        router_doc['gw_port_id'] = router['gw_port_id']

        # add gateway port documents.
        port_doc = EventSubnetAdd().add_port_document(env,
                                                      router_doc['gw_port_id'],
                                                      project_name=project)

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

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

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

        ret = add_vnic_document()
        if not ret:
            time.sleep(self.delay)
            self.log.info("Wait %s second, and then fetch vnic document again." % self.delay)
            add_vnic_document()

    def update_router(self, env, project, network_id, network_name, router_doc, host_id):
        if router_doc:
            if 'network' in router_doc:
                if network_id not in router_doc['network']:
                    router_doc['network'].append(network_id)
            else:
                router_doc['network'] = [network_id]

            # if gw_port_id is None, add gateway port first.
            if not router_doc.get('gw_port_id'):
                self.add_gateway_port(env, project, network_name, router_doc, host_id)
            else:
                # check the gateway port document, add it if document does not exist.
                port = self.inv.get_by_id(env, router_doc['gw_port_id'])
                if not port:
                    self.add_gateway_port(env, project, network_name, router_doc, host_id)
            self.inv.set(router_doc)
        else:
            self.log.info("router document not found, aborting interface adding")

    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)