## [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
"""
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
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):
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):
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]}
__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))
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
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})
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,
# SPDX-License-Identifier: Apache-2.0
# ============LICENSE_END=====================================================
-from mod import logger
+from mod import logger, db
from mod.subscription import AdministrativeState
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
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
@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}, ' \
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):
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,
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
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():
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):
if nf:
db.session.delete(nf)
db.session.commit()
+ db.session.remove()
class NetworkFunctionFilter:
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 """
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
"""
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'
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
"""
sub_model = SubscriptionModel.query.filter(
SubscriptionModel.subscription_name == self.subscriptionName).one_or_none()
+ db.session.remove()
return sub_model.status
@staticmethod
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)
list(NfSubRelationalModel): NetworkFunctions per Subscription list else empty
"""
nf_per_subscriptions = NfSubRelationalModel.query.all()
+ db.session.remove()
return nf_per_subscriptions
@staticmethod
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
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,
"policyName":"pmsh-operational-policy",\r
"changeType":"CREATE",\r
"closedLoopControlName":"pmsh-control-loop",\r
+ "ipv4Address": "1.2.3.4",\r
"subscription":{\r
"subscriptionName":"ExtraPM-All-gNB-R2B",\r
"administrativeState":"UNLOCKED",\r
@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)
@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):
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())
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:
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()
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],
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)
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()
'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'