Removing unused imports in python scripts
[demo.git] / tutorials / vFWDT / workflow / workflow.py
1 '''
2 /*-
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
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
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.
17 *
18 * ============LICENSE_END=========================================================
19 */
20 '''
21
22 import os
23 import json
24 import sys
25 import uuid
26 import time
27 import copy
28 import warnings
29 import contextlib
30 import requests
31 import simplejson
32 import http.server
33 import threading
34 from datetime import datetime
35 from datetime import timedelta
36 from simple_rest_client.api import API
37 from simple_rest_client.resource import Resource
38 from basicauth import encode
39 from urllib3.exceptions import InsecureRequestWarning
40
41
42 old_merge_environment_settings = requests.Session.merge_environment_settings
43
44
45 hostname_cache = []
46 ansible_inventory = {}
47 osdf_response = {"last": { "id": "id", "data": None}}
48 print_performance=False
49 stats = open("stats.csv", "w")
50 stats.write("operation;time\n")
51
52
53 class BaseServer(http.server.BaseHTTPRequestHandler):
54
55     def __init__(self, one, two, three):
56         self.osdf_resp = osdf_response
57         super().__init__(one, two, three)
58
59     def _set_headers(self):
60         self.send_response(200)
61         self.send_header('Content-type', 'application/json')
62         self.end_headers()
63
64     def do_GET(self):
65         self._set_headers()
66
67     def do_HEAD(self):
68         self._set_headers()
69
70     def do_POST(self):
71         self._set_headers()
72         self.data_string = self.rfile.read(int(self.headers['Content-Length']))
73         self.send_response(200)
74         self.end_headers()
75
76         data = simplejson.loads(self.data_string)
77         #print(json.dumps(data, indent=4))
78         self.osdf_resp["last"]["data"] = data
79         self.osdf_resp["last"]["id"] = data["requestId"]
80         with open("response.json", "w") as outfile:
81             simplejson.dump(data, outfile)
82
83
84 class timing(object):
85
86     def __init__(self, description):
87         self.description = description
88
89     def __call__(self, f):
90         def wrap(*args, **kwargs):
91             req = None
92             if f.__name__ == "appc_lcm_request" or f.__name__ == "confirm_appc_lcm_action":
93                 req = args[1]
94             description = self.description
95             if req is not None:
96                 description = self.description + ' ' + req['input']['action']
97             if description.find('>') < 0 and print_performance:
98                 print (('> {} START').format(description))
99             try:
100                 time1 = time.time()
101                 ret = f(*args, **kwargs)
102             finally:
103                 time2 = time.time()
104                 if print_performance:
105                     print ('> {} DONE {:0.3f} ms'.format(description, (time2-time1)*1000.0))
106                 stats.write("{};{:0.3f}\n".format(description, (time2-time1)*1000.0).replace(".", ","))
107             return ret
108         return wrap
109
110
111 def _run_osdf_resp_server():
112     server_address = ('', 9000)
113     httpd = http.server.HTTPServer(server_address, BaseServer)
114     print('Starting OSDF Response Server...')
115     httpd.serve_forever()
116
117
118 @contextlib.contextmanager
119 def _no_ssl_verification():
120     opened_adapters = set()
121     def merge_environment_settings(self, url, proxies, stream, verify, cert):
122         # Verification happens only once per connection so we need to close
123         # all the opened adapters once we're done. Otherwise, the effects of
124         # verify=False persist beyond the end of this context manager.
125         opened_adapters.add(self.get_adapter(url))
126
127         settings = old_merge_environment_settings(self, url, proxies, stream, verify, cert)
128         settings['verify'] = False
129
130         return settings
131
132     requests.Session.merge_environment_settings = merge_environment_settings
133     try:
134         with warnings.catch_warnings():
135             warnings.simplefilter('ignore', InsecureRequestWarning)
136             yield
137     finally:
138         requests.Session.merge_environment_settings = old_merge_environment_settings
139
140         for adapter in opened_adapters:
141             try:
142                 adapter.close()
143             except:
144                 pass
145
146
147 def _get_aai_rel_link_data(data, related_to, search_key=None, match_dict=None):
148     # some strings that we will encounter frequently
149     rel_lst = "relationship-list"
150     rkey = "relationship-key"
151     rval = "relationship-value"
152     rdata = "relationship-data"
153     response = list()
154     if match_dict:
155         m_key = match_dict.get('key')
156         m_value = match_dict.get('value')
157     else:
158         m_key = None
159         m_value = None
160     rel_dict = data.get(rel_lst)
161     if rel_dict:  # check if data has relationship lists
162         for key, rel_list in rel_dict.items():
163             for rel in rel_list:
164                 if rel.get("related-to") == related_to:
165                     dval = None
166                     matched = False
167                     link = rel.get("related-link")
168                     r_data = rel.get(rdata, [])
169                     if search_key:
170                         for rd in r_data:
171                             if rd.get(rkey) == search_key:
172                                 dval = rd.get(rval)
173                                 if not match_dict:  # return first match
174                                     response.append(
175                                         {"link": link, "d_value": dval}
176                                     )
177                                     break  # go to next relation
178                             if rd.get(rkey) == m_key \
179                                     and rd.get(rval) == m_value:
180                                 matched = True
181                         if match_dict and matched:  # if matching required
182                             response.append(
183                                 {"link": link, "d_value": dval}
184                             )
185                             # matched, return search value corresponding
186                             # to the matched r_data group
187                     else:  # no search key; just return the link
188                         response.append(
189                             {"link": link, "d_value": dval}
190                         )
191     if len(response) == 0:
192         response.append(
193             {"link": None, "d_value": None}
194         )
195     return response
196
197
198 class AAIApiResource(Resource):
199     actions = {
200         'generic_vnf': {'method': 'GET', 'url': 'network/generic-vnfs/generic-vnf/{}'},
201         'vnfc': {'method': 'GET', 'url': 'network/vnfcs/vnfc/{}'},
202         'link': {'method': 'GET', 'url': '{}'},
203         'service_instance': {'method': 'GET',
204                              'url': 'business/customers/customer/{}/service-subscriptions/service-subscription/{}/service-instances/service-instance/{}'}
205     }
206
207
208 class HASApiResource(Resource):
209     actions = {
210         'plans': {'method': 'POST', 'url': 'plans/'},
211         'plan': {'method': 'GET', 'url': 'plans/{}'}
212     }
213
214
215 class OSDFApiResource(Resource):
216     actions = {
217         'placement': {'method': 'POST', 'url': 'placement'}
218     }
219
220
221 class APPCLcmApiResource(Resource):
222     actions = {
223         'distribute_traffic': {'method': 'POST', 'url': 'appc-provider-lcm:distribute-traffic/'},
224         'distribute_traffic_check': {'method': 'POST', 'url': 'appc-provider-lcm:distribute-traffic-check/'},
225         'upgrade_software': {'method': 'POST', 'url': 'appc-provider-lcm:upgrade-software/'},
226         'upgrade_pre_check': {'method': 'POST', 'url': 'appc-provider-lcm:upgrade-pre-check/'},
227         'upgrade_post_check': {'method': 'POST', 'url': 'appc-provider-lcm:upgrade-post-check/'},
228         'action_status': {'method': 'POST', 'url': 'appc-provider-lcm:action-status/'},
229         'check_lock': {'method': 'POST', 'url': 'appc-provider-lcm:check-lock/'},
230         'lock': {'method': 'POST', 'url': 'appc-provider-lcm:lock/'},
231         'unlock': {'method': 'POST', 'url': 'appc-provider-lcm:unlock/'}
232     }
233
234
235 def _init_python_aai_api(onap_ip):
236     api = API(
237         api_root_url="https://{}:30233/aai/v14/".format(onap_ip),
238         params={},
239         headers={
240             'Authorization': encode("AAI", "AAI"),
241             'X-FromAppId': 'SCRIPT',
242             'Accept': 'application/json',
243             'Content-Type': 'application/json',
244             'X-TransactionId': str(uuid.uuid4()),
245         },
246         timeout=30,
247         append_slash=False,
248         json_encode_body=True # encode body as json
249     )
250     api.add_resource(resource_name='aai', resource_class=AAIApiResource)
251     return api
252
253
254 def _init_python_has_api(onap_ip):
255     api = API(
256         api_root_url="https://{}:30275/v1/".format(onap_ip),
257         params={},
258         headers={
259             'Authorization': encode("admin1", "plan.15"),
260             'X-FromAppId': 'SCRIPT',
261             'Accept': 'application/json',
262             'Content-Type': 'application/json',
263             'X-TransactionId': str(uuid.uuid4()),
264         },
265         timeout=30,
266         append_slash=False,
267         json_encode_body=True # encode body as json
268     )
269     api.add_resource(resource_name='has', resource_class=HASApiResource)
270     return api
271
272
273 def _init_python_osdf_api(onap_ip):
274     api = API(
275         api_root_url="https://{}:30248/api/oof/v1/".format(onap_ip),
276         params={},
277         headers={
278             'Authorization': encode("test", "testpwd"),
279             'X-FromAppId': 'SCRIPT',
280             'Accept': 'application/json',
281             'Content-Type': 'application/json',
282             'X-TransactionId': str(uuid.uuid4()),
283         },
284         timeout=30,
285         append_slash=False,
286         json_encode_body=True # encode body as json
287     )
288     api.add_resource(resource_name='osdf', resource_class=OSDFApiResource)
289     return api
290
291
292 def _init_python_appc_lcm_api(onap_ip):
293     api = API(
294         api_root_url="https://{}:30230/restconf/operations/".format(onap_ip),
295         params={},
296         headers={
297             'Authorization': encode("admin", "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U"),
298             'X-FromAppId': 'SCRIPT',
299             'Accept': 'application/json',
300             'Content-Type': 'application/json',
301         },
302         timeout=300,
303         append_slash=False,
304         json_encode_body=True # encode body as json
305     )
306     api.add_resource(resource_name='lcm', resource_class=APPCLcmApiResource)
307     return api
308
309
310 @timing("Load AAI Data")
311 def load_aai_data(vfw_vnf_id, onap_ip):
312     api = _init_python_aai_api(onap_ip)
313     aai_data = {}
314     aai_data['service-info'] = {'global-customer-id': '', 'service-instance-id': '', 'service-type': ''}
315     aai_data['vfw-model-info'] = {'model-invariant-id': '', 'model-version-id': '', 'vnf-name': '', 'vnf-type': ''}
316     aai_data['vpgn-model-info'] = {'model-invariant-id': '', 'model-version-id': '', 'vnf-name': '', 'vnf-type': ''}
317     with _no_ssl_verification():
318         response = api.aai.generic_vnf(vfw_vnf_id, body=None, params={'depth': 2}, headers={})
319         aai_data['vfw-model-info']['model-invariant-id'] = response.body.get('model-invariant-id')
320         aai_data['vfw-model-info']['model-version-id'] = response.body.get('model-version-id')
321         aai_data['vfw-model-info']['vnf-name'] = response.body.get('vnf-name')
322         aai_data['vfw-model-info']['vnf-type'] = response.body.get('vnf-type')
323         aai_data['vf-module-id'] = response.body['vf-modules']['vf-module'][0]['vf-module-id']
324
325         related_to = "service-instance"
326         search_key = "customer.global-customer-id"
327         rl_data_list = _get_aai_rel_link_data(data=response.body, related_to=related_to, search_key=search_key)
328         aai_data['service-info']['global-customer-id'] = rl_data_list[0]['d_value']
329
330         search_key = "service-subscription.service-type"
331         rl_data_list = _get_aai_rel_link_data(data=response.body, related_to=related_to, search_key=search_key)
332         aai_data['service-info']['service-type'] = rl_data_list[0]['d_value']
333
334         search_key = "service-instance.service-instance-id"
335         rl_data_list = _get_aai_rel_link_data(data=response.body, related_to=related_to, search_key=search_key)
336         aai_data['service-info']['service-instance-id'] = rl_data_list[0]['d_value']
337
338         service_link = rl_data_list[0]['link']
339         response = api.aai.link(service_link, body=None, params={}, headers={})
340
341         related_to = "generic-vnf"
342         search_key = "generic-vnf.vnf-id"
343         rl_data_list = _get_aai_rel_link_data(data=response.body, related_to=related_to, search_key=search_key)
344         for i in range(0, len(rl_data_list)):
345             vnf_id = rl_data_list[i]['d_value']
346
347             if vnf_id != vfw_vnf_id:
348                 vnf_link = rl_data_list[i]['link']
349                 response = api.aai.link(vnf_link, body=None, params={}, headers={})
350                 if aai_data['vfw-model-info']['model-invariant-id'] != response.body.get('model-invariant-id'):
351                     aai_data['vpgn-model-info']['model-invariant-id'] = response.body.get('model-invariant-id')
352                     aai_data['vpgn-model-info']['model-version-id'] = response.body.get('model-version-id')
353                     aai_data['vpgn-model-info']['vnf-name'] = response.body.get('vnf-name')
354                     aai_data['vpgn-model-info']['vnf-type'] = response.body.get('vnf-type')
355                     break
356     return aai_data
357
358
359 @timing("> OSDF REQ")
360 def _osdf_request(rancher_ip, onap_ip, aai_data, exclude, use_oof_cache):
361     dirname = os.path.join('templates/oof-cache/', aai_data['vf-module-id'])
362     if exclude:
363         file = os.path.join(dirname, 'sample-osdf-excluded.json')
364     else:
365         file = os.path.join(dirname, 'sample-osdf-required.json')
366     if use_oof_cache and os.path.exists(file):
367         migrate_from = json.loads(open(file).read())
368         return migrate_from
369
370     print('Making OSDF request for excluded {}'.format(str(exclude)))
371     api = _init_python_osdf_api(onap_ip)
372     request_id = str(uuid.uuid4())
373     transaction_id = str(uuid.uuid4())
374     callback_url = "http://{}:9000/osdfCallback/".format(str(rancher_ip))
375     template = json.loads(open('templates/osdfRequest.json').read())
376     template["requestInfo"]["transactionId"] = transaction_id
377     template["requestInfo"]["requestId"] = request_id
378     template["requestInfo"]["callbackUrl"] = callback_url
379     template["serviceInfo"]["serviceInstanceId"] = aai_data['service-info']['service-instance-id']
380     template["placementInfo"]["requestParameters"]["chosenCustomerId"] = aai_data['service-info']['global-customer-id']
381     template["placementInfo"]["placementDemands"][0]["resourceModelInfo"]["modelInvariantId"] =\
382         aai_data['vfw-model-info']['model-invariant-id']
383     template["placementInfo"]["placementDemands"][0]["resourceModelInfo"]["modelVersionId"] =\
384         aai_data['vfw-model-info']['model-version-id']
385     template["placementInfo"]["placementDemands"][1]["resourceModelInfo"]["modelInvariantId"] =\
386         aai_data['vpgn-model-info']['model-invariant-id']
387     template["placementInfo"]["placementDemands"][1]["resourceModelInfo"]["modelVersionId"] =\
388         aai_data['vpgn-model-info']['model-version-id']
389     if exclude:
390         template["placementInfo"]["placementDemands"][0]["excludedCandidates"][0]["identifiers"].\
391             append(aai_data['vf-module-id'])
392         del template["placementInfo"]["placementDemands"][0]["requiredCandidates"]
393     else:
394         template["placementInfo"]["placementDemands"][0]["requiredCandidates"][0]["identifiers"].\
395             append(aai_data['vf-module-id'])
396         del template["placementInfo"]["placementDemands"][0]["excludedCandidates"]
397
398     #print(json.dumps(template, indent=4))
399
400     with _no_ssl_verification():
401         response = api.osdf.placement(body=template, params={}, headers={})
402         #if response.body.get('error_message') is not None:
403         #    raise Exception(response.body['error_message']['explanation'])
404
405     counter = 0
406     while counter < 600 and osdf_response["last"]["id"] != request_id:
407         time.sleep(1)
408         if counter % 20 == 0:
409             print("solving")
410         counter += 1
411
412     if osdf_response["last"]["id"] == request_id:
413         status = osdf_response["last"]["data"]["requestStatus"]
414         if status == "completed":
415             result = {
416                 "solution": osdf_response["last"]["data"]["solutions"]["placementSolutions"]
417             }
418             if not os.path.exists(dirname):
419                 os.makedirs(dirname)
420             f = open(file, 'w+')
421             f.write(json.dumps(result, indent=4))
422             f.close()
423             return result
424         else:
425             message = osdf_response["last"]["data"]["statusMessage"]
426             raise Exception("OOF request {}: {}".format(status, message))
427     else:
428         raise Exception("No response for OOF request")
429
430
431 @timing("> HAS REQ")
432 def _has_request(onap_ip, aai_data, exclude, use_oof_cache):
433     dirname = os.path.join('templates/oof-cache/', aai_data['vf-module-id'])
434     if exclude:
435         file = os.path.join(dirname, 'sample-has-excluded.json')
436     else:
437         file = os.path.join(dirname, 'sample-has-required.json')
438     if use_oof_cache and os.path.exists(file):
439         migrate_from = json.loads(open(file).read())
440         return migrate_from
441
442     print('Making HAS request for excluded {}'.format(str(exclude)))
443     api = _init_python_has_api(onap_ip)
444     request_id = str(uuid.uuid4())
445     template = json.loads(open('templates/hasRequest.json').read())
446     result = {}
447     template['name'] = request_id
448     node = template['template']['parameters']
449     node['chosen_customer_id'] = aai_data['service-info']['global-customer-id']
450     node['service_id'] = aai_data['service-info']['service-instance-id']
451     node = template['template']['demands']['vFW-SINK'][0]
452     node['attributes']['model-invariant-id'] = aai_data['vfw-model-info']['model-invariant-id']
453     node['attributes']['model-version-id'] = aai_data['vfw-model-info']['model-version-id']
454     if exclude:
455         node['excluded_candidates'][0]['candidate_id'][0] = aai_data['vf-module-id']
456         del node['required_candidates']
457     else:
458         node['required_candidates'][0]['candidate_id'][0] = aai_data['vf-module-id']
459         del node['excluded_candidates']
460     node = template['template']['demands']['vPGN'][0]
461     node['attributes']['model-invariant-id'] = aai_data['vpgn-model-info']['model-invariant-id']
462     node['attributes']['model-version-id'] = aai_data['vpgn-model-info']['model-version-id']
463
464     #print(json.dumps(template, indent=4))
465
466     with _no_ssl_verification():
467         response = api.has.plans(body=template, params={}, headers={})
468         if response.body.get('error_message') is not None:
469             raise Exception(response.body['error_message']['explanation'])
470         else:
471             plan_id = response.body['id']
472             response = api.has.plan(plan_id, body=None, params={}, headers={})
473             status = response.body['plans'][0]['status']
474             while status != 'done' and status != 'error':
475                 print(status)
476                 response = api.has.plan(plan_id, body=None, params={}, headers={})
477                 status = response.body['plans'][0]['status']
478             if status == 'done':
479                 result = response.body['plans'][0]['recommendations'][0]
480             else:
481                 raise Exception(response.body['plans'][0]['message'])
482
483     if not os.path.exists(dirname):
484         os.makedirs(dirname)
485     f = open(file, 'w+')
486     f.write(json.dumps(result, indent=4))
487     f.close()
488     return result
489
490
491 def _extract_has_appc_identifiers(has_result, demand, onap_ip):
492     if demand == 'vPGN':
493         v_server = has_result[demand]['attributes']['vservers'][0]
494     else:
495         if len(has_result[demand]['attributes']['vservers'][0]['l-interfaces']) == 4:
496             v_server = has_result[demand]['attributes']['vservers'][0]
497         else:
498             v_server = has_result[demand]['attributes']['vservers'][1]
499     for itf in v_server['l-interfaces']:
500         if itf['ipv4-addresses'][0].startswith("10.0."):
501             ip = itf['ipv4-addresses'][0]
502             break
503
504     if v_server['vserver-name'] in hostname_cache and demand != 'vPGN':
505         v_server['vserver-name'] = v_server['vserver-name'].replace("01", "02")
506     hostname_cache.append(v_server['vserver-name'])
507
508     api = _init_python_aai_api(onap_ip)
509     vnfc_type = demand.lower()
510 #    with _no_ssl_verification():
511 #        response = api.aai.vnfc(v_server['vserver-name'], body=None, params={}, headers={})
512 #        vnfc_type = response.body.get('nfc-naming-code')
513
514     config = {
515         'vnf-id': has_result[demand]['attributes']['nf-id'],
516         'vf-module-id': has_result[demand]['attributes']['vf-module-id'],
517         'ip': ip,
518         'vserver-id': v_server['vserver-id'],
519         'vserver-name': v_server['vserver-name'],
520         'vnfc-type': vnfc_type,
521         'physical-location-id': has_result[demand]['attributes']['physical-location-id']
522     }
523     ansible_inventory_entry = "{} ansible_ssh_host={} ansible_ssh_user=ubuntu".format(config['vserver-name'], config['ip'])
524     if demand.lower() not in ansible_inventory:
525         ansible_inventory[demand.lower()] = {}
526     ansible_inventory[demand.lower()][config['vserver-name']] = ansible_inventory_entry
527     return config
528
529
530 def _extract_osdf_appc_identifiers(has_result, demand, onap_ip):
531     if demand == 'vPGN':
532         v_server = has_result[demand]['vservers'][0]
533     else:
534         if len(has_result[demand]['vservers'][0]['l-interfaces']) == 4:
535             v_server = has_result[demand]['vservers'][0]
536         else:
537             v_server = has_result[demand]['vservers'][1]
538     for itf in v_server['l-interfaces']:
539         if itf['ipv4-addresses'][0].startswith("10.0."):
540             ip = itf['ipv4-addresses'][0]
541             break
542
543     if v_server['vserver-name'] in hostname_cache and demand != 'vPGN':
544         v_server['vserver-name'] = v_server['vserver-name'].replace("01", "02")
545     hostname_cache.append(v_server['vserver-name'])
546
547     api = _init_python_aai_api(onap_ip)
548     vnfc_type = demand.lower(),
549     with _no_ssl_verification():
550         response = api.aai.vnfc(v_server['vserver-name'], body=None, params={}, headers={})
551         vnfc_type = response.body.get('nfc-naming-code')
552
553     config = {
554         'vnf-id': has_result[demand]['nf-id'],
555         'vf-module-id': has_result[demand]['vf-module-id'],
556         'ip': ip,
557         'vserver-id': v_server['vserver-id'],
558         'vserver-name': v_server['vserver-name'],
559         'vnfc-type': vnfc_type,
560         'physical-location-id': has_result[demand]['locationId']
561     }
562     ansible_inventory_entry = "{} ansible_ssh_host={} ansible_ssh_user=ubuntu".format(config['vserver-name'], config['ip'])
563     if demand.lower() not in ansible_inventory:
564         ansible_inventory[demand.lower()] = {}
565     ansible_inventory[demand.lower()][config['vserver-name']] = ansible_inventory_entry
566     return config
567
568
569 def _extract_has_appc_dt_config(has_result, demand):
570     if demand == 'vPGN':
571         return {}
572     else:
573         config = {
574             "nf-type": has_result[demand]['attributes']['nf-type'],
575             "nf-name": has_result[demand]['attributes']['nf-name'],
576             "vf-module-name": has_result[demand]['attributes']['vf-module-name'],
577             "vnf-type": has_result[demand]['attributes']['vnf-type'],
578             "service_instance_id": "319e60ef-08b1-47aa-ae92-51b97f05e1bc",
579             "cloudClli": has_result[demand]['attributes']['physical-location-id'],
580             "nf-id": has_result[demand]['attributes']['nf-id'],
581             "vf-module-id": has_result[demand]['attributes']['vf-module-id'],
582             "aic_version": has_result[demand]['attributes']['aic_version'],
583             "ipv4-oam-address": has_result[demand]['attributes']['ipv4-oam-address'],
584             "vnfHostName": has_result[demand]['candidate']['host_id'],
585             "cloudOwner": has_result[demand]['candidate']['cloud_owner'],
586             "isRehome": has_result[demand]['candidate']['is_rehome'],
587             "locationId": has_result[demand]['candidate']['location_id'],
588             "locationType": has_result[demand]['candidate']['location_type'],
589             'vservers': has_result[demand]['attributes']['vservers']
590         }
591         return config
592
593
594 def _extract_osdf_appc_dt_config(osdf_result, demand):
595     if demand == 'vPGN':
596         return {}
597     else:
598         return osdf_result[demand]
599
600
601 def _build_config_from_has(has_result, onap_ip):
602     v_pgn_result = _extract_has_appc_identifiers(has_result, 'vPGN', onap_ip)
603     v_fw_result = _extract_has_appc_identifiers(has_result, 'vFW-SINK', onap_ip)
604     dt_config = _extract_has_appc_dt_config(has_result, 'vFW-SINK')
605
606     config = {
607         'vPGN': v_pgn_result,
608         'vFW-SINK': v_fw_result
609     }
610     #print(json.dumps(config, indent=4))
611     config['dt-config'] = {
612         'destinations': [dt_config]
613     }
614     return config
615
616
617 def _adapt_osdf_result(osdf_result):
618     result = {}
619     demand = _build_osdf_result_demand(osdf_result["solution"][0][0])
620     result[demand["name"]] = demand["value"]
621     demand = _build_osdf_result_demand(osdf_result["solution"][0][1])
622     result[demand["name"]] = demand["value"]
623     return result
624
625
626 def _build_osdf_result_demand(solution):
627     result = {}
628     result["name"] = solution["resourceModuleName"]
629     value = {"candidateId": solution["solution"]["identifiers"][0]}
630     for info in solution["assignmentInfo"]:
631         value[info["key"]] = info["value"]
632     result["value"] = value
633     return result
634
635
636 def _build_config_from_osdf(osdf_result, onap_ip):
637     osdf_result = _adapt_osdf_result(osdf_result)
638     v_pgn_result = _extract_osdf_appc_identifiers(osdf_result, 'vPGN', onap_ip)
639     v_fw_result = _extract_osdf_appc_identifiers(osdf_result, 'vFW-SINK', onap_ip)
640     dt_config = _extract_osdf_appc_dt_config(osdf_result, 'vFW-SINK')
641
642     config = {
643         'vPGN': v_pgn_result,
644         'vFW-SINK': v_fw_result
645     }
646     #print(json.dumps(config, indent=4))
647     config['dt-config'] = {
648         'destinations': [dt_config]
649     }
650     return config
651
652
653 def _build_appc_lcm_dt_payload(demand, oof_config, action, traffic_presence):
654     is_check = traffic_presence is not None
655     oof_config = copy.deepcopy(oof_config)
656     #if is_vpkg:
657     #    node_list = "[ {} ]".format(oof_config['vPGN']['vserver-id'])
658     #else:
659     #    node_list = "[ {} ]".format(oof_config['vFW-SINK']['vserver-id'])
660     book_name = "{}/latest/ansible/{}/site.yml".format(demand.lower(), action.lower())
661     config = oof_config[demand]
662     #node = {
663     #    'site': config['physical-location-id'],
664     #    'vnfc_type': config['vnfc-type'],
665     #    'vm_info': [{
666     #        'ne_id': config['vserver-name'],
667     #        'fixed_ip_address': config['ip']
668     #   }]
669     #}
670     #node_list = list()
671     #node_list.append(node)
672
673     if is_check:
674         oof_config['dt-config']['trafficpresence'] = traffic_presence
675
676     file_content = oof_config['dt-config']
677
678     config = {
679         "configuration-parameters": {
680             "file_parameter_content":  json.dumps(file_content)
681         },
682         "request-parameters": {
683             "vserver-id": config['vserver-id']
684         }
685     }
686     if book_name != '':
687         config["configuration-parameters"]["book_name"] = book_name
688     payload = json.dumps(config)
689     return payload
690
691
692 def _build_appc_lcm_upgrade_payload(demand, oof_config, action, old_version, new_version):
693     oof_config = copy.deepcopy(oof_config)
694     book_name = "{}/latest/ansible/{}/site.yml".format(demand.lower(), action.lower())
695     config = oof_config[demand]
696
697     file_content = {}  #oof_config['dt-config']
698
699     config = {
700         "configuration-parameters": {
701             "file_parameter_content":  json.dumps(file_content),
702             "existing-software-version": old_version,
703             "new-software-version": new_version
704         },
705         "request-parameters": {
706             "vserver-id": config['vserver-id']
707         }
708     }
709     if book_name != '':
710         config["configuration-parameters"]["book_name"] = book_name
711     payload = json.dumps(config)
712     return payload
713
714
715 def _build_appc_lcm_status_body(req):
716     payload = {
717         'request-id': req['input']['common-header']['request-id'],
718         'sub-request-id': req['input']['common-header']['sub-request-id'],
719         'originator-id': req['input']['common-header']['originator-id']
720     }
721     payload = json.dumps(payload)
722     template = json.loads(open('templates/appcRestconfLcm.json').read())
723     template['input']['action'] = 'ActionStatus'
724     template['input']['payload'] = payload
725     template['input']['common-header']['request-id'] = req['input']['common-header']['request-id']
726     template['input']['common-header']['sub-request-id'] = str(uuid.uuid4())
727     template['input']['action-identifiers']['vnf-id'] = req['input']['action-identifiers']['vnf-id']
728     return template
729
730
731 @timing("> DT REQ BODY")
732 def _build_appc_lcm_lock_request_body(is_vpkg, config, req_id, action):
733     if is_vpkg:
734         demand = 'vPGN'
735     else:
736         demand = 'vFW-SINK'
737     return _build_appc_lcm_request_body(None, demand, config, req_id, action)
738
739
740 @timing("> DT REQ BODY")
741 def _build_appc_lcm_dt_request_body(is_vpkg, config, req_id, action, traffic_presence=None):
742     if is_vpkg:
743         demand = 'vPGN'
744     else:
745         demand = 'vFW-SINK'
746     payload = _build_appc_lcm_dt_payload(demand, config, action, traffic_presence)
747     return _build_appc_lcm_request_body(payload, demand, config, req_id, action)
748
749
750 @timing("> UP REQ BODY")
751 def _build_appc_lcm_upgrade_request_body(config, req_id, action, old_version, new_version):
752     demand = 'vFW-SINK'
753     payload = _build_appc_lcm_upgrade_payload(demand, config, action, old_version, new_version)
754     return _build_appc_lcm_request_body(payload, demand, config, req_id, action)
755
756
757 def _build_appc_lcm_request_body(payload, demand, config, req_id, action):
758     #print(config[demand])
759     template = json.loads(open('templates/appcRestconfLcm.json').read())
760     template['input']['action'] = action
761     if payload is not None:
762         template['input']['payload'] = payload
763     else:
764         del template['input']['payload']
765     template['input']['common-header']['request-id'] = req_id
766     template['input']['common-header']['sub-request-id'] = str(uuid.uuid4())
767     template['input']['action-identifiers']['vnf-id'] = config[demand]['vnf-id']
768     return template
769
770
771 def _set_appc_lcm_timestamp(body, timestamp=None):
772     if timestamp is None:
773         t = datetime.utcnow() + timedelta(seconds=-10)
774         timestamp = t.strftime('%Y-%m-%dT%H:%M:%S.244Z')
775     body['input']['common-header']['timestamp'] = timestamp
776
777
778 @timing("Load OOF Data and Build APPC REQ")
779 def build_appc_lcms_requests_body(rancher_ip, onap_ip, aai_data, use_oof_cache, if_close_loop_vfw, new_version=None):
780     if_has = True
781
782     if if_has:
783         migrate_from = _has_request(onap_ip, aai_data, False, use_oof_cache)
784
785         if if_close_loop_vfw:
786             migrate_to = migrate_from
787         else:
788             migrate_to = _has_request(onap_ip, aai_data, True, use_oof_cache)
789
790         migrate_from = _build_config_from_has(migrate_from, onap_ip)
791         migrate_to = _build_config_from_has(migrate_to, onap_ip)
792     else:
793         migrate_from = _osdf_request(rancher_ip, onap_ip, aai_data, False, use_oof_cache)
794
795         if if_close_loop_vfw:
796             migrate_to = migrate_from
797         else:
798             migrate_to = _osdf_request(rancher_ip, onap_ip, aai_data, True, use_oof_cache)
799
800         migrate_from = _build_config_from_osdf(migrate_from, onap_ip)
801         migrate_to = _build_config_from_osdf(migrate_to, onap_ip)
802
803     #print(json.dumps(migrate_from, indent=4))
804     #print(json.dumps(migrate_to, indent=4))
805     req_id = str(uuid.uuid4())
806     result = list()
807     old_version = 2.0
808     if_dt_only = new_version is None
809     if new_version is not None and new_version != "1.0":
810         old_version = 1.0
811
812     requests = list()
813     include_lock = True
814
815     if include_lock:
816         result.append({"payload": _build_appc_lcm_lock_request_body(True, migrate_from, req_id, 'CheckLock'), "breakOnFailure": True,
817                       "description": "Check vPGN Lock Status"})
818         result.append({"payload": _build_appc_lcm_lock_request_body(False, migrate_from, req_id, 'CheckLock'), "breakOnFailure": True,
819                       "description": "Check vFW-1 Lock Status"})
820         result.append({"payload": _build_appc_lcm_lock_request_body(False, migrate_to, req_id, 'CheckLock'), "breakOnFailure": True,
821                       "description": "Check vFW-2 Lock "})
822
823         result.append({"payload": _build_appc_lcm_lock_request_body(True, migrate_from, req_id, 'Lock'), "breakOnFailure": True,
824                       "description": "Lock vPGN"})
825         result.append({"payload": _build_appc_lcm_lock_request_body(False, migrate_from, req_id, 'Lock'), "breakOnFailure": True,
826                       "description": "Lock vFW-1"})
827         result.append({"payload": _build_appc_lcm_lock_request_body(False, migrate_to, req_id, 'Lock'), "breakOnFailure": True,
828                       "description": "Lock vFW-2"})
829
830     if if_dt_only:
831         payload_dt_check_vpkg = _build_appc_lcm_dt_request_body(True, migrate_from, req_id, 'DistributeTrafficCheck', True)
832         payload_dt_vpkg_to = _build_appc_lcm_dt_request_body(True, migrate_to, req_id, 'DistributeTraffic')
833         payload_dt_check_vfw_from = _build_appc_lcm_dt_request_body(False, migrate_from, req_id, 'DistributeTrafficCheck',
834                                                                     False)
835         payload_dt_check_vfw_to = _build_appc_lcm_dt_request_body(False, migrate_to, req_id, 'DistributeTrafficCheck', True)
836
837         requests.append({"payload": payload_dt_vpkg_to, "breakOnFailure": True, "description": "Migrating source vFW traffic to destination vFW"})
838         requests.append({"payload": payload_dt_check_vfw_from, "breakOnFailure": True, "description": "Checking traffic has been stopped on the source vFW"})
839         requests.append({"payload": payload_dt_check_vfw_to, "breakOnFailure": True, "description": "Checking traffic has appeared on the destination vFW"})
840         result.append({"payload": payload_dt_check_vpkg, "breakOnFailure": False, "description": "Check current traffic destination on vPGN",
841                       "workflow": {"requests": requests, "description": "Migrate Traffic and Verify"}})
842     else:
843         #_build_appc_lcm_dt_request_body(is_vpkg, config, req_id, action, traffic_presence=None):
844         payload_dt_check_vpkg = _build_appc_lcm_dt_request_body(True, migrate_from, req_id, 'DistributeTrafficCheck', True)
845         payload_dt_vpkg_to = _build_appc_lcm_dt_request_body(True, migrate_to, req_id, 'DistributeTraffic')
846         payload_dt_vpkg_from = _build_appc_lcm_dt_request_body(True, migrate_from, req_id, 'DistributeTraffic')
847
848         payload_dt_check_vfw_from_absent = _build_appc_lcm_dt_request_body(False, migrate_from, req_id, 'DistributeTrafficCheck', False)
849         payload_dt_check_vfw_to_present = _build_appc_lcm_dt_request_body(False, migrate_to, req_id, 'DistributeTrafficCheck', True)
850         payload_dt_check_vfw_to_absent = _build_appc_lcm_dt_request_body(False, migrate_to, req_id, 'DistributeTrafficCheck', False)
851         payload_dt_check_vfw_from_present = _build_appc_lcm_dt_request_body(False, migrate_from, req_id, 'DistributeTrafficCheck', True)
852
853         payload_old_version_check_vfw_from =  _build_appc_lcm_upgrade_request_body(migrate_from, req_id, 'UpgradePreCheck', old_version, new_version)
854         payload_new_version_check_vfw_from =  _build_appc_lcm_upgrade_request_body(migrate_from, req_id, 'UpgradePostCheck', old_version, new_version)
855         payload_upgrade_vfw_from =  _build_appc_lcm_upgrade_request_body(migrate_from, req_id, 'UpgradeSoftware', old_version, new_version)
856
857         migrate_requests = list()
858         migrate_requests.append({"payload": payload_dt_vpkg_to, "breakOnFailure": True, "description": "Migrating source vFW traffic to destination vFW"})
859         migrate_requests.append({"payload": payload_dt_check_vfw_from_absent, "breakOnFailure": True, "description": "Checking traffic has been stopped on the source vFW"})
860         migrate_requests.append({"payload": payload_dt_check_vfw_to_present, "breakOnFailure": True, "description": "Checking traffic has appeared on the destination vFW"})
861
862         requests.append({"payload": payload_dt_check_vpkg, "breakOnFailure": False, "description": "Check current traffic destination on vPGN",
863                         "workflow": {"requests": migrate_requests, "description": "Migrate Traffic and Verify"}})
864         requests.append({"payload": payload_upgrade_vfw_from, "breakOnFailure": True, "description": "Upgrading Software on source vFW"})
865         requests.append({"payload": payload_new_version_check_vfw_from, "breakOnFailure": True, "description": "Check current software version on source vFW"})
866         requests.append({"payload": payload_dt_vpkg_from, "breakOnFailure": True, "description": "Migrating destination vFW traffic to source vFW"})
867         requests.append({"payload": payload_dt_check_vfw_to_absent, "breakOnFailure": True, "description": "Checking traffic has been stopped on the destination vFW"})
868         requests.append({"payload": payload_dt_check_vfw_from_present, "breakOnFailure": True, "description": "Checking traffic has appeared on the source vFW"})
869
870         result.append({"payload": payload_old_version_check_vfw_from, "breakOnFailure": False, "description": "Check current software version on source vFW",
871                       "workflow": {"requests": requests, "description": "Migrate Traffic and Upgrade Software"}})
872
873     if include_lock:
874         result.append({"payload": _build_appc_lcm_lock_request_body(True, migrate_from, req_id, 'Unlock'), "breakOnFailure": False,
875                       "description": "Unlock vPGN"})
876         result.append({"payload": _build_appc_lcm_lock_request_body(False, migrate_from, req_id, 'Unlock'), "breakOnFailure": False,
877                       "description": "Unlock vFW-1"})
878         result.append({"payload": _build_appc_lcm_lock_request_body(False, migrate_to, req_id, 'Unlock'), "breakOnFailure": False,
879                       "description": "Unlock vFW-2"})
880
881     return result
882
883
884 @timing("> Execute APPC REQ")
885 def appc_lcm_request(onap_ip, req):
886     print(req)
887     api = _init_python_appc_lcm_api(onap_ip)
888     with _no_ssl_verification():
889     #print(json.dumps(req, indent=4))
890         if req['input']['action'] == "DistributeTraffic":
891             result = api.lcm.distribute_traffic(body=req, params={}, headers={})
892         elif req['input']['action'] == "DistributeTrafficCheck":
893             result = api.lcm.distribute_traffic_check(body=req, params={}, headers={})
894         elif req['input']['action'] == "UpgradeSoftware":
895             result = api.lcm.upgrade_software(body=req, params={}, headers={})
896         elif req['input']['action'] == "UpgradePreCheck":
897             result = api.lcm.upgrade_pre_check(body=req, params={}, headers={})
898         elif req['input']['action'] == "UpgradePostCheck":
899             result = api.lcm.upgrade_post_check(body=req, params={}, headers={})
900         elif req['input']['action'] == "CheckLock":
901             result = api.lcm.check_lock(body=req, params={}, headers={})
902         elif req['input']['action'] == "Lock":
903             result = api.lcm.lock(body=req, params={}, headers={})
904         elif req['input']['action'] == "Unlock":
905             result = api.lcm.unlock(body=req, params={}, headers={})
906         else:
907             raise Exception("{} action not supported".format(req['input']['action']))
908
909     if result.body['output']['status']['code'] == 400:
910         if req['input']['action'] == "CheckLock":
911             if result.body['output']['locked'] == "FALSE":
912                 print("UNLOCKED")
913             else:
914                 print("LOCKED")
915                 result.body['output']['status']['code'] = 401
916         else:
917             print("SUCCESSFUL")
918     elif result.body['output']['status']['code'] == 100:
919         print("ACCEPTED")
920     elif result.body['output']['status']['code'] >= 300 and result.body['output']['status']['code'] < 400:
921         print("APPC LCM <<{}>> REJECTED [{} - {}]".format(req['input']['action'], result.body['output']['status']['code'],
922                                          result.body['output']['status']['message']))
923     elif result.body['output']['status']['code'] > 400 and result.body['output']['status']['code'] < 500:
924         print("APPC LCM <<{}>> FAILED [{} - {}]".format(req['input']['action'], result.body['output']['status']['code'],
925                                          result.body['output']['status']['message']))
926 #    elif result.body['output']['status']['code'] == 311:
927 #        timestamp = result.body['output']['common-header']['timestamp']
928 #        _set_appc_lcm_timestamp(req, timestamp)
929 #        appc_lcm_request(onap_ip, req)
930 #        return
931     else:
932         raise Exception("{} - {}".format(result.body['output']['status']['code'],
933                                          result.body['output']['status']['message']))
934     #print(result)
935     return result.body['output']['status']['code']
936
937
938 def appc_lcm_status_request(onap_ip, req):
939     api = _init_python_appc_lcm_api(onap_ip)
940     status_body = _build_appc_lcm_status_body(req)
941     _set_appc_lcm_timestamp(status_body)
942     print("CHECK STATUS")
943     with _no_ssl_verification():
944         result = api.lcm.action_status(body=status_body, params={}, headers={})
945
946     if result.body['output']['status']['code'] == 400:
947         status = json.loads(result.body['output']['payload'])
948         return status
949     else:
950         raise Exception("{} - {}".format(result.body['output']['status']['code'],
951                                          result.body['output']['status']['message']))
952
953
954 @timing("> Confirm APPC REQ")
955 def confirm_appc_lcm_action(onap_ip, req, check_appc_result):
956     print("APPC LCM << {} >> [Status]".format(req['input']['action']))
957
958     while True:
959         time.sleep(2)
960         status = appc_lcm_status_request(onap_ip, req)
961         print(status['status'])
962         if status['status'] == 'SUCCESSFUL':
963             return True
964         elif status['status'] == 'IN_PROGRESS':
965             continue
966         elif check_appc_result:
967             print("APPC LCM <<{}>> [{} - {}]".format(req['input']['action'], status['status'], status['status-reason']))
968             return False
969         else:
970             return True
971
972
973 @timing("Execute APPC LCM REQs")
974 def _execute_lcm_requests(workflow, onap_ip, check_result):
975     lcm_requests = workflow["requests"]
976     print("WORKFLOW << {} >>".format(workflow["description"]))
977     for i in range(len(lcm_requests)):
978        req = lcm_requests[i]["payload"]
979        #print(json.dumps(req, indent=4))
980        print("APPC LCM << {} >> [{}]".format(req['input']['action'], lcm_requests[i]["description"]))
981        _set_appc_lcm_timestamp(req)
982        conf_result = False
983        result = appc_lcm_request(onap_ip, req)
984        print("Result {}".format(result))
985
986        if result == 100:
987            conf_result = confirm_appc_lcm_action(onap_ip, req, check_result)
988            #time.sleep(30)
989        elif result == 400:
990            conf_result = True
991
992        if not conf_result:
993            if lcm_requests[i]["breakOnFailure"]:
994                raise Exception("APPC LCM << {} >> FAILED".format(req['input']['action']))
995            elif "workflow" in lcm_requests[i]:
996                print("WORKFLOW << {} >> SKIP".format(lcm_requests[i]["workflow"]["description"]))
997        elif "workflow" in lcm_requests[i]:
998            _execute_lcm_requests(lcm_requests[i]["workflow"], onap_ip, check_result)
999
1000
1001 def _generate_cdt_artifact_request(req_id, artifact, action, vnfc_type):
1002     req = {
1003       'input': {
1004           'design-request': {
1005               'request-id': req_id,
1006               'action': "uploadArtifact",
1007               'payload': json.dumps(artifact['payload'])
1008           }
1009        }
1010     }
1011
1012     file = "{}_{}_{}.json".format(artifact['type'], action.lower(), vnfc_type)
1013     dirname = "templates/cdt-requests"
1014     #print(file)
1015     if not os.path.exists(dirname):
1016         os.makedirs(dirname)
1017     f = open("{}/{}".format(dirname, file), 'w')
1018     f.write(json.dumps(req, indent=4))
1019     f.close()
1020
1021     return req
1022
1023
1024 def _get_name_of_artifact(prefix, action, vnf_type):
1025     return "{}_{}_{}_0.0.1V.json".format(prefix, action, vnf_type)
1026
1027
1028 def _set_artifact_payload(vnf_type, vnfc_type, action, artifact):
1029     sw_upgrade = False
1030     if action == "DistributeTraffic" or action == "DistributeTrafficCheck" or action == "AllAction":
1031         pass
1032     elif action == "UpgradeSoftware" or action == "UpgradePreCheck" or action == "UpgradePostCheck":
1033         sw_upgrade = True
1034     else:
1035         raise Exception("{} action not supported".format(action))
1036
1037     artifact_contents = ''
1038     if artifact['type'] == 'config_template':
1039         file = 'templates/cdt-templates/templates/action-template.json'
1040         template_file = 'templates/cdt-templates/{}/{}'
1041         if sw_upgrade:
1042             template_file = template_file.format(vnfc_type, 'upgrade.json')
1043         else:
1044             template_file = template_file.format(vnfc_type, 'traffic.json')
1045
1046         artifact_contents = json.dumps(json.loads(open(template_file).read()))
1047     elif artifact['type'] == 'parameter_definitions':
1048         file = 'templates/cdt-templates/templates/{}'
1049         if sw_upgrade:
1050             file = file.format('upgrade-params.json')
1051         else:
1052             file = file.format('traffic-params.json')
1053     elif artifact['type'] == 'param_values':
1054         file = 'templates/cdt-templates/templates/{}'
1055         if sw_upgrade:
1056             file = file.format('upgrade-params-list.json')
1057         else:
1058             file = file.format('traffic-params-list.json')
1059     elif artifact['type'] == 'reference_template':
1060         file = 'templates/cdt-templates/templates/reference-all-actions.json'
1061     else:
1062         raise Exception("{} not supported artifact type".format(artifact['type']))
1063
1064     payload = json.loads(open(file).read())
1065     payload['vnf-type'] = vnf_type
1066     payload['artifact-name'] = artifact['name']
1067     payload['action'] = action
1068
1069     if artifact['type'] == 'config_template':
1070         artifact['artifact-contents'] = artifact_contents
1071     artifact['payload'] = payload
1072
1073
1074 def _generate_artifacts_for_cdt(vnf_type, vnf_type_formatted, vnfc_type, action):
1075     artifacts = []
1076     artifacts.append({
1077         'name': _get_name_of_artifact("template", action, vnf_type_formatted),
1078         'type': 'config_template',
1079         'payload': {'test': 'test'}
1080     })
1081     artifacts.append({
1082         'name': _get_name_of_artifact("pd", action, vnf_type_formatted),
1083         'type': 'parameter_definitions',
1084         'payload': {'test': 'test'}
1085     })
1086     artifacts.append({
1087         'name': _get_name_of_artifact("param", action, vnf_type_formatted),
1088         'type': 'param_values',
1089         'payload': {'test': 'test'}
1090     })
1091
1092     _set_artifact_payload(vnf_type, vnfc_type, action, artifacts[0])
1093     _set_artifact_payload(vnf_type, vnfc_type, action, artifacts[1])
1094     _set_artifact_payload(vnf_type, vnfc_type, action, artifacts[2])
1095
1096     return artifacts
1097
1098
1099 def _generate_cdt_payloads_for_vnf(vnf_info, vnfc_type, actions):
1100     req_id = str(uuid.uuid4()).replace('-','')
1101     vnf_type_formatted = vnf_info['vnf-type'].replace(' ','').replace('/', '_')
1102     artifacts = {
1103         'AllAction': [{
1104             'name': _get_name_of_artifact("reference", 'AllAction', vnf_type_formatted),
1105             'type': 'reference_template'
1106         }]
1107     }
1108
1109     all_action_artifact = artifacts['AllAction'][0]
1110
1111     _set_artifact_payload(vnf_info['vnf-type'], vnfc_type, 'AllAction', all_action_artifact)
1112
1113     for action in actions:
1114         action_artifacts = _generate_artifacts_for_cdt(vnf_info['vnf-type'], vnf_type_formatted, vnfc_type, action)
1115         artifacts[action] = action_artifacts
1116
1117     all_action_artifacts = list()
1118
1119     for action in artifacts:
1120         artifact_list = list()
1121         action_info = {
1122             'action': action,
1123             'action-level': "vnf",
1124             'scope': {
1125                  'vnf-type': vnf_info['vnf-type'],
1126                  'vnfc-type-list': [],
1127                  'vnfc-type': ""
1128             },
1129             'artifact-list': artifact_list
1130         }
1131
1132         if action != 'AllAction':
1133             action_info.update({
1134                 'template': "Y",
1135                 'vm': [],
1136                 'device-protocol': "ANSIBLE",
1137                 'user-name': "admin",
1138                 'port-number': "8000",
1139                 'scopeType': "vnf-type"
1140             })
1141
1142         for action_artifact in artifacts[action]:
1143             artifact_list.append({'artifact-name': action_artifact['name'], 'artifact-type': action_artifact['type']})
1144             if action != 'AllAction':
1145                 req = _generate_cdt_artifact_request(req_id, action_artifact, action, vnfc_type)
1146                 #print(json.dumps(req, indent=4))
1147
1148         #print(json.dumps(action_info, indent=4))
1149         all_action_artifacts.append(action_info)
1150
1151     all_action_artifact['payload']['artifact-contents'] = json.dumps({'reference_data': all_action_artifacts})
1152     req = _generate_cdt_artifact_request(req_id, all_action_artifact, 'AllAction', vnfc_type)
1153     #print(json.dumps(req, indent=4))
1154
1155
1156 def _generate_cdt_payloads(aai_data):
1157     vfw_actions = ["DistributeTrafficCheck", "UpgradeSoftware", "UpgradePreCheck", "UpgradePostCheck", "UpgradeSoftware"]
1158     vpgn_actions = ["DistributeTraffic", "DistributeTrafficCheck"]
1159     _generate_cdt_payloads_for_vnf(aai_data["vfw-model-info"], "vfw-sink", vfw_actions)
1160     _generate_cdt_payloads_for_vnf(aai_data["vpgn-model-info"], "vpgn", vpgn_actions)
1161
1162
1163 def execute_workflow(vfw_vnf_id, rancher_ip, onap_ip, use_oof_cache, if_close_loop_vfw, info_only, check_result, new_version=None):
1164     print("\nExecuting workflow for VNF ID '{}' on Rancher with IP {} and ONAP with IP {}".format(
1165         vfw_vnf_id, rancher_ip, onap_ip))
1166     print("\nOOF Cache {}, is CL vFW {}, only info {}, check LCM result {}".format(use_oof_cache, if_close_loop_vfw,
1167                                                                                    info_only, check_result))
1168     if new_version is not None:
1169         print("\nNew vFW software version {}\n".format(new_version))
1170
1171     x = threading.Thread(target=_run_osdf_resp_server, daemon=True)
1172     x.start()
1173     aai_data = load_aai_data(vfw_vnf_id, onap_ip)
1174     print("\nvFWDT Service Information:")
1175     print(json.dumps(aai_data, indent=4))
1176     lcm_requests = build_appc_lcms_requests_body(rancher_ip, onap_ip, aai_data, use_oof_cache, if_close_loop_vfw, new_version)
1177     print("\nAnsible Inventory:")
1178     inventory = "[host]\nlocalhost   ansible_connection=local\n"
1179     for key in ansible_inventory:
1180         inventory += str("[{}]\n").format(key)
1181         for host in ansible_inventory[key]:
1182             inventory += str("{}\n").format(ansible_inventory[key][host])
1183
1184     print(inventory)
1185     f = open("Ansible_inventory", 'w+')
1186     f.write(inventory)
1187     f.close()
1188
1189     _generate_cdt_payloads(aai_data)
1190
1191     if info_only:
1192         return
1193     print("\nDistribute Traffic Workflow Execution:")
1194
1195     _execute_lcm_requests({"requests": lcm_requests, "description": "Migrate vFW Traffic Conditionally"}, onap_ip, check_result)
1196
1197
1198
1199 help = """\npython3 workflow.py <VNF-ID> <RANCHER-NODE-IP> <K8S-NODE-IP> <IF-CACHE> <IF-VFWCL> <INITIAL-ONLY> <CHECK-STATUS> <VERSION>
1200 \n<VNF-ID> - vnf-id of vFW VNF instance that traffic should be migrated out from
1201 <RANCHER-NODE-IP> - External IP of ONAP Rancher Node i.e. 10.12.5.160 (If Rancher Node is missing this is NFS node)
1202 <K8S-NODE-IP> - External IP of ONAP K8s Worker Node i.e. 10.12.5.212
1203 <IF-CACHE> - If script should use and build OOF response cache (cache it speed-ups further executions of script)
1204 <IF-VFWCL> - If instead of vFWDT service instance vFW or vFWCL one is used (should be False always)
1205 <INITIAL-ONLY> - If only configuration information will be collected (True for initial phase and False for full execution of workflow)
1206 <CHECK-STATUS> - If APPC LCM action status should be verified and FAILURE should stop workflow (when False FAILED status of LCM action does not stop execution of further LCM actions)
1207 <VERSION> - New version of vFW - for tests '1.0' or '2.0'. Ommit when traffic distribution only\n"""
1208
1209 for key in sys.argv:
1210     if key == "-h" or key == "--help":
1211         print(help)
1212         sys.exit()
1213
1214 new_version = None
1215 if len(sys.argv) > 8:
1216     new_version = sys.argv[8]
1217
1218 try:
1219     #vnf_id, Rancher node IP, K8s node IP, use OOF cache, if close loop vfw, if info_only, if check APPC result
1220     execute_workflow(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4].lower() == 'true', sys.argv[5].lower() == 'true',
1221                      sys.argv[6].lower() == 'true', sys.argv[7].lower() == 'true', new_version)
1222 finally:
1223     stats.close()