summaryrefslogtreecommitdiffstats
path: root/oti/event-handler/otihandler/web_server.py
diff options
context:
space:
mode:
Diffstat (limited to 'oti/event-handler/otihandler/web_server.py')
-rw-r--r--oti/event-handler/otihandler/web_server.py605
1 files changed, 0 insertions, 605 deletions
diff --git a/oti/event-handler/otihandler/web_server.py b/oti/event-handler/otihandler/web_server.py
deleted file mode 100644
index 45c407f..0000000
--- a/oti/event-handler/otihandler/web_server.py
+++ /dev/null
@@ -1,605 +0,0 @@
-# ================================================================================
-# Copyright (c) 2019-2020 AT&T Intellectual Property. All rights reserved.
-# ================================================================================
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# ============LICENSE_END=========================================================
-
-"""web-service for oti_handler"""
-
-import json
-import logging
-import os
-import time
-from datetime import datetime
-
-import cherrypy
-
-from otihandler.cbs_rest import CBSRest
-from otihandler.config import Config
-from otihandler.dti_processor import DTIProcessor
-from otihandler.onap.audit import Audit
-
-
-class DTIWeb(object):
- """run REST API of OTI Handler"""
-
- logger = logging.getLogger("oti_handler.web_server")
- HOST_INADDR_ANY = ".".join("0"*4)
-
- @staticmethod
- def run_forever(audit):
- """run the web-server of OTI Handler forever"""
-
- cherrypy.config.update({"server.socket_host": DTIWeb.HOST_INADDR_ANY,
- "server.socket_port": Config.wservice_port})
-
- protocol = "http"
- tls_info = ""
- if Config.tls_server_cert_file and Config.tls_private_key_file:
- tm_cert = os.path.getmtime(Config.tls_server_cert_file)
- tm_key = os.path.getmtime(Config.tls_private_key_file)
- #cherrypy.server.ssl_module = 'builtin'
- cherrypy.server.ssl_module = 'pyOpenSSL'
- cherrypy.server.ssl_certificate = Config.tls_server_cert_file
- cherrypy.server.ssl_private_key = Config.tls_private_key_file
- if Config.tls_server_ca_chain_file:
- cherrypy.server.ssl_certificate_chain = Config.tls_server_ca_chain_file
- protocol = "https"
- tls_info = "cert: {} {} {}".format(Config.tls_server_cert_file,
- Config.tls_private_key_file,
- Config.tls_server_ca_chain_file)
-
- cherrypy.tree.mount(_DTIWeb(), '/')
-
- DTIWeb.logger.info(
- "%s with config: %s", audit.info("running oti_handler as {}://{}:{} {}".format(
- protocol, cherrypy.server.socket_host, cherrypy.server.socket_port, tls_info)),
- json.dumps(cherrypy.config))
- cherrypy.engine.start()
-
- # If HTTPS server certificate changes, exit to let kubernetes restart us
- if Config.tls_server_cert_file and Config.tls_private_key_file:
- while True:
- time.sleep(600)
- c_tm_cert = os.path.getmtime(Config.tls_server_cert_file)
- c_tm_key = os.path.getmtime(Config.tls_private_key_file)
- if c_tm_cert > tm_cert or c_tm_key > tm_key:
- DTIWeb.logger.info("cert or key file updated")
- cherrypy.engine.stop()
- cherrypy.engine.exit()
- break
-
-
-class _DTIWeb(object):
- """REST API of DTI Handler"""
-
- VALID_EVENT_TYPES = ['deploy', 'undeploy', 'add', 'delete', 'update', 'notify']
-
- @staticmethod
- def _get_request_info(request):
- """Returns info about the http request."""
-
- return "{} {}{}".format(request.method, request.script_name, request.path_info)
-
-
- #----- Common endpoint methods
-
- @cherrypy.expose
- @cherrypy.tools.json_out()
- def healthcheck(self):
- """Returns healthcheck results."""
-
- req_info = _DTIWeb._get_request_info(cherrypy.request)
- audit = Audit(req_message=req_info, headers=cherrypy.request.headers)
-
- DTIWeb.logger.info("%s", req_info)
-
- result = Audit.health()
-
- DTIWeb.logger.info("healthcheck %s: result=%s", req_info, json.dumps(result))
-
- audit.audit_done(result=json.dumps(result))
- return result
-
- @cherrypy.expose
- def shutdown(self):
- """Shutdown the web server."""
-
- req_info = _DTIWeb._get_request_info(cherrypy.request)
- audit = Audit(req_message=req_info, headers=cherrypy.request.headers)
-
- DTIWeb.logger.info("%s: --- stopping REST API of DTI Handler ---", req_info)
-
- cherrypy.engine.exit()
-
- health = json.dumps(Audit.health())
- audit.info("oti_handler health: {}".format(health))
- DTIWeb.logger.info("oti_handler health: %s", health)
- DTIWeb.logger.info("%s: --------- the end -----------", req_info)
- result = str(datetime.now())
- audit.info_requested(result)
- return "goodbye! shutdown requested {}".format(result)
-
- # ----- DTI Handler mock endpoint methods
- @cherrypy.expose
- @cherrypy.tools.json_out()
- @cherrypy.tools.json_in()
- def mockevents(self):
-
- result = {"KubeNamespace":"com-my-dcae-test", "KubePod":"pod-0", "KubeServiceName":"pod-0.service.local", "KubeServicePort":"8880", "KubeClusterFqdn":"fqdn-1"}
-
- return result
-
- #----- DTI Handler endpoint methods
-
- @cherrypy.expose
- @cherrypy.tools.json_out()
- @cherrypy.tools.json_in()
- def events(self, notify="y"):
- """
- Run dti reconfig script in service component instances configured to accept the DTI Event.
-
- POST /events < <dcae_event>
-
- POST /events?ndtify="n" < <dcae_event>
-
- where <dcae_event> is the entire DTI Event passed as a JSON object and contains at least these top-level keys:
- dcae_service_action : string
- required, 'deploy' or 'undeploy'
- dcae_target_name : string
- required, VNF Instance ID
- dcae_target_type : string
- required, VNF Type of the VNF Instance
- dcae_service_location : string
- optional, CLLI location. Not provided or '' infers all locations.
-
- Parameters
- ----------
- notify : string
- optional, default "y", any of these will not notify components: [ "f", "false", "False", "FALSE", "n", "no" ]
- When "n" will **not** notify components of this DTI Event update to Consul.
-
- Returns
- -------
- dict
- JSON object containing success or error of executing the dti reconfig script on
- each component instance's docker container, keyed by service_component_name.
-
- """
-
- if cherrypy.request.method != "POST":
- raise cherrypy.HTTPError(404, "unexpected method {}".format(cherrypy.request.method))
-
- msg = ""
-
- dti_event = cherrypy.request.json or {}
- str_dti_event = json.dumps(dti_event)
-
- req_info = _DTIWeb._get_request_info(cherrypy.request)
- audit = Audit(req_message="{}: {}".format(req_info, str_dti_event), \
- headers=cherrypy.request.headers)
- DTIWeb.logger.info("%s: dti_event=%s headers=%s", \
- req_info, str_dti_event, json.dumps(cherrypy.request.headers))
-
- dcae_service_action = dti_event.get('dcae_service_action')
- if not dcae_service_action:
- msg = 'dcae_service_action is missing'
- elif dcae_service_action.lower() not in self.VALID_EVENT_TYPES:
- msg = 'dcae_service_action is invalid'
-
- dcae_target_name = dti_event.get('dcae_target_name')
- if not msg and not dcae_target_name:
- msg = 'dcae_target_name is missing'
-
- dcae_target_type = dti_event.get('dcae_target_type', '')
- if not msg and not dcae_target_type:
- msg = 'dcae_target_type is missing'
-
- if msg:
- result = {"ERROR": msg}
-
- DTIWeb.logger.error("%s: dti_event=%s result=%s", \
- req_info, str_dti_event, json.dumps(result))
- else:
- send_notification = True
- if (isinstance(notify, bool) and not notify) or \
- (isinstance(notify, str) and notify.lower() in [ "f", "false", "n", "no" ]):
- send_notification = False
-
- prc = DTIProcessor(dti_event, send_notification=send_notification)
- result = prc.get_result()
-
- DTIWeb.logger.info("%s: dti_event=%s result=%s", \
- req_info, str_dti_event, json.dumps(result))
-
- success, http_status_code, _ = audit.audit_done(result=json.dumps(result))
- if msg:
- cherrypy.response.status = "400 Bad Request"
- elif not success:
- cherrypy.response.status = http_status_code
-
- return result
-
- def get_docker_events(self, request, service, location):
- """
- common routine for dti_docker_events and oti_docker_events
-
- :param request: HTTP GET request
- :param service: HTTP request query parameter for service name
- :param location: HTTP request query parameter for location CLLI
- :return:
- """
-
- if request.method != "GET":
- raise cherrypy.HTTPError(404, "unexpected method {}".format(request.method))
-
- req_info = _DTIWeb._get_request_info(request)
- audit = Audit(req_message=req_info, headers=request.headers)
-
- return DTIProcessor.get_docker_raw_events(service, location)
-
- def get_k8s_events(self, request, **params):
- """
- common routine for dti_k8s_events and oti_k8s_events
-
- :param request: HTTP GET request
- :param params: HTTP request query parameters
- :return:
- """
- if request.method != "GET":
- raise cherrypy.HTTPError(404, "unexpected method {}".format(request.method))
-
- req_info = _DTIWeb._get_request_info(request)
- audit = Audit(req_message=req_info, headers=request.headers)
-
- pod = request.params['pod']
- namespace = request.params['namespace']
- cluster = request.params['cluster']
-
- return DTIProcessor.get_k8_raw_events(pod, cluster, namespace)
-
- @cherrypy.expose
- @cherrypy.tools.json_out()
- def oti_k8s_events(self, **params):
- """
- Retrieve raw JSON events from application events database
-
- GET /oti_k8_events?pod=<sts-1>&namespace=<ns1>&cluster=<cluster1>
-
- Parameters
- ----------
- pod ID : string
- POD ID of the stateful set POD
- namespace: string
- kubernetes namespace
- cluster: string
- kubernetes cluster FQDN
-
- Returns
- -------
- dict
- JSON object containing the fully-bound configuration.
-
- """
-
- return self.get_k8s_events(cherrypy.request, params)
-
- @cherrypy.expose
- @cherrypy.tools.json_out()
- def dti_k8s_events(self, **params):
- """
- Retrieve raw JSON events from application events database
-
- GET /dti_k8_events?pod=<sts-1>&namespace=<ns1>&cluster=<cluster1>
-
- Parameters
- ----------
- pod ID : string
- POD ID of the stateful set POD
- namespace: string
- kubernetes namespace
- cluster: string
- kubernetes cluster FQDN
-
- Returns
- -------
- dict
- JSON object containing the fully-bound configuration.
-
- """
-
- return self.get_k8s_events(cherrypy.request, params)
-
- @cherrypy.expose
- @cherrypy.tools.json_out()
- def oti_docker_events(self, service, location=None):
- """
- Retrieve raw JSON events from application events database related to docker deployments
-
- GET /oti_docker_events?service=<svc>&location=<location>
-
- Parameters
- ----------
- service : string
- The service component name assigned by dockerplugin to the component
- that is unique to the cloudify node instance and used in its Consul key(s).
- location : string
- optional. allows multiple values separated by commas. Filters DTI events with dcae_service_location in service_location.
- If service_location is not provided, then defaults to dockerhost or k8s cluster master node service Consul TAGs if service_name is provided,
- otherwise results are not location filtered.
-
- Returns
- -------
- dict
- JSON object containing the fully-bound configuration.
-
- """
-
- return self.get_docker_events(cherrypy.request, service, location)
-
- @cherrypy.expose
- @cherrypy.tools.json_out()
- def dti_docker_events(self, service, location=None):
- """
- Retrieve raw JSON events from application events database related to docker deployments
-
- GET /dti_docker_events?service=<svc>&location=<location>
-
- Parameters
- ----------
- service : string
- The service component name assigned by dockerplugin to the component
- that is unique to the cloudify node instance and used in its Consul key(s).
- location : string
- optional. allows multiple values separated by commas. Filters DTI events with dcae_service_location in service_location.
- If service_location is not provided, then defaults to dockerhost or k8s cluster master node service Consul TAGs if service_name is provided,
- otherwise results are not location filtered.
-
- Returns
- -------
- dict
- JSON object containing the fully-bound configuration.
-
- """
-
- return self.get_docker_events(cherrypy.request, service, location)
-
- #----- Config Binding Service (CBS) endpoint methods
-
- @cherrypy.expose
- @cherrypy.popargs('service_name')
- @cherrypy.tools.json_out()
- def service_component(self, service_name):
- """
- Retrieve fully-bound configuration for service_name from Consul KVs.
-
- GET /service_component/<service_name>
-
- Parameters
- ----------
- service_name : string
- The service component name assigned by dockerplugin to the component
- that is unique to the cloudify node instance and used in its Consul key(s).
-
- Returns
- -------
- dict
- JSON object containing the fully-bound configuration.
-
- """
-
- if cherrypy.request.method != "GET":
- raise cherrypy.HTTPError(404, "unexpected method {}".format(cherrypy.request.method))
-
- req_info = _DTIWeb._get_request_info(cherrypy.request)
- audit = Audit(req_message=req_info, headers=cherrypy.request.headers)
- DTIWeb.logger.info("%s: service_name=%s headers=%s", \
- req_info, service_name, json.dumps(cherrypy.request.headers))
-
- try:
- result = CBSRest.get_service_component(service_name)
- except Exception as e:
- result = {"ERROR": "exception {}: {!s}".format(type(e).__name__, e)}
- audit.set_http_status_code(404)
-
- DTIWeb.logger.info("%s: service_name=%s result=%s", \
- req_info, service_name, json.dumps(result))
-
- success, http_status_code, _ = audit.audit_done(result=json.dumps(result))
- if not success:
- cherrypy.response.status = http_status_code
-
- return result
-
- @cherrypy.expose
- @cherrypy.popargs('service_name')
- @cherrypy.tools.json_out()
- def service_component_all(self, service_name, service_location=None, policy_ids="y"):
- """
- Retrieve all information for service_name (config, dti, dti_events, and policies) from Consul KVs.
-
- GET /service_component_all/<service_name>
-
- GET /service_component_all/<service_name>?service_location=<service_location>
-
- GET /service_component_all/<service_name>?service_location=<service_location>;policy_ids=n
-
- Parameters
- ----------
- service_name : string
- The service component name assigned by dockerplugin to the component
- that is unique to the cloudify node instance and used in its Consul key(s).
- service_location : string
- optional, allows multiple values separated by commas.
- Filters DTI events with dcae_service_location in service_location.
- policy_ids : string
- optional, default "y", any of these will unset: [ "f", "false", "False", "FALSE", "n", "no" ]
- When unset, formats policies items as a list (without policy_ids) rather than as an object indexed by policy_id.
-
- Returns
- -------
- dict
- JSON object containing all information for component service_name.
- The top-level keys may include the following:
- config : dict
- The cloudify node's application_config property from when the start workflow was executed.
- dti : dict
- Keys are VNF Types that the component currently is assigned to monitor. Policy can change them.
- dti_events : dict
- The latest deploy DTI events, keyed by VNF Type and sub-keyed by VNF Instance ID.
- policies : dict
- event : dict
- Contains information about when the policies folder was last written.
- items : dict
- Contains all policy bodies for the service_name component, keyed by policy_id.
-
- """
-
- if cherrypy.request.method != "GET":
- raise cherrypy.HTTPError(404, "unexpected method {}".format(cherrypy.request.method))
-
- req_info = _DTIWeb._get_request_info(cherrypy.request)
- audit = Audit(req_message=req_info, headers=cherrypy.request.headers)
- DTIWeb.logger.info("%s: service_name=%s headers=%s", \
- req_info, service_name, json.dumps(cherrypy.request.headers))
-
- policies_as_list = False
- if (isinstance(policy_ids, bool) and not policy_ids) or \
- (isinstance(policy_ids, str) and policy_ids.lower() in [ "f", "false", "n", "no" ]):
- policies_as_list = True
- try:
- result = CBSRest.get_service_component_all(service_name, service_location=service_location, policies_as_list=policies_as_list)
- except Exception as e:
- result = {"ERROR": "exception {}: {!s}".format(type(e).__name__, e)}
- audit.set_http_status_code(404)
-
- DTIWeb.logger.info("%s: service_name=%s result=%s", \
- req_info, service_name, json.dumps(result))
-
- success, http_status_code, _ = audit.audit_done(result=json.dumps(result))
- if not success:
- cherrypy.response.status = http_status_code
-
- return result
-
- @cherrypy.expose
- @cherrypy.popargs('service_name')
- @cherrypy.tools.json_out()
- def dti(self, service_name=None, vnf_type=None, vnf_id=None, service_location=None):
- """
- Retrieve current (latest, not undeployed) DTI events from Consul KVs.
-
- GET /dti/<service_name>
-
- GET /dti/<service_name>?vnf_type=<vnf_type>;vnf_id=<vnf_id>;service_location=<service_location>
-
- GET /dti
-
- GET /dti?vnf_type=<vnf_type>;vnf_id=<vnf_id>;service_location=<service_location>
-
- Parameters
- ----------
- service_name : string
- optional. The service component name assigned by dockerplugin to the component
- that is unique to the cloudify node instance and used in its Consul key(s).
- vnf_type : string
- optional, allows multiple values separated by commas. Gets DTI events for these vnf_type(s).
- vnf_id : string
- optional. Requires vnf_type also. Gets DTI event for this vnf_id.
- service_location : string
- optional, allows multiple values separated by commas.
- Filters DTI events with dcae_service_location in service_location.
-
- Returns
- -------
- dict
- Dictionary of DTI event(s).
- If one vnf_type and vnf_id are both specified, then object returned will be just the one DTI event.
- If one vnf_type is specified but not vnf_id, then DTI events will be keyed by vnf_id.
- Otherwise the DTI events will be keyed by vnf_type, sub-keyed by vnf_id.
-
- """
-
- if cherrypy.request.method != "GET":
- raise cherrypy.HTTPError(404, "unexpected method {}".format(cherrypy.request.method))
-
- req_info = _DTIWeb._get_request_info(cherrypy.request)
- audit = Audit(req_message=req_info, headers=cherrypy.request.headers)
- DTIWeb.logger.info("%s: service_name=%s headers=%s", \
- req_info, service_name, json.dumps(cherrypy.request.headers))
-
- try:
- result = CBSRest.get_oti(service_name=service_name, vnf_type=vnf_type, vnf_id=vnf_id, service_location=service_location)
- except Exception as e:
- result = {"ERROR": "exception {}: {!s}".format(type(e).__name__, e)}
- audit.set_http_status_code(404)
-
- DTIWeb.logger.info("%s: service_name=%s result=%s", \
- req_info, service_name, json.dumps(result))
-
- success, http_status_code, _ = audit.audit_done(result=json.dumps(result))
- if not success:
- cherrypy.response.status = http_status_code
-
- return result
-
- @cherrypy.expose
- @cherrypy.popargs('service_name')
- @cherrypy.tools.json_out()
- def policies(self, service_name, policy_id=None):
- """
- Retrieve policies for service_name from Consul KVs.
-
- GET /policies/<service_name>
-
- GET /policies/<service_name>?policy_id=<policy_id>
-
- Parameters
- ----------
- service_name : string
- The service component name assigned by dockerplugin to the component
- that is unique to the cloudify node instance and used in its Consul key(s).
- policy_id : string
- optional. Limits returned policy to this policy_id.
-
- Returns
- -------
- dict
- JSON object containing policy bodies for the service_name component.
- If policy_id is specified, then object returned will be just the one policy body.
- If policy_id is not specified, then object will contain all policy bodies, keyed by policy_id.
-
- """
-
- if cherrypy.request.method != "GET":
- raise cherrypy.HTTPError(404, "unexpected method {}".format(cherrypy.request.method))
-
- req_info = _DTIWeb._get_request_info(cherrypy.request)
- audit = Audit(req_message=req_info, headers=cherrypy.request.headers)
- DTIWeb.logger.info("%s: service_name=%s headers=%s", \
- req_info, service_name, json.dumps(cherrypy.request.headers))
-
- try:
- result = CBSRest.get_policies(service_name, policy_id=policy_id)
- except Exception as e:
- result = {"ERROR": "exception {}: {!s}".format(type(e).__name__, e)}
- audit.set_http_status_code(404)
-
- DTIWeb.logger.info("%s: service_name=%s result=%s", \
- req_info, service_name, json.dumps(result))
-
- success, http_status_code, _ = audit.audit_done(result=json.dumps(result))
- if not success:
- cherrypy.response.status = http_status_code
-
- return result