Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / management / commands / network-modify.py @ 35f2fc07

History | View | Annotate | Download (10.4 kB)

1 449c2d82 Christos Stavrakakis
# Copyright 2012-2013 GRNET S.A. All rights reserved.
2 8fad925a Giorgos Verigakis
#
3 8fad925a Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 8fad925a Giorgos Verigakis
# without modification, are permitted provided that the following
5 8fad925a Giorgos Verigakis
# conditions are met:
6 8fad925a Giorgos Verigakis
#
7 8fad925a Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 8fad925a Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 8fad925a Giorgos Verigakis
#      disclaimer.
10 8fad925a Giorgos Verigakis
#
11 8fad925a Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 8fad925a Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 8fad925a Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 8fad925a Giorgos Verigakis
#      provided with the distribution.
15 8fad925a Giorgos Verigakis
#
16 8fad925a Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 8fad925a Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 8fad925a Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 8fad925a Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 8fad925a Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 8fad925a Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 8fad925a Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 8fad925a Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 8fad925a Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 8fad925a Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 8fad925a Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 8fad925a Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 8fad925a Giorgos Verigakis
#
29 8fad925a Giorgos Verigakis
# The views and conclusions contained in the software and
30 8fad925a Giorgos Verigakis
# documentation are those of the authors and should not be
31 8fad925a Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 8fad925a Giorgos Verigakis
# or implied, of GRNET S.A.
33 8fad925a Giorgos Verigakis
34 8fad925a Giorgos Verigakis
from optparse import make_option
35 8fad925a Giorgos Verigakis
36 8fad925a Giorgos Verigakis
from django.core.management.base import BaseCommand, CommandError
37 8fad925a Giorgos Verigakis
38 5e5b2476 Christos Stavrakakis
from synnefo.db.models import (Network, Backend, BackendNetwork,
39 5e5b2476 Christos Stavrakakis
                               pooled_rapi_client)
40 a4658bbe Christos Stavrakakis
from synnefo.management.common import (get_network, get_backend)
41 d758784b Christos Stavrakakis
from snf_django.management.utils import parse_bool
42 a4658bbe Christos Stavrakakis
from synnefo.logic import networks
43 5ec446aa Christos Stavrakakis
from synnefo.logic.backend import create_network, delete_network
44 53b9ba10 Christos Stavrakakis
45 9621c777 Christos Stavrakakis
HELP_MSG = """Modify a network.
46 53b9ba10 Christos Stavrakakis

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

52 53b9ba10 Christos Stavrakakis
The only exception is add_reserved_ips and remove_reserved_ips options, which
53 53b9ba10 Christos Stavrakakis
modify the IP pool in the Ganeti backends.
54 53b9ba10 Christos Stavrakakis
"""
55 8fad925a Giorgos Verigakis
56 8fad925a Giorgos Verigakis
57 8fad925a Giorgos Verigakis
class Command(BaseCommand):
58 8fad925a Giorgos Verigakis
    args = "<network id>"
59 53b9ba10 Christos Stavrakakis
    help = HELP_MSG
60 53b9ba10 Christos Stavrakakis
    output_transaction = True
61 8fad925a Giorgos Verigakis
62 8fad925a Giorgos Verigakis
    option_list = BaseCommand.option_list + (
63 9621c777 Christos Stavrakakis
        make_option(
64 9621c777 Christos Stavrakakis
            '--name',
65 8fad925a Giorgos Verigakis
            dest='name',
66 8fad925a Giorgos Verigakis
            metavar='NAME',
67 8fad925a Giorgos Verigakis
            help="Set network's name"),
68 9621c777 Christos Stavrakakis
        make_option(
69 9621c777 Christos Stavrakakis
            '--userid',
70 53b9ba10 Christos Stavrakakis
            dest='userid',
71 53b9ba10 Christos Stavrakakis
            help="Set the userid of the network owner"),
72 9621c777 Christos Stavrakakis
        make_option(
73 9621c777 Christos Stavrakakis
            '--subnet',
74 bf1d3a70 Christos Stavrakakis
            dest='subnet',
75 bf1d3a70 Christos Stavrakakis
            help="Set network's subnet"),
76 9621c777 Christos Stavrakakis
        make_option(
77 9621c777 Christos Stavrakakis
            '--gateway',
78 bf1d3a70 Christos Stavrakakis
            dest='gateway',
79 bf1d3a70 Christos Stavrakakis
            help="Set network's gateway"),
80 9621c777 Christos Stavrakakis
        make_option(
81 9621c777 Christos Stavrakakis
            '--subnet6',
82 cc3f266e Christos Stavrakakis
            dest='subnet6',
83 cc3f266e Christos Stavrakakis
            help="Set network's IPv6 subnet"),
84 9621c777 Christos Stavrakakis
        make_option(
85 9621c777 Christos Stavrakakis
            '--gateway6',
86 cc3f266e Christos Stavrakakis
            dest='gateway6',
87 cc3f266e Christos Stavrakakis
            help="Set network's IPv6 gateway"),
88 9621c777 Christos Stavrakakis
        make_option(
89 9621c777 Christos Stavrakakis
            '--dhcp',
90 bf1d3a70 Christos Stavrakakis
            dest='dhcp',
91 052ef3b9 Christos Stavrakakis
            metavar="True|False",
92 052ef3b9 Christos Stavrakakis
            choices=["True", "False"],
93 bf1d3a70 Christos Stavrakakis
            help="Set if network will use nfdhcp"),
94 9621c777 Christos Stavrakakis
        make_option(
95 9621c777 Christos Stavrakakis
            '--state',
96 8fad925a Giorgos Verigakis
            dest='state',
97 8fad925a Giorgos Verigakis
            metavar='STATE',
98 53b9ba10 Christos Stavrakakis
            help="Set network's state"),
99 9621c777 Christos Stavrakakis
        make_option(
100 9621c777 Christos Stavrakakis
            '--link',
101 53b9ba10 Christos Stavrakakis
            dest='link',
102 53b9ba10 Christos Stavrakakis
            help="Set the connectivity link"),
103 9621c777 Christos Stavrakakis
        make_option(
104 9621c777 Christos Stavrakakis
            '--mac-prefix',
105 53b9ba10 Christos Stavrakakis
            dest="mac_prefix",
106 53b9ba10 Christos Stavrakakis
            help="Set the MAC prefix"),
107 9621c777 Christos Stavrakakis
        make_option(
108 9621c777 Christos Stavrakakis
            '--add-reserved-ips',
109 53b9ba10 Christos Stavrakakis
            dest="add_reserved_ips",
110 53b9ba10 Christos Stavrakakis
            help="Comma seperated list of IPs to externally reserve."),
111 9621c777 Christos Stavrakakis
        make_option(
112 9621c777 Christos Stavrakakis
            '--remove-reserved-ips',
113 53b9ba10 Christos Stavrakakis
            dest="remove_reserved_ips",
114 53b9ba10 Christos Stavrakakis
            help="Comma seperated list of IPs to externally release."),
115 6dafedf6 Christos Stavrakakis
        make_option(
116 6dafedf6 Christos Stavrakakis
            "--drained",
117 6dafedf6 Christos Stavrakakis
            dest="drained",
118 6dafedf6 Christos Stavrakakis
            metavar="True|False",
119 6dafedf6 Christos Stavrakakis
            choices=["True", "False"],
120 6dafedf6 Christos Stavrakakis
            help="Set as drained to exclude for IP allocation."
121 5ec446aa Christos Stavrakakis
                 " Only used for public networks."),
122 5ec446aa Christos Stavrakakis
        make_option(
123 5ec446aa Christos Stavrakakis
            "--add-to-backend",
124 5ec446aa Christos Stavrakakis
            dest="add_to_backend",
125 5ec446aa Christos Stavrakakis
            help="Create a public network to a Ganeti backend."),
126 5ec446aa Christos Stavrakakis
        make_option(
127 5ec446aa Christos Stavrakakis
            "--remove-from-backend",
128 5ec446aa Christos Stavrakakis
            dest="remove_from_backend",
129 5ec446aa Christos Stavrakakis
            help="Remove a public network from a Ganeti backend."),
130 5e5b2476 Christos Stavrakakis
        make_option(
131 5e5b2476 Christos Stavrakakis
            "--floating-ip-pool",
132 5e5b2476 Christos Stavrakakis
            dest="floating_ip_pool",
133 5e5b2476 Christos Stavrakakis
            metavar="True|False",
134 5e5b2476 Christos Stavrakakis
            choices=["True", "False"],
135 5e5b2476 Christos Stavrakakis
            help="Convert network to a floating IP pool. During this"
136 5e5b2476 Christos Stavrakakis
                 " conversation the network will be created to all"
137 5e5b2476 Christos Stavrakakis
                 " available Ganeti backends."),
138 8fad925a Giorgos Verigakis
    )
139 8fad925a Giorgos Verigakis
140 8fad925a Giorgos Verigakis
    def handle(self, *args, **options):
141 8fad925a Giorgos Verigakis
        if len(args) != 1:
142 c2d969cb Christos Stavrakakis
            raise CommandError("Please provide a network ID")
143 8fad925a Giorgos Verigakis
144 b84ed662 Christos Stavrakakis
        network = get_network(args[0])
145 8fad925a Giorgos Verigakis
146 53b9ba10 Christos Stavrakakis
        # Validate subnet
147 a4658bbe Christos Stavrakakis
        subnet = options["subnet"] or network.subnet
148 a4658bbe Christos Stavrakakis
        gateway = options["gateway"] or network.gateway
149 a4658bbe Christos Stavrakakis
        subnet6 = options["subnet6"] or network.subnet6
150 a4658bbe Christos Stavrakakis
        gateway6 = options["gateway6"] or network.gateway6
151 a4658bbe Christos Stavrakakis
        networks.validate_network_params(subnet, gateway, subnet6, gateway6)
152 bf1d3a70 Christos Stavrakakis
153 53b9ba10 Christos Stavrakakis
        # Validate state
154 8fad925a Giorgos Verigakis
        state = options.get('state')
155 53b9ba10 Christos Stavrakakis
        if state:
156 fd33b074 Kostas Papadimitriou
            allowed = [x[0] for x in Network.OPER_STATES]
157 8fad925a Giorgos Verigakis
            if state not in allowed:
158 8fad925a Giorgos Verigakis
                msg = "Invalid state, must be one of %s" % ', '.join(allowed)
159 8fad925a Giorgos Verigakis
                raise CommandError(msg)
160 53b9ba10 Christos Stavrakakis
161 5e5b2476 Christos Stavrakakis
        floating_ip_pool = options["floating_ip_pool"]
162 b47f167a Christos Stavrakakis
        if floating_ip_pool is not None:
163 b47f167a Christos Stavrakakis
            floating_ip_pool = parse_bool(floating_ip_pool)
164 4111c53e Christos Stavrakakis
            options["floating_ip_pool"] = floating_ip_pool
165 5e5b2476 Christos Stavrakakis
        if floating_ip_pool is False and network.floating_ip_pool is True:
166 5e5b2476 Christos Stavrakakis
            if network.floating_ips.filter(deleted=False).exists():
167 b47f167a Christos Stavrakakis
                msg = ("Can not make network a non floating IP pool. There are"
168 b47f167a Christos Stavrakakis
                       " still reserved floating IPs.")
169 5e5b2476 Christos Stavrakakis
                raise CommandError(msg)
170 5e5b2476 Christos Stavrakakis
        elif floating_ip_pool is True:
171 16855230 Christos Stavrakakis
            existing =\
172 16855230 Christos Stavrakakis
                network.backend_networks.filter(operstate="ACTIVE")\
173 16855230 Christos Stavrakakis
                                        .values_list("backend", flat=True)
174 16855230 Christos Stavrakakis
            for backend in Backend.objects.filter(offline=False)\
175 16855230 Christos Stavrakakis
                                          .exclude(id__in=existing):
176 5e5b2476 Christos Stavrakakis
                check_link_availability(backend, network)
177 5e5b2476 Christos Stavrakakis
178 052ef3b9 Christos Stavrakakis
        dhcp = options.get("dhcp")
179 052ef3b9 Christos Stavrakakis
        if dhcp:
180 052ef3b9 Christos Stavrakakis
            options["dhcp"] = parse_bool(dhcp)
181 6dafedf6 Christos Stavrakakis
        drained = options.get("drained")
182 6dafedf6 Christos Stavrakakis
        if drained:
183 6dafedf6 Christos Stavrakakis
            options["drained"] = parse_bool(drained)
184 53b9ba10 Christos Stavrakakis
        fields = ('name', 'userid', 'subnet', 'gateway', 'subnet6', 'gateway6',
185 5e5b2476 Christos Stavrakakis
                  'dhcp', 'state', 'link', 'mac_prefix', 'drained',
186 5e5b2476 Christos Stavrakakis
                  'floating_ip_pool')
187 53b9ba10 Christos Stavrakakis
        for field in fields:
188 53b9ba10 Christos Stavrakakis
            value = options.get(field, None)
189 052ef3b9 Christos Stavrakakis
            if value is not None:
190 53b9ba10 Christos Stavrakakis
                network.__setattr__(field, value)
191 53b9ba10 Christos Stavrakakis
192 449c2d82 Christos Stavrakakis
        network.save()
193 449c2d82 Christos Stavrakakis
194 53b9ba10 Christos Stavrakakis
        add_reserved_ips = options.get('add_reserved_ips')
195 53b9ba10 Christos Stavrakakis
        remove_reserved_ips = options.get('remove_reserved_ips')
196 53b9ba10 Christos Stavrakakis
        if add_reserved_ips or remove_reserved_ips:
197 53b9ba10 Christos Stavrakakis
            if add_reserved_ips:
198 53b9ba10 Christos Stavrakakis
                add_reserved_ips = add_reserved_ips.split(",")
199 53b9ba10 Christos Stavrakakis
            if remove_reserved_ips:
200 53b9ba10 Christos Stavrakakis
                remove_reserved_ips = remove_reserved_ips.split(",")
201 53b9ba10 Christos Stavrakakis
202 449c2d82 Christos Stavrakakis
            for bnetwork in network.backend_networks.all():
203 449c2d82 Christos Stavrakakis
                with pooled_rapi_client(bnetwork.backend) as c:
204 449c2d82 Christos Stavrakakis
                    c.ModifyNetwork(network=network.backend_id,
205 449c2d82 Christos Stavrakakis
                                    add_reserved_ips=add_reserved_ips,
206 449c2d82 Christos Stavrakakis
                                    remove_reserved_ips=remove_reserved_ips)
207 5ec446aa Christos Stavrakakis
208 5e5b2476 Christos Stavrakakis
        if floating_ip_pool is True:
209 5e5b2476 Christos Stavrakakis
            for backend in Backend.objects.filter(offline=False):
210 5e5b2476 Christos Stavrakakis
                try:
211 5e5b2476 Christos Stavrakakis
                    bnet = network.backend_networks.get(backend=backend)
212 5e5b2476 Christos Stavrakakis
                except BackendNetwork.DoesNotExist:
213 5e5b2476 Christos Stavrakakis
                    bnet = network.create_backend_network(backend=backend)
214 b47f167a Christos Stavrakakis
                if bnet.operstate != "ACTIVE":
215 5e5b2476 Christos Stavrakakis
                    create_network(network, backend, connect=True)
216 5e5b2476 Christos Stavrakakis
                    msg = "Sent job to create network '%s' in backend '%s'\n"
217 5e5b2476 Christos Stavrakakis
                    self.stdout.write(msg % (network, backend))
218 5e5b2476 Christos Stavrakakis
219 5ec446aa Christos Stavrakakis
        add_to_backend = options["add_to_backend"]
220 5ec446aa Christos Stavrakakis
        if add_to_backend is not None:
221 5ec446aa Christos Stavrakakis
            backend = get_backend(add_to_backend)
222 5ec446aa Christos Stavrakakis
            network.create_backend_network(backend=backend)
223 5ec446aa Christos Stavrakakis
            create_network(network, backend, connect=True)
224 5ec446aa Christos Stavrakakis
            msg = "Sent job to create network '%s' in backend '%s'\n"
225 5ec446aa Christos Stavrakakis
            self.stdout.write(msg % (network, backend))
226 5ec446aa Christos Stavrakakis
227 5ec446aa Christos Stavrakakis
        remove_from_backend = options["remove_from_backend"]
228 5ec446aa Christos Stavrakakis
        if remove_from_backend is not None:
229 5ec446aa Christos Stavrakakis
            backend = get_backend(remove_from_backend)
230 5ec446aa Christos Stavrakakis
            if network.nics.filter(machine__backend=backend,
231 5ec446aa Christos Stavrakakis
                                   machine__deleted=False).exists():
232 5ec446aa Christos Stavrakakis
                msg = "Can not remove. There are still connected VMs to this"\
233 5ec446aa Christos Stavrakakis
                      " network"
234 5ec446aa Christos Stavrakakis
                raise CommandError(msg)
235 5ec446aa Christos Stavrakakis
            network.action = "DESTROY"
236 5ec446aa Christos Stavrakakis
            network.save()
237 5ec446aa Christos Stavrakakis
            delete_network(network, backend, disconnect=True)
238 5ec446aa Christos Stavrakakis
            msg = "Sent job to delete network '%s' from backend '%s'\n"
239 5ec446aa Christos Stavrakakis
            self.stdout.write(msg % (network, backend))
240 5e5b2476 Christos Stavrakakis
241 5e5b2476 Christos Stavrakakis
242 5e5b2476 Christos Stavrakakis
def check_link_availability(backend, network):
243 5e5b2476 Christos Stavrakakis
    """Check if network link is available in backend."""
244 5e5b2476 Christos Stavrakakis
    with pooled_rapi_client(backend) as c:
245 5e5b2476 Christos Stavrakakis
        ganeti_networks = c.GetNetworks(bulk=True)
246 5e5b2476 Christos Stavrakakis
    name = network.backend_id
247 5e5b2476 Christos Stavrakakis
    mode = network.mode
248 5e5b2476 Christos Stavrakakis
    link = network.link
249 5e5b2476 Christos Stavrakakis
    for gnet in ganeti_networks:
250 b47f167a Christos Stavrakakis
        if (gnet["name"] != name and
251 16855230 Christos Stavrakakis
            reduce(lambda x, y: x or y,
252 16855230 Christos Stavrakakis
                   ["(%s, %s)" % (mode, link) in gnet["group_list"]],
253 16855230 Christos Stavrakakis
                   False)):
254 16855230 Christos Stavrakakis
           # Ganeti >= 2.7
255 16855230 Christos Stavrakakis
           #(mode, link) in [(m, l) for (_, m, l) in gnet["group_list"]]):
256 5e5b2476 Christos Stavrakakis
            msg = "Can not create network '%s' in backend '%s'. Link '%s'" \
257 5e5b2476 Christos Stavrakakis
                  " is already used by network '%s" % \
258 16855230 Christos Stavrakakis
                  (network, backend, link, gnet["name"])
259 5e5b2476 Christos Stavrakakis
            raise CommandError(msg)