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 # -------------------------------------------------------------------------
24 from requests import RequestException
25 from osdf.operation.exceptions import BusinessException
26 from osdf.adapters.local_data.local_policies import get_local_policies
27 from osdf.adapters.policy.utils import _regex_policy_name
28 from osdf.config.base import osdf_config
29 from osdf.logging.osdf_logging import audit_log, MH, metrics_log, error_log, debug_log
30 from osdf.utils.interfaces import RestClient
31 from osdf.optimizers.placementopt.conductor.api_builder import retrieve_node
32 # from osdf.utils import data_mapping
35 def get_by_name(rest_client, policy_name_list, wildcards=True):
37 for policy_name in policy_name_list:
39 query_name = policy_name
41 query_name = _regex_policy_name(query_name)
42 policy_list.append(rest_client.request(json={"policyName": query_name}))
43 except RequestException as err:
44 audit_log.warn("Error in fetching policy: " + policy_name)
45 raise BusinessException("Cannot fetch policy {}: ".format(policy_name), err)
49 def get_subscriber_name(req, pmain):
50 subs_name = retrieve_node(req, pmain['subscriber_name'])
54 subs_name_uc = subs_name.upper()
55 if subs_name_uc in ("DEFAULT", "NULL", ""):
60 def get_subscriber_role(rest_client, req, pmain, service_name, scope):
61 """Make a request to policy and return subscriberRole
62 :param rest_client: rest client to make call
63 :param req: request object from MSO
64 :param pmain: main config that will have policy path information
65 :param service_name: the type of service to call: e.g. "vCPE
66 :param scope: the scope of policy to call: e.g. "OOF_HAS_vCPE".
67 :return: subscriberRole and provStatus retrieved from Subscriber policy
69 subscriber_role = "DEFAULT"
71 subs_name = get_subscriber_name(req, pmain)
72 if subs_name == "DEFAULT":
73 return subscriber_role, prov_status
75 policy_subs = pmain['policy_subscriber']
76 policy_scope = {"policyName": "{}.*".format(scope),
78 "serviceType": "{}".format(service_name),
79 "service": "{}".format(policy_subs)}
83 policy_list.append(rest_client.request(json=policy_scope))
84 except RequestException as err:
85 audit_log.warn("Error in fetching policy for {}: ".format(policy_subs))
86 return subscriber_role, prov_status
88 formatted_policies = []
89 for x in itertools.chain(*policy_list):
90 if x['config'] is None:
91 raise BusinessException("Config not found for policy with name %s" % x['policyName'])
93 formatted_policies.append(json.loads(x['config']))
95 for policy in formatted_policies:
96 property_list = policy['content']['property']
97 for prop in property_list:
98 if subs_name in prop['subscriberName']:
99 subs_role_list = prop['subscriberRole']
100 prov_status = prop['provStatus']
101 if isinstance(subs_role_list, list): # as list is returned
102 return subs_role_list[0], prov_status
103 return subscriber_role, prov_status
106 def get_by_scope(rest_client, req, config_local, type_service):
108 pmain = config_local['policy_info'][type_service]
109 pscope = pmain['policy_scope']
111 model_name = retrieve_node(req, pscope['service_name'])
112 service_name = model_name
113 # service_name = data_mapping.get_request_service_type(req)
114 # if service_name is None:
115 # service_name = data_mapping.get_service_type(model_name)
116 scope = pscope['scope_{}'.format(service_name.lower())]
117 subscriber_role, prov_status = get_subscriber_role(rest_client, req, pmain, service_name, scope)
118 policy_type_list = pmain['policy_type_{}'.format(service_name.lower())]
119 for policy_type in policy_type_list:
120 policy_scope = {"policyName": "{}.*".format(scope),
121 "configAttributes": {
122 "serviceType": "{}".format(service_name),
123 "service": "{}".format(policy_type),
124 "subscriberRole": "{}".format(subscriber_role)}
126 policy_list.append(rest_client.request(json=policy_scope))
127 return policy_list, prov_status
130 def remote_api(req_json, osdf_config, service_type="placement"):
131 """Make a request to policy and return response -- it accounts for multiple requests that be needed
132 :param req_json: policy request object (can have multiple policy names)
133 :param osdf_config: main config that will have credential information
134 :param service_type: the type of service to call: "placement", "scheduling"
135 :return: all related policies and provStatus retrieved from Subscriber policy
137 # if not req_json[service_type + "Info"]['policyId']:
140 config = osdf_config.deployment
141 uid, passwd = config['policyPlatformUsername'], config['policyPlatformPassword']
142 pcuid, pcpasswd = config['policyClientUsername'], config['policyClientPassword']
143 headers = {"ClientAuth": base64.b64encode(bytes("{}:{}".format(pcuid, pcpasswd), "ascii"))}
144 headers.update({'Environment': config['policyPlatformEnv']})
145 url = config['policyPlatformUrl']
146 rc = RestClient(userid=uid, passwd=passwd, headers=headers, url=url, log_func=debug_log.debug)
148 if osdf_config.core['policy_info'][service_type]['policy_fetch'] == "by_name":
149 policies = get_by_name(rc, req_json[service_type + "Info"]['policyId'], wildcards=True)
150 elif osdf_config.core['policy_info'][service_type]['policy_fetch'] == "by_name_no_wildcards":
151 policies = get_by_name(rc, req_json[service_type + "Info"]['policyId'], wildcards=False)
152 else: # Get policy by scope
153 policies, prov_status = get_by_scope(rc, req_json, osdf_config.core, service_type)
155 # policies in res are list of lists, so flatten them; also only keep config part
156 formatted_policies = []
157 for x in itertools.chain(*policies):
158 if x['config'] is None:
159 raise BusinessException("Config not found for policy with name %s" % x['policyName'])
161 formatted_policies.append(json.loads(x['config']))
162 return formatted_policies, prov_status
165 def local_policies_location(req_json, osdf_config, service_type):
167 Get folder and list of policy_files if "local policies" option is enabled
168 :param service_type: placement supported for now, but can be any other service
169 :return: a tuple (folder, file_list) or None
171 lp = osdf_config.core.get('osdf_hacks', {}).get('local_policies', {})
172 if lp.get('global_disabled'):
173 return None # short-circuit to disable all local policies
174 if lp.get('local_{}_policies_enabled'.format(service_type)):
175 if service_type == "scheduling":
176 return lp.get('{}_policy_dir'.format(service_type)), lp.get('{}_policy_files'.format(service_type))
178 model_name = retrieve_node(req_json, osdf_config.core['policy_info'][service_type]['policy_scope']['service_name'])
179 service_name = data_mapping.get_service_type(model_name)
180 return lp.get('{}_policy_dir_{}'.format(service_type, service_name.lower())), lp.get('{}_policy_files_{}'.format(service_type, service_name.lower()))
184 def get_policies(request_json, service_type):
185 """Validate the request and get relevant policies
186 :param request_json: Request object
187 :param service_type: the type of service to call: "placement", "scheduling"
188 :return: policies associated with this request and provStatus retrieved from Subscriber policy
191 req_info = request_json['requestInfo']
192 req_id = req_info['requestId']
193 metrics_log.info(MH.requesting("policy", req_id))
194 local_info = local_policies_location(request_json, osdf_config, service_type)
196 if local_info: # tuple containing location and list of files
198 if osdf_config.core['policy_info'][service_type]['policy_fetch'] == "by_name":
199 to_filter = request_json[service_type + "Info"]['policyId']
200 policies = get_local_policies(local_info[0], local_info[1], to_filter)
202 policies, prov_status= remote_api(request_json, osdf_config, service_type)
204 return policies, prov_status