<commit_before>class ConversionHost < ApplicationRecord
  include NewWithTypeStiMixin

  acts_as_miq_taggable

  belongs_to :resource, :polymorphic => true
  has_many :service_template_transformation_plan_tasks, :dependent => :nullify
  has_many :active_tasks, -> { where(:state => 'active') }, :class_name => ServiceTemplateTransformationPlanTask, :inverse_of => :conversion_host
  delegate :ext_management_system, :hostname, :ems_ref, :to => :resource, :allow_nil => true

  # To be eligible, a conversion host must have the following properties
  #  - A transport mechanism is configured for source (set by 3rd party)
  #  - Credentials are set on the resource and SSH connection works
  #  - The number of concurrent tasks has not reached the limit
  def eligible?
    source_transport_method.present? && check_ssh_connection && check_concurrent_tasks
  end

  def check_concurrent_tasks
    max_tasks = max_concurrent_tasks || Settings.transformation.limits.max_concurrent_tasks_per_host
    active_tasks.size < max_tasks
  end

  def check_ssh_connection
    connect_ssh { |ssu| ssu.shell_exec('uname -a') }
    true
  rescue => e
    false
  end

  def source_transport_method
    return 'vddk' if vddk_transport_supported
    return 'ssh' if ssh_transport_supported
  end

  def ipaddress(family = 'ipv4')
    return address if address && IPAddr.new(address).send("#{family}?")
    resource.ipaddresses.detect { |ip| IPAddr.new(ip).send("#{family}?") }
  end 

  def run_conversion(conversion_options)
    result = connect_ssh { |ssu| ssu.shell_exec('/usr/bin/virt-v2v-wrapper.py', nil, nil, conversion_options.to_json) }
    JSON.parse(result)
  rescue => e
    raise "Starting conversion failed on '#{resource.name}' with [#{e.class}: #{e}]"
  end

  def kill_process(pid, signal = 'TERM')
    connect_ssh { |ssu| ssu.shell_exec("/bin/kill -s #{signal} #{pid}") }
    true
  rescue
    false
  end

  def get_conversion_state(path)
    json_state = connect_ssh { |ssu| ssu.get_file(path, nil) }
    JSON.parse(json_state)
  rescue => e
    raise "Could not get state file '#{path}' from '#{resource.name}' with [#{e.class}: #{e}"
  end

  def get_conversion_log(path)
    connect_ssh { |ssu| ssu.get_file(path, nil) }
  rescue => e
    raise "Could not get conversion log '#{path}' from '#{resource.name}' with [#{e.class}: #{e}"
  end 

  def check_conversion_host_role
    install_conversion_host_module
    playbook = "/usr/share/ovirt-ansible-v2v-conversion-host/playbooks/conversion_host_check.yml"
    extra_vars = { :v2v_manageiq_conversion_host_check => true }
    ansible_playbook(playbook, extra_vars)
    tag_resource_as('enabled')
  rescue
    tag_resource_as('disabled')
  end

  def self.notify_configuration_result(op, success, resource_info)
    Notification.create(
      :type    => success ? :conversion_host_config_success : :conversion_host_config_failure,
      :options => {
        :op_name => op,
        :op_arg  => "#{resource_info}",
      }
    )
  end

  def self.queue_configuration(op, instance_id, resource, params, auth_user = nil)
    task_opts = {
      :action => "Configuring a conversion_host: operation=#{op} resource=(type: #{resource.class.name} id:#{resource.id})",
      :userid => auth_user
    }
    queue_opts = {
      :class_name  => name,
      :method_name => op,
      :instance_id => instance_id,
      :role        => 'ems_operations',
      :zone        => resource.ext_management_system.my_zone,
      :args        => [params]
    }
    MiqTask.generic_action_with_callback(task_opts, queue_opts)
  end

  def self.enable_queue(params, auth_user = nil)
    resource_type = params[:resource_type]
    resource_id = params[:resource_id]
    resource = resource_type.constantize.find(resource_id)

    queue_configuration('enable', nil, resource, params, auth_user)
  end

  def self.enable(params)
    success = false
    resource_info = 'not found/invalid'

    op_arg = params.each_with_object([]) { |(k, v), l| l.push("#{k}=#{v}") }.join(', ')
    _log.info "Enabling a conversion_host with parameters: #{op_arg}"

    resource_type = params[:resource_type]
    resource_id = params[:resource_id]
    resource = resource_type.constantize.find(resource_id)

    success = create!(:resource => resource)
    resource_info = "type=#{params[:resource_type]} id=#{params[:resource_id]}"
  ensure
    notify_configuration_result('enable', success, resource_info)
  end

  def self.disable_queue(params, auth_user = nil)
    id = params[:id]
    resource = find(id).resource
    queue_configuration('disable', id, resource, params, auth_user)
  end

  def disable(params)
    success = false
    resource_info = "type=#{resource.class.name} id=#{resource.id}"

    op_arg = params.each_with_object([]) { |(k, v), l| l.push("#{k}=#{v}") }.join(', ')
    _log.info "Disabling a conversion_host with parameters: #{op_arg}"

    success = destroy
  ensure
    notify_configuration_result('disable', success, resource_info)
  end

  def enable_conversion_host_role<commit_msg>using params for conversion_host<commit_after>class ConversionHost < ApplicationRecord
  include NewWithTypeStiMixin

  acts_as_miq_taggable

  belongs_to :resource, :polymorphic => true
  has_many :service_template_transformation_plan_tasks, :dependent => :nullify
  has_many :active_tasks, -> { where(:state => 'active') }, :class_name => ServiceTemplateTransformationPlanTask, :inverse_of => :conversion_host
  delegate :ext_management_system, :hostname, :ems_ref, :to => :resource, :allow_nil => true

  # To be eligible, a conversion host must have the following properties
  #  - A transport mechanism is configured for source (set by 3rd party)
  #  - Credentials are set on the resource and SSH connection works
  #  - The number of concurrent tasks has not reached the limit
  def eligible?
    source_transport_method.present? && check_ssh_connection && check_concurrent_tasks
  end

  def check_concurrent_tasks
    max_tasks = max_concurrent_tasks || Settings.transformation.limits.max_concurrent_tasks_per_host
    active_tasks.size < max_tasks
  end

  def check_ssh_connection
    connect_ssh { |ssu| ssu.shell_exec('uname -a') }
    true
  rescue => e
    false
  end

  def source_transport_method
    return 'vddk' if vddk_transport_supported
    return 'ssh' if ssh_transport_supported
  end

  def ipaddress(family = 'ipv4')
    return address if address && IPAddr.new(address).send("#{family}?")
    resource.ipaddresses.detect { |ip| IPAddr.new(ip).send("#{family}?") }
  end 

  def run_conversion(conversion_options)
    result = connect_ssh { |ssu| ssu.shell_exec('/usr/bin/virt-v2v-wrapper.py', nil, nil, conversion_options.to_json) }
    JSON.parse(result)
  rescue => e
    raise "Starting conversion failed on '#{resource.name}' with [#{e.class}: #{e}]"
  end

  def kill_process(pid, signal = 'TERM')
    connect_ssh { |ssu| ssu.shell_exec("/bin/kill -s #{signal} #{pid}") }
    true
  rescue
    false
  end

  def get_conversion_state(path)
    json_state = connect_ssh { |ssu| ssu.get_file(path, nil) }
    JSON.parse(json_state)
  rescue => e
    raise "Could not get state file '#{path}' from '#{resource.name}' with [#{e.class}: #{e}"
  end

  def get_conversion_log(path)
    connect_ssh { |ssu| ssu.get_file(path, nil) }
  rescue => e
    raise "Could not get conversion log '#{path}' from '#{resource.name}' with [#{e.class}: #{e}"
  end 

  def check_conversion_host_role
    install_conversion_host_module
    playbook = "/usr/share/ovirt-ansible-v2v-conversion-host/playbooks/conversion_host_check.yml"
    extra_vars = { :v2v_manageiq_conversion_host_check => true }
    ansible_playbook(playbook, extra_vars)
    tag_resource_as('enabled')
  rescue
    tag_resource_as('disabled')
  end

  def self.notify_configuration_result(op, success, resource_info)
    Notification.create(
      :type    => success ? :conversion_host_config_success : :conversion_host_config_failure,
      :options => {
        :op_name => op,
        :op_arg  => resource_info,
      }
    )
  end

  def self.queue_configuration(op, instance_id, resource, params, auth_user = nil)
    task_opts = {
      :action => "Configuring a conversion_host: operation=#{op} resource=(type: #{resource.class.name} id:#{resource.id})",
      :userid => auth_user
    }
    queue_opts = {
      :class_name  => name,
      :method_name => op,
      :instance_id => instance_id,
      :role        => 'ems_operations',
      :zone        => resource.ext_management_system.my_zone,
      :args        => [params]
    }
    MiqTask.generic_action_with_callback(task_opts, queue_opts)
  end

  def self.enable_queue(params, auth_user = nil)
    resource_type = params[:resource_type]
    resource_id = params[:resource_id]
    resource = resource_type.constantize.find(resource_id)

    queue_configuration('enable', nil, resource, params, auth_user)
  end

  def self.enable(params)
    op_arg = params.each_with_object([]) { |(k, v), l| l.push("#{k}=#{v}") }.join(', ')
    _log.info("Enabling a conversion_host with parameters: #{op_arg}")

    success = false
    resource_info = 'not found/invalid'

    vddk_url = params.delete("param_v2v_vddk_package_url")
    resource_id = params[:resource_id]
    resource_type = params[:resource_type]
    resource = resource_type.constantize.find(resource_id)

    success = create!(params)
    resource_info = "type=#{params[:resource_type]} id=#{params[:resource_id]}"
  ensure
    notify_configuration_result('enable', success, resource_info)
  end

  def self.disable_queue(params, auth_user = nil)
    id = params[:id]
    resource = find(id).resource
    queue_configuration('disable', id, resource, params, auth_user)
  end

  def disable(params)
    success = false
    resource_info = "type=#{resource.class.name} id=#{resource.id}"

    op_arg = params.each_with_object([]) { |(k, v), l| l.push("#{k}=#{v}") }.join(', ')
    _log.info("Disabling a conversion_host with parameters: #{op_arg}")

    success = destroy
  ensure
    notify_configuration_result('disable', success, resource_info)
  end

  def enable_conversion_host_role
{'fraction_non_alphanumeric': 0.12052953961667655, 'fraction_numerical': 0.0010867417506421656, 'mean_word_length': 4.026315789473684, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 54, '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': '899365', 'n_tokens_mistral': 3331, 'n_tokens_neox': 3242, 'n_words': 723}