Statistics
| Branch: | Tag: | Revision:

root / api / actions.py @ dca6520b

History | View | Annotate | Download (8.7 kB)

1 b016b476 Giorgos Verigakis
#
2 b016b476 Giorgos Verigakis
# Copyright (c) 2010 Greek Research and Technology Network
3 b016b476 Giorgos Verigakis
#
4 b016b476 Giorgos Verigakis
5 aea3e7c6 Vangelis Koukis
from socket import getfqdn
6 aea3e7c6 Vangelis Koukis
7 b016b476 Giorgos Verigakis
from django.conf import settings
8 b016b476 Giorgos Verigakis
from django.http import HttpResponse
9 09471611 Vangelis Koukis
from django.template.loader import render_to_string
10 09471611 Vangelis Koukis
from django.utils import simplejson as json
11 b016b476 Giorgos Verigakis
12 529178b1 Giorgos Verigakis
from synnefo.api.faults import BadRequest, ServiceUnavailable
13 e2ee7808 Giorgos Verigakis
from synnefo.api.util import random_password, get_vm
14 09471611 Vangelis Koukis
from synnefo.util.vapclient import request_forwarding as request_vnc_forwarding
15 529178b1 Giorgos Verigakis
from synnefo.logic.backend import (reboot_instance, startup_instance, shutdown_instance,
16 529178b1 Giorgos Verigakis
                                    get_instance_console)
17 20a51b1e Giorgos Verigakis
from synnefo.logic.utils import get_rsapi_state
18 d8e50a39 Giorgos Verigakis
19 0971fa71 Markos Gogoulos
20 b016b476 Giorgos Verigakis
server_actions = {}
21 e2ee7808 Giorgos Verigakis
network_actions = {}
22 b016b476 Giorgos Verigakis
23 b016b476 Giorgos Verigakis
24 b016b476 Giorgos Verigakis
def server_action(name):
25 d8e50a39 Giorgos Verigakis
    '''Decorator for functions implementing server actions.
26 529178b1 Giorgos Verigakis
    `name` is the key in the dict passed by the client.
27 d8e50a39 Giorgos Verigakis
    '''
28 d8e50a39 Giorgos Verigakis
    
29 b016b476 Giorgos Verigakis
    def decorator(func):
30 b016b476 Giorgos Verigakis
        server_actions[name] = func
31 b016b476 Giorgos Verigakis
        return func
32 b016b476 Giorgos Verigakis
    return decorator
33 b016b476 Giorgos Verigakis
34 e2ee7808 Giorgos Verigakis
def network_action(name):
35 e2ee7808 Giorgos Verigakis
    '''Decorator for functions implementing network actions.
36 e2ee7808 Giorgos Verigakis
    `name` is the key in the dict passed by the client.
37 e2ee7808 Giorgos Verigakis
    '''
38 e2ee7808 Giorgos Verigakis
39 e2ee7808 Giorgos Verigakis
    def decorator(func):
40 e2ee7808 Giorgos Verigakis
        network_actions[name] = func
41 e2ee7808 Giorgos Verigakis
        return func
42 e2ee7808 Giorgos Verigakis
    return decorator
43 e2ee7808 Giorgos Verigakis
44 b016b476 Giorgos Verigakis
45 b016b476 Giorgos Verigakis
@server_action('changePassword')
46 20a51b1e Giorgos Verigakis
def change_password(request, vm, args):
47 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
48 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
49 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
50 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
51 b016b476 Giorgos Verigakis
    #                       badRequest (400),
52 b016b476 Giorgos Verigakis
    #                       badMediaType(415),
53 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
54 b016b476 Giorgos Verigakis
    #                       buildInProgress (409),
55 b016b476 Giorgos Verigakis
    #                       overLimit (413)
56 b016b476 Giorgos Verigakis
    
57 b016b476 Giorgos Verigakis
    try:
58 529178b1 Giorgos Verigakis
        password = args['adminPass']
59 b016b476 Giorgos Verigakis
    except KeyError:
60 529178b1 Giorgos Verigakis
        raise BadRequest('Malformed request.')
61 b016b476 Giorgos Verigakis
62 529178b1 Giorgos Verigakis
    raise ServiceUnavailable('Changing password is not supported.')
63 b016b476 Giorgos Verigakis
64 b016b476 Giorgos Verigakis
@server_action('reboot')
65 20a51b1e Giorgos Verigakis
def reboot(request, vm, args):
66 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
67 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
68 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
69 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
70 b016b476 Giorgos Verigakis
    #                       badRequest (400),
71 b016b476 Giorgos Verigakis
    #                       badMediaType(415),
72 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
73 b016b476 Giorgos Verigakis
    #                       buildInProgress (409),
74 b016b476 Giorgos Verigakis
    #                       overLimit (413)
75 b016b476 Giorgos Verigakis
    
76 0971fa71 Markos Gogoulos
    reboot_type = args.get('type', '')
77 0971fa71 Markos Gogoulos
    if reboot_type not in ('SOFT', 'HARD'):
78 529178b1 Giorgos Verigakis
        raise BadRequest('Malformed Request.')
79 529178b1 Giorgos Verigakis
    reboot_instance(vm, reboot_type.lower())
80 b016b476 Giorgos Verigakis
    return HttpResponse(status=202)
81 b016b476 Giorgos Verigakis
82 b016b476 Giorgos Verigakis
@server_action('start')
83 20a51b1e Giorgos Verigakis
def start(request, vm, args):
84 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
85 d8e50a39 Giorgos Verigakis
    # Error Response Codes: serviceUnavailable (503),
86 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404)
87 529178b1 Giorgos Verigakis
    
88 529178b1 Giorgos Verigakis
    if args:
89 529178b1 Giorgos Verigakis
        raise BadRequest('Malformed Request.')
90 529178b1 Giorgos Verigakis
    startup_instance(vm)
91 b016b476 Giorgos Verigakis
    return HttpResponse(status=202)
92 b016b476 Giorgos Verigakis
93 b016b476 Giorgos Verigakis
@server_action('shutdown')
94 20a51b1e Giorgos Verigakis
def shutdown(request, vm, args):
95 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
96 d8e50a39 Giorgos Verigakis
    # Error Response Codes: serviceUnavailable (503),
97 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404)
98 b016b476 Giorgos Verigakis
    
99 529178b1 Giorgos Verigakis
    if args:
100 529178b1 Giorgos Verigakis
        raise BadRequest('Malformed Request.')
101 529178b1 Giorgos Verigakis
    shutdown_instance(vm)
102 b016b476 Giorgos Verigakis
    return HttpResponse(status=202)
103 b016b476 Giorgos Verigakis
104 b016b476 Giorgos Verigakis
@server_action('rebuild')
105 20a51b1e Giorgos Verigakis
def rebuild(request, vm, args):
106 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
107 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
108 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
109 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
110 b016b476 Giorgos Verigakis
    #                       badRequest (400),
111 b016b476 Giorgos Verigakis
    #                       badMediaType(415),
112 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
113 b016b476 Giorgos Verigakis
    #                       buildInProgress (409),
114 b016b476 Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
115 b016b476 Giorgos Verigakis
    #                       overLimit (413)
116 b016b476 Giorgos Verigakis
117 529178b1 Giorgos Verigakis
    raise ServiceUnavailable('Rebuild not supported.')
118 b016b476 Giorgos Verigakis
119 b016b476 Giorgos Verigakis
@server_action('resize')
120 20a51b1e Giorgos Verigakis
def resize(request, vm, args):
121 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
122 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
123 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
124 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
125 b016b476 Giorgos Verigakis
    #                       badRequest (400),
126 b016b476 Giorgos Verigakis
    #                       badMediaType(415),
127 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
128 b016b476 Giorgos Verigakis
    #                       buildInProgress (409),
129 b016b476 Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
130 b016b476 Giorgos Verigakis
    #                       overLimit (413),
131 b016b476 Giorgos Verigakis
    #                       resizeNotAllowed (403)
132 b016b476 Giorgos Verigakis
    
133 529178b1 Giorgos Verigakis
    raise ServiceUnavailable('Resize not supported.')
134 b016b476 Giorgos Verigakis
135 b016b476 Giorgos Verigakis
@server_action('confirmResize')
136 20a51b1e Giorgos Verigakis
def confirm_resize(request, vm, args):
137 b016b476 Giorgos Verigakis
    # Normal Response Code: 204
138 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
139 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
140 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
141 b016b476 Giorgos Verigakis
    #                       badRequest (400),
142 b016b476 Giorgos Verigakis
    #                       badMediaType(415),
143 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
144 b016b476 Giorgos Verigakis
    #                       buildInProgress (409),
145 b016b476 Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
146 b016b476 Giorgos Verigakis
    #                       overLimit (413),
147 b016b476 Giorgos Verigakis
    #                       resizeNotAllowed (403)
148 b016b476 Giorgos Verigakis
    
149 529178b1 Giorgos Verigakis
    raise ServiceUnavailable('Resize not supported.')
150 b016b476 Giorgos Verigakis
151 b016b476 Giorgos Verigakis
@server_action('revertResize')
152 20a51b1e Giorgos Verigakis
def revert_resize(request, vm, args):
153 b016b476 Giorgos Verigakis
    # Normal Response Code: 202
154 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
155 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
156 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
157 b016b476 Giorgos Verigakis
    #                       badRequest (400),
158 b016b476 Giorgos Verigakis
    #                       badMediaType(415),
159 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
160 b016b476 Giorgos Verigakis
    #                       buildInProgress (409),
161 b016b476 Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
162 b016b476 Giorgos Verigakis
    #                       overLimit (413),
163 b016b476 Giorgos Verigakis
    #                       resizeNotAllowed (403)
164 b016b476 Giorgos Verigakis
165 529178b1 Giorgos Verigakis
    raise ServiceUnavailable('Resize not supported.')
166 529178b1 Giorgos Verigakis
167 529178b1 Giorgos Verigakis
@server_action('console')
168 529178b1 Giorgos Verigakis
def get_console(request, vm, args):
169 529178b1 Giorgos Verigakis
    """Arrange for an OOB console of the specified type
170 529178b1 Giorgos Verigakis

171 529178b1 Giorgos Verigakis
    This method arranges for an OOB console of the specified type.
172 529178b1 Giorgos Verigakis
    Only consoles of type "vnc" are supported for now.
173 529178b1 Giorgos Verigakis

174 529178b1 Giorgos Verigakis
    It uses a running instance of vncauthproxy to setup proper
175 529178b1 Giorgos Verigakis
    VNC forwarding with a random password, then returns the necessary
176 529178b1 Giorgos Verigakis
    VNC connection info to the caller.
177 529178b1 Giorgos Verigakis
    """
178 529178b1 Giorgos Verigakis
    # Normal Response Code: 200
179 529178b1 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
180 529178b1 Giorgos Verigakis
    #                       serviceUnavailable (503),
181 529178b1 Giorgos Verigakis
    #                       unauthorized (401),
182 529178b1 Giorgos Verigakis
    #                       badRequest (400),
183 529178b1 Giorgos Verigakis
    #                       badMediaType(415),
184 529178b1 Giorgos Verigakis
    #                       itemNotFound (404),
185 529178b1 Giorgos Verigakis
    #                       buildInProgress (409),
186 529178b1 Giorgos Verigakis
    #                       overLimit (413)
187 529178b1 Giorgos Verigakis
    
188 529178b1 Giorgos Verigakis
    console_type = args.get('type', '')
189 529178b1 Giorgos Verigakis
    if console_type != 'vnc':
190 529178b1 Giorgos Verigakis
        raise BadRequest('Type can only be "vnc".')
191 529178b1 Giorgos Verigakis
192 529178b1 Giorgos Verigakis
    # Use RAPI to get VNC console information for this instance
193 529178b1 Giorgos Verigakis
    if get_rsapi_state(vm) != 'ACTIVE':
194 529178b1 Giorgos Verigakis
        raise BadRequest('Server not in ACTIVE state.')
195 529178b1 Giorgos Verigakis
    
196 529178b1 Giorgos Verigakis
    if settings.TEST:
197 529178b1 Giorgos Verigakis
        console_data = {'kind': 'vnc', 'host': 'ganeti_node', 'port': 1000}
198 529178b1 Giorgos Verigakis
    else:
199 529178b1 Giorgos Verigakis
        console_data = get_instance_console(vm)
200 529178b1 Giorgos Verigakis
    
201 529178b1 Giorgos Verigakis
    if console_data['kind'] != 'vnc':
202 529178b1 Giorgos Verigakis
        raise ServiceUnavailable('Could not create a console of requested type.')
203 529178b1 Giorgos Verigakis
    
204 529178b1 Giorgos Verigakis
    # Let vncauthproxy decide on the source port.
205 529178b1 Giorgos Verigakis
    # The alternative: static allocation, e.g.
206 529178b1 Giorgos Verigakis
    # sport = console_data['port'] - 1000
207 529178b1 Giorgos Verigakis
    sport = 0
208 529178b1 Giorgos Verigakis
    daddr = console_data['host']
209 529178b1 Giorgos Verigakis
    dport = console_data['port']
210 529178b1 Giorgos Verigakis
    password = random_password()
211 529178b1 Giorgos Verigakis
    
212 529178b1 Giorgos Verigakis
    try:
213 529178b1 Giorgos Verigakis
        if settings.TEST:
214 529178b1 Giorgos Verigakis
            fwd = {'source_port': 1234, 'status': 'OK'}
215 529178b1 Giorgos Verigakis
        else:
216 529178b1 Giorgos Verigakis
            fwd = request_vnc_forwarding(sport, daddr, dport, password)
217 529178b1 Giorgos Verigakis
    except Exception:
218 529178b1 Giorgos Verigakis
        raise ServiceUnavailable('Could not allocate VNC console port.')
219 529178b1 Giorgos Verigakis
220 529178b1 Giorgos Verigakis
    if fwd['status'] != "OK":
221 529178b1 Giorgos Verigakis
        raise ServiceUnavailable('Could not allocate VNC console.')
222 529178b1 Giorgos Verigakis
    
223 529178b1 Giorgos Verigakis
    console = {
224 529178b1 Giorgos Verigakis
        'type': 'vnc',
225 529178b1 Giorgos Verigakis
        'host': getfqdn(),
226 529178b1 Giorgos Verigakis
        'port': fwd['source_port'],
227 529178b1 Giorgos Verigakis
        'password': password}
228 529178b1 Giorgos Verigakis
    
229 529178b1 Giorgos Verigakis
    if request.serialization == 'xml':
230 529178b1 Giorgos Verigakis
        mimetype = 'application/xml'
231 529178b1 Giorgos Verigakis
        data = render_to_string('console.xml', {'console': console})
232 529178b1 Giorgos Verigakis
    else:
233 529178b1 Giorgos Verigakis
        mimetype = 'application/json'
234 529178b1 Giorgos Verigakis
        data = json.dumps({'console': console})
235 529178b1 Giorgos Verigakis
    
236 529178b1 Giorgos Verigakis
    return HttpResponse(data, mimetype=mimetype, status=200)
237 e2ee7808 Giorgos Verigakis
238 e2ee7808 Giorgos Verigakis
239 e2ee7808 Giorgos Verigakis
@network_action('add')
240 e2ee7808 Giorgos Verigakis
def add(request, net, args):
241 dca6520b Giorgos Verigakis
    server_id = args.get('serverRef', None)
242 e2ee7808 Giorgos Verigakis
    if not server_id:
243 e2ee7808 Giorgos Verigakis
        raise BadRequest('Malformed Request.')
244 e2ee7808 Giorgos Verigakis
    vm = get_vm(server_id, request.user)
245 e2ee7808 Giorgos Verigakis
    net.machines.add(vm)
246 e2ee7808 Giorgos Verigakis
    net.save()
247 e2ee7808 Giorgos Verigakis
    return HttpResponse(status=202)
248 e2ee7808 Giorgos Verigakis
249 e2ee7808 Giorgos Verigakis
@network_action('remove')
250 e2ee7808 Giorgos Verigakis
def remove(request, net, args):
251 dca6520b Giorgos Verigakis
    server_id = args.get('serverRef', None)
252 e2ee7808 Giorgos Verigakis
    if not server_id:
253 e2ee7808 Giorgos Verigakis
        raise BadRequest('Malformed Request.')
254 e2ee7808 Giorgos Verigakis
    vm = get_vm(server_id, request.user)
255 e2ee7808 Giorgos Verigakis
    net.machines.remove(vm)
256 e2ee7808 Giorgos Verigakis
    net.save()
257 e2ee7808 Giorgos Verigakis
    return HttpResponse(status=202)