Passed
Push — master ( 646846...4fca5c )
by Humberto
02:21 queued 11s
created

build.main.Main.get_interface_metadata()   A

Complexity

Conditions 3

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 7.608

Importance

Changes 0
Metric Value
cc 3
eloc 13
nop 2
dl 0
loc 16
ccs 2
cts 10
cp 0.2
crap 7.608
rs 9.75
c 0
b 0
f 0
1
"""Main module of kytos/topology Kytos Network Application.
2
3
Manage the network topology
4
"""
5 1
import time
6
7 1
from flask import jsonify, request
8 1
9 1
from kytos.core import KytosEvent, KytosNApp, log, rest
10 1
from kytos.core.helpers import listen_to
11 1
from kytos.core.interface import Interface
12
from kytos.core.link import Link
13 1
from kytos.core.switch import Switch
14
from napps.kytos.topology import settings
15
from napps.kytos.topology.models import Topology
16 1
from napps.kytos.topology.storehouse import StoreHouse
17
18
DEFAULT_LINK_UP_TIMER = 10
19
20
21
class Main(KytosNApp):  # pylint: disable=too-many-public-methods
22 1
    """Main class of kytos/topology NApp.
23
24 1
    This class is the entry point for this napp.
25 1
    """
26
27 1
    def setup(self):
28 1
        """Initialize the NApp's links list."""
29 1
        self.links = {}
30
        self.store_items = {}
31 1
        self.link_up_timer = getattr(settings, 'LINK_UP_TIMER',
32
                                     DEFAULT_LINK_UP_TIMER)
33
34 1
        self.verify_storehouse('switches')
35
        self.verify_storehouse('interfaces')
36
        self.verify_storehouse('links')
37
38 1
        self.storehouse = StoreHouse(self.controller)
39
40
    def execute(self):
41
        """Do nothing."""
42
43
    def shutdown(self):
44
        """Do nothing."""
45
        log.info('NApp kytos/topology shutting down.')
46
47
    def _get_link_or_create(self, endpoint_a, endpoint_b):
48 1
        new_link = Link(endpoint_a, endpoint_b)
49
50
        for link in self.links.values():
51
            if new_link == link:
52
                return link
53 1
54
        self.links[new_link.id] = new_link
55
        return new_link
56
57
    def _get_switches_dict(self):
58 1
        """Return a dictionary with the known switches."""
59
        return {'switches': {s.id: s.as_dict() for s in
60
                             self.controller.switches.values()}}
61
62
    def _get_links_dict(self):
63 1
        """Return a dictionary with the known links."""
64
        return {'links': {l.id: l.as_dict() for l in
65 1
                          self.links.values()}}
66
67 1
    def _get_topology_dict(self):
68
        """Return a dictionary with the known topology."""
69
        return {'topology': {**self._get_switches_dict(),
70
                             **self._get_links_dict()}}
71
72
    def _get_topology(self):
73
        """Return an object representing the topology."""
74 1
        return Topology(self.controller.switches, self.links)
75
76
    def _get_link_from_interface(self, interface):
77
        """Return the link of the interface, or None if it does not exist."""
78
        for link in self.links.values():
79
            if interface in (link.endpoint_a, link.endpoint_b):
80
                return link
81
        return None
82
83 1
    def _restore_status(self, switches_status, interfaces_status):
84
        """Restore the network administrative status saved in StoreHouse."""
85
        # restore Switches
86
        for switch_id, state in switches_status.items():
87
            try:
88 1
                if state:
89
                    self.controller.switches[switch_id].enable()
90
                else:
91
                    self.controller.switches[switch_id].disable()
92
            except KeyError:
93
                error = ('Error while restoring switches status. The '
94
                         f'{switch_id} does not exist.')
95
                raise KeyError(error)
96
        # restore interfaces
97 1
        for interface_id, state in interfaces_status.items():
98
            switch_id = ":".join(interface_id.split(":")[:-1])
99
            interface_number = int(interface_id.split(":")[-1])
100
            try:
101
                switch = self.controller.switches[switch_id]
102
                if state:
103
                    switch.interfaces[interface_number].enable()
104
                else:
105
                    switch.interfaces[interface_number].disable()
106 1
            except KeyError:
107
                error = ('Error while restoring interface status. The '
108
                         f'interface {interface_id} does not exist.')
109
                raise KeyError(error)
110
111
        log.info('Network status restored.')
112
113
    def _load_network_status(self):
114
        """Load network status saved in storehouse."""
115 1
        switches_status = {}
116
        interfaces_status = {}
117
        status = self.storehouse.get_data()
118
        if status:
119
            switches = status.get(0)['switches']
120
            for switch, switch_attributes in switches.items():
121
                # get status the switches
122
                switches_status[switch] = switch_attributes.get('enabled')
123
                interfaces = switch_attributes['interfaces']
124
                # get status the interfaces
125
                for interface, interface_attributes in interfaces.items():
126
                    enabled_value = interface_attributes.get('enabled')
127
                    interfaces_status[interface] = enabled_value
128 1
129
        else:
130
            error = 'There is no status saved to restore.'
131
            log.info(error)
132
            raise FileNotFoundError(error)
133
134
        return switches_status, interfaces_status
135
136
    @rest('v3/')
137
    def get_topology(self):
138
        """Return the latest known topology.
139
140
        This topology is updated when there are network events.
141 1
        """
142
        return jsonify(self._get_topology_dict())
143
144
    @rest('v3/restore')
145
    def restore_network_status(self):
146
        """Restore the network administrative status saved in StoreHouse."""
147
        try:
148
            switches_status, interfaces_status = self._load_network_status()
149
            self._restore_status(switches_status, interfaces_status)
150
        except (KeyError, FileNotFoundError) as exc:
151
            return jsonify(f'{str(exc)}'), 404
152 1
153
        return jsonify('Administrative status restored.'), 200
154
155
    # Switch related methods
156
    @rest('v3/switches')
157
    def get_switches(self):
158
        """Return a json with all the switches in the topology."""
159
        return jsonify(self._get_switches_dict())
160
161
    @rest('v3/switches/<dpid>/enable', methods=['POST'])
162
    def enable_switch(self, dpid):
163
        """Administratively enable a switch in the topology."""
164
        try:
165
            self.controller.switches[dpid].enable()
166
            self.save_status_on_storehouse()
167
            return jsonify("Operation successful"), 201
168
        except KeyError:
169
            return jsonify("Switch not found"), 404
170 1
171
    @rest('v3/switches/<dpid>/disable', methods=['POST'])
172
    def disable_switch(self, dpid):
173
        """Administratively disable a switch in the topology."""
174
        try:
175
            self.controller.switches[dpid].disable()
176
            self.save_status_on_storehouse()
177
            return jsonify("Operation successful"), 201
178
        except KeyError:
179
            return jsonify("Switch not found"), 404
180
181
    @rest('v3/switches/<dpid>/metadata')
182
    def get_switch_metadata(self, dpid):
183
        """Get metadata from a switch."""
184
        try:
185
            return jsonify({"metadata":
186
                            self.controller.switches[dpid].metadata}), 200
187
        except KeyError:
188 1
            return jsonify("Switch not found"), 404
189
190
    @rest('v3/switches/<dpid>/metadata', methods=['POST'])
191
    def add_switch_metadata(self, dpid):
192
        """Add metadata to a switch."""
193
        metadata = request.get_json()
194
        try:
195
            switch = self.controller.switches[dpid]
196
        except KeyError:
197
            return jsonify("Switch not found"), 404
198
199
        switch.extend_metadata(metadata)
200
        self.notify_metadata_changes(switch, 'added')
201
        return jsonify("Operation successful"), 201
202
203
    @rest('v3/switches/<dpid>/metadata/<key>', methods=['DELETE'])
204
    def delete_switch_metadata(self, dpid, key):
205 1
        """Delete metadata from a switch."""
206
        try:
207
            switch = self.controller.switches[dpid]
208
        except KeyError:
209
            return jsonify("Switch not found"), 404
210
211
        switch.remove_metadata(key)
212
        self.notify_metadata_changes(switch, 'removed')
213
        return jsonify("Operation successful"), 200
214
215
    # Interface related methods
216
    @rest('v3/interfaces')
217
    def get_interfaces(self):
218
        """Return a json with all the interfaces in the topology."""
219
        interfaces = {}
220
        switches = self._get_switches_dict()
221
        for switch in switches['switches'].values():
222
            for interface_id, interface in switch['interfaces'].items():
223
                interfaces[interface_id] = interface
224
225
        return jsonify({'interfaces': interfaces})
226 1
227 View Code Duplication
    @rest('v3/interfaces/switch/<dpid>/enable', methods=['POST'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
228
    @rest('v3/interfaces/<interface_enable_id>/enable', methods=['POST'])
229
    def enable_interface(self, interface_enable_id=None, dpid=None):
230
        """Administratively enable interfaces in the topology."""
231
        error_list = []  # List of interfaces that were not activated.
232
        msg_error = "Some interfaces couldn't be found and activated: "
233
        if dpid is None:
234
            dpid = ":".join(interface_enable_id.split(":")[:-1])
235
        try:
236
            switch = self.controller.switches[dpid]
237
        except KeyError as exc:
238
            return jsonify(f"Switch not found: {exc}"), 404
239
240
        if interface_enable_id:
241
            interface_number = int(interface_enable_id.split(":")[-1])
242
243
            try:
244
                switch.interfaces[interface_number].enable()
245
            except KeyError as exc:
246
                error_list.append(f"Switch {dpid} Interface {exc}")
247
        else:
248
            for interface in switch.interfaces.values():
249 1
                interface.enable()
250
        if not error_list:
251
            self.save_status_on_storehouse()
252
            return jsonify("Operation successful"), 200
253
        return jsonify({msg_error:
254
                        error_list}), 409
255
256 View Code Duplication
    @rest('v3/interfaces/switch/<dpid>/disable', methods=['POST'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
257 1
    @rest('v3/interfaces/<interface_disable_id>/disable', methods=['POST'])
258
    def disable_interface(self, interface_disable_id=None, dpid=None):
259
        """Administratively disable interfaces in the topology."""
260
        error_list = []  # List of interfaces that were not deactivated.
261
        msg_error = "Some interfaces couldn't be found and deactivated: "
262
        if dpid is None:
263
            dpid = ":".join(interface_disable_id.split(":")[:-1])
264
        try:
265
            switch = self.controller.switches[dpid]
266
        except KeyError as exc:
267 1
            return jsonify(f"Switch not found: {exc}"), 404
268
269
        if interface_disable_id:
270
            interface_number = int(interface_disable_id.split(":")[-1])
271
272
            try:
273
                switch.interfaces[interface_number].disable()
274
            except KeyError as exc:
275
                error_list.append(f"Switch {dpid} Interface {exc}")
276
        else:
277 1
            for interface in switch.interfaces.values():
278
                interface.disable()
279
        if not error_list:
280
            self.save_status_on_storehouse()
281
            return jsonify("Operation successful"), 200
282
        return jsonify({msg_error:
283
                        error_list}), 409
284
285 1
    @rest('v3/interfaces/<interface_id>/metadata')
286
    def get_interface_metadata(self, interface_id):
287
        """Get metadata from an interface."""
288
        switch_id = ":".join(interface_id.split(":")[:-1])
289
        interface_number = int(interface_id.split(":")[-1])
290
        try:
291
            switch = self.controller.switches[switch_id]
292
        except KeyError:
293
            return jsonify("Switch not found"), 404
294
295
        try:
296
            interface = switch.interfaces[interface_number]
297
        except KeyError:
298 1
            return jsonify("Interface not found"), 404
299
300
        return jsonify({"metadata": interface.metadata}), 200
301
302
    @rest('v3/interfaces/<interface_id>/metadata', methods=['POST'])
303
    def add_interface_metadata(self, interface_id):
304
        """Add metadata to an interface."""
305
        metadata = request.get_json()
306
307
        switch_id = ":".join(interface_id.split(":")[:-1])
308
        interface_number = int(interface_id.split(":")[-1])
309
        try:
310
            switch = self.controller.switches[switch_id]
311
        except KeyError:
312 1
            return jsonify("Switch not found"), 404
313
314
        try:
315
            interface = switch.interfaces[interface_number]
316
        except KeyError:
317
            return jsonify("Interface not found"), 404
318
319 1
        interface.extend_metadata(metadata)
320 1
        self.notify_metadata_changes(interface, 'added')
321 1
        return jsonify("Operation successful"), 201
322 1
323 1
    @rest('v3/interfaces/<interface_id>/metadata/<key>', methods=['DELETE'])
324
    def delete_interface_metadata(self, interface_id, key):
325 1
        """Delete metadata from an interface."""
326
        switch_id = ":".join(interface_id.split(":")[:-1])
327
        interface_number = int(interface_id.split(":")[-1])
328
329
        try:
330
            switch = self.controller.switches[switch_id]
331
        except KeyError:
332 1
            return jsonify("Switch not found"), 404
333 1
334 1
        try:
335 1
            interface = switch.interfaces[interface_number]
336 1
        except KeyError:
337
            return jsonify("Interface not found"), 404
338 1
339
        if interface.remove_metadata(key) is False:
340
            return jsonify("Metadata not found"), 404
341
342
        self.notify_metadata_changes(interface, 'removed')
343 1
        return jsonify("Operation successful"), 200
344 1
345 1
    # Link related methods
346 1
    @rest('v3/links')
347
    def get_links(self):
348 1
        """Return a json with all the links in the topology.
349
350
        Links are connections between interfaces.
351 1
        """
352
        return jsonify(self._get_links_dict()), 200
353 1
354
    @rest('v3/links/<link_id>/enable', methods=['POST'])
355
    def enable_link(self, link_id):
356
        """Administratively enable a link in the topology."""
357
        try:
358 1
            self.links[link_id].enable()
359 1
        except KeyError:
360 1
            return jsonify("Link not found"), 404
361 1
362
        return jsonify("Operation successful"), 201
363 1
364
    @rest('v3/links/<link_id>/disable', methods=['POST'])
365
    def disable_link(self, link_id):
366 1
        """Administratively disable a link in the topology."""
367
        try:
368 1
            self.links[link_id].disable()
369
        except KeyError:
370
            return jsonify("Link not found"), 404
371
372
        return jsonify("Operation successful"), 201
373
374 1
    @rest('v3/links/<link_id>/metadata')
375 1
    def get_link_metadata(self, link_id):
376 1
        """Get metadata from a link."""
377 1
        try:
378 1
            return jsonify({"metadata": self.links[link_id].metadata}), 200
379 1
        except KeyError:
380 1
            return jsonify("Link not found"), 404
381
382 1
    @rest('v3/links/<link_id>/metadata', methods=['POST'])
383
    def add_link_metadata(self, link_id):
384
        """Add metadata to a link."""
385
        metadata = request.get_json()
386
        try:
387
            link = self.links[link_id]
388 1
        except KeyError:
389 1
            return jsonify("Link not found"), 404
390 1
391 1
        link.extend_metadata(metadata)
392 1
        self.notify_metadata_changes(link, 'added')
393 1
        return jsonify("Operation successful"), 201
394
395 1
    @rest('v3/links/<link_id>/metadata/<key>', methods=['DELETE'])
396
    def delete_link_metadata(self, link_id, key):
397
        """Delete metadata from a link."""
398 1
        try:
399 1
            link = self.links[link_id]
400
        except KeyError:
401 1
            return jsonify("Link not found"), 404
402 1
403 1
        if link.remove_metadata(key) is False:
404
            return jsonify("Metadata not found"), 404
405 1
406 1
        self.notify_metadata_changes(link, 'removed')
407
        return jsonify("Operation successful"), 200
408 1
409
    @listen_to('.*.switch.(new|reconnected)')
410
    def handle_new_switch(self, event):
411
        """Create a new Device on the Topology.
412
413
        Handle the event of a new created switch and update the topology with
414
        this new device.
415
        """
416
        switch = event.content['switch']
417
        switch.activate()
418
        log.debug('Switch %s added to the Topology.', switch.id)
419
        self.notify_topology_update()
420
        self.update_instance_metadata(switch)
421
422
    @listen_to('.*.connection.lost')
423
    def handle_connection_lost(self, event):
424
        """Remove a Device from the topology.
425
426
        Remove the disconnected Device and every link that has one of its
427 1
        interfaces.
428
        """
429 1
        switch = event.content['source'].switch
430 1
        if switch:
431
            switch.deactivate()
432 1
            log.debug('Switch %s removed from the Topology.', switch.id)
433
            self.notify_topology_update()
434 1
435
    def handle_interface_up(self, event):
436 1
        """Update the topology based on a Port Modify event.
437 1
438 1
        The event notifies that an interface was changed to 'up'.
439
        """
440
        interface = event.content['interface']
441 1
        interface.activate()
442 1
        self.notify_topology_update()
443
        self.update_instance_metadata(interface)
444 1
445
    @listen_to('.*.switch.interface.created')
446 1
    def handle_interface_created(self, event):
447 1
        """Update the topology based on a Port Create event."""
448 1
        self.handle_interface_up(event)
449
450
    def handle_interface_down(self, event):
451
        """Update the topology based on a Port Modify event.
452
453
        The event notifies that an interface was changed to 'down'.
454
        """
455
        interface = event.content['interface']
456 1
        interface.deactivate()
457 1
        self.handle_interface_link_down(event)
458
        self.notify_topology_update()
459 1
460 1
    @listen_to('.*.switch.interface.deleted')
461
    def handle_interface_deleted(self, event):
462 1
        """Update the topology based on a Port Delete event."""
463
        self.handle_interface_down(event)
464
465 1
    @listen_to('.*.switch.interface.link_up')
466 1
    def handle_interface_link_up(self, event):
467 1
        """Update the topology based on a Port Modify event.
468
469 1
        The event notifies that an interface's link was changed to 'up'.
470
        """
471
        interface = event.content['interface']
472
        link = self._get_link_from_interface(interface)
473
        if not link:
474
            return
475
        if link.endpoint_a == interface:
476
            other_interface = link.endpoint_b
477
        else:
478
            other_interface = link.endpoint_a
479
        interface.activate()
480
        if other_interface.is_active() is False:
481
            return
482
        if link.is_active() is False:
483
            link.update_metadata('last_status_change', time.time())
484
            link.activate()
485
486
            # As each run of this method uses a different thread,
487
            # there is no risk this sleep will lock the NApp.
488
            time.sleep(self.link_up_timer)
489
490
            last_status_change = link.get_metadata('last_status_change')
491
            now = time.time()
492
            if link.is_active() and \
493
                    now - last_status_change >= self.link_up_timer:
494
                self.notify_topology_update()
495 1
                self.update_instance_metadata(link)
496
                self.notify_link_status_change(link)
497
498
    @listen_to('.*.switch.interface.link_down')
499
    def handle_interface_link_down(self, event):
500
        """Update the topology based on a Port Modify event.
501
502
        The event notifies that an interface's link was changed to 'down'.
503
        """
504 1
        interface = event.content['interface']
505
        link = self._get_link_from_interface(interface)
506 1
        if link and link.is_active():
507 1
            link.deactivate()
508
            link.update_metadata('last_status_change', time.time())
509 1
            self.notify_topology_update()
510 1
            self.notify_link_status_change(link)
511 1
512
    @listen_to('.*.interface.is.nni')
513 1
    def add_links(self, event):
514
        """Update the topology with links related to the NNI interfaces."""
515
        interface_a = event.content['interface_a']
516
        interface_b = event.content['interface_b']
517
518
        link = self._get_link_or_create(interface_a, interface_b)
519
        interface_a.update_link(link)
520
        interface_b.update_link(link)
521
522
        interface_a.nni = True
523
        interface_b.nni = True
524
525
        self.notify_topology_update()
526
527
    # def add_host(self, event):
528
    #    """Update the topology with a new Host."""
529
530
    #    interface = event.content['port']
531
    #    mac = event.content['reachable_mac']
532 1
533
    #    host = Host(mac)
534
    #    link = self.topology.get_link(interface.id)
535
    #    if link is not None:
536
    #        return
537
538
    #    self.topology.add_link(interface.id, host.id)
539
    #    self.topology.add_device(host)
540
541 1
    #    if settings.DISPLAY_FULL_DUPLEX_LINKS:
542
    #        self.topology.add_link(host.id, interface.id)
543
544
    def save_status_on_storehouse(self):
545
        """Save the network administrative status using storehouse."""
546
        status = self._get_switches_dict()
547
        status['id'] = 0
548
        self.storehouse.save_status(status)
549
550
    def notify_topology_update(self):
551
        """Send an event to notify about updates on the topology."""
552
        name = 'kytos/topology.updated'
553
        event = KytosEvent(name=name, content={'topology':
554
                                               self._get_topology()})
555
        self.controller.buffers.app.put(event)
556
557
    def notify_link_status_change(self, link):
558
        """Send an event to notify about a status change on a link."""
559
        name = 'kytos/topology.'
560
        if link.is_active():
561
            status = 'link_up'
562
        else:
563
            status = 'link_down'
564
        event = KytosEvent(name=name+status, content={'link': link})
565
        self.controller.buffers.app.put(event)
566
567
    def notify_metadata_changes(self, obj, action):
568
        """Send an event to notify about metadata changes."""
569
        if isinstance(obj, Switch):
570
            entity = 'switch'
571
            entities = 'switches'
572
        elif isinstance(obj, Interface):
573
            entity = 'interface'
574
            entities = 'interfaces'
575
        elif isinstance(obj, Link):
576
            entity = 'link'
577
            entities = 'links'
578
579
        name = f'kytos/topology.{entities}.metadata.{action}'
580
        event = KytosEvent(name=name, content={entity: obj,
0 ignored issues
show
introduced by
The variable entity does not seem to be defined for all execution paths.
Loading history...
581
                                               'metadata': obj.metadata})
582
        self.controller.buffers.app.put(event)
583
        log.debug(f'Metadata from {obj.id} was {action}.')
584
585
    @listen_to('.*.switch.port.created')
586
    def notify_port_created(self, original_event):
587
        """Notify when a port is created."""
588
        name = 'kytos/topology.port.created'
589
        event = KytosEvent(name=name, content=original_event.content)
590
        self.controller.buffers.app.put(event)
591
592
    @listen_to('kytos/topology.*.metadata.*')
593
    def save_metadata_on_store(self, event):
594
        """Send to storehouse the data updated."""
595
        name = 'kytos.storehouse.update'
596
        if 'switch' in event.content:
597
            store = self.store_items.get('switches')
598
            obj = event.content.get('switch')
599
            namespace = 'kytos.topology.switches.metadata'
600
        elif 'interface' in event.content:
601
            store = self.store_items.get('interfaces')
602
            obj = event.content.get('interface')
603
            namespace = 'kytos.topology.iterfaces.metadata'
604
        elif 'link' in event.content:
605
            store = self.store_items.get('links')
606
            obj = event.content.get('link')
607
            namespace = 'kytos.topology.links.metadata'
608
609
        store.data[obj.id] = obj.metadata
0 ignored issues
show
introduced by
The variable store does not seem to be defined for all execution paths.
Loading history...
introduced by
The variable obj does not seem to be defined for all execution paths.
Loading history...
610
        content = {'namespace': namespace,
0 ignored issues
show
introduced by
The variable namespace does not seem to be defined for all execution paths.
Loading history...
611
                   'box_id': store.box_id,
612
                   'data': store.data,
613
                   'callback': self.update_instance}
614
615
        event = KytosEvent(name=name, content=content)
616
        self.controller.buffers.app.put(event)
617
618
    @staticmethod
619
    def update_instance(event, _data, error):
620
        """Display in Kytos console if the data was updated."""
621
        entities = event.content.get('namespace', '').split('.')[-2]
622
        if error:
623
            log.error(f'Error trying to update storehouse {entities}.')
624
        else:
625
            log.debug(f'Storehouse update to entities: {entities}.')
626
627
    def verify_storehouse(self, entities):
628
        """Request a list of box saved by specific entity."""
629
        name = 'kytos.storehouse.list'
630
        content = {'namespace': f'kytos.topology.{entities}.metadata',
631
                   'callback': self.request_retrieve_entities}
632
        event = KytosEvent(name=name, content=content)
633
        self.controller.buffers.app.put(event)
634
        log.info(f'verify data in storehouse for {entities}.')
635
636
    def request_retrieve_entities(self, event, data, _error):
637
        """Create a box or retrieve an existent box from storehouse."""
638
        msg = ''
639
        content = {'namespace': event.content.get('namespace'),
640
                   'callback': self.load_from_store,
641
                   'data': {}}
642
643
        if not data:
644
            name = 'kytos.storehouse.create'
645
            msg = 'Create new box in storehouse'
646
        else:
647
            name = 'kytos.storehouse.retrieve'
648
            content['box_id'] = data[0]
649
            msg = 'Retrieve data from storeohouse.'
650
651
        event = KytosEvent(name=name, content=content)
652
        self.controller.buffers.app.put(event)
653
        log.debug(msg)
654
655
    def load_from_store(self, event, box, error):
656
        """Save the data retrived from storehouse."""
657
        entities = event.content.get('namespace', '').split('.')[-2]
658
        if error:
659
            log.error('Error while get a box from storehouse.')
660
        else:
661
            self.store_items[entities] = box
662
            log.debug('Data updated')
663
664
    def update_instance_metadata(self, obj):
665
        """Update object instance with saved metadata."""
666
        metadata = None
667
        if isinstance(obj, Interface):
668
            all_metadata = self.store_items.get('interfaces', None)
669
            if all_metadata:
670
                metadata = all_metadata.data.get(obj.id)
671
        elif isinstance(obj, Switch):
672
            all_metadata = self.store_items.get('switches', None)
673
            if all_metadata:
674
                metadata = all_metadata.data.get(obj.id)
675
        elif isinstance(obj, Link):
676
            all_metadata = self.store_items.get('links', None)
677
            if all_metadata:
678
                metadata = all_metadata.data.get(obj.id)
679
680
        if metadata:
681
            obj.extend_metadata(metadata)
682
            log.debug(f'Metadata to {obj.id} was updated')
683