Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / management / commands / network-modify.py @ 449c2d82

History | View | Annotate | Download (7.5 kB)

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

    
34
from optparse import make_option
35

    
36
from django.core.management.base import BaseCommand, CommandError
37

    
38
from synnefo.db.models import Network, pooled_rapi_client
39
from synnefo.management.common import (validate_network_info, get_network,
40
                                       get_backend)
41
from synnefo.webproject.management.utils import parse_bool
42
from synnefo.logic.backend import create_network, delete_network
43

    
44
HELP_MSG = """Modify a network.
45

46
This management command will only modify the state of the network in Cyclades
47
DB. The state of the network in the Ganeti backends will remain unchanged. You
48
should manually modify the network in all the backends, to synchronize the
49
state of DB and Ganeti.
50

51
The only exception is add_reserved_ips and remove_reserved_ips options, which
52
modify the IP pool in the Ganeti backends.
53
"""
54

    
55

    
56
class Command(BaseCommand):
57
    args = "<network id>"
58
    help = HELP_MSG
59
    output_transaction = True
60

    
61
    option_list = BaseCommand.option_list + (
62
        make_option(
63
            '--name',
64
            dest='name',
65
            metavar='NAME',
66
            help="Set network's name"),
67
        make_option(
68
            '--userid',
69
            dest='userid',
70
            help="Set the userid of the network owner"),
71
        make_option(
72
            '--subnet',
73
            dest='subnet',
74
            help="Set network's subnet"),
75
        make_option(
76
            '--gateway',
77
            dest='gateway',
78
            help="Set network's gateway"),
79
        make_option(
80
            '--subnet6',
81
            dest='subnet6',
82
            help="Set network's IPv6 subnet"),
83
        make_option(
84
            '--gateway6',
85
            dest='gateway6',
86
            help="Set network's IPv6 gateway"),
87
        make_option(
88
            '--dhcp',
89
            dest='dhcp',
90
            metavar="True|False",
91
            choices=["True", "False"],
92
            help="Set if network will use nfdhcp"),
93
        make_option(
94
            '--state',
95
            dest='state',
96
            metavar='STATE',
97
            help="Set network's state"),
98
        make_option(
99
            '--link',
100
            dest='link',
101
            help="Set the connectivity link"),
102
        make_option(
103
            '--mac-prefix',
104
            dest="mac_prefix",
105
            help="Set the MAC prefix"),
106
        make_option(
107
            '--add-reserved-ips',
108
            dest="add_reserved_ips",
109
            help="Comma seperated list of IPs to externally reserve."),
110
        make_option(
111
            '--remove-reserved-ips',
112
            dest="remove_reserved_ips",
113
            help="Comma seperated list of IPs to externally release."),
114
        make_option(
115
            "--drained",
116
            dest="drained",
117
            metavar="True|False",
118
            choices=["True", "False"],
119
            help="Set as drained to exclude for IP allocation."
120
                 " Only used for public networks."),
121
        make_option(
122
            "--add-to-backend",
123
            dest="add_to_backend",
124
            help="Create a public network to a Ganeti backend."),
125
        make_option(
126
            "--remove-from-backend",
127
            dest="remove_from_backend",
128
            help="Remove a public network from a Ganeti backend."),
129
    )
130

    
131
    def handle(self, *args, **options):
132
        if len(args) != 1:
133
            raise CommandError("Please provide a network ID")
134

    
135
        network = get_network(args[0])
136

    
137
        # Validate subnet
138
        if options.get('subnet'):
139
            validate_network_info(options)
140

    
141
        # Validate state
142
        state = options.get('state')
143
        if state:
144
            allowed = [x[0] for x in Network.OPER_STATES]
145
            if state not in allowed:
146
                msg = "Invalid state, must be one of %s" % ', '.join(allowed)
147
                raise CommandError(msg)
148

    
149
        dhcp = options.get("dhcp")
150
        if dhcp:
151
            options["dhcp"] = parse_bool(dhcp)
152
        drained = options.get("drained")
153
        if drained:
154
            options["drained"] = parse_bool(drained)
155
        fields = ('name', 'userid', 'subnet', 'gateway', 'subnet6', 'gateway6',
156
                  'dhcp', 'state', 'link', 'mac_prefix', 'drained')
157
        for field in fields:
158
            value = options.get(field, None)
159
            if value is not None:
160
                network.__setattr__(field, value)
161

    
162
        network.save()
163

    
164
        add_reserved_ips = options.get('add_reserved_ips')
165
        remove_reserved_ips = options.get('remove_reserved_ips')
166
        if add_reserved_ips or remove_reserved_ips:
167
            if add_reserved_ips:
168
                add_reserved_ips = add_reserved_ips.split(",")
169
            if remove_reserved_ips:
170
                remove_reserved_ips = remove_reserved_ips.split(",")
171

    
172
            for bnetwork in network.backend_networks.all():
173
                with pooled_rapi_client(bnetwork.backend) as c:
174
                    c.ModifyNetwork(network=network.backend_id,
175
                                    add_reserved_ips=add_reserved_ips,
176
                                    remove_reserved_ips=remove_reserved_ips)
177

    
178
        add_to_backend = options["add_to_backend"]
179
        if add_to_backend is not None:
180
            backend = get_backend(add_to_backend)
181
            network.create_backend_network(backend=backend)
182
            create_network(network, backend, connect=True)
183
            msg = "Sent job to create network '%s' in backend '%s'\n"
184
            self.stdout.write(msg % (network, backend))
185

    
186
        remove_from_backend = options["remove_from_backend"]
187
        if remove_from_backend is not None:
188
            backend = get_backend(remove_from_backend)
189
            if network.nics.filter(machine__backend=backend,
190
                                   machine__deleted=False).exists():
191
                msg = "Can not remove. There are still connected VMs to this"\
192
                      " network"
193
                raise CommandError(msg)
194
            network.action = "DESTROY"
195
            network.save()
196
            delete_network(network, backend, disconnect=True)
197
            msg = "Sent job to delete network '%s' from backend '%s'\n"
198
            self.stdout.write(msg % (network, backend))