Project

General

Profile

« Previous | Next » 

Revision e54016da

Added by Marek Hulán over 8 years ago

Fixes #10782 - global host status

Introduce new global host status that is composed of host substatuses.
Each substatus defines a mapping to the global one which can result in
three values
  • OK
  • WARN
  • ERROR

Plugins can add their own substatuses. These are automatically
propagated also to API.

Thanks to Tomas Strachota who wrote the original code.

View differences:

app/models/host/managed.rb
class Host::Managed < Host::Base
include ReportCommon
include Hostext::Search
PROVISION_METHODS = %w[build image]
......
has_many :puppetclasses, :through => :host_classes, :dependent => :destroy
belongs_to :hostgroup
has_many :reports, :foreign_key => :host_id
has_one :last_report_object, :foreign_key => :host_id, :order => "#{Report.table_name}.id DESC", :class_name => 'Report'
has_many :host_parameters, :dependent => :destroy, :foreign_key => :reference_id, :inverse_of => :host
has_many :parameters, :dependent => :destroy, :foreign_key => :reference_id, :class_name => "HostParameter"
accepts_nested_attributes_for :host_parameters, :allow_destroy => true
......
belongs_to :owner, :polymorphic => true
belongs_to :compute_resource
belongs_to :image
has_many :host_statuses, :class_name => 'HostStatus::Status', :foreign_key => 'host_id', :inverse_of => :host,
:dependent => :destroy
has_one :configuration_status_object, :class_name => 'HostStatus::ConfigurationStatus', :foreign_key => 'host_id'
has_one :token, :foreign_key => :host_id, :dependent => :destroy
before_destroy :remove_reports
......
define_model_callbacks :build, :only => :after
define_model_callbacks :provision, :only => :before
before_validation :refresh_build_status, :if => :build_changed?
# Custom hooks will be executed after_commit
after_commit :build_hooks
before_save :clear_data_on_build
......
scope :with_os, -> { where('hosts.operatingsystem_id IS NOT NULL') }
scope :with_status, lambda { |status_type|
includes(:host_statuses).where("host_status.type = '#{status_type}'")
}
scope :with_config_status, lambda {
with_status('HostStatus::ConfigurationStatus')
}
# search for a metric - e.g.:
# Host::Managed.with("failed") --> all reports which have a failed counter > 0
# Host::Managed.with("failed",20) --> all reports which have a failed counter > 20
scope :with, lambda { |*arg|
with_config_status.where("(host_status.status >> #{HostStatus::ConfigurationStatus.bit_mask(arg[0].to_s)}) > #{arg[1] || 0}")
}
scope :with_error, lambda {
where("(puppet_status > 0) and
( ((puppet_status >> #{BIT_NUM*METRIC.index("failed")} & #{MAX}) != 0) or
((puppet_status >> #{BIT_NUM*METRIC.index("failed_restarts")} & #{MAX}) != 0) )")
with_config_status.where("(host_status.status > 0) and (
#{HostStatus::ConfigurationStatus.is('failed')} or
#{HostStatus::ConfigurationStatus.is('failed_restarts')}
)")
}
scope :without_error, lambda {
where("((puppet_status >> #{BIT_NUM*METRIC.index("failed")} & #{MAX}) = 0) and
((puppet_status >> #{BIT_NUM*METRIC.index("failed_restarts")} & #{MAX}) = 0)")
with_config_status.where("
#{HostStatus::ConfigurationStatus.is_not('failed')} and
#{HostStatus::ConfigurationStatus.is_not('failed_restarts')}
")
}
scope :with_changes, lambda {
where("(puppet_status > 0) and
( ((puppet_status >> #{BIT_NUM*METRIC.index("applied")} & #{MAX}) != 0) or
((puppet_status >> #{BIT_NUM*METRIC.index("restarted")} & #{MAX}) != 0) )")
with_config_status.where("(host_status.status > 0) and (
#{HostStatus::ConfigurationStatus.is('applied')} or
#{HostStatus::ConfigurationStatus.is('restarted')}
)")
}
scope :without_changes, lambda {
where("((puppet_status >> #{BIT_NUM*METRIC.index("applied")} & #{MAX}) = 0) and
((puppet_status >> #{BIT_NUM*METRIC.index("restarted")} & #{MAX}) = 0)")
with_config_status.where("
#{HostStatus::ConfigurationStatus.is_not('applied')} and
#{HostStatus::ConfigurationStatus.is_not('restarted')}
")
}
scope :with_pending_changes, -> { where("(puppet_status > 0) and ((puppet_status >> #{BIT_NUM*METRIC.index("pending")} & #{MAX}) != 0)") }
scope :without_pending_changes, -> { where("((puppet_status >> #{BIT_NUM*METRIC.index("pending")} & #{MAX}) = 0)") }
scope :with_pending_changes, lambda {
with_config_status.where("(host_status.status > 0) AND (#{HostStatus::ConfigurationStatus.is('pending')})")
}
scope :without_pending_changes, lambda {
with_config_status.where("#{HostStatus::ConfigurationStatus.is_not('pending')}")
}
scope :successful, -> { without_changes.without_error.without_pending_changes}
......
if self.compute_resource
host.compute_attributes = host.compute_resource.vm_compute_attributes_for(self.uuid)
end
host.puppet_status = 0
host.refresh_global_status
host
end
......
compute_resource ? compute_resource.vm_compute_attributes_for(uuid) : nil
end
def host_status
if build
N_("Pending Installation")
elsif respond_to?(:enabled) && !enabled
N_("Alerts disabled")
elsif respond_to?(:last_report) && last_report.nil?
N_("No reports")
elsif no_report
N_("Out of sync")
elsif error?
N_("Error")
elsif changes?
N_("Active")
elsif pending?
N_("Pending")
else
N_("No changes")
end
end
def smart_proxies
SmartProxy.where(:id => smart_proxy_ids)
end
......
unattended_render(template)
end
def build_status
def build_status_checker
build_status = HostBuildStatus.new(self)
build_status.check_all_statuses
build_status
......
@old = super { |clone| clone.interfaces = self.interfaces.map {|i| setup_object_clone(i) } }
end
def refresh_global_status
self.global_status = build_global_status.status
end
def refresh_statuses
HostStatus.status_registry.each do |status_class|
status = get_status(status_class)
status.refresh! if status.relevant?
end
host_statuses.reload
refresh_global_status
end
def get_status(type)
status = self.new_record? ? host_statuses.detect { |s| s.type == type.to_s } : host_statuses.find_by_type(type.to_s)
if status.nil?
host_statuses.new(:host => self, :type => type.to_s)
else
status
end
end
def build_global_status(options = {})
HostStatus::Global.build(host_statuses, options)
end
def global_status_label(options = {})
HostStatus::Global.build(host_statuses, options).to_label
end
def configuration_status(options = {})
@configuration_status ||= get_status(HostStatus::ConfigurationStatus).to_status(options)
end
def configuration_status_label(options = {})
@configuration_status_label ||= get_status(HostStatus::ConfigurationStatus).to_label(options)
end
def puppet_status
Foreman::Deprecation.deprecation_warning('1.12', 'Host#puppet_status has been deprecated, you should use configuration_status')
configuration_status
end
def build_status(options = {})
@build_status ||= get_status(HostStatus::BuildStatus).to_status(options)
end
def build_status_label(options = {})
@build_status_label ||= get_status(HostStatus::BuildStatus).to_label(options)
end
private
# validate uniqueness can't prevent saving two interfaces that has same DNS name
......
status
end
# alias to ensure same method that resolves the last report between the hosts and reports tables.
def reported_at
last_report
end
# puppet report status table column name
def self.report_status
"puppet_status"
end
# converts a name into ip address using DNS.
# if we are managing DNS, we can query the correct DNS server
# otherwise, use normal systems dns settings to resolv
......
self.config_groups = []
end
end
def refresh_build_status
self.get_status(HostStatus::BuildStatus).refresh
end
end

Also available in: Unified diff