Passed
Pull Request — master (#32)
by Italo Valcy
03:01
created

build.storehouse   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 89
dl 0
loc 131
ccs 76
cts 76
cp 1
rs 10
c 0
b 0
f 0
wmc 24

10 Methods

Rating   Name   Duplication   Size   Complexity  
A StoreHouse.__init__() 0 9 3
A StoreHouse.get_data() 0 11 4
A StoreHouse.get_stored_box() 0 9 1
A StoreHouse.create_box() 0 7 1
A StoreHouse._get_or_create_a_box_from_list_of_boxes() 0 6 2
A StoreHouse._get_box_callback() 0 6 2
A StoreHouse.list_stored_boxes() 0 8 1
A StoreHouse._create_box_callback() 0 7 2
A StoreHouse.__new__() 0 9 2
B StoreHouse.save_status() 0 37 6
1
"""Module to handle the storehouse."""
2 1
import threading
3 1
import time
4
5 1
from kytos.core import log
6 1
from kytos.core.events import KytosEvent
7 1
from napps.kytos.topology import settings
8
9
10 1
class StoreHouse:
11
    """Class to handle storehouse."""
12
13 1
    @classmethod
14
    def __new__(cls, *args, **kwargs):
15
        # pylint: disable=unused-argument
16
        """Make this class a Singleton."""
17 1
        instance = cls.__dict__.get("__instance__")
18 1
        if instance is not None:
19 1
            return instance
20 1
        cls.__instance__ = instance = object.__new__(cls)
21 1
        return instance
22
23 1
    def __init__(self, controller):
24
        """Create a storehouse client instance."""
25 1
        self.controller = controller
26 1
        self.namespace = 'kytos.topology.status'
27 1
        if '_lock' not in self.__dict__:
28 1
            self._lock = threading.Lock()
29 1
        if 'box' not in self.__dict__:
30 1
            self.box = None
31 1
        self.list_stored_boxes()
32
33 1
    def get_data(self):
34
        """Return the persistence box data."""
35
        # Wait for box retrieve from storehouse
36 1
        i = 0
37 1
        while not self.box and i < settings.STOREHOUSE_TIMEOUT:
38 1
            time.sleep(settings.STOREHOUSE_WAIT_INTERVAL)
39 1
            i += settings.STOREHOUSE_WAIT_INTERVAL
40 1
        if not self.box:
41 1
            error = 'Error retrieving persistence box from storehouse.'
42 1
            raise FileNotFoundError(error)
43 1
        return self.box.data
44
45 1
    def create_box(self):
46
        """Create a persistence box to store administrative changes."""
47 1
        content = {'namespace': self.namespace,
48
                   'callback': self._create_box_callback,
49
                   'data': {}}
50 1
        event = KytosEvent(name='kytos.storehouse.create', content=content)
51 1
        self.controller.buffers.app.put(event)
52
53 1
    def _create_box_callback(self, _event, data, error):
54
        """Execute the callback to handle create_box."""
55 1
        if error:
56 1
            log.error(f'Can\'t create persistence'
57
                      f'box with namespace {self.namespace}')
58
59 1
        self.box = data
60
61 1
    def list_stored_boxes(self):
62
        """List all persistence box stored in storehouse."""
63 1
        name = 'kytos.storehouse.list'
64 1
        content = {'namespace': self.namespace,
65
                   'callback': self._get_or_create_a_box_from_list_of_boxes}
66
67 1
        event = KytosEvent(name=name, content=content)
68 1
        self.controller.buffers.app.put(event)
69
70 1
    def _get_or_create_a_box_from_list_of_boxes(self, _event, data, _error):
71
        """Create a persistence box or retrieve the stored box."""
72 1
        if data:
73 1
            self.get_stored_box(data[0])
74
        else:
75 1
            self.create_box()
76
77 1
    def get_stored_box(self, box_id):
78
        """Get persistence box from storehouse."""
79 1
        content = {'namespace': self.namespace,
80
                   'callback': self._get_box_callback,
81
                   'box_id': box_id,
82
                   'data': {}}
83 1
        name = 'kytos.storehouse.retrieve'
84 1
        event = KytosEvent(name=name, content=content)
85 1
        self.controller.buffers.app.put(event)
86
87 1
    def _get_box_callback(self, _event, data, error):
88
        """Handle get_box method saving the box or logging with the error."""
89 1
        if error:
90 1
            log.error('Persistence box not found.')
91
92 1
        self.box = data
93
94 1
    def save_status(self, status):
95
        """Save the network administrative status using storehouse."""
96 1
        storehouse_done = False
97 1
        storehouse_error = None
98
99 1
        def _storehouse_callback(event, data, error):
100
            """Handle storehouse update result."""
101
            # pylint: disable=unused-argument
102
            nonlocal storehouse_done, storehouse_error
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable storehouse_error does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable storehouse_done does not seem to be defined.
Loading history...
103 1
            storehouse_done = True
104 1
            storehouse_error = error
105
106 1
        with self._lock:
107 1
            self.box.data[status.get('id')] = status
108 1
            content = {'namespace': self.namespace,
109
                       'box_id': self.box.box_id,
110
                       'data': self.box.data,
111
                       'callback': _storehouse_callback}
112 1
            event = KytosEvent(name='kytos.storehouse.update',
113
                               content=content)
114 1
            self.controller.buffers.app.put(event)
115
116 1
            i = 0
117 1
            while not storehouse_done and i < settings.STOREHOUSE_TIMEOUT:
118 1
                time.sleep(settings.STOREHOUSE_WAIT_INTERVAL)
119 1
                i += settings.STOREHOUSE_WAIT_INTERVAL
120
121 1
            if not storehouse_done:
122 1
                storehouse_error = 'Timeout while waiting for storehouse'
123
124 1
            if storehouse_error:
125 1
                log.error('Fail to update persistence box in '
126
                          f'{self.namespace}.{self.box.box_id}. '
127
                          f'Error: {storehouse_error}')
128 1
                return
129
130 1
        log.info('Network administrative status saved in '
131
                 f'{self.namespace}.{self.box.box_id}')
132