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) |