Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (13 kB)

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

214 529178b1 Giorgos Verigakis
    This method arranges for an OOB console of the specified type.
215 529178b1 Giorgos Verigakis
    Only consoles of type "vnc" are supported for now.
216 529178b1 Giorgos Verigakis

217 529178b1 Giorgos Verigakis
    It uses a running instance of vncauthproxy to setup proper
218 529178b1 Giorgos Verigakis
    VNC forwarding with a random password, then returns the necessary
219 529178b1 Giorgos Verigakis
    VNC connection info to the caller.
220 71099804 Vangelis Koukis

221 529178b1 Giorgos Verigakis
    """
222 529178b1 Giorgos Verigakis
    # Normal Response Code: 200
223 529178b1 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
224 529178b1 Giorgos Verigakis
    #                       serviceUnavailable (503),
225 529178b1 Giorgos Verigakis
    #                       unauthorized (401),
226 529178b1 Giorgos Verigakis
    #                       badRequest (400),
227 529178b1 Giorgos Verigakis
    #                       badMediaType(415),
228 529178b1 Giorgos Verigakis
    #                       itemNotFound (404),
229 529178b1 Giorgos Verigakis
    #                       buildInProgress (409),
230 529178b1 Giorgos Verigakis
    #                       overLimit (413)
231 aa197ee4 Vangelis Koukis
232 bf5c82dc Christos Stavrakakis
    log.info("Get console  VM %s", vm)
233 bf5c82dc Christos Stavrakakis
234 529178b1 Giorgos Verigakis
    console_type = args.get('type', '')
235 529178b1 Giorgos Verigakis
    if console_type != 'vnc':
236 529178b1 Giorgos Verigakis
        raise BadRequest('Type can only be "vnc".')
237 529178b1 Giorgos Verigakis
238 529178b1 Giorgos Verigakis
    # Use RAPI to get VNC console information for this instance
239 529178b1 Giorgos Verigakis
    if get_rsapi_state(vm) != 'ACTIVE':
240 529178b1 Giorgos Verigakis
        raise BadRequest('Server not in ACTIVE state.')
241 aa197ee4 Vangelis Koukis
242 529178b1 Giorgos Verigakis
    if settings.TEST:
243 529178b1 Giorgos Verigakis
        console_data = {'kind': 'vnc', 'host': 'ganeti_node', 'port': 1000}
244 529178b1 Giorgos Verigakis
    else:
245 64938cb0 Giorgos Verigakis
        console_data = backend.get_instance_console(vm)
246 aa197ee4 Vangelis Koukis
247 529178b1 Giorgos Verigakis
    if console_data['kind'] != 'vnc':
248 71099804 Vangelis Koukis
        message = 'got console of kind %s, not "vnc"' % console_data['kind']
249 b36f78fa Giorgos Verigakis
        raise ServiceUnavailable(message)
250 aa197ee4 Vangelis Koukis
251 529178b1 Giorgos Verigakis
    # Let vncauthproxy decide on the source port.
252 529178b1 Giorgos Verigakis
    # The alternative: static allocation, e.g.
253 529178b1 Giorgos Verigakis
    # sport = console_data['port'] - 1000
254 529178b1 Giorgos Verigakis
    sport = 0
255 529178b1 Giorgos Verigakis
    daddr = console_data['host']
256 529178b1 Giorgos Verigakis
    dport = console_data['port']
257 529178b1 Giorgos Verigakis
    password = random_password()
258 aa197ee4 Vangelis Koukis
259 71099804 Vangelis Koukis
    if settings.TEST:
260 71099804 Vangelis Koukis
        fwd = {'source_port': 1234, 'status': 'OK'}
261 71099804 Vangelis Koukis
    else:
262 71099804 Vangelis Koukis
        fwd = request_vnc_forwarding(sport, daddr, dport, password)
263 529178b1 Giorgos Verigakis
264 529178b1 Giorgos Verigakis
    if fwd['status'] != "OK":
265 71099804 Vangelis Koukis
        raise ServiceUnavailable('vncauthproxy returned error status')
266 aa197ee4 Vangelis Koukis
267 bb54871d Stratos Psomadakis
    # Verify that the VNC server settings haven't changed
268 bb54871d Stratos Psomadakis
    if not settings.TEST:
269 bb54871d Stratos Psomadakis
        if console_data != backend.get_instance_console(vm):
270 bb54871d Stratos Psomadakis
            raise ServiceUnavailable('VNC Server settings changed.')
271 bb54871d Stratos Psomadakis
272 529178b1 Giorgos Verigakis
    console = {
273 529178b1 Giorgos Verigakis
        'type': 'vnc',
274 529178b1 Giorgos Verigakis
        'host': getfqdn(),
275 529178b1 Giorgos Verigakis
        'port': fwd['source_port'],
276 529178b1 Giorgos Verigakis
        'password': password}
277 aa197ee4 Vangelis Koukis
278 529178b1 Giorgos Verigakis
    if request.serialization == 'xml':
279 529178b1 Giorgos Verigakis
        mimetype = 'application/xml'
280 529178b1 Giorgos Verigakis
        data = render_to_string('console.xml', {'console': console})
281 529178b1 Giorgos Verigakis
    else:
282 529178b1 Giorgos Verigakis
        mimetype = 'application/json'
283 529178b1 Giorgos Verigakis
        data = json.dumps({'console': console})
284 aa197ee4 Vangelis Koukis
285 529178b1 Giorgos Verigakis
    return HttpResponse(data, mimetype=mimetype, status=200)
286 e2ee7808 Giorgos Verigakis
287 4dba0480 Christos Stavrakakis
288 91826390 Giorgos Verigakis
@server_action('firewallProfile')
289 91826390 Giorgos Verigakis
def set_firewall_profile(request, vm, args):
290 26563957 Giorgos Verigakis
    # Normal Response Code: 200
291 26563957 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
292 26563957 Giorgos Verigakis
    #                       serviceUnavailable (503),
293 26563957 Giorgos Verigakis
    #                       unauthorized (401),
294 26563957 Giorgos Verigakis
    #                       badRequest (400),
295 26563957 Giorgos Verigakis
    #                       badMediaType(415),
296 26563957 Giorgos Verigakis
    #                       itemNotFound (404),
297 26563957 Giorgos Verigakis
    #                       buildInProgress (409),
298 26563957 Giorgos Verigakis
    #                       overLimit (413)
299 4dba0480 Christos Stavrakakis
300 91826390 Giorgos Verigakis
    profile = args.get('profile', '')
301 bf5c82dc Christos Stavrakakis
    log.info("Set VM %s firewall %s", vm, profile)
302 26563957 Giorgos Verigakis
    if profile not in [x[0] for x in NetworkInterface.FIREWALL_PROFILES]:
303 91826390 Giorgos Verigakis
        raise BadRequest("Unsupported firewall profile")
304 91826390 Giorgos Verigakis
    backend.set_firewall_profile(vm, profile)
305 91826390 Giorgos Verigakis
    return HttpResponse(status=202)
306 91826390 Giorgos Verigakis
307 e2ee7808 Giorgos Verigakis
308 e2ee7808 Giorgos Verigakis
@network_action('add')
309 77f0fa63 Christos Stavrakakis
@transaction.commit_on_success
310 e2ee7808 Giorgos Verigakis
def add(request, net, args):
311 13b954b0 Giorgos Verigakis
    # Normal Response Code: 202
312 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
313 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
314 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
315 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
316 57986639 Christos Stavrakakis
    #                       buildInProgress (409),
317 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
318 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
319 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
320 aa197ee4 Vangelis Koukis
321 e221ade2 Christos Stavrakakis
    if net.state != 'ACTIVE':
322 57986639 Christos Stavrakakis
        raise BuildInProgress('Network not active yet')
323 e221ade2 Christos Stavrakakis
324 dca6520b Giorgos Verigakis
    server_id = args.get('serverRef', None)
325 e2ee7808 Giorgos Verigakis
    if not server_id:
326 e2ee7808 Giorgos Verigakis
        raise BadRequest('Malformed Request.')
327 bf5c82dc Christos Stavrakakis
328 e221ade2 Christos Stavrakakis
    vm = get_vm(server_id, request.user_uniq, non_suspended=True)
329 8d03316d Dimitris Aragiorgis
330 87920bc3 Christos Stavrakakis
    address = None
331 87920bc3 Christos Stavrakakis
    if net.dhcp:
332 87920bc3 Christos Stavrakakis
        # Get a free IP from the address pool.
333 87920bc3 Christos Stavrakakis
        try:
334 87920bc3 Christos Stavrakakis
            address = get_network_free_address(net)
335 87920bc3 Christos Stavrakakis
        except EmptyPool:
336 57986639 Christos Stavrakakis
            raise OverLimit('Network is full')
337 77f0fa63 Christos Stavrakakis
338 bf5c82dc Christos Stavrakakis
    log.info("Connecting VM %s to Network %s(%s)", vm, net, address)
339 bf5c82dc Christos Stavrakakis
340 77f0fa63 Christos Stavrakakis
    backend.connect_to_network(vm, net, address)
341 e2ee7808 Giorgos Verigakis
    return HttpResponse(status=202)
342 e2ee7808 Giorgos Verigakis
343 77f0fa63 Christos Stavrakakis
344 e2ee7808 Giorgos Verigakis
@network_action('remove')
345 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
346 e2ee7808 Giorgos Verigakis
def remove(request, net, args):
347 13b954b0 Giorgos Verigakis
    # Normal Response Code: 202
348 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
349 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
350 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
351 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
352 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
353 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
354 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
355 aa197ee4 Vangelis Koukis
356 4dba0480 Christos Stavrakakis
    try:  # attachment string: nic-<vm-id>-<nic-index>
357 08b079e2 Stavros Sachtouris
        server_id = args.get('attachment', None).split('-')[1]
358 08b079e2 Stavros Sachtouris
        nic_index = args.get('attachment', None).split('-')[2]
359 99a74636 Christos Stavrakakis
    except AttributeError:
360 99a74636 Christos Stavrakakis
        raise BadRequest("Malformed Request")
361 08b079e2 Stavros Sachtouris
    except IndexError:
362 08b079e2 Stavros Sachtouris
        raise BadRequest('Malformed Network Interface Id')
363 08b079e2 Stavros Sachtouris
364 08b079e2 Stavros Sachtouris
    if not server_id or not nic_index:
365 e2ee7808 Giorgos Verigakis
        raise BadRequest('Malformed Request.')
366 e221ade2 Christos Stavrakakis
367 e221ade2 Christos Stavrakakis
    vm = get_vm(server_id, request.user_uniq, non_suspended=True)
368 08b079e2 Stavros Sachtouris
    nic = get_nic_from_index(vm, nic_index)
369 0196d9a3 Christos Stavrakakis
370 e221ade2 Christos Stavrakakis
    log.info("Removing NIC %s from VM %s", str(nic.index), vm)
371 bf5c82dc Christos Stavrakakis
372 0196d9a3 Christos Stavrakakis
    if nic.dirty:
373 0196d9a3 Christos Stavrakakis
        raise BuildInProgress('Machine is busy.')
374 0196d9a3 Christos Stavrakakis
    else:
375 0196d9a3 Christos Stavrakakis
        vm.nics.all().update(dirty=True)
376 0196d9a3 Christos Stavrakakis
377 0196d9a3 Christos Stavrakakis
    backend.disconnect_from_network(vm, nic)
378 e2ee7808 Giorgos Verigakis
    return HttpResponse(status=202)