Towards a1 1.0.0: rmr improvements
[ric-plt/a1.git] / a1 / data.py
1 # ==================================================================================
2 #       Copyright (c) 2019 Nokia
3 #       Copyright (c) 2018-2019 AT&T Intellectual Property.
4 #
5 #   Licensed under the Apache License, Version 2.0 (the "License");
6 #   you may not use this file except in compliance with the License.
7 #   You may obtain a copy of the License at
8 #
9 #          http://www.apache.org/licenses/LICENSE-2.0
10 #
11 #   Unless required by applicable law or agreed to in writing, software
12 #   distributed under the License is distributed on an "AS IS" BASIS,
13 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 #   See the License for the specific language governing permissions and
15 #   limitations under the License.
16 # ==================================================================================
17
18 """
19 Represents A1s database and database access functions.
20 In the future, this may change to use a different backend, possibly dramatically.
21 Hopefully, the access functions are a good api so nothing else has to change when this happens
22
23 For now, the database is in memory.
24 We use dict data structures (KV) with the expectation of having to move this into Redis
25 """
26 import json
27 from a1.exceptions import PolicyTypeNotFound, PolicyInstanceNotFound, PolicyTypeAlreadyExists
28 from a1 import get_module_logger
29 from a1 import a1rmr
30
31 logger = get_module_logger(__name__)
32
33 # This is essentially mockouts for future KV
34 # Note that the D subkey won't be needed when in redis, since you can store data at x anx x_y
35 POLICY_DATA = {}
36 I = "instances"
37 H = "handlers"
38 D = "data"
39
40
41 # Types
42
43
44 def type_is_valid(policy_type_id):
45     """
46     check that a type is valid
47     """
48     if policy_type_id not in POLICY_DATA:
49         logger.error("%s not found", policy_type_id)
50         raise PolicyTypeNotFound()
51
52
53 def store_policy_type(policy_type_id, body):
54     """
55     store a policy type if it doesn't already exist
56     """
57     if policy_type_id in POLICY_DATA:
58         raise PolicyTypeAlreadyExists()
59
60     POLICY_DATA[policy_type_id] = {}
61     POLICY_DATA[policy_type_id][D] = body
62     POLICY_DATA[policy_type_id][I] = {}
63
64
65 def get_policy_type(policy_type_id):
66     """
67     retrieve a type
68     """
69     type_is_valid(policy_type_id)
70     return POLICY_DATA[policy_type_id][D]
71
72
73 def get_type_list():
74     """
75     retrieve all type ids
76     """
77     return list(POLICY_DATA.keys())
78
79
80 # Instances
81
82
83 def instance_is_valid(policy_type_id, policy_instance_id):
84     """
85     check that an instance is valid
86     """
87     type_is_valid(policy_type_id)
88     if policy_instance_id not in POLICY_DATA[policy_type_id][I]:
89         raise PolicyInstanceNotFound
90
91
92 def store_policy_instance(policy_type_id, policy_instance_id, instance):
93     """
94     Store a policy instance
95     """
96     type_is_valid(policy_type_id)
97
98     # store the instance
99     # Reset the statuses because this is a new policy instance, even if it was overwritten
100     POLICY_DATA[policy_type_id][I][policy_instance_id] = {}
101     POLICY_DATA[policy_type_id][I][policy_instance_id][D] = instance
102     POLICY_DATA[policy_type_id][I][policy_instance_id][H] = {}
103
104
105 def delete_policy_instance_if_applicable(policy_type_id, policy_instance_id):
106     """
107     delete a policy instance if all known statuses are DELETED
108
109     pops a1s waiting mailbox
110     """
111     # pop through a1s mailbox, updating a1s db of all policy statuses
112     for msg in a1rmr.dequeue_all_waiting_messages([21024]):
113         # try to parse the messages as responses. Drop those that are malformed
114         # NOTE: we don't use the parameters "policy_type_id, policy_instance" from above here,
115         # because we are popping the whole mailbox, which might include other statuses
116         pay = json.loads(msg["payload"])
117         if "policy_type_id" in pay and "policy_instance_id" in pay and "handler_id" in pay and "status" in pay:
118             set_policy_instance_status(pay["policy_type_id"], pay["policy_instance_id"], pay["handler_id"], pay["status"])
119         else:
120             logger.debug("Dropping message")
121             logger.debug(pay)
122
123     # raise if not valid
124     instance_is_valid(policy_type_id, policy_instance_id)
125
126     # see if we can delete
127     vector = get_policy_instance_statuses(policy_type_id, policy_instance_id)
128     if vector != []:
129         all_deleted = True
130         for i in vector:
131             if i != "DELETED":
132                 all_deleted = False
133                 break  # have at least one not DELETED, do nothing
134
135         # blow away from a1 db
136         if all_deleted:
137             del POLICY_DATA[policy_type_id][I][policy_instance_id]
138
139
140 def get_policy_instance(policy_type_id, policy_instance_id):
141     """
142     Retrieve a policy instance
143     """
144     instance_is_valid(policy_type_id, policy_instance_id)
145     return POLICY_DATA[policy_type_id][I][policy_instance_id][D]
146
147
148 def get_policy_instance_statuses(policy_type_id, policy_instance_id):
149     """
150     Retrieve the status vector for a policy instance
151     """
152     instance_is_valid(policy_type_id, policy_instance_id)
153
154     return [v for _, v in POLICY_DATA[policy_type_id][I][policy_instance_id][H].items()]
155
156
157 def set_policy_instance_status(policy_type_id, policy_instance_id, handler_id, status):
158     """
159     Update the status of a handler id of a policy instance
160     """
161     instance_is_valid(policy_type_id, policy_instance_id)
162
163     POLICY_DATA[policy_type_id][I][policy_instance_id][H][handler_id] = status
164
165
166 def get_instance_list(policy_type_id):
167     """
168     retrieve all instance ids for a type
169     """
170     type_is_valid(policy_type_id)
171     return list(POLICY_DATA[policy_type_id][I].keys())