Revision 5d805533 snf-cyclades-app/synnefo/api/servers.py
b/snf-cyclades-app/synnefo/api/servers.py | ||
---|---|---|
66 | 66 |
(r'^/(\d+)/os-volume_attachments/(\d+)(?:.json)?$', 'demux_volumes_item'), |
67 | 67 |
) |
68 | 68 |
|
69 |
VOLUME_SOURCE_TYPES = [ |
|
70 |
"snapshot", |
|
71 |
"image", |
|
72 |
"volume", |
|
73 |
"blank" |
|
74 |
] |
|
75 |
|
|
69 | 76 |
|
70 | 77 |
def demux(request): |
71 | 78 |
if request.method == 'GET': |
... | ... | |
413 | 420 |
except (KeyError, AssertionError): |
414 | 421 |
raise faults.BadRequest("Malformed request") |
415 | 422 |
|
423 |
volumes = None |
|
424 |
dev_map = server.get("block_device_mapping_v2") |
|
425 |
if dev_map is not None: |
|
426 |
volumes = parse_block_device_mapping(dev_map) |
|
427 |
|
|
416 | 428 |
# Verify that personalities are well-formed |
417 | 429 |
util.verify_personality(personality) |
418 |
# Get image information |
|
419 |
image = util.get_image_dict(image_id, user_id) |
|
420 | 430 |
# Get flavor (ensure it is active) |
421 | 431 |
flavor = util.get_flavor(flavor_id, include_deleted=False) |
422 | 432 |
if not flavor.allow_create: |
... | ... | |
426 | 436 |
# Generate password |
427 | 437 |
password = util.random_password() |
428 | 438 |
|
429 |
vm = servers.create(user_id, name, password, flavor, image, |
|
439 |
vm = servers.create(user_id, name, password, flavor, image_id,
|
|
430 | 440 |
metadata=metadata, personality=personality, |
431 |
networks=networks) |
|
441 |
networks=networks, volumes=volumes)
|
|
432 | 442 |
|
433 | 443 |
server = vm_to_dict(vm, detail=True) |
434 | 444 |
server['status'] = 'BUILD' |
... | ... | |
439 | 449 |
return response |
440 | 450 |
|
441 | 451 |
|
452 |
def parse_block_device_mapping(dev_map): |
|
453 |
"""Parse 'block_device_mapping_v2' attribute""" |
|
454 |
if not isinstance(dev_map, list): |
|
455 |
raise faults.BadRequest("Block Device Mapping is Invalid") |
|
456 |
return [_parse_block_device(device) for device in dev_map] |
|
457 |
|
|
458 |
|
|
459 |
def _parse_block_device(device): |
|
460 |
"""Parse and validate a block device mapping""" |
|
461 |
if not isinstance(device, dict): |
|
462 |
raise faults.BadRequest("Block Device Mapping is Invalid") |
|
463 |
|
|
464 |
# Validate source type |
|
465 |
source_type = device.get("source_type") |
|
466 |
if source_type is None: |
|
467 |
raise faults.BadRequest("Block Device Mapping is Invalid: Invalid" |
|
468 |
" source_type field") |
|
469 |
elif source_type not in VOLUME_SOURCE_TYPES: |
|
470 |
raise faults.BadRequest("Block Device Mapping is Invalid: source_type" |
|
471 |
" must be on of %s" |
|
472 |
% ", ".join(VOLUME_SOURCE_TYPES)) |
|
473 |
|
|
474 |
# Validate source UUID |
|
475 |
uuid = device.get("uuid") |
|
476 |
if uuid is None and source_type != "blank": |
|
477 |
raise faults.BadRequest("Block Device Mapping is Invalid: uuid of" |
|
478 |
" %s is missing" % source_type) |
|
479 |
|
|
480 |
# Validate volume size |
|
481 |
size = device.get("volume_size") |
|
482 |
if size is not None: |
|
483 |
try: |
|
484 |
size = int(size) |
|
485 |
except (TypeError, ValueError): |
|
486 |
raise faults.BadRequest("Block Device Mapping is Invalid: Invalid" |
|
487 |
" size field") |
|
488 |
|
|
489 |
# Validate 'delete_on_termination' |
|
490 |
delete_on_termination = device.get("delete_on_termination") |
|
491 |
if delete_on_termination is not None: |
|
492 |
if not isinstance(delete_on_termination, bool): |
|
493 |
raise faults.BadRequest("Block Device Mapping is Invalid: Invalid" |
|
494 |
" delete_on_termination field") |
|
495 |
else: |
|
496 |
if source_type == "volume": |
|
497 |
delete_on_termination = False |
|
498 |
else: |
|
499 |
delete_on_termination = True |
|
500 |
|
|
501 |
# Unused API Attributes |
|
502 |
# boot_index = device.get("boot_index") |
|
503 |
# destination_type = device.get("destination_type") |
|
504 |
|
|
505 |
return {"source_type": source_type, |
|
506 |
"source_uuid": uuid, |
|
507 |
"size": size, |
|
508 |
"delete_on_termination": delete_on_termination} |
|
509 |
|
|
510 |
|
|
442 | 511 |
@api.api_method(http_method='GET', user_required=True, logger=log) |
443 | 512 |
def get_server_details(request, server_id): |
444 | 513 |
# Normal Response Codes: 200, 203 |
... | ... | |
984 | 1053 |
return {"id": volume.id, |
985 | 1054 |
"volumeId": volume.id, |
986 | 1055 |
"serverId": volume.machine_id, |
987 |
"device": ""} # TODO: What device to return?
|
|
1056 |
"device": ""} # TODO: What device to return? |
|
988 | 1057 |
|
989 | 1058 |
|
990 | 1059 |
@api.api_method(http_method='GET', user_required=True, logger=log) |
Also available in: Unified diff