summaryrefslogtreecommitdiffstats
path: root/components/pm-subscription-handler/pmsh_service
diff options
context:
space:
mode:
authorSagarS <sagar.shetty@est.tech>2022-01-27 15:05:50 +0000
committerSagarS <sagar.shetty@est.tech>2022-02-07 18:04:39 +0000
commit2a21c78886d13c4266da639252d8fb899b7d34a5 (patch)
treeea006b6db878c6635f3f96479c19769f9f3e0e87 /components/pm-subscription-handler/pmsh_service
parent5b11f4ff05cf4bd3f042a4c531848b939e4ead8a (diff)
[DCAEGEN2] Update Administrative status for measurement group2.0.0-pmsh
Issue-ID: DCAEGEN2-2820 Change-Id: I290693edc5061c21bab6e0706eda02acb52e38e1 Signed-off-by: SagarS <sagar.shetty@est.tech>
Diffstat (limited to 'components/pm-subscription-handler/pmsh_service')
-rwxr-xr-xcomponents/pm-subscription-handler/pmsh_service/mod/api/controller.py47
-rw-r--r--components/pm-subscription-handler/pmsh_service/mod/api/custom_exception.py17
-rwxr-xr-xcomponents/pm-subscription-handler/pmsh_service/mod/api/db_models.py4
-rw-r--r--components/pm-subscription-handler/pmsh_service/mod/api/pmsh_swagger.yml39
-rw-r--r--components/pm-subscription-handler/pmsh_service/mod/api/services/measurement_group_service.py145
-rw-r--r--components/pm-subscription-handler/pmsh_service/mod/api/services/subscription_service.py2
-rw-r--r--components/pm-subscription-handler/pmsh_service/mod/policy_response_handler.py4
7 files changed, 239 insertions, 19 deletions
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 d887187a..96fb1b79 100755
--- a/components/pm-subscription-handler/pmsh_service/mod/api/controller.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/api/controller.py
@@ -20,7 +20,8 @@ from http import HTTPStatus
from mod import logger
from mod.api.services import subscription_service, measurement_group_service
from connexion import NoContent
-from mod.api.custom_exception import InvalidDataException, DuplicateDataException
+from mod.api.custom_exception import InvalidDataException, DuplicateDataException, \
+ DataConflictException
def status():
@@ -58,12 +59,12 @@ def post_subscription(body):
logger.error(f'Failed to create subscription for '
f'{body["subscription"]["subscriptionName"]} due to duplicate data: {e}',
exc_info=True)
- response = e.duplicate_field_info, HTTPStatus.CONFLICT.value
+ response = e.args[0], HTTPStatus.CONFLICT.value
except InvalidDataException as e:
logger.error(f'Failed to create subscription for '
f'{body["subscription"]["subscriptionName"]} due to invalid data: {e}',
exc_info=True)
- response = e.invalid_message, HTTPStatus.BAD_REQUEST.value
+ response = e.args[0], HTTPStatus.BAD_REQUEST.value
return response
@@ -186,3 +187,43 @@ def delete_subscription_by_name(subscription_name):
return {'error': f'Try again, subscription with name {subscription_name}'
f'is not deleted due to following exception: {exception}'}, \
HTTPStatus.INTERNAL_SERVER_ERROR.value
+
+
+def update_admin_state(subscription_name, measurement_group_name, body):
+ """
+ Performs administrative state update for the respective subscription
+ and measurement group name
+
+ Args:
+ subscription_name (String): Name of the subscription.
+ measurement_group_name (String): Name of the measurement group
+ body (dict): Request body with admin state to update.
+ Returns:
+ string, HTTPStatus: Successfully updated admin state, 200
+ string, HTTPStatus: Invalid request details, 400
+ string, HTTPStatus: Cannot update as Locked request is in progress, 409
+ string, HTTPStatus: Exception details of server failure, 500
+ """
+ logger.info('Performing administration status update for measurement group '
+ f'with sub name: {subscription_name} and measurement '
+ f'group name: {measurement_group_name} to {body["administrativeState"]} status')
+ response = 'Successfully updated admin state', HTTPStatus.OK.value
+ try:
+ meas_group = measurement_group_service.query_meas_group_by_name(subscription_name,
+ measurement_group_name)
+ measurement_group_service.update_admin_status(meas_group, body["administrativeState"])
+ except InvalidDataException as exception:
+ logger.error(exception.args[0])
+ response = exception.args[0], HTTPStatus.BAD_REQUEST.value
+ except DataConflictException as exception:
+ logger.error(exception.args[0])
+ response = exception.args[0], HTTPStatus.CONFLICT.value
+ except Exception as exception:
+ logger.error('Update admin status request was not processed for sub name: '
+ f'{subscription_name} and meas group name: '
+ f'{measurement_group_name} due to Exception : {exception}')
+ response = 'Update admin status request was not processed for sub name: '\
+ f'{subscription_name} and meas group name: {measurement_group_name}'\
+ f' due to Exception : {exception}', HTTPStatus.INTERNAL_SERVER_ERROR
+
+ return response
diff --git a/components/pm-subscription-handler/pmsh_service/mod/api/custom_exception.py b/components/pm-subscription-handler/pmsh_service/mod/api/custom_exception.py
index 606d500c..2bee3ff9 100644
--- a/components/pm-subscription-handler/pmsh_service/mod/api/custom_exception.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/api/custom_exception.py
@@ -1,5 +1,5 @@
# ============LICENSE_START===================================================
-# Copyright (C) 2021 Nordix Foundation.
+# Copyright (C) 2021-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.
@@ -24,7 +24,7 @@ class InvalidDataException(Exception):
"""
def __init__(self, invalid_message):
- self.invalid_message = invalid_message
+ super().__init__(invalid_message)
class DuplicateDataException(Exception):
@@ -35,4 +35,15 @@ class DuplicateDataException(Exception):
"""
def __init__(self, duplicate_field_info):
- self.duplicate_field_info = duplicate_field_info
+ super().__init__(duplicate_field_info)
+
+
+class DataConflictException(Exception):
+ """Exception raised for conflicting data state in PMSH.
+
+ Attributes:
+ message -- detail on conflicting data
+ """
+
+ def __init__(self, data_conflict_message):
+ super().__init__(data_conflict_message)
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 548e4f28..2eccbac1 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
@@ -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.
@@ -149,7 +149,6 @@ class NfSubRelationalModel(db.Model):
def serialize_nf(self):
nf = NetworkFunctionModel.query.filter(
NetworkFunctionModel.nf_name == self.nf_name).one_or_none()
- db.session.remove()
return {'nf_name': self.nf_name,
'ipv4_address': nf.ipv4_address,
'ipv6_address': nf.ipv6_address,
@@ -297,7 +296,6 @@ class NfMeasureGroupRelationalModel(db.Model):
"""
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,
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 3319b7ef..1c4c7927 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
@@ -112,6 +112,8 @@ paths:
delete:
description: Deletes the Subscription from PMSH specified by Name
operationId: mod.api.controller.delete_subscription_by_name
+ tags:
+ - "Subscription"
parameters:
- name: subscription_name
in: path
@@ -136,7 +138,7 @@ paths:
from PMSH by using sub name and meas group name
operationId: mod.api.controller.get_meas_group_with_nfs
tags:
- - "measurement group"
+ - "Measurement Group"
parameters:
- name : subscription_name
in: path
@@ -158,6 +160,41 @@ paths:
500:
description: Exception occurred while querying database
+ /subscription/{subscription_name}/measurementGroups/{measurement_group_name}/adminState:
+ put:
+ description: Update the admin status of the Measurement Group by using sub name and measurement group name
+ operationId: mod.api.controller.update_admin_state
+ 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
+ type: string
+ - in: "body"
+ name: "body"
+ required: true
+ schema:
+ properties:
+ administrativeState:
+ type: string
+ enum: [ LOCKED, UNLOCKED ]
+ responses:
+ 200:
+ description: Successfully updated admin state
+ 409:
+ description: Cannot update as Locked request is in progress
+ 400:
+ description: Invalid input request details
+ 500:
+ description: Exception details of server failure
+
definitions:
subscription:
type: object
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 692efe27..a1c141f8 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
@@ -1,5 +1,5 @@
# ============LICENSE_START===================================================
-# Copyright (C) 2021 Nordix Foundation.
+# Copyright (C) 2021-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.
@@ -16,11 +16,14 @@
# SPDX-License-Identifier: Apache-2.0
# ============LICENSE_END=====================================================
-from mod.api.db_models import MeasurementGroupModel, NfMeasureGroupRelationalModel
+from mod.api.custom_exception import InvalidDataException, DataConflictException
+from mod.api.db_models import MeasurementGroupModel, NfMeasureGroupRelationalModel, \
+ SubscriptionModel
from mod import db, logger
-from mod.api.services import nf_service
+from mod.api.services import nf_service, subscription_service
from mod.network_function import NetworkFunction
from mod.pmsh_config import MRTopic, AppConfig
+from mod.subscription import AdministrativeState, SubNfState
def save_measurement_group(measurement_group, subscription_name):
@@ -64,16 +67,17 @@ def apply_nf_status_to_measurement_group(nf_name, measurement_group_name, status
db.session.add(new_nf_measure_grp_rel)
-def publish_measurement_group(sub_model, measurement_group, nf):
+def publish_measurement_group(sub_model, measurement_group, nf, change_type):
"""
Publishes an event for measurement group against nfs to MR
Args:
sub_model(SubscriptionModel): Subscription model object
measurement_group (MeasurementGroupModel): Measurement group to publish
- nf (NetworkFunction): Network function to publish.
+ nf (NetworkFunction): Network function to publish
+ change_type (string): defines event type like CREATE or DELETE
"""
- event_body = nf_service.create_nf_event_body(nf, 'CREATE', sub_model)
+ event_body = nf_service.create_nf_event_body(nf, change_type, sub_model)
event_body['subscription'] = {
"administrativeState": measurement_group.administrative_state,
"subscriptionName": sub_model.subscription_name,
@@ -152,3 +156,132 @@ def query_meas_group_by_name(subscription_name, measurement_group_name):
MeasurementGroupModel.subscription_name == subscription_name,
MeasurementGroupModel.measurement_group_name == measurement_group_name).one_or_none()
return meas_group
+
+
+def lock_nf_to_meas_grp(nf_name, measurement_group_name, status):
+ """ Deletes a particular nf related to a measurement group name and
+ if no more relations of nf exist to measurement group then delete nf from PMSH
+
+ Args:
+ nf_name (string): The network function name
+ measurement_group_name (string): Measurement group name
+ status (string): status of the network function for measurement group
+ """
+ try:
+ delete_nf_to_measurement_group(nf_name, measurement_group_name, status)
+ nf_measurement_group_rels = NfMeasureGroupRelationalModel.query.filter(
+ NfMeasureGroupRelationalModel.measurement_grp_name == measurement_group_name).all()
+ if not nf_measurement_group_rels:
+ MeasurementGroupModel.query.filter(
+ MeasurementGroupModel.measurement_group_name == measurement_group_name). \
+ update({MeasurementGroupModel.administrative_state: AdministrativeState.
+ LOCKED.value}, synchronize_session='evaluate')
+ db.session.commit()
+ except Exception as e:
+ logger.error('Failed update LOCKED status for measurement group name: '
+ f'{measurement_group_name} due to: {e}')
+
+
+def deactivate_nfs(sub_model, measurement_group, nf_meas_relations):
+ """
+ Deactivates network functions associated with measurement group
+
+ Args:
+ sub_model (SubscriptionModel): Subscription model
+ measurement_group (MeasurementGroupModel): Measurement group to update
+ nf_meas_relations (list[NfMeasureGroupRelationalModel]): nf to measurement grp relations
+ """
+ for nf in nf_meas_relations:
+ logger.info(f'Saving measurement group to nf name, measure_grp_name: {nf.nf_name},'
+ f'{measurement_group.measurement_group_name} with DELETE request')
+ update_measurement_group_nf_status(measurement_group.measurement_group_name,
+ SubNfState.PENDING_DELETE.value, nf.nf_name)
+ try:
+ network_function = NetworkFunction(**nf.serialize_meas_group_nfs())
+ logger.info(f'Publishing event for nf name, measure_grp_name: {nf.nf_name},'
+ f'{measurement_group.measurement_group_name} with DELETE request')
+ publish_measurement_group(sub_model, measurement_group, network_function, 'DELETE')
+ except Exception as ex:
+ logger.error(f'Publish event failed for nf name, measure_grp_name, sub_name: '
+ f'{nf.nf_name},{measurement_group.measurement_group_name}, '
+ f'{sub_model.subscription_name} with error: {ex}')
+
+
+def activate_nfs(sub_model, measurement_group):
+ """
+ Activates network functions associated with measurement group
+
+ Args:
+ sub_model (SubscriptionModel): Subscription model
+ measurement_group (MeasurementGroupModel): Measurement group to update
+ """
+ new_nfs = []
+ sub_nf_names = [nf.nf_name for nf in sub_model.nfs]
+ filtered_nfs = nf_service.capture_filtered_nfs(sub_model.subscription_name)
+ for nf in filtered_nfs:
+ if nf.nf_name not in sub_nf_names:
+ new_nfs.append(nf)
+ if new_nfs:
+ logger.info(f'Adding new nfs to the subscription: '
+ f'{sub_model.subscription_name}')
+ subscription_service.save_filtered_nfs(new_nfs)
+ subscription_service.apply_subscription_to_nfs(new_nfs,
+ sub_model.subscription_name)
+ for nf in filtered_nfs:
+ logger.info(f'Saving measurement group to nf name, measure_grp_name: {nf.nf_name},'
+ f'{measurement_group.measurement_group_name} with CREATE request')
+
+ apply_nf_status_to_measurement_group(nf.nf_name,
+ measurement_group.measurement_group_name,
+ SubNfState.PENDING_CREATE.value)
+ db.session.commit()
+ try:
+ network_function = NetworkFunction(**nf.serialize_nf())
+ logger.info(f'Publishing event for nf name, measure_grp_name: {nf.nf_name},'
+ f'{measurement_group.measurement_group_name} with CREATE request')
+ publish_measurement_group(sub_model, measurement_group, network_function, 'CREATE')
+ except Exception as ex:
+ logger.error(f'Publish event failed for nf name, measure_grp_name, sub_name: '
+ f'{nf.nf_name},{measurement_group.measurement_group_name}, '
+ f'{sub_model.subscription_name} with error: {ex}')
+
+
+def update_admin_status(measurement_group, status):
+ """
+ Performs administrative status updates for the measurement group
+
+ Args:
+ measurement_group (MeasurementGroupModel): Measurement group to update
+ status (string): Admin status to update for measurement group
+
+ Raises:
+ InvalidDataException: contains details on invalid fields
+ DataConflictException: contains details on conflicting state of a field
+ Exception: contains runtime error details
+ """
+ if measurement_group is None:
+ raise InvalidDataException('Requested measurement group not available '
+ 'for admin status update')
+ elif measurement_group.administrative_state == AdministrativeState.LOCKING.value:
+ raise DataConflictException('Cannot update admin status as Locked request is in progress'
+ f' for sub name: {measurement_group.subscription_name} and '
+ f'meas group name: {measurement_group.measurement_group_name}')
+ elif measurement_group.administrative_state == status:
+ raise InvalidDataException(f'Measurement group is already in {status} state '
+ f'for sub name: {measurement_group.subscription_name} and '
+ f'meas group name: {measurement_group.measurement_group_name}')
+ else:
+ sub_model = SubscriptionModel.query.filter(
+ SubscriptionModel.subscription_name == measurement_group.subscription_name) \
+ .one_or_none()
+ nf_meas_relations = NfMeasureGroupRelationalModel.query.filter(
+ NfMeasureGroupRelationalModel.measurement_grp_name == measurement_group.
+ measurement_group_name).all()
+ if nf_meas_relations and status == AdministrativeState.LOCKED.value:
+ status = AdministrativeState.LOCKING.value
+ measurement_group.administrative_state = status
+ db.session.commit()
+ if status == AdministrativeState.LOCKING.value:
+ deactivate_nfs(sub_model, measurement_group, nf_meas_relations)
+ elif status == AdministrativeState.UNLOCKED.value:
+ activate_nfs(sub_model, measurement_group)
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 7b31de50..338ab89e 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
@@ -89,7 +89,7 @@ def publish_measurement_grp_to_nfs(sub_model, filtered_nfs,
logger.info(f'Publishing event for nf name, measure_grp_name: {nf.nf_name},'
f'{measurement_group.measurement_group_name}')
measurement_group_service.publish_measurement_group(
- sub_model, measurement_group, nf)
+ sub_model, measurement_group, nf, 'CREATE')
except Exception as ex:
logger.error(f'Publish event failed for nf name, measure_grp_name, sub_name: '
f'{nf.nf_name},{measurement_group.measurement_group_name}, '
diff --git a/components/pm-subscription-handler/pmsh_service/mod/policy_response_handler.py b/components/pm-subscription-handler/pmsh_service/mod/policy_response_handler.py
index 1bc58081..a0a7bd67 100644
--- a/components/pm-subscription-handler/pmsh_service/mod/policy_response_handler.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/policy_response_handler.py
@@ -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.
@@ -32,7 +32,7 @@ policy_response_handle_functions = {
'failed': measurement_group_service.update_measurement_group_nf_status
},
AdministrativeState.LOCKING.value: {
- 'success': measurement_group_service.delete_nf_to_measurement_group,
+ 'success': measurement_group_service.lock_nf_to_meas_grp,
'failed': measurement_group_service.update_measurement_group_nf_status
}
}