lib/vmdb/appliance.rb
require 'linux_admin'
module Vmdb
module Appliance
def self.VERSION
@EVM_VERSION ||= File.read(Rails.root.join("VERSION").to_s).strip
end
def self.BUILD
@EVM_BUILD ||= get_build
end
def self.CODENAME
"Spassky".freeze
end
def self.RELEASE
release_file = Rails.root.join("RELEASE").to_s
File.exist?(release_file) ? File.read(release_file).strip : self.CODENAME
end
def self.BANNER
"#{self.PRODUCT_NAME} #{self.VERSION}, codename: #{self.CODENAME}"
end
def self.BUILD_NUMBER
@EVM_BUILD_NUMBER ||= self.BUILD.nil? ? "N/A" : self.BUILD.split("-").last # Grab the build number after the last hyphen
end
def self.log_config_on_startup
Vmdb::Appliance.log_config(:startup => true)
Vmdb::Appliance.log_server_identity
Vmdb::Appliance.log_diagnostics
end
def self.PRODUCT_NAME
::Settings.product.name || I18n.t("product.name").freeze
end
def self.USER_AGENT
"#{self.PRODUCT_NAME}/#{self.VERSION}".freeze
end
def self.check_automate_disk_version_against_db(fh)
ae_domains = MiqAeDomain.where(:source => MiqAeDomain::SYSTEM_SOURCE)
ae_domains.each do |domain|
if domain.version.blank? || domain.available_version.blank?
fh.warn("Cannot check #{domain.name} Automate domain version because version information not found")
elsif domain.version != domain.available_version
fh.warn("#{domain.name} domain version on disk differs from db version:")
fh.warn("Current version - #{domain.version}, Available version - #{domain.available_version}")
end
end
end
def self.log_config(*args)
options = args.extract_options!
fh = options[:logger] || $log
init_msg = options[:startup] == true ? "* [VMDB] started on [#{Time.now}] *" : "* [VMDB] configuration *"
border = "*" * init_msg.length
fh.info(border)
fh.info(init_msg)
fh.info(border)
fh.info("Release: #{self.RELEASE}")
fh.info("Version: #{self.VERSION}")
fh.info("Build: #{self.BUILD}")
fh.info("Codename: #{self.CODENAME}")
fh.info("RUBY Environment: #{Object.const_defined?(:RUBY_DESCRIPTION) ? RUBY_DESCRIPTION : "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE} patchlevel #{RUBY_PATCHLEVEL}) [#{RUBY_PLATFORM}]"}")
fh.info("RAILS Environment: #{Rails.env} version #{Rails.version}")
check_automate_disk_version_against_db(fh)
fh.info("VMDB settings:")
fh.log_hashes(::Settings, :filter => Vmdb::Settings.secret_filter)
fh.info("VMDB settings END")
fh.info("---")
fh.info("DATABASE settings:")
fh.log_hashes(ActiveRecord::Base.connection_db_config.configuration_hash)
fh.info("DATABASE settings END")
fh.info("---")
end
def self.log_server_identity
return unless MiqEnvironment::Command.is_appliance?
# this is the request to overwrite a small file in the vmdb/log directory for each time the evm server is restarted.
# the file must not be named ".log" or it will be removed by logrotate, and it must contain the Server GUID (by which the appliance is known in the vmdb,
# the build identifier of the appliance as it is being started, the appliance hostname and the name of the appliance as configured from our configuration screen.
last_startup_file = Rails.root.join("log/last_startup.txt")
last_startup_file.delete if last_startup_file.exist?
begin
startup = ManageIQ::Loggers::Base.new(last_startup_file)
log_config(:logger => startup, :startup => true)
startup.info("Server GUID: #{MiqServer.my_guid}")
startup.info("Server Zone: #{MiqServer.my_zone}")
startup.info("Server Role: #{MiqServer.my_role}")
s = MiqServer.my_server
region = MiqRegion.my_region
startup.info("Server Region number: #{region.region}, name: #{region.name}") if region
startup.info("Server EVM id and name: #{s.id} #{s.name}")
startup.info("Currently assigned server roles:")
s.assigned_server_roles.includes(:server_role).each { |r| startup.info("Role: #{r.server_role.name}, Priority: #{r.priority}") }
issue = `cat /etc/issue 2> /dev/null` rescue nil
startup.info("OS: #{issue.chomp}") if issue.present?
network = get_network
unless network.empty?
startup.info("Network Information:")
network.each { |k, v| startup.info("#{k}: #{v}") }
end
mem = `cat /proc/meminfo 2> /dev/null` rescue nil
startup.info("System Memory Information:\n#{mem}") if mem.present?
cpu = `cat /proc/cpuinfo 2> /dev/null` rescue nil
startup.info("CPU Information:\n#{cpu}") if cpu.present?
fstab = `cat /etc/fstab 2> /dev/null` rescue nil
startup.info("fstab information:\n#{fstab}") if fstab.present?
ensure
startup.close rescue nil
end
end
def self.log_diagnostics
return unless MiqEnvironment::Command.is_appliance?
init_diagnostics
@diags.each do |diag|
begin
if diag[:cmd].kind_of?(Proc)
res = diag[:cmd].call
else
res = AwesomeSpawn.run(diag[:cmd], :params => diag[:params]).output
end
rescue => e
$log.warn("Diagnostics: [#{diag[:msg]}] command [#{diag[:cmd]}] failed with error [#{e}]")
next # go to next diagnostic command if this one blew up
end
$log.info("Diagnostics: [#{diag[:msg]}]\n#{res}") if res.present?
end
end
def self.get_build
build_file = Rails.root.join("BUILD").to_s
if File.exist?(build_file)
build = File.read(build_file).strip.split("-").last
else
sha = `git rev-parse --short HEAD`.chomp
build = "unknown_#{sha}"
end
build
end
private_class_method :get_build
def self.get_network
retVal = {}
eth0 = LinuxAdmin::NetworkInterface.new("eth0")
retVal[:hostname] = LinuxAdmin::Hosts.new.hostname
retVal[:macaddress] = eth0.mac_address
retVal[:ipaddress] = eth0.address
retVal[:netmask] = eth0.netmask
retVal[:gateway] = eth0.gateway
retVal[:primary_dns], retVal[:secondary_dns] = LinuxAdmin::Dns.new.nameservers
retVal
end
private_class_method :get_network
def self.installed_rpms
File.open(log_dir.join("package_list_rpm.txt"), "a") do |file|
file.puts "start: date time is: #{Time.now.utc}"
LinuxAdmin::Rpm.list_installed.sort.each do |name, version|
file.puts "#{name} #{version}"
end
end
end
private_class_method :installed_rpms
def self.installed_gems
File.open(log_dir.join("gem_list.txt"), "a") do |file|
file.puts "start: date time is: #{Time.now.utc}"
file.puts `gem list`
end
end
private_class_method :installed_gems
def self.log_dir
Pathname.new("/var/www/miq/vmdb/log")
end
private_class_method :log_dir
def self.init_diagnostics
@diags ||= [
{:cmd => "top", :params => [:b, {:n => 1}], :msg => "Uptime, top processes, and memory usage"}, # batch mode - 1 iteration
{:cmd => "pstree", :params => [:a, :p], :msg => "Process tree"},
{:cmd => "df", :params => [:all, :local, :human_readable, :print_type], :msg => "File system disk usage"}, # All including dummy fs, local, human readable, file system type
{:cmd => "mount", :msg => "Mounted file systems"},
{:cmd => "ifconfig", :params => [:a], :msg => "Currently active interfaces"}, # -a display all interfaces which are currently available, even if down
{:cmd => "route", :msg => "IP Routing table"},
{:cmd => "netstat", :params => [:interfaces, :all], :msg => "Network interface table"},
{:cmd => "netstat", :params => [:statistics], :msg => "Network statistics"},
{:cmd => -> { File.read('/etc/hosts') if File.exist?('/etc/hosts') }, :msg => "Hosts file contents"},
{:cmd => -> { File.read('/etc/fstab') if File.exist?('/etc/fstab') }, :msg => "FStab file contents"},
{:cmd => -> { installed_gems }, :msg => "Installed Ruby Gems"},
{:cmd => -> { installed_rpms }, :msg => "Installed RPMs"},
]
end
private_class_method :init_diagnostics
end
end