Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / subnets.py @ 9f6760ee

History | View | Annotate | Download (14.1 kB)

1 16f7d0d9 Dionysis Grigoropoulos
# Copyright 2013 GRNET S.A. All rights reserved.
2 16f7d0d9 Dionysis Grigoropoulos
#
3 16f7d0d9 Dionysis Grigoropoulos
# Redistribution and use in source and binary forms, with or
4 16f7d0d9 Dionysis Grigoropoulos
# without modification, are permitted provided that the following
5 16f7d0d9 Dionysis Grigoropoulos
# conditions are met:
6 16f7d0d9 Dionysis Grigoropoulos
#
7 16f7d0d9 Dionysis Grigoropoulos
#   1. Redistributions of source code must retain the above
8 16f7d0d9 Dionysis Grigoropoulos
#      copyright notice, this list of conditions and the following
9 16f7d0d9 Dionysis Grigoropoulos
#      disclaimer.
10 16f7d0d9 Dionysis Grigoropoulos
#
11 16f7d0d9 Dionysis Grigoropoulos
#   2. Redistributions in binary form must reproduce the above
12 16f7d0d9 Dionysis Grigoropoulos
#      copyright notice, this list of conditions and the following
13 16f7d0d9 Dionysis Grigoropoulos
#      disclaimer in the documentation and/or other materials
14 16f7d0d9 Dionysis Grigoropoulos
#      provided with the distribution.
15 16f7d0d9 Dionysis Grigoropoulos
#
16 16f7d0d9 Dionysis Grigoropoulos
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 16f7d0d9 Dionysis Grigoropoulos
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 16f7d0d9 Dionysis Grigoropoulos
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 16f7d0d9 Dionysis Grigoropoulos
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 16f7d0d9 Dionysis Grigoropoulos
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 16f7d0d9 Dionysis Grigoropoulos
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 16f7d0d9 Dionysis Grigoropoulos
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 16f7d0d9 Dionysis Grigoropoulos
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 16f7d0d9 Dionysis Grigoropoulos
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 16f7d0d9 Dionysis Grigoropoulos
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 16f7d0d9 Dionysis Grigoropoulos
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 16f7d0d9 Dionysis Grigoropoulos
# POSSIBILITY OF SUCH DAMAGE.
28 16f7d0d9 Dionysis Grigoropoulos
#
29 16f7d0d9 Dionysis Grigoropoulos
# The views and conclusions contained in the software and
30 16f7d0d9 Dionysis Grigoropoulos
# documentation are those of the authors and should not be
31 16f7d0d9 Dionysis Grigoropoulos
# interpreted as representing official policies, either expressed
32 16f7d0d9 Dionysis Grigoropoulos
# or implied, of GRNET S.A.
33 16f7d0d9 Dionysis Grigoropoulos
34 16f7d0d9 Dionysis Grigoropoulos
from logging import getLogger
35 16f7d0d9 Dionysis Grigoropoulos
from snf_django.lib import api
36 16f7d0d9 Dionysis Grigoropoulos
from snf_django.lib.api import faults
37 16f7d0d9 Dionysis Grigoropoulos
38 6a959c73 Dionysis Grigoropoulos
from django.conf.urls import patterns
39 16f7d0d9 Dionysis Grigoropoulos
from django.http import HttpResponse
40 16f7d0d9 Dionysis Grigoropoulos
from django.utils import simplejson as json
41 16f7d0d9 Dionysis Grigoropoulos
42 16f7d0d9 Dionysis Grigoropoulos
from snf_django.lib.api import utils
43 4445f97a Dionysis Grigoropoulos
from synnefo.db.models import Subnet, Network, IPPoolTable
44 16f7d0d9 Dionysis Grigoropoulos
from synnefo.logic import networks
45 16f7d0d9 Dionysis Grigoropoulos
46 a996065e Dionysis Grigoropoulos
from ipaddr import IPv4Network, IPv6Network, IPv4Address, IPAddress, IPNetwork
47 16f7d0d9 Dionysis Grigoropoulos
48 16f7d0d9 Dionysis Grigoropoulos
log = getLogger(__name__)
49 16f7d0d9 Dionysis Grigoropoulos
50 16f7d0d9 Dionysis Grigoropoulos
51 6a959c73 Dionysis Grigoropoulos
urlpatterns = patterns(
52 6a959c73 Dionysis Grigoropoulos
    'synnefo.api.subnets',
53 6a959c73 Dionysis Grigoropoulos
    (r'^(?:/|.json|.xml)?$', 'demux'),
54 6a959c73 Dionysis Grigoropoulos
    (r'^/([-\w]+)(?:/|.json|.xml)?$', 'subnet_demux'))
55 6a959c73 Dionysis Grigoropoulos
56 6a959c73 Dionysis Grigoropoulos
57 16f7d0d9 Dionysis Grigoropoulos
def demux(request):
58 16f7d0d9 Dionysis Grigoropoulos
    if request.method == 'GET':
59 16f7d0d9 Dionysis Grigoropoulos
        return list_subnets(request)
60 16f7d0d9 Dionysis Grigoropoulos
    elif request.method == 'POST':
61 16f7d0d9 Dionysis Grigoropoulos
        return create_subnet(request)
62 16f7d0d9 Dionysis Grigoropoulos
    else:
63 16f7d0d9 Dionysis Grigoropoulos
        return api.api_method_not_allowed(request)
64 16f7d0d9 Dionysis Grigoropoulos
65 16f7d0d9 Dionysis Grigoropoulos
66 16f7d0d9 Dionysis Grigoropoulos
def subnet_demux(request, sub_id):
67 16f7d0d9 Dionysis Grigoropoulos
    if request.method == 'GET':
68 16f7d0d9 Dionysis Grigoropoulos
        return get_subnet(request, sub_id)
69 16f7d0d9 Dionysis Grigoropoulos
    elif request.method == 'DELETE':
70 16f7d0d9 Dionysis Grigoropoulos
        return delete_subnet(request, sub_id)
71 16f7d0d9 Dionysis Grigoropoulos
    elif request.method == 'PUT':
72 16f7d0d9 Dionysis Grigoropoulos
        return update_subnet(request, sub_id)
73 16f7d0d9 Dionysis Grigoropoulos
    else:
74 16f7d0d9 Dionysis Grigoropoulos
        return api.api_method_not_allowed(request)
75 16f7d0d9 Dionysis Grigoropoulos
76 16f7d0d9 Dionysis Grigoropoulos
77 16f7d0d9 Dionysis Grigoropoulos
@api.api_method(http_method='GET', user_required=True, logger=log)
78 16f7d0d9 Dionysis Grigoropoulos
def list_subnets(request):
79 16f7d0d9 Dionysis Grigoropoulos
    """List all subnets of a user"""
80 16f7d0d9 Dionysis Grigoropoulos
    log.debug('list_subnets')
81 16f7d0d9 Dionysis Grigoropoulos
82 16f7d0d9 Dionysis Grigoropoulos
    user_subnets = Subnet.objects.filter(network__userid=request.user_uniq)
83 16f7d0d9 Dionysis Grigoropoulos
    subnets_dict = [subnet_to_dict(sub)
84 16f7d0d9 Dionysis Grigoropoulos
                    for sub in user_subnets.order_by('id')]
85 16f7d0d9 Dionysis Grigoropoulos
    data = json.dumps({'subnets': subnets_dict})
86 16f7d0d9 Dionysis Grigoropoulos
87 16f7d0d9 Dionysis Grigoropoulos
    return HttpResponse(data, status=200)
88 16f7d0d9 Dionysis Grigoropoulos
89 16f7d0d9 Dionysis Grigoropoulos
90 16f7d0d9 Dionysis Grigoropoulos
@api.api_method(http_method='POST', user_required=True, logger=log)
91 16f7d0d9 Dionysis Grigoropoulos
def create_subnet(request):
92 a996065e Dionysis Grigoropoulos
    """
93 a996065e Dionysis Grigoropoulos
    Create a subnet
94 a996065e Dionysis Grigoropoulos
    network_id and the desired cidr are mandatory, everything else is optional
95 a996065e Dionysis Grigoropoulos
    """
96 16f7d0d9 Dionysis Grigoropoulos
97 16f7d0d9 Dionysis Grigoropoulos
    dictionary = utils.get_request_dict(request)
98 16f7d0d9 Dionysis Grigoropoulos
    log.info('create subnet %s', dictionary)
99 16f7d0d9 Dionysis Grigoropoulos
    user_id = request.user_uniq
100 16f7d0d9 Dionysis Grigoropoulos
101 16f7d0d9 Dionysis Grigoropoulos
    try:
102 16f7d0d9 Dionysis Grigoropoulos
        subnet = dictionary['subnet']
103 16f7d0d9 Dionysis Grigoropoulos
        network_id = subnet['network_id']
104 16f7d0d9 Dionysis Grigoropoulos
        cidr = subnet['cidr']
105 16f7d0d9 Dionysis Grigoropoulos
    except KeyError:
106 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Malformed request")
107 16f7d0d9 Dionysis Grigoropoulos
108 16f7d0d9 Dionysis Grigoropoulos
    try:
109 16f7d0d9 Dionysis Grigoropoulos
        network = Network.objects.get(id=network_id)
110 16f7d0d9 Dionysis Grigoropoulos
    except Network.DoesNotExist:
111 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.ItemNotFound("No networks found with that id")
112 16f7d0d9 Dionysis Grigoropoulos
113 16f7d0d9 Dionysis Grigoropoulos
    if user_id != network.userid:
114 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.Unauthorized("Unauthorized operation")
115 16f7d0d9 Dionysis Grigoropoulos
116 16f7d0d9 Dionysis Grigoropoulos
    ipversion = subnet.get('ip_version', 4)
117 16f7d0d9 Dionysis Grigoropoulos
    if ipversion not in [4, 6]:
118 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Malformed IP version type")
119 16f7d0d9 Dionysis Grigoropoulos
120 16f7d0d9 Dionysis Grigoropoulos
    # Returns the first available IP in the subnet
121 16f7d0d9 Dionysis Grigoropoulos
    if ipversion == 6:
122 16f7d0d9 Dionysis Grigoropoulos
        potential_gateway = str(IPv6Network(cidr).network + 1)
123 16f7d0d9 Dionysis Grigoropoulos
        check_number_of_subnets(network, 6)
124 16f7d0d9 Dionysis Grigoropoulos
    else:
125 16f7d0d9 Dionysis Grigoropoulos
        potential_gateway = str(IPv4Network(cidr).network + 1)
126 16f7d0d9 Dionysis Grigoropoulos
        check_number_of_subnets(network, 4)
127 16f7d0d9 Dionysis Grigoropoulos
128 16f7d0d9 Dionysis Grigoropoulos
    gateway = subnet.get('gateway_ip', potential_gateway)
129 16f7d0d9 Dionysis Grigoropoulos
130 16f7d0d9 Dionysis Grigoropoulos
    if ipversion == 6:
131 16f7d0d9 Dionysis Grigoropoulos
        networks.validate_network_params(None, None, cidr, gateway)
132 097009bf Dionysis Grigoropoulos
        slac = subnet.get('enable_slac', None)
133 97ca522f Dionysis Grigoropoulos
        if slac is not None:
134 097009bf Dionysis Grigoropoulos
            dhcp = check_boolean_value(slac, "enable_slac")
135 97ca522f Dionysis Grigoropoulos
        else:
136 911a1bc1 Dionysis Grigoropoulos
            dhcp = check_boolean_value(subnet.get('enable_dhcp', True), "dhcp")
137 16f7d0d9 Dionysis Grigoropoulos
    else:
138 16f7d0d9 Dionysis Grigoropoulos
        networks.validate_network_params(cidr, gateway)
139 911a1bc1 Dionysis Grigoropoulos
        dhcp = check_boolean_value(subnet.get('enable_dhcp', True), "dhcp")
140 16f7d0d9 Dionysis Grigoropoulos
141 a996065e Dionysis Grigoropoulos
    name = check_name_length(subnet.get('name', None))
142 a996065e Dionysis Grigoropoulos
143 a996065e Dionysis Grigoropoulos
    dns = subnet.get('dns_nameservers', None)
144 a996065e Dionysis Grigoropoulos
    hosts = subnet.get('host_routes', None)
145 a996065e Dionysis Grigoropoulos
146 a996065e Dionysis Grigoropoulos
    gateway_ip = IPAddress(gateway)
147 a996065e Dionysis Grigoropoulos
    cidr_ip = IPNetwork(cidr)
148 a996065e Dionysis Grigoropoulos
149 16f7d0d9 Dionysis Grigoropoulos
    allocation_pools = subnet.get('allocation_pools', None)
150 16f7d0d9 Dionysis Grigoropoulos
151 4445f97a Dionysis Grigoropoulos
    sub = Subnet.objects.create(name=name, network=network, cidr=cidr,
152 4445f97a Dionysis Grigoropoulos
                                ipversion=ipversion, gateway=gateway,
153 4445f97a Dionysis Grigoropoulos
                                dhcp=dhcp, host_routes=hosts,
154 4445f97a Dionysis Grigoropoulos
                                dns_nameservers=dns)
155 4445f97a Dionysis Grigoropoulos
156 4445f97a Dionysis Grigoropoulos
    pool_list = list()
157 4445f97a Dionysis Grigoropoulos
    if allocation_pools is not None:
158 4445f97a Dionysis Grigoropoulos
        # If the user specified IP allocation pools, validate them and use them
159 16f7d0d9 Dionysis Grigoropoulos
        if ipversion == 6:
160 a996065e Dionysis Grigoropoulos
            raise api.faults.Conflict("Can't allocate an IP Pool in IPv6")
161 a996065e Dionysis Grigoropoulos
        pools = parse_ip_pools(allocation_pools)
162 4445f97a Dionysis Grigoropoulos
        pool_list = string_to_ipaddr(pools)
163 4445f97a Dionysis Grigoropoulos
        validate_subpools(pool_list, cidr_ip, gateway_ip)
164 4445f97a Dionysis Grigoropoulos
    if allocation_pools is None and ipversion == 4:
165 4445f97a Dionysis Grigoropoulos
        # Check if the gateway is the first IP of the subnet, in this case
166 4445f97a Dionysis Grigoropoulos
        # create a single ip pool
167 4445f97a Dionysis Grigoropoulos
        if int(gateway_ip) - int(cidr_ip) == 1:
168 4445f97a Dionysis Grigoropoulos
            pool_list = [[gateway_ip + 1, cidr_ip.broadcast - 1]]
169 4445f97a Dionysis Grigoropoulos
        else:
170 4445f97a Dionysis Grigoropoulos
            # If the gateway isn't the first available ip, create two different
171 4445f97a Dionysis Grigoropoulos
            # ip pools adjacent to said ip
172 4445f97a Dionysis Grigoropoulos
            pool_list.append([cidr_ip.network + 1, gateway_ip - 1])
173 4445f97a Dionysis Grigoropoulos
            pool_list.append([gateway_ip + 1, cidr_ip.broadcast - 1])
174 16f7d0d9 Dionysis Grigoropoulos
175 4445f97a Dionysis Grigoropoulos
    if pool_list:
176 4445f97a Dionysis Grigoropoulos
        create_ip_pools(pool_list, cidr_ip, sub)
177 16f7d0d9 Dionysis Grigoropoulos
178 16f7d0d9 Dionysis Grigoropoulos
    subnet_dict = subnet_to_dict(sub)
179 16f7d0d9 Dionysis Grigoropoulos
    data = json.dumps({'subnet': subnet_dict})
180 16f7d0d9 Dionysis Grigoropoulos
    return HttpResponse(data, status=200)
181 16f7d0d9 Dionysis Grigoropoulos
182 16f7d0d9 Dionysis Grigoropoulos
183 16f7d0d9 Dionysis Grigoropoulos
@api.api_method(http_method='GET', user_required=True, logger=log)
184 16f7d0d9 Dionysis Grigoropoulos
def get_subnet(request, sub_id):
185 16f7d0d9 Dionysis Grigoropoulos
    """Show info of a specific subnet"""
186 16f7d0d9 Dionysis Grigoropoulos
    log.debug('get_subnet %s', sub_id)
187 16f7d0d9 Dionysis Grigoropoulos
    user_id = request.user_uniq
188 16f7d0d9 Dionysis Grigoropoulos
189 16f7d0d9 Dionysis Grigoropoulos
    try:
190 16f7d0d9 Dionysis Grigoropoulos
        subnet = Subnet.objects.get(id=sub_id)
191 16f7d0d9 Dionysis Grigoropoulos
    except Subnet.DoesNotExist:
192 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.ItemNotFound("Subnet not found")
193 16f7d0d9 Dionysis Grigoropoulos
194 16f7d0d9 Dionysis Grigoropoulos
    if subnet.network.userid != user_id:
195 16f7d0d9 Dionysis Grigoropoulos
        raise api.failts.Unauthorized("You're not allowed to view this subnet")
196 16f7d0d9 Dionysis Grigoropoulos
197 16f7d0d9 Dionysis Grigoropoulos
    subnet_dict = subnet_to_dict(subnet)
198 16f7d0d9 Dionysis Grigoropoulos
    data = json.dumps({'subnet': subnet_dict})
199 16f7d0d9 Dionysis Grigoropoulos
    return HttpResponse(data, status=200)
200 16f7d0d9 Dionysis Grigoropoulos
201 16f7d0d9 Dionysis Grigoropoulos
202 16f7d0d9 Dionysis Grigoropoulos
@api.api_method(http_method='DELETE', user_required=True, logger=log)
203 16f7d0d9 Dionysis Grigoropoulos
def delete_subnet(request, sub_id):
204 16f7d0d9 Dionysis Grigoropoulos
    """
205 16f7d0d9 Dionysis Grigoropoulos
    Delete a subnet, raises BadRequest
206 16f7d0d9 Dionysis Grigoropoulos
    A subnet is deleted ONLY when the network that it belongs to is deleted
207 16f7d0d9 Dionysis Grigoropoulos
    """
208 16f7d0d9 Dionysis Grigoropoulos
    raise api.faults.BadRequest("Deletion of a subnet is not supported")
209 16f7d0d9 Dionysis Grigoropoulos
210 16f7d0d9 Dionysis Grigoropoulos
211 16f7d0d9 Dionysis Grigoropoulos
@api.api_method(http_method='PUT', user_required=True, logger=log)
212 16f7d0d9 Dionysis Grigoropoulos
def update_subnet(request, sub_id):
213 16f7d0d9 Dionysis Grigoropoulos
    """
214 16f7d0d9 Dionysis Grigoropoulos
    Update the fields of a subnet
215 16f7d0d9 Dionysis Grigoropoulos
    Only the name can be updated, everything else returns BadRequest
216 16f7d0d9 Dionysis Grigoropoulos
    """
217 16f7d0d9 Dionysis Grigoropoulos
218 16f7d0d9 Dionysis Grigoropoulos
    dictionary = utils.get_request_dict(request)
219 16f7d0d9 Dionysis Grigoropoulos
    log.info('Update subnet %s', dictionary)
220 16f7d0d9 Dionysis Grigoropoulos
    user_id = request.user_uniq
221 16f7d0d9 Dionysis Grigoropoulos
222 16f7d0d9 Dionysis Grigoropoulos
    try:
223 16f7d0d9 Dionysis Grigoropoulos
        subnet = dictionary['subnet']
224 16f7d0d9 Dionysis Grigoropoulos
    except KeyError:
225 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Malformed request")
226 16f7d0d9 Dionysis Grigoropoulos
227 16f7d0d9 Dionysis Grigoropoulos
    original_subnet = get_subnet_fromdb(sub_id, user_id)
228 16f7d0d9 Dionysis Grigoropoulos
    original_dict = subnet_to_dict(original_subnet)
229 16f7d0d9 Dionysis Grigoropoulos
230 16f7d0d9 Dionysis Grigoropoulos
    if len(subnet) != 1:
231 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Only the name of subnet can be updated")
232 16f7d0d9 Dionysis Grigoropoulos
233 16f7d0d9 Dionysis Grigoropoulos
    name = subnet.get("name", None)
234 16f7d0d9 Dionysis Grigoropoulos
235 16f7d0d9 Dionysis Grigoropoulos
    if not name:
236 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Only the name of subnet can be updated")
237 16f7d0d9 Dionysis Grigoropoulos
238 16f7d0d9 Dionysis Grigoropoulos
    check_name_length(name)
239 16f7d0d9 Dionysis Grigoropoulos
240 16f7d0d9 Dionysis Grigoropoulos
    try:
241 16f7d0d9 Dionysis Grigoropoulos
        original_subnet.name = name
242 16f7d0d9 Dionysis Grigoropoulos
        original_subnet.save()
243 16f7d0d9 Dionysis Grigoropoulos
    except:
244 16f7d0d9 Dionysis Grigoropoulos
        #Fix me
245 16f7d0d9 Dionysis Grigoropoulos
        return "Unknown Error"
246 16f7d0d9 Dionysis Grigoropoulos
247 16f7d0d9 Dionysis Grigoropoulos
    subnet_dict = subnet_to_dict(original_subnet)
248 16f7d0d9 Dionysis Grigoropoulos
    data = json.dumps({'subnet': subnet_dict})
249 16f7d0d9 Dionysis Grigoropoulos
    return HttpResponse(data, status=200)
250 16f7d0d9 Dionysis Grigoropoulos
251 16f7d0d9 Dionysis Grigoropoulos
252 16f7d0d9 Dionysis Grigoropoulos
#Utility functions
253 16f7d0d9 Dionysis Grigoropoulos
def subnet_to_dict(subnet):
254 16f7d0d9 Dionysis Grigoropoulos
    """Returns a dictionary containing the info of a subnet"""
255 911a1bc1 Dionysis Grigoropoulos
    dns = check_empty_lists(subnet.dns_nameservers)
256 911a1bc1 Dionysis Grigoropoulos
    hosts = check_empty_lists(subnet.host_routes)
257 4445f97a Dionysis Grigoropoulos
    allocation_pools = subnet.ip_pools.all()
258 4445f97a Dionysis Grigoropoulos
    pools = list()
259 4445f97a Dionysis Grigoropoulos
260 4445f97a Dionysis Grigoropoulos
    if allocation_pools:
261 4445f97a Dionysis Grigoropoulos
        for pool in allocation_pools:
262 4445f97a Dionysis Grigoropoulos
            cidr = IPNetwork(pool.base)
263 4445f97a Dionysis Grigoropoulos
            start = str(cidr.network + pool.offset)
264 4445f97a Dionysis Grigoropoulos
            end = str(cidr.network + pool.offset + pool.size - 1)
265 868e4ce0 Dionysis Grigoropoulos
            pools.append({"start": start, "end": end})
266 911a1bc1 Dionysis Grigoropoulos
267 911a1bc1 Dionysis Grigoropoulos
    dictionary = dict({'id': str(subnet.id),
268 911a1bc1 Dionysis Grigoropoulos
                       'network_id': str(subnet.network.id),
269 911a1bc1 Dionysis Grigoropoulos
                       'name': subnet.name if subnet.name is not None else "",
270 911a1bc1 Dionysis Grigoropoulos
                       'tenant_id': subnet.network.userid,
271 911a1bc1 Dionysis Grigoropoulos
                       'user_id': subnet.network.userid,
272 16f7d0d9 Dionysis Grigoropoulos
                       'gateway_ip': subnet.gateway,
273 911a1bc1 Dionysis Grigoropoulos
                       'ip_version': subnet.ipversion,
274 911a1bc1 Dionysis Grigoropoulos
                       'cidr': subnet.cidr,
275 16f7d0d9 Dionysis Grigoropoulos
                       'enable_dhcp': subnet.dhcp,
276 911a1bc1 Dionysis Grigoropoulos
                       'dns_nameservers': dns,
277 911a1bc1 Dionysis Grigoropoulos
                       'host_routes': hosts,
278 4445f97a Dionysis Grigoropoulos
                       'allocation_pools': pools if pools is not None else []})
279 97ca522f Dionysis Grigoropoulos
280 97ca522f Dionysis Grigoropoulos
    if subnet.ipversion == 6:
281 097009bf Dionysis Grigoropoulos
        dictionary['enable_slac'] = subnet.dhcp
282 97ca522f Dionysis Grigoropoulos
283 16f7d0d9 Dionysis Grigoropoulos
    return dictionary
284 16f7d0d9 Dionysis Grigoropoulos
285 16f7d0d9 Dionysis Grigoropoulos
286 4445f97a Dionysis Grigoropoulos
def string_to_ipaddr(pools):
287 4445f97a Dionysis Grigoropoulos
    """
288 4445f97a Dionysis Grigoropoulos
    Convert [["192.168.42.1", "192.168.42.15"],
289 4445f97a Dionysis Grigoropoulos
            ["192.168.42.30", "192.168.42.60"]]
290 4445f97a Dionysis Grigoropoulos
    to
291 4445f97a Dionysis Grigoropoulos
            [[IPv4Address('192.168.42.1'), IPv4Address('192.168.42.15')],
292 4445f97a Dionysis Grigoropoulos
            [IPv4Address('192.168.42.30'), IPv4Address('192.168.42.60')]]
293 4445f97a Dionysis Grigoropoulos
    and sort the output
294 4445f97a Dionysis Grigoropoulos
    """
295 4445f97a Dionysis Grigoropoulos
    pool_list = [(map(lambda ip_str: IPAddress(ip_str), pool))
296 4445f97a Dionysis Grigoropoulos
                 for pool in pools]
297 4445f97a Dionysis Grigoropoulos
    pool_list.sort()
298 4445f97a Dionysis Grigoropoulos
    return pool_list
299 4445f97a Dionysis Grigoropoulos
300 4445f97a Dionysis Grigoropoulos
301 4445f97a Dionysis Grigoropoulos
def create_ip_pools(pools, cidr, subnet):
302 4445f97a Dionysis Grigoropoulos
    """Placeholder"""
303 4445f97a Dionysis Grigoropoulos
    for pool in pools:
304 4445f97a Dionysis Grigoropoulos
        size = int(pool[1]) - int(pool[0]) + 1
305 4445f97a Dionysis Grigoropoulos
        base = str(cidr)
306 4445f97a Dionysis Grigoropoulos
        offset = int(pool[0]) - int(cidr.network)
307 4445f97a Dionysis Grigoropoulos
        ip_pool = IPPoolTable.objects.create(size=size, offset=offset,
308 4445f97a Dionysis Grigoropoulos
                                             base=base, subnet=subnet)
309 4445f97a Dionysis Grigoropoulos
310 4445f97a Dionysis Grigoropoulos
311 911a1bc1 Dionysis Grigoropoulos
def check_empty_lists(value):
312 911a1bc1 Dionysis Grigoropoulos
    """Check if value is Null/None, in which case we return an empty list"""
313 911a1bc1 Dionysis Grigoropoulos
    if value is None:
314 911a1bc1 Dionysis Grigoropoulos
        return []
315 911a1bc1 Dionysis Grigoropoulos
    return value
316 911a1bc1 Dionysis Grigoropoulos
317 911a1bc1 Dionysis Grigoropoulos
318 16f7d0d9 Dionysis Grigoropoulos
def check_number_of_subnets(network, version):
319 16f7d0d9 Dionysis Grigoropoulos
    """Check if a user can add a subnet in a network"""
320 6a959c73 Dionysis Grigoropoulos
    if network.subnets.filter(ipversion=version):
321 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Only one subnet of IPv4/IPv6 per "
322 16f7d0d9 Dionysis Grigoropoulos
                                    "network is allowed")
323 16f7d0d9 Dionysis Grigoropoulos
324 16f7d0d9 Dionysis Grigoropoulos
325 911a1bc1 Dionysis Grigoropoulos
def check_boolean_value(value, key):
326 16f7d0d9 Dionysis Grigoropoulos
    """Check if dhcp value is in acceptable values"""
327 911a1bc1 Dionysis Grigoropoulos
    if value not in [True, False]:
328 911a1bc1 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Malformed request, %s must "
329 911a1bc1 Dionysis Grigoropoulos
                                    "be True or False" % key)
330 911a1bc1 Dionysis Grigoropoulos
    return value
331 16f7d0d9 Dionysis Grigoropoulos
332 16f7d0d9 Dionysis Grigoropoulos
333 16f7d0d9 Dionysis Grigoropoulos
def check_name_length(name):
334 16f7d0d9 Dionysis Grigoropoulos
    """Check if the length of a name is within acceptable value"""
335 16f7d0d9 Dionysis Grigoropoulos
    if len(str(name)) > Subnet.SUBNET_NAME_LENGTH:
336 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Subnet name too long")
337 16f7d0d9 Dionysis Grigoropoulos
    return name
338 16f7d0d9 Dionysis Grigoropoulos
339 16f7d0d9 Dionysis Grigoropoulos
340 16f7d0d9 Dionysis Grigoropoulos
def check_for_hosts_dns(subnet):
341 16f7d0d9 Dionysis Grigoropoulos
    """
342 16f7d0d9 Dionysis Grigoropoulos
    Check if a request contains host_routes or dns_nameservers options
343 16f7d0d9 Dionysis Grigoropoulos
    Expects the request in a dictionary format
344 16f7d0d9 Dionysis Grigoropoulos
    """
345 16f7d0d9 Dionysis Grigoropoulos
    if subnet.get('host_routes', None):
346 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Setting host routes isn't supported")
347 16f7d0d9 Dionysis Grigoropoulos
    if subnet.get('dns_nameservers', None):
348 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Setting dns nameservers isn't supported")
349 16f7d0d9 Dionysis Grigoropoulos
350 16f7d0d9 Dionysis Grigoropoulos
351 16f7d0d9 Dionysis Grigoropoulos
def get_subnet_fromdb(subnet_id, user_id, for_update=False):
352 16f7d0d9 Dionysis Grigoropoulos
    """
353 16f7d0d9 Dionysis Grigoropoulos
    Return a Subnet instance or raise ItemNotFound.
354 16f7d0d9 Dionysis Grigoropoulos
    This is the same as util.get_network
355 16f7d0d9 Dionysis Grigoropoulos
    """
356 16f7d0d9 Dionysis Grigoropoulos
    try:
357 16f7d0d9 Dionysis Grigoropoulos
        subnet_id = int(subnet_id)
358 16f7d0d9 Dionysis Grigoropoulos
        if for_update:
359 16f7d0d9 Dionysis Grigoropoulos
            return Subnet.objects.select_for_update().get(id=subnet_id,
360 16f7d0d9 Dionysis Grigoropoulos
                                                          network__userid=
361 16f7d0d9 Dionysis Grigoropoulos
                                                          user_id)
362 16f7d0d9 Dionysis Grigoropoulos
        return Subnet.objects.get(id=subnet_id, network__userid=user_id)
363 16f7d0d9 Dionysis Grigoropoulos
    except (ValueError, Subnet.DoesNotExist):
364 911a1bc1 Dionysis Grigoropoulos
        raise api.faults.ItemNotFound('Subnet not found')
365 812a1114 Dionysis Grigoropoulos
366 812a1114 Dionysis Grigoropoulos
367 812a1114 Dionysis Grigoropoulos
def parse_ip_pools(pools):
368 812a1114 Dionysis Grigoropoulos
    """
369 812a1114 Dionysis Grigoropoulos
    Convert [{'start': '192.168.42.1', 'end': '192.168.42.15'},
370 812a1114 Dionysis Grigoropoulos
             {'start': '192.168.42.30', 'end': '192.168.42.60'}]
371 812a1114 Dionysis Grigoropoulos
    to
372 812a1114 Dionysis Grigoropoulos
            [["192.168.42.1", "192.168.42.15"],
373 812a1114 Dionysis Grigoropoulos
             ["192.168.42.30", "192.168.42.60"]]
374 812a1114 Dionysis Grigoropoulos
    """
375 812a1114 Dionysis Grigoropoulos
    pool_list = list()
376 812a1114 Dionysis Grigoropoulos
    for pool in pools:
377 911a1bc1 Dionysis Grigoropoulos
        parse = [pool["start"], pool["end"]]
378 911a1bc1 Dionysis Grigoropoulos
        pool_list.append(parse)
379 812a1114 Dionysis Grigoropoulos
    return pool_list
380 812a1114 Dionysis Grigoropoulos
381 812a1114 Dionysis Grigoropoulos
382 4445f97a Dionysis Grigoropoulos
def validate_subpools(pool_list, cidr, gateway):
383 812a1114 Dionysis Grigoropoulos
    """
384 812a1114 Dionysis Grigoropoulos
    Validate the given IP pools are inside the cidr range
385 812a1114 Dionysis Grigoropoulos
    Validate there are no overlaps in the given pools
386 911a1bc1 Dionysis Grigoropoulos
    Finally, validate the gateway isn't in the given ip pools
387 4445f97a Dionysis Grigoropoulos
    Input must be a list containing a sublist with start/end ranges as
388 4445f97a Dionysis Grigoropoulos
    ipaddr.IPAddress items eg.,
389 4445f97a Dionysis Grigoropoulos
    [[IPv4Address('192.168.42.11'), IPv4Address('192.168.42.15')],
390 4445f97a Dionysis Grigoropoulos
     [IPv4Address('192.168.42.30'), IPv4Address('192.168.42.60')]]
391 812a1114 Dionysis Grigoropoulos
    """
392 812a1114 Dionysis Grigoropoulos
    if pool_list[0][0] <= cidr.network:
393 a996065e Dionysis Grigoropoulos
        raise api.faults.Conflict("IP Pool out of bounds")
394 812a1114 Dionysis Grigoropoulos
    elif pool_list[-1][1] >= cidr.broadcast:
395 a996065e Dionysis Grigoropoulos
        raise api.faults.Conflict("IP Pool out of bounds")
396 812a1114 Dionysis Grigoropoulos
397 812a1114 Dionysis Grigoropoulos
    for start, end in pool_list:
398 911a1bc1 Dionysis Grigoropoulos
        if start > end:
399 812a1114 Dionysis Grigoropoulos
            raise api.faults.Conflict("Invalid IP pool range")
400 812a1114 Dionysis Grigoropoulos
        # Raise BadRequest if gateway is inside the pool range
401 812a1114 Dionysis Grigoropoulos
        if not (gateway < start or gateway > end):
402 812a1114 Dionysis Grigoropoulos
            raise api.faults.Conflict("Gateway cannot be in pool range")
403 812a1114 Dionysis Grigoropoulos
404 812a1114 Dionysis Grigoropoulos
    # Check if there is a conflict between the IP Poll ranges
405 812a1114 Dionysis Grigoropoulos
    end = cidr.network
406 812a1114 Dionysis Grigoropoulos
    for pool in pool_list:
407 911a1bc1 Dionysis Grigoropoulos
        if end >= pool[0]:
408 812a1114 Dionysis Grigoropoulos
            raise api.faults.Conflict("IP Pool range conflict")
409 812a1114 Dionysis Grigoropoulos
        end = pool[1]