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

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'

CONFIG = VCenterConf.new

dfile        = ARGV[0]
cluster_name = ARGV[1]
vm_id        = ARGV[2]

## Helpers

def deploy_id_valid?(deploy_id)
    deploy_id && !deploy_id.empty?
end

drv_action = OpenNebula::XMLElement.new
drv_action.initialize_xml(Base64.decode64(STDIN.read), 'VM')

deploy_id    = drv_action['DEPLOY_ID']
host_id      = drv_action['HISTORY_RECORDS/HISTORY[last()]/HID']
deploy       = {}

begin
    retries ||= 0
    vi_client = VCenterDriver::VIClient.new_from_host(host_id)
    one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vm_id)

    if deploy_id_valid?(deploy_id)
        # VM is not new, we just need to reconfigure it and to power it on
        vm = VCenterDriver::VirtualMachine.new_one(vi_client, deploy_id, one_vm)
    else
        deploy[:boot] = drv_action['TEMPLATE/OS']
        vm = VCenterDriver::VirtualMachine.new_from_clone(vi_client,
                                                          drv_action,
                                                          vm_id)
    end

    if vm.is_powered_off?
        vm.sync(deploy)
        # Only mark the VM as running if we are deploying it for the first time
        set_running = !deploy_id_valid?(deploy_id)
        vm.poweron(set_running)
    end

    puts vm['_ref']
rescue StandardError => e
    message =  "Deploy of VM #{vm_id} on vCenter cluster #{cluster_name} " \
               "with #{dfile} failed due to \"#{e.message}\"" \
               "on attempt \##{retries}."
    unless (retries += 1) < CONFIG[:retries]
        if e.message.include?('ManagedObjectNotFound')
            template_id = drv_action['TEMPLATE/TEMPLATE_ID'].to_i

            client = OpenNebula::Client.new
            resource = OpenNebula::Template.new_with_id(template_id, client)
            rc = resource.info

            if OpenNebula.is_error?(rc)
                message << "\n#{rc.message}"
            else
                template_name = resource.name

                message << "\nVerify inside vCenter cluster #{cluster_name} " \
                           "that template #{template_name} currently " \
                           'exists and has not been deleted'
            end
        end
    end
    OpenNebula.log_error(message)
    if VCenterDriver::CONFIG[:debug_information]
        STDERR.puts "#{message} #{e.backtrace}"
    end
    sleep CONFIG[:retry_interval].to_i
    retry if retries < CONFIG[:retries]

    exit(-1)
ensure
    vi_client.close_connection if vi_client
end
