Revision 3e7c63f8

b/snf-cyclades-app/synnefo/db/pools/__init__.py
27 27
    """
28 28
    def __init__(self, pool_table):
29 29
        self.pool_table = pool_table
30

  
30
        self.pool_size = pool_table.size
31 31
        if pool_table.available_map:
32 32
            self.available = _bitarray_from_string(pool_table.available_map)
33 33
            self.reserved = _bitarray_from_string(pool_table.reserved_map)
34 34
        else:
35
            size = self.pool_table.size
36
            padding = find_padding(size)
37
            size = size + padding
38
            self.pool_size = size
39
            self.available = self._create_empty_pool()
40
            self.reserved = self._create_empty_pool()
41
            for i in xrange(0, padding):
42
                self._reserve(size - i - 1, external=True)
43

  
44
    def _create_empty_pool(self):
45
        assert(self.pool_size % 8 == 0)
46
        ba = bitarray(self.pool_size)
35
            self.available = self._create_empty_pool(self.pool_size)
36
            self.reserved = self._create_empty_pool(self.pool_size)
37
            self.add_padding(self.pool_size)
38

  
39
    def _create_empty_pool(self, size):
40
        ba = bitarray(size)
47 41
        ba.setall(AVAILABLE)
48 42
        return ba
49 43

  
44
    def add_padding(self, pool_size):
45
        bits = find_padding(pool_size)
46
        self.available.extend([AVAILABLE] * bits)
47
        self.reserved.extend([UNAVAILABLE] * bits)
48

  
49
    def cut_padding(self, pool_size):
50
        bits = find_padding(pool_size)
51
        self.available = self.available[:-bits]
52
        self.reserved = self.reserved[:-bits]
53

  
50 54
    @property
51 55
    def pool(self):
52 56
        return (self.available & self.reserved)
......
57 61
            raise EmptyPool
58 62
        # Get the first available index
59 63
        index = int(self.pool.index(AVAILABLE))
64
        assert(index < self.pool_size)
60 65
        self._reserve(index)
61 66
        return self.index_to_value(index)
62 67

  
......
85 90
        return not self.pool.any()
86 91

  
87 92
    def size(self):
93
        """Return the size of the bitarray(original size + padding)."""
88 94
        return self.pool.length()
89 95

  
90 96
    def _reserve(self, index, external=False):
......
106 112
        return self.pool.count(UNAVAILABLE)
107 113

  
108 114
    def count_reserved(self):
109
        return self.reserved.count(UNAVAILABLE)
115
        return self.reserved[:self.pool_size].count(UNAVAILABLE)
110 116

  
111 117
    def count_unreserved(self):
112
        return self.size() - self.count_reserved()
118
        return self.pool_size - self.count_reserved()
113 119

  
114 120
    def is_available(self, value, index=False):
115 121
        if not index:
......
126 132
        return self.reserved[idx] == UNAVAILABLE
127 133

  
128 134
    def to_01(self):
129
        return self.pool.to01()
135
        return self.pool[:self.pool_size].to01()
130 136

  
131 137
    def to_map(self):
132 138
        return self.to_01().replace("0", "X").replace("1", ".")
133 139

  
140
    def extend(self, bits_num):
141
        assert(bits_num >= 0)
142
        self.resize(bits_num)
143

  
144
    def shrink(self, bits_num):
145
        assert(bits_num >= 0)
146
        size = self.pool_size
147
        tmp = self.available[(size - bits_num): size]
148
        if tmp.count(UNAVAILABLE):
149
            raise Exception("Can not shrink. In use")
150
        self.resize(-bits_num)
151

  
152
    def resize(self, bits_num):
153
        if bits_num == 0:
154
            return
155
        # Cut old padding
156
        self.cut_padding(self.pool_size)
157
        # Do the resize
158
        if bits_num > 0:
159
            self.available.extend([AVAILABLE] * bits_num)
160
            self.reserved.extend([AVAILABLE] * bits_num)
161
        else:
162
            self.available = self.available[:bits_num]
163
            self.reserved = self.reserved[:bits_num]
164
        # Add new padding
165
        self.pool_size = self.pool_size + bits_num
166
        self.add_padding(self.pool_size)
167
        self.pool_table.size = self.pool_size
168

  
134 169
    def index_to_value(self, index):
135 170
        raise NotImplementedError
136 171

  
......
183 218
        do_init = False if pool_table.available_map else True
184 219
        super(MacPrefixPool, self).__init__(pool_table)
185 220
        if do_init:
186
            for i in xrange(1, self.size()):
221
            for i in xrange(1, self.pool_size):
187 222
                if not self.validate_mac(self.index_to_value(i)):
188 223
                    self._reserve(i, external=True)
189 224
            # Reserve the first mac-prefix for public-networks
......
221 256
            self._reserve(0, external=True)
222 257
            if gateway:
223 258
                self.reserve(gateway, external=True)
224
            self._reserve(self.size() - 1, external=True)
259
            self._reserve(self.pool_size - 1, external=True)
225 260

  
226 261
    def value_to_index(self, value):
227 262
        addr = ipaddr.IPAddress(value)
b/snf-cyclades-app/synnefo/db/pools/tests.py
1 1
import sys
2 2
from synnefo.db.pools import (PoolManager, EmptyPool, BridgePool,
3 3
                              MacPrefixPool, IPPool)
4
from bitarray import bitarray
4 5

  
5 6
# Use backported unittest functionality if Python < 2.7
6 7
try:
......
34 35
    def test_created_pool(self):
35 36
        obj = DummyObject(42)
36 37
        pool = DummyPool(obj)
37
        self.assertEqual(pool.to_01(), '1' * 42 + '0' * 6)
38
        self.assertEqual(pool.to_map(), '.' * 42 + 'X' * 6)
38
        self.assertEqual(pool.to_01(), '1' * 42)
39
        self.assertEqual(pool.to_map(), '.' * 42)
40
        self.assertEqual(pool.available, bitarray('1' * 42 + '0' * 6))
41
        self.assertEqual(pool.reserved, bitarray('1' * 42 + '0' * 6))
39 42

  
40 43
    def test_save_pool(self):
41 44
        obj = DummyObject(42)
......
89 92
        pool.put(0)
90 93
        self.assertEqual(pool.get(), 1)
91 94

  
95
    def test_extend_pool(self):
96
        obj = DummyObject(42)
97
        pool = DummyPool(obj)
98
        pool.extend(7)
99
        self.assertEqual(pool.to_01(), '1' * 49)
100
        self.assertEqual(pool.to_map(), '.' * 49)
101
        self.assertEqual(pool.available, bitarray('1' * 49 + '0' * 7))
102
        self.assertEqual(pool.reserved, bitarray('1' * 49 + '0' * 7))
103

  
104
    def test_shrink_pool(self):
105
        obj = DummyObject(42)
106
        pool = DummyPool(obj)
107
        pool.shrink(3)
108
        self.assertEqual(pool.to_01(), '1' * 39)
109
        self.assertEqual(pool.to_map(), '.' * 39)
110
        self.assertEqual(pool.available, bitarray('1' * 39 + '0' * 1))
111
        self.assertEqual(pool.reserved, bitarray('1' * 39 + '0' * 1))
112

  
92 113

  
93 114
class BridgePoolTestCase(unittest.TestCase):
94 115
    def test_bridge_conversion(self):
......
96 117
        obj.base = "bridge"
97 118
        pool = BridgePool(obj)
98 119
        for i in range(0, 13):
99
            self.assertEqual("bridge" + str(i), pool.get())
120
            self.assertEqual("bridge" + str(i + 1), pool.get())
100 121
        pool.put("bridge2")
101 122
        pool.put("bridge6")
102 123
        self.assertEqual("bridge2", pool.get())
b/snf-cyclades-app/synnefo/logic/management/commands/pool-modify.py
49 49
                    help="Type of pool"
50 50
                    ),
51 51
        make_option('--offset', dest='offset'),
52
        make_option('--size', dest='size'),
52 53
        make_option('--base', dest='base'),
53 54
        make_option('--add-reserved', dest='add-reserved',
54 55
                    help="Comma-seperated list of values to reserve"),
......
90 91
        if base:
91 92
            pool_row.base = base
92 93

  
94
        # Save now, to avoid conflict with resizing pool.save()
93 95
        pool_row.save()
96

  
97
        if size:
98
            try:
99
                size = int(size)
100
            except ValueError:
101
                raise CommandError("Invalid size")
102
            pool = pool_row.get_pool()
103
            self.resize_pool(pool, pool_row.size, size)
104
            pool.save()
105

  
106
    def resize_pool(self, pool, old_size, new_size):
107
        if new_size == old_size:
108
            return
109
        elif new_size > old_size:
110
            pool.extend(new_size - old_size)
111
        else:
112
            pool.shrink(old_size - new_size)
113
        pool.save()
b/snf-cyclades-app/synnefo/logic/management/commands/pool-show.py
81 81

  
82 82
        step = (type_ == 'bridge') and 64 or 80
83 83
        print_map('Pool', pool.to_map(), step, self.stdout)
84
        print_map('Reserved', bitarray_to_map(pool.reserved), step, self.stdout)
84
        print_map('Reserved', bitarray_to_map(pool.reserved[:pool_row.size]), step, self.stdout)
85 85

  
86 86

  
87 87
def print_map(name, pool_map, step, out):

Also available in: Unified diff