From 43eac1e0ea322648e9ca00fcf98b2bdfd6a35871 Mon Sep 17 00:00:00 2001 From: Patricia Reinoso Date: Wed, 26 Oct 2022 08:55:54 +0000 Subject: [PATCH] Addition of PaaS Add "paas" topic and operations Change-Id: Ib3d274d406e42025b4d1f52bf733d7c112e6116c Signed-off-by: Patricia Reinoso --- osm_nbi/admin_topics.py | 115 ++++++++------- osm_nbi/engine.py | 11 +- osm_nbi/nbi.py | 218 +++++++++++++++++++--------- osm_nbi/resources_to_operations.yml | 14 ++ osm_nbi/roles_to_operations.yml | 4 + osm_nbi/tests/test_admin_topics.py | 104 ++++++++++++- osm_nbi/validation.py | 122 ++++++++++++---- 7 files changed, 431 insertions(+), 157 deletions(-) diff --git a/osm_nbi/admin_topics.py b/osm_nbi/admin_topics.py index b695693..daeb260 100644 --- a/osm_nbi/admin_topics.py +++ b/osm_nbi/admin_topics.py @@ -37,6 +37,8 @@ from osm_nbi.validation import ( k8srepo_edit_schema, vca_new_schema, vca_edit_schema, + paas_new_schema, + paas_edit_schema, osmrepo_new_schema, osmrepo_edit_schema, validate_input, @@ -370,14 +372,21 @@ class CommonVimWimSdn(BaseTopic): """ super().format_on_new(content, project_id=project_id, make_public=make_public) content["schema_version"] = schema_version = "1.11" + self._encrypt_password(content, schema_version) + self._encrypt_config_fields(content, schema_version) + content["_admin"]["operationalState"] = "PROCESSING" + self._insert_create_operation(content) + return "{}:0".format(content["_id"]) - # encrypt passwords + def _encrypt_password(self, content, schema_version): 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"], ) + + def _encrypt_config_fields(self, content, schema_version): config_to_encrypt_keys = self.config_to_encrypt.get( schema_version ) or self.config_to_encrypt.get("default") @@ -390,8 +399,7 @@ class CommonVimWimSdn(BaseTopic): salt=content["_id"], ) - content["_admin"]["operationalState"] = "PROCESSING" - + def _insert_create_operation(self, content): # create operation content["_admin"]["operations"] = [self._create_operation("create")] content["_admin"]["current_operation"] = None @@ -399,50 +407,25 @@ class CommonVimWimSdn(BaseTopic): if content.get("vim_type"): if content["vim_type"] == "openstack": compute = { - "ram": { - "total": None, - "used": None - }, - "vcpus": { - "total": None, - "used": None - }, - "instances": { - "total": None, - "used": None - } + "ram": {"total": None, "used": None}, + "vcpus": {"total": None, "used": None}, + "instances": {"total": None, "used": None}, } storage = { - "volumes": { - "total": None, - "used": None - }, - "snapshots": { - "total": None, - "used": None - }, - "storage": { - "total": None, - "used": None - } + "volumes": {"total": None, "used": None}, + "snapshots": {"total": None, "used": None}, + "storage": {"total": None, "used": None}, } network = { - "networks": { - "total": None, - "used": None - }, - "subnets": { - "total": None, - "used": None - }, - "floating_ips": { - "total": None, - "used": None - } + "networks": {"total": None, "used": None}, + "subnets": {"total": None, "used": None}, + "floating_ips": {"total": None, "used": None}, + } + content["resources"] = { + "compute": compute, + "storage": storage, + "network": network, } - content["resources"] = {"compute": compute, "storage": storage, "network": network} - - return "{}:0".format(content["_id"]) def delete(self, session, _id, dry_run=False, not_send_msg=None): """ @@ -746,6 +729,39 @@ class VcaTopic(CommonVimWimSdn): super().check_conflict_on_del(session, _id, db_content) +class PaasTopic(CommonVimWimSdn): + topic = "paas" + topic_msg = "paas" + schema_new = paas_new_schema + schema_edit = paas_edit_schema + multiproject = True + password_to_encrypt = "secret" + config_to_encrypt = {} + + def format_on_edit(self, final_content, edit_content): + oid = super().format_on_edit(final_content, edit_content) + final_content["_admin"]["operationalState"] = "PROCESSING" + final_content["_admin"]["detailed-status"] = "Editing" + return oid + + def _check_if_used_by_ns(self): + pass + + def check_conflict_on_del(self, session, _id, db_content): + """ + Check if deletion can be done because of dependencies if it is not force. + :param session: contains "username", "admin", "force", "public", "project_id", "set_project" + :param _id: internal _id + :param db_content: The database content of this item _id + :return: None if ok or raises EngineException with the conflict + """ + if session["force"]: + return + self._check_if_used_by_ns() + + super().check_conflict_on_del(session, _id, db_content) + + class K8sRepoTopic(CommonVimWimSdn): topic = "k8srepos" topic_msg = "k8srepo" @@ -1093,10 +1109,7 @@ class UserTopicAuth(UserTopic): if to_add["project"] in ( mapping["project"], mapping["project_name"], - ) and to_add["role"] in ( - mapping["role"], - mapping["role_name"], - ): + ) and to_add["role"] in (mapping["role"], mapping["role_name"]): if mapping in mappings_to_remove: # do not remove mappings_to_remove.remove(mapping) @@ -1113,10 +1126,7 @@ class UserTopicAuth(UserTopic): if to_set["project"] in ( mapping["project"], mapping["project_name"], - ) and to_set["role"] in ( - mapping["role"], - mapping["role_name"], - ): + ) and to_set["role"] in (mapping["role"], mapping["role_name"]): if mapping in mappings_to_remove: # do not remove mappings_to_remove.remove(mapping) break # do not add, it is already at user @@ -1129,10 +1139,7 @@ class UserTopicAuth(UserTopic): if to_set["project"] in ( mapping["project"], mapping["project_name"], - ) and to_set["role"] in ( - mapping["role"], - mapping["role_name"], - ): + ) and to_set["role"] in (mapping["role"], mapping["role_name"]): break else: # delete diff --git a/osm_nbi/engine.py b/osm_nbi/engine.py index 37f1fb2..1f0308a 100644 --- a/osm_nbi/engine.py +++ b/osm_nbi/engine.py @@ -36,7 +36,7 @@ from osm_nbi.authconn_tacacs import AuthconnTacacs from osm_nbi.base_topic import EngineException, versiontuple from osm_nbi.admin_topics import VimAccountTopic, WimAccountTopic, SdnTopic from osm_nbi.admin_topics import K8sClusterTopic, K8sRepoTopic, OsmRepoTopic -from osm_nbi.admin_topics import VcaTopic +from osm_nbi.admin_topics import VcaTopic, PaasTopic from osm_nbi.admin_topics import UserTopicAuth, ProjectTopicAuth, RoleTopicAuth from osm_nbi.descriptor_topics import ( VnfdTopic, @@ -78,6 +78,7 @@ class Engine(object): "sdns": SdnTopic, "k8sclusters": K8sClusterTopic, "vca": VcaTopic, + "paas": PaasTopic, "k8srepos": K8sRepoTopic, "osmrepos": OsmRepoTopic, "users": UserTopicAuth, # Valid for both internal and keystone authentication backends @@ -293,7 +294,9 @@ class Engine(object): :return: The list, it can be empty if no one match the filter_q. """ if topic not in self.map_topic: - raise EngineException("Unknown topic {}!!!".format(topic), HTTPStatus.INTERNAL_SERVER_ERROR) + raise EngineException( + "Unknown topic {}!!!".format(topic), HTTPStatus.INTERNAL_SERVER_ERROR + ) return self.map_topic[topic].list(session, filter_q, api_req) def get_item(self, session, topic, _id, filter_q=None, api_req=False): @@ -307,7 +310,9 @@ class Engine(object): :return: dictionary, raise exception if not found. """ if topic not in self.map_topic: - raise EngineException("Unknown topic {}!!!".format(topic), HTTPStatus.INTERNAL_SERVER_ERROR) + raise EngineException( + "Unknown topic {}!!!".format(topic), HTTPStatus.INTERNAL_SERVER_ERROR + ) return self.map_topic[topic].show(session, _id, filter_q, api_req) def get_file(self, session, topic, _id, path=None, accept_header=None): diff --git a/osm_nbi/nbi.py b/osm_nbi/nbi.py index d78379f..80548ce 100644 --- a/osm_nbi/nbi.py +++ b/osm_nbi/nbi.py @@ -115,6 +115,8 @@ URL: /osm GET POST / O O O /k8sclusters O O / O O O + /paas O5 O5 + / O5 O5 O5 /k8srepos O O / O O /osmrepos O O @@ -288,6 +290,14 @@ valid_url_methods = { "ROLE_PERMISSION": "vca:id:", }, }, + "paas": { + "METHODS": ("GET", "POST"), + "ROLE_PERMISSION": "paas:", + "": { + "METHODS": ("GET", "DELETE", "PATCH"), + "ROLE_PERMISSION": "paas:id:", + }, + }, "k8srepos": { "METHODS": ("GET", "POST"), "ROLE_PERMISSION": "k8srepos:", @@ -463,8 +473,8 @@ valid_url_methods = { }, "verticalscale": { "METHODS": ("POST",), - "ROLE_PERMISSION": "ns_instances:id:verticalscale:" - }, + "ROLE_PERMISSION": "ns_instances:id:verticalscale:", + }, }, }, "ns_lcm_op_occs": { @@ -497,33 +507,42 @@ valid_url_methods = { }, "vnflcm": { "v1": { - "vnf_instances": {"METHODS": ("GET", "POST"), - "ROLE_PERMISSION": "vnflcm_instances:", - "": {"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:", - "": {"METHODS": ("GET",), - "ROLE_PERMISSION": "vnf_instances:opps:id:" - }, - }, - "subscriptions": {"METHODS": ("GET", "POST"), - "ROLE_PERMISSION": "vnflcm_subscriptions:", - "": {"METHODS": ("GET", "DELETE"), - "ROLE_PERMISSION": "vnflcm_subscriptions:id:" - } - }, + "vnf_instances": { + "METHODS": ("GET", "POST"), + "ROLE_PERMISSION": "vnflcm_instances:", + "": { + "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:", + "": { + "METHODS": ("GET",), + "ROLE_PERMISSION": "vnf_instances:opps:id:", + }, + }, + "subscriptions": { + "METHODS": ("GET", "POST"), + "ROLE_PERMISSION": "vnflcm_subscriptions:", + "": { + "METHODS": ("GET", "DELETE"), + "ROLE_PERMISSION": "vnflcm_subscriptions:id:", + }, + }, } }, "nst": { @@ -620,12 +639,14 @@ valid_url_methods = { }, "nsfm": { "v1": { - "alarms": {"METHODS": ("GET", "PATCH"), - "ROLE_PERMISSION": "alarms:", - "": {"METHODS": ("GET", "PATCH"), - "ROLE_PERMISSION": "alarms:id:", - }, - } + "alarms": { + "METHODS": ("GET", "PATCH"), + "ROLE_PERMISSION": "alarms:", + "": { + "METHODS": ("GET", "PATCH"), + "ROLE_PERMISSION": "alarms:id:", + }, + } }, }, } @@ -884,54 +905,87 @@ class Server(object): # NS Fault Management @cherrypy.expose - def nsfm(self, version=None, topic=None, uuid=None, project_name=None, ns_id=None, *args, **kwargs): - if topic == 'alarms': + def nsfm( + self, + version=None, + topic=None, + uuid=None, + project_name=None, + ns_id=None, + *args, + **kwargs + ): + if topic == "alarms": try: method = cherrypy.request.method - role_permission = self._check_valid_url_method(method, "nsfm", version, topic, None, None, *args) - query_string_operations = self._extract_query_string_operations(kwargs, method) + role_permission = self._check_valid_url_method( + method, "nsfm", version, topic, None, None, *args + ) + query_string_operations = self._extract_query_string_operations( + kwargs, method + ) - self.authenticator.authorize(role_permission, query_string_operations, None) + self.authenticator.authorize( + role_permission, query_string_operations, None + ) # to handle get request - if cherrypy.request.method == 'GET': + if cherrypy.request.method == "GET": # if request is on basis of uuid - if uuid and uuid != 'None': + if uuid and uuid != "None": try: alarm = self.engine.db.get_one("alarms", {"uuid": uuid}) - alarm_action = self.engine.db.get_one("alarms_action", {"uuid": uuid}) + alarm_action = self.engine.db.get_one( + "alarms_action", {"uuid": uuid} + ) alarm.update(alarm_action) - vnf = self.engine.db.get_one("vnfrs", {"nsr-id-ref": alarm["tags"]["ns_id"]}) + vnf = self.engine.db.get_one( + "vnfrs", {"nsr-id-ref": alarm["tags"]["ns_id"]} + ) alarm["vnf-id"] = vnf["_id"] return self._format_out(str(alarm)) except Exception: return self._format_out("Please provide valid alarm uuid") - elif ns_id and ns_id != 'None': + elif ns_id and ns_id != "None": # if request is on basis of ns_id try: - alarms = self.engine.db.get_list("alarms", {"tags.ns_id": ns_id}) + alarms = self.engine.db.get_list( + "alarms", {"tags.ns_id": ns_id} + ) for alarm in alarms: - alarm_action = self.engine.db.get_one("alarms_action", {"uuid": alarm['uuid']}) + alarm_action = self.engine.db.get_one( + "alarms_action", {"uuid": alarm["uuid"]} + ) alarm.update(alarm_action) return self._format_out(str(alarms)) except Exception: return self._format_out("Please provide valid ns id") else: # to return only alarm which are related to given project - project = self.engine.db.get_one("projects", {"name": project_name}) - project_id = project.get('_id') - ns_list = self.engine.db.get_list("nsrs", {"_admin.projects_read": project_id}) + project = self.engine.db.get_one( + "projects", {"name": project_name} + ) + project_id = project.get("_id") + ns_list = self.engine.db.get_list( + "nsrs", {"_admin.projects_read": project_id} + ) ns_ids = [] for ns in ns_list: ns_ids.append(ns.get("_id")) alarms = self.engine.db.get_list("alarms") - alarm_list = [alarm for alarm in alarms if alarm["tags"]["ns_id"] in ns_ids] + alarm_list = [ + alarm + for alarm in alarms + if alarm["tags"]["ns_id"] in ns_ids + ] for alrm in alarm_list: - action = self.engine.db.get_one("alarms_action", {"uuid": alrm.get("uuid")}) + action = self.engine.db.get_one( + "alarms_action", {"uuid": alrm.get("uuid")} + ) alrm.update(action) return self._format_out(str(alarm_list)) # to handle patch request for alarm update - elif cherrypy.request.method == 'PATCH': + elif cherrypy.request.method == "PATCH": data = yaml.load(cherrypy.request.body, Loader=yaml.SafeLoader) try: # check if uuid is valid @@ -940,24 +994,43 @@ class Server(object): return self._format_out("Please provide valid alarm uuid.") if data.get("is_enable") is not None: if data.get("is_enable"): - alarm_status = 'ok' + alarm_status = "ok" else: - alarm_status = 'disabled' - self.engine.db.set_one("alarms", {"uuid": data.get("uuid")}, - {"alarm_status": alarm_status}) + alarm_status = "disabled" + self.engine.db.set_one( + "alarms", + {"uuid": data.get("uuid")}, + {"alarm_status": alarm_status}, + ) else: - self.engine.db.set_one("alarms", {"uuid": data.get("uuid")}, - {"threshold": data.get("threshold")}) + self.engine.db.set_one( + "alarms", + {"uuid": data.get("uuid")}, + {"threshold": data.get("threshold")}, + ) return self._format_out("Alarm updated") except Exception as e: cherrypy.response.status = e.http_code.value - if isinstance(e, (NbiException, EngineException, DbException, FsException, MsgException, AuthException, - ValidationError, AuthconnException)): + if isinstance( + e, + ( + NbiException, + EngineException, + DbException, + FsException, + MsgException, + AuthException, + ValidationError, + AuthconnException, + ), + ): http_code_value = cherrypy.response.status = e.http_code.value http_code_name = e.http_code.name cherrypy.log("Exception {}".format(e)) else: - http_code_value = cherrypy.response.status = HTTPStatus.BAD_REQUEST.value # INTERNAL_SERVER_ERROR + http_code_value = ( + cherrypy.response.status + ) = HTTPStatus.BAD_REQUEST.value # INTERNAL_SERVER_ERROR cherrypy.log("CRITICAL: Exception {}".format(e), traceback=True) http_code_name = HTTPStatus.BAD_REQUEST.name problem_details = { @@ -1004,10 +1077,11 @@ class Server(object): self._format_login(token_info) # password expiry check if self.authenticator.check_password_expiry(outdata): - outdata = {"id": outdata["id"], - "message": "change_password", - "user_id": outdata["user_id"] - } + outdata = { + "id": outdata["id"], + "message": "change_password", + "user_id": outdata["user_id"], + } # cherrypy.response.cookie["Authorization"] = outdata["id"] # cherrypy.response.cookie["Authorization"]['expires'] = 3600 elif method == "DELETE": @@ -1453,7 +1527,9 @@ class Server(object): filter_q = None if "vcaStatusRefresh" in kwargs: filter_q = {"vcaStatusRefresh": kwargs["vcaStatusRefresh"]} - outdata = self.engine.get_item(engine_session, engine_topic, _id, filter_q, True) + outdata = self.engine.get_item( + engine_session, engine_topic, _id, filter_q, True + ) elif method == "POST": cherrypy.response.status = HTTPStatus.CREATED.value @@ -1560,8 +1636,12 @@ class Server(object): 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) + _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: diff --git a/osm_nbi/resources_to_operations.yml b/osm_nbi/resources_to_operations.yml index 3c5ba3d..3c553e0 100644 --- a/osm_nbi/resources_to_operations.yml +++ b/osm_nbi/resources_to_operations.yml @@ -257,6 +257,20 @@ resources_to_operations: "PATCH /admin/v1/vca/": "vca:id:patch" +################################################################################ +###################################### PAASs ################################### +################################################################################ + + "GET /admin/v1/paas": "paas:get" + + "POST /admin/v1/paas": "paas:post" + + "GET /admin/v1/paas/": "paas:id:get" + + "DELETE /admin/v1/paas/": "paas:id:delete" + + "PATCH /admin/v1/paas/": "paas:id:patch" + ################################################################################ ################################# K8s Repos ############################## ################################################################################ diff --git a/osm_nbi/roles_to_operations.yml b/osm_nbi/roles_to_operations.yml index a97e0c1..4d1ae46 100644 --- a/osm_nbi/roles_to_operations.yml +++ b/osm_nbi/roles_to_operations.yml @@ -140,6 +140,10 @@ roles: vca: false vca:get: true vca:id:get: true + # PAAS + paas: false + paas:get: true + paas:id:get: true # K8s repos k8srepos: true # OSM repos diff --git a/osm_nbi/tests/test_admin_topics.py b/osm_nbi/tests/test_admin_topics.py index 8124ce4..ae50198 100755 --- a/osm_nbi/tests/test_admin_topics.py +++ b/osm_nbi/tests/test_admin_topics.py @@ -32,6 +32,7 @@ from osm_nbi.admin_topics import ( UserTopicAuth, CommonVimWimSdn, VcaTopic, + PaasTopic, ) from osm_nbi.engine import EngineException from osm_nbi.authconn import AuthconnNotFoundException @@ -165,6 +166,105 @@ class TestVcaTopic(TestCase): mock_check_conflict_on_del.assert_not_called() +class TestPaaSTopic(TestCase): + def setUp(self): + self.db = Mock(dbbase.DbBase()) + self.fs = Mock(fsbase.FsBase()) + self.msg = Mock(msgbase.MsgBase()) + self.auth = Mock(authconn.Authconn(None, None, None)) + self.paas_topic = PaasTopic(self.db, self.fs, self.msg, self.auth) + + def test_format_on_new(self): + content = { + "_id": "id", + "secret": "secret_to_encrypt", + } + self.db.encrypt.side_effect = ["encrypted_secret"] + + expecte_oid = "id:0" + expected_num_operations = 1 + oid = self.paas_topic.format_on_new(content) + + self.assertEqual(oid, expecte_oid) + self.assertEqual(content["secret"], "encrypted_secret") + self.assertEqual(content["_admin"]["operationalState"], "PROCESSING") + self.assertEqual(content["_admin"]["current_operation"], None) + self.assertEqual(len(content["_admin"]["operations"]), expected_num_operations) + self.assertEqual( + content["_admin"]["operations"][0]["lcmOperationType"], "create" + ) + self.db.encrypt.assert_called_with( + "secret_to_encrypt", schema_version="1.11", salt="id" + ) + + @patch("osm_nbi.base_topic.BaseTopic._get_project_filter") + def test_check_conflict_on_new(self, mock_get_project_filter): + indata = {"name": "new_paas_name"} + session = {} + mock_get_project_filter.return_value = {} + self.db.get_one.return_value = None + self.paas_topic.check_conflict_on_new(session, indata) + + @patch("osm_nbi.base_topic.BaseTopic._get_project_filter") + def test_check_conflict_on_new_raise_exception(self, mock_get_project_filter): + indata = {"name": "new_paas_name"} + session = {} + mock_get_project_filter.return_value = {} + self.db.get_one.return_value = ["Found_PaaS"] + with self.assertRaises(EngineException): + self.paas_topic.check_conflict_on_new(session, indata) + + @patch("osm_nbi.base_topic.BaseTopic._get_project_filter") + def test_check_conflict_on_edit(self, mock_get_project_filter): + edit_content = {"name": "new_paas_name"} + final_content = {} + session = {"force": None} + mock_get_project_filter.return_value = {} + self.db.get_one.return_value = None + self.paas_topic.check_conflict_on_edit( + session, final_content, edit_content, "id" + ) + + @patch("osm_nbi.base_topic.BaseTopic._get_project_filter") + def test_check_conflict_on_edit_raise_exception(self, mock_get_project_filter): + edit_content = {"name": "new_paas_name"} + final_content = {} + session = {"force": None} + mock_get_project_filter.return_value = {} + self.db.get_one.return_value = ["Found_PaaS"] + with self.assertRaises(EngineException): + self.paas_topic.check_conflict_on_edit( + session, final_content, edit_content, "id" + ) + + def test_format_on_edit(self): + edit_content = { + "_id": "id", + "secret": "secret_to_encrypt", + } + final_content = { + "_id": "id", + "_admin": {"operations": [{"lcmOperationType": "create"}]}, + "schema_version": "1.11", + } + self.db.encrypt.side_effect = ["encrypted_secret"] + expected_oid = "id:1" + expected_num_operations = 2 + print(self.paas_topic.password_to_encrypt) + oid = self.paas_topic.format_on_edit(final_content, edit_content) + + self.assertEqual(oid, expected_oid) + self.assertEqual(final_content["secret"], "encrypted_secret") + self.assertEqual( + len(final_content["_admin"]["operations"]), expected_num_operations + ) + self.assertEqual(final_content["_admin"]["operationalState"], "PROCESSING") + self.assertEqual(final_content["_admin"]["detailed-status"], "Editing") + self.db.encrypt.assert_called_with( + "secret_to_encrypt", schema_version="1.11", salt="id" + ) + + class Test_ProjectTopicAuth(TestCase): @classmethod def setUpClass(cls): @@ -1013,7 +1113,9 @@ class Test_UserTopicAuth(TestCase): }, ) content = self.auth.update_user.call_args[0][0] - self.assertEqual(content["old_password"], old_password, "Wrong old password") + self.assertEqual( + content["old_password"], old_password, "Wrong old password" + ) self.assertEqual(content["password"], new_pasw, "Wrong user password") def test_delete_user(self): diff --git a/osm_nbi/validation.py b/osm_nbi/validation.py index a17e241..32a2d3e 100644 --- a/osm_nbi/validation.py +++ b/osm_nbi/validation.py @@ -449,7 +449,12 @@ ns_update = { "nsInstanceId": id_schema, "timeout_ns_update": integer1_schema, "updateType": { - "enum": ["CHANGE_VNFPKG", "REMOVE_VNF", "MODIFY_VNF_INFORMATION", "OPERATE_VNF"] + "enum": [ + "CHANGE_VNFPKG", + "REMOVE_VNF", + "MODIFY_VNF_INFORMATION", + "OPERATE_VNF", + ] }, "modifyVnfInfoData": { "type": "object", @@ -482,10 +487,10 @@ ns_update = { }, "required": ["vdu_id", "count-index"], "additionalProperties": False, - } + }, }, "required": ["vnfInstanceId", "changeStateTo"], - } + }, }, "required": ["updateType"], "additionalProperties": False, @@ -556,16 +561,16 @@ ns_migrate = { "migrateToHost": string_schema, "vdu": { "type": "object", - "properties": { - "vduId": name_schema, - "vduCountIndex": integer0_schema, - }, - "required": ["vduId"], - "additionalProperties": False, + "properties": { + "vduId": name_schema, + "vduCountIndex": integer0_schema, + }, + "required": ["vduId"], + "additionalProperties": False, }, }, "required": ["vnfInstanceId"], - "additionalProperties": False + "additionalProperties": False, } ns_heal = { @@ -633,13 +638,13 @@ ns_verticalscale = { "virtualMemory": integer1_schema, "sizeOfStorage": integer0_schema, "numVirtualCpu": integer1_schema, - }, - } + }, }, + }, "required": ["vnfInstanceId", "additionalParams"], "additionalProperties": False, - } }, + }, "required": ["lcmOperationType", "verticalScale", "nsInstanceId"], "additionalProperties": False, } @@ -926,6 +931,48 @@ vca_edit_schema = { "additionalProperties": False, } +# PAAS +paas_types = {"enum": ["juju"]} +paas_new_schema = { + "title": "paas creation input schema", + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "schema_version": schema_version, + "schema_type": schema_type, + "name": name_schema, + "paas_type": paas_types, + "description": description_schema, + "endpoints": description_list_schema, + "user": string_schema, + "secret": passwd_schema, + "config": object_schema, + }, + "required": [ + "name", + "paas_type", + "endpoints", + "user", + "secret", + ], + "additionalProperties": False, +} +paas_edit_schema = { + "title": "paas edition input schema", + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "name": name_schema, + "paas_type": paas_types, + "description": description_schema, + "endpoints": description_list_schema, + "user": string_schema, + "secret": passwd_schema, + "config": object_schema, + }, + "additionalProperties": False, +} + # K8s Repos k8srepo_types = {"enum": ["helm-chart", "juju-bundle"]} k8srepo_properties = { @@ -1126,6 +1173,7 @@ topics_with_quota = [ "sdn_controllers", "k8sclusters", "vca", + "paas", "k8srepos", "osmrepos", "ns_subscriptions", @@ -1436,32 +1484,46 @@ vnflcmsub_schema = { "enum": [ "VnfIdentifierCreationNotification", "VnfLcmOperationOccurrenceNotification", - "VnfIdentifierDeletionNotification" - ] - } + "VnfIdentifierDeletionNotification", + ] + }, }, "operationTypes": { "type": "array", "items": { "enum": [ - "INSTANTIATE", "SCALE", "SCALE_TO_LEVEL", "CHANGE_FLAVOUR", "TERMINATE", - "HEAL", "OPERATE", "CHANGE_EXT_CONN", "MODIFY_INFO", "CREATE_SNAPSHOT", - "REVERT_TO_SNAPSHOT", "CHANGE_VNFPKG" - ] - } + "INSTANTIATE", + "SCALE", + "SCALE_TO_LEVEL", + "CHANGE_FLAVOUR", + "TERMINATE", + "HEAL", + "OPERATE", + "CHANGE_EXT_CONN", + "MODIFY_INFO", + "CREATE_SNAPSHOT", + "REVERT_TO_SNAPSHOT", + "CHANGE_VNFPKG", + ] + }, }, "operationStates": { "type": "array", "items": { "enum": [ - "STARTING", "PROCESSING", "COMPLETED", "FAILED_TEMP", "FAILED", - "ROLLING_BACK", "ROLLED_BACK" - ] - } - } + "STARTING", + "PROCESSING", + "COMPLETED", + "FAILED_TEMP", + "FAILED", + "ROLLING_BACK", + "ROLLED_BACK", + ] + }, + }, }, - "required": ["VnfInstanceSubscriptionFilter", "notificationTypes"] - } + "required": ["VnfInstanceSubscriptionFilter", "notificationTypes"], +} vnf_subscription = { "title": "vnf subscription input schema", @@ -1470,9 +1532,9 @@ vnf_subscription = { "properties": { "filter": vnflcmsub_schema, "CallbackUri": description_schema, - "authentication": authentication_schema + "authentication": authentication_schema, }, - "required": ["filter", "CallbackUri"] + "required": ["filter", "CallbackUri"], } -- 2.25.1