Project

General

Profile

Download (22 KB) Statistics
| Branch: | Tag: | Revision:
b4b14336 Ohad Levy
class Host < Puppet::Rails::Host
9fd7478e Paul Kelly
include Authorization
a393106d Ohad Levy
belongs_to :architecture
db59a916 Jochen Schalanda
belongs_to :medium
6e50fa1d Ohad Levy
belongs_to :model
950ddeb3 Ohad Levy
belongs_to :domain
286a2207 Ohad Levy
belongs_to :operatingsystem
8a65dff7 Ohad Levy
has_many :host_classes, :dependent => :destroy
has_many :puppetclasses, :through => :host_classes
6e50fa1d Ohad Levy
belongs_to :environment
belongs_to :subnet
9a55cdc2 Ohad Levy
belongs_to :ptable
086ec942 Ohad Levy
belongs_to :hostgroup
87c40d2e Ohad Levy
has_many :reports, :dependent => :destroy
aa1796f3 Paul Kelly
has_many :host_parameters, :dependent => :destroy, :foreign_key => :reference_id
b09b4515 Ohad Levy
accepts_nested_attributes_for :host_parameters, :reject_if => lambda { |a| a[:value].blank? }, :allow_destroy => true
9c0e127b Paul Kelly
belongs_to :owner, :polymorphic => true
36f93e4d Ohad Levy
belongs_to :puppetproxy, :class_name => "SmartProxy"
816b9c22 Ohad Levy
7747485a Ohad Levy
include Hostext::Search
e5d3f34e Ohad Levy
include HostCommon
a6db0470 Paul Kelly
include HostTemplateHelpers
e5d3f34e Ohad Levy
32847027 Justin Sherrill
class Jail < Safemode::Jail
d0c58f85 Justin Sherrill
allow :name, :diskLayout, :puppetmaster, :operatingsystem, :environment, :ptable, :hostgroup, :url_for_boot,
:params, :hostgroup, :domain, :ip, :mac
32847027 Justin Sherrill
end

76607ed5 Ohad Levy
named_scope :recent, lambda { |*args| {:conditions => ["last_report > ?", (args.first || (Setting[:puppet_interval] + 5).minutes.ago)]} }
named_scope :out_of_sync, lambda { |*args| {:conditions => ["last_report < ? and enabled != ?", (args.first || (Setting[:puppet_interval] + 5).minutes.ago), false]} }
06160506 Ohad Levy
named_scope :with_fact, lambda { |fact,value|
unless fact.nil? or value.nil?
51b0abad Ohad Levy
{ :joins => "INNER JOIN fact_values fv_#{fact} ON fv_#{fact}.host_id = hosts.id
INNER JOIN fact_names fn_#{fact} ON fn_#{fact}.id = fv_#{fact}.fact_name_id",
:select => "DISTINCT hosts.name, hosts.id", :conditions =>
c73efa8d Ohad Levy
["fv_#{fact}.value = ? and fn_#{fact}.name = ? and fv_#{fact}.fact_name_id = fn_#{fact}.id",value, fact ] }
06160506 Ohad Levy
else
raise "invalid fact"
end
}

named_scope :with_class, lambda { |klass|
unless klass.nil?
{ :joins => :puppetclasses, :select => "hosts.name", :conditions => {:puppetclasses => {:name => klass }} }
else
9a9b3e75 Paul Kelly
raise "invalid class"
06160506 Ohad Levy
end
}

16cb7742 Ohad Levy
named_scope :with, lambda { |*arg| { :conditions =>
"(puppet_status >> #{Report::BIT_NUM*Report::METRIC.index(arg[0])} & #{Report::MAX}) > #{arg[1] || 0}"}
}
named_scope :with_error, { :conditions => "(puppet_status > 0) and
8f823b83 Ohad Levy
((puppet_status >> #{Report::BIT_NUM*Report::METRIC.index("failed")} & #{Report::MAX}) != 0) or
1c039da8 Ohad Levy
((puppet_status >> #{Report::BIT_NUM*Report::METRIC.index("failed_restarts")} & #{Report::MAX}) != 0)"
16cb7742 Ohad Levy
}


named_scope :with_changes, { :conditions => "(puppet_status > 0) and
8f823b83 Ohad Levy
((puppet_status >> #{Report::BIT_NUM*Report::METRIC.index("applied")} & #{Report::MAX}) != 0) or
((puppet_status >> #{Report::BIT_NUM*Report::METRIC.index("restarted")} & #{Report::MAX}) !=0)"
16cb7742 Ohad Levy
}

named_scope :successful, {:conditions => "puppet_status = 0"}
5aee7268 Eric Shamow
named_scope :alerts_disabled, {:conditions => ["enabled = ?", false] }
16cb7742 Ohad Levy
9fd7478e Paul Kelly
named_scope :my_hosts, lambda {
user = User.current
owner_conditions = sanitize_sql_for_conditions(["((hosts.owner_id in (?) AND hosts.owner_type = 'Usergroup') OR (hosts.owner_id = ? AND hosts.owner_type = 'User'))", user.my_usergroups.map(&:id), user.id])
domain_conditions = sanitize_sql_for_conditions([" (hosts.domain_id in (?))",dms = (user.domains).map(&:id)])
hostgroup_conditions = sanitize_sql_for_conditions([" (hosts.hostgroup_id in (?))",(hgs = user.hostgroups).map(&:id)])

fact_conditions = ""
for user_fact in (ufs = user.user_facts)
fact_conditions += sanitize_sql_for_conditions ["(hosts.id = fact_values.host_id and fact_values.fact_name_id = ? and fact_values.value #{user_fact.operator} ?)", user_fact.fact_name_id, user_fact.criteria]
fact_conditions = user_fact.andor == "and" ? "(#{fact_conditions}) and " : "#{fact_conditions} or "
end
if match = fact_conditions.match(/^(.*).....$/)
fact_conditions = "(#{match[1]})"
end

conditions = ""
if user.filtering?
conditions = "#{owner_conditions}" if user.filter_on_owner
(conditions = (user.domains_andor == "and") ? "(#{conditions}) and #{domain_conditions} " : "#{conditions} or #{domain_conditions} ") unless dms.empty?
(conditions = (user.hostgroups_andor == "and") ? "(#{conditions}) and #{hostgroup_conditions} " : "#{conditions} or #{hostgroup_conditions} ") unless hgs.empty?
(conditions = (user.facts_andor == "and") ? "(#{conditions}) and #{fact_conditions} " : "#{conditions} or #{fact_conditions} ") unless ufs.empty?
conditions.sub!(/\s*\(\)\s*/, "")
conditions.sub!(/^(?:\(\))?\s?(?:and|or)\s*/, "")
conditions.sub!(/\(\s*(?:or|and)\s*\(/, "((")
end
{:conditions => conditions}
}

aa5a2230 Ohad Levy
# audit the changes to this model
acts_as_audited :except => [:last_report, :puppet_status, :last_compile]

c22d6db2 Ohad Levy
# some shortcuts
alias_attribute :os, :operatingsystem
alias_attribute :arch, :architecture
dd2b33da Ohad Levy
alias_attribute :hostname, :name
9afa092e Ohad Levy
alias_attribute :fqdn, :name
d3d91384 Ohad Levy
50b094c0 Ohad Levy
validates_uniqueness_of :name
69923df9 Ohad Levy
validates_presence_of :name, :environment_id
9c3ffb6b Ohad Levy
if SETTINGS[:unattended].nil? or SETTINGS[:unattended]
90b83222 Ohad Levy
# handles all orchestration of smart proxies.
include Orchestration

e26c3e9b Ohad Levy
validates_uniqueness_of :ip, :if => Proc.new {|host| host.managed}
validates_uniqueness_of :mac, :unless => Proc.new { |host| host.hypervisor? or !host.managed }
69923df9 Ohad Levy
validates_uniqueness_of :sp_mac, :allow_nil => true, :allow_blank => true
validates_uniqueness_of :sp_name, :sp_ip, :allow_blank => true, :allow_nil => true
validates_format_of :sp_name, :with => /.*-sp/, :allow_nil => true, :allow_blank => true
c9fff7c1 Paul Kelly
validates_presence_of :architecture_id, :operatingsystem_id, :if => Proc.new {|host| host.managed}
96be8845 Ohad Levy
validates_presence_of :domain_id
e26c3e9b Ohad Levy
validates_presence_of :mac, :unless => Proc.new { |host| host.hypervisor? or !host.managed }

69923df9 Ohad Levy
validates_length_of :root_pass, :minimum => 8,:too_short => 'should be 8 characters or more'
e26c3e9b Ohad Levy
validates_format_of :mac, :with => (/([a-f0-9]{1,2}:){5}[a-f0-9]{1,2}/), :unless => Proc.new { |host| host.hypervisor_id or !host.managed }
validates_format_of :ip, :with => (/(\d{1,3}\.){3}\d{1,3}/), :if => Proc.new {|host| host.managed}
19bd108a Paul Kelly
validates_presence_of :ptable, :message => "cant be blank unless a custom partition has been defined",
c9fff7c1 Paul Kelly
:if => Proc.new { |host| host.managed and host.disk.empty? and not defined?(Rake) }
69923df9 Ohad Levy
validates_format_of :sp_mac, :with => /([a-f0-9]{1,2}:){5}[a-f0-9]{1,2}/, :allow_nil => true, :allow_blank => true
validates_format_of :sp_ip, :with => /(\d{1,3}\.){3}\d{1,3}/, :allow_nil => true, :allow_blank => true
validates_format_of :serial, :with => /[01],\d{3,}n\d/, :message => "should follow this format: 0,9600n8", :allow_blank => true, :allow_nil => true
end
d3d91384 Ohad Levy
ad36b317 Ohad Levy
before_validation :normalize_addresses, :normalize_hostname
d3d91384 Ohad Levy
91e8f35b Paul Kelly
def after_initialize
self.owner ||= User.current
end

86744a6b Ohad Levy
def to_param
name
end

9c0e127b Paul Kelly
def <=>(other)
self.name <=> other.name
end

ea4fd101 Ohad Levy
def shortname
59ff4da6 Ohad Levy
domain.nil? ? name : name.chomp("." + domain.name)
d3d91384 Ohad Levy
end

9c0e127b Paul Kelly
# method to return the correct owner list for host edit owner select dropbox
def is_owned_by
owner.id_and_type if owner
end

# virtual attributes which sets the owner based on the user selection
# supports a simple user, or a usergroup
# selection parameter is expected to be an ActiveRecord id_and_type method (see Foreman's AR extentions).
def is_owned_by=(selection)
9fd7478e Paul Kelly
oid = User.find(selection.to_i) if selection =~ (/-Users$/)
oid = Usergroup.find(selection.to_i) if selection =~ (/-Usergroups$/)
9c0e127b Paul Kelly
self.owner = oid
end

b4b14336 Ohad Levy
def clearReports
d3d91384 Ohad Levy
# Remove any reports that may be held against this host
2dcf4736 Ohad Levy
Report.delete_all("host_id = #{id}")
d3d91384 Ohad Levy
end

def clearFacts
2dcf4736 Ohad Levy
FactValue.delete_all("host_id = #{id}")
d3d91384 Ohad Levy
end

# Called from the host build post install process to indicate that the base build has completed
# Build is cleared and the boot link and autosign entries are removed
# A site specific build script is called at this stage that can do site specific tasks
7700f32f Frank Sweetser
def built(installed = true)
d3d91384 Ohad Levy
self.build = false
7700f32f Frank Sweetser
self.installed_at = Time.now.utc if installed
36f93e4d Ohad Levy
# If this save fails then an exception is raised and further actions are not processed
unless Rails.env == "test"
# Disallow any auto signing for our host.
GW::Puppetca.disable name unless puppetca?
GW::Tftp.remove mac unless respond_to?(:tftp?) and tftp?
end
b34e9aea Ohad Levy
self.save
36f93e4d Ohad Levy
rescue => e
logger.warn "Failed to set Build on #{self}: #{e}"
false
d3d91384 Ohad Levy
end

b0d3f4ee Ohad Levy
#retuns fqdn of host puppetmaster
def pm_fqdn
3fe6982a Ohad Levy
puppetmaster == "puppet" ? "puppet.#{domain.name}" : "#{puppetmaster}"
36f93e4d Ohad Levy
end

# Cleans Certificate and enable Autosign
# Called after a host is given their provisioning template
# Returns : Boolean status of the operation
def handle_ca
return true if Rails.env == "test"
if puppetca?
9b1fd486 Paul Kelly
respond_to?(:initialize_puppetca) && initialize_puppetca && delCertificate && setAutosign
36f93e4d Ohad Levy
else
# Legacy CA handling
GW::Puppetca.clean(name) && GW::Puppetca.sign(name)
end
b0d3f4ee Ohad Levy
end

286a2207 Ohad Levy
# returns the host correct disk layout, custom or common
def diskLayout
65b5ea5e Frank Sweetser
(disk.empty? ? ptable.layout : disk).gsub("\r","")
286a2207 Ohad Levy
end

cab0d8c6 Ohad Levy
# returns a configuration template (such as kickstart) to a given host
69f9cb82 Ohad Levy
def configTemplate opts = {}
opts[:kind] ||= "provision"
opts[:operatingsystem_id] ||= operatingsystem_id
opts[:hostgroup_id] ||= hostgroup_id
opts[:environment_id] ||= environment_id

ConfigTemplate.find_template opts
cab0d8c6 Ohad Levy
end

87c40d2e Ohad Levy
# reports methods

def error_count
2dcf4736 Ohad Levy
%w[failed failed_restarts].sum {|f| status f}
87c40d2e Ohad Levy
end

ff1cc6b1 Ohad Levy
def status(type = nil)
raise "invalid type #{type}" if type and not Report::METRIC.include?(type)
h = {}
(type || Report::METRIC).each do |m|
h[m] = (read_attribute(:puppet_status) || 0) >> (Report::BIT_NUM*Report::METRIC.index(m)) & Report::MAX
end
return type.nil? ? h : h[type]
87c40d2e Ohad Levy
end

ff1cc6b1 Ohad Levy
# generate dynamically methods for all metrics
# e.g. Report.last.applied
Report::METRIC.each do |method|
define_method method do
status method
end
87c40d2e Ohad Levy
end

def no_report
76607ed5 Ohad Levy
last_report.nil? or last_report < Time.now - (Setting[:puppet_interval] + 3).minutes and enabled?
87c40d2e Ohad Levy
end

5aee7268 Eric Shamow
def disabled?
not enabled?
end

1ba05a93 Ohad Levy
# returns the list of puppetclasses a host is in.
c6eee281 Ohad Levy
def puppetclasses_names
9fd7478e Paul Kelly
return all_puppetclasses.collect {|c| c.name}
c6eee281 Ohad Levy
end

b09b4515 Ohad Levy
def all_puppetclasses
4d4b84f6 Ohad Levy
return hostgroup.nil? ? puppetclasses : (hostgroup.classes + puppetclasses).uniq
b09b4515 Ohad Levy
end
fce2cbc0 Ohad Levy
e22af92d Ohad Levy
# provide information about each node, mainly used for puppet external nodes
# TODO: remove hard coded default parameters into some selectable values in the database.
c6eee281 Ohad Levy
def info
fce2cbc0 Ohad Levy
# Static parameters
c6eee281 Ohad Levy
param = {}
c7643fc9 Ohad Levy
# maybe these should be moved to the common parameters, leaving them in for now
dbb7c2f2 Paul Kelly
param["puppetmaster"] = puppetmaster.to_s
param["domainname"] = domain.fullname unless domain.nil? or domain.fullname.nil?
76607ed5 Ohad Levy
if Setting[:ignore_puppet_facts_for_provisioning]
d97375e0 Ohad Levy
param["ip"] = ip
param["mac"] = mac
end
fce2cbc0 Ohad Levy
param.update self.params
a6e10c72 Jochen Schalanda
9afa092e Ohad Levy
# lookup keys
86d01ac3 Ohad Levy
if Setting["Enable_Smart_Variables_in_ENC"]
klasses = puppetclasses.map(&:id)
klasses += hostgroup.classes.map(&:id) if hostgroup
LookupKey.all(:conditions => {:puppetclass_id =>klasses.flatten } ).each do |k|
param[k.to_s] = k.value_for(self)
end unless klasses.empty?
end
9afa092e Ohad Levy
a6e10c72 Jochen Schalanda
info_hash = {}
info_hash['classes'] = self.puppetclasses_names
info_hash['parameters'] = param
info_hash['environment'] = environment.to_s unless environment.nil? or environment.name.nil?

return info_hash
c6eee281 Ohad Levy
end

0ce8fa05 Ohad Levy
def params
parameters = {}
c7643fc9 Ohad Levy
# read common parameters
e6c75845 Ohad Levy
CommonParameter.all.each {|p| parameters.update Hash[p.name => p.value] }
c7643fc9 Ohad Levy
# read domain parameters
b09b4515 Ohad Levy
domain.domain_parameters.each {|p| parameters.update Hash[p.name => p.value] } unless domain.nil?
11782648 Ohad Levy
# read OS parameters
operatingsystem.os_parameters.each {|p| parameters.update Hash[p.name => p.value] } unless operatingsystem.nil?
c7643fc9 Ohad Levy
# read group parameters only if a host belongs to a group
4d4b84f6 Ohad Levy
parameters.update hostgroup.parameters unless hostgroup.nil?
086ec942 Ohad Levy
# and now read host parameters, override if required
host_parameters.each {|p| parameters.update Hash[p.name => p.value] }
0ce8fa05 Ohad Levy
return parameters
end

363141af Ohad Levy
def self.importHostAndFacts yaml
2dcf4736 Ohad Levy
facts = YAML::load yaml
895a7680 Ohad Levy
return false unless facts.is_a?(Puppet::Node::Facts)
2dcf4736 Ohad Levy
895a7680 Ohad Levy
h=find_or_create_by_name(facts.name)
h.save(false) if h.new_record?
h.importFacts(facts)
363141af Ohad Levy
end

# import host facts, required when running without storeconfigs.
# expect a Puppet::Node::Facts
def importFacts facts
raise "invalid Fact" unless facts.is_a?(Puppet::Node::Facts)

# we are not importing facts for hosts in build state (e.g. waiting for a re-installation)
raise "Host is pending for Build" if build
a7db5993 Ohad Levy
time = facts.values[:_timestamp]
time = time.to_time if time.is_a?(String)
895a7680 Ohad Levy
# we are not doing anything we already processed this fact (or a newer one)
return true unless last_compile.nil? or (last_compile + 1.minute < time)

self.last_compile = time
# save all other facts - pre 0.25 it was called setfacts
49f31762 Ohad Levy
respond_to?("merge_facts") ? self.merge_facts(facts.values) : self.setfacts(facts.values)
save(false)
895a7680 Ohad Levy
# we want to import other information only if this host was never installed via Foreman
populateFieldsFromFacts if installed_at.nil?

# we are saving here with no validations, as we want this process to be as fast
# as possible, assuming we already have all the right settings in Foreman.
# If we don't (e.g. we never install the server via Foreman, we populate the fields from facts
# TODO: if it was installed by Foreman and there is a mismatch,
# we should probably send out an alert.
return self.save(false)

rescue Exception => e
logger.warn "Failed to save #{facts.name}: #{e}"
e22af92d Ohad Levy
end

ea4fd101 Ohad Levy
def fv name
2dcf4736 Ohad Levy
v=fact_values.first(:select => "fact_values.value", :joins => :fact_name,
9fd7478e Paul Kelly
:conditions => "fact_names.name = '#{name}'")
749973b4 Ohad Levy
v.value unless v.nil?
ea4fd101 Ohad Levy
end

e22af92d Ohad Levy
def populateFieldsFromFacts
76607ed5 Ohad Levy
unless Setting[:ignore_puppet_facts_for_provisioning]
d568c4cc Ohad Levy
self.mac = fv(:macaddress).downcase unless fv(:macaddress).blank?
d97375e0 Ohad Levy
self.ip = fv(:ipaddress) if ip.nil?
end
895a7680 Ohad Levy
self.domain = Domain.find_or_create_by_name fv(:domain) unless fv(:domain).empty?
e22af92d Ohad Levy
# On solaris architecture fact is harwareisa
363141af Ohad Levy
if myarch=fv(:architecture) || fv(:hardwareisa)
895a7680 Ohad Levy
self.arch=Architecture.find_or_create_by_name myarch unless myarch.empty?
363141af Ohad Levy
end
e22af92d Ohad Levy
# by default, puppet doesnt store an env name in the database
76607ed5 Ohad Levy
env=fv(:environment) || Setting[:default_puppet_environment]
4dd00cbc Ohad Levy
self.environment ||= Environment.find_or_create_by_name env
e22af92d Ohad Levy
ea4fd101 Ohad Levy
os_name = fv(:operatingsystem)
363141af Ohad Levy
if orel = fv(:lsbdistrelease) || fv(:operatingsystemrelease)
major, minor = orel.split(".")
51252890 Frank Sweetser
minor ||= ""
363141af Ohad Levy
self.os = Operatingsystem.find_or_create_by_name_and_major_and_minor os_name, major, minor
end
2dcf4736 Ohad Levy
bc1d0900 Ohad Levy
modelname = fv(:productname) || fv(:model) || (fv(:is_virtual) == "true" ? fv(:virtual) : nil)
8ac3ea75 Ohad Levy
self.model = Model.find_or_create_by_name(modelname.strip) if model.nil? and not modelname.empty?

363141af Ohad Levy
# again we are saving without validations as input is required (e.g. partition tables)
2dcf4736 Ohad Levy
self.save(false)
e22af92d Ohad Levy
end

8613dec9 Ohad Levy
# Called by build link in the list
# Build is set
# The boot link and autosign entry are created
# Any existing puppet certificates are deleted
# Any facts are discarded
def setBuild
5617cefe Ohad Levy
clearFacts
clearReports
5942416f Ohad Levy
# ensures that the legacy TFTP code is not called when using a smart proxy.
unless respond_to?(:tftp?) and tftp?
return false unless GW::Tftp.create([mac, os.to_s.gsub(" ","-"), arch.name, serial])
end

5617cefe Ohad Levy
self.build = true
self.save
90b83222 Ohad Levy
errors.empty?
8613dec9 Ohad Levy
end

816465f2 Ohad Levy
# this method accepts a puppets external node yaml output and generate a node in our setup
# it is assumed that you already have the node (e.g. imported by one of the rack tasks)
def importNode nodeinfo
727312c3 Ohad Levy
myklasses= []
816465f2 Ohad Levy
# puppet classes
nodeinfo["classes"].each do |klass|
if pc = Puppetclass.find_by_name(klass)
727312c3 Ohad Levy
myklasses << pc
816465f2 Ohad Levy
else
0da5bcf1 Ohad Levy
error = "Failed to import #{klass} for #{name}: doesn't exists in our database - ignoring"
722ba6f1 Ohad Levy
logger.warn error
cf2f7656 Ohad Levy
$stdout.puts error
816465f2 Ohad Levy
end
727312c3 Ohad Levy
self.puppetclasses = myklasses
816465f2 Ohad Levy
end

# parameters are a bit more tricky, as some classifiers provide the facts as parameters as well
# not sure what is puppet priority about it, but we ignore it if has a fact with the same name.
# additionally, we don't import any non strings values, as puppet don't know what to do with those as well.

myparams = self.info["parameters"]
nodeinfo["parameters"].each_pair do |param,value|
next if fact_names.exists? :name => param
next unless value.is_a?(String)

# we already have this parameter
next if myparams.has_key?(param) and myparams[param] == value

unless (hp = self.host_parameters.create(:name => param, :value => value))
logger.warn "Failed to import #{param}/#{value} for #{name}: #{hp.errors.full_messages.join(", ")}"
cf2f7656 Ohad Levy
$stdout.puts $!
816465f2 Ohad Levy
end
end

self.save
end

300c8b44 Ohad Levy
# counts each association of a given host
# e.g. how many hosts belongs to each os
# returns sorted hash
def self.count_distribution assocication
output = {}
2c7da330 Ohad Levy
count(:group => assocication).each do |k,v|
begin
output[k.to_label] = v unless v == 0
rescue
logger.info "skipped #{k} as it has has no label"
end
end
300c8b44 Ohad Levy
output
end

# counts each association of a given host for HABTM relationships
# TODO: Merge these two into one method
# e.g. how many hosts belongs to each os
# returns sorted hash
def self.count_habtm assocication
output = {}
Host.count(:include => assocication.pluralize, :group => "#{assocication}_id").to_a.each do |a|
#Ugly Ugly Ugly - I guess I'm missing something basic here
label = eval(assocication.camelize).send("find",a[0].to_i).to_label if a[0]
output[label] = a[1]
end
output
end

3eecf845 Amos Benari
def resources_chart(timerange = 1.day.ago)
c6f1b718 Ohad Levy
data = {}
3eecf845 Amos Benari
data[:applied], data[:failed], data[:restarted], data[:failed_restarts], data[:skipped] = [],[],[],[],[]
e6c75845 Ohad Levy
reports.recent(timerange).each do |r|
3eecf845 Amos Benari
data[:applied] << "[ #{r.reported_at.to_i}000, #{r.applied} ]"
data[:failed] << "[ #{r.reported_at.to_i}000, #{r.failed} ]"
data[:restarted] << "[ #{r.reported_at.to_i}000, #{r.restarted} ]"
data[:failed_restarts] << "[ #{r.reported_at.to_i}000, #{r.failed_restarts} ]"
data[:skipped] << "[ #{r.reported_at.to_i}000, #{r.skipped} ]"
end
return data
end

def runtime_chart(timerange = 1.day.ago)
data = {}
data[:config], data[:runtime] = [], []
reports.recent(timerange).each do |r|
data[:config] << "[ #{r.reported_at.to_i}000, #{r.config_retrieval} ]"
data[:runtime] << "[ #{r.reported_at.to_i}000, #{r.runtime} ]"
72e65b31 Ohad Levy
end
c6f1b718 Ohad Levy
return data
72e65b31 Ohad Levy
end
300c8b44 Ohad Levy
5af52b3b Ohad Levy
def classes_from_storeconfigs
6fc77b66 Ohad Levy
klasses = resources.all(:conditions => {:restype => "Class"}, :select => :title, :order => :title)
9fd7478e Paul Kelly
klasses.map!(&:title).delete(:main)
return klasses
5af52b3b Ohad Levy
end

4e85a944 Ohad Levy
def can_be_build?
2e392b73 Ohad Levy
managed? and (SETTINGS[:unattended].nil? or SETTINGS[:unattended]) ? build == false : false
4e85a944 Ohad Levy
end

3c7750e1 Ohad Levy
def facts_hash
hash = {}
fact_values.all(:include => :fact_name).collect do |fact|
hash[fact.fact_name.name] = fact.value
hash
end
return hash
end

9fd7478e Paul Kelly
def enforce_permissions operation
if operation == "edit" and new_record?
return true # We get called again with the operation being set to create
end
current = User.current
if (operation == "edit") or operation == "destroy"
if current.allowed_to?("#{operation}_hosts".to_sym)
return true if Host.my_hosts(current).include? self
end
else # create
if current.allowed_to?(:create_hosts)
# We are unconstrained
return true if current.domains.empty? and current.hostgroups.empty?
4ebe38c7 Ohad Levy
# We are constrained and the constraint is matched
9fd7478e Paul Kelly
return true if (!current.domains.empty? and current.domains.include?(domain)) or
(!current.hostgroups.empty? and current.hostgroups.include?(hostgroup))
end
end
errors.add_to_base "You do not have permission to #{operation} this host"
false
end

90b83222 Ohad Levy
def sp_valid?
!sp_name.empty? and !sp_ip.empty? and !sp_mac.empty?
end

d3d91384 Ohad Levy
private
# align common mac and ip address input
ad36b317 Ohad Levy
def normalize_addresses
c22d6db2 Ohad Levy
# a helper for variable scoping
helper = []
[self.mac,self.sp_mac].each do |m|
d3d91384 Ohad Levy
unless m.empty?
m.downcase!
if m=~/[a-f0-9]{12}/
m = m.gsub(/(..)/){|mh| mh + ":"}[/.{17}/]
elsif mac=~/([a-f0-9]{1,2}:){5}[a-f0-9]{1,2}/
m = m.split(":").map{|nibble| "%02x" % ("0x" + nibble)}.join(":")
end
end
c22d6db2 Ohad Levy
helper << m
d3d91384 Ohad Levy
end
c22d6db2 Ohad Levy
self.mac, self.sp_mac = helper
d3d91384 Ohad Levy
c22d6db2 Ohad Levy
helper = []
[self.ip,self.sp_ip].each do |i|
unless i.empty?
i = i.split(".").map{|nibble| nibble.to_i}.join(".") if i=~/(\d{1,3}\.){3}\d{1,3}/
d3d91384 Ohad Levy
end
c22d6db2 Ohad Levy
helper << i
d3d91384 Ohad Levy
end
c22d6db2 Ohad Levy
self.ip, self.sp_ip = helper
d3d91384 Ohad Levy
end

a26b8b66 Ohad Levy
# ensure that host name is fqdn
61dc8cee mattmoran76@gmail.com
# if the user inputed short name, the domain name will be appended
8613dec9 Ohad Levy
# this is done to ensure compatibility with puppet storeconfigs
a26b8b66 Ohad Levy
def normalize_hostname
61dc8cee mattmoran76@gmail.com
# no hostname was given or a domain was selected, since this is before validation we need to ignore
# it and let the validations to produce an error
3af5f2e6 Ohad Levy
return if name.empty?

if domain.nil? and name.match(/\./)
# try to assign the domain automaticilly based on our existing domains from the host FQDN
self.domain = Domain.all.select{|d| name.match(d.name)}.first rescue nil
else
# if our host is in short name, append the domain name
99f00455 Frank Sweetser
self.name += ".#{domain}" unless name =~ /.#{domain}$/i
3af5f2e6 Ohad Levy
end
a26b8b66 Ohad Levy
end
d3d91384 Ohad Levy
end