1 # -*- coding: utf-8 -*-
5 import logging
.handlers
9 from lcm_utils
import LcmException
, LcmBase
10 from osm_common
.dbbase
import DbException
12 from http
import HTTPStatus
13 from copy
import deepcopy
16 __author__
= "Felipe Vicens, Pol Alemany, Alfonso Tierno"
19 def get_iterable(in_dict
, in_key
):
21 Similar to <dict>.get(), but if value is None, False, ..., An empty tuple is returned instead
22 :param in_dict: a dictionary
23 :param in_key: the key to look for at in_dict
24 :return: in_dict[in_var] or () if it is None or not present
26 if not in_dict
.get(in_key
):
28 return in_dict
[in_key
]
31 class NetsliceLcm(LcmBase
):
33 total_deploy_timeout
= 2 * 3600 # global timeout for deployment
35 def __init__(self
, db
, msg
, fs
, lcm_tasks
, ro_config
, vca_config
, loop
):
37 Init, Connect to database, filesystem storage, and messaging
38 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
42 self
.logger
= logging
.getLogger('lcm.netslice')
44 self
.lcm_tasks
= lcm_tasks
45 self
.ns
= ns
.NsLcm(db
, msg
, fs
, lcm_tasks
, ro_config
, vca_config
, loop
)
46 self
.ro_config
= ro_config
48 super().__init
__(db
, msg
, fs
, self
.logger
)
50 async def instantiate(self
, nsir_id
, nsilcmop_id
):
51 logging_text
= "Task netslice={} instantiate={} ".format(nsir_id
, nsilcmop_id
)
52 self
.logger
.debug(logging_text
+ "Enter")
53 # get all needed from database
57 db_nsir_update
= {"_admin.nsilcmop": nsilcmop_id
}
58 db_nsilcmop_update
= {}
59 nsilcmop_operation_state
= None
61 RO
= ROclient
.ROClient(self
.loop
, **self
.ro_config
)
64 def vim_account_2_RO(vim_account
):
66 Translate a RO vim_account from OSM vim_account params
67 :param ns_params: OSM instantiate params
68 :return: The RO ns descriptor
70 if vim_account
in vim_2_RO
:
71 return vim_2_RO
[vim_account
]
73 db_vim
= self
.db
.get_one("vim_accounts", {"_id": vim_account
})
74 if db_vim
["_admin"]["operationalState"] != "ENABLED":
75 raise LcmException("VIM={} is not available. operationalState={}".format(
76 vim_account
, db_vim
["_admin"]["operationalState"]))
77 RO_vim_id
= db_vim
["_admin"]["deployed"]["RO"]
78 vim_2_RO
[vim_account
] = RO_vim_id
81 def nsi_update_nsir(self
, nsi_update_nsir
, db_nsir
, nsir_desc_RO
):
83 Updates database nsir with the RO info for the created vld
84 :param nsi_update_nsir: dictionary to be filled with the updated info
85 :param db_nsir: content of db_nsir. This is also modified
86 :param nsir_desc_RO: nsir descriptor from RO
87 :return: Nothing, LcmException is raised on errors
90 for vld_index
, vld
in enumerate(get_iterable(db_nsir
, "vld")):
91 for net_RO
in get_iterable(nsir_desc_RO
, "nets"):
92 if vld
["id"] != net_RO
.get("ns_net_osm_id"):
94 vld
["vim-id"] = net_RO
.get("vim_net_id")
95 vld
["name"] = net_RO
.get("vim_name")
96 vld
["status"] = net_RO
.get("status")
97 vld
["status-detailed"] = net_RO
.get("error_msg")
98 nsi_update_nsir
["vld.{}".format(vld_index
)] = vld
101 raise LcmException("ns_update_nsir: Not found vld={} at RO info".format(vld
["id"]))
104 step
= "Getting nsir={} from db".format(nsir_id
)
105 db_nsir
= self
.db
.get_one("nsis", {"_id": nsir_id
})
106 step
= "Getting nsilcmop={} from db".format(nsilcmop_id
)
107 db_nsilcmop
= self
.db
.get_one("nsilcmops", {"_id": nsilcmop_id
})
109 # look if previous tasks is in process
110 task_name
, task_dependency
= self
.lcm_tasks
.lookfor_related("nsi", nsir_id
, nsilcmop_id
)
112 step
= db_nsilcmop_update
["detailed-status"] = \
113 "Waiting for related tasks to be completed: {}".format(task_name
)
114 self
.logger
.debug(logging_text
+ step
)
115 self
.update_db_2("nsilcmops", nsilcmop_id
, db_nsilcmop_update
)
116 _
, pending
= await asyncio
.wait(task_dependency
, timeout
=3600)
118 raise LcmException("Timeout waiting related tasks to be completed")
120 # Empty list to keep track of network service records status in the netslice
121 nsir_admin
= db_nsir
["_admin"]
122 nsir_vlds
= nsir_admin
["netslice-vld"]
123 nsir_admin
["nsrs-detailed-list"] = []
125 # Slice status Creating
126 db_nsir_update
["detailed-status"] = "creating"
127 db_nsir_update
["operational-status"] = "init"
128 self
.update_db_2("nsis", nsir_id
, db_nsir_update
)
130 # TODO: Multiple VIMs networks: datacenters
132 for netslice_vld
in nsir_vlds
:
134 RO_ns_params
["name"] = db_nsir
["name"]
135 if netslice_vld
.get("vim-network-name"):
136 if not isinstance(netslice_vld
["vim-network-name"], str):
137 name
= netslice_vld
["vim-network-name"][netslice_vld
["vimAccountId"]]
138 nets
.append({"name": name
, "external": False, "type": "bridge"})
140 nets
.append({"name": netslice_vld
["vim-network-name"], "external": False, "type": "bridge"})
142 nets
.append({"name": "default", "external": False, "type": "bridge"})
143 RO_ns_params
["scenario"] = {"nets": nets
}
144 RO_ns_params
["datacenter"] = vim_account_2_RO(netslice_vld
["vimAccountId"])
147 # if present use it unless in error status
148 RO_nsir_id
= db_nsir
["_admin"].get("deployed", {}).get("RO", {}).get("nsir_id")
151 step
= db_nsir_update
["detailed-status"] = "Looking for existing ns at RO"
152 # self.logger.debug(logging_text + step + " RO_ns_id={}".format(RO_nsir_id))
153 desc
= await RO
.show("ns", RO_nsir_id
)
154 except ROclient
.ROClientException
as e
:
155 if e
.http_code
!= HTTPStatus
.NOT_FOUND
:
157 RO_nsir_id
= db_nsir_update
["_admin.deployed.RO.nsir_id"] = None
159 ns_status
, ns_status_info
= RO
.check_ns_status(desc
)
160 db_nsir_update
["_admin.deployed.RO.nsir_status"] = ns_status
161 if ns_status
== "ERROR":
162 step
= db_nsir_update
["detailed-status"] = "Deleting ns at RO. RO_ns_id={}".format(RO_nsir_id
)
163 self
.logger
.debug(logging_text
+ step
)
164 await RO
.delete("ns", RO_nsir_id
)
165 RO_nsir_id
= db_nsir_update
["_admin.deployed.RO.nsir_id"] = None
167 step
= db_nsir_update
["detailed-status"] = "Checking dependencies"
168 # self.logger.debug(logging_text + step)
169 # check if VIM is creating and wait look if previous tasks in process
170 for vimAccountId_unit
in RO_ns_params
["datacenter"]:
171 task_name
, task_dependency
= self
.lcm_tasks
.lookfor_related("vim_account", vimAccountId_unit
)
173 step
= "Waiting for related tasks to be completed: {}".format(task_name
)
174 self
.logger
.debug(logging_text
+ step
)
175 await asyncio
.wait(task_dependency
, timeout
=3600)
177 step
= db_nsir_update
["detailed-status"] = "Creating ns at RO"
178 desc
= await RO
.create("ns", descriptor
=RO_ns_params
)
179 RO_nsir_id
= db_nsir_update
["_admin.deployed.RO.nsir_id"] = desc
["uuid"]
180 db_nsir_update
["_admin.nsState"] = "INSTANTIATED"
181 db_nsir_update
["_admin.deployed.RO.nsir_status"] = "BUILD"
182 self
.logger
.debug(logging_text
+ "ns created at RO. RO_id={}".format(desc
["uuid"]))
183 self
.update_db_2("nsis", nsir_id
, db_nsir_update
)
185 # wait until NS scenario for netslice-vld is ready
186 step
= ns_status_detailed
= detailed_status
= "Waiting ns ready at RO. RO_id={}".format(RO_nsir_id
)
187 detailed_status_old
= None
188 self
.logger
.debug(logging_text
+ step
)
190 while time() <= start_deploy
+ self
.total_deploy_timeout
:
191 desc
= await RO
.show("ns", RO_nsir_id
)
192 ns_status
, ns_status_info
= RO
.check_ns_status(desc
)
193 db_nsir_update
["admin.deployed.RO.nsir_status"] = ns_status
194 db_nsir_update
["admin.deployed.RO.nsr_id"] = desc
.get("uuid")
195 if ns_status
== "ERROR":
196 raise ROclient
.ROClientException(ns_status_info
)
197 elif ns_status
== "BUILD":
198 detailed_status
= ns_status_detailed
+ "; {}".format(ns_status_info
)
199 elif ns_status
== "ACTIVE":
202 assert False, "ROclient.check_ns_status returns unknown {}".format(ns_status
)
203 if detailed_status
!= detailed_status_old
:
204 detailed_status_old
= db_nsir_update
["detailed-status"] = detailed_status
205 self
.update_db_2("nsis", nsir_id
, db_nsir_update
)
206 await asyncio
.sleep(5, loop
=self
.loop
)
207 else: # total_deploy_timeout
208 raise ROclient
.ROClientException("Timeout waiting ns to be ready")
210 step
= "Updating NSIR"
211 nsi_update_nsir(self
, db_nsir_update
, db_nsir
, desc
)
213 # Iterate over the network services operation ids to instantiate NSs
214 # TODO: (future improvement) look another way check the tasks instead of keep asking
215 # -> https://docs.python.org/3/library/asyncio-task.html#waiting-primitives
216 # steps: declare ns_tasks, add task when terminate is called, await asyncio.wait(vca_task_list, timeout=300)
218 nslcmop_ids
= db_nsilcmop
["operationParams"].get("nslcmops_ids")
219 for nslcmop_id
in nslcmop_ids
:
220 nslcmop
= self
.db
.get_one("nslcmops", {"_id": nslcmop_id
})
221 nsr_id
= nslcmop
.get("nsInstanceId")
222 step
= "Launching ns={} instantiate={} task".format(nsr_id
, nslcmop
)
223 task
= asyncio
.ensure_future(self
.ns
.instantiate(nsr_id
, nslcmop_id
))
224 self
.lcm_tasks
.register("ns", nsr_id
, nslcmop_id
, "ns_instantiate", task
)
226 # Wait until Network Slice is ready
227 step
= nsir_status_detailed
= " Waiting nsi ready. nsi_id={}".format(nsir_id
)
228 nsrs_detailed_list_old
= None
229 self
.logger
.debug(logging_text
+ step
)
231 # TODO: substitute while for await (all task to be done or not)
232 deployment_timeout
= 2 * 3600 # Two hours
233 while deployment_timeout
> 0:
234 # Check ns instantiation status
236 nsrs_detailed_list
= []
237 for nslcmop_item
in nslcmop_ids
:
238 nslcmop
= self
.db
.get_one("nslcmops", {"_id": nslcmop_item
})
239 status
= nslcmop
.get("operationState")
240 # TODO: (future improvement) other possible status: ROLLING_BACK,ROLLED_BACK
241 nsrs_detailed_list
.append({"nsrId": nslcmop
["nsInstanceId"], "status": nslcmop
["operationState"],
243 nsir_status_detailed
+ "; {}".format(nslcmop
.get("detailed-status"))})
244 if status
not in ["COMPLETED", "PARTIALLY_COMPLETED", "FAILED", "FAILED_TEMP"]:
247 # TODO: Check admin and _admin
248 if nsrs_detailed_list
!= nsrs_detailed_list_old
:
249 nsir_admin
["nsrs-detailed-list"] = nsrs_detailed_list
250 nsrs_detailed_list_old
= nsrs_detailed_list
251 db_nsir_update
["_admin"] = nsir_admin
252 self
.update_db_2("nsis", nsir_id
, db_nsir_update
)
255 step
= "Network Slice Instance is ready. nsi_id={}".format(nsir_id
)
256 for items
in nsrs_detailed_list
:
257 if "FAILED" in items
.values():
258 raise LcmException("Error deploying NSI: {}".format(nsir_id
))
261 # TODO: future improvement due to synchronism -> await asyncio.wait(vca_task_list, timeout=300)
262 await asyncio
.sleep(5, loop
=self
.loop
)
263 deployment_timeout
-= 5
265 if deployment_timeout
<= 0:
266 raise LcmException("Timeout waiting nsi to be ready. nsi_id={}".format(nsir_id
))
268 db_nsir_update
["operational-status"] = "running"
269 db_nsir_update
["detailed-status"] = "done"
270 db_nsir_update
["config-status"] = "configured"
271 db_nsilcmop_update
["operationState"] = nsilcmop_operation_state
= "COMPLETED"
272 db_nsilcmop_update
["statusEnteredTime"] = time()
273 db_nsilcmop_update
["detailed-status"] = "done"
276 except (LcmException
, DbException
) as e
:
277 self
.logger
.error(logging_text
+ "Exit Exception while '{}': {}".format(step
, e
))
279 except asyncio
.CancelledError
:
280 self
.logger
.error(logging_text
+ "Cancelled Exception while '{}'".format(step
))
281 exc
= "Operation was cancelled"
282 except Exception as e
:
283 exc
= traceback
.format_exc()
284 self
.logger
.critical(logging_text
+ "Exit Exception {} while '{}': {}".format(type(e
).__name
__, step
, e
),
289 db_nsir_update
["detailed-status"] = "ERROR {}: {}".format(step
, exc
)
290 db_nsir_update
["operational-status"] = "failed"
292 db_nsilcmop_update
["detailed-status"] = "FAILED {}: {}".format(step
, exc
)
293 db_nsilcmop_update
["operationState"] = nsilcmop_operation_state
= "FAILED"
294 db_nsilcmop_update
["statusEnteredTime"] = time()
296 db_nsir_update
["_admin.nsiState"] = "INSTANTIATED"
297 db_nsir_update
["_admin.nsilcmop"] = None
298 self
.update_db_2("nsis", nsir_id
, db_nsir_update
)
301 self
.update_db_2("nsilcmops", nsilcmop_id
, db_nsilcmop_update
)
302 if nsilcmop_operation_state
:
304 await self
.msg
.aiowrite("nsi", "instantiated", {"nsir_id": nsir_id
, "nsilcmop_id": nsilcmop_id
,
305 "operationState": nsilcmop_operation_state
})
306 except Exception as e
:
307 self
.logger
.error(logging_text
+ "kafka_write notification Exception {}".format(e
))
308 self
.logger
.debug(logging_text
+ "Exit")
309 self
.lcm_tasks
.remove("nsi", nsir_id
, nsilcmop_id
, "nsi_instantiate")
311 async def terminate(self
, nsir_id
, nsilcmop_id
):
312 logging_text
= "Task nsi={} terminate={} ".format(nsir_id
, nsilcmop_id
)
313 self
.logger
.debug(logging_text
+ "Enter")
317 db_nsir_update
= {"_admin.nsilcmop": nsilcmop_id
}
318 db_nsilcmop_update
= {}
319 RO
= ROclient
.ROClient(self
.loop
, **self
.ro_config
)
320 failed_detail
= [] # annotates all failed error messages
321 nsilcmop_operation_state
= None
323 step
= "Getting nsir={} from db".format(nsir_id
)
324 db_nsir
= self
.db
.get_one("nsis", {"_id": nsir_id
})
325 nsir_deployed
= deepcopy(db_nsir
["admin"].get("deployed"))
326 step
= "Getting nsilcmop={} from db".format(nsilcmop_id
)
327 db_nsilcmop
= self
.db
.get_one("nsilcmops", {"_id": nsilcmop_id
})
329 # TODO: Check if makes sense check the nsiState=NOT_INSTANTIATED when terminate
330 # CASE: Instance was terminated but there is a second request to terminate the instance
331 if db_nsir
["_admin"]["nsiState"] == "NOT_INSTANTIATED":
334 # Slice status Terminating
335 db_nsir_update
["operational-status"] = "terminating"
336 db_nsir_update
["config-status"] = "terminating"
337 self
.update_db_2("nsis", nsir_id
, db_nsir_update
)
339 # look if previous tasks is in process
340 task_name
, task_dependency
= self
.lcm_tasks
.lookfor_related("nsi", nsir_id
, nsilcmop_id
)
342 step
= db_nsilcmop_update
["detailed-status"] = \
343 "Waiting for related tasks to be completed: {}".format(task_name
)
344 self
.logger
.debug(logging_text
+ step
)
345 self
.update_db_2("nsilcmops", nsilcmop_id
, db_nsilcmop_update
)
346 _
, pending
= await asyncio
.wait(task_dependency
, timeout
=3600)
348 raise LcmException("Timeout waiting related tasks to be completed")
350 # Gets the list to keep track of network service records status in the netslice
351 nsir_admin
= db_nsir
["_admin"]
352 nsrs_detailed_list
= []
354 # Iterate over the network services operation ids to terminate NSs
355 # TODO: (future improvement) look another way check the tasks instead of keep asking
356 # -> https://docs.python.org/3/library/asyncio-task.html#waiting-primitives
357 # steps: declare ns_tasks, add task when terminate is called, await asyncio.wait(vca_task_list, timeout=300)
359 nslcmop_ids
= db_nsilcmop
["operationParams"].get("nslcmops_ids")
360 for nslcmop_id
in nslcmop_ids
:
361 nslcmop
= self
.db
.get_one("nslcmops", {"_id": nslcmop_id
})
362 nsr_id
= nslcmop
["operationParams"].get("nsInstanceId")
363 task
= asyncio
.ensure_future(self
.ns
.terminate(nsr_id
, nslcmop_id
))
364 self
.lcm_tasks
.register("ns", nsr_id
, nslcmop_id
, "ns_instantiate", task
)
366 # Wait until Network Slice is terminated
367 step
= nsir_status_detailed
= " Waiting nsi terminated. nsi_id={}".format(nsir_id
)
368 nsrs_detailed_list_old
= None
369 self
.logger
.debug(logging_text
+ step
)
371 termination_timeout
= 2 * 3600 # Two hours
372 while termination_timeout
> 0:
373 # Check ns termination status
375 nsrs_detailed_list
= []
376 for nslcmop_item
in nslcmop_ids
:
377 nslcmop
= self
.db
.get_one("nslcmops", {"_id": nslcmop_item
})
378 status
= nslcmop
["operationState"]
379 # TODO: (future improvement) other possible status: ROLLING_BACK,ROLLED_BACK
380 nsrs_detailed_list
.append({"nsrId": nslcmop
["nsInstanceId"], "status": nslcmop
["operationState"],
382 nsir_status_detailed
+ "; {}".format(nslcmop
.get("detailed-status"))})
383 if status
not in ["COMPLETED", "PARTIALLY_COMPLETED", "FAILED", "FAILED_TEMP"]:
386 if nsrs_detailed_list
!= nsrs_detailed_list_old
:
387 nsir_admin
["nsrs-detailed-list"] = nsrs_detailed_list
388 nsrs_detailed_list_old
= nsrs_detailed_list
389 db_nsir_update
["_admin"] = nsir_admin
390 self
.update_db_2("nsis", nsir_id
, db_nsir_update
)
393 step
= "Network Slice Instance is terminated. nsi_id={}".format(nsir_id
)
394 for items
in nsrs_detailed_list
:
395 if "FAILED" in items
.values():
396 raise LcmException("Error terminating NSI: {}".format(nsir_id
))
399 await asyncio
.sleep(5, loop
=self
.loop
)
400 termination_timeout
-= 5
402 if termination_timeout
<= 0:
403 raise LcmException("Timeout waiting nsi to be terminated. nsi_id={}".format(nsir_id
))
406 RO_nsir_id
= RO_delete_action
= None
407 if nsir_deployed
and nsir_deployed
.get("RO"):
408 RO_nsir_id
= nsir_deployed
["RO"].get("nsr_id")
409 RO_delete_action
= nsir_deployed
["RO"].get("nsr_delete_action_id")
412 step
= db_nsir_update
["detailed-status"] = "Deleting ns at RO"
413 db_nsilcmop_update
["detailed-status"] = "Deleting ns at RO"
414 self
.logger
.debug(logging_text
+ step
)
415 desc
= await RO
.delete("ns", RO_nsir_id
)
416 RO_delete_action
= desc
["action_id"]
417 db_nsir_update
["_admin.deployed.RO.nsr_delete_action_id"] = RO_delete_action
418 db_nsir_update
["_admin.deployed.RO.nsr_id"] = None
419 db_nsir_update
["_admin.deployed.RO.nsr_status"] = "DELETED"
421 # wait until NS is deleted from VIM
422 step
= detailed_status
= "Waiting ns deleted from VIM. RO_id={}".format(RO_nsir_id
)
423 detailed_status_old
= None
424 self
.logger
.debug(logging_text
+ step
)
426 delete_timeout
= 20 * 60 # 20 minutes
427 while delete_timeout
> 0:
428 desc
= await RO
.show("ns", item_id_name
=RO_nsir_id
, extra_item
="action",
429 extra_item_id
=RO_delete_action
)
430 ns_status
, ns_status_info
= RO
.check_action_status(desc
)
431 if ns_status
== "ERROR":
432 raise ROclient
.ROClientException(ns_status_info
)
433 elif ns_status
== "BUILD":
434 detailed_status
= step
+ "; {}".format(ns_status_info
)
435 elif ns_status
== "ACTIVE":
438 assert False, "ROclient.check_action_status returns unknown {}".format(ns_status
)
439 await asyncio
.sleep(5, loop
=self
.loop
)
441 if detailed_status
!= detailed_status_old
:
442 detailed_status_old
= db_nsilcmop_update
["detailed-status"] = detailed_status
443 self
.update_db_2("nslcmops", nslcmop_id
, db_nsilcmop_update
)
444 else: # delete_timeout <= 0:
445 raise ROclient
.ROClientException("Timeout waiting ns deleted from VIM")
447 except ROclient
.ROClientException
as e
:
448 if e
.http_code
== 404: # not found
449 db_nsir_update
["_admin.deployed.RO.nsr_id"] = None
450 db_nsir_update
["_admin.deployed.RO.nsr_status"] = "DELETED"
451 self
.logger
.debug(logging_text
+ "RO_ns_id={} already deleted".format(RO_nsir_id
))
452 elif e
.http_code
== 409: # conflict
453 failed_detail
.append("RO_ns_id={} delete conflict: {}".format(RO_nsir_id
, e
))
454 self
.logger
.debug(logging_text
+ failed_detail
[-1])
456 failed_detail
.append("RO_ns_id={} delete error: {}".format(RO_nsir_id
, e
))
457 self
.logger
.error(logging_text
+ failed_detail
[-1])
459 db_nsir_update
["operational-status"] = "terminated"
460 db_nsir_update
["config-status"] = "configured"
461 db_nsir_update
["detailed-status"] = "done"
462 db_nsilcmop_update
["operationState"] = nsilcmop_operation_state
= "COMPLETED"
463 db_nsilcmop_update
["statusEnteredTime"] = time()
464 db_nsilcmop_update
["detailed-status"] = "done"
467 except (LcmException
, DbException
) as e
:
468 self
.logger
.error(logging_text
+ "Exit Exception while '{}': {}".format(step
, e
))
470 except asyncio
.CancelledError
:
471 self
.logger
.error(logging_text
+ "Cancelled Exception while '{}'".format(step
))
472 exc
= "Operation was cancelled"
473 except Exception as e
:
474 exc
= traceback
.format_exc()
475 self
.logger
.critical(logging_text
+ "Exit Exception {} while '{}': {}".format(type(e
).__name
__, step
, e
),
480 db_nsir_update
["detailed-status"] = "ERROR {}: {}".format(step
, exc
)
481 db_nsir_update
["operational-status"] = "failed"
483 db_nsilcmop_update
["detailed-status"] = "FAILED {}: {}".format(step
, exc
)
484 db_nsilcmop_update
["operationState"] = nsilcmop_operation_state
= "FAILED"
485 db_nsilcmop_update
["statusEnteredTime"] = time()
487 db_nsir_update
["_admin.nsilcmop"] = None
488 db_nsir_update
["_admin.nsiState"] = "TERMINATED"
489 self
.update_db_2("nsis", nsir_id
, db_nsir_update
)
491 self
.update_db_2("nsilcmops", nsilcmop_id
, db_nsilcmop_update
)
493 if nsilcmop_operation_state
:
495 await self
.msg
.aiowrite("nsi", "terminated", {"nsir_id": nsir_id
, "nsilcmop_id": nsilcmop_id
,
496 "operationState": nsilcmop_operation_state
})
497 except Exception as e
:
498 self
.logger
.error(logging_text
+ "kafka_write notification Exception {}".format(e
))
499 self
.logger
.debug(logging_text
+ "Exit")
500 self
.lcm_tasks
.remove("nsi", nsir_id
, nsilcmop_id
, "nsi_terminate")