from os import environ
# from vca import DeployApplication, RemoveApplication
from n2vc.vnf import N2VC
+from n2vc import version as N2VC_version
# import os.path
# import time
# artifacts=config['VCA'][''],
artifacts=None,
)
-
+ # check version of N2VC
+ # TODO enhance with int conversion or from distutils.version import LooseVersion
+ # or with list(map(int, version.split(".")))
+ if N2VC_version < "0.0.2":
+ raise LcmException("Not compatible osm/N2VC version '{}'. Needed '0.0.2' or higher".format(N2VC_version))
try:
if config["database"]["driver"] == "mongo":
self.db = dbmongo.DbMongo()
if ci_file:
ci_file.close()
- def n2vc_callback(self, model_name, application_name, workload_status, db_nsr, db_nslcmop, vnf_member_index, task=None):
- """Update the lcm database with the status of the charm.
-
- Updates the VNF's operational status with the state of the charm:
- - blocked: The unit needs manual intervention
- - maintenance: The unit is actively deploying/configuring
- - waiting: The unit is waiting for another charm to be ready
- - active: The unit is deployed, configured, and ready
- - error: The charm has failed and needs attention.
- - terminated: The charm has been destroyed
- - removing,
- - removed
-
- Updates the network service's config-status to reflect the state of all
- charms.
+ def n2vc_callback(self, model_name, application_name, status, message, db_nsr, db_nslcmop, vnf_member_index, task=None):
+ """
+ Callback both for charm status change and task completion
+ :param model_name: Charm model name
+ :param application_name: Charm application name
+ :param status: Can be
+ - blocked: The unit needs manual intervention
+ - maintenance: The unit is actively deploying/configuring
+ - waiting: The unit is waiting for another charm to be ready
+ - active: The unit is deployed, configured, and ready
+ - error: The charm has failed and needs attention.
+ - terminated: The charm has been destroyed
+ - removing,
+ - removed
+ :param message: detailed message error
+ :param db_nsr: nsr database content
+ :param db_nslcmop: nslcmop database content
+ :param vnf_member_index: NSD vnf-member-index
+ :param task: None for charm status change, or task for completion task callback
+ :return:
"""
nsr_id = None
nslcmop_id = None
nsr_lcm["VCA"][vnf_member_index]['detailed-status'] = str(exc)
elif ns_action == "action":
db_nslcmop["operationState"] = "FAILED"
- db_nslcmop["detailedStatus"] = str(exc)
+ db_nslcmop["detailed-status"] = str(exc)
db_nslcmop["statusEnteredTime"] = time()
update_nslcmop = True
return
# TODO revise with Adam if action is finished and ok when task is done
if ns_action == "action":
db_nslcmop["operationState"] = "COMPLETED"
- db_nslcmop["detailedStatus"] = "Done"
+ db_nslcmop["detailed-status"] = "Done"
db_nslcmop["statusEnteredTime"] = time()
update_nslcmop = True
# task is Done, but callback is still ongoing. So ignore
return
- elif workload_status:
- self.logger.debug(logging_text + " Enter workload_status={}".format(workload_status))
- if nsr_lcm["VCA"][vnf_member_index]['operational-status'] == workload_status:
+ elif status:
+ self.logger.debug(logging_text + " Enter status={}".format(status))
+ if nsr_lcm["VCA"][vnf_member_index]['operational-status'] == status:
return # same status, ignore
- nsr_lcm["VCA"][vnf_member_index]['operational-status'] = workload_status
- # TODO N2VC some error message in case of error should be obtained from N2VC
- nsr_lcm["VCA"][vnf_member_index]['detailed-status'] = ""
+ nsr_lcm["VCA"][vnf_member_index]['operational-status'] = status
+ nsr_lcm["VCA"][vnf_member_index]['detailed-status'] = str(message)
else:
self.logger.critical(logging_text + " Enter with bad parameters", exc_info=True)
return
- some_failed = False
all_active = True
status_map = {}
+ n2vc_error_text = [] # contain text error list. If empty no one is in error status
for vnf_index, vca_info in nsr_lcm["VCA"].items():
vca_status = vca_info["operational-status"]
if vca_status not in status_map:
if vca_status != "active":
all_active = False
- if vca_status == "error":
- some_failed = True
- db_nsr["config-status"] = "failed"
- error_text = "fail configuring vnf_index={} {}".format(vnf_member_index,
- vca_info["detailed-status"])
- db_nsr["detailed-status"] = error_text
- db_nslcmop["operationState"] = "FAILED_TEMP"
- db_nslcmop["detailedStatus"] = error_text
- db_nslcmop["statusEnteredTime"] = time()
- break
+ elif vca_status in ("error", "blocked"):
+ n2vc_error_text.append("member_vnf_index={} {}: {}".format(vnf_member_index, vca_status,
+ vca_info["detailed-status"]))
if all_active:
self.logger.debug("[n2vc_callback] ns_instantiate={} vnf_index={} All active".format(nsr_id, vnf_member_index))
db_nsr["config-status"] = "configured"
db_nsr["detailed-status"] = "done"
db_nslcmop["operationState"] = "COMPLETED"
- db_nslcmop["detailedStatus"] = "Done"
+ db_nslcmop["detailed-status"] = "Done"
+ db_nslcmop["statusEnteredTime"] = time()
+ elif n2vc_error_text:
+ db_nsr["config-status"] = "failed"
+ error_text = "fail configuring " + ";".join(n2vc_error_text)
+ db_nsr["detailed-status"] = error_text
+ db_nslcmop["operationState"] = "FAILED_TEMP"
+ db_nslcmop["detailed-status"] = error_text
db_nslcmop["statusEnteredTime"] = time()
- elif some_failed:
- pass
else:
cs = "configuring: "
separator = ""
cs += separator + "{}: {}".format(status, num)
separator = ", "
db_nsr["config-status"] = cs
- db_nslcmop["detailedStatus"] = cs
+ db_nsr["detailed-status"] = cs
+ db_nslcmop["detailed-status"] = cs
update_nsr = update_nslcmop = True
except Exception as e:
self.logger.critical("[n2vc_callback] vnf_index={} Update database Exception {}".format(
vnf_member_index, e), exc_info=True)
+ def ns_params_2_RO(self, ns_params):
+ """
+ Creates a RO ns descriptor from OSM ns_instantite params
+ :param ns_params: OSM instantiate params
+ :return: The RO ns descriptor
+ """
+ vim_2_RO = {}
+ def vim_account_2_RO(vim_account):
+ if vim_account in vim_2_RO:
+ return vim_2_RO[vim_account]
+ db_vim = self.db.get_one("vim_accounts", {"_id": vim_account})
+ # if db_vim["_admin"]["operationalState"] == "PROCESSING":
+ # #TODO check if VIM is creating and wait
+ if db_vim["_admin"]["operationalState"] != "ENABLED":
+ raise LcmException("VIM={} is not available. operationalSstatus={}".format(
+ vim_account, db_vim["_admin"]["operationalState"]))
+ RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
+ vim_2_RO[vim_account] = RO_vim_id
+ return RO_vim_id
+
+ if not ns_params:
+ return None
+ RO_ns_params = {
+ # "name": ns_params["nsName"],
+ # "description": ns_params.get("nsDescription"),
+ "datacenter": vim_account_2_RO(ns_params["vimAccountId"]),
+ # "scenario": ns_params["nsdId"],
+ "vnfs": {},
+ "networks": {},
+ }
+ if ns_params.get("ssh-authorized-key"):
+ RO_ns_params["cloud-config"] = {"key-pairs": ns_params["ssh-authorized-key"]}
+ if ns_params.get("vnf"):
+ for vnf in ns_params["vnf"]:
+ RO_vnf = {}
+ if "vimAccountId" in vnf:
+ RO_vnf["datacenter"] = vim_account_2_RO(vnf["vimAccountId"])
+ if RO_vnf:
+ RO_ns_params["vnfs"][vnf["member-vnf-index"]] = RO_vnf
+ if ns_params.get("vld"):
+ for vld in ns_params["vld"]:
+ RO_vld = {}
+ if "ip-profile" in vld:
+ RO_vld["ip-profile"] = vld["ip-profile"]
+ if "vim-network-name" in vld:
+ RO_vld["sites"] = []
+ if isinstance(vld["vim-network-name"], dict):
+ for vim_account, vim_net in vld["vim-network-name"].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["vim-network-name"]})
+ if RO_vld:
+ RO_ns_params["networks"][vld["name"]] = RO_vld
+ return RO_ns_params
+
async def ns_instantiate(self, nsr_id, nslcmop_id):
logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
self.logger.debug(logging_text + "Enter")
nsd = db_nsr["nsd"]
nsr_name = db_nsr["name"] # TODO short-name??
- db_vim = self.db.get_one("vim_accounts", {"_id": db_nsr["datacenter"]})
- # if db_vim["_admin"]["operationalState"] == "PROCESSING":
- # #TODO check if VIM is creating and wait
- if db_vim["_admin"]["operationalState"] != "ENABLED":
- raise LcmException("VIM={} is not available. operationalSstatus={}".format(
- db_nsr["datacenter"], db_vim["_admin"]["operationalState"]))
- RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
-
needed_vnfd = {}
for c_vnf in nsd["constituent-vnfd"]:
vnfd_id = c_vnf["vnfd-id-ref"]
db_nsr["detailed-status"] = "creating"
db_nsr["operational-status"] = "init"
- deloyment_timeout = 120
-
- RO = ROclient.ROClient(self.loop, datacenter=RO_vim_id, **self.ro_config)
+ RO = ROclient.ROClient(self.loop, **self.ro_config)
# get vnfds, instantiate at RO
for vnfd_id, vnfd in needed_vnfd.items():
if not RO_nsr_id:
step = db_nsr["detailed-status"] = "Creating ns at RO"
self.logger.debug(logging_text + step)
-
- desc = await RO.create("ns", name=db_nsr["name"], datacenter=RO_vim_id,
+ RO_ns_params = self.ns_params_2_RO(db_nsr.get("instantiate_params"))
+ desc = await RO.create("ns", descriptor=RO_ns_params,
+ name=db_nsr["name"],
scenario=nsr_lcm["RO"]["nsd_id"])
RO_nsr_id = nsr_lcm["RO"]["nsr_id"] = desc["uuid"]
db_nsr["_admin"]["nsState"] = "INSTANTIATED"
step = ns_status_detailed = "Waiting ns ready at RO"
db_nsr["detailed-status"] = ns_status_detailed
self.logger.debug(logging_text + step + " RO_ns_id={}".format(RO_nsr_id))
- deloyment_timeout = 600
- while deloyment_timeout > 0:
+ deployment_timeout = 2*3600 # Two hours
+ while deployment_timeout > 0:
desc = await RO.show("ns", RO_nsr_id)
ns_status, ns_status_info = RO.check_ns_status(desc)
nsr_lcm["RO"]["nsr_status"] = ns_status
db_nsr["detailed-status"] = ns_status_detailed + "; {}".format(ns_status_info)
self.update_db("nsrs", nsr_id, db_nsr)
elif ns_status == "ACTIVE":
+ step = "Getting ns VNF management IP address"
nsr_lcm["nsr_ip"] = RO.get_ns_vnf_ip(desc)
break
else:
assert False, "ROclient.check_ns_status returns unknown {}".format(ns_status)
await asyncio.sleep(5, loop=self.loop)
- deloyment_timeout -= 5
- if deloyment_timeout <= 0:
+ deployment_timeout -= 5
+ if deployment_timeout <= 0:
raise ROclient.ROClientException("Timeout waiting ns to be ready")
db_nsr["detailed-status"] = "Configuring vnfr"
self.update_db("nsrs", nsr_id, db_nsr)
None, # Callback parameter (task)
)
)
- task.add_done_callback(functools.partial(self.n2vc_callback, model_name, application_name, None,
+ task.add_done_callback(functools.partial(self.n2vc_callback, model_name, application_name, None, None,
db_nsr, db_nslcmop, vnf_index))
self.lcm_ns_tasks[nsr_id][nslcmop_id]["create_charm:" + vnf_index] = task
"_admin": {"deployed": nsr_lcm, }
}
db_nslcmop_update = {
- "detailedStatus": "; ".join(failed_detail),
+ "detailed-status": "; ".join(failed_detail),
"operationState": "FAILED",
"statusEnteredTime": time()
}
"_admin": {"deployed": nsr_lcm, "nsState": "NOT_INSTANTIATED"}
}
db_nslcmop_update = {
- "detailedStatus": "Done",
+ "detailed-status": "Done",
"operationState": "COMPLETED",
"statusEnteredTime": time()
}
result = "FAILED" # by default
result_detail = ""
if task.cancelled():
- db_nslcmop["detailedStatus"] = "Task has been cancelled"
+ db_nslcmop["detailed-status"] = "Task has been cancelled"
elif task.done():
exc = task.exception()
if exc:
result_detail = "timeout"
db_nslcmop_update = {
- "detailedStatus": result_detail,
+ "detailed-status": result_detail,
"operationState": result,
"statusEnteredTime": time()
}