aboutsummaryrefslogtreecommitdiffstats
path: root/policyhandler
diff options
context:
space:
mode:
authorAlex Shatov <alexs@att.com>2018-03-08 13:12:23 -0500
committerAlex Shatov <alexs@att.com>2018-03-08 13:12:23 -0500
commitb9b955c0c2875effc1ce02d5576f0d2a59284c5d (patch)
treec073f6678be20cc4371bd1e91ca2796a6abf330d /policyhandler
parentdfd79f0cb9f8d418871b5fb7f3616554c3261800 (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.py9
-rw-r--r--policyhandler/customize/__init__.py32
-rw-r--r--policyhandler/customize/customizer.py35
-rw-r--r--policyhandler/customize/customizer_base.py62
-rw-r--r--policyhandler/deploy_handler.py39
-rw-r--r--policyhandler/discovery.py43
-rw-r--r--policyhandler/web_server.py4
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,