foreman/app/models/puppetclass.rb @ 8a65dff7
c6eee281 | Ohad Levy | class Puppetclass < ActiveRecord::Base
|
|
9fd7478e | Paul Kelly | include Authorization
|
|
6e50fa1d | Ohad Levy | has_and_belongs_to_many :environments
|
|
c6eee281 | Ohad Levy | has_and_belongs_to_many :operatingsystems
|
|
086ec942 | Ohad Levy | has_and_belongs_to_many :hostgroups
|
|
8a65dff7 | Ohad Levy | has_many :host_classes, :dependent => :destroy
|
|
has_many :hosts, :through => :host_classes
|
|||
9afa092e | Ohad Levy | has_many :lookup_keys, :inverse_of => :puppetclass
|
|
accepts_nested_attributes_for :lookup_keys, :reject_if => lambda { |a| a[:key].blank? }, :allow_destroy => true
|
|||
c6eee281 | Ohad Levy | ||
6e50fa1d | Ohad Levy | validates_uniqueness_of :name
|
|
validates_presence_of :name
|
|||
f8e711fe | Ohad Levy | validates_associated :environments
|
|
cec4503c | Lucas Tolchinsky | validates_format_of :name, :with => /\A(\S+\s?)+\Z/, :message => "can't be blank or contain white spaces."
|
|
611397af | Ohad Levy | acts_as_audited
|
|
f8e711fe | Ohad Levy | ||
af6e2624 | Ohad Levy | before_destroy Ensure_not_used_by.new(:hosts)
|
|
before_destroy Ensure_not_used_by.new(:hostgroups)
|
|||
5410421d | Ohad Levy | default_scope :order => 'LOWER(puppetclasses.name)'
|
|
af6e2624 | Ohad Levy | ||
ac7fe332 | Ohad Levy | scoped_search :on => :name, :complete_value => :true
|
|
scoped_search :in => :environments, :on => :name, :complete_value => :true, :rename => "environment"
|
|||
scoped_search :in => :hostgroups, :on => :name, :complete_value => :true, :rename => "hostgroup"
|
|||
7d46a25e | Ohad Levy | scoped_search :in => :hosts, :on => :name, :complete_value => :true, :rename => "host", :ext_method => :search_by_host, :only_explicit => true
|
|
31207a31 | Ohad Levy | ||
def to_param
|
|||
name
|
|||
end
|
|||
ac7fe332 | Ohad Levy | ||
4e7b2b98 | Paul Kelly | # Scans a directory path for puppet classes
|
|
# +paths+ : String containing a colon separated module path
|
|||
adcd0374 | Paul Kelly | # returns
|
|
4ebe38c7 | Ohad Levy | # Array of Strings containing puppet class names
|
|
4e7b2b98 | Paul Kelly | def self.scanForClasses(paths)
|
|
f8e711fe | Ohad Levy | klasses=Array.new
|
|
4e7b2b98 | Paul Kelly | for path in paths.split(":")
|
|
Dir.glob("#{path}/*/manifests/**/*.pp").each do |manifest|
|
|||
File.read(manifest).each_line do |line|
|
|||
klass=line.match(/^class (\S+).*\{/)
|
|||
klasses << klass[1] if klass
|
|||
end
|
|||
f8e711fe | Ohad Levy | end
|
|
end
|
|||
4e7b2b98 | Paul Kelly | return klasses.uniq
|
|
f8e711fe | Ohad Levy | end
|
|
300c8b44 | Ohad Levy | ||
bd46fa41 | Ohad Levy | # returns a hash containing modules and associated classes
|
|
def self.classes2hash classes
|
|||
hash = {}
|
|||
for klass in classes
|
|||
if mod = klass.module_name
|
|||
hash[mod] ||= []
|
|||
hash[mod] << klass
|
|||
else
|
|||
next
|
|||
end
|
|||
end
|
|||
return hash
|
|||
end
|
|||
# returns module name (excluding of the class name)
|
|||
4ebe38c7 | Ohad Levy | # if class separator does not exists (the "::" chars), then returns the whole class name
|
|
bd46fa41 | Ohad Levy | def module_name
|
|
163711af | Ohad Levy | return (i = name.index("::")) ? name[0..i-1] : name
|
|
bd46fa41 | Ohad Levy | end
|
|
# returns class name (excluding of the module name)
|
|||
def klass
|
|||
163711af | Ohad Levy | return name.gsub(module_name+"::","")
|
|
end
|
|||
# add sort by class name
|
|||
def <=>(other)
|
|||
klass <=> other.klass
|
|||
bd46fa41 | Ohad Levy | end
|
|
4ebe38c7 | Ohad Levy | # Retrieve the manifest dir from the puppet configuration
|
|
a67b0923 | Paul Kelly | # Returns: String
|
|
def self.manifestdir
|
|||
ps = Puppet.settings.instance_variable_get(:@values)
|
|||
ps[:main][:manifestdir] || ps[:puppetmasterd][:manifestdir] || ps[:puppetd][:manifestdir] || Puppet.settings[:manifestdir] || "/etc/puppet/manifests"
|
|||
end
|
|||
# Populates the rdoc tree with information about all the classes in your modules.
|
|||
# Firstly, we prepare the modules tree
|
|||
# Secondly we run puppetdoc over the modulespath and manifestdir for all environments
|
|||
# The results are written into document_root/puppet/rdoc/<env>/<class>"
|
|||
def self.rdoc root
|
|||
debug, verbose = false, false
|
|||
relocated = root != "/" # This is true if the prepare phase copied the modules tree
|
|||
# Retrieve an optional http server's DocumentRoot from the settings.yaml file, and prepare it for writing
|
|||
76607ed5 | Ohad Levy | doc_root = Pathname.new(Setting[:document_root])
|
|
a67b0923 | Paul Kelly | doc_root.mkpath
|
|
unless doc_root.directory? and doc_root.writable?
|
|||
puts "Unable to write html to #{doc_root}"
|
|||
return false
|
|||
end
|
|||
aa6430ed | Paul Kelly | validator = '<div id="validator-badges">'
|
|
a67b0923 | Paul Kelly | # For each environment we write a puppetdoc tree
|
|
for env, path in Environment.puppetEnvs
|
|||
# We may need to rewrite the modulepaths because they have been changed by the prepare step
|
|||
modulepaths = relocated ? path.split(":").map{|p| root + p}.join(":") : path
|
|||
# Identify and prepare the output directory
|
|||
out = doc_root + env.id2name
|
|||
out.rmtree if out.directory?
|
|||
aa6430ed | Paul Kelly | replacement = "<div id=\\\"validator-badges\\\"><small><a href=\\\"/puppet/rdoc/#{env}/\\\">[Browser]</a></small>"
|
|
a67b0923 | Paul Kelly | # Create the documentation
|
|
aa6430ed | Paul Kelly | ||
cmd = "puppetdoc --output #{out} --modulepath #{modulepaths} -m rdoc"
|
|||
puts cmd if defined?(Rake)
|
|||
sh cmd do |ok, res|
|
|||
unless ok
|
|||
logger.warn "Failed to process puppetdocs for #{out} while executing #{cmd}"
|
|||
warn "Failed to process puppetdocs for #{out} while executing #{cmd}"
|
|||
return false
|
|||
end
|
|||
# Add a link to the class browser
|
|||
files = %x{find #{out} -exec grep -l 'validator-badges' {} \\; 2>/dev/null}.gsub(/\n/, " ")
|
|||
if files.empty?
|
|||
warn "No files to update with the browser link in #{out}. This is probably due to a previous error."
|
|||
a67b0923 | Paul Kelly | else
|
|
aa6430ed | Paul Kelly | cmd = "ruby -p -i -e '$_.gsub!(/#{validator}/,\"#{replacement}\")' #{files}"
|
|
puts cmd if debug
|
|||
sh cmd
|
|||
end
|
|||
# Relocate the paths for files and references if the manifests were relocated and sanitized
|
|||
if relocated and (files = %x{find #{out} -exec grep -l '#{root}' {} \\;}.gsub(/\n/, " ")) != ""
|
|||
puts "Rewriting..." if verbose
|
|||
cmd = "ruby -p -i -e 'rex=%r{#{root}};$_.gsub!(rex,\"\")' #{files}"
|
|||
puts cmd if debug
|
|||
sh cmd
|
|||
# Now relocate the files/* files to match the rewritten url
|
|||
mv Dir.glob("#{out}/files/#{root}/*"), "#{out}/files", :verbose => verbose
|
|||
a67b0923 | Paul Kelly | end
|
|
end
|
|||
end
|
|||
end
|
|||
# Optionally creates a copy of the current puppet modules and sanitizes it.
|
|||
# If your 'live' manifests and modules can be parsed by puppetdoc
|
|||
4ebe38c7 | Ohad Levy | # then you do not need to do this step. (Unfortunately some sites have circular
|
|
a67b0923 | Paul Kelly | # symlinks which have to be removed.)
|
|
# If the executable RAILS_ROOT/script/rdoc_prepare_script exists then it is run
|
|||
# and passed a list of all directory paths in all environments.
|
|||
# It should return the directory into which it has copied the cleaned modules"
|
|||
def self.prepare_rdoc root
|
|||
debug, verbose = false, false
|
|||
prepare_script = Pathname.new(RAILS_ROOT) + "script/rdoc_prepare_script.rb"
|
|||
if prepare_script.executable?
|
|||
dirs = Environment.puppetEnvs.values.join(":").split(":").uniq.sort.join(" ")
|
|||
puts "Running #{prepare_script} #{dirs}" if debug
|
|||
location = %x{#{prepare_script} #{dirs}}
|
|||
if $? == 0
|
|||
root = location.chomp
|
|||
puts "Relocated modules to #{root}" if verbose
|
|||
end
|
|||
else
|
|||
puts "No executable #{prepare_script} found so using the uncopied module sources" if verbose
|
|||
end
|
|||
root
|
|||
end
|
|||
3aa6ea3f | Ohad Levy | ||
def as_json(options={})
|
|||
super({:only => [:name, :id]}.merge(options))
|
|||
end
|
|||
31207a31 | Ohad Levy | def self.search_by_host(key, operator, value)
|
|
conditions = "hosts.name #{operator} '#{value_to_sql(operator, value)}'"
|
|||
direct = Puppetclass.all(:conditions => conditions, :joins => :hosts, :select => 'DISTINCT puppetclasses.id').map(&:id)
|
|||
indirect = Hostgroup.all(:conditions => conditions, :joins => [:hosts,:puppetclasses], :select => 'DISTINCT puppetclasses.id').map(&:id)
|
|||
opts = ''
|
|||
opts += "puppetclasses.id IN(#{direct.join(',')})" unless direct.blank?
|
|||
opts += " OR " unless direct.blank? || indirect.blank?
|
|||
opts += "hostgroups.id IN(#{indirect.join(',')})" unless indirect.blank?
|
|||
opts = "puppetclasses.id = 'nil'" if direct.blank? && indirect.blank?
|
|||
return {:conditions => opts, :include => :hostgroups}
|
|||
end
|
|||
def self.value_to_sql(operator, value)
|
|||
return value if operator !~ /LIKE/i
|
|||
return value.tr_s('%*', '%') if (value ~ /%|\*/)
|
|||
return "%#{value}%"
|
|||
end
|
|||
6e50fa1d | Ohad Levy | end
|