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

from optparse import make_option

from django.core.management.base import BaseCommand, CommandError
37
from synnefo.management.common import convert_api_faults
38
from snf_django.management.utils import parse_bool
39

40
from synnefo.db.models import Network
41
from synnefo.logic import networks, subnets
42
from synnefo.management import pprint
43

44
45
import ipaddr

46
NETWORK_FLAVORS = Network.FLAVORS.keys()
47
48
49


class Command(BaseCommand):
50
    can_import_settings = True
51
    output_transaction = True
52

53
54
55
    help = "Create a new network"

    option_list = BaseCommand.option_list + (
56
57
        make_option(
            '--name',
58
            dest='name',
59
            help="Name of the network"),
60
61
        make_option(
            '--owner',
62
63
            dest='owner',
            help="The owner of the network"),
64
65
        make_option(
            '--subnet',
66
67
68
            dest='subnet',
            default=None,
            # required=True,
69
            help='IPv4 subnet of the network'),
70
71
        make_option(
            '--gateway',
72
73
            dest='gateway',
            default=None,
74
            help='IPv4 gateway of the network'),
75
76
        make_option(
            '--subnet6',
77
78
79
            dest='subnet6',
            default=None,
            help='IPv6 subnet of the network'),
80
81
        make_option(
            '--gateway6',
82
83
84
            dest='gateway6',
            default=None,
            help='IPv6 gateway of the network'),
85
86
        make_option(
            '--dhcp',
87
            dest='dhcp',
88
            default="False",
89
90
            choices=["True", "False"],
            metavar="True|False",
91
            help='Automatically assign IPs'),
92
93
        make_option(
            '--public',
94
95
96
97
            dest='public',
            action='store_true',
            default=False,
            help='Network is public'),
98
99
        make_option(
            '--flavor',
100
            dest='flavor',
101
            default=None,
102
103
            choices=NETWORK_FLAVORS,
            help='Network flavor. Choices: ' + ', '.join(NETWORK_FLAVORS)),
104
105
        make_option(
            '--mode',
106
            dest='mode',
107
            default=None,
108
            help="Overwrite flavor connectivity mode."),
109
110
        make_option(
            '--link',
111
112
            dest='link',
            default=None,
113
            help="Overwrite flavor connectivity link."),
114
115
        make_option(
            '--mac-prefix',
116
117
            dest='mac_prefix',
            default=None,
118
            help="Overwrite flavor connectivity MAC prefix"),
119
120
        make_option(
            '--tags',
121
122
123
            dest='tags',
            default=None,
            help='The tags of the Network (comma separated strings)'),
124
125
126
127
128
129
        make_option(
            '--floating-ip-pool',
            dest='floating_ip_pool',
            default="False",
            choices=["True", "False"],
            metavar="True|False",
130
            help="Use the network as a Floating IP pool."),
131
        make_option(
Christos Stavrakakis's avatar
Christos Stavrakakis committed
132
            '--allocation-pool',
133
134
135
136
137
            dest='allocation_pools',
            action='append',
            help="IP allocation pools to be used for assigning IPs to"
                 " VMs. Can be used multiple times. Syntax: \n"
                 "192.168.42.220,192.168.42.240. Starting IP must proceed "
138
139
140
                 "ending IP. If no allocation pools are given, the whole "
                 "subnet range is used, excluding the gateway IP, the "
                 "broadcast address and the network address"),
141
142
143
144
145
146
147
        make_option(
            "--drained",
            dest="drained",
            metavar="True|False",
            choices=["True", "False"],
            default="False",
            help="Set network as drained to prevent creation of new ports."),
148
    )
149

150
    @convert_api_faults
151
152
153
154
155
156
    def handle(self, *args, **options):
        if args:
            raise CommandError("Command doesn't accept any arguments")

        name = options['name']
        subnet = options['subnet']
157
158
159
        gateway = options['gateway']
        subnet6 = options['subnet6']
        gateway6 = options['gateway6']
160
        public = options['public']
161
162
        flavor = options['flavor']
        mode = options['mode']
163
164
        link = options['link']
        mac_prefix = options['mac_prefix']
165
        tags = options['tags']
166
        userid = options["owner"]
167
        allocation_pools = options["allocation_pools"]
168
        floating_ip_pool = parse_bool(options["floating_ip_pool"])
169
        dhcp = parse_bool(options["dhcp"])
170
        drained = parse_bool(options["drained"])
171

172
173
174
        if name is None:
            name = ""
        if flavor is None:
175
176
            raise CommandError("flavor is required")

177
178
        if ((subnet is None) and (subnet6 is None)) and dhcp is not False:
            raise CommandError("Cannot set DHCP without subnet or subnet6")
179

180
        if subnet is None and gateway is not None:
181
            raise CommandError("Cannot use gateway without subnet")
182
183
        if subnet is None and allocation_pools is not None:
            raise CommandError("Cannot use allocation-pools without subnet")
184
        if subnet6 is None and gateway6 is not None:
185
            raise CommandError("Cannot use gateway6 without subnet6")
186

187
188
        if not (userid or public):
            raise CommandError("'owner' is required for private networks")
189

190
        network = networks.create(userid=userid, name=name, flavor=flavor,
191
                                  public=public, mode=mode,
192
                                  link=link, mac_prefix=mac_prefix, tags=tags,
193
194
                                  floating_ip_pool=floating_ip_pool,
                                  drained=drained)
195

196
        if subnet is not None:
197
198
199
200
            alloc = None
            if allocation_pools is not None:
                alloc = subnets.parse_allocation_pools(allocation_pools)
                alloc.sort()
201
202
203
            name = "IPv4 Subnet of Network %s" % network.id
            subnets.create_subnet(network.id, cidr=subnet, name=name,
                                  ipversion=4, gateway=gateway, dhcp=dhcp,
204
                                  user_id=userid,
205
                                  allocation_pools=alloc)
206

207
208
209
210
211
        if subnet6 is not None:
            name = "IPv6 Subnet of Network %s" % network.id
            subnets.create_subnet(network.id, cidr=subnet6, name=name,
                                  ipversion=6, gateway=gateway6,
                                  dhcp=dhcp, user_id=userid)
212

213
214
215
        self.stdout.write("Created network '%s' in DB:\n" % network)
        pprint.pprint_network(network, stdout=self.stdout)
        pprint.pprint_network_subnets(network, stdout=self.stdout)
216
217
218
219
220

        networks.create_network_in_backends(network)
        # TODO: Add --wait option to track job progress and report successful
        # creation in each backend.
        self.stdout.write("\nSuccessfully issued job to create network in"
221
                          " backends\n")