#!/usr/bin/ruby

# -------------------------------------------------------------------------- #
# Copyright 2002-2025, OpenNebula Project, OpenNebula Systems                #
#                                                                            #
# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
# not use this file except in compliance with the License. You may obtain    #
# a copy of the License at                                                   #
#                                                                            #
# http://www.apache.org/licenses/LICENSE-2.0                                 #
#                                                                            #
# Unless required by applicable law or agreed to in writing, software        #
# distributed under the License is distributed on an "AS IS" BASIS,          #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
# See the License for the specific language governing permissions and        #
# limitations under the License.                                             #
#--------------------------------------------------------------------------- #

# %%RUBYGEMS_SETUP_BEGIN%%
require 'load_opennebula_paths'
# %%RUBYGEMS_SETUP_END%%

###############################################################################
# This script copies a disk back to its image datastore (executed for the
# disk-saveas operation)
###############################################################################
#
# ARGUMENTS: host:remote_system_ds/disk.i fe:SOURCE snap_id vm_id img_ds_id
# STDIN: -
# RETURNS: -
#
###############################################################################

require 'securerandom'
require_relative '../../datastore/lvm'
require_relative '../lib/tm_action'

arg_src = ARGV[0]
arg_dst = ARGV[1]
arg_snapid = ARGV[2].to_i
arg_vmid = ARGV[3]
arg_imgds_id = ARGV[4]

src = TransferManager::Action::Location.new(arg_src)
# DST IS AN LVFNAME
dst = TransferManager::Action::Location.new(arg_dst)

action = TransferManager::Action.new(:vm_id => arg_vmid, :action_name => 'cpds')
lvmvm = MAD::LVMVM.new(action.vm.to_xml)
lvmdisk = lvmvm.disk(src.disk_id)

(lvmhost, activate) =
    if lvmvm.undeployed?
        oneimgds = OpenNebula::Datastore.new_with_id(arg_imgds_id, action.one)
        rc = oneimgds.info
        raise rc.message.to_s if OpenNebula.is_error?(rc)

        lvmimgds = MAD::LVMDatastore.new(oneimgds.to_xml)
        [lvmimgds.pick_bridge, true]
    else
        [src.host, false]
    end

srclv = lvmdisk.lv
tmp_snap_info = nil
if arg_snapid >= 0
    activate = true
    srclv = srclv.snap(arg_snapid)
elsif lvmvm.lcm_state_str == 'HOTPLUG_SAVEAS'
    # If the VM is running, and there's no snapid (copying the active LV), create a temporary
    # snapshot to ensure data integrity
    tmp_snap_info = {
        :id => "_cpds_#{SecureRandom.hex(2)}",
        :origlv => srclv
    }
    lvmdisk.snap_create(tmp_snap_info[:id], :activate => true)
    srclv = srclv.snap(tmp_snap_info[:id])
end

extend MAD::LVMWrapper # import function lvmsync

(vgname, lvname) = dst.path.split
destlv = MAD::LV.new(vgname, lvname)

script = <<~EOF
    #{destlv.activate_sh(true, :quiet => true).strip}
    dd if=#{srclv.dev} of=#{destlv.dev} bs=64k conv=sparse || true
    #{destlv.activate_sh(false, :quiet => true).strip}
EOF

if activate
    script = <<~EOF
        #{srclv.activate_sh(true, :quiet => true).strip}
        #{script.strip}
        #{srclv.activate_sh(false, :quiet => true).strip}
    EOF
end

# If source LV is a temporary snapshot, delete it after the copy
if tmp_snap_info
    script = <<~EOF
        #{script.strip}
        #{tmp_snap_info[:origlv].snap_delete_sh(tmp_snap_info[:id]).strip}
    EOF
end

MAD.run(lvmhost, lvmsync(script))
