From 9aa0b665b1d8ad6105ea783e176eacc58b26a804 Mon Sep 17 00:00:00 2001 From: shivasubedi Date: Mon, 18 Jan 2021 13:59:18 +0000 Subject: [PMSH] Validate schema of PMSH monitoring policy Change-Id: I42b002f855a03b39ab85cfcb20d7857d30447e40 Signed-off-by: shivasubedi Issue-ID: DCAEGEN2-2152 --- .../pmsh_service/mod/pmsh_utils.py | 36 +++++- .../pmsh_service/mod/sub_schema.json | 122 +++++++++++++++++++++ .../pmsh_service/mod/subscription_handler.py | 8 ++ 3 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 components/pm-subscription-handler/pmsh_service/mod/sub_schema.json (limited to 'components/pm-subscription-handler/pmsh_service') diff --git a/components/pm-subscription-handler/pmsh_service/mod/pmsh_utils.py b/components/pm-subscription-handler/pmsh_service/mod/pmsh_utils.py index 18834134..7b91a307 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/pmsh_utils.py +++ b/components/pm-subscription-handler/pmsh_service/mod/pmsh_utils.py @@ -15,7 +15,10 @@ # # SPDX-License-Identifier: Apache-2.0 # ============LICENSE_END===================================================== +import json +import os import uuid +from json import JSONDecodeError from os import getenv from threading import Timer @@ -24,8 +27,8 @@ from onap_dcae_cbs_docker_client.client import get_all from onaplogging.mdcContext import MDC from requests.auth import HTTPBasicAuth from tenacity import wait_fixed, stop_after_attempt, retry, retry_if_exception_type +from jsonschema import validate, ValidationError -import mod.network_function from mod import logger from mod.subscription import Subscription @@ -41,6 +44,7 @@ def mdc_handler(function): kwargs['request_id'] = request_id kwargs['invocation_id'] = invocation_id return function(*args, **kwargs) + return decorator @@ -58,6 +62,16 @@ class MySingleton(object): return type(clz.__name__, (MySingleton,), dict(clz.__dict__)) +def _load_sub_schema_from_file(): + try: + with open(os.path.join(os.path.dirname(__file__), 'sub_schema.json')) as sub: + return json.load(sub) + except OSError as err: + logger.error(f'Failed to read sub schema file: {err}', exc_info=True) + except JSONDecodeError as json_err: + logger.error(f'sub schema file is not a valid JSON file: {json_err}', exc_info=True) + + class AppConfig: INSTANCE = None @@ -73,8 +87,9 @@ class AppConfig: self.streams_publishes = conf['config'].get('streams_publishes') self.operational_policy_name = conf['config'].get('operational_policy_name') self.control_loop_name = conf['config'].get('control_loop_name') + self.sub_schema = _load_sub_schema_from_file() self.subscription = Subscription(**conf['policy']['subscription']) - self.nf_filter = mod.network_function.NetworkFunctionFilter(**self.subscription.nfFilter) + self.nf_filter = None def __new__(cls, *args, **kwargs): if AppConfig.INSTANCE is None: @@ -103,6 +118,23 @@ class AppConfig: logger.error(f'Failed to get config from CBS: {e}', exc_info=True) raise ValueError(e) + def validate_sub_schema(self): + """ + Validates schema of PMSH subscription + + Raises: + ValidationError: If the PMSH subscription schema is invalid + """ + sub_data = self.subscription.__dict__ + validate(instance=sub_data, schema=self.sub_schema) + nf_filter = sub_data["nfFilter"] + for filter_name in nf_filter: + if len(nf_filter[filter_name]) > 0: + break + else: + raise ValidationError("At least one filter within nfFilter must not be empty") + logger.debug("Subscription schema is valid.") + def refresh_config(self): """ Update the relevant attributes of the AppConfig object. diff --git a/components/pm-subscription-handler/pmsh_service/mod/sub_schema.json b/components/pm-subscription-handler/pmsh_service/mod/sub_schema.json new file mode 100644 index 00000000..7a1da5bb --- /dev/null +++ b/components/pm-subscription-handler/pmsh_service/mod/sub_schema.json @@ -0,0 +1,122 @@ +{ + "type":"object", + "properties":{ + "subscriptionName":{ + "type":"string" + }, + "administrativeState":{ + "allOf":[ + { + "type":"string" + }, + { + "enum":[ + "UNLOCKED", + "LOCKED" + ] + } + ] + }, + "fileBasedGP":{ + "type":"integer" + }, + "fileLocation":{ + "type":"string" + }, + "nfFilter":{ + "type":"object", + "properties":{ + "nfNames":{ + "type":"array", + "items":{ + "type":"string" + } + }, + "modelInvariantIDs":{ + "type":"array", + "items":{ + "type":"string" + } + }, + "modelVersionIDs":{ + "type":"array", + "items":{ + "type":"string" + } + }, + "modelNames":{ + "type":"array", + "items":{ + "type":"string" + } + } + }, + "required":[ + "nfNames", + "modelInvariantIDs", + "modelVersionIDs", + "modelNames" + ] + }, + "measurementGroups":{ + "type":"array", + "minItems": 1, + "items":{ + "type":"object", + "properties":{ + "measurementGroup":{ + "type":"object", + "properties":{ + "measurementTypes":{ + "type":"array", + "minItems": 1, + "items":{ + "type":"object", + "properties":{ + "measurementType":{ + "type":"string" + } + }, + "required":[ + "measurementType" + ] + } + }, + "managedObjectDNsBasic":{ + "type":"array", + "minItems": 1, + "items":{ + "type":"object", + "properties":{ + "DN":{ + "type":"string" + } + }, + "required":[ + "DN" + ] + } + } + }, + "required":[ + "measurementTypes", + "managedObjectDNsBasic" + ] + } + }, + "required":[ + "measurementGroup" + ] + } + } + }, + "required":[ + "subscriptionName", + "administrativeState", + "fileBasedGP", + "fileLocation", + "nfFilter", + "measurementGroups" + ] + +} \ No newline at end of file diff --git a/components/pm-subscription-handler/pmsh_service/mod/subscription_handler.py b/components/pm-subscription-handler/pmsh_service/mod/subscription_handler.py index f50f5ab2..6238a298 100644 --- a/components/pm-subscription-handler/pmsh_service/mod/subscription_handler.py +++ b/components/pm-subscription-handler/pmsh_service/mod/subscription_handler.py @@ -15,9 +15,11 @@ # # SPDX-License-Identifier: Apache-2.0 # ============LICENSE_END===================================================== +from jsonschema import ValidationError from mod import logger, aai_client from mod.aai_event_handler import process_aai_events +from mod.network_function import NetworkFunctionFilter from mod.pmsh_utils import PeriodicTask from mod.subscription import AdministrativeState @@ -42,12 +44,16 @@ class SubscriptionHandler: self._check_for_failed_nfs() else: self.app_conf.refresh_config() + self.app_conf.validate_sub_schema() new_administrative_state = self.app_conf.subscription.administrativeState if local_admin_state == new_administrative_state: logger.info(f'Administrative State did not change in the app config: ' f'{new_administrative_state}') else: self._check_state_change(local_admin_state, new_administrative_state) + except (ValidationError, TypeError) as err: + logger.error(f'Error occurred during validation of subscription schema {err}', + exc_info=True) except Exception as err: logger.error(f'Error occurred during the activation/deactivation process {err}', exc_info=True) @@ -65,6 +71,8 @@ class SubscriptionHandler: raise Exception(f'Invalid AdministrativeState: {new_administrative_state}') def _activate(self, new_administrative_state): + if not self.app_conf.nf_filter: + self.app_conf.nf_filter = NetworkFunctionFilter(**self.app_conf.subscription.nfFilter) self._start_aai_event_thread() self.app_conf.subscription.update_sub_params(new_administrative_state, self.app_conf.subscription.fileBasedGP, -- cgit 1.2.3-korg