Passed
Pull Request — master (#80)
by
unknown
02:01
created

build.main   F

Complexity

Total Complexity 106

Size/Duplication

Total Lines 598
Duplicated Lines 9.53 %

Test Coverage

Coverage 36.49%

Importance

Changes 0
Metric Value
eloc 404
dl 57
loc 598
rs 2
c 0
b 0
f 0
ccs 131
cts 359
cp 0.3649
wmc 106

49 Methods

Rating   Name   Duplication   Size   Complexity  
A Main.shutdown() 0 3 1
A Main.setup() 0 8 1
A Main.execute() 0 2 1
A Main._get_link_or_create() 0 9 3
A Main.notify_port_created() 0 6 1
A Main.disable_switch() 0 8 2
A Main.verify_storehouse() 0 8 1
A Main.load_from_store() 0 8 2
A Main.request_retrieve_entities() 0 18 2
A Main.enable_switch() 0 8 2
A Main.disable_link() 0 9 2
B Main.enable_interface() 28 28 6
A Main.add_switch_metadata() 0 12 2
A Main.get_interfaces() 0 10 3
A Main._get_switches_dict() 0 4 1
A Main.delete_interface_metadata() 0 21 4
A Main.add_interface_metadata() 0 20 3
B Main.update_instance_metadata() 0 19 8
A Main.get_switches() 0 4 1
A Main.notify_link_status_change() 0 9 2
A Main.handle_interface_down() 0 9 1
A Main.handle_interface_link_up() 0 13 3
A Main.handle_interface_created() 0 4 1
A Main.get_interface_metadata() 0 16 3
A Main.delete_link_metadata() 0 13 3
A Main.notify_topology_update() 0 6 1
A Main.enable_link() 0 9 2
A Main.handle_new_switch() 0 12 1
A Main.get_switch_metadata() 0 8 2
A Main.update_instance() 0 8 2
A Main.handle_connection_lost() 0 12 2
A Main.get_links() 0 7 1
B Main.disable_interface() 29 29 6
A Main.get_topology() 0 7 1
A Main.save_metadata_on_store() 0 25 4
A Main.handle_interface_link_down() 0 12 3
A Main._get_links_dict() 0 4 1
A Main.add_links() 0 14 1
A Main.handle_interface_deleted() 0 4 1
A Main.handle_interface_up() 0 9 1
A Main.add_link_metadata() 0 12 2
A Main._get_link_from_interface() 0 6 3
A Main.notify_metadata_changes() 0 17 4
A Main._get_data() 0 5 1
A Main.delete_switch_metadata() 0 11 2
A Main._get_topology_dict() 0 4 1
A Main._get_interfaces() 0 8 2
A Main.get_link_metadata() 0 7 2
A Main._get_topology() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like build.main often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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