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) |