Added implementation code for SOL003 STD support API's for VNF Lifecycle management interface
Change-Id: Ibd483a99aec24b1e7d8166d9e17a899e70b27647
Signed-off-by: selvi.j <selvi.j@tataelxsi.co.in>
NsiTopic,
NsiLcmOpTopic,
)
+from osm_nbi.vnf_instance_topics import VnfInstances, VnfLcmOpTopic
from osm_nbi.pmjobs_topics import PmJobsTopic
from osm_nbi.subscription_topics import NslcmSubscriptionsTopic
from base64 import b64encode
"nsilcmops": NsiLcmOpTopic,
"vnfpkgops": VnfPkgOpTopic,
"nslcm_subscriptions": NslcmSubscriptionsTopic,
+ "vnf_instances": VnfInstances,
+ "vnflcmops": VnfLcmOpTopic,
# [NEW_TOPIC]: add an entry here
# "pm_jobs": PmJobsTopic will be added manually because it needs other parameters
}
},
}
},
+ "vnflcm": {
+ "v1": {
+ "vnf_instances": {"METHODS": ("GET", "POST"),
+ "ROLE_PERMISSION": "vnflcm_instances:",
+ "<ID>": {"METHODS": ("GET", "DELETE"),
+ "ROLE_PERMISSION": "vnflcm_instances:id:",
+ "scale": {"METHODS": ("POST",),
+ "ROLE_PERMISSION": "vnflcm_instances:id:scale:"
+ },
+ "terminate": {"METHODS": ("POST",),
+ "ROLE_PERMISSION": "vnflcm_instances:id:terminate:"
+ },
+ "instantiate": {"METHODS": ("POST",),
+ "ROLE_PERMISSION": "vnflcm_instances:id:instantiate:"
+ },
+ }
+ },
+ "vnf_lcm_op_occs": {"METHODS": ("GET",),
+ "ROLE_PERMISSION": "vnf_instances:opps:",
+ "<ID>": {"METHODS": ("GET",),
+ "ROLE_PERMISSION": "vnf_instances:opps:id:"
+ },
+ },
+ }
+ },
"nst": {
"v1": {
"netslice_templates_content": {
"nst",
"nsilcm",
"nspm",
+ "vnflcm",
):
raise NbiException(
"URL main_topic '{}' not supported".format(main_topic),
engine_topic = "nslcmops"
if topic == "vnfrs" or topic == "vnf_instances":
engine_topic = "vnfrs"
+ elif main_topic == "vnflcm":
+ if topic == "vnf_lcm_op_occs":
+ engine_topic = "vnflcmops"
elif main_topic == "nst":
engine_topic = "nsts"
elif main_topic == "nsilcm":
"_links": link,
}
cherrypy.response.status = HTTPStatus.CREATED.value
+ elif topic == "vnf_instances" and item:
+ indata["lcmOperationType"] = item
+ indata["vnfInstanceId"] = _id
+ _id, _ = self.engine.new_item(rollback, engine_session, "vnflcmops", indata, kwargs)
+ self._set_location_header(main_topic, version, "vnf_lcm_op_occs", _id)
+ outdata = {"id": _id}
+ cherrypy.response.status = HTTPStatus.ACCEPTED.value
else:
_id, op_id = self.engine.new_item(
rollback,
--- /dev/null
+# Copyright 2021 K Sai Kiran (Tata Elxsi)
+#
+# 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.
--- /dev/null
+# Copyright 2021 K Sai Kiran (Tata Elxsi)
+#
+# 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.
+
+__author__ = "K Sai Kiran <saikiran.k@tataelxsi.co.in>, Selvi Jayaraman <selvi.j@tataelxsi.co.in>"
+__date__ = "$12-June-2021 8:30:59$"
+
+
+import logging
+
+
+class BaseMethod:
+
+ def __init__(self):
+ """
+ Constructor of the base method
+ """
+ self.logger = logging.getLogger("nbi.engine")
--- /dev/null
+# Copyright 2021 K Sai Kiran (Tata Elxsi)
+#
+# 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.
+
+__author__ = "K Sai Kiran <saikiran.k@tataelxsi.co.in>, Selvi Jayaraman <selvi.j@tataelxsi.co.in>"
+__date__ = "$12-June-2021 8:30:59$"
+
+from osm_nbi.instance_topics import NsrTopic, NsLcmOpTopic, VnfrTopic
+from .base_methods import BaseMethod
+
+
+class VnfLcmOp2NsLcmOp:
+
+ def __init__(self, db, fs, msg, auth):
+ """
+ Constructor of Vnf lcm op to Ns lcm op
+ """
+ self.new_vnf_lcmop = NewVnfLcmOp(db, fs, msg, auth)
+ self.list_vnf_lcmop = ListVnfLcmOp(db, fs, msg, auth)
+ self.show_vnf_lcmop = ShowVnfLcmOp(db, fs, msg, auth)
+
+ def new(self, rollback, session, indata=None, kwargs=None, headers=None):
+ """
+ Creates a new entry into database.
+ :param rollback: list to append created items at database in case a rollback may to be done
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param indata: data to be inserted
+ :param kwargs: used to override the indata descriptor
+ :param headers: http request headers
+ :return: _id, op_id:
+ _id: identity of the inserted data.
+ op_id: operation id if this is asynchronous, None otherwise
+ """
+ return self.new_vnf_lcmop.action(rollback, session, indata, kwargs, headers)
+
+ def list(self, session, filter_q=None, api_req=False):
+ """
+ Get a list of the Vnf Lcm Operation that matches a filter
+ :param session: contains the used login username and working project
+ :param filter_q: filter of data to be applied
+ :param api_req: True if this call is serving an external API request. False if serving internal request.
+ :return: The list, it can be empty if no one match the filter.
+ """
+ return self.list_vnf_lcmop.action(session, filter_q, api_req)
+
+ def show(self, session, _id, api_req=False):
+ """
+ Get complete information on an Vnf Lcm Operation
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param _id: server internal id
+ :param api_req: True if this call is serving an external API request. False if serving internal request.
+ :return: dictionary, raise exception if not found.
+ """
+ return self.show_vnf_lcmop.action(session, _id, api_req)
+
+
+class NewVnfLcmOp(BaseMethod):
+
+ def __init__(self, db, fs, msg, auth):
+ """
+ Constructor of new Vnf Lcm Op
+ """
+ super().__init__()
+ self.msg = msg
+ self.nslcmoptopic = NsLcmOpTopic(db, fs, msg, auth)
+ self.nsrtopic = NsrTopic(db, fs, msg, auth)
+ self.vnfrtopic = VnfrTopic(db, fs, msg, auth)
+
+ def __get_nsdid(self, session, vnf_instance_id):
+ """
+ Returns a nsd id from vnf instance id.
+ :param session: contains the used login username and working project
+ :param vnf_instance_id: id of vnf instance
+ :return: id of nsd id
+ """
+ nsr = self.nsrtopic.show(session, vnf_instance_id)
+ return nsr['nsd']['_id']
+
+ def __get_formatted_indata(self, session, indata):
+ """
+ Returns formatted data for new vnf lcm op
+ :param session: contains the used login username and working project
+ :param indata: contains information for new lcm operation.
+ :return: formatted indata for new lcm op.
+ """
+ formatted_indata = {}
+ if indata["lcmOperationType"] == "instantiate":
+ formatted_indata = {
+ "nsName": indata["vnfName"],
+ "nsDescription": indata["vnfDescription"],
+ "nsdId": self.__get_nsdid(session, indata["vnfInstanceId"]),
+ "vimAccountId": indata["vimAccountId"],
+ "nsr_id": indata["vnfInstanceId"],
+ "lcmOperationType": indata["lcmOperationType"],
+ "nsInstanceId": indata["vnfInstanceId"]
+ }
+ elif indata["lcmOperationType"] == "terminate":
+ formatted_indata = {
+ "lcmOperationType": indata["lcmOperationType"],
+ "nsInstanceId": indata["vnfInstanceId"]
+ }
+ elif indata["lcmOperationType"] == "scale":
+ formatted_indata = {
+ "lcmOperationType": indata["lcmOperationType"],
+ "nsInstanceId": indata["vnfInstanceId"],
+ "scaleType": "SCALE_VNF",
+ "scaleVnfData": {
+ "scaleVnfType": indata["type"],
+ "scaleByStepData": {
+ "scaling-group-descriptor": indata["aspectId"],
+ "member-vnf-index": indata["additionalParams"]["member-vnf-index"]
+ }
+ }
+ }
+ elif indata["lcmOperationType"] == "action":
+ formatted_indata = {
+ "lcmOperationType": indata["lcmOperationType"],
+ "nsInstanceId": indata["vnfInstanceId"],
+ "member_vnf_index": indata["member_vnf_index"],
+ "primitive": indata["primitive"],
+ "primitive_params": indata["primitive_params"]
+ }
+ return formatted_indata
+
+ def action(self, rollback, session, indata=None, kwargs=None, headers=None):
+ """
+ Creates an new lcm operation.
+ :param rollback: list to append the created items at database in case a rollback must be done
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param indata: params to be used for the nsr
+ :param kwargs: used to override the indata
+ :param headers: http request headers
+ :return: id of new lcm operation.
+ """
+ vnfInstanceId = indata["vnfInstanceId"]
+ lcm_operation = indata["lcmOperationType"]
+ vnfr = self.vnfrtopic.show(session, vnfInstanceId)
+ indata["vnfInstanceId"] = vnfr.get("nsr-id-ref")
+ indata = self.__get_formatted_indata(session, indata)
+ op_id, _ = self.nslcmoptopic.new(rollback, session, indata, kwargs, headers)
+ return op_id, _
+
+
+class ListVnfLcmOp(BaseMethod):
+
+ def __init__(self, db, fs, msg, auth):
+ """
+ Constructor call for listing vnf lcm operations
+ """
+ super().__init__()
+ self.nslcmoptopic = NsLcmOpTopic(db, fs, msg, auth)
+ self.nsrtopic = NsrTopic(db, fs, msg, auth)
+
+ def action(self, session, filter_q=None, api_req=False):
+ """
+ To get list of vnf lcm operations that matches a filter
+ :param session: contains the used login username and working project
+ :param filter_q: filter of data to be applied
+ :param api_req: True if this call is serving an external API request. False if serving internal request.
+ :return: The list, it can be empty if no one match the filter.
+ """
+ list = []
+ records = self.nslcmoptopic.list(session, filter_q, api_req)
+ for record in records:
+ ns_id = record.get("nsInstanceId")
+ nsr = self.nsrtopic.show(session, ns_id)
+ vnfInstance_id = nsr['constituent-vnfr-ref'][0]
+ outdata = sol003_projection(record, vnfInstance_id)
+ list.append(outdata)
+ return list
+
+
+class ShowVnfLcmOp(BaseMethod):
+
+ def __init__(self, db, fs, msg, auth):
+ """
+ Constructor call for showing vnf lcm operation
+ """
+ super().__init__()
+ self.nslcmoptopic = NsLcmOpTopic(db, fs, msg, auth)
+ self.nsrtopic = NsrTopic(db, fs, msg, auth)
+
+ def action(self, session, _id, api_req=False):
+ """
+ Get complete information on an Vnf Lcm Operation.
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param _id: Vnf Lcm operation id
+ :param api_req: True if this call is serving an external API request. False if serving internal request.
+ :return: dictionary, raise exception if not found.
+ """
+ record = self.nslcmoptopic.show(session, _id, api_req)
+ ns_id = record.get("nsInstanceId")
+ nsr = self.nsrtopic.show(session, ns_id)
+ vnfinstance_id = nsr['constituent-vnfr-ref'][0]
+ outdata = sol003_projection(record, vnfinstance_id)
+ return outdata
+
+
+def sol003_projection(data, vnfinstance_id):
+ """
+ Returns SOL003 formatted data
+ :param data: contains Lcm Operation information
+ :param vnfinstance_id: id of vnf_instance
+ :return: SOL003 formatted data of vnf lcm op
+ """
+ data.pop("nsInstanceId")
+ data.pop("operationParams")
+ data.pop("links")
+ links = {
+ "self": "/osm/vnflcm/v1/vnf_lcm_op_occs/" + data["_id"],
+ "vnfInstance": "/osm/vnflcm/v1/vnf_instances/" + vnfinstance_id,
+ }
+ data["_links"] = links
+ data["vnfInstanceId"] = vnfinstance_id
+ return data
--- /dev/null
+# Copyright 2021 K Sai Kiran (Tata Elxsi)
+#
+# 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.
+
+__author__ = "K Sai Kiran <saikiran.k@tataelxsi.co.in>, Selvi Jayaraman <selvi.j@tataelxsi.co.in>"
+__date__ = "$12-June-2021 8:30:59$"
+
+from copy import deepcopy
+from osm_nbi.descriptor_topics import NsdTopic
+from .base_methods import BaseMethod
+
+from osm_nbi.instance_topics import NsrTopic, VnfrTopic
+
+
+class VnfInstances2NsInstances:
+
+ def __init__(self, db, fs, msg, auth):
+ """
+ Constructor of Vnf Instances to Ns Instances
+ """
+ self.new_vnf_instance = NewVnfInstance(db, fs, msg, auth)
+ self.list_vnf_instance = ListVnfInstance(db, fs, msg, auth)
+ self.show_vnf_instance = ShowVnfInstance(db, fs, msg, auth)
+ self.delete_vnf_instance = DeleteVnfInstance(db, fs, msg, auth)
+
+ def new(self, rollback, session, indata=None, kwargs=None, headers=None):
+ """
+ Creates a new entry into database.
+ :param rollback: list to append created items at database in case a rollback may have to be done
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param indata: data to be inserted
+ :param kwargs: used to override the indata descriptor
+ :param headers: http request headers
+ :return: _id, op_id:
+ _id: identity of the inserted data.
+ op_id: operation id if this is asynchronous, None otherwise
+ """
+ return self.new_vnf_instance.action(rollback, session, indata, kwargs, headers)
+
+ def list(self, session, filter_q=None, api_req=False):
+ """
+ Get a list of the Vnfs that match a filter
+ :param session: contains the used login username and working project
+ :param filter_q: filter of data to be applied
+ :param api_req: True if this call is serving an external API request. False if serving internal request.
+ :return: The list, it can be empty if no one match the filter.
+ """
+ return self.list_vnf_instance.action(session, filter_q, api_req)
+
+ def show(self, session, _id, api_req=False):
+ """
+ Get complete information on an Vnf
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param _id: server internal id
+ :param api_req: True if this call is serving an external API request. False if serving internal request.
+ :return: dictionary, raise exception if not found.
+ """
+ return self.show_vnf_instance.action(session, _id, api_req)
+
+ def delete(self, session, _id, dry_run=False, not_send_msg=None):
+ """
+ Delete item by its internal _id
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param _id: server internal id
+ :param dry_run: make checking but do not delete
+ :param not_send_msg: To not send message (False) or store content (list) instead
+ :return: operation id (None if there is not operation), raise exception if error or not found, conflict, ...
+ """
+ return self.delete_vnf_instance.action(session, _id, dry_run, not_send_msg)
+
+
+class NewVnfInstance(BaseMethod):
+
+ # sample ns descriptor
+ sample_nsd = {
+ "nsd": {
+ "nsd": [
+ {
+ "df": [
+ {
+ "id": "default-df",
+ "vnf-profile": [
+ {
+ "id": 1,
+ "virtual-link-connectivity": [
+ {
+ "constituent-cpd-id": [
+ {"constituent-base-element-id": 1,
+ "constituent-cpd-id": "eth0-ext"}
+ ],
+ "virtual-link-profile-id": "mgmtnet",
+ }
+ ],
+ "vnfd-id": "cirros_vnfd"
+ }
+ ],
+ }
+ ],
+ "vnfd-id": ["cirros_vnfd"],
+ "description": "Generated by OSM pacakage generator",
+ "id": "cirros_2vnf_nsd",
+ "name": "cirros_2vnf_ns",
+ "short-name": "cirros_2vnf_ns",
+ "vendor": "OSM",
+ "version": "1.0",
+ }
+ ]
+ }
+ }
+
+ @staticmethod
+ def __get_formatted_indata(indata, nsd_id):
+ """
+ Create indata for nsd_id
+ :param indata: Contains unformatted data for new vnf instance
+ :param nsd_id: Id of nsd
+ :return: formatted indata for nsd_id
+ """
+ formatted_indata = deepcopy(indata)
+ formatted_indata["nsdId"] = nsd_id
+ formatted_indata["nsName"] = indata["vnfInstanceName"] + "-ns"
+ for invalid_key in ("vnfdId", "vnfInstanceName", "vnfInstanceDescription", "additionalParams"):
+ formatted_indata.pop(invalid_key)
+ return formatted_indata
+
+ def __init__(self, db, fs, msg, auth):
+ """
+ Constructor for new vnf instance
+ """
+ super().__init__()
+ self.msg = msg
+ self.nsdtopic = NsdTopic(db, fs, msg, auth)
+ self.nsrtopic = NsrTopic(db, fs, msg, auth)
+
+ def __get_vnfd(self):
+ # get vnfd from nfvo
+ pass
+
+ def __onboard_vnfd(self):
+ self.__get_vnfd()
+ pass
+
+ def __create_nsd(self, rollback, session, indata=None, kwargs=None, headers=None):
+ """
+ Creates new ns descriptor from a vnfd.
+ :param rollback: list to append the created items at database in case a rollback must be done
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param indata: params to be used for the nsr
+ :param kwargs: used to override the indata
+ :param headers: http request headers
+ :return: id of new nsd created
+ """
+ _id, *others = self.nsdtopic.new(rollback, session, {}, None, headers)
+ new_nsd = deepcopy(NewVnfInstance.sample_nsd)
+ vnf_content = {
+ "id":"default-df",
+ "vnf-profile": [
+ {
+ "id": "1",
+ "virtual-link-connectivity": [
+ {
+ "constituent-cpd-id": [
+ {
+ "constituent-base-element-id": "1",
+ "constituent-cpd-id": indata["additionalParams"]["constituent-cpd-id"]
+ }
+ ],
+ "virtual-link-profile-id": indata["additionalParams"]["virtual-link-profile-id"]
+ }
+ ],
+ "vnfd-id": indata["vnfdId"]
+ }
+ ]
+ }
+ new_nsd["nsd"]["nsd"][0] = {
+ "description": indata["vnfInstanceDescription"],
+ "designer": "OSM",
+ "id": indata["vnfdId"] + "-ns",
+ "name": indata["vnfdId"] + "-ns",
+ "version": "1.0",
+ "df": [vnf_content, ],
+ "virtual-link-desc": indata["additionalParams"]["virtual-link-desc"],
+ "vnfd-id": [indata["vnfdId"]]
+ }
+ return _id, new_nsd
+
+ def __create_nsr(self, rollback, session, indata=None, kwargs=None, headers=None):
+ """
+ Creates an new ns record in database
+ :param rollback: list to append the created items at database in case a rollback must be done
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param indata: params to be used for the nsr
+ :param kwargs: used to override the indata
+ :param headers: http request headers
+ :return: id of new nsr
+ """
+ return self.nsrtopic.new(rollback, session, indata, kwargs, headers)
+
+ def __action_pre_processing(self, rollback, session, indata=None, kwargs=None, headers=None):
+ """
+ Pre process for creating new vnf instance
+ :param rollback: list to append the created items at database in case a rollback must be done
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param indata: params to be used for the nsr
+ :param kwargs: used to override the indata
+ :param headers: http request headers
+ :return: id nsr
+ """
+ self.__onboard_vnfd()
+ nsd_id, nsd = self.__create_nsd(rollback, session, indata, kwargs, headers)
+ self.nsdtopic.upload_content(session, nsd_id, nsd, kwargs, headers)
+ formatted_indata = NewVnfInstance.__get_formatted_indata(indata, nsd_id)
+ nsr_id, _ = self.__create_nsr(rollback, session, formatted_indata, kwargs, headers)
+ nsr = self.nsrtopic.show(session, nsr_id)
+ vnfr_id = nsr['constituent-vnfr-ref'][0]
+ return vnfr_id, None
+
+ def action(self, rollback, session, indata=None, kwargs=None, headers=None):
+ """
+ Creates an new vnf instance
+ :param rollback: list to append the created items at database in case a rollback must be done
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param indata: params to be used for the nsr
+ :param kwargs: used to override the indata
+ :param headers: http request headers
+ :return: id of new vnf instance
+ """
+ return self.__action_pre_processing(rollback, session, indata, kwargs, headers)
+
+
+class ListVnfInstance(BaseMethod):
+
+ def __init__(self, db, fs, msg, auth):
+ """
+ Constructor call for listing vnfs
+ """
+ super().__init__()
+ self.vnfrtopic = VnfrTopic(db, fs, msg, auth)
+
+ def action(self, session, filter_q=None, api_req=False):
+ """
+ To get list of vnfs that matches a filter
+ :param session: contains the used login username and working project
+ :param filter_q: filter of data to be applied
+ :param api_req: True if this call is serving an external API request. False if serving internal request.
+ :return: The list, it can be empty if no one match the filter.
+ """
+ return self.vnfrtopic.list(session, filter_q, api_req)
+
+
+class ShowVnfInstance(BaseMethod):
+
+ def __init__(self, db, fs, msg, auth):
+ """
+ Constructor call for showing vnf lcm operation
+ """
+ super().__init__()
+ self.vnfrtopic = VnfrTopic(db, fs, msg, auth)
+
+ def action(self, session, _id, api_req=False):
+ """
+ Get complete information on an Vnf Lcm Operation.
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param _id: Vnf Lcm operation id
+ :param api_req: True if this call is serving an external API request. False if serving internal request.
+ :return: dictionary, raise exception if not found.
+ """
+ return self.vnfrtopic.show(session, _id, api_req)
+
+
+class DeleteVnfInstance(BaseMethod):
+
+ def __init__(self, db, fs, msg, auth):
+ """
+ Constructor call for deleting vnf
+ """
+ super().__init__()
+ self.msg = msg
+ self.nsrtopic = NsrTopic(db, fs, msg, auth)
+ self.nsdtopic = NsdTopic(db, fs, msg, auth)
+ self.vnfrtopic = VnfrTopic(db, fs, msg, auth)
+
+ def action(self, session, _id, dry_run=False, not_send_msg=None):
+ """
+ Delete vnf instance by its internal _id
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param _id: server internal id
+ :param dry_run: make checking but do not delete
+ :param not_send_msg: To not send message (False) or store content (list) instead
+ :return: operation id (None if there is not operation), raise exception if error or not found, conflict, ...
+ """
+ vnfInstanceId = _id
+ vnfr = self.vnfrtopic.show(session, vnfInstanceId)
+ ns_id = vnfr.get("nsr-id-ref")
+ nsr = self.nsrtopic.show(session, ns_id)
+ nsd_to_del = nsr['nsd']['_id']
+ self.nsrtopic.delete(session, ns_id, dry_run, not_send_msg)
+ return self.nsdtopic.delete(session, nsd_to_del, dry_run, not_send_msg)
"GET /nslcm/v1/vnfrs/<vnfInstanceId>": "vnf_instances:id:get"
"GET /nslcm/v1/vnf_instances/<vnfInstanceId>": "vnf_instances:id:get"
+ "GET /vnflcm/v1/vnf_instances/": "vnflcm_instances:get"
+ "POST /vnflcm/v1/vnf_instances/": "vnflcm_instances:post"
+
+ "GET /vnflcm/v1/vnf_instances/<vnfInstanceId>": "vnflcm_instances:id:get"
+ "DELETE /vnflcm/v1/vnf_instances/<vnfInstanceId>": "vnflcm_instances:id:delete"
+
################################################################################
#################################### Tokens ####################################
################################################################################
vnfd-id: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77
vnfd-ref: hackfest3charmed-vnf
"""
+
+db_vnfm_vnfd_text = """
+---
+- _admin:
+ created: 1647529096.3635302
+ modified: 1650456936.518325
+ onboardingState: ONBOARDED
+ operationalState: ENABLED
+ projects_read:
+ - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4
+ projects_write:
+ - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4
+ storage:
+ descriptor: hackfest_basic_metrics_vnf/hackfest_basic_metrics_vnfd.yaml
+ folder: 70b47595-fafa-4f63-904b-fc3ada60eebb
+ fs: mongo
+ path: /app/storage/
+ pkg-dir: hackfest_basic_metrics_vnf
+ zipfile: package.tar.gz
+ type: vnfd
+ usageState: NOT_IN_USE
+ userDefinedData: {}
+ _id: 70b47595-fafa-4f63-904b-fc3ada60eebb
+ _links:
+ packageContent:
+ href: /vnfpkgm/v1/vnf_packages/70b47595-fafa-4f63-904b-fc3ada60eebb/package_content
+ self:
+ href: /vnfpkgm/v1/vnf_packages/70b47595-fafa-4f63-904b-fc3ada60eebb
+ vnfd:
+ href: /vnfpkgm/v1/vnf_packages/70b47595-fafa-4f63-904b-fc3ada60eebb/vnfd
+ description: A basic VNF descriptor with one VDU and VIM metrics
+ df:
+ - id: default-df
+ instantiation-level:
+ - id: default-instantiation-level
+ vdu-level:
+ - number-of-instances: 1
+ vdu-id: hackfest_basic_metrics-VM
+ scaling-aspect:
+ - aspect-delta-details:
+ deltas:
+ - id: vdu_autoscale-delta
+ vdu-delta:
+ - id: hackfest_basic_metrics-VM
+ number-of-instances: 1
+ id: vdu_autoscale
+ max-scale-level: 1
+ name: vdu_autoscale
+ scaling-policy:
+ - cooldown-time: 120
+ name: cpu_util_above_threshold
+ scaling-criteria:
+ - name: cpu_util_above_threshold
+ scale-in-relational-operation: LT
+ scale-in-threshold: '10.0000000000'
+ scale-out-relational-operation: GT
+ scale-out-threshold: '60.0000000000'
+ vnf-monitoring-param-ref: vnf_cpu_util
+ scaling-type: automatic
+ threshold-time: 10
+ vdu-profile:
+ - id: hackfest_basic_metrics-VM
+ max-number-of-instances: 2
+ min-number-of-instances: 1
+ ext-cpd:
+ - id: vnf-cp0-ext
+ int-cpd:
+ cpd: vdu-eth0-int
+ vdu-id: hackfest_basic_metrics-VM
+ id: hackfest_basic_metrics-vnf
+ mgmt-cp: vnf-cp0-ext
+ onboardingState: ONBOARDED
+ operationalState: ENABLED
+ product-name: hackfest_basic_metrics-vnf
+ sw-image-desc:
+ - id: bionic
+ image: bionic
+ name: bionic
+ - id: ubuntu18.04-aws
+ image: ubuntu/images/hvm-ssd/ubuntu-artful-17.10-amd64-server-20180509
+ name: ubuntu18.04-aws
+ vim-type: aws
+ - id: ubuntu18.04-azure
+ image: Canonical:UbuntuServer:18.04-LTS:latest
+ name: ubuntu18.04-azure
+ vim-type: azure
+ - id: ubuntu18.04-gcp
+ image: ubuntu-os-cloud:image-family:ubuntu-1804-lts
+ name: ubuntu18.04-gcp
+ vim-type: gcp
+ usageState: NOT_IN_USE
+ vdu:
+ - alarm:
+ - actions:
+ alarm:
+ - url: https://webhook.site/b79f9bf9-4c19-429d-81ed-19be26a3d5d8
+ insufficient-data:
+ - url: https://webhook.site/b79f9bf9-4c19-429d-81ed-19be26a3d5d8
+ ok:
+ - url: https://webhook.site/b79f9bf9-4c19-429d-81ed-19be26a3d5d8
+ alarm-id: alarm-1
+ operation: LT
+ value: '20.0000'
+ vnf-monitoring-param-ref: vnf_cpu_util
+ alternative-sw-image-desc:
+ - ubuntu18.04-aws
+ - ubuntu18.04-azure
+ - ubuntu18.04-gcp
+ cloud-init-file: cloud-config
+ id: hackfest_basic_metrics-VM
+ int-cpd:
+ - id: vdu-eth0-int
+ virtual-network-interface-requirement:
+ - name: vdu-eth0
+ virtual-interface:
+ type: PARAVIRT
+ monitoring-parameter:
+ - id: vnf_cpu_util
+ name: vnf_cpu_util
+ performance-metric: cpu_utilization
+ - id: vnf_memory_util
+ name: vnf_memory_util
+ performance-metric: average_memory_utilization
+ - id: vnf_packets_sent
+ name: vnf_packets_sent
+ performance-metric: packets_sent
+ - id: vnf_packets_received
+ name: vnf_packets_received
+ performance-metric: packets_received
+ name: hackfest_basic_metrics-VM
+ sw-image-desc: bionic
+ virtual-compute-desc: hackfest_basic_metrics-VM-compute
+ virtual-storage-desc:
+ - hackfest_basic_metrics-VM-storage
+ version: '1.0'
+ virtual-compute-desc:
+ - id: hackfest_basic_metrics-VM-compute
+ virtual-cpu:
+ num-virtual-cpu: 1
+ virtual-memory:
+ size: 1.0
+ virtual-storage-desc:
+ - id: hackfest_basic_metrics-VM-storage
+ size-of-storage: '10'
+"""
--- /dev/null
+# Copyright 2021 Selvi Jayaraman (Tata Elxsi)
+#
+# 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.
+
+__author__ = "Selvi Jayaraman <selvi.j@tataelxsi.co.in>"
+
+import unittest
+from uuid import uuid4
+from unittest.mock import Mock, patch, mock_open
+from osm_common.dbmemory import DbMemory
+from osm_common.fsbase import FsBase
+from osm_common.msgbase import MsgBase
+from osm_nbi.vnf_instance_topics import VnfInstances, VnfLcmOpTopic
+from osm_nbi.instance_topics import NsrTopic
+from osm_nbi.tests.test_db_descriptors import (
+ db_vim_accounts_text,
+ db_vnfm_vnfd_text,
+ db_nsds_text,
+ db_nsrs_text,
+ db_vnfrs_text,
+ db_nslcmops_text
+)
+import yaml
+
+
+class TestVnfInstances(unittest.TestCase):
+ def setUp(self):
+ self.db = DbMemory()
+ self.fs = Mock(FsBase())
+ self.msg = Mock(MsgBase())
+ self.vnfinstances = VnfInstances(self.db, self.fs, self.msg, None)
+ self.nsrtopic = NsrTopic(self.db, self.fs, self.msg, None)
+ self.db.create_list(
+ "vim_accounts", yaml.load(db_vim_accounts_text, Loader=yaml.Loader)
+ )
+ self.db.create_list("vnfds", yaml.load(db_vnfm_vnfd_text, Loader=yaml.Loader))
+ self.vnfd = self.db.get_list("vnfds")[0]
+ self.vnfd_id = self.vnfd["id"]
+ self.vnfd_project = self.vnfd["_admin"]["projects_read"][0]
+
+ self.vim = self.db.get_list("vim_accounts")[0]
+ self.vim_id = self.vim["_id"]
+
+ @patch("osm_nbi.descriptor_topics.shutil")
+ @patch("osm_nbi.descriptor_topics.os.rename")
+ def test_create_identifier(self, mock_rename, mock_shutil):
+ session = {
+ "force": True,
+ "admin": False,
+ "public": False,
+ "project_id": [self.vnfd_project],
+ "method": "write",
+ }
+ indata = {
+ "vnfdId": self.vnfd_id,
+ "vnfInstanceName": "vnf_instance_name",
+ "vnfInstanceDescription": "vnf instance description",
+ "vimAccountId": self.vim_id,
+ "additionalParams": {
+ "virtual-link-desc": [
+ {
+ "id": "mgmt-net",
+ "mgmt-network": True
+ }
+ ],
+ "constituent-cpd-id": "vnf-cp0-ext",
+ "virtual-link-profile-id": "mgmt-net"
+ }
+ }
+ rollback = []
+ headers = {}
+ self.fs.path = ""
+ self.fs.get_params.return_value = {}
+ self.fs.file_exists.return_value = False
+ self.fs.file_open.side_effect = lambda path, mode: open(
+ "/tmp/" + str(uuid4()), "a+b"
+ )
+
+ vnfr_id, _ = self.vnfinstances.new(
+ rollback, session, indata, {}, headers={"Content-Type": []}
+ )
+ vnfr = self.db.get_one("vnfrs")
+ self.assertEqual(
+ vnfr_id,
+ vnfr["id"],
+ "Mismatch between return id and database id"
+ )
+ self.assertEqual(
+ "NOT_INSTANTIATED",
+ vnfr["_admin"]["nsState"],
+ "Database record must contain 'nsState' NOT_INSTANTIATED"
+ )
+ self.assertEqual(
+ self.vnfd_id,
+ vnfr["vnfd-ref"],
+ "vnfr record is not properly created for the given vnfd")
+
+ def test_show_vnfinstance(self):
+ session = {
+ "force": False,
+ "admin": False,
+ "public": False,
+ "project_id": [self.vnfd_project],
+ "method": "write",
+ }
+ filter_q = {}
+ self.db.create_list("vnfrs", yaml.load(db_vnfrs_text, Loader=yaml.Loader))
+ actual_vnfr = self.db.get_list("vnfrs")[0]
+ id = actual_vnfr["_id"]
+ expected_vnfr = self.vnfinstances.show(session, id, filter_q)
+ self.assertEqual(
+ actual_vnfr["_id"],
+ expected_vnfr["_id"],
+ "Mismatch between return vnfr Id and database vnfr Id"
+ )
+
+ def test_delete_vnfinstance(self):
+ session = {
+ "force": False,
+ "admin": False,
+ "public": False,
+ "project_id": [self.vnfd_project],
+ "method": "delete",
+ }
+ self.db.create_list("vnfrs", yaml.load(db_vnfrs_text, Loader=yaml.Loader))
+ self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
+ self.db.create_list("nsds", yaml.load(db_nsds_text, Loader=yaml.Loader))
+
+ self.vnfr = self.db.get_list("vnfrs")[0]
+ self.vnfr_id = self.vnfr["_id"]
+ self.db.set_one = self.db.set_one
+ self.db.set_one = Mock()
+
+ self.vnfinstances.delete(session, self.vnfr_id)
+ msg_args = self.msg.write.call_args[0]
+ self.assertEqual(msg_args[1], "deleted", "Wrong message action")
+
+
+class TestVnfLcmOpTopic(unittest.TestCase):
+ def setUp(self):
+ self.db = DbMemory()
+ self.fs = Mock(FsBase())
+ self.fs.get_params.return_value = {"./fake/folder"}
+ self.fs.file_open = mock_open()
+ self.msg = Mock(MsgBase())
+
+ self.vnflcmop_topic = VnfLcmOpTopic(self.db, self.fs, self.msg, None)
+ self.vnflcmop_topic.check_quota = Mock(return_value=None) # skip quota
+
+ self.db.create_list(
+ "vim_accounts", yaml.load(db_vim_accounts_text, Loader=yaml.Loader)
+ )
+ self.db.create_list("nsds", yaml.load(db_nsds_text, Loader=yaml.Loader))
+ self.db.create_list("vnfds", yaml.load(db_vnfm_vnfd_text, Loader=yaml.Loader))
+ self.db.create_list("vnfrs", yaml.load(db_vnfrs_text, Loader=yaml.Loader))
+ self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
+
+ self.vnfd = self.db.get_list("vnfds")[0]
+ self.vnfd_id = self.vnfd["_id"]
+ self.vnfr = self.db.get_list("vnfrs")[0]
+ self.vnfr_id = self.vnfr["_id"]
+
+ self.vnfd_project = self.vnfd["_admin"]["projects_read"][0]
+
+ self.vim = self.db.get_list("vim_accounts")[0]
+ self.vim_id = self.vim["_id"]
+
+ def test_create_vnf_instantiate(self):
+ session = {
+ "force": False,
+ "admin": False,
+ "public": False,
+ "project_id": [self.vnfd_project],
+ "method": "write",
+ }
+ indata = {
+ "vnfInstanceId": self.vnfr_id,
+ "lcmOperationType": "instantiate",
+ "vnfName": "vnf_instance_name",
+ "vnfDescription": "vnf instance description",
+ "vnfId": self.vnfd_id,
+ "vimAccountId": self.vim_id
+ }
+ rollback = []
+ headers = {}
+ vnflcmop_id, _ = self.vnflcmop_topic.new(
+ rollback, session, indata, kwargs=None, headers=headers
+ )
+ vnflcmop_info = self.db.get_one("nslcmops")
+ self.assertEqual(
+ vnflcmop_id,
+ vnflcmop_info["_id"],
+ "Mismatch between return id and database '_id'",
+ )
+ self.assertTrue(
+ vnflcmop_info["lcmOperationType"] == "instantiate",
+ "Database record must contain 'lcmOperationType=instantiate'",
+ )
+
+ def test_show_vnflmcop(self):
+ session = {
+ "force": False,
+ "admin": False,
+ "public": False,
+ "project_id": [self.vnfd_project],
+ "method": "write",
+ }
+ self.db.create_list("nslcmops", yaml.load(db_nslcmops_text, Loader=yaml.Loader))
+ filter_q = {}
+ actual_lcmop = self.db.get_list("nslcmops")[0]
+ id = actual_lcmop["_id"]
+ vnfr = self.db.get_list("vnfrs")[0]
+ vnfr_id = vnfr["_id"]
+ vnflcmop = self.vnflcmop_topic.show(session, id, filter_q)
+ _id = vnflcmop["vnfInstanceId"]
+ self.assertEqual(_id, vnfr_id, "Mismatch between vnflcmop's vnfInstanceId and database vnfr's id")
--- /dev/null
+# Copyright 2021 K Sai Kiran (Tata Elxsi)
+#
+# 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.
+
+__author__ = "K Sai Kiran <saikiran.k@tataelxsi.co.in>, Selvi Jayaraman <selvi.j@tataelxsi.co.in>"
+__date__ = "$12-June-2021 8:30:59$"
+
+from osm_nbi.base_topic import BaseTopic
+from .osm_vnfm.vnf_instances import VnfInstances2NsInstances
+from .osm_vnfm.vnf_instance_actions import VnfLcmOp2NsLcmOp
+
+
+class VnfInstances(BaseTopic):
+
+ def __init__(self, db, fs, msg, auth):
+ """
+ Constructor call for vnf instance topic
+ """
+ BaseTopic.__init__(self, db, fs, msg, auth)
+ self.vnfinstances2nsinstances = VnfInstances2NsInstances(db, fs, msg, auth)
+
+ def new(self, rollback, session, indata=None, kwargs=None, headers=None):
+ """
+ Creates new vnf instance
+ :param rollback: list to append the created items at database in case a rollback must be done
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param indata: params to be used for the vnf instance
+ :param kwargs: used to override the indata descriptor
+ :param headers: http request headers
+ :return: the _id of vnf instance created at database. Or an exception.
+ """
+ return self.vnfinstances2nsinstances.new(rollback, session, indata, kwargs, headers)
+
+ def list(self, session, filter_q=None, api_req=False):
+ """
+ Get a list of the vnf instances that match a filter
+ :param session: contains the used login username and working project
+ :param filter_q: filter of data to be applied
+ :param api_req: True if this call is serving an external API request. False if serving internal request.
+ :return: The list, it can be empty if no one match the filter.
+ """
+ return self.vnfinstances2nsinstances.list(session, filter_q, api_req)
+
+ def show(self, session, _id, filter_q=None, api_req=False):
+ """
+ Get complete information on an vnf instance
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param _id: server internal id
+ :param api_req: True if this call is serving an external API request. False if serving internal request.
+ :return: dictionary, raise exception if not found.
+ """
+ return self.vnfinstances2nsinstances.show(session, _id, api_req)
+
+ def delete(self, session, _id, dry_run=False, not_send_msg=None):
+ """
+ Delete vnf instance by its internal _id
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param _id: server internal id
+ :param dry_run: make checking but do not delete
+ :param not_send_msg: To not send message (False) or store content (list) instead
+ :return: operation id (None if there is not operation), raise exception if error or not found, conflict, ...
+ """
+ return self.vnfinstances2nsinstances.delete(session, _id, dry_run, not_send_msg)
+
+
+class VnfLcmOpTopic(BaseTopic):
+
+ def __init__(self, db, fs, msg, auth):
+ """
+ Constructor call for vnf lcm op topic
+ """
+ BaseTopic.__init__(self, db, fs, msg, auth)
+ self.vnflcmop2nslcmop = VnfLcmOp2NsLcmOp(db, fs, msg, auth)
+
+ def new(self, rollback, session, indata=None, kwargs=None, headers=None):
+ """
+ Creates new vnf lcm op
+ :param rollback: list to append the created items at database in case a rollback must be done
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param indata: params to be used for the vnf instance
+ :param kwargs: used to override the indata descriptor
+ :param headers: http request headers
+ :return: the _id of vnf lcm op created at database. Or an exception.
+ """
+ return self.vnflcmop2nslcmop.new(rollback, session, indata, kwargs, headers)
+
+ def list(self, session, filter_q=None, api_req=False):
+ """
+ Get a list of the vnf lcm op that match a filter
+ :param session: contains the used login username and working project
+ :param filter_q: filter of data to be applied
+ :param api_req: True if this call is serving an external API request. False if serving internal request.
+ :return: The list, it can be empty if no one match the filter.
+ """
+ return self.vnflcmop2nslcmop.list(session, filter_q, api_req)
+
+ def show(self, session, _id, filter_q=None, api_req=False):
+ """
+ Get complete information on an vnf lcm op
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param _id: server internal id
+ :param api_req: True if this call is serving an external API request. False if serving internal request.
+ :return: dictionary, raise exception if not found.
+ """
+ return self.vnflcmop2nslcmop.show(session, _id, api_req)