Revision c19ad1e9 snf-cyclades-app/synnefo/logic/servers.py

b/snf-cyclades-app/synnefo/logic/servers.py
79 79
    elif (action == "START" and operstate != "STOPPED") or\
80 80
         (action == "STOP" and operstate != "STARTED") or\
81 81
         (action == "RESIZE" and operstate != "STOPPED") or\
82
         (action in ["CONNECT", "DISCONNECT"] and operstate != "STOPPED"
82
         (action in ["CONNECT", "DISCONNECT"]
83
          and operstate != "STOPPED"
84
          and not settings.GANETI_USE_HOTPLUG) or \
85
         (action in ["ATTACH_VOLUME", "DETACH_VOLUME"]
86
          and operstate != "STOPPED"
83 87
          and not settings.GANETI_USE_HOTPLUG):
84 88
        raise faults.BadRequest("Cannot perform '%s' action while server is"
85 89
                                " in '%s' state." % (action, operstate))
......
756 760
    else:
757 761
        raise faults.BadRequest("Network 'uuid' or 'port' attribute"
758 762
                                " is required.")
763

  
764

  
765
@server_command("ATTACH_VOLUME")
766
def attach_volume(vm, volume):
767
    """Attach a volume to a server.
768

  
769
    The volume must be in 'AVAILABLE' status in order to be attached. Also,
770
    number of the volumes that are attached to the server must remain less
771
    than 'GANETI_MAX_DISKS_PER_INSTANCE' setting. This function will send
772
    the corresponding job to Ganeti backend and update the status of the
773
    volume to 'ATTACHING'.
774

  
775
    """
776
    # Check volume state
777
    if volume.status not in ["AVAILABLE", "CREATING"]:
778
        raise faults.BadRequest("Cannot attach volume while volume is in"
779
                                " '%s' status." % volume.status)
780

  
781
    # Check that disk templates are the same
782
    if volume.disk_template != vm.flavor.disk_template:
783
        msg = ("Volume and server must have the same disk template. Volume has"
784
               " disk template '%s' while server has '%s'"
785
               % (volume.disk_template, vm.flavor.disk_template))
786
        raise faults.BadRequest(msg)
787

  
788
    # Check maximum disk per instance hard limit
789
    if vm.volumes.count() == settings.GANETI_MAX_DISKS_PER_INSTANCE:
790
        raise faults.BadRequest("Maximum volumes per server limit reached")
791

  
792
    jobid = backend.attach_volume(vm, volume)
793

  
794
    log.info("Attached volume '%s' to server '%s'. JobID: '%s'", volume.id,
795
             volume.machine_id, jobid)
796

  
797
    volume.backendjobid = jobid
798
    volume.machine = vm
799
    volume.status = "ATTACHING"
800
    volume.save()
801
    return jobid
802

  
803

  
804
@server_command("DETACH_VOLUME")
805
def detach_volume(vm, volume):
806
    """Detach a volume to a server.
807

  
808
    The volume must be in 'IN_USE' status in order to be detached. Also,
809
    the root volume of the instance (index=0) can not be detached. This
810
    function will send the corresponding job to Ganeti backend and update the
811
    status of the volume to 'DETACHING'.
812

  
813
    """
814

  
815
    _check_attachment(vm, volume)
816
    if volume.status != "IN_USE":
817
        #TODO: Maybe allow other statuses as well ?
818
        raise faults.BadRequest("Cannot detach volume while volume is in"
819
                                " '%s' status." % volume.status)
820
    if volume.index == 0:
821
        raise faults.BadRequest("Cannot detach the root volume of a server")
822
    jobid = backend.detach_volume(vm, volume)
823
    log.info("Detached volume '%s' from server '%s'. JobID: '%s'", volume.id,
824
             volume.machine_id, jobid)
825
    volume.backendjobid = jobid
826
    volume.status = "DETACHING"
827
    volume.save()
828
    return jobid
829

  
830

  
831
def _check_attachment(vm, volume):
832
    """Check that volume is attached to vm."""
833
    if volume.machine_id != vm.id:
834
        raise faults.BadRequest("Volume '%s' is not attached to server '%s'"
835
                                % volume.id, vm.id)

Also available in: Unified diff