<commit_before>require 'tmpdir'
require 'fileutils'
require 'ruby_vcloud_sdk'

module VmShepherd
  class VcloudManager
    def initialize(login_info, vdc_name, logger)
      @login_info = login_info
      @vdc_name = vdc_name
      @logger = logger
    end

    def deploy(vapp_template_tar_path, vapp_config)
      tmpdir = Dir.mktmpdir

      check_vapp_status(vapp_config)

      untar_vapp_template_tar(File.expand_path(vapp_template_tar_path), tmpdir)

      vapp = deploy_vapp(tmpdir, vapp_config)
      reconfigure_vm(vapp, vapp_config)
      vapp.power_on
    ensure
      FileUtils.remove_entry_secure(tmpdir, force: true)
    end

    def destroy(vapp_names, catalog)
      delete_vapps(vapp_names)
      delete_catalog(catalog)
    end

    def clean_environment(vapp_names, catalog)
      destroy(vapp_names, catalog)
    end

    private

    def check_vapp_status(vapp_config)
      log('Checking for existing VM') do
        ip = vapp_config[:ip]
        raise "VM exists at #{ip}" if system("ping -c 5 #{ip}")
      end
    end

    def untar_vapp_template_tar(vapp_template_tar_path, dir)
      log("Untarring #{vapp_template_tar_path}") do
        system_or_exit("cd #{dir} && tar xfv '#{vapp_template_tar_path}'")
      end
    end

    def client
      @client ||= VCloudSdk::Client.new(
        @login_info[:url],
        "#{@login_info[:user]}@#{@login_info[:organization]}",
        @login_info[:password],
        {},
        @logger,
      )
    end

    def deploy_vapp(ovf_dir, vapp_config)
      # setup the catalog
      client.delete_catalog_by_name(vapp_config[:catalog]) if client.catalog_exists?(vapp_config[:catalog])
      catalog = client.create_catalog(vapp_config[:catalog])

      # upload template and instantiate vapp
      catalog.upload_vapp_template(@vdc_name, vapp_config[:name], ovf_dir)

      # instantiate template
      network_config = VCloudSdk::NetworkConfig.new(vapp_config[:network], 'Network 1')
      catalog.instantiate_vapp_template(
        vapp_config[:name], @vdc_name, vapp_config[:name], nil, nil, network_config)
    rescue => e
      @logger.error(e.http_body) if e.respond_to?(:http_body)
      raise e
    end

    def reconfigure_vm(vapp, vapp_config)
      vm = vapp.find_vm_by_name(vapp_config[:name])
      vm.product_section_properties = build_properties(vapp_config)
      vm
    end

    def build_properties(vapp_config)
      [
        {
          'type' => 'string',
          'key' => 'gateway',
          'value' => vapp_config[:gateway],
          'password' => '<PASSWORD>',
          'userConfigurable' => 'true',
          'Label' => 'Default Gateway',
          'Description' => 'The default gateway address for the VM network. Leave blank if DHCP is desired.'
        },
        {
          'type' => 'string',
          'key' => 'DNS',
          'value' => vapp_config[:dns],
          'password' => '<PASSWORD>',
          'userConfigurable' => 'true',
          'Label' => 'DNS',
          'Description' => 'The domain name servers for the VM (comma separated). Leave blank if DHCP is desired.',
        },
        {
          'type' => 'string',
          'key' => 'ntp_servers',
          'value' => vapp_config[:ntp],
          'password' => '<PASSWORD>',
          'userConfigurable' => 'true',
          'Label' => 'NTP Servers',
          'Description' => 'Comma-delimited list of NTP servers'
        },
        {
          'type' => 'string',
          'key' => 'admin_password',
          'value' => 'tempest',
          'password' => '<PASSWORD>',
          'userConfigurable' => 'true',
          'Label' => 'Admin Password',
          'Description' => 'This password is used to SSH into the VM. The username is "tempest".',
        },
        {
          'type' => 'string',
          'key' => 'ip0',
          'value' => vapp_config[:ip],
          'password' => '<PASSWORD>',
          'userConfigurable' => 'true',
          'Label' => 'IP Address',
          'Description' => 'The IP address for the VM. Leave blank if DHCP is desired.',
        },
        {
          'type' => 'string',
          'key' => 'netmask0',
          'value' => vapp_config[:netmask],
          'password' => '<PASSWORD>',
          'userConfigurable' => 'true',
          'Label' => 'Netmask',<commit_msg>Pass arguments explicitly internally, use #fetch to fail early<commit_after>require 'tmpdir'
require 'fileutils'
require 'ruby_vcloud_sdk'

module VmShepherd
  class VcloudManager
    def initialize(login_info, vdc_name, logger)
      @login_info = login_info
      @vdc_name = vdc_name
      @logger = logger
    end

    def deploy(vapp_template_tar_path, vapp_config)
      tmpdir = Dir.mktmpdir

      check_vapp_status(vapp_config)

      untar_vapp_template_tar(File.expand_path(vapp_template_tar_path), tmpdir)

      vapp = deploy_vapp(tmpdir, vapp_config)
      reconfigure_vm(vapp, vapp_config)
      vapp.power_on
    ensure
      FileUtils.remove_entry_secure(tmpdir, force: true)
    end

    def destroy(vapp_names, catalog)
      delete_vapps(vapp_names)
      delete_catalog(catalog)
    end

    def clean_environment(vapp_names, catalog)
      destroy(vapp_names, catalog)
    end

    private

    def check_vapp_status(vapp_config)
      log('Checking for existing VM') do
        ip = vapp_config[:ip]
        raise "VM exists at #{ip}" if system("ping -c 5 #{ip}")
      end
    end

    def untar_vapp_template_tar(vapp_template_tar_path, dir)
      log("Untarring #{vapp_template_tar_path}") do
        system_or_exit("cd #{dir} && tar xfv '#{vapp_template_tar_path}'")
      end
    end

    def client
      @client ||= VCloudSdk::Client.new(
        @login_info[:url],
        "#{@login_info[:user]}@#{@login_info[:organization]}",
        @login_info[:password],
        {},
        @logger,
      )
    end

    def deploy_vapp(ovf_dir, vapp_config)
      vapp_name = vapp_config.fetch(:name)
      catalog = vapp_config.fetch(:catalog)
      network = vapp_config.fetch(:network)
      # setup the catalog
      client.delete_catalog_by_name(catalog) if client.catalog_exists?(catalog)
      catalog = client.create_catalog(catalog)

      # upload template and instantiate vapp
      catalog.upload_vapp_template(@vdc_name, vapp_name, ovf_dir)

      # instantiate template
      network_config = VCloudSdk::NetworkConfig.new(network, 'Network 1')
      catalog.instantiate_vapp_template(vapp_name, @vdc_name, vapp_name, nil, nil, network_config)
    rescue => e
      @logger.error(e.http_body) if e.respond_to?(:http_body)
      raise e
    end

    def reconfigure_vm(vapp, vapp_config)
      vapp_name = vapp_config.fetch(:name)
      gateway = vapp_config.fetch(:gateway)
      dns = vapp_config.fetch(:dns)
      ntp = vapp_config.fetch(:ntp)
      ip = vapp_config.fetch(:ip)
      netmask = vapp_config.fetch(:netmask)

      vm = vapp.find_vm_by_name(vapp_name)
      vm.product_section_properties = build_properties(gateway: gateway, dns: dns, ntp: ntp, ip: ip, netmask: netmask)
      vm
    end

    def build_properties(gateway:, dns:, ntp:, ip:, netmask:)
      [
        {
          'type' => 'string',
          'key' => 'gateway',
          'value' => gateway,
          'password' => '<PASSWORD>',
          'userConfigurable' => 'true',
          'Label' => 'Default Gateway',
          'Description' => 'The default gateway address for the VM network. Leave blank if DHCP is desired.'
        },
        {
          'type' => 'string',
          'key' => 'DNS',
          'value' => dns,
          'password' => '<PASSWORD>',
          'userConfigurable' => 'true',
          'Label' => 'DNS',
          'Description' => 'The domain name servers for the VM (comma separated). Leave blank if DHCP is desired.',
        },
        {
          'type' => 'string',
          'key' => 'ntp_servers',
          'value' => ntp,
          'password' => '<PASSWORD>',
          'userConfigurable' => 'true',
          'Label' => 'NTP Servers',
          'Description' => 'Comma-delimited list of NTP servers'
        },
        {
          'type' => 'string',
          'key' => 'admin_password',
          'value' => 'tempest',
          'password' => '<PASSWORD>',
          'userConfigurable' => 'true',
          'Label' => 'Admin Password',
          'Description' => 'This password is used to SSH into the VM. The username is "tempest".',
        },
        {
          'type' => 'string',
          'key' => 'ip0',
          'value' => ip,
          'password' => '<PASSWORD>',
          'userConfigurable' => 'true',
          'Label' => 'IP Address',
          'Description' => 'The IP address for the VM. Leave blank if DHCP is desired.',
        },
        {
          'type' => 'string',
          'key' => 'netmask0',
          'value' => netmask,
          'password' => '<PASSWORD>',
          'userConfigurable' => 'true',
          'Label' => 'Netmask',
{'fraction_non_alphanumeric': 0.13075713322848798, 'fraction_numerical': 0.0008986744551786115, 'mean_word_length': 2.4006875477463714, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4102477', 'n_tokens_mistral': 2874, 'n_tokens_neox': 2828, 'n_words': 611}