blob: ebe3995ba7c3a1f261a1ef95da4248294561294e [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
49 # The resource ranges for a given device vendor_type should be placed
50 # at 'resource_manager/<technology>/resource_ranges/<olt_vendor_type>'
51 # path on the KV store.
52 # If Resource Range parameters are to be read from the external KV store,
53 # they are expected to be stored in the following format.
54 # Note: All parameters are MANDATORY for now.
55 '''
Girish Gowdru1e77ea02018-09-24 09:10:35 -070056 {
57 "onu_id_start": 1,
58 "onu_id_end": 127,
59 "alloc_id_start": 1024,
60 "alloc_id_end": 2816,
61 "gemport_id_start": 1024,
62 "gemport_id_end": 8960,
63 "pon_ports": 16
64 }
65
Girish Gowdru141ced82018-09-17 20:19:14 -070066 '''
67 # constants used as keys to reference the resource range parameters from
68 # and external KV store.
Craig Lutgen1dd47082018-10-23 13:12:26 -050069 ONU_ID_START_IDX = "onu_id_start"
70 ONU_ID_END_IDX = "onu_id_end"
71 ONU_ID_SHARED_IDX = "onu_id_shared"
Girish Gowdru1e77ea02018-09-24 09:10:35 -070072 ALLOC_ID_START_IDX = "alloc_id_start"
73 ALLOC_ID_END_IDX = "alloc_id_end"
Craig Lutgen1dd47082018-10-23 13:12:26 -050074 ALLOC_ID_SHARED_IDX = "alloc_id_shared"
75 GEMPORT_ID_START_IDX = "gemport_id_start"
76 GEMPORT_ID_END_IDX = "gemport_id_end"
77 GEMPORT_ID_SHARED_IDX = "gemport_id_shared"
Girish Gowdru1e77ea02018-09-24 09:10:35 -070078 NUM_OF_PON_PORT = "pon_ports"
Girish Gowdru141ced82018-09-17 20:19:14 -070079
80 # PON Resource range configuration on the KV store.
81 # Format: 'resource_manager/<technology>/resource_ranges/<olt_vendor_type>'
Girish Gowdru1e77ea02018-09-24 09:10:35 -070082 # The KV store backend is initialized with a path prefix and we need to
83 # provide only the suffix.
84 PON_RESOURCE_RANGE_CONFIG_PATH = 'resource_ranges/{}'
Girish Gowdru141ced82018-09-17 20:19:14 -070085
Girish Gowdru1e77ea02018-09-24 09:10:35 -070086 # resource path suffix
87 ALLOC_ID_POOL_PATH = '{}/alloc_id_pool/{}'
88 GEMPORT_ID_POOL_PATH = '{}/gemport_id_pool/{}'
89 ONU_ID_POOL_PATH = '{}/onu_id_pool/{}'
90
91 # Path on the KV store for storing list of alloc IDs for a given ONU
92 # Format: <device_id>/<(pon_intf_id, onu_id)>/alloc_ids
93 ALLOC_ID_RESOURCE_MAP_PATH = '{}/{}/alloc_ids'
94
95 # Path on the KV store for storing list of gemport IDs for a given ONU
96 # Format: <device_id>/<(pon_intf_id, onu_id)>/gemport_ids
97 GEMPORT_ID_RESOURCE_MAP_PATH = '{}/{}/gemport_ids'
Girish Gowdru141ced82018-09-17 20:19:14 -070098
99 # Constants for internal usage.
100 PON_INTF_ID = 'pon_intf_id'
101 START_IDX = 'start_idx'
102 END_IDX = 'end_idx'
103 POOL = 'pool'
104
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700105 def __init__(self, technology, extra_args, device_id,
Girish Gowdru141ced82018-09-17 20:19:14 -0700106 backend, host, port):
107 """
108 Create PONResourceManager object.
109
110 :param technology: PON technology
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700111 :param: extra_args: This string contains extra arguments passed during
112 pre-provisioning of OLT and specifies the OLT Vendor type
Girish Gowdru141ced82018-09-17 20:19:14 -0700113 :param device_id: OLT device id
114 :param backend: backend store
115 :param host: ip of backend store
116 :param port: port on which backend store listens
117 :raises exception when invalid backend store passed as an argument
118 """
119 # logger
120 self._log = structlog.get_logger()
121
122 try:
Girish Gowdru141ced82018-09-17 20:19:14 -0700123 self.technology = technology
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700124 self.extra_args = extra_args
Girish Gowdru141ced82018-09-17 20:19:14 -0700125 self.device_id = device_id
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700126 self.backend = backend
127 self.host = host
128 self.port = port
129 self.olt_vendor = None
Craig Lutgen1dd47082018-10-23 13:12:26 -0500130
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700131 self._kv_store = ResourceKvStore(technology, device_id, backend,
132 host, port)
Craig Lutgen1dd47082018-10-23 13:12:26 -0500133
Girish Gowdru141ced82018-09-17 20:19:14 -0700134 # Below attribute, pon_resource_ranges, should be initialized
135 # by reading from KV store.
136 self.pon_resource_ranges = dict()
Craig Lutgen1dd47082018-10-23 13:12:26 -0500137 self.pon_resource_ranges[PONResourceManager.ONU_ID_SHARED_IDX] = None
138 self.pon_resource_ranges[PONResourceManager.ALLOC_ID_SHARED_IDX] = None
139 self.pon_resource_ranges[PONResourceManager.GEMPORT_ID_SHARED_IDX] = None
140
141 self.shared_resource_mgrs = dict()
142 self.shared_resource_mgrs[PONResourceManager.ONU_ID_SHARED_IDX] = None
143 self.shared_resource_mgrs[PONResourceManager.ALLOC_ID_SHARED_IDX] = None
144 self.shared_resource_mgrs[PONResourceManager.GEMPORT_ID_SHARED_IDX] = None
145
146 self.shared_idx_by_type = dict()
147 self.shared_idx_by_type[PONResourceManager.ONU_ID] = PONResourceManager.ONU_ID_SHARED_IDX
148 self.shared_idx_by_type[PONResourceManager.ALLOC_ID] = PONResourceManager.ALLOC_ID_SHARED_IDX
149 self.shared_idx_by_type[PONResourceManager.GEMPORT_ID] = PONResourceManager.GEMPORT_ID_SHARED_IDX
150
151 self.intf_ids = None
152
Girish Gowdru141ced82018-09-17 20:19:14 -0700153 except Exception as e:
154 self._log.exception("exception-in-init")
155 raise Exception(e)
156
Girish Gowdru141ced82018-09-17 20:19:14 -0700157 def init_resource_ranges_from_kv_store(self):
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700158 """
159 Initialize PON resource ranges with config fetched from kv store.
Girish Gowdru141ced82018-09-17 20:19:14 -0700160
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700161 :return boolean: True if PON resource ranges initialized else false
162 """
163 self.olt_vendor = self._get_olt_vendor()
164 # Try to initialize the PON Resource Ranges from KV store based on the
165 # OLT vendor key, if available
166 if self.olt_vendor is None:
167 self._log.info("olt-vendor-unavailable--not-reading-from-kv-store")
168 return False
Girish Gowdru141ced82018-09-17 20:19:14 -0700169
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700170 path = self.PON_RESOURCE_RANGE_CONFIG_PATH.format(self.olt_vendor)
171 try:
172 # get resource from kv store
173 result = self._kv_store.get_from_kv_store(path)
174
175 if result is None:
176 self._log.debug("resource-range-config-unavailable-on-kvstore")
177 return False
178
179 resource_range_config = result
180
181 if resource_range_config is not None:
182 self.pon_resource_ranges = json.loads(resource_range_config)
183 self._log.debug("Init-resource-ranges-from-kvstore-success",
184 pon_resource_ranges=self.pon_resource_ranges,
185 path=path)
186 return True
187
188 except Exception as e:
189 self._log.exception("error-initializing-resource-range-from-kv-store",
190 e=e)
191 return False
Girish Gowdru141ced82018-09-17 20:19:14 -0700192
Craig Lutgen1dd47082018-10-23 13:12:26 -0500193
194 def update_range_(self, start_idx, start, end_idx, end, shared_idx, shared_pool_id, shared_resource_mgr):
195 if (start is not None) and \
196 (start_idx not in self.pon_resource_ranges or self.pon_resource_ranges[start_idx] < start):
197 self.pon_resource_ranges[start_idx] = start
198 if (end is not None) and \
199 (end_idx not in self.pon_resource_ranges or self.pon_resource_ranges[end_idx] > end):
200 self.pon_resource_ranges[end_idx] = end
201 if (shared_pool_id is not None) and \
202 (shared_idx not in self.pon_resource_ranges or self.pon_resource_ranges[shared_idx] is None):
203 self.pon_resource_ranges[shared_idx] = shared_pool_id
204 if (shared_resource_mgr is not None) and \
205 (shared_idx not in self.shared_resource_mgrs or self.shared_resource_mgrs[shared_idx] is None):
206 self.shared_resource_mgrs[shared_idx] = shared_resource_mgr
207
208 def update_ranges(self,
209 onu_id_start_idx=None,
210 onu_id_end_idx=None,
211 onu_id_shared_pool_id=None,
212 onu_id_shared_resource_mgr=None,
213 alloc_id_start_idx=None,
214 alloc_id_end_idx=None,
215 alloc_id_shared_pool_id=None,
216 alloc_id_shared_resource_mgr=None,
217 gemport_id_start_idx=None,
218 gemport_id_end_idx=None,
219 gemport_id_shared_pool_id=None,
220 gemport_id_shared_resource_mgr=None):
221
222 self.update_range_(PONResourceManager.ONU_ID_START_IDX, onu_id_start_idx,
223 PONResourceManager.ONU_ID_END_IDX, onu_id_end_idx,
224 PONResourceManager.ONU_ID_SHARED_IDX, onu_id_shared_pool_id,
225 onu_id_shared_resource_mgr)
226
227 self.update_range_(PONResourceManager.ALLOC_ID_START_IDX, alloc_id_start_idx,
228 PONResourceManager.ALLOC_ID_END_IDX, alloc_id_end_idx,
229 PONResourceManager.ALLOC_ID_SHARED_IDX, alloc_id_shared_pool_id,
230 alloc_id_shared_resource_mgr)
231
232 self.update_range_(PONResourceManager.GEMPORT_ID_START_IDX, gemport_id_start_idx,
233 PONResourceManager.GEMPORT_ID_END_IDX, gemport_id_end_idx,
234 PONResourceManager.GEMPORT_ID_SHARED_IDX, gemport_id_shared_pool_id,
235 gemport_id_shared_resource_mgr)
236
237 def init_default_pon_resource_ranges(self,
238 onu_id_start_idx=1,
239 onu_id_end_idx=127,
240 onu_id_shared_pool_id=None,
Girish Gowdru141ced82018-09-17 20:19:14 -0700241 alloc_id_start_idx=1024,
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700242 alloc_id_end_idx=2816,
Craig Lutgen1dd47082018-10-23 13:12:26 -0500243 alloc_id_shared_pool_id=None,
244 gemport_id_start_idx=1024,
245 gemport_id_end_idx=8960,
246 gemport_id_shared_pool_id=None,
247 num_of_pon_ports=16,
248 intf_ids=None):
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700249 """
250 Initialize default PON resource ranges
251
Craig Lutgen1dd47082018-10-23 13:12:26 -0500252 :param onu_id_start_idx: onu id start index
253 :param onu_id_end_idx: onu id end index
254 :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 -0700255 :param alloc_id_start_idx: alloc id start index
256 :param alloc_id_end_idx: alloc id end index
Craig Lutgen1dd47082018-10-23 13:12:26 -0500257 :param alloc_id_shared_pool_id: pool idx for alloc id shared by all intfs or None for no sharing
258 :param gemport_id_start_idx: gemport id start index
259 :param gemport_id_end_idx: gemport id end index
260 :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 -0700261 :param num_of_pon_ports: number of PON ports
Craig Lutgen1dd47082018-10-23 13:12:26 -0500262 :param intf_ids: interfaces serviced by this manager
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700263 """
Girish Gowdru141ced82018-09-17 20:19:14 -0700264 self._log.info("initialize-default-resource-range-values")
Craig Lutgen1dd47082018-10-23 13:12:26 -0500265
266 self.update_ranges(onu_id_start_idx, onu_id_end_idx, onu_id_shared_pool_id, None,
267 alloc_id_start_idx, alloc_id_end_idx, alloc_id_shared_pool_id, None,
268 gemport_id_start_idx, gemport_id_end_idx, gemport_id_shared_pool_id, None)
269
270 if intf_ids is None:
271 intf_ids = range(0, num_of_pon_ports)
272
273 self.intf_ids = intf_ids
Girish Gowdru141ced82018-09-17 20:19:14 -0700274
275 def init_device_resource_pool(self):
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700276 """
277 Initialize resource pool for all PON ports.
278 """
Craig Lutgen1dd47082018-10-23 13:12:26 -0500279
280 self._log.info("init-device-resource-pool", technology=self.technology,
281 pon_resource_ranges=self.pon_resource_ranges)
282
283 for i in self.intf_ids:
284 shared_pool_id = self.pon_resource_ranges[PONResourceManager.ONU_ID_SHARED_IDX]
285 if shared_pool_id is not None: i = shared_pool_id
Girish Gowdru141ced82018-09-17 20:19:14 -0700286 self.init_resource_id_pool(
287 pon_intf_id=i,
288 resource_type=PONResourceManager.ONU_ID,
289 start_idx=self.pon_resource_ranges[
Craig Lutgen1dd47082018-10-23 13:12:26 -0500290 PONResourceManager.ONU_ID_START_IDX],
Girish Gowdru141ced82018-09-17 20:19:14 -0700291 end_idx=self.pon_resource_ranges[
Craig Lutgen1dd47082018-10-23 13:12:26 -0500292 PONResourceManager.ONU_ID_END_IDX])
293 if shared_pool_id is not None: break
Girish Gowdru141ced82018-09-17 20:19:14 -0700294
Craig Lutgen1dd47082018-10-23 13:12:26 -0500295 for i in self.intf_ids:
296 shared_pool_id = self.pon_resource_ranges[PONResourceManager.ALLOC_ID_SHARED_IDX]
297 if shared_pool_id is not None: i = shared_pool_id
298 self.init_resource_id_pool(
299 pon_intf_id=i,
300 resource_type=PONResourceManager.ALLOC_ID,
301 start_idx=self.pon_resource_ranges[
302 PONResourceManager.ALLOC_ID_START_IDX],
303 end_idx=self.pon_resource_ranges[
304 PONResourceManager.ALLOC_ID_END_IDX])
305 if shared_pool_id is not None: break
Girish Gowdru141ced82018-09-17 20:19:14 -0700306
Craig Lutgen1dd47082018-10-23 13:12:26 -0500307 for i in self.intf_ids:
308 shared_pool_id = self.pon_resource_ranges[PONResourceManager.GEMPORT_ID_SHARED_IDX]
309 if shared_pool_id is not None: i = shared_pool_id
310 self.init_resource_id_pool(
311 pon_intf_id=i,
312 resource_type=PONResourceManager.GEMPORT_ID,
313 start_idx=self.pon_resource_ranges[
314 PONResourceManager.GEMPORT_ID_START_IDX],
315 end_idx=self.pon_resource_ranges[
316 PONResourceManager.GEMPORT_ID_END_IDX])
317 if shared_pool_id is not None: break
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700318
Girish Gowdru141ced82018-09-17 20:19:14 -0700319 def clear_device_resource_pool(self):
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700320 """
321 Clear resource pool of all PON ports.
322 """
Craig Lutgen1dd47082018-10-23 13:12:26 -0500323 for i in self.intf_ids:
324 shared_pool_id = self.pon_resource_ranges[PONResourceManager.ONU_ID_SHARED_IDX]
325 if shared_pool_id is not None: i = shared_pool_id
Girish Gowdru141ced82018-09-17 20:19:14 -0700326 self.clear_resource_id_pool(
327 pon_intf_id=i,
328 resource_type=PONResourceManager.ONU_ID,
329 )
Craig Lutgen1dd47082018-10-23 13:12:26 -0500330 if shared_pool_id is not None: break
Girish Gowdru141ced82018-09-17 20:19:14 -0700331
Craig Lutgen1dd47082018-10-23 13:12:26 -0500332 for i in self.intf_ids:
333 shared_pool_id = self.pon_resource_ranges[PONResourceManager.ALLOC_ID_SHARED_IDX]
334 if shared_pool_id is not None: i = shared_pool_id
335 self.clear_resource_id_pool(
336 pon_intf_id=i,
337 resource_type=PONResourceManager.ALLOC_ID,
338 )
339 if shared_pool_id is not None: break
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700340
Craig Lutgen1dd47082018-10-23 13:12:26 -0500341 for i in self.intf_ids:
342 shared_pool_id = self.pon_resource_ranges[PONResourceManager.GEMPORT_ID_SHARED_IDX]
343 if shared_pool_id is not None: i = shared_pool_id
344 self.clear_resource_id_pool(
345 pon_intf_id=i,
346 resource_type=PONResourceManager.GEMPORT_ID,
347 )
348 if shared_pool_id is not None: break
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700349
Girish Gowdru141ced82018-09-17 20:19:14 -0700350 def init_resource_id_pool(self, pon_intf_id, resource_type, start_idx,
351 end_idx):
352 """
353 Initialize Resource ID pool for a given Resource Type on a given PON Port
354
355 :param pon_intf_id: OLT PON interface id
356 :param resource_type: String to identify type of resource
357 :param start_idx: start index for onu id pool
358 :param end_idx: end index for onu id pool
359 :return boolean: True if resource id pool initialized else false
360 """
361 status = False
Craig Lutgen1dd47082018-10-23 13:12:26 -0500362
363 # delegate to the master instance if sharing enabled across instances
364 shared_resource_mgr = self.shared_resource_mgrs[self.shared_idx_by_type[resource_type]]
365 if shared_resource_mgr is not None and shared_resource_mgr is not self:
366 return shared_resource_mgr.init_resource_id_pool(pon_intf_id, resource_type,
367 start_idx, end_idx)
368
Girish Gowdru141ced82018-09-17 20:19:14 -0700369 path = self._get_path(pon_intf_id, resource_type)
370 if path is None:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700371 return status
Girish Gowdru141ced82018-09-17 20:19:14 -0700372
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700373 try:
374 # In case of adapter reboot and reconciliation resource in kv store
375 # checked for its presence if not kv store update happens
376 resource = self._get_resource(path)
Girish Gowdru141ced82018-09-17 20:19:14 -0700377
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700378 if resource is not None:
379 self._log.info("Resource-already-present-in-store", path=path)
Girish Gowdru141ced82018-09-17 20:19:14 -0700380 status = True
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700381 else:
382 resource = self._format_resource(pon_intf_id, start_idx,
383 end_idx)
384 self._log.info("Resource-initialized", path=path)
Girish Gowdru141ced82018-09-17 20:19:14 -0700385
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700386 # Add resource as json in kv store.
387 result = self._kv_store.update_to_kv_store(path, resource)
388 if result is True:
389 status = True
390
391 except Exception as e:
392 self._log.exception("error-initializing-resource-pool", e=e)
393
394 return status
395
Girish Gowdru141ced82018-09-17 20:19:14 -0700396 def get_resource_id(self, pon_intf_id, resource_type, num_of_id=1):
397 """
398 Create alloc/gemport/onu id for given OLT PON interface.
399
400 :param pon_intf_id: OLT PON interface id
401 :param resource_type: String to identify type of resource
402 :param num_of_id: required number of ids
403 :return list/int/None: list, int or None if resource type is
404 alloc_id/gemport_id, onu_id or invalid type
405 respectively
406 """
407 result = None
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700408
Craig Lutgen1dd47082018-10-23 13:12:26 -0500409 # delegate to the master instance if sharing enabled across instances
410 shared_resource_mgr = self.shared_resource_mgrs[self.shared_idx_by_type[resource_type]]
411 if shared_resource_mgr is not None and shared_resource_mgr is not self:
412 return shared_resource_mgr.get_resource_id(pon_intf_id, resource_type)
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700413
Girish Gowdru141ced82018-09-17 20:19:14 -0700414 path = self._get_path(pon_intf_id, resource_type)
415 if path is None:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700416 return result
Girish Gowdru141ced82018-09-17 20:19:14 -0700417
Girish Gowdru141ced82018-09-17 20:19:14 -0700418 try:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700419 resource = self._get_resource(path)
Girish Gowdru141ced82018-09-17 20:19:14 -0700420 if resource is not None and resource_type == \
421 PONResourceManager.ONU_ID:
422 result = self._generate_next_id(resource)
423 elif resource is not None and (
424 resource_type == PONResourceManager.GEMPORT_ID or
425 resource_type == PONResourceManager.ALLOC_ID):
426 result = list()
427 while num_of_id > 0:
428 result.append(self._generate_next_id(resource))
429 num_of_id -= 1
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700430 else:
431 raise Exception("get-resource-failed")
Girish Gowdru141ced82018-09-17 20:19:14 -0700432
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700433 self._log.debug("Get-" + resource_type + "-success", result=result,
434 path=path)
Girish Gowdru141ced82018-09-17 20:19:14 -0700435 # Update resource in kv store
436 self._update_resource(path, resource)
437
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700438 except Exception as e:
Girish Gowdru141ced82018-09-17 20:19:14 -0700439 self._log.exception("Get-" + resource_type + "-id-failed",
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700440 path=path, e=e)
441 return result
Girish Gowdru141ced82018-09-17 20:19:14 -0700442
Girish Gowdru141ced82018-09-17 20:19:14 -0700443 def free_resource_id(self, pon_intf_id, resource_type, release_content):
444 """
445 Release alloc/gemport/onu id for given OLT PON interface.
446
447 :param pon_intf_id: OLT PON interface id
448 :param resource_type: String to identify type of resource
449 :param release_content: required number of ids
450 :return boolean: True if all IDs in given release_content released
451 else False
452 """
453 status = False
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700454
Craig Lutgen1dd47082018-10-23 13:12:26 -0500455 # delegate to the master instance if sharing enabled across instances
456 shared_resource_mgr = self.shared_resource_mgrs[self.shared_idx_by_type[resource_type]]
457 if shared_resource_mgr is not None and shared_resource_mgr is not self:
458 return shared_resource_mgr.free_resource_id(pon_intf_id, resource_type)
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700459
Girish Gowdru141ced82018-09-17 20:19:14 -0700460 path = self._get_path(pon_intf_id, resource_type)
461 if path is None:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700462 return status
Girish Gowdru141ced82018-09-17 20:19:14 -0700463
Girish Gowdru141ced82018-09-17 20:19:14 -0700464 try:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700465 resource = self._get_resource(path)
Girish Gowdru141ced82018-09-17 20:19:14 -0700466 if resource is not None and resource_type == \
467 PONResourceManager.ONU_ID:
468 self._release_id(resource, release_content)
469 elif resource is not None and (
470 resource_type == PONResourceManager.ALLOC_ID or
471 resource_type == PONResourceManager.GEMPORT_ID):
472 for content in release_content:
473 self._release_id(resource, content)
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700474 else:
475 raise Exception("get-resource-failed")
476
Girish Gowdru141ced82018-09-17 20:19:14 -0700477 self._log.debug("Free-" + resource_type + "-success", path=path)
478
479 # Update resource in kv store
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700480 status = self._update_resource(path, resource)
Girish Gowdru141ced82018-09-17 20:19:14 -0700481
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700482 except Exception as e:
483 self._log.exception("Free-" + resource_type + "-failed",
484 path=path, e=e)
485 return status
Girish Gowdru141ced82018-09-17 20:19:14 -0700486
Girish Gowdru141ced82018-09-17 20:19:14 -0700487 def clear_resource_id_pool(self, pon_intf_id, resource_type):
488 """
489 Clear Resource Pool for a given Resource Type on a given PON Port.
490
491 :return boolean: True if removed else False
492 """
Craig Lutgen1dd47082018-10-23 13:12:26 -0500493
494 # delegate to the master instance if sharing enabled across instances
495 shared_resource_mgr = self.shared_resource_mgrs[self.shared_idx_by_type[resource_type]]
496 if shared_resource_mgr is not None and shared_resource_mgr is not self:
497 return shared_resource_mgr.clear_resource_id_pool(pon_intf_id, resource_type)
498
Girish Gowdru141ced82018-09-17 20:19:14 -0700499 path = self._get_path(pon_intf_id, resource_type)
500 if path is None:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700501 return False
Girish Gowdru141ced82018-09-17 20:19:14 -0700502
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700503 try:
504 result = self._kv_store.remove_from_kv_store(path)
505 if result is True:
506 self._log.debug("Resource-pool-cleared",
507 device_id=self.device_id,
508 path=path)
509 return True
510 except Exception as e:
511 self._log.exception("error-clearing-resource-pool", e=e)
512
Girish Gowdru141ced82018-09-17 20:19:14 -0700513 self._log.error("Clear-resource-pool-failed", device_id=self.device_id,
514 path=path)
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700515 return False
516
517 def init_resource_map(self, pon_intf_onu_id):
518 """
519 Initialize resource map
520
521 :param pon_intf_onu_id: reference of PON interface id and onu id
522 """
523 # initialize pon_intf_onu_id tuple to alloc_ids map
524 alloc_id_path = PONResourceManager.ALLOC_ID_RESOURCE_MAP_PATH.format(
525 self.device_id, str(pon_intf_onu_id)
526 )
527 alloc_ids = list()
528 self._kv_store.update_to_kv_store(
529 alloc_id_path, json.dumps(alloc_ids)
530 )
531
532 # initialize pon_intf_onu_id tuple to gemport_ids map
533 gemport_id_path = PONResourceManager.GEMPORT_ID_RESOURCE_MAP_PATH.format(
534 self.device_id, str(pon_intf_onu_id)
535 )
536 gemport_ids = list()
537 self._kv_store.update_to_kv_store(
538 gemport_id_path, json.dumps(gemport_ids)
539 )
540
541 def remove_resource_map(self, pon_intf_onu_id):
542 """
543 Remove resource map
544
545 :param pon_intf_onu_id: reference of PON interface id and onu id
546 """
547 # remove pon_intf_onu_id tuple to alloc_ids map
548 alloc_id_path = PONResourceManager.ALLOC_ID_RESOURCE_MAP_PATH.format(
549 self.device_id, str(pon_intf_onu_id)
550 )
551 self._kv_store.remove_from_kv_store(alloc_id_path)
552
553 # remove pon_intf_onu_id tuple to gemport_ids map
554 gemport_id_path = PONResourceManager.GEMPORT_ID_RESOURCE_MAP_PATH.format(
555 self.device_id, str(pon_intf_onu_id)
556 )
557 self._kv_store.remove_from_kv_store(gemport_id_path)
558
559 def get_current_alloc_ids_for_onu(self, pon_intf_onu_id):
560 """
561 Get currently configured alloc ids for given pon_intf_onu_id
562
563 :param pon_intf_onu_id: reference of PON interface id and onu id
564 """
565 path = PONResourceManager.ALLOC_ID_RESOURCE_MAP_PATH.format(
566 self.device_id,
567 str(pon_intf_onu_id))
568 value = self._kv_store.get_from_kv_store(path)
569 if value is not None:
570 alloc_id_list = json.loads(value)
571 if len(alloc_id_list) > 0:
572 return alloc_id_list
573
574 return None
575
576 def get_current_gemport_ids_for_onu(self, pon_intf_onu_id):
577 """
578 Get currently configured gemport ids for given pon_intf_onu_id
579
580 :param pon_intf_onu_id: reference of PON interface id and onu id
581 """
582
583 path = PONResourceManager.GEMPORT_ID_RESOURCE_MAP_PATH.format(
584 self.device_id,
585 str(pon_intf_onu_id))
586 value = self._kv_store.get_from_kv_store(path)
587 if value is not None:
588 gemport_id_list = json.loads(value)
589 if len(gemport_id_list) > 0:
590 return gemport_id_list
591
592 return None
593
594 def update_alloc_ids_for_onu(self, pon_intf_onu_id, alloc_ids):
595 """
596 Update currently configured alloc ids for given pon_intf_onu_id
597
598 :param pon_intf_onu_id: reference of PON interface id and onu id
599 """
600 path = PONResourceManager.ALLOC_ID_RESOURCE_MAP_PATH.format(
601 self.device_id, str(pon_intf_onu_id)
602 )
603 self._kv_store.update_to_kv_store(
604 path, json.dumps(alloc_ids)
605 )
606
607 def update_gemport_ids_for_onu(self, pon_intf_onu_id, gemport_ids):
608 """
609 Update currently configured gemport ids for given pon_intf_onu_id
610
611 :param pon_intf_onu_id: reference of PON interface id and onu id
612 """
613 path = PONResourceManager.GEMPORT_ID_RESOURCE_MAP_PATH.format(
614 self.device_id, str(pon_intf_onu_id)
615 )
616 self._kv_store.update_to_kv_store(
617 path, json.dumps(gemport_ids)
618 )
619
620 def _get_olt_vendor(self):
621 """
622 Get olt vendor variant
623
624 :return: type of olt vendor
625 """
626 olt_vendor = None
627 if self.extra_args and len(self.extra_args) > 0:
628 parser = OltVendorArgumentParser(add_help=False)
629 parser.add_argument('--olt_vendor', '-o', action='store',
Craig Lutgen1dd47082018-10-23 13:12:26 -0500630 choices=['default', 'asfvolt16', 'cigolt24',
631 'tlabvolt4', 'tlabvolt8', 'tlabvolt16', 'tlabvolt24'],
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700632 default='default')
633 try:
634 args = parser.parse_args(shlex.split(self.extra_args))
635 self._log.debug('parsing-extra-arguments', args=args)
636 olt_vendor = args.olt_vendor
637 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
642 return olt_vendor
Girish Gowdru141ced82018-09-17 20:19:14 -0700643
644 def _generate_next_id(self, resource):
645 """
646 Generate unique id having OFFSET as start index.
647
648 :param resource: resource used to generate ID
649 :return int: generated id
650 """
651 pos = resource[PONResourceManager.POOL].find('0b0')
652 resource[PONResourceManager.POOL].set(1, pos)
653 return pos[0] + resource[PONResourceManager.START_IDX]
654
655 def _release_id(self, resource, unique_id):
656 """
657 Release unique id having OFFSET as start index.
658
659 :param resource: resource used to release ID
660 :param unique_id: id need to be released
661 """
662 pos = ((int(unique_id)) - resource[PONResourceManager.START_IDX])
663 resource[PONResourceManager.POOL].set(0, pos)
664
665 def _get_path(self, pon_intf_id, resource_type):
666 """
667 Get path for given resource type.
668
669 :param pon_intf_id: OLT PON interface id
670 :param resource_type: String to identify type of resource
671 :return: path for given resource type
672 """
Craig Lutgen1dd47082018-10-23 13:12:26 -0500673
674 shared_pool_id = self.pon_resource_ranges[self.shared_idx_by_type[resource_type]]
675 if shared_pool_id is not None: pon_intf_id = shared_pool_id
676
Girish Gowdru141ced82018-09-17 20:19:14 -0700677 path = None
678 if resource_type == PONResourceManager.ONU_ID:
679 path = self._get_onu_id_resource_path(pon_intf_id)
680 elif resource_type == PONResourceManager.ALLOC_ID:
681 path = self._get_alloc_id_resource_path(pon_intf_id)
682 elif resource_type == PONResourceManager.GEMPORT_ID:
683 path = self._get_gemport_id_resource_path(pon_intf_id)
684 else:
685 self._log.error("invalid-resource-pool-identifier")
686 return path
687
688 def _get_alloc_id_resource_path(self, pon_intf_id):
689 """
690 Get alloc id resource path.
691
692 :param pon_intf_id: OLT PON interface id
693 :return: alloc id resource path
694 """
695 return PONResourceManager.ALLOC_ID_POOL_PATH.format(
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700696 self.device_id, pon_intf_id)
Girish Gowdru141ced82018-09-17 20:19:14 -0700697
698 def _get_gemport_id_resource_path(self, pon_intf_id):
699 """
700 Get gemport id resource path.
701
702 :param pon_intf_id: OLT PON interface id
703 :return: gemport id resource path
704 """
705 return PONResourceManager.GEMPORT_ID_POOL_PATH.format(
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700706 self.device_id, pon_intf_id)
Girish Gowdru141ced82018-09-17 20:19:14 -0700707
708 def _get_onu_id_resource_path(self, pon_intf_id):
709 """
710 Get onu id resource path.
711
712 :param pon_intf_id: OLT PON interface id
713 :return: onu id resource path
714 """
715 return PONResourceManager.ONU_ID_POOL_PATH.format(
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700716 self.device_id, pon_intf_id)
Girish Gowdru141ced82018-09-17 20:19:14 -0700717
Girish Gowdru141ced82018-09-17 20:19:14 -0700718 def _update_resource(self, path, resource):
719 """
720 Update resource in resource kv store.
721
722 :param path: path to update resource
723 :param resource: resource need to be updated
724 :return boolean: True if resource updated in kv store else False
725 """
726 resource[PONResourceManager.POOL] = \
727 resource[PONResourceManager.POOL].bin
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700728 result = self._kv_store.update_to_kv_store(path, json.dumps(resource))
729 if result is True:
730 return True
731 return False
Girish Gowdru141ced82018-09-17 20:19:14 -0700732
Girish Gowdru141ced82018-09-17 20:19:14 -0700733 def _get_resource(self, path):
734 """
735 Get resource from kv store.
736
737 :param path: path to get resource
738 :return: resource if resource present in kv store else None
739 """
740 # get resource from kv store
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700741 result = self._kv_store.get_from_kv_store(path)
742 if result is None:
743 return result
744 self._log.info("dumping resource", result=result)
745 resource = result
Girish Gowdru141ced82018-09-17 20:19:14 -0700746
747 if resource is not None:
748 # decode resource fetched from backend store to dictionary
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700749 resource = json.loads(resource)
Girish Gowdru141ced82018-09-17 20:19:14 -0700750
751 # resource pool in backend store stored as binary string whereas to
752 # access the pool to generate/release IDs it need to be converted
753 # as BitArray
754 resource[PONResourceManager.POOL] = \
755 BitArray('0b' + resource[PONResourceManager.POOL])
756
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700757 return resource
Girish Gowdru141ced82018-09-17 20:19:14 -0700758
759 def _format_resource(self, pon_intf_id, start_idx, end_idx):
760 """
761 Format resource as json.
762
763 :param pon_intf_id: OLT PON interface id
764 :param start_idx: start index for id pool
765 :param end_idx: end index for id pool
766 :return dictionary: resource formatted as dictionary
767 """
768 # Format resource as json to be stored in backend store
769 resource = dict()
770 resource[PONResourceManager.PON_INTF_ID] = pon_intf_id
771 resource[PONResourceManager.START_IDX] = start_idx
772 resource[PONResourceManager.END_IDX] = end_idx
773
774 # resource pool stored in backend store as binary string
775 resource[PONResourceManager.POOL] = BitArray(end_idx).bin
776
777 return json.dumps(resource)