1 # -------------------------------------------------------------------------
2 # Copyright (c) 2015-2017 AT&T Intellectual Property
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 # -------------------------------------------------------------------------
22 from requests import RequestException
26 from osdf.adapters.local_data.local_policies import get_local_policies
27 from osdf.adapters.policy.utils import policy_name_as_regex
28 from osdf.config.base import osdf_config
29 from osdf.logging.osdf_logging import audit_log
30 from osdf.logging.osdf_logging import debug_log
31 from osdf.logging.osdf_logging import metrics_log
32 from osdf.logging.osdf_logging import MH
33 from osdf.operation.exceptions import BusinessException
34 from osdf.utils.interfaces import RestClient
35 from osdf.utils.programming_utils import dot_notation
36 from osdf.utils.programming_utils import list_flatten
39 def get_by_name(rest_client, policy_name_list, wildcards=True):
41 for policy_name in policy_name_list:
43 query_name = policy_name
45 query_name = policy_name_as_regex(query_name)
46 policy_list.append(rest_client.request(json={"policyName": query_name}))
47 except RequestException as err:
48 audit_log.warn("Error in fetching policy: " + policy_name)
49 raise BusinessException("Cannot fetch policy {}: ".format(policy_name), err)
53 def get_by_scope(rest_client, req, config_local, type_service):
54 """Get policies by scopes as defined in the configuration file.
56 :param rest_client: a rest client object to make a call.
57 :param req: an optimization request.
58 :param config_local: application configuration file.
59 :param type_service: the type of optimization service.
60 :return: policies in the form of list of list where inner list contains policies for a single a scope.
63 references = config_local.get('references', {})
64 pscope = config_local.get('policy_info', {}).get(type_service, {}).get('policy_scope', [])
68 for key in scopes.keys():
69 for field in scopes[key]:
70 scope_fields[key] = list_flatten([get_scope_fields(field, references, req, policies)
71 if 'get_param' in field else field])
72 if scope_fields.get('resources') and len(scope_fields['resources']) > 1:
73 for s in scope_fields['resources']:
74 scope_fields['resources'] = [s]
75 policies.update(policy_api_call(rest_client, scope_fields).get('policies', {}))
77 policies.update(policy_api_call(rest_client, scope_fields).get('policies', {}))
78 for policyName in policies.keys():
79 keys = scope_fields.keys() & policies[policyName]['properties'].keys()
81 policy[policyName] = policies[policyName]
83 if set(policies.get(policyName, {}).get('properties', {}).get(k)) >= set(scope_fields[k]) \
84 and policy not in scope_policies:
85 scope_policies.append(policy)
90 def get_scope_fields(field, references, req, policies):
91 """Retrieve the values for scope fields from a request and policies
93 They are derived as per the configuration and references defined in a
94 configuration file. If the value of a scope field missing in a request or
95 policies, throw an exception since correct policies cannot be retrieved.
97 :param field: details on a scope field from a configuration file.
98 :param references: references defined in a configuration file.
99 :param req: an optimization request.
100 :param policy_info: a list of policies.
101 :return: scope fields retrieved from a request and policies.
103 ref_source = references.get(field.get('get_param', ""), {}).get('source')
104 ref_value = references.get(field.get('get_param', ""), {}).get('value')
105 if ref_source == "request":
106 scope_field = dot_notation(req, ref_value)
109 raise BusinessException("Field {} is missing a value in a request".format(ref_value.split('.')[-1]))
112 for policyName in policies.keys():
113 policy_content = policies.get(policyName)
114 if policy_content.get('type', "invalid_policy") == ref_source:
115 scope_fields.append(dot_notation(policy_content, ref_value))
116 scope_values = list_flatten(scope_fields)
117 if len(scope_values) > 0:
119 raise BusinessException("Field {} is missing a value in all policies of type {}".format(
120 ref_value.split('.')[-1], ref_source))
123 def policy_api_call(rest_client, scope_fields):
124 """Makes the api call to policy and return the response if policies are present
126 :param rest_client: rest client to make a call
127 :param scope_fields: a collection of scopes to be used for filtering
128 :return: a list of policies matching all filters
130 api_call_body = {"ONAPName": "OOF",
131 "ONAPComponent": "OOF_Component",
132 "ONAPInstance": "OOF_Component_Instance",
133 "action": "optimize",
134 "resource": scope_fields}
135 response = rest_client.request(json=api_call_body)
136 if not response.get("policies"):
137 raise Exception("Policies not found for the scope {}".format(scope_fields))
141 def remote_api(req_json, osdf_config, service_type="placement"):
142 """Make a request to policy and return response -- it accounts for multiple requests that be needed
144 :param req_json: policy request object (can have multiple policy names)
145 :param osdf_config: main config that will have credential information
146 :param service_type: the type of service to call: "placement", "scheduling"
147 :return: all related policies and provStatus retrieved from Subscriber policy
149 config = osdf_config.deployment
150 headers = {"Content-type": "application/json"}
151 uid, passwd = config['policyPlatformUsername'], config['policyPlatformPassword']
152 url = config['policyPlatformUrl']
153 rc = RestClient(userid=uid, passwd=passwd, headers=headers, url=url, log_func=debug_log.debug)
155 if osdf_config.core['policy_info'][service_type]['policy_fetch'] == "by_name":
156 policies = get_by_name(rc, req_json[service_type + "Info"]['policyId'], wildcards=True)
157 elif osdf_config.core['policy_info'][service_type]['policy_fetch'] == "by_name_no_wildcards":
158 policies = get_by_name(rc, req_json[service_type + "Info"]['policyId'], wildcards=False)
160 policies = get_by_scope(rc, req_json, osdf_config.core, service_type)
162 formatted_policies = []
164 if x[list(x.keys())[0]].get('properties') is None:
165 raise BusinessException("Properties not found for policy with name %s" % x[list(x.keys()[0])])
167 formatted_policies.append(x)
168 return formatted_policies
171 def local_policies_location(req_json, osdf_config, service_type):
172 """Get folder and list of policy_files if "local policies" option is enabled
174 :param service_type: placement supported for now, but can be any other service
175 :return: a tuple (folder, file_list) or None
177 lp = osdf_config.core.get('osdf_temp', {}).get('local_policies', {})
178 if lp.get('global_disabled'):
179 return None # short-circuit to disable all local policies
180 if lp.get('local_{}_policies_enabled'.format(service_type)):
181 debug_log.debug('Loading local policies for service type: {}'.format(service_type))
182 if service_type == "scheduling":
183 return lp.get('{}_policy_dir'.format(service_type)), lp.get('{}_policy_files'.format(service_type))
185 service_name = req_json['serviceInfo']['serviceName']
186 debug_log.debug('Loading local policies for service name: {}'.format(service_name))
187 return lp.get('{}_policy_dir_{}'.format(service_type, service_name.lower())), \
188 lp.get('{}_policy_files_{}'.format(service_type, service_name.lower()))
192 def get_policies(request_json, service_type):
193 """Validate the request and get relevant policies
195 :param request_json: Request object
196 :param service_type: the type of service to call: "placement", "scheduling"
197 :return: policies associated with this request and provStatus retrieved from Subscriber policy
199 req_info = request_json['requestInfo']
200 req_id = req_info['requestId']
201 metrics_log.info(MH.requesting("policy", req_id))
202 local_info = local_policies_location(request_json, osdf_config, service_type)
204 if local_info: # tuple containing location and list of files
205 if local_info[0] is None or local_info[1] is None:
206 raise ValueError("Error fetching local policy info")
208 if osdf_config.core['policy_info'][service_type]['policy_fetch'] == "by_name":
209 to_filter = request_json[service_type + "Info"]['policyId']
210 policies = get_local_policies(local_info[0], local_info[1], to_filter)
212 policies = remote_api(request_json, osdf_config, service_type)
217 def upload_policy_models():
218 """Upload all the policy models reside in the folder"""
219 requestId = uuid.uuid4()
220 config = osdf_config.deployment
221 model_path = config['pathPolicyModelUpload']
222 uid, passwd = config['policyPlatformUsername'], config['policyPlatformPassword']
223 pcuid, pcpasswd = config['policyClientUsername'], config['policyClientPassword']
224 headers = {"ClientAuth": base64.b64encode(bytes("{}:{}".format(pcuid, pcpasswd), "ascii"))}
225 headers.update({'Environment': config['policyPlatformEnv']})
226 headers.update({'X-ONAP-RequestID': requestId})
227 url = config['policyPlatformUrlModelUpload']
228 rc = RestClient(userid=uid, passwd=passwd, headers=headers, url=url, log_func=debug_log.debug)
230 for file in os.listdir(model_path):
231 if not file.endswith(".yaml"):
233 with open(file) as f:
234 file_converted = json.dumps(yaml.load(f))
235 response = rc.request(json=file_converted, ok_codes=(200))
238 audit_log.warn("Policy model %s uploading failed!" % file)
240 return "Policy model uploading success!"
242 return "Policy model uploading not success!"