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 # ==================================================================================
17 from flask import Response
20 from jsonschema.exceptions import ValidationError
21 from a1 import get_module_logger
22 from a1 import a1rmr, exceptions, utils
25 logger = get_module_logger(__name__)
28 def _get_policy_definition(policyname):
29 # Currently we read the manifest on each call, which would seem to allow updating A1 in place. Revisit this?
30 manifest = utils.get_ric_manifest()
31 for m in manifest["controls"]:
32 if m["name"] == policyname:
34 raise exceptions.PolicyNotFound()
37 def _get_needed_policy_info(policyname):
39 Get the needed info for a policy
41 m = _get_policy_definition(policyname)
43 utils.rmr_string_to_int(m["message_receives_rmr_type"]),
44 m["message_receives_payload_schema"] if "message_receives_payload_schema" in m else None,
45 utils.rmr_string_to_int(m["message_sends_rmr_type"]),
49 def _get_needed_policy_fetch_info(policyname):
51 Get the needed info for fetching a policy state
53 m = _get_policy_definition(policyname)
54 req_k = "control_state_request_rmr_type"
55 ack_k = "control_state_request_reply_rmr_type"
57 utils.rmr_string_to_int(m[req_k]) if req_k in m else None,
58 utils.rmr_string_to_int(m[ack_k]) if ack_k in m else None,
62 def _try_func_return(func):
64 generic caller that returns the apporp http response if exceptions are raised
68 except ValidationError as exc:
71 except exceptions.PolicyNotFound as exc:
74 except exceptions.MissingManifest as exc:
76 return "A1 was unable to find the required RIC manifest. report this!", 500
77 except exceptions.MissingRmrString as exc:
79 return "A1 does not have a mapping for the desired rmr string. report this!", 500
80 except exceptions.MessageSendFailure as exc:
82 return "A1 was unable to send a needed message to a downstream subscriber", 504
83 except exceptions.ExpectedAckNotReceived as exc:
85 return "A1 was expecting an ACK back but it didn't receive one or didn't recieve the expected ACK", 504
86 except BaseException as exc:
87 # catch all, should never happen...
89 return Response(status=500)
92 def _put_handler(policyname, data):
97 mtype_send, schema, mtype_return = _get_needed_policy_info(policyname)
99 # validate the PUT against the schema, or if there is no shema, make sure the pUT is empty
101 utils.validate_json(data, schema)
103 return "BODY SUPPLIED BUT POLICY HAS NO EXPECTED BODY", 400
105 # send rmr, wait for ACK
106 return_payload = a1rmr.send_ack_retry(json.dumps(data), message_type=mtype_send, expected_ack_message_type=mtype_return)
108 # right now it is assumed that xapps respond with JSON payloads
109 # it is further assumed that they include a field "status" and that the value "SUCCESS" indicates a good policy change
111 rpj = json.loads(return_payload)
112 return (rpj, 200) if rpj["status"] == "SUCCESS" else ({"reason": "BAD STATUS", "return_payload": rpj}, 502)
113 except json.decoder.JSONDecodeError:
114 return {"reason": "NOT JSON", "return_payload": return_payload}, 502
116 return {"reason": "NO STATUS", "return_payload": rpj}, 502
119 def _get_handler(policyname):
123 mtype_send, mtype_return = _get_needed_policy_fetch_info(policyname)
125 if not (mtype_send and mtype_return):
126 return "POLICY DOES NOT SUPPORT FETCHING", 400
128 # send rmr, wait for ACK
129 return_payload = a1rmr.send_ack_retry("", message_type=mtype_send, expected_ack_message_type=mtype_return)
131 # right now it is assumed that xapps respond with JSON payloads
133 return (json.loads(return_payload), 200)
134 except json.decoder.JSONDecodeError:
135 return {"reason": "NOT JSON", "return_payload": return_payload}, 502
141 def put_handler(policyname):
143 Handles policy replacement
145 data = connexion.request.json
146 return _try_func_return(lambda: _put_handler(policyname, data))
149 def get_handler(policyname):
153 return _try_func_return(lambda: _get_handler(policyname))
156 def healthcheck_handler():
158 Handles healthcheck GET
159 Currently, this basically checks the server is alive.a1rmr