Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #10782 - global host status #2580

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/assets/stylesheets/application.scss
Expand Up @@ -527,3 +527,11 @@ table {
.error-message{
padding-right: 10px;
}

i.glyphicon.host-status {
margin-right: 5px;
}

span.glyphicon.host-status {
top: 3px;
}
11 changes: 11 additions & 0 deletions app/assets/stylesheets/status-colors.scss
@@ -0,0 +1,11 @@
.status-ok {
color: #5CB85C;
}

.status-error {
color: #D9534F
}

.status-warn, .status-question {
color: #DB843D;
}
3 changes: 2 additions & 1 deletion app/controllers/api/v1/hosts_controller.rb
Expand Up @@ -125,7 +125,8 @@ def destroy
eos

def status
render :json => { :status => @host.host_status }.to_json if @host
Foreman::Deprecation.api_deprecation_warning('The /status route is deprecated, please use the new /status/configuration instead')
render :json => { :status => @host.get_status(HostStatus::ConfigurationStatus).to_label }.to_json if @host
end

private
Expand Down
31 changes: 27 additions & 4 deletions app/controllers/api/v2/hosts_controller.rb
Expand Up @@ -25,7 +25,10 @@ class HostsController < V2::BaseController
param_group :search_and_pagination, ::Api::V2::BaseController

def index
@hosts = resource_scope_for_index
@hosts = resource_scope_for_index.includes([ :host_statuses, :compute_resource, :hostgroup, :operatingsystem, :interfaces])
# SQL optimizations queries
@last_report_ids = Report.where(:host_id => @hosts.map(&:id)).group(:host_id).maximum(:id)
@last_reports = Report.where(:id => @last_report_ids.values)
end

api :GET, "/hosts/:id/", N_("Show a host")
Expand Down Expand Up @@ -109,7 +112,7 @@ def destroy
process_response @host.destroy
end

api :GET, "/hosts/:id/status", N_("Get status of host")
api :GET, "/hosts/:id/status", N_("Get configuration status of host")
param :id, :identifier_dottable, :required => true
description <<-eos
Return value may either be one of the following:
Expand All @@ -123,7 +126,27 @@ def destroy
eos

def status
render :json => { :status => @host.host_status }.to_json if @host
Foreman::Deprecation.api_deprecation_warning('The /status route is deprecated, please use the new /status/configuration instead')
render :json => { :status => @host.get_status(HostStatus::ConfigurationStatus).to_label }.to_json if @host
end

api :GET, "/hosts/:id/status/:type", N_("Get status of host")
param :id, :identifier_dottable, :required => true
param :type, [ HostStatus::Global ] + HostStatus.status_registry.to_a.map { |s| s.humanized_name }, :required => true, :desc => N_(<<-eos
status type, can be one of
* global
* configuration
* build
eos
)
description N_('Returns string representing a host status of a given type')
def get_status
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing functional test coverage.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

case params[:type]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How will plugins get their status types recognised here? Shouldn't it be looked up in the registry?

when 'global'
@status = @host.build_global_status
else
@status = @host.get_status(HostStatus.find_status_by_humanized_name(params[:type]))
end
end

api :GET, "/hosts/:id/vm_compute_attributes", N_("Get vm attributes of host")
Expand Down Expand Up @@ -245,7 +268,7 @@ def action_permission
:console
when 'disassociate'
:edit
when 'vm_compute_attributes'
when 'vm_compute_attributes', 'get_status'
:view
else
super
Expand Down
3 changes: 1 addition & 2 deletions app/controllers/application_controller.rb
Expand Up @@ -338,8 +338,7 @@ def check_empty_taxonomy
# If the user has a fact_filter then we need to include :fact_values
# We do not include most associations unless we are processing a html page
def included_associations(include = [])
include += [:hostgroup, :compute_resource, :operatingsystem, :environment, :model ]
include
include + [ :hostgroup, :compute_resource, :operatingsystem, :environment, :model, :host_statuses ]
end

def errors_hash(errors)
Expand Down
5 changes: 3 additions & 2 deletions app/controllers/hosts_controller.rb
Expand Up @@ -40,7 +40,8 @@ def index(title = nil)
format.html do
@hosts = search.includes(included_associations).paginate(:page => params[:page])
# SQL optimizations queries
@last_reports = Report.where(:host_id => @hosts.map(&:id)).group(:host_id).maximum(:id)
@last_report_ids = Report.where(:host_id => @hosts.map(&:id)).group(:host_id).maximum(:id)
@last_reports = Report.where(:id => @last_report_ids.values)
# rendering index page for non index page requests (out of sync hosts etc)
@hostgroup_authorizer = Authorizer.new(User.current, :collection => @hosts.map(&:hostgroup_id).compact.uniq)
render :index if title and (@title = title)
Expand Down Expand Up @@ -194,7 +195,7 @@ def puppetrun
end

def review_before_build
@build = @host.build_status
@build = @host.build_status_checker
render :layout => false
end

Expand Down
97 changes: 59 additions & 38 deletions app/helpers/hosts_helper.rb
Expand Up @@ -62,7 +62,7 @@ def last_report_column(record)

def last_report_tooltip(record)
opts = { :rel => "twipsy" }
if @last_reports[record.id]
if @last_report_ids[record.id]
opts.merge!( "data-original-title" => _("View last report details"))
else
opts.merge!(:disabled => true, :class => "disabled", :onclick => 'return false')
Expand All @@ -72,44 +72,47 @@ def last_report_tooltip(record)
end

# method that reformat the hostname column by adding the status icons
def name_column(record)
label = record.host_status
case label
when "Pending Installation"
style ="label-info"
# TRANSLATORS: host's status: first character of "build"
short = s_("Build|B")
when "Alerts disabled"
style = "label-default"
# TRANSLATORS: host's status: first character of "disabled"
short = s_("Disabled|D")
when "No reports"
style = "label-default"
# TRANSLATORS: host's status: first character of "no reports"
short = s_("No reports|N")
when "Out of sync"
style = "label-warning"
# TRANSLATORS: host's status: first character of "sync" (out of sync)
short = s_("Sync|S")
when "Error"
style = "label-danger"
# TRANSLATORS: host's status: first character of "error"
short = s_("Error|E")
when "Active"
style = "label-info"
# TRANSLATORS: host's status: first character of "active"
short = s_("Active|A")
when "Pending"
style = "label-warning"
# TRANSLATORS: host's status: first character of "pending"
short = s_("Pending|P")
else
style = "label-success"
# TRANSLATORS: host's status: first character of "OK"
short = s_("OK|O")
def name_column(host)
style = host_global_status_icon_class_for_host(host)
tooltip = host.host_statuses.select(&:relevant?).sort_by(&:type).map { |status| "#{_(status.name)}: #{_(status.to_label)}" }.join(', ')

content = content_tag(:span, "", {:rel => "twipsy", :class => style, :"data-original-title" => tooltip} )
content += link_to(trunc_with_tooltip(" #{host}"), host_path(host))
content
end

def host_global_status_icon_class_for_host(host)
options = {}
options[:last_reports] = @last_reports unless @last_reports.nil?
host_global_status_icon_class(host.build_global_status(options).status)
end

def host_global_status_icon_class(status)
icon_class = case status
when HostStatus::Global::OK
'glyphicon-ok-sign'
when HostStatus::Global::WARN
'glyphicon-info-sign'
when HostStatus::Global::ERROR
'glyphicon-exclamation-sign'
else
'glyphicon-question-sign'
end

"host-status glyphicon #{icon_class} #{host_global_status_class(status)}"
end

def host_global_status_class(status)
case status
when HostStatus::Global::OK
'status-ok'
when HostStatus::Global::WARN
'status-warn'
when HostStatus::Global::ERROR
'status-error'
else
'status-question'
end
content_tag(:span, short, {:rel => "twipsy", :class => "label label-light " + style, :"data-original-title" => _(label)} ) +
link_to(trunc_with_tooltip(" #{record}"), host_path(record))
end

def days_ago(time)
Expand Down Expand Up @@ -247,7 +250,14 @@ def show_templates
end

def overview_fields(host)
global_status = host.build_global_status
fields = [
[_("Status"), content_tag(:i, ''.html_safe, :class => host_global_status_icon_class(global_status.status)) +
content_tag(:span, _(global_status.to_label), :class => host_global_status_class(global_status.status))
]
]
fields += host_detailed_status_list(host)
fields += [
[_("Domain"), (link_to(host.domain, hosts_path(:search => "domain = #{host.domain}")) if host.domain)],
[_("Realm"), (link_to(host.realm, hosts_path(:search => "realm = #{host.realm}")) if host.realm)],
[_("IP Address"), host.ip],
Expand All @@ -270,6 +280,17 @@ def overview_fields(host)
fields
end

def host_detailed_status_list(host)
host.host_statuses.sort_by(&:type).map do |status|
next unless status.relevant?
[
_(status.name),
content_tag(:i, ' '.html_safe, :class => host_global_status_icon_class(status.to_global)) +
content_tag(:span, _(status.to_label), :class => host_global_status_class(status.to_global))
]
end
end

def possible_images(cr, arch = nil, os = nil)
return cr.images unless controller_name == "hosts"
return [] unless arch && os
Expand Down
10 changes: 10 additions & 0 deletions app/models/concerns/configuration_status_scoped_search.rb
@@ -0,0 +1,10 @@
module ConfigurationStatusScopedSearch
extend ActiveSupport::Concern

module ClassMethods
def scoped_search_status(status, options)
options.merge!({ :offset => Report::METRIC.index(status.to_s), :word_size => Report::BIT_NUM })
scoped_search options
end
end
end
18 changes: 11 additions & 7 deletions app/models/concerns/hostext/search.rb
Expand Up @@ -4,6 +4,7 @@ module Search

included do
include ScopedSearchExtensions
include ConfigurationStatusScopedSearch

has_many :search_parameters, :class_name => 'Parameter', :foreign_key => :reference_id
belongs_to :search_users, :class_name => 'User', :foreign_key => :owner_id
Expand All @@ -15,13 +16,16 @@ module Search
scoped_search :on => :managed, :complete_value => {:true => true, :false => false}
scoped_search :on => :owner_type, :complete_value => true, :only_explicit => true
scoped_search :on => :owner_id, :complete_enabled => false, :only_explicit => true
scoped_search :on => :puppet_status, :offset => 0, :word_size => Report::BIT_NUM*4, :complete_value => {:true => true, :false => false}, :rename => :'status.interesting'
scoped_search :on => :puppet_status, :offset => Report::METRIC.index("applied"), :word_size => Report::BIT_NUM, :rename => :'status.applied'
scoped_search :on => :puppet_status, :offset => Report::METRIC.index("restarted"), :word_size => Report::BIT_NUM, :rename => :'status.restarted'
scoped_search :on => :puppet_status, :offset => Report::METRIC.index("failed"), :word_size => Report::BIT_NUM, :rename => :'status.failed'
scoped_search :on => :puppet_status, :offset => Report::METRIC.index("failed_restarts"), :word_size => Report::BIT_NUM, :rename => :'status.failed_restarts'
scoped_search :on => :puppet_status, :offset => Report::METRIC.index("skipped"), :word_size => Report::BIT_NUM, :rename => :'status.skipped'
scoped_search :on => :puppet_status, :offset => Report::METRIC.index("pending"), :word_size => Report::BIT_NUM, :rename => :'status.pending'

scoped_search :in => :configuration_status_object, :on => :status, :offset => 0, :word_size => Report::BIT_NUM*4, :rename => :'status.interesting', :complete_value => {:true => true, :false => false}
scoped_search_status "applied", :in => :configuration_status_object, :on => :status, :rename => :'status.applied'
scoped_search_status "restarted", :in => :configuration_status_object, :on => :status, :rename => :'status.restarted'
scoped_search_status "failed", :in => :configuration_status_object, :on => :status, :rename => :'status.failed'
scoped_search_status "failed_restarts", :in => :configuration_status_object, :on => :status, :rename => :'status.failed_restarts'
scoped_search_status "skipped", :in => :configuration_status_object, :on => :status, :rename => :'status.skipped'
scoped_search_status "pending", :in => :configuration_status_object, :on => :status, :rename => :'status.pending'

scoped_search :on => :global_status, :complete_value => { :ok => HostStatus::Global::OK, :warning => HostStatus::Global::WARN, :error => HostStatus::Global::ERROR }

scoped_search :in => :model, :on => :name, :complete_value => true, :rename => :model
scoped_search :in => :hostgroup, :on => :name, :complete_value => true, :rename => :hostgroup
Expand Down
46 changes: 0 additions & 46 deletions app/models/concerns/report_common.rb

This file was deleted.

2 changes: 1 addition & 1 deletion app/models/host/hostmix.rb
Expand Up @@ -8,4 +8,4 @@ def belongs_to_host(options = {})
belongs_to :host, {:class_name => "Host::Managed", :foreign_key => :host_id}.merge(options)
end
end
end
end