Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (12.1 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
35 ce55f211 Kostas Papadimitriou
from django.conf import settings
36 b3fd98ae Christos Stavrakakis
from django.conf.urls.defaults import patterns
37 4dba0480 Christos Stavrakakis
from django.db import transaction
38 b3fd98ae Christos Stavrakakis
from django.db.models import Q
39 0269afd6 Giorgos Verigakis
from django.http import HttpResponse
40 69d6d7dd Giorgos Verigakis
from django.template.loader import render_to_string
41 0269afd6 Giorgos Verigakis
from django.utils import simplejson as json
42 0269afd6 Giorgos Verigakis
43 b3fd98ae Christos Stavrakakis
from snf_django.lib import api
44 b3fd98ae Christos Stavrakakis
from snf_django.lib.api import faults, utils
45 5061546f Christos Stavrakakis
from synnefo.api import util
46 b36f78fa Giorgos Verigakis
from synnefo.api.actions import network_actions
47 77f45438 Christos Stavrakakis
from synnefo import quotas
48 03992c72 Christos Stavrakakis
from synnefo.db.models import Network
49 99af08a4 Christos Stavrakakis
from synnefo.db.utils import validate_mac
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 b3fd98ae Christos Stavrakakis
from logging import getLogger
55 b3fd98ae Christos Stavrakakis
log = getLogger(__name__)
56 b36f78fa Giorgos Verigakis
57 e440e835 Christos Stavrakakis
urlpatterns = patterns(
58 e440e835 Christos Stavrakakis
    'synnefo.api.networks',
59 0269afd6 Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
60 0269afd6 Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_networks', {'detail': True}),
61 f4fe8796 Giorgos Verigakis
    (r'^/(\w+)(?:.json|.xml)?$', 'network_demux'),
62 f4fe8796 Giorgos Verigakis
    (r'^/(\w+)/action(?:.json|.xml)?$', 'network_action'),
63 0269afd6 Giorgos Verigakis
)
64 0269afd6 Giorgos Verigakis
65 0269afd6 Giorgos Verigakis
66 0269afd6 Giorgos Verigakis
def demux(request):
67 0269afd6 Giorgos Verigakis
    if request.method == 'GET':
68 0269afd6 Giorgos Verigakis
        return list_networks(request)
69 0269afd6 Giorgos Verigakis
    elif request.method == 'POST':
70 0269afd6 Giorgos Verigakis
        return create_network(request)
71 0269afd6 Giorgos Verigakis
    else:
72 b3fd98ae Christos Stavrakakis
        return api.method_not_allowed(request)
73 0269afd6 Giorgos Verigakis
74 6ef51e9f Giorgos Verigakis
75 b19653d1 Giorgos Verigakis
def network_demux(request, network_id):
76 0269afd6 Giorgos Verigakis
    if request.method == 'GET':
77 b19653d1 Giorgos Verigakis
        return get_network_details(request, network_id)
78 0269afd6 Giorgos Verigakis
    elif request.method == 'PUT':
79 b19653d1 Giorgos Verigakis
        return update_network_name(request, network_id)
80 0269afd6 Giorgos Verigakis
    elif request.method == 'DELETE':
81 b19653d1 Giorgos Verigakis
        return delete_network(request, network_id)
82 0269afd6 Giorgos Verigakis
    else:
83 b3fd98ae Christos Stavrakakis
        return api.method_not_allowed(request)
84 0269afd6 Giorgos Verigakis
85 0269afd6 Giorgos Verigakis
86 6ef51e9f Giorgos Verigakis
def network_to_dict(network, user_id, detail=True):
87 7fede91e Christos Stavrakakis
    d = {'id': str(network.id), 'name': network.name}
88 0269afd6 Giorgos Verigakis
    if detail:
89 08b079e2 Stavros Sachtouris
        d['cidr'] = network.subnet
90 cc3f266e Christos Stavrakakis
        d['cidr6'] = network.subnet6
91 08b079e2 Stavros Sachtouris
        d['gateway'] = network.gateway
92 cc3f266e Christos Stavrakakis
        d['gateway6'] = network.gateway6
93 08b079e2 Stavros Sachtouris
        d['dhcp'] = network.dhcp
94 b7d38981 Dimitris Aragiorgis
        d['type'] = network.flavor
95 b3fd98ae Christos Stavrakakis
        d['updated'] = utils.isoformat(network.updated)
96 b3fd98ae Christos Stavrakakis
        d['created'] = utils.isoformat(network.created)
97 d44c236b Giorgos Verigakis
        d['status'] = network.state
98 7fede91e Christos Stavrakakis
        d['public'] = network.public
99 08b079e2 Stavros Sachtouris
100 7fede91e Christos Stavrakakis
        attachments = [util.construct_nic_id(nic)
101 e440e835 Christos Stavrakakis
                       for nic in network.nics.filter(machine__userid=user_id)
102 939d71dd Christos Stavrakakis
                                              .filter(state="ACTIVE")
103 cd2b0bf5 Christos Stavrakakis
                                              .order_by('machine')]
104 5029ff36 Christos Stavrakakis
        d['attachments'] = attachments
105 0269afd6 Giorgos Verigakis
    return d
106 0269afd6 Giorgos Verigakis
107 6ef51e9f Giorgos Verigakis
108 0269afd6 Giorgos Verigakis
def render_network(request, networkdict, status=200):
109 0269afd6 Giorgos Verigakis
    if request.serialization == 'xml':
110 0269afd6 Giorgos Verigakis
        data = render_to_string('network.xml', {'network': networkdict})
111 0269afd6 Giorgos Verigakis
    else:
112 0269afd6 Giorgos Verigakis
        data = json.dumps({'network': networkdict})
113 0269afd6 Giorgos Verigakis
    return HttpResponse(data, status=status)
114 0269afd6 Giorgos Verigakis
115 0269afd6 Giorgos Verigakis
116 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
117 0269afd6 Giorgos Verigakis
def list_networks(request, detail=False):
118 0269afd6 Giorgos Verigakis
    # Normal Response Codes: 200, 203
119 0269afd6 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
120 0269afd6 Giorgos Verigakis
    #                       serviceUnavailable (503),
121 0269afd6 Giorgos Verigakis
    #                       unauthorized (401),
122 0269afd6 Giorgos Verigakis
    #                       badRequest (400),
123 0269afd6 Giorgos Verigakis
    #                       overLimit (413)
124 ce55f211 Kostas Papadimitriou
125 0c37a721 Christos Stavrakakis
    log.debug('list_networks detail=%s', detail)
126 b3fd98ae Christos Stavrakakis
    since = utils.isoparse(request.GET.get('changes-since'))
127 8b2515a9 Christos Stavrakakis
    user_networks = Network.objects.filter(Q(userid=request.user_uniq) |
128 3878553d Kostas Papadimitriou
                                           Q(public=True))
129 ce55f211 Kostas Papadimitriou
130 0269afd6 Giorgos Verigakis
    if since:
131 d44c236b Giorgos Verigakis
        user_networks = user_networks.filter(updated__gte=since)
132 0269afd6 Giorgos Verigakis
        if not user_networks:
133 0269afd6 Giorgos Verigakis
            return HttpResponse(status=304)
134 3878553d Kostas Papadimitriou
    else:
135 3878553d Kostas Papadimitriou
        user_networks = user_networks.filter(deleted=False)
136 ce55f211 Kostas Papadimitriou
137 4b3b8688 Giorgos Verigakis
    networks = [network_to_dict(network, request.user_uniq, detail)
138 cd2b0bf5 Christos Stavrakakis
                for network in user_networks.order_by('id')]
139 ce55f211 Kostas Papadimitriou
140 0269afd6 Giorgos Verigakis
    if request.serialization == 'xml':
141 b36f78fa Giorgos Verigakis
        data = render_to_string('list_networks.xml', {
142 b36f78fa Giorgos Verigakis
            'networks': networks,
143 b36f78fa Giorgos Verigakis
            'detail': detail})
144 0269afd6 Giorgos Verigakis
    else:
145 5029ff36 Christos Stavrakakis
        data = json.dumps({'networks': networks})
146 aa197ee4 Vangelis Koukis
147 0269afd6 Giorgos Verigakis
    return HttpResponse(data, status=200)
148 0269afd6 Giorgos Verigakis
149 6ef51e9f Giorgos Verigakis
150 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
151 d4993f77 Christos Stavrakakis
@transaction.commit_manually
152 2509ce17 Christos Stavrakakis
def create_network(request):
153 0269afd6 Giorgos Verigakis
    # Normal Response Code: 202
154 0269afd6 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
155 0269afd6 Giorgos Verigakis
    #                       serviceUnavailable (503),
156 0269afd6 Giorgos Verigakis
    #                       unauthorized (401),
157 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
158 0269afd6 Giorgos Verigakis
    #                       badRequest (400),
159 17c2ed57 Christos Stavrakakis
    #                       forbidden (403)
160 0269afd6 Giorgos Verigakis
    #                       overLimit (413)
161 aa197ee4 Vangelis Koukis
162 3165f027 Christos Stavrakakis
    try:
163 b3fd98ae Christos Stavrakakis
        req = utils.get_request_dict(request)
164 d4993f77 Christos Stavrakakis
        log.info('create_network %s', req)
165 d4993f77 Christos Stavrakakis
166 4e1133ab Christos Stavrakakis
        user_id = request.user_uniq
167 d4993f77 Christos Stavrakakis
        try:
168 d4993f77 Christos Stavrakakis
            d = req['network']
169 d4993f77 Christos Stavrakakis
            name = d['name']
170 4e1133ab Christos Stavrakakis
        except KeyError:
171 bd40abfa Christos Stavrakakis
            raise faults.BadRequest("Malformed request")
172 4e1133ab Christos Stavrakakis
173 4e1133ab Christos Stavrakakis
        # Get and validate flavor. Flavors are still exposed as 'type' in the
174 4e1133ab Christos Stavrakakis
        # API.
175 4e1133ab Christos Stavrakakis
        flavor = d.get("type", None)
176 4e1133ab Christos Stavrakakis
        if flavor is None:
177 bd40abfa Christos Stavrakakis
            raise faults.BadRequest("Missing request parameter 'type'")
178 4e1133ab Christos Stavrakakis
        elif flavor not in Network.FLAVORS.keys():
179 bd40abfa Christos Stavrakakis
            raise faults.BadRequest("Invalid network type '%s'" % flavor)
180 4e1133ab Christos Stavrakakis
        elif flavor not in settings.API_ENABLED_NETWORK_FLAVORS:
181 99af08a4 Christos Stavrakakis
            raise faults.Forbidden("Can not create network of type '%s'" %
182 99af08a4 Christos Stavrakakis
                                   flavor)
183 4e1133ab Christos Stavrakakis
184 4e1133ab Christos Stavrakakis
        public = d.get("public", False)
185 d4993f77 Christos Stavrakakis
        if public:
186 bd40abfa Christos Stavrakakis
            raise faults.Forbidden("Can not create a public network.")
187 d4993f77 Christos Stavrakakis
188 4e1133ab Christos Stavrakakis
        dhcp = d.get('dhcp', True)
189 d4993f77 Christos Stavrakakis
190 4e1133ab Christos Stavrakakis
        # Get and validate network parameters
191 4e1133ab Christos Stavrakakis
        subnet = d.get('cidr', '192.168.1.0/24')
192 4e1133ab Christos Stavrakakis
        subnet6 = d.get('cidr6', None)
193 4e1133ab Christos Stavrakakis
        gateway = d.get('gateway', None)
194 4e1133ab Christos Stavrakakis
        gateway6 = d.get('gateway6', None)
195 d368ec0c Christos Stavrakakis
        # Check that user provided a valid subnet
196 9ae613af Christos Stavrakakis
        util.validate_network_params(subnet, gateway, subnet6, gateway6)
197 d4993f77 Christos Stavrakakis
198 d4993f77 Christos Stavrakakis
        try:
199 d4993f77 Christos Stavrakakis
            mode, link, mac_prefix, tags = util.values_from_flavor(flavor)
200 99af08a4 Christos Stavrakakis
            validate_mac(mac_prefix + "0:00:00:00")
201 d4993f77 Christos Stavrakakis
            network = Network.objects.create(
202 e440e835 Christos Stavrakakis
                name=name,
203 e440e835 Christos Stavrakakis
                userid=user_id,
204 e440e835 Christos Stavrakakis
                subnet=subnet,
205 e440e835 Christos Stavrakakis
                subnet6=subnet6,
206 e440e835 Christos Stavrakakis
                gateway=gateway,
207 e440e835 Christos Stavrakakis
                gateway6=gateway6,
208 e440e835 Christos Stavrakakis
                dhcp=dhcp,
209 e440e835 Christos Stavrakakis
                flavor=flavor,
210 e440e835 Christos Stavrakakis
                mode=mode,
211 e440e835 Christos Stavrakakis
                link=link,
212 e440e835 Christos Stavrakakis
                mac_prefix=mac_prefix,
213 e440e835 Christos Stavrakakis
                tags=tags,
214 e440e835 Christos Stavrakakis
                action='CREATE',
215 99af08a4 Christos Stavrakakis
                state='ACTIVE')
216 d4993f77 Christos Stavrakakis
        except EmptyPool:
217 d4993f77 Christos Stavrakakis
            log.error("Failed to allocate resources for network of type: %s",
218 d4993f77 Christos Stavrakakis
                      flavor)
219 99af08a4 Christos Stavrakakis
            raise faults.ServiceUnavailable("Failed to allocate network"
220 99af08a4 Christos Stavrakakis
                                            " resources")
221 d4993f77 Christos Stavrakakis
222 2509ce17 Christos Stavrakakis
        # Issue commission to Quotaholder and accept it since at the end of
223 2509ce17 Christos Stavrakakis
        # this transaction the Network object will be created in the DB.
224 2509ce17 Christos Stavrakakis
        # Note: the following call does a commit!
225 2509ce17 Christos Stavrakakis
        quotas.issue_and_accept_commission(network)
226 d4993f77 Christos Stavrakakis
    except:
227 d4993f77 Christos Stavrakakis
        transaction.rollback()
228 e7a8d451 Christos Stavrakakis
        raise
229 d4993f77 Christos Stavrakakis
    else:
230 d4993f77 Christos Stavrakakis
        transaction.commit()
231 7cfbbf32 Christos Stavrakakis
232 4b3b8688 Giorgos Verigakis
    networkdict = network_to_dict(network, request.user_uniq)
233 77f45438 Christos Stavrakakis
    response = render_network(request, networkdict, status=202)
234 77f45438 Christos Stavrakakis
235 77f45438 Christos Stavrakakis
    return response
236 0269afd6 Giorgos Verigakis
237 6ef51e9f Giorgos Verigakis
238 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
239 b19653d1 Giorgos Verigakis
def get_network_details(request, network_id):
240 0269afd6 Giorgos Verigakis
    # Normal Response Codes: 200, 203
241 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
242 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
243 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
244 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
245 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
246 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
247 ce55f211 Kostas Papadimitriou
248 0c37a721 Christos Stavrakakis
    log.debug('get_network_details %s', network_id)
249 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
250 4b3b8688 Giorgos Verigakis
    netdict = network_to_dict(net, request.user_uniq)
251 0269afd6 Giorgos Verigakis
    return render_network(request, netdict)
252 0269afd6 Giorgos Verigakis
253 6ef51e9f Giorgos Verigakis
254 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
255 b19653d1 Giorgos Verigakis
def update_network_name(request, network_id):
256 0269afd6 Giorgos Verigakis
    # Normal Response Code: 204
257 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
258 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
259 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
260 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
261 17c2ed57 Christos Stavrakakis
    #                       forbidden (403)
262 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
263 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
264 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
265 aa197ee4 Vangelis Koukis
266 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
267 bf5c82dc Christos Stavrakakis
    log.info('update_network_name %s', network_id)
268 ce55f211 Kostas Papadimitriou
269 0269afd6 Giorgos Verigakis
    try:
270 0269afd6 Giorgos Verigakis
        name = req['network']['name']
271 0269afd6 Giorgos Verigakis
    except (TypeError, KeyError):
272 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Malformed request.')
273 0269afd6 Giorgos Verigakis
274 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
275 207b70d5 Giorgos Verigakis
    if net.public:
276 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Can not rename the public network.')
277 22a9959d Christos Stavrakakis
    if net.deleted:
278 05d401cf Christos Stavrakakis
        raise faults.BadRequest("Network has been deleted.")
279 0269afd6 Giorgos Verigakis
    net.name = name
280 0269afd6 Giorgos Verigakis
    net.save()
281 0269afd6 Giorgos Verigakis
    return HttpResponse(status=204)
282 0269afd6 Giorgos Verigakis
283 6ef51e9f Giorgos Verigakis
284 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
285 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
286 b19653d1 Giorgos Verigakis
def delete_network(request, network_id):
287 0269afd6 Giorgos Verigakis
    # Normal Response Code: 204
288 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
289 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
290 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
291 17c2ed57 Christos Stavrakakis
    #                       forbidden (403)
292 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
293 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
294 ce55f211 Kostas Papadimitriou
295 bf5c82dc Christos Stavrakakis
    log.info('delete_network %s', network_id)
296 d2e73c0c Christos Stavrakakis
    net = util.get_network(network_id, request.user_uniq, for_update=True)
297 207b70d5 Giorgos Verigakis
    if net.public:
298 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Can not delete the public network.')
299 5061546f Christos Stavrakakis
300 22a9959d Christos Stavrakakis
    if net.deleted:
301 05d401cf Christos Stavrakakis
        raise faults.BadRequest("Network has been deleted.")
302 22a9959d Christos Stavrakakis
303 0196d9a3 Christos Stavrakakis
    if net.machines.all():  # Nics attached on network
304 bd40abfa Christos Stavrakakis
        raise faults.NetworkInUse('Machines are connected to network.')
305 0196d9a3 Christos Stavrakakis
306 5061546f Christos Stavrakakis
    net.action = 'DESTROY'
307 5061546f Christos Stavrakakis
    net.save()
308 5061546f Christos Stavrakakis
309 99af08a4 Christos Stavrakakis
    backend_networks = net.backend_networks.exclude(operstate="DELETED")
310 99af08a4 Christos Stavrakakis
    for bnet in backend_networks:
311 99af08a4 Christos Stavrakakis
        backend.delete_network(net, bnet.backend)
312 27cda06b Christos Stavrakakis
    if not backend_networks:
313 27cda06b Christos Stavrakakis
        backend.update_network_state(net)
314 0269afd6 Giorgos Verigakis
    return HttpResponse(status=204)
315 0269afd6 Giorgos Verigakis
316 6ef51e9f Giorgos Verigakis
317 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
318 b19653d1 Giorgos Verigakis
def network_action(request, network_id):
319 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
320 0c37a721 Christos Stavrakakis
    log.debug('network_action %s %s', network_id, req)
321 9e98ba3c Giorgos Verigakis
    if len(req) != 1:
322 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Malformed request.')
323 ce55f211 Kostas Papadimitriou
324 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
325 207b70d5 Giorgos Verigakis
    if net.public:
326 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Can not modify the public network.')
327 22a9959d Christos Stavrakakis
    if net.deleted:
328 05d401cf Christos Stavrakakis
        raise faults.BadRequest("Network has been deleted.")
329 ce55f211 Kostas Papadimitriou
330 0269afd6 Giorgos Verigakis
    try:
331 e221ade2 Christos Stavrakakis
        key = req.keys()[0]
332 e221ade2 Christos Stavrakakis
        val = req[key]
333 0269afd6 Giorgos Verigakis
        assert isinstance(val, dict)
334 0269afd6 Giorgos Verigakis
        return network_actions[key](request, net, req[key])
335 0269afd6 Giorgos Verigakis
    except KeyError:
336 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Unknown action.')
337 0269afd6 Giorgos Verigakis
    except AssertionError:
338 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Invalid argument.')