summaryrefslogtreecommitdiffstats
path: root/components/pm-subscription-handler/pmsh_service
diff options
context:
space:
mode:
authorSagarS <sagar.shetty@est.tech>2022-02-24 17:07:01 +0000
committerSagarS <sagar.shetty@est.tech>2022-03-02 13:47:51 +0000
commit5f69c24ad78121a2840b5299583791e557f8b535 (patch)
tree22e84dc45427065d7bfa35e2ee0dcc80311a0753 /components/pm-subscription-handler/pmsh_service
parent37762006756658532012d9b8e4286e80acb612c4 (diff)
[PMSH] Update Filter API
Issue-ID: DCAEGEN2-2922 Change-Id: Ibf0ef167642027429b3ba91daea60228cf5fa4c6 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.py33
-rw-r--r--components/pm-subscription-handler/pmsh_service/mod/api/pmsh_swagger.yml31
-rw-r--r--components/pm-subscription-handler/pmsh_service/mod/api/services/measurement_group_service.py33
-rw-r--r--components/pm-subscription-handler/pmsh_service/mod/api/services/nf_service.py21
-rw-r--r--components/pm-subscription-handler/pmsh_service/mod/api/services/subscription_service.py226
-rw-r--r--components/pm-subscription-handler/pmsh_service/mod/policy_response_handler.py23
-rwxr-xr-xcomponents/pm-subscription-handler/pmsh_service/mod/subscription.py3
7 files changed, 320 insertions, 50 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 de3aa5f3..57d3e021 100755
--- a/components/pm-subscription-handler/pmsh_service/mod/api/controller.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/api/controller.py
@@ -267,3 +267,36 @@ def update_admin_state(subscription_name, measurement_group_name, body):
f' due to Exception : {exception}', HTTPStatus.INTERNAL_SERVER_ERROR
return response
+
+
+def put_nf_filter(subscription_name, body):
+ """
+ Performs network function filter update for the respective subscription
+
+ Args:
+ subscription_name (String): Name of the subscription.
+ body (dict): Request body with nf filter data to update.
+ Returns:
+ string, HTTPStatus: Successfully updated network function Filter, 200
+ string, HTTPStatus: Invalid request details, 400
+ string, HTTPStatus: Cannot update as Locked/Filtering request is in progress, 409
+ string, HTTPStatus: Exception details of server failure, 500
+ """
+ logger.info('Performing network function filter update for subscription '
+ f'with sub name: {subscription_name} ')
+ response = 'Successfully updated network function Filter', HTTPStatus.OK.value
+ try:
+ subscription_service.update_filter(subscription_name, body)
+ 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 nf filter request was not processed for sub name: '
+ f'{subscription_name} due to Exception : {exception}')
+ response = 'Update nf filter request was not processed for sub name: ' \
+ f'{subscription_name} due to Exception : {exception}', \
+ HTTPStatus.INTERNAL_SERVER_ERROR
+ return response
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 274e0ebb..1f24f171 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
@@ -131,6 +131,33 @@ paths:
500:
description: Exception occurred on the server
+ /subscription/{subscription_name}/nfFilter:
+ put:
+ tags:
+ - "Subscription"
+ description: >-
+ Update a Subscription nf filter
+ operationId: mod.api.controller.put_nf_filter
+ parameters:
+ - name: subscription_name
+ in: path
+ required: true
+ description: The name of the subscription to update nf filters
+ type: string
+ - in: "body"
+ name: "body"
+ required: true
+ schema:
+ $ref: "#/definitions/nfFilter"
+ responses:
+ 201:
+ description: Successfully updated nf filter
+ 409:
+ description: Conflicting data
+ 400:
+ description: Invalid input
+ 500:
+ description: Exception occurred while querying database
/subscription/{subscription_name}/measurementGroups/{measurement_group_name}:
get:
@@ -162,9 +189,9 @@ paths:
delete:
description: Delete a measurement group
- operationId: mod.api.controller.delete_meas_group
+ operationId: mod.api.controller.delete_meas_group_by_name
tags:
- - "measurement group"
+ - "Measurement Group"
parameters:
- name : subscription_name
in: path
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 b272e5b8..07d1b642 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
@@ -24,6 +24,7 @@ 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
+from sqlalchemy import or_
def save_measurement_group(measurement_group, subscription_name):
@@ -318,3 +319,35 @@ def update_admin_status(measurement_group, status):
deactivate_nfs(sub_model, measurement_group, nf_meas_relations)
elif status == AdministrativeState.UNLOCKED.value:
activate_nfs(sub_model, measurement_group)
+
+
+def filter_nf_to_meas_grp(nf_name, measurement_group_name, status):
+ """ Performs successful status update for a nf under filter update
+ request for a particular subscription and measurement group
+
+ 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:
+ if status == SubNfState.DELETED.value:
+ delete_nf_to_measurement_group(nf_name, measurement_group_name,
+ SubNfState.DELETED.value)
+ elif status == SubNfState.CREATED.value:
+ update_measurement_group_nf_status(measurement_group_name,
+ SubNfState.CREATED.value, nf_name)
+ nf_measurement_group_rels = NfMeasureGroupRelationalModel.query.filter(
+ NfMeasureGroupRelationalModel.measurement_grp_name == measurement_group_name,
+ or_(NfMeasureGroupRelationalModel.nf_measure_grp_status.like('PENDING_%'),
+ NfMeasureGroupRelationalModel.nf_measure_grp_status.like('%_FAILED'))
+ ).all()
+ if not nf_measurement_group_rels:
+ MeasurementGroupModel.query.filter(
+ MeasurementGroupModel.measurement_group_name == measurement_group_name). \
+ update({MeasurementGroupModel.administrative_state: AdministrativeState.
+ UNLOCKED.value}, synchronize_session='evaluate')
+ db.session.commit()
+ except Exception as e:
+ logger.error('Failed update filter response for measurement group name: '
+ f'{measurement_group_name}, nf name: {nf_name} due to: {e}')
diff --git a/components/pm-subscription-handler/pmsh_service/mod/api/services/nf_service.py b/components/pm-subscription-handler/pmsh_service/mod/api/services/nf_service.py
index ce463ed0..a3c2a036 100644
--- a/components/pm-subscription-handler/pmsh_service/mod/api/services/nf_service.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/api/services/nf_service.py
@@ -17,7 +17,7 @@
# ============LICENSE_END=====================================================
from mod import db, aai_client, logger
-from mod.api.db_models import NetworkFunctionModel
+from mod.api.db_models import NetworkFunctionModel, NetworkFunctionFilterModel
from mod.pmsh_config import AppConfig
from mod.network_function import NetworkFunctionFilter
@@ -74,3 +74,22 @@ def save_nf(nf):
sdnc_model_name=nf.sdnc_model_name,
sdnc_model_version=nf.sdnc_model_version)
db.session.add(network_function)
+
+
+def save_nf_filter_update(sub_name, nf_filter):
+ """
+ Updates the network function filter for the subscription in the db
+
+ Args:
+ sub_name (String): Name of the Subscription
+ nf_filter (dict): filter object to update in the subscription
+ """
+ NetworkFunctionFilterModel.query.filter(
+ NetworkFunctionFilterModel.subscription_name == sub_name). \
+ update({NetworkFunctionFilterModel.nf_names: nf_filter['nfNames'],
+ NetworkFunctionFilterModel.model_invariant_ids: nf_filter['modelInvariantIDs'],
+ NetworkFunctionFilterModel.model_version_ids: nf_filter['modelVersionIDs'],
+ NetworkFunctionFilterModel.model_names: nf_filter['modelNames']},
+ synchronize_session='evaluate')
+ db.session.commit()
+ logger.info(f'Successfully saved filter for subscription: {sub_name}')
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 338ab89e..032fc4a0 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,9 +18,11 @@
from mod import db, logger
from mod.api.db_models import SubscriptionModel, NfSubRelationalModel, \
- NetworkFunctionFilterModel, NetworkFunctionModel, MeasurementGroupModel
+ NetworkFunctionFilterModel, NetworkFunctionModel, MeasurementGroupModel, \
+ NfMeasureGroupRelationalModel
from mod.api.services import measurement_group_service, nf_service
-from mod.api.custom_exception import InvalidDataException, DuplicateDataException
+from mod.api.custom_exception import InvalidDataException, DuplicateDataException, \
+ DataConflictException
from mod.subscription import AdministrativeState, SubNfState
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import joinedload
@@ -40,32 +42,16 @@ def create_subscription(subscription):
logger.info(f'Initiating create subscription for: {subscription["subscriptionName"]}')
perform_validation(subscription)
try:
- sub_model, measurement_groups = save_subscription_request(subscription)
+ sub_model = save_subscription_request(subscription)
db.session.commit()
logger.info(f'Successfully saved subscription request for: '
f'{subscription["subscriptionName"]}')
filtered_nfs = nf_service.capture_filtered_nfs(sub_model.subscription_name)
- if filtered_nfs:
- logger.info(f'Applying the filtered nfs for subscription: '
- f'{sub_model.subscription_name}')
- save_filtered_nfs(filtered_nfs)
- apply_subscription_to_nfs(filtered_nfs, sub_model.subscription_name)
- unlocked_msmt_groups = apply_measurement_grp_to_nfs(filtered_nfs, measurement_groups)
- db.session.commit()
- if unlocked_msmt_groups:
- publish_measurement_grp_to_nfs(sub_model, filtered_nfs,
- unlocked_msmt_groups)
- else:
- logger.error(f'All measurement groups are locked for subscription: '
- f'{sub_model.subscription_name}, '
- f'please verify/check measurement groups.')
- else:
- logger.error(f'No network functions found for subscription: '
- f'{sub_model.subscription_name}, '
- f'please verify/check NetworkFunctionFilter.')
+ unlocked_mgs = get_unlocked_measurement_grps(sub_model)
+ add_new_filtered_nfs(filtered_nfs, unlocked_mgs, sub_model)
except IntegrityError as e:
db.session.rollback()
- raise DuplicateDataException(f'DB Integrity issue encountered: {e.orig.args[0]}')
+ raise DuplicateDataException(f'DB Integrity issue encountered: {e.orig.args[0]}') from e
except Exception as e:
db.session.rollback()
raise e
@@ -73,6 +59,36 @@ def create_subscription(subscription):
db.session.remove()
+def add_new_filtered_nfs(filtered_nfs, unlocked_mgs, sub_model):
+ """
+ Inserts the filtered nfs in measurement groups of subscription
+
+ Args:
+ filtered_nfs (List[NetworkFunction]): nfs to be inserted
+ unlocked_mgs (List[MeasurementGroupModel]): mgs to be updated with new nfs
+ sub_model (SubscriptionModel): subscription model to update
+ """
+ if filtered_nfs:
+ logger.info(f'Applying the filtered nfs for subscription: '
+ f'{sub_model.subscription_name}')
+ save_filtered_nfs(filtered_nfs)
+ apply_subscription_to_nfs(filtered_nfs, sub_model.subscription_name)
+ db.session.commit()
+ if unlocked_mgs:
+ apply_measurement_grp_to_nfs(filtered_nfs, unlocked_mgs)
+ db.session.commit()
+ publish_measurement_grp_to_nfs(sub_model, filtered_nfs,
+ unlocked_mgs)
+ else:
+ logger.error(f'All measurement groups are locked for subscription: '
+ f'{sub_model.subscription_name}, '
+ f'please verify/check measurement groups.')
+ else:
+ logger.error(f'No network functions found for subscription: '
+ f'{sub_model.subscription_name}, '
+ f'please verify/check NetworkFunctionFilter.')
+
+
def publish_measurement_grp_to_nfs(sub_model, filtered_nfs,
measurement_groups):
"""
@@ -124,32 +140,22 @@ def apply_subscription_to_nfs(filtered_nfs, subscription_name):
db.session.add(new_nf_sub_rel)
-def apply_measurement_grp_to_nfs(filtered_nfs, measurement_groups):
+def apply_measurement_grp_to_nfs(filtered_nfs, unlocked_mgs):
"""
Saves measurement groups against nfs with status as PENDING_CREATE
Args:
filtered_nfs (list[NetworkFunction]): list of filtered network functions
- measurement_groups (list[MeasurementGroupModel]): list of measurement group
+ unlocked_mgs (list[MeasurementGroupModel]): list of measurement group
- Returns:
- list[MeasurementGroupModel]: list of Unlocked measurement groups
"""
- unlocked_msmt_groups = []
- for measurement_group in measurement_groups:
- if measurement_group.administrative_state \
- == AdministrativeState.UNLOCKED.value:
- unlocked_msmt_groups.append(measurement_group)
- 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}')
- measurement_group_service.apply_nf_status_to_measurement_group(
- nf.nf_name, measurement_group.measurement_group_name,
- SubNfState.PENDING_CREATE.value)
- else:
- logger.info(f'No nfs added as measure_grp_name: '
- f'{measurement_group.measurement_group_name} is LOCKED')
- return unlocked_msmt_groups
+ for measurement_group in unlocked_mgs:
+ 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}')
+ measurement_group_service.apply_nf_status_to_measurement_group(
+ nf.nf_name, measurement_group.measurement_group_name,
+ SubNfState.PENDING_CREATE.value)
def check_missing_data(subscription):
@@ -217,7 +223,7 @@ def save_subscription_request(subscription):
measurement_group_service.save_measurement_group(
measurement_group['measurementGroup'],
subscription["subscriptionName"]))
- return sub_model, measurement_groups
+ return sub_model
def check_duplicate_fields(subscription_name):
@@ -380,3 +386,139 @@ def query_to_delete_subscription_by_name(subscription_name):
.filter_by(subscription_name=subscription_name).delete()
db.session.commit()
return effected_rows
+
+
+def is_duplicate_filter(nf_filter, db_network_filter):
+ """
+ Checks if the network function filter is unchanged for the subscription
+
+ Args:
+ nf_filter (dict): filter object to update in the subscription
+ db_network_filter (NetworkFunctionFilterModel): nf filter object from db
+
+ Returns:
+ (boolean) : True is nf filters are same else False
+ """
+ return nf_filter == db_network_filter.serialize()
+
+
+def update_filter(sub_name, nf_filter):
+ """
+ Updates the network function filter for the subscription
+
+ Args:
+ sub_name (String): Name of the Subscription
+ nf_filter (dict): filter object to update in the subscription
+
+ Returns:
+ InvalidDataException: contains details on invalid fields
+ DataConflictException: contains details on conflicting state of a field
+ Exception: contains runtime error details
+ """
+ sub_model = query_subscription_by_name(sub_name)
+ if sub_model is None:
+ raise InvalidDataException('Requested subscription is not available '
+ f'with sub name: {sub_name} for nf filter update')
+ if is_duplicate_filter(nf_filter, sub_model.network_filter):
+ raise InvalidDataException('Duplicate nf filter update requested for subscription '
+ f'with sub name: {sub_name}')
+ validate_sub_mgs_state(sub_model)
+ nf_service.save_nf_filter_update(sub_name, nf_filter)
+ del_nfs, new_nfs = extract_del_new_nfs(sub_model)
+ NfSubRelationalModel.query.filter(
+ NfSubRelationalModel.subscription_name == sub_name,
+ NfSubRelationalModel.nf_name.in_(del_nfs)).delete()
+ db.session.commit()
+ unlocked_mgs = get_unlocked_measurement_grps(sub_model)
+ if unlocked_mgs:
+ add_new_filtered_nfs(new_nfs, unlocked_mgs, sub_model)
+ delete_filtered_nfs(del_nfs, sub_model, unlocked_mgs)
+ db.session.remove()
+
+
+def get_unlocked_measurement_grps(sub_model):
+ """
+ Gets unlocked measurement groups and logs locked measurement groups
+
+ Args:
+ sub_model (SubscriptionModel): Subscription model to perform nfs delete
+
+ Returns:
+ unlocked_mgs (List[MeasurementGroupModel]): unlocked msgs in a subscription
+
+ """
+ unlocked_mgs = []
+ for measurement_group in sub_model.measurement_groups:
+ if measurement_group.administrative_state \
+ == AdministrativeState.UNLOCKED.value:
+ unlocked_mgs.append(measurement_group)
+ else:
+ logger.info(f'No nfs added as measure_grp_name: '
+ f'{measurement_group.measurement_group_name} is LOCKED')
+ return unlocked_mgs
+
+
+def delete_filtered_nfs(del_nfs, sub_model, unlocked_mgs):
+ """
+ Removes unfiltered nfs
+
+ Args:
+ del_nfs (List[String]): Names of nfs to be deleted
+ sub_model (SubscriptionModel): Subscription model to perform nfs delete
+ unlocked_mgs (List[MeasurementGroupModel]): unlocked msgs to perform nfs delete
+
+ """
+ if del_nfs:
+ logger.info(f'Removing nfs from subscription: '
+ f'{sub_model.subscription_name}')
+ for mg in unlocked_mgs:
+ MeasurementGroupModel.query.filter(
+ MeasurementGroupModel.measurement_group_name == mg.measurement_group_name) \
+ .update({MeasurementGroupModel.administrative_state: AdministrativeState.
+ FILTERING.value}, synchronize_session='evaluate')
+ db.session.commit()
+ nf_meas_relations = NfMeasureGroupRelationalModel.query.filter(
+ NfMeasureGroupRelationalModel.measurement_grp_name == mg.
+ measurement_group_name, NfMeasureGroupRelationalModel.
+ nf_name.in_(del_nfs)).all()
+ measurement_group_service.deactivate_nfs(sub_model, mg, nf_meas_relations)
+
+
+def extract_del_new_nfs(sub_model):
+ """
+ Captures nfs to be deleted and created for the subscription
+
+ Args:
+ sub_model (SubscriptionModel): Subscription model to perform nfs delete
+
+ Returns:
+ del_nfs (List[String]): Names of nfs to be deleted
+ new_nfs (List[NetworkFunction]): nfs to be inserted
+ """
+ filtered_nfs = nf_service.capture_filtered_nfs(sub_model.subscription_name)
+ filtered_nf_names = [nf.nf_name for nf in filtered_nfs]
+ existing_nf_names = [nf.nf_name for nf in sub_model.nfs]
+ new_nfs = list(filter(lambda x: x.nf_name not in existing_nf_names, filtered_nfs))
+ del_nfs = [nf.nf_name for nf in sub_model.nfs if nf.nf_name not in filtered_nf_names]
+ return del_nfs, new_nfs
+
+
+def validate_sub_mgs_state(sub_model):
+ """
+ Validates if any measurement group in subscription has
+ status Locking or Filtering
+
+ Args:
+ sub_model (SubscriptionModel): Subscription model to perform validation before nf filter
+
+ Returns:
+ DataConflictException: contains details on conflicting status in measurement group
+ """
+ mg_names_processing = [mg for mg in sub_model.measurement_groups
+ if mg.administrative_state in [AdministrativeState.FILTERING.value,
+ AdministrativeState.LOCKING.value]]
+ if mg_names_processing:
+ raise DataConflictException('Cannot update filter as subscription: '
+ f'{sub_model.subscription_name} is under '
+ 'transitioning state for the following measurement '
+ f'groups: {mg_names_processing}')
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 a0a7bd67..5065ce8a 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
@@ -18,8 +18,8 @@
import json
from mod.pmsh_config import MRTopic, AppConfig
from mod import logger
-from mod.subscription import AdministrativeState, subscription_nf_states
-from mod.api.db_models import MeasurementGroupModel
+from mod.subscription import AdministrativeState, subscription_nf_states, SubNfState
+from mod.api.db_models import MeasurementGroupModel, NfMeasureGroupRelationalModel
from mod.api.services import measurement_group_service
policy_response_handle_functions = {
@@ -34,6 +34,10 @@ policy_response_handle_functions = {
AdministrativeState.LOCKING.value: {
'success': measurement_group_service.lock_nf_to_meas_grp,
'failed': measurement_group_service.update_measurement_group_nf_status
+ },
+ AdministrativeState.FILTERING.value: {
+ 'success': measurement_group_service.filter_nf_to_meas_grp,
+ 'failed': measurement_group_service.update_measurement_group_nf_status
}
}
@@ -86,8 +90,19 @@ class PolicyResponseHandler:
logger.info(f'Response from MR: measurement group name: {measurement_group_name} for '
f'NF: {nf_name} received, updating the DB')
try:
- nf_measure_grp_status = subscription_nf_states[administrative_state][response_message]\
- .value
+
+ if administrative_state == AdministrativeState.FILTERING.value:
+ nf_msg_rel = NfMeasureGroupRelationalModel.query.filter(
+ NfMeasureGroupRelationalModel.measurement_grp_name == measurement_group_name,
+ NfMeasureGroupRelationalModel.nf_name == nf_name
+ ).one_or_none()
+ if nf_msg_rel.nf_measure_grp_status == SubNfState.PENDING_DELETE.value:
+ administrative_state = AdministrativeState.LOCKING.value
+ elif nf_msg_rel.nf_measure_grp_status == SubNfState.PENDING_CREATE.value:
+ administrative_state = AdministrativeState.UNLOCKED.value
+
+ nf_measure_grp_status = (subscription_nf_states[administrative_state]
+ [response_message]).value
policy_response_handle_functions[administrative_state][response_message](
measurement_group_name=measurement_group_name, status=nf_measure_grp_status,
nf_name=nf_name)
diff --git a/components/pm-subscription-handler/pmsh_service/mod/subscription.py b/components/pm-subscription-handler/pmsh_service/mod/subscription.py
index 603343f0..ddb6e1f5 100755
--- a/components/pm-subscription-handler/pmsh_service/mod/subscription.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/subscription.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.
@@ -34,6 +34,7 @@ class AdministrativeState(Enum):
UNLOCKED = 'UNLOCKED'
LOCKING = 'LOCKING'
LOCKED = 'LOCKED'
+ FILTERING = 'FILTERING'
subscription_nf_states = {