summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Shatov <alexs@att.com>2017-09-12 11:46:25 -0400
committerAlex Shatov <alexs@att.com>2017-09-12 11:46:25 -0400
commit0c209c0c2b6e4bbadf413c048d9c535d3c2d1a0b (patch)
tree0d4b4db47b5d7cc931bb63363fb168bc62c41f4a
parenteee6ffd3ab306b38487746ec5f883fee4dde72e9 (diff)
1.0.0 and removed dcae.node.type and policy_get
* moved dcae.node.type and policy_get from lib to dcaepolicy plugin and dcae.node.type * removed dependency on cloudify-plugins-common and requests packages * removed discovery logic since the lib does not talk to policy-handler anymore - happens in the new dcaepolicy plugin now * no more policy_apply_mode per policy node - it is up to component's blueprint to decide how to notify about policy change Change-Id: Ieefc3b5af1166a5c201574144fbf8c399e5ddc15 Issue-Id: DCAEGEN2-62 Signed-off-by: Alex Shatov <alexs@att.com>
-rw-r--r--python-dcae-policy/README.md78
-rw-r--r--python-dcae-policy/dcaepolicy/dcae_consul_client.py45
-rw-r--r--python-dcae-policy/dcaepolicy/dcae_policy.py91
-rw-r--r--python-dcae-policy/requirements.txt3
-rw-r--r--python-dcae-policy/setup.py6
5 files changed, 36 insertions, 187 deletions
diff --git a/python-dcae-policy/README.md b/python-dcae-policy/README.md
index eb26087..78047a5 100644
--- a/python-dcae-policy/README.md
+++ b/python-dcae-policy/README.md
@@ -33,38 +33,28 @@ from dcaepolicy import Policies
# examples of **@operation** with **@Policies.<>** decorator
-## **dcae.nodes.policy** cloudify.interfaces.lifecycle.**create**
+## Usage
+
+import the dcaepolicy-node-type.yaml into your blueprint to use the dcae.nodes.type node
-- retrieve the latest policy data on dcae.nodes.policy node
```yaml
- dcae.nodes.policy:
- derived_from: cloudify.nodes.Root
- properties:
- policy_id:
- description: PK to policy
- type: string
- default: DCAE_alex.Config_empty-policy
- policy_apply_mode:
- description: choice of how to apply the policy update (none|script)
- type: string
- default: none
- interfaces:
- cloudify.interfaces.lifecycle:
- create:
- implementation: dcae_policy_plugin.dcaepolicy.policy_get
+imports:
+ - https://YOUR_NEXUS_RAW_SERVER/type_files/dcaepolicy/1.0.0/node-type.yaml
```
-```python
-@operation
-@Policies.populate_policy_on_node
-def policy_get(**kwargs):
- """decorate with @Policies.populate_policy_on_node on dcae.nodes.policy node to
- retrieve the latest policy_body for policy_id
- property and save it in runtime_properties
- """
- pass
+provide the value for policy_id property
+
+```yaml
+node_templates:
+...
+ host_capacity_policy:
+ type: dcae.nodes.policy
+ properties:
+ policy_id: { get_input: host_capacity_policy_id }
```
+Then the dcaepolicyplugin will bring the latest policy to the dcae.nodes.policy node during the install workflow of cloudify.
+
------
## cloudify.interfaces.lifecycle.**configure**
- gather policy data into runtime_properties of policy consumer node
@@ -72,11 +62,9 @@ def policy_get(**kwargs):
cloudify.interfaces.lifecycle:
configure:
implementation: dcae_policy_plugin.dcaepolicy.node_configure
-
```
```python
-
from dcaepolicy import Policies, POLICIES
from .discovery import DiscoveryClient
from .demo_app import DemoApp
@@ -145,41 +133,39 @@ SERVICE_COMPONENT_NAME = "service_component_name"
@operation
@Policies.update_policies_on_node(configs_only=True)
-def policy_update(updated_policies, notify_app_through_script=False, **kwargs):
+def policy_update(updated_policies, **kwargs):
"""decorate with @Policies.update_policies_on_node() to update runtime_properties[POLICIES]
:updated_policies: contains the list of changed policy-configs when configs_only=True (default).
Use configs_only=False to bring the full policy objects in :updated_policies:.
-
- :notify_app_through_script: in kwargs is set to True/False to indicate whether to invoke
- the script based on policy_apply_mode property in the blueprint
"""
-
- if not updated_policies or POLICIES not in ctx.instance.runtime_properties:
- return
-
app_config = DiscoveryClient.get_value(ctx.instance.runtime_properties[SERVICE_COMPONENT_NAME])
+
+ # This is how to merge the policies into app_config object
app_config = Policies.shallow_merge_policies_into(app_config)
+
+ ctx.logger.info("merged updated_policies {0} into app_config {1}"
+ .format(json.dumps(updated_policies), json.dumps(app_config)))
+
ctx.instance.runtime_properties[APPLICATION_CONFIG] = app_config
- ctx.logger.info("example: updated app_config {0} with updated_policies: {1}" \
- .format(json.dumps(app_config), json.dumps(updated_policies)))
+
DiscoveryClient.put_kv(ctx.instance.runtime_properties[SERVICE_COMPONENT_NAME], app_config)
+ # example how to notify the dockerized component about the policy change
+ notify_app_through_script = True
if notify_app_through_script:
+ ctx.logger.info("notify dockerized app about updated_policies {0} and app_config {1}"
+ .format(json.dumps(updated_policies), json.dumps(app_config)))
demo_app = DemoApp(ctx.node.id)
demo_app.notify_app_through_script(
POLICY_MESSAGE_TYPE,
updated_policies=updated_policies,
application_config=app_config
)
-
- # alternative 1 - use the list of updated_policies on your own
- if updated_policies:
- ctx.logger.warn("TBD: apply updated_policies: {0}".format(json.dumps(updated_policies)))
```
-example of the **changed\_policies** with **configs_only=True**
-- list of config objects (preparsed from json string)
+example of the **changed\_policies** with **configs_only=True**
+- list of config objects (preparsed from json string)
- manual mess produced by mock_policy_updater
```json
[{
@@ -224,7 +210,7 @@ example of **policies** in runtime_properties **before policy-update**
"policyName": "DCAE_alex.Config_db_client_policy_id_value.2.xml",
"policyConfigMessage": "Config Retrieved! ",
"responseAttributes": {
-
+
},
"policyConfigStatus": "CONFIG_RETRIEVED",
"matchingConditions": {
@@ -280,7 +266,7 @@ example of **policies** in runtime_properties **after policy-update**
"policyName": "DCAE_alex.Config_db_client_policy_id_value.3.xml",
"policyConfigMessage": "Config Retrieved! ",
"responseAttributes": {
-
+
},
"policyConfigStatus": "CONFIG_RETRIEVED",
"matchingConditions": {
diff --git a/python-dcae-policy/dcaepolicy/dcae_consul_client.py b/python-dcae-policy/dcaepolicy/dcae_consul_client.py
deleted file mode 100644
index 9856eeb..0000000
--- a/python-dcae-policy/dcaepolicy/dcae_consul_client.py
+++ /dev/null
@@ -1,45 +0,0 @@
-"""client to talk to consul on standard port 8500"""
-
-# 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 requests
-
-CONSUL_HOST = "localhost"
-CONSUL_PORT = 8500
-
-class ConsulClient(object):
- """talking to the local Consul agent for interfacing with Consul from the plugin.
- Safe to assume that the Consul agent is always at localhost.
- """
- CONSUL_SERVICE_MASK = "{0}/v1/catalog/service/{1}"
- SERVICE_MASK = "http://{0}:{1}"
- _consul_url = "http://{0}:{1}".format(CONSUL_HOST, CONSUL_PORT)
-
- @staticmethod
- def get_service_url(service_name):
- """find the service record in consul"""
- response = requests.get(ConsulClient.CONSUL_SERVICE_MASK.format( \
- ConsulClient._consul_url, service_name))
- response.raise_for_status()
- resp_json = response.json()
- if resp_json:
- service = resp_json[0]
- return ConsulClient.SERVICE_MASK.format( \
- service["ServiceAddress"], service["ServicePort"])
diff --git a/python-dcae-policy/dcaepolicy/dcae_policy.py b/python-dcae-policy/dcaepolicy/dcae_policy.py
index 1ae9b8f..d64d50f 100644
--- a/python-dcae-policy/dcaepolicy/dcae_policy.py
+++ b/python-dcae-policy/dcaepolicy/dcae_policy.py
@@ -19,23 +19,15 @@
#
# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-
import json
-import uuid
import copy
from functools import wraps
-import requests
-
from cloudify import ctx
from cloudify.context import NODE_INSTANCE
from cloudify.exceptions import NonRecoverableError
-from .dcae_consul_client import ConsulClient
-
POLICIES = 'policies'
-SERVICE_NAME_POLICY_HANDLER = "policy_handler"
-X_ECOMP_REQUESTID = 'X-ECOMP-RequestID'
POLICY_ID = 'policy_id'
POLICY_APPLY_MODE = 'policy_apply_mode'
@@ -44,69 +36,9 @@ POLICY_VERSION = "policyVersion"
POLICY_CONFIG = 'config'
DCAE_POLICY_TYPE = 'dcae.nodes.policy'
POLICY_MESSAGE_TYPE = 'policy'
-POLICY_NOTIFICATION_SCRIPT = 'script'
class Policies(object):
"""static class for policy operations"""
- _policy_handler_url = None
-
- @staticmethod
- def _get_latest_policy(policy_id):
- """retrieve the latest policy for policy_id from policy-handler"""
- if not Policies._policy_handler_url:
- Policies._policy_handler_url = ConsulClient.get_service_url(SERVICE_NAME_POLICY_HANDLER)
-
- ph_path = "{0}/policy_latest/{1}".format(Policies._policy_handler_url, policy_id)
- headers = {X_ECOMP_REQUESTID: str(uuid.uuid4())}
-
- ctx.logger.info("getting latest policy from {0} headers={1}".format( \
- ph_path, json.dumps(headers)))
- res = requests.get(ph_path, headers=headers)
- res.raise_for_status()
-
- if res.status_code == requests.codes.ok:
- return res.json()
- return {}
-
- @staticmethod
- def populate_policy_on_node(func):
- """dcae.nodes.policy node retrieves the policy_body identified by policy_id property
- from policy-handler that gets it from policy-engine.
-
- Places the found policy into runtime_properties["policy_body"].
- """
- if not func:
- return
-
- @wraps(func)
- def wrapper(*args, **kwargs):
- """retrieve and save the latest policy body per policy_id"""
- try:
- if ctx.type != NODE_INSTANCE:
- return func(*args, **kwargs)
-
- if POLICY_ID not in ctx.node.properties:
- ctx.logger.error("no {0} found in ctx.node.properties".format(POLICY_ID))
- return func(*args, **kwargs)
-
- policy_id = ctx.node.properties[POLICY_ID]
- policy = Policies._get_latest_policy(policy_id)
- if policy:
- ctx.logger.info("found policy {0}".format(json.dumps(policy)))
- if POLICY_BODY in policy:
- ctx.instance.runtime_properties[POLICY_BODY] = policy[POLICY_BODY]
- else:
- error = "policy not found for policy_id {0}".format(policy_id)
- ctx.logger.error(error)
- raise NonRecoverableError(error)
-
- except Exception as ex:
- error = "Failed to get the policy {0}".format(str(ex))
- ctx.logger.error(error)
- raise NonRecoverableError(error)
-
- return func(*args, **kwargs)
- return wrapper
@staticmethod
def gather_policies_to_node(func):
@@ -206,9 +138,6 @@ class Policies(object):
Passes through the filtered list of updated_policies that apply to the current node instance
:updated_policies: contains the list of changed policy-configs when configs_only=True.
-
- :notify_app_through_script: in kwargs is set to True/False to indicate whether to invoke
- the script based on policy_apply_mode property in the blueprint
"""
def update_policies_decorator(func):
"""actual decorator"""
@@ -223,34 +152,16 @@ class Policies(object):
updated_policies = Policies._update_policies_on_ctx(updated_policies)
if updated_policies:
- notify_app_through_script = max(
- updated_policies,
- key=lambda pol: pol.get(POLICY_APPLY_MODE) == POLICY_NOTIFICATION_SCRIPT
- )
-
if configs_only:
updated_policies = [policy[POLICY_BODY][POLICY_CONFIG] \
for policy in updated_policies \
if POLICY_BODY in policy \
and POLICY_CONFIG in policy[POLICY_BODY] \
]
- return func(updated_policies,
- notify_app_through_script=notify_app_through_script, **kwargs)
+ return func(updated_policies, **kwargs)
return wrapper
return update_policies_decorator
- @staticmethod
- def get_notify_app_through_script():
- """returns True if any of the policy has property policy_apply_mode==script"""
- if ctx.type != NODE_INSTANCE \
- or POLICIES not in ctx.instance.runtime_properties:
- return
- policies = ctx.instance.runtime_properties[POLICIES]
- if not policies:
- return
- for policy_id in policies:
- if policies[policy_id].get(POLICY_APPLY_MODE) == POLICY_NOTIFICATION_SCRIPT:
- return True
@staticmethod
def get_policy_configs():
diff --git a/python-dcae-policy/requirements.txt b/python-dcae-policy/requirements.txt
index cdcf98d..2f98303 100644
--- a/python-dcae-policy/requirements.txt
+++ b/python-dcae-policy/requirements.txt
@@ -1,2 +1 @@
-cloudify-plugins-common==3.4
-requests>=2.11.0,<3.0.0
+# - not here because cloudify provides it: cloudify-plugins-common==3.4
diff --git a/python-dcae-policy/setup.py b/python-dcae-policy/setup.py
index 1fd4550..5f0c765 100644
--- a/python-dcae-policy/setup.py
+++ b/python-dcae-policy/setup.py
@@ -24,17 +24,15 @@ from setuptools import setup
setup(
name='dcaepolicy',
description='lib of policy decorators to be used by cloudify plugins of dcae controller',
- version="0.0.2",
+ version="1.0.0",
author='Alex Shatov',
email="dcae@lists.openecomp.org",
packages=['dcaepolicy'],
install_requires=[
- "cloudify-plugins-common==3.4",
- "requests>=2.11.0,<3.0.0"
],
keywords='policy dcae controller cloudify plugin',
classifiers=[
- 'Development Status :: 3 - Alpha',
+ 'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Programming Language :: Python :: 2.7'
]