Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / subnets.py @ 53b0ea25

History | View | Annotate | Download (9.5 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 9cd6d7e9 Dionysis Grigoropoulos
from synnefo.logic import networks, subnets
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 5d83d2ff Dionysis Grigoropoulos
    subnet_list = subnets.list_subnets(request.user_uniq)
81 5d83d2ff Dionysis Grigoropoulos
    subnets_dict = [subnet_to_dict(sub)
82 5d83d2ff Dionysis Grigoropoulos
                    for sub in subnet_list.order_by('id')]
83 5d83d2ff Dionysis Grigoropoulos
84 16f7d0d9 Dionysis Grigoropoulos
    data = json.dumps({'subnets': subnets_dict})
85 16f7d0d9 Dionysis Grigoropoulos
86 16f7d0d9 Dionysis Grigoropoulos
    return HttpResponse(data, status=200)
87 16f7d0d9 Dionysis Grigoropoulos
88 16f7d0d9 Dionysis Grigoropoulos
89 16f7d0d9 Dionysis Grigoropoulos
@api.api_method(http_method='POST', user_required=True, logger=log)
90 16f7d0d9 Dionysis Grigoropoulos
def create_subnet(request):
91 316787ab Dionysis Grigoropoulos
    """Create a subnet
92 a996065e Dionysis Grigoropoulos
    network_id and the desired cidr are mandatory, everything else is optional
93 316787ab Dionysis Grigoropoulos

94 a996065e Dionysis Grigoropoulos
    """
95 16f7d0d9 Dionysis Grigoropoulos
    dictionary = utils.get_request_dict(request)
96 16f7d0d9 Dionysis Grigoropoulos
    log.info('create subnet %s', dictionary)
97 16f7d0d9 Dionysis Grigoropoulos
98 16f7d0d9 Dionysis Grigoropoulos
    try:
99 16f7d0d9 Dionysis Grigoropoulos
        subnet = dictionary['subnet']
100 16f7d0d9 Dionysis Grigoropoulos
        network_id = subnet['network_id']
101 16f7d0d9 Dionysis Grigoropoulos
        cidr = subnet['cidr']
102 16f7d0d9 Dionysis Grigoropoulos
    except KeyError:
103 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Malformed request")
104 16f7d0d9 Dionysis Grigoropoulos
105 16f7d0d9 Dionysis Grigoropoulos
    allocation_pools = subnet.get('allocation_pools', None)
106 4445f97a Dionysis Grigoropoulos
    if allocation_pools is not None:
107 9cd6d7e9 Dionysis Grigoropoulos
        pool = parse_ip_pools(allocation_pools)
108 9cd6d7e9 Dionysis Grigoropoulos
        allocation_pools = string_to_ipaddr(pool)
109 9cd6d7e9 Dionysis Grigoropoulos
110 5d83d2ff Dionysis Grigoropoulos
    name = subnet.get('name', None)
111 5d83d2ff Dionysis Grigoropoulos
    ipversion = subnet.get('ip_version', 4)
112 99718617 Dionysis Grigoropoulos
    # If no gateway is specified, send an empty string, because None is used
113 99718617 Dionysis Grigoropoulos
    # if the user wants no gateway at all
114 99718617 Dionysis Grigoropoulos
    gateway = subnet.get('gateway_ip', "")
115 5d83d2ff Dionysis Grigoropoulos
    dhcp = subnet.get('enable_dhcp', True)
116 5d83d2ff Dionysis Grigoropoulos
    slac = subnet.get('enable_slac', None)
117 5d83d2ff Dionysis Grigoropoulos
    dns = subnet.get('dns_nameservers', None)
118 5d83d2ff Dionysis Grigoropoulos
    hosts = subnet.get('host_routes', None)
119 5d83d2ff Dionysis Grigoropoulos
120 9cd6d7e9 Dionysis Grigoropoulos
    sub = subnets.create_subnet(network_id=network_id,
121 9cd6d7e9 Dionysis Grigoropoulos
                                cidr=cidr,
122 9cd6d7e9 Dionysis Grigoropoulos
                                name=name,
123 9cd6d7e9 Dionysis Grigoropoulos
                                ipversion=ipversion,
124 9cd6d7e9 Dionysis Grigoropoulos
                                gateway=gateway,
125 9cd6d7e9 Dionysis Grigoropoulos
                                dhcp=dhcp,
126 9cd6d7e9 Dionysis Grigoropoulos
                                slac=slac,
127 9cd6d7e9 Dionysis Grigoropoulos
                                dns_nameservers=dns,
128 9cd6d7e9 Dionysis Grigoropoulos
                                allocation_pools=allocation_pools,
129 9cd6d7e9 Dionysis Grigoropoulos
                                host_routes=hosts,
130 9cd6d7e9 Dionysis Grigoropoulos
                                user_id=request.user_uniq)
131 16f7d0d9 Dionysis Grigoropoulos
132 16f7d0d9 Dionysis Grigoropoulos
    subnet_dict = subnet_to_dict(sub)
133 16f7d0d9 Dionysis Grigoropoulos
    data = json.dumps({'subnet': subnet_dict})
134 16f7d0d9 Dionysis Grigoropoulos
    return HttpResponse(data, status=200)
135 16f7d0d9 Dionysis Grigoropoulos
136 16f7d0d9 Dionysis Grigoropoulos
137 16f7d0d9 Dionysis Grigoropoulos
@api.api_method(http_method='GET', user_required=True, logger=log)
138 16f7d0d9 Dionysis Grigoropoulos
def get_subnet(request, sub_id):
139 16f7d0d9 Dionysis Grigoropoulos
    """Show info of a specific subnet"""
140 16f7d0d9 Dionysis Grigoropoulos
    user_id = request.user_uniq
141 9cd6d7e9 Dionysis Grigoropoulos
    subnet = subnets.get_subnet(sub_id)
142 16f7d0d9 Dionysis Grigoropoulos
143 16f7d0d9 Dionysis Grigoropoulos
    if subnet.network.userid != user_id:
144 16f7d0d9 Dionysis Grigoropoulos
        raise api.failts.Unauthorized("You're not allowed to view this subnet")
145 16f7d0d9 Dionysis Grigoropoulos
146 5d83d2ff Dionysis Grigoropoulos
    subnet_dict = subnet_to_dict(subnet)
147 16f7d0d9 Dionysis Grigoropoulos
    data = json.dumps({'subnet': subnet_dict})
148 16f7d0d9 Dionysis Grigoropoulos
    return HttpResponse(data, status=200)
149 16f7d0d9 Dionysis Grigoropoulos
150 16f7d0d9 Dionysis Grigoropoulos
151 16f7d0d9 Dionysis Grigoropoulos
@api.api_method(http_method='DELETE', user_required=True, logger=log)
152 16f7d0d9 Dionysis Grigoropoulos
def delete_subnet(request, sub_id):
153 316787ab Dionysis Grigoropoulos
    """Delete a subnet, raises BadRequest
154 16f7d0d9 Dionysis Grigoropoulos
    A subnet is deleted ONLY when the network that it belongs to is deleted
155 316787ab Dionysis Grigoropoulos

156 16f7d0d9 Dionysis Grigoropoulos
    """
157 16f7d0d9 Dionysis Grigoropoulos
    raise api.faults.BadRequest("Deletion of a subnet is not supported")
158 16f7d0d9 Dionysis Grigoropoulos
159 16f7d0d9 Dionysis Grigoropoulos
160 16f7d0d9 Dionysis Grigoropoulos
@api.api_method(http_method='PUT', user_required=True, logger=log)
161 16f7d0d9 Dionysis Grigoropoulos
def update_subnet(request, sub_id):
162 316787ab Dionysis Grigoropoulos
    """Update the fields of a subnet
163 16f7d0d9 Dionysis Grigoropoulos
    Only the name can be updated, everything else returns BadRequest
164 316787ab Dionysis Grigoropoulos

165 16f7d0d9 Dionysis Grigoropoulos
    """
166 16f7d0d9 Dionysis Grigoropoulos
167 16f7d0d9 Dionysis Grigoropoulos
    dictionary = utils.get_request_dict(request)
168 16f7d0d9 Dionysis Grigoropoulos
    user_id = request.user_uniq
169 16f7d0d9 Dionysis Grigoropoulos
170 16f7d0d9 Dionysis Grigoropoulos
    try:
171 16f7d0d9 Dionysis Grigoropoulos
        subnet = dictionary['subnet']
172 16f7d0d9 Dionysis Grigoropoulos
    except KeyError:
173 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Malformed request")
174 16f7d0d9 Dionysis Grigoropoulos
175 5d83d2ff Dionysis Grigoropoulos
    if len(subnet) != 1 or "name" not in subnet:
176 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Only the name of subnet can be updated")
177 16f7d0d9 Dionysis Grigoropoulos
178 16f7d0d9 Dionysis Grigoropoulos
    name = subnet.get("name", None)
179 16f7d0d9 Dionysis Grigoropoulos
180 8646e606 Dionysis Grigoropoulos
    subnet_dict = subnet_to_dict(subnets.update_subnet(sub_id, name, user_id))
181 16f7d0d9 Dionysis Grigoropoulos
    data = json.dumps({'subnet': subnet_dict})
182 16f7d0d9 Dionysis Grigoropoulos
    return HttpResponse(data, status=200)
183 16f7d0d9 Dionysis Grigoropoulos
184 16f7d0d9 Dionysis Grigoropoulos
185 16f7d0d9 Dionysis Grigoropoulos
#Utility functions
186 16f7d0d9 Dionysis Grigoropoulos
def subnet_to_dict(subnet):
187 16f7d0d9 Dionysis Grigoropoulos
    """Returns a dictionary containing the info of a subnet"""
188 911a1bc1 Dionysis Grigoropoulos
    dns = check_empty_lists(subnet.dns_nameservers)
189 911a1bc1 Dionysis Grigoropoulos
    hosts = check_empty_lists(subnet.host_routes)
190 4445f97a Dionysis Grigoropoulos
    allocation_pools = subnet.ip_pools.all()
191 4445f97a Dionysis Grigoropoulos
    pools = list()
192 4445f97a Dionysis Grigoropoulos
193 4445f97a Dionysis Grigoropoulos
    if allocation_pools:
194 4445f97a Dionysis Grigoropoulos
        for pool in allocation_pools:
195 4445f97a Dionysis Grigoropoulos
            cidr = IPNetwork(pool.base)
196 4445f97a Dionysis Grigoropoulos
            start = str(cidr.network + pool.offset)
197 4445f97a Dionysis Grigoropoulos
            end = str(cidr.network + pool.offset + pool.size - 1)
198 868e4ce0 Dionysis Grigoropoulos
            pools.append({"start": start, "end": end})
199 911a1bc1 Dionysis Grigoropoulos
200 911a1bc1 Dionysis Grigoropoulos
    dictionary = dict({'id': str(subnet.id),
201 911a1bc1 Dionysis Grigoropoulos
                       'network_id': str(subnet.network.id),
202 911a1bc1 Dionysis Grigoropoulos
                       'name': subnet.name if subnet.name is not None else "",
203 911a1bc1 Dionysis Grigoropoulos
                       'tenant_id': subnet.network.userid,
204 911a1bc1 Dionysis Grigoropoulos
                       'user_id': subnet.network.userid,
205 16f7d0d9 Dionysis Grigoropoulos
                       'gateway_ip': subnet.gateway,
206 911a1bc1 Dionysis Grigoropoulos
                       'ip_version': subnet.ipversion,
207 911a1bc1 Dionysis Grigoropoulos
                       'cidr': subnet.cidr,
208 16f7d0d9 Dionysis Grigoropoulos
                       'enable_dhcp': subnet.dhcp,
209 911a1bc1 Dionysis Grigoropoulos
                       'dns_nameservers': dns,
210 911a1bc1 Dionysis Grigoropoulos
                       'host_routes': hosts,
211 4445f97a Dionysis Grigoropoulos
                       'allocation_pools': pools if pools is not None else []})
212 97ca522f Dionysis Grigoropoulos
213 97ca522f Dionysis Grigoropoulos
    if subnet.ipversion == 6:
214 097009bf Dionysis Grigoropoulos
        dictionary['enable_slac'] = subnet.dhcp
215 97ca522f Dionysis Grigoropoulos
216 16f7d0d9 Dionysis Grigoropoulos
    return dictionary
217 16f7d0d9 Dionysis Grigoropoulos
218 16f7d0d9 Dionysis Grigoropoulos
219 4445f97a Dionysis Grigoropoulos
def string_to_ipaddr(pools):
220 316787ab Dionysis Grigoropoulos
    """Convert [["192.168.42.1", "192.168.42.15"],
221 316787ab Dionysis Grigoropoulos
                ["192.168.42.30", "192.168.42.60"]]
222 4445f97a Dionysis Grigoropoulos
    to
223 316787ab Dionysis Grigoropoulos
                [[IPv4Address('192.168.42.1'), IPv4Address('192.168.42.15')],
224 316787ab Dionysis Grigoropoulos
                [IPv4Address('192.168.42.30'), IPv4Address('192.168.42.60')]]
225 4445f97a Dionysis Grigoropoulos
    and sort the output
226 316787ab Dionysis Grigoropoulos

227 4445f97a Dionysis Grigoropoulos
    """
228 4445f97a Dionysis Grigoropoulos
    pool_list = [(map(lambda ip_str: IPAddress(ip_str), pool))
229 4445f97a Dionysis Grigoropoulos
                 for pool in pools]
230 4445f97a Dionysis Grigoropoulos
    pool_list.sort()
231 4445f97a Dionysis Grigoropoulos
    return pool_list
232 4445f97a Dionysis Grigoropoulos
233 4445f97a Dionysis Grigoropoulos
234 911a1bc1 Dionysis Grigoropoulos
def check_empty_lists(value):
235 911a1bc1 Dionysis Grigoropoulos
    """Check if value is Null/None, in which case we return an empty list"""
236 911a1bc1 Dionysis Grigoropoulos
    if value is None:
237 911a1bc1 Dionysis Grigoropoulos
        return []
238 911a1bc1 Dionysis Grigoropoulos
    return value
239 911a1bc1 Dionysis Grigoropoulos
240 911a1bc1 Dionysis Grigoropoulos
241 16f7d0d9 Dionysis Grigoropoulos
def check_name_length(name):
242 16f7d0d9 Dionysis Grigoropoulos
    """Check if the length of a name is within acceptable value"""
243 16f7d0d9 Dionysis Grigoropoulos
    if len(str(name)) > Subnet.SUBNET_NAME_LENGTH:
244 16f7d0d9 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Subnet name too long")
245 16f7d0d9 Dionysis Grigoropoulos
    return name
246 16f7d0d9 Dionysis Grigoropoulos
247 16f7d0d9 Dionysis Grigoropoulos
248 16f7d0d9 Dionysis Grigoropoulos
def get_subnet_fromdb(subnet_id, user_id, for_update=False):
249 316787ab Dionysis Grigoropoulos
    """Return a Subnet instance or raise ItemNotFound.
250 16f7d0d9 Dionysis Grigoropoulos
    This is the same as util.get_network
251 316787ab Dionysis Grigoropoulos

252 16f7d0d9 Dionysis Grigoropoulos
    """
253 16f7d0d9 Dionysis Grigoropoulos
    try:
254 16f7d0d9 Dionysis Grigoropoulos
        subnet_id = int(subnet_id)
255 16f7d0d9 Dionysis Grigoropoulos
        if for_update:
256 16f7d0d9 Dionysis Grigoropoulos
            return Subnet.objects.select_for_update().get(id=subnet_id,
257 16f7d0d9 Dionysis Grigoropoulos
                                                          network__userid=
258 16f7d0d9 Dionysis Grigoropoulos
                                                          user_id)
259 16f7d0d9 Dionysis Grigoropoulos
        return Subnet.objects.get(id=subnet_id, network__userid=user_id)
260 16f7d0d9 Dionysis Grigoropoulos
    except (ValueError, Subnet.DoesNotExist):
261 911a1bc1 Dionysis Grigoropoulos
        raise api.faults.ItemNotFound('Subnet not found')
262 812a1114 Dionysis Grigoropoulos
263 812a1114 Dionysis Grigoropoulos
264 812a1114 Dionysis Grigoropoulos
def parse_ip_pools(pools):
265 316787ab Dionysis Grigoropoulos
    """Convert [{'start': '192.168.42.1', 'end': '192.168.42.15'},
266 812a1114 Dionysis Grigoropoulos
             {'start': '192.168.42.30', 'end': '192.168.42.60'}]
267 812a1114 Dionysis Grigoropoulos
    to
268 812a1114 Dionysis Grigoropoulos
            [["192.168.42.1", "192.168.42.15"],
269 812a1114 Dionysis Grigoropoulos
             ["192.168.42.30", "192.168.42.60"]]
270 316787ab Dionysis Grigoropoulos

271 812a1114 Dionysis Grigoropoulos
    """
272 812a1114 Dionysis Grigoropoulos
    pool_list = list()
273 812a1114 Dionysis Grigoropoulos
    for pool in pools:
274 911a1bc1 Dionysis Grigoropoulos
        parse = [pool["start"], pool["end"]]
275 911a1bc1 Dionysis Grigoropoulos
        pool_list.append(parse)
276 812a1114 Dionysis Grigoropoulos
    return pool_list