blob: 9c2656e162ff43f676a82af7537ca6424abcf742 [file] [log] [blame]
alex_sh9d980ce2017-08-23 17:30:56 -04001# ================================================================================
Alex Shatovebc1a062019-01-31 16:07:48 -05002# Copyright (c) 2017-2019 AT&T Intellectual Property. All rights reserved.
alex_sh9d980ce2017-08-23 17:30:56 -04003# ================================================================================
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15# ============LICENSE_END=========================================================
16#
alex_sh9d980ce2017-08-23 17:30:56 -040017
Alex Shatovd7f34d42018-08-07 12:11:35 -040018"""web-server for policy_handler"""
Alex Shatovf53e5e72018-01-11 11:15:56 -050019
alex_sh9d980ce2017-08-23 17:30:56 -040020import json
21from datetime import datetime
Schmalzried, Terry (ts862m)05f475f2019-11-13 16:47:45 -050022import os
23import time
Alex Shatovd7f34d42018-08-07 12:11:35 -040024
alex_sh9d980ce2017-08-23 17:30:56 -040025import cherrypy
26
Alex Shatov9a4d3c52019-04-01 11:32:06 -040027from . import pdp_client
alex_sh9d980ce2017-08-23 17:30:56 -040028from .config import Config
Alex Shatovd7f34d42018-08-07 12:11:35 -040029from .deploy_handler import PolicyUpdateMessage
Alex Shatova39f4e82018-12-05 15:23:50 -050030from .onap.audit import Audit, AuditHttpCode
Alex Shatov1369bea2018-01-10 11:00:50 -050031from .policy_receiver import PolicyReceiver
Alex Shatov9a4d3c52019-04-01 11:32:06 -040032from .utils import Utils
Alex Shatovd7f34d42018-08-07 12:11:35 -040033
alex_sh9d980ce2017-08-23 17:30:56 -040034
35class PolicyWeb(object):
Alex Shatovd7f34d42018-08-07 12:11:35 -040036 """run http API of policy-handler on 0.0.0.0:wservice_port - any incoming address"""
Alex Shatova39f4e82018-12-05 15:23:50 -050037 DATA_NOT_FOUND_ERROR = 404
Alex Shatovd7f34d42018-08-07 12:11:35 -040038 HOST_INADDR_ANY = ".".join("0"*4)
Alex Shatov9a4d3c52019-04-01 11:32:06 -040039 logger = Utils.get_logger(__file__)
alex_sh9d980ce2017-08-23 17:30:56 -040040
41 @staticmethod
Alex Shatov1369bea2018-01-10 11:00:50 -050042 def run_forever(audit):
43 """run the web-server of the policy-handler forever"""
Alex Shatovd7f34d42018-08-07 12:11:35 -040044 cherrypy.config.update({"server.socket_host": PolicyWeb.HOST_INADDR_ANY,
45 "server.socket_port": Config.wservice_port})
Alex Shatova39f4e82018-12-05 15:23:50 -050046
47 protocol = "http"
48 tls_info = ""
Schmalzried, Terry (ts862m)05f475f2019-11-13 16:47:45 -050049 if Config.tls_server_cert_file and Config.tls_private_key_file:
50 tm_cert = os.path.getmtime(Config.tls_server_cert_file)
51 tm_key = os.path.getmtime(Config.tls_private_key_file)
52 cherrypy.server.ssl_module = 'builtin'
53 cherrypy.server.ssl_certificate = Config.tls_server_cert_file
54 cherrypy.server.ssl_private_key = Config.tls_private_key_file
55 if Config.tls_server_ca_chain_file:
56 cherrypy.server.ssl_certificate_chain = Config.tls_server_ca_chain_file
57 protocol = "https"
58 tls_info = "cert: {} {} {}".format(Config.tls_server_cert_file,
59 Config.tls_private_key_file,
60 Config.tls_server_ca_chain_file)
Alex Shatova39f4e82018-12-05 15:23:50 -050061
Alex Shatov1369bea2018-01-10 11:00:50 -050062 cherrypy.tree.mount(_PolicyWeb(), '/')
Alex Shatova39f4e82018-12-05 15:23:50 -050063
64 PolicyWeb.logger.info(
65 "%s with config: %s", audit.info("running policy_handler as {}://{}:{} {}".format(
66 protocol, cherrypy.server.socket_host, cherrypy.server.socket_port, tls_info)),
67 json.dumps(cherrypy.config))
Alex Shatov1369bea2018-01-10 11:00:50 -050068 cherrypy.engine.start()
alex_sh9d980ce2017-08-23 17:30:56 -040069
Schmalzried, Terry (ts862m)05f475f2019-11-13 16:47:45 -050070 # If HTTPS server certificate changes, exit to let kubernetes restart us
71 if Config.tls_server_cert_file and Config.tls_private_key_file:
72 while True:
73 time.sleep(600)
74 c_tm_cert = os.path.getmtime(Config.tls_server_cert_file)
75 c_tm_key = os.path.getmtime(Config.tls_private_key_file)
76 if c_tm_cert > tm_cert or c_tm_key > tm_key:
77 PolicyWeb.logger.info("cert or key file updated")
78 cherrypy.engine.stop()
79 cherrypy.engine.exit()
80 break
81
82
Alex Shatov1369bea2018-01-10 11:00:50 -050083class _PolicyWeb(object):
84 """REST API of policy-handler"""
85
86 @staticmethod
87 def _get_request_info(request):
88 """returns info about the http request"""
89 return "{0} {1}{2}".format(request.method, request.script_name, request.path_info)
90
alex_sh9d980ce2017-08-23 17:30:56 -040091 @cherrypy.expose
Alex Shatov1369bea2018-01-10 11:00:50 -050092 @cherrypy.popargs('policy_id')
93 @cherrypy.tools.json_out()
94 def policy_latest(self, policy_id):
95 """retireves the latest policy identified by policy_id"""
96 req_info = _PolicyWeb._get_request_info(cherrypy.request)
Alex Shatov50bed532018-04-27 11:53:55 -040097 audit = Audit(job_name="get_latest_policy",
98 req_message=req_info, headers=cherrypy.request.headers)
Alex Shatova39f4e82018-12-05 15:23:50 -050099 PolicyWeb.logger.info("%s policy_id=%s headers=%s",
100 req_info, policy_id, json.dumps(cherrypy.request.headers))
Alex Shatov1369bea2018-01-10 11:00:50 -0500101
Alex Shatov9a4d3c52019-04-01 11:32:06 -0400102 latest_policy = pdp_client.PolicyRest.get_latest_policy(
103 (audit, policy_id, None, None)) or {}
Alex Shatov1369bea2018-01-10 11:00:50 -0500104
Alex Shatov2322ef82018-01-25 17:40:39 -0500105 PolicyWeb.logger.info("res %s policy_id=%s latest_policy=%s",
106 req_info, policy_id, json.dumps(latest_policy))
Alex Shatov1369bea2018-01-10 11:00:50 -0500107
Alex Shatova39f4e82018-12-05 15:23:50 -0500108 _, http_status_code, _ = audit.audit_done(result=json.dumps(latest_policy))
109 if http_status_code == AuditHttpCode.DATA_NOT_FOUND_OK.value:
110 http_status_code = PolicyWeb.DATA_NOT_FOUND_ERROR
111 cherrypy.response.status = http_status_code
Alex Shatov2322ef82018-01-25 17:40:39 -0500112
113 return latest_policy
Alex Shatov1369bea2018-01-10 11:00:50 -0500114
115 def _get_all_policies_latest(self):
116 """retireves all the latest policies on GET /policies_latest"""
117 req_info = _PolicyWeb._get_request_info(cherrypy.request)
Alex Shatov50bed532018-04-27 11:53:55 -0400118 audit = Audit(job_name="get_all_policies_latest",
119 req_message=req_info, headers=cherrypy.request.headers)
Alex Shatov1369bea2018-01-10 11:00:50 -0500120
121 PolicyWeb.logger.info("%s", req_info)
122
Alex Shatov9a4d3c52019-04-01 11:32:06 -0400123 result, policies, policy_filters = pdp_client.PolicyMatcher.get_deployed_policies(audit)
Alex Shatova39f4e82018-12-05 15:23:50 -0500124 if not result:
Alex Shatov9a4d3c52019-04-01 11:32:06 -0400125 result, policy_update = pdp_client.PolicyMatcher.build_catch_up_message(
Alex Shatova39f4e82018-12-05 15:23:50 -0500126 audit, policies, policy_filters)
127 if policy_update and isinstance(policy_update, PolicyUpdateMessage):
128 result["policy_update"] = policy_update.get_message()
Alex Shatov1369bea2018-01-10 11:00:50 -0500129
Alex Shatova39f4e82018-12-05 15:23:50 -0500130 result_str = json.dumps(result, sort_keys=True)
131 PolicyWeb.logger.info("result %s: %s", req_info, result_str)
Alex Shatov1369bea2018-01-10 11:00:50 -0500132
Alex Shatova39f4e82018-12-05 15:23:50 -0500133 _, http_status_code, _ = audit.audit_done(result=result_str)
134 if http_status_code == AuditHttpCode.DATA_NOT_FOUND_OK.value:
135 http_status_code = PolicyWeb.DATA_NOT_FOUND_ERROR
136 cherrypy.response.status = http_status_code
Alex Shatov2322ef82018-01-25 17:40:39 -0500137
Alex Shatovac779d32018-02-01 14:16:56 -0500138 return result
Alex Shatov1369bea2018-01-10 11:00:50 -0500139
140 @cherrypy.expose
141 @cherrypy.tools.json_out()
142 @cherrypy.tools.json_in()
143 def policies_latest(self):
144 """
Alex Shatovd7f34d42018-08-07 12:11:35 -0400145 on :GET: retrieves all the latest policies from policy-engine that are deployed
Alex Shatov1369bea2018-01-10 11:00:50 -0500146
147 on :POST: expects to receive the params that mimic the /getConfig of policy-engine
148 and retrieves the matching policies from policy-engine and picks the latest on each policy.
149
150 sample request - policies filter
151
152 {
153 "configAttributes": { "key1":"value1" },
154 "configName": "alex_config_name",
Alex Shatovb9b955c2018-03-08 13:12:23 -0500155 "onapName": "DCAE",
Alex Shatov1369bea2018-01-10 11:00:50 -0500156 "policyName": "DCAE_alex.Config_alex_.*",
157 "unique": false
158 }
159
160 sample response
161
162 {
163 "DCAE_alex.Config_alex_priority": {
164 "policy_body": {
165 "policyName": "DCAE_alex.Config_alex_priority.3.xml",
166 "policyConfigMessage": "Config Retrieved! ",
167 "responseAttributes": {},
168 "policyConfigStatus": "CONFIG_RETRIEVED",
169 "type": "JSON",
170 "matchingConditions": {
171 "priority": "10",
172 "key1": "value1",
Alex Shatovb9b955c2018-03-08 13:12:23 -0500173 "ONAPName": "DCAE",
Alex Shatov1369bea2018-01-10 11:00:50 -0500174 "ConfigName": "alex_config_name"
175 },
176 "property": null,
177 "config": {
178 "foo": "bar",
Alex Shatov2322ef82018-01-25 17:40:39 -0500179 "foo_updated": "2018-10-06T16:54:31.696Z"
Alex Shatov1369bea2018-01-10 11:00:50 -0500180 },
181 "policyVersion": "3"
182 },
183 "policy_id": "DCAE_alex.Config_alex_priority"
184 }
185 }
186 """
Alex Shatov9a4d3c52019-04-01 11:32:06 -0400187 if Config.is_pdp_api_default():
188 raise cherrypy.HTTPError(404, "temporarily unsupported due to the new pdp API")
189
Alex Shatov1369bea2018-01-10 11:00:50 -0500190 if cherrypy.request.method == "GET":
191 return self._get_all_policies_latest()
192
193 if cherrypy.request.method != "POST":
194 raise cherrypy.HTTPError(404, "unexpected method {0}".format(cherrypy.request.method))
195
196 policy_filter = cherrypy.request.json or {}
197 str_policy_filter = json.dumps(policy_filter)
198
199 req_info = _PolicyWeb._get_request_info(cherrypy.request)
Alex Shatov50bed532018-04-27 11:53:55 -0400200 audit = Audit(job_name="get_latest_policies",
Alex Shatova39f4e82018-12-05 15:23:50 -0500201 req_message="{0}: {1}".format(req_info, str_policy_filter),
202 headers=cherrypy.request.headers)
203 PolicyWeb.logger.info("%s: policy_filter=%s headers=%s",
204 req_info, str_policy_filter, json.dumps(cherrypy.request.headers))
Alex Shatov1369bea2018-01-10 11:00:50 -0500205
Alex Shatov9a4d3c52019-04-01 11:32:06 -0400206 result = pdp_client.PolicyRest.get_latest_policies(audit, policy_filter=policy_filter) or {}
Alex Shatova39f4e82018-12-05 15:23:50 -0500207 result_str = json.dumps(result, sort_keys=True)
Alex Shatov1369bea2018-01-10 11:00:50 -0500208
Alex Shatova39f4e82018-12-05 15:23:50 -0500209 PolicyWeb.logger.info("result %s: policy_filter=%s result=%s",
210 req_info, str_policy_filter, result_str)
Alex Shatov1369bea2018-01-10 11:00:50 -0500211
Alex Shatova39f4e82018-12-05 15:23:50 -0500212 _, http_status_code, _ = audit.audit_done(result=result_str)
213 if http_status_code == AuditHttpCode.DATA_NOT_FOUND_OK.value:
214 http_status_code = PolicyWeb.DATA_NOT_FOUND_ERROR
215 cherrypy.response.status = http_status_code
Alex Shatov2322ef82018-01-25 17:40:39 -0500216
Alex Shatovac779d32018-02-01 14:16:56 -0500217 return result
Alex Shatov1369bea2018-01-10 11:00:50 -0500218
219 @cherrypy.expose
220 @cherrypy.tools.json_out()
221 def catch_up(self):
222 """catch up with all DCAE policies"""
Alex Shatovf2d7bef2018-05-10 09:23:16 -0400223 started = str(datetime.utcnow())
Alex Shatov1369bea2018-01-10 11:00:50 -0500224 req_info = _PolicyWeb._get_request_info(cherrypy.request)
Alex Shatov50bed532018-04-27 11:53:55 -0400225 audit = Audit(job_name="catch_up", req_message=req_info, headers=cherrypy.request.headers)
Alex Shatov1369bea2018-01-10 11:00:50 -0500226
227 PolicyWeb.logger.info("%s", req_info)
228 PolicyReceiver.catch_up(audit)
229
Alex Shatovebc1a062019-01-31 16:07:48 -0500230 res = {"catch-up requested": started, "request_id": audit.request_id}
231 PolicyWeb.logger.info("requested %s: %s", req_info, json.dumps(res))
232 audit.info_requested(started)
233 return res
234
235 @cherrypy.expose
236 @cherrypy.tools.json_out()
237 def reconfigure(self):
238 """schedule reconfigure"""
239 started = str(datetime.utcnow())
240 req_info = _PolicyWeb._get_request_info(cherrypy.request)
241 audit = Audit(job_name="reconfigure", req_message=req_info,
242 headers=cherrypy.request.headers)
243
244 PolicyWeb.logger.info("%s", req_info)
245 PolicyReceiver.reconfigure(audit)
246
247 res = {"reconfigure requested": started, "request_id": audit.request_id}
Alex Shatov1369bea2018-01-10 11:00:50 -0500248 PolicyWeb.logger.info("requested %s: %s", req_info, json.dumps(res))
249 audit.info_requested(started)
250 return res
251
252 @cherrypy.expose
253 def shutdown(self):
254 """Shutdown the policy-handler"""
255 req_info = _PolicyWeb._get_request_info(cherrypy.request)
Alex Shatov50bed532018-04-27 11:53:55 -0400256 audit = Audit(job_name="shutdown", req_message=req_info, headers=cherrypy.request.headers)
Alex Shatov1369bea2018-01-10 11:00:50 -0500257
258 PolicyWeb.logger.info("%s: --- stopping REST API of policy-handler ---", req_info)
259
alex_sh9d980ce2017-08-23 17:30:56 -0400260 cherrypy.engine.exit()
Alex Shatov1369bea2018-01-10 11:00:50 -0500261
262 PolicyReceiver.shutdown(audit)
263
Alex Shatovf2d7bef2018-05-10 09:23:16 -0400264 PolicyWeb.logger.info("policy_handler health: {0}"
265 .format(json.dumps(audit.health(full=True))))
Alex Shatov1369bea2018-01-10 11:00:50 -0500266 PolicyWeb.logger.info("%s: --------- the end -----------", req_info)
Alex Shatovf2d7bef2018-05-10 09:23:16 -0400267 res = str(datetime.utcnow())
alex_sh9d980ce2017-08-23 17:30:56 -0400268 audit.info_requested(res)
Alex Shatov51052582018-05-18 15:13:40 -0400269 PolicyWeb.logger.info("process_info: %s", json.dumps(audit.process_info()))
alex_sh9d980ce2017-08-23 17:30:56 -0400270 return "goodbye! shutdown requested {0}".format(res)
271
alex_sh9d980ce2017-08-23 17:30:56 -0400272 @cherrypy.expose
273 @cherrypy.tools.json_out()
Alex Shatov1369bea2018-01-10 11:00:50 -0500274 def healthcheck(self):
275 """returns the healthcheck results"""
276 req_info = _PolicyWeb._get_request_info(cherrypy.request)
Alex Shatov50bed532018-04-27 11:53:55 -0400277 audit = Audit(job_name="healthcheck",
278 req_message=req_info, headers=cherrypy.request.headers)
Alex Shatov1369bea2018-01-10 11:00:50 -0500279
280 PolicyWeb.logger.info("%s", req_info)
281
Alex Shatovf2d7bef2018-05-10 09:23:16 -0400282 res = audit.health()
Alex Shatov1369bea2018-01-10 11:00:50 -0500283
284 PolicyWeb.logger.info("healthcheck %s: res=%s", req_info, json.dumps(res))
285
alex_sh9d980ce2017-08-23 17:30:56 -0400286 audit.audit_done(result=json.dumps(res))
287 return res