Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (6.7 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

    
38
from synnefo.db.models import Network, Backend
39
from synnefo.api.util import net_resources, validate_network_size
40
from synnefo.logic.backend import create_network
41
from synnefo import settings
42

    
43
import ipaddr
44

    
45
NETWORK_TYPES = ['PUBLIC_ROUTED', 'PRIVATE_MAC_FILTERED',
46
                 'PRIVATE_PHYSICAL_VLAN', 'CUSTOM_ROUTED',
47
                 'CUSTOM_BRIDGED']
48

    
49

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

    
54
    help = "Create a new network"
55

    
56
    option_list = BaseCommand.option_list + (
57
        make_option('--name',
58
            dest='name',
59
            help="Name of network"),
60
        make_option('--owner',
61
            dest='owner',
62
            help="The owner of the network"),
63
        make_option('--subnet',
64
            dest='subnet',
65
            default=None,
66
            # required=True,
67
            help='Subnet of the network'),
68
        make_option('--gateway',
69
            dest='gateway',
70
            default=None,
71
            help='Gateway of the network'),
72
        make_option('--dhcp',
73
            dest='dhcp',
74
            action='store_true',
75
            default=False,
76
            help='Automatically assign IPs'),
77
        make_option('--public',
78
            dest='public',
79
            action='store_true',
80
            default=False,
81
            help='Network is public'),
82
        make_option('--type',
83
            dest='type',
84
            default='PRIVATE_MAC_FILTERED',
85
            choices=NETWORK_TYPES,
86
            help='Type of network. Choices: ' + ', '.join(NETWORK_TYPES)),
87
        make_option('--subnet6',
88
            dest='subnet6',
89
            default=None,
90
            help='IPv6 subnet of the network'),
91
        make_option('--gateway6',
92
            dest='gateway6',
93
            default=None,
94
            help='IPv6 gateway of the network'),
95
        make_option('--backend-id',
96
            dest='backend_id',
97
            default=None,
98
            help='ID of the backend that the network will be created. Only for'
99
                 ' public networks')
100
        )
101

    
102
    def handle(self, *args, **options):
103
        if args:
104
            raise CommandError("Command doesn't accept any arguments")
105

    
106
        name = options['name']
107
        subnet = options['subnet']
108
        net_type = options['type']
109
        backend_id = options['backend_id']
110
        public = options['public']
111

    
112
        if not name:
113
            raise CommandError("Name is required")
114
        if not subnet:
115
            raise CommandError("Subnet is required")
116
        if public and not backend_id:
117
            raise CommandError("backend-id is required")
118
        if public and not net_type == 'PUBLIC_ROUTED':
119
            raise CommandError("Invalid type for public network")
120
        if backend_id and not public:
121
            raise CommandError("Private networks must be created to"
122
                               " all backends")
123

    
124
        if backend_id:
125
            try:
126
                backend_id = int(backend_id)
127
                backend = Backend.objects.get(id=backend_id)
128
            except ValueError:
129
                raise CommandError("Invalid backend ID")
130
            except Backend.DoesNotExist:
131
                raise CommandError("Backend not found in DB")
132

    
133
        link, mac_prefix = net_resources(net_type)
134

    
135
        subnet, gateway, subnet6, gateway6 = validate_network_info(options)
136

    
137
        if not link:
138
            raise CommandError("Can not create network. No connectivity link")
139

    
140
        network = Network.objects.create(
141
                name=name,
142
                userid=options['owner'],
143
                subnet=subnet,
144
                gateway=gateway,
145
                dhcp=options['dhcp'],
146
                type=net_type,
147
                public=public,
148
                link=link,
149
                mac_prefix=mac_prefix,
150
                gateway6=gateway6,
151
                subnet6=subnet6,
152
                state='PENDING')
153

    
154
        if public:
155
            # Create BackendNetwork only to the specified Backend
156
            network.create_backend_network(backend)
157
            create_network(network, backends=[backend])
158
        else:
159
            # Create BackendNetwork entries for all Backends
160
            network.create_backend_network()
161
            create_network(network)
162

    
163

    
164
def validate_network_info(options):
165
    subnet = options['subnet']
166
    gateway = options['gateway']
167
    subnet6 = options['subnet6']
168
    gateway6 = options['gateway6']
169

    
170
    try:
171
        net = ipaddr.IPv4Network(subnet)
172
        prefix = net.prefixlen
173
        if not validate_network_size(prefix):
174
            raise CommandError("Unsupport network mask %d."
175
                               " Must be in range (%s,29] "
176
                               % (prefix, settings.MAX_CIDR_BLOCK))
177
    except ValueError:
178
        raise CommandError('Malformed subnet')
179
    try:
180
        gateway and ipaddr.IPv4Address(gateway) or None
181
    except ValueError:
182
        raise CommandError('Malformed gateway')
183

    
184
    try:
185
        subnet6 and ipaddr.IPv6Network(subnet6) or None
186
    except ValueError:
187
        raise CommandError('Malformed subnet6')
188

    
189
    try:
190
        gateway6 and ipaddr.IPv6Address(gateway6) or None
191
    except ValueError:
192
        raise CommandError('Malformed gateway6')
193

    
194
    return subnet, gateway, subnet6, gateway6