Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / management / commands / reconcile-networks.py @ d4325f42

History | View | Annotate | Download (11.9 kB)

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

32 0e9a423f Christos Stavrakakis
Management command to reconcile the contents of the Synnefo DB with
33 0e9a423f Christos Stavrakakis
the state of the Ganeti backend. See docstring on top of
34 0e9a423f Christos Stavrakakis
logic/reconciliation.py for a description of reconciliation rules.
35 0e9a423f Christos Stavrakakis

36 0e9a423f Christos Stavrakakis
"""
37 c346aed0 Christos Stavrakakis
import sys
38 0e9a423f Christos Stavrakakis
import datetime
39 c55b0cdc Christos Stavrakakis
import bitarray
40 0e9a423f Christos Stavrakakis
41 0e9a423f Christos Stavrakakis
from optparse import make_option
42 0e9a423f Christos Stavrakakis
43 d1b1e683 Dimitris Aragiorgis
from synnefo.settings import PUBLIC_USE_POOL
44 c55b0cdc Christos Stavrakakis
from django.core.management.base import BaseCommand
45 0e9a423f Christos Stavrakakis
46 0e9a423f Christos Stavrakakis
from synnefo.db.models import Backend, Network, BackendNetwork
47 fdc94944 Christos Stavrakakis
from synnefo.db.pools import IPPool
48 c346aed0 Christos Stavrakakis
from synnefo.logic import reconciliation, utils
49 c346aed0 Christos Stavrakakis
from synnefo.logic import backend as backend_mod
50 c346aed0 Christos Stavrakakis
51 c346aed0 Christos Stavrakakis
fix = False
52 c346aed0 Christos Stavrakakis
write = sys.stdout.write
53 0e9a423f Christos Stavrakakis
54 0e9a423f Christos Stavrakakis
55 0e9a423f Christos Stavrakakis
class Command(BaseCommand):
56 c346aed0 Christos Stavrakakis
    help = """Reconcile contents of Synnefo DB with state of Ganeti backend
57 c346aed0 Christos Stavrakakis

58 c346aed0 Christos Stavrakakis
Network reconciliation can detect and fix the following cases:
59 c346aed0 Christos Stavrakakis
    - Missing database entries for a network in a Ganeti backend
60 c346aed0 Christos Stavrakakis
    - Stale database networks, which do no exist in the Ganeti backend
61 c346aed0 Christos Stavrakakis
    - Missing Ganeti networks
62 c346aed0 Christos Stavrakakis
    - Ganeti networks that are not connected to all Ganeti nodegroups
63 c346aed0 Christos Stavrakakis
    - Networks that have unsynced state
64 c346aed0 Christos Stavrakakis
    - Networks that have unsynced IP pools
65 c346aed0 Christos Stavrakakis
    - Orphan networks in the Ganeti backend
66 c346aed0 Christos Stavrakakis
"""
67 c346aed0 Christos Stavrakakis
68 ad297723 Christos Stavrakakis
    can_import_settings = True
69 0e9a423f Christos Stavrakakis
    output_transaction = True  # The management command runs inside
70 0e9a423f Christos Stavrakakis
                               # an SQL transaction
71 0e9a423f Christos Stavrakakis
    option_list = BaseCommand.option_list + (
72 0e9a423f Christos Stavrakakis
        make_option('--fix-all', action='store_true',
73 0e9a423f Christos Stavrakakis
                    dest='fix', default=False,
74 0e9a423f Christos Stavrakakis
                    help='Fix all issues.'),
75 c55b0cdc Christos Stavrakakis
        make_option('--conflicting-ips', action='store_true',
76 c55b0cdc Christos Stavrakakis
                    dest='conflicting_ips', default=False,
77 c55b0cdc Christos Stavrakakis
                    help='Detect conflicting ips')
78 cc92b70f Christos Stavrakakis
    )
79 0e9a423f Christos Stavrakakis
80 0e9a423f Christos Stavrakakis
    def handle(self, **options):
81 c346aed0 Christos Stavrakakis
        global fix, write
82 0e9a423f Christos Stavrakakis
        fix = options['fix']
83 c346aed0 Christos Stavrakakis
        write = self.stdout.write
84 c346aed0 Christos Stavrakakis
        self.verbosity = int(options['verbosity'])
85 c55b0cdc Christos Stavrakakis
        conflicting_ips = options['conflicting_ips']
86 c346aed0 Christos Stavrakakis
        reconcile_networks(conflicting_ips)
87 0e9a423f Christos Stavrakakis
88 0e9a423f Christos Stavrakakis
89 c346aed0 Christos Stavrakakis
def reconcile_networks(conflicting_ips=False):
90 0e9a423f Christos Stavrakakis
    # Get models from DB
91 0e9a423f Christos Stavrakakis
    backends = Backend.objects.exclude(offline=True)
92 0e9a423f Christos Stavrakakis
    networks = Network.objects.filter(deleted=False)
93 0e9a423f Christos Stavrakakis
94 0e9a423f Christos Stavrakakis
    # Get info from all ganeti backends
95 0e9a423f Christos Stavrakakis
    ganeti_networks = {}
96 0e9a423f Christos Stavrakakis
    ganeti_hanging_networks = {}
97 0e9a423f Christos Stavrakakis
    for b in backends:
98 0e9a423f Christos Stavrakakis
        g_nets = reconciliation.get_networks_from_ganeti(b)
99 0e9a423f Christos Stavrakakis
        ganeti_networks[b] = g_nets
100 0e9a423f Christos Stavrakakis
        g_hanging_nets = reconciliation.hanging_networks(b, g_nets)
101 0e9a423f Christos Stavrakakis
        ganeti_hanging_networks[b] = g_hanging_nets
102 0e9a423f Christos Stavrakakis
103 0e9a423f Christos Stavrakakis
    # Perform reconciliation for each network
104 0e9a423f Christos Stavrakakis
    for network in networks:
105 fdc94944 Christos Stavrakakis
        ip_available_maps = []
106 fdc94944 Christos Stavrakakis
        ip_reserved_maps = []
107 c346aed0 Christos Stavrakakis
        uses_pool = not network.public or PUBLIC_USE_POOL
108 c346aed0 Christos Stavrakakis
        for bend in backends:
109 c346aed0 Christos Stavrakakis
            bnet = get_backend_network(network, bend)
110 de1fed2b Christos Stavrakakis
            gnet = ganeti_networks[bend].get(network.id)
111 de1fed2b Christos Stavrakakis
            if not (bnet or gnet):
112 de1fed2b Christos Stavrakakis
                # Network does not exist either in Ganeti nor in BD.
113 de1fed2b Christos Stavrakakis
                continue
114 de1fed2b Christos Stavrakakis
            if not bnet and gnet:
115 de1fed2b Christos Stavrakakis
                # Network exists in Ganeti and not in DB.
116 de1fed2b Christos Stavrakakis
                if network.action != "DESTROY" and not network.public:
117 de1fed2b Christos Stavrakakis
                    reconcile_parted_network(network, bend)
118 de1fed2b Christos Stavrakakis
119 de1fed2b Christos Stavrakakis
            if not gnet:
120 de1fed2b Christos Stavrakakis
                # Network does not exist in Ganeti. If the network action is
121 de1fed2b Christos Stavrakakis
                # DESTROY, we have to mark as deleted in DB, else we have to
122 de1fed2b Christos Stavrakakis
                # create it in Ganeti.
123 de1fed2b Christos Stavrakakis
                if network.action == "DESTROY":
124 de1fed2b Christos Stavrakakis
                    if bnet.operstate != "DELETED":
125 de1fed2b Christos Stavrakakis
                        reconcile_stale_network(bnet)
126 0e9a423f Christos Stavrakakis
                else:
127 c346aed0 Christos Stavrakakis
                    reconcile_missing_network(network, bend)
128 de1fed2b Christos Stavrakakis
                # Skip rest reconciliation!
129 de1fed2b Christos Stavrakakis
                continue
130 0e9a423f Christos Stavrakakis
131 0e9a423f Christos Stavrakakis
            try:
132 c346aed0 Christos Stavrakakis
                hanging_groups = ganeti_hanging_networks[bend][network.id]
133 0e9a423f Christos Stavrakakis
            except KeyError:
134 0e9a423f Christos Stavrakakis
                # Network is connected to all nodegroups
135 0e9a423f Christos Stavrakakis
                hanging_groups = []
136 0e9a423f Christos Stavrakakis
137 c346aed0 Christos Stavrakakis
            if hanging_groups:
138 c346aed0 Christos Stavrakakis
                # CASE-3: Ganeti networks not connected to all nodegroups
139 c346aed0 Christos Stavrakakis
                reconcile_hanging_groups(network, bend, hanging_groups)
140 c346aed0 Christos Stavrakakis
                continue
141 c346aed0 Christos Stavrakakis
142 c346aed0 Christos Stavrakakis
            if bnet.operstate != 'ACTIVE':
143 c346aed0 Christos Stavrakakis
                # CASE-4: Unsynced network state. At this point the network
144 c346aed0 Christos Stavrakakis
                # exists and is connected to all nodes so is must be active!
145 c346aed0 Christos Stavrakakis
                reconcile_unsynced_network(network, bend, bnet)
146 0e9a423f Christos Stavrakakis
147 ad297723 Christos Stavrakakis
            if uses_pool:
148 c346aed0 Christos Stavrakakis
                # Get ganeti IP Pools
149 c346aed0 Christos Stavrakakis
                available_map, reserved_map = get_network_pool(gnet)
150 c346aed0 Christos Stavrakakis
                ip_available_maps.append(available_map)
151 c346aed0 Christos Stavrakakis
                ip_reserved_maps.append(reserved_map)
152 fdc94944 Christos Stavrakakis
153 fdc94944 Christos Stavrakakis
        if uses_pool and (ip_available_maps or ip_reserved_maps):
154 c346aed0 Christos Stavrakakis
            # CASE-5: Unsynced IP Pools
155 c346aed0 Christos Stavrakakis
            reconcile_ip_pools(network, ip_available_maps, ip_reserved_maps)
156 c346aed0 Christos Stavrakakis
157 c55b0cdc Christos Stavrakakis
        if conflicting_ips:
158 c346aed0 Christos Stavrakakis
            detect_conflicting_ips()
159 c346aed0 Christos Stavrakakis
160 c346aed0 Christos Stavrakakis
    # CASE-6: Orphan networks
161 c346aed0 Christos Stavrakakis
    reconcile_orphan_networks(networks, ganeti_networks)
162 c346aed0 Christos Stavrakakis
163 c346aed0 Christos Stavrakakis
164 c346aed0 Christos Stavrakakis
def get_backend_network(network, backend):
165 c346aed0 Christos Stavrakakis
    try:
166 c346aed0 Christos Stavrakakis
        return BackendNetwork.objects.get(network=network, backend=backend)
167 c346aed0 Christos Stavrakakis
    except BackendNetwork.DoesNotExist:
168 c346aed0 Christos Stavrakakis
        return None
169 c346aed0 Christos Stavrakakis
170 c346aed0 Christos Stavrakakis
171 c346aed0 Christos Stavrakakis
def reconcile_parted_network(network, backend):
172 c346aed0 Christos Stavrakakis
    write("D: Missing DB entry for network %s in backend %s\n" %
173 c346aed0 Christos Stavrakakis
          (network, backend))
174 c346aed0 Christos Stavrakakis
    if fix:
175 c346aed0 Christos Stavrakakis
        network.create_backend_network(backend)
176 c346aed0 Christos Stavrakakis
        write("F: Created DB entry\n")
177 c346aed0 Christos Stavrakakis
        bnet = get_backend_network(network, backend)
178 c346aed0 Christos Stavrakakis
        return bnet
179 c55b0cdc Christos Stavrakakis
180 c346aed0 Christos Stavrakakis
181 c346aed0 Christos Stavrakakis
def reconcile_stale_network(backend_network):
182 c346aed0 Christos Stavrakakis
    write("D: Stale DB entry for network %s in backend %s\n" %
183 c346aed0 Christos Stavrakakis
          (backend_network.network, backend_network.backend))
184 c346aed0 Christos Stavrakakis
    if fix:
185 c346aed0 Christos Stavrakakis
        etime = datetime.datetime.now()
186 c346aed0 Christos Stavrakakis
        backend_mod.process_network_status(backend_network, etime, 0,
187 cc92b70f Christos Stavrakakis
                                           "OP_NETWORK_REMOVE",
188 cc92b70f Christos Stavrakakis
                                           "success",
189 cc92b70f Christos Stavrakakis
                                           "Reconciliation simulated event")
190 c346aed0 Christos Stavrakakis
        write("F: Reconciled event: OP_NETWORK_REMOVE\n")
191 c346aed0 Christos Stavrakakis
192 c346aed0 Christos Stavrakakis
193 c346aed0 Christos Stavrakakis
def reconcile_missing_network(network, backend):
194 c346aed0 Christos Stavrakakis
    write("D: Missing Ganeti network %s in backend %s\n" %
195 c346aed0 Christos Stavrakakis
          (network, backend))
196 c346aed0 Christos Stavrakakis
    if fix:
197 99af08a4 Christos Stavrakakis
        backend_mod.create_network(network, backend)
198 c346aed0 Christos Stavrakakis
        write("F: Issued OP_NETWORK_CONNECT\n")
199 c346aed0 Christos Stavrakakis
200 c346aed0 Christos Stavrakakis
201 c346aed0 Christos Stavrakakis
def reconcile_hanging_groups(network, backend, hanging_groups):
202 c346aed0 Christos Stavrakakis
    write('D: Network %s in backend %s is not connected to '
203 c346aed0 Christos Stavrakakis
          'the following groups:\n' % (network, backend))
204 c346aed0 Christos Stavrakakis
    write('-  ' + '\n-  '.join(hanging_groups) + '\n')
205 c346aed0 Christos Stavrakakis
    if fix:
206 c346aed0 Christos Stavrakakis
        for group in hanging_groups:
207 c346aed0 Christos Stavrakakis
            write('F: Connecting network %s to nodegroup %s\n'
208 c346aed0 Christos Stavrakakis
                  % (network, group))
209 99af08a4 Christos Stavrakakis
            backend_mod.connect_network(network, backend, depends=[],
210 99af08a4 Christos Stavrakakis
                                        group=group)
211 c346aed0 Christos Stavrakakis
212 c346aed0 Christos Stavrakakis
213 c346aed0 Christos Stavrakakis
def reconcile_unsynced_network(network, backend, backend_network):
214 c346aed0 Christos Stavrakakis
    write("D: Unsynced network %s in backend %s\n" % (network, backend))
215 c346aed0 Christos Stavrakakis
    if fix:
216 c346aed0 Christos Stavrakakis
        write("F: Issuing OP_NETWORK_CONNECT\n")
217 c346aed0 Christos Stavrakakis
        etime = datetime.datetime.now()
218 c346aed0 Christos Stavrakakis
        backend_mod.process_network_status(backend_network, etime, 0,
219 cc92b70f Christos Stavrakakis
                                           "OP_NETWORK_CONNECT",
220 cc92b70f Christos Stavrakakis
                                           "success",
221 cc92b70f Christos Stavrakakis
                                           "Reconciliation simulated eventd")
222 c346aed0 Christos Stavrakakis
223 c346aed0 Christos Stavrakakis
224 c346aed0 Christos Stavrakakis
def reconcile_ip_pools(network, available_maps, reserved_maps):
225 c346aed0 Christos Stavrakakis
    available_map = reduce(lambda x, y: x & y, available_maps)
226 c346aed0 Christos Stavrakakis
    reserved_map = reduce(lambda x, y: x & y, reserved_maps)
227 c346aed0 Christos Stavrakakis
228 c346aed0 Christos Stavrakakis
    pool = network.get_pool()
229 c346aed0 Christos Stavrakakis
    if pool.available != available_map:
230 c346aed0 Christos Stavrakakis
        write("D: Unsynced available map of network %s:\n"
231 c346aed0 Christos Stavrakakis
              "\tDB: %r\n\tGB: %r\n" %
232 2f70b788 Christos Stavrakakis
              (network, pool.available.to01(), available_map.to01()))
233 c346aed0 Christos Stavrakakis
        if fix:
234 c346aed0 Christos Stavrakakis
            pool.available = available_map
235 c346aed0 Christos Stavrakakis
    if pool.reserved != reserved_map:
236 c346aed0 Christos Stavrakakis
        write("D: Unsynced reserved map of network %s:\n"
237 c346aed0 Christos Stavrakakis
              "\tDB: %r\n\tGB: %r\n" %
238 c346aed0 Christos Stavrakakis
              (network, pool.reserved.to01(), reserved_map.to01()))
239 c346aed0 Christos Stavrakakis
        if fix:
240 c346aed0 Christos Stavrakakis
            pool.reserved = reserved_map
241 c346aed0 Christos Stavrakakis
    pool.save()
242 c346aed0 Christos Stavrakakis
243 c346aed0 Christos Stavrakakis
244 c346aed0 Christos Stavrakakis
def detect_conflicting_ips(network):
245 c346aed0 Christos Stavrakakis
    """Detect NIC's that have the same IP in the same network."""
246 c346aed0 Christos Stavrakakis
    machine_ips = network.nics.all().values_list('ipv4', 'machine')
247 c346aed0 Christos Stavrakakis
    ips = map(lambda x: x[0], machine_ips)
248 c346aed0 Christos Stavrakakis
    distinct_ips = set(ips)
249 c346aed0 Christos Stavrakakis
    if len(distinct_ips) < len(ips):
250 c346aed0 Christos Stavrakakis
        for i in distinct_ips:
251 c346aed0 Christos Stavrakakis
            ips.remove(i)
252 c346aed0 Christos Stavrakakis
        for i in ips:
253 cc92b70f Christos Stavrakakis
            machines = [utils.id_to_instance_name(x[1])
254 c346aed0 Christos Stavrakakis
                        for x in machine_ips if x[0] == i]
255 c346aed0 Christos Stavrakakis
            write('D: Conflicting IP:%s Machines: %s\n' %
256 c346aed0 Christos Stavrakakis
                  (i, ', '.join(machines)))
257 c346aed0 Christos Stavrakakis
258 c346aed0 Christos Stavrakakis
259 c346aed0 Christos Stavrakakis
def reconcile_orphan_networks(db_networks, ganeti_networks):
260 0e9a423f Christos Stavrakakis
    # Detect Orphan Networks in Ganeti
261 c346aed0 Christos Stavrakakis
    db_network_ids = set([net.id for net in db_networks])
262 0e9a423f Christos Stavrakakis
    for back_end, ganeti_networks in ganeti_networks.items():
263 0e9a423f Christos Stavrakakis
        ganeti_network_ids = set(ganeti_networks.keys())
264 0e9a423f Christos Stavrakakis
        orphans = ganeti_network_ids - db_network_ids
265 0e9a423f Christos Stavrakakis
266 0e9a423f Christos Stavrakakis
        if len(orphans) > 0:
267 c346aed0 Christos Stavrakakis
            write('D: Orphan Networks in backend %s:\n' % back_end.clustername)
268 c346aed0 Christos Stavrakakis
            write('-  ' + '\n-  '.join([str(o) for o in orphans]) + '\n')
269 0e9a423f Christos Stavrakakis
            if fix:
270 fdc94944 Christos Stavrakakis
                for net_id in orphans:
271 c346aed0 Christos Stavrakakis
                    write('Disconnecting and deleting network %d\n' % net_id)
272 8b71fc91 Christos Stavrakakis
                    try:
273 8b71fc91 Christos Stavrakakis
                        network = Network.objects.get(id=net_id)
274 8b71fc91 Christos Stavrakakis
                        backend_mod.delete_network(network,
275 99af08a4 Christos Stavrakakis
                                                   backend=back_end)
276 8b71fc91 Christos Stavrakakis
                    except Network.DoesNotExist:
277 8b71fc91 Christos Stavrakakis
                        write("Not entry for network %s in DB !!\n" % net_id)
278 c346aed0 Christos Stavrakakis
279 c346aed0 Christos Stavrakakis
280 c346aed0 Christos Stavrakakis
def get_network_pool(gnet):
281 c346aed0 Christos Stavrakakis
    """Return available and reserved IP maps.
282 c346aed0 Christos Stavrakakis

283 c346aed0 Christos Stavrakakis
    Extract the available and reserved IP map from the info return from Ganeti
284 c346aed0 Christos Stavrakakis
    for a network.
285 c346aed0 Christos Stavrakakis

286 c346aed0 Christos Stavrakakis
    """
287 c346aed0 Christos Stavrakakis
    converter = IPPool(Foo(gnet['network']))
288 c346aed0 Christos Stavrakakis
    a_map = bitarray_from_map(gnet['map'])
289 c346aed0 Christos Stavrakakis
    a_map.invert()
290 c346aed0 Christos Stavrakakis
    reserved = gnet['external_reservations']
291 c346aed0 Christos Stavrakakis
    r_map = a_map.copy()
292 c346aed0 Christos Stavrakakis
    r_map.setall(True)
293 c346aed0 Christos Stavrakakis
    for address in reserved.split(','):
294 c346aed0 Christos Stavrakakis
        index = converter.value_to_index(address)
295 c346aed0 Christos Stavrakakis
        a_map[index] = True
296 c346aed0 Christos Stavrakakis
        r_map[index] = False
297 c346aed0 Christos Stavrakakis
    return a_map, r_map
298 c55b0cdc Christos Stavrakakis
299 c55b0cdc Christos Stavrakakis
300 fdc94944 Christos Stavrakakis
def bitarray_from_map(bitmap):
301 c55b0cdc Christos Stavrakakis
    return bitarray.bitarray(bitmap.replace("X", "1").replace(".", "0"))
302 c55b0cdc Christos Stavrakakis
303 c55b0cdc Christos Stavrakakis
304 fdc94944 Christos Stavrakakis
class Foo():
305 fdc94944 Christos Stavrakakis
    def __init__(self, subnet):
306 fdc94944 Christos Stavrakakis
        self.available_map = ''
307 fdc94944 Christos Stavrakakis
        self.reserved_map = ''
308 fdc94944 Christos Stavrakakis
        self.size = 0
309 fdc94944 Christos Stavrakakis
        self.network = Foo.Foo1(subnet)
310 fdc94944 Christos Stavrakakis
311 fdc94944 Christos Stavrakakis
    class Foo1():
312 fdc94944 Christos Stavrakakis
        def __init__(self, subnet):
313 fdc94944 Christos Stavrakakis
            self.subnet = subnet
314 fdc94944 Christos Stavrakakis
            self.gateway = None