Statistics
| Branch: | Tag: | Revision:

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

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 c55b0cdc Christos Stavrakakis
from django.db import transaction
46 0e9a423f Christos Stavrakakis
47 0e9a423f Christos Stavrakakis
from synnefo.db.models import Backend, Network, BackendNetwork
48 fdc94944 Christos Stavrakakis
from synnefo.db.pools import IPPool
49 c346aed0 Christos Stavrakakis
from synnefo.logic import reconciliation, utils
50 c346aed0 Christos Stavrakakis
from synnefo.logic import backend as backend_mod
51 c346aed0 Christos Stavrakakis
52 c346aed0 Christos Stavrakakis
fix = False
53 c346aed0 Christos Stavrakakis
write = sys.stdout.write
54 0e9a423f Christos Stavrakakis
55 0e9a423f Christos Stavrakakis
56 0e9a423f Christos Stavrakakis
class Command(BaseCommand):
57 c346aed0 Christos Stavrakakis
    help = """Reconcile contents of Synnefo DB with state of Ganeti backend
58 c346aed0 Christos Stavrakakis

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

286 c346aed0 Christos Stavrakakis
    Extract the available and reserved IP map from the info return from Ganeti
287 c346aed0 Christos Stavrakakis
    for a network.
288 c346aed0 Christos Stavrakakis

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