Revision 40777cc8
b/aai/middleware.py | ||
---|---|---|
12 | 12 |
auth_key = "X-Auth-Key" |
13 | 13 |
|
14 | 14 |
def process_request(self, request): |
15 |
if self.auth_token in request.META: |
|
15 |
token = request.META.get('HTTP_X_AUTH_TOKEN', None) |
|
16 |
if token: |
|
16 | 17 |
user = None |
17 | 18 |
#Retrieve user from DB or other caching mechanism |
18 | 19 |
try: |
19 |
user = SynnefoUser.objects.get(auth_token = request.META[self.auth_token])
|
|
20 |
user = SynnefoUser.objects.get(auth_token=token)
|
|
20 | 21 |
except SynnefoUser.DoesNotExist: |
21 | 22 |
return HttpResponseRedirect(settings.APP_INSTALL_URL + settings.LOGIN_PATH) |
22 | 23 |
|
23 | 24 |
#Check user's auth token |
24 | 25 |
if (time.time() - |
25 |
time.mktime(user.auth_token_created.timetuple()) +
|
|
26 |
time.mktime(user.auth_token_created.timetuple()) -
|
|
26 | 27 |
settings.AUTH_TOKEN_DURATION * 3600) > 0: |
27 | 28 |
#The user's token has expired, re-login |
28 | 29 |
return HttpResponseRedirect(settings.APP_INSTALL_URL + settings.LOGIN_PATH) |
b/api/fixtures/api_test_data.json | ||
---|---|---|
247 | 247 |
"pk": 1, |
248 | 248 |
"fields": { |
249 | 249 |
"name": "Debian Squeeze", |
250 |
"owner": 1, |
|
250 | 251 |
"created": "2011-02-06 00:00:00", |
251 | 252 |
"updated": "2011-02-06 00:00:00", |
252 | 253 |
"state": "ACTIVE" |
b/api/images.py | ||
---|---|---|
4 | 4 |
|
5 | 5 |
from synnefo.api.common import method_not_allowed |
6 | 6 |
from synnefo.api.faults import BadRequest, Unauthorized |
7 |
from synnefo.api.util import (isoformat, isoparse, get_user, get_vm, get_image, get_image_meta,
|
|
7 |
from synnefo.api.util import (isoformat, isoparse, get_vm, get_image, get_image_meta, |
|
8 | 8 |
get_request_dict, render_metadata, render_meta, api_method) |
9 | 9 |
from synnefo.db.models import Image, ImageMetadata |
10 | 10 |
|
... | ... | |
93 | 93 |
since = isoparse(request.GET.get('changes-since')) |
94 | 94 |
|
95 | 95 |
if since: |
96 |
avail_images = Image.objects.filter(updated__gte=since) |
|
96 |
avail_images = Image.objects.filter(owner=request.user, updated__gte=since)
|
|
97 | 97 |
if not avail_images: |
98 | 98 |
return HttpResponse(status=304) |
99 | 99 |
else: |
100 |
avail_images = Image.objects.all()
|
|
100 |
avail_images = Image.objects.filter(owner=request.user)
|
|
101 | 101 |
|
102 | 102 |
images = [image_to_dict(image, detail) for image in avail_images] |
103 | 103 |
|
... | ... | |
132 | 132 |
except (KeyError, ValueError): |
133 | 133 |
raise BadRequest('Malformed request.') |
134 | 134 |
|
135 |
owner = get_user()
|
|
136 |
vm = get_vm(server_id) |
|
135 |
owner = request.user
|
|
136 |
vm = get_vm(server_id, owner)
|
|
137 | 137 |
image = Image.objects.create(name=name, owner=owner, sourcevm=vm) |
138 | 138 |
|
139 | 139 |
imagedict = image_to_dict(image) |
... | ... | |
154 | 154 |
# itemNotFound (404), |
155 | 155 |
# overLimit (413) |
156 | 156 |
|
157 |
image = get_image(image_id) |
|
157 |
image = get_image(image_id, request.user)
|
|
158 | 158 |
imagedict = image_to_dict(image) |
159 | 159 |
|
160 | 160 |
if request.serialization == 'xml': |
... | ... | |
173 | 173 |
# itemNotFound (404), |
174 | 174 |
# overLimit (413) |
175 | 175 |
|
176 |
image = get_image(image_id) |
|
177 |
if image.owner != get_user(): |
|
178 |
raise Unauthorized('Image does not belong to user.') |
|
176 |
image = get_image(image_id, request.user) |
|
179 | 177 |
image.delete() |
180 | 178 |
return HttpResponse(status=204) |
181 | 179 |
|
... | ... | |
188 | 186 |
# badRequest (400), |
189 | 187 |
# overLimit (413) |
190 | 188 |
|
191 |
image = get_image(image_id) |
|
189 |
image = get_image(image_id, request.user)
|
|
192 | 190 |
metadata = metadata_to_dict(image) |
193 | 191 |
return render_metadata(request, metadata, use_values=True, status=200) |
194 | 192 |
|
... | ... | |
203 | 201 |
# badMediaType(415), |
204 | 202 |
# overLimit (413) |
205 | 203 |
|
206 |
image = get_image(image_id) |
|
204 |
image = get_image(image_id, request.user)
|
|
207 | 205 |
req = get_request_dict(request) |
208 | 206 |
try: |
209 | 207 |
metadata = req['metadata'] |
... | ... | |
233 | 231 |
# itemNotFound (404), |
234 | 232 |
# badRequest (400), |
235 | 233 |
# overLimit (413) |
236 |
|
|
237 |
meta = get_image_meta(image_id, key) |
|
234 |
|
|
235 |
image = get_image(image_id, request.user) |
|
236 |
meta = get_image_meta(image, key) |
|
238 | 237 |
return render_meta(request, meta, status=200) |
239 | 238 |
|
240 | 239 |
@api_method('PUT') |
... | ... | |
249 | 248 |
# badMediaType(415), |
250 | 249 |
# overLimit (413) |
251 | 250 |
|
252 |
image = get_image(image_id) |
|
251 |
image = get_image(image_id, request.user)
|
|
253 | 252 |
req = get_request_dict(request) |
254 | 253 |
try: |
255 | 254 |
metadict = req['meta'] |
... | ... | |
275 | 274 |
# buildInProgress (409), |
276 | 275 |
# badMediaType(415), |
277 | 276 |
# overLimit (413), |
278 |
|
|
279 |
meta = get_image_meta(image_id, key) |
|
277 |
|
|
278 |
image = get_image(image_id, request.user) |
|
279 |
meta = get_image_meta(image, key) |
|
280 | 280 |
meta.delete() |
281 | 281 |
return HttpResponse(status=204) |
b/api/servers.py | ||
---|---|---|
13 | 13 |
from synnefo.api.common import method_not_allowed |
14 | 14 |
from synnefo.api.faults import BadRequest, ItemNotFound, ServiceUnavailable |
15 | 15 |
from synnefo.api.util import (isoformat, isoparse, random_password, |
16 |
get_user, get_vm, get_vm_meta, get_image, get_flavor,
|
|
16 |
get_vm, get_vm_meta, get_image, get_flavor, |
|
17 | 17 |
get_request_dict, render_metadata, render_meta, api_method) |
18 | 18 |
from synnefo.db.models import VirtualMachine, VirtualMachineMetadata |
19 | 19 |
from synnefo.logic.backend import create_instance, delete_instance |
... | ... | |
115 | 115 |
# badRequest (400), |
116 | 116 |
# overLimit (413) |
117 | 117 |
|
118 |
owner = get_user() |
|
119 | 118 |
since = isoparse(request.GET.get('changes-since')) |
120 | 119 |
|
121 | 120 |
if since: |
122 |
user_vms = VirtualMachine.objects.filter(updated__gte=since) |
|
121 |
user_vms = VirtualMachine.objects.filter(owner=request.user, updated__gte=since)
|
|
123 | 122 |
if not user_vms: |
124 | 123 |
return HttpResponse(status=304) |
125 | 124 |
else: |
126 |
user_vms = VirtualMachine.objects.filter(owner=owner, deleted=False)
|
|
125 |
user_vms = VirtualMachine.objects.filter(owner=request.user, deleted=False)
|
|
127 | 126 |
servers = [vm_to_dict(server, detail) for server in user_vms] |
128 | 127 |
|
129 | 128 |
if request.serialization == 'xml': |
... | ... | |
157 | 156 |
except (KeyError, AssertionError): |
158 | 157 |
raise BadRequest('Malformed request.') |
159 | 158 |
|
160 |
image = get_image(image_id) |
|
159 |
image = get_image(image_id, request.user)
|
|
161 | 160 |
flavor = get_flavor(flavor_id) |
162 | 161 |
|
163 | 162 |
# We must save the VM instance now, so that it gets a valid vm.backend_id. |
164 | 163 |
vm = VirtualMachine.objects.create( |
165 | 164 |
name=name, |
166 |
owner=get_user(),
|
|
165 |
owner=request.user,
|
|
167 | 166 |
sourceimage=image, |
168 | 167 |
ipfour='0.0.0.0', |
169 | 168 |
ipsix='::1', |
... | ... | |
198 | 197 |
# itemNotFound (404), |
199 | 198 |
# overLimit (413) |
200 | 199 |
|
201 |
vm = get_vm(server_id) |
|
200 |
vm = get_vm(server_id, request.user)
|
|
202 | 201 |
server = vm_to_dict(vm, detail=True) |
203 | 202 |
return render_server(request, server) |
204 | 203 |
|
... | ... | |
221 | 220 |
except (TypeError, KeyError): |
222 | 221 |
raise BadRequest('Malformed request.') |
223 | 222 |
|
224 |
vm = get_vm(server_id) |
|
223 |
vm = get_vm(server_id, request.user)
|
|
225 | 224 |
vm.name = name |
226 | 225 |
vm.save() |
227 | 226 |
|
... | ... | |
238 | 237 |
# buildInProgress (409), |
239 | 238 |
# overLimit (413) |
240 | 239 |
|
241 |
vm = get_vm(server_id) |
|
240 |
vm = get_vm(server_id, request.user)
|
|
242 | 241 |
delete_instance(vm) |
243 | 242 |
return HttpResponse(status=204) |
244 | 243 |
|
245 | 244 |
@api_method('POST') |
246 | 245 |
def server_action(request, server_id): |
247 |
vm = get_vm(server_id) |
|
246 |
vm = get_vm(server_id, request.user)
|
|
248 | 247 |
req = get_request_dict(request) |
249 | 248 |
if len(req) != 1: |
250 | 249 |
raise BadRequest('Malformed request.') |
... | ... | |
269 | 268 |
# badRequest (400), |
270 | 269 |
# overLimit (413) |
271 | 270 |
|
272 |
vm = get_vm(server_id) |
|
271 |
vm = get_vm(server_id, request.user)
|
|
273 | 272 |
addresses = [address_to_dict(vm.ipfour, vm.ipsix)] |
274 | 273 |
|
275 | 274 |
if request.serialization == 'xml': |
... | ... | |
289 | 288 |
# itemNotFound (404), |
290 | 289 |
# overLimit (413) |
291 | 290 |
|
292 |
vm = get_vm(server_id) |
|
291 |
vm = get_vm(server_id, request.user)
|
|
293 | 292 |
if network_id != 'public': |
294 | 293 |
raise ItemNotFound('Unknown network.') |
295 | 294 |
|
... | ... | |
311 | 310 |
# badRequest (400), |
312 | 311 |
# overLimit (413) |
313 | 312 |
|
314 |
vm = get_vm(server_id) |
|
313 |
vm = get_vm(server_id, request.user)
|
|
315 | 314 |
metadata = metadata_to_dict(vm) |
316 | 315 |
return render_metadata(request, metadata, use_values=True, status=200) |
317 | 316 |
|
... | ... | |
326 | 325 |
# badMediaType(415), |
327 | 326 |
# overLimit (413) |
328 | 327 |
|
329 |
vm = get_vm(server_id) |
|
328 |
vm = get_vm(server_id, request.user)
|
|
330 | 329 |
req = get_request_dict(request) |
331 | 330 |
try: |
332 | 331 |
metadata = req['metadata'] |
... | ... | |
356 | 355 |
# itemNotFound (404), |
357 | 356 |
# badRequest (400), |
358 | 357 |
# overLimit (413) |
359 |
|
|
360 |
meta = get_vm_meta(server_id, key) |
|
358 |
|
|
359 |
vm = get_vm(server_id, request.user) |
|
360 |
meta = get_vm_meta(vm, key) |
|
361 | 361 |
return render_meta(request, meta, status=200) |
362 | 362 |
|
363 | 363 |
@api_method('PUT') |
... | ... | |
372 | 372 |
# badMediaType(415), |
373 | 373 |
# overLimit (413) |
374 | 374 |
|
375 |
vm = get_vm(server_id) |
|
375 |
vm = get_vm(server_id, request.user)
|
|
376 | 376 |
req = get_request_dict(request) |
377 | 377 |
try: |
378 | 378 |
metadict = req['meta'] |
... | ... | |
398 | 398 |
# buildInProgress (409), |
399 | 399 |
# badMediaType(415), |
400 | 400 |
# overLimit (413), |
401 |
|
|
402 |
meta = get_vm_meta(server_id, key) |
|
401 |
|
|
402 |
vm = get_vm(server_id, request.user) |
|
403 |
meta = get_vm_meta(vm, key) |
|
403 | 404 |
meta.delete() |
404 | 405 |
return HttpResponse(status=204) |
b/api/tests.py | ||
---|---|---|
15 | 15 |
from django.test import TestCase |
16 | 16 |
from django.test.client import Client |
17 | 17 |
|
18 |
#from synnefo.api.tests_auth import AuthTestCase |
|
19 | 18 |
from synnefo.db.models import * |
20 |
from synnefo.logic import utils |
|
19 |
from synnefo.logic.utils import get_rsapi_state |
|
20 |
|
|
21 |
|
|
22 |
class AaiClient(Client): |
|
23 |
def request(self, **request): |
|
24 |
request['HTTP_X_AUTH_TOKEN'] = '46e427d657b20defe352804f0eb6f8a2' |
|
25 |
return super(AaiClient, self).request(**request) |
|
21 | 26 |
|
22 | 27 |
|
23 | 28 |
class APITestCase(TestCase): |
... | ... | |
33 | 38 |
#make the testing with these id's |
34 | 39 |
|
35 | 40 |
def setUp(self): |
36 |
self.client = Client() |
|
41 |
self.client = AaiClient()
|
|
37 | 42 |
|
38 | 43 |
def test_api_version(self): |
39 | 44 |
"""Check API version.""" |
... | ... | |
68 | 73 |
self.assertEqual(vm_from_api['id'], vm_from_db.id) |
69 | 74 |
self.assertEqual(vm_from_api['imageRef'], vm_from_db.flavor.id) |
70 | 75 |
self.assertEqual(vm_from_api['name'], vm_from_db.name) |
71 |
self.assertEqual(vm_from_api['status'], utils.get_rsapi_state(vm_from_db))
|
|
76 |
self.assertEqual(vm_from_api['status'], get_rsapi_state(vm_from_db)) |
|
72 | 77 |
self.assertTrue(response.status_code in [200, 203]) |
73 | 78 |
|
74 | 79 |
def test_servers_details(self): |
... | ... | |
93 | 98 |
self.assertEqual(vm_from_api['id'], vm_from_db.id) |
94 | 99 |
self.assertEqual(vm_from_api['imageRef'], vm_from_db.flavor.id) |
95 | 100 |
self.assertEqual(vm_from_api['name'], vm_from_db.name) |
96 |
self.assertEqual(vm_from_api['status'], utils.get_rsapi_state(vm_from_db))
|
|
101 |
self.assertEqual(vm_from_api['status'], get_rsapi_state(vm_from_db)) |
|
97 | 102 |
number += 1 |
98 | 103 |
for vm_from_api in vms_from_api: |
99 | 104 |
vm_from_db = VirtualMachine.objects.get(id=vm_from_api['id']) |
... | ... | |
102 | 107 |
self.assertEqual(vm_from_api['id'], vm_from_db.id) |
103 | 108 |
self.assertEqual(vm_from_api['imageRef'], vm_from_db.flavor.id) |
104 | 109 |
self.assertEqual(vm_from_api['name'], vm_from_db.name) |
105 |
self.assertEqual(vm_from_api['status'], utils.get_rsapi_state(vm_from_db))
|
|
110 |
self.assertEqual(vm_from_api['status'], get_rsapi_state(vm_from_db)) |
|
106 | 111 |
self.assertTrue(response.status_code in [200,203]) |
107 | 112 |
|
108 | 113 |
def test_wrong_server(self): |
... | ... | |
125 | 130 |
request = { |
126 | 131 |
"server": { |
127 | 132 |
"name": "new-server-test", |
133 |
"owner": 1, |
|
128 | 134 |
"imageRef": 1, |
129 | 135 |
"flavorRef": 1, |
130 | 136 |
"metadata": { |
... | ... | |
414 | 420 |
|
415 | 421 |
|
416 | 422 |
class BaseTestCase(TestCase): |
417 |
USERS = 1
|
|
423 |
USERS = 0
|
|
418 | 424 |
FLAVORS = 1 |
419 | 425 |
IMAGES = 1 |
420 | 426 |
SERVERS = 1 |
... | ... | |
422 | 428 |
IMAGE_METADATA = 0 |
423 | 429 |
|
424 | 430 |
def setUp(self): |
425 |
self.client = Client() |
|
431 |
self.client = AaiClient()
|
|
426 | 432 |
create_users(self.USERS) |
427 | 433 |
create_flavors(self.FLAVORS) |
428 | 434 |
create_images(self.IMAGES) |
b/api/util.py | ||
---|---|---|
67 | 67 |
return ''.join(choice(pool) for i in range(length)) |
68 | 68 |
|
69 | 69 |
|
70 |
def get_user(): |
|
71 |
# XXX Placeholder function, everything belongs to a single SynnefoUser for now |
|
72 |
try: |
|
73 |
return SynnefoUser.objects.all()[0] |
|
74 |
except IndexError: |
|
75 |
raise Unauthorized('No users found.') |
|
76 |
|
|
77 |
def get_vm(server_id): |
|
70 |
def get_vm(server_id, owner): |
|
78 | 71 |
"""Return a VirtualMachine instance or raise ItemNotFound.""" |
79 | 72 |
|
80 | 73 |
try: |
81 | 74 |
server_id = int(server_id) |
82 |
return VirtualMachine.objects.get(id=server_id) |
|
75 |
return VirtualMachine.objects.get(id=server_id, owner=owner)
|
|
83 | 76 |
except ValueError: |
84 | 77 |
raise BadRequest('Invalid server ID.') |
85 | 78 |
except VirtualMachine.DoesNotExist: |
86 | 79 |
raise ItemNotFound('Server not found.') |
87 | 80 |
|
88 |
def get_vm_meta(server_id, key):
|
|
81 |
def get_vm_meta(vm, key):
|
|
89 | 82 |
"""Return a VirtualMachineMetadata instance or raise ItemNotFound.""" |
90 | 83 |
|
91 | 84 |
try: |
92 |
server_id = int(server_id) |
|
93 |
return VirtualMachineMetadata.objects.get(meta_key=key, vm=server_id) |
|
85 |
return VirtualMachineMetadata.objects.get(meta_key=key, vm=vm) |
|
94 | 86 |
except VirtualMachineMetadata.DoesNotExist: |
95 | 87 |
raise ItemNotFound('Metadata key not found.') |
96 | 88 |
|
97 |
def get_image(image_id): |
|
89 |
def get_image(image_id, owner):
|
|
98 | 90 |
"""Return an Image instance or raise ItemNotFound.""" |
99 | 91 |
|
100 | 92 |
try: |
101 | 93 |
image_id = int(image_id) |
102 |
return Image.objects.get(id=image_id) |
|
94 |
return Image.objects.get(id=image_id, owner=owner) |
|
95 |
except ValueError: |
|
96 |
raise BadRequest('Invalid image ID.') |
|
103 | 97 |
except Image.DoesNotExist: |
104 | 98 |
raise ItemNotFound('Image not found.') |
105 | 99 |
|
106 |
def get_image_meta(image_id, key):
|
|
100 |
def get_image_meta(image, key): |
|
107 | 101 |
"""Return a ImageMetadata instance or raise ItemNotFound.""" |
108 | 102 |
|
109 | 103 |
try: |
110 |
image_id = int(image_id) |
|
111 |
return ImageMetadata.objects.get(meta_key=key, image=image_id) |
|
104 |
return ImageMetadata.objects.get(meta_key=key, image=image) |
|
112 | 105 |
except ImageMetadata.DoesNotExist: |
113 | 106 |
raise ItemNotFound('Metadata key not found.') |
114 | 107 |
|
... | ... | |
118 | 111 |
try: |
119 | 112 |
flavor_id = int(flavor_id) |
120 | 113 |
return Flavor.objects.get(id=flavor_id) |
114 |
except ValueError: |
|
115 |
raise BadRequest('Invalid flavor ID.') |
|
121 | 116 |
except Flavor.DoesNotExist: |
122 | 117 |
raise ItemNotFound('Flavor not found.') |
123 | 118 |
|
... | ... | |
208 | 203 |
@wraps(func) |
209 | 204 |
def wrapper(request, *args, **kwargs): |
210 | 205 |
try: |
206 |
if not request.user: |
|
207 |
raise Unauthorized('No user found.') |
|
211 | 208 |
request.serialization = request_serialization(request, atom_allowed) |
212 | 209 |
if http_method and request.method != http_method: |
213 | 210 |
raise BadRequest('Method not allowed.') |
b/tools/cloud | ||
---|---|---|
11 | 11 |
DEFAULT_HOST = '127.0.0.1:8000' |
12 | 12 |
DEFAULT_API = 'v1.1' |
13 | 13 |
|
14 |
TOKEN = '46e427d657b20defe352804f0eb6f8a2' |
|
15 |
|
|
14 | 16 |
|
15 | 17 |
commands = {} |
16 | 18 |
|
... | ... | |
67 | 69 |
conn = HTTPConnection(self.host) |
68 | 70 |
|
69 | 71 |
kwargs = {} |
72 |
kwargs['headers'] = {'X-Auth-Token': TOKEN} |
|
70 | 73 |
if body: |
71 |
kwargs['headers'] = {'Content-Type': 'application/json'}
|
|
74 |
kwargs['headers']['Content-Type'] = 'application/json'
|
|
72 | 75 |
kwargs['body'] = body |
73 | 76 |
conn.request(method, path, **kwargs) |
74 | 77 |
|
Also available in: Unified diff