Fix "brain-overload" functions flagged by SONAR 55/37655/2
authorSastry Isukapalli <sastry@research.att.com>
Thu, 22 Mar 2018 04:58:14 +0000 (00:58 -0400)
committerSastry Isukapalli <sastry@research.att.com>
Thu, 22 Mar 2018 05:06:43 +0000 (05:06 +0000)
Refactored two brain-overload functions
Moved a policy util function from conductor/api_builder.py to policy/utils.py

Issue-ID: OPTFRA-195
Change-Id: I879e7f4f5d92cc530c66d3ed071bf5246397ba13
Signed-off-by: Sastry Isukapalli <sastry@research.att.com>
osdf/adapters/policy/interface.py
osdf/adapters/policy/utils.py
osdf/optimizers/licenseopt/simple_license_allocation.py
osdf/optimizers/placementopt/conductor/api_builder.py

index 288571f..02b8ff3 100644 (file)
@@ -1,4 +1,4 @@
-# -------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
 #   Copyright (c) 2015-2017 AT&T Intellectual Property
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,12 +24,10 @@ import json
 from requests import RequestException
 from osdf.operation.exceptions import BusinessException
 from osdf.adapters.local_data.local_policies import get_local_policies
-from osdf.adapters.policy.utils import _regex_policy_name
+from osdf.adapters.policy.utils import policy_name_as_regex, retrieve_node
 from osdf.config.base import osdf_config
-from osdf.logging.osdf_logging import audit_log, MH, metrics_log, error_log, debug_log
+from osdf.logging.osdf_logging import audit_log, MH, metrics_log, debug_log
 from osdf.utils.interfaces import RestClient
-from osdf.optimizers.placementopt.conductor.api_builder import retrieve_node
-# from osdf.utils import data_mapping
 
 
 def get_by_name(rest_client, policy_name_list, wildcards=True):
@@ -38,7 +36,7 @@ def get_by_name(rest_client, policy_name_list, wildcards=True):
         try:
             query_name = policy_name
             if wildcards:
-                query_name = _regex_policy_name(query_name)
+                query_name = policy_name_as_regex(query_name)
             policy_list.append(rest_client.request(json={"policyName": query_name}))
         except RequestException as err:
             audit_log.warn("Error in fetching policy: " + policy_name)
@@ -68,46 +66,57 @@ def get_subscriber_role(rest_client, req, pmain, service_name, scope):
     """
     subscriber_role = "DEFAULT"
     prov_status = []
-    subs_name = get_subscriber_name(req, pmain)
+    subs_name = get_subscriber_name(req, pmain)  # what if there is no subs_name
     if subs_name == "DEFAULT":
         return subscriber_role, prov_status
-    
+
     policy_subs = pmain['policy_subscriber']
     policy_scope = {"policyName": "{}.*".format(scope),
                     "configAttributes": {
                         "serviceType": "{}".format(service_name),
                         "service": "{}".format(policy_subs)}
                     }
-    policy_list = []
     try:
-        policy_list.append(rest_client.request(json=policy_scope))
+        policy_list = rest_client.request(json=policy_scope)
     except RequestException as err:
-        audit_log.warn("Error in fetching policy for {}: ".format(policy_subs))
+        audit_log.warn("Error in fetching policy for {}, {}: ".format(policy_subs, err))
         return subscriber_role, prov_status
-            
-    formatted_policies = []
-    for x in itertools.chain(*policy_list):
-        if x['config'] is None:
+
+    policies = list(itertools.chain(*policy_list))
+    for x in policies:  
+        if not x['config']:  # some policy has no 'config' field, so it will be empty
             raise BusinessException("Config not found for policy with name %s" % x['policyName'])
-        else:
-            formatted_policies.append(json.loads(x['config']))
-    
-    for policy in formatted_policies:
+
+    formatted_policies = [json.loads(x['config']) for x in policies]
+    role, prov = _get_subscriber_role_from_policies(formatted_policies, subs_name, subscriber_role, prov_status)
+    return role, prov
+
+
+def _get_subscriber_role_from_policies(policies, subs_name, default_role, default_prov):
+    """
+    Get the first subscriber role found in policies
+    :param policies: JSON-loaded policies
+    :param subs_name: subscriber name
+    :param default_val: default role (e.g. "DEFAULT")
+    :param default_prov: default prov_status (e.g. [])
+    :return: role and prov_status
+    """
+    for policy in policies:
         property_list = policy['content']['property']
         for prop in property_list:
             if subs_name in prop['subscriberName']:
                 subs_role_list = prop['subscriberRole']
                 prov_status = prop['provStatus']
-                if isinstance(subs_role_list, list): # as list is returned
-                    return subs_role_list[0], prov_status
-    return subscriber_role, prov_status
-    
+                if isinstance(subs_role_list, list):
+                    return subs_role_list[0], prov_status   # TODO: check what to do otherwise
+    return default_role, default_prov
+
 
 def get_by_scope(rest_client, req, config_local, type_service):
     policy_list = []
     pmain = config_local['policy_info'][type_service]
     pscope = pmain['policy_scope']
-    
+
     model_name = retrieve_node(req, pscope['service_name'])
     service_name = model_name
 
@@ -198,5 +207,5 @@ def get_policies(request_json, service_type):
         policies = get_local_policies(local_info[0], local_info[1], to_filter)
     else:
         policies, prov_status = remote_api(request_json, osdf_config, service_type)
-        
+
     return policies, prov_status
index 27885a5..9acfa2a 100644 (file)
 #
 # -------------------------------------------------------------------------
 #
+import copy
+import json
 
 from collections import defaultdict
 
+from osdf.utils.programming_utils import dot_notation, list_flatten
+
 
 def group_policies(flat_policies):
     """Filter policies using the following steps:
@@ -27,29 +31,30 @@ def group_policies(flat_policies):
     :param flat_policies: list of flat policies
     :return: Filtered policies
     """
-    aggregated_policies = {}
-    filter_policies = defaultdict(list)
+    filtered_policies = defaultdict(list)
     policy_name = []
-    for policy in flat_policies:
+    policies = [x for x in flat_policies if x['content'].get('policy_type')]  # drop ones without 'policy_type'
+    policy_types = set([x['content'].get('policyType') for x in policies])
+    aggregated_policies = dict((x, defaultdict(list)) for x in policy_types)
+
+    for policy in policies:
         policy_type = policy['content'].get('policyType')
-        if not policy_type:
-            continue
-        if policy_type not in aggregated_policies:
-            aggregated_policies[policy_type] = defaultdict(list)
         for resource in policy['content'].get('resourceInstanceType', []):
             aggregated_policies[policy_type][resource].append(policy)
+
     for policy_type in aggregated_policies:
         for resource in aggregated_policies[policy_type]:
-            if len(aggregated_policies[policy_type][resource]) > 0:
+            if aggregated_policies[policy_type][resource]:
                 aggregated_policies[policy_type][resource].sort(key=lambda x: x['priority'], reverse=True)
-                policy = aggregated_policies[policy_type][resource][0]
-                if policy['policyName'] not in policy_name:
-                    filter_policies[policy['content']['policyType']].append(policy)
-                    policy_name.append(policy['policyName'])
-    return filter_policies
+                prioritized_policy = aggregated_policies[policy_type][resource][0]
+                if prioritized_policy['policyName'] not in policy_name:
+                    # TODO: Check logic here... should policy appear only once across all groups?
+                    filtered_policies[prioritized_policy['content']['policyType']].append(prioritized_policy)
+                    policy_name.append(prioritized_policy['policyName'])
+    return filtered_policies
 
 
-def _regex_policy_name(policy_name):
+def policy_name_as_regex(policy_name):
     """Get the correct policy name as a regex
     (e.g. OOF_HAS_vCPE.cloudAttributePolicy ends up in policy as OOF_HAS_vCPE.Config_MS_cloudAttributePolicy.1.xml
     So, for now, we query it as OOF_HAS_vCPE..*aicAttributePolicy.*)
@@ -58,3 +63,16 @@ def _regex_policy_name(policy_name):
     """
     p = policy_name.partition('.')
     return p[0] + p[1] + ".*" + p[2] + ".*"
+
+
+def retrieve_node(req_json, reference):
+    """
+    Get the child node(s) from the dot-notation [reference] and parent [req_json].
+    For placement and other requests, there are encoded JSONs inside the request or policy,
+    so we need to expand it and then do a search over the parent plus expanded JSON.
+    """
+    req_json_copy = copy.deepcopy(req_json)  # since we expand the JSON in place, we work on a copy
+    if 'orderInfo' in req_json_copy['placementInfo']:
+        req_json_copy['placementInfo']['orderInfo'] = json.loads(req_json_copy['placementInfo']['orderInfo'])
+    info = dot_notation(req_json_copy, reference)
+    return list_flatten(info) if isinstance(info, list) else info
\ No newline at end of file
index ad9acfc..74d220f 100644 (file)
@@ -31,10 +31,10 @@ def license_optim(request_json):
 
     license_info = []
 
-    for licenseDemand in request_json.get('placementInfo', {}).get('demandInfo', {}).get('licenseDemands', []):
+    for demand in request_json.get('placementInfo', {}).get('demandInfo', {}).get('licenseDemands', []):
         license_info.append(
-            {'serviceResourceId': licenseDemand['serviceResourceId'],
-             'resourceModuleName': licenseDemand['resourceModuleName'],
+            {'serviceResourceId': demand['serviceResourceId'],
+             'resourceModuleName': demand['resourceModuleName'],
              'entitlementPoolList': "NOT SUPPORTED",
              'licenseKeyGroupList': "NOT SUPPORTED"
              })
index d8a2083..bfc7f19 100644 (file)
 # -------------------------------------------------------------------------
 #
 
-import copy
 import json
+
 from jinja2 import Template
-from osdf.utils.programming_utils import list_flatten, dot_notation
+
 import osdf.optimizers.placementopt.conductor.translation as tr
 from osdf.adapters.policy.utils import group_policies
+from osdf.utils.programming_utils import list_flatten
 
 
 def conductor_api_builder(request_json, flat_policies: list, local_config, prov_status,
                           template="templates/conductor_interface.json"):
-    """Build a SNIRO southbound API call for Conductor/Placement optimization
+    """Build an OSDF southbound API call for HAS-Conductor/Placement optimization
     :param request_json: parameter data received from a client
     :param flat_policies: policy data received from the policy platform (flat policies)
     :param template: template to generate southbound API call to conductor
@@ -61,7 +62,6 @@ def conductor_api_builder(request_json, flat_policies: list, local_config, prov_
     req_info = request_json['requestInfo']
     model_name = request_json['serviceInfo']['serviceName']
     service_type = model_name
-    # service_type = data_mapping.get_service_type(model_name)
     service_info = local_config.get('service_info', {}).get(service_type, {})
     order_info = {}
     if 'orderInfo' in request_json["placementInfo"]:
@@ -72,7 +72,6 @@ def conductor_api_builder(request_json, flat_policies: list, local_config, prov_
         subs_com_site_id = request_json['placementInfo']['subscriberInfo'].get('subscriberCommonSiteId', "")
     rendered_req = None
     if service_type == 'vCPE':
-        # data_mapping.normalize_user_params(order_info)
         rendered_req = templ.render(
             requestType=request_type,
             chosenComplex=subs_com_site_id,
@@ -84,22 +83,8 @@ def conductor_api_builder(request_json, flat_policies: list, local_config, prov_
             limit=req_info['numSolutions'],
             serviceType=service_type,
             serviceInstance=request_json['serviceInfo']['serviceInstanceId'],
-            provStatus = prov_status,
-            chosenRegion=order_info.get('requestParameters',{}).get('lcpCloudRegionId'),
+            provStatus=prov_status,
+            chosenRegion=order_info.get('requestParameters', {}).get('lcpCloudRegionId'),
             json=json)
-    json_payload = json.dumps(json.loads(rendered_req)) # need this because template's JSON is ugly!
+    json_payload = json.dumps(json.loads(rendered_req))  # need this because template's JSON is ugly!
     return json_payload
-
-
-def retrieve_node(req_json, reference):
-    """
-    Get the child node(s) from the dot-notation [reference] and parent [req_json].
-    For placement and other requests, there are encoded JSONs inside the request or policy,
-    so we need to expand it and then do a search over the parent plus expanded JSON.
-    """
-    req_json_copy = copy.deepcopy(req_json)  # since we expand the JSON in place, we work on a copy
-    if 'orderInfo' in req_json_copy['placementInfo']:
-        req_json_copy['placementInfo']['orderInfo'] = json.loads(req_json_copy['placementInfo']['orderInfo'])
-    info = dot_notation(req_json_copy, reference)
-    return list_flatten(info) if isinstance(info, list) else info
-