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