update link to upper-constraints.txt
[vfc/nfvo/lcm.git] / lcm / workflows / build_in.py
1 # Copyright 2017 ZTE Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #         http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 import json
15 import logging
16 import traceback
17 from threading import Thread
18 import time
19 from lcm.jobs.const import JOB_INSTANCE_URI, JOB_INSTANCE_RESPONSE_ID_URI
20 from lcm.jobs.enum import JOB_ERROR_CODE
21 from lcm.pub.utils.syscomm import fun_name
22 from lcm.pub.utils.values import ignore_case_get
23 from lcm.pub.utils import restcall
24 from lcm.pub.exceptions import NSLCMException
25 from lcm.ns.biz.ns_lcm_op_occ import NsLcmOpOcc
26
27 logger = logging.getLogger(__name__)
28
29 RESULT_OK, RESULT_NG = "0", "1"
30 JOB_ERROR = 255
31
32 g_jobs_status = {}
33
34 """
35 format of input_data
36 {
37     "jobId": uuid of job,
38     "nsInstanceId": id of ns instance,
39     "object_context": json format of nsd,
40     "object_additionalParamForNs": json format of additional parameters for ns,
41     "object_additionalParamForVnf": json format of additional parameters for vnf,
42     "vlCount": int type of VL count,
43     "vnfCount: int type of VNF count,
44     "sfcCount": int type of SFC count,
45     "sdnControllerId": uuid of SDN controller
46 }
47 """
48
49
50 def run_ns_instantiate(input_data, occ_id):
51     logger.debug("Enter %s, input_data is %s", fun_name(), input_data)
52     ns_instantiate_ok = False
53     job_id = ignore_case_get(input_data, "jobId")
54     ns_inst_id = ignore_case_get(input_data, "nsInstanceId")
55     nsd_json = ignore_case_get(input_data, "object_context")
56     ns_param_json = ignore_case_get(input_data, "object_additionalParamForNs")
57     vnf_param_json = ignore_case_get(input_data, "object_additionalParamForVnf")
58     pnf_param_json = ignore_case_get(input_data, "object_additionalParamForPnf")
59     vl_count = int(ignore_case_get(input_data, "vlCount", 0))
60     vnf_count = int(ignore_case_get(input_data, "vnfCount", 0))
61     sfc_count = int(ignore_case_get(input_data, "sfcCount", 0))
62     sdnc_id = ignore_case_get(input_data, "sdnControllerId")
63     g_jobs_status[job_id] = [1 for i in range(vnf_count)]
64     try:
65         update_job(job_id, 10, JOB_ERROR_CODE.NO_ERROR, "Start to create VL")
66         for i in range(vl_count):
67             create_vl(ns_inst_id, i + 1, nsd_json, ns_param_json)
68
69         update_job(job_id, 30, JOB_ERROR_CODE.NO_ERROR, "Start to create VNF")
70         jobs = [create_vnf(ns_inst_id, i + 1, vnf_param_json) for i in range(vnf_count)]
71         wait_until_jobs_done(job_id, jobs)
72
73         [confirm_vnf_status(inst_id) for inst_id, _, _ in jobs]
74
75         update_job(job_id, 50, JOB_ERROR_CODE.NO_ERROR, "Start to create PNF")
76         create_pnf(pnf_param_json)
77
78         update_job(job_id, 70, JOB_ERROR_CODE.NO_ERROR, "Start to create SFC")
79         g_jobs_status[job_id] = [1 for i in range(sfc_count)]
80         jobs = [create_sfc(ns_inst_id, i + 1, nsd_json, sdnc_id) for i in range(sfc_count)]
81         wait_until_jobs_done(job_id, jobs)
82
83         [confirm_sfc_status(inst_id) for inst_id, _, _ in jobs]
84
85         update_job(job_id, 90, JOB_ERROR_CODE.NO_ERROR, "Start to post deal")
86         post_deal(ns_inst_id, "true")
87
88         update_job(job_id, 100, JOB_ERROR_CODE.NO_ERROR, "Create NS successfully.")
89         NsLcmOpOcc.update(occ_id, "COMPLETED")
90         ns_instantiate_ok = True
91     except NSLCMException as e:
92         logger.error("Failded to Create NS: %s", e.args[0])
93         update_job(job_id, JOB_ERROR, JOB_ERROR_CODE.ERROR, "Failded to Create NS.")
94         NsLcmOpOcc.update(occ_id, operationState="FAILED", error=e.args[0])
95         post_deal(ns_inst_id, "false")
96     except Exception as e:
97         logger.error(traceback.format_exc())
98         update_job(job_id, JOB_ERROR, JOB_ERROR_CODE.ERROR, "Failded to Create NS.")
99         NsLcmOpOcc.update(occ_id, operationState="FAILED", error=e.args[0])
100         post_deal(ns_inst_id, "false")
101     finally:
102         g_jobs_status.pop(job_id)
103     return ns_instantiate_ok
104
105
106 def create_vl(ns_inst_id, vl_index, nsd, ns_param):
107     uri = "api/nslcm/v1/ns/vls"
108     data = json.JSONEncoder().encode({
109         "nsInstanceId": ns_inst_id,
110         "vlIndex": vl_index,
111         "context": nsd,
112         "additionalParamForNs": ns_param
113     })
114
115     ret = restcall.req_by_msb(uri, "POST", data)
116     if ret[0] != 0:
117         logger.error("Failed to call create_vl(%s): %s", vl_index, ret[1])
118         raise NSLCMException("Failed to call create_vl(index is %s)" % vl_index)
119     ret[1] = json.JSONDecoder().decode(ret[1])
120
121     result = str(ret[1]["result"])
122     detail = ret[1]["detail"]
123     vl_id = ret[1]["vlId"]
124     if result != RESULT_OK:
125         logger.error("Failed to create VL(%s): %s", vl_id, detail)
126         raise NSLCMException("Failed to create VL(%s)" % vl_id)
127
128     logger.debug("Create VL(%s) successfully.", vl_id)
129
130
131 def create_vnf(ns_inst_id, vnf_index, nf_param):
132     uri = "api/nslcm/v1/ns/vnfs"
133     data = json.JSONEncoder().encode({
134         "nsInstanceId": ns_inst_id,
135         "vnfIndex": vnf_index,
136         "additionalParamForVnf": json.JSONDecoder().decode(nf_param)
137     })
138
139     ret = restcall.req_by_msb(uri, "POST", data)
140     if ret[0] != 0:
141         logger.error("Failed to call create_vnf(%s): %s", vnf_index, ret[1])
142         raise NSLCMException("Failed to call create_vnf(index is %s)" % vnf_index)
143     ret[1] = json.JSONDecoder().decode(ret[1])
144
145     vnf_inst_id = ret[1]["vnfInstId"]
146     job_id = ret[1]["jobId"]
147     logger.debug("Create VNF(%s) started.", vnf_inst_id)
148     return vnf_inst_id, job_id, vnf_index - 1
149
150
151 def create_sfc(ns_inst_id, fp_index, nsd_json, sdnc_id):
152     uri = "api/nslcm/v1/ns/sfcs"
153     data = json.JSONEncoder().encode({
154         "nsInstanceId": ns_inst_id,
155         "context": nsd_json,
156         "fpindex": fp_index,
157         "sdnControllerId": sdnc_id
158     })
159
160     ret = restcall.req_by_msb(uri, "POST", data)
161     if ret[0] != 0:
162         logger.error("Failed to call create_sfc(%s): %s", fp_index, ret[1])
163         raise NSLCMException("Failed to call create_sfc(index is %s)" % fp_index)
164     ret[1] = json.JSONDecoder().decode(ret[1])
165
166     sfc_inst_id = ret[1]["sfcInstId"]
167     job_id = ret[1]["jobId"]
168     logger.debug("Create SFC(%s) started.", sfc_inst_id)
169     return sfc_inst_id, job_id, fp_index - 1
170
171
172 def post_deal(ns_inst_id, status):
173     uri = "api/nslcm/v1/ns/{nsInstanceId}/postdeal".format(nsInstanceId=ns_inst_id)
174     data = json.JSONEncoder().encode({
175         "status": status
176     })
177
178     ret = restcall.req_by_msb(uri, "POST", data)
179     if ret[0] != 0:
180         logger.error("Failed to call post_deal(%s): %s", ns_inst_id, ret[1])
181     logger.debug("Call post_deal(%s, %s) successfully.", ns_inst_id, status)
182
183
184 def update_job(job_id, progress, errcode, desc):
185     uri = JOB_INSTANCE_URI % job_id
186     data = json.JSONEncoder().encode({
187         "progress": progress,
188         "errcode": errcode,
189         "desc": desc
190     })
191     restcall.req_by_msb(uri, "POST", data)
192
193
194 class JobWaitThread(Thread):
195     """
196     Job Wait
197     """
198
199     def __init__(self, inst_id, job_id, ns_job_id, index):
200         Thread.__init__(self)
201         self.inst_id = inst_id
202         self.job_id = job_id
203         self.ns_job_id = ns_job_id
204         self.index = index
205         self.retry_count = 600
206         self.interval_second = 3
207
208     def run(self):
209         count = 0
210         response_id, new_response_id = 0, 0
211         job_end_normal, job_timeout = False, True
212         while count < self.retry_count:
213             count = count + 1
214             time.sleep(self.interval_second)
215             uri = JOB_INSTANCE_RESPONSE_ID_URI % (self.job_id, response_id)
216             ret = restcall.req_by_msb(uri, "GET")
217             if ret[0] != 0:
218                 logger.error("Failed to query job: %s:%s", ret[2], ret[1])
219                 continue
220             job_result = json.JSONDecoder().decode(ret[1])
221             if "responseDescriptor" not in job_result:
222                 logger.debug("No new progress after response_id(%s) in job(%s)", response_id, self.job_id)
223                 continue
224             progress = job_result["responseDescriptor"]["progress"]
225             new_response_id = job_result["responseDescriptor"]["responseId"]
226             job_desc = job_result["responseDescriptor"]["statusDescription"]
227             if new_response_id != response_id:
228                 logger.debug("%s:%s:%s", progress, new_response_id, job_desc)
229                 response_id = new_response_id
230                 count = 0
231             if progress == JOB_ERROR:
232                 job_timeout = False
233                 logger.error("Job(%s) failed: %s", self.job_id, job_desc)
234                 break
235             elif progress == 100:
236                 job_end_normal, job_timeout = True, False
237                 logger.info("Job(%s) ended normally", self.job_id)
238                 break
239         if job_timeout:
240             logger.error("Job(%s) timeout", self.job_id)
241         if self.ns_job_id in g_jobs_status:
242             if job_end_normal:
243                 g_jobs_status[self.ns_job_id][self.index] = 0
244
245
246 def wait_until_jobs_done(g_job_id, jobs):
247     job_threads = []
248     for inst_id, job_id, index in jobs:
249         job_threads.append(JobWaitThread(inst_id, job_id, g_job_id, index))
250     for t in job_threads:
251         t.start()
252     for t in job_threads:
253         t.join()
254     if g_job_id in g_jobs_status:
255         if sum(g_jobs_status[g_job_id]) > 0:
256             logger.error("g_jobs_status[%s]: %s", g_job_id, g_jobs_status[g_job_id])
257             raise NSLCMException("Some jobs failed!")
258
259
260 def confirm_vnf_status(vnf_inst_id):
261     uri = "api/nslcm/v1/ns/vnfs/{vnfInstId}".format(vnfInstId=vnf_inst_id)
262     ret = restcall.req_by_msb(uri, "GET")
263     if ret[0] != 0:
264         raise NSLCMException("Failed to call get_vnf(%s)" % vnf_inst_id)
265     ret[1] = json.JSONDecoder().decode(ret[1])
266
267     vnf_status = ret[1]["vnfStatus"]
268     if vnf_status != "active":
269         raise NSLCMException("Status of VNF(%s) is not active" % vnf_inst_id)
270
271
272 def confirm_sfc_status(sfc_inst_id):
273     uri = "api/nslcm/v1/ns/sfcs/{sfcInstId}".format(sfcInstId=sfc_inst_id)
274     ret = restcall.req_by_msb(uri, "GET")
275     if ret[0] != 0:
276         raise NSLCMException("Failed to call get_sfc(%s)" % sfc_inst_id)
277     ret[1] = json.JSONDecoder().decode(ret[1])
278
279     sfc_status = ret[1]["sfcStatus"]
280     if sfc_status != "active":
281         raise NSLCMException("Status of SFC(%s) is not active" % sfc_inst_id)
282
283
284 def create_pnf(pnf_param_json):
285     if pnf_param_json and len(pnf_param_json) > 0:
286         pnfs = json.JSONDecoder().decode(pnf_param_json)
287         for pnf in list(pnfs.values()):
288             uri = "/api/nslcm/v1/pnfs"
289             method = "POST"
290             content = json.JSONEncoder().encode(pnf["input"]["content"])
291             ret = restcall.req_by_msb(uri, method, content)
292             if ret[0] != 0:
293                 logger.error("Failed to call create_pnf(%s) result %s", content, ret)
294                 raise NSLCMException("Failed to call create_pnf(%s)" % content)