Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / networks.py @ 17600d55

History | View | Annotate | Download (11.2 kB)

1 6ef51e9f Giorgos Verigakis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 ce55f211 Kostas Papadimitriou
#
3 adee02b8 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 adee02b8 Giorgos Verigakis
# without modification, are permitted provided that the following
5 adee02b8 Giorgos Verigakis
# conditions are met:
6 ce55f211 Kostas Papadimitriou
#
7 adee02b8 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 adee02b8 Giorgos Verigakis
#      disclaimer.
10 ce55f211 Kostas Papadimitriou
#
11 adee02b8 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 adee02b8 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 adee02b8 Giorgos Verigakis
#      provided with the distribution.
15 ce55f211 Kostas Papadimitriou
#
16 adee02b8 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 adee02b8 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 adee02b8 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 adee02b8 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 adee02b8 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 adee02b8 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 adee02b8 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 adee02b8 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 adee02b8 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 adee02b8 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 adee02b8 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 adee02b8 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 ce55f211 Kostas Papadimitriou
#
29 adee02b8 Giorgos Verigakis
# The views and conclusions contained in the software and
30 adee02b8 Giorgos Verigakis
# documentation are those of the authors and should not be
31 adee02b8 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 adee02b8 Giorgos Verigakis
# or implied, of GRNET S.A.
33 adee02b8 Giorgos Verigakis
34 2035039b Giorgos Verigakis
from logging import getLogger
35 2035039b Giorgos Verigakis
36 0269afd6 Giorgos Verigakis
from django.conf.urls.defaults import patterns
37 ce55f211 Kostas Papadimitriou
from django.conf import settings
38 d44c236b Giorgos Verigakis
from django.db.models import Q
39 4dba0480 Christos Stavrakakis
from django.db import transaction
40 0269afd6 Giorgos Verigakis
from django.http import HttpResponse
41 69d6d7dd Giorgos Verigakis
from django.template.loader import render_to_string
42 0269afd6 Giorgos Verigakis
from django.utils import simplejson as json
43 0269afd6 Giorgos Verigakis
44 5061546f Christos Stavrakakis
from synnefo.api import util
45 b36f78fa Giorgos Verigakis
from synnefo.api.actions import network_actions
46 b36f78fa Giorgos Verigakis
from synnefo.api.common import method_not_allowed
47 17c2ed57 Christos Stavrakakis
from synnefo.api.faults import (ServiceUnavailable, BadRequest, Forbidden,
48 6eed1ede Christos Stavrakakis
                                NetworkInUse, OverLimit)
49 03992c72 Christos Stavrakakis
from synnefo.db.models import Network
50 03992c72 Christos Stavrakakis
from synnefo.db.pools import EmptyPool
51 b36f78fa Giorgos Verigakis
from synnefo.logic import backend
52 9e98ba3c Giorgos Verigakis
53 9e98ba3c Giorgos Verigakis
54 9e98ba3c Giorgos Verigakis
log = getLogger('synnefo.api')
55 b36f78fa Giorgos Verigakis
56 0269afd6 Giorgos Verigakis
urlpatterns = patterns('synnefo.api.networks',
57 0269afd6 Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
58 0269afd6 Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_networks', {'detail': True}),
59 f4fe8796 Giorgos Verigakis
    (r'^/(\w+)(?:.json|.xml)?$', 'network_demux'),
60 f4fe8796 Giorgos Verigakis
    (r'^/(\w+)/action(?:.json|.xml)?$', 'network_action'),
61 0269afd6 Giorgos Verigakis
)
62 0269afd6 Giorgos Verigakis
63 0269afd6 Giorgos Verigakis
64 0269afd6 Giorgos Verigakis
def demux(request):
65 0269afd6 Giorgos Verigakis
    if request.method == 'GET':
66 0269afd6 Giorgos Verigakis
        return list_networks(request)
67 0269afd6 Giorgos Verigakis
    elif request.method == 'POST':
68 0269afd6 Giorgos Verigakis
        return create_network(request)
69 0269afd6 Giorgos Verigakis
    else:
70 0269afd6 Giorgos Verigakis
        return method_not_allowed(request)
71 0269afd6 Giorgos Verigakis
72 6ef51e9f Giorgos Verigakis
73 b19653d1 Giorgos Verigakis
def network_demux(request, network_id):
74 0269afd6 Giorgos Verigakis
    if request.method == 'GET':
75 b19653d1 Giorgos Verigakis
        return get_network_details(request, network_id)
76 0269afd6 Giorgos Verigakis
    elif request.method == 'PUT':
77 b19653d1 Giorgos Verigakis
        return update_network_name(request, network_id)
78 0269afd6 Giorgos Verigakis
    elif request.method == 'DELETE':
79 b19653d1 Giorgos Verigakis
        return delete_network(request, network_id)
80 0269afd6 Giorgos Verigakis
    else:
81 0269afd6 Giorgos Verigakis
        return method_not_allowed(request)
82 0269afd6 Giorgos Verigakis
83 0269afd6 Giorgos Verigakis
84 6ef51e9f Giorgos Verigakis
def network_to_dict(network, user_id, detail=True):
85 7fede91e Christos Stavrakakis
    d = {'id': str(network.id), 'name': network.name}
86 0269afd6 Giorgos Verigakis
    if detail:
87 08b079e2 Stavros Sachtouris
        d['cidr'] = network.subnet
88 cc3f266e Christos Stavrakakis
        d['cidr6'] = network.subnet6
89 08b079e2 Stavros Sachtouris
        d['gateway'] = network.gateway
90 cc3f266e Christos Stavrakakis
        d['gateway6'] = network.gateway6
91 08b079e2 Stavros Sachtouris
        d['dhcp'] = network.dhcp
92 08b079e2 Stavros Sachtouris
        d['type'] = network.type
93 b36f78fa Giorgos Verigakis
        d['updated'] = util.isoformat(network.updated)
94 b36f78fa Giorgos Verigakis
        d['created'] = util.isoformat(network.created)
95 d44c236b Giorgos Verigakis
        d['status'] = network.state
96 7fede91e Christos Stavrakakis
        d['public'] = network.public
97 08b079e2 Stavros Sachtouris
98 7fede91e Christos Stavrakakis
        attachments = [util.construct_nic_id(nic)
99 7fede91e Christos Stavrakakis
                       for nic in network.nics.filter(machine__userid=user_id)]
100 7fede91e Christos Stavrakakis
        d['attachments'] = {'values': attachments}
101 0269afd6 Giorgos Verigakis
    return d
102 0269afd6 Giorgos Verigakis
103 6ef51e9f Giorgos Verigakis
104 0269afd6 Giorgos Verigakis
def render_network(request, networkdict, status=200):
105 0269afd6 Giorgos Verigakis
    if request.serialization == 'xml':
106 0269afd6 Giorgos Verigakis
        data = render_to_string('network.xml', {'network': networkdict})
107 0269afd6 Giorgos Verigakis
    else:
108 0269afd6 Giorgos Verigakis
        data = json.dumps({'network': networkdict})
109 0269afd6 Giorgos Verigakis
    return HttpResponse(data, status=status)
110 0269afd6 Giorgos Verigakis
111 0269afd6 Giorgos Verigakis
112 b36f78fa Giorgos Verigakis
@util.api_method('GET')
113 0269afd6 Giorgos Verigakis
def list_networks(request, detail=False):
114 0269afd6 Giorgos Verigakis
    # Normal Response Codes: 200, 203
115 0269afd6 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
116 0269afd6 Giorgos Verigakis
    #                       serviceUnavailable (503),
117 0269afd6 Giorgos Verigakis
    #                       unauthorized (401),
118 0269afd6 Giorgos Verigakis
    #                       badRequest (400),
119 0269afd6 Giorgos Verigakis
    #                       overLimit (413)
120 ce55f211 Kostas Papadimitriou
121 0c37a721 Christos Stavrakakis
    log.debug('list_networks detail=%s', detail)
122 b36f78fa Giorgos Verigakis
    since = util.isoparse(request.GET.get('changes-since'))
123 8b2515a9 Christos Stavrakakis
    user_networks = Network.objects.filter(Q(userid=request.user_uniq) |
124 3878553d Kostas Papadimitriou
                                           Q(public=True))
125 ce55f211 Kostas Papadimitriou
126 0269afd6 Giorgos Verigakis
    if since:
127 d44c236b Giorgos Verigakis
        user_networks = user_networks.filter(updated__gte=since)
128 0269afd6 Giorgos Verigakis
        if not user_networks:
129 0269afd6 Giorgos Verigakis
            return HttpResponse(status=304)
130 3878553d Kostas Papadimitriou
    else:
131 3878553d Kostas Papadimitriou
        user_networks = user_networks.filter(deleted=False)
132 ce55f211 Kostas Papadimitriou
133 4b3b8688 Giorgos Verigakis
    networks = [network_to_dict(network, request.user_uniq, detail)
134 73aed6bf Giorgos Verigakis
                for network in user_networks]
135 ce55f211 Kostas Papadimitriou
136 0269afd6 Giorgos Verigakis
    if request.serialization == 'xml':
137 b36f78fa Giorgos Verigakis
        data = render_to_string('list_networks.xml', {
138 b36f78fa Giorgos Verigakis
            'networks': networks,
139 b36f78fa Giorgos Verigakis
            'detail': detail})
140 0269afd6 Giorgos Verigakis
    else:
141 0269afd6 Giorgos Verigakis
        data = json.dumps({'networks': {'values': networks}})
142 aa197ee4 Vangelis Koukis
143 0269afd6 Giorgos Verigakis
    return HttpResponse(data, status=200)
144 0269afd6 Giorgos Verigakis
145 6ef51e9f Giorgos Verigakis
146 b36f78fa Giorgos Verigakis
@util.api_method('POST')
147 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
148 0269afd6 Giorgos Verigakis
def create_network(request):
149 0269afd6 Giorgos Verigakis
    # Normal Response Code: 202
150 0269afd6 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
151 0269afd6 Giorgos Verigakis
    #                       serviceUnavailable (503),
152 0269afd6 Giorgos Verigakis
    #                       unauthorized (401),
153 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
154 0269afd6 Giorgos Verigakis
    #                       badRequest (400),
155 17c2ed57 Christos Stavrakakis
    #                       forbidden (403)
156 0269afd6 Giorgos Verigakis
    #                       overLimit (413)
157 aa197ee4 Vangelis Koukis
158 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
159 bf5c82dc Christos Stavrakakis
    log.info('create_network %s', req)
160 ce55f211 Kostas Papadimitriou
161 0269afd6 Giorgos Verigakis
    try:
162 0269afd6 Giorgos Verigakis
        d = req['network']
163 0269afd6 Giorgos Verigakis
        name = d['name']
164 5061546f Christos Stavrakakis
        # TODO: Fix this temp values:
165 b9a0b3d5 Stavros Sachtouris
        subnet = d.get('cidr', '192.168.1.0/24')
166 cc3f266e Christos Stavrakakis
        subnet6 = d.get('cidr6', None)
167 5061546f Christos Stavrakakis
        gateway = d.get('gateway', None)
168 cc3f266e Christos Stavrakakis
        gateway6 = d.get('gateway6', None)
169 af6a3bc5 Christos Stavrakakis
        net_type = d.get('type', 'PRIVATE_MAC_FILTERED')
170 5061546f Christos Stavrakakis
        dhcp = d.get('dhcp', True)
171 0269afd6 Giorgos Verigakis
    except (KeyError, ValueError):
172 0269afd6 Giorgos Verigakis
        raise BadRequest('Malformed request.')
173 ce55f211 Kostas Papadimitriou
174 af6a3bc5 Christos Stavrakakis
    if net_type == 'PUBLIC_ROUTED':
175 17c2ed57 Christos Stavrakakis
        raise Forbidden('Can not create a public network.')
176 87994836 Christos Stavrakakis
177 17600d55 Christos Stavrakakis
    if net_type not in ['PUBLIC_ROUTED', 'PRIVATE_MAC_FILTERED',
178 17600d55 Christos Stavrakakis
                        'PRIVATE_PHYSICAL_VLAN', 'CUSTOM_ROUTED',
179 17600d55 Christos Stavrakakis
                        'CUSTOM_BRIDGED']:
180 17600d55 Christos Stavrakakis
        raise BadRequest("Invalid network type: %s", net_type)
181 17600d55 Christos Stavrakakis
    if net_type not in settings.ENABLED_NETWORKS:
182 17600d55 Christos Stavrakakis
        raise Forbidden("Can not create %s network" % net_type)
183 17600d55 Christos Stavrakakis
184 f91dee69 Christos Stavrakakis
    user_networks = len(Network.objects.filter(userid=request.user_uniq,
185 f91dee69 Christos Stavrakakis
                                               deleted=False))
186 3e316e90 Christos Stavrakakis
187 3e316e90 Christos Stavrakakis
    if user_networks >= settings.MAX_NETWORKS_PER_USER:
188 f4a66897 Christos Stavrakakis
        raise OverLimit('Network count limit exceeded for your account.')
189 f4a66897 Christos Stavrakakis
190 6eed1ede Christos Stavrakakis
    cidr_block = int(subnet.split('/')[1])
191 b14725eb Christos Stavrakakis
    if not util.validate_network_size(cidr_block):
192 b14725eb Christos Stavrakakis
        raise OverLimit("Unsupported network size.")
193 6dd70a5c Christos Stavrakakis
194 3165f027 Christos Stavrakakis
    try:
195 af6a3bc5 Christos Stavrakakis
        link, mac_prefix = util.net_resources(net_type)
196 3165f027 Christos Stavrakakis
        if not link:
197 3165f027 Christos Stavrakakis
            raise Exception("Can not create network. No connectivity link.")
198 3165f027 Christos Stavrakakis
199 3165f027 Christos Stavrakakis
        network = Network.objects.create(
200 3165f027 Christos Stavrakakis
                name=name,
201 3165f027 Christos Stavrakakis
                userid=request.user_uniq,
202 3165f027 Christos Stavrakakis
                subnet=subnet,
203 3165f027 Christos Stavrakakis
                subnet6=subnet6,
204 3165f027 Christos Stavrakakis
                gateway=gateway,
205 3165f027 Christos Stavrakakis
                gateway6=gateway6,
206 3165f027 Christos Stavrakakis
                dhcp=dhcp,
207 af6a3bc5 Christos Stavrakakis
                type=net_type,
208 3165f027 Christos Stavrakakis
                link=link,
209 af6a3bc5 Christos Stavrakakis
                mac_prefix=mac_prefix,
210 1cf6ac86 Christos Stavrakakis
                action='CREATE',
211 3165f027 Christos Stavrakakis
                state='PENDING')
212 03992c72 Christos Stavrakakis
    except EmptyPool:
213 5e1d07d4 Christos Stavrakakis
        log.error("Failed to allocate resources for network of type: %s",
214 5e1d07d4 Christos Stavrakakis
                  net_type)
215 5e1d07d4 Christos Stavrakakis
        raise ServiceUnavailable("Failed to allocate resources for network")
216 5061546f Christos Stavrakakis
217 7cfbbf32 Christos Stavrakakis
    # Create BackendNetwork entries for each Backend
218 7cfbbf32 Christos Stavrakakis
    network.create_backend_network()
219 7cfbbf32 Christos Stavrakakis
220 7cfbbf32 Christos Stavrakakis
    # Create the network in the actual backends
221 87994836 Christos Stavrakakis
    backend.create_network(network)
222 ce55f211 Kostas Papadimitriou
223 4b3b8688 Giorgos Verigakis
    networkdict = network_to_dict(network, request.user_uniq)
224 0269afd6 Giorgos Verigakis
    return render_network(request, networkdict, status=202)
225 0269afd6 Giorgos Verigakis
226 6ef51e9f Giorgos Verigakis
227 b36f78fa Giorgos Verigakis
@util.api_method('GET')
228 b19653d1 Giorgos Verigakis
def get_network_details(request, network_id):
229 0269afd6 Giorgos Verigakis
    # Normal Response Codes: 200, 203
230 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
231 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
232 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
233 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
234 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
235 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
236 ce55f211 Kostas Papadimitriou
237 0c37a721 Christos Stavrakakis
    log.debug('get_network_details %s', network_id)
238 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
239 4b3b8688 Giorgos Verigakis
    netdict = network_to_dict(net, request.user_uniq)
240 0269afd6 Giorgos Verigakis
    return render_network(request, netdict)
241 0269afd6 Giorgos Verigakis
242 6ef51e9f Giorgos Verigakis
243 b36f78fa Giorgos Verigakis
@util.api_method('PUT')
244 b19653d1 Giorgos Verigakis
def update_network_name(request, network_id):
245 0269afd6 Giorgos Verigakis
    # Normal Response Code: 204
246 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
247 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
248 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
249 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
250 17c2ed57 Christos Stavrakakis
    #                       forbidden (403)
251 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
252 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
253 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
254 aa197ee4 Vangelis Koukis
255 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
256 bf5c82dc Christos Stavrakakis
    log.info('update_network_name %s', network_id)
257 ce55f211 Kostas Papadimitriou
258 0269afd6 Giorgos Verigakis
    try:
259 0269afd6 Giorgos Verigakis
        name = req['network']['name']
260 0269afd6 Giorgos Verigakis
    except (TypeError, KeyError):
261 0269afd6 Giorgos Verigakis
        raise BadRequest('Malformed request.')
262 0269afd6 Giorgos Verigakis
263 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
264 207b70d5 Giorgos Verigakis
    if net.public:
265 17c2ed57 Christos Stavrakakis
        raise Forbidden('Can not rename the public network.')
266 22a9959d Christos Stavrakakis
    if net.deleted:
267 22a9959d Christos Stavrakakis
        raise Network.DeletedError
268 0269afd6 Giorgos Verigakis
    net.name = name
269 0269afd6 Giorgos Verigakis
    net.save()
270 0269afd6 Giorgos Verigakis
    return HttpResponse(status=204)
271 0269afd6 Giorgos Verigakis
272 6ef51e9f Giorgos Verigakis
273 b36f78fa Giorgos Verigakis
@util.api_method('DELETE')
274 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
275 b19653d1 Giorgos Verigakis
def delete_network(request, network_id):
276 0269afd6 Giorgos Verigakis
    # Normal Response Code: 204
277 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
278 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
279 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
280 17c2ed57 Christos Stavrakakis
    #                       forbidden (403)
281 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
282 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
283 ce55f211 Kostas Papadimitriou
284 bf5c82dc Christos Stavrakakis
    log.info('delete_network %s', network_id)
285 d2e73c0c Christos Stavrakakis
    net = util.get_network(network_id, request.user_uniq, for_update=True)
286 207b70d5 Giorgos Verigakis
    if net.public:
287 17c2ed57 Christos Stavrakakis
        raise Forbidden('Can not delete the public network.')
288 5061546f Christos Stavrakakis
289 22a9959d Christos Stavrakakis
    if net.deleted:
290 22a9959d Christos Stavrakakis
        raise Network.DeletedError
291 22a9959d Christos Stavrakakis
292 0196d9a3 Christos Stavrakakis
    if net.machines.all():  # Nics attached on network
293 0196d9a3 Christos Stavrakakis
        raise NetworkInUse('Machines are connected to network.')
294 0196d9a3 Christos Stavrakakis
295 22a9959d Christos Stavrakakis
296 5061546f Christos Stavrakakis
    net.action = 'DESTROY'
297 5061546f Christos Stavrakakis
    net.save()
298 5061546f Christos Stavrakakis
299 64938cb0 Giorgos Verigakis
    backend.delete_network(net)
300 0269afd6 Giorgos Verigakis
    return HttpResponse(status=204)
301 0269afd6 Giorgos Verigakis
302 6ef51e9f Giorgos Verigakis
303 b36f78fa Giorgos Verigakis
@util.api_method('POST')
304 b19653d1 Giorgos Verigakis
def network_action(request, network_id):
305 9e98ba3c Giorgos Verigakis
    req = util.get_request_dict(request)
306 0c37a721 Christos Stavrakakis
    log.debug('network_action %s %s', network_id, req)
307 9e98ba3c Giorgos Verigakis
    if len(req) != 1:
308 9e98ba3c Giorgos Verigakis
        raise BadRequest('Malformed request.')
309 ce55f211 Kostas Papadimitriou
310 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
311 207b70d5 Giorgos Verigakis
    if net.public:
312 17c2ed57 Christos Stavrakakis
        raise Forbidden('Can not modify the public network.')
313 22a9959d Christos Stavrakakis
    if net.deleted:
314 22a9959d Christos Stavrakakis
        raise Network.DeletedError
315 ce55f211 Kostas Papadimitriou
316 0269afd6 Giorgos Verigakis
    try:
317 e221ade2 Christos Stavrakakis
        key = req.keys()[0]
318 e221ade2 Christos Stavrakakis
        val = req[key]
319 0269afd6 Giorgos Verigakis
        assert isinstance(val, dict)
320 0269afd6 Giorgos Verigakis
        return network_actions[key](request, net, req[key])
321 0269afd6 Giorgos Verigakis
    except KeyError:
322 0269afd6 Giorgos Verigakis
        raise BadRequest('Unknown action.')
323 0269afd6 Giorgos Verigakis
    except AssertionError:
324 0269afd6 Giorgos Verigakis
        raise BadRequest('Invalid argument.')