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

build.main   F

Complexity

Total Complexity 106

Size/Duplication

Total Lines 586
Duplicated Lines 9.22 %

Test Coverage

Coverage 37.04%

Importance

Changes 0
Metric Value
wmc 106
eloc 395
dl 54
loc 586
ccs 130
cts 351
cp 0.3704
rs 2
c 0
b 0
f 0

48 Methods

Rating   Name   Duplication   Size   Complexity  
A Main._get_switches_dict() 0 4 1
A Main.shutdown() 0 3 1
A Main.setup() 0 8 1
A Main.execute() 0 2 1
A Main._get_links_dict() 0 4 1
A Main._get_link_or_create() 0 9 3
A Main._get_link_from_interface() 0 6 3
A Main._get_topology_dict() 0 4 1
A Main.enable_link() 0 9 2
A Main.get_switch_metadata() 0 8 2
A Main.disable_switch() 0 8 2
A Main.enable_switch() 0 8 2
A Main.add_switch_metadata() 0 12 2
A Main.get_interfaces() 0 10 3
A Main.get_switches() 0 4 1
A Main.get_topology() 0 7 1
A Main._get_data() 0 5 1
A Main.delete_switch_metadata() 0 11 2
A Main._get_topology() 0 3 1
A Main.verify_storehouse() 0 8 1
A Main.notify_port_created() 0 6 1
A Main.load_from_store() 0 8 2
A Main.request_retrieve_entities() 0 18 2
B Main.update_instance_metadata() 0 19 8
A Main.notify_link_status_change() 0 9 2
A Main.notify_topology_update() 0 6 1
A Main.update_instance() 0 8 2
A Main.save_metadata_on_store() 0 25 4
A Main.add_links() 0 14 1
A Main.notify_metadata_changes() 0 17 4
A Main.disable_link() 0 9 2
B Main.enable_interface() 27 27 7
A Main.add_interface_metadata() 0 20 3
A Main.delete_interface_metadata() 0 21 4
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.handle_new_switch() 0 12 1
A Main.handle_connection_lost() 0 12 2
A Main.get_links() 0 7 1
B Main.disable_interface() 27 27 7
A Main.handle_interface_link_down() 0 12 3
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_metadata() 0 7 2

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