aboutsummaryrefslogtreecommitdiffstats
path: root/osdf/adapters
diff options
context:
space:
mode:
authordhebeha <dhebeha.mj71@wipro.com>2020-09-05 20:16:48 +0530
committerVikas Varma <vikas.varma@att.com>2020-09-18 19:34:01 +0000
commitedf98746a52408386efab26143778198b0efd3c5 (patch)
treeadc101beb879a57547cc828283803bfe7c5fd89b /osdf/adapters
parentf9b3575cae2b521ba8c6b6b30b15c89bd8a1cb48 (diff)
Add support to process NSI selection request
Issue-ID: OPTFRA-802 Signed-off-by: dhebeha <dhebeha.mj71@wipro.com> Signed-off-by: krishnaa96 <krishna.moorthy6@wipro.com> Change-Id: I85d951061abc697714425bd223b89102d4f2ede9
Diffstat (limited to 'osdf/adapters')
-rw-r--r--osdf/adapters/conductor/api_builder.py19
-rw-r--r--osdf/adapters/conductor/conductor.py12
-rwxr-xr-xosdf/adapters/conductor/templates/conductor_interface.json2
-rw-r--r--osdf/adapters/conductor/translation.py75
4 files changed, 67 insertions, 41 deletions
diff --git a/osdf/adapters/conductor/api_builder.py b/osdf/adapters/conductor/api_builder.py
index daf8e54..f3b0798 100644
--- a/osdf/adapters/conductor/api_builder.py
+++ b/osdf/adapters/conductor/api_builder.py
@@ -20,14 +20,14 @@
from jinja2 import Template
import json
-from osdf.adapters.policy.utils import group_policies_gen
import osdf.adapters.conductor.translation as tr
+from osdf.adapters.policy.utils import group_policies_gen
from osdf.utils.programming_utils import list_flatten
def _build_parameters(group_policies, service_info, request_parameters):
- """
- Function prepares parameters section for has request
+ """Function prepares parameters section for has request
+
:param group_policies: filtered policies
:param service_info: service info
:param request_parameters: request parameters
@@ -50,14 +50,15 @@ def _build_parameters(group_policies, service_info, request_parameters):
def conductor_api_builder(req_info, demands, request_parameters, service_info,
- location_enabled, flat_policies: list, local_config,
+ template_fields, flat_policies: list, local_config,
template="osdf/adapters/conductor/templates/conductor_interface.json"):
"""Build an OSDF southbound API call for HAS-Conductor/Placement optimization
+
:param req_info: parameter data received from a client
:param demands: list of demands
:param request_parameters: request parameters
:param service_info: service info object
- :param location_enabled: boolean to check location to be sent in the request
+ :param template_fields: Fields that has to be passed to the template to render
:param flat_policies: policy data received from the policy platform (flat policies)
:param template: template to generate southbound API call to conductor
:param local_config: local configuration file with pointers for
@@ -73,6 +74,7 @@ def conductor_api_builder(req_info, demands, request_parameters, service_info,
demand_list = tr.gen_demands(demands, gp['onap.policies.optimization.resource.VnfPolicy'])
attribute_policy_list = tr.gen_attribute_policy(
demand_name_list, gp['onap.policies.optimization.resource.AttributePolicy'])
+
distance_to_location_policy_list = tr.gen_distance_to_location_policy(
demand_name_list, gp['onap.policies.optimization.resource.DistancePolicy'])
inventory_policy_list = tr.gen_inventory_group_policy(
@@ -95,8 +97,8 @@ def conductor_api_builder(req_info, demands, request_parameters, service_info,
gp['onap.policies.optimization.resource.'
'ThresholdPolicy'])
aggregation_policy_list = tr.gen_aggregation_policy(demand_name_list,
- gp['onap.policies.optimization.resource.'
- 'AggregationPolicy'])
+ gp['onap.policies.optimization.resource.'
+ 'AggregationPolicy'])
req_params_dict = _build_parameters(gp, service_info, request_parameters)
conductor_policies = [attribute_policy_list, distance_to_location_policy_list,
inventory_policy_list, resource_instance_policy_list,
@@ -114,7 +116,8 @@ def conductor_api_builder(req_info, demands, request_parameters, service_info,
timeout=req_info['timeout'],
limit=req_info['numSolutions'],
request_params=req_params_dict,
- location_enabled=location_enabled,
+ location_enabled=template_fields.get('location_enabled'),
+ version=template_fields.get('version'),
json=json)
json_payload = json.dumps(json.loads(rendered_req)) # need this because template's JSON is ugly!
return json_payload
diff --git a/osdf/adapters/conductor/conductor.py b/osdf/adapters/conductor/conductor.py
index 155d4d5..6749c2c 100644
--- a/osdf/adapters/conductor/conductor.py
+++ b/osdf/adapters/conductor/conductor.py
@@ -18,17 +18,16 @@
#
import json
-
from requests import RequestException
import time
from osdf.adapters.conductor.api_builder import conductor_api_builder
from osdf.logging.osdf_logging import debug_log
-from osdf.utils.interfaces import RestClient
from osdf.operation.exceptions import BusinessException
+from osdf.utils.interfaces import RestClient
-def request(req_info, demands, request_parameters, service_info, location_enabled,
+def request(req_info, demands, request_parameters, service_info, template_fields,
osdf_config, flat_policies):
config = osdf_config.deployment
local_config = osdf_config.core
@@ -53,7 +52,7 @@ def request(req_info, demands, request_parameters, service_info, location_enable
rc = RestClient(userid=uid, passwd=passwd, method="GET", log_func=debug_log.debug,
headers=headers)
conductor_req_json_str = conductor_api_builder(req_info, demands, request_parameters,
- service_info, location_enabled, flat_policies,
+ service_info, template_fields, flat_policies,
local_config)
conductor_req_json = json.loads(conductor_req_json_str)
@@ -74,7 +73,7 @@ def request(req_info, demands, request_parameters, service_info, location_enable
if resp["plans"][0].get("status") in ["done", "not found"]:
return resp
- new_url = resp['plans'][0]['links'][0][0]['href'] # TODO: check why a list of lists
+ new_url = resp['plans'][0]['links'][0][0]['href'] # TODO(krishna): check why a list of lists
if total_time >= max_timeout:
raise BusinessException("Conductor could not provide a solution within {} seconds,"
@@ -95,6 +94,7 @@ def request(req_info, demands, request_parameters, service_info, location_enable
def initial_request_to_conductor(rc, conductor_url, conductor_req_json):
"""First steps in the request-redirect chain in making a call to Conductor
+
:param rc: REST client object for calling conductor
:param conductor_url: conductor's base URL to submit a placement request
:param conductor_req_json: request json object to send to Conductor
@@ -112,7 +112,7 @@ def initial_request_to_conductor(rc, conductor_url, conductor_req_json):
debug_log.debug("Attempting to read the plan from "
"the conductor provided url {}".format(plan_url))
raw_resp = rc.request(raw_response=True,
- url=plan_url) # TODO: check why a list of lists for links
+ url=plan_url)
resp = raw_resp.json()
if resp["plans"][0]["status"] in ["error"]:
diff --git a/osdf/adapters/conductor/templates/conductor_interface.json b/osdf/adapters/conductor/templates/conductor_interface.json
index d4a9a0e..e8d47b3 100755
--- a/osdf/adapters/conductor/templates/conductor_interface.json
+++ b/osdf/adapters/conductor/templates/conductor_interface.json
@@ -4,7 +4,7 @@
"timeout": {{ timeout }},
"num_solution": "{{ limit }}",
"template": {
- "homing_template_version": "2017-10-10",
+ "homing_template_version": "{{ version }}",
"parameters": {
{% set comma=joiner(",") %}
{% for key, value in request_params.items() %} {{ comma() }}
diff --git a/osdf/adapters/conductor/translation.py b/osdf/adapters/conductor/translation.py
index 4b012f5..238428a 100644
--- a/osdf/adapters/conductor/translation.py
+++ b/osdf/adapters/conductor/translation.py
@@ -19,8 +19,8 @@
import copy
import json
import re
-
import yaml
+
from osdf.utils.programming_utils import dot_notation
policy_config_mapping = yaml.safe_load(open('config/has_config.yaml')).get('policy_config_mapping')
@@ -41,8 +41,8 @@ CONSTRAINT_TYPE_MAP = {"onap.policies.optimization.resource.AttributePolicy": "a
def get_opt_query_data(request_parameters, policies):
- """
- Fetch service and order specific details from the requestParameters field of a request.
+ """Fetch service and order specific details from the requestParameters field of a request.
+
:param request_parameters: A list of request parameters
:param policies: A set of policies
:return: A dictionary with service and order-specific attributes.
@@ -60,10 +60,20 @@ def get_opt_query_data(request_parameters, policies):
def gen_optimization_policy(vnf_list, optimization_policy):
"""Generate optimization policy details to pass to Conductor
+
:param vnf_list: List of vnf's to used in placement request
:param optimization_policy: optimization objective policy information provided in the incoming request
:return: List of optimization objective policies in a format required by Conductor
"""
+ if len(optimization_policy) == 1:
+ policy = optimization_policy[0]
+ policy_content = policy[list(policy.keys())[0]]
+ if policy_content['type_version'] == '2.0.0':
+ properties = policy_content['properties']
+ objective = {'goal': properties['goal'],
+ 'operation_function': properties['operation_function']}
+ return [objective]
+
optimization_policy_list = []
for policy in optimization_policy:
content = policy[list(policy.keys())[0]]['properties']
@@ -71,7 +81,7 @@ def gen_optimization_policy(vnf_list, optimization_policy):
parameters = ["cloud_version", "hpa_score"]
for attr in content['objectiveParameter']['parameterAttributes']:
- parameter = attr['parameter'] if attr['parameter'] in parameters else attr['parameter']+"_between"
+ parameter = attr['parameter'] if attr['parameter'] in parameters else attr['parameter'] + "_between"
default, vnfs = get_matching_vnfs(attr['resources'], vnf_list)
for vnf in vnfs:
value = [vnf] if attr['parameter'] in parameters else [attr['customerLocationInfo'], vnf]
@@ -80,13 +90,14 @@ def gen_optimization_policy(vnf_list, optimization_policy):
})
optimization_policy_list.append({
- content['objective']: {content['objectiveParameter']['operator']: parameter_list }
+ content['objective']: {content['objectiveParameter']['operator']: parameter_list}
})
return optimization_policy_list
def get_matching_vnfs(resources, vnf_list, match_type="intersection"):
"""Get a list of matching VNFs from the list of resources
+
:param resources:
:param vnf_list: List of vnfs to used in placement request
:param match_type: "intersection" or "all" or "any" (any => send all_vnfs if there is any intersection)
@@ -106,6 +117,7 @@ def get_matching_vnfs(resources, vnf_list, match_type="intersection"):
def gen_policy_instance(vnf_list, resource_policy, match_type="intersection", rtype=None):
"""Generate a list of policies
+
:param vnf_list: List of vnf's to used in placement request
:param resource_policy: policy for this specific resource
:param match_type: How to match the vnf_names with the vnf_list (intersection or "any")
@@ -129,13 +141,14 @@ def gen_policy_instance(vnf_list, resource_policy, match_type="intersection", rt
if default:
for d in demands:
resource_repeated = True \
- if {pc['properties']['identity']: {'type': CONSTRAINT_TYPE_MAP.get(pc['type']), 'demands': d}} \
- in resource_policy_list else False
+ if {pc['properties']['identity']: {'type': CONSTRAINT_TYPE_MAP.get(pc['type']),
+ 'demands': d}} in resource_policy_list else False
if resource_repeated:
continue
else:
resource_policy_list.append(
- {pc['properties']['identity']: {'type': CONSTRAINT_TYPE_MAP.get(pc['type']), 'demands': d }})
+ {pc['properties']['identity']: {'type': CONSTRAINT_TYPE_MAP.get(pc['type']),
+ 'demands': d}})
policy[list(policy.keys())[0]]['properties']['resources'] = d
related_policies.append(policy)
# Need to override the default policies, here delete the outdated policy stored in the db
@@ -194,9 +207,9 @@ def gen_attribute_policy(vnf_list, attribute_policy):
properties = p_main[list(p_main.keys())[0]]['properties']['attributeProperties']
attribute_mapping = policy_config_mapping['filtering_attributes'] # wanted attributes and mapping
p_new[p_main[list(p_main.keys())[0]]['properties']['identity']]['properties'] = {
- 'evaluate': dict((attribute_mapping[k], properties.get(k)
- if k != "cloudRegion" else gen_cloud_region(properties))
- for k in attribute_mapping.keys())
+ 'evaluate': dict((attribute_mapping[k], properties.get(k)
+ if k != "cloudRegion" else gen_cloud_region(properties))
+ for k in attribute_mapping.keys())
}
return cur_policies # cur_policies gets updated in place...
@@ -271,7 +284,7 @@ def get_policy_properties(demand, policies):
policy_demands = set([x.lower() for x in policy[list(policy.keys())[0]]['properties']['resources']])
if policy_demands and demand['resourceModuleName'].lower() not in policy_demands:
continue # no match for this policy
- elif policy_demands == set(): # Append resource name for default policy
+ elif policy_demands == set(): # Append resource name for default policy
policy[list(policy.keys())[0]]['properties'].update(resources=list(demand.get('resourceModuleName')))
for policy_property in policy[list(policy.keys())[0]]['properties']['vnfProperties']:
yield policy_property
@@ -285,35 +298,44 @@ def get_demand_properties(demand, policies):
inventory_type=policy_property['inventoryType'],
service_type=demand.get('serviceResourceId', ''),
service_resource_id=demand.get('serviceResourceId', ''))
+ policy_property_mapping = {'filtering_attributes': 'attributes',
+ 'passthrough_attributes': 'passthroughAttributes',
+ 'default_attributes': 'defaultAttributes'}
prop.update({'unique': policy_property['unique']} if 'unique' in policy_property and
policy_property['unique'] else {})
prop['filtering_attributes'] = dict()
- if policy_property.get('attributes'):
- for attr_key, attr_val in policy_property['attributes'].items():
- update_converted_attribute(attr_key, attr_val, prop, 'filtering_attributes')
- if policy_property.get('passthroughAttributes'):
- prop['passthrough_attributes'] = dict()
- for attr_key, attr_val in policy_property['passthroughAttributes'].items():
- update_converted_attribute(attr_key, attr_val, prop, 'passthrough_attributes')
+ for key, value in policy_property_mapping.items():
+ get_demand_attributes(prop, policy_property, key, value)
prop['filtering_attributes'].update({'global-customer-id': policy_property['customerId']}
- if 'customerId' in policy_property and policy_property['customerId'] else {})
+ if 'customerId' in policy_property and policy_property['customerId']
+ else {})
prop['filtering_attributes'].update({'model-invariant-id': demand['resourceModelInfo']['modelInvariantId']}
- if 'modelInvariantId' in demand['resourceModelInfo'] and demand['resourceModelInfo']['modelInvariantId'] else {})
+ if 'modelInvariantId' in demand['resourceModelInfo']
+ and demand['resourceModelInfo']['modelInvariantId'] else {})
prop['filtering_attributes'].update({'model-version-id': demand['resourceModelInfo']['modelVersionId']}
- if 'modelVersionId' in demand['resourceModelInfo'] and demand['resourceModelInfo']['modelVersionId'] else {})
+ if 'modelVersionId' in demand['resourceModelInfo']
+ and demand['resourceModelInfo']['modelVersionId'] else {})
prop['filtering_attributes'].update({'equipment-role': policy_property['equipmentRole']}
- if 'equipmentRole' in policy_property and policy_property['equipmentRole'] else {})
+ if 'equipmentRole' in policy_property and policy_property['equipmentRole']
+ else {})
prop.update(get_candidates_demands(demand))
demand_properties.append(prop)
return demand_properties
+def get_demand_attributes(prop, policy_property, attribute_type, key):
+ if policy_property.get(key):
+ prop[attribute_type] = dict()
+ for attr_key, attr_val in policy_property[key].items():
+ update_converted_attribute(attr_key, attr_val, prop, attribute_type)
+
+
def update_converted_attribute(attr_key, attr_val, properties, attribute_type):
- """
- Updates dictonary of attributes with one specified in the arguments.
+ """Updates dictonary of attributes with one specified in the arguments.
+
Automatically translates key namr from camelCase to hyphens
:param attribute_type: attribute section name
:param attr_key: key of the attribute
@@ -333,6 +355,7 @@ def update_converted_attribute(attr_key, attr_val, properties, attribute_type):
def gen_demands(demands, vnf_policies):
"""Generate list of demands based on request and VNF policies
+
:param demands: A List of demands
:param vnf_policies: Policies associated with demand resources
(e.g. from grouped_policies['vnfPolicy'])
@@ -349,6 +372,6 @@ def gen_demands(demands, vnf_policies):
def gen_cloud_region(property):
prop = {"cloud_region_attributes": dict()}
if 'cloudRegion' in property:
- for k,v in property['cloudRegion'].items():
+ for k, v in property['cloudRegion'].items():
update_converted_attribute(k, v, prop, 'cloud_region_attributes')
return prop["cloud_region_attributes"]