3 * ============LICENSE_START=======================================================
4 * Copyright (C) 2019 Orange
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * ============LICENSE_END=========================================================
28 import netifaces as ni
35 from datetime import datetime
36 from datetime import timedelta
37 from simple_rest_client.api import API
38 from simple_rest_client.resource import Resource
39 from basicauth import encode
40 from pprint import pprint
41 from random import randint
42 from urllib3.exceptions import InsecureRequestWarning
45 old_merge_environment_settings = requests.Session.merge_environment_settings
48 ansible_inventory = {}
49 osdf_response = {"last": { "id": "id", "data": None}}
52 class BaseServer(http.server.BaseHTTPRequestHandler):
54 def __init__(self, one, two, three):
55 self.osdf_resp = osdf_response
56 super().__init__(one, two, three)
58 def _set_headers(self):
59 self.send_response(200)
60 self.send_header('Content-type', 'application/json')
71 self.data_string = self.rfile.read(int(self.headers['Content-Length']))
72 self.send_response(200)
75 data = simplejson.loads(self.data_string)
76 self.osdf_resp["last"]["data"] = data
77 self.osdf_resp["last"]["id"] = data["requestId"]
78 with open("response.json", "w") as outfile:
79 simplejson.dump(data, outfile)
82 def _run_osdf_resp_server():
83 server_address = ('', 9000)
84 httpd = http.server.HTTPServer(server_address, BaseServer)
85 print('Starting OSDF Response Server...')
88 @contextlib.contextmanager
89 def _no_ssl_verification():
90 opened_adapters = set()
92 def merge_environment_settings(self, url, proxies, stream, verify, cert):
93 # Verification happens only once per connection so we need to close
94 # all the opened adapters once we're done. Otherwise, the effects of
95 # verify=False persist beyond the end of this context manager.
96 opened_adapters.add(self.get_adapter(url))
98 settings = old_merge_environment_settings(self, url, proxies, stream, verify, cert)
99 settings['verify'] = False
103 requests.Session.merge_environment_settings = merge_environment_settings
106 with warnings.catch_warnings():
107 warnings.simplefilter('ignore', InsecureRequestWarning)
110 requests.Session.merge_environment_settings = old_merge_environment_settings
112 for adapter in opened_adapters:
119 def _get_aai_rel_link_data(data, related_to, search_key=None, match_dict=None):
120 # some strings that we will encounter frequently
121 rel_lst = "relationship-list"
122 rkey = "relationship-key"
123 rval = "relationship-value"
124 rdata = "relationship-data"
127 m_key = match_dict.get('key')
128 m_value = match_dict.get('value')
132 rel_dict = data.get(rel_lst)
133 if rel_dict: # check if data has relationship lists
134 for key, rel_list in rel_dict.items():
136 if rel.get("related-to") == related_to:
139 link = rel.get("related-link")
140 r_data = rel.get(rdata, [])
143 if rd.get(rkey) == search_key:
145 if not match_dict: # return first match
147 {"link": link, "d_value": dval}
149 break # go to next relation
150 if rd.get(rkey) == m_key \
151 and rd.get(rval) == m_value:
153 if match_dict and matched: # if matching required
155 {"link": link, "d_value": dval}
157 # matched, return search value corresponding
158 # to the matched r_data group
159 else: # no search key; just return the link
161 {"link": link, "d_value": dval}
163 if len(response) == 0:
165 {"link": None, "d_value": None}
170 class AAIApiResource(Resource):
172 'generic_vnf': {'method': 'GET', 'url': 'network/generic-vnfs/generic-vnf/{}'},
173 'link': {'method': 'GET', 'url': '{}'},
174 'service_instance': {'method': 'GET',
175 'url': 'business/customers/customer/{}/service-subscriptions/service-subscription/{}/service-instances/service-instance/{}'}
179 class HASApiResource(Resource):
181 'plans': {'method': 'POST', 'url': 'plans/'},
182 'plan': {'method': 'GET', 'url': 'plans/{}'}
186 class OSDFApiResource(Resource):
188 'placement': {'method': 'POST', 'url': 'placement'}
192 class APPCLcmApiResource(Resource):
194 'distribute_traffic': {'method': 'POST', 'url': 'appc-provider-lcm:distribute-traffic/'},
195 'distribute_traffic_check': {'method': 'POST', 'url': 'appc-provider-lcm:distribute-traffic-check/'},
196 'action_status': {'method': 'POST', 'url': 'appc-provider-lcm:action-status/'},
200 def _init_python_aai_api(onap_ip):
202 api_root_url="https://{}:30233/aai/v14/".format(onap_ip),
205 'Authorization': encode("AAI", "AAI"),
206 'X-FromAppId': 'SCRIPT',
207 'Accept': 'application/json',
208 'Content-Type': 'application/json',
209 'X-TransactionId': str(uuid.uuid4()),
213 json_encode_body=True # encode body as json
215 api.add_resource(resource_name='aai', resource_class=AAIApiResource)
219 def _init_python_has_api(onap_ip):
221 api_root_url="https://{}:30275/v1/".format(onap_ip),
224 'Authorization': encode("admin1", "plan.15"),
225 'X-FromAppId': 'SCRIPT',
226 'Accept': 'application/json',
227 'Content-Type': 'application/json',
228 'X-TransactionId': str(uuid.uuid4()),
232 json_encode_body=True # encode body as json
234 api.add_resource(resource_name='has', resource_class=HASApiResource)
238 def _init_python_osdf_api(onap_ip):
240 api_root_url="https://{}:30248/api/oof/v1/".format(onap_ip),
243 'Authorization': encode("test", "testpwd"),
244 'X-FromAppId': 'SCRIPT',
245 'Accept': 'application/json',
246 'Content-Type': 'application/json',
247 'X-TransactionId': str(uuid.uuid4()),
251 json_encode_body=True # encode body as json
253 api.add_resource(resource_name='osdf', resource_class=OSDFApiResource)
257 def _init_python_appc_lcm_api(onap_ip):
259 api_root_url="http://{}:30230/restconf/operations/".format(onap_ip),
262 'Authorization': encode("admin", "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U"),
263 'X-FromAppId': 'SCRIPT',
264 'Accept': 'application/json',
265 'Content-Type': 'application/json',
269 json_encode_body=True # encode body as json
271 api.add_resource(resource_name='lcm', resource_class=APPCLcmApiResource)
275 def load_aai_data(vfw_vnf_id, onap_ip):
276 api = _init_python_aai_api(onap_ip)
278 aai_data['service-info'] = {'global-customer-id': '', 'service-instance-id': '', 'service-type': ''}
279 aai_data['vfw-model-info'] = {'model-invariant-id': '', 'model-version-id': '', 'vnf-name': '', 'vnf-type': ''}
280 aai_data['vpgn-model-info'] = {'model-invariant-id': '', 'model-version-id': '', 'vnf-name': '', 'vnf-type': ''}
281 with _no_ssl_verification():
282 response = api.aai.generic_vnf(vfw_vnf_id, body=None, params={'depth': 2}, headers={})
283 aai_data['vfw-model-info']['model-invariant-id'] = response.body.get('model-invariant-id')
284 aai_data['vfw-model-info']['model-version-id'] = response.body.get('model-version-id')
285 aai_data['vfw-model-info']['vnf-name'] = response.body.get('vnf-name')
286 aai_data['vfw-model-info']['vnf-type'] = response.body.get('vnf-type')
287 aai_data['vf-module-id'] = response.body['vf-modules']['vf-module'][0]['vf-module-id']
289 related_to = "service-instance"
290 search_key = "customer.global-customer-id"
291 rl_data_list = _get_aai_rel_link_data(data=response.body, related_to=related_to, search_key=search_key)
292 aai_data['service-info']['global-customer-id'] = rl_data_list[0]['d_value']
294 search_key = "service-subscription.service-type"
295 rl_data_list = _get_aai_rel_link_data(data=response.body, related_to=related_to, search_key=search_key)
296 aai_data['service-info']['service-type'] = rl_data_list[0]['d_value']
298 search_key = "service-instance.service-instance-id"
299 rl_data_list = _get_aai_rel_link_data(data=response.body, related_to=related_to, search_key=search_key)
300 aai_data['service-info']['service-instance-id'] = rl_data_list[0]['d_value']
302 service_link = rl_data_list[0]['link']
303 response = api.aai.link(service_link, body=None, params={}, headers={})
305 related_to = "generic-vnf"
306 search_key = "generic-vnf.vnf-id"
307 rl_data_list = _get_aai_rel_link_data(data=response.body, related_to=related_to, search_key=search_key)
308 for i in range(0, len(rl_data_list)):
309 vnf_id = rl_data_list[i]['d_value']
311 if vnf_id != vfw_vnf_id:
312 vnf_link = rl_data_list[i]['link']
313 response = api.aai.link(vnf_link, body=None, params={}, headers={})
314 if aai_data['vfw-model-info']['model-invariant-id'] != response.body.get('model-invariant-id'):
315 aai_data['vpgn-model-info']['model-invariant-id'] = response.body.get('model-invariant-id')
316 aai_data['vpgn-model-info']['model-version-id'] = response.body.get('model-version-id')
317 aai_data['vpgn-model-info']['vnf-name'] = response.body.get('vnf-name')
318 aai_data['vpgn-model-info']['vnf-type'] = response.body.get('vnf-type')
323 def _osdf_request(rancher_ip, onap_ip, aai_data, exclude, use_oof_cache):
324 dirname = os.path.join('templates/oof-cache/', aai_data['vf-module-id'])
326 file = os.path.join(dirname, 'sample-osdf-excluded.json')
328 file = os.path.join(dirname, 'sample-osdf-required.json')
329 if use_oof_cache and os.path.exists(file):
330 migrate_from = json.loads(open(file).read())
333 print('Making OSDF request for excluded {}'.format(str(exclude)))
334 api = _init_python_osdf_api(onap_ip)
335 request_id = str(uuid.uuid4())
336 transaction_id = str(uuid.uuid4())
337 callback_url = "http://{}:9000/osdfCallback/".format(str(rancher_ip))
338 template = json.loads(open('templates/osdfRequest.json').read())
339 template["requestInfo"]["transactionId"] = transaction_id
340 template["requestInfo"]["requestId"] = request_id
341 template["requestInfo"]["callbackUrl"] = callback_url
342 template["serviceInfo"]["serviceInstanceId"] = aai_data['service-info']['service-instance-id']
343 template["placementInfo"]["requestParameters"]["chosenCustomerId"] = aai_data['service-info']['global-customer-id']
344 template["placementInfo"]["placementDemands"][0]["resourceModelInfo"]["modelInvariantId"] =\
345 aai_data['vfw-model-info']['model-invariant-id']
346 template["placementInfo"]["placementDemands"][0]["resourceModelInfo"]["modelVersionId"] =\
347 aai_data['vfw-model-info']['model-version-id']
348 template["placementInfo"]["placementDemands"][1]["resourceModelInfo"]["modelInvariantId"] =\
349 aai_data['vpgn-model-info']['model-invariant-id']
350 template["placementInfo"]["placementDemands"][1]["resourceModelInfo"]["modelVersionId"] =\
351 aai_data['vpgn-model-info']['model-version-id']
353 template["placementInfo"]["placementDemands"][0]["excludedCandidates"][0]["identifiers"].\
354 append(aai_data['vf-module-id'])
356 template["placementInfo"]["placementDemands"][0]["requiredCandidates"][0]["identifiers"].\
357 append(aai_data['vf-module-id'])
359 #print(json.dumps(template, indent=4))
361 with _no_ssl_verification():
362 response = api.osdf.placement(body=template, params={}, headers={})
363 #if response.body.get('error_message') is not None:
364 # raise Exception(response.body['error_message']['explanation'])
367 while counter < 600 and osdf_response["last"]["id"] != request_id:
369 if counter % 20 == 0:
373 if osdf_response["last"]["id"] == request_id:
374 status = osdf_response["last"]["data"]["requestStatus"]
375 if status == "completed":
377 "solution": osdf_response["last"]["data"]["solutions"]["placementSolutions"]
379 if not os.path.exists(dirname):
382 f.write(json.dumps(result, indent=4))
386 message = osdf_response["last"]["data"]["statusMessage"]
387 raise Exception("OOF request {}: {}".format(status, message))
389 raise Exception("No response for OOF request")
392 def _has_request(onap_ip, aai_data, exclude, use_oof_cache):
393 dirname = os.path.join('templates/oof-cache/', aai_data['vf-module-id'])
395 file = os.path.join(dirname, 'sample-has-excluded.json')
397 file = os.path.join(dirname, 'sample-has-required.json')
398 if use_oof_cache and os.path.exists(file):
399 migrate_from = json.loads(open(file).read())
402 print('Making HAS request for excluded {}'.format(str(exclude)))
403 api = _init_python_has_api(onap_ip)
404 request_id = str(uuid.uuid4())
405 template = json.loads(open('templates/hasRequest.json').read())
407 template['name'] = request_id
408 node = template['template']['parameters']
409 node['chosen_customer_id'] = aai_data['service-info']['global-customer-id']
410 node['service_id'] = aai_data['service-info']['service-instance-id']
411 node = template['template']['demands']['vFW-SINK'][0]
412 node['attributes']['model-invariant-id'] = aai_data['vfw-model-info']['model-invariant-id']
413 node['attributes']['model-version-id'] = aai_data['vfw-model-info']['model-version-id']
415 node['excluded_candidates'][0]['candidate_id'][0] = aai_data['vf-module-id']
416 del node['required_candidates']
418 node['required_candidates'][0]['candidate_id'][0] = aai_data['vf-module-id']
419 del node['excluded_candidates']
420 node = template['template']['demands']['vPGN'][0]
421 node['attributes']['model-invariant-id'] = aai_data['vpgn-model-info']['model-invariant-id']
422 node['attributes']['model-version-id'] = aai_data['vpgn-model-info']['model-version-id']
424 #print(json.dumps(template, indent=4))
426 with _no_ssl_verification():
427 response = api.has.plans(body=template, params={}, headers={})
428 if response.body.get('error_message') is not None:
429 raise Exception(response.body['error_message']['explanation'])
431 plan_id = response.body['id']
432 response = api.has.plan(plan_id, body=None, params={}, headers={})
433 status = response.body['plans'][0]['status']
434 while status != 'done' and status != 'error':
436 response = api.has.plan(plan_id, body=None, params={}, headers={})
437 status = response.body['plans'][0]['status']
439 result = response.body['plans'][0]['recommendations'][0]
441 raise Exception(response.body['plans'][0]['message'])
443 if not os.path.exists(dirname):
446 f.write(json.dumps(result, indent=4))
451 def _extract_has_appc_identifiers(has_result, demand):
453 v_server = has_result[demand]['attributes']['vservers'][0]
455 if len(has_result[demand]['attributes']['vservers'][0]['l-interfaces']) == 4:
456 v_server = has_result[demand]['attributes']['vservers'][0]
458 v_server = has_result[demand]['attributes']['vservers'][1]
459 for itf in v_server['l-interfaces']:
460 if itf['ipv4-addresses'][0].startswith("10.0."):
461 ip = itf['ipv4-addresses'][0]
464 if v_server['vserver-name'] in hostname_cache and demand != 'vPGN':
465 v_server['vserver-name'] = v_server['vserver-name'].replace("01", "02")
466 hostname_cache.append(v_server['vserver-name'])
469 'vnf-id': has_result[demand]['attributes']['nf-id'],
470 'vf-module-id': has_result[demand]['attributes']['vf-module-id'],
472 'vserver-id': v_server['vserver-id'],
473 'vserver-name': v_server['vserver-name'],
474 'vnfc-type': demand.lower(),
475 'physical-location-id': has_result[demand]['attributes']['physical-location-id']
477 ansible_inventory_entry = "{} ansible_ssh_host={} ansible_ssh_user=ubuntu".format(config['vserver-name'], config['ip'])
478 if demand.lower() not in ansible_inventory:
479 ansible_inventory[demand.lower()] = {}
480 ansible_inventory[demand.lower()][config['vserver-name']] = ansible_inventory_entry
484 def _extract_osdf_appc_identifiers(has_result, demand):
486 v_server = has_result[demand]['vservers'][0]
488 if len(has_result[demand]['vservers'][0]['l-interfaces']) == 4:
489 v_server = has_result[demand]['vservers'][0]
491 v_server = has_result[demand]['vservers'][1]
492 for itf in v_server['l-interfaces']:
493 if itf['ipv4-addresses'][0].startswith("10.0."):
494 ip = itf['ipv4-addresses'][0]
497 if v_server['vserver-name'] in hostname_cache and demand != 'vPGN':
498 v_server['vserver-name'] = v_server['vserver-name'].replace("01", "02")
499 hostname_cache.append(v_server['vserver-name'])
502 'vnf-id': has_result[demand]['nf-id'],
503 'vf-module-id': has_result[demand]['vf-module-id'],
505 'vserver-id': v_server['vserver-id'],
506 'vserver-name': v_server['vserver-name'],
507 'vnfc-type': demand.lower(),
508 'physical-location-id': has_result[demand]['locationId']
510 ansible_inventory_entry = "{} ansible_ssh_host={} ansible_ssh_user=ubuntu".format(config['vserver-name'], config['ip'])
511 if demand.lower() not in ansible_inventory:
512 ansible_inventory[demand.lower()] = {}
513 ansible_inventory[demand.lower()][config['vserver-name']] = ansible_inventory_entry
517 def _extract_has_appc_dt_config(has_result, demand):
522 "nf-type": has_result[demand]['attributes']['nf-type'],
523 "nf-name": has_result[demand]['attributes']['nf-name'],
524 "vf-module-name": has_result[demand]['attributes']['vf-module-name'],
525 "vnf-type": has_result[demand]['attributes']['vnf-type'],
526 "service_instance_id": "319e60ef-08b1-47aa-ae92-51b97f05e1bc",
527 "cloudClli": has_result[demand]['attributes']['physical-location-id'],
528 "nf-id": has_result[demand]['attributes']['nf-id'],
529 "vf-module-id": has_result[demand]['attributes']['vf-module-id'],
530 "aic_version": has_result[demand]['attributes']['aic_version'],
531 "ipv4-oam-address": has_result[demand]['attributes']['ipv4-oam-address'],
532 "vnfHostName": has_result[demand]['candidate']['host_id'],
533 "ipv6-oam-address": has_result[demand]['attributes']['ipv6-oam-address'],
534 "cloudOwner": has_result[demand]['candidate']['cloud_owner'],
535 "isRehome": has_result[demand]['candidate']['is_rehome'],
536 "locationId": has_result[demand]['candidate']['location_id'],
537 "locationType": has_result[demand]['candidate']['location_type'],
538 'vservers': has_result[demand]['attributes']['vservers']
543 def _extract_osdf_appc_dt_config(osdf_result, demand):
547 return osdf_result[demand]
550 def _build_config_from_has(has_result):
551 v_pgn_result = _extract_has_appc_identifiers(has_result, 'vPGN')
552 v_fw_result = _extract_has_appc_identifiers(has_result, 'vFW-SINK')
553 dt_config = _extract_has_appc_dt_config(has_result, 'vFW-SINK')
556 'vPGN': v_pgn_result,
557 'vFW-SINK': v_fw_result
559 #print(json.dumps(config, indent=4))
560 config['dt-config'] = {
561 'destinations': [dt_config]
566 def _adapt_osdf_result(osdf_result):
568 demand = _build_osdf_result_demand(osdf_result["solution"][0][0])
569 result[demand["name"]] = demand["value"]
570 demand = _build_osdf_result_demand(osdf_result["solution"][0][1])
571 result[demand["name"]] = demand["value"]
575 def _build_osdf_result_demand(solution):
577 result["name"] = solution["resourceModuleName"]
578 value = {"candidateId": solution["solution"]["identifiers"][0]}
579 for info in solution["assignmentInfo"]:
580 value[info["key"]] = info["value"]
581 result["value"] = value
585 def _build_config_from_osdf(osdf_result):
586 osdf_result = _adapt_osdf_result(osdf_result)
587 v_pgn_result = _extract_osdf_appc_identifiers(osdf_result, 'vPGN')
588 v_fw_result = _extract_osdf_appc_identifiers(osdf_result, 'vFW-SINK')
589 dt_config = _extract_osdf_appc_dt_config(osdf_result, 'vFW-SINK')
592 'vPGN': v_pgn_result,
593 'vFW-SINK': v_fw_result
595 #print(json.dumps(config, indent=4))
596 config['dt-config'] = {
597 'destinations': [dt_config]
602 def _build_appc_lcm_dt_payload(is_vpkg, oof_config, book_name, traffic_presence):
603 is_check = traffic_presence is not None
604 oof_config = copy.deepcopy(oof_config)
606 # node_list = "[ {} ]".format(oof_config['vPGN']['vserver-id'])
608 # node_list = "[ {} ]".format(oof_config['vFW-SINK']['vserver-id'])
611 config = oof_config['vPGN']
613 config = oof_config['vFW-SINK']
615 # 'site': config['physical-location-id'],
616 # 'vnfc_type': config['vnfc-type'],
618 # 'ne_id': config['vserver-name'],
619 # 'fixed_ip_address': config['ip']
623 #node_list.append(node)
626 oof_config['dt-config']['trafficpresence'] = traffic_presence
628 file_content = oof_config['dt-config']
631 "configuration-parameters": {
632 #"node_list": node_list,
633 "ne_id": config['vserver-name'],
634 "fixed_ip_address": config['ip'],
635 "file_parameter_content": json.dumps(file_content)
639 config["configuration-parameters"]["book_name"] = book_name
640 payload = json.dumps(config)
644 def _build_appc_lcm_status_body(req):
646 'request-id': req['input']['common-header']['request-id'],
647 'sub-request-id': req['input']['common-header']['sub-request-id'],
648 'originator-id': req['input']['common-header']['originator-id']
650 payload = json.dumps(payload)
651 template = json.loads(open('templates/appcRestconfLcm.json').read())
652 template['input']['action'] = 'ActionStatus'
653 template['input']['payload'] = payload
654 template['input']['common-header']['request-id'] = req['input']['common-header']['request-id']
655 template['input']['common-header']['sub-request-id'] = str(uuid.uuid4())
656 template['input']['action-identifiers']['vnf-id'] = req['input']['action-identifiers']['vnf-id']
660 def _build_appc_lcm_request_body(is_vpkg, config, req_id, action, traffic_presence=None):
666 book_name = "{}/latest/ansible/{}/site.yml".format(demand.lower(), action.lower())
667 payload = _build_appc_lcm_dt_payload(is_vpkg, config, book_name, traffic_presence)
668 template = json.loads(open('templates/appcRestconfLcm.json').read())
669 template['input']['action'] = action
670 template['input']['payload'] = payload
671 template['input']['common-header']['request-id'] = req_id
672 template['input']['common-header']['sub-request-id'] = str(uuid.uuid4())
673 template['input']['action-identifiers']['vnf-id'] = config[demand]['vnf-id']
677 def _set_appc_lcm_timestamp(body, timestamp=None):
678 if timestamp is None:
679 t = datetime.utcnow() + timedelta(seconds=-10)
680 timestamp = t.strftime('%Y-%m-%dT%H:%M:%S.244Z')
681 body['input']['common-header']['timestamp'] = timestamp
684 def build_appc_lcms_requests_body(rancher_ip, onap_ip, aai_data, use_oof_cache, if_close_loop_vfw):
688 migrate_from = _has_request(onap_ip, aai_data, False, use_oof_cache)
690 if if_close_loop_vfw:
691 migrate_to = migrate_from
693 migrate_to = _has_request(onap_ip, aai_data, True, use_oof_cache)
695 migrate_from = _build_config_from_has(migrate_from)
696 migrate_to = _build_config_from_has(migrate_to)
698 migrate_from = _osdf_request(rancher_ip, onap_ip, aai_data, False, use_oof_cache)
700 if if_close_loop_vfw:
701 migrate_to = migrate_from
703 migrate_to = _osdf_request(rancher_ip, onap_ip, aai_data, True, use_oof_cache)
705 migrate_from = _build_config_from_osdf(migrate_from)
706 migrate_to = _build_config_from_osdf(migrate_to)
708 #print(json.dumps(migrate_from, indent=4))
709 #print(json.dumps(migrate_to, indent=4))
710 req_id = str(uuid.uuid4())
711 payload_dt_check_vpkg = _build_appc_lcm_request_body(True, migrate_from, req_id, 'DistributeTrafficCheck', True)
712 payload_dt_vpkg_to = _build_appc_lcm_request_body(True, migrate_to, req_id, 'DistributeTraffic')
713 payload_dt_check_vfw_from = _build_appc_lcm_request_body(False, migrate_from, req_id, 'DistributeTrafficCheck',
715 payload_dt_check_vfw_to = _build_appc_lcm_request_body(False, migrate_to, req_id, 'DistributeTrafficCheck', True)
718 result.append(payload_dt_check_vpkg)
719 result.append(payload_dt_vpkg_to)
720 result.append(payload_dt_check_vfw_from)
721 result.append(payload_dt_check_vfw_to)
725 def appc_lcm_request(onap_ip, req):
726 api = _init_python_appc_lcm_api(onap_ip)
727 #print(json.dumps(req, indent=4))
728 if req['input']['action'] == "DistributeTraffic":
729 result = api.lcm.distribute_traffic(body=req, params={}, headers={})
730 elif req['input']['action'] == "DistributeTrafficCheck":
731 result = api.lcm.distribute_traffic_check(body=req, params={}, headers={})
733 raise Exception("{} action not supported".format(req['input']['action']))
735 if result.body['output']['status']['code'] == 400:
736 print("Request Completed")
737 elif result.body['output']['status']['code'] == 100:
738 print("Request Accepted. Receiving result status...")
739 # elif result.body['output']['status']['code'] == 311:
740 # timestamp = result.body['output']['common-header']['timestamp']
741 # _set_appc_lcm_timestamp(req, timestamp)
742 # appc_lcm_request(onap_ip, req)
745 raise Exception("{} - {}".format(result.body['output']['status']['code'],
746 result.body['output']['status']['message']))
748 return result.body['output']['status']['code']
751 def appc_lcm_status_request(onap_ip, req):
752 api = _init_python_appc_lcm_api(onap_ip)
753 status_body = _build_appc_lcm_status_body(req)
754 _set_appc_lcm_timestamp(status_body)
756 result = api.lcm.action_status(body=status_body, params={}, headers={})
758 if result.body['output']['status']['code'] == 400:
759 status = json.loads(result.body['output']['payload'])
762 raise Exception("{} - {}".format(result.body['output']['status']['code'],
763 result.body['output']['status']['message']))
766 def confirm_appc_lcm_action(onap_ip, req, check_appc_result):
767 print("Checking LCM {} Status".format(req['input']['action']))
771 status = appc_lcm_status_request(onap_ip, req)
772 print(status['status'])
773 if status['status'] == 'SUCCESSFUL':
775 elif status['status'] == 'IN_PROGRESS':
777 elif check_appc_result:
778 raise Exception("LCM {} {} - {}".format(req['input']['action'], status['status'], status['status-reason']))
783 def execute_workflow(vfw_vnf_id, rancher_ip, onap_ip, use_oof_cache, if_close_loop_vfw, info_only, check_result):
784 print("\nExecuting workflow for VNF ID '{}' on Rancher with IP {} and ONAP with IP {}".format(
785 vfw_vnf_id, rancher_ip, onap_ip))
786 print("\nOOF Cache {}, is CL vFW {}, only info {}, check LCM result {}".format(use_oof_cache, if_close_loop_vfw,
787 info_only, check_result))
788 x = threading.Thread(target=_run_osdf_resp_server, daemon=True)
790 aai_data = load_aai_data(vfw_vnf_id, onap_ip)
791 print("\nvFWDT Service Information:")
792 print(json.dumps(aai_data, indent=4))
793 lcm_requests = build_appc_lcms_requests_body(rancher_ip, onap_ip, aai_data, use_oof_cache, if_close_loop_vfw)
794 print("\nAnsible Inventory:")
795 for key in ansible_inventory:
796 print("[{}]".format(key))
797 for host in ansible_inventory[key]:
798 print(ansible_inventory[key][host])
802 print("\nDistribute Traffic Workflow Execution:")
803 for i in range(len(lcm_requests)):
804 req = lcm_requests[i]
805 print("APPC REQ {} - {}".format(i, req['input']['action']))
806 _set_appc_lcm_timestamp(req)
807 result = appc_lcm_request(onap_ip, req)
809 confirm_appc_lcm_action(onap_ip, req, check_result)
813 #vnf_id, Rancher node IP, K8s node IP, use OOF cache, if close loop vfw, if info_only, if check APPC result
814 execute_workflow(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4].lower() == 'true', sys.argv[5].lower() == 'true',
815 sys.argv[6].lower() == 'true', sys.argv[7].lower() == 'true')