From 27ec381034605d03285140cff8c21098e13808fe Mon Sep 17 00:00:00 2001 From: efiacor Date: Wed, 14 Oct 2020 11:17:50 +0100 Subject: [PMSH] Bug fix to include ip in event # Add fix for DB cleardown on exit Signed-off-by: efiacor Change-Id: I6630f74258d072f683b5b5e42f0da2e63ea1b3c2 Issue-ID: DCAEGEN2-2486 --- components/pm-subscription-handler/Changelog.md | 1 + .../pmsh_service/mod/aai_client.py | 3 ++- .../pmsh_service/mod/aai_event_handler.py | 1 + .../pmsh_service/mod/api/db_models.py | 8 +++++++- .../pmsh_service/mod/exit_handler.py | 17 ++++++++++++----- .../pmsh_service/mod/network_function.py | 21 ++++++++++++++++----- .../pmsh_service/mod/subscription.py | 22 +++++++++++++++++----- .../pmsh_service/pmsh_service_main.py | 4 ++++ .../tests/data/pm_subscription_event.json | 1 + .../tests/test_aai_service.py | 10 +++++----- .../tests/test_network_function.py | 2 ++ .../tests/test_subscription.py | 15 ++------------- 12 files changed, 70 insertions(+), 35 deletions(-) (limited to 'components/pm-subscription-handler') diff --git a/components/pm-subscription-handler/Changelog.md b/components/pm-subscription-handler/Changelog.md index ca988296..6e7e0428 100755 --- a/components/pm-subscription-handler/Changelog.md +++ b/components/pm-subscription-handler/Changelog.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [1.1.2] ### Changed * Bug fix for missing sdnc params in DELETE event (DCAEGEN2-2483) +* Fix to add IP to event sent to Policy framework (DCAEGEN2-2486) ## [1.1.1] ### Changed 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 73bf8d4c..48f757da 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/aai_client.py +++ b/components/pm-subscription-handler/pmsh_service/mod/aai_client.py @@ -97,7 +97,7 @@ def _get_aai_service_url(): """ try: aai_ssl_port = environ['AAI_SERVICE_PORT'] - return f'https://aai:{aai_ssl_port}/aai/v20' + return f'https://aai:{aai_ssl_port}/aai/v21' except KeyError as e: logger.error(f'Failed to get AAI env var: {e}', exc_info=True) raise @@ -135,6 +135,7 @@ def _filter_nf_data(nf_data, app_conf): name_identifier = 'pnf-name' if nf['node-type'] == 'pnf' else 'vnf-name' new_nf = mod.network_function.NetworkFunction( nf_name=nf['properties'].get(name_identifier), + ip_address=nf['properties'].get('ipaddress-v4-oam'), model_invariant_id=nf['properties'].get('model-invariant-id'), model_version_id=nf['properties'].get('model-version-id')) if not new_nf.set_sdnc_params(app_conf): diff --git a/components/pm-subscription-handler/pmsh_service/mod/aai_event_handler.py b/components/pm-subscription-handler/pmsh_service/mod/aai_event_handler.py index 61b42b52..f39f1f46 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/aai_event_handler.py +++ b/components/pm-subscription-handler/pmsh_service/mod/aai_event_handler.py @@ -63,6 +63,7 @@ def process_aai_events(mr_sub, mr_pub, app, app_conf): f'is not "Active"') continue nf = NetworkFunction(nf_name=xnf_name, + ip_address=aai_entity['ipaddress-v4-oam'], model_invariant_id=aai_entity['model-invariant-id'], model_version_id=aai_entity['model-version-id']) if not nf.set_sdnc_params(app_conf): 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 a8b13e89..b6735cc9 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 @@ -48,6 +48,7 @@ class SubscriptionModel(db.Model): def serialize(self): sub_nfs = NfSubRelationalModel.query.filter( NfSubRelationalModel.subscription_name == self.subscription_name).all() + db.session.remove() return {'subscription_name': self.subscription_name, 'subscription_status': self.status, 'network_functions': [sub_nf.serialize_nf() for sub_nf in sub_nfs]} @@ -56,6 +57,7 @@ class NetworkFunctionModel(db.Model): __tablename__ = 'network_functions' id = Column(Integer, primary_key=True, autoincrement=True) nf_name = Column(String(100), unique=True) + ip_address = Column(String(50)) model_invariant_id = Column(String(100)) model_version_id = Column(String(100)) sdnc_model_name = Column(String(100)) @@ -66,9 +68,10 @@ class NetworkFunctionModel(db.Model): cascade='all, delete-orphan', backref='nf') - def __init__(self, nf_name, model_invariant_id, model_version_id, sdnc_model_name, + def __init__(self, nf_name, ip_address, model_invariant_id, model_version_id, sdnc_model_name, sdnc_model_version): self.nf_name = nf_name + self.ip_address = ip_address self.model_invariant_id = model_invariant_id self.model_version_id = model_version_id self.sdnc_model_name = sdnc_model_name @@ -82,6 +85,7 @@ class NetworkFunctionModel(db.Model): return NetworkFunction(sdnc_model_name=self.sdnc_model_name, sdnc_model_version=self.sdnc_model_version, **{'nf_name': self.nf_name, + 'ip_address': self.ip_address, 'model_invariant_id': self.model_invariant_id, 'model_version_id': self.model_version_id}) @@ -118,7 +122,9 @@ 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, + 'ip_address': nf.ip_address, 'nf_sub_status': self.nf_sub_status, 'model_invariant_id': nf.model_invariant_id, 'model_version_id': nf.model_version_id, diff --git a/components/pm-subscription-handler/pmsh_service/mod/exit_handler.py b/components/pm-subscription-handler/pmsh_service/mod/exit_handler.py index 12932966..fbb8b241 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/exit_handler.py +++ b/components/pm-subscription-handler/pmsh_service/mod/exit_handler.py @@ -16,7 +16,7 @@ # SPDX-License-Identifier: Apache-2.0 # ============LICENSE_END===================================================== -from mod import logger +from mod import logger, db from mod.subscription import AdministrativeState @@ -39,14 +39,21 @@ class ExitHandler: def __call__(self, sig_num, frame): logger.info('Graceful shutdown of PMSH initiated.') logger.debug(f'ExitHandler was called with signal number: {sig_num}.') + for thread in self.periodic_tasks: + if thread.name == 'app_conf_thread': + logger.info(f'Cancelling thread {thread.name}') + thread.cancel() current_sub = self.app_conf.subscription if current_sub.administrativeState == AdministrativeState.UNLOCKED.value: try: current_sub.deactivate_subscription(self.subscription_handler.mr_pub, self.app_conf) - current_sub.update_subscription_status() - for thread in self.periodic_tasks: - logger.debug(f'Cancelling periodic task with thread name: {thread.name}.') - thread.cancel() except Exception as e: logger.error(f'Failed to shut down PMSH application: {e}', exc_info=True) + for thread in self.periodic_tasks: + logger.info(f'Cancelling thread {thread.name}') + thread.cancel() + logger.info('Closing all DB connections') + db.session.bind.dispose() + db.session.close() + db.engine.dispose() ExitHandler.shutdown_signal_received = True diff --git a/components/pm-subscription-handler/pmsh_service/mod/network_function.py b/components/pm-subscription-handler/pmsh_service/mod/network_function.py index 798da00b..3f383885 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/network_function.py +++ b/components/pm-subscription-handler/pmsh_service/mod/network_function.py @@ -27,6 +27,7 @@ class NetworkFunction: def __init__(self, sdnc_model_name=None, sdnc_model_version=None, **kwargs): """ Object representation of the NetworkFunction. """ self.nf_name = kwargs.get('nf_name') + self.ip_address = kwargs.get('ip_address') self.model_invariant_id = kwargs.get('model_invariant_id') self.model_version_id = kwargs.get('model_version_id') self.sdnc_model_name = sdnc_model_name @@ -34,11 +35,12 @@ class NetworkFunction: @classmethod def nf_def(cls): - return cls(nf_name=None, model_invariant_id=None, model_version_id=None, + return cls(nf_name=None, ip_address=None, model_invariant_id=None, model_version_id=None, sdnc_model_name=None, sdnc_model_version=None) def __str__(self): return f'nf-name: {self.nf_name}, ' \ + f'ipaddress-v4-oam: {self.ip_address}, ' \ f'model-invariant-id: {self.model_invariant_id}, ' \ f'model-version-id: {self.model_version_id}, ' \ f'sdnc-model-name: {self.sdnc_model_name}, ' \ @@ -47,13 +49,14 @@ class NetworkFunction: def __eq__(self, other): return \ self.nf_name == other.nf_name and \ + self.ip_address == other.ip_address and \ self.model_invariant_id == other.model_invariant_id and \ self.model_version_id == other.model_version_id and \ self.sdnc_model_name == other.sdnc_model_name and \ self.sdnc_model_version == other.sdnc_model_version def __hash__(self): - return hash((self.nf_name, self.model_invariant_id, + return hash((self.nf_name, self.ip_address, self.model_invariant_id, self.model_version_id, self.sdnc_model_name, self.sdnc_model_version)) def create(self): @@ -63,6 +66,7 @@ class NetworkFunction: if existing_nf is None: new_nf = NetworkFunctionModel(nf_name=self.nf_name, + ip_address=self.ip_address, model_invariant_id=self.model_invariant_id, model_version_id=self.model_version_id, sdnc_model_name=self.sdnc_model_name, @@ -90,7 +94,8 @@ class NetworkFunction: f'sdnc-model data associated in AAI: {e}', exc_info=True) return not params_set except Exception as e: - logger.error(f'Failed to get sdnc-model info for XNFs from AAI: {e}', exc_info=True) + logger.error(f'Failed to get sdnc-model info for XNF {self.nf_name} from AAI: {e}', + exc_info=True) return not params_set @staticmethod @@ -101,8 +106,10 @@ class NetworkFunction: Returns: NetworkFunctionModel object else None """ - return NetworkFunctionModel.query.filter( + nf_model = NetworkFunctionModel.query.filter( NetworkFunctionModel.nf_name == nf_name).one_or_none() + db.session.remove() + return nf_model @staticmethod def get_all(): @@ -110,7 +117,10 @@ class NetworkFunction: Returns: list: NetworkFunctionModel objects else empty """ - return NetworkFunctionModel.query.all() + + nf_models = NetworkFunctionModel.query.all() + db.session.remove() + return nf_models @staticmethod def delete(**kwargs): @@ -122,6 +132,7 @@ class NetworkFunction: if nf: db.session.delete(nf) db.session.commit() + db.session.remove() class NetworkFunctionFilter: diff --git a/components/pm-subscription-handler/pmsh_service/mod/subscription.py b/components/pm-subscription-handler/pmsh_service/mod/subscription.py index 21e2399d..34753e84 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/subscription.py +++ b/components/pm-subscription-handler/pmsh_service/mod/subscription.py @@ -79,6 +79,8 @@ class Subscription: except Exception as e: logger.error(f'Failed to create subscription {self.subscriptionName} in the DB: {e}', exc_info=True) + finally: + db.session.remove() def update_subscription_status(self): """ Updates the status of subscription in subscription table """ @@ -92,6 +94,8 @@ class Subscription: except Exception as e: logger.error(f'Failed to update status of subscription: {self.subscriptionName}: {e}', exc_info=True) + finally: + db.session.remove() def prepare_subscription_event(self, nf, app_conf): """Prepare the sub event for publishing @@ -105,7 +109,9 @@ class Subscription: """ try: clean_sub = {k: v for k, v in self.__dict__.items() if k != 'nfFilter'} - sub_event = {'nfName': nf.nf_name, 'blueprintName': nf.sdnc_model_name, + sub_event = {'nfName': nf.nf_name, + 'ipv4Address': nf.ip_address, + 'blueprintName': nf.sdnc_model_name, 'blueprintVersion': nf.sdnc_model_version, 'policyName': app_conf.operational_policy_name, 'changeType': 'DELETE' @@ -149,8 +155,9 @@ class Subscription: Returns: SubscriptionModel object else None """ - return SubscriptionModel.query.filter( + sub_model = SubscriptionModel.query.filter( SubscriptionModel.subscription_name == self.subscriptionName).one_or_none() + return sub_model def get_local_sub_admin_state(self): """ Retrieves the subscription admin state @@ -160,6 +167,7 @@ class Subscription: """ sub_model = SubscriptionModel.query.filter( SubscriptionModel.subscription_name == self.subscriptionName).one_or_none() + db.session.remove() return sub_model.status @staticmethod @@ -169,14 +177,17 @@ class Subscription: Returns: list(SubscriptionModel): Subscriptions list else empty """ - return SubscriptionModel.query.all() + + sub_models = SubscriptionModel.query.all() + db.session.remove() + return sub_models def activate_subscription(self, nfs, mr_pub, app_conf): logger.info(f'Activate subscription initiated for {self.subscriptionName}.') try: existing_nfs = self.get_network_functions() sub_model = self.get() - for nf in set(nfs + existing_nfs): + for nf in [new_nf for new_nf in nfs if new_nf not in existing_nfs]: logger.info(f'Publishing event to activate ' f'Sub: {self.subscriptionName} for the nf: {nf.nf_name}') mr_pub.publish_subscription_event_data(self, nf, app_conf) @@ -209,6 +220,7 @@ class Subscription: list(NfSubRelationalModel): NetworkFunctions per Subscription list else empty """ nf_per_subscriptions = NfSubRelationalModel.query.all() + db.session.remove() return nf_per_subscriptions @staticmethod @@ -238,5 +250,5 @@ class Subscription: nf_model_object = NetworkFunctionModel.query.filter( NetworkFunctionModel.nf_name == nf_sub_entry.nf_name).one_or_none() nfs.append(nf_model_object.to_nf()) - + db.session.remove() return nfs 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 6b6b9baa..f92fdc91 100755 --- a/components/pm-subscription-handler/pmsh_service/pmsh_service_main.py +++ b/components/pm-subscription-handler/pmsh_service/pmsh_service_main.py @@ -41,18 +41,22 @@ def main(): sys.exit(e) app_conf_thread = PeriodicTask(10, app_conf.refresh_config) + app_conf_thread.name = 'app_conf_thread' app_conf_thread.start() policy_response_handler = PolicyResponseHandler(policy_mr_sub, app_conf, app) policy_response_handler_thread = PeriodicTask(25, policy_response_handler.poll_policy_topic) + policy_response_handler_thread.name = 'policy_event_thread' aai_event_thread = PeriodicTask(20, process_aai_events, args=(aai_event_mr_sub, policy_mr_pub, app, app_conf)) + aai_event_thread.name = 'aai_event_thread' subscription_handler = SubscriptionHandler(policy_mr_pub, app, app_conf, aai_event_thread, policy_response_handler_thread) subscription_handler_thread = PeriodicTask(30, subscription_handler.execute) + subscription_handler_thread.name = 'sub_handler_thread' subscription_handler_thread.start() periodic_tasks = [app_conf_thread, aai_event_thread, subscription_handler_thread, diff --git a/components/pm-subscription-handler/tests/data/pm_subscription_event.json b/components/pm-subscription-handler/tests/data/pm_subscription_event.json index 9416ec28..cd547d9d 100755 --- a/components/pm-subscription-handler/tests/data/pm_subscription_event.json +++ b/components/pm-subscription-handler/tests/data/pm_subscription_event.json @@ -5,6 +5,7 @@ "policyName":"pmsh-operational-policy", "changeType":"CREATE", "closedLoopControlName":"pmsh-control-loop", + "ipv4Address": "1.2.3.4", "subscription":{ "subscriptionName":"ExtraPM-All-gNB-R2B", "administrativeState":"UNLOCKED", diff --git a/components/pm-subscription-handler/tests/test_aai_service.py b/components/pm-subscription-handler/tests/test_aai_service.py index 7a3b846d..27694851 100644 --- a/components/pm-subscription-handler/tests/test_aai_service.py +++ b/components/pm-subscription-handler/tests/test_aai_service.py @@ -72,21 +72,21 @@ class AaiClientTestCase(BaseClassSetup): @responses.activate def test_aai_client_get_all_aai_xnf_data_not_found(self): responses.add(responses.PUT, - 'https://1.2.3.4:8443/aai/v20/query?format=simple&nodesOnly=true', + 'https://1.2.3.4:8443/aai/v21/query?format=simple&nodesOnly=true', json={'error': 'not found'}, status=404) self.assertIsNone(aai_client._get_all_aai_nf_data(self.app_conf)) @responses.activate def test_aai_client_get_all_aai_xnf_data_success(self): responses.add(responses.PUT, - 'https://aai:8443/aai/v20/query?format=simple&nodesOnly=true', + 'https://aai:8443/aai/v21/query?format=simple&nodesOnly=true', json={'dummy_data': 'blah_blah'}, status=200) self.assertIsNotNone(aai_client._get_all_aai_nf_data(self.app_conf)) @responses.activate def test_aai_client_get_sdnc_params_success(self): responses.add(responses.GET, - 'https://aai:8443/aai/v20/service-design-and-creation/models/model/' + 'https://aai:8443/aai/v21/service-design-and-creation/models/model/' '6fb9f466-7a79-4109-a2a3-72b340aca53d/model-vers/model-ver/' '6d25b637-8bca-47e2-af1a-61258424183d', json=json.loads(self.good_model_info), status=200) @@ -98,7 +98,7 @@ class AaiClientTestCase(BaseClassSetup): @responses.activate def test_aai_client_get_sdnc_params_fail(self): responses.add(responses.GET, - 'https://aai:8443/aai/v20/service-design-and-creation/models/model/' + 'https://aai:8443/aai/v21/service-design-and-creation/models/model/' '9fb9f466-7a79-4109-a2a3-72b340aca53d/model-vers/model-ver/' 'b7469cc5-be51-41cc-b37f-361537656771', status=404) with self.assertRaises(HTTPError): @@ -111,4 +111,4 @@ class AaiClientTestCase(BaseClassSetup): aai_client._get_aai_service_url() def test_aai_client_get_aai_service_url_success(self): - self.assertEqual('https://aai:8443/aai/v20', aai_client._get_aai_service_url()) + self.assertEqual('https://aai:8443/aai/v21', aai_client._get_aai_service_url()) diff --git a/components/pm-subscription-handler/tests/test_network_function.py b/components/pm-subscription-handler/tests/test_network_function.py index ea5d2c7e..c930c41d 100755 --- a/components/pm-subscription-handler/tests/test_network_function.py +++ b/components/pm-subscription-handler/tests/test_network_function.py @@ -33,10 +33,12 @@ class NetworkFunctionTests(BaseClassSetup): super().setUp() self.nf_1 = NetworkFunction(sdnc_model_name='blah', sdnc_model_version=1.0, **{'nf_name': 'pnf_1', + 'ip_address': '1.2.3.4', 'model_invariant_id': 'some_id', 'model_version_id': 'some_other_id'}) self.nf_2 = NetworkFunction(sdnc_model_name='blah', sdnc_model_version=2.0, **{'nf_name': 'pnf_2', + 'ip_address': '1.2.3.4', 'model_invariant_id': 'some_id', 'model_version_id': 'some_other_id'}) with open(os.path.join(os.path.dirname(__file__), 'data/aai_model_info.json'), 'r') as data: diff --git a/components/pm-subscription-handler/tests/test_subscription.py b/components/pm-subscription-handler/tests/test_subscription.py index 9bfe825f..62a9e16e 100755 --- a/components/pm-subscription-handler/tests/test_subscription.py +++ b/components/pm-subscription-handler/tests/test_subscription.py @@ -47,6 +47,7 @@ class SubscriptionTest(BaseClassSetup): mock_session_get.return_value.text = self.aai_model_data self.mock_mr_sub = Mock() self.mock_mr_pub = Mock() + self.app_conf.subscription.create() self.xnfs = aai_client.get_pmsh_nfs_from_aai(self.app_conf) self.sub_model = self.app_conf.subscription.get() @@ -65,12 +66,10 @@ class SubscriptionTest(BaseClassSetup): def test_get_subscription(self): sub_name = 'ExtraPM-All-gNB-R2B' - self.app_conf.subscription.create() new_sub = self.app_conf.subscription.get() self.assertEqual(sub_name, new_sub.subscription_name) def test_get_nf_names_per_sub(self): - self.app_conf.subscription.create() self.app_conf.subscription.add_network_function_to_subscription(list(self.xnfs)[0], self.sub_model) self.app_conf.subscription.add_network_function_to_subscription(list(self.xnfs)[1], @@ -82,16 +81,6 @@ class SubscriptionTest(BaseClassSetup): self.assertEqual(sub1, same_sub1) self.assertEqual(1, len(self.app_conf.subscription.get_all())) - def test_add_network_functions_per_subscription(self): - for nf in self.xnfs: - self.app_conf.subscription.add_network_function_to_subscription(nf, self.sub_model) - nfs_for_sub_1 = Subscription.get_all_nfs_subscription_relations() - self.assertEqual(3, len(nfs_for_sub_1)) - new_nf = NetworkFunction(nf_name='vnf_3', orchestration_status='Active') - self.app_conf.subscription.add_network_function_to_subscription(new_nf, self.sub_model) - nf_subs = Subscription.get_all_nfs_subscription_relations() - self.assertEqual(4, len(nf_subs)) - def test_add_duplicate_network_functions_per_subscription(self): self.app_conf.subscription.add_network_function_to_subscription(list(self.xnfs)[0], self.sub_model) @@ -103,7 +92,6 @@ class SubscriptionTest(BaseClassSetup): self.assertEqual(1, len(nf_subs)) def test_update_subscription_status(self): - self.app_conf.subscription.create() self.app_conf.subscription.administrativeState = 'new_status' self.app_conf.subscription.update_subscription_status() sub = self.app_conf.subscription.get() @@ -152,6 +140,7 @@ class SubscriptionTest(BaseClassSetup): 'data/pm_subscription_event.json'), 'r') as data: expected_sub_event = json.load(data) nf = NetworkFunction(nf_name='pnf_1', + ip_address='1.2.3.4', model_invariant_id='some-id', model_version_id='some-id') nf.sdnc_model_name = 'some-name' -- cgit 1.2.3-korg