<commit_before>require 'logger'
require 'rbvmomi'

module VmShepherd
  class VsphereManager
    TEMPLATE_PREFIX         = 'tpl'.freeze
    VALID_FOLDER_REGEX      = /\A([\w-]{1,80}\/)*[\w-]{1,80}\/?\z/
    VALID_DISK_FOLDER_REGEX = /\A[\w-]{1,80}\z/

    def initialize(host, username, password, datacenter_name, logger)
      @host            = host
      @username        = username
      @password        = password
      @datacenter_name = datacenter_name
      @logger          = logger
    end

    def deploy(ova_path, vm_config, vsphere_config)
      validate_folder_name!(vsphere_config[:folder])

      ensure_no_running_vm(vm_config)

      ovf_file_path = extract_ovf_from(ova_path)

      boot_vm(ovf_file_path, vm_config, vsphere_config)
    ensure
      FileUtils.remove_entry_secure(ovf_file_path, force: true) unless ovf_file_path.nil?
    end

    def clean_environment(datacenter_folders_to_clean:, datastores:, datastore_folders_to_clean:)
      return if datacenter_folders_to_clean.nil? || datastores.nil? || datacenter_folders_to_clean.nil?

      datacenter_folders_to_clean.each do |folder_name|
        validate_folder_name!(folder_name)
        delete_folder_and_vms(folder_name)
      end

      datastore_folders_to_clean.each do |folder_name|
        datastores.each do |datastore|
          validate_disk_folder_name!(folder_name)
          begin
            logger.info("BEGIN datastore_folder.destroy_task folder=#{folder_name}")

            file_manager.DeleteDatastoreFile_Task(
              datacenter: datacenter,
              name:       "[#{datastore}] #{folder_name}"
            ).wait_for_completion

            logger.info("END   datastore_folder.destroy_task folder=#{folder_name}")
          rescue RbVmomi::Fault => e
            logger.info("ERROR datastore_folder.destroy_task folder=#{folder_name} #{e.inspect}")
          end
        end
      end
    end

    def prepare_environment
    end

    def destroy(ip_address, resource_pool_name)
      vms = connection.serviceContent.searchIndex.FindAllByIp(ip: ip_address, vmSearch: true)
      vms = vms.select { |vm| resource_pool_name == vm.resourcePool.name } if resource_pool_name
      vms.each do |vm|
        power_off_vm(vm)
        destroy_vm(vm)
      end
    end

    def destroy_vm(vm)
      vm_name = vm.name
      logger.info("BEGIN vm.destroy_task vm=#{vm_name}")
      vm.Destroy_Task.wait_for_completion
      logger.info("END   vm.destroy_task vm=#{vm_name}")
    end

    private

    attr_reader :host, :username, :password, :datacenter_name, :logger

    def validate_disk_folder_name!(folder_name)
      VALID_DISK_FOLDER_REGEX.match(folder_name) || fail("#{folder_name.inspect} is not a valid disk folder name")
    end

    def validate_folder_name!(folder_name)
      VALID_FOLDER_REGEX.match(folder_name) || fail("#{folder_name.inspect} is not a valid folder name")
    end

    def ensure_no_running_vm(vm_config)
      ip_port = "#{vm_config.fetch(:ip)} #{vm_config.fetch(:external_port, 443)}"
      logger.info("BEGIN checking for VM at #{ip_port}")
      fail("VM exists at #{ip_port}") if system("nc -z -G 5 #{ip_port}")
      logger.info("END   checking for VM at #{ip_port}")
    end

    def extract_ovf_from(ova_path)
      logger.info("BEGIN extract_ovf_from #{ova_path}")
      ova_path = File.expand_path(ova_path.strip)

      untar_dir = Dir.mktmpdir

      system("cd #{untar_dir} && tar xfv '#{ova_path}'") || fail("ERROR: Untarring #{ova_path}")

      Dir["#{untar_dir}/*.ovf"].first.tap { logger.info("END   extract_ovf_from #{ova_path}") } ||
        fail('Failed to find ovf')
    end

    def create_network_mappings(ovf_file_path, vsphere_config)
      ovf = Nokogiri::XML(File.read(ovf_file_path))
      ovf.remove_namespaces!
      networks = ovf.xpath('//NetworkSection/Network').map { |x| x['name'] }
      Hash[networks.map { |ovf_network| [ovf_network, network(vsphere_config)] }]
    end

    def boot_vm(ovf_file_path, vm_config, vsphere_config)
      datacenter.vmFolder.traverse(vsphere_config[:folder], RbVmomi::VIM::Folder, true)
      template = deploy_ovf_template(ovf_file_path, vsphere_config)
      vm       = create_vm_from_template(template, vsphere_config)

      reconfigure_vm(vm, vm_config)
      power_on_vm(vm)<commit_msg>Stop passing `-G` to `nc`, this is not supported in our build containers<commit_after>require 'logger'
require 'rbvmomi'

module VmShepherd
  class VsphereManager
    TEMPLATE_PREFIX         = 'tpl'.freeze
    VALID_FOLDER_REGEX      = /\A([\w-]{1,80}\/)*[\w-]{1,80}\/?\z/
    VALID_DISK_FOLDER_REGEX = /\A[\w-]{1,80}\z/

    def initialize(host, username, password, datacenter_name, logger)
      @host            = host
      @username        = username
      @password        = password
      @datacenter_name = datacenter_name
      @logger          = logger
    end

    def deploy(ova_path, vm_config, vsphere_config)
      validate_folder_name!(vsphere_config[:folder])

      ensure_no_running_vm(vm_config)

      ovf_file_path = extract_ovf_from(ova_path)

      boot_vm(ovf_file_path, vm_config, vsphere_config)
    ensure
      FileUtils.remove_entry_secure(ovf_file_path, force: true) unless ovf_file_path.nil?
    end

    def clean_environment(datacenter_folders_to_clean:, datastores:, datastore_folders_to_clean:)
      return if datacenter_folders_to_clean.nil? || datastores.nil? || datacenter_folders_to_clean.nil?

      datacenter_folders_to_clean.each do |folder_name|
        validate_folder_name!(folder_name)
        delete_folder_and_vms(folder_name)
      end

      datastore_folders_to_clean.each do |folder_name|
        datastores.each do |datastore|
          validate_disk_folder_name!(folder_name)
          begin
            logger.info("BEGIN datastore_folder.destroy_task folder=#{folder_name}")

            file_manager.DeleteDatastoreFile_Task(
              datacenter: datacenter,
              name:       "[#{datastore}] #{folder_name}"
            ).wait_for_completion

            logger.info("END   datastore_folder.destroy_task folder=#{folder_name}")
          rescue RbVmomi::Fault => e
            logger.info("ERROR datastore_folder.destroy_task folder=#{folder_name} #{e.inspect}")
          end
        end
      end
    end

    def prepare_environment
    end

    def destroy(ip_address, resource_pool_name)
      vms = connection.serviceContent.searchIndex.FindAllByIp(ip: ip_address, vmSearch: true)
      vms = vms.select { |vm| resource_pool_name == vm.resourcePool.name } if resource_pool_name
      vms.each do |vm|
        power_off_vm(vm)
        destroy_vm(vm)
      end
    end

    def destroy_vm(vm)
      vm_name = vm.name
      logger.info("BEGIN vm.destroy_task vm=#{vm_name}")
      vm.Destroy_Task.wait_for_completion
      logger.info("END   vm.destroy_task vm=#{vm_name}")
    end

    private

    attr_reader :host, :username, :password, :datacenter_name, :logger

    def validate_disk_folder_name!(folder_name)
      VALID_DISK_FOLDER_REGEX.match(folder_name) || fail("#{folder_name.inspect} is not a valid disk folder name")
    end

    def validate_folder_name!(folder_name)
      VALID_FOLDER_REGEX.match(folder_name) || fail("#{folder_name.inspect} is not a valid folder name")
    end

    def ensure_no_running_vm(vm_config)
      ip_port = "#{vm_config.fetch(:ip)} #{vm_config.fetch(:external_port, 443)}"
      logger.info("BEGIN checking for VM at #{ip_port}")
      fail("VM exists at #{ip_port}") if system("nc -z -w 1 #{ip_port}")
      logger.info("END   checking for VM at #{ip_port}")
    end

    def extract_ovf_from(ova_path)
      logger.info("BEGIN extract_ovf_from #{ova_path}")
      ova_path = File.expand_path(ova_path.strip)

      untar_dir = Dir.mktmpdir

      system("cd #{untar_dir} && tar xfv '#{ova_path}'") || fail("ERROR: Untar'ing #{ova_path}")

      Dir["#{untar_dir}/*.ovf"].first.tap { logger.info("END   extract_ovf_from #{ova_path}") } ||
        fail('Failed to find ovf')
    end

    def create_network_mappings(ovf_file_path, vsphere_config)
      ovf = Nokogiri::XML(File.read(ovf_file_path))
      ovf.remove_namespaces!
      networks = ovf.xpath('//NetworkSection/Network').map { |x| x['name'] }
      Hash[networks.map { |ovf_network| [ovf_network, network(vsphere_config)] }]
    end

    def boot_vm(ovf_file_path, vm_config, vsphere_config)
      datacenter.vmFolder.traverse(vsphere_config[:folder], RbVmomi::VIM::Folder, true)
      template = deploy_ovf_template(ovf_file_path, vsphere_config)
      vm       = create_vm_from_template(template, vsphere_config)

      reconfigure_vm(vm, vm_config)
      power_on_vm(vm)
{'fraction_non_alphanumeric': 0.10962227099457086, 'fraction_numerical': 0.0030033498902622157, 'mean_word_length': 3.231671554252199, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '909798', 'n_tokens_mistral': 3003, 'n_tokens_neox': 2929, 'n_words': 509}