Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / db / pools / __init__.py @ 5ba2cfd2

History | View | Annotate | Download (11.9 kB)

1 91884d63 Giorgos Korfiatis
# Copyright 2012, 2013 GRNET S.A. All rights reserved.
2 91884d63 Giorgos Korfiatis
#
3 91884d63 Giorgos Korfiatis
# Redistribution and use in source and binary forms, with or without
4 91884d63 Giorgos Korfiatis
# modification, are permitted provided that the following conditions
5 91884d63 Giorgos Korfiatis
# are met:
6 91884d63 Giorgos Korfiatis
#
7 91884d63 Giorgos Korfiatis
#   1. Redistributions of source code must retain the above copyright
8 91884d63 Giorgos Korfiatis
#      notice, this list of conditions and the following disclaimer.
9 91884d63 Giorgos Korfiatis
#
10 91884d63 Giorgos Korfiatis
#  2. Redistributions in binary form must reproduce the above copyright
11 91884d63 Giorgos Korfiatis
#     notice, this list of conditions and the following disclaimer in the
12 91884d63 Giorgos Korfiatis
#     documentation and/or other materials provided with the distribution.
13 91884d63 Giorgos Korfiatis
#
14 91884d63 Giorgos Korfiatis
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15 91884d63 Giorgos Korfiatis
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 91884d63 Giorgos Korfiatis
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 91884d63 Giorgos Korfiatis
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18 91884d63 Giorgos Korfiatis
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 91884d63 Giorgos Korfiatis
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 91884d63 Giorgos Korfiatis
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 91884d63 Giorgos Korfiatis
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 91884d63 Giorgos Korfiatis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 91884d63 Giorgos Korfiatis
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 91884d63 Giorgos Korfiatis
# SUCH DAMAGE.
25 91884d63 Giorgos Korfiatis
#
26 91884d63 Giorgos Korfiatis
# The views and conclusions contained in the software and documentation are
27 91884d63 Giorgos Korfiatis
# those of the authors and should not be interpreted as representing official
28 91884d63 Giorgos Korfiatis
# policies, either expressed or implied, of GRNET S.A.
29 91884d63 Giorgos Korfiatis
30 03992c72 Christos Stavrakakis
from bitarray import bitarray
31 03992c72 Christos Stavrakakis
from base64 import b64encode, b64decode
32 03992c72 Christos Stavrakakis
import ipaddr
33 03992c72 Christos Stavrakakis
34 03992c72 Christos Stavrakakis
AVAILABLE = True
35 03992c72 Christos Stavrakakis
UNAVAILABLE = False
36 03992c72 Christos Stavrakakis
37 03992c72 Christos Stavrakakis
38 03992c72 Christos Stavrakakis
class PoolManager(object):
39 03992c72 Christos Stavrakakis
    """PoolManager for DB PoolTable models.
40 03992c72 Christos Stavrakakis

41 03992c72 Christos Stavrakakis
    This class implements a persistent Pool mechanism based on rows of
42 03992c72 Christos Stavrakakis
    PoolTable objects. Values that are pooled by this class, are mapped to an
43 03992c72 Christos Stavrakakis
    index on a bitarray, which is the one that is stored on the DB.
44 03992c72 Christos Stavrakakis

45 03992c72 Christos Stavrakakis
    The object that will be used in order to initialize this pool, must have
46 03992c72 Christos Stavrakakis
    two string attributes (available_map and reserved_map) and the size of the
47 03992c72 Christos Stavrakakis
    pool.
48 03992c72 Christos Stavrakakis

49 03992c72 Christos Stavrakakis
    Subclasses of PoolManager must implement value_to_index and index_to_value
50 03992c72 Christos Stavrakakis
    method's in order to denote how the value will be mapped to the index in
51 03992c72 Christos Stavrakakis
    the bitarray.
52 03992c72 Christos Stavrakakis

53 03992c72 Christos Stavrakakis
    Important!!: Updates on a PoolManager object are not reflected to the DB,
54 03992c72 Christos Stavrakakis
    until save() method is called.
55 03992c72 Christos Stavrakakis

56 03992c72 Christos Stavrakakis
    """
57 03992c72 Christos Stavrakakis
    def __init__(self, pool_table):
58 03992c72 Christos Stavrakakis
        self.pool_table = pool_table
59 3e7c63f8 Christos Stavrakakis
        self.pool_size = pool_table.size
60 03992c72 Christos Stavrakakis
        if pool_table.available_map:
61 03992c72 Christos Stavrakakis
            self.available = _bitarray_from_string(pool_table.available_map)
62 03992c72 Christos Stavrakakis
            self.reserved = _bitarray_from_string(pool_table.reserved_map)
63 03992c72 Christos Stavrakakis
        else:
64 3e7c63f8 Christos Stavrakakis
            self.available = self._create_empty_pool(self.pool_size)
65 3e7c63f8 Christos Stavrakakis
            self.reserved = self._create_empty_pool(self.pool_size)
66 3e7c63f8 Christos Stavrakakis
            self.add_padding(self.pool_size)
67 3e7c63f8 Christos Stavrakakis
68 3e7c63f8 Christos Stavrakakis
    def _create_empty_pool(self, size):
69 3e7c63f8 Christos Stavrakakis
        ba = bitarray(size)
70 03992c72 Christos Stavrakakis
        ba.setall(AVAILABLE)
71 03992c72 Christos Stavrakakis
        return ba
72 03992c72 Christos Stavrakakis
73 3e7c63f8 Christos Stavrakakis
    def add_padding(self, pool_size):
74 3e7c63f8 Christos Stavrakakis
        bits = find_padding(pool_size)
75 35e2f2d4 Christos Stavrakakis
        self.available.extend([UNAVAILABLE] * bits)
76 3e7c63f8 Christos Stavrakakis
        self.reserved.extend([UNAVAILABLE] * bits)
77 3e7c63f8 Christos Stavrakakis
78 3e7c63f8 Christos Stavrakakis
    def cut_padding(self, pool_size):
79 3e7c63f8 Christos Stavrakakis
        bits = find_padding(pool_size)
80 3e7c63f8 Christos Stavrakakis
        self.available = self.available[:-bits]
81 3e7c63f8 Christos Stavrakakis
        self.reserved = self.reserved[:-bits]
82 3e7c63f8 Christos Stavrakakis
83 03992c72 Christos Stavrakakis
    @property
84 03992c72 Christos Stavrakakis
    def pool(self):
85 03992c72 Christos Stavrakakis
        return (self.available & self.reserved)
86 03992c72 Christos Stavrakakis
87 413fb1dd Christos Stavrakakis
    def get(self, value=None):
88 03992c72 Christos Stavrakakis
        """Get a value from the pool."""
89 413fb1dd Christos Stavrakakis
        if value is None:
90 691c98cf Christos Stavrakakis
            if self.empty():
91 691c98cf Christos Stavrakakis
                raise EmptyPool
92 413fb1dd Christos Stavrakakis
            # Get the first available index
93 413fb1dd Christos Stavrakakis
            index = int(self.pool.index(AVAILABLE))
94 413fb1dd Christos Stavrakakis
            assert(index < self.pool_size)
95 413fb1dd Christos Stavrakakis
            self._reserve(index)
96 413fb1dd Christos Stavrakakis
            return self.index_to_value(index)
97 413fb1dd Christos Stavrakakis
        else:
98 ae994d2e Christos Stavrakakis
            if not self.contains(value):
99 ae994d2e Christos Stavrakakis
                raise InvalidValue("Value %s does not belong to pool." % value)
100 413fb1dd Christos Stavrakakis
            if self.is_available(value):
101 413fb1dd Christos Stavrakakis
                self.reserve(value)
102 413fb1dd Christos Stavrakakis
                return value
103 413fb1dd Christos Stavrakakis
            else:
104 413fb1dd Christos Stavrakakis
                raise ValueNotAvailable("Value %s is not available" % value)
105 03992c72 Christos Stavrakakis
106 03992c72 Christos Stavrakakis
    def put(self, value, external=False):
107 03992c72 Christos Stavrakakis
        """Return a value to the pool."""
108 03992c72 Christos Stavrakakis
        if value is None:
109 03992c72 Christos Stavrakakis
            raise ValueError
110 3b2984dc Christos Stavrakakis
        if not self.contains(value):
111 3b2984dc Christos Stavrakakis
            raise InvalidValue("%s does not belong to pool." % value)
112 03992c72 Christos Stavrakakis
        index = self.value_to_index(value)
113 03992c72 Christos Stavrakakis
        self._release(index, external)
114 03992c72 Christos Stavrakakis
115 fdc94944 Christos Stavrakakis
    def reserve(self, value, external=False):
116 03992c72 Christos Stavrakakis
        """Reserve a value."""
117 3b2984dc Christos Stavrakakis
        if not self.contains(value):
118 3b2984dc Christos Stavrakakis
            raise InvalidValue("%s does not belong to pool." % value)
119 03992c72 Christos Stavrakakis
        index = self.value_to_index(value)
120 03992c72 Christos Stavrakakis
        self._reserve(index, external)
121 03992c72 Christos Stavrakakis
        return True
122 03992c72 Christos Stavrakakis
123 03992c72 Christos Stavrakakis
    def save(self, db=True):
124 03992c72 Christos Stavrakakis
        """Save changes to the DB."""
125 03992c72 Christos Stavrakakis
        self.pool_table.available_map = _bitarray_to_string(self.available)
126 03992c72 Christos Stavrakakis
        self.pool_table.reserved_map = _bitarray_to_string(self.reserved)
127 03992c72 Christos Stavrakakis
        if db:
128 03992c72 Christos Stavrakakis
            self.pool_table.save()
129 03992c72 Christos Stavrakakis
130 03992c72 Christos Stavrakakis
    def empty(self):
131 03992c72 Christos Stavrakakis
        """Return True when pool is empty."""
132 03992c72 Christos Stavrakakis
        return not self.pool.any()
133 03992c72 Christos Stavrakakis
134 03992c72 Christos Stavrakakis
    def size(self):
135 3e7c63f8 Christos Stavrakakis
        """Return the size of the bitarray(original size + padding)."""
136 03992c72 Christos Stavrakakis
        return self.pool.length()
137 03992c72 Christos Stavrakakis
138 03992c72 Christos Stavrakakis
    def _reserve(self, index, external=False):
139 03992c72 Christos Stavrakakis
        if external:
140 03992c72 Christos Stavrakakis
            self.reserved[index] = UNAVAILABLE
141 03992c72 Christos Stavrakakis
        else:
142 03992c72 Christos Stavrakakis
            self.available[index] = UNAVAILABLE
143 03992c72 Christos Stavrakakis
144 03992c72 Christos Stavrakakis
    def _release(self, index, external=False):
145 03992c72 Christos Stavrakakis
        if external:
146 03992c72 Christos Stavrakakis
            self.reserved[index] = AVAILABLE
147 03992c72 Christos Stavrakakis
        else:
148 03992c72 Christos Stavrakakis
            self.available[index] = AVAILABLE
149 03992c72 Christos Stavrakakis
150 3b2984dc Christos Stavrakakis
    def contains(self, value, index=False):
151 3b2984dc Christos Stavrakakis
        if index is False:
152 3b2984dc Christos Stavrakakis
            index = self.value_to_index(value)
153 ae994d2e Christos Stavrakakis
        return index >= 0 and index < self.pool_size
154 ae994d2e Christos Stavrakakis
155 03992c72 Christos Stavrakakis
    def count_available(self):
156 03992c72 Christos Stavrakakis
        return self.pool.count(AVAILABLE)
157 03992c72 Christos Stavrakakis
158 03992c72 Christos Stavrakakis
    def count_unavailable(self):
159 fcf2479a Christos Stavrakakis
        return self.pool_size - self.count_available()
160 03992c72 Christos Stavrakakis
161 03992c72 Christos Stavrakakis
    def count_reserved(self):
162 3e7c63f8 Christos Stavrakakis
        return self.reserved[:self.pool_size].count(UNAVAILABLE)
163 03992c72 Christos Stavrakakis
164 03992c72 Christos Stavrakakis
    def count_unreserved(self):
165 3e7c63f8 Christos Stavrakakis
        return self.pool_size - self.count_reserved()
166 03992c72 Christos Stavrakakis
167 03992c72 Christos Stavrakakis
    def is_available(self, value, index=False):
168 3b2984dc Christos Stavrakakis
        if not self.contains(value, index=index):
169 3b2984dc Christos Stavrakakis
            raise InvalidValue("%s does not belong to pool." % value)
170 03992c72 Christos Stavrakakis
        if not index:
171 03992c72 Christos Stavrakakis
            idx = self.value_to_index(value)
172 03992c72 Christos Stavrakakis
        else:
173 03992c72 Christos Stavrakakis
            idx = value
174 03992c72 Christos Stavrakakis
        return self.pool[idx] == AVAILABLE
175 03992c72 Christos Stavrakakis
176 03992c72 Christos Stavrakakis
    def is_reserved(self, value, index=False):
177 3b2984dc Christos Stavrakakis
        if not self.contains(value, index=index):
178 3b2984dc Christos Stavrakakis
            raise InvalidValue("%s does not belong to pool." % value)
179 03992c72 Christos Stavrakakis
        if not index:
180 03992c72 Christos Stavrakakis
            idx = self.value_to_index(value)
181 03992c72 Christos Stavrakakis
        else:
182 03992c72 Christos Stavrakakis
            idx = value
183 03992c72 Christos Stavrakakis
        return self.reserved[idx] == UNAVAILABLE
184 03992c72 Christos Stavrakakis
185 03992c72 Christos Stavrakakis
    def to_01(self):
186 3e7c63f8 Christos Stavrakakis
        return self.pool[:self.pool_size].to01()
187 03992c72 Christos Stavrakakis
188 03992c72 Christos Stavrakakis
    def to_map(self):
189 03992c72 Christos Stavrakakis
        return self.to_01().replace("0", "X").replace("1", ".")
190 03992c72 Christos Stavrakakis
191 3e7c63f8 Christos Stavrakakis
    def extend(self, bits_num):
192 3e7c63f8 Christos Stavrakakis
        assert(bits_num >= 0)
193 3e7c63f8 Christos Stavrakakis
        self.resize(bits_num)
194 3e7c63f8 Christos Stavrakakis
195 3e7c63f8 Christos Stavrakakis
    def shrink(self, bits_num):
196 3e7c63f8 Christos Stavrakakis
        assert(bits_num >= 0)
197 3e7c63f8 Christos Stavrakakis
        size = self.pool_size
198 3e7c63f8 Christos Stavrakakis
        tmp = self.available[(size - bits_num): size]
199 3e7c63f8 Christos Stavrakakis
        if tmp.count(UNAVAILABLE):
200 8d5795b4 Christos Stavrakakis
            raise Exception("Cannot shrink. In use")
201 3e7c63f8 Christos Stavrakakis
        self.resize(-bits_num)
202 3e7c63f8 Christos Stavrakakis
203 3e7c63f8 Christos Stavrakakis
    def resize(self, bits_num):
204 3e7c63f8 Christos Stavrakakis
        if bits_num == 0:
205 3e7c63f8 Christos Stavrakakis
            return
206 3e7c63f8 Christos Stavrakakis
        # Cut old padding
207 3e7c63f8 Christos Stavrakakis
        self.cut_padding(self.pool_size)
208 3e7c63f8 Christos Stavrakakis
        # Do the resize
209 3e7c63f8 Christos Stavrakakis
        if bits_num > 0:
210 3e7c63f8 Christos Stavrakakis
            self.available.extend([AVAILABLE] * bits_num)
211 3e7c63f8 Christos Stavrakakis
            self.reserved.extend([AVAILABLE] * bits_num)
212 3e7c63f8 Christos Stavrakakis
        else:
213 3e7c63f8 Christos Stavrakakis
            self.available = self.available[:bits_num]
214 3e7c63f8 Christos Stavrakakis
            self.reserved = self.reserved[:bits_num]
215 3e7c63f8 Christos Stavrakakis
        # Add new padding
216 3e7c63f8 Christos Stavrakakis
        self.pool_size = self.pool_size + bits_num
217 3e7c63f8 Christos Stavrakakis
        self.add_padding(self.pool_size)
218 3e7c63f8 Christos Stavrakakis
        self.pool_table.size = self.pool_size
219 3e7c63f8 Christos Stavrakakis
220 03992c72 Christos Stavrakakis
    def index_to_value(self, index):
221 03992c72 Christos Stavrakakis
        raise NotImplementedError
222 03992c72 Christos Stavrakakis
223 03992c72 Christos Stavrakakis
    def value_to_index(self, value):
224 03992c72 Christos Stavrakakis
        raise NotImplementedError
225 03992c72 Christos Stavrakakis
226 d793786b Christos Stavrakakis
    def __repr__(self):
227 d793786b Christos Stavrakakis
        return repr(self.pool_table)
228 d793786b Christos Stavrakakis
229 03992c72 Christos Stavrakakis
230 03992c72 Christos Stavrakakis
class EmptyPool(Exception):
231 03992c72 Christos Stavrakakis
    pass
232 03992c72 Christos Stavrakakis
233 03992c72 Christos Stavrakakis
234 413fb1dd Christos Stavrakakis
class ValueNotAvailable(Exception):
235 413fb1dd Christos Stavrakakis
    pass
236 413fb1dd Christos Stavrakakis
237 413fb1dd Christos Stavrakakis
238 ae994d2e Christos Stavrakakis
class InvalidValue(Exception):
239 ae994d2e Christos Stavrakakis
    pass
240 ae994d2e Christos Stavrakakis
241 ae994d2e Christos Stavrakakis
242 03992c72 Christos Stavrakakis
def find_padding(size):
243 03992c72 Christos Stavrakakis
    extra = size % 8
244 03992c72 Christos Stavrakakis
    return extra and (8 - extra) or 0
245 03992c72 Christos Stavrakakis
246 03992c72 Christos Stavrakakis
247 03992c72 Christos Stavrakakis
def bitarray_to_01(bitarray_):
248 03992c72 Christos Stavrakakis
    return bitarray_.to01()
249 03992c72 Christos Stavrakakis
250 03992c72 Christos Stavrakakis
251 03992c72 Christos Stavrakakis
def bitarray_to_map(bitarray_):
252 03992c72 Christos Stavrakakis
    return bitarray_to_01(bitarray_).replace("0", "X").replace("1", ".")
253 03992c72 Christos Stavrakakis
254 03992c72 Christos Stavrakakis
255 03992c72 Christos Stavrakakis
def _bitarray_from_string(bitarray_):
256 03992c72 Christos Stavrakakis
    ba = bitarray()
257 698306b8 Christos Stavrakakis
    ba.frombytes(b64decode(bitarray_))
258 03992c72 Christos Stavrakakis
    return ba
259 03992c72 Christos Stavrakakis
260 03992c72 Christos Stavrakakis
261 03992c72 Christos Stavrakakis
def _bitarray_to_string(bitarray_):
262 698306b8 Christos Stavrakakis
    return b64encode(bitarray_.tobytes())
263 03992c72 Christos Stavrakakis
264 03992c72 Christos Stavrakakis
##
265 03992c72 Christos Stavrakakis
## Custom pools
266 03992c72 Christos Stavrakakis
##
267 03992c72 Christos Stavrakakis
268 03992c72 Christos Stavrakakis
269 03992c72 Christos Stavrakakis
class BridgePool(PoolManager):
270 03992c72 Christos Stavrakakis
    def index_to_value(self, index):
271 dd2689f9 Christos Stavrakakis
        # Bridge indexes should start from 1
272 dd2689f9 Christos Stavrakakis
        return self.pool_table.base + str(index + 1)
273 03992c72 Christos Stavrakakis
274 03992c72 Christos Stavrakakis
    def value_to_index(self, value):
275 dd2689f9 Christos Stavrakakis
        return int(value.replace(self.pool_table.base, "")) - 1
276 03992c72 Christos Stavrakakis
277 03992c72 Christos Stavrakakis
278 03992c72 Christos Stavrakakis
class MacPrefixPool(PoolManager):
279 03992c72 Christos Stavrakakis
    def __init__(self, pool_table):
280 03992c72 Christos Stavrakakis
        do_init = False if pool_table.available_map else True
281 03992c72 Christos Stavrakakis
        super(MacPrefixPool, self).__init__(pool_table)
282 03992c72 Christos Stavrakakis
        if do_init:
283 3e7c63f8 Christos Stavrakakis
            for i in xrange(1, self.pool_size):
284 03992c72 Christos Stavrakakis
                if not self.validate_mac(self.index_to_value(i)):
285 03992c72 Christos Stavrakakis
                    self._reserve(i, external=True)
286 03992c72 Christos Stavrakakis
            # Reserve the first mac-prefix for public-networks
287 03992c72 Christos Stavrakakis
            self._reserve(0, external=True)
288 03992c72 Christos Stavrakakis
289 03992c72 Christos Stavrakakis
    def index_to_value(self, index):
290 03992c72 Christos Stavrakakis
        """Convert index to mac_prefix"""
291 03992c72 Christos Stavrakakis
        base = self.pool_table.base
292 03992c72 Christos Stavrakakis
        a = hex(int(base.replace(":", ""), 16) + index).replace("0x", '')
293 03992c72 Christos Stavrakakis
        mac_prefix = ":".join([a[x:x + 2] for x in xrange(0, len(a), 2)])
294 03992c72 Christos Stavrakakis
        return mac_prefix
295 03992c72 Christos Stavrakakis
296 03992c72 Christos Stavrakakis
    def value_to_index(self, value):
297 03992c72 Christos Stavrakakis
        base = self.pool_table.base
298 03992c72 Christos Stavrakakis
        return int(value.replace(":", ""), 16) - int(base.replace(":", ""), 16)
299 03992c72 Christos Stavrakakis
300 03992c72 Christos Stavrakakis
    @staticmethod
301 03992c72 Christos Stavrakakis
    def validate_mac(value):
302 03992c72 Christos Stavrakakis
        hex_ = value.replace(":", "")
303 03992c72 Christos Stavrakakis
        bin_ = bin(int(hex_, 16))[2:].zfill(8)
304 03992c72 Christos Stavrakakis
        return bin_[6] == '1' and bin_[7] == '0'
305 03992c72 Christos Stavrakakis
306 03992c72 Christos Stavrakakis
307 fdc94944 Christos Stavrakakis
class IPPool(PoolManager):
308 fdc94944 Christos Stavrakakis
    def __init__(self, pool_table):
309 b4695420 Christos Stavrakakis
        subnet = pool_table.subnet
310 b4695420 Christos Stavrakakis
        self.net = ipaddr.IPNetwork(subnet.cidr)
311 f8714db8 Christos Stavrakakis
        self.offset = pool_table.offset
312 f8714db8 Christos Stavrakakis
        self.base = pool_table.base
313 833f2ad5 Christos Stavrakakis
        if pool_table.available_map:
314 833f2ad5 Christos Stavrakakis
            initialized_pool = True
315 a1d3bc8a Christos Stavrakakis
        else:
316 833f2ad5 Christos Stavrakakis
            initialized_pool = False
317 fdc94944 Christos Stavrakakis
        super(IPPool, self).__init__(pool_table)
318 833f2ad5 Christos Stavrakakis
        if not initialized_pool:
319 833f2ad5 Christos Stavrakakis
            self.check_pool_integrity()
320 833f2ad5 Christos Stavrakakis
321 f8714db8 Christos Stavrakakis
    def check_pool_integrity(self):
322 833f2ad5 Christos Stavrakakis
        """Check the integrity of the IP pool
323 833f2ad5 Christos Stavrakakis

324 833f2ad5 Christos Stavrakakis
        This check is required only for old IP pools(one IP pool per network
325 833f2ad5 Christos Stavrakakis
        that contained the whole subnet cidr) that had not been initialized
326 833f2ad5 Christos Stavrakakis
        before the migration. This checks that the network, gateway and
327 833f2ad5 Christos Stavrakakis
        broadcast IP addresses are externally reserved, and if not reserves
328 833f2ad5 Christos Stavrakakis
        them.
329 833f2ad5 Christos Stavrakakis

330 833f2ad5 Christos Stavrakakis
        """
331 833f2ad5 Christos Stavrakakis
        subnet = self.pool_table.subnet
332 833f2ad5 Christos Stavrakakis
        check_ips = [str(self.net.network), str(self.net.broadcast)]
333 833f2ad5 Christos Stavrakakis
        if subnet.gateway is not None:
334 833f2ad5 Christos Stavrakakis
            check_ips.append(subnet.gateway)
335 833f2ad5 Christos Stavrakakis
        for ip in check_ips:
336 833f2ad5 Christos Stavrakakis
            if self.contains(ip):
337 833f2ad5 Christos Stavrakakis
                self.reserve(ip, external=True)
338 03992c72 Christos Stavrakakis
339 fdc94944 Christos Stavrakakis
    def value_to_index(self, value):
340 fdc94944 Christos Stavrakakis
        addr = ipaddr.IPAddress(value)
341 f82dfec6 Christos Stavrakakis
        return int(addr) - int(self.net.network) - int(self.offset)
342 03992c72 Christos Stavrakakis
343 fdc94944 Christos Stavrakakis
    def index_to_value(self, index):
344 f82dfec6 Christos Stavrakakis
        return str(self.net[index + int(self.offset)])
345 a3d99af0 Christos Stavrakakis
346 e59cda53 Christos Stavrakakis
    def contains(self, address, index=False):
347 e59cda53 Christos Stavrakakis
        if index is False:
348 fb676f00 Dionysis Grigoropoulos
            try:
349 fb676f00 Dionysis Grigoropoulos
                addr = ipaddr.IPAddress(address)
350 fb676f00 Dionysis Grigoropoulos
            except ValueError:
351 fb676f00 Dionysis Grigoropoulos
                raise InvalidValue("Invalid IP address")
352 fb676f00 Dionysis Grigoropoulos
353 e59cda53 Christos Stavrakakis
            if addr not in self.net:
354 e59cda53 Christos Stavrakakis
                return False
355 e59cda53 Christos Stavrakakis
        return super(IPPool, self).contains(address, index=False)
356 4445f97a Dionysis Grigoropoulos
357 4445f97a Dionysis Grigoropoulos
    def return_start(self):
358 e4758367 Dionysis Grigoropoulos
        return str(ipaddr.IPAddress(ipaddr.IPNetwork(self.base).network) +
359 e4758367 Dionysis Grigoropoulos
                   self.offset)
360 4445f97a Dionysis Grigoropoulos
361 4445f97a Dionysis Grigoropoulos
    def return_end(self):
362 e4758367 Dionysis Grigoropoulos
        return str(ipaddr.IPAddress(ipaddr.IPNetwork(self.base).network) +
363 e4758367 Dionysis Grigoropoulos
                   self.offset + self.pool_size - 1)