Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / management / commands / network-create.py @ 64cdd31b

History | View | Annotate | Download (8.2 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 BaseCommand, CommandError
37
from synnefo.management.common import validate_network_info, get_backend
38
from synnefo.webproject.management.utils import pprint_table, parse_bool
39

    
40
from synnefo import quotas
41
from synnefo.db.models import Network, Backend
42
from synnefo.db.utils import validate_mac, InvalidMacAddress
43
from synnefo.logic.backend import create_network
44
from synnefo.api.util import values_from_flavor
45

    
46
NETWORK_FLAVORS = Network.FLAVORS.keys()
47

    
48

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

    
53
    help = "Create a new network"
54

    
55
    option_list = BaseCommand.option_list + (
56
        make_option(
57
            "-n",
58
            "--dry-run",
59
            dest="dry_run",
60
            default=False,
61
            action="store_true"),
62
        make_option(
63
            '--name',
64
            dest='name',
65
            help="Name of network"),
66
        make_option(
67
            '--owner',
68
            dest='owner',
69
            help="The owner of the network"),
70
        make_option(
71
            '--subnet',
72
            dest='subnet',
73
            default=None,
74
            # required=True,
75
            help='Subnet of the network'),
76
        make_option(
77
            '--gateway',
78
            dest='gateway',
79
            default=None,
80
            help='Gateway of the network'),
81
        make_option(
82
            '--subnet6',
83
            dest='subnet6',
84
            default=None,
85
            help='IPv6 subnet of the network'),
86
        make_option(
87
            '--gateway6',
88
            dest='gateway6',
89
            default=None,
90
            help='IPv6 gateway of the network'),
91
        make_option(
92
            '--dhcp',
93
            dest='dhcp',
94
            action='store_true',
95
            default=False,
96
            help='Automatically assign IPs'),
97
        make_option(
98
            '--public',
99
            dest='public',
100
            action='store_true',
101
            default=False,
102
            help='Network is public'),
103
        make_option(
104
            '--flavor',
105
            dest='flavor',
106
            default=None,
107
            choices=NETWORK_FLAVORS,
108
            help='Network flavor. Choices: ' + ', '.join(NETWORK_FLAVORS)),
109
        make_option(
110
            '--mode',
111
            dest='mode',
112
            default=None,
113
            help="Overwrite flavor connectivity mode."),
114
        make_option(
115
            '--link',
116
            dest='link',
117
            default=None,
118
            help="Overwrite flavor connectivity link."),
119
        make_option(
120
            '--mac-prefix',
121
            dest='mac_prefix',
122
            default=None,
123
            help="Overwrite flavor connectivity MAC prefix"),
124
        make_option(
125
            '--tags',
126
            dest='tags',
127
            default=None,
128
            help='The tags of the Network (comma separated strings)'),
129
        make_option(
130
            '--floating-ip-pool',
131
            dest='floating_ip_pool',
132
            default="False",
133
            choices=["True", "False"],
134
            metavar="True|False",
135
            help="Use the network as a Floating IP pool. Floating IP pools"
136
                 " are created in all available backends."),
137
        make_option(
138
            '--backend-id',
139
            dest='backend_id',
140
            default=None,
141
            help='ID of the backend that the network will be created. Only for'
142
                 ' public networks'),
143
    )
144

    
145
    def handle(self, *args, **options):
146
        if args:
147
            raise CommandError("Command doesn't accept any arguments")
148

    
149
        dry_run = options["dry_run"]
150
        name = options['name']
151
        subnet = options['subnet']
152
        backend_id = options['backend_id']
153
        public = options['public']
154
        flavor = options['flavor']
155
        mode = options['mode']
156
        link = options['link']
157
        mac_prefix = options['mac_prefix']
158
        tags = options['tags']
159
        userid = options["owner"]
160
        floating_ip_pool = parse_bool(options["floating_ip_pool"])
161

    
162
        if not name:
163
            raise CommandError("Name is required")
164
        if not subnet:
165
            raise CommandError("Subnet is required")
166
        if not flavor:
167
            raise CommandError("Flavor is required")
168
        if public and not (backend_id or floating_ip_pool):
169
            raise CommandError("backend-id is required")
170
        if not userid and not public:
171
            raise CommandError("'owner' is required for private networks")
172

    
173
        if mac_prefix and flavor == "MAC_FILTERED":
174
            raise CommandError("Can not override MAC_FILTERED mac-prefix")
175
        if link and flavor == "PHYSICAL_VLAN":
176
            raise CommandError("Can not override PHYSICAL_VLAN link")
177

    
178
        if backend_id:
179
            backend = get_backend(backend_id)
180

    
181
        fmode, flink, fmac_prefix, ftags = values_from_flavor(flavor)
182
        mode = mode or fmode
183
        link = link or flink
184
        mac_prefix = mac_prefix or fmac_prefix
185
        tags = tags or ftags
186

    
187
        try:
188
            validate_mac(mac_prefix + "0:00:00:00")
189
        except InvalidMacAddress:
190
            raise CommandError("Invalid MAC prefix '%s'" % mac_prefix)
191
        subnet, gateway, subnet6, gateway6 = validate_network_info(options)
192

    
193
        if not link or not mode:
194
            raise CommandError("Can not create network."
195
                               " No connectivity link or mode")
196
        netinfo = {
197
           "name": name,
198
           "userid": options["owner"],
199
           "subnet": subnet,
200
           "gateway": gateway,
201
           "gateway6": gateway6,
202
           "subnet6": subnet6,
203
           "dhcp": options["dhcp"],
204
           "flavor": flavor,
205
           "public": public,
206
           "mode": mode,
207
           "link": link,
208
           "mac_prefix": mac_prefix,
209
           "tags": tags,
210
           "floating_ip_pool": floating_ip_pool,
211
           "state": "ACTIVE"}
212

    
213
        if dry_run:
214
            self.stdout.write("Creating network:\n")
215
            pprint_table(self.stdout, tuple(netinfo.items()))
216
            return
217

    
218
        network = Network.objects.create(**netinfo)
219
        if userid:
220
            quotas.issue_and_accept_commission(network)
221

    
222
        # Create network in Backend if needed
223
        if floating_ip_pool:
224
            backends = Backend.objects.filter(offline=False)
225
        elif backend_id:
226
            backends = [backend]
227
        else:
228
            backends = []
229

    
230
        for backend in backends:
231
            network.create_backend_network(backend)
232
            self.stdout.write("Trying to connect network to backend '%s'\n" %
233
                              backend)
234
            jobs = create_network(network=network, backend=backend,
235
                                   connect=True)
236
            self.stdout.write("Successfully issued jobs: %s\n" %
237
                              ",".join(jobs))