From 1e9e52138d7ab6f1f44948d25ad6cbfc062a6b28 Mon Sep 17 00:00:00 2001
From: Vlastimil Holer <vholer@opennebula.org>
Date: Tue, 29 Aug 2017 17:28:48 +0200
Subject: [PATCH] F #1310: Added support for multiple deployment modes. This
 commit adds support of SSH mode for a Ceph datastore.

Author: Vlastimil Holer <vholer@opennebula.org>
Author: juanmont <jjmontiel@opennebula.org>
(cherry picked from commit 8ab9c02102e2e7f72c4835aa819bab49c229ef45)
---
 include/PoolObjectSQL.h                       |   6 +
 include/VirtualMachineDisk.h                  |  21 +++-
 share/etc/oned.conf                           |   3 +-
 src/datastore/Datastore.cc                    |  98 +++++++++++++++-
 .../form-panels/create/wizard-tabs/storage.js |  75 +++++++++++-
 .../create/wizard-tabs/storage/disk-tab.js    |   1 +
 .../create/wizard-tabs/storage/html.hbs       |  17 +++
 src/tm_mad/ceph/clone                         |  66 +++++++----
 src/tm_mad/ceph/cpds                          |  55 +++++++--
 src/tm_mad/ceph/delete                        |  26 +++--
 src/tm_mad/ceph/ln                            |  36 ++++--
 src/tm_mad/ceph/mvds                          | 107 +++++++++++++++++-
 src/tm_mad/ceph/resize                        |  15 ++-
 src/tm_mad/ceph/snap_create                   |   9 +-
 src/tm_mad/ceph/snap_create_live              |   9 +-
 src/tm_mad/ceph/snap_delete                   |   9 +-
 src/tm_mad/ceph/snap_revert                   |   9 +-
 src/vm/VirtualMachine.cc                      |  41 +++++--
 src/vm/VirtualMachineDisk.cc                  |  67 ++++++++++-
 19 files changed, 594 insertions(+), 76 deletions(-)

diff --git a/include/PoolObjectSQL.h b/include/PoolObjectSQL.h
index d5a0caa131..b1759cdd74 100644
--- a/include/PoolObjectSQL.h
+++ b/include/PoolObjectSQL.h
@@ -376,6 +376,12 @@ public:
      */
 	template<typename T>
     bool get_template_attribute(const char * name, T& value) const
+    {
+        return obj_template->get(name,value);
+    }
+
+	template<typename T>
+    bool get_template_attribute(const string& name, T& value) const
     {
         return obj_template->get(name,value);
     }
diff --git a/include/VirtualMachineDisk.h b/include/VirtualMachineDisk.h
index 41634ef420..b4f39133e2 100644
--- a/include/VirtualMachineDisk.h
+++ b/include/VirtualMachineDisk.h
@@ -162,6 +162,11 @@ public:
      */
     int get_image_id(int &id, int uid);
 
+    /**
+     *  Return the TM_MAD_SYSTEM attribute
+     */
+    std::string get_tm_mad_system();
+
     /* ---------------------------------------------------------------------- */
     /* Image Manager Interface                                                */
     /* ---------------------------------------------------------------------- */
@@ -320,6 +325,13 @@ public:
      */
     void datastore_sizes(int& ds_id, long long& img_sz, long long& sys_sz);
 
+    /**
+     *  Update the TYPE and DISK_TYPE attributes based on the system DS
+     *  name
+     *    @param ds_name of the system ds tm_mad
+     */
+    void set_types(const string& ds_name);
+
 private:
 
     Snapshots * snapshots;
@@ -478,13 +490,15 @@ public:
      *  Get all disk images for this Virtual Machine
      *  @param vm_id of the VirtualMachine
      *  @param uid of owner
+     *  @param tm_mad_sys tm_mad_sys mode to deploy the disks
      *  @param disks list of DISK Attribute in VirtualMachine Template
      *  @param context attribute, 0 if none
      *  @param error_str Returns the error reason, if any
      *  @return 0 if success
      */
-    int get_images(int vm_id, int uid, vector<Attribute *> disks,
-            VectorAttribute * context, std::string& error_str);
+    int get_images(int vm_id, int uid, const std::string& tm_mad_sys,
+            vector<Attribute *> disks, VectorAttribute * context,
+            std::string& error_str);
 
     /**
      *  Release the images in the disk set
@@ -562,7 +576,8 @@ public:
      *     @return Pointer to the new disk or 0 in case of error
      */
     VirtualMachineDisk * set_up_attach(int vmid, int uid, int cluster_id,
-            VectorAttribute * vdisk, VectorAttribute * vcontext, string& error);
+            VectorAttribute * vdisk, const std::string& tsys,
+            VectorAttribute * vcontext, string& error);
 
     /* ---------------------------------------------------------------------- */
     /* Save as Interface                                                      */
diff --git a/share/etc/oned.conf b/share/etc/oned.conf
index 72fa1459b2..82cb872cf8 100644
--- a/share/etc/oned.conf
+++ b/share/etc/oned.conf
@@ -1091,7 +1091,8 @@ TM_MAD_CONF = [
 
 TM_MAD_CONF = [
     NAME = "ceph", LN_TARGET = "NONE", CLONE_TARGET = "SELF", SHARED = "YES",
-    DS_MIGRATE = "NO", DRIVER = "raw", ALLOW_ORPHANS="yes"
+    DS_MIGRATE = "NO", DRIVER = "raw", ALLOW_ORPHANS="yes", TM_MAD_SYSTEM = "ssh",
+    LN_TARGET_SSH = "SYSTEM", CLONE_TARGET_SSH = "SYSTEM", DISK_TYPE_SSH = "FILE"
 ]
 
 TM_MAD_CONF = [
diff --git a/src/datastore/Datastore.cc b/src/datastore/Datastore.cc
index def084789a..77d197cdc4 100644
--- a/src/datastore/Datastore.cc
+++ b/src/datastore/Datastore.cc
@@ -101,7 +101,7 @@ void Datastore::disk_attribute(
         VirtualMachineDisk *    disk,
         const vector<string>&   inherit_attrs)
 {
-    string st;
+    string st, tm_mad;
     string inherit_val;
     string current_val;
     string type;
@@ -116,14 +116,46 @@ void Datastore::disk_attribute(
 
     disk->replace("CLUSTER_ID", one_util::join(cluster_ids, ','));
 
-    get_template_attribute("CLONE_TARGET", st);
+    tm_mad = disk->get_tm_mad_system();
+
+    if (!tm_mad.empty())
+    {
+        string tm_mad_t = one_util::trim(tm_mad);
+        tm_mad = one_util::toupper(tm_mad_t);
+    }
+
+    if (!tm_mad.empty())
+    {
+        get_template_attribute("CLONE_TARGET_" + tm_mad, st);
+
+        if (st.empty())
+        {
+            get_template_attribute("CLONE_TARGET", st);
+        }
+    }
+    else
+    {
+        get_template_attribute("CLONE_TARGET", st);
+    }
 
     if(!st.empty())
     {
         disk->replace("CLONE_TARGET", st);
     }
 
-    get_template_attribute("LN_TARGET", st);
+    if (!tm_mad.empty())
+    {
+        get_template_attribute("LN_TARGET_" + tm_mad, st);
+
+        if (st.empty())
+        {
+            get_template_attribute("LN_TARGET", st);
+        }
+    }
+    else
+    {
+        get_template_attribute("LN_TARGET", st);
+    }
 
     if(!st.empty())
     {
@@ -141,7 +173,16 @@ void Datastore::disk_attribute(
         }
     }
 
-    if (disk->is_volatile())
+    if (!tm_mad.empty())
+    {
+        get_template_attribute("DISK_TYPE_" + tm_mad, st);
+
+        if (!st.empty())
+        {
+            disk->set_types(st);
+        }
+    }
+    else if (disk->is_volatile())
     {
         disk->replace("DISK_TYPE", Image::disk_type_to_str(get_disk_type()));
     }
@@ -280,9 +321,10 @@ int Datastore::set_tm_mad(string &tm_mad, string &error_str)
 {
     const VectorAttribute* vatt;
 
-    string st;
+    std::vector<std::string> modes;
 
     ostringstream oss;
+    std::stringstream ss;
 
     if ( Nebula::instance().get_tm_conf_attribute(tm_mad, vatt) != 0 )
     {
@@ -327,6 +369,52 @@ int Datastore::set_tm_mad(string &tm_mad, string &error_str)
     }
     else
     {
+        string st = vatt->vector_value("TM_MAD_SYSTEM");
+
+        if (!st.empty())
+        {
+            std::vector<std::string>::iterator it;
+
+            replace_template_attribute("TM_MAD_SYSTEM", st);
+
+            modes = one_util::split(st, ',', true);
+
+            string s;
+
+            for (it = modes.begin() ; it != modes.end(); ++it)
+            {
+                string tm_mad_t = one_util::trim(*it);
+                string tm_mad = one_util::toupper(tm_mad_t);
+
+                st = vatt->vector_value("LN_TARGET_" + tm_mad);
+
+                if (check_tm_target_type(st) == -1)
+                {
+                    goto error;
+                }
+
+                replace_template_attribute("LN_TARGET_" + tm_mad, st);
+
+                st = vatt->vector_value("CLONE_TARGET_" + tm_mad);
+
+                if (check_tm_target_type(st) == -1)
+                {
+                    goto error;
+                }
+
+                replace_template_attribute("CLONE_TARGET_" + tm_mad, st);
+
+                st = vatt->vector_value("DISK_TYPE_" + tm_mad);
+
+                if (st.empty())
+                {
+                    goto error;
+                }
+
+                replace_template_attribute("DISK_TYPE_" + tm_mad, st);
+            }
+        }
+
         st = vatt->vector_value("LN_TARGET");
 
         if (check_tm_target_type(st) == -1)
diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage.js
index 7f168e40a8..cfc94b27fe 100644
--- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage.js
+++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage.js
@@ -26,6 +26,7 @@ define(function(require) {
   var WizardFields = require('utils/wizard-fields');
   var DiskTab = require('./storage/disk-tab');
   var UniqueId = require('utils/unique-id');
+  var OpenNebula = require('opennebula');
 
   /*
     TEMPLATES
@@ -111,7 +112,7 @@ define(function(require) {
   }
 
   function _retrieve(context) {
-    var templateJSON = {};
+    var templateJSON = WizardFields.retrieve(context);
     var disksJSON = [];
     var diskJSON;
     $.each(this.diskTabObjects, function(id, diskTab) {
@@ -131,6 +132,14 @@ define(function(require) {
   function _fill(context, templateJSON) {
     var that = this;
     var disks = templateJSON.DISK
+    var modes = [];
+    var groupDropdownOptions = '<option value=></option>';
+
+    var tmpl_tm_mad_system;
+    if (templateJSON.TM_MAD_SYSTEM){
+      tmpl_tm_mad_system = templateJSON.TM_MAD_SYSTEM;
+    }
+
     if (disks instanceof Array) {
       $.each(disks, function(diskId, diskJSON) {
         if (diskId > 0) {
@@ -139,11 +148,75 @@ define(function(require) {
 
         var diskTab = that.diskTabObjects[that.numberOfDisks];
         var diskContext = $('#' + diskTab.diskTabId, context);
+        OpenNebula.Image.show({
+          timeout: true,
+          data : {
+            name: diskJSON.IMAGE,
+            uname: diskJSON.IMAGE_UNAME
+          },
+          success: function(request, obj_file){
+            OpenNebula.Datastore.show({
+              data : {
+                id: obj_file.IMAGE.DATASTORE_ID
+              },
+              timeout: true,
+              success: function(request, ds){
+                  var tm_mad_system = ds.DATASTORE.TEMPLATE.TM_MAD_SYSTEM;
+                  if (tm_mad_system) {
+                    tm_mad_system.split(",").map(function(item) {
+                      var i = item.trim();
+                      if(modes.indexOf(i) === -1){
+                        modes.push(i);
+                        groupDropdownOptions += '<option elem_id="'+i+'" value="'+i+'">'+i+'</option>';
+                      }
+                    });
+                    $('select#TM_MAD_SYSTEM', context).html(groupDropdownOptions);
+                    if ( tmpl_tm_mad_system ){
+                      $('select#TM_MAD_SYSTEM', context).val(tmpl_tm_mad_system);
+                    }
+                  }
+              }
+            });
+          }
+        });
         diskTab.fill(diskContext, diskJSON);
       });
     } else if (disks instanceof Object) {
       var diskTab = that.diskTabObjects[that.numberOfDisks];
       var diskContext = $('#' + diskTab.diskTabId, context);
+
+      OpenNebula.Image.show({
+        timeout: true,
+        data : {
+          name: disks.IMAGE,
+          uname: disks.IMAGE_UNAME
+        },
+        success: function(request, obj_file){
+          OpenNebula.Datastore.show({
+            data : {
+              id: obj_file.IMAGE.DATASTORE_ID
+            },
+            timeout: true,
+            success: function(request, ds){
+              var tm_mad_system = ds.DATASTORE.TEMPLATE.TM_MAD_SYSTEM;
+              if (tm_mad_system) {
+                tm_mad_system.split(",").map(function(item) {
+                  var i = item.trim();
+                  if(modes.indexOf(i) === -1){
+                    modes.push(i);
+                    groupDropdownOptions += '<option elem_id="'+i+'" value="'+i+'">'+i+'</option>';
+                  }
+                });
+                $('select#TM_MAD_SYSTEM', context).html(groupDropdownOptions);
+                if ( tmpl_tm_mad_system ){
+                  $('select#TM_MAD_SYSTEM', context).val(tmpl_tm_mad_system);
+                }
+              }
+            }
+          });
+        }
+      });
+
       diskTab.fill(diskContext, disks);
     }
 
diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/disk-tab.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/disk-tab.js
index 75081e498d..d06386e027 100644
--- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/disk-tab.js
+++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/disk-tab.js
@@ -218,6 +218,7 @@ define(function(require) {
         }
 
         this.imageTable.selectResourceTableSelect(selectedResources);
+
       } else if (templateJSON.IMAGE != undefined && templateJSON.IMAGE_UNAME != undefined) {
         var selectedResources = {
           names : {
diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/html.hbs b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/html.hbs
index 73a90a85c8..9ac62cc8d5 100644
--- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/html.hbs
+++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/html.hbs
@@ -13,6 +13,23 @@
 {{! See the License for the specific language governing permissions and        }}
 {{! limitations under the License.                                             }}
 {{! -------------------------------------------------------------------------- }}
+<div class="row">
+  <div class="medium-2 columns"></div>
+  <div class="medium-10 columns">
+    <fieldset>
+      <legend>{{tr "Deployment Requirements"}}</legend>
+      <div class="row">
+        <div class="medium-12 columns">
+          <label for="TM_MAD_SYSTEM">
+            {{tr "Deploy Mode"}}
+          </label>
+          <select wizard_field="TM_MAD_SYSTEM" id="TM_MAD_SYSTEM" name="TM_MAD_SYSTEM">
+          </select>
+        </div>
+      </div>
+    </fieldset>
+  </div>
+</div>
 <div class="row collapse">
   <div class="medium-2 columns">
     <ul class="tabs vertical" id="{{linksContainerId}}" data-tabs>
diff --git a/src/tm_mad/ceph/clone b/src/tm_mad/ceph/clone
index fd1507da0f..ac1325a673 100755
--- a/src/tm_mad/ceph/clone
+++ b/src/tm_mad/ceph/clone
@@ -51,6 +51,9 @@ CEPH_UTILS=${DRIVER_PATH}/../../datastore/ceph/ceph_utils.sh
 DST_HOST=`arg_host $DST`
 
 SRC_PATH=`arg_path $SRC`
+DST_PATH=`arg_path $DST`
+
+DST_DIR=`dirname $DST_PATH`
 
 DISK_ID=$(echo $DST|awk -F. '{print $NF}')
 RBD_DST="${SRC_PATH}-${VM_ID}-${DISK_ID}"
@@ -65,18 +68,20 @@ unset i j XPATH_ELEMENTS
 
 while IFS= read -r -d '' element; do
         XPATH_ELEMENTS[i++]="$element"
-        done < <(onevm show -x $VM_ID| $XPATH  \
-                            /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER \
-                            /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_KEY \
-                            /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF \
-                            /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SIZE \
-                            /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/ORIGINAL_SIZE)
+done < <(onevm show -x $VM_ID| $XPATH  \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_KEY \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SIZE \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/ORIGINAL_SIZE \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TYPE )
 
 CEPH_USER="${XPATH_ELEMENTS[j++]}"
 CEPH_KEY="${XPATH_ELEMENTS[j++]}"
 CEPH_CONF="${XPATH_ELEMENTS[j++]}"
 SIZE="${XPATH_ELEMENTS[j++]}"
 ORIGINAL_SIZE="${XPATH_ELEMENTS[j++]}"
+TYPE="${XPATH_ELEMENTS[j++]}"
 
 #-------------------------------------------------------------------------------
 # Clone the image and create @snap if it does not exists
@@ -94,26 +99,49 @@ if [ -n "$CEPH_CONF" ]; then
     RBD="$RBD --conf ${CEPH_CONF}"
 fi
 
-CLONE_CMD=$(cat <<EOF
-    RBD="${RBD}"
+if [ "${TYPE}" = 'FILE' ]; then
+    ssh_make_path $DST_HOST $DST_DIR
 
-    $RBD info $RBD_DST >/dev/null 2>&1 && exit 0
+    CLONE_CMD=$(cat <<EOF
+        RBD="${RBD}"
 
-    rbd_make_snap $SRC_PATH
+        rbd_make_snap $SRC_PATH
 
-    set -e -o pipefail
+        set -e -o pipefail
 
-    if [ "\$(rbd_format $SRC_PATH)" = "2" ]; then
-        $RBD clone "$SRC_PATH@snap" $RBD_DST
-    else
-        $RBD copy $SRC_PATH $RBD_DST
-    fi
+        if [ "\$(rbd_format $SRC_PATH)" = "2" ]; then
+            $RBD export "$SRC_PATH@snap" $DST_PATH
+        else
+            $RBD export $SRC_PATH $DST_PATH
+        fi
 
-    if [ -n "$ORIGINAL_SIZE" -a "$SIZE" -gt "$ORIGINAL_SIZE" ]; then
-        $RBD resize $RBD_DST --size $SIZE
-    fi
+        if [ -n "$ORIGINAL_SIZE" -a "$SIZE" -gt "$ORIGINAL_SIZE" ]; then
+            qemu-img resize ${DST_PATH} ${SIZE}M
+        fi
 EOF
 )
+else
+    CLONE_CMD=$(cat <<EOF
+        RBD="${RBD}"
+
+        $RBD info $RBD_DST >/dev/null 2>&1 && exit 0
+
+        rbd_make_snap $SRC_PATH
+
+        set -e -o pipefail
+
+        if [ "\$(rbd_format $SRC_PATH)" = "2" ]; then
+            $RBD clone "$SRC_PATH@snap" $RBD_DST
+        else
+            $RBD copy $SRC_PATH $RBD_DST
+        fi
+
+        if [ -n "$ORIGINAL_SIZE" -a "$SIZE" -gt "$ORIGINAL_SIZE" ]; then
+            $RBD resize $RBD_DST --size $SIZE
+        fi
+EOF
+)
+fi
 
 ssh_exec_and_log_stdin "$DST_HOST" "$CLONE_CMD" "$CEPH_UTILS" \
                  "Error cloning $SRC_PATH to $RBD_DST in $DST_HOST"
diff --git a/src/tm_mad/ceph/cpds b/src/tm_mad/ceph/cpds
index 8c93696be7..20be7ce2ee 100755
--- a/src/tm_mad/ceph/cpds
+++ b/src/tm_mad/ceph/cpds
@@ -43,6 +43,7 @@ DRIVER_PATH=$(dirname $0)
 
 source $TMCOMMON
 source ${DRIVER_PATH}/../../datastore/ceph/ceph.conf
+source ${DRIVER_PATH}/../../vmm/kvm/kvmrc
 
 CEPH_UTILS=${DRIVER_PATH}/../../datastore/ceph/ceph_utils.sh
 
@@ -50,6 +51,7 @@ CEPH_UTILS=${DRIVER_PATH}/../../datastore/ceph/ceph_utils.sh
 # Set dst path and dir
 #-------------------------------------------------------------------------------
 
+SRC_PATH=`arg_path $SRC`
 SRC_HOST=`arg_host $SRC`
 RBD_SRC=`arg_path $SRC`
 
@@ -66,17 +68,21 @@ unset i j XPATH_ELEMENTS
 while IFS= read -r -d '' element; do
     XPATH_ELEMENTS[i++]="$element"
 done < <(onevm show -x $VM_ID| $XPATH \
+                    /VM/DEPLOY_ID \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_KEY \
-                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF)
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TYPE )
 
+DEPLOY_ID="${XPATH_ELEMENTS[j++]}"
 RBD_SRC="${XPATH_ELEMENTS[j++]}"
 CLONE="${XPATH_ELEMENTS[j++]}"
 CEPH_USER="${XPATH_ELEMENTS[j++]}"
 CEPH_KEY="${XPATH_ELEMENTS[j++]}"
 CEPH_CONF="${XPATH_ELEMENTS[j++]}"
+TYPE="${XPATH_ELEMENTS[j++]}"
 
 #-------------------------------------------------------------------------------
 # Copy Image back to the datastore
@@ -100,25 +106,50 @@ if [ -n "$CEPH_CONF" ]; then
     RBD="$RBD --conf ${CEPH_CONF}"
 fi
 
-COPY_CMD=$(cat <<EOF
-    RBD="${RBD}"
+if [ "$RBD_FORMAT" = "2" ]; then
+    FORMAT_OPT="--image-format 2"
+fi
 
+if [ "${TYPE}" = 'FILE' ]; then
     if [ "$SNAP_ID" != "-1" ]; then
-        rbd_check_2 $RBD_DST
+        error_message "$script_name: Operation not supported on disk type ${TYPE} with snapshots"
+        exit 1
+    fi
 
-        RBD_DST=\$(rbd_find_snap $RBD_DST $SNAP_ID)
-
-        if [ -z "\$RBD_DST" ]; then
-            echo "Target RBD not found." >&2
+    COPY_CMD=$(cat <<EOF
+        if virsh -c $LIBVIRT_URI domfsfreeze $DEPLOY_ID ; then
+            trap "virsh -c $LIBVIRT_URI domfsthaw $DEPLOY_ID" EXIT TERM INT HUP
+        elif virsh -c $LIBVIRT_URI suspend $DEPLOY_ID; then
+            trap "virsh -c $LIBVIRT_URI resume $DEPLOY_ID" EXIT TERM INT HUP
+        else
+            echo "Could not domfsfreeze or suspend domain" >&2
             exit 1
         fi
 
-        RBD_DST=\$RBD_DST@$SNAP_ID
-    fi
-
-    $RBD copy $RBD_DST $DST
+        $RBD import $FORMAT_OPT $SRC_PATH $DST
 EOF
 )
+else
+    COPY_CMD=$(cat <<EOF
+        RBD="${RBD}"
+
+        if [ "$SNAP_ID" != "-1" ]; then
+            rbd_check_2 $RBD_DST
+
+            RBD_DST=\$(rbd_find_snap $RBD_DST $SNAP_ID)
+
+            if [ -z "\$RBD_DST" ]; then
+                echo "Target RBD not found." >&2
+                exit 1
+            fi
+
+            RBD_DST=\$RBD_DST@$SNAP_ID
+        fi
+
+        $RBD copy $RBD_DST $DST
+EOF
+)
+fi
 
 ssh_exec_and_log_stdin "$SRC_HOST" "$COPY_CMD" "$CEPH_UTILS" \
                  "Error cloning $RBD_DST to $DST in $SRC_HOST"
diff --git a/src/tm_mad/ceph/delete b/src/tm_mad/ceph/delete
index 1d9e76f796..84ae76100b 100755
--- a/src/tm_mad/ceph/delete
+++ b/src/tm_mad/ceph/delete
@@ -115,7 +115,8 @@ done < <(onevm show -x $VM_ID | $XPATH \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_KEY \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF \
-                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/POOL_NAME)
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/POOL_NAME \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TYPE )
 
 SRC="${XPATH_ELEMENTS[j++]}"
 CLONE="${XPATH_ELEMENTS[j++]}"
@@ -123,6 +124,7 @@ CEPH_USER="${XPATH_ELEMENTS[j++]}"
 CEPH_KEY="${XPATH_ELEMENTS[j++]}"
 CEPH_CONF="${XPATH_ELEMENTS[j++]}"
 POOL_NAME="${XPATH_ELEMENTS[j++]:-$POOL_NAME}"
+TYPE="${XPATH_ELEMENTS[j++]}"
 
 # No need to delete no cloned images
 if [ "$CLONE" = "NO" ]; then
@@ -157,20 +159,24 @@ fi
 
 log "Deleting $DST_PATH"
 
-DELETE_CMD=$(cat <<EOF
-    RBD="${RBD}"
+if [ "${TYPE}" = 'FILE' ]; then
+    exit 0
+else
+    DELETE_CMD=$(cat <<EOF
+        RBD="${RBD}"
 
-    if [ "\$(rbd_format $RBD_SRC)" = "2" ]; then
-        rbd_rm_r \$(rbd_top_parent $RBD_SRC)
+        if [ "\$(rbd_format $RBD_SRC)" = "2" ]; then
+            rbd_rm_r \$(rbd_top_parent $RBD_SRC)
 
-        if [ -n "$RBD_SNAP" ]; then
-            rbd_rm_snap $SRC $RBD_SNAP
+            if [ -n "$RBD_SNAP" ]; then
+                rbd_rm_snap $SRC $RBD_SNAP
+            fi
+        else
+            $RBD rm $RBD_SRC
         fi
-    else
-        $RBD rm $RBD_SRC
-    fi
 EOF
 )
+fi
 
 ssh_exec_and_log_stdin "$DST_HOST" "$DELETE_CMD" "$CEPH_UTILS" \
                  "Error deleting $RBD_SRC in $DST_HOST"
diff --git a/src/tm_mad/ceph/ln b/src/tm_mad/ceph/ln
index 669eaeab1a..63fd9276a4 100755
--- a/src/tm_mad/ceph/ln
+++ b/src/tm_mad/ceph/ln
@@ -56,6 +56,9 @@ DISK_ID=$(echo $DST|awk -F. '{print $NF}')
 #-------------------------------------------------------------------------------
 
 SRC_PATH=`arg_path $SRC`
+DST_PATH=`arg_path $DST`
+
+DST_DIR=`dirname $DST_PATH`
 
 XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
 
@@ -63,14 +66,16 @@ unset i j XPATH_ELEMENTS
 
 while IFS= read -r -d '' element; do
         XPATH_ELEMENTS[i++]="$element"
-        done < <(onevm show -x $VM_ID| $XPATH  \
-                            /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER \
-                            /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_KEY \
-                            /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF)
+done < <(onevm show -x $VM_ID| $XPATH  \
+                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER \
+                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_KEY \
+                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF \
+                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TYPE )
 
 CEPH_USER="${XPATH_ELEMENTS[j++]}"
 CEPH_KEY="${XPATH_ELEMENTS[j++]}"
 CEPH_CONF="${XPATH_ELEMENTS[j++]}"
+TYPE="${XPATH_ELEMENTS[j++]}"
 
 #-------------------------------------------------------------------------------
 # Remove any @snap in image (non persistent -> persistnet)
@@ -88,13 +93,28 @@ if [ -n "$CEPH_CONF" ]; then
     RBD="$RBD --conf ${CEPH_CONF}"
 fi
 
-CLONE_CMD=$(cat <<EOF
-    RBD="${RBD}"
+if [ "${TYPE}" = 'FILE' ]; then
+    ssh_make_path $DST_HOST $DST_DIR
 
-    rbd_rm_snap $SRC_PATH
+    LN_CMD=$(cat <<EOF
+        RBD="${RBD}"
+
+        rbd_rm_snap $SRC_PATH
+
+        set -e -o pipefail
+
+        $RBD export $SRC_PATH $DST_PATH
 EOF
 )
+else
+    LN_CMD=$(cat <<EOF
+        RBD="${RBD}"
 
-ssh_exec_and_log_stdin "$DST_HOST" "$CLONE_CMD" "$CEPH_UTILS" \
+        rbd_rm_snap $SRC_PATH
+EOF
+)
+fi
+
+ssh_exec_and_log_stdin "$DST_HOST" "$LN_CMD" "$CEPH_UTILS" \
                  "Error cloning $SRC_PATH to $RBD_DST in $DST_HOST"
 exit 0
diff --git a/src/tm_mad/ceph/mvds b/src/tm_mad/ceph/mvds
index fed6dd2fe6..aaa5d1442f 100755
--- a/src/tm_mad/ceph/mvds
+++ b/src/tm_mad/ceph/mvds
@@ -16,4 +16,109 @@
 # limitations under the License.                                             #
 #--------------------------------------------------------------------------- #
 
-exit 0
+# mvds host:remote_system_ds/disk.i fe:SOURCE vmid dsid
+#   - fe is the front-end hostname
+#   - SOURCE is the path of the disk image in the form DS_BASE_PATH/disk
+#   - host is the target host to deploy the VM
+#   - remote_system_ds is the path for the system datastore in the host
+#   - vmid is the id of the VM
+#   - dsid is the target datastore (0 is the system datastore)
+
+SRC=$1
+DST=$2
+VMID=$3
+DSID=$4
+
+#--------------------------------------------------------------------------------
+
+if [ -z "${ONE_LOCATION}" ]; then
+    TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh
+    LIB_LOCATION=/usr/lib/one
+else
+    TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh
+    LIB_LOCATION=$ONE_LOCATION/lib
+fi
+
+DRIVER_PATH=$(dirname $0)
+
+source $TMCOMMON
+source ${DRIVER_PATH}/../../datastore/ceph/ceph.conf
+
+CEPH_UTILS=${DRIVER_PATH}/../../datastore/ceph/ceph_utils.sh
+
+#-------------------------------------------------------------------------------
+# Set dst path and dir
+#-------------------------------------------------------------------------------
+
+SRC_PATH=`arg_path $SRC`
+SRC_HOST=`arg_host $SRC`
+RBD_SRC=`arg_path $SRC`
+
+#-------------------------------------------------------------------------------
+# Get Image information
+#-------------------------------------------------------------------------------
+
+DISK_ID=$(echo "$RBD_SRC" | $AWK -F. '{print $NF}')
+
+XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
+
+unset i j XPATH_ELEMENTS
+
+while IFS= read -r -d '' element; do
+    XPATH_ELEMENTS[i++]="$element"
+done < <(onevm show -x $VMID| $XPATH \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_KEY \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TYPE \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SIZE \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/ORIGINAL_SIZE )
+
+RBD_SRC="${XPATH_ELEMENTS[j++]}"
+CLONE="${XPATH_ELEMENTS[j++]}"
+CEPH_USER="${XPATH_ELEMENTS[j++]}"
+CEPH_KEY="${XPATH_ELEMENTS[j++]}"
+CEPH_CONF="${XPATH_ELEMENTS[j++]}"
+TYPE="${XPATH_ELEMENTS[j++]}"
+SIZE="${XPATH_ELEMENTS[j++]}"
+ORIGINAL_SIZE="${XPATH_ELEMENTS[j++]}"
+
+#-------------------------------------------------------------------------------
+# Copy Image back to the datastore
+#-------------------------------------------------------------------------------
+
+if [ -n "$CEPH_USER" ]; then
+    RBD="$RBD --id ${CEPH_USER}"
+fi
+
+if [ -n "$CEPH_KEY" ]; then
+    RBD="$RBD --keyfile ${CEPH_KEY}"
+fi
+
+if [ -n "$CEPH_CONF" ]; then
+    RBD="$RBD --conf ${CEPH_CONF}"
+fi
+
+if [ "${TYPE}" = 'FILE' ]; then
+    MVDS_CMD=$(cat <<EOF
+        RBD="${RBD}"
+
+        set -e -o pipefail
+
+        if [ -n "$ORIGINAL_SIZE" -a "$SIZE" -gt "$ORIGINAL_SIZE" ]; then
+            $RBD resize $RBD_SRC --size $SIZE
+        fi
+
+        $SUDO $RBD map $RBD_SRC
+        trap "$SUDO $RBD unmap /dev/rbd/$RBD_SRC" EXIT TERM INT HUP
+        $DD if=$SRC_PATH of=/dev/rbd/$RBD_SRC bs=64k
+EOF
+)
+else
+    exit 0
+fi
+
+ssh_exec_and_log_stdin "$SRC_HOST" "$MVDS_CMD" "$CEPH_UTILS" \
+                 "Error copying $RBD_SRC to $DST in $SRC_HOST" #??
diff --git a/src/tm_mad/ceph/resize b/src/tm_mad/ceph/resize
index 249ec6f048..fc1d12848d 100755
--- a/src/tm_mad/ceph/resize
+++ b/src/tm_mad/ceph/resize
@@ -64,7 +64,8 @@ done < <(onevm show -x $VM_ID| $XPATH \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_KEY \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/PERSISTENT \
-                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/POOL_NAME )
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/POOL_NAME \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TYPE )
 
 RBD_SRC="${XPATH_ELEMENTS[j++]}"
 CEPH_USER="${XPATH_ELEMENTS[j++]}"
@@ -72,6 +73,7 @@ CEPH_KEY="${XPATH_ELEMENTS[j++]}"
 CEPH_CONF="${XPATH_ELEMENTS[j++]}"
 PERSISTENT="${XPATH_ELEMENTS[j++]}"
 POOL_NAME="${XPATH_ELEMENTS[j++]:-$POOL_NAME}"
+TYPE="${XPATH_ELEMENTS[j++]}"
 
 if [ -n "${RBD_SRC}" ]; then
     if [ "${PERSISTENT}" = 'YES' ]; then
@@ -99,10 +101,17 @@ if [ -n "$CEPH_CONF" ]; then
     RBD="$RBD --conf ${CEPH_CONF}"
 fi
 
-RESIZE_CMD=$(cat <<EOF
-    $RBD resize --size ${SIZE} $RBD_DST
+if [ "${TYPE}" = 'FILE' ]; then
+    RESIZE_CMD=$(cat <<EOF
+        ${QEMU_IMG} resize "${SRC_PATH}" "${SIZE}M"
 EOF
 )
+else
+    RESIZE_CMD=$(cat <<EOF
+        $RBD resize --size ${SIZE} $RBD_DST
+EOF
+)
+fi
 
 ssh_exec_and_log_stdin "$SRC_HOST" "$RESIZE_CMD" "$CEPH_UTILS" \
                  "Error resizing disk $RBD_DST"
diff --git a/src/tm_mad/ceph/snap_create b/src/tm_mad/ceph/snap_create
index e4f09e4f0c..5adeb2f929 100755
--- a/src/tm_mad/ceph/snap_create
+++ b/src/tm_mad/ceph/snap_create
@@ -64,13 +64,15 @@ done < <(onevm show -x $VM_ID| $XPATH \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_KEY \
-                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF)
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TYPE )
 
 RBD_SRC="${XPATH_ELEMENTS[j++]}"
 CLONE="${XPATH_ELEMENTS[j++]}"
 CEPH_USER="${XPATH_ELEMENTS[j++]}"
 CEPH_KEY="${XPATH_ELEMENTS[j++]}"
 CEPH_CONF="${XPATH_ELEMENTS[j++]}"
+TYPE="${XPATH_ELEMENTS[j++]}"
 
 if [ "$CLONE" = "NO" ]; then
     RBD_DST="${RBD_SRC}"
@@ -94,6 +96,11 @@ if [ -n "$CEPH_CONF" ]; then
     RBD="$RBD --conf ${CEPH_CONF}"
 fi
 
+if [ "${TYPE}" != 'RBD' ]; then
+    error_message "$script_name: Operation not supported on disk type ${TYPE}"
+    exit 1
+fi
+
 SNAP_CREATE_CMD=$(cat <<EOF
     set -e -o pipefail
 
diff --git a/src/tm_mad/ceph/snap_create_live b/src/tm_mad/ceph/snap_create_live
index ec645b610e..9ff45c1e8d 100755
--- a/src/tm_mad/ceph/snap_create_live
+++ b/src/tm_mad/ceph/snap_create_live
@@ -66,7 +66,8 @@ done < <(onevm show -x $VM_ID| $XPATH \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_KEY \
-                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF)
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TYPE )
 
 DEPLOY_ID="${XPATH_ELEMENTS[j++]}"
 RBD_SRC="${XPATH_ELEMENTS[j++]}"
@@ -74,6 +75,7 @@ CLONE="${XPATH_ELEMENTS[j++]}"
 CEPH_USER="${XPATH_ELEMENTS[j++]}"
 CEPH_KEY="${XPATH_ELEMENTS[j++]}"
 CEPH_CONF="${XPATH_ELEMENTS[j++]}"
+TYPE="${XPATH_ELEMENTS[j++]}"
 
 if [ "$CLONE" = "NO" ]; then
     RBD_DST="${RBD_SRC}"
@@ -97,6 +99,11 @@ if [ -n "$CEPH_CONF" ]; then
     RBD="$RBD --conf ${CEPH_CONF}"
 fi
 
+if [ "${TYPE}" != 'RBD' ]; then
+    error_message "$script_name: Operation not supported on disk type ${TYPE}"
+    exit 1
+fi
+
 SNAP_CREATE_CMD=$(cat <<EOF
     set -e -o pipefail
 
diff --git a/src/tm_mad/ceph/snap_delete b/src/tm_mad/ceph/snap_delete
index 7b7e0c16bf..28387858cc 100755
--- a/src/tm_mad/ceph/snap_delete
+++ b/src/tm_mad/ceph/snap_delete
@@ -64,13 +64,15 @@ done < <(onevm show -x $VM_ID| $XPATH \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_KEY \
-                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF)
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TYPE )
 
 RBD_SRC="${XPATH_ELEMENTS[j++]}"
 CLONE="${XPATH_ELEMENTS[j++]}"
 CEPH_USER="${XPATH_ELEMENTS[j++]}"
 CEPH_KEY="${XPATH_ELEMENTS[j++]}"
 CEPH_CONF="${XPATH_ELEMENTS[j++]}"
+TYPE="${XPATH_ELEMENTS[j++]}"
 
 if [ "$CLONE" = "NO" ]; then
     RBD_DST="${RBD_SRC}"
@@ -96,6 +98,11 @@ if [ -n "$CEPH_CONF" ]; then
     RBD="$RBD --conf ${CEPH_CONF}"
 fi
 
+if [ "${TYPE}" != 'RBD' ]; then
+    error_message "$script_name: Operation not supported on disk type ${TYPE}"
+    exit 1
+fi
+
 SNAP_DELETE_CMD=$(cat <<EOF
     RBD="${RBD}"
 
diff --git a/src/tm_mad/ceph/snap_revert b/src/tm_mad/ceph/snap_revert
index f65f7b7cfd..89677089ca 100755
--- a/src/tm_mad/ceph/snap_revert
+++ b/src/tm_mad/ceph/snap_revert
@@ -64,13 +64,15 @@ done < <(onevm show -x $VM_ID| $XPATH \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER \
                     /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_KEY \
-                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF)
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_CONF \
+                    /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TYPE )
 
 RBD_SRC="${XPATH_ELEMENTS[j++]}"
 CLONE="${XPATH_ELEMENTS[j++]}"
 CEPH_USER="${XPATH_ELEMENTS[j++]}"
 CEPH_KEY="${XPATH_ELEMENTS[j++]}"
 CEPH_CONF="${XPATH_ELEMENTS[j++]}"
+TYPE="${XPATH_ELEMENTS[j++]}"
 
 if [ "$CLONE" = "NO" ]; then
     RBD_DST="${RBD_SRC}"
@@ -109,6 +111,11 @@ if [ -n "$CEPH_CONF" ]; then
     RBD="$RBD --conf ${CEPH_CONF}"
 fi
 
+if [ "${TYPE}" != 'RBD' ]; then
+    error_message "$script_name: Operation not supported on disk type ${TYPE}"
+    exit 1
+fi
+
 SNAP_REVERT_CMD=$(cat <<EOF
     RBD="${RBD}"
 
diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc
index 97b81898cb..3261d9bdca 100644
--- a/src/vm/VirtualMachine.cc
+++ b/src/vm/VirtualMachine.cc
@@ -504,7 +504,7 @@ int VirtualMachine::select(SqlDB * db)
         return rc;
     }
 
-    //Get History Records. 
+    //Get History Records.
     if( hasHistory() )
     {
         last_seq = history->seq;
@@ -1400,6 +1400,7 @@ error_common:
 int VirtualMachine::automatic_requirements(set<int>& cluster_ids,
     string& error_str)
 {
+    string tm_mad_system;
     ostringstream   oss;
     set<string>     clouds;
 
@@ -1451,21 +1452,28 @@ int VirtualMachine::automatic_requirements(set<int>& cluster_ids,
 
     obj_template->add("AUTOMATIC_REQUIREMENTS", oss.str());
 
+    oss.str("");
+
+    if ( obj_template->get("TM_MAD_SYSTEM", tm_mad_system) )
+    {
+        oss << "(TM_MAD = " << one_util::trim(tm_mad_system) << ") & ";
+    }
+
     // Set automatic System DS requirements
 
     if ( !cluster_ids.empty() )
     {
-        oss.str("");
-
         set<int>::iterator i = cluster_ids.begin();
 
-        oss << "\"CLUSTERS/ID\" @> " << *i;
+        oss << "(\"CLUSTERS/ID\" @> " << *i;
 
         for (++i; i != cluster_ids.end(); i++)
         {
             oss << " | \"CLUSTERS/ID\" @> " << *i;
         }
 
+        oss << ")";
+
         obj_template->add("AUTOMATIC_DS_REQUIREMENTS", oss.str());
     }
 
@@ -2129,7 +2137,7 @@ int VirtualMachine::from_xml(const string &xml_str)
     // -------------------------------------------------------------------------
     int last_seq;
 
-    if ( xpath(last_seq,"/VM/HISTORY_RECORDS/HISTORY/SEQ", -1) == 0 && 
+    if ( xpath(last_seq,"/VM/HISTORY_RECORDS/HISTORY/SEQ", -1) == 0 &&
             last_seq != -1 )
     {
         history_records.resize(last_seq + 1);
@@ -2677,7 +2685,19 @@ int VirtualMachine::get_disk_images(string& error_str)
         context = static_cast<VectorAttribute * >(acontext_disks[0]);
     }
 
-    return disks.get_images(oid, uid, adisks, context, error_str);
+    // -------------------------------------------------------------------------
+    // Deployment mode for the VM disks
+    // -------------------------------------------------------------------------
+    std::string tm_mad_sys;
+
+    if ( user_obj_template->get("TM_MAD_SYSTEM", tm_mad_sys) == true )
+    {
+        user_obj_template->erase("TM_MAD_SYSTEM");
+
+        obj_template->add("TM_MAD_SYSTEM", tm_mad_sys);
+    }
+
+    return disks.get_images(oid, uid, tm_mad_sys, adisks, context, error_str);
 }
 
 /* -------------------------------------------------------------------------- */
@@ -2711,7 +2731,14 @@ int VirtualMachine::set_up_attach_disk(VirtualMachineTemplate * tmpl, string& er
 
     VirtualMachineDisk * new_disk;
 
-    new_disk = disks.set_up_attach(oid, uid, get_cid(), new_vdisk, context, err);
+    // -------------------------------------------------------------------------
+    // Deployment mode for the VM disks
+    // -------------------------------------------------------------------------
+    std::string tm_mad_sys;
+
+    obj_template->get("TM_MAD_SYSTEM", tm_mad_sys);
+
+    new_disk = disks.set_up_attach(oid, uid, get_cid(), new_vdisk, tm_mad_sys, context, err);
 
     if ( new_disk == 0 )
     {
diff --git a/src/vm/VirtualMachineDisk.cc b/src/vm/VirtualMachineDisk.cc
index 6a16425201..3d55b894d8 100644
--- a/src/vm/VirtualMachineDisk.cc
+++ b/src/vm/VirtualMachineDisk.cc
@@ -140,6 +140,21 @@ int VirtualMachineDisk::get_image_id(int &id, int uid)
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
+string VirtualMachineDisk::get_tm_mad_system()
+{
+    std::string tm_mad_system;
+
+    if (vector_value("TM_MAD_SYSTEM", tm_mad_system) != 0)
+    {
+        return "";
+    }
+
+    return tm_mad_system;
+}
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
 void VirtualMachineDisk::extended_info(int uid)
 {
     ImagePool * ipool  = Nebula::instance().get_ipool();
@@ -504,6 +519,37 @@ void VirtualMachineDisk::clear_resize(bool restore)
     clear_resize();
 }
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+void VirtualMachineDisk::set_types(const string& ds_name)
+{
+    string type = vector_value("TYPE");
+
+    switch(Image::str_to_disk_type(type))
+    {
+        case Image::RBD_CDROM:
+        case Image::GLUSTER_CDROM:
+        case Image::SHEEPDOG_CDROM:
+        case Image::CD_ROM:
+            if (ds_name != "FILE" && ds_name != "ISCSI" && ds_name != "NONE")
+            {
+                replace("TYPE", ds_name+"_CDROM");
+            }
+            else
+            {
+                replace("TYPE", "CDROM");
+            }
+            break;
+
+        default:
+            replace("TYPE", ds_name);
+            break;
+    }
+
+    replace("DISK_TYPE", ds_name);
+}
+
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
@@ -662,7 +708,7 @@ void VirtualMachineDisks::assign_disk_targets(
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-int VirtualMachineDisks::get_images(int vm_id, int uid,
+int VirtualMachineDisks::get_images(int vm_id, int uid, const std::string& tsys,
         vector<Attribute *> disks, VectorAttribute * vcontext,
         std::string& error_str)
 {
@@ -695,6 +741,15 @@ int VirtualMachineDisks::get_images(int vm_id, int uid,
         // ---------------------------------------------------------------------
         VirtualMachineDisk * disk = new VirtualMachineDisk(vdisk, disk_id);
 
+        if ( !tsys.empty() )
+        {
+            disk->replace("TM_MAD_SYSTEM", tsys);
+        }
+        else
+        {
+            disk->remove("TM_MAD_SYSTEM");
+        }
+
         if ( ipool->acquire_disk(vm_id, disk, disk_id, image_type, dev_prefix,
                 uid, image_id, &snapshots, error_str) != 0 )
         {
@@ -959,7 +1014,7 @@ int VirtualMachineDisks::set_attach(int id)
 /* -------------------------------------------------------------------------- */
 
 VirtualMachineDisk * VirtualMachineDisks::set_up_attach(int vmid, int uid,
-        int cluster_id, VectorAttribute * vdisk, VectorAttribute * vcontext,
+        int cluster_id, VectorAttribute * vdisk, const std::string& tsys, VectorAttribute * vcontext,
         string& error)
 {
     set<string> used_targets;
@@ -1083,6 +1138,14 @@ VirtualMachineDisk * VirtualMachineDisks::set_up_attach(int vmid, int uid,
     // -------------------------------------------------------------------------
 
     disk->set_attach();
+    if ( !tsys.empty() )
+    {
+        disk->replace("TM_MAD_SYSTEM", tsys);
+    }
+    else
+    {
+        disk->remove("TM_MAD_SYSTEM");
+    }
 
     add_attribute(disk, disk->get_disk_id());