From 5b11f4ff05cf4bd3f042a4c531848b939e4ead8a Mon Sep 17 00:00:00 2001 From: "raviteja.karumuri" Date: Wed, 12 Jan 2022 18:48:44 +0000 Subject: [PMSH] Delete subscription API by Name Issue-ID: DCAEGEN2-2821 Signed-off-by: Raviteja, Karumuri Change-Id: I22eb00c74e40b5428c3c7bd2b0546175cd6f30ed --- components/pm-subscription-handler/Changelog.md | 1 + .../pmsh_service/mod/api/controller.py | 41 +++++++++++++++- .../pmsh_service/mod/api/pmsh_swagger.yml | 23 ++++++++- .../mod/api/services/subscription_service.py | 37 ++++++++++++++- .../tests/test_controller.py | 54 +++++++++++++++++++++- 5 files changed, 151 insertions(+), 5 deletions(-) diff --git a/components/pm-subscription-handler/Changelog.md b/components/pm-subscription-handler/Changelog.md index fb06f8a6..db8d5758 100755 --- a/components/pm-subscription-handler/Changelog.md +++ b/components/pm-subscription-handler/Changelog.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). * AAI Event handler changes with new subscription format (DCAEGEN2-2912) * Read NFS associated with MG by using MGName and subName(DCAEGEN2-2993) * Lazy loading error for nfs in read API (DCAEGEN2-3029) +* Delete subscription API by Name(DCAEGEN2-2821) ## [1.3.2] ### Changed diff --git a/components/pm-subscription-handler/pmsh_service/mod/api/controller.py b/components/pm-subscription-handler/pmsh_service/mod/api/controller.py index aee6df0e..d887187a 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/api/controller.py +++ b/components/pm-subscription-handler/pmsh_service/mod/api/controller.py @@ -1,5 +1,5 @@ # ============LICENSE_START=================================================== -# Copyright (C) 2019-2021 Nordix Foundation. +# Copyright (C) 2019-2022 Nordix Foundation. # ============================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -147,3 +147,42 @@ def get_meas_group_with_nfs(subscription_name, measurement_group_name): f'{exception}') return {'error': 'Request was not processed due to Exception : ' f'{exception}'}, HTTPStatus.INTERNAL_SERVER_ERROR.value + + +def delete_subscription_by_name(subscription_name): + """ Deletes the subscription by name + + Args: + subscription_name (String): Name of the subscription + + Returns: + NoneType, HTTPStatus: None, 204 + dict, HTTPStatus: subscription not defined, 404 + dict, HTTPStatus: Reason for not deleting subscription, 409 + dict, HTTPStatus: Exception details of failure, 500 + """ + logger.info(f'API call received to delete subscription by name: {subscription_name}') + try: + unlocked_locking_mgs = \ + subscription_service.query_unlocked_mg_by_sub_name(subscription_name) + if not unlocked_locking_mgs: + if subscription_service.query_to_delete_subscription_by_name(subscription_name) == 1: + return None, HTTPStatus.NO_CONTENT + else: + logger.error(f'Subscription is not defined with name {subscription_name}') + return {'error': f'Subscription is not defined with name {subscription_name}'}, \ + HTTPStatus.NOT_FOUND.value + else: + logger.error('Subscription is not deleted due to associated MGs were UNLOCKED ' + '(or) under update process to LOCKED') + return {'error': 'Subscription is not deleted due to the following MGs were UNLOCKED ' + '(or) under update process to LOCKED', 'measurementGroupNames': + [{'measurementGroupName': + mg.measurement_group_name}for mg in unlocked_locking_mgs]}, \ + HTTPStatus.CONFLICT.value + except Exception as exception: + logger.error(f'Try again, subscription with name {subscription_name}' + f'is not deleted due to following exception: {exception}') + return {'error': f'Try again, subscription with name {subscription_name}' + f'is not deleted due to following exception: {exception}'}, \ + HTTPStatus.INTERNAL_SERVER_ERROR.value diff --git a/components/pm-subscription-handler/pmsh_service/mod/api/pmsh_swagger.yml b/components/pm-subscription-handler/pmsh_service/mod/api/pmsh_swagger.yml index 4dd1cc70..3319b7ef 100644 --- a/components/pm-subscription-handler/pmsh_service/mod/api/pmsh_swagger.yml +++ b/components/pm-subscription-handler/pmsh_service/mod/api/pmsh_swagger.yml @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (C) 2020-2021 Nordix Foundation. +# Copyright (C) 2020-2022 Nordix Foundation. # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -109,6 +109,27 @@ paths: 500: description: Exception occurred while querying database + delete: + description: Deletes the Subscription from PMSH specified by Name + operationId: mod.api.controller.delete_subscription_by_name + parameters: + - name: subscription_name + in: path + required: true + description: The name of the subscription to delete + type: string + responses: + 204: + description: Successfully deleted the subscription and returns NO Content + 404: + description: Subscription with the specified name not found + 409: + description: Subscription could not be deleted as it contains measurement groups + with state UNLOCKED OR state change to LOCKED was under process + 500: + description: Exception occurred on the server + + /subscription/{subscription_name}/measurementGroups/{measurement_group_name}: get: description: Get the measurement group and associated network functions diff --git a/components/pm-subscription-handler/pmsh_service/mod/api/services/subscription_service.py b/components/pm-subscription-handler/pmsh_service/mod/api/services/subscription_service.py index d9f44001..7b31de50 100644 --- a/components/pm-subscription-handler/pmsh_service/mod/api/services/subscription_service.py +++ b/components/pm-subscription-handler/pmsh_service/mod/api/services/subscription_service.py @@ -18,7 +18,7 @@ from mod import db, logger from mod.api.db_models import SubscriptionModel, NfSubRelationalModel, \ - NetworkFunctionFilterModel, NetworkFunctionModel + NetworkFunctionFilterModel, NetworkFunctionModel, MeasurementGroupModel from mod.api.services import measurement_group_service, nf_service from mod.api.custom_exception import InvalidDataException, DuplicateDataException from mod.subscription import AdministrativeState, SubNfState @@ -345,3 +345,38 @@ def get_subscriptions_list(): (len(subscription.measurement_groups) != 0): subscriptions_list.append(subscription.serialize()) return subscriptions_list + + +def query_unlocked_mg_by_sub_name(subscription_name): + """ + Queries the db for unlocked/locking measurement groups by subscription name + + Args: + subscription_name (String): Name of the Subscription + + Returns: + list (MeasurementGroupModel): If measurement groups with admin state + UNLOCKED exists else empty list + """ + logger.info(f'Attempting to fetch measurement groups by subscription name: {subscription_name}') + mg_model = db.session.query(MeasurementGroupModel) \ + .filter_by(subscription_name=subscription_name) \ + .filter(MeasurementGroupModel.administrative_state.in_(('UNLOCKED', 'LOCKING'))).all() + db.session.remove() + return mg_model + + +def query_to_delete_subscription_by_name(subscription_name): + """ + Deletes the subscription by name + + Args: + subscription_name (String): Name of the Subscription + + Returns: + int: Returns '1' if subscription exists and deleted successfully else '0' + """ + effected_rows = db.session.query(SubscriptionModel) \ + .filter_by(subscription_name=subscription_name).delete() + db.session.commit() + return effected_rows diff --git a/components/pm-subscription-handler/tests/test_controller.py b/components/pm-subscription-handler/tests/test_controller.py index fa96c319..1de7c175 100755 --- a/components/pm-subscription-handler/tests/test_controller.py +++ b/components/pm-subscription-handler/tests/test_controller.py @@ -22,14 +22,14 @@ from http import HTTPStatus from mod import aai_client, db from mod.api.controller import status, post_subscription, get_subscription_by_name, \ - get_subscriptions, get_meas_group_with_nfs + get_subscriptions, get_meas_group_with_nfs, delete_subscription_by_name from tests.base_setup import BaseClassSetup from mod.api.db_models import SubscriptionModel, NfMeasureGroupRelationalModel from mod.subscription import SubNfState from mod.network_function import NetworkFunctionFilter from tests.base_setup import create_subscription_data, create_multiple_subscription_data, \ create_multiple_network_function_data -from mod.api.services import measurement_group_service, nf_service +from mod.api.services import measurement_group_service, nf_service, subscription_service class ControllerTestCase(BaseClassSetup): @@ -202,3 +202,53 @@ class ControllerTestCase(BaseClassSetup): def test_get_meas_group_with_nfs_api_exception(self): error, status_code = get_meas_group_with_nfs('sub1', 'MG1') self.assertEqual(status_code, HTTPStatus.INTERNAL_SERVER_ERROR.value) + + def test_delete_when_state_unlocked(self): + subscription_unlocked_data = create_subscription_data('MG_unlocked') + subscription_unlocked_data.measurement_groups[0].measurement_group_name = 'unlock' + subscription_unlocked_data.measurement_groups[0].administrative_state = 'UNLOCKED' + db.session.add(subscription_unlocked_data) + db.session.add(subscription_unlocked_data.measurement_groups[0]) + db.session.commit() + db.session.remove() + message, status_code = delete_subscription_by_name('MG_unlocked') + self.assertEqual(status_code, HTTPStatus.CONFLICT.value) + self.assertEqual(subscription_service.query_subscription_by_name('MG_unlocked') + .subscription_name, 'MG_unlocked') + + def test_delete_when_state_locked(self): + subscription_unlocked_data = create_subscription_data('MG_locked') + subscription_unlocked_data.measurement_groups[0].measurement_group_name = 'lock' + subscription_unlocked_data.measurement_groups[0].administrative_state = 'LOCKED' + db.session.add(subscription_unlocked_data) + db.session.add(subscription_unlocked_data.measurement_groups[0]) + db.session.commit() + db.session.remove() + none_type, status_code = delete_subscription_by_name('MG_locked') + self.assertEqual(none_type, None) + self.assertEqual(status_code, HTTPStatus.NO_CONTENT.value) + self.assertEqual(subscription_service.query_subscription_by_name('MG_locked'), None) + + def test_delete_when_state_locking(self): + subscription_locking_data = create_subscription_data('MG_locking') + subscription_locking_data.measurement_groups[0].measurement_group_name = 'locking' + subscription_locking_data.measurement_groups[0].administrative_state = 'LOCKING' + db.session.add(subscription_locking_data) + db.session.add(subscription_locking_data.measurement_groups[0]) + db.session.commit() + db.session.remove() + message, status_code = delete_subscription_by_name('MG_locking') + self.assertEqual(status_code, HTTPStatus.CONFLICT.value) + self.assertEqual(subscription_service.query_subscription_by_name('MG_locking') + .subscription_name, 'MG_locking') + + def test_delete_sub_none(self): + message, status_code = delete_subscription_by_name('None') + self.assertEqual(message['error'], 'Subscription is not defined with name None') + self.assertEqual(status_code, HTTPStatus.NOT_FOUND.value) + + @patch('mod.api.services.subscription_service.query_to_delete_subscription_by_name', + MagicMock(side_effect=Exception('something failed'))) + def test_delete_sub_exception(self): + error, status_code = delete_subscription_by_name('None') + self.assertEqual(status_code, HTTPStatus.INTERNAL_SERVER_ERROR.value) -- cgit 1.2.3-korg