root / snf-cyclades-app / synnefo / neutron / subnet_views.py @ 2e0916f2
History | View | Annotate | Download (7 kB)
1 | 7eae8fce | Dionysis Grigoropoulos | # Copyright 2013 GRNET S.A. All rights reserved.
|
---|---|---|---|
2 | 7eae8fce | Dionysis Grigoropoulos | #
|
3 | 7eae8fce | Dionysis Grigoropoulos | # Redistribution and use in source and binary forms, with or
|
4 | 7eae8fce | Dionysis Grigoropoulos | # without modification, are permitted provided that the following
|
5 | 7eae8fce | Dionysis Grigoropoulos | # conditions are met:
|
6 | 7eae8fce | Dionysis Grigoropoulos | #
|
7 | 7eae8fce | Dionysis Grigoropoulos | # 1. Redistributions of source code must retain the above
|
8 | 7eae8fce | Dionysis Grigoropoulos | # copyright notice, this list of conditions and the following
|
9 | 7eae8fce | Dionysis Grigoropoulos | # disclaimer.
|
10 | 7eae8fce | Dionysis Grigoropoulos | #
|
11 | 7eae8fce | Dionysis Grigoropoulos | # 2. Redistributions in binary form must reproduce the above
|
12 | 7eae8fce | Dionysis Grigoropoulos | # copyright notice, this list of conditions and the following
|
13 | 7eae8fce | Dionysis Grigoropoulos | # disclaimer in the documentation and/or other materials
|
14 | 7eae8fce | Dionysis Grigoropoulos | # provided with the distribution.
|
15 | 7eae8fce | Dionysis Grigoropoulos | #
|
16 | 7eae8fce | Dionysis Grigoropoulos | # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
17 | 7eae8fce | Dionysis Grigoropoulos | # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 | 7eae8fce | Dionysis Grigoropoulos | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19 | 7eae8fce | Dionysis Grigoropoulos | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
20 | 7eae8fce | Dionysis Grigoropoulos | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 | 7eae8fce | Dionysis Grigoropoulos | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 | 7eae8fce | Dionysis Grigoropoulos | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
23 | 7eae8fce | Dionysis Grigoropoulos | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
24 | 7eae8fce | Dionysis Grigoropoulos | # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 | 7eae8fce | Dionysis Grigoropoulos | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
26 | 7eae8fce | Dionysis Grigoropoulos | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 | 7eae8fce | Dionysis Grigoropoulos | # POSSIBILITY OF SUCH DAMAGE.
|
28 | 7eae8fce | Dionysis Grigoropoulos | #
|
29 | 7eae8fce | Dionysis Grigoropoulos | # The views and conclusions contained in the software and
|
30 | 7eae8fce | Dionysis Grigoropoulos | # documentation are those of the authors and should not be
|
31 | 7eae8fce | Dionysis Grigoropoulos | # interpreted as representing official policies, either expressed
|
32 | 7eae8fce | Dionysis Grigoropoulos | # or implied, of GRNET S.A.
|
33 | 7eae8fce | Dionysis Grigoropoulos | |
34 | 7eae8fce | Dionysis Grigoropoulos | from logging import getLogger |
35 | 7eae8fce | Dionysis Grigoropoulos | from snf_django.lib import api |
36 | 7eae8fce | Dionysis Grigoropoulos | from snf_django.lib.api import faults |
37 | 7eae8fce | Dionysis Grigoropoulos | |
38 | d6b24130 | Marios Kogias | from django.http import HttpResponse |
39 | d6b24130 | Marios Kogias | from django.utils import simplejson as json |
40 | d6b24130 | Marios Kogias | |
41 | d6b24130 | Marios Kogias | from snf_django.lib.api import utils |
42 | 0dae1b9f | Dionysis Grigoropoulos | from models import Subnet, Network |
43 | f261896d | Dionysis Grigoropoulos | from synnefo.logic import networks |
44 | f261896d | Dionysis Grigoropoulos | |
45 | 0dae1b9f | Dionysis Grigoropoulos | from ipaddr import IPv4Network, IPv6Network |
46 | d6b24130 | Marios Kogias | |
47 | 882b662f | Dionysis Grigoropoulos | log = getLogger(__name__) |
48 | d6b24130 | Marios Kogias | |
49 | d6b24130 | Marios Kogias | |
50 | d6b24130 | Marios Kogias | def demux(request): |
51 | d6b24130 | Marios Kogias | if request.method == 'GET': |
52 | 7eae8fce | Dionysis Grigoropoulos | return list_subnets(request)
|
53 | d6b24130 | Marios Kogias | elif request.method == 'POST': |
54 | 882b662f | Dionysis Grigoropoulos | return create_subnet(request)
|
55 | d6b24130 | Marios Kogias | else:
|
56 | d6b24130 | Marios Kogias | return api.api_method_not_allowed(request)
|
57 | d6b24130 | Marios Kogias | |
58 | 7eae8fce | Dionysis Grigoropoulos | |
59 | 0dae1b9f | Dionysis Grigoropoulos | def subnet_demux(request, sub_id): |
60 | d6b24130 | Marios Kogias | if request.method == 'GET': |
61 | 0dae1b9f | Dionysis Grigoropoulos | return get_subnet(request, sub_id)
|
62 | d6b24130 | Marios Kogias | elif request.method == 'DELETE': |
63 | 0dae1b9f | Dionysis Grigoropoulos | return delete_subnet(request, sub_id)
|
64 | d6b24130 | Marios Kogias | elif request.method == 'PUT': |
65 | 0dae1b9f | Dionysis Grigoropoulos | return update_subnet(request, sub_id)
|
66 | d6b24130 | Marios Kogias | else:
|
67 | d6b24130 | Marios Kogias | return api.api_method_not_allowed(request)
|
68 | d6b24130 | Marios Kogias | |
69 | 7eae8fce | Dionysis Grigoropoulos | |
70 | d6b24130 | Marios Kogias | @api.api_method(http_method='GET', user_required=True, logger=log) |
71 | 7eae8fce | Dionysis Grigoropoulos | def list_subnets(request): |
72 | 6de57f9c | Dionysis Grigoropoulos | '''List all subnets of a user'''
|
73 | 7eae8fce | Dionysis Grigoropoulos | log.debug('list_subnets')
|
74 | 7eae8fce | Dionysis Grigoropoulos | |
75 | 7eae8fce | Dionysis Grigoropoulos | user_subnets = Subnet.objects.filter(network__userid=request.user_uniq) |
76 | 0dae1b9f | Dionysis Grigoropoulos | subnets_dict = [subnet_to_dict(sub) |
77 | 0dae1b9f | Dionysis Grigoropoulos | for sub in user_subnets.order_by('id')] |
78 | 7eae8fce | Dionysis Grigoropoulos | data = json.dumps({'subnets': subnets_dict})
|
79 | 7eae8fce | Dionysis Grigoropoulos | |
80 | d6b24130 | Marios Kogias | return HttpResponse(data, status=200) |
81 | d6b24130 | Marios Kogias | |
82 | 7eae8fce | Dionysis Grigoropoulos | |
83 | d6b24130 | Marios Kogias | @api.api_method(http_method='POST', user_required=True, logger=log) |
84 | 7eae8fce | Dionysis Grigoropoulos | def create_subnet(request): |
85 | f261896d | Dionysis Grigoropoulos | '''Create a subnet'''
|
86 | 882b662f | Dionysis Grigoropoulos | |
87 | 0dae1b9f | Dionysis Grigoropoulos | dictionary = utils.get_request_dict(request) |
88 | 0dae1b9f | Dionysis Grigoropoulos | log.info('create subnet %s', dictionary)
|
89 | f261896d | Dionysis Grigoropoulos | user_id = request.user_uniq |
90 | 7eae8fce | Dionysis Grigoropoulos | |
91 | d6b24130 | Marios Kogias | try:
|
92 | 0dae1b9f | Dionysis Grigoropoulos | subnet = dictionary['subnet']
|
93 | 7eae8fce | Dionysis Grigoropoulos | network_id = subnet['network_id']
|
94 | 7eae8fce | Dionysis Grigoropoulos | cidr = subnet['cidr']
|
95 | d6b24130 | Marios Kogias | except KeyError: |
96 | 7eae8fce | Dionysis Grigoropoulos | raise api.faults.BadRequest("Malformed request") |
97 | 7eae8fce | Dionysis Grigoropoulos | |
98 | 0dae1b9f | Dionysis Grigoropoulos | try:
|
99 | 0dae1b9f | Dionysis Grigoropoulos | network = Network.objects.get(id=network_id) |
100 | 0dae1b9f | Dionysis Grigoropoulos | except Network.DoesNotExist:
|
101 | 0dae1b9f | Dionysis Grigoropoulos | raise api.faults.ItemNotFound("No networks found with that id") |
102 | 0dae1b9f | Dionysis Grigoropoulos | |
103 | 0dae1b9f | Dionysis Grigoropoulos | if user_id != network.userid:
|
104 | 0dae1b9f | Dionysis Grigoropoulos | raise api.faults.Unauthorized("Unauthorized operation") |
105 | 0dae1b9f | Dionysis Grigoropoulos | |
106 | f261896d | Dionysis Grigoropoulos | ipversion = subnet.get('ip_version', 4) |
107 | f261896d | Dionysis Grigoropoulos | if ipversion not in [4, 6]: |
108 | 882b662f | Dionysis Grigoropoulos | raise api.faults.BadRequest("Malformed IP version type") |
109 | f261896d | Dionysis Grigoropoulos | |
110 | 7eae8fce | Dionysis Grigoropoulos | dhcp = subnet.get('enable_dhcp', True) |
111 | 882b662f | Dionysis Grigoropoulos | if dhcp not in [True, False]: |
112 | 0dae1b9f | Dionysis Grigoropoulos | raise api.faults.BadRequest("Malformed request, enable_dhcp must be " |
113 | 0dae1b9f | Dionysis Grigoropoulos | "True or False")
|
114 | 7eae8fce | Dionysis Grigoropoulos | name = subnet.get('name', None) |
115 | 882b662f | Dionysis Grigoropoulos | if len(str(name)) > Subnet.SUBNET_NAME_LENGTH: |
116 | 882b662f | Dionysis Grigoropoulos | raise api.faults.BadRequest("Subnet name too long") |
117 | 7eae8fce | Dionysis Grigoropoulos | |
118 | 882b662f | Dionysis Grigoropoulos | # Returns the first available IP in the subnet
|
119 | 0dae1b9f | Dionysis Grigoropoulos | if ipversion == 6: |
120 | 0dae1b9f | Dionysis Grigoropoulos | potential_gateway = IPv6Network(cidr).network + 1
|
121 | 0dae1b9f | Dionysis Grigoropoulos | check_number_of_subnets(network, 6)
|
122 | 0dae1b9f | Dionysis Grigoropoulos | else:
|
123 | 0dae1b9f | Dionysis Grigoropoulos | potential_gateway = IPv4Network(cidr).network + 1
|
124 | 0dae1b9f | Dionysis Grigoropoulos | check_number_of_subnets(network, 4)
|
125 | 7eae8fce | Dionysis Grigoropoulos | |
126 | 0dae1b9f | Dionysis Grigoropoulos | gateway = subnet.get('gateway_ip', potential_gateway)
|
127 | 0dae1b9f | Dionysis Grigoropoulos | networks.validate_network_params(cidr, gateway) |
128 | f261896d | Dionysis Grigoropoulos | |
129 | 882b662f | Dionysis Grigoropoulos | # FIX ME
|
130 | f261896d | Dionysis Grigoropoulos | try:
|
131 | 0dae1b9f | Dionysis Grigoropoulos | sub = Subnet.objects.create(name=name, network=network, cidr=cidr, |
132 | 0dae1b9f | Dionysis Grigoropoulos | ipversion=ipversion, gateway=gateway, |
133 | 0dae1b9f | Dionysis Grigoropoulos | dhcp=dhcp) |
134 | f261896d | Dionysis Grigoropoulos | except:
|
135 | 0dae1b9f | Dionysis Grigoropoulos | return "Error" |
136 | 7eae8fce | Dionysis Grigoropoulos | |
137 | 0dae1b9f | Dionysis Grigoropoulos | return HttpResponse(sub, status=200) |
138 | d6b24130 | Marios Kogias | |
139 | d6b24130 | Marios Kogias | |
140 | d6b24130 | Marios Kogias | @api.api_method(http_method='GET', user_required=True, logger=log) |
141 | 0dae1b9f | Dionysis Grigoropoulos | def get_subnet(request, sub_id): |
142 | 6de57f9c | Dionysis Grigoropoulos | '''Show info of a specific subnet'''
|
143 | 0dae1b9f | Dionysis Grigoropoulos | log.debug('get_subnet %s', sub_id)
|
144 | 0dae1b9f | Dionysis Grigoropoulos | user_id = request.user_uniq |
145 | 0dae1b9f | Dionysis Grigoropoulos | |
146 | d6b24130 | Marios Kogias | try:
|
147 | 0dae1b9f | Dionysis Grigoropoulos | subnet = Subnet.objects.get(id=sub_id) |
148 | 7eae8fce | Dionysis Grigoropoulos | except Subnet.DoesNotExist:
|
149 | 7eae8fce | Dionysis Grigoropoulos | raise api.faults.ItemNotFound("Subnet not found") |
150 | 7eae8fce | Dionysis Grigoropoulos | |
151 | 0dae1b9f | Dionysis Grigoropoulos | if subnet.network.userid != user_id:
|
152 | 0dae1b9f | Dionysis Grigoropoulos | raise api.failts.Unauthorized("You're not allowed to view this subnet") |
153 | 0dae1b9f | Dionysis Grigoropoulos | |
154 | 0dae1b9f | Dionysis Grigoropoulos | subnet_dict = subnet_to_dict(subnet) |
155 | 0dae1b9f | Dionysis Grigoropoulos | data = json.dumps({'subnet': subnet_dict})
|
156 | 7eae8fce | Dionysis Grigoropoulos | return HttpResponse(data, status=200) |
157 | d6b24130 | Marios Kogias | |
158 | d6b24130 | Marios Kogias | |
159 | d6b24130 | Marios Kogias | @api.api_method(http_method='DELETE', user_required=True, logger=log) |
160 | 0dae1b9f | Dionysis Grigoropoulos | def delete_subnet(request, sub_id): |
161 | 0dae1b9f | Dionysis Grigoropoulos | '''Delete a subnet -- Operation not allowed'''
|
162 | 882b662f | Dionysis Grigoropoulos | raise api.faults.BadRequest("Deletion of a subnet is not supported") |
163 | d6b24130 | Marios Kogias | |
164 | d6b24130 | Marios Kogias | |
165 | 2e0916f2 | Marios Kogias | |
166 | 0dae1b9f | Dionysis Grigoropoulos | @api.api_method(http_method='PUT', user_required=True, logger=log) |
167 | 0dae1b9f | Dionysis Grigoropoulos | def update_subnet(request, sub_id): |
168 | 0dae1b9f | Dionysis Grigoropoulos | '''Update info of a subnet'''
|
169 | 0dae1b9f | Dionysis Grigoropoulos | |
170 | 0dae1b9f | Dionysis Grigoropoulos | |
171 | 2e0916f2 | Marios Kogias | # util functions
|
172 | 2e0916f2 | Marios Kogias | |
173 | 2e0916f2 | Marios Kogias | |
174 | 7eae8fce | Dionysis Grigoropoulos | def subnet_to_dict(subnet): |
175 | 7eae8fce | Dionysis Grigoropoulos | '''Returns a dictionary containing the info of a subnet'''
|
176 | f261896d | Dionysis Grigoropoulos | # FIX ME, allocation pools
|
177 | 0dae1b9f | Dionysis Grigoropoulos | dictionary = dict({'id': subnet.id, 'network_id': subnet.network.id, |
178 | 0dae1b9f | Dionysis Grigoropoulos | 'name': subnet.name, 'tenant_id': subnet.network.userid, |
179 | 0dae1b9f | Dionysis Grigoropoulos | 'gateway_ip': subnet.gateway,
|
180 | 0dae1b9f | Dionysis Grigoropoulos | 'ip_version': subnet.ipversion, 'cidr': subnet.cidr, |
181 | 0dae1b9f | Dionysis Grigoropoulos | 'enable_dhcp': subnet.dhcp, 'dns_nameservers': [], |
182 | 0dae1b9f | Dionysis Grigoropoulos | 'host_routes': [], 'allocation_pools': []}) |
183 | 0dae1b9f | Dionysis Grigoropoulos | return dictionary
|
184 | 0dae1b9f | Dionysis Grigoropoulos | |
185 | 0dae1b9f | Dionysis Grigoropoulos | |
186 | 0dae1b9f | Dionysis Grigoropoulos | def check_number_of_subnets(network, version): |
187 | 0dae1b9f | Dionysis Grigoropoulos | '''Checks if a user can add a subnet in a network'''
|
188 | 0dae1b9f | Dionysis Grigoropoulos | if network.subnet_set.filter(ipversion=version):
|
189 | 0dae1b9f | Dionysis Grigoropoulos | raise api.faults.BadRequest("Only one subnet of IPv4/IPv6 per " |
190 | 0dae1b9f | Dionysis Grigoropoulos | "network is allowed")
|
191 | 2e0916f2 | Marios Kogias | |
192 | 2e0916f2 | Marios Kogias | def get_subnet_fromdb(subnet_id, user_id, for_update=False): |
193 | 2e0916f2 | Marios Kogias | """
|
194 | 2e0916f2 | Marios Kogias | Return a Subnet instance or raise ItemNotFound.
|
195 | 2e0916f2 | Marios Kogias | This is the same as util.get_network
|
196 | 2e0916f2 | Marios Kogias | """
|
197 | 2e0916f2 | Marios Kogias | try:
|
198 | 2e0916f2 | Marios Kogias | subnet_id = int(subnet_id)
|
199 | 2e0916f2 | Marios Kogias | objects = Subnet.objects |
200 | 2e0916f2 | Marios Kogias | if for_update:
|
201 | 2e0916f2 | Marios Kogias | objects = objects.select_for_update() |
202 | 2e0916f2 | Marios Kogias | return objects.get(userid=user_id, id=subnet_id)
|
203 | 2e0916f2 | Marios Kogias | except (ValueError, Subnet.DoesNotExist): |
204 | 2e0916f2 | Marios Kogias | raise api.faults.ItemNotFound('Network not found.') |