From ae21e35b8eb8008cf1a3119bab2ad987db9f9e7f Mon Sep 17 00:00:00 2001 From: efiacor Date: Tue, 21 Apr 2020 13:39:35 +0100 Subject: [PMSH] Adding cbs module support Signed-off-by: efiacor Change-Id: Ie711995a3c7a2111f6cb872952507f511c0de6dd Issue-ID: DCAEGEN2-2156 --- .../pmsh_service/mod/aai_client.py | 4 +- .../pmsh_service/mod/config_handler.py | 74 ----------------- .../pmsh_service/mod/pmsh_logging.py | 5 +- .../pmsh_service/mod/pmsh_utils.py | 25 ++++++ .../pmsh_service/mod/subscription_handler.py | 7 +- .../pmsh_service/pmsh_service_main.py | 12 +-- components/pm-subscription-handler/setup.py | 3 +- .../tests/test_aai_service.py | 2 +- .../tests/test_config_handler.py | 95 ---------------------- .../tests/test_subscription_handler.py | 33 +++----- 10 files changed, 56 insertions(+), 204 deletions(-) delete mode 100755 components/pm-subscription-handler/pmsh_service/mod/config_handler.py delete mode 100755 components/pm-subscription-handler/tests/test_config_handler.py diff --git a/components/pm-subscription-handler/pmsh_service/mod/aai_client.py b/components/pm-subscription-handler/pmsh_service/mod/aai_client.py index 86cecb50..5e71da4d 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/aai_client.py +++ b/components/pm-subscription-handler/pmsh_service/mod/aai_client.py @@ -55,7 +55,7 @@ def _get_all_aai_nf_data(): Return queried nf data from the AAI service. Returns: - json: the json response from AAI query, else None. + dict: the json response from AAI query, else None. """ nf_data = None try: @@ -94,7 +94,7 @@ def _get_aai_service_url(): """ try: aai_service = environ['AAI_SERVICE_HOST'] - aai_ssl_port = environ['AAI_SERVICE_PORT_AAI_SSL'] + aai_ssl_port = environ['AAI_SERVICE_PORT'] return f'https://{aai_service}:{aai_ssl_port}' except KeyError as e: logger.debug(f'Failed to get AAI env vars: {e}') diff --git a/components/pm-subscription-handler/pmsh_service/mod/config_handler.py b/components/pm-subscription-handler/pmsh_service/mod/config_handler.py deleted file mode 100755 index 26b03153..00000000 --- a/components/pm-subscription-handler/pmsh_service/mod/config_handler.py +++ /dev/null @@ -1,74 +0,0 @@ -# ============LICENSE_START=================================================== -# Copyright (C) 2019-2020 Nordix Foundation. -# ============================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# ============LICENSE_END===================================================== - -from os import environ - -import requests -from tenacity import retry, wait_fixed, stop_after_attempt, retry_if_exception_type - -import mod.pmsh_logging as logger - - -class ConfigHandler: - """ Handles retrieval of PMSH's configuration from Configbinding service.""" - - def __init__(self): - self.cbs_url = f'http://{self.cbs_hostname}:{str(self.cbs_port)}/' \ - f'service_component_all/{self.hostname}' - self._config = None - - @property - def cbs_hostname(self): - return _get_environment_variable('CONFIG_BINDING_SERVICE_SERVICE_HOST') - - @property - def cbs_port(self): - return _get_environment_variable('CONFIG_BINDING_SERVICE_SERVICE_PORT') - - @property - def hostname(self): - return _get_environment_variable('HOSTNAME') - - @retry(wait=wait_fixed(2), stop=stop_after_attempt(5), retry=retry_if_exception_type(Exception)) - def get_config(self): - """ Retrieves PMSH's configuration from Configbinding service. If a non-2xx response - is received, it retries after 2 seconds for 5 times before raising an exception. - - Returns: - dict: Dictionary representation of the the service configuration - - Raises: - Exception: If any error occurred pulling configuration from Configbinding service. - """ - - try: - response = requests.get(self.cbs_url) - response.raise_for_status() - self._config = response.json() - logger.debug(f'PMSH Configuration from Configbinding Service: {self._config}') - return self._config - except Exception as err: - raise Exception(f'Error retrieving configuration from CBS: {err}') - - -def _get_environment_variable(env_var_key): - try: - env_var = environ[env_var_key] - except KeyError as error: - raise KeyError(f'Environment variable {env_var_key} must be set. {error}') - return env_var diff --git a/components/pm-subscription-handler/pmsh_service/mod/pmsh_logging.py b/components/pm-subscription-handler/pmsh_service/mod/pmsh_logging.py index 885644b4..e0a7e1b1 100644 --- a/components/pm-subscription-handler/pmsh_service/mod/pmsh_logging.py +++ b/components/pm-subscription-handler/pmsh_service/mod/pmsh_logging.py @@ -17,6 +17,7 @@ # ============LICENSE_END===================================================== import datetime import logging as log +import sys from logging.handlers import RotatingFileHandler from os import makedirs @@ -41,7 +42,9 @@ def _create_logger(name, logfile): formatter = log.Formatter("%(message)s") file_handler.setFormatter(formatter) logger.setLevel(log.DEBUG) + stdout_handler = log.StreamHandler(sys.stdout) logger.addHandler(file_handler) + logger.addHandler(stdout_handler) return logger @@ -107,7 +110,7 @@ def debug(msg="n/a"): """ ets = utc() - _DEBUG_LOGGER.info( + _DEBUG_LOGGER.debug( "{ets}|{msg}".format( ets=ets.isoformat(), msg=msg, 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 750b7211..8db3c1f8 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/pmsh_utils.py +++ b/components/pm-subscription-handler/pmsh_service/mod/pmsh_utils.py @@ -20,11 +20,36 @@ import uuid from threading import Timer import requests +from onap_dcae_cbs_docker_client.client import get_all from requests.auth import HTTPBasicAuth +from tenacity import wait_fixed, stop_after_attempt, retry, retry_if_exception_type import mod.pmsh_logging as logger +class ConfigHandler: + """ Handles retrieval of PMSH's configuration from Configbinding service.""" + @staticmethod + @retry(wait=wait_fixed(2), stop=stop_after_attempt(5), retry=retry_if_exception_type(Exception)) + def get_pmsh_config(): + """ Retrieves PMSH's configuration from Config binding service. If a non-2xx response + is received, it retries after 2 seconds for 5 times before raising an exception. + + Returns: + dict: Dictionary representation of the the service configuration + + Raises: + Exception: If any error occurred pulling configuration from Config binding service. + """ + try: + config = get_all() + logger.debug(f'PMSH config from CBS: {config}') + return config + except Exception as err: + logger.debug(f'Failed to get config from CBS: {err}') + raise Exception + + class AppConfig: def __init__(self, **kwargs): self.aaf_creds = {'aaf_id': kwargs.get('aaf_identity'), 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 40b8c962..4d4c5311 100644 --- a/components/pm-subscription-handler/pmsh_service/mod/subscription_handler.py +++ b/components/pm-subscription-handler/pmsh_service/mod/subscription_handler.py @@ -18,15 +18,14 @@ import mod.aai_client as aai import mod.pmsh_logging as logger +from mod.pmsh_utils import ConfigHandler from mod.subscription import AdministrativeState class SubscriptionHandler: - def __init__(self, config_handler, administrative_state, mr_pub, app, app_conf, - aai_event_thread): + def __init__(self, administrative_state, mr_pub, app, app_conf, aai_event_thread): self.current_nfs = None self.current_sub = None - self.config_handler = config_handler self.administrative_state = administrative_state self.mr_pub = mr_pub self.app = app @@ -39,7 +38,7 @@ class SubscriptionHandler: the Subscription if a change has occurred """ self.app.app_context().push() - config = self.config_handler.get_config() + config = ConfigHandler.get_pmsh_config() new_administrative_state = config['policy']['subscription']['administrativeState'] try: diff --git a/components/pm-subscription-handler/pmsh_service/pmsh_service_main.py b/components/pm-subscription-handler/pmsh_service/pmsh_service_main.py index 60cf89c0..a2ba1fd3 100755 --- a/components/pm-subscription-handler/pmsh_service/pmsh_service_main.py +++ b/components/pm-subscription-handler/pmsh_service/pmsh_service_main.py @@ -23,9 +23,8 @@ import mod.aai_client as aai import mod.pmsh_logging as logger from mod import db, create_app, launch_api_server from mod.aai_event_handler import process_aai_events -from mod.config_handler import ConfigHandler from mod.exit_handler import ExitHandler -from mod.pmsh_utils import AppConfig, PeriodicTask +from mod.pmsh_utils import AppConfig, PeriodicTask, ConfigHandler from mod.policy_response_handler import PolicyResponseHandler from mod.subscription import Subscription, AdministrativeState from mod.subscription_handler import SubscriptionHandler @@ -33,12 +32,13 @@ from mod.subscription_handler import SubscriptionHandler def main(): try: - config_handler = ConfigHandler() - config = config_handler.get_config() - app_conf = AppConfig(**config['config']) app = create_app() app.app_context().push() db.create_all(app=app) + + config = ConfigHandler.get_pmsh_config() + app_conf = AppConfig(**config['config']) + sub, nfs = aai.get_pmsh_subscription_data(config) policy_mr_pub = app_conf.get_mr_pub('policy_pm_publisher') policy_mr_sub = app_conf.get_mr_sub('policy_pm_subscriber') @@ -50,7 +50,7 @@ def main(): aai_event_thread = PeriodicTask(10, process_aai_events, args=(mr_aai_event_sub, sub, policy_mr_pub, app, app_conf)) - subscription_handler = SubscriptionHandler(config_handler, administrative_state, + subscription_handler = SubscriptionHandler(administrative_state, policy_mr_pub, app, app_conf, aai_event_thread) policy_response_handler = PolicyResponseHandler(policy_mr_sub, sub.subscriptionName, app) diff --git a/components/pm-subscription-handler/setup.py b/components/pm-subscription-handler/setup.py index 056a5d82..0437f5dd 100644 --- a/components/pm-subscription-handler/setup.py +++ b/components/pm-subscription-handler/setup.py @@ -34,5 +34,6 @@ setup( "connexion==2.5.0", "flask_sqlalchemy==2.4.1", "Flask==1.1.1", - "psycopg2-binary==2.8.4"] + "psycopg2-binary==2.8.4", + "onap_dcae_cbs_docker_client==2.1.0"] ) diff --git a/components/pm-subscription-handler/tests/test_aai_service.py b/components/pm-subscription-handler/tests/test_aai_service.py index aaf2bb14..1ee71554 100644 --- a/components/pm-subscription-handler/tests/test_aai_service.py +++ b/components/pm-subscription-handler/tests/test_aai_service.py @@ -32,7 +32,7 @@ class AaiClientTestCase(TestCase): def setUp(self): self.env = EnvironmentVarGuard() self.env.set('AAI_SERVICE_HOST', '1.2.3.4') - self.env.set('AAI_SERVICE_PORT_AAI_SSL', '8443') + self.env.set('AAI_SERVICE_PORT', '8443') with open(os.path.join(os.path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data: self.cbs_data = json.load(data) with open(os.path.join(os.path.dirname(__file__), 'data/aai_xnfs.json'), 'r') as data: diff --git a/components/pm-subscription-handler/tests/test_config_handler.py b/components/pm-subscription-handler/tests/test_config_handler.py deleted file mode 100755 index dce48fca..00000000 --- a/components/pm-subscription-handler/tests/test_config_handler.py +++ /dev/null @@ -1,95 +0,0 @@ -# ============LICENSE_START=================================================== -# Copyright (C) 2019-2020 Nordix Foundation. -# ============================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# ============LICENSE_END===================================================== - -import json -import unittest -from os import environ -from os import path - -import responses -from tenacity import wait_none - -from mod.config_handler import ConfigHandler - - -class ConfigHandlerTestCase(unittest.TestCase): - - def setUp(self): - self.env_vars = {'CONFIG_BINDING_SERVICE_SERVICE_HOST': 'cbs_hostname', - 'CONFIG_BINDING_SERVICE_SERVICE_PORT': '10000', - 'HOSTNAME': 'hostname'} - for key, value in self.env_vars.items(): - environ[key] = value - self.cbs_url = 'http://cbs_hostname:10000/service_component_all/hostname' - with open(path.join(path.dirname(__file__), 'data/cbs_data_2.json'))as json_file: - self.expected_config = json.load(json_file) - - def test_missing_environment_variable(self): - for key, value in self.env_vars.items(): - with self.assertRaises(KeyError): - environ.pop(key) - test_value = globals()[value] - test_value() - environ[key] = value - - @responses.activate - def test_get_config_success(self): - responses.add(responses.GET, self.cbs_url, json=self.expected_config, - status=200) - - config_handler = ConfigHandler() - config_handler.get_config.retry.wait = wait_none() - - self.assertEqual(self.expected_config, config_handler.get_config()) - - @responses.activate - def test_get_config_error(self): - responses.add(responses.GET, self.cbs_url, status=404) - config_handler = ConfigHandler() - config_handler.get_config.retry.wait = wait_none() - - with self.assertRaises(Exception): - config_handler.get_config() - - @responses.activate - def test_get_config_max_retries_error(self): - retry_limit = 5 - config_handler = ConfigHandler() - config_handler.get_config.retry.wait = wait_none() - - for __ in range(retry_limit): - responses.add(responses.GET, self.cbs_url, status=500) - - with self.assertRaises(Exception): - config_handler.get_config() - self.assertEqual(retry_limit, len(responses.calls)) - - @responses.activate - def test_get_config_less_than_5_retries_success(self): - retry_attempts = 4 - responses.add(responses.GET, self.cbs_url, status=500) - responses.add(responses.GET, self.cbs_url, status=400) - responses.add(responses.GET, self.cbs_url, status=300) - responses.add(responses.GET, self.cbs_url, json=json.dumps(self.expected_config), - status=200) - - config_handler = ConfigHandler() - config_handler.get_config.retry.wait = wait_none() - config_handler.get_config() - - self.assertEqual(retry_attempts, len(responses.calls)) diff --git a/components/pm-subscription-handler/tests/test_subscription_handler.py b/components/pm-subscription-handler/tests/test_subscription_handler.py index 168d0366..d922b96f 100644 --- a/components/pm-subscription-handler/tests/test_subscription_handler.py +++ b/components/pm-subscription-handler/tests/test_subscription_handler.py @@ -30,17 +30,15 @@ class SubscriptionHandlerTest(TestCase): @patch('mod.create_app') @patch('mod.subscription.Subscription') @patch('mod.pmsh_utils._MrPub') - @patch('mod.config_handler.ConfigHandler') @patch('mod.pmsh_utils.AppConfig') @patch('mod.pmsh_utils.PeriodicTask') - def setUp(self, mock_aai_event_thread, mock_app_conf, mock_config_handler, mock_mr_pub, + def setUp(self, mock_aai_event_thread, mock_app_conf, mock_mr_pub, mock_sub, mock_app): with open(os.path.join(os.path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data: self.cbs_data_1 = json.load(data) self.mock_app = mock_app self.mock_sub = mock_sub self.mock_mr_pub = mock_mr_pub - self.mock_config_handler = mock_config_handler self.mock_app_conf = mock_app_conf self.mock_aai_event_thread = mock_aai_event_thread self.nf_1 = NetworkFunction(nf_name='pnf_1') @@ -51,25 +49,22 @@ class SubscriptionHandlerTest(TestCase): @patch('mod.aai_client.get_pmsh_subscription_data') def test_execute_no_change_of_state(self, mock_get_aai, mock_logger): mock_get_aai.return_value = self.mock_sub, self.nfs - self.mock_config_handler.get_config.return_value = self.cbs_data_1 - sub_handler = SubscriptionHandler(self.mock_config_handler, - AdministrativeState.UNLOCKED.value, self.mock_mr_pub, + sub_handler = SubscriptionHandler(AdministrativeState.UNLOCKED.value, self.mock_mr_pub, self.mock_app, self.mock_app_conf, self.mock_aai_event_thread) - sub_handler.execute() - + with patch('mod.pmsh_utils.ConfigHandler.get_pmsh_config', return_value=self.cbs_data_1): + sub_handler.execute() mock_logger.assert_called_with('Administrative State did not change in the Config') @patch('mod.aai_client.get_pmsh_subscription_data') def test_execute_change_of_state_unlocked(self, mock_get_aai): mock_get_aai.return_value = self.mock_sub, self.nfs self.mock_aai_event_thread.return_value.start.return_value = 'start_method' - self.mock_config_handler.get_config.return_value = self.cbs_data_1 - sub_handler = SubscriptionHandler(self.mock_config_handler, - AdministrativeState.LOCKED.value, self.mock_mr_pub, + sub_handler = SubscriptionHandler(AdministrativeState.LOCKED.value, self.mock_mr_pub, self.mock_app, self.mock_app_conf, self.mock_aai_event_thread.return_value) - sub_handler.execute() + with patch('mod.pmsh_utils.ConfigHandler.get_pmsh_config', return_value=self.cbs_data_1): + sub_handler.execute() self.assertEqual(AdministrativeState.UNLOCKED.value, sub_handler.administrative_state) self.mock_sub.process_subscription.assert_called_with(self.nfs, self.mock_mr_pub, @@ -82,12 +77,11 @@ class SubscriptionHandlerTest(TestCase): self.mock_aai_event_thread.return_value.cancel.return_value = 'cancel_method' self.cbs_data_1['policy']['subscription']['administrativeState'] = \ AdministrativeState.LOCKED.value - self.mock_config_handler.get_config.return_value = self.cbs_data_1 - sub_handler = SubscriptionHandler(self.mock_config_handler, - AdministrativeState.UNLOCKED.value, self.mock_mr_pub, + sub_handler = SubscriptionHandler(AdministrativeState.UNLOCKED.value, self.mock_mr_pub, self.mock_app, self.mock_app_conf, self.mock_aai_event_thread.return_value) - sub_handler.execute() + with patch('mod.pmsh_utils.ConfigHandler.get_pmsh_config', return_value=self.cbs_data_1): + sub_handler.execute() self.assertEqual(AdministrativeState.LOCKED.value, sub_handler.administrative_state) self.mock_sub.process_subscription.assert_called_with(self.nfs, self.mock_mr_pub, @@ -98,12 +92,11 @@ class SubscriptionHandlerTest(TestCase): @patch('mod.aai_client.get_pmsh_subscription_data') def test_execute_exception(self, mock_get_aai, mock_logger): mock_get_aai.return_value = self.mock_sub, self.nfs - self.mock_config_handler.get_config.return_value = self.cbs_data_1 self.mock_sub.process_subscription.side_effect = Exception - sub_handler = SubscriptionHandler(self.mock_config_handler, - AdministrativeState.LOCKED.value, self.mock_mr_pub, + sub_handler = SubscriptionHandler(AdministrativeState.LOCKED.value, self.mock_mr_pub, self.mock_app, self.mock_app_conf, self.mock_aai_event_thread) - sub_handler.execute() + with patch('mod.pmsh_utils.ConfigHandler.get_pmsh_config', return_value=self.cbs_data_1): + sub_handler.execute() mock_logger.assert_called_with('Error occurred during the activation/deactivation process ') -- cgit 1.2.3-korg