2 # -------------------------------------------------------------------------
3 # Copyright (C) 2020 Wipro Limited.
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # -------------------------------------------------------------------------
21 from operator import eq
22 from operator import ge
23 from operator import le
26 from oslo_log import log
28 from conductor.data.plugins.inventory_provider import base
29 from conductor.data.plugins.inventory_provider.candidates.candidate import Candidate
30 from conductor.data.plugins.inventory_provider.candidates.slice_profiles_candidate import get_slice_requirements
31 from conductor.data.plugins.inventory_provider.candidates.slice_profiles_candidate import SliceProfilesCandidate
33 LOG = log.getLogger(__name__)
36 OPERATORS = {'gte': ge,
41 class Generator(base.InventoryProviderBase):
44 """Initialize variables"""
51 """Return human-readable name."""
54 def resolve_demands(self, demands, plan_info, triage_translator_data):
55 """Resolve demands into candidate list"""
57 for name, requirements in demands.items():
58 resolved_demands[name] = []
59 for requirement in requirements:
60 inventory_type = requirement.get('inventory_type').lower()
61 candidate_uniqueness = requirement.get('unique', 'true')
62 filtering_attributes = requirement.get('filtering_attributes')
63 default_fields = requirement.get('default_attributes')
64 resolved_demands[name].extend(self.generate_candidates(inventory_type,
69 return resolved_demands
71 def generate_candidates(self, inventory_type, filtering_attributes, candidate_uniqueness, default_fields):
73 if inventory_type == "slice_profiles":
74 return self.generate_slice_profile_candidates(filtering_attributes, inventory_type,
75 candidate_uniqueness, default_fields)
77 LOG.debug("No functionality implemented for \
78 generating candidates for inventory_type {}".format(inventory_type))
81 def generate_slice_profile_candidates(self, filtering_attributes, inventory_type,
82 candidate_uniqueness, default_fields):
83 """Generates a list of slice profile candidate based on the filtering attributes,
85 A sample filtering attribute is given below
86 filtering_attributes = {'core': {'latency': {'min': 15, 'max': 20, 'steps': 1},
87 'reliability': {'values': [99.999]}},
88 'ran': {'latency': {'min': 10, 'max': 20, 'steps': 1},
89 'reliability': {'values': [99.99]},
90 'coverage_area_ta_list': {'values': ['City: Chennai']}}}
91 It will generate slice profile combination from the attributes for each subnet and
92 generates combination of slice profile tuples from the each subnet.
94 subnet_combinations = {}
95 for subnet, attributes in filtering_attributes['subnets'].items():
96 attribute_names, attribute_combinations = generate_combinations(attributes)
97 subnet_combinations[subnet] = organize_combinations(attribute_names, attribute_combinations)
99 subnet_names, slice_profile_combinations = get_combinations_from_dict(subnet_combinations)
100 organized_combinations = organize_combinations(subnet_names, slice_profile_combinations)
102 for combination in organized_combinations:
103 if is_valid(get_slice_requirements(combination), filtering_attributes['service_profile']):
104 info = Candidate.build_candidate_info(self.name(), inventory_type, 1.0, candidate_uniqueness,
106 candidate = SliceProfilesCandidate(info=info, subnet_requirements=combination,
107 default_fields=default_fields)
108 converted_candidate = candidate.convert_nested_dict_to_dict()
109 candidates.append(converted_candidate)
114 def is_valid(converted_candidate, service_profile):
115 for attr, attr_value in service_profile.items():
116 if not OPERATORS[attr_value['operator']](converted_candidate[attr], attr_value['value']):
121 def generate_combinations(attributes):
122 """Generates all combination of the given attribute values.
124 The params can have a values list or range(min, max)
125 from which the combinations are generated.
128 for attribute, attr_params in attributes.items():
129 values = attr_params.get('values')
131 values = range(attr_params.get('min', 1), attr_params.get('max'),
132 attr_params.get('steps', 1))
133 attr[attribute] = values
135 return get_combinations_from_dict(attr)
138 def get_combinations_from_dict(attr):
139 """Generates combinations from a dictionary containing lists
142 attr = {"latency": [1,2,3],
143 "reliability": [99.99, 99.9]
146 attribute_name: ["latency", "reliability"]
147 attribute_combinations: [[1,99.99], [2,99.99], [3,99.99], [1,99.9], [2,99.9], [3,99.9]]
149 attribute_names = list(attr.keys())
150 attribute_combinations = list(itertools.product(*attr.values()))
151 return attribute_names, attribute_combinations
154 def organize_combinations(attribute_names, attribute_combinations):
155 """Organise the generated combinations into list of dicts.
158 attribute_name: ["latency", "reliability"]
159 attribute_combinations: [[1,99.99], [2,99.99], [3,99.99], [1,99.9], [2,99.9], [3,99.9]]
161 combinations = [{'latency': 1, 'reliability': 99.99},
162 {'latency': 2, 'reliability': 99.99},
163 {'latency': 3, 'reliability': 99.99},
164 {'latency': 1, 'reliability': 99.9},
165 {'latency': 2, 'reliability': 99.9},
166 {'latency': 3, 'reliability': 99.9}
170 for combination in attribute_combinations:
172 for (name, value) in zip(attribute_names, combination):
174 combinations.append(comb)