Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / management / commands / network_reconcile.py @ 0e9a423f

History | View | Annotate | Download (7.4 kB)

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

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

36
"""
37
import datetime
38

    
39
from optparse import make_option
40

    
41
from django.conf import settings
42
from django.core.management.base import BaseCommand, CommandError
43

    
44
from synnefo.db.models import Backend, Network, BackendNetwork
45
from synnefo.logic import reconciliation, backend
46

    
47

    
48
class Command(BaseCommand):
49
    can_import_settings = True
50

    
51
    help = 'Reconcile contents of Synnefo DB with state of Ganeti backend'
52
    output_transaction = True  # The management command runs inside
53
                               # an SQL transaction
54
    option_list = BaseCommand.option_list + (
55
        make_option('--fix-all', action='store_true',
56
                    dest='fix', default=False,
57
                    help='Fix all issues.'),
58
        )
59

    
60
    def handle(self, **options):
61
        self.verbosity = int(options['verbosity'])
62
        fix = options['fix']
63
        reconcile_networks(self.stdout, fix)
64

    
65

    
66
def reconcile_networks(out, fix):
67
    # Get models from DB
68
    backends = Backend.objects.exclude(offline=True)
69
    networks = Network.objects.filter(deleted=False)
70

    
71
    # Get info from all ganeti backends
72
    ganeti_networks = {}
73
    ganeti_hanging_networks = {}
74
    for b in backends:
75
        g_nets = reconciliation.get_networks_from_ganeti(b)
76
        ganeti_networks[b] = g_nets
77
        g_hanging_nets = reconciliation.hanging_networks(b, g_nets)
78
        ganeti_hanging_networks[b] = g_hanging_nets
79

    
80
    # Perform reconciliation for each network
81
    for network in networks:
82
        net_id = network.id
83
        destroying = network.action == 'DESTROY'
84

    
85
        # Perform reconcilliation for each backend
86
        for b in backends:
87
            info = (net_id, b.clustername)
88
            back_network = None
89

    
90
            try:
91
                # Get the model describing the network to this backend
92
                back_network = BackendNetwork.objects.get(network=network,
93
                                                          backend=b)
94
            except BackendNetwork.DoesNotExist:
95
                out.write('D: No DB entry for network %d in backend %s\n' % info)
96
                if fix:
97
                    out.write('F: Created entry in DB\n')
98
                    back_network = \
99
                        BackendNetwork.objects.create(network=network,
100
                                                      backend=b)
101

    
102
            try:
103
                # Get the info from backend
104
                ganeti_networks[b][net_id]
105
            except KeyError:
106
                # Stale network does not exist in backend
107
                if destroying:
108
                    out.write('D: Stale network %d in backend %s\n' % info)
109
                    if fix:
110
                        out.write("F: Issued OP_NETWORK_REMOVE'\n")
111
                        etime = datetime.datetime.now()
112
                        backend.process_network_status(back_network, etime,
113
                                            0, 'OP_NETWORK_REMOVE', 'success',
114
                                            'Reconciliation simulated event.')
115
                    continue
116
                else:
117
                    # Pending network
118
                    out.write('D: Pending network %d in backend %s\n' % info)
119
                    if fix:
120
                        out.write('F: Creating network in backend.\n')
121
                        backend.create_network(network, [b])
122
                        # Skip rest reconciliation as the network is just
123
                        # being created
124
                    continue
125

    
126
            try:
127
                hanging_groups = ganeti_hanging_networks[b][net_id]
128
            except KeyError:
129
                # Network is connected to all nodegroups
130
                hanging_groups = []
131

    
132
            if hanging_groups and not destroying:
133
                # Hanging network = not connected to all nodegroups of backend
134
                out.write('D: Network %d in backend %s is not connected to '
135
                          'the following groups:\n' % info)
136
                out.write('-  ' + '\n-  '.join(hanging_groups) + '\n')
137
                if fix:
138
                    for group in hanging_groups:
139
                        out.write('F: Connecting network %d to nodegroup %s\n'
140
                                  % (net_id, group))
141
                        backend.connect_network_group(b, network, group)
142
            elif back_network and back_network.operstate != 'ACTIVE':
143
                # Network is active
144
                out.write('D: Unsynced network %d in backend %s\n' % info)
145
                if fix:
146
                    out.write("F: Issued OP_NETWORK_CONNECT\n")
147
                    etime = datetime.datetime.now()
148
                    backend.process_network_status(back_network, etime,
149
                                        0, 'OP_NETWORK_CONNECT', 'success',
150
                                        'Reconciliation simulated event.')
151

    
152
    # Detect Orphan Networks in Ganeti
153
    db_network_ids = set([net.id for net in networks])
154
    for back_end, ganeti_networks in ganeti_networks.items():
155
        ganeti_network_ids = set(ganeti_networks.keys())
156
        orphans = ganeti_network_ids - db_network_ids
157

    
158
        if len(orphans) > 0:
159
            out.write('D: Orphan Networks in backend %s:\n' % back_end.clustername)
160
            out.write('-  ' + '\n-  '.join([str(o) for o in orphans]) + '\n')
161
            client = back_end.client
162
            if fix:
163
                #XXX:Move this to backend
164
                for id in orphans:
165
                    out.write('Disconnecting and deleting network %d\n' % id)
166
                    network = '%s%s' % (settings.BACKEND_PREFIX_ID, str(id))
167
                    for group in client.GetGroups():
168
                        client.DisconnectNetwork(network, group)
169
                        client.DeleteNetwork(network)