Source code for paradrop.lib.config.pool

import ipaddress
import itertools

from pdtools.lib.output import out


[docs]class ResourcePool(object): def __init__(self, values, numValues): """ Initialize resource pool. values - must be iterable, such as a list or generator numValues - number of values, since len need not be defined """ self.values = values self.numValues = numValues self.cycle = itertools.cycle(values) self.recentlyReleased = list() self.used = set()
[docs] def next(self): if len(self.used) >= self.numValues: raise Exception("No items left in pool") while len(self.recentlyReleased) > 0: item = self.recentlyReleased.pop(0) if item not in self.used: out.info("Claiming recently released {} from pool {}\n".format( str(item), self.__class__.__name__)) self.used.add(item) return item # The for loop puts a limit on the number of iterations that we spend # looking for a free subnet. Passing the check above should imply that # there is at least one available item, but we want to be extra # careful to avoid a busy loop. for i in range(self.numValues): item = self.cycle.next() if item not in self.used: out.info("Claiming new item {} from pool {}\n".format( str(item), self.__class__.__name__)) self.used.add(item) return item # There is a bug if we hit this line. raise Exception("No items left in pool (BUG)")
[docs] def release(self, item): out.info("Trying to release {} from pool {}\n".format(str(item), self.__class__.__name__)) if item in self.used: self.used.remove(item) self.recentlyReleased.append(item) else: raise Exception("Trying to release unreserved item")
[docs] def reserve(self, item, strict=True): """ Mark item as used. If strict is True, raises an exception if the item is already used. """ out.info("Trying to reserve {} from pool {}\n".format(str(item), self.__class__.__name__)) if item in self.used: if strict: raise Exception("Trying to reserve a used item") else: self.used.add(item)
[docs]class NetworkPool(ResourcePool): def __init__(self, network, subnetSize=24): """ network should be a string with network size in slash notation or as a netmask (e.g. 192.168.0.0/16 or 192.168.0.0/255.255.0.0). subnetSize specifies the size of subnets to create from the given network and should be larger than the prefix length of network (e.g. from 192.168.0.0/16 we can make 256 /24 subnets). """ self.network = ipaddress.ip_network(unicode(network), strict=False) if subnetSize < self.network.prefixlen: raise Exception("Invalid subnetSize {} for network {}".format( subnetSize, network)) subnets = self.network.subnets(new_prefix=subnetSize) numSubnets = 2 ** (subnetSize - self.network.prefixlen) super(NetworkPool, self).__init__(subnets, numSubnets)
[docs]class NumericPool(ResourcePool): def __init__(self, digits=4): self.digits = digits # NOTE: Using base 16 for string representation. It might be nice to # use a larger base ([0-9a-z] would allow base 36) for more possible # values for the same length. numNames = 16 ** digits values = range(numNames) super(NumericPool, self).__init__(values, numNames)