From c77c6d999abd83235798b20d7c76e1005f7135a3 Mon Sep 17 00:00:00 2001 From: "raviteja.karumuri" Date: Thu, 2 Dec 2021 19:13:27 +0000 Subject: [PMSH] Read NFS associated with MG by using MGName and subName Issue-ID: DCAEGEN2-2993 Signed-off-by: Raviteja, Karumuri Change-Id: I651a687ab7480fc0d42bf976c3d1b34f00e73e98 --- components/pm-subscription-handler/Changelog.md | 1 + .../pmsh_service/mod/api/controller.py | 37 +++++++++- .../pmsh_service/mod/api/db_models.py | 78 +++++++++++++++----- .../pmsh_service/mod/api/pmsh_swagger.yml | 85 ++++++++++++++++++++++ .../mod/api/services/measurement_group_service.py | 17 +++++ .../pm-subscription-handler/tests/base_setup.py | 22 +++++- .../tests/test_controller.py | 42 ++++++++++- 7 files changed, 258 insertions(+), 24 deletions(-) diff --git a/components/pm-subscription-handler/Changelog.md b/components/pm-subscription-handler/Changelog.md index 77cd827a..db096b11 100755 --- a/components/pm-subscription-handler/Changelog.md +++ b/components/pm-subscription-handler/Changelog.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). * Response Event Handler Integration (DCAEGEN2-2915) * Updated to get NFs list when requesting a specific subscription (DCAEGEN2-2992) * AAI Event handler changes with new subscription format (DCAEGEN2-2912) +* Read NFS associated with MG by using MGName and subName(DCAEGEN2-2993) ## [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 e852324d..aee6df0e 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/api/controller.py +++ b/components/pm-subscription-handler/pmsh_service/mod/api/controller.py @@ -18,7 +18,7 @@ from http import HTTPStatus from mod import logger -from mod.api.services import subscription_service +from mod.api.services import subscription_service, measurement_group_service from connexion import NoContent from mod.api.custom_exception import InvalidDataException, DuplicateDataException @@ -112,3 +112,38 @@ def get_subscriptions(): logger.error(f'The following exception occurred while fetching subscriptions: {exception}') return {'error': 'Request was not processed due to Exception : ' f'{exception}'}, HTTPStatus.INTERNAL_SERVER_ERROR.value + + +def get_meas_group_with_nfs(subscription_name, measurement_group_name): + """ + Retrieves the measurement group and it's associated network functions + + Args: + subscription_name (String): Name of the subscription. + measurement_group_name (String): Name of the measurement group + + Returns: + dict, HTTPStatus: measurement group info with associated nfs, 200 + dict, HTTPStatus: measurement group was not defined, 404 + dict, HTTPStatus: Exception details of failure, 500 + """ + logger.info('API call received to query measurement group and associated network' + f' functions by using sub name: {subscription_name} and measurement ' + f'group name: {measurement_group_name}') + try: + meas_group = measurement_group_service.query_meas_group_by_name(subscription_name, + measurement_group_name) + if meas_group is not None: + return meas_group.meas_group_with_nfs(), HTTPStatus.OK.value + else: + logger.error('measurement group was not defined with the sub name: ' + f'{subscription_name} and meas group name: ' + f'{measurement_group_name}') + return {'error': 'measurement group was not defined with the sub name: ' + f'{subscription_name} and meas group name: ' + f'{measurement_group_name}'}, HTTPStatus.NOT_FOUND.value + except Exception as exception: + logger.error('The following exception occurred while fetching measurement group: ' + f'{exception}') + return {'error': 'Request was not processed due to Exception : ' + f'{exception}'}, HTTPStatus.INTERNAL_SERVER_ERROR.value diff --git a/components/pm-subscription-handler/pmsh_service/mod/api/db_models.py b/components/pm-subscription-handler/pmsh_service/mod/api/db_models.py index 9ecc80e6..548e4f28 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/api/db_models.py +++ b/components/pm-subscription-handler/pmsh_service/mod/api/db_models.py @@ -52,10 +52,10 @@ class SubscriptionModel(db.Model): self.status = status def __repr__(self): - return f'subscription_name: {self.subscription_name},' \ - f'operational_policy_name: {self.operational_policy_name},' \ - f'control_loop_name: {self.control_loop_name},' \ - f'status: {self.status}' + return (f'subscription_name: {self.subscription_name}, ' + f'operational_policy_name: {self.operational_policy_name}, ' + f'control_loop_name: {self.control_loop_name}, ' + f'status: {self.status}') def __eq__(self, other): if isinstance(self, other.__class__): @@ -139,8 +139,8 @@ class NfSubRelationalModel(db.Model): self.nf_sub_status = nf_sub_status def __repr__(self): - return f'subscription_name: {self.subscription_name}, ' \ - f'nf_name: {self.nf_name}, nf_sub_status: {self.nf_sub_status}' + return (f'subscription_name: {self.subscription_name}, ' + f'nf_name: {self.nf_name}, nf_sub_status: {self.nf_sub_status}') def serialize(self): return {'subscription_name': self.subscription_name, 'nf_name': self.nf_name, @@ -183,9 +183,9 @@ class NetworkFunctionFilterModel(db.Model): self.model_names = model_names def __repr__(self): - return f'subscription_name: {self.subscription_name}, ' \ - f'nf_names: {self.nf_names}, model_invariant_ids: {self.model_invariant_ids}' \ - f'model_version_ids: {self.model_version_ids}, model_names: {self.model_names}' + return (f'subscription_name: {self.subscription_name}, ' + f'nf_names: {self.nf_names}, model_invariant_ids: {self.model_invariant_ids}, ' + f'model_version_ids: {self.model_version_ids}, model_names: {self.model_names}') def serialize(self): return {'nfNames': convert_db_string_to_list(self.nf_names), @@ -220,13 +220,13 @@ class MeasurementGroupModel(db.Model): self.managed_object_dns_basic = managed_object_dns_basic def __repr__(self): - return f'subscription_name: {self.subscription_name}, ' \ - f'measurement_group_name: {self.measurement_group_name},' \ - f'administrative_state: {self.administrative_state},' \ - f'file_based_gp: {self.file_based_gp},' \ - f'file_location: {self.file_location},' \ - f'measurement_type: {self.measurement_type}' \ - f'managed_object_dns_basic: {self.managed_object_dns_basic}' + return (f'subscription_name: {self.subscription_name}, ' + f'measurement_group_name: {self.measurement_group_name}, ' + f'administrative_state: {self.administrative_state}, ' + f'file_based_gp: {self.file_based_gp}, ' + f'file_location: {self.file_location}, ' + f'measurement_type: {self.measurement_type}, ' + f'managed_object_dns_basic: {self.managed_object_dns_basic}') def serialize(self): return {'measurementGroup': {'measurementGroupName': self.measurement_group_name, @@ -236,6 +236,28 @@ class MeasurementGroupModel(db.Model): 'measurementTypes': self.measurement_type, 'managedObjectDNsBasic': self.managed_object_dns_basic}} + def meas_group_with_nfs(self): + """ + Generates the dictionary of subscription name, measurement group name, administrative state + and network functions + + Returns: + dict: of subscription name, measurement group name, administrative state + and network functions + """ + meas_group_nfs = db.session.query(NfMeasureGroupRelationalModel).filter( + NfMeasureGroupRelationalModel.measurement_grp_name == self.measurement_group_name).all() + db.session.remove() + return {'subscriptionName': self.subscription_name, + 'measurementGroupName': self.measurement_group_name, + 'administrativeState': self.administrative_state, + 'fileBasedGP': self.file_based_gp, + 'fileLocation': self.file_location, + 'measurementTypes': self.measurement_type, + 'managedObjectDNsBasic': self.managed_object_dns_basic, + 'networkFunctions': + [meas_group_nf.serialize_meas_group_nfs() for meas_group_nf in meas_group_nfs]} + class NfMeasureGroupRelationalModel(db.Model): __tablename__ = 'nf_to_measure_grp_rel' @@ -263,8 +285,28 @@ class NfMeasureGroupRelationalModel(db.Model): self.retry_count = retry_count def __repr__(self): - return f'measurement_grp_name: {self.measurement_grp_name}, ' \ - f'nf_name: {self.nf_name}, nf_measure_grp_status: {self.nf_measure_grp_status}' + return (f'measurement_grp_name: {self.measurement_grp_name}, ' + f'nf_name: {self.nf_name}, nf_measure_grp_status: {self.nf_measure_grp_status}') + + def serialize_meas_group_nfs(self): + """ + Generates the dictionary of all the network function properties + + Returns: + dict: of network function properties + """ + nf = db.session.query(NetworkFunctionModel).filter( + NetworkFunctionModel.nf_name == self.nf_name).one_or_none() + db.session.remove() + return {'nfName': self.nf_name, + 'ipv4Address': nf.ipv4_address, + 'ipv6Address': nf.ipv6_address, + 'nfMgStatus': self.nf_measure_grp_status, + 'modelInvariantId': nf.model_invariant_id, + 'modelVersionId': nf.model_version_id, + 'modelName': nf.model_name, + 'sdncModelName': nf.sdnc_model_name, + 'sdncModelVersion': nf.sdnc_model_version} def convert_db_string_to_list(db_string): 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 39f6dc3b..4dd1cc70 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 @@ -109,6 +109,34 @@ paths: 500: description: Exception occurred while querying database + /subscription/{subscription_name}/measurementGroups/{measurement_group_name}: + get: + description: Get the measurement group and associated network functions + from PMSH by using sub name and meas group name + operationId: mod.api.controller.get_meas_group_with_nfs + tags: + - "measurement group" + parameters: + - name : subscription_name + in: path + required: true + description: Name of the subscription + type: string + - name: measurement_group_name + in: path + required: true + description: Name of the measurement group name + type: string + responses: + 200: + description: OK; Received requested measurement group with associated NF's + schema: + $ref : "#/definitions/measGroupWithNFs" + 404: + description: Measurement group with specified name not found + 500: + description: Exception occurred while querying database + definitions: subscription: type: object @@ -215,3 +243,60 @@ definitions: type: string required: - DN + + measGroupWithNFs: + type: object + properties: + subscriptionName: + type: string + measurementGroupName: + type: string + administrativeState: + type: string + enum: [ LOCKED, UNLOCKED ] + fileBasedGP: + type: integer + fileLocation: + type: string + measurementTypes: + type: array + minItems: 1 + items: + $ref: "#/definitions/measurementType" + managedObjectDNsBasic: + type: array + minItems: 1 + items: + $ref: "#/definitions/managedObjectDNs" + network_functions: + type: array + items: + type: object + properties: + nfName: + type: string + description: Name of the Network Function + ipv4Address: + type: string + description: Address of the IPV4 + ipv6Address: + type: string + description: Address of the IPV6 + nfMgStatus: + type: string + description: status of network function for one meas group + modelInvariantId: + type: string + description: ID of the model invariant + modelVersionId: + type: string + description: ID of the model version + modelName: + type: string + description: Name of the model + sdncModelName: + type: string + description: Name of the sdnc model + sdncModelVersion: + type: string + description: Version of the sdnc model diff --git a/components/pm-subscription-handler/pmsh_service/mod/api/services/measurement_group_service.py b/components/pm-subscription-handler/pmsh_service/mod/api/services/measurement_group_service.py index cc07cc03..692efe27 100644 --- a/components/pm-subscription-handler/pmsh_service/mod/api/services/measurement_group_service.py +++ b/components/pm-subscription-handler/pmsh_service/mod/api/services/measurement_group_service.py @@ -135,3 +135,20 @@ def delete_nf_to_measurement_group(nf_name, measurement_group_name, status): except Exception as e: logger.error(f'Failed to delete nf: {nf_name} for measurement group: ' f'{measurement_group_name} due to: {e}') + + +def query_meas_group_by_name(subscription_name, measurement_group_name): + """ + Retrieves the measurement group by using sub name and measurement group name + + Args: + subscription_name (String): Name of the subscription. + measurement_group_name (String): Name of the measurement group + + Returns: + MeasurementGroupModel: queried measurement group (or) None + """ + meas_group = db.session.query(MeasurementGroupModel).filter( + MeasurementGroupModel.subscription_name == subscription_name, + MeasurementGroupModel.measurement_group_name == measurement_group_name).one_or_none() + return meas_group diff --git a/components/pm-subscription-handler/tests/base_setup.py b/components/pm-subscription-handler/tests/base_setup.py index 0005be74..560eaeb8 100755 --- a/components/pm-subscription-handler/tests/base_setup.py +++ b/components/pm-subscription-handler/tests/base_setup.py @@ -23,7 +23,7 @@ from unittest.mock import patch, MagicMock from mod import create_app, db from mod.api.db_models import NetworkFunctionFilterModel, MeasurementGroupModel, \ - SubscriptionModel, NfSubRelationalModel + SubscriptionModel, NetworkFunctionModel, NfSubRelationalModel from mod.network_function import NetworkFunctionFilter from mod.pmsh_utils import AppConfig from mod.pmsh_config import AppConfig as NewAppConfig @@ -89,6 +89,26 @@ def create_multiple_subscription_data(subscription_names): return subscriptions +def create_multiple_network_function_data(nf_name_list): + """ + Creates list of network function model objects + + Args: + nf_name_list (list): Network function names + + Returns + list: of network function model objects + """ + nf_list = [] + for nf_name in nf_name_list: + nf = NetworkFunctionModel(nf_name, '10.10.10.32', '2001:0db8:0:0:0:0:1428:57ab', + '687kj45-d396-4efb-af02-6b83499b12f8', + 'e80a6ae3-cafd-4d24-850d-e14c084a5ca9', + 'model_name', 'pm_control', '1.0.2') + nf_list.append(nf) + return nf_list + + class BaseClassSetup(TestCase): app = None app_context = None diff --git a/components/pm-subscription-handler/tests/test_controller.py b/components/pm-subscription-handler/tests/test_controller.py index 77ab889c..962e8fb2 100755 --- a/components/pm-subscription-handler/tests/test_controller.py +++ b/components/pm-subscription-handler/tests/test_controller.py @@ -20,14 +20,16 @@ import os from unittest.mock import patch, MagicMock from http import HTTPStatus -from mod import aai_client -from mod.api.controller import status, post_subscription, get_subscription_by_name,\ - get_subscriptions +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 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 +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 class ControllerTestCase(BaseClassSetup): @@ -165,3 +167,35 @@ class ControllerTestCase(BaseClassSetup): def test_get_subscriptions_api_exception(self): subs, status_code = get_subscriptions() self.assertEqual(status_code, HTTPStatus.INTERNAL_SERVER_ERROR.value) + + def test_get_meas_group_with_nfs_api(self): + sub = create_subscription_data('sub1') + nf_list = create_multiple_network_function_data(['pnf101', 'pnf102']) + measurement_group_service.save_measurement_group(sub.measurement_groups[0]. + serialize()['measurementGroup'], + sub.subscription_name) + for nf in nf_list: + nf_service.save_nf(nf) + measurement_group_service. \ + apply_nf_status_to_measurement_group(nf.nf_name, sub.measurement_groups[0]. + measurement_group_name, + SubNfState.PENDING_CREATE.value) + db.session.commit() + mg_with_nfs, status_code = get_meas_group_with_nfs('sub1', 'MG1') + self.assertEqual(status_code, HTTPStatus.OK.value) + self.assertEqual(mg_with_nfs['subscriptionName'], 'sub1') + self.assertEqual(mg_with_nfs['measurementGroupName'], 'MG1') + self.assertEqual(mg_with_nfs['administrativeState'], 'UNLOCKED') + self.assertEqual(len(mg_with_nfs['networkFunctions']), 2) + + def test_get_meas_group_with_nfs_api_none(self): + error, status_code = get_meas_group_with_nfs('sub1', 'MG1') + self.assertEqual(error['error'], 'measurement group was not defined with ' + 'the sub name: sub1 and meas group name: MG1') + self.assertEqual(status_code, HTTPStatus.NOT_FOUND.value) + + @patch('mod.api.services.measurement_group_service.query_meas_group_by_name', + MagicMock(side_effect=Exception('something failed'))) + 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) -- cgit 1.2.3-korg