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()
exc = None
try:
step = "Getting vim from db"
- db_vim = self.db.get_one("vims", {"_id": vim_id})
+ db_vim = self.db.get_one("vim_accounts", {"_id": vim_id})
if "_admin" not in db_vim:
db_vim["_admin"] = {}
if "deployed" not in db_vim["_admin"]:
desc = await RO.create("vim", descriptor=vim_RO)
RO_vim_id = desc["uuid"]
db_vim["_admin"]["deployed"]["RO"] = RO_vim_id
- self.update_db("vims", vim_id, db_vim)
+ self.update_db("vim_accounts", vim_id, db_vim)
step = "Attach vim to RO tenant"
vim_RO = {"vim_tenant_name": vim_content["vim_tenant_name"],
}
desc = await RO.attach_datacenter(RO_vim_id , descriptor=vim_RO)
db_vim["_admin"]["operationalState"] = "ENABLED"
- self.update_db("vims", vim_id, db_vim)
+ self.update_db("vim_accounts", vim_id, db_vim)
self.logger.debug(logging_text + "Exit Ok RO_vim_id".format(RO_vim_id))
return RO_vim_id
if exc and db_vim:
db_vim["_admin"]["operationalState"] = "ERROR"
db_vim["_admin"]["detailed-status"] = "ERROR {}: {}".format(step , exc)
- self.update_db("vims", vim_id, db_vim)
+ self.update_db("vim_accounts", vim_id, db_vim)
async def vim_edit(self, vim_content, order_id):
vim_id = vim_content["_id"]
exc = None
step = "Getting vim from db"
try:
- db_vim = self.db.get_one("vims", {"_id": vim_id})
+ db_vim = self.db.get_one("vim_accounts", {"_id": vim_id})
if db_vim.get("_admin") and db_vim["_admin"].get("deployed") and db_vim["_admin"]["deployed"].get("RO"):
RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
step = "Editing vim at RO"
if vim_RO:
desc = await RO.edit("vim_account", RO_vim_id, descriptor=vim_RO)
db_vim["_admin"]["operationalState"] = "ENABLED"
- self.update_db("vims", vim_id, db_vim)
+ self.update_db("vim_accounts", vim_id, db_vim)
self.logger.debug(logging_text + "Exit Ok RO_vim_id".format(RO_vim_id))
return RO_vim_id
if exc and db_vim:
db_vim["_admin"]["operationalState"] = "ERROR"
db_vim["_admin"]["detailed-status"] = "ERROR {}: {}".format(step , exc)
- self.update_db("vims", vim_id, db_vim)
+ self.update_db("vim_accounts", vim_id, db_vim)
async def vim_delete(self, vim_id, order_id):
logging_text = "Task vim_delete={} ".format(vim_id)
exc = None
step = "Getting vim from db"
try:
- db_vim = self.db.get_one("vims", {"_id": vim_id})
+ db_vim = self.db.get_one("vim_accounts", {"_id": vim_id})
if db_vim.get("_admin") and db_vim["_admin"].get("deployed") and db_vim["_admin"]["deployed"].get("RO"):
RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
RO = ROclient.ROClient(self.loop, **self.ro_config)
else:
# nothing to delete
self.logger.error(logging_text + "Skipping. There is not RO information at database")
- self.db.del_one("vims", {"_id": vim_id})
+ self.db.del_one("vim_accounts", {"_id": vim_id})
self.logger.debug("vim_delete task vim_id={} Exit Ok".format(vim_id))
return None
if exc and db_vim:
db_vim["_admin"]["operationalState"] = "ERROR"
db_vim["_admin"]["detailed-status"] = "ERROR {}: {}".format(step , exc)
- self.update_db("vims", vim_id, db_vim)
+ self.update_db("vim_accounts", vim_id, db_vim)
async def sdn_create(self, sdn_content, order_id):
sdn_id = sdn_content["_id"]
sdn_RO.pop("_admin", None)
sdn_RO.pop("schema_version", None)
sdn_RO.pop("schema_type", None)
+ sdn_RO.pop("description", None)
desc = await RO.create("sdn", descriptor=sdn_RO)
RO_sdn_id = desc["uuid"]
db_sdn["_admin"]["deployed"]["RO"] = RO_sdn_id
sdn_RO.pop("_admin", None)
sdn_RO.pop("schema_version", None)
sdn_RO.pop("schema_type", None)
+ sdn_RO.pop("description", None)
if sdn_RO:
desc = await RO.edit("sdn", RO_sdn_id, descriptor=sdn_RO)
db_sdn["_admin"]["operationalState"] = "ENABLED"
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. operationalState={}".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")
# get all needed from database
db_nsr = None
db_nslcmop = None
+ db_vnfr = {}
exc = None
step = "Getting nsr, nslcmop, RO_vims from db"
try:
db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
nsd = db_nsr["nsd"]
nsr_name = db_nsr["name"] # TODO short-name??
-
- db_vim = self.db.get_one("vims", {"_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 = {}
+ vnfr_filter = {"nsr-id-ref": nsr_id, "member-vnf-index-ref": None}
for c_vnf in nsd["constituent-vnfd"]:
vnfd_id = c_vnf["vnfd-id-ref"]
+ vnfr_filter["member-vnf-index-ref"] = c_vnf["member-vnf-index"]
+ db_vnfr[c_vnf["member-vnf-index"]] = self.db.get_one("vnfrs", vnfr_filter)
if vnfd_id not in needed_vnfd:
step = "Getting vnfd={} from db".format(vnfd_id)
needed_vnfd[vnfd_id] = self.db.get_one("vnfds", {"id": vnfd_id})
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():
self.logger.debug(logging_text + step + " RO_ns_id={}".format(RO_nsr_id))
await RO.delete("ns", RO_nsr_id)
RO_nsr_id = nsr_lcm["RO"]["nsr_id"] = None
-
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"
nsr_lcm["RO"]["nsr_status"] = "BUILD"
+
self.update_db("nsrs", nsr_id, db_nsr)
+ # update VNFR vimAccount
+ step = "Updating VNFR vimAcccount"
+ for vnf_index, vnfr in db_vnfr.items():
+ if vnfr.get("vim-account-id"):
+ continue
+ if db_nsr["instantiate_params"].get("vnf") and db_nsr["instantiate_params"]["vnf"].get(vnf_index) \
+ and db_nsr["instantiate_params"]["vnf"][vnf_index].get("vimAccountId"):
+ vnfr["vim-account-id"] = db_nsr["instantiate_params"]["vnf"][vnf_index]["vimAccountId"]
+ else:
+ vnfr["vim-account-id"] = db_nsr["instantiate_params"]["vimAccountId"]
+ self.update_db("vnfrs", vnfr["_id"], vnfr)
# wait until NS is ready
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":
- nsr_lcm["nsr_ip"] = RO.get_ns_vnf_ip(desc)
+ step = "Getting ns VIM information"
+ ns_RO_info = nsr_lcm["nsr_ip"] = RO.get_ns_vnf_info(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")
+ step = "Updating VNFRs"
+ for vnf_index, vnfr_deployed in ns_RO_info.items():
+ vnfr = db_vnfr[vnf_index]
+ vnfr["ip-address"] = vnfr_deployed.get("ip_address")
+ for vdu_id, vdu_deployed in vnfr_deployed["vdur"].items():
+ for vdur in vnfr["vdur"]:
+ if vdur["vdu-id-ref"] == vdu_id:
+ vdur["vim-id"] = vdu_deployed.get("vim_id")
+ vdur["ip-address"] = vdu_deployed.get("ip_address")
+ break
+ self.update_db("vnfrs", vnfr["_id"], vnfr)
+
db_nsr["detailed-status"] = "Configuring vnfr"
self.update_db("nsrs", nsr_id, db_nsr)
)
# Setup the runtime parameters for this VNF
- params['rw_mgmt_ip'] = nsr_lcm['nsr_ip']["vnf"][vnf_index]
+ params['rw_mgmt_ip'] = db_vnfr[vnf_index]["ip-address"]
# ns_name will be ignored in the current version of N2VC
# but will be implemented for the next point release.
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
if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
return
# TODO ALF remove
- # db_vim = self.db.get_one("vims", {"_id": db_nsr["datacenter"]})
+ # 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"]
"_admin": {"deployed": nsr_lcm, }
}
db_nslcmop_update = {
- "detailedStatus": "; ".join(failed_detail),
+ "detailed-status": "; ".join(failed_detail),
"operationState": "FAILED",
"statusEnteredTime": time()
}
elif db_nslcmop["operationParams"].get("autoremove"):
self.db.del_one("nsrs", {"_id": nsr_id})
self.db.del_list("nslcmops", {"nsInstanceId": nsr_id})
+ self.db.del_list("vnfrs", {"nsr-id-ref": nsr_id})
else:
db_nsr_update = {
"operational-status": "terminated",
"_admin": {"deployed": nsr_lcm, "nsState": "NOT_INSTANTIATED"}
}
db_nslcmop_update = {
- "detailedStatus": "Done",
+ "detailed-status": "Done",
"operationState": "COMPLETED",
"statusEnteredTime": time()
}
db_nslcmop = None
db_nslcmop_update = None
exc = None
- step = "Getting nsr, nslcmop"
try:
+ step = "Getting information from database"
db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
nsr_lcm = db_nsr["_admin"].get("deployed")
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()
}