#!/usr/bin/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']

if !ONE_LOCATION
    RUBY_LIB_LOCATION ||= '/usr/lib/one/ruby'
    GEMS_LOCATION     ||= '/usr/share/one/gems'
else
    RUBY_LIB_LOCATION ||= ONE_LOCATION + '/lib/ruby'
    GEMS_LOCATION     ||= ONE_LOCATION + '/share/gems'
end

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

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

require 'vcenter_driver'

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

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

def there_is_not_system_error?(rc)
    !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')

DRV_ACTION_DS = '/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/'

img_path     = drv_action['/DS_DRIVER_ACTION_DATA/IMAGE/PATH']
ds_id        = drv_action['/DS_DRIVER_ACTION_DATA/DATASTORE/ID']
ds_ref       = drv_action[DRV_ACTION_DS + 'VCENTER_DS_REF']
ds_image_dir = drv_action[DRV_ACTION_DS + '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[DRV_ACTION_DS + 'NO_DECOMPRESS']
limit_bw     = drv_action[DRV_ACTION_DS + '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 doesnt 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 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
    # rubocop:disable Style/DoubleNegation
    if !!/[^.]+vmdk$/.match(path) && VCenterDriver::FileHelper.is_vmdk?(f)
        path.gsub!(/vmdk$/, '')
        extension = '.vmdk'
    end
    # rubocop:enable Style/DoubleNegation

    # 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 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)

    next unless there_is_not_system_error?(rc)

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

FileUtils.rm_rf(temp_file) if temp_file
