X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osm_lcm%2Fns.py;h=20a40180893e3227bd6fce1f82143409a5839c48;hb=35be915861daf31fe227ee1e90e063d3796d42ef;hp=6148d02aeb99d272218015444a52f23ecb9589ab;hpb=e4f7e6cc71c5e81a7f58fddab055901c5bdf64db;p=osm%2FLCM.git diff --git a/osm_lcm/ns.py b/osm_lcm/ns.py index 6148d02..20a4018 100644 --- a/osm_lcm/ns.py +++ b/osm_lcm/ns.py @@ -1,12 +1,28 @@ -#!/usr/bin/python3 # -*- coding: utf-8 -*- +## +# Copyright 2018 Telefonica S.A. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +## + import asyncio import yaml import logging import logging.handlers import functools import traceback +from jinja2 import Environment, Template, meta, TemplateError, TemplateNotFound, TemplateSyntaxError import ROclient from lcm_utils import LcmException, LcmExceptionNoMgmtIP, LcmBase @@ -54,6 +70,7 @@ def populate_dict(target_dict, key_list, value): class NsLcm(LcmBase): timeout_vca_on_error = 5 * 60 # Time for charm from first time at blocked,error status to mark as failed total_deploy_timeout = 2 * 3600 # global timeout for deployment + timeout_charm_delete = 10 * 60 def __init__(self, db, msg, fs, lcm_tasks, ro_config, vca_config, loop): """ @@ -83,11 +100,13 @@ class NsLcm(LcmBase): artifacts=None, ) - def vnfd2RO(self, vnfd, new_id=None): + def vnfd2RO(self, vnfd, new_id=None, additionalParams=None, nsrId=None): """ Converts creates a new vnfd descriptor for RO base on input OSM IM vnfd :param vnfd: input vnfd :param new_id: overrides vnf id if provided + :param additionalParamsForVnf: Instantiation params for VNFs provided + :param nsrId: Id of the NSR :return: copy of vnfd """ ci_file = None @@ -100,19 +119,29 @@ class NsLcm(LcmBase): for vdu in vnfd_RO.get("vdu", ()): if "cloud-init-file" in vdu: base_folder = vnfd["_admin"]["storage"] - clout_init_file = "{}/{}/cloud_init/{}".format( - base_folder["folder"], - base_folder["pkg-dir"], - vdu["cloud-init-file"] - ) - ci_file = self.fs.file_open(clout_init_file, "r") - # TODO: detect if binary or text. Propose to read as binary and try to decode to utf8. If fails - # convert to base 64 or similar - clout_init_content = ci_file.read() - ci_file.close() - ci_file = None + cloud_init_file = "{}/{}/cloud_init/{}".format(base_folder["folder"], base_folder["pkg-dir"], + vdu["cloud-init-file"]) + with self.fs.file_open(cloud_init_file, "r") as ci_file: + cloud_init_content = ci_file.read() vdu.pop("cloud-init-file", None) - vdu["cloud-init"] = clout_init_content + elif "cloud-init" in vdu: + cloud_init_content = vdu["cloud-init"] + try: + env = Environment() + ast = env.parse(cloud_init_content) + mandatory_vars = meta.find_undeclared_variables(ast) + if mandatory_vars: + for var in mandatory_vars: + if not additionalParams or var not in additionalParams.keys(): + raise LcmException("Variable '{}' defined in vnfd[id={}] vdu[id={}] cloud-init or " + "cloud-init-file, must be provided in the instantiation parameters " + "inside the 'additionalParamsForVnf' block".format(var, vnfd["id"], + vdu["id"])) + template = Template(cloud_init_content) + cloud_init_content = template.render(additionalParams) + except (TemplateError, TemplateNotFound, TemplateSyntaxError) as e: + raise LcmException("Error in jinja2 template: {}".format(e)) + vdu["cloud-init"] = cloud_init_content # remnove unused by RO configuration, monitoring, scaling vnfd_RO.pop("vnf-configuration", None) vnfd_RO.pop("monitoring-param", None) @@ -329,6 +358,10 @@ class NsLcm(LcmBase): populate_dict(RO_ns_params, ("vnfs", vnf_params["member-vnf-index"], "networks", internal_vld_params["name"], "vim-network-name"), internal_vld_params["vim-network-name"]) + if internal_vld_params.get("vim-network-id"): + populate_dict(RO_ns_params, ("vnfs", vnf_params["member-vnf-index"], "networks", + internal_vld_params["name"], "vim-network-id"), + internal_vld_params["vim-network-id"]) if internal_vld_params.get("ip-profile"): populate_dict(RO_ns_params, ("vnfs", vnf_params["member-vnf-index"], "networks", internal_vld_params["name"], "ip-profile"), @@ -377,6 +410,18 @@ class NsLcm(LcmBase): RO_vld_sites.append({"netmap-use": vld_params["vim-network-name"]}) if RO_vld_sites: populate_dict(RO_ns_params, ("networks", vld_params["name"], "sites"), RO_vld_sites) + if vld_params.get("vim-network-id"): + RO_vld_sites = [] + if isinstance(vld_params["vim-network-id"], dict): + for vim_account, vim_net in vld_params["vim-network-id"].items(): + RO_vld_sites.append({ + "netmap-use": vim_net, + "datacenter": vim_account_2_RO(vim_account) + }) + else: # isinstance str + RO_vld_sites.append({"netmap-use": vld_params["vim-network-id"]}) + if RO_vld_sites: + populate_dict(RO_ns_params, ("networks", vld_params["name"], "sites"), RO_vld_sites) if "vnfd-connection-point-ref" in vld_params: for cp_params in vld_params["vnfd-connection-point-ref"]: # look for interface @@ -557,7 +602,7 @@ class NsLcm(LcmBase): nslcmop_operation_state = None db_vnfrs = {} RO_descriptor_number = 0 # number of descriptors created at RO - descriptor_id_2_RO = {} # map between vnfd/nsd id to the id used at RO + vnf_index_2_RO_id = {} # map between vnfd/nsd id to the id used at RO n2vc_info = {} exc = None try: @@ -611,13 +656,18 @@ class NsLcm(LcmBase): RO = ROclient.ROClient(self.loop, **self.ro_config) + # set state to INSTANTIATED. When instantiated NBI will not delete directly + db_nsr_update["_admin.nsState"] = "INSTANTIATED" + self.update_db_2("nsrs", nsr_id, db_nsr_update) + # get vnfds, instantiate at RO - for vnfd_id, vnfd in db_vnfds.items(): + for c_vnf in nsd.get("constituent-vnfd", ()): + member_vnf_index = c_vnf["member-vnf-index"] vnfd_ref = vnfd["id"] step = db_nsr_update["detailed-status"] = "Creating vnfd={} at RO".format(vnfd_ref) # self.logger.debug(logging_text + step) - vnfd_id_RO = "{}.{}.{}".format(nsr_id, RO_descriptor_number, vnfd_ref[:23]) - descriptor_id_2_RO[vnfd_ref] = vnfd_id_RO + vnfd_id_RO = "{}.{}.{}".format(nsr_id, RO_descriptor_number, member_vnf_index[:23]) + vnf_index_2_RO_id[member_vnf_index] = vnfd_id_RO RO_descriptor_number += 1 # look if present @@ -627,10 +677,10 @@ class NsLcm(LcmBase): self.logger.debug(logging_text + "vnfd={} exists at RO. Using RO_id={}".format( vnfd_ref, vnfd_list[0]["uuid"])) else: - vnfd_RO = self.vnfd2RO(vnfd, vnfd_id_RO) + vnfd_RO = self.vnfd2RO(vnfd, vnfd_id_RO, db_vnfrs[c_vnf["member-vnf-index"]]. + get("additionalParamsForVnf"), nsr_id) desc = await RO.create("vnfd", descriptor=vnfd_RO) db_nsr_update["_admin.deployed.RO.vnfd_id.{}".format(vnfd_id)] = desc["uuid"] - db_nsr_update["_admin.nsState"] = "INSTANTIATED" self.logger.debug(logging_text + "vnfd={} created at RO. RO_id={}".format( vnfd_ref, desc["uuid"])) self.update_db_2("nsrs", nsr_id, db_nsr_update) @@ -641,7 +691,6 @@ class NsLcm(LcmBase): # self.logger.debug(logging_text + step) RO_osm_nsd_id = "{}.{}.{}".format(nsr_id, RO_descriptor_number, nsd_ref[:23]) - descriptor_id_2_RO[nsd_ref] = RO_osm_nsd_id RO_descriptor_number += 1 nsd_list = await RO.get_list("nsd", filter_by={"osm_id": RO_osm_nsd_id}) if nsd_list: @@ -654,8 +703,13 @@ class NsLcm(LcmBase): nsd_RO.pop("_id", None) nsd_RO.pop("_admin", None) for c_vnf in nsd_RO.get("constituent-vnfd", ()): - vnfd_id = c_vnf["vnfd-id-ref"] - c_vnf["vnfd-id-ref"] = descriptor_id_2_RO[vnfd_id] + member_vnf_index = c_vnf["member-vnf-index"] + c_vnf["vnfd-id-ref"] = vnf_index_2_RO_id[member_vnf_index] + for c_vld in nsd_RO.get("vld", ()): + for cp in c_vld.get("vnfd-connection-point-ref", ()): + member_vnf_index = cp["member-vnf-index-ref"] + cp["vnfd-id-ref"] = vnf_index_2_RO_id[member_vnf_index] + desc = await RO.create("nsd", descriptor=nsd_RO) db_nsr_update["_admin.nsState"] = "INSTANTIATED" db_nsr_update["_admin.deployed.RO.nsd_id"] = RO_nsd_uuid = desc["uuid"] @@ -790,20 +844,18 @@ class NsLcm(LcmBase): # ns_name will be ignored in the current version of N2VC # but will be implemented for the next point release. - model_name = 'default' # TODO bug 581 : change to nsr_id + model_name = "default" # TODO bug 585 nsr_id if vdu_id: - vdu_id_text = vdu_id + vdu_id_text = vdu_id + "-" else: - vdu_id_text = "vnfd" # TODO bug 581 remove and add just an empty string "" + vdu_id_text = "-" application_name = self.n2vc.FormatApplicationName(nsr_name, vnf_index, vdu_id_text) - # TODO bug 581 Add "-" as a final argument vca_index = len(vca_deployed_list) # trunk name and add two char index at the end to ensure that it is unique. It is assumed no more than # 26*26 charm in the same NS - # TODO bug 581 uncoment - # application_name = application_name[0:48] - # application_name += chr(97 + vca_index / 26) + chr(97 + vca_index % 26) + application_name = application_name[0:48] + application_name += chr(97 + vca_index // 26) + chr(97 + vca_index % 26) vca_deployed_ = { "member-vnf-index": vnf_index, "vdu_id": vdu_id, @@ -997,11 +1049,14 @@ class NsLcm(LcmBase): db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc) db_nslcmop_update["operationState"] = nslcmop_operation_state = "FAILED" db_nslcmop_update["statusEnteredTime"] = time() - if db_nsr: - db_nsr_update["_admin.nslcmop"] = None - self.update_db_2("nsrs", nsr_id, db_nsr_update) - if db_nslcmop_update: - self.update_db_2("nslcmops", nslcmop_id, db_nslcmop_update) + try: + if db_nsr: + db_nsr_update["_admin.nslcmop"] = None + self.update_db_2("nsrs", nsr_id, db_nsr_update) + if db_nslcmop_update: + self.update_db_2("nslcmops", nslcmop_id, db_nslcmop_update) + except DbException as e: + self.logger.error(logging_text + "Cannot update database: {}".format(e)) if nslcmop_operation_state: try: await self.msg.aiowrite("ns", "instantiated", {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id, @@ -1012,6 +1067,34 @@ class NsLcm(LcmBase): self.logger.debug(logging_text + "Exit") self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate") + async def _destroy_charm(self, model, application): + """ + Order N2VC destroy a charm + :param model: + :param application: + :return: True if charm does not exist. False if it exist + """ + if not await self.n2vc.HasApplication(model, application): + return True # Already removed + await self.n2vc.RemoveCharms(model, application) + return False + + async def _wait_charm_destroyed(self, model, application, timeout): + """ + Wait until charm does not exist + :param model: + :param application: + :param timeout: + :return: True if not exist, False if timeout + """ + while True: + if not await self.n2vc.HasApplication(model, application): + return True + if timeout < 0: + return False + await asyncio.sleep(10) + timeout -= 10 + async def terminate(self, nsr_id, nslcmop_id): logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id) self.logger.debug(logging_text + "Enter") @@ -1019,9 +1102,7 @@ class NsLcm(LcmBase): db_nslcmop = None exc = None failed_detail = [] # annotates all failed error messages - vca_task_list = [] - vca_task_dict = {} - vca_application_name2index = {} + vca_time_destroy = None # time of where destroy charm order db_nsr_update = {"_admin.nslcmop": nslcmop_id} db_nslcmop_update = {} nslcmop_operation_state = None @@ -1034,8 +1115,6 @@ class NsLcm(LcmBase): nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED": return - # TODO ALF remove - # db_vim = self.db.get_one("vim_accounts", {"_id": db_nsr["datacenter"]}) # #TODO check if VIM is creating and wait # RO_vim_id = db_vim["_admin"]["deployed"]["RO"] @@ -1048,25 +1127,19 @@ class NsLcm(LcmBase): db_nsr_update["detailed-status"] = "Deleting charms" self.logger.debug(logging_text + step) self.update_db_2("nsrs", nsr_id, db_nsr_update) + # for backward compatibility + if isinstance(nsr_deployed["VCA"], dict): + nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values()) + db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"] + self.update_db_2("nsrs", nsr_id, db_nsr_update) + for vca_index, vca_deployed in enumerate(nsr_deployed["VCA"]): - if vca_deployed: # TODO it would be desirable having a and deploy_info.get("deployed"): - task = asyncio.ensure_future( - self.n2vc.RemoveCharms( - vca_deployed['model'], - vca_deployed["application"], - # self.n2vc_callback, - # db_nsr, - # db_nslcmop, - ) - ) - vca_application_name2index[vca_deployed["application"]] = vca_index - vca_task_list.append(task) - vca_task_dict[vca_deployed["application"]] = task - # task.add_done_callback(functools.partial(self.n2vc_callback, vca_deployed['model'], - # vca_deployed['application'], None, db_nsr, - # db_nslcmop, vnf_index)) - self.lcm_tasks.register("ns", nsr_id, nslcmop_id, - "delete_charm:" + vca_deployed["application"], task) + if vca_deployed: + if await self._destroy_charm(vca_deployed['model'], vca_deployed["application"]): + vca_deployed.clear() + db_nsr["_admin.deployed.VCA.{}".format(vca_index)] = None + else: + vca_time_destroy = time() except Exception as e: self.logger.debug(logging_text + "Failed while deleting charms: {}".format(e)) @@ -1082,6 +1155,8 @@ class NsLcm(LcmBase): try: if RO_nsr_id: step = db_nsr_update["detailed-status"] = db_nslcmop_update["detailed-status"] = "Deleting ns at RO" + self.update_db_2("nslcmops", nslcmop_id, db_nslcmop_update) + self.update_db_2("nsrs", nsr_id, db_nsr_update) self.logger.debug(logging_text + step) desc = await RO.delete("ns", RO_nsr_id) RO_delete_action = desc["action_id"] @@ -1090,7 +1165,8 @@ class NsLcm(LcmBase): db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED" if RO_delete_action: # wait until NS is deleted from VIM - step = detailed_status = "Waiting ns deleted from VIM. RO_id={}".format(RO_nsr_id) + step = detailed_status = "Waiting ns deleted from VIM. RO_id={} RO_delete_action={}".\ + format(RO_nsr_id, RO_delete_action) detailed_status_old = None self.logger.debug(logging_text + step) @@ -1104,14 +1180,18 @@ class NsLcm(LcmBase): elif ns_status == "BUILD": detailed_status = step + "; {}".format(ns_status_info) elif ns_status == "ACTIVE": + db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None + db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED" break else: assert False, "ROclient.check_action_status returns unknown {}".format(ns_status) - await asyncio.sleep(5, loop=self.loop) - delete_timeout -= 5 if detailed_status != detailed_status_old: - detailed_status_old = db_nslcmop_update["detailed-status"] = detailed_status + detailed_status_old = db_nslcmop_update["detailed-status"] = \ + db_nsr_update["detailed-status"] = detailed_status self.update_db_2("nslcmops", nslcmop_id, db_nslcmop_update) + self.update_db_2("nsrs", nsr_id, db_nsr_update) + await asyncio.sleep(5, loop=self.loop) + delete_timeout -= 5 else: # delete_timeout <= 0: raise ROclient.ROClientException("Timeout waiting ns deleted from VIM") @@ -1119,6 +1199,7 @@ class NsLcm(LcmBase): if e.http_code == 404: # not found db_nsr_update["_admin.deployed.RO.nsr_id"] = None db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED" + db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None self.logger.debug(logging_text + "RO_ns_id={} already deleted".format(RO_nsr_id)) elif e.http_code == 409: # conflict failed_detail.append("RO_ns_id={} delete conflict: {}".format(RO_nsr_id, e)) @@ -1172,28 +1253,23 @@ class NsLcm(LcmBase): failed_detail.append("RO_vnfd_id={} delete error: {}".format(RO_vnfd_id, e)) self.logger.error(logging_text + failed_detail[-1]) - if vca_task_list: - db_nsr_update["detailed-status"] = db_nslcmop_update["detailed-status"] =\ + # wait until charm deleted + if vca_time_destroy: + db_nsr_update["detailed-status"] = db_nslcmop_update["detailed-status"] = step = \ "Waiting for deletion of configuration charms" self.update_db_2("nslcmops", nslcmop_id, db_nslcmop_update) self.update_db_2("nsrs", nsr_id, db_nsr_update) - await asyncio.wait(vca_task_list, timeout=300) - for application_name, task in vca_task_dict.items(): - if task.cancelled(): - failed_detail.append("VCA[application_name={}] Deletion has been cancelled" - .format(application_name)) - elif task.done(): - exc = task.exception() - if exc: - failed_detail.append("VCA[application_name={}] Deletion exception: {}" - .format(application_name, exc)) + for vca_index, vca_deployed in enumerate(nsr_deployed["VCA"]): + if not vca_deployed: + continue + step = "Waiting for deletion of charm application_name={}".format(vca_deployed["application"]) + timeout = self.timeout_charm_delete - int(time() - vca_time_destroy) + if not await self._wait_charm_destroyed(vca_deployed['model'], vca_deployed["application"], + timeout): + failed_detail.append("VCA[application_name={}] Deletion timeout".format( + vca_deployed["application"])) else: - vca_index = vca_application_name2index[application_name] - db_nsr_update["_admin.deployed.VCA.{}".format(vca_index)] = None - else: # timeout - # TODO Should it be cancelled?!! - task.cancel() - failed_detail.append("VCA[application_name={}] Deletion timeout".format(application_name)) + db_nsr["_admin.deployed.VCA.{}".format(vca_index)] = None if failed_detail: self.logger.error(logging_text + " ;".join(failed_detail)) @@ -1204,13 +1280,15 @@ class NsLcm(LcmBase): db_nslcmop_update["statusEnteredTime"] = time() elif db_nslcmop["operationParams"].get("autoremove"): self.db.del_one("nsrs", {"_id": nsr_id}) + db_nsr = None db_nsr_update.clear() self.db.del_list("nslcmops", {"nsInstanceId": nsr_id}) + db_nslcmop = None nslcmop_operation_state = "COMPLETED" db_nslcmop_update.clear() self.db.del_list("vnfrs", {"nsr-id-ref": nsr_id}) self.db.set_list("pdus", {"_admin.usage.nsr_id": nsr_id}, - {"_admin.usageSate": "NOT_IN_USE", "_admin.usage": None}) + {"_admin.usageState": "NOT_IN_USE", "_admin.usage": None}) self.logger.debug(logging_text + "Delete from database") else: db_nsr_update["operational-status"] = "terminated" @@ -1234,11 +1312,14 @@ class NsLcm(LcmBase): db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc) db_nslcmop_update["operationState"] = nslcmop_operation_state = "FAILED" db_nslcmop_update["statusEnteredTime"] = time() - if db_nslcmop_update: - self.update_db_2("nslcmops", nslcmop_id, db_nslcmop_update) - if db_nsr: - db_nsr_update["_admin.nslcmop"] = None - self.update_db_2("nsrs", nsr_id, db_nsr_update) + try: + if db_nslcmop and db_nslcmop_update: + self.update_db_2("nslcmops", nslcmop_id, db_nslcmop_update) + if db_nsr: + db_nsr_update["_admin.nslcmop"] = None + self.update_db_2("nsrs", nsr_id, db_nsr_update) + except DbException as e: + self.logger.error(logging_text + "Cannot update database: {}".format(e)) if nslcmop_operation_state: try: await self.msg.aiowrite("ns", "terminated", {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id, @@ -1340,6 +1421,12 @@ class NsLcm(LcmBase): if pending: raise LcmException("Timeout waiting related tasks to be completed") + # for backward compatibility + if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict): + nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values()) + db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"] + self.update_db_2("nsrs", nsr_id, db_nsr_update) + # TODO check if ns is in a proper status primitive = db_nslcmop["operationParams"]["primitive"] primitive_params = db_nslcmop["operationParams"]["primitive_params"] @@ -1366,11 +1453,14 @@ class NsLcm(LcmBase): db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc) db_nslcmop_update["operationState"] = nslcmop_operation_state = "FAILED" db_nslcmop_update["statusEnteredTime"] = time() - if db_nslcmop_update: - self.update_db_2("nslcmops", nslcmop_id, db_nslcmop_update) - if db_nsr: - db_nsr_update["_admin.nslcmop"] = None - self.update_db_2("nsrs", nsr_id, db_nsr_update) + try: + if db_nslcmop_update: + self.update_db_2("nslcmops", nslcmop_id, db_nslcmop_update) + if db_nsr: + db_nsr_update["_admin.nslcmop"] = None + self.update_db_2("nsrs", nsr_id, db_nsr_update) + except DbException as e: + self.logger.error(logging_text + "Cannot update database: {}".format(e)) self.logger.debug(logging_text + "Exit") if nslcmop_operation_state: try: @@ -1426,6 +1516,12 @@ class NsLcm(LcmBase): scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"] # scaling_policy = db_nslcmop["operationParams"]["scaleVnfData"]["scaleByStepData"].get("scaling-policy") + # for backward compatibility + if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict): + nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values()) + db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"] + self.update_db_2("nsrs", nsr_id, db_nsr_update) + step = "Getting vnfr from database" db_vnfr = self.db.get_one("vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}) step = "Getting vnfd from database" @@ -1702,11 +1798,14 @@ class NsLcm(LcmBase): db_nsr_update["operational-status"] = "failed" db_nsr_update["detailed-status"] = "FAILED scaling nslcmop={} {}: {}".format(nslcmop_id, step, exc) - if db_nslcmop_update: - self.update_db_2("nslcmops", nslcmop_id, db_nslcmop_update) - if db_nsr: - db_nsr_update["_admin.nslcmop"] = None - self.update_db_2("nsrs", nsr_id, db_nsr_update) + try: + if db_nslcmop and db_nslcmop_update: + self.update_db_2("nslcmops", nslcmop_id, db_nslcmop_update) + if db_nsr: + db_nsr_update["_admin.nslcmop"] = None + self.update_db_2("nsrs", nsr_id, db_nsr_update) + except DbException as e: + self.logger.error(logging_text + "Cannot update database: {}".format(e)) if nslcmop_operation_state: try: await self.msg.aiowrite("ns", "scaled", {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id,