Revision 40086e5c

View differences:

install.sh
987 987
                 src/tm_mad/shared/failmigrate \
988 988
                 src/tm_mad/shared/mvds \
989 989
                 src/tm_mad/shared/snap_create \
990
                 src/tm_mad/shared/snap_create_live \
990 991
                 src/tm_mad/shared/snap_delete \
991 992
                 src/tm_mad/shared/snap_revert \
992 993
                 src/tm_mad/shared/cpds"
......
999 1000
                 src/tm_mad/fs_lvm/premigrate \
1000 1001
                 src/tm_mad/fs_lvm/postmigrate \
1001 1002
                 src/tm_mad/fs_lvm/snap_create \
1003
                 src/tm_mad/fs_lvm/snap_create_live \
1002 1004
                 src/tm_mad/fs_lvm/snap_delete \
1003 1005
                 src/tm_mad/fs_lvm/snap_revert \
1004 1006
                 src/tm_mad/fs_lvm/failmigrate \
......
1016 1018
                 src/tm_mad/qcow2/failmigrate \
1017 1019
                 src/tm_mad/qcow2/mvds \
1018 1020
                 src/tm_mad/qcow2/snap_create \
1021
                 src/tm_mad/qcow2/snap_create_live \
1019 1022
                 src/tm_mad/qcow2/snap_delete \
1020 1023
                 src/tm_mad/qcow2/snap_revert \
1021 1024
                 src/tm_mad/qcow2/cpds"
......
1032 1035
              src/tm_mad/ssh/failmigrate \
1033 1036
              src/tm_mad/ssh/mvds \
1034 1037
              src/tm_mad/ssh/snap_create \
1038
              src/tm_mad/ssh/snap_create_live \
1035 1039
              src/tm_mad/ssh/snap_delete \
1036 1040
              src/tm_mad/ssh/snap_revert \
1037 1041
              src/tm_mad/ssh/cpds"
......
1048 1052
              src/tm_mad/dummy/failmigrate \
1049 1053
              src/tm_mad/dummy/mvds \
1050 1054
              src/tm_mad/dummy/snap_create \
1055
              src/tm_mad/dummy/snap_create_live \
1051 1056
              src/tm_mad/dummy/snap_delete \
1052 1057
              src/tm_mad/dummy/snap_revert \
1053 1058
              src/tm_mad/dummy/cpds"
......
1063 1068
                 src/tm_mad/vmfs/cpds \
1064 1069
                 src/tm_mad/vmfs/postmigrate \
1065 1070
                 src/tm_mad/vmfs/snap_create \
1071
                 src/tm_mad/vmfs/snap_create_live \
1066 1072
                 src/tm_mad/vmfs/snap_delete \
1067 1073
                 src/tm_mad/vmfs/snap_revert \
1068 1074
                 src/tm_mad/vmfs/failmigrate \
......
1076 1082
                 src/tm_mad/lvm/premigrate \
1077 1083
                 src/tm_mad/lvm/postmigrate \
1078 1084
                 src/tm_mad/lvm/snap_create \
1085
                 src/tm_mad/lvm/snap_create_live \
1079 1086
                 src/tm_mad/lvm/snap_delete \
1080 1087
                 src/tm_mad/lvm/snap_revert \
1081 1088
                 src/tm_mad/lvm/failmigrate \
......
1089 1096
                 src/tm_mad/ceph/premigrate \
1090 1097
                 src/tm_mad/ceph/postmigrate \
1091 1098
                 src/tm_mad/ceph/snap_create \
1099
                 src/tm_mad/ceph/snap_create_live \
1092 1100
                 src/tm_mad/ceph/snap_delete \
1093 1101
                 src/tm_mad/ceph/snap_revert \
1094 1102
                 src/tm_mad/ceph/failmigrate \
......
1102 1110
                 src/tm_mad/dev/premigrate \
1103 1111
                 src/tm_mad/dev/postmigrate \
1104 1112
                 src/tm_mad/dev/snap_create \
1113
                 src/tm_mad/dev/snap_create_live \
1105 1114
                 src/tm_mad/dev/snap_delete \
1106 1115
                 src/tm_mad/dev/snap_revert \
1107 1116
                 src/tm_mad/dev/failmigrate \
share/etc/oned.conf
420 420
#        An example: "-l migrate=migrate_local,save"
421 421
#    -p more than one action per host in parallel, needs support from hypervisor
422 422
#    -s <shell> to execute remote commands, bash by default
423
#    -d detach disks on running VMs before creating/reverting snaps, by default
424
#      the VM will be suspended
423
#    -d default snapshot strategy. It can be either 'detach' or 'suspend'. It
424
#       defaults to 'suspend'.
425
#    -i try to do live-snapshot if available. Currently supported only for kvm
426
#       with qcow2 as the datastore TM_MAD. If not available, it will fallback
427
#       on the default (-d)
425 428
#
426 429
#  Note: You can use type = "qemu" to use qemu emulated guests, e.g. if your
427 430
#  CPU does not have virtualization extensions or use nested Qemu-KVM hosts
......
429 432
VM_MAD = [
430 433
    name       = "kvm",
431 434
    executable = "one_vmm_exec",
432
    arguments  = "-t 15 -r 0 kvm",
435
    arguments  = "-t 15 -r 0 -d detach -i kvm",
433 436
    default    = "vmm_exec/vmm_exec_kvm.conf",
434 437
    type       = "kvm" ]
438

  
435 439
#-------------------------------------------------------------------------------
436 440

  
437 441
#-------------------------------------------------------------------------------
......
444 448
#        An example: "-l migrate,save"
445 449
#    -p more than one action per host in parallel, needs support from hypervisor
446 450
#    -s <shell> to execute commands, bash by default
447
#    -d detach disks on running VMs before creating/reverting snaps, by default
448
#      the VM will be suspended
451
#    -d default snapshot strategy. It can be either 'detach' or 'suspend'. It
452
#       defaults to 'suspend'.
449 453
#-------------------------------------------------------------------------------
450 454
#
451 455
# Driver for Xen 3.x
......
472 476
#    -t number of threads, i.e. number of hosts monitored at the same time
473 477
#    -p more than one action per host in parallel, needs support from hypervisor
474 478
#    -s <shell> to execute commands, bash by default
475
#    -d detach disks on running VMs before creating/reverting snaps, by default
476
#      the VM will be suspended
479
#    -d default snapshot strategy. It can be either 'detach' or 'suspend'. It
480
#       defaults to 'suspend'.
477 481
#-------------------------------------------------------------------------------
478 482
#VM_MAD = [
479 483
#    name       = "vmware",
......
489 493
#    -t number of threads, i.e. number of hosts monitored at the same time
490 494
#    -p more than one action per host in parallel, needs support from hypervisor
491 495
#    -s <shell> to execute commands, bash by default
492
#    -d detach disks on running VMs before creating/reverting snaps, by default
493
#      the VM will be suspended
496
#    -d default snapshot strategy. It can be either 'detach' or 'suspend'. It
497
#       defaults to 'suspend'.
494 498
#-------------------------------------------------------------------------------
495 499
#VM_MAD = [
496 500
#    name       = "vcenter",
src/tm_mad/ceph/snap_create_live
1
../common/not_supported.sh
src/tm_mad/dev/snap_create_live
1
../common/not_supported.sh
src/tm_mad/dummy/snap_create_live
1
../common/not_supported.sh
src/tm_mad/fs_lvm/snap_create_live
1
../common/not_supported.sh
src/tm_mad/lvm/snap_create_live
1
../common/not_supported.sh
src/tm_mad/qcow2/cpds
74 74

  
75 75
DST_PATH="${SRC_DS_PATH}${DST_ARG_PATH##$DST_DS_PATH}"
76 76

  
77
if [ "$CLONE" != "YES" ]; then
78
    SRC_PATH="$DISK_SRC"
79
fi
80

  
81 77
if [ "$SNAP_ID" != "-1" ]; then
78
    [ "$CLONE" != "YES" ] && SRC_PATH="$DISK_SRC"
82 79
    SRC_PATH="$SRC_PATH.snap/$(($SNAP_ID+1))"
83 80
fi
84 81

  
85 82
#-------------------------------------------------------------------------------
86 83
# Move the image back to the datastore
87 84
#-------------------------------------------------------------------------------
88
CPSCRIPT=$(cat <<EOF
85

  
86
CPDS_CMD=$(cat <<EOF
89 87
SRC_READLN=\$($READLINK -f $SRC_PATH)
90 88
DST_READLN=\$($READLINK -f $DST_PATH)
91 89

  
......
97 95
EOF
98 96
)
99 97

  
98
# TODO: after taking a snapshot, if you try to save the current state, and if
99
# cache='none', it will fail, as the changes are not commited to the image. This
100
# happens even after running 'sync' inside the guest and in the hypervisor. A
101
# solution that does work is to run:
102
#
103
#     $ touch $DST_PATH
104
#     $ virsh blockcopy --domain $DEPLOY_ID $TARGET $DST_PATH --wait --verbose
105
#
106
# However this is in turn problematic because there is no easy way to tell if the
107
# global configuration for taking snapshot is live, detach or suspend. If it's
108
# live, and the VM is running, the virsh blockcopy can be run, otherwise it should
109
# never be run. If we can detect this configuration parameter in this script, and
110
# check with libvirt if the vm is running, we should have all the information we
111
# need to do choose whether to run the blockcopy or not.
112

  
100 113
log "Copying $SRC_PATH to datastore as $DST_PATH"
101 114

  
102
ssh_exec_and_log $SRC_HOST "$CPSCRIPT" "Could not move image $DST_PATH"
115
ssh_exec_and_log $SRC_HOST "$CPDS_CMD" "Could not move image $DST_PATH"
103 116

  
104 117
exit 0
src/tm_mad/qcow2/snap_create
52 52
    XPATH_ELEMENTS[i++]="$element"
53 53
done < <(onevm show -x $VMID| $XPATH \
54 54
                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \
55
                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
56
                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TARGET \
57
                    /VM/HISTORY_RECORDS/HISTORY/VMMMAD \
58
                    /VM/STATE \
59
                    /VM/LCM_STATE \
60
                    /VM/DEPLOY_ID \
61
                    '%m%/VM/TEMPLATE/DISK/TARGET')
55
                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE )
62 56

  
63 57
DISK_SRC="${XPATH_ELEMENTS[j++]}"
64 58
CLONE="${XPATH_ELEMENTS[j++]}"
65
TARGET="${XPATH_ELEMENTS[j++]}"
66
VMMMAD="${XPATH_ELEMENTS[j++]}"
67
STATE="${XPATH_ELEMENTS[j++]}"
68
LCM_STATE="${XPATH_ELEMENTS[j++]}"
69
DEPLOY_ID="${XPATH_ELEMENTS[j++]}"
70
ALL_DISKS="${XPATH_ELEMENTS[j++]}"
71 59

  
72 60
SYSTEM_DS_PATH=$(dirname ${SRC_PATH})
73
IMAGE_DS_PATH=$(dirname ${DISK_SRC})
74

  
75 61
SYSTEM_DS_DISK_PATH="${SYSTEM_DS_PATH}/disk.${DISK_ID}"
76 62

  
77 63
if [ "$CLONE" = "YES" ]; then
78 64
    DISK_PATH="${SYSTEM_DS_DISK_PATH}"
79
    DISK_PATH_ORIG="${DISK_PATH}.orig"
80 65
else
81 66
    DISK_PATH=$DISK_SRC
82
    DISK_PATH_ORIG=$DISK_PATH
83 67
fi
84 68

  
85 69
NEXT_SNAP_ID=$(($SNAP_ID+1))
......
87 71
SNAP_DIR="${DISK_PATH}.snap"
88 72
SNAP_PATH="${SNAP_DIR}/${NEXT_SNAP_ID}"
89 73

  
90
# virsh snapshot-create by default creates snapshots for all the disks that
91
# are not read only. To be able to make a snapshot in only one of the disks
92
# an xml must be created describing all of the disks and setting the value
93
# snapshot='no' to the disks that are not going to be snapshotted.
94

  
95
# <domainsnapshot>
96
#   <name>1</name>
97
#   <description>snap 1</description>
98
#   <disks>
99
#     <disk name='vda' snapshot='no'/>
100
#     <disk name='vdb'>
101
#       <source file='/var/lib/one/datastores/1/09eec196c67b38dea41048a628978600.snap/1'/>
102
#     </disk>
103
#     <disk name='vdc' snapshot='no'/>
104
#   </disks>
105
# </domainsnapshot>
106

  
107
DOC="
108
<domainsnapshot>
109
  <name>${DISK_ID}-${SNAP_ID}</name>
110
  <description>snap ${DISK_ID}-${SNAP_ID}</description>
111
  <disks>"
112

  
113
for disk in $ALL_DISKS; do
114
    if [ "$disk" = "$TARGET" ]; then
115
        DOC="$DOC
116
    <disk name='$disk' snapshot='external'>
117
      <source file='$SNAP_PATH'/>
118
    </disk>"
119
    else
120
        DOC="$DOC
121
    <disk name='$disk' snapshot='no'/>"
122
    fi
123
done
124

  
125
DOC="$DOC
126
  </disks>
127
</domainsnapshot>"
128

  
129
CMD=$(cat <<EOT
74
SNAP_CMD=$(cat <<EOT
130 75
set -ex
131 76

  
132
if [ ! -d "${SNAP_DIR}" ]; then
133
    mkdir "${SNAP_DIR}"
134
fi
77
mkdir -p "${SNAP_DIR}"
135 78

  
136 79
PREVIOUS_SNAP=$(readlink $SYSTEM_DS_DISK_PATH)
137 80

  
138
# 57 is DISK_SNAPSHOT. When the snapshot is done with the VM in running state
139
# TODO: LCM_STATE will *always* be 57. Need to check virsh status.
140
if [ "$LCM_STATE" = "57" ] && [ "$VMMMAD" = "kvm" ] ; then
141
    # The file must be created beforehand or libvirt complains with
142
    # "permission denied"
143
    touch $SNAP_PATH
144

  
145
    # Temporary xml file
146
    FILENAME="/tmp/snapshot-$VMID-$DISK_ID-$SNAP_ID"
147
    echo -e "$DOC" > \$FILENAME
148

  
149
    virsh -c qemu:///system snapshot-create $DEPLOY_ID --disk-only --atomic \
150
        --xmlfile \$FILENAME
151

  
152
    rm \${FILENAME}
153

  
154
    qemu-img rebase -u -b "\${PREVIOUS_SNAP}" "${SNAP_PATH}"
155
    ln -sf $SNAP_PATH $SYSTEM_DS_DISK_PATH
156
else
157
    qemu-img create -f qcow2 -b "\${PREVIOUS_SNAP}" "${SNAP_PATH}"
158
    ln -sf $SNAP_PATH $SYSTEM_DS_DISK_PATH
159
fi
81
qemu-img create -f qcow2 -b "\${PREVIOUS_SNAP}" "${SNAP_PATH}"
82
ln -sf $SNAP_PATH $SYSTEM_DS_DISK_PATH
160 83
EOT
161 84
)
162 85

  
163
ssh_exec_and_log "${SRC_HOST}" "${CMD}" \
86
ssh_exec_and_log "${SRC_HOST}" "${SNAP_CMD}" \
164 87
                 "Error creating snapshot ${SNAP_PATH}"
165 88

  
src/tm_mad/qcow2/snap_create_live
1
#!/bin/bash
2

  
3
# -------------------------------------------------------------------------- #
4
# Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs        #
5
#                                                                            #
6
# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
7
# not use this file except in compliance with the License. You may obtain    #
8
# a copy of the License at                                                   #
9
#                                                                            #
10
# http://www.apache.org/licenses/LICENSE-2.0                                 #
11
#                                                                            #
12
# Unless required by applicable law or agreed to in writing, software        #
13
# distributed under the License is distributed on an "AS IS" BASIS,          #
14
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
15
# See the License for the specific language governing permissions and        #
16
# limitations under the License.                                             #
17
#--------------------------------------------------------------------------- #
18

  
19
# snap_create host:parent_image snap_id vmid ds_id
20

  
21
SRC=$1
22
SNAP_ID=$2
23
VMID=$3
24
DSID=$4
25

  
26
if [ -z "${ONE_LOCATION}" ]; then
27
    TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh
28
    DATASTORES=/var/lib/one/datastores
29
else
30
    TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh
31
    DATASTORES=$ONE_LOCATION/var/datastores
32
fi
33

  
34
DRIVER_PATH=$(dirname $0)
35

  
36
. $TMCOMMON
37

  
38
SRC_PATH=$(arg_path $SRC)
39
SRC_HOST=$(arg_host $SRC)
40

  
41
#-------------------------------------------------------------------------------
42
# Get Image information
43
#-------------------------------------------------------------------------------
44

  
45
DISK_ID=$(basename ${SRC} | cut -d. -f2)
46

  
47
XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
48

  
49
unset i j XPATH_ELEMENTS
50

  
51
while IFS= read -r -d '' element; do
52
    XPATH_ELEMENTS[i++]="$element"
53
done < <(onevm show -x $VMID| $XPATH \
54
                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \
55
                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
56
                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TARGET \
57
                    /VM/DEPLOY_ID \
58
                    '%m%/VM/TEMPLATE/DISK/TARGET')
59

  
60
DISK_SRC="${XPATH_ELEMENTS[j++]}"
61
CLONE="${XPATH_ELEMENTS[j++]}"
62
TARGET="${XPATH_ELEMENTS[j++]}"
63
DEPLOY_ID="${XPATH_ELEMENTS[j++]}"
64
ALL_DISKS="${XPATH_ELEMENTS[j++]}"
65

  
66
SYSTEM_DS_PATH=$(dirname ${SRC_PATH})
67

  
68
SYSTEM_DS_DISK_PATH="${SYSTEM_DS_PATH}/disk.${DISK_ID}"
69

  
70
if [ "$CLONE" = "YES" ]; then
71
    DISK_PATH="${SYSTEM_DS_DISK_PATH}"
72
else
73
    DISK_PATH=$DISK_SRC
74
fi
75

  
76
NEXT_SNAP_ID=$(($SNAP_ID+1))
77

  
78
SNAP_DIR="${DISK_PATH}.snap"
79
SNAP_PATH="${SNAP_DIR}/${NEXT_SNAP_ID}"
80

  
81
# virsh snapshot-create by default creates snapshots for all the disks that
82
# are not read only. To be able to make a snapshot in only one of the disks
83
# an xml must be created describing all of the disks and setting the value
84
# snapshot='no' to the disks that are not going to be snapshotted.
85

  
86
# <domainsnapshot>
87
#   <name>1</name>
88
#   <description>snap 1</description>
89
#   <disks>
90
#     <disk name='vda' snapshot='no'/>
91
#     <disk name='vdb'>
92
#       <source file='/var/lib/one/datastores/1/09eec196c67b38dea41048a628978600.snap/1'/>
93
#     </disk>
94
#     <disk name='vdc' snapshot='no'/>
95
#   </disks>
96
# </domainsnapshot>
97

  
98
DOC="
99
<domainsnapshot>
100
  <name>${DISK_ID}-${SNAP_ID}</name>
101
  <description>snap ${DISK_ID}-${SNAP_ID}</description>
102
  <disks>"
103

  
104
for disk in $ALL_DISKS; do
105
    if [ "$disk" = "$TARGET" ]; then
106
        DOC="$DOC
107
    <disk name='$disk' snapshot='external'>
108
      <source file='$SNAP_PATH'/>
109
    </disk>"
110
    else
111
        DOC="$DOC
112
    <disk name='$disk' snapshot='no'/>"
113
    fi
114
done
115

  
116
DOC="$DOC
117
  </disks>
118
</domainsnapshot>"
119

  
120
CMD=$(cat <<EOT
121
set -ex
122

  
123
mkdir -p "${SNAP_DIR}"
124

  
125
PREVIOUS_SNAP=$(readlink $SYSTEM_DS_DISK_PATH)
126

  
127
# The file must be created beforehand or libvirt complains with
128
# "permission denied"
129
touch $SNAP_PATH
130

  
131
# Temporary xml file
132
FILENAME="/tmp/snapshot-$VMID-$DISK_ID-$SNAP_ID"
133
echo -e "$DOC" > \$FILENAME
134

  
135
virsh -c qemu:///system snapshot-create $DEPLOY_ID --disk-only --atomic \
136
    --xmlfile \$FILENAME
137

  
138
rm \${FILENAME}
139

  
140
qemu-img rebase -u -b "\${PREVIOUS_SNAP}" "${SNAP_PATH}"
141
ln -sf $SNAP_PATH $SYSTEM_DS_DISK_PATH
142
EOT
143
)
144

  
145
ssh_exec_and_log "${SRC_HOST}" "${CMD}" \
146
                 "Error creating snapshot ${SNAP_PATH}"
147

  
src/tm_mad/shared/snap_create_live
1
../common/not_supported.sh
src/tm_mad/ssh/snap_create_live
1
../common/not_supported.sh
src/tm_mad/vmfs/snap_create_live
1
../common/not_supported.sh
src/vmm_mad/exec/one_vmm_exec.rb
888 888
    # DISKSNAPSHOTCREATE action, takes a snapshot of a disk
889 889
    #
890 890
    def disk_snapshot_create(id, drv_message)
891
        action   = ACTION[:disk_snapshot_create]
892
        xml_data = decode(drv_message)
893

  
891
        snap_action  = prepare_snap_action(id, drv_message, ACTION[:disk_snapshot_create])
892
        action       = snap_action[:action]
893
        strategy     = snap_action[:strategy]
894
        drv_message  = snap_action[:drv_message]
895
        target       = snap_action[:target]
896
        target_index = snap_action[:target_index]
897
        xml_data     = snap_action[:xml_data]
898

  
899
        # Get TM command
894 900
        tm_command = ensure_xpath(xml_data, id, action, 'TM_COMMAND') || return
895 901
        tm_rollback= xml_data.elements['TM_COMMAND_ROLLBACK'].text.strip
896 902

  
897
        target_xpath = "VM/TEMPLATE/DISK[DISK_SNAPSHOT_ACTIVE='YES']/TARGET"
898
        target       = ensure_xpath(xml_data, id, action, target_xpath) ||return
899

  
900
        target_index = target.downcase[-1..-1].unpack('c').first - 97
901

  
902
        if @options[:detach_snap]
903
          disk   = xml_data.elements[target_xpath].parent
904
          attach = REXML::Element.new('ATTACH')
905

  
906
          attach.add_text('YES')
907
          disk.add(attach)
908

  
909
          drv_message = Base64.encode64(xml_data.to_s)
910
        end
911

  
912
        action = VmmAction.new(self, id, :disk_snapshot_create, drv_message)
913

  
914
        vmm_driver_path = 'VM/HISTORY_RECORDS/HISTORY/VMMMAD'
915
        tm_driver_path = "VM/TEMPLATE/DISK[DISK_SNAPSHOT_ACTIVE='YES']/TM_MAD"
916

  
917
        vmm_driver = ensure_xpath(xml_data, id, action, vmm_driver_path) ||
918
            return
919
        tm_driver = ensure_xpath(xml_data, id, action, tm_driver_path) ||
920
            return
921

  
922
        # live_snapshots option is an array of VM and TM pairs
923
        # For example "kvm-qcow2". If found then only TM action is called.
924
        # Extra actions (suspend or attach) will be skipped
925
        live_snapshot = @options[:live_snapshots].include? "#{vmm_driver}-#{tm_driver}"
926

  
927
        if @options[:detach_snap]
928
          pre_action = :detach_disk
929
          pre_params = [:deploy_id, :disk_target_path, target, target_index]
930

  
931
          post_action = :attach_disk
932
          post_params = [:deploy_id, :disk_target_path, target, target_index,
933
                         drv_message]
903
        # Build the process
904
        if strategy == :live
905
            tm_command_split = tm_command.split
906
            tm_command_split[0] += "_LIVE"
907

  
908
            steps = [
909
                {
910
                    :driver     => :tm,
911
                    :action     => :tm_snap_create_live,
912
                    :parameters => tm_command_split,
913
                    :no_fail    => true
914
                }
915
            ]
934 916
        else
935
          pre_action = :save
936
          pre_params = [:deploy_id, :checkpoint_file, :host]
937

  
938
          post_action = :restore
939
          post_params = [:checkpoint_file, :host, :deploy_id]
940
        end
941

  
942
        steps = []
917
            if strategy == :detach
918
                pre_action = :detach_disk
919
                pre_params = [:deploy_id, :disk_target_path, target, target_index]
920

  
921
                post_action = :attach_disk
922
                post_params = [:deploy_id, :disk_target_path, target, target_index,
923
                               drv_message]
924
            else # suspend
925
                pre_action = :save
926
                pre_params = [:deploy_id, :checkpoint_file, :host]
927

  
928
                post_action = :restore
929
                post_params = [:checkpoint_file, :host, :deploy_id]
930
            end
943 931

  
944
        if !live_snapshot
945
            # Save VM state / detach the disk
946
            steps << {
947
                :driver     => :vmm,
948
                :action     => pre_action,
949
                :parameters => pre_params
950
            }
951
        end
952

  
953
        # Do the snapshot
954
        steps << {
955
            :driver     => :tm,
956
            :action     => :tm_snap_create,
957
            :parameters => tm_command.split,
958
            :no_fail    => true
959
        }
960

  
961
        if !live_snapshot
962
            # Restore VM / attach the disk
963
            steps << {
964
                :driver     => :vmm,
965
                :action     => post_action,
966
                :parameters => post_params,
967
                :fail_actions => [
968
                    {
969
                        :driver     => :tm,
970
                        :action     => :tm_snap_delete,
971
                        :parameters => tm_rollback.split
972
                    }
973
                ]
974
            }
932
            steps = [
933
                {
934
                    :driver     => :vmm,
935
                    :action     => pre_action,
936
                    :parameters => pre_params
937
                },
938
                {
939
                    :driver     => :tm,
940
                    :action     => :tm_snap_create,
941
                    :parameters => tm_command.split,
942
                    :no_fail    => true
943
                },
944
                {
945
                    :driver     => :vmm,
946
                    :action     => post_action,
947
                    :parameters => post_params,
948
                    :fail_actions => [
949
                        {
950
                            :driver     => :tm,
951
                            :action     => :tm_snap_delete,
952
                            :parameters => tm_rollback.split
953
                        }
954
                    ]
955
                }
956
            ]
975 957
        end
976 958

  
977 959
        action.run(steps)
......
981 963
    # DISKSNAPSHOTREVERT action, takes a snapshot of a disk
982 964
    #
983 965
    def disk_snapshot_revert(id, drv_message)
984
        action   = ACTION[:disk_snapshot_revert]
985
        xml_data = decode(drv_message)
986

  
966
        snap_action  = prepare_snap_action(id, drv_message, ACTION[:disk_snapshot_revert])
967
        action       = snap_action[:action]
968
        strategy     = @options[:snapshots_strategy]
969
        drv_message  = snap_action[:drv_message]
970
        target       = snap_action[:target]
971
        target_index = snap_action[:target_index]
972
        xml_data     = snap_action[:xml_data]
973

  
974
        # Get TM command
987 975
        tm_command = ensure_xpath(xml_data, id, action, 'TM_COMMAND') || return
988 976

  
989
        target_xpath = "VM/TEMPLATE/DISK[DISK_SNAPSHOT_ACTIVE='YES']/TARGET"
990
        target       = ensure_xpath(xml_data, id, action, target_xpath) ||return
991

  
992
        target_index = target.downcase[-1..-1].unpack('c').first - 97
993

  
994
        if @options[:detach_snap]
995
            disk   = xml_data.elements[target_xpath].parent
996
            attach = REXML::Element.new('ATTACH')
997

  
998
            attach.add_text('YES')
999
            disk.add(attach)
1000

  
1001
            drv_message = Base64.encode64(xml_data.to_s)
1002
        end
1003

  
1004
        action = VmmAction.new(self, id, :disk_snapshot_revert, drv_message)
1005

  
1006
        if @options[:detach_snap]
977
        # Build the process
978
        if strategy == :detach
1007 979
          pre_action = :detach_disk
1008 980
          pre_params = [:deploy_id, :disk_target_path, target, target_index]
1009 981

  
1010 982
          post_action = :attach_disk
1011 983
          post_params = [:deploy_id, :disk_target_path, target, target_index,
1012 984
                         drv_message]
1013
        else
985
        else # suspend
1014 986
          pre_action = :save
1015 987
          pre_params = [:deploy_id, :checkpoint_file, :host]
1016 988

  
......
1042 1014

  
1043 1015
        action.run(steps)
1044 1016
    end
1017

  
1045 1018
private
1046 1019

  
1047 1020
    def ensure_xpath(xml_data, id, action, xpath)
......
1056 1029
        end
1057 1030
    end
1058 1031

  
1032
    def prepare_snap_action(id, drv_message, action)
1033
        xml_data = decode(drv_message)
1034

  
1035
        # Make sure disk target has been defined
1036
        target_xpath = "VM/TEMPLATE/DISK[DISK_SNAPSHOT_ACTIVE='YES']/TARGET"
1037
        target       = ensure_xpath(xml_data, id, action, target_xpath) || return
1038
        target_index = target.downcase[-1..-1].unpack('c').first - 97
1039

  
1040
        # Always send ATTACH='YES' for the selected target in case it will end
1041
        # up being a 'detach' strategy
1042
        disk   = xml_data.elements[target_xpath].parent
1043
        attach = REXML::Element.new('ATTACH')
1044

  
1045
        attach.add_text('YES')
1046
        disk.add(attach)
1047

  
1048
        drv_message = Base64.encode64(xml_data.to_s)
1049
        action = VmmAction.new(self, id, :disk_snapshot_create, drv_message)
1050

  
1051
        # Determine the strategy
1052
        vmm_driver_path = 'VM/HISTORY_RECORDS/HISTORY/VMMMAD'
1053
        tm_driver_path  = "VM/TEMPLATE/DISK[DISK_SNAPSHOT_ACTIVE='YES']/TM_MAD"
1054

  
1055
        vmm_driver = ensure_xpath(xml_data, id, action, vmm_driver_path) || return
1056
        tm_driver  = ensure_xpath(xml_data, id, action, tm_driver_path)  || return
1057

  
1058
        strategy = @options[:snapshots_strategy]
1059
        if @options[:live_snapshots] && LIVE_DISK_SNAPSHOTS.include?("#{vmm_driver}-#{tm_driver}")
1060
            strategy = :live
1061
        end
1062

  
1063
        {
1064
            :action       => action,
1065
            :strategy     => strategy,
1066
            :drv_message  => drv_message,
1067
            :target       => target,
1068
            :target_index => target_index,
1069
            :xml_data     => xml_data
1070
        }
1071
    end
1059 1072
end
1060 1073

  
1061 1074
################################################################################
......
1064 1077
#
1065 1078
################################################################################
1066 1079

  
1080
LIVE_DISK_SNAPSHOTS = ENV['LIVE_DISK_SNAPSHOTS'].split rescue []
1081

  
1067 1082
opts = GetoptLong.new(
1068
    [ '--retries',        '-r', GetoptLong::OPTIONAL_ARGUMENT ],
1069
    [ '--threads',        '-t', GetoptLong::OPTIONAL_ARGUMENT ],
1070
    [ '--local',          '-l', GetoptLong::REQUIRED_ARGUMENT ],
1071
    [ '--shell',          '-s', GetoptLong::REQUIRED_ARGUMENT ],
1072
    [ '--parallel',       '-p', GetoptLong::NO_ARGUMENT ],
1073
    [ '--detach-snap',    '-d', GetoptLong::NO_ARGUMENT ],
1074
    [ '--live-snapshots', '-i', GetoptLong::REQUIRED_ARGUMENT ]
1083
    [ '--retries',           '-r', GetoptLong::OPTIONAL_ARGUMENT ],
1084
    [ '--threads',           '-t', GetoptLong::OPTIONAL_ARGUMENT ],
1085
    [ '--local',             '-l', GetoptLong::REQUIRED_ARGUMENT ],
1086
    [ '--shell',             '-s', GetoptLong::REQUIRED_ARGUMENT ],
1087
    [ '--parallel',          '-p', GetoptLong::NO_ARGUMENT ],
1088
    [ '--live-snapshots',    '-i', GetoptLong::NO_ARGUMENT ],
1089
    [ '--default-snapshots', '-d', GetoptLong::REQUIRED_ARGUMENT ]
1075 1090
)
1076 1091

  
1077
hypervisor    = ''
1078
retries       = 0
1079
threads       = 15
1080
shell         = 'bash'
1081
local_actions = {}
1082
single_host   = true
1083
detach_snap   = false
1084
live_snapshots= ['kvm-qcow2']
1092
hypervisor         = ''
1093
retries            = 0
1094
threads            = 15
1095
shell              = 'bash'
1096
local_actions      = {}
1097
single_host        = true
1098
live_snapshots     = false
1099
snapshots_strategy = :suspend # Either :detach or :suspend
1085 1100

  
1086 1101
begin
1087 1102
    opts.each do |opt, arg|
1088 1103
        case opt
1089 1104
            when '--retries'
1090
                retries   = arg.to_i
1105
                retries = arg.to_i
1091 1106
            when '--threads'
1092
                threads   = arg.to_i
1107
                threads = arg.to_i
1093 1108
            when '--local'
1094
                local_actions=OpenNebulaDriver.parse_actions_list(arg)
1109
                local_actions = OpenNebulaDriver.parse_actions_list(arg)
1095 1110
            when '--shell'
1096
                shell   = arg
1111
                shell = arg
1097 1112
            when '--parallel'
1098 1113
                single_host = false
1099
            when '--detach-snap'
1100
                detach_snap = true
1114
            when '--default-snapshots'
1115
                snapshots_strategy = arg.to_sym
1101 1116
            when '--live-snapshots'
1102
                live_snapshots = arg.split(',')
1117
                live_snapshots = true
1103 1118
        end
1104 1119
    end
1105 1120
rescue Exception => e
......
1113 1128
end
1114 1129

  
1115 1130
exec_driver = ExecDriver.new(hypervisor,
1116
                :concurrency => threads,
1117
                :retries => retries,
1118
                :local_actions => local_actions,
1119
                :shell => shell,
1120
                :single_host => single_host,
1121
                :detach_snap => detach_snap,
1122
                :live_snapshots => live_snapshots)
1131
                :concurrency        => threads,
1132
                :retries            => retries,
1133
                :local_actions      => local_actions,
1134
                :shell              => shell,
1135
                :single_host        => single_host,
1136
                :snapshots_strategy => snapshots_strategy,
1137
                :live_snapshots     => live_snapshots)
1123 1138

  
1124 1139
exec_driver.start_driver
src/vmm_mad/exec/vmm_execrc
13 13
# See the License for the specific language governing permissions and        #
14 14
# limitations under the License.                                             #
15 15
#--------------------------------------------------------------------------- #
16

  
17
# Space separated list of VMM-TM pairs that support live disk snapshots. VMM
18
# and TM must be separated by '-'
19
LIVE_DISK_SNAPSHOTS="kvm-qcow2"

Also available in: Unified diff