1 # ============LICENSE_START===================================================
2 # Copyright (C) 2019-2020 Nordix Foundation.
3 # ============================================================================
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 # SPDX-License-Identifier: Apache-2.0
17 # ============LICENSE_END=====================================================
20 from mod import db, logger
21 from mod.api.db_models import SubscriptionModel, NfSubRelationalModel, NetworkFunctionModel
22 from mod.network_function import NetworkFunction
25 class SubNfState(Enum):
26 PENDING_CREATE = 'PENDING_CREATE'
27 CREATE_FAILED = 'CREATE_FAILED'
29 PENDING_DELETE = 'PENDING_DELETE'
30 DELETE_FAILED = 'DELETE_FAILED'
33 class AdministrativeState(Enum):
39 subscription_nf_states = {
40 AdministrativeState.LOCKED.value: {
41 'success': SubNfState.CREATED,
42 'failed': SubNfState.DELETE_FAILED
44 AdministrativeState.UNLOCKED.value: {
45 'success': SubNfState.CREATED,
46 'failed': SubNfState.CREATE_FAILED
52 def __init__(self, **kwargs):
53 self.subscriptionName = kwargs.get('subscriptionName')
54 self.administrativeState = kwargs.get('administrativeState')
55 self.fileBasedGP = kwargs.get('fileBasedGP')
56 self.fileLocation = kwargs.get('fileLocation')
57 self.nfFilter = kwargs.get('nfFilter')
58 self.measurementGroups = kwargs.get('measurementGroups')
62 """ Creates a subscription database entry
68 existing_subscription = (SubscriptionModel.query.filter(
69 SubscriptionModel.subscription_name == self.subscriptionName).one_or_none())
70 if existing_subscription is None:
71 new_subscription = SubscriptionModel(subscription_name=self.subscriptionName,
72 status=AdministrativeState.PENDING.value)
73 db.session.add(new_subscription)
75 return new_subscription
77 logger.debug(f'Subscription {self.subscriptionName} already exists,'
78 f' returning this subscription..')
79 return existing_subscription
80 except Exception as e:
81 logger.error(f'Failed to create subscription {self.subscriptionName} in the DB: {e}',
84 def update_subscription_status(self):
85 """ Updates the status of subscription in subscription table """
87 SubscriptionModel.query.filter(
88 SubscriptionModel.subscription_name == self.subscriptionName)\
89 .update({SubscriptionModel.status: self.administrativeState},
90 synchronize_session='evaluate')
93 except Exception as e:
94 logger.error(f'Failed to update status of subscription: {self.subscriptionName}: {e}',
97 def delete_subscription(self):
98 """ Deletes a subscription and all its association from the database. A network function
99 that is only associated with the subscription being removed will also be deleted."""
101 subscription = SubscriptionModel.query.filter(
102 SubscriptionModel.subscription_name == self.subscriptionName).one_or_none()
104 for nf_relationship in subscription.nfs:
105 other_nf_relationship = NfSubRelationalModel.query.filter(
106 NfSubRelationalModel.subscription_name != self.subscriptionName,
107 NfSubRelationalModel.nf_name == nf_relationship.nf_name).one_or_none()
108 if not other_nf_relationship:
109 db.session.delete(nf_relationship.nf)
110 db.session.delete(subscription)
112 except Exception as e:
113 logger.error(f'Failed to delete subscription: {self.subscriptionName} '
114 f'and it\'s relations from the DB: {e}', exc_info=True)
116 def prepare_subscription_event(self, xnf_name, app_conf):
117 """Prepare the sub event for publishing
120 xnf_name: the AAI xnf name.
121 app_conf (AppConfig): the application configuration.
124 dict: the Subscription event to be published.
127 clean_sub = {k: v for k, v in self.__dict__.items() if k != 'nfFilter'}
128 sub_event = {'nfName': xnf_name, 'policyName': app_conf.operational_policy_name,
129 'changeType': 'DELETE'
130 if self.administrativeState == AdministrativeState.LOCKED.value
131 else 'CREATE', 'closedLoopControlName': app_conf.control_loop_name,
132 'subscription': clean_sub}
134 except Exception as e:
135 logger.error(f'Failed to prep Sub event for xNF {xnf_name}: {e}', exc_info=True)
138 def add_network_function_to_subscription(self, nf, sub_model):
139 """ Associates a network function to a Subscription
142 sub_model(SubscriptionModel): The SubscriptionModel from the DB.
143 nf(NetworkFunction): A NetworkFunction object.
146 current_nf = nf.create()
147 existing_entry = NfSubRelationalModel.query.filter(
148 NfSubRelationalModel.subscription_name == self.subscriptionName,
149 NfSubRelationalModel.nf_name == current_nf.nf_name).one_or_none()
150 if existing_entry is None:
151 new_nf_sub = NfSubRelationalModel(self.subscriptionName,
152 nf.nf_name, SubNfState.PENDING_CREATE.value)
153 sub_model.nfs.append(new_nf_sub)
154 db.session.add(sub_model)
156 logger.info(f'Network function {current_nf.nf_name} added to Subscription '
157 f'{self.subscriptionName}')
158 except Exception as e:
159 logger.error(f'Failed to add nf {nf.nf_name} to subscription '
160 f'{self.subscriptionName}: {e}', exc_info=True)
161 logger.debug(f'Subscription {self.subscriptionName} now contains these XNFs:'
162 f'{Subscription.get_nf_names_per_sub(self.subscriptionName)}')
165 """ Retrieves a SubscriptionModel object
168 SubscriptionModel object else None
170 return SubscriptionModel.query.filter(
171 SubscriptionModel.subscription_name == self.subscriptionName).one_or_none()
173 def get_local_sub_admin_state(self):
174 """ Retrieves the subscription admin state
177 str: The admin state of the SubscriptionModel
179 sub_model = SubscriptionModel.query.filter(
180 SubscriptionModel.subscription_name == self.subscriptionName).one_or_none()
181 return sub_model.status
185 """ Retrieves a list of subscriptions
188 list(SubscriptionModel): Subscriptions list else empty
190 return SubscriptionModel.query.all()
193 def get_nf_names_per_sub(subscription_name):
194 """ Retrieves a list of network function names related to the subscription
197 subscription_name (str): The subscription name
200 list(str): List of network function names
202 nf_sub_rel = NfSubRelationalModel.query.filter(
203 NfSubRelationalModel.subscription_name == subscription_name).all()
205 for nf in nf_sub_rel:
206 list_of_nfs.append(nf.nf_name)
210 def activate_subscription(self, nfs, mr_pub, app_conf):
211 logger.info(f'Activate subscription initiated for {self.subscriptionName}.')
213 sub_model = self.get()
215 mr_pub.publish_subscription_event_data(self, nf.nf_name, app_conf)
216 logger.info(f'Publishing event to activate '
217 f'Sub: {self.subscriptionName} for the nf: {nf.nf_name}')
218 self.add_network_function_to_subscription(nf, sub_model)
219 self.update_sub_nf_status(self.subscriptionName, SubNfState.PENDING_CREATE.value,
221 except Exception as err:
222 raise Exception(f'Error publishing activation event to MR: {err}')
224 def deactivate_subscription(self, mr_pub, app_conf):
225 nfs = self.get_network_functions()
228 logger.info(f'Deactivate subscription initiated for {self.subscriptionName}.')
230 mr_pub.publish_subscription_event_data(self, nf.nf_name, app_conf)
231 logger.debug(f'Publishing Event to deactivate '
232 f'Sub: {self.subscriptionName} for the nf: {nf.nf_name}')
233 self.update_sub_nf_status(self.subscriptionName,
234 SubNfState.PENDING_DELETE.value,
236 except Exception as err:
237 raise Exception(f'Error publishing deactivation event to MR: {err}')
240 def get_all_nfs_subscription_relations():
241 """ Retrieves all network function to subscription relations
244 list(NfSubRelationalModel): NetworkFunctions per Subscription list else empty
246 nf_per_subscriptions = NfSubRelationalModel.query.all()
247 return nf_per_subscriptions
250 def update_sub_nf_status(subscription_name, status, nf_name):
251 """ Updates the status of the subscription for a particular nf
254 subscription_name (str): The subscription name
255 nf_name (str): The network function name
256 status (str): Status of the subscription
259 NfSubRelationalModel.query.filter(
260 NfSubRelationalModel.subscription_name == subscription_name,
261 NfSubRelationalModel.nf_name == nf_name). \
262 update({NfSubRelationalModel.nf_sub_status: status}, synchronize_session='evaluate')
264 except Exception as e:
265 logger.error(f'Failed to update status of nf: {nf_name} for subscription: '
266 f'{subscription_name}: {e}', exc_info=True)
268 def _get_nf_models(self):
269 nf_sub_relationships = NfSubRelationalModel.query.filter(
270 NfSubRelationalModel.subscription_name == self.subscriptionName)
272 for nf_sub_entry in nf_sub_relationships:
273 nf_model_object = NetworkFunctionModel.query.filter(
274 NetworkFunctionModel.nf_name == nf_sub_entry.nf_name).one_or_none()
275 nf_models.append(nf_model_object)
279 def get_network_functions(self):
281 nf_models = self._get_nf_models()
282 for nf_model in nf_models:
283 nf = NetworkFunction(
284 nf_name=nf_model.nf_name,
285 orchestration_status=nf_model.orchestration_status