Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / neutron / subnet_views.py @ 5cf968ab

History | View | Annotate | Download (7 kB)

1
# Copyright 2013 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 logging import getLogger
35
from snf_django.lib import api
36
from snf_django.lib.api import faults
37

    
38
from django.http import HttpResponse
39
from django.utils import simplejson as json
40

    
41
from snf_django.lib.api import utils
42
from models import Subnet, Network
43
from synnefo.logic import networks
44

    
45
from ipaddr import IPv4Network, IPv6Network
46

    
47
log = getLogger(__name__)
48

    
49

    
50
def demux(request):
51
    if request.method == 'GET':
52
        return list_subnets(request)
53
    elif request.method == 'POST':
54
        return create_subnet(request)
55
    else:
56
        return api.api_method_not_allowed(request)
57

    
58

    
59
def subnet_demux(request, sub_id):
60
    if request.method == 'GET':
61
        return get_subnet(request, sub_id)
62
    elif request.method == 'DELETE':
63
        return delete_subnet(request, sub_id)
64
    elif request.method == 'PUT':
65
        return update_subnet(request, sub_id)
66
    else:
67
        return api.api_method_not_allowed(request)
68

    
69

    
70
@api.api_method(http_method='GET', user_required=True, logger=log)
71
def list_subnets(request):
72
    '''List all subnets of a user'''
73
    log.debug('list_subnets')
74

    
75
    user_subnets = Subnet.objects.filter(network__userid=request.user_uniq)
76
    subnets_dict = [subnet_to_dict(sub)
77
                    for sub in user_subnets.order_by('id')]
78
    data = json.dumps({'subnets': subnets_dict})
79

    
80
    return HttpResponse(data, status=200)
81

    
82

    
83
@api.api_method(http_method='POST', user_required=True, logger=log)
84
def create_subnet(request):
85
    '''Create a subnet'''
86

    
87
    dictionary = utils.get_request_dict(request)
88
    log.info('create subnet %s', dictionary)
89
    user_id = request.user_uniq
90

    
91
    try:
92
        subnet = dictionary['subnet']
93
        network_id = subnet['network_id']
94
        cidr = subnet['cidr']
95
    except KeyError:
96
        raise api.faults.BadRequest("Malformed request")
97

    
98
    try:
99
        network = Network.objects.get(id=network_id)
100
    except Network.DoesNotExist:
101
        raise api.faults.ItemNotFound("No networks found with that id")
102

    
103
    if user_id != network.userid:
104
        raise api.faults.Unauthorized("Unauthorized operation")
105

    
106
    ipversion = subnet.get('ip_version', 4)
107
    if ipversion not in [4, 6]:
108
        raise api.faults.BadRequest("Malformed IP version type")
109

    
110
    dhcp = subnet.get('enable_dhcp', True)
111
    if dhcp not in [True, False]:
112
        raise api.faults.BadRequest("Malformed request, enable_dhcp must be "
113
                                    "True or False")
114
    name = subnet.get('name', None)
115
    if len(str(name)) > Subnet.SUBNET_NAME_LENGTH:
116
        raise api.faults.BadRequest("Subnet name too long")
117

    
118
    # Returns the first available IP in the subnet
119
    if ipversion == 6:
120
        potential_gateway = IPv6Network(cidr).network + 1
121
        check_number_of_subnets(network, 6)
122
    else:
123
        potential_gateway = IPv4Network(cidr).network + 1
124
        check_number_of_subnets(network, 4)
125

    
126
    gateway = subnet.get('gateway_ip', potential_gateway)
127
    networks.validate_network_params(cidr, gateway)
128

    
129
    # FIX ME
130
    try:
131
        sub = Subnet.objects.create(name=name, network=network, cidr=cidr,
132
                                    ipversion=ipversion, gateway=gateway,
133
                                    dhcp=dhcp)
134
    except:
135
        return "Error"
136

    
137
    return HttpResponse(sub, status=200)
138

    
139

    
140
@api.api_method(http_method='GET', user_required=True, logger=log)
141
def get_subnet(request, sub_id):
142
    '''Show info of a specific subnet'''
143
    log.debug('get_subnet %s', sub_id)
144
    user_id = request.user_uniq
145

    
146
    try:
147
        subnet = Subnet.objects.get(id=sub_id)
148
    except Subnet.DoesNotExist:
149
        raise api.faults.ItemNotFound("Subnet not found")
150

    
151
    if subnet.network.userid != user_id:
152
        raise api.failts.Unauthorized("You're not allowed to view this subnet")
153

    
154
    subnet_dict = subnet_to_dict(subnet)
155
    data = json.dumps({'subnet': subnet_dict})
156
    return HttpResponse(data, status=200)
157

    
158

    
159
@api.api_method(http_method='DELETE', user_required=True, logger=log)
160
def delete_subnet(request, sub_id):
161
    '''Delete a subnet -- Operation not allowed'''
162
    raise api.faults.BadRequest("Deletion of a subnet is not supported")
163

    
164

    
165
@api.api_method(http_method='PUT', user_required=True, logger=log)
166
def update_subnet(request, sub_id):
167
    '''Update info of a subnet'''
168

    
169

    
170
# util functions
171

    
172

    
173
def subnet_to_dict(subnet):
174
    '''Returns a dictionary containing the info of a subnet'''
175
    # FIX ME, allocation pools
176
    dictionary = dict({'id': subnet.id, 'network_id': subnet.network.id,
177
                       'name': subnet.name, 'tenant_id': subnet.network.userid,
178
                       'gateway_ip': subnet.gateway,
179
                       'ip_version': subnet.ipversion, 'cidr': subnet.cidr,
180
                       'enable_dhcp': subnet.dhcp, 'dns_nameservers': [],
181
                       'host_routes': [], 'allocation_pools': []})
182
    return dictionary
183

    
184

    
185
def check_number_of_subnets(network, version):
186
    '''Checks if a user can add a subnet in a network'''
187
    if network.subnet_set.filter(ipversion=version):
188
        raise api.faults.BadRequest("Only one subnet of IPv4/IPv6 per "
189
                                    "network is allowed")
190

    
191

    
192
def get_subnet_fromdb(subnet_id, user_id, for_update=False):
193
    """
194
    Return a Subnet instance or raise ItemNotFound.
195
    This is the same as util.get_network
196
    """
197
    try:
198
        subnet_id = int(subnet_id)
199
        objects = Subnet.objects
200
        if for_update:
201
            objects = objects.select_for_update()
202
        return objects.get(id=subnet_id, network__userid=user_id)
203
    except (ValueError, Subnet.DoesNotExist):
204
        raise api.faults.ItemNotFound('Subnet not found.')