Passed
Push — master ( c2b06d...36be2f )
by Italo Valcy
03:12 queued 11s
created

build.storehouse   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 90
dl 0
loc 131
ccs 78
cts 78
cp 1
rs 10
c 0
b 0
f 0
wmc 25

11 Methods

Rating   Name   Duplication   Size   Complexity  
A StoreHouse.__new__() 0 9 2
A StoreHouse.__init__() 0 11 3
A StoreHouse._save_status_callback() 0 4 1
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
B StoreHouse.save_status() 0 29 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.storehouse_done = False
32 1
        self.storehouse_error = None
33 1
        self.list_stored_boxes()
34
35 1
    def get_data(self):
36
        """Return the persistence box data."""
37
        # Wait for box retrieve from storehouse
38 1
        i = 0
39 1
        while not self.box and i < settings.STOREHOUSE_TIMEOUT:
40 1
            time.sleep(settings.STOREHOUSE_WAIT_INTERVAL)
41 1
            i += settings.STOREHOUSE_WAIT_INTERVAL
42 1
        if not self.box:
43 1
            error = 'Error retrieving persistence box from storehouse.'
44 1
            raise FileNotFoundError(error)
45 1
        return self.box.data
46
47 1
    def create_box(self):
48
        """Create a persistence box to store administrative changes."""
49 1
        content = {'namespace': self.namespace,
50
                   'callback': self._create_box_callback,
51
                   'data': {}}
52 1
        event = KytosEvent(name='kytos.storehouse.create', content=content)
53 1
        self.controller.buffers.app.put(event)
54
55 1
    def _create_box_callback(self, _event, data, error):
56
        """Execute the callback to handle create_box."""
57 1
        if error:
58 1
            log.error(f'Can\'t create persistence'
59
                      f'box with namespace {self.namespace}')
60
61 1
        self.box = data
62
63 1
    def list_stored_boxes(self):
64
        """List all persistence box stored in storehouse."""
65 1
        name = 'kytos.storehouse.list'
66 1
        content = {'namespace': self.namespace,
67
                   'callback': self._get_or_create_a_box_from_list_of_boxes}
68
69 1
        event = KytosEvent(name=name, content=content)
70 1
        self.controller.buffers.app.put(event)
71
72 1
    def _get_or_create_a_box_from_list_of_boxes(self, _event, data, _error):
73
        """Create a persistence box or retrieve the stored box."""
74 1
        if data:
75 1
            self.get_stored_box(data[0])
76
        else:
77 1
            self.create_box()
78
79 1
    def get_stored_box(self, box_id):
80
        """Get persistence box from storehouse."""
81 1
        content = {'namespace': self.namespace,
82
                   'callback': self._get_box_callback,
83
                   'box_id': box_id,
84
                   'data': {}}
85 1
        name = 'kytos.storehouse.retrieve'
86 1
        event = KytosEvent(name=name, content=content)
87 1
        self.controller.buffers.app.put(event)
88
89 1
    def _get_box_callback(self, _event, data, error):
90
        """Handle get_box method saving the box or logging with the error."""
91 1
        if error:
92 1
            log.error('Persistence box not found.')
93
94 1
        self.box = data
95
96 1
    def save_status(self, status):
97
        """Save the network administrative status using storehouse."""
98 1
        with self._lock:
99 1
            self.storehouse_done = False
100 1
            self.storehouse_error = None
101 1
            self.box.data[status.get('id')] = status
102 1
            content = {'namespace': self.namespace,
103
                       'box_id': self.box.box_id,
104
                       'data': self.box.data,
105
                       'callback': self._save_status_callback}
106 1
            event = KytosEvent(name='kytos.storehouse.update',
107
                               content=content)
108 1
            self.controller.buffers.app.put(event)
109
110 1
            i = 0
111 1
            while not self.storehouse_done and i < settings.STOREHOUSE_TIMEOUT:
112 1
                time.sleep(settings.STOREHOUSE_WAIT_INTERVAL)
113 1
                i += settings.STOREHOUSE_WAIT_INTERVAL
114
115 1
            if not self.storehouse_done:
116 1
                self.storehouse_error = 'Timeout while waiting for storehouse'
117
118 1
            if self.storehouse_error:
119 1
                log.error('Fail to update persistence box in '
120
                          f'{self.namespace}.{self.box.box_id}. '
121
                          f'Error: {self.storehouse_error}')
122 1
                return
123
124 1
        log.info('Network administrative status saved in '
125
                 f'{self.namespace}.{self.box.box_id}')
126
127 1
    def _save_status_callback(self, _event, _data, error):
128
        """Handle storehouse update result."""
129 1
        self.storehouse_done = True
130
        self.storehouse_error = error
131