Updates to address new HPA policies
[optf/osdf.git] / osdf / adapters / policy / utils.py
1 # -------------------------------------------------------------------------
2 #   Copyright (c) 2015-2017 AT&T Intellectual Property
3 #
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
7 #
8 #       http://www.apache.org/licenses/LICENSE-2.0
9 #
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.
15 #
16 # -------------------------------------------------------------------------
17 #
18 import copy
19 import json
20
21 from collections import defaultdict
22 import itertools
23 from osdf.utils.programming_utils import dot_notation, list_flatten
24
25
26 def group_policies(flat_policies):
27     """Filter policies using the following steps:
28     1. Apply prioritization among the policies that are sharing the same policy type and resource type
29     2. Remove redundant policies that may applicable across different types of resource
30     3. Filter policies based on type and return
31     :param flat_policies: list of flat policies
32     :return: Filtered policies
33     """
34     filtered_policies = defaultdict(list)
35     policy_name = []
36     policies = [x for x in flat_policies if x['content'].get('policyType')]  # drop ones without 'policy_type'
37     policy_types = set([x['content'].get('policyType') for x in policies])
38     aggregated_policies = dict((x, defaultdict(list)) for x in policy_types)
39
40     for policy in policies:
41         policy_type = policy['content'].get('policyType')
42         for resource in policy['content'].get('resources', []):
43             aggregated_policies[policy_type][resource].append(policy)
44
45     for policy_type in aggregated_policies:
46         for resource in aggregated_policies[policy_type]:
47             if aggregated_policies[policy_type][resource]:
48                 aggregated_policies[policy_type][resource].sort(key=lambda x: x['priority'], reverse=True)
49                 prioritized_policy = aggregated_policies[policy_type][resource][0]
50                 if prioritized_policy['policyName'] not in policy_name:
51                     # TODO: Check logic here... should policy appear only once across all groups?
52                     filtered_policies[prioritized_policy['content']['policyType']].append(prioritized_policy)
53                     policy_name.append(prioritized_policy['policyName'])
54     return filtered_policies
55
56
57 def group_policies_gen(flat_policies, config):
58     """Filter policies using the following steps:
59     1. Apply prioritization among the policies that are sharing the same policy type and resource type
60     2. Remove redundant policies that may applicable across different types of resource
61     3. Filter policies based on type and return
62     :param flat_policies: list of flat policies
63     :return: Filtered policies
64     """
65     filtered_policies = defaultdict(list)
66     policy_name = []
67     policies = [x for x in flat_policies if x['content'].get('policyType')]  # drop ones without 'policy_type'
68     priority = config.get('policy_info', {}).get('prioritization_attributes', {})
69     aggregated_policies = dict()
70     for plc in policies:
71         attrs = [dot_notation(plc, dot_path) for key in priority.keys() for dot_path in priority[key]]
72         attrs_list  = [x if isinstance(x, list) else [x] for x in attrs]
73         attributes = [list_flatten(x) if isinstance(x, list) else x for x in attrs_list]
74         for y in itertools.product(*attributes):
75             aggregated_policies.setdefault(y, [])
76             aggregated_policies[y].append(plc)
77
78     for key in aggregated_policies.keys():
79         aggregated_policies[key].sort(key=lambda x: x['priority'], reverse=True)
80         prioritized_policy = aggregated_policies[key][0]
81         if prioritized_policy['policyName'] not in policy_name:
82             # TODO: Check logic here... should policy appear only once across all groups?
83             filtered_policies[prioritized_policy['content']['policyType']].append(prioritized_policy)
84             policy_name.append(prioritized_policy['policyName'])
85
86     return filtered_policies
87
88
89 def policy_name_as_regex(policy_name):
90     """Get the correct policy name as a regex
91     (e.g. OOF_HAS_vCPE.cloudAttributePolicy ends up in policy as OOF_HAS_vCPE.Config_MS_cloudAttributePolicy.1.xml
92     So, for now, we query it as OOF_HAS_vCPE..*aicAttributePolicy.*)
93     :param policy_name: Example: OOF_HAS_vCPE.aicAttributePolicy
94     :return: regexp for policy: Example: OOF_HAS_vCPE..*aicAttributePolicy.*
95     """
96     p = policy_name.partition('.')
97     return p[0] + p[1] + ".*" + p[2] + ".*"
98
99
100 def retrieve_node(req_json, reference):
101     """
102     Get the child node(s) from the dot-notation [reference] and parent [req_json].
103     For placement and other requests, there are encoded JSONs inside the request or policy,
104     so we need to expand it and then do a search over the parent plus expanded JSON.
105     """
106     req_json_copy = copy.deepcopy(req_json)  # since we expand the JSON in place, we work on a copy
107     if 'orderInfo' in req_json_copy['placementInfo']:
108         req_json_copy['placementInfo']['orderInfo'] = json.loads(req_json_copy['placementInfo']['orderInfo'])
109     info = dot_notation(req_json_copy, reference)
110     return list_flatten(info) if isinstance(info, list) else info