diff options
author | 2018-03-08 13:12:23 -0500 | |
---|---|---|
committer | 2018-03-08 13:12:23 -0500 | |
commit | b9b955c0c2875effc1ce02d5576f0d2a59284c5d (patch) | |
tree | c073f6678be20cc4371bd1e91ca2796a6abf330d /policyhandler | |
parent | dfd79f0cb9f8d418871b5fb7f3616554c3261800 (diff) |
2.2.0 policy-handler - customization per company
- added etc_customize/ folder and customize.sh script
= customize.sh script is expected to be overridden by company
to customize Docker image build
= the whole etc_customize/ folder is copied into docker image
= it is up to the company what to put into that folder - any files
- added customize/ folder with CustomizeBase and Customize classes
= CustomizeBase defines the interface and the default=ONAP behavior
= CustomizeBase is owned by ONAP and should not be changed
by the company
= Customize inherits CustomizeBase
= policy-handler instantiates Customize
to get the customized behavior
= Customize is owned by the company and should be changed
by the company = ONAP is not going to change Customize
= the methods of Customize are expected to be overridden
by the company to change the behavior of the policy-handler
= sample Customize class can be found in README.md
= Company is allowed to add more files to customize/ folder
if that is required for better structuring of their code
as soon as it is invoked by the methods of Customize
Change-Id: I46f8170afaaa48e1005e4398a768a781db0a0e6c
Signed-off-by: Alex Shatov <alexs@att.com>
Issue-ID: DCAEGEN2-379
Diffstat (limited to 'policyhandler')
-rw-r--r-- | policyhandler/config.py | 9 | ||||
-rw-r--r-- | policyhandler/customize/__init__.py | 32 | ||||
-rw-r--r-- | policyhandler/customize/customizer.py | 35 | ||||
-rw-r--r-- | policyhandler/customize/customizer_base.py | 62 | ||||
-rw-r--r-- | policyhandler/deploy_handler.py | 39 | ||||
-rw-r--r-- | policyhandler/discovery.py | 43 | ||||
-rw-r--r-- | policyhandler/web_server.py | 4 |
7 files changed, 190 insertions, 34 deletions
diff --git a/policyhandler/config.py b/policyhandler/config.py index d7768fa..8a8f418 100644 --- a/policyhandler/config.py +++ b/policyhandler/config.py @@ -18,11 +18,11 @@ """read and use the config""" -import os -import json import copy +import json import logging import logging.config +import os from .discovery import DiscoveryClient @@ -78,7 +78,7 @@ class Config(object): discovery_key, json.dumps(new_config)) Config._logger.debug("config before merge from discovery: %s", json.dumps(Config.config)) Config.merge(new_config.get(Config.SERVICE_NAME_POLICY_HANDLER)) - Config._logger.debug("merged config from discovery: %s", json.dumps(Config.config)) + Config._logger.info("merged config from discovery: %s", json.dumps(Config.config)) @staticmethod def load_from_file(file_path=None): @@ -92,7 +92,7 @@ class Config(object): loaded_config = json.load(config_json) if not loaded_config: - Config._logger.info("config not loaded from file: %s", file_path) + Config._logger.warn("config not loaded from file: %s", file_path) return Config._logger.info("config loaded from file: %s", file_path) @@ -102,4 +102,5 @@ class Config(object): Config.wservice_port = loaded_config.get(Config.FIELD_WSERVICE_PORT, Config.wservice_port) Config.merge(loaded_config.get(Config.SERVICE_NAME_POLICY_HANDLER)) + Config._logger.info("config loaded from file: %s", json.dumps(Config.config)) return True diff --git a/policyhandler/customize/__init__.py b/policyhandler/customize/__init__.py new file mode 100644 index 0000000..7449528 --- /dev/null +++ b/policyhandler/customize/__init__.py @@ -0,0 +1,32 @@ +# ================================================================================ +# Copyright (c) 2018 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========================================================= +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. + +"""polymorphic customizer changes the behavior of predefined methods in policy-handler""" + +from .customizer import Customizer + +class CustomizerUser(object): + """unprotected singleton around Customizer""" + _customizer = None + + @staticmethod + def get_customizer(): + """get instance of customizer""" + if not CustomizerUser._customizer: + CustomizerUser._customizer = Customizer() + return CustomizerUser._customizer diff --git a/policyhandler/customize/customizer.py b/policyhandler/customize/customizer.py new file mode 100644 index 0000000..22bf60e --- /dev/null +++ b/policyhandler/customize/customizer.py @@ -0,0 +1,35 @@ +# ================================================================================ +# Copyright (c) 2018 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========================================================= +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. + +"""contains the Customizer class with method overrides per company specification""" + +from .customizer_base import CustomizerBase + +class Customizer(CustomizerBase): + """ + the Customizer class inherits CustomizerBase that is owned by ONAP + + :Customizer: class is owned by the company that needs to customize the policy-handler + + :override: any method defined in the CustomizerBase class to customize the behavior of the policy-handler + + see README.md for the sample of the customizer.py + """ + def __init__(self): + """class that contains the customization""" + super(Customizer, self).__init__() diff --git a/policyhandler/customize/customizer_base.py b/policyhandler/customize/customizer_base.py new file mode 100644 index 0000000..97e1550 --- /dev/null +++ b/policyhandler/customize/customizer_base.py @@ -0,0 +1,62 @@ +# ================================================================================ +# Copyright (c) 2018 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========================================================= +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. + +""" +contains the base class :CustomizerBase: +that defines the signatures and default behavior of the methods called by the policy-handler + +the methods are expected to be overriden by the child class Cutomizer that is company specific + +:do NOT change: this class and/or this file - it is owned by ONAP +""" + +import logging + +class CustomizerBase(object): + """ + base class for Customizer class + + do NOT change this class and/or this file - it is owned by ONAP + + policy-hanlder is using the instance of the child Customizer class to get the overriden methods + + the methods defined in this class are the placeholders and are expected to be overriden by the Customizer class + """ + + def __init__(self): + """base class for customization contains the default methods""" + self._logger = logging.getLogger("policy_handler.customizer") + self._logger.info("created customizer") + + def get_service_url(self, audit, service_name, service): + """returns the service url when called from DiscoveryClient""" + service_url = "http://{0}:{1}".format( + service.get("ServiceAddress", ""), service.get("ServicePort", "")) + + info = "no customization for service_url: {0} on {1}".format(service_url, service_name) + self._logger.info(info) + audit.info(info) + return service_url + + def get_deploy_handler_kwargs(self, audit): + """returns the optional dict-kwargs for requests.post to deploy_handler""" + info = "no optional kwargs for requests.post to deploy_handler" + self._logger.info(info) + audit.info(info) + kwargs = {} + return kwargs diff --git a/policyhandler/deploy_handler.py b/policyhandler/deploy_handler.py index 5792631..0950dfd 100644 --- a/policyhandler/deploy_handler.py +++ b/policyhandler/deploy_handler.py @@ -18,13 +18,15 @@ """ send notification to deploy-handler""" -import logging import json +import logging + import requests from .config import Config from .discovery import DiscoveryClient from .onap.audit import REQUEST_X_ECOMP_REQUESTID, Audit, AuditHttpCode +from .customize import CustomizerUser POOL_SIZE = 1 @@ -38,14 +40,21 @@ class DeployHandler(object): _url = None _url_path = None _target_entity = None + _custom_kwargs = None @staticmethod - def _lazy_init(): + def _lazy_init(audit): """ set static properties """ if DeployHandler._lazy_inited: return DeployHandler._lazy_inited = True + DeployHandler._custom_kwargs = CustomizerUser.get_customizer() \ + .get_deploy_handler_kwargs(audit) + if not DeployHandler._custom_kwargs \ + or not isinstance(DeployHandler._custom_kwargs, dict): + DeployHandler._custom_kwargs = {} + DeployHandler._requests_session = requests.Session() DeployHandler._requests_session.mount( 'https://', @@ -56,8 +65,8 @@ class DeployHandler(object): requests.adapters.HTTPAdapter(pool_connections=POOL_SIZE, pool_maxsize=POOL_SIZE) ) - DeployHandler._target_entity = Config.config["deploy_handler"] - DeployHandler._url = DiscoveryClient.get_service_url(DeployHandler._target_entity) + DeployHandler._target_entity = Config.config.get("deploy_handler", "deploy_handler") + DeployHandler._url = DiscoveryClient.get_service_url(audit, DeployHandler._target_entity) DeployHandler._url_path = (DeployHandler._url or "") + '/policy' DeployHandler._logger.info("DeployHandler url(%s)", DeployHandler._url) @@ -67,7 +76,7 @@ class DeployHandler(object): if not message: return - DeployHandler._lazy_init() + DeployHandler._lazy_init(audit) sub_aud = Audit(aud_parent=audit, targetEntity=DeployHandler._target_entity, targetServiceName=DeployHandler._url_path) headers = {REQUEST_X_ECOMP_REQUESTID : sub_aud.request_id} @@ -75,10 +84,10 @@ class DeployHandler(object): msg_str = json.dumps(message) headers_str = json.dumps(headers) - DeployHandler._logger.info("message: %s", msg_str) - log_line = "post to deployment-handler {0} msg={1} headers={2}".format( - DeployHandler._url_path, msg_str, headers_str) - + log_action = "post to {0} at {1}".format( + DeployHandler._target_entity, DeployHandler._url_path) + log_data = " msg={0} headers={1}".format(msg_str, headers_str) + log_line = log_action + log_data DeployHandler._logger.info(log_line) sub_aud.metrics_start(log_line) @@ -93,11 +102,11 @@ class DeployHandler(object): res = None try: res = DeployHandler._requests_session.post( - DeployHandler._url_path, json=message, headers=headers + DeployHandler._url_path, json=message, headers=headers, + **DeployHandler._custom_kwargs ) except requests.exceptions.RequestException as ex: - error_msg = "failed to post to deployment-handler {0} {1} msg={2} headers={3}" \ - .format(DeployHandler._url_path, str(ex), msg_str, headers_str) + error_msg = "failed to {0}: {1}{2}".format(log_action, str(ex), log_data) DeployHandler._logger.exception(error_msg) sub_aud.set_http_status_code(AuditHttpCode.SERVICE_UNAVAILABLE_ERROR.value) audit.set_http_status_code(AuditHttpCode.SERVICE_UNAVAILABLE_ERROR.value) @@ -107,10 +116,8 @@ class DeployHandler(object): sub_aud.set_http_status_code(res.status_code) audit.set_http_status_code(res.status_code) - sub_aud.metrics( - "response from deployment-handler to post {0}: {1} msg={2} text={3} headers={4}" \ - .format(DeployHandler._url_path, res.status_code, msg_str, res.text, - res.request.headers)) + sub_aud.metrics("response {0} from {1}: text={2}{3}" \ + .format(res.status_code, log_action, res.text, log_data)) if res.status_code == requests.codes.ok: return res.json() diff --git a/policyhandler/discovery.py b/policyhandler/discovery.py index a7e3c56..ce24c3d 100644 --- a/policyhandler/discovery.py +++ b/policyhandler/discovery.py @@ -18,11 +18,14 @@ """client to talk to consul at the standard port 8500""" -import logging -import json import base64 +import json +import logging + import requests +from .customize import CustomizerUser + class DiscoveryClient(object): """talking to consul at http://consul:8500 @@ -39,27 +42,43 @@ class DiscoveryClient(object): """ CONSUL_SERVICE_MASK = "http://consul:8500/v1/catalog/service/{0}" CONSUL_KV_MASK = "http://consul:8500/v1/kv/{0}" - SERVICE_MASK = "http://{0}:{1}" - SERVICE_ADDRESS = "ServiceAddress" - SERVICE_PORT = "ServicePort" _logger = logging.getLogger("policy_handler.discovery") - @staticmethod - def get_service_url(service_name): + def get_service_url(audit, service_name): """find the service record in consul""" service_path = DiscoveryClient.CONSUL_SERVICE_MASK.format(service_name) - DiscoveryClient._logger.info("discover %s", service_path) + log_line = "discover {0}".format(service_path) + DiscoveryClient._logger.info(log_line) + audit.info(log_line) response = requests.get(service_path) + + log_line = "response {0} for {1}: {2}".format( + response.status_code, service_path, response.text) + DiscoveryClient._logger.info(log_line) + audit.info(log_line) + response.raise_for_status() + service = response.json() if not service: - DiscoveryClient._logger.error("failed discover %s", service_path) + log_line = "failed discover {0}".format(service_path) + DiscoveryClient._logger.error(log_line) + audit.error(log_line) return service = service[0] - return DiscoveryClient.SERVICE_MASK.format( - service[DiscoveryClient.SERVICE_ADDRESS], service[DiscoveryClient.SERVICE_PORT] - ) + + service_url = CustomizerUser.get_customizer().get_service_url(audit, service_name, service) + if not service_url: + log_line = "failed to get service_url for {0}".format(service_name) + DiscoveryClient._logger.error(log_line) + audit.error(log_line) + return + + log_line = "got service_url: {0} for {1}".format(service_url, service_name) + DiscoveryClient._logger.info(log_line) + audit.info(log_line) + return service_url @staticmethod def get_value(key): diff --git a/policyhandler/web_server.py b/policyhandler/web_server.py index 8efb51d..20e74e3 100644 --- a/policyhandler/web_server.py +++ b/policyhandler/web_server.py @@ -104,7 +104,7 @@ class _PolicyWeb(object): { "configAttributes": { "key1":"value1" }, "configName": "alex_config_name", - "ecompName": "DCAE", + "onapName": "DCAE", "policyName": "DCAE_alex.Config_alex_.*", "unique": false } @@ -122,7 +122,7 @@ class _PolicyWeb(object): "matchingConditions": { "priority": "10", "key1": "value1", - "ECOMPName": "DCAE", + "ONAPName": "DCAE", "ConfigName": "alex_config_name" }, "property": null, |