Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / actions.py @ bb54871d

History | View | Annotate | Download (11.7 kB)

1 adee02b8 Giorgos Verigakis
# Copyright 2011 GRNET S.A. All rights reserved.
2 adee02b8 Giorgos Verigakis
# 
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 adee02b8 Giorgos Verigakis
# 
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 adee02b8 Giorgos Verigakis
# 
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 adee02b8 Giorgos Verigakis
# 
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 adee02b8 Giorgos Verigakis
# 
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 b016b476 Giorgos Verigakis
34 aea3e7c6 Vangelis Koukis
from socket import getfqdn
35 1f092444 Faidon Liambotis
from vncauthproxy.client import request_forwarding as request_vnc_forwarding
36 aea3e7c6 Vangelis Koukis
37 b016b476 Giorgos Verigakis
from django.conf import settings
38 b016b476 Giorgos Verigakis
from django.http import HttpResponse
39 09471611 Vangelis Koukis
from django.template.loader import render_to_string
40 09471611 Vangelis Koukis
from django.utils import simplejson as json
41 b016b476 Giorgos Verigakis
42 529178b1 Giorgos Verigakis
from synnefo.api.faults import BadRequest, ServiceUnavailable
43 64938cb0 Giorgos Verigakis
from synnefo.api.util import random_password, get_vm
44 26563957 Giorgos Verigakis
from synnefo.db.models import NetworkInterface
45 64938cb0 Giorgos Verigakis
from synnefo.logic import backend
46 20a51b1e Giorgos Verigakis
from synnefo.logic.utils import get_rsapi_state
47 d8e50a39 Giorgos Verigakis
48 0971fa71 Markos Gogoulos
49 b016b476 Giorgos Verigakis
server_actions = {}
50 e2ee7808 Giorgos Verigakis
network_actions = {}
51 b016b476 Giorgos Verigakis
52 b016b476 Giorgos Verigakis
53 b016b476 Giorgos Verigakis
def server_action(name):
54 d8e50a39 Giorgos Verigakis
    '''Decorator for functions implementing server actions.
55 529178b1 Giorgos Verigakis
    `name` is the key in the dict passed by the client.
56 d8e50a39 Giorgos Verigakis
    '''
57 aa197ee4 Vangelis Koukis
58 b016b476 Giorgos Verigakis
    def decorator(func):
59 b016b476 Giorgos Verigakis
        server_actions[name] = func
60 b016b476 Giorgos Verigakis
        return func
61 b016b476 Giorgos Verigakis
    return decorator
62 b016b476 Giorgos Verigakis
63 e2ee7808 Giorgos Verigakis
def network_action(name):
64 e2ee7808 Giorgos Verigakis
    '''Decorator for functions implementing network actions.
65 e2ee7808 Giorgos Verigakis
    `name` is the key in the dict passed by the client.
66 e2ee7808 Giorgos Verigakis
    '''
67 e2ee7808 Giorgos Verigakis
68 e2ee7808 Giorgos Verigakis
    def decorator(func):
69 e2ee7808 Giorgos Verigakis
        network_actions[name] = func
70 e2ee7808 Giorgos Verigakis
        return func
71 e2ee7808 Giorgos Verigakis
    return decorator
72 e2ee7808 Giorgos Verigakis
73 b016b476 Giorgos Verigakis
74 b016b476 Giorgos Verigakis
@server_action('changePassword')
75 20a51b1e Giorgos Verigakis
def change_password(request, vm, args):
76 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
77 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
78 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
79 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
80 b016b476 Giorgos Verigakis
    #                       badRequest (400),
81 b016b476 Giorgos Verigakis
    #                       badMediaType(415),
82 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
83 b016b476 Giorgos Verigakis
    #                       buildInProgress (409),
84 b016b476 Giorgos Verigakis
    #                       overLimit (413)
85 aa197ee4 Vangelis Koukis
86 b016b476 Giorgos Verigakis
    try:
87 529178b1 Giorgos Verigakis
        password = args['adminPass']
88 b016b476 Giorgos Verigakis
    except KeyError:
89 529178b1 Giorgos Verigakis
        raise BadRequest('Malformed request.')
90 b016b476 Giorgos Verigakis
91 529178b1 Giorgos Verigakis
    raise ServiceUnavailable('Changing password is not supported.')
92 b016b476 Giorgos Verigakis
93 b016b476 Giorgos Verigakis
@server_action('reboot')
94 20a51b1e Giorgos Verigakis
def reboot(request, vm, args):
95 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
96 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
97 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
98 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
99 b016b476 Giorgos Verigakis
    #                       badRequest (400),
100 b016b476 Giorgos Verigakis
    #                       badMediaType(415),
101 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
102 b016b476 Giorgos Verigakis
    #                       buildInProgress (409),
103 b016b476 Giorgos Verigakis
    #                       overLimit (413)
104 aa197ee4 Vangelis Koukis
105 0971fa71 Markos Gogoulos
    reboot_type = args.get('type', '')
106 0971fa71 Markos Gogoulos
    if reboot_type not in ('SOFT', 'HARD'):
107 529178b1 Giorgos Verigakis
        raise BadRequest('Malformed Request.')
108 64938cb0 Giorgos Verigakis
    backend.reboot_instance(vm, reboot_type.lower())
109 b016b476 Giorgos Verigakis
    return HttpResponse(status=202)
110 b016b476 Giorgos Verigakis
111 b016b476 Giorgos Verigakis
@server_action('start')
112 20a51b1e Giorgos Verigakis
def start(request, vm, args):
113 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
114 d8e50a39 Giorgos Verigakis
    # Error Response Codes: serviceUnavailable (503),
115 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404)
116 aa197ee4 Vangelis Koukis
117 529178b1 Giorgos Verigakis
    if args:
118 529178b1 Giorgos Verigakis
        raise BadRequest('Malformed Request.')
119 64938cb0 Giorgos Verigakis
    backend.startup_instance(vm)
120 b016b476 Giorgos Verigakis
    return HttpResponse(status=202)
121 b016b476 Giorgos Verigakis
122 b016b476 Giorgos Verigakis
@server_action('shutdown')
123 20a51b1e Giorgos Verigakis
def shutdown(request, vm, args):
124 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
125 d8e50a39 Giorgos Verigakis
    # Error Response Codes: serviceUnavailable (503),
126 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404)
127 aa197ee4 Vangelis Koukis
128 529178b1 Giorgos Verigakis
    if args:
129 529178b1 Giorgos Verigakis
        raise BadRequest('Malformed Request.')
130 64938cb0 Giorgos Verigakis
    backend.shutdown_instance(vm)
131 b016b476 Giorgos Verigakis
    return HttpResponse(status=202)
132 b016b476 Giorgos Verigakis
133 b016b476 Giorgos Verigakis
@server_action('rebuild')
134 20a51b1e Giorgos Verigakis
def rebuild(request, vm, args):
135 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
136 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
137 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
138 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
139 b016b476 Giorgos Verigakis
    #                       badRequest (400),
140 b016b476 Giorgos Verigakis
    #                       badMediaType(415),
141 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
142 b016b476 Giorgos Verigakis
    #                       buildInProgress (409),
143 b016b476 Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
144 b016b476 Giorgos Verigakis
    #                       overLimit (413)
145 b016b476 Giorgos Verigakis
146 529178b1 Giorgos Verigakis
    raise ServiceUnavailable('Rebuild not supported.')
147 b016b476 Giorgos Verigakis
148 b016b476 Giorgos Verigakis
@server_action('resize')
149 20a51b1e Giorgos Verigakis
def resize(request, vm, args):
150 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
151 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
152 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
153 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
154 b016b476 Giorgos Verigakis
    #                       badRequest (400),
155 b016b476 Giorgos Verigakis
    #                       badMediaType(415),
156 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
157 b016b476 Giorgos Verigakis
    #                       buildInProgress (409),
158 b016b476 Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
159 b016b476 Giorgos Verigakis
    #                       overLimit (413),
160 b016b476 Giorgos Verigakis
    #                       resizeNotAllowed (403)
161 aa197ee4 Vangelis Koukis
162 529178b1 Giorgos Verigakis
    raise ServiceUnavailable('Resize not supported.')
163 b016b476 Giorgos Verigakis
164 b016b476 Giorgos Verigakis
@server_action('confirmResize')
165 20a51b1e Giorgos Verigakis
def confirm_resize(request, vm, args):
166 b016b476 Giorgos Verigakis
    # Normal Response Code: 204
167 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
168 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
169 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
170 b016b476 Giorgos Verigakis
    #                       badRequest (400),
171 b016b476 Giorgos Verigakis
    #                       badMediaType(415),
172 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
173 b016b476 Giorgos Verigakis
    #                       buildInProgress (409),
174 b016b476 Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
175 b016b476 Giorgos Verigakis
    #                       overLimit (413),
176 b016b476 Giorgos Verigakis
    #                       resizeNotAllowed (403)
177 aa197ee4 Vangelis Koukis
178 529178b1 Giorgos Verigakis
    raise ServiceUnavailable('Resize not supported.')
179 b016b476 Giorgos Verigakis
180 b016b476 Giorgos Verigakis
@server_action('revertResize')
181 20a51b1e Giorgos Verigakis
def revert_resize(request, vm, args):
182 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
183 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
184 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
185 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
186 b016b476 Giorgos Verigakis
    #                       badRequest (400),
187 b016b476 Giorgos Verigakis
    #                       badMediaType(415),
188 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
189 b016b476 Giorgos Verigakis
    #                       buildInProgress (409),
190 b016b476 Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
191 b016b476 Giorgos Verigakis
    #                       overLimit (413),
192 b016b476 Giorgos Verigakis
    #                       resizeNotAllowed (403)
193 b016b476 Giorgos Verigakis
194 529178b1 Giorgos Verigakis
    raise ServiceUnavailable('Resize not supported.')
195 529178b1 Giorgos Verigakis
196 529178b1 Giorgos Verigakis
@server_action('console')
197 529178b1 Giorgos Verigakis
def get_console(request, vm, args):
198 529178b1 Giorgos Verigakis
    """Arrange for an OOB console of the specified type
199 529178b1 Giorgos Verigakis

200 529178b1 Giorgos Verigakis
    This method arranges for an OOB console of the specified type.
201 529178b1 Giorgos Verigakis
    Only consoles of type "vnc" are supported for now.
202 529178b1 Giorgos Verigakis

203 529178b1 Giorgos Verigakis
    It uses a running instance of vncauthproxy to setup proper
204 529178b1 Giorgos Verigakis
    VNC forwarding with a random password, then returns the necessary
205 529178b1 Giorgos Verigakis
    VNC connection info to the caller.
206 71099804 Vangelis Koukis

207 529178b1 Giorgos Verigakis
    """
208 529178b1 Giorgos Verigakis
    # Normal Response Code: 200
209 529178b1 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
210 529178b1 Giorgos Verigakis
    #                       serviceUnavailable (503),
211 529178b1 Giorgos Verigakis
    #                       unauthorized (401),
212 529178b1 Giorgos Verigakis
    #                       badRequest (400),
213 529178b1 Giorgos Verigakis
    #                       badMediaType(415),
214 529178b1 Giorgos Verigakis
    #                       itemNotFound (404),
215 529178b1 Giorgos Verigakis
    #                       buildInProgress (409),
216 529178b1 Giorgos Verigakis
    #                       overLimit (413)
217 aa197ee4 Vangelis Koukis
218 529178b1 Giorgos Verigakis
    console_type = args.get('type', '')
219 529178b1 Giorgos Verigakis
    if console_type != 'vnc':
220 529178b1 Giorgos Verigakis
        raise BadRequest('Type can only be "vnc".')
221 529178b1 Giorgos Verigakis
222 529178b1 Giorgos Verigakis
    # Use RAPI to get VNC console information for this instance
223 529178b1 Giorgos Verigakis
    if get_rsapi_state(vm) != 'ACTIVE':
224 529178b1 Giorgos Verigakis
        raise BadRequest('Server not in ACTIVE state.')
225 aa197ee4 Vangelis Koukis
226 529178b1 Giorgos Verigakis
    if settings.TEST:
227 529178b1 Giorgos Verigakis
        console_data = {'kind': 'vnc', 'host': 'ganeti_node', 'port': 1000}
228 529178b1 Giorgos Verigakis
    else:
229 64938cb0 Giorgos Verigakis
        console_data = backend.get_instance_console(vm)
230 aa197ee4 Vangelis Koukis
231 529178b1 Giorgos Verigakis
    if console_data['kind'] != 'vnc':
232 71099804 Vangelis Koukis
        message = 'got console of kind %s, not "vnc"' % console_data['kind']
233 b36f78fa Giorgos Verigakis
        raise ServiceUnavailable(message)
234 aa197ee4 Vangelis Koukis
235 529178b1 Giorgos Verigakis
    # Let vncauthproxy decide on the source port.
236 529178b1 Giorgos Verigakis
    # The alternative: static allocation, e.g.
237 529178b1 Giorgos Verigakis
    # sport = console_data['port'] - 1000
238 529178b1 Giorgos Verigakis
    sport = 0
239 529178b1 Giorgos Verigakis
    daddr = console_data['host']
240 529178b1 Giorgos Verigakis
    dport = console_data['port']
241 529178b1 Giorgos Verigakis
    password = random_password()
242 aa197ee4 Vangelis Koukis
243 71099804 Vangelis Koukis
    if settings.TEST:
244 71099804 Vangelis Koukis
        fwd = {'source_port': 1234, 'status': 'OK'}
245 71099804 Vangelis Koukis
    else:
246 71099804 Vangelis Koukis
        fwd = request_vnc_forwarding(sport, daddr, dport, password)
247 529178b1 Giorgos Verigakis
248 529178b1 Giorgos Verigakis
    if fwd['status'] != "OK":
249 71099804 Vangelis Koukis
        raise ServiceUnavailable('vncauthproxy returned error status')
250 aa197ee4 Vangelis Koukis
251 bb54871d Stratos Psomadakis
    # Verify that the VNC server settings haven't changed
252 bb54871d Stratos Psomadakis
    if not settings.TEST:
253 bb54871d Stratos Psomadakis
        if console_data != backend.get_instance_console(vm):
254 bb54871d Stratos Psomadakis
            raise ServiceUnavailable('VNC Server settings changed.')
255 bb54871d Stratos Psomadakis
256 529178b1 Giorgos Verigakis
    console = {
257 529178b1 Giorgos Verigakis
        'type': 'vnc',
258 529178b1 Giorgos Verigakis
        'host': getfqdn(),
259 529178b1 Giorgos Verigakis
        'port': fwd['source_port'],
260 529178b1 Giorgos Verigakis
        'password': password}
261 aa197ee4 Vangelis Koukis
262 529178b1 Giorgos Verigakis
    if request.serialization == 'xml':
263 529178b1 Giorgos Verigakis
        mimetype = 'application/xml'
264 529178b1 Giorgos Verigakis
        data = render_to_string('console.xml', {'console': console})
265 529178b1 Giorgos Verigakis
    else:
266 529178b1 Giorgos Verigakis
        mimetype = 'application/json'
267 529178b1 Giorgos Verigakis
        data = json.dumps({'console': console})
268 aa197ee4 Vangelis Koukis
269 529178b1 Giorgos Verigakis
    return HttpResponse(data, mimetype=mimetype, status=200)
270 e2ee7808 Giorgos Verigakis
271 91826390 Giorgos Verigakis
@server_action('firewallProfile')
272 91826390 Giorgos Verigakis
def set_firewall_profile(request, vm, args):
273 26563957 Giorgos Verigakis
    # Normal Response Code: 200
274 26563957 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
275 26563957 Giorgos Verigakis
    #                       serviceUnavailable (503),
276 26563957 Giorgos Verigakis
    #                       unauthorized (401),
277 26563957 Giorgos Verigakis
    #                       badRequest (400),
278 26563957 Giorgos Verigakis
    #                       badMediaType(415),
279 26563957 Giorgos Verigakis
    #                       itemNotFound (404),
280 26563957 Giorgos Verigakis
    #                       buildInProgress (409),
281 26563957 Giorgos Verigakis
    #                       overLimit (413)
282 26563957 Giorgos Verigakis
    
283 91826390 Giorgos Verigakis
    profile = args.get('profile', '')
284 26563957 Giorgos Verigakis
    if profile not in [x[0] for x in NetworkInterface.FIREWALL_PROFILES]:
285 91826390 Giorgos Verigakis
        raise BadRequest("Unsupported firewall profile")
286 91826390 Giorgos Verigakis
    backend.set_firewall_profile(vm, profile)
287 91826390 Giorgos Verigakis
    return HttpResponse(status=202)
288 91826390 Giorgos Verigakis
289 e2ee7808 Giorgos Verigakis
290 e2ee7808 Giorgos Verigakis
@network_action('add')
291 e2ee7808 Giorgos Verigakis
def add(request, net, args):
292 13b954b0 Giorgos Verigakis
    # Normal Response Code: 202
293 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
294 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
295 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
296 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
297 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
298 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
299 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
300 aa197ee4 Vangelis Koukis
301 dca6520b Giorgos Verigakis
    server_id = args.get('serverRef', None)
302 e2ee7808 Giorgos Verigakis
    if not server_id:
303 e2ee7808 Giorgos Verigakis
        raise BadRequest('Malformed Request.')
304 4b3b8688 Giorgos Verigakis
    vm = get_vm(server_id, request.user_uniq)
305 64938cb0 Giorgos Verigakis
    backend.connect_to_network(vm, net)
306 5509b599 Giorgos Verigakis
    vm.save()
307 d44c236b Giorgos Verigakis
    net.save()
308 e2ee7808 Giorgos Verigakis
    return HttpResponse(status=202)
309 e2ee7808 Giorgos Verigakis
310 e2ee7808 Giorgos Verigakis
@network_action('remove')
311 e2ee7808 Giorgos Verigakis
def remove(request, net, args):
312 13b954b0 Giorgos Verigakis
    # Normal Response Code: 202
313 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
314 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
315 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
316 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
317 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
318 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
319 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
320 aa197ee4 Vangelis Koukis
321 dca6520b Giorgos Verigakis
    server_id = args.get('serverRef', None)
322 e2ee7808 Giorgos Verigakis
    if not server_id:
323 e2ee7808 Giorgos Verigakis
        raise BadRequest('Malformed Request.')
324 4b3b8688 Giorgos Verigakis
    vm = get_vm(server_id, request.user_uniq)
325 64938cb0 Giorgos Verigakis
    backend.disconnect_from_network(vm, net)
326 5509b599 Giorgos Verigakis
    vm.save()
327 d44c236b Giorgos Verigakis
    net.save()
328 e2ee7808 Giorgos Verigakis
    return HttpResponse(status=202)