blob: 031609aa4e1a62f620c8b8c4e573b5ec0b8aa22f [file] [log] [blame]
efiacorbbe05d82019-12-11 12:00:26 +00001# ============LICENSE_START===================================================
efiacor8b3fc622020-01-24 13:19:01 +00002# Copyright (C) 2019-2020 Nordix Foundation.
efiacorbbe05d82019-12-11 12:00:26 +00003# ============================================================================
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
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
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.
15#
16# SPDX-License-Identifier: Apache-2.0
17# ============LICENSE_END=====================================================
18import re
ERIMROB26b76c02020-02-12 11:35:20 +000019from enum import Enum
efiacorbbe05d82019-12-11 12:00:26 +000020
efiacor8b3fc622020-01-24 13:19:01 +000021import mod.pmsh_logging as logger
22from mod import db
23from mod.db_models import SubscriptionModel, NfSubRelationalModel
ERIMROB26b76c02020-02-12 11:35:20 +000024from tenacity import retry, retry_if_exception_type, wait_exponential, stop_after_attempt
25
26
27class SubNfState(Enum):
28 PENDING_CREATE = 'PENDING_CREATE'
29 CREATE_FAILED = 'CREATE_FAILED'
30 CREATED = 'CREATED'
31 PENDING_DELETE = 'PENDING_DELETE'
32 DELETE_FAILED = 'DELETE_FAILED'
33
34
35class AdministrativeState(Enum):
36 UNLOCKED = 'UNLOCKED'
37 LOCKED = 'LOCKED'
efiacor8b3fc622020-01-24 13:19:01 +000038
efiacorbbe05d82019-12-11 12:00:26 +000039
40class Subscription:
41 def __init__(self, **kwargs):
42 self.subscriptionName = kwargs.get('subscriptionName')
43 self.administrativeState = kwargs.get('administrativeState')
44 self.fileBasedGP = kwargs.get('fileBasedGP')
45 self.fileLocation = kwargs.get('fileLocation')
46 self.nfTypeModelInvariantId = kwargs.get('nfTypeModelInvariantId')
47 self.nfFilter = kwargs.get('nfFilter')
48 self.measurementGroups = kwargs.get('measurementGroups')
49
50 def prepare_subscription_event(self, xnf_name):
51 """Prepare the sub event for publishing
52
53 Args:
54 xnf_name: the AAI xnf name.
55
56 Returns:
57 dict: the Subscription event to be published.
58 """
59 clean_sub = {k: v for k, v in self.__dict__.items() if k != 'nfFilter'}
ERIMROB26b76c02020-02-12 11:35:20 +000060 clean_sub.update({'nfName': xnf_name, 'policyName': f'OP-{self.subscriptionName}',
61 'changeType': 'DELETE'
62 if self.administrativeState == AdministrativeState.LOCKED.value
63 else 'CREATE'})
efiacorbbe05d82019-12-11 12:00:26 +000064 return clean_sub
65
efiacor8b3fc622020-01-24 13:19:01 +000066 def create(self):
67 """ Creates a subscription database entry
efiacorbbe05d82019-12-11 12:00:26 +000068
efiacor8b3fc622020-01-24 13:19:01 +000069 Returns:
70 Subscription object
71 """
72 existing_subscription = (SubscriptionModel.query.filter(
73 SubscriptionModel.subscription_name == self.subscriptionName).one_or_none())
74
75 if existing_subscription is None:
76 new_subscription = SubscriptionModel(subscription_name=self.subscriptionName,
77 status=self.administrativeState)
78
79 db.session.add(new_subscription)
80 db.session.commit()
81
82 return new_subscription
83
84 else:
85 logger.debug(f'Subscription {self.subscriptionName} already exists,'
86 f' returning this subscription..')
87 return existing_subscription
88
89 def add_network_functions_to_subscription(self, nf_list):
90 """ Associates network functions to a Subscription
91
92 Args:
93 nf_list : A list of NetworkFunction objects.
94 """
95 current_sub = self.create()
96 logger.debug(f'Adding network functions to subscription {current_sub.subscription_name}')
97
98 for nf in nf_list:
99 current_nf = nf.create()
100
101 existing_entry = NfSubRelationalModel.query.filter(
102 NfSubRelationalModel.subscription_name == current_sub.subscription_name,
103 NfSubRelationalModel.nf_name == current_nf.nf_name).one_or_none()
104 if existing_entry is None:
ERIMROB26b76c02020-02-12 11:35:20 +0000105 new_nf_sub = NfSubRelationalModel(current_sub.subscription_name,
106 nf.nf_name, SubNfState.PENDING_CREATE.value)
efiacor8b3fc622020-01-24 13:19:01 +0000107 new_nf_sub.nf = current_nf
108 logger.debug(current_nf)
109 current_sub.nfs.append(new_nf_sub)
110
111 db.session.add(current_sub)
112 db.session.commit()
113
114 @staticmethod
115 def get(subscription_name):
116 """ Retrieves a subscription
117
118 Args:
119 subscription_name (str): The subscription name
120
121 Returns:
122 Subscription object else None
123 """
124 return SubscriptionModel.query.filter(
125 SubscriptionModel.subscription_name == subscription_name).one_or_none()
126
127 @staticmethod
128 def get_all():
129 """ Retrieves a list of subscriptions
130
131 Returns:
132 list: Subscription list else empty
133 """
134 return SubscriptionModel.query.all()
135
ERIMROB26b76c02020-02-12 11:35:20 +0000136 def update_subscription_status(self):
137 """ Updates the status of subscription in subscription table """
138 SubscriptionModel.query.filter(
139 SubscriptionModel.subscription_name == self.subscriptionName). \
140 update({SubscriptionModel.status: self.administrativeState},
141 synchronize_session='evaluate')
142
143 db.session.commit()
144
145 def delete_subscription(self):
146 """ Deletes a subscription from the database """
147 SubscriptionModel.query.filter(
148 SubscriptionModel.subscription_name == self.subscriptionName). \
149 delete(synchronize_session='evaluate')
150
151 db.session.commit()
152
153 @retry(wait=wait_exponential(multiplier=1, min=30, max=120), stop=stop_after_attempt(3),
154 retry=retry_if_exception_type(Exception))
155 def process_subscription(self, nfs, mr_pub):
156 action = 'Deactivate'
157 sub_nf_state = SubNfState.PENDING_DELETE.value
158 self.update_subscription_status()
159
160 if self.administrativeState == AdministrativeState.UNLOCKED.value:
161 action = 'Activate'
162 sub_nf_state = SubNfState.PENDING_CREATE.value
163
164 try:
165 for nf in nfs:
166 mr_pub.publish_subscription_event_data(self, nf.nf_name)
167 logger.debug(f'Publishing Event to {action} '
168 f'Sub: {self.subscriptionName} for the nf: {nf.nf_name}')
169 self.add_network_functions_to_subscription(nfs)
170 self.update_sub_nf_status(self.subscriptionName, sub_nf_state, nf.nf_name)
171 except Exception as err:
172 raise Exception(f'Error publishing activation event to MR: {err}')
173
efiacor8b3fc622020-01-24 13:19:01 +0000174 @staticmethod
175 def get_all_nfs_subscription_relations():
176 """ Retrieves all network function to subscription relations
177
178 Returns:
179 list: NetworkFunctions per Subscription list else empty
180 """
181 nf_per_subscriptions = NfSubRelationalModel.query.all()
182
183 return nf_per_subscriptions
184
ERIMROB26b76c02020-02-12 11:35:20 +0000185 @staticmethod
186 def update_sub_nf_status(subscription_name, status, nf_name):
187 """ Updates the status of the subscription for a particular nf
188
189 Args:
190 subscription_name (str): The subscription name
191 nf_name (str): The network function name
192 status (str): Status of the subscription
193 """
194 NfSubRelationalModel.query.filter(
195 NfSubRelationalModel.subscription_name == subscription_name,
196 NfSubRelationalModel.nf_name == nf_name). \
197 update({NfSubRelationalModel.nf_sub_status: status}, synchronize_session='evaluate')
198
199 db.session.commit()
200
efiacor8b3fc622020-01-24 13:19:01 +0000201
202class NetworkFunctionFilter:
efiacorbbe05d82019-12-11 12:00:26 +0000203 def __init__(self, **kwargs):
204 self.nf_sw_version = kwargs.get('swVersions')
205 self.nf_names = kwargs.get('nfNames')
206 self.regex_matcher = re.compile('|'.join(raw_regex for raw_regex in self.nf_names))
207
efiacor8b3fc622020-01-24 13:19:01 +0000208 def is_nf_in_filter(self, nf_name):
209 """Match the nf name against regex values in Subscription.nfFilter.nfNames
efiacorbbe05d82019-12-11 12:00:26 +0000210
211 Args:
efiacor8b3fc622020-01-24 13:19:01 +0000212 nf_name: the AAI nf name.
efiacorbbe05d82019-12-11 12:00:26 +0000213
214 Returns:
215 bool: True if matched, else False.
216 """
efiacor8b3fc622020-01-24 13:19:01 +0000217 return self.regex_matcher.search(nf_name)