blob: f2c082d860a008a67620e777bf4e1cfc097db134 [file] [log] [blame]
Girish Gowdru141ced82018-09-17 20:19:14 -07001#
2# Copyright 2018 the original author or authors.
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
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
17"""
18Resource Manager will be unique for each OLT device.
19
20It exposes APIs to create/free alloc_ids/onu_ids/gemport_ids. Resource Manager
21uses a KV store in backend to ensure resiliency of the data.
22"""
23import json
24import structlog
25from bitstring import BitArray
Girish Gowdru1e77ea02018-09-24 09:10:35 -070026from ast import literal_eval
27import shlex
28from argparse import ArgumentParser, ArgumentError
Girish Gowdru141ced82018-09-17 20:19:14 -070029
Girish Gowdru1e77ea02018-09-24 09:10:35 -070030from common.pon_resource_manager.resource_kv_store import ResourceKvStore
31
32
33# Used to parse extra arguments to OpenOlt adapter from the NBI
34class OltVendorArgumentParser(ArgumentParser):
35 # Must override the exit command to prevent it from
36 # calling sys.exit(). Return exception instead.
37 def exit(self, status=0, message=None):
38 raise Exception(message)
Girish Gowdru141ced82018-09-17 20:19:14 -070039
40
41class PONResourceManager(object):
42 """Implements APIs to initialize/allocate/release alloc/gemport/onu IDs."""
43
44 # Constants to identify resource pool
45 ONU_ID = 'ONU_ID'
46 ALLOC_ID = 'ALLOC_ID'
47 GEMPORT_ID = 'GEMPORT_ID'
48
Craig Lutgenf7601472018-11-02 13:27:41 +000049 # Constants for passing command line arugments
50 OLT_MODEL_ARG = '--olt_model'
51
52 # The resource ranges for a given device model should be placed
53 # at 'resource_manager/<technology>/resource_ranges/<olt_model_type>'
Girish Gowdru141ced82018-09-17 20:19:14 -070054 # path on the KV store.
55 # If Resource Range parameters are to be read from the external KV store,
56 # they are expected to be stored in the following format.
57 # Note: All parameters are MANDATORY for now.
58 '''
Girish Gowdru1e77ea02018-09-24 09:10:35 -070059 {
60 "onu_id_start": 1,
61 "onu_id_end": 127,
62 "alloc_id_start": 1024,
63 "alloc_id_end": 2816,
64 "gemport_id_start": 1024,
65 "gemport_id_end": 8960,
66 "pon_ports": 16
67 }
68
Girish Gowdru141ced82018-09-17 20:19:14 -070069 '''
70 # constants used as keys to reference the resource range parameters from
71 # and external KV store.
Craig Lutgen1dd47082018-10-23 13:12:26 -050072 ONU_ID_START_IDX = "onu_id_start"
73 ONU_ID_END_IDX = "onu_id_end"
74 ONU_ID_SHARED_IDX = "onu_id_shared"
Girish Gowdru1e77ea02018-09-24 09:10:35 -070075 ALLOC_ID_START_IDX = "alloc_id_start"
76 ALLOC_ID_END_IDX = "alloc_id_end"
Craig Lutgen1dd47082018-10-23 13:12:26 -050077 ALLOC_ID_SHARED_IDX = "alloc_id_shared"
78 GEMPORT_ID_START_IDX = "gemport_id_start"
79 GEMPORT_ID_END_IDX = "gemport_id_end"
80 GEMPORT_ID_SHARED_IDX = "gemport_id_shared"
Girish Gowdru1e77ea02018-09-24 09:10:35 -070081 NUM_OF_PON_PORT = "pon_ports"
Girish Gowdru141ced82018-09-17 20:19:14 -070082
83 # PON Resource range configuration on the KV store.
Craig Lutgenf7601472018-11-02 13:27:41 +000084 # Format: 'resource_manager/<technology>/resource_ranges/<olt_model_type>'
Girish Gowdru1e77ea02018-09-24 09:10:35 -070085 # The KV store backend is initialized with a path prefix and we need to
86 # provide only the suffix.
87 PON_RESOURCE_RANGE_CONFIG_PATH = 'resource_ranges/{}'
Girish Gowdru141ced82018-09-17 20:19:14 -070088
Girish Gowdru1e77ea02018-09-24 09:10:35 -070089 # resource path suffix
90 ALLOC_ID_POOL_PATH = '{}/alloc_id_pool/{}'
91 GEMPORT_ID_POOL_PATH = '{}/gemport_id_pool/{}'
92 ONU_ID_POOL_PATH = '{}/onu_id_pool/{}'
93
94 # Path on the KV store for storing list of alloc IDs for a given ONU
95 # Format: <device_id>/<(pon_intf_id, onu_id)>/alloc_ids
96 ALLOC_ID_RESOURCE_MAP_PATH = '{}/{}/alloc_ids'
97
98 # Path on the KV store for storing list of gemport IDs for a given ONU
99 # Format: <device_id>/<(pon_intf_id, onu_id)>/gemport_ids
100 GEMPORT_ID_RESOURCE_MAP_PATH = '{}/{}/gemport_ids'
Girish Gowdru141ced82018-09-17 20:19:14 -0700101
102 # Constants for internal usage.
103 PON_INTF_ID = 'pon_intf_id'
104 START_IDX = 'start_idx'
105 END_IDX = 'end_idx'
106 POOL = 'pool'
107
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700108 def __init__(self, technology, extra_args, device_id,
Girish Gowdru141ced82018-09-17 20:19:14 -0700109 backend, host, port):
110 """
111 Create PONResourceManager object.
112
113 :param technology: PON technology
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700114 :param: extra_args: This string contains extra arguments passed during
115 pre-provisioning of OLT and specifies the OLT Vendor type
Girish Gowdru141ced82018-09-17 20:19:14 -0700116 :param device_id: OLT device id
117 :param backend: backend store
118 :param host: ip of backend store
119 :param port: port on which backend store listens
120 :raises exception when invalid backend store passed as an argument
121 """
122 # logger
123 self._log = structlog.get_logger()
124
125 try:
Girish Gowdru141ced82018-09-17 20:19:14 -0700126 self.technology = technology
Craig Lutgenf7601472018-11-02 13:27:41 +0000127 self.extra_args = extra_args
Girish Gowdru141ced82018-09-17 20:19:14 -0700128 self.device_id = device_id
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700129 self.backend = backend
130 self.host = host
131 self.port = port
Craig Lutgenf7601472018-11-02 13:27:41 +0000132 self.olt_model = None
Craig Lutgen1dd47082018-10-23 13:12:26 -0500133
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700134 self._kv_store = ResourceKvStore(technology, device_id, backend,
135 host, port)
Craig Lutgen1dd47082018-10-23 13:12:26 -0500136
Girish Gowdru141ced82018-09-17 20:19:14 -0700137 # Below attribute, pon_resource_ranges, should be initialized
138 # by reading from KV store.
139 self.pon_resource_ranges = dict()
Craig Lutgen1dd47082018-10-23 13:12:26 -0500140 self.pon_resource_ranges[PONResourceManager.ONU_ID_SHARED_IDX] = None
141 self.pon_resource_ranges[PONResourceManager.ALLOC_ID_SHARED_IDX] = None
142 self.pon_resource_ranges[PONResourceManager.GEMPORT_ID_SHARED_IDX] = None
143
144 self.shared_resource_mgrs = dict()
145 self.shared_resource_mgrs[PONResourceManager.ONU_ID_SHARED_IDX] = None
146 self.shared_resource_mgrs[PONResourceManager.ALLOC_ID_SHARED_IDX] = None
147 self.shared_resource_mgrs[PONResourceManager.GEMPORT_ID_SHARED_IDX] = None
148
149 self.shared_idx_by_type = dict()
150 self.shared_idx_by_type[PONResourceManager.ONU_ID] = PONResourceManager.ONU_ID_SHARED_IDX
151 self.shared_idx_by_type[PONResourceManager.ALLOC_ID] = PONResourceManager.ALLOC_ID_SHARED_IDX
152 self.shared_idx_by_type[PONResourceManager.GEMPORT_ID] = PONResourceManager.GEMPORT_ID_SHARED_IDX
153
Craig Lutgen65423ce2018-10-29 23:24:21 -0500154 self.intf_ids = None
Craig Lutgen1dd47082018-10-23 13:12:26 -0500155
Girish Gowdru141ced82018-09-17 20:19:14 -0700156 except Exception as e:
157 self._log.exception("exception-in-init")
158 raise Exception(e)
159
Girish Gowdru141ced82018-09-17 20:19:14 -0700160 def init_resource_ranges_from_kv_store(self):
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700161 """
162 Initialize PON resource ranges with config fetched from kv store.
Girish Gowdru141ced82018-09-17 20:19:14 -0700163
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700164 :return boolean: True if PON resource ranges initialized else false
165 """
Craig Lutgenf7601472018-11-02 13:27:41 +0000166 self.olt_model = self._get_olt_model()
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700167 # Try to initialize the PON Resource Ranges from KV store based on the
Craig Lutgenf7601472018-11-02 13:27:41 +0000168 # OLT model key, if available
169 if self.olt_model is None:
170 self._log.info("device-model-unavailable--not-reading-from-kv-store")
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700171 return False
Girish Gowdru141ced82018-09-17 20:19:14 -0700172
Craig Lutgenf7601472018-11-02 13:27:41 +0000173 path = self.PON_RESOURCE_RANGE_CONFIG_PATH.format(self.olt_model)
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700174 try:
175 # get resource from kv store
176 result = self._kv_store.get_from_kv_store(path)
177
178 if result is None:
179 self._log.debug("resource-range-config-unavailable-on-kvstore")
180 return False
181
182 resource_range_config = result
183
184 if resource_range_config is not None:
185 self.pon_resource_ranges = json.loads(resource_range_config)
186 self._log.debug("Init-resource-ranges-from-kvstore-success",
187 pon_resource_ranges=self.pon_resource_ranges,
188 path=path)
189 return True
190
191 except Exception as e:
192 self._log.exception("error-initializing-resource-range-from-kv-store",
193 e=e)
194 return False
Girish Gowdru141ced82018-09-17 20:19:14 -0700195
Craig Lutgen1dd47082018-10-23 13:12:26 -0500196
197 def update_range_(self, start_idx, start, end_idx, end, shared_idx, shared_pool_id, shared_resource_mgr):
198 if (start is not None) and \
199 (start_idx not in self.pon_resource_ranges or self.pon_resource_ranges[start_idx] < start):
200 self.pon_resource_ranges[start_idx] = start
201 if (end is not None) and \
202 (end_idx not in self.pon_resource_ranges or self.pon_resource_ranges[end_idx] > end):
203 self.pon_resource_ranges[end_idx] = end
204 if (shared_pool_id is not None) and \
205 (shared_idx not in self.pon_resource_ranges or self.pon_resource_ranges[shared_idx] is None):
206 self.pon_resource_ranges[shared_idx] = shared_pool_id
207 if (shared_resource_mgr is not None) and \
208 (shared_idx not in self.shared_resource_mgrs or self.shared_resource_mgrs[shared_idx] is None):
209 self.shared_resource_mgrs[shared_idx] = shared_resource_mgr
210
211 def update_ranges(self,
212 onu_id_start_idx=None,
213 onu_id_end_idx=None,
214 onu_id_shared_pool_id=None,
215 onu_id_shared_resource_mgr=None,
216 alloc_id_start_idx=None,
217 alloc_id_end_idx=None,
218 alloc_id_shared_pool_id=None,
219 alloc_id_shared_resource_mgr=None,
220 gemport_id_start_idx=None,
221 gemport_id_end_idx=None,
222 gemport_id_shared_pool_id=None,
223 gemport_id_shared_resource_mgr=None):
224
225 self.update_range_(PONResourceManager.ONU_ID_START_IDX, onu_id_start_idx,
226 PONResourceManager.ONU_ID_END_IDX, onu_id_end_idx,
227 PONResourceManager.ONU_ID_SHARED_IDX, onu_id_shared_pool_id,
228 onu_id_shared_resource_mgr)
229
230 self.update_range_(PONResourceManager.ALLOC_ID_START_IDX, alloc_id_start_idx,
231 PONResourceManager.ALLOC_ID_END_IDX, alloc_id_end_idx,
232 PONResourceManager.ALLOC_ID_SHARED_IDX, alloc_id_shared_pool_id,
233 alloc_id_shared_resource_mgr)
234
235 self.update_range_(PONResourceManager.GEMPORT_ID_START_IDX, gemport_id_start_idx,
236 PONResourceManager.GEMPORT_ID_END_IDX, gemport_id_end_idx,
237 PONResourceManager.GEMPORT_ID_SHARED_IDX, gemport_id_shared_pool_id,
238 gemport_id_shared_resource_mgr)
239
240 def init_default_pon_resource_ranges(self,
241 onu_id_start_idx=1,
242 onu_id_end_idx=127,
243 onu_id_shared_pool_id=None,
Girish Gowdru141ced82018-09-17 20:19:14 -0700244 alloc_id_start_idx=1024,
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700245 alloc_id_end_idx=2816,
Craig Lutgen1dd47082018-10-23 13:12:26 -0500246 alloc_id_shared_pool_id=None,
247 gemport_id_start_idx=1024,
248 gemport_id_end_idx=8960,
249 gemport_id_shared_pool_id=None,
250 num_of_pon_ports=16,
251 intf_ids=None):
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700252 """
253 Initialize default PON resource ranges
254
Craig Lutgen1dd47082018-10-23 13:12:26 -0500255 :param onu_id_start_idx: onu id start index
256 :param onu_id_end_idx: onu id end index
257 :param onu_id_shared_pool_id: pool idx for id shared by all intfs or None for no sharing
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700258 :param alloc_id_start_idx: alloc id start index
259 :param alloc_id_end_idx: alloc id end index
Craig Lutgen1dd47082018-10-23 13:12:26 -0500260 :param alloc_id_shared_pool_id: pool idx for alloc id shared by all intfs or None for no sharing
261 :param gemport_id_start_idx: gemport id start index
262 :param gemport_id_end_idx: gemport id end index
263 :param gemport_id_shared_pool_id: pool idx for gemport id shared by all intfs or None for no sharing
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700264 :param num_of_pon_ports: number of PON ports
Craig Lutgen1dd47082018-10-23 13:12:26 -0500265 :param intf_ids: interfaces serviced by this manager
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700266 """
Girish Gowdru141ced82018-09-17 20:19:14 -0700267 self._log.info("initialize-default-resource-range-values")
Craig Lutgen1dd47082018-10-23 13:12:26 -0500268
269 self.update_ranges(onu_id_start_idx, onu_id_end_idx, onu_id_shared_pool_id, None,
270 alloc_id_start_idx, alloc_id_end_idx, alloc_id_shared_pool_id, None,
271 gemport_id_start_idx, gemport_id_end_idx, gemport_id_shared_pool_id, None)
272
273 if intf_ids is None:
274 intf_ids = range(0, num_of_pon_ports)
275
276 self.intf_ids = intf_ids
Girish Gowdru141ced82018-09-17 20:19:14 -0700277
278 def init_device_resource_pool(self):
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700279 """
280 Initialize resource pool for all PON ports.
281 """
Craig Lutgen1dd47082018-10-23 13:12:26 -0500282
283 self._log.info("init-device-resource-pool", technology=self.technology,
284 pon_resource_ranges=self.pon_resource_ranges)
285
286 for i in self.intf_ids:
287 shared_pool_id = self.pon_resource_ranges[PONResourceManager.ONU_ID_SHARED_IDX]
288 if shared_pool_id is not None: i = shared_pool_id
Girish Gowdru141ced82018-09-17 20:19:14 -0700289 self.init_resource_id_pool(
290 pon_intf_id=i,
291 resource_type=PONResourceManager.ONU_ID,
292 start_idx=self.pon_resource_ranges[
Craig Lutgen1dd47082018-10-23 13:12:26 -0500293 PONResourceManager.ONU_ID_START_IDX],
Girish Gowdru141ced82018-09-17 20:19:14 -0700294 end_idx=self.pon_resource_ranges[
Craig Lutgen1dd47082018-10-23 13:12:26 -0500295 PONResourceManager.ONU_ID_END_IDX])
296 if shared_pool_id is not None: break
Girish Gowdru141ced82018-09-17 20:19:14 -0700297
Craig Lutgen1dd47082018-10-23 13:12:26 -0500298 for i in self.intf_ids:
299 shared_pool_id = self.pon_resource_ranges[PONResourceManager.ALLOC_ID_SHARED_IDX]
300 if shared_pool_id is not None: i = shared_pool_id
301 self.init_resource_id_pool(
302 pon_intf_id=i,
303 resource_type=PONResourceManager.ALLOC_ID,
304 start_idx=self.pon_resource_ranges[
305 PONResourceManager.ALLOC_ID_START_IDX],
306 end_idx=self.pon_resource_ranges[
307 PONResourceManager.ALLOC_ID_END_IDX])
308 if shared_pool_id is not None: break
Girish Gowdru141ced82018-09-17 20:19:14 -0700309
Craig Lutgen1dd47082018-10-23 13:12:26 -0500310 for i in self.intf_ids:
311 shared_pool_id = self.pon_resource_ranges[PONResourceManager.GEMPORT_ID_SHARED_IDX]
312 if shared_pool_id is not None: i = shared_pool_id
313 self.init_resource_id_pool(
314 pon_intf_id=i,
315 resource_type=PONResourceManager.GEMPORT_ID,
316 start_idx=self.pon_resource_ranges[
317 PONResourceManager.GEMPORT_ID_START_IDX],
318 end_idx=self.pon_resource_ranges[
319 PONResourceManager.GEMPORT_ID_END_IDX])
320 if shared_pool_id is not None: break
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700321
Girish Gowdru141ced82018-09-17 20:19:14 -0700322 def clear_device_resource_pool(self):
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700323 """
324 Clear resource pool of all PON ports.
325 """
Craig Lutgen1dd47082018-10-23 13:12:26 -0500326 for i in self.intf_ids:
327 shared_pool_id = self.pon_resource_ranges[PONResourceManager.ONU_ID_SHARED_IDX]
328 if shared_pool_id is not None: i = shared_pool_id
Girish Gowdru141ced82018-09-17 20:19:14 -0700329 self.clear_resource_id_pool(
330 pon_intf_id=i,
331 resource_type=PONResourceManager.ONU_ID,
332 )
Craig Lutgen1dd47082018-10-23 13:12:26 -0500333 if shared_pool_id is not None: break
Girish Gowdru141ced82018-09-17 20:19:14 -0700334
Craig Lutgen1dd47082018-10-23 13:12:26 -0500335 for i in self.intf_ids:
336 shared_pool_id = self.pon_resource_ranges[PONResourceManager.ALLOC_ID_SHARED_IDX]
337 if shared_pool_id is not None: i = shared_pool_id
338 self.clear_resource_id_pool(
339 pon_intf_id=i,
340 resource_type=PONResourceManager.ALLOC_ID,
341 )
342 if shared_pool_id is not None: break
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700343
Craig Lutgen1dd47082018-10-23 13:12:26 -0500344 for i in self.intf_ids:
345 shared_pool_id = self.pon_resource_ranges[PONResourceManager.GEMPORT_ID_SHARED_IDX]
346 if shared_pool_id is not None: i = shared_pool_id
347 self.clear_resource_id_pool(
348 pon_intf_id=i,
349 resource_type=PONResourceManager.GEMPORT_ID,
350 )
351 if shared_pool_id is not None: break
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700352
Girish Gowdru141ced82018-09-17 20:19:14 -0700353 def init_resource_id_pool(self, pon_intf_id, resource_type, start_idx,
354 end_idx):
355 """
356 Initialize Resource ID pool for a given Resource Type on a given PON Port
357
358 :param pon_intf_id: OLT PON interface id
359 :param resource_type: String to identify type of resource
360 :param start_idx: start index for onu id pool
361 :param end_idx: end index for onu id pool
362 :return boolean: True if resource id pool initialized else false
363 """
364 status = False
Craig Lutgen1dd47082018-10-23 13:12:26 -0500365
366 # delegate to the master instance if sharing enabled across instances
367 shared_resource_mgr = self.shared_resource_mgrs[self.shared_idx_by_type[resource_type]]
368 if shared_resource_mgr is not None and shared_resource_mgr is not self:
369 return shared_resource_mgr.init_resource_id_pool(pon_intf_id, resource_type,
370 start_idx, end_idx)
371
Girish Gowdru141ced82018-09-17 20:19:14 -0700372 path = self._get_path(pon_intf_id, resource_type)
373 if path is None:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700374 return status
Girish Gowdru141ced82018-09-17 20:19:14 -0700375
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700376 try:
377 # In case of adapter reboot and reconciliation resource in kv store
378 # checked for its presence if not kv store update happens
379 resource = self._get_resource(path)
Girish Gowdru141ced82018-09-17 20:19:14 -0700380
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700381 if resource is not None:
382 self._log.info("Resource-already-present-in-store", path=path)
Girish Gowdru141ced82018-09-17 20:19:14 -0700383 status = True
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700384 else:
385 resource = self._format_resource(pon_intf_id, start_idx,
386 end_idx)
387 self._log.info("Resource-initialized", path=path)
Girish Gowdru141ced82018-09-17 20:19:14 -0700388
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700389 # Add resource as json in kv store.
390 result = self._kv_store.update_to_kv_store(path, resource)
391 if result is True:
392 status = True
393
394 except Exception as e:
395 self._log.exception("error-initializing-resource-pool", e=e)
396
397 return status
398
Girish Gowdru141ced82018-09-17 20:19:14 -0700399 def get_resource_id(self, pon_intf_id, resource_type, num_of_id=1):
400 """
401 Create alloc/gemport/onu id for given OLT PON interface.
402
403 :param pon_intf_id: OLT PON interface id
404 :param resource_type: String to identify type of resource
405 :param num_of_id: required number of ids
406 :return list/int/None: list, int or None if resource type is
407 alloc_id/gemport_id, onu_id or invalid type
408 respectively
409 """
410 result = None
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700411
Craig Lutgen1dd47082018-10-23 13:12:26 -0500412 # delegate to the master instance if sharing enabled across instances
413 shared_resource_mgr = self.shared_resource_mgrs[self.shared_idx_by_type[resource_type]]
414 if shared_resource_mgr is not None and shared_resource_mgr is not self:
415 return shared_resource_mgr.get_resource_id(pon_intf_id, resource_type)
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700416
Girish Gowdru141ced82018-09-17 20:19:14 -0700417 path = self._get_path(pon_intf_id, resource_type)
418 if path is None:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700419 return result
Girish Gowdru141ced82018-09-17 20:19:14 -0700420
Girish Gowdru141ced82018-09-17 20:19:14 -0700421 try:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700422 resource = self._get_resource(path)
Girish Gowdru141ced82018-09-17 20:19:14 -0700423 if resource is not None and resource_type == \
424 PONResourceManager.ONU_ID:
425 result = self._generate_next_id(resource)
426 elif resource is not None and (
427 resource_type == PONResourceManager.GEMPORT_ID or
428 resource_type == PONResourceManager.ALLOC_ID):
429 result = list()
430 while num_of_id > 0:
431 result.append(self._generate_next_id(resource))
432 num_of_id -= 1
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700433 else:
434 raise Exception("get-resource-failed")
Girish Gowdru141ced82018-09-17 20:19:14 -0700435
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700436 self._log.debug("Get-" + resource_type + "-success", result=result,
437 path=path)
Girish Gowdru141ced82018-09-17 20:19:14 -0700438 # Update resource in kv store
439 self._update_resource(path, resource)
440
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700441 except Exception as e:
Girish Gowdru141ced82018-09-17 20:19:14 -0700442 self._log.exception("Get-" + resource_type + "-id-failed",
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700443 path=path, e=e)
444 return result
Girish Gowdru141ced82018-09-17 20:19:14 -0700445
Girish Gowdru141ced82018-09-17 20:19:14 -0700446 def free_resource_id(self, pon_intf_id, resource_type, release_content):
447 """
448 Release alloc/gemport/onu id for given OLT PON interface.
449
450 :param pon_intf_id: OLT PON interface id
451 :param resource_type: String to identify type of resource
452 :param release_content: required number of ids
453 :return boolean: True if all IDs in given release_content released
454 else False
455 """
456 status = False
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700457
Craig Lutgen1dd47082018-10-23 13:12:26 -0500458 # delegate to the master instance if sharing enabled across instances
459 shared_resource_mgr = self.shared_resource_mgrs[self.shared_idx_by_type[resource_type]]
460 if shared_resource_mgr is not None and shared_resource_mgr is not self:
461 return shared_resource_mgr.free_resource_id(pon_intf_id, resource_type)
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700462
Girish Gowdru141ced82018-09-17 20:19:14 -0700463 path = self._get_path(pon_intf_id, resource_type)
464 if path is None:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700465 return status
Girish Gowdru141ced82018-09-17 20:19:14 -0700466
Girish Gowdru141ced82018-09-17 20:19:14 -0700467 try:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700468 resource = self._get_resource(path)
Girish Gowdru141ced82018-09-17 20:19:14 -0700469 if resource is not None and resource_type == \
470 PONResourceManager.ONU_ID:
471 self._release_id(resource, release_content)
472 elif resource is not None and (
473 resource_type == PONResourceManager.ALLOC_ID or
474 resource_type == PONResourceManager.GEMPORT_ID):
475 for content in release_content:
476 self._release_id(resource, content)
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700477 else:
478 raise Exception("get-resource-failed")
479
Girish Gowdru141ced82018-09-17 20:19:14 -0700480 self._log.debug("Free-" + resource_type + "-success", path=path)
481
482 # Update resource in kv store
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700483 status = self._update_resource(path, resource)
Girish Gowdru141ced82018-09-17 20:19:14 -0700484
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700485 except Exception as e:
486 self._log.exception("Free-" + resource_type + "-failed",
487 path=path, e=e)
488 return status
Girish Gowdru141ced82018-09-17 20:19:14 -0700489
Girish Gowdru141ced82018-09-17 20:19:14 -0700490 def clear_resource_id_pool(self, pon_intf_id, resource_type):
491 """
492 Clear Resource Pool for a given Resource Type on a given PON Port.
493
494 :return boolean: True if removed else False
495 """
Craig Lutgen1dd47082018-10-23 13:12:26 -0500496
497 # delegate to the master instance if sharing enabled across instances
498 shared_resource_mgr = self.shared_resource_mgrs[self.shared_idx_by_type[resource_type]]
499 if shared_resource_mgr is not None and shared_resource_mgr is not self:
500 return shared_resource_mgr.clear_resource_id_pool(pon_intf_id, resource_type)
501
Girish Gowdru141ced82018-09-17 20:19:14 -0700502 path = self._get_path(pon_intf_id, resource_type)
503 if path is None:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700504 return False
Girish Gowdru141ced82018-09-17 20:19:14 -0700505
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700506 try:
507 result = self._kv_store.remove_from_kv_store(path)
508 if result is True:
509 self._log.debug("Resource-pool-cleared",
510 device_id=self.device_id,
511 path=path)
512 return True
513 except Exception as e:
514 self._log.exception("error-clearing-resource-pool", e=e)
515
Girish Gowdru141ced82018-09-17 20:19:14 -0700516 self._log.error("Clear-resource-pool-failed", device_id=self.device_id,
517 path=path)
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700518 return False
519
520 def init_resource_map(self, pon_intf_onu_id):
521 """
522 Initialize resource map
523
524 :param pon_intf_onu_id: reference of PON interface id and onu id
525 """
526 # initialize pon_intf_onu_id tuple to alloc_ids map
527 alloc_id_path = PONResourceManager.ALLOC_ID_RESOURCE_MAP_PATH.format(
528 self.device_id, str(pon_intf_onu_id)
529 )
530 alloc_ids = list()
531 self._kv_store.update_to_kv_store(
532 alloc_id_path, json.dumps(alloc_ids)
533 )
534
535 # initialize pon_intf_onu_id tuple to gemport_ids map
536 gemport_id_path = PONResourceManager.GEMPORT_ID_RESOURCE_MAP_PATH.format(
537 self.device_id, str(pon_intf_onu_id)
538 )
539 gemport_ids = list()
540 self._kv_store.update_to_kv_store(
541 gemport_id_path, json.dumps(gemport_ids)
542 )
543
544 def remove_resource_map(self, pon_intf_onu_id):
545 """
546 Remove resource map
547
548 :param pon_intf_onu_id: reference of PON interface id and onu id
549 """
550 # remove pon_intf_onu_id tuple to alloc_ids map
551 alloc_id_path = PONResourceManager.ALLOC_ID_RESOURCE_MAP_PATH.format(
552 self.device_id, str(pon_intf_onu_id)
553 )
554 self._kv_store.remove_from_kv_store(alloc_id_path)
555
556 # remove pon_intf_onu_id tuple to gemport_ids map
557 gemport_id_path = PONResourceManager.GEMPORT_ID_RESOURCE_MAP_PATH.format(
558 self.device_id, str(pon_intf_onu_id)
559 )
560 self._kv_store.remove_from_kv_store(gemport_id_path)
561
562 def get_current_alloc_ids_for_onu(self, pon_intf_onu_id):
563 """
564 Get currently configured alloc ids for given pon_intf_onu_id
565
566 :param pon_intf_onu_id: reference of PON interface id and onu id
567 """
568 path = PONResourceManager.ALLOC_ID_RESOURCE_MAP_PATH.format(
569 self.device_id,
570 str(pon_intf_onu_id))
571 value = self._kv_store.get_from_kv_store(path)
572 if value is not None:
573 alloc_id_list = json.loads(value)
574 if len(alloc_id_list) > 0:
575 return alloc_id_list
576
577 return None
578
579 def get_current_gemport_ids_for_onu(self, pon_intf_onu_id):
580 """
581 Get currently configured gemport ids for given pon_intf_onu_id
582
583 :param pon_intf_onu_id: reference of PON interface id and onu id
584 """
585
586 path = PONResourceManager.GEMPORT_ID_RESOURCE_MAP_PATH.format(
587 self.device_id,
588 str(pon_intf_onu_id))
589 value = self._kv_store.get_from_kv_store(path)
590 if value is not None:
591 gemport_id_list = json.loads(value)
592 if len(gemport_id_list) > 0:
593 return gemport_id_list
594
595 return None
596
597 def update_alloc_ids_for_onu(self, pon_intf_onu_id, alloc_ids):
598 """
599 Update currently configured alloc ids for given pon_intf_onu_id
600
601 :param pon_intf_onu_id: reference of PON interface id and onu id
602 """
603 path = PONResourceManager.ALLOC_ID_RESOURCE_MAP_PATH.format(
604 self.device_id, str(pon_intf_onu_id)
605 )
606 self._kv_store.update_to_kv_store(
607 path, json.dumps(alloc_ids)
608 )
609
610 def update_gemport_ids_for_onu(self, pon_intf_onu_id, gemport_ids):
611 """
612 Update currently configured gemport ids for given pon_intf_onu_id
613
614 :param pon_intf_onu_id: reference of PON interface id and onu id
615 """
616 path = PONResourceManager.GEMPORT_ID_RESOURCE_MAP_PATH.format(
617 self.device_id, str(pon_intf_onu_id)
618 )
619 self._kv_store.update_to_kv_store(
620 path, json.dumps(gemport_ids)
621 )
622
Craig Lutgenf7601472018-11-02 13:27:41 +0000623 def _get_olt_model(self):
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700624 """
Craig Lutgenf7601472018-11-02 13:27:41 +0000625 Get olt model variant
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700626
Craig Lutgenf7601472018-11-02 13:27:41 +0000627 :return: type of olt model
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700628 """
Craig Lutgenf7601472018-11-02 13:27:41 +0000629 olt_model = None
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700630 if self.extra_args and len(self.extra_args) > 0:
631 parser = OltVendorArgumentParser(add_help=False)
Craig Lutgenf7601472018-11-02 13:27:41 +0000632 parser.add_argument(PONResourceManager.OLT_MODEL_ARG, '-m', action='store', default='default')
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700633 try:
634 args = parser.parse_args(shlex.split(self.extra_args))
635 self._log.debug('parsing-extra-arguments', args=args)
Craig Lutgenf7601472018-11-02 13:27:41 +0000636 olt_model = args.olt_model
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700637 except ArgumentError as e:
638 self._log.exception('invalid-arguments: {}', e=e)
639 except Exception as e:
640 self._log.exception('option-parsing-error: {}', e=e)
641
Craig Lutgenf7601472018-11-02 13:27:41 +0000642 self._log.debug('olt-model', olt_model=olt_model)
643 return olt_model
Girish Gowdru141ced82018-09-17 20:19:14 -0700644
645 def _generate_next_id(self, resource):
646 """
647 Generate unique id having OFFSET as start index.
648
649 :param resource: resource used to generate ID
650 :return int: generated id
651 """
652 pos = resource[PONResourceManager.POOL].find('0b0')
653 resource[PONResourceManager.POOL].set(1, pos)
654 return pos[0] + resource[PONResourceManager.START_IDX]
655
656 def _release_id(self, resource, unique_id):
657 """
658 Release unique id having OFFSET as start index.
659
660 :param resource: resource used to release ID
661 :param unique_id: id need to be released
662 """
663 pos = ((int(unique_id)) - resource[PONResourceManager.START_IDX])
664 resource[PONResourceManager.POOL].set(0, pos)
665
666 def _get_path(self, pon_intf_id, resource_type):
667 """
668 Get path for given resource type.
669
670 :param pon_intf_id: OLT PON interface id
671 :param resource_type: String to identify type of resource
672 :return: path for given resource type
673 """
Craig Lutgen1dd47082018-10-23 13:12:26 -0500674
675 shared_pool_id = self.pon_resource_ranges[self.shared_idx_by_type[resource_type]]
676 if shared_pool_id is not None: pon_intf_id = shared_pool_id
677
Girish Gowdru141ced82018-09-17 20:19:14 -0700678 path = None
679 if resource_type == PONResourceManager.ONU_ID:
680 path = self._get_onu_id_resource_path(pon_intf_id)
681 elif resource_type == PONResourceManager.ALLOC_ID:
682 path = self._get_alloc_id_resource_path(pon_intf_id)
683 elif resource_type == PONResourceManager.GEMPORT_ID:
684 path = self._get_gemport_id_resource_path(pon_intf_id)
685 else:
686 self._log.error("invalid-resource-pool-identifier")
687 return path
688
689 def _get_alloc_id_resource_path(self, pon_intf_id):
690 """
691 Get alloc id resource path.
692
693 :param pon_intf_id: OLT PON interface id
694 :return: alloc id resource path
695 """
696 return PONResourceManager.ALLOC_ID_POOL_PATH.format(
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700697 self.device_id, pon_intf_id)
Girish Gowdru141ced82018-09-17 20:19:14 -0700698
699 def _get_gemport_id_resource_path(self, pon_intf_id):
700 """
701 Get gemport id resource path.
702
703 :param pon_intf_id: OLT PON interface id
704 :return: gemport id resource path
705 """
706 return PONResourceManager.GEMPORT_ID_POOL_PATH.format(
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700707 self.device_id, pon_intf_id)
Girish Gowdru141ced82018-09-17 20:19:14 -0700708
709 def _get_onu_id_resource_path(self, pon_intf_id):
710 """
711 Get onu id resource path.
712
713 :param pon_intf_id: OLT PON interface id
714 :return: onu id resource path
715 """
716 return PONResourceManager.ONU_ID_POOL_PATH.format(
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700717 self.device_id, pon_intf_id)
Girish Gowdru141ced82018-09-17 20:19:14 -0700718
Girish Gowdru141ced82018-09-17 20:19:14 -0700719 def _update_resource(self, path, resource):
720 """
721 Update resource in resource kv store.
722
723 :param path: path to update resource
724 :param resource: resource need to be updated
725 :return boolean: True if resource updated in kv store else False
726 """
727 resource[PONResourceManager.POOL] = \
728 resource[PONResourceManager.POOL].bin
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700729 result = self._kv_store.update_to_kv_store(path, json.dumps(resource))
730 if result is True:
731 return True
732 return False
Girish Gowdru141ced82018-09-17 20:19:14 -0700733
Girish Gowdru141ced82018-09-17 20:19:14 -0700734 def _get_resource(self, path):
735 """
736 Get resource from kv store.
737
738 :param path: path to get resource
739 :return: resource if resource present in kv store else None
740 """
741 # get resource from kv store
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700742 result = self._kv_store.get_from_kv_store(path)
743 if result is None:
744 return result
745 self._log.info("dumping resource", result=result)
746 resource = result
Girish Gowdru141ced82018-09-17 20:19:14 -0700747
748 if resource is not None:
749 # decode resource fetched from backend store to dictionary
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700750 resource = json.loads(resource)
Girish Gowdru141ced82018-09-17 20:19:14 -0700751
752 # resource pool in backend store stored as binary string whereas to
753 # access the pool to generate/release IDs it need to be converted
754 # as BitArray
755 resource[PONResourceManager.POOL] = \
756 BitArray('0b' + resource[PONResourceManager.POOL])
757
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700758 return resource
Girish Gowdru141ced82018-09-17 20:19:14 -0700759
760 def _format_resource(self, pon_intf_id, start_idx, end_idx):
761 """
762 Format resource as json.
763
764 :param pon_intf_id: OLT PON interface id
765 :param start_idx: start index for id pool
766 :param end_idx: end index for id pool
767 :return dictionary: resource formatted as dictionary
768 """
769 # Format resource as json to be stored in backend store
770 resource = dict()
771 resource[PONResourceManager.PON_INTF_ID] = pon_intf_id
772 resource[PONResourceManager.START_IDX] = start_idx
773 resource[PONResourceManager.END_IDX] = end_idx
774
775 # resource pool stored in backend store as binary string
776 resource[PONResourceManager.POOL] = BitArray(end_idx).bin
777
778 return json.dumps(resource)