#!/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'
    REMOTES_LOCATION  = '/var/lib/one/remotes/'
else
    RUBY_LIB_LOCATION = ONE_LOCATION + '/lib/ruby'
    GEMS_LOCATION     = ONE_LOCATION + '/share/gems'
    REMOTES_LOCATION  = ONE_LOCATION + '/var/remotes/'
end

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

$LOAD_PATH << RUBY_LIB_LOCATION
$LOAD_PATH << RUBY_LIB_LOCATION + '/cli'
$LOAD_PATH << REMOTES_LOCATION + 'vmm/vcenter/'

require 'command_parser'
require 'one_helper/onevcenter_helper'
require 'vcenter_driver'

CommandParser::CmdParser.new(ARGV) do
    usage '`onevcenter` <command> [<args>] [<options>]'
    version OpenNebulaHelper::ONE_VERSION

    helper = OneVcenterHelper.new

    before_proc do
        helper.set_client(options)
    end

    OBJECT = {
        :name => 'object',
        :short => '-o object',
        :large => '--object object ',
        :format => String,
        :description => 'vCenter object: [datastores, templates,'\
                        'networks, datastores, images]'
    }

    HOST = {
        :name => 'host',
        :short => '-h host_id',
        :large => '--host host_id',
        :format => String,
        :description => 'OpenNebula host used to authenticate the operation'
    }

    DATASTORE = {
        :name => 'datastore',
        :short => '-d datastore_id',
        :large => '--datastore datastore_id',
        :format => String,
        :description => 'OpenNebula datastore used'
    }

    CONFIG = {
        :name => 'configuration',
        :large => '--config file',
        :format => String,
        :description => 'Configuration file for custom options'
    }

    VCENTER = {
        :name => 'vcenter',
        :large => '--vcenter vCenter',
        :description => 'The vCenter hostname',
        :format => String
    }

    USER = {
        :name => 'vuser',
        :large => '--vuser username',
        :description => 'The username to interact with vCenter',
        :format => String
    }

    PASS = {
        :name => 'vpass',
        :large => '--vpass password',
        :description => 'The password for the user',
        :format => String
    }

    PORT = {
        :name => 'port',
        :short => '-p port',
        :large => '--port port',
        :format => String,
        :description => 'vCenter API port, defaults to 443 (SSL) or 80'
    }

    USE_DEFAULTS = {
        :name => 'defaults',
        :large => '--use-defaults',
        :description => 'Use defaults for answers to questions',
        :format => String
    }

    ALL = {
        :name => 'all',
        :large => '--all',
        :description => 'Import all list',
        :format => String
    }

    ############################################################################
    # Global Options
    ############################################################################
    cmd_options = CommandParser::OPTIONS - [CommandParser::VERBOSE]
    set :option, cmd_options + OpenNebulaHelper::CLIENT_OPTIONS

    ############################################################################
    # list resources
    ############################################################################
    list_desc = <<-EOT.unindent
        Show a list with unimported vCenter objects

        Examples:
           - listing available templates:

             onevcenter list -o templates -h <host_id>

           - listing available images:

             onevcenter list -o datastores -h <host_id> -d <ds-img_id>
    EOT

    command :list,
            list_desc,
            :options => [OBJECT, HOST, DATASTORE, VCENTER, USER, PASS] do
        begin
            args = helper.parse_opts(options)
            args[:filter] = true
            vi_client = VCenterDriver::VIClient.new_from_host(options[:host])
            importer = VCenterDriver::VcImporter
                       .new_child(helper.client, vi_client, options[:object])

            list = importer.retrieve_resources(args)

            helper.list_object(options, list)
        rescue StandardError => e
            puts e.message
        end

        exit 0
    end

    list_desc = <<-EOT.unindent
        Show a list with unimported vCenter objects excluding all filters

        Examples:
          - listing networks including uplinks:

            onevcenter list_all -o networks -h <host_id>

    EOT

    command :list_all,
            list_desc,
            :options => [OBJECT, HOST, DATASTORE, VCENTER, USER, PASS] do
        begin
            args = helper.parse_opts(options)
            args[:filter] = false
            vi_client = VCenterDriver::VIClient.new_from_host(options[:host])
            importer = VCenterDriver::VcImporter
                       .new_child(helper.client, vi_client, options[:object])

            list = importer.retrieve_resources(args)

            helper.list_object(options, list)
        rescue StandardError => e
            puts e.message
        end

        exit 0
    end

    import_desc = <<-EOT.unindent
        Import the the desired vCenter object

        Examples:
           - importing first datastore

             onevcenter list -o templates -h <host_id>

           - importing 2 concrete templates:

             onevcenter import "vm-1252, vm-553, vm-1248" -o templates -h <host_id>

           - importing a image range:

             onevcenter import 0..10 -o images -h <host_id> -d <ds-img_id>
    EOT

    command :import,
            import_desc, [:oid, nil],
            :options => [OBJECT, HOST, DATASTORE] do
        begin
            vi_client = VCenterDriver::VIClient.new_from_host(options[:host])
            importer = VCenterDriver::VcImporter.new_child(helper.client,
                                                           vi_client,
                                                           options[:object])

            importer.retrieve_resources(helper.parse_opts(options))
            indexes = importer.get_indexes(args.first)

            if indexes.nil?
                raise "Could not get any unimported #{options[:object]}"\
                    " resources info in host: #{options[:host]} with"\
                    " this input: #{args.first}"
            end

            importer.process_import(indexes) do |object_info|
                helper.cli_dialogue(object_info)
            end

            importer.stdout
        rescue StandardError => e
            puts e.message
        end

        exit 0
    end

    command :import_defaults,
            import_desc,
            [:oid, nil],
            :options => [OBJECT, HOST, DATASTORE, CONFIG] do
        begin
            vi_client = VCenterDriver::VIClient.new_from_host(options[:host])
            importer = VCenterDriver::VcImporter.new_child(helper.client,
                                                           vi_client,
                                                           options[:object])
            importer.retrieve_resources(helper.parse_opts(options))
            indexes = importer.get_indexes(args.first)

            importer.process_import(indexes)

            importer.stdout
        rescue StandardError => e
            puts e.message
        end

        exit 0
    end

    ############################################################################
    # Import clusters
    ############################################################################
    host_desc = <<-EOT.unindent
        Import vCenter clusters as OpenNebula hosts

        Example:
           - Get available clusters:

             onevcenter hosts --vcenter <vcenter> --vuser <vcenter_user> --vpass <password>
    EOT
    command :hosts,
            host_desc,
            :options => [VCENTER, USER, PASS, USE_DEFAULTS, PORT] do
        con_ops = helper.connection_options('Hosts', options)

        VCenterDriver::VcImporter.import_clusters(con_ops, options)

        exit 0
    end
end
