Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / management / commands / network-create.py @ b6426ead

History | View | Annotate | Download (8.4 kB)

1
# Copyright 2012 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 CommandError
37

    
38
from snf_django.management.commands import SynnefoCommand
39
from synnefo.management.common import convert_api_faults
40
from snf_django.management.utils import parse_bool
41

    
42
from synnefo.db.models import Network
43
from synnefo.logic import networks, subnets
44
from synnefo.management import pprint
45

    
46

    
47
NETWORK_FLAVORS = Network.FLAVORS.keys()
48

    
49

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

    
54
    help = "Create a new network"
55

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

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

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

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

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

    
181
        if subnet is None and gateway is not None:
182
            raise CommandError("Cannot use gateway without subnet")
183
        if subnet is None and allocation_pools is not None:
184
            raise CommandError("Cannot use allocation-pools without subnet")
185
        if subnet6 is None and gateway6 is not None:
186
            raise CommandError("Cannot use gateway6 without subnet6")
187
        if flavor == "IP_LESS_ROUTED" and not (subnet or subnet6):
188
            raise CommandError("Cannot create 'IP_LESS_ROUTED' network without"
189
                               " subnet")
190

    
191
        if not (userid or public):
192
            raise CommandError("'owner' is required for private networks")
193

    
194
        network = networks.create(userid=userid, name=name, flavor=flavor,
195
                                  public=public, mode=mode,
196
                                  link=link, mac_prefix=mac_prefix, tags=tags,
197
                                  floating_ip_pool=floating_ip_pool,
198
                                  drained=drained)
199

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

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

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

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