theforeman/foreman_remote_execution

View on GitHub
app/controllers/job_invocations_controller.rb

Summary

Maintainability
A
1 hr
Test Coverage
class JobInvocationsController < ApplicationController
  include ::Foreman::Controller::AutoCompleteSearch
  include ::ForemanTasks::Concerns::Parameters::Triggering
  include ::JobInvocationsChartHelper

  def new
    return @composer = prepare_composer if params[:feature].present?

    ui_params = {
      :host_ids => params[:host_ids],
      :targeting => {
        :targeting_type => Targeting::STATIC_TYPE,
        :bookmark_id => params[:bookmark_id],
      },
    }
    # replace an empty string search with a dummy search query to match all hosts
    # but only if search query was entered (based on presence of :search parameter)
    if params.key?(:search)
      query = params[:search].empty? ? "name != ''" : params[:search]
      ui_params[:targeting].update(:search_query => query)
    end

    if (template = JobTemplate.find_by(id: params[:template_id]))
      ui_params[:job_invocation] = {
        :job_category => template.job_category,
        :providers => {
          template.provider_type => {:job_template_id => template.id},
        },
      }
    end

    @composer = JobInvocationComposer.from_ui_params(ui_params)
  end

  def rerun
    job_invocation = resource_base.find(params[:id])
    @composer = JobInvocationComposer.from_job_invocation(job_invocation, params)
    @job_organization = Taxonomy.find_by(id: job_invocation.task.input[:current_organization_id])
    @job_location = Taxonomy.find_by(id: job_invocation.task.input[:current_location_id])
    render :action => 'new'
  end

  def legacy_create
    @composer = prepare_composer
    if @composer.trigger
      redirect_to job_invocation_path(@composer.job_invocation)
    else
      @composer.job_invocation.description_format = nil if params.fetch(:job_invocation, {}).key?(:description_override)
      render :action => 'new'
    end
  end

  def create
    @composer = prepare_composer
    if @composer.trigger
      redirect_to job_invocation_path(@composer.job_invocation)
    else
      redirect_to new_job_invocation_path({:inputs => params[:inputs], :feature => params[:feature], :host_ids => params[:host_ids]})
    end
  end

  def show
    @job_invocation = resource_base.includes(:template_invocations => :run_host_job_task).find(params[:id])
    @job_organization = Taxonomy.find_by(id: @job_invocation.task.input[:current_organization_id])
    @job_location = Taxonomy.find_by(id: @job_invocation.task.input[:current_location_id])
    @auto_refresh = @job_invocation.task.try(:pending?)

    respond_to do |format|
      format.json do
        targeting_hosts_resources
      end

      format.html
      format.js
    end
  end

  def index
    @job_invocations = resource_base_search_and_page.preload(:task, :targeting).order('job_invocations.id DESC')
  end

  # refreshes the form
  def refresh
    params[:job_invocation].delete :description_format if params[:job_invocation].key?(:description_override)
    @composer = prepare_composer
  end

  def chart
    find_resource
    render :json => {
      :finished => @job_invocation.finished?,
      :job_invocations => job_invocation_data(@job_invocation)[:columns],
      :statuses => {
        :success => @job_invocation.progress_report[:success],
        :cancelled => @job_invocation.progress_report[:cancelled],
        :failed => @job_invocation.progress_report[:error],
        :pending => @job_invocation.progress_report[:pending],
      },
    }
  end

  def preview_hosts
    composer = prepare_composer

    @hosts = composer.targeted_hosts.limit(Setting[:entries_per_page])
    @additional = composer.targeted_hosts.count - Setting[:entries_per_page]
    @dynamic = composer.targeting.dynamic?
    @query = composer.displayed_search_query

    render :partial => 'job_invocations/preview_hosts_list'
  end

  def cancel
    @job_invocation = resource_base.find(params[:id])
    result = @job_invocation.cancel(params[:force])

    if result
      flash[:info] = if params[:force]
                       _('Trying to abort the job')
                     else
                       _('Trying to cancel the job')
                     end
    else
      flash[:warning] = if params[:force]
                          _('The job cannot be aborted at the moment.')
                        else
                          _('The job cannot be cancelled at the moment.')
                        end
    end
    redirect_back(:fallback_location => job_invocation_path(@job_invocation))
  end

  def preview_job_invocations_per_host
    job_invocations = resource_base.search_for("targeted_host_id = #{params[:host_id]} and (status=#{params[:status]})").limit(params[:limit] || 3)

    job_invocations = job_invocations.map do |job|
      @job_invocation = job
      template_invocation = job.template_invocations.find { |template_inv| template_inv.host_id == params[:host_id].to_i }
      task = template_invocation.try(:run_host_job_task)
      status_mapper = task ? HostStatus::ExecutionStatus::ExecutionTaskStatusMapper.new(task) : job
      {
        start_at: job.start_at,
        description: job.description,
        id: job.id,
        status: status_mapper.status,
        status_label: status_mapper.status_label,
      }
    end
    render :json => {:job_invocations => job_invocations}
  end

  private

  def action_permission
    case params[:action]
      when 'rerun'
        'create'
      when 'preview_hosts'
        'create'
      when 'cancel'
        'cancel'
      when 'chart', 'preview_job_invocations_per_host'
        'view'
      else
        super
    end
  end

  def prepare_composer
    if params[:feature].present?
      inputs = params[:inputs].permit!.to_hash if params.include?(:inputs)
      JobInvocationComposer.for_feature(
        params[:feature],
        params[:host_ids],
        inputs
      )
    else
      # triggering_params is a Hash
      #   when a hash is merged into ActionController::Parameters,
      #   it is assumed not to be #permitted?
      with_triggering = params.merge(:triggering => triggering_params)
      with_triggering[:triggering].permit!
      JobInvocationComposer.from_ui_params(with_triggering)
    end
  end

  def targeting_hosts_resources
    @auto_refresh = @job_invocation.task.try(:pending?)
    @resource_base = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)

    unless params[:search].nil?
      @resource_base = @resource_base.joins(:template_invocations)
                                     .where(:template_invocations => { :job_invocation_id => @job_invocation.id})
    end
    @hosts = resource_base_search_and_page
    @total_hosts = resource_base_with_search.size
  end
end