final_content["_admin"]["salt"] = salt
final_content["password"] = sha256(edit_content["password"].encode('utf-8') +
salt.encode('utf-8')).hexdigest()
+ return None
def edit(self, session, _id, indata=None, kwargs=None, content=None):
if not session["admin"]:
return BaseTopic.new(self, rollback, session, indata=indata, kwargs=kwargs, headers=headers)
-class VimAccountTopic(BaseTopic):
- topic = "vim_accounts"
- topic_msg = "vim_account"
- schema_new = vim_account_new_schema
- schema_edit = vim_account_edit_schema
- vim_config_encrypted = ("admin_password", "nsx_password", "vcenter_password")
- multiproject = True
+class CommonVimWimSdn(BaseTopic):
+ """Common class for VIM, WIM SDN just to unify methods that are equal to all of them"""
+ config_to_encrypt = () # what keys at config must be encrypted because contains passwords
+ password_to_encrypt = "" # key that contains a password
- def __init__(self, db, fs, msg):
- BaseTopic.__init__(self, db, fs, msg)
+ @staticmethod
+ def _create_operation(op_type, params=None):
+ """
+ Creates a dictionary with the information to an operation, similar to ns-lcm-op
+ :param op_type: can be create, edit, delete
+ :param params: operation input parameters
+ :return: new dictionary with
+ """
+ now = time()
+ return {
+ "lcmOperationType": op_type,
+ "operationState": "PROCESSING",
+ "startTime": now,
+ "statusEnteredTime": now,
+ "detailed-status": "",
+ "operationParams": params,
+ }
def check_conflict_on_new(self, session, indata):
+ """
+ Check that the data to be inserted is valid. It is checked that name is unique
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param indata: data to be inserted
+ :return: None or raises EngineException
+ """
self.check_unique_name(session, indata["name"], _id=None)
def check_conflict_on_edit(self, session, final_content, edit_content, _id):
+ """
+ Check that the data to be edited/uploaded is valid. It is checked that name is unique
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param final_content: data once modified. This method may change it.
+ :param edit_content: incremental data that contains the modifications to apply
+ :param _id: internal _id
+ :return: None or raises EngineException
+ """
if not session["force"] and edit_content.get("name"):
self.check_unique_name(session, edit_content["name"], _id=_id)
+ def format_on_edit(self, final_content, edit_content):
+ """
+ Modifies final_content inserting admin information upon edition
+ :param final_content: final content to be stored at database
+ :param edit_content: user requested update content
+ :return: operation id
+ """
+
# encrypt passwords
schema_version = final_content.get("schema_version")
if schema_version:
- if edit_content.get("vim_password"):
- final_content["vim_password"] = self.db.encrypt(edit_content["vim_password"],
- schema_version=schema_version, salt=_id)
- if edit_content.get("config"):
- for p in self.vim_config_encrypted:
+ if edit_content.get(self.password_to_encrypt):
+ final_content[self.password_to_encrypt] = self.db.encrypt(edit_content[self.password_to_encrypt],
+ schema_version=schema_version,
+ salt=final_content["_id"])
+ if edit_content.get("config") and self.config_to_encrypt:
+ for p in self.config_to_encrypt:
if edit_content["config"].get(p):
final_content["config"][p] = self.db.encrypt(edit_content["config"][p],
- schema_version=schema_version, salt=_id)
+ schema_version=schema_version,
+ salt=final_content["_id"])
+
+ # create edit operation
+ final_content["_admin"]["operations"].append(self._create_operation("edit"))
+ return "{}:{}".format(final_content["_id"], len(final_content["_admin"]["operations"]) - 1)
def format_on_new(self, content, project_id=None, make_public=False):
- BaseTopic.format_on_new(content, project_id=project_id, make_public=make_public)
+ """
+ Modifies content descriptor to include _admin and insert create operation
+ :param content: descriptor to be modified
+ :param project_id: if included, it add project read/write permissions. Can be None or a list
+ :param make_public: if included it is generated as public for reading.
+ :return: op_id: operation id on asynchronous operation, None otherwise. In addition content is modified
+ """
+ super().format_on_new(content, project_id=project_id, make_public=make_public)
content["schema_version"] = schema_version = "1.1"
# encrypt passwords
- if content.get("vim_password"):
- content["vim_password"] = self.db.encrypt(content["vim_password"], schema_version=schema_version,
- salt=content["_id"])
- if content.get("config"):
- for p in self.vim_config_encrypted:
+ if content.get(self.password_to_encrypt):
+ content[self.password_to_encrypt] = self.db.encrypt(content[self.password_to_encrypt],
+ schema_version=schema_version,
+ salt=content["_id"])
+ if content.get("config") and self.config_to_encrypt:
+ for p in self.config_to_encrypt:
if content["config"].get(p):
- content["config"][p] = self.db.encrypt(content["config"][p], schema_version=schema_version,
+ content["config"][p] = self.db.encrypt(content["config"][p],
+ schema_version=schema_version,
salt=content["_id"])
content["_admin"]["operationalState"] = "PROCESSING"
+ # create operation
+ content["_admin"]["operations"] = [self._create_operation("create")]
+ content["_admin"]["current_operation"] = None
+
+ return "{}:0".format(content["_id"])
+
def delete(self, session, _id, dry_run=False):
"""
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
- :return: dictionary with deleted item _id. It raises EngineException on error: not found, conflict, ...
+ :return: operation id if it is ordered to delete. None otherwise
"""
- # TODO add admin to filter, validate rights
- if dry_run or session["force"]: # delete completely
- return BaseTopic.delete(self, session, _id, dry_run)
- else: # if not, sent to kafka
- v = BaseTopic.delete(self, session, _id, dry_run=True)
- self.db.set_one("vim_accounts", {"_id": _id}, {"_admin.to_delete": True}) # TODO change status
- self._send_msg("delete", {"_id": _id})
- return v # TODO indicate an offline operation to return 202 ACCEPTED
-
-class WimAccountTopic(BaseTopic):
- topic = "wim_accounts"
- topic_msg = "wim_account"
- schema_new = wim_account_new_schema
- schema_edit = wim_account_edit_schema
- multiproject = True
- wim_config_encrypted = ()
+ filter_q = self._get_project_filter(session)
+ filter_q["_id"] = _id
+ db_content = self.db.get_one(self.topic, filter_q)
- def __init__(self, db, fs, msg):
- BaseTopic.__init__(self, db, fs, msg)
+ self.check_conflict_on_del(session, _id, db_content)
+ if dry_run:
+ return None
- def check_conflict_on_new(self, session, indata):
- self.check_unique_name(session, indata["name"], _id=None)
+ # remove reference from project_read. If not last delete
+ if session["project_id"]:
+ for project_id in session["project_id"]:
+ if project_id in db_content["_admin"]["projects_read"]:
+ db_content["_admin"]["projects_read"].remove(project_id)
+ if project_id in db_content["_admin"]["projects_write"]:
+ db_content["_admin"]["projects_write"].remove(project_id)
+ else:
+ db_content["_admin"]["projects_read"].clear()
+ db_content["_admin"]["projects_write"].clear()
- def check_conflict_on_edit(self, session, final_content, edit_content, _id):
- if not session["force"] and edit_content.get("name"):
- self.check_unique_name(session, edit_content["name"], _id=_id)
+ update_dict = {"_admin.projects_read": db_content["_admin"]["projects_read"],
+ "_admin.projects_write": db_content["_admin"]["projects_write"]
+ }
- # encrypt passwords
- schema_version = final_content.get("schema_version")
- if schema_version:
- if edit_content.get("wim_password"):
- final_content["wim_password"] = self.db.encrypt(edit_content["wim_password"],
- schema_version=schema_version, salt=_id)
- if edit_content.get("config"):
- for p in self.wim_config_encrypted:
- if edit_content["config"].get(p):
- final_content["config"][p] = self.db.encrypt(edit_content["config"][p],
- schema_version=schema_version, salt=_id)
-
- def format_on_new(self, content, project_id=None, make_public=False):
- BaseTopic.format_on_new(content, project_id=project_id, make_public=make_public)
- content["schema_version"] = schema_version = "1.1"
+ # check if there are projects referencing it (apart from ANY that means public)....
+ if db_content["_admin"]["projects_read"] and (len(db_content["_admin"]["projects_read"]) > 1 or
+ db_content["_admin"]["projects_read"][0] != "ANY"):
+ self.db.set_one(self.topic, filter_q, update_dict=update_dict) # remove references but not delete
+ return None
- # encrypt passwords
- if content.get("wim_password"):
- content["wim_password"] = self.db.encrypt(content["wim_password"], schema_version=schema_version,
- salt=content["_id"])
- if content.get("config"):
- for p in self.wim_config_encrypted:
- if content["config"].get(p):
- content["config"][p] = self.db.encrypt(content["config"][p], schema_version=schema_version,
- salt=content["_id"])
+ # It must be deleted
+ if session["force"]:
+ self.db.del_one(self.topic, {"_id": _id})
+ op_id = None
+ self._send_msg("deleted", {"_id": _id, "op_id": op_id})
+ else:
+ update_dict["_admin.to_delete"] = True
+ self.db.set_one(self.topic, {"_id": _id},
+ update_dict=update_dict,
+ push={"_admin.operations": self._create_operation("delete")}
+ )
+ # the number of operations is the operation_id. db_content does not contains the new operation inserted,
+ # so the -1 is not needed
+ op_id = "{}:{}".format(db_content["_id"], len(db_content["_admin"]["operations"]))
+ self._send_msg("delete", {"_id": _id, "op_id": op_id})
+ return op_id
+
+
+class VimAccountTopic(CommonVimWimSdn):
+ topic = "vim_accounts"
+ topic_msg = "vim_account"
+ schema_new = vim_account_new_schema
+ schema_edit = vim_account_edit_schema
+ multiproject = True
+ password_to_encrypt = "vim_password"
+ config_to_encrypt = ("admin_password", "nsx_password", "vcenter_password")
- content["_admin"]["operationalState"] = "PROCESSING"
- def delete(self, session, _id, dry_run=False):
- """
- 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
- :return: dictionary with deleted item _id. It raises EngineException on error: not found, conflict, ...
- """
- # TODO add admin to filter, validate rights
- if dry_run or session["force"]: # delete completely
- return BaseTopic.delete(self, session, _id, dry_run)
- else: # if not, sent to kafka
- v = BaseTopic.delete(self, session, _id, dry_run=True)
- self.db.set_one("wim_accounts", {"_id": _id}, {"_admin.to_delete": True}) # TODO change status
- self._send_msg("delete", {"_id": _id})
- return v # TODO indicate an offline operation to return 202 ACCEPTED
+class WimAccountTopic(CommonVimWimSdn):
+ topic = "wim_accounts"
+ topic_msg = "wim_account"
+ schema_new = wim_account_new_schema
+ schema_edit = wim_account_edit_schema
+ multiproject = True
+ password_to_encrypt = "wim_password"
+ config_to_encrypt = ()
-class SdnTopic(BaseTopic):
+class SdnTopic(CommonVimWimSdn):
topic = "sdns"
topic_msg = "sdn"
schema_new = sdn_new_schema
schema_edit = sdn_edit_schema
multiproject = True
-
- def __init__(self, db, fs, msg):
- BaseTopic.__init__(self, db, fs, msg)
-
- def check_conflict_on_new(self, session, indata):
- self.check_unique_name(session, indata["name"], _id=None)
-
- def check_conflict_on_edit(self, session, final_content, edit_content, _id):
- if not session["force"] and edit_content.get("name"):
- self.check_unique_name(session, edit_content["name"], _id=_id)
-
- # encrypt passwords
- schema_version = final_content.get("schema_version")
- if schema_version and edit_content.get("password"):
- final_content["password"] = self.db.encrypt(edit_content["password"], schema_version=schema_version,
- salt=_id)
-
- def format_on_new(self, content, project_id=None, make_public=False):
- BaseTopic.format_on_new(content, project_id=project_id, make_public=make_public)
- content["schema_version"] = schema_version = "1.1"
- # encrypt passwords
- if content.get("password"):
- content["password"] = self.db.encrypt(content["password"], schema_version=schema_version,
- salt=content["_id"])
-
- content["_admin"]["operationalState"] = "PROCESSING"
-
- def delete(self, session, _id, dry_run=False):
- """
- 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
- :return: dictionary with deleted item _id. It raises EngineException on error: not found, conflict, ...
- """
- if dry_run or session["force"]: # delete completely
- return BaseTopic.delete(self, session, _id, dry_run)
- else: # if not sent to kafka
- v = BaseTopic.delete(self, session, _id, dry_run=True)
- self.db.set_one("sdns", {"_id": _id}, {"_admin.to_delete": True}) # TODO change status
- self._send_msg("delete", {"_id": _id})
- return v # TODO indicate an offline operation to return 202 ACCEPTED
+ password_to_encrypt = "password"
+ config_to_encrypt = ()
class UserTopicAuth(UserTopic):
final_content["permissions"]["default"] = False
if "admin" not in final_content["permissions"]:
final_content["permissions"]["admin"] = False
+ return None
# @staticmethod
# def format_on_show(content):
"""
Check that the data to be edited/uploaded is valid
:param session: contains "username", "admin", "force", "public", "project_id", "set_project"
- :param final_content: data once modified. This methdo may change it.
+ :param final_content: data once modified. This method may change it.
:param edit_content: incremental data that contains the modifications to apply
:param _id: internal _id
:return: None or raises EngineException
:param content: descriptor to be modified
:param project_id: if included, it add project read/write permissions. Can be None or a list
:param make_public: if included it is generated as public for reading.
- :return: None, but content is modified
+ :return: op_id: operation id on asynchronous operation, None otherwise. In addition content is modified
"""
now = time()
if "_admin" not in content:
content["_admin"]["projects_read"].append("ANY")
if not content["_admin"].get("projects_write"):
content["_admin"]["projects_write"] = list(project_id)
+ return None
@staticmethod
def format_on_edit(final_content, edit_content):
+ """
+ Modifies final_content to admin information upon edition
+ :param final_content: final content to be stored at database
+ :param edit_content: user requested update content
+ :return: operation id, if this edit implies an asynchronous operation; None otherwise
+ """
if final_content.get("_admin"):
now = time()
final_content["_admin"]["modified"] = now
+ return None
def _send_msg(self, action, content):
if self.topic_msg:
:param indata: data to be inserted
:param kwargs: used to override the indata descriptor
:param headers: http request headers
- :return: _id: identity of the inserted data.
+ :return: _id, op_id:
+ _id: identity of the inserted data.
+ op_id: operation id if this is asynchronous, None otherwise
"""
try:
content = self._remove_envelop(indata)
self._update_input_with_kwargs(content, kwargs)
content = self._validate_input_new(content, force=session["force"])
self.check_conflict_on_new(session, content)
- self.format_on_new(content, project_id=session["project_id"], make_public=session["public"])
+ op_id = self.format_on_new(content, project_id=session["project_id"], make_public=session["public"])
_id = self.db.create(self.topic, content)
rollback.append({"topic": self.topic, "_id": _id})
+ if op_id:
+ content["op_id"] = op_id
self._send_msg("create", content)
- return _id
+ return _id, op_id
except ValidationError as e:
raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
: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
- :return: dictionary with deleted item _id. It raises EngineException on error: not found, conflict, ...
+ :return: operation id (None if there is not operation), raise exception if error or not found, conflict, ...
"""
# To allow addressing projects and users by name AS WELL AS by _id
filter_q.update(self._get_project_filter(session))
if self.multiproject and session["project_id"]:
# remove reference from project_read. If not last delete
+ # if this topic is not part of session["project_id"] no midification at database is done and an exception
+ # is raised
self.db.set_one(self.topic, filter_q, update_dict=None,
pull={"_admin.projects_read": {"$in": session["project_id"]}})
# try to delete if there is not any more reference from projects. Ignore if it is not deleted
filter_q = {'_id': _id, '_admin.projects_read': [[], ["ANY"]]}
v = self.db.del_one(self.topic, filter_q, fail_on_empty=False)
if not v or not v["deleted"]:
- return v
+ return None
else:
- v = self.db.del_one(self.topic, filter_q)
+ self.db.del_one(self.topic, filter_q)
self.delete_extra(session, _id, item_content)
self._send_msg("deleted", {"_id": _id})
- return v
+ return None
def edit(self, session, _id, indata=None, kwargs=None, content=None):
"""
:param indata: contains the changes to apply
:param kwargs: modifies indata
:param content: original content of the item
- :return:
+ :return: op_id: operation id if this is processed asynchronously, None otherwise
"""
indata = self._remove_envelop(indata)
if not content:
content = self.show(session, _id)
deep_update_rfc7396(content, indata)
+
+ # To allow project addressing by name AS WELL AS _id. Get the _id, just in case the provided one is a name
+ _id = content.get("_id") or _id
+
self.check_conflict_on_edit(session, content, indata, _id=_id)
- self.format_on_edit(content, indata)
- # To allow project addressing by name AS WELL AS _id
- # self.db.replace(self.topic, _id, content)
- cid = content.get("_id")
- self.db.replace(self.topic, cid if cid else _id, content)
+ op_id = self.format_on_edit(content, indata)
+
+ self.db.replace(self.topic, _id, content)
indata.pop("_admin", None)
+ if op_id:
+ indata["op_id"] = op_id
indata["_id"] = _id
self._send_msg("edit", indata)
- return _id
+ return op_id
except ValidationError as e:
raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
:param indata: data to be inserted
:param kwargs: used to override the indata descriptor
:param headers: http request headers
- :return: _id: identity of the inserted data.
+ :return: _id, None: identity of the inserted data; and None as there is not any operation
"""
try:
self.format_on_new(content, session["project_id"], make_public=session["public"])
_id = self.db.create(self.topic, content)
rollback.append({"topic": self.topic, "_id": _id})
- return _id
+ return _id, None
except ValidationError as e:
raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
:param session: contains the used login username and working project
:param topic: it can be: users, projects, vnfds, nsds, ...
:param _id: server id of the item
- :return: dictionary with deleted item _id. It raises exception if not found.
+ :return: operation id (None if there is not operation), raise exception if error or not found.
"""
if topic not in self.map_topic:
raise EngineException("Unknown topic {}!!!".format(topic), HTTPStatus.INTERNAL_SERVER_ERROR)
:param _id: identifier to be updated
:param indata: data to be inserted
:param kwargs: used to override the indata descriptor
- :return: dictionary, raise exception if not found.
+ :return: operation id (None if there is not operation), raise exception if error or not found.
"""
if topic not in self.map_topic:
raise EngineException("Unknown topic {}!!!".format(topic), HTTPStatus.INTERNAL_SERVER_ERROR)
def format_on_new(content, project_id=None, make_public=False):
BaseTopic.format_on_new(content, project_id=project_id, make_public=make_public)
content["_admin"]["nsState"] = "NOT_INSTANTIATED"
+ return None
def check_conflict_on_del(self, session, _id, db_content):
"""
member_vnf["vnfd-id-ref"], member_vnf["member-vnf-index"])
# add at database
- BaseTopic.format_on_new(vnfr_descriptor, session["project_id"], make_public=session["public"])
+ self.format_on_new(vnfr_descriptor, session["project_id"], make_public=session["public"])
self.db.create("vnfrs", vnfr_descriptor)
rollback.append({"topic": "vnfrs", "_id": vnfr_id})
nsr_descriptor["constituent-vnfr-ref"].append(vnfr_id)
step = "creating nsr temporal folder"
self.fs.mkdir(nsr_id)
- return nsr_id
+ return nsr_id, None
+ except ValidationError as e: # TODO remove try Except, it is captured at nbi.py
+ raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
except Exception as e:
self.logger.exception("Exception {} at NsrTopic.new()".format(e), exc_info=True)
raise EngineException("Error {}: {}".format(step, e))
- except ValidationError as e:
- raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
def edit(self, session, _id, indata=None, kwargs=None, content=None):
raise EngineException("Method edit called directly", HTTPStatus.INTERNAL_SERVER_ERROR)
rollback.append({"topic": "nslcmops", "_id": _id})
if not slice_object:
self.msg.write("ns", operation, nslcmop_desc)
- return _id
- except ValidationError as e:
+ return _id, None
+ except ValidationError as e: # TODO remove try Except, it is captured at nbi.py
raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
# except DbException as e:
# raise EngineException("Cannot get ns_instance '{}': {}".format(e), HTTPStatus.NOT_FOUND)
break
# Creates Nsr objects
- _id_nsr = self.nsrTopic.new(rollback, session, indata_ns, kwargs, headers)
+ _id_nsr, _ = self.nsrTopic.new(rollback, session, indata_ns, kwargs, headers)
nsrs_item = {"nsrId": _id_nsr, "shared": service.get("is-shared-nss"), "nsd-id": service["nsd-ref"],
"nslcmop_instantiate": None}
indata_ns["nss-id"] = service["id"]
# Creating the entry in the database
self.db.create("nsis", nsi_descriptor)
rollback.append({"topic": "nsis", "_id": nsi_id})
- return nsi_id
- except Exception as e:
+ return nsi_id, None
+ except Exception as e: # TODO remove try Except, it is captured at nbi.py
self.logger.exception("Exception {} at NsiTopic.new()".format(e), exc_info=True)
raise EngineException("Error {}: {}".format(step, e))
except ValidationError as e:
indata_ns["netsliceInstanceId"] = netsliceInstanceId
# Creating NS_LCM_OP with the flag slice_object=True to not trigger the service instantiation
# message via kafka bus
- nslcmop = self.nsi_NsLcmOpTopic.new(rollback, session, indata_ns, kwargs, headers,
- slice_object=True)
+ nslcmop, _ = self.nsi_NsLcmOpTopic.new(rollback, session, indata_ns, kwargs, headers,
+ slice_object=True)
nslcmops.append(nslcmop)
if operation == "terminate":
nslcmop = None
_id = self.db.create("nsilcmops", nsilcmop_desc)
rollback.append({"topic": "nsilcmops", "_id": _id})
self.msg.write("nsi", operation, nsilcmop_desc)
- return _id
+ return _id, None
except ValidationError as e:
raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
_id = args[0]
outdata = self.engine.get_item(engine_session, engine_topic, _id)
elif method == "POST":
+ cherrypy.response.status = HTTPStatus.CREATED.value
if topic in ("ns_descriptors_content", "vnf_packages_content", "netslice_templates_content"):
_id = cherrypy.request.headers.get("Transaction-Id")
if not _id:
- _id = self.engine.new_item(rollback, engine_session, engine_topic, {}, None,
- cherrypy.request.headers)
+ _id, _ = self.engine.new_item(rollback, engine_session, engine_topic, {}, None,
+ cherrypy.request.headers)
completed = self.engine.upload_content(engine_session, engine_topic, _id, indata, kwargs,
cherrypy.request.headers)
if completed:
outdata = {"id": _id}
elif topic == "ns_instances_content":
# creates NSR
- _id = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs)
+ _id, _ = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs)
# creates nslcmop
indata["lcmOperationType"] = "instantiate"
indata["nsInstanceId"] = _id
- nslcmop_id = self.engine.new_item(rollback, engine_session, "nslcmops", indata, None)
+ nslcmop_id, _ = self.engine.new_item(rollback, engine_session, "nslcmops", indata, None)
self._set_location_header(main_topic, version, topic, _id)
outdata = {"id": _id, "nslcmop_id": nslcmop_id}
elif topic == "ns_instances" and item:
indata["lcmOperationType"] = item
indata["nsInstanceId"] = _id
- _id = self.engine.new_item(rollback, engine_session, "nslcmops", indata, kwargs)
+ _id, _ = self.engine.new_item(rollback, engine_session, "nslcmops", indata, kwargs)
self._set_location_header(main_topic, version, "ns_lcm_op_occs", _id)
outdata = {"id": _id}
cherrypy.response.status = HTTPStatus.ACCEPTED.value
elif topic == "netslice_instances_content":
# creates NetSlice_Instance_record (NSIR)
- _id = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs)
+ _id, _ = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs)
self._set_location_header(main_topic, version, topic, _id)
indata["lcmOperationType"] = "instantiate"
indata["netsliceInstanceId"] = _id
- nsilcmop_id = self.engine.new_item(rollback, engine_session, "nsilcmops", indata, kwargs)
+ nsilcmop_id, _ = self.engine.new_item(rollback, engine_session, "nsilcmops", indata, kwargs)
outdata = {"id": _id, "nsilcmop_id": nsilcmop_id}
elif topic == "netslice_instances" and item:
indata["lcmOperationType"] = item
indata["netsliceInstanceId"] = _id
- _id = self.engine.new_item(rollback, engine_session, "nsilcmops", indata, kwargs)
+ _id, _ = self.engine.new_item(rollback, engine_session, "nsilcmops", indata, kwargs)
self._set_location_header(main_topic, version, "nsi_lcm_op_occs", _id)
outdata = {"id": _id}
cherrypy.response.status = HTTPStatus.ACCEPTED.value
else:
- _id = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs,
- cherrypy.request.headers)
+ _id, op_id = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs,
+ cherrypy.request.headers)
self._set_location_header(main_topic, version, topic, _id)
outdata = {"id": _id}
+ if op_id:
+ outdata["op_id"] = op_id
+ cherrypy.response.status = HTTPStatus.ACCEPTED.value
# TODO form NsdInfo when topic in ("ns_descriptors", "vnf_packages")
- cherrypy.response.status = HTTPStatus.CREATED.value
elif method == "DELETE":
if not _id:
"nsInstanceId": _id,
"autoremove": True
}
- opp_id = self.engine.new_item(rollback, engine_session, "nslcmops", nslcmop_desc, None)
+ opp_id, _ = self.engine.new_item(rollback, engine_session, "nslcmops", nslcmop_desc, None)
if opp_id:
delete_in_process = True
outdata = {"_id": opp_id}
"netsliceInstanceId": _id,
"autoremove": True
}
- opp_id = self.engine.new_item(rollback, engine_session, "nsilcmops", nsilcmop_desc, None)
+ opp_id, _ = self.engine.new_item(rollback, engine_session, "nsilcmops", nsilcmop_desc, None)
if opp_id:
delete_in_process = True
outdata = {"_id": opp_id}
cherrypy.response.status = HTTPStatus.ACCEPTED.value
elif method in ("PUT", "PATCH"):
- outdata = None
+ op_id = None
if not indata and not kwargs and not engine_session.get("set_project"):
raise NbiException("Nothing to update. Provide payload and/or query string",
HTTPStatus.BAD_REQUEST)
if not completed:
cherrypy.response.headers["Transaction-Id"] = id
else:
- self.engine.edit_item(engine_session, engine_topic, _id, indata, kwargs)
- cherrypy.response.status = HTTPStatus.NO_CONTENT.value
+ op_id = self.engine.edit_item(engine_session, engine_topic, _id, indata, kwargs)
+
+ if op_id:
+ cherrypy.response.status = HTTPStatus.ACCEPTED.value
+ outdata = {"op_id": op_id}
+ else:
+ cherrypy.response.status = HTTPStatus.NO_CONTENT.value
+ outdata = None
else:
raise NbiException("Method {} not allowed".format(method), HTTPStatus.METHOD_NOT_ALLOWED)
vim_data = "{schema_version: '1.0', name: fakeVim, vim_type: openstack, vim_url: 'http://10.11.12.13/fake'"\
", vim_tenant_name: 'vimtenant', vim_user: vimuser, vim_password: vimpassword}"
self.test("Create VIM", "POST", "/admin/v1/vim_accounts", headers_yaml, vim_data,
- (201), {"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/yaml"}, "yaml")
+ (201, 202), {"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/yaml"}, "yaml")
return self.last_id
def print_results(self):
vnfd_ids = []
engine.set_test_name("ProjectDescriptors")
engine.get_autorization()
+
+ project_admin_id = None
+ res = engine.test("Get my project Padmin", "GET", "/admin/v1/projects/{}".format(engine.project), headers_json,
+ None, 200, r_header_json, "json")
+ if res:
+ response = res.json()
+ project_admin_id = response["_id"]
engine.test("Create project Padmin", "POST", "/admin/v1/projects", headers_json,
{"name": "Padmin", "admin": True}, (201, 204),
{"Location": "/admin/v1/projects/", "Content-Type": "application/json"}, "json")
engine.failed_tests += 1
# list vnfds belonging to project "admin"
- res = engine.test("List VNFD of admin project", "GET", "/vnfpkgm/v1/vnf_packages?ADMIN=admin",
+ res = engine.test("List VNFD of admin project", "GET",
+ "/vnfpkgm/v1/vnf_packages?ADMIN={}".format(project_admin_id),
headers_json, None, 200, r_header_json, "json")
response = res.json()
if len(response) != 3:
engine.set_test_name("FakeVim")
engine.get_autorization()
- engine.test("Create VIM", "POST", "/admin/v1/vim_accounts", headers_json, self.vim, (201, 204),
+ engine.test("Create VIM", "POST", "/admin/v1/vim_accounts", headers_json, self.vim, (201, 202),
{"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/json"}, "json")
vim_id = engine.last_id
engine.test("Create VIM without name, bad schema", "POST", "/admin/v1/vim_accounts", headers_json,
engine.set_test_name("VimSdn")
engine.get_autorization()
# Added SDN
- engine.test("Create SDN", "POST", "/admin/v1/sdns", headers_json, self.sdn, (201, 204),
+ engine.test("Create SDN", "POST", "/admin/v1/sdns", headers_json, self.sdn, (201, 202),
{"Location": "/admin/v1/sdns/", "Content-Type": "application/json"}, "json")
sdnc_id = engine.last_id
# sleep(5)
# Edit SDN
engine.test("Edit SDN", "PATCH", "/admin/v1/sdns/{}".format(sdnc_id), headers_json, {"name": "new_sdn_name"},
- 204, None, None)
+ (202, 204), None, None)
# sleep(5)
# VIM with SDN
self.vim["config"]["sdn-controller"] = sdnc_id
self.vim["config"]["sdn-port-mapping"] = self.port_mapping
- engine.test("Create VIM", "POST", "/admin/v1/vim_accounts", headers_json, self.vim, (200, 204, 201),
+ engine.test("Create VIM", "POST", "/admin/v1/vim_accounts", headers_json, self.vim, (200, 202, 201),
{"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/json"}, "json"),
vim_id = engine.last_id
self.port_mapping[0]["compute_node"] = "compute node XX"
engine.test("Edit VIM change port-mapping", "PUT", "/admin/v1/vim_accounts/{}".format(vim_id), headers_json,
- {"config": {"sdn-port-mapping": self.port_mapping}}, 204, None, None)
+ {"config": {"sdn-port-mapping": self.port_mapping}}, (202, 204), None, None)
engine.test("Edit VIM remove port-mapping", "PUT", "/admin/v1/vim_accounts/{}".format(vim_id), headers_json,
- {"config": {"sdn-port-mapping": None}}, 204, None, None)
+ {"config": {"sdn-port-mapping": None}}, (202, 204), None, None)
- engine.test("Create WIM", "POST", "/admin/v1/wim_accounts", headers_json, self.wim, (200, 204, 201),
+ engine.test("Create WIM", "POST", "/admin/v1/wim_accounts", headers_json, self.wim, (200, 202, 201),
{"Location": "/admin/v1/wim_accounts/", "Content-Type": "application/json"}, "json"),
wim_id = engine.last_id
ns_data_text = yaml.safe_dump(ns_data, default_flow_style=True, width=256)
# create NS Two steps
r = engine.test("Create NS step 1", "POST", "/nslcm/v1/ns_instances",
- headers_yaml, ns_data_text, 201,
+ headers_yaml, ns_data_text, (201, 202),
{"Location": "nslcm/v1/ns_instances/", "Content-Type": "application/yaml"}, "yaml")
if not r:
return
self.ns_id = engine.last_id
engine.test("Instantiate NS step 2", "POST",
"/nslcm/v1/ns_instances/{}/instantiate".format(self.ns_id), headers_yaml, ns_data_text,
- 201, r_headers_yaml_location_nslcmop, "yaml")
+ (201, 202), r_headers_yaml_location_nslcmop, "yaml")
nslcmop_id = engine.last_id
if test_osm:
# remove deployment
if test_osm:
engine.test("Terminate NS", "POST", "/nslcm/v1/ns_instances/{}/terminate".format(self.ns_id), headers_yaml,
- None, 201, r_headers_yaml_location_nslcmop, "yaml")
+ None, (201, 202), r_headers_yaml_location_nslcmop, "yaml")
nslcmop2_id = engine.last_id
# Wait until status is Ok
engine.wait_operation_ready("ns", nslcmop2_id, timeout_deploy)
for i in range(0, 2):
engine.test("Execute scale action over NS", "POST",
"/nslcm/v1/ns_instances/{}/scale".format(self.ns_id), headers_yaml, payload,
- 201, r_headers_yaml_location_nslcmop, "yaml")
+ (201, 202), r_headers_yaml_location_nslcmop, "yaml")
nslcmop2_scale_out = engine.last_id
engine.wait_operation_ready("ns", nslcmop2_scale_out, timeout_deploy)
if manual_check:
for i in range(0, 2):
engine.test("Execute scale IN action over NS", "POST",
"/nslcm/v1/ns_instances/{}/scale".format(self.ns_id), headers_yaml, payload,
- 201, r_headers_yaml_location_nslcmop, "yaml")
+ (201, 202), r_headers_yaml_location_nslcmop, "yaml")
nslcmop2_scale_in = engine.last_id
engine.wait_operation_ready("ns", nslcmop2_scale_in, timeout_deploy)
if manual_check:
# perform scale in that must fail as reached limit
engine.test("Execute scale IN out of limit action over NS", "POST",
"/nslcm/v1/ns_instances/{}/scale".format(self.ns_id), headers_yaml, payload,
- 201, r_headers_yaml_location_nslcmop, "yaml")
+ (201, 202), r_headers_yaml_location_nslcmop, "yaml")
nslcmop2_scale_in = engine.last_id
engine.wait_operation_ready("ns", nslcmop2_scale_in, timeout_deploy, expected_fail=True)
payload = '{member_vnf_index: "2", primitive: touch, primitive_params: { filename: /home/ubuntu/OSMTESTNBI }}'
engine.test("Exec service primitive over NS", "POST",
"/nslcm/v1/ns_instances/{}/action".format(self.ns_id), headers_yaml, payload,
- 201, r_headers_yaml_location_nslcmop, "yaml")
+ (201, 202), r_headers_yaml_location_nslcmop, "yaml")
nslcmop2_action = engine.last_id
# Wait until status is Ok
engine.wait_operation_ready("ns", nslcmop2_action, timeout_deploy)
# '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
# engine.test("Execute scale action over NS", "POST",
# "/nslcm/v1/ns_instances/{}/scale".format(self.ns_id), headers_yaml, payload,
- # 201, r_headers_yaml_location_nslcmop, "yaml")
+ # (201, 202), r_headers_yaml_location_nslcmop, "yaml")
# nslcmop2_scale_out = engine.last_id
# engine.wait_operation_ready("ns", nslcmop2_scale_out, timeout_deploy)
# if manual_check:
# '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
# engine.test("Execute scale action over NS", "POST",
# "/nslcm/v1/ns_instances/{}/scale".format(self.ns_id), headers_yaml, payload,
- # 201, r_headers_yaml_location_nslcmop, "yaml")
+ # (201, 202), r_headers_yaml_location_nslcmop, "yaml")
# nslcmop2_scale_in = engine.last_id
# engine.wait_operation_ready("ns", nslcmop2_scale_in, timeout_deploy)
# if manual_check:
'{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
engine.test("Execute scale action over NS", "POST",
"/nslcm/v1/ns_instances/{}/scale".format(self.ns_id), headers_yaml, payload,
- 201, r_headers_yaml_location_nslcmop, "yaml")
+ (201, 202), r_headers_yaml_location_nslcmop, "yaml")
nslcmop2_scale_out = engine.last_id
engine.wait_operation_ready("ns", nslcmop2_scale_out, timeout_deploy)
if manual_check:
'{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
engine.test("Execute scale action over NS", "POST",
"/nslcm/v1/ns_instances/{}/scale".format(self.ns_id), headers_yaml, payload,
- 201, r_headers_yaml_location_nslcmop, "yaml")
+ (201, 202), r_headers_yaml_location_nslcmop, "yaml")
nslcmop2_scale_in = engine.last_id
engine.wait_operation_ready("ns", nslcmop2_scale_in, timeout_deploy)
if manual_check:
def create_slice(self, engine, nsi_data, name):
ns_data_text = yaml.safe_dump(nsi_data, default_flow_style=True, width=256)
r = engine.test(name, "POST", "/nsilcm/v1/netslice_instances",
- headers_yaml, ns_data_text, 201,
+ headers_yaml, ns_data_text, (201, 202),
{"Location": "nsilcm/v1/netslice_instances/", "Content-Type": "application/yaml"}, "yaml")
return r
ns_data_text = yaml.safe_dump(nsi_data, default_flow_style=True, width=256)
engine.test(name, "POST",
"/nsilcm/v1/netslice_instances/{}/instantiate".format(nsi_id), headers_yaml, ns_data_text,
- 201, r_headers_yaml_location_nsilcmop, "yaml")
+ (201, 202), r_headers_yaml_location_nsilcmop, "yaml")
def terminate_slice(self, engine, nsi_id, name):
engine.test(name, "POST", "/nsilcm/v1/netslice_instances/{}/terminate".format(nsi_id),
- headers_yaml, None, 201, r_headers_yaml_location_nsilcmop, "yaml")
+ headers_yaml, None, (201, 202), r_headers_yaml_location_nsilcmop, "yaml")
def delete_slice(self, engine, nsi_id, name):
engine.test(name, "DELETE", "/nsilcm/v1/netslice_instances/{}".format(nsi_id), headers_yaml, None,
try:
if UUID(x):
return True
- except (TypeError, ValueError):
+ except (TypeError, ValueError, AttributeError):
return False