Coverage for dcaepolicyplugin/tasks.py : 72%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# ================================================================================
2# Copyright (c) 2017-2020 AT&T Intellectual Property. All rights reserved.
3# Copyright (c) 2019 Pantheon.tech. All rights reserved.
4# ================================================================================
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16# ============LICENSE_END=========================================================
17#
19"""tasks are the cloudify operations invoked on interfaces defined in the blueprint"""
21import copy
22import json
23import traceback
24import uuid
26import requests
27from cloudify import ctx
28from cloudify.context import NODE_INSTANCE
29from cloudify.decorators import operation
30from cloudify.exceptions import NonRecoverableError
32from .discovery import discover_service_url, discover_value
34DCAE_POLICY_PLUGIN = "dcaepolicyplugin"
35POLICY_ID = 'policy_id'
36POLICY_REQUIRED = 'policy_required'
37POLICY_BODY = 'policy_body'
38POLICIES_FILTERED = 'policies_filtered'
39POLICY_FILTER = 'policy_filter'
40LATEST_POLICIES = "latest_policies"
42REQUEST_ID = "requestID"
44DCAE_POLICY_TYPE = 'dcae.nodes.policy'
45DCAE_POLICIES_TYPE = 'dcae.nodes.policies'
46DCAE_POLICY_TYPES = [DCAE_POLICY_TYPE, DCAE_POLICIES_TYPE]
47CONFIG_ATTRIBUTES = "configAttributes"
50class PolicyHandler(object):
51 """talk to policy-handler"""
52 SERVICE_NAME_POLICY_HANDLER = "policy_handler"
53 X_ECOMP_REQUESTID = 'X-ECOMP-RequestID'
54 STATUS_CODE_POLICIES_NOT_FOUND = 404
55 DEFAULT_URL = "http://policy-handler"
56 _url = None
58 @staticmethod
59 def _lazy_init():
60 """discover policy-handler"""
61 if PolicyHandler._url:
62 return
64 PolicyHandler._url = discover_service_url(PolicyHandler.SERVICE_NAME_POLICY_HANDLER)
65 if PolicyHandler._url:
66 return
68 config = discover_value(DCAE_POLICY_PLUGIN)
69 if config and isinstance(config, dict): 69 ↛ 82line 69 didn't jump to line 82, because the condition on line 69 was never false
70 # expected structure for the config value for dcaepolicyplugin key
71 # {
72 # "dcaepolicyplugin" : {
73 # "policy_handler" : {
74 # "target_entity" : "policy_handler",
75 # "url" : "http://policy-handler:25577"
76 # }
77 # }
78 # }
79 PolicyHandler._url = config.get(DCAE_POLICY_PLUGIN, {}) \
80 .get(PolicyHandler.SERVICE_NAME_POLICY_HANDLER, {}).get("url")
82 if PolicyHandler._url: 82 ↛ 85line 82 didn't jump to line 85, because the condition on line 82 was never false
83 return
85 PolicyHandler._url = PolicyHandler.DEFAULT_URL
87 @staticmethod
88 def get_latest_policy(policy_id):
89 """retrieve the latest policy for policy_id from policy-handler"""
90 PolicyHandler._lazy_init()
92 ph_path = "{0}/policy_latest/{1}".format(PolicyHandler._url, policy_id)
93 headers = {PolicyHandler.X_ECOMP_REQUESTID: str(uuid.uuid4())}
95 ctx.logger.info("getting latest policy from {0} headers={1}".format(
96 ph_path, json.dumps(headers)))
97 res = requests.get(ph_path, headers=headers, timeout=60)
98 ctx.logger.info("latest policy for policy_id({0}) status({1}) response: {2}"
99 .format(policy_id, res.status_code, res.text))
101 if res.status_code == PolicyHandler.STATUS_CODE_POLICIES_NOT_FOUND: 101 ↛ 102line 101 didn't jump to line 102, because the condition on line 101 was never true
102 return
104 res.raise_for_status()
105 return res.json()
107 @staticmethod
108 def find_latest_policies(policy_filter):
109 """retrieve the latest policies by policy filter (selection criteria) from policy-handler"""
110 PolicyHandler._lazy_init()
112 ph_path = "{0}/policies_latest".format(PolicyHandler._url)
113 headers = {
114 PolicyHandler.X_ECOMP_REQUESTID: policy_filter.get(REQUEST_ID, str(uuid.uuid4()))
115 }
117 ctx.logger.info("finding the latest polices from {0} by {1} headers={2}".format(
118 ph_path, json.dumps(policy_filter), json.dumps(headers)))
120 res = requests.post(ph_path, json=policy_filter, headers=headers, timeout=60)
121 ctx.logger.info("latest policies status({0}) response: {1}"
122 .format(res.status_code, res.text))
124 if res.status_code == PolicyHandler.STATUS_CODE_POLICIES_NOT_FOUND: 124 ↛ 125line 124 didn't jump to line 125, because the condition on line 124 was never true
125 return
127 res.raise_for_status()
128 return res.json().get(LATEST_POLICIES)
131def _policy_get():
132 """
133 dcae.nodes.policy -
134 retrieve the latest policy_body for policy_id property
135 and save policy_body in runtime_properties
136 """
137 if DCAE_POLICY_TYPE not in ctx.node.type_hierarchy:
138 return
140 policy_id = ctx.node.properties.get(POLICY_ID)
141 policy_required = ctx.node.properties.get(POLICY_REQUIRED)
142 if not policy_id: 142 ↛ 143line 142 didn't jump to line 143, because the condition on line 142 was never true
143 error = "no {0} found in ctx.node.properties".format(POLICY_ID)
144 ctx.logger.error(error)
145 raise NonRecoverableError(error)
147 policy = None
148 try:
149 policy = PolicyHandler.get_latest_policy(policy_id)
150 except Exception as ex:
151 error = "failed to get policy({0}): {1}".format(policy_id, str(ex))
152 ctx.logger.error("{0}: {1}".format(error, traceback.format_exc()))
153 raise NonRecoverableError(error)
155 if not policy: 155 ↛ 156line 155 didn't jump to line 156, because the condition on line 155 was never true
156 error = "policy not found for policy_id {0}".format(policy_id)
157 ctx.logger.info(error)
158 if policy_required:
159 raise NonRecoverableError(error)
160 return True
162 ctx.logger.info("found policy {0}: {1}".format(policy_id, json.dumps(policy)))
163 if POLICY_BODY in policy: 163 ↛ 165line 163 didn't jump to line 165, because the condition on line 163 was never false
164 ctx.instance.runtime_properties[POLICY_BODY] = policy[POLICY_BODY]
165 return True
168def _fix_policy_filter(policy_filter):
169 if CONFIG_ATTRIBUTES in policy_filter: 169 ↛ exitline 169 didn't return from function '_fix_policy_filter', because the condition on line 169 was never false
170 config_attributes = policy_filter.get(CONFIG_ATTRIBUTES)
171 if isinstance(config_attributes, dict): 171 ↛ 172line 171 didn't jump to line 172, because the condition on line 171 was never true
172 return
173 try:
174 config_attributes = json.loads(config_attributes)
175 if config_attributes and isinstance(config_attributes, dict): 175 ↛ 180line 175 didn't jump to line 180, because the condition on line 175 was never false
176 policy_filter[CONFIG_ATTRIBUTES] = config_attributes
177 return
178 except (ValueError, TypeError):
179 pass
180 if config_attributes:
181 ctx.logger.warn("unexpected %s: %s", CONFIG_ATTRIBUTES, config_attributes)
182 del policy_filter[CONFIG_ATTRIBUTES]
185def _policies_find():
186 """
187 dcae.nodes.policies -
188 retrieve the latest policies for selection criteria
189 and save found policies in runtime_properties
190 """
191 if DCAE_POLICIES_TYPE not in ctx.node.type_hierarchy:
192 return
194 policy_required = ctx.node.properties.get(POLICY_REQUIRED)
196 try:
197 policy_filter = ctx.node.properties.get(POLICY_FILTER)
198 if policy_filter: 198 ↛ 205line 198 didn't jump to line 205, because the condition on line 198 was never false
199 policy_filter = {
200 k: copy.deepcopy(v) for k, v in policy_filter.items()
201 if v or isinstance(v, (int, float))
202 }
203 _fix_policy_filter(policy_filter)
204 else:
205 policy_filter = {}
207 if REQUEST_ID not in policy_filter: 207 ↛ 210line 207 didn't jump to line 210, because the condition on line 207 was never false
208 policy_filter[REQUEST_ID] = str(uuid.uuid4())
210 policies_filtered = PolicyHandler.find_latest_policies(policy_filter)
212 if not policies_filtered: 212 ↛ 213line 212 didn't jump to line 213, because the condition on line 212 was never true
213 error = "policies not found by {0}".format(json.dumps(policy_filter))
214 ctx.logger.info(error)
215 if policy_required:
216 raise NonRecoverableError(error)
217 return True
219 ctx.logger.info("found policies by {0}: {1}".format(
220 json.dumps(policy_filter), json.dumps(policies_filtered)
221 ))
222 ctx.instance.runtime_properties[POLICIES_FILTERED] = policies_filtered
224 except Exception as ex:
225 error = "failed to find policies: {0}".format(str(ex))
226 ctx.logger.error("{0}: {1}".format(error, traceback.format_exc()))
227 raise NonRecoverableError(error)
229 return True
232#########################################################
233@operation
234def policy_get(**kwargs):
235 """retrieve the policy or policies and save it in runtime_properties"""
236 if ctx.type != NODE_INSTANCE: 236 ↛ 237line 236 didn't jump to line 237, because the condition on line 236 was never true
237 raise NonRecoverableError("can only invoke policy_get on node of types: {0}"
238 .format(DCAE_POLICY_TYPES))
240 if not _policy_get() and not _policies_find():
241 error = "unexpected node type {0} for policy_get - expected types: {1}" \
242 .format(ctx.node.type_hierarchy, DCAE_POLICY_TYPES)
243 ctx.logger.error(error)
244 raise NonRecoverableError(error)
246 ctx.logger.info("exit policy_get")