aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Shatov <alexs@att.com>2017-09-12 13:00:25 -0400
committerAlex Shatov <alexs@att.com>2017-09-12 13:00:25 -0400
commit42a989a6b9b6388947da6fc273728a24c19fa686 (patch)
tree9d1dfc98ddd56fe058c030f9b4b8ce117aa16717
parentfe9c74b9933745144bfd8134bc96fd77fa3291f8 (diff)
1.0.0 and policy API to deployment-handler
* policy API to deployment-handler /policy * removed pycrypto of config - the same way as other apps * simple upload of config to consul - curl * preparation for policy-handler blueprint Change-Id: I424a1ded0795562ea36b5409304cbb8b5a7e8a24 Issue-Id: DCAEGEN2-62 Signed-off-by: Alex Shatov <alexs@att.com>
-rw-r--r--etc/config.json1
-rw-r--r--etc_upload/restart_upload_config_for_ph_in_docker.sh30
-rw-r--r--etc_upload/upload_config_for_ph_in_docker.sh38
-rw-r--r--policyhandler/config.py40
-rw-r--r--policyhandler/deploy_handler.py22
-rw-r--r--policyhandler/onap/crypto.py72
-rw-r--r--policyhandler/policy_engine.py22
-rw-r--r--policyhandler/policy_handler.py25
-rw-r--r--requirements.txt1
-rw-r--r--setup.py9
-rw-r--r--start_ph_in_docker.sh14
11 files changed, 48 insertions, 226 deletions
diff --git a/etc/config.json b/etc/config.json
index 211ce16..e54569b 100644
--- a/etc/config.json
+++ b/etc/config.json
@@ -1,5 +1,4 @@
{
- "config_pwd" : "onap-secret@2017!",
"wservice_port" : 25577,
"policy_handler" : {
"system" : "policy_handler"
diff --git a/etc_upload/restart_upload_config_for_ph_in_docker.sh b/etc_upload/restart_upload_config_for_ph_in_docker.sh
deleted file mode 100644
index 5fd97a9..0000000
--- a/etc_upload/restart_upload_config_for_ph_in_docker.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash
-
-# org.onap.dcae
-# ================================================================================
-# Copyright (c) 2017 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.
-
-APPNAME=policy_handler
-docker stop ${APPNAME}
-docker rm ${APPNAME}
-docker rmi ${APPNAME}
-docker build -t ${APPNAME} .
-
-RUNSCRIPT=$(dirname $0)/upload_config_for_ph_in_docker.sh
-echo "running script ${RUNSCRIPT}"
-${RUNSCRIPT}
diff --git a/etc_upload/upload_config_for_ph_in_docker.sh b/etc_upload/upload_config_for_ph_in_docker.sh
index e37215e..1eb0364 100644
--- a/etc_upload/upload_config_for_ph_in_docker.sh
+++ b/etc_upload/upload_config_for_ph_in_docker.sh
@@ -31,39 +31,11 @@ if [[ -n ${DOCKER_HOST} ]]; then
DOCKER_HOSTNAME=${DOCKER_HOST//tcp:/}
DOCKER_HOSTNAME=${DOCKER_HOSTNAME//:*[0-9]/}
DOCKER_HOSTNAME=${DOCKER_HOSTNAME//\//}
- echo "${APPNAME} on DOCKER_HOSTNAME=${DOCKER_HOSTNAME}"
- export HOSTNAME=${DOCKER_HOSTNAME}
-
- # replace CONSUL_IP with docker-host-ip if consul-agent is local
- CONSUL_HOST=${HOSTNAME}
- CONSUL_IP=$(host ${CONSUL_HOST} | awk '/has address/ { print $4 ; exit }')
-
- echo "starting ${APPNAME} on HOSTNAME=${HOSTNAME} CONSUL_HOST=${CONSUL_HOST} CONSUL_IP=${CONSUL_IP}"
-
- docker run --name ${APPNAME} -d \
- -e HOSTNAME \
- --add-host consul:${CONSUL_IP} \
- ${APPNAME}
+ CONSUL_HOST=${DOCKER_HOSTNAME}
else
- export HOSTNAME=$(hostname --fqdn)
-
- # replace CONSUL_IP with docker-host-ip if consul-agent is local
- CONSUL_HOST=${HOSTNAME}
- CONSUL_IP=$(host ${CONSUL_HOST} | awk '/has address/ { print $4 ; exit }')
-
- echo "starting ${APPNAME} on HOSTNAME=${HOSTNAME} CONSUL_HOST=${CONSUL_HOST} CONSUL_IP=${CONSUL_IP}"
-
- BASEDIR=$(pwd)
- TARGETDIR=/opt/app/${APPNAME}
+ CONSUL_HOST=devcnsl00.dcae.sic.research.att.com
+fi
- mkdir -p ${BASEDIR}/logs
- mkdir -p ${BASEDIR}/etc_upload/logs
+echo "uploading etc_upload/config.json for ${APPNAME} to CONSUL_HOST=${CONSUL_HOST}"
- docker run --name ${APPNAME} -d \
- -e HOSTNAME \
- --add-host consul:${CONSUL_IP} \
- -v ${BASEDIR}/etc:${TARGETDIR}/etc \
- -v ${BASEDIR}/etc_upload:${TARGETDIR}/etc_upload \
- -v ${BASEDIR}/etc_upload/logs:${TARGETDIR}/logs \
- ${APPNAME}
-fi
+curl -X PUT -H 'Content-Type: application/json' --data-binary "$(cat etc_upload/config.json)" http://${CONSUL_HOST}:8500/v1/kv/${APPNAME} \ No newline at end of file
diff --git a/policyhandler/config.py b/policyhandler/config.py
index ea10167..9a4980a 100644
--- a/policyhandler/config.py
+++ b/policyhandler/config.py
@@ -26,7 +26,6 @@ import base64
import logging
from .discovery import DiscoveryClient
-from .onap.crypto import Cipher
logging.basicConfig(
filename='logs/policy_handler.log', \
@@ -38,14 +37,10 @@ class Config(object):
"""main config of the application"""
CONFIG_FILE_PATH = "etc/config.json"
LOGGER_CONFIG_FILE_PATH = "etc/common_logger.config"
- UPLOAD_CONFIG_FILE_PATH = "etc_upload/config.json"
SERVICE_NAME_POLICY_HANDLER = "policy_handler"
FIELD_SYSTEM = "system"
- FIELD_CONFIG_PWD = "config_pwd"
FIELD_WSERVICE_PORT = "wservice_port"
FIELD_POLICY_ENGINE = "policy_engine"
- CRYPTED_FIELDS = ["ClientAuth", "Authorization", "config_pwd"]
- config_pwd = "donottell150&$"
wservice_port = 25577
_logger = logging.getLogger("policy_handler.config")
config = None
@@ -64,32 +59,6 @@ class Config(object):
Config.config.update(new_config)
@staticmethod
- def decrypt_secret_value(field_name, field_value):
- """decrypt the value of the secret field"""
- if field_name in Config.CRYPTED_FIELDS and isinstance(field_value, basestring):
- return Cipher.decrypt(Config.config_pwd, field_value)
- return field_value
-
- @staticmethod
- def encrypt_secret_value(field_name, field_value):
- """encrypt the value of the secret field"""
- if field_name in Config.CRYPTED_FIELDS and isinstance(field_value, basestring):
- return Cipher.encrypt(Config.config_pwd, field_value)
- return field_value
-
- @staticmethod
- def update_tree_leaves(tree_element, func_on_leaf):
- """traverse through json tree and apply function func_on_leaf to each leaf"""
- if not tree_element:
- return
-
- for field_name in tree_element:
- field_value = func_on_leaf(field_name, tree_element[field_name])
- tree_element[field_name] = field_value
- if isinstance(field_value, dict):
- Config.update_tree_leaves(field_value, func_on_leaf)
-
- @staticmethod
def get_system_name():
"""find the name of the policy-handler system
to be used as the key in consul-kv for config of policy-handler
@@ -112,9 +81,8 @@ class Config(object):
Config._logger.debug("loaded config from discovery(%s): %s", \
discovery_key, json.dumps(new_config))
- Config.update_tree_leaves(new_config, Config.decrypt_secret_value)
Config._logger.debug("config before merge from discovery: %s", json.dumps(Config.config))
- Config.merge(new_config)
+ Config.merge(new_config.get(Config.SERVICE_NAME_POLICY_HANDLER))
Config._logger.debug("merged config from discovery: %s", json.dumps(Config.config))
@staticmethod
@@ -124,11 +92,8 @@ class Config(object):
Config._logger.error("unexpected config: %s", Config.config)
return
- latest_config = copy.deepcopy(Config.config)
- Config.update_tree_leaves(latest_config, Config.encrypt_secret_value)
-
discovery_key = Config.get_system_name()
- latest_config = json.dumps(latest_config)
+ latest_config = json.dumps({Config.SERVICE_NAME_POLICY_HANDLER:Config.config})
DiscoveryClient.put_kv(discovery_key, latest_config)
Config._logger.debug("uploaded config to discovery(%s): %s", \
discovery_key, latest_config)
@@ -153,7 +118,6 @@ class Config(object):
if logging_config:
logging.config.dictConfig(logging_config)
- Config.config_pwd = loaded_config.get(Config.FIELD_CONFIG_PWD, Config.config_pwd)
Config.wservice_port = loaded_config.get(Config.FIELD_WSERVICE_PORT, Config.wservice_port)
Config.merge(loaded_config.get(Config.SERVICE_NAME_POLICY_HANDLER))
return True
diff --git a/policyhandler/deploy_handler.py b/policyhandler/deploy_handler.py
index 02807f8..7d9c513 100644
--- a/policyhandler/deploy_handler.py
+++ b/policyhandler/deploy_handler.py
@@ -30,11 +30,10 @@ from .onap.audit import REQUEST_X_ECOMP_REQUESTID, Audit, AuditHttpCode
class DeployHandler(object):
""" deploy-handler """
_logger = logging.getLogger("policy_handler.deploy_handler")
- _policy_update = '/policy_update'
_lazy_inited = False
_config = None
_url = None
- _path = None
+ _url_path = None
_target_entity = None
@staticmethod
@@ -45,7 +44,7 @@ class DeployHandler(object):
DeployHandler._lazy_inited = True
DeployHandler._target_entity = Config.config["deploy_handler"]
DeployHandler._url = DiscoveryClient.get_service_url(DeployHandler._target_entity)
- DeployHandler._path = DeployHandler._url + DeployHandler._policy_update
+ DeployHandler._url_path = DeployHandler._url + '/policy'
DeployHandler._logger.info("DeployHandler url(%s)", DeployHandler._url)
@staticmethod
@@ -53,24 +52,24 @@ class DeployHandler(object):
""" post policy_updated message to deploy-handler """
DeployHandler._lazy_init()
msg = {"latest_policies":latest_policies}
- sub_aud = Audit(aud_parent=audit, targetEntity=DeployHandler._target_entity, \
- targetServiceName=DeployHandler._path)
+ sub_aud = Audit(aud_parent=audit, targetEntity=DeployHandler._target_entity,
+ targetServiceName=DeployHandler._url_path)
headers = {REQUEST_X_ECOMP_REQUESTID : sub_aud.request_id}
msg_str = json.dumps(msg)
headers_str = json.dumps(headers)
- log_line = "post to deployment-handler {0} msg={1} headers={2}".format(\
- DeployHandler._path, msg_str, headers_str)
+ log_line = "post to deployment-handler {0} msg={1} headers={2}".format(
+ DeployHandler._url_path, msg_str, headers_str)
sub_aud.metrics_start(log_line)
DeployHandler._logger.info(log_line)
res = None
try:
- res = requests.post(DeployHandler._path, json=msg, headers=headers)
+ res = requests.post(DeployHandler._url_path, json=msg, headers=headers)
except requests.exceptions.RequestException as ex:
error_msg = "failed to post to deployment-handler {0} {1} msg={2} headers={3}" \
- .format(DeployHandler._path, str(ex), msg_str, headers_str)
+ .format(DeployHandler._url_path, str(ex), msg_str, headers_str)
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)
@@ -80,9 +79,10 @@ class DeployHandler(object):
sub_aud.set_http_status_code(res.status_code)
audit.set_http_status_code(res.status_code)
- sub_aud.metrics( \
+ sub_aud.metrics(
"response from deployment-handler to post {0}: {1} msg={2} text={3} headers={4}" \
- .format(DeployHandler._path, res.status_code, msg_str, res.text, res.request.headers))
+ .format(DeployHandler._url_path, res.status_code, msg_str, res.text,
+ res.request.headers))
if res.status_code == requests.codes.ok:
return res.json()
diff --git a/policyhandler/onap/crypto.py b/policyhandler/onap/crypto.py
deleted file mode 100644
index e2d58db..0000000
--- a/policyhandler/onap/crypto.py
+++ /dev/null
@@ -1,72 +0,0 @@
-"""ONAP specific encryption-decryption for passwords"""
-
-# org.onap.dcae
-# ================================================================================
-# Copyright (c) 2017 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.
-
-import base64
-from Crypto.Cipher import AES
-from Crypto.Protocol.KDF import PBKDF2
-from Crypto import Random
-
-class Cipher(object):
- """class for AES-256 encryption and decryption of text using the salted password"""
- KEY_SIZE = 32 # AES-256
- KDF_ITERATIONS = 16384
- AES_MODE = AES.MODE_CFB
-
- @staticmethod
- def encrypt(password, plain_text):
- """
- encrypt the :plain_text: into :cipher_text: using the password
-
- :cipher_text: formatted as pbkdf2_salt + init_vector + encrypt(:plain_text:)
- then cipher_text is encoded as base64 to make it textable (non-binary)
-
- :pbkdf2_salt: has the fixed length of 32 (AES-256)
- :init_vector: has the fixed length of AES.block_size
- """
- pbkdf2_salt = Random.new().read(Cipher.KEY_SIZE)
- init_vector = Random.new().read(AES.block_size)
- derived_key = PBKDF2(password, pbkdf2_salt, Cipher.KEY_SIZE, Cipher.KDF_ITERATIONS)
-
- cipher = AES.new(derived_key, Cipher.AES_MODE, init_vector)
- cipher_text = base64.b64encode(pbkdf2_salt + init_vector + cipher.encrypt(plain_text))
- return cipher_text
-
- @staticmethod
- def decrypt(password, cipher_text):
- """
- decrypt the :cipher_text: into :plain_text: using the password
-
- :cipher_text: is expected to be encoded as base64 to make it textable (non-binary)
- inside of that it is expected to be formatted as
- pbkdf2_salt + init_vector + encrypt(:plain_text:)
-
- :pbkdf2_salt: has the fixed length of 32 (AES-256)
- :init_vector: has the fixed length of AES.block_size
- """
- cipher_text = base64.b64decode(cipher_text)
- pbkdf2_salt = cipher_text[: Cipher.KEY_SIZE]
- init_vector = cipher_text[Cipher.KEY_SIZE : Cipher.KEY_SIZE + AES.block_size]
- cipher_text = cipher_text[Cipher.KEY_SIZE + AES.block_size :]
- derived_key = PBKDF2(password, pbkdf2_salt, Cipher.KEY_SIZE, Cipher.KDF_ITERATIONS)
-
- cipher = AES.new(derived_key, Cipher.AES_MODE, init_vector)
- plain_text = cipher.decrypt(cipher_text).decode('utf-8')
- return plain_text
diff --git a/policyhandler/policy_engine.py b/policyhandler/policy_engine.py
index 838ccc7..68e81cf 100644
--- a/policyhandler/policy_engine.py
+++ b/policyhandler/policy_engine.py
@@ -32,7 +32,7 @@ class PolicyNotificationHandler(NotificationHandler):
_logger = logging.getLogger("policy_handler.policy_notification")
def __init__(self, policy_updater):
- scope_prefixes = [scope_prefix.replace(".", "[.]") \
+ scope_prefixes = [scope_prefix.replace(".", "[.]")
for scope_prefix in Config.config["scope_prefixes"]]
self._policy_scopes = re.compile("(" + "|".join(scope_prefixes) + ")")
PolicyNotificationHandler._logger.info("_policy_scopes %s", self._policy_scopes.pattern)
@@ -43,13 +43,13 @@ class PolicyNotificationHandler(NotificationHandler):
if not notification or not notification._loadedPolicies:
return
- policy_names = [loaded._policyName \
- for loaded in notification._loadedPolicies \
- if self._policy_scopes.match(loaded._policyName)]
+ policy_names = [loaded._policyName
+ for loaded in notification._loadedPolicies
+ if self._policy_scopes.match(loaded._policyName)]
if not policy_names:
- PolicyNotificationHandler._logger.info("no policy updated for scopes %s", \
- self._policy_scopes.pattern)
+ PolicyNotificationHandler._logger.info("no policy updated for scopes %s",
+ self._policy_scopes.pattern)
return
audit = Audit(req_message="notificationReceived from PDP")
@@ -89,11 +89,13 @@ class PolicyEngineClient(object):
sub_aud = Audit(aud_parent=audit)
sub_aud.metrics_start("create client to PDP")
PolicyEngineConfig.save_to_file()
- PolicyEngineClient._policy_engine = PolicyEngine(PolicyEngineConfig.PATH_TO_PROPERTIES, \
- scheme=NotificationScheme.AUTO_ALL_NOTIFICATIONS.name,\
- handler=PolicyEngineClient._pdp_notification_handler)
+ PolicyEngineClient._policy_engine = PolicyEngine(
+ PolicyEngineConfig.PATH_TO_PROPERTIES,
+ scheme=NotificationScheme.AUTO_ALL_NOTIFICATIONS.name,
+ handler=PolicyEngineClient._pdp_notification_handler
+ )
sub_aud.metrics("created client to PDP")
- seed_scope = Config.config["scope_prefixes"][0] + ".*"
+ seed_scope = ".*"
PolicyEngineClient._policy_engine.getConfig(policyName=seed_scope)
sub_aud.metrics("seeded client by PDP.getConfig for policyName={0}".format(seed_scope))
diff --git a/policyhandler/policy_handler.py b/policyhandler/policy_handler.py
index 10633cd..50d59bc 100644
--- a/policyhandler/policy_handler.py
+++ b/policyhandler/policy_handler.py
@@ -60,28 +60,5 @@ def run_policy_handler():
PolicyEngineClient.run()
PolicyWeb.run()
-def upload_config_to_discovery():
- """read the config from file and upload it to discovery"""
- logger = logging.getLogger("policy_handler")
- sys.stdout = LogWriter(logger.info)
- sys.stderr = LogWriter(logger.error)
-
- Config.load_from_file()
-
- if not Config.load_from_file(Config.UPLOAD_CONFIG_FILE_PATH):
- logger.info("not found config %s", Config.UPLOAD_CONFIG_FILE_PATH)
- return
-
- logger.info("========== upload_config_to_discovery ==========")
- Config.upload_to_discovery()
-
- logger.info("========== upload_config_to_discovery - get it back ==========")
- Config.config = None
- Config.load_from_file()
- Config.discover()
- logger.info("========== upload_config_to_discovery - done ==========")
- return True
-
if __name__ == "__main__":
- if not upload_config_to_discovery():
- run_policy_handler()
+ run_policy_handler()
diff --git a/requirements.txt b/requirements.txt
index cafb36d..43e8bf7 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,6 @@
CherryPy>=10.2.2
enum34>=1.1.6
future>=0.16.0
-pycrypto>=2.6.1
requests>=2.13.0,<3.0.0
six>=1.10.0
websocket-client>=0.40.0
diff --git a/setup.py b/setup.py
index adfcf98..d39a1c2 100644
--- a/setup.py
+++ b/setup.py
@@ -24,7 +24,7 @@ from setuptools import setup
setup(
name='policyhandler',
description='DCAE-Controller policy-handler to communicate with policy-engine',
- version="0.0.1",
+ version="1.0.0",
author='Alex Shatov',
packages=['policyhandler'],
zip_safe=False,
@@ -32,9 +32,14 @@ setup(
"CherryPy>=10.2.2",
"enum34>=1.1.6",
"future>=0.16.0",
- "pycrypto>=2.6.1",
"requests>=2.13.0",
"six>=1.10.0",
"websocket-client>=0.40.0"
+ ],
+ keywords='policy dcae controller',
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Intended Audience :: Developers',
+ 'Programming Language :: Python :: 2.7'
]
)
diff --git a/start_ph_in_docker.sh b/start_ph_in_docker.sh
index 13b94df..e94bdb0 100644
--- a/start_ph_in_docker.sh
+++ b/start_ph_in_docker.sh
@@ -33,13 +33,13 @@ if [[ -n ${DOCKER_HOST} ]]; then
# replace CONSUL_IP with docker-host-ip if consul-agent is local
CONSUL_HOST=${HOSTNAME}
CONSUL_IP=$(host ${CONSUL_HOST} | awk '/has address/ { print $4 ; exit }')
+ if [ "0${CONSUL_IP}" = "0" ]; then
+ CONSUL_IP=${CONSUL_HOST}
+ fi
echo "starting ${APPNAME} on HOSTNAME=${HOSTNAME} CONSUL_HOST=${CONSUL_HOST} CONSUL_IP=${CONSUL_IP}"
docker run --name ${APPNAME} -d -e HOSTNAME --add-host consul:${CONSUL_IP} -P ${APPNAME}
-
- # cd logs
- # docker cp ${APPNAME}:/opt/app/${APPNAME}/logs .
else
export HOSTNAME=$(hostname --fqdn)
@@ -61,4 +61,10 @@ else
-v ${BASEDIR}/logs:${TARGETDIR}/logs \
-p 25577:25577 \
${APPNAME}
-fi \ No newline at end of file
+fi
+
+docker ps -a | grep ${APPNAME}
+echo "--- --- --- --- ---"
+docker exec ${APPNAME} sh -c "whoami;pwd;set;ls -la;ls -l logs"
+echo "copy logs: docker cp ${APPNAME}:/opt/app/${APPNAME}/logs logs/"
+echo "export logs: docker logs ${APPNAME} > logs/"'$(date +%Y_%m%d-%H%M%S)_'"${APPNAME}.log 2>&1"