#!/usr/bin/env ruby

# ---------------------------------------------------------------------------- #
# Copyright 2002-2019, 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.                                               #
# ---------------------------------------------------------------------------- #

ONE_LOCATION = ENV['ONE_LOCATION'] unless defined?(ONE_LOCATION)

if !ONE_LOCATION
    RUBY_LIB_LOCATION = '/usr/lib/one/ruby' unless defined?(RUBY_LIB_LOCATION)
    GEMS_LOCATION     = '/usr/share/one/gems' unless defined?(GEMS_LOCATION)
    VAR_LOCATION      = '/var/lib/one' unless defined?(VAR_LOCATION)
else
    RUBY_LIB_LOCATION = ONE_LOCATION + '/lib/ruby' unless defined?(RUBY_LIB_LOCATION)
    GEMS_LOCATION     = ONE_LOCATION + '/share/gems' unless defined?(GEMS_LOCATION)
    VAR_LOCATION      = ONE_LOCATION + '/var' unless defined?(VAR_LOCATION)
end

if File.directory?(GEMS_LOCATION)
    Gem.use_paths(GEMS_LOCATION)
end

$LOAD_PATH << RUBY_LIB_LOCATION
$LOAD_PATH << File.dirname(__FILE__)

require 'vcenter_driver'

def is_the_file_location?(target_path, f)
    return target_path == File.basename(f)
end

def is_last_file_to_upload?(index, files_to_upload)
    return index == files_to_upload.size - 1
end

def there_is_not_system_error?(rc)
    return !rc
end

drv_action_enc = ARGV[0]
id             = ARGV[1]

drv_action = OpenNebula::XMLElement.new
drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA')

img_path     = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/PATH"]
ds_id        = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/ID"]
ds_ref       = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"]
ds_image_dir = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_IMAGE_DIR"].match(%r{^/*(.*?)/*$})[1] rescue "one"
md5          = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/MD5"]
sha1         = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/SHA1"]
nodecomp     = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/NO_DECOMPRESS"]
limit_bw     = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/LIMIT_TRANSFER_BW"]

check_valid img_path, "img_path"

# if image is already in a vCenter datastore return the path
if img_path.start_with? "vcenter://"
    img_path = img_path.sub("vcenter://", "")
    img_path = VCenterDriver::FileHelper.escape_path(img_path)
    puts img_path
    exit(0)
end

temp_file = nil
filename = File.basename(img_path)
target_path = "#{ds_image_dir}/#{id}"

# If image is in a remote http location it has to be downloaded
# or if is a zipped file it has to be unzipped in a temp folder

if VCenterDriver::FileHelper.is_remote_or_needs_unpack?(img_path)
    temp_folder = File.join(VAR_LOCATION, "vcenter/#{target_path}")
    temp_file = File.join(temp_folder, File.basename(img_path))
    # if the original file doesn't have the .vmdk extension, add it
    if !temp_file.match(/\.vmdk$/) && !temp_file.match(/\.iso$/)
        temp_file += ".vmdk"
    end

    # Create tmp directory
    FileUtils.mkdir_p(temp_folder)

    # Specify downloader args
    downsh_args = " "
    downsh_args << "--md5 #{md5} " if md5 && !md5.empty? && !md5.eql?("-")
    downsh_args << "--sha1 #{sha1} " if sha1 && !sha1.empty?
    downsh_args << "--nodecomp " if nodecomp && !nodecomp.empty?
    downsh_args << "--limit #{limit_bw} " if limit_bw && !limit_bw.empty?
    downsh_args << '--convert vmdk'

    downloader = "#{File.dirname(__FILE__)}/../downloader.sh #{downsh_args}"

    rc = system("#{downloader} #{img_path} #{temp_file}")

    if there_is_not_system_error?(rc)
        STDERR.puts "Error downloading #{img_path}"
        FileUtils.rm_rf(temp_file)
        exit -1
    end

    img_path = temp_file
end

# Time to upload files to vCenter
files_to_upload = []

info = VCenterDriver::FileHelper.vcenter_file_info(img_path)
extension = info[:extension] || ''

case info[:type]
when :standalone
    files_to_upload << info[:file]
when :flat
    files_to_upload = info[:flat_files]
    files_to_upload << info[:file]
end

files_to_upload.each_with_index do |f, index|

    path = "#{target_path}/#{File.basename(f)}"

    # Change path for gzipped standalone file
    if is_the_file_location?(target_path, f)
        path = "#{target_path}/#{filename}"

        # remove gz or bz2 if part of filename
        if path.end_with?("gz") && VCenterDriver::FileHelper.is_vmdk?(f)
            path.gsub!(/gz$/,'')
        end

        if path.end_with?("bz2") && VCenterDriver::FileHelper.is_vmdk?(f)
            path.gsub!(/bz2$/,'')
        end
    end

    # Change path if vmdk is part of filename but it's not the extension
    if !!/[^.]+vmdk$/.match(path) && VCenterDriver::FileHelper.is_vmdk?(f)
        path.gsub!(/vmdk$/,'')
        extension = '.vmdk'
    end

    # Add iso extension if file is an ISO file
    if VCenterDriver::FileHelper.is_iso?(f)
        path = "#{File.dirname(path)}/#{File.basename(path,".*")}"
        extension = '.iso'
    end

    if is_last_file_to_upload?(index, files_to_upload)
        uploader_args = "#{ds_id} #{ds_ref} #{path}#{extension} #{f}"
    else
        uploader_args = "#{ds_id} #{ds_ref} #{path} #{f} &> /dev/null"
    end

    cmd = "#{File.dirname(__FILE__)}/../vcenter_uploader.rb #{uploader_args}"
    rc = system(cmd)

    if there_is_not_system_error?(rc)
        STDERR.puts "Cannot upload file #{f}"
        FileUtils.rm_rf(temp_file) if temp_file
        exit(-1)
    end

end
FileUtils.rm_rf(temp_file) if temp_file
