blob: dc76353c8a792b9807c0311ef6677fbaf2bad110 [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#
17# ECOMP is a trademark and service mark of AT&T Intellectual Property.
18
Alex Shatovd7f34d42018-08-07 12:11:35 -040019"""web-server for policy_handler"""
Alex Shatovf53e5e72018-01-11 11:15:56 -050020
alex_sh9d980ce2017-08-23 17:30:56 -040021import json
Alex Shatovd7f34d42018-08-07 12:11:35 -040022import logging
alex_sh9d980ce2017-08-23 17:30:56 -040023from datetime import datetime
Alex Shatovd7f34d42018-08-07 12:11:35 -040024
alex_sh9d980ce2017-08-23 17:30:56 -040025import cherrypy
26
27from .config import Config
Alex Shatovd7f34d42018-08-07 12:11:35 -040028from .deploy_handler import PolicyUpdateMessage
Alex Shatova39f4e82018-12-05 15:23:50 -050029from .onap.audit import Audit, AuditHttpCode
Alex Shatovd7f34d42018-08-07 12:11:35 -040030from .policy_matcher import PolicyMatcher
Alex Shatov1369bea2018-01-10 11:00:50 -050031from .policy_receiver import PolicyReceiver
Alex Shatovd7f34d42018-08-07 12:11:35 -040032from .policy_rest import PolicyRest
33
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 Shatov1369bea2018-01-10 11:00:50 -050039 logger = logging.getLogger("policy_handler.policy_web")
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 = ""
49 # if Config.tls_server_cert_file and Config.tls_private_key_file:
50 # cherrypy.server.ssl_module = 'builtin'
51 # cherrypy.server.ssl_certificate = Config.tls_server_cert_file
52 # cherrypy.server.ssl_private_key = Config.tls_private_key_file
53 # if Config.tls_server_ca_chain_file:
54 # cherrypy.server.ssl_certificate_chain = Config.tls_server_ca_chain_file
55 # protocol = "https"
56 # tls_info = "cert: {} {} {}".format(Config.tls_server_cert_file,
57 # Config.tls_private_key_file,
58 # Config.tls_server_ca_chain_file)
59
Alex Shatov1369bea2018-01-10 11:00:50 -050060 cherrypy.tree.mount(_PolicyWeb(), '/')
Alex Shatova39f4e82018-12-05 15:23:50 -050061
62 PolicyWeb.logger.info(
63 "%s with config: %s", audit.info("running policy_handler as {}://{}:{} {}".format(
64 protocol, cherrypy.server.socket_host, cherrypy.server.socket_port, tls_info)),
65 json.dumps(cherrypy.config))
Alex Shatov1369bea2018-01-10 11:00:50 -050066 cherrypy.engine.start()
alex_sh9d980ce2017-08-23 17:30:56 -040067
Alex Shatov1369bea2018-01-10 11:00:50 -050068class _PolicyWeb(object):
69 """REST API of policy-handler"""
70
71 @staticmethod
72 def _get_request_info(request):
73 """returns info about the http request"""
74 return "{0} {1}{2}".format(request.method, request.script_name, request.path_info)
75
alex_sh9d980ce2017-08-23 17:30:56 -040076 @cherrypy.expose
Alex Shatov1369bea2018-01-10 11:00:50 -050077 @cherrypy.popargs('policy_id')
78 @cherrypy.tools.json_out()
79 def policy_latest(self, policy_id):
80 """retireves the latest policy identified by policy_id"""
81 req_info = _PolicyWeb._get_request_info(cherrypy.request)
Alex Shatov50bed532018-04-27 11:53:55 -040082 audit = Audit(job_name="get_latest_policy",
83 req_message=req_info, headers=cherrypy.request.headers)
Alex Shatova39f4e82018-12-05 15:23:50 -050084 PolicyWeb.logger.info("%s policy_id=%s headers=%s",
85 req_info, policy_id, json.dumps(cherrypy.request.headers))
Alex Shatov1369bea2018-01-10 11:00:50 -050086
Alex Shatov2322ef82018-01-25 17:40:39 -050087 latest_policy = PolicyRest.get_latest_policy((audit, policy_id, None, None)) or {}
Alex Shatov1369bea2018-01-10 11:00:50 -050088
Alex Shatov2322ef82018-01-25 17:40:39 -050089 PolicyWeb.logger.info("res %s policy_id=%s latest_policy=%s",
90 req_info, policy_id, json.dumps(latest_policy))
Alex Shatov1369bea2018-01-10 11:00:50 -050091
Alex Shatova39f4e82018-12-05 15:23:50 -050092 _, http_status_code, _ = audit.audit_done(result=json.dumps(latest_policy))
93 if http_status_code == AuditHttpCode.DATA_NOT_FOUND_OK.value:
94 http_status_code = PolicyWeb.DATA_NOT_FOUND_ERROR
95 cherrypy.response.status = http_status_code
Alex Shatov2322ef82018-01-25 17:40:39 -050096
97 return latest_policy
Alex Shatov1369bea2018-01-10 11:00:50 -050098
99 def _get_all_policies_latest(self):
100 """retireves all the latest policies on GET /policies_latest"""
101 req_info = _PolicyWeb._get_request_info(cherrypy.request)
Alex Shatov50bed532018-04-27 11:53:55 -0400102 audit = Audit(job_name="get_all_policies_latest",
103 req_message=req_info, headers=cherrypy.request.headers)
Alex Shatov1369bea2018-01-10 11:00:50 -0500104
105 PolicyWeb.logger.info("%s", req_info)
106
Alex Shatova39f4e82018-12-05 15:23:50 -0500107 result, policies, policy_filters = PolicyMatcher.get_deployed_policies(audit)
108 if not result:
109 result, policy_update = PolicyMatcher.build_catch_up_message(
110 audit, policies, policy_filters)
111 if policy_update and isinstance(policy_update, PolicyUpdateMessage):
112 result["policy_update"] = policy_update.get_message()
Alex Shatov1369bea2018-01-10 11:00:50 -0500113
Alex Shatova39f4e82018-12-05 15:23:50 -0500114 result_str = json.dumps(result, sort_keys=True)
115 PolicyWeb.logger.info("result %s: %s", req_info, result_str)
Alex Shatov1369bea2018-01-10 11:00:50 -0500116
Alex Shatova39f4e82018-12-05 15:23:50 -0500117 _, http_status_code, _ = audit.audit_done(result=result_str)
118 if http_status_code == AuditHttpCode.DATA_NOT_FOUND_OK.value:
119 http_status_code = PolicyWeb.DATA_NOT_FOUND_ERROR
120 cherrypy.response.status = http_status_code
Alex Shatov2322ef82018-01-25 17:40:39 -0500121
Alex Shatovac779d32018-02-01 14:16:56 -0500122 return result
Alex Shatov1369bea2018-01-10 11:00:50 -0500123
124 @cherrypy.expose
125 @cherrypy.tools.json_out()
126 @cherrypy.tools.json_in()
127 def policies_latest(self):
128 """
Alex Shatovd7f34d42018-08-07 12:11:35 -0400129 on :GET: retrieves all the latest policies from policy-engine that are deployed
Alex Shatov1369bea2018-01-10 11:00:50 -0500130
131 on :POST: expects to receive the params that mimic the /getConfig of policy-engine
132 and retrieves the matching policies from policy-engine and picks the latest on each policy.
133
134 sample request - policies filter
135
136 {
137 "configAttributes": { "key1":"value1" },
138 "configName": "alex_config_name",
Alex Shatovb9b955c2018-03-08 13:12:23 -0500139 "onapName": "DCAE",
Alex Shatov1369bea2018-01-10 11:00:50 -0500140 "policyName": "DCAE_alex.Config_alex_.*",
141 "unique": false
142 }
143
144 sample response
145
146 {
147 "DCAE_alex.Config_alex_priority": {
148 "policy_body": {
149 "policyName": "DCAE_alex.Config_alex_priority.3.xml",
150 "policyConfigMessage": "Config Retrieved! ",
151 "responseAttributes": {},
152 "policyConfigStatus": "CONFIG_RETRIEVED",
153 "type": "JSON",
154 "matchingConditions": {
155 "priority": "10",
156 "key1": "value1",
Alex Shatovb9b955c2018-03-08 13:12:23 -0500157 "ONAPName": "DCAE",
Alex Shatov1369bea2018-01-10 11:00:50 -0500158 "ConfigName": "alex_config_name"
159 },
160 "property": null,
161 "config": {
162 "foo": "bar",
Alex Shatov2322ef82018-01-25 17:40:39 -0500163 "foo_updated": "2018-10-06T16:54:31.696Z"
Alex Shatov1369bea2018-01-10 11:00:50 -0500164 },
165 "policyVersion": "3"
166 },
167 "policy_id": "DCAE_alex.Config_alex_priority"
168 }
169 }
170 """
171 if cherrypy.request.method == "GET":
172 return self._get_all_policies_latest()
173
174 if cherrypy.request.method != "POST":
175 raise cherrypy.HTTPError(404, "unexpected method {0}".format(cherrypy.request.method))
176
177 policy_filter = cherrypy.request.json or {}
178 str_policy_filter = json.dumps(policy_filter)
179
180 req_info = _PolicyWeb._get_request_info(cherrypy.request)
Alex Shatov50bed532018-04-27 11:53:55 -0400181 audit = Audit(job_name="get_latest_policies",
Alex Shatova39f4e82018-12-05 15:23:50 -0500182 req_message="{0}: {1}".format(req_info, str_policy_filter),
183 headers=cherrypy.request.headers)
184 PolicyWeb.logger.info("%s: policy_filter=%s headers=%s",
185 req_info, str_policy_filter, json.dumps(cherrypy.request.headers))
Alex Shatov1369bea2018-01-10 11:00:50 -0500186
Alex Shatovac779d32018-02-01 14:16:56 -0500187 result = PolicyRest.get_latest_policies(audit, policy_filter=policy_filter) or {}
Alex Shatova39f4e82018-12-05 15:23:50 -0500188 result_str = json.dumps(result, sort_keys=True)
Alex Shatov1369bea2018-01-10 11:00:50 -0500189
Alex Shatova39f4e82018-12-05 15:23:50 -0500190 PolicyWeb.logger.info("result %s: policy_filter=%s result=%s",
191 req_info, str_policy_filter, result_str)
Alex Shatov1369bea2018-01-10 11:00:50 -0500192
Alex Shatova39f4e82018-12-05 15:23:50 -0500193 _, http_status_code, _ = audit.audit_done(result=result_str)
194 if http_status_code == AuditHttpCode.DATA_NOT_FOUND_OK.value:
195 http_status_code = PolicyWeb.DATA_NOT_FOUND_ERROR
196 cherrypy.response.status = http_status_code
Alex Shatov2322ef82018-01-25 17:40:39 -0500197
Alex Shatovac779d32018-02-01 14:16:56 -0500198 return result
Alex Shatov1369bea2018-01-10 11:00:50 -0500199
200 @cherrypy.expose
201 @cherrypy.tools.json_out()
202 def catch_up(self):
203 """catch up with all DCAE policies"""
Alex Shatovf2d7bef2018-05-10 09:23:16 -0400204 started = str(datetime.utcnow())
Alex Shatov1369bea2018-01-10 11:00:50 -0500205 req_info = _PolicyWeb._get_request_info(cherrypy.request)
Alex Shatov50bed532018-04-27 11:53:55 -0400206 audit = Audit(job_name="catch_up", req_message=req_info, headers=cherrypy.request.headers)
Alex Shatov1369bea2018-01-10 11:00:50 -0500207
208 PolicyWeb.logger.info("%s", req_info)
209 PolicyReceiver.catch_up(audit)
210
Alex Shatovebc1a062019-01-31 16:07:48 -0500211 res = {"catch-up requested": started, "request_id": audit.request_id}
212 PolicyWeb.logger.info("requested %s: %s", req_info, json.dumps(res))
213 audit.info_requested(started)
214 return res
215
216 @cherrypy.expose
217 @cherrypy.tools.json_out()
218 def reconfigure(self):
219 """schedule reconfigure"""
220 started = str(datetime.utcnow())
221 req_info = _PolicyWeb._get_request_info(cherrypy.request)
222 audit = Audit(job_name="reconfigure", req_message=req_info,
223 headers=cherrypy.request.headers)
224
225 PolicyWeb.logger.info("%s", req_info)
226 PolicyReceiver.reconfigure(audit)
227
228 res = {"reconfigure requested": started, "request_id": audit.request_id}
Alex Shatov1369bea2018-01-10 11:00:50 -0500229 PolicyWeb.logger.info("requested %s: %s", req_info, json.dumps(res))
230 audit.info_requested(started)
231 return res
232
233 @cherrypy.expose
234 def shutdown(self):
235 """Shutdown the policy-handler"""
236 req_info = _PolicyWeb._get_request_info(cherrypy.request)
Alex Shatov50bed532018-04-27 11:53:55 -0400237 audit = Audit(job_name="shutdown", req_message=req_info, headers=cherrypy.request.headers)
Alex Shatov1369bea2018-01-10 11:00:50 -0500238
239 PolicyWeb.logger.info("%s: --- stopping REST API of policy-handler ---", req_info)
240
alex_sh9d980ce2017-08-23 17:30:56 -0400241 cherrypy.engine.exit()
Alex Shatov1369bea2018-01-10 11:00:50 -0500242
243 PolicyReceiver.shutdown(audit)
244
Alex Shatovf2d7bef2018-05-10 09:23:16 -0400245 PolicyWeb.logger.info("policy_handler health: {0}"
246 .format(json.dumps(audit.health(full=True))))
Alex Shatov1369bea2018-01-10 11:00:50 -0500247 PolicyWeb.logger.info("%s: --------- the end -----------", req_info)
Alex Shatovf2d7bef2018-05-10 09:23:16 -0400248 res = str(datetime.utcnow())
alex_sh9d980ce2017-08-23 17:30:56 -0400249 audit.info_requested(res)
Alex Shatov51052582018-05-18 15:13:40 -0400250 PolicyWeb.logger.info("process_info: %s", json.dumps(audit.process_info()))
alex_sh9d980ce2017-08-23 17:30:56 -0400251 return "goodbye! shutdown requested {0}".format(res)
252
alex_sh9d980ce2017-08-23 17:30:56 -0400253 @cherrypy.expose
254 @cherrypy.tools.json_out()
Alex Shatov1369bea2018-01-10 11:00:50 -0500255 def healthcheck(self):
256 """returns the healthcheck results"""
257 req_info = _PolicyWeb._get_request_info(cherrypy.request)
Alex Shatov50bed532018-04-27 11:53:55 -0400258 audit = Audit(job_name="healthcheck",
259 req_message=req_info, headers=cherrypy.request.headers)
Alex Shatov1369bea2018-01-10 11:00:50 -0500260
261 PolicyWeb.logger.info("%s", req_info)
262
Alex Shatovf2d7bef2018-05-10 09:23:16 -0400263 res = audit.health()
Alex Shatov1369bea2018-01-10 11:00:50 -0500264
265 PolicyWeb.logger.info("healthcheck %s: res=%s", req_info, json.dumps(res))
266
alex_sh9d980ce2017-08-23 17:30:56 -0400267 audit.audit_done(result=json.dumps(res))
268 return res