1 # ==================================================================================
2 # Copyright (c) 2019 Nokia
3 # Copyright (c) 2018-2019 AT&T Intellectual Property.
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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 # ==================================================================================
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
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
26 from a1.exceptions import PolicyTypeNotFound, PolicyInstanceNotFound, PolicyTypeAlreadyExists
27 from a1 import get_module_logger
31 logger = get_module_logger(__name__)
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
44 def type_is_valid(policy_type_id):
46 check that a type is valid
48 if policy_type_id not in POLICY_DATA:
49 logger.error("%s not found", policy_type_id)
50 raise PolicyTypeNotFound()
53 def store_policy_type(policy_type_id, body):
55 store a policy type if it doesn't already exist
57 if policy_type_id in POLICY_DATA:
58 raise PolicyTypeAlreadyExists()
60 POLICY_DATA[policy_type_id] = {}
61 POLICY_DATA[policy_type_id][D] = body
62 POLICY_DATA[policy_type_id][I] = {}
65 def get_policy_type(policy_type_id):
69 type_is_valid(policy_type_id)
70 return POLICY_DATA[policy_type_id][D]
77 return list(POLICY_DATA.keys())
83 def instance_is_valid(policy_type_id, policy_instance_id):
85 check that an instance is valid
87 type_is_valid(policy_type_id)
88 if policy_instance_id not in POLICY_DATA[policy_type_id][I]:
89 raise PolicyInstanceNotFound
92 def store_policy_instance(policy_type_id, policy_instance_id, instance):
94 Store a policy instance
96 type_is_valid(policy_type_id)
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] = {}
105 def delete_policy_instance_if_applicable(policy_type_id, policy_instance_id):
107 delete a policy instance if all known statuses are DELETED
109 pops a1s waiting mailbox
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"])
120 logger.debug("Dropping message")
124 instance_is_valid(policy_type_id, policy_instance_id)
126 # see if we can delete
127 vector = get_policy_instance_statuses(policy_type_id, policy_instance_id)
133 break # have at least one not DELETED, do nothing
135 # blow away from a1 db
137 del POLICY_DATA[policy_type_id][I][policy_instance_id]
140 def get_policy_instance(policy_type_id, policy_instance_id):
142 Retrieve a policy instance
144 instance_is_valid(policy_type_id, policy_instance_id)
145 return POLICY_DATA[policy_type_id][I][policy_instance_id][D]
148 def get_policy_instance_statuses(policy_type_id, policy_instance_id):
150 Retrieve the status vector for a policy instance
152 instance_is_valid(policy_type_id, policy_instance_id)
154 return [v for _, v in POLICY_DATA[policy_type_id][I][policy_instance_id][H].items()]
157 def set_policy_instance_status(policy_type_id, policy_instance_id, handler_id, status):
159 Update the status of a handler id of a policy instance
161 instance_is_valid(policy_type_id, policy_instance_id)
163 POLICY_DATA[policy_type_id][I][policy_instance_id][H][handler_id] = status
166 def get_instance_list(policy_type_id):
168 retrieve all instance ids for a type
170 type_is_valid(policy_type_id)
171 return list(POLICY_DATA[policy_type_id][I].keys())