1 | """Module to handle the storehouse.""" |
||
2 | 1 | import time |
|
3 | |||
4 | 1 | from kytos.core import log |
|
5 | 1 | from kytos.core.events import KytosEvent |
|
6 | 1 | from napps.kytos.flow_manager import settings |
|
7 | |||
8 | 1 | DEFAULT_BOX_RESTORE_TIMER = 0.1 |
|
9 | 1 | BOX_RESTORE_ATTEMPTS = 10 |
|
10 | |||
11 | |||
12 | 1 | class StoreHouse: |
|
13 | """Class to handle storehouse.""" |
||
14 | |||
15 | 1 | @classmethod |
|
16 | def __new__(cls, *args, **kwargs): |
||
17 | # pylint: disable=unused-argument |
||
18 | """Make this class a Singleton.""" |
||
19 | 1 | instance = cls.__dict__.get("__instance__") |
|
20 | 1 | if instance is not None: |
|
21 | 1 | return instance |
|
22 | 1 | cls.__instance__ = instance = object.__new__(cls) |
|
23 | 1 | return instance |
|
24 | |||
25 | 1 | def __init__(self, controller): |
|
26 | """Create a storehouse client instance.""" |
||
27 | 1 | self.controller = controller |
|
28 | 1 | self.namespace = 'kytos.flow.persistence' |
|
29 | 1 | self.box_restore_timer = getattr(settings, 'BOX_RESTORE_TIMER', |
|
30 | DEFAULT_BOX_RESTORE_TIMER) |
||
31 | |||
32 | 1 | if 'box' not in self.__dict__: |
|
33 | 1 | self.box = None |
|
34 | 1 | self.list_stored_boxes() |
|
35 | |||
36 | 1 | def get_data(self): |
|
37 | """Return the persistence box data.""" |
||
38 | # Wait retrieve or create box in storehouse |
||
39 | 1 | i = 0 |
|
40 | 1 | while not self.box and i < BOX_RESTORE_ATTEMPTS: |
|
41 | time.sleep(self.box_restore_timer) |
||
42 | i += 1 |
||
43 | 1 | if not self.box: |
|
44 | error = 'Error retrieving persistence box from storehouse.' |
||
45 | log.error(error) |
||
46 | raise FileNotFoundError(error) |
||
47 | 1 | return self.box.data |
|
48 | |||
49 | 1 | def create_box(self): |
|
50 | """Create a persistence box to store administrative changes.""" |
||
51 | 1 | content = {'namespace': self.namespace, |
|
52 | 'callback': self._create_box_callback, |
||
53 | 'data': {}} |
||
54 | 1 | event = KytosEvent(name='kytos.storehouse.create', content=content) |
|
55 | 1 | self.controller.buffers.app.put(event) |
|
56 | |||
57 | 1 | def _create_box_callback(self, _event, data, error): |
|
58 | """Execute the callback to handle create_box.""" |
||
59 | if error: |
||
60 | log.error(f'Can\'t create persistence' |
||
61 | f'box with namespace {self.namespace}') |
||
62 | |||
63 | self.box = data |
||
64 | |||
65 | 1 | def list_stored_boxes(self): |
|
66 | """List all persistence box stored in storehouse.""" |
||
67 | 1 | name = 'kytos.storehouse.list' |
|
68 | 1 | content = {'namespace': self.namespace, |
|
69 | 'callback': self._get_or_create_a_box_from_list_of_boxes} |
||
70 | |||
71 | 1 | event = KytosEvent(name=name, content=content) |
|
72 | 1 | self.controller.buffers.app.put(event) |
|
73 | |||
74 | 1 | def _get_or_create_a_box_from_list_of_boxes(self, _event, data, _error): |
|
75 | """Create a persistence box or retrieve the stored box.""" |
||
76 | 1 | if data: |
|
77 | 1 | self.get_stored_box(data[0]) |
|
78 | else: |
||
79 | 1 | self.create_box() |
|
80 | |||
81 | 1 | def get_stored_box(self, box_id): |
|
82 | """Get persistence box from storehouse.""" |
||
83 | 1 | content = {'namespace': self.namespace, |
|
84 | 'callback': self._get_box_callback, |
||
85 | 'box_id': box_id, |
||
86 | 'data': {}} |
||
87 | 1 | name = 'kytos.storehouse.retrieve' |
|
88 | 1 | event = KytosEvent(name=name, content=content) |
|
89 | 1 | self.controller.buffers.app.put(event) |
|
90 | |||
91 | 1 | def _get_box_callback(self, _event, data, error): |
|
92 | """Handle get_box method saving the box or logging with the error.""" |
||
93 | if error: |
||
94 | log.error('Persistence box not found.') |
||
95 | |||
96 | self.box = data |
||
97 | |||
98 | 1 | def save_flow(self, flows): |
|
99 | """Save flows in storehouse.""" |
||
100 | 1 | self.box.data[flows['id']] = flows |
|
101 | 1 | content = {'namespace': self.namespace, |
|
102 | 'box_id': self.box.box_id, |
||
103 | 'data': self.box.data, |
||
104 | 'callback': self._save_flow_callback} |
||
105 | |||
106 | 1 | event = KytosEvent(name='kytos.storehouse.update', content=content) |
|
107 | 1 | self.controller.buffers.app.put(event) |
|
108 | |||
109 | 1 | def _save_flow_callback(self, _event, data, error): |
|
110 | """Display stored flow.""" |
||
111 | if error: |
||
112 | log.error(f'Can\'t update persistence box {data.box_id}.') |
||
113 | |||
114 | log.info(f'Flow saved in {self.namespace}.{data.box_id}') |
||
115 |