Skip to content

Commit

Permalink
Fixes #37630 - Display basic list of hosts on the new job_invocations…
Browse files Browse the repository at this point in the history
… page
  • Loading branch information
kmalyjur committed Oct 10, 2024
1 parent d4abcf5 commit 916d0f6
Show file tree
Hide file tree
Showing 16 changed files with 422 additions and 73 deletions.
50 changes: 33 additions & 17 deletions app/controllers/api/v2/job_invocations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ module V2
class JobInvocationsController < ::Api::V2::BaseController
include ::Api::Version2
include ::Foreman::Renderer
include RemoteExecutionHelper

before_action :find_optional_nested_object, :only => %w{output raw_output}
before_action :find_host, :only => %w{output raw_output}
before_action :find_resource, :only => %w{show update destroy clone cancel rerun outputs}
before_action :find_resource, :only => %w{show update destroy clone cancel rerun outputs hosts}

wrap_parameters JobInvocation, :include => (JobInvocation.attribute_names + [:ssh])

Expand All @@ -20,14 +21,9 @@ def index
param :id, :identifier, :required => true
param :host_status, :bool, required: false, desc: N_('Show Job status for the hosts')
def show
@hosts = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)
@template_invocations = @job_invocation.template_invocations
.where(host: @hosts)
.includes(:input_values)

set_hosts_and_template_invocations
if params[:host_status] == 'true'
template_invocations = @template_invocations.includes(:run_host_job_task).to_a
@host_statuses = Hash[template_invocations.map { |ti| [ti.host_id, template_invocation_status(ti)] }]
set_statuses_and_smart_proxies
end
end

Expand Down Expand Up @@ -111,6 +107,18 @@ def output
render :json => host_output(@nested_obj, @host, :default => [], :since => params[:since])
end

api :GET, '/job_invocations/:id/hosts', N_('List hosts belonging to job invocation')
param_group :search_and_pagination, ::Api::V2::BaseController
add_scoped_search_description_for(JobInvocation)
param :id, :identifier, :required => true
def hosts
set_hosts_and_template_invocations
set_statuses_and_smart_proxies
@total = @job_invocation.targeting.hosts.size
@hosts = @hosts.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page], :per_page => params[:per_page])
render :hosts, :layout => 'api/v2/layouts/index_layout'
end

api :GET, '/job_invocations/:id/hosts/:host_id/raw', N_('Get raw output for a host')
param :id, :identifier, :required => true
param :host_id, :identifier, :required => true
Expand Down Expand Up @@ -187,7 +195,7 @@ def allowed_nested_id

def action_permission
case params[:action]
when 'output', 'raw_output', 'outputs'
when 'output', 'raw_output', 'outputs', 'hosts'
:view
when 'cancel'
:cancel
Expand Down Expand Up @@ -256,15 +264,23 @@ def parent_scope
resource_class.where(nil)
end

def template_invocation_status(template_invocation)
task = template_invocation.try(:run_host_job_task)
parent_task = @job_invocation.task

return(parent_task.result == 'cancelled' ? 'cancelled' : 'N/A') if task.nil?
return task.state if task.state == 'running' || task.state == 'planned'
return 'error' if task.result == 'warning'
def set_hosts_and_template_invocations
@hosts = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)
@template_invocations = @job_invocation.template_invocations
.where(host: @hosts)
.includes(:input_values)
end

task.result
def set_statuses_and_smart_proxies
template_invocations = @template_invocations.includes(:run_host_job_task).to_a
hosts = @hosts.to_a
@host_statuses = Hash[hosts.map do |host|
template_invocation = template_invocations.find { |ti| ti.host_id == host.id }
task = template_invocation.try(:run_host_job_task)
[host.id, template_invocation_status(task, @job_invocation.task)]
end]
@smart_proxy_id = Hash[template_invocations.map { |ti| [ti.host_id, ti.smart_proxy_id] }]
@smart_proxy_name = Hash[template_invocations.map { |ti| [ti.host_id, ti.smart_proxy_name] }]
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions app/helpers/remote_execution_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ def host_counter(label, count)
end

def template_invocation_status(task, parent_task)
return(parent_task.result == 'cancelled' ? _('cancelled') : _('Awaiting start')) if task.nil?
return(parent_task.result == 'cancelled' ? 'cancelled' : 'N/A') if task.nil?
return task.state if task.state == 'running' || task.state == 'planned'
return _('error') if task.result == 'warning'
return 'error' if task.result == 'warning'

task.result
end
Expand Down
15 changes: 15 additions & 0 deletions app/views/api/v2/job_invocations/hosts.json.rabl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
collection @hosts

attribute :name, :operatingsystem_id, :operatingsystem_name, :hostgroup_id, :hostgroup_name

node :job_status do |host|
@host_statuses[host.id]
end

node :smart_proxy_id do |host|
@smart_proxy_id[host.id]
end

node :smart_proxy_name do |host|
@smart_proxy_name[host.id]
end
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
get '/raw', :to => 'job_invocations#raw_output'
end
member do
get 'hosts'
post 'cancel'
post 'rerun'
get 'template_invocations', :to => 'template_invocations#template_invocations'
Expand Down
2 changes: 1 addition & 1 deletion webpack/JobInvocationDetail/JobInvocationActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
UPDATE_JOB,
} from './JobInvocationConstants';

export const getData = url => dispatch => {
export const getJobInvocation = url => dispatch => {
const fetchData = withInterval(
get({
key: JOB_INVOCATION_KEY,
Expand Down
84 changes: 84 additions & 0 deletions webpack/JobInvocationDetail/JobInvocationConstants.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
/* eslint-disable camelcase */
import React from 'react';
import { foremanUrl } from 'foremanReact/common/helpers';
import { translate as __ } from 'foremanReact/common/I18n';
import { useForemanHostDetailsPageUrl } from 'foremanReact/Root/Context/ForemanContext';
import JobStatusIcon from '../react_app/components/RecentJobsCard/JobStatusIcon';

export const JOB_INVOCATION_KEY = 'JOB_INVOCATION_KEY';
export const CURRENT_PERMISSIONS = 'CURRENT_PERMISSIONS';
export const UPDATE_JOB = 'UPDATE_JOB';
export const CANCEL_JOB = 'CANCEL_JOB';
export const GET_TASK = 'GET_TASK';
export const GET_TEMPLATE_INVOCATIONS = 'GET_TEMPLATE_INVOCATIONS';
export const CHANGE_ENABLED_RECURRING_LOGIC = 'CHANGE_ENABLED_RECURRING_LOGIC';
export const CANCEL_RECURRING_LOGIC = 'CANCEL_RECURRING_LOGIC';
export const GET_REPORT_TEMPLATES = 'GET_REPORT_TEMPLATES';
export const GET_REPORT_TEMPLATE_INPUTS = 'GET_REPORT_TEMPLATE_INPUTS';
export const JOB_INVOCATION_HOSTS = 'JOB_INVOCATION_HOSTS';
export const currentPermissionsUrl = foremanUrl(
'/api/v2/permissions/current_permissions'
);
Expand All @@ -20,6 +27,12 @@ export const STATUS = {
CANCELLED: 'cancelled',
};

export const STATUS_UPPERCASE = {
RESOLVED: 'RESOLVED',
ERROR: 'ERROR',
PENDING: 'PENDING',
};

export const DATE_OPTIONS = {
day: 'numeric',
month: 'short',
Expand All @@ -29,3 +42,74 @@ export const DATE_OPTIONS = {
hour12: false,
timeZoneName: 'short',
};

const Columns = () => {
const getColumnsStatus = ({ hostJobStatus }) => {
switch (hostJobStatus) {
case 'success':
return { title: __('Succeeded'), status: 0 };
case 'error':
return { title: __('Failed'), status: 1 };
case 'planned':
return { title: __('Scheduled'), status: 2 };
case 'running':
return { title: __('Pending'), status: 3 };
case 'cancelled':
return { title: __('Cancelled'), status: 4 };
case 'N/A':
return { title: __('Awaiting start'), status: 5 };
default:
return { title: hostJobStatus, status: 6 };
}
};
const hostDetailsPageUrl = useForemanHostDetailsPageUrl();

return {
name: {
title: __('Name'),
wrapper: ({ name }) => (
<a href={`${hostDetailsPageUrl}${name}`}>{name}</a>
),
weight: 1,
},
groups: {
title: __('Host group'),
wrapper: ({ hostgroup_id, hostgroup_name }) => (
<a href={`/hostgroups/${hostgroup_id}/edit`}>{hostgroup_name}</a>
),
weight: 2,
},
os: {
title: __('OS'),
wrapper: ({ operatingsystem_id, operatingsystem_name }) => (
<a href={`/operatingsystems/${operatingsystem_id}/edit`}>
{operatingsystem_name}
</a>
),
weight: 3,
},
smart_proxy: {
title: __('Smart proxy'),
wrapper: ({ smart_proxy_name, smart_proxy_id }) => (
<a href={`/smart_proxies/${smart_proxy_id}`}>{smart_proxy_name}</a>
),
weight: 4,
},
status: {
title: __('Status'),
wrapper: ({ job_status }) => {
const { title, status } = getColumnsStatus({
hostJobStatus: job_status,
});
return (
<JobStatusIcon status={status}>
{title || __('Unknown')}
</JobStatusIcon>
);
},
weight: 5,
},
};
};

export default Columns;
1 change: 0 additions & 1 deletion webpack/JobInvocationDetail/JobInvocationDetail.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,3 @@
height: $chart_size;
}
}

Loading

0 comments on commit 916d0f6

Please sign in to comment.