We need this because the RAL uses ‘should’ as a method. This allows us the same behaviour but with a different method name.
Add our wrapper to the method.
Behavior for custom classes
msdn.microsoft.com/en-us/library/windows/desktop/aa368542(v=vs.85).aspx
The query format by which we identify installed packages
This map exists due to the use of hyphens and reserved words in the authorization schema.
This provides a mapping of puppet types to DirectoryService type strings.
# File lib/puppet/type/file.rb, line 304 def self.[](path) return nil unless path super(path.gsub(/\/+/, '/').sub(/\/$/, '')) end
# File lib/puppet/type/zone.rb, line 63 def self.alias_state(values) values.each do |k,v| fsm.alias_state(k,v) end end
Group attributes to ignore
# File lib/puppet/provider/group/aix.rb, line 27 def self.attribute_ignore [] end
Turns a pkgutil -a listing into hashes with the common alias, full package name and available version
# File lib/puppet/provider/package/pkgutil.rb, line 63 def self.availlist output = pkguti ["-a"] list = output.split("\n").collect do |line| next if line =~ /^common\s+package/ # header of package list next if noise?(line) if line =~ /\s*(\S+)\s+(\S+)\s+(.*)/ { :alias => $1, :name => $2, :avail => $3 } else Puppet.warning "Cannot match %s" % line end end.reject { |h| h.nil? } end
Turn our blastwave listing into a bunch of hashes.
# File lib/puppet/provider/package/blastwave.rb, line 35 def self.blastlist(hash) command = ["-c"] command << hash[:justme] if hash[:justme] output = Puppet::Util.withenv(:PAGER => "/usr/bin/cat") { pkgget command } list = output.split("\n").collect do |line| next if line =~ /^#/ next if line =~ /^WARNING/ next if line =~ /localrev\s+remoterev/ blastsplit(line) end.reject { |h| h.nil? } if hash[:justme] return list[0] else list.reject! { |h| h[:ensure] == :absent } return list end end
Split the different lines into hashes.
# File lib/puppet/provider/package/blastwave.rb, line 62 def self.blastsplit(line) if line =~ /\s*(\S+)\s+((\[Not installed\])|(\S+))\s+(\S+)/ hash = {} hash[:name] = $1 hash[:ensure] = if $2 == "[Not installed]" :absent else $2 end hash[:avail] = $5 hash[:avail] = hash[:ensure] if hash[:avail] == "SAME" # Use the name method, so it works with subclasses. hash[:provider] = self.name return hash else Puppet.warning "Cannot match #{line}" return nil end end
# File lib/puppet/provider/package/pip.rb, line 38 def self.cmd case Facter.value(:osfamily) when "RedHat" "pip-python" else "pip" end end
This method will accept a binary plist (as a string) and convert it to a hash via Plist::parse_xml.
# File lib/puppet/provider/user/directoryservice.rb, line 201 def self.convert_binary_to_xml(plist_data) Puppet.debug('Converting binary plist to XML') Puppet.debug('Executing: \plutil -convert xml1 -o - -\') IO.popen('plutil -convert xml1 -o - -', mode='r+') do |io| io.write plist_data io.close_write @converted_plist = io.read end Puppet.debug('Converting XML values to a hash.') Plist::parse_xml(@converted_plist) end
This method will accept a hash that has been returned from Plist::parse_xml and convert it to a binary plist (string value).
# File lib/puppet/provider/user/directoryservice.rb, line 188 def self.convert_xml_to_binary(plist_data) Puppet.debug('Converting XML plist to binary') Puppet.debug('Executing: \plutil -convert binary1 -o - -\') IO.popen('plutil -convert binary1 -o - -', mode='r+') do |io| io.write Plist::Emit.dump(plist_data) io.close_write @converted_plist = io.read end @converted_plist end
returns the daemon dir on this node
# File lib/puppet/provider/service/daemontools.rb, line 84 def self.daemondir self.defpath end
# File lib/puppet/provider/zone/solaris.rb, line 49 def self.def_multiprop(var, &conf) define_method(var.to_s) do |v| o = properties[var] return '' if o.nil? or o == :absent o.join(' ') end define_method('%s=' % var.to_s) do |v| setconfig self.send( ('%s_conf'% var).intern, v) end define_method('%s_conf' % var.to_s) do |v| multi_conf(var, v, &conf) end end
# File lib/puppet/provider/zone/solaris.rb, line 40 def self.def_prop(var, str) define_method('%s_conf' % var.to_s) do |v| str % v end define_method('%s=' % var.to_s) do |v| setconfig self.send( ('%s_conf'% var).intern, v) end end
# File lib/puppet/provider/service/bsd.rb, line 16 def self.defpath superclass.defpath end
removes all reports for a given host?
# File lib/puppet/reports/store.rb, line 52 def self.destroy(host) validate_host(host) dir = File.join(Puppet[:reportdir], host) if File.exists?(dir) Dir.entries(dir).each do |file| next if ['.','..'].include?(file) file = File.join(dir, file) File.unlink(file) if File.file?(file) end Dir.rmdir(dir) end end
This method exists to map the dscl values to the correct Puppet properties. This stays relatively consistent, but who knows what Apple will do next year…
# File lib/puppet/provider/user/directoryservice.rb, line 40 def self.ds_to_ns_attribute_map { 'RecordName' => :name, 'PrimaryGroupID' => :gid, 'NFSHomeDirectory' => :home, 'UserShell' => :shell, 'UniqueID' => :uid, 'RealName' => :comment, 'Password' => :password, 'GeneratedUID' => :guid, 'IPAddress' => :ip_address, 'ENetAddress' => :en_address, 'GroupMembership' => :members, } end
# File lib/puppet/provider/package/portage.rb, line 130 def self.eix_result_fields [:category, :name, :ensure, :version_available, :vendor, :description] end
# File lib/puppet/provider/package/portage.rb, line 126 def self.eix_result_format /^(\S+)\s+(\S+)\s+\[(\S*)\]\s+\[(\S*)\]\s+(\S+)\s+(.*)$/ end
# File lib/puppet/provider/package/portage.rb, line 138 def self.eix_search_arguments ["--nocolor", "--pure-packages", "--format",self.eix_search_format] end
# File lib/puppet/provider/package/portage.rb, line 122 def self.eix_search_format "'<category> <name> [<installedversions:LASTVERSION>] [<bestversion:LASTVERSION>] <homepage> <description>'" end
# File lib/puppet/provider/package/portage.rb, line 134 def self.eix_version_format "{last}<version>{}" end
# File lib/puppet/provider/package/blastwave.rb, line 15 def self.extended(mod) unless command(:pkgget) != "pkg-get" raise Puppet::Error, "The pkg-get command is missing; blastwave packaging unavailable" end unless FileTest.exists?("/var/pkg-get/admin") Puppet.notice "It is highly recommended you create '/var/pkg-get/admin'." Puppet.notice "See /var/pkg-get/admin-fullauto" end end
# File lib/puppet/type/zone.rb, line 58 def self.fsm return @fsm if @fsm @fsm = StateMachine.new end
# File lib/puppet/provider/package/gem.rb, line 15 def self.gemlist(options) gem_list_command = [command(:gemcmd), "list"] if options[:local] gem_list_command << "--local" else gem_list_command << "--remote" end if options[:source] gem_list_command << "--source" << options[:source] end if name = options[:justme] gem_list_command << name + "$" end begin list = execute(gem_list_command).lines. map {|set| gemsplit(set) }. reject {|x| x.nil? } rescue Puppet::ExecutionFailure => detail raise Puppet::Error, "Could not list gems: #{detail}" end if options[:justme] return list.shift else return list end end
# File lib/puppet/provider/package/gem.rb, line 45 def self.gemsplit(desc) # `gem list` when output console has a line like: # *** LOCAL GEMS *** # but when it's not to the console that line # and all blank lines are stripped # so we don't need to check for them if desc =~ /^(\S+)\s+\((.+)\)/ name = $1 versions = $2.split(/,\s*/) { :name => name, :ensure => versions, :provider => :gem } else Puppet.warning "Could not match #{desc}" unless desc.chomp.empty? nil end end
This method accepts an individual user plist, passed as a hash, and strips the dsAttrTypeStandard: prefix that dscl adds for each key. An attribute hash is assembled and returned from the properties supported by the user type.
# File lib/puppet/provider/user/directoryservice.rb, line 98 def self.generate_attribute_hash(input_hash) attribute_hash = {} input_hash.keys.each do |key| ds_attribute = key.sub("dsAttrTypeStandard:", "") next unless ds_to_ns_attribute_map.keys.include?(ds_attribute) ds_value = input_hash[key] case ds_to_ns_attribute_map[ds_attribute] when :gid, :uid # OS X stores objects like uid/gid as strings. # Try casting to an integer for these cases to be # consistent with the other providers and the group type # validation begin ds_value = Integer(ds_value[0]) rescue ArgumentError ds_value = ds_value[0] end else ds_value = ds_value[0] end attribute_hash[ds_to_ns_attribute_map[ds_attribute]] = ds_value end attribute_hash[:ensure] = :present attribute_hash[:provider] = :directoryservice attribute_hash[:shadowhashdata] = get_attribute_from_dscl('Users', attribute_hash[:name], 'ShadowHashData') ############## # Get Groups # ############## groups_array = [] get_list_of_groups.each do |group| if group["dsAttrTypeStandard:GroupMembership"] and group["dsAttrTypeStandard:GroupMembership"].include?(attribute_hash[:name]) groups_array << group["dsAttrTypeStandard:RecordName"][0] end if group["dsAttrTypeStandard:GroupMembers"] and group["dsAttrTypeStandard:GroupMembers"].include?(attribute_hash[:guid]) groups_array << group["dsAttrTypeStandard:RecordName"][0] end end attribute_hash[:groups] = groups_array.uniq.sort.join(',') ################################ # Get Password/Salt/Iterations # ################################ if (Puppet::Util::Package.versioncmp(get_os_version, '10.7') == -1) attribute_hash[:password] = get_sha1(attribute_hash[:guid]) else if attribute_hash[:shadowhashdata].empty? attribute_hash[:password] = '*' else embedded_binary_plist = get_embedded_binary_plist(attribute_hash[:shadowhashdata]) if embedded_binary_plist['SALTED-SHA512'] attribute_hash[:password] = get_salted_sha512(embedded_binary_plist) else attribute_hash[:password] = get_salted_sha512_pbkdf2('entropy', embedded_binary_plist) attribute_hash[:salt] = get_salted_sha512_pbkdf2('salt', embedded_binary_plist) attribute_hash[:iterations] = get_salted_sha512_pbkdf2('iterations', embedded_binary_plist) end end end attribute_hash end
Return an array of hashes containing information about every user on the system.
# File lib/puppet/provider/user/directoryservice.rb, line 90 def self.get_all_users Plist.parse_xml(dscl '-plist', '.', 'readall', '/Users') end
Perform a dscl lookup at the path specified for the specific keyname value. The value returned is the first item within the array returned from dscl
# File lib/puppet/provider/user/directoryservice.rb, line 174 def self.get_attribute_from_dscl(path, username, keyname) Plist.parse_xml(dscl '-plist', '.', 'read', "/#{path}/#{username}", keyname) end
The plist embedded in the ShadowHashData key is a binary plist. The facter/util/plist library doesn’t read binary plists, so we need to extract the binary plist, convert it to XML, and return it.
# File lib/puppet/provider/user/directoryservice.rb, line 181 def self.get_embedded_binary_plist(shadow_hash_data) embedded_binary_plist = Array(shadow_hash_data['dsAttrTypeNative:ShadowHashData'][0].delete(' ')).pack('H*') convert_binary_to_xml(embedded_binary_plist) end
Use dscl to retrieve an array of hashes containing attributes about all of the local groups on the machine.
# File lib/puppet/provider/user/directoryservice.rb, line 167 def self.get_list_of_groups @groups ||= Plist.parse_xml(dscl '-plist', '.', 'readall', '/Groups') end
# File lib/puppet/provider/service/launchd.rb, line 202 def self.get_macosx_version_major return @macosx_version_major if @macosx_version_major begin # Make sure we've loaded all of the facts Facter.loadfacts product_version_major = Facter.value(:macosx_productversion_major) fail("#{product_version_major} is not supported by the launchd provider") if %w{10.0 10.1 10.2 10.3 10.4}.include?(product_version_major) @macosx_version_major = product_version_major return @macosx_version_major rescue Puppet::ExecutionFailure => detail fail("Could not determine OS X version: #{detail}") end end
# File lib/puppet/provider/user/directoryservice.rb, line 161 def self.get_os_version @os_version ||= Facter.value(:macosx_productversion_major) end
The salted-SHA512 password hash in 10.7 is stored in the ‘SALTED-SHA512’ key as binary data. That data is extracted and converted to a hex string.
# File lib/puppet/provider/user/directoryservice.rb, line 215 def self.get_salted_sha512(embedded_binary_plist) embedded_binary_plist['SALTED-SHA512'].string.unpack("H*")[0] end
This method reads the passed embedded_binary_plist hash and returns values according to which field is passed. Arguments passed are the hash containing the value read from the ‘ShadowHashData’ key in the User’s plist, and the field to be read (one of ‘entropy’, ‘salt’, or ‘iterations’)
# File lib/puppet/provider/user/directoryservice.rb, line 223 def self.get_salted_sha512_pbkdf2(field, embedded_binary_plist) case field when 'salt', 'entropy' embedded_binary_plist['SALTED-SHA512-PBKDF2'][field].string.unpack('H*').first when 'iterations' Integer(embedded_binary_plist['SALTED-SHA512-PBKDF2'][field]) else raise Puppet::Error, 'Puppet has tried to read an incorrect value from the ' + "SALTED-SHA512-PBKDF2 hash. Acceptable fields are 'salt', " + "'entropy', or 'iterations'." end end
# File lib/puppet/provider/service/init.rb, line 27 def self.get_services(defpath, exclude=[]) defpath = [defpath] unless defpath.is_a? Array instances = [] defpath.each do |path| unless FileTest.directory?(path) Puppet.debug "Service path #{path} does not exist" next end check = [:ensure] check << :enable if public_method_defined? :enabled? Dir.entries(path).each do |name| fullpath = File.join(path, name) next if name =~ /^\./ next if exclude.include? name next if not FileTest.executable?(fullpath) next if not is_init?(fullpath) instances << new(:name => name, :path => path, :hasstatus => true) end end instances end
In versions 10.5 and 10.6 of OS X, the password hash is stored in a file in the /var/db/shadow/hash directory that matches the GUID of the user.
# File lib/puppet/provider/user/directoryservice.rb, line 238 def self.get_sha1(guid) password_hash = nil password_hash_file = "#{password_hash_dir}/#{guid}" if File.exists?(password_hash_file) and File.file?(password_hash_file) raise Puppet::Error, "Could not read password hash file at #{password_hash_file}" if not File.readable?(password_hash_file) f = File.new(password_hash_file) password_hash = f.read f.close end password_hash end
Get the groupname from its id
# File lib/puppet/provider/user/aix.rb, line 149 def self.groupname_by_id(gid) groupname=nil execute(lsgroupscmd("ALL")).each_line { |entry| attrs = self.parse_attr_list(entry, nil) if attrs and attrs.include? :id and gid == attrs[:id].to_i groupname = entry.split(" ")[0] end } groupname end
# File lib/puppet/provider/package/macports.rb, line 39 def self.hash_from_line(line, regex, fields) hash = {} if match = regex.match(line) fields.zip(match.captures) { |field, value| hash[field] = value } hash[:provider] = self.name return hash end nil end
Return the header placed at the top of each generated file, warning users that modifying this file manually is probably a bad idea.
# File lib/puppet/provider/cron/crontab.rb, line 80 def self.header %Q{# HEADER: This file was autogenerated at #{Time.now} by puppet. # HEADER: While it can still be managed manually, it is definitely not recommended. # HEADER: Note particularly that the comments starting with 'Puppet Name' should # HEADER: not be deleted, as doing so could cause duplicate cron jobs.\n} end
# File lib/puppet/provider/package/pkgutil.rb, line 16 def self.healthcheck() unless FileTest.exists?("/var/opt/csw/pkgutil/admin") Puppet.notice "It is highly recommended you create '/var/opt/csw/pkgutil/admin'." Puppet.notice "See /var/opt/csw/pkgutil" end correct_wgetopts = false [ "/opt/csw/etc/pkgutil.conf", "/etc/opt/csw/pkgutil.conf" ].each do |confpath| File.open(confpath) do |conf| conf.each_line {|line| correct_wgetopts = true if line =~ /^\s*wgetopts\s*=.*(-nv|-q|--no-verbose|--quiet)/ } end end if ! correct_wgetopts Puppet.notice "It is highly recommended that you set 'wgetopts=-nv' in your pkgutil.conf." end end
The IFO flag field is just what it names, the first field can have ether i_nstalled or -, and second field f_rozen or -, and last o_bsolate or r_rename or - so this checks if the installed field is present, and also verifies that if not the field is -, else we dont know what we are doing and exit with out doing more damage.
# File lib/puppet/provider/package/pkg.rb, line 38 def self.ifo_flag(flags) ( case flags[0..0] when 'i' {:status => 'installed'} when '-' {:status => 'known'} else raise ArgumentError, 'Unknown format %s: %s[%s]' % [self.name, flags, flags[0..0]] end ).merge( case flags[1..1] when 'f' {:ensure => 'held'} when '-' {} else raise ArgumentError, 'Unknown format %s: %s[%s]' % [self.name, flags, flags[1..1]] end ) end
# File lib/puppet/provider/package/appdmg.rb, line 42 def self.installapp(source, name, orig_source) appname = File.basename(source); ditto "--rsrc", source, "/Applications/#{appname}" File.open("/var/db/.puppet_appdmg_installed_#{name}", "w") do |t| t.print "name: '#{name}'\n" t.print "source: '#{orig_source}'\n" end end
# File lib/puppet/provider/package/pkgdmg.rb, line 46 def self.installpkg(source, name, orig_source) installer "-pkg", source, "-target", "/" # Non-zero exit status will throw an exception. File.open("/var/db/.puppet_pkgdmg_installed_#{name}", "w") do |t| t.print "name: '#{name}'\n" t.print "source: '#{orig_source}'\n" end end
# File lib/puppet/provider/package/appdmg.rb, line 51 def self.installpkgdmg(source, name) unless source =~ /\.dmg$/ self.fail "Mac OS X PKG DMG's must specify a source string ending in .dmg" end require 'open-uri' require 'facter/util/plist' cached_source = source tmpdir = Dir.mktmpdir begin if %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ cached_source cached_source = File.join(tmpdir, name) begin curl "-o", cached_source, "-C", "-", "-k", "-L", "-s", "--url", source Puppet.debug "Success: curl transfered [#{name}]" rescue Puppet::ExecutionFailure Puppet.debug "curl did not transfer [#{name}]. Falling back to slower open-uri transfer methods." cached_source = source end end open(cached_source) do |dmg| xml_str = hdiutil "mount", "-plist", "-nobrowse", "-readonly", "-mountrandom", "/tmp", dmg.path ptable = Plist::parse_xml xml_str # JJM Filter out all mount-paths into a single array, discard the rest. mounts = ptable['system-entities'].collect { |entity| entity['mount-point'] }.select { |mountloc|; mountloc } begin mounts.each do |fspath| Dir.entries(fspath).select { |f| f =~ /\.app$/ }.each do |pkg| installapp("#{fspath}/#{pkg}", name, source) end end ensure hdiutil "eject", mounts[0] end end ensure FileUtils.remove_entry_secure(tmpdir, force=true) end end
# File lib/puppet/provider/package/apple.rb, line 24 def self.instance_by_name Dir.entries("/Library/Receipts").find_all { |f| f =~ /\.pkg$/ }.collect { |f| name = f.sub(/\.pkg/, '') yield name if block_given? name } end
# File lib/puppet/provider/group/windows_adsi.rb, line 51 def self.instances Puppet::Util::ADSI::Group.map { |g| new(:ensure => :present, :name => g.name) } end
JJM We store a cookie for each installed .app.dmg in /var/db
# File lib/puppet/provider/package/appdmg.rb, line 26 def self.instances_by_name Dir.entries("/var/db").find_all { |f| f =~ /^\.puppet_appdmg_installed_/ }.collect do |f| name = f.sub(/^\.puppet_appdmg_installed_/, '') yield name if block_given? name end end
# File lib/puppet/provider/service/init.rb, line 136 def self.is_init?(script = initscript) !File.symlink?(script) || File.readlink(script) != "/lib/init/upstart-job" end
This status method lists out all currently running services. This hash is returned at the end of the method.
# File lib/puppet/provider/service/launchd.rb, line 154 def self.job_list @job_list = Hash.new begin output = launchctl :list raise Puppet::Error.new("launchctl list failed to return any data.") if output.nil? output.split("\n").each do |line| @job_list[line.split(/\s/).last] = :running end rescue Puppet::ExecutionFailure raise Puppet::Error.new("Unable to determine status of #{resource[:name]}") end @job_list end
Sets a class instance variable with a hash of all launchd plist files that are found on the system. The key of the hash is the job id and the value is the path to the file. If a label is passed, we return the job id and path for that specific job.
# File lib/puppet/provider/service/launchd.rb, line 119 def self.jobsearch(label=nil) @label_to_path_map ||= {} if @label_to_path_map.empty? launchd_paths.each do |path| return_globbed_list_of_file_paths(path).each do |filepath| job = read_plist(filepath) next if job.nil? if job.has_key?("Label") if job["Label"] == label return { label => filepath } else @label_to_path_map[job["Label"]] = filepath end else Puppet.warning("The #{filepath} plist does not contain a 'label' key; " + "Puppet is skipping it") next end end end end if label if @label_to_path_map.has_key? label return { label => @label_to_path_map[label] } else raise Puppet::Error.new("Unable to find launchd plist for job: #{label}") end else @label_to_path_map end end
Defines the path to the overrides plist file where service enabling behavior is defined in 10.6 and greater.
@api private
# File lib/puppet/provider/service/launchd.rb, line 73 def self.launchd_overrides "/var/db/launchd.db/com.apple.launchd/overrides.plist" end
These are the paths in OS X where a launchd service plist could exist. This is a helper method, versus a constant, for easy testing and mocking
@api private
# File lib/puppet/provider/service/launchd.rb, line 60 def self.launchd_paths [ "/Library/LaunchAgents", "/Library/LaunchDaemons", "/System/Library/LaunchAgents", "/System/Library/LaunchDaemons" ] end
Convert the output of a list into a hash
# File lib/puppet/provider/zone/solaris.rb, line 10 def self.line2hash(line) fields = [:id, :name, :ensure, :path, :uuid, :brand, :iptype] properties = Hash[fields.zip(line.split(':'))] del_id = [:brand, :uuid] # Configured but not installed zones do not have IDs del_id << :id if properties[:id] == "-" del_id.each { |p| properties.delete(p) } properties[:ensure] = properties[:ensure].intern properties[:iptype] = 'exclusive' if properties[:iptype] == 'excl' properties end
# File lib/puppet/provider/package/freebsd.rb, line 14 def self.listcmd command(:pkginfo) end
# File lib/puppet/provider/interface/cisco.rb, line 9 def self.lookup(device, name) interface = nil device.command do |ng| interface = device.interface(name) end interface end
See if we can match the record against an existing cron job.
# File lib/puppet/provider/cron/crontab.rb, line 88 def self.match(record, resources) resources.each do |name, resource| # Match the command first, since it's the most important one. next unless record[:target] == resource.value(:target) next unless record[:command] == resource.value(:command) # Then check the @special stuff if record[:special] next unless resource.value(:special) == record[:special] end # Then the normal fields. matched = true record_type(record[:record_type]).fields.each do |field| next if field == :command next if field == :special if record[field] and ! resource.value(field) #Puppet.info "Cron is missing %s: %s and %s" % # [field, record[field].inspect, resource.value(field).inspect] matched = false break end if ! record[field] and resource.value(field) #Puppet.info "Hash is missing %s: %s and %s" % # [field, resource.value(field).inspect, record[field].inspect] matched = false break end # Yay differing definitions of absent. next if (record[field] == :absent and resource.value(field) == "*") # Everything should be in the form of arrays, not the normal text. next if (record[field] == resource.value(field)) #Puppet.info "Did not match %s: %s vs %s" % # [field, resource.value(field).inspect, record[field].inspect] matched = false break end return resource if matched end false end
# File lib/puppet/util/log/destinations.rb, line 49 def self.match?(obj) Puppet::Util.absolute_path?(obj) end
# File lib/puppet/provider/mcx/mcxcontent.rb, line 62 def self.mcxexport(ds_type, ds_name) ds_t = TypeMap[ds_type] ds_n = ds_name.to_s ds_path = "/Local/Default/#{ds_t}/#{ds_n}" dscl 'localhost', '-mcxexport', ds_path end
# File lib/puppet/provider/mount/parsed.rb, line 89 def self.mountinstances # XXX: Will not work for mount points that have spaces in path (does fstab support this anyways?) regex = case Facter.value(:osfamily) when "Darwin" / on (?:\/private\/var\/automount)?(\S*)/ when "Solaris", "HP-UX" /^(\S*) on / when "AIX" /^(?:\S*\s+\S+\s+)(\S+)/ else / on (\S*)/ end instances = [] mount_output = mountcmd.split("\n") if mount_output.length >= 2 and mount_output[1] =~ /^[- \t]*$/ # On some OSes (e.g. AIX) mount output begins with a header line # followed by a line consisting of dashes and whitespace. # Discard these two lines. mount_output[0..1] = [] end mount_output.each do |line| if match = regex.match(line) and name = match.captures.first instances << {:name => name, :mounted => :yes} # Only :name is important here else raise Puppet::Error, "Could not understand line #{line} from mount output" end end instances end
Convert a group name to an id.
# File lib/puppet/provider/group/ldap.rb, line 38 def self.name2id(group) return nil unless result = manager.search("cn=#{group}") and result.length > 0 # Only use the first result. group = result[0] gid = group[:gid][0] end
# File lib/puppet/provider/package/sun.rb, line 28 def self.namemap(hash) Namemap.keys.inject({}) do |hsh,k| hsh.merge(Namemap[k] => hash[k]) end end
# File lib/puppet/provider/package/rpm.rb, line 124 def self.nevra_to_hash(line) line.chomp! hash = {} NEVRA_FIELDS.zip(line.split) { |f, v| hash[f] = v } hash[:provider] = self.name hash[:ensure] = "#{hash[:version]}-#{hash[:release]}" hash end
# File lib/puppet/provider/interface/cisco.rb, line 17 def initialize(device, *args) super end
Identify common types of pkgutil noise as it downloads catalogs etc
# File lib/puppet/provider/package/pkgutil.rb, line 115 def self.noise?(line) true if line =~ /^#/ true if line =~ /^Checking integrity / # use_gpg true if line =~ /^gpg: / # gpg verification true if line =~ /^=+> / # catalog fetch true if line =~ /\d+:\d+:\d+ URL:/ # wget without -q false end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 253 def self.normalized_date(date_string) date = Date.parse("#{date_string}") "#{date.year}-#{date.month}-#{date.day}" end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 258 def self.normalized_time(time_string) Time.parse("#{time_string}").strftime('%H:%M') end
# File lib/puppet/provider/user/directoryservice.rb, line 56 def self.ns_to_ds_attribute_map @ns_to_ds_attribute_map ||= ds_to_ns_attribute_map.invert end
Parse lines of output from `pip freeze`, which are structured as package==version.
# File lib/puppet/provider/package/pip.rb, line 16 def self.parse(line) if line.chomp =~ /^([^=]+)==([^=]+)$/ {:ensure => $2, :name => $1, :provider => name} else nil end end
# File lib/puppet/provider/package/macports.rb, line 33 def self.parse_info_query_line(line) regex = /(\S+)\s+(\S+)/ fields = [:version, :revision] hash_from_line(line, regex, fields) end
# File lib/puppet/provider/package/macports.rb, line 27 def self.parse_installed_query_line(line) regex = /(\S+)\s+@(\S+)_(\d+).*\(active\)/ fields = [:name, :ensure, :revision] hash_from_line(line, regex, fields) end
# File lib/puppet/provider/package/dpkg.rb, line 40 def self.parse_line(line) if match = self::REGEX.match(line) hash = {} self::FIELDS.zip(match.captures) { |field,value| hash[field] = value } hash[:provider] = self.name if hash[:status] == 'not-installed' hash[:ensure] = :purged elsif ['config-files', 'half-installed', 'unpacked', 'half-configured'].include?(hash[:status]) hash[:ensure] = :absent end hash[:ensure] = :held if hash[:desired] == 'hold' else Puppet.warning "Failed to match dpkg-query line #{line.inspect}" return nil end hash end
parse sshv2 option strings, wich is a comma separated list of either key=“values” elements or bare-word elements
# File lib/puppet/provider/ssh_authorized_key/parsed.rb, line 71 def self.parse_options(options) result = [] scanner = StringScanner.new(options) while !scanner.eos? scanner.skip(/[ \t]*/) # scan a long option if out = scanner.scan(/[-a-z0-9A-Z_]+=\".*?\"/) or out = scanner.scan(/[-a-z0-9A-Z_]+/) result << out else # found an unscannable token, let's abort break end # eat a comma scanner.skip(/[ \t]*,[ \t]*/) end result end
# File lib/puppet/provider/package/pkgin.rb, line 12 def self.parse_pkgin_line(package, force_status=nil) # e.g. # vim-7.2.446 = Vim editor (vi clone) without GUI match, name, version, status = *package.match(/(\S+)-(\S+)(?: (=|>|<))?\s+.+$/) if match ensure_status = if force_status force_status elsif status :present else :absent end { :name => name, :ensure => ensure_status, :provider => :pkgin } end end
# File lib/puppet/provider/package/sun.rb, line 34 def self.parse_pkginfo(out) # collect all the lines with : in them, and separate them out by ^$ pkgs = [] pkg = {} out.each_line do |line| case line.chomp when /^\s*$/ pkgs << pkg unless pkg.empty? pkg = {} when /^\s*([^:]+):\s+(.+)$/ pkg[$1] = $2 end end pkgs << pkg unless pkg.empty? pkgs end
Turn our pkgutil -c listing into a bunch of hashes.
# File lib/puppet/provider/package/pkgutil.rb, line 87 def self.parse_pkglist(output, hash = {}) output = output.split("\n") if output[-1] == "Not in catalog" Puppet.warning "Package not in pkgutil catalog: %s" % hash[:justme] return nil end list = output.collect do |line| next if line =~ /installed\s+catalog/ # header of package list next if noise?(line) pkgsplit(line) end.reject { |h| h.nil? } if hash[:justme] # Single queries may have been for an alias so return the name requested if list.any? list[-1][:name] = hash[:justme] return list[-1] end else list.reject! { |h| h[:ensure] == :absent } return list end end
# File lib/puppet/provider/user/directoryservice.rb, line 480 def self.password_hash_dir '/var/db/shadow/hash' end
pkg state was present in the older version of pkg (with UFOXI) but is no longer available with the IFO field version. When it was present, it was used to indicate that a particular version was present (installed) and later versions were known. Note that according to the pkg man page, known never lists older versions of the package. So we can rely on this field to make sure that if a known is present, then the pkg is upgradable.
# File lib/puppet/provider/package/pkg.rb, line 78 def self.pkg_state(state) case state when /installed/ {:status => 'installed'} when /known/ {:status => 'known'} else raise ArgumentError, 'Unknown format %s: %s' % [self.name, state] end end
# File lib/puppet/provider/package/aix.rb, line 77 def self.pkglist(hash = {}) cmd = [command(:lslpp), "-qLc"] if name = hash[:pkgname] cmd << name end begin list = execute(cmd).scan(/^[^#][^:]*:([^:]*):([^:]*)/).collect { |n,e| { :name => n, :ensure => e, :provider => self.name } } rescue Puppet::ExecutionFailure => detail if hash[:pkgname] return nil else raise Puppet::Error, "Could not list installed Packages: #{detail}" end end if hash[:pkgname] return list.shift else return list end end
Split the different lines into hashes.
# File lib/puppet/provider/package/pkgutil.rb, line 125 def self.pkgsplit(line) if line =~ /\s*(\S+)\s+(\S+)\s+(.*)/ hash = {} hash[:name] = $1 hash[:ensure] = if $2 == "notinst" :absent else $2 end hash[:avail] = $3 if hash[:avail] =~ /^SAME\s*$/ hash[:avail] = hash[:ensure] end # Use the name method, so it works with subclasses. hash[:provider] = self.name return hash else Puppet.warning "Cannot match %s" % line return nil end end
# File lib/puppet/provider/macauthorization/macauthorization.rb, line 64 def populate_rules_rights auth_plist = Plist::parse_xml(AuthDB) raise Puppet::Error.new("Cannot parse: #{AuthDB}") if not auth_plist self.rights = auth_plist["rights"].dup self.rules = auth_plist["rules"].dup self.parsed_auth_db = self.rights.dup self.parsed_auth_db.merge!(self.rules.dup) end
# File lib/puppet/provider/macauthorization/macauthorization.rb, line 51 def prefetch(resources) self.populate_rules_rights end
Collapse name and env records.
# File lib/puppet/provider/cron/crontab.rb, line 135 def self.prefetch_hook(records) name = nil envs = nil result = records.each { |record| case record[:record_type] when :comment if record[:name] name = record[:name] record[:skip] = true # Start collecting env values envs = [] end when :environment # If we're collecting env values (meaning we're in a named cronjob), # store the line and skip the record. if envs envs << record[:line] record[:skip] = true end when :blank # nothing else if name record[:name] = name name = nil end if envs.nil? or envs.empty? record[:environment] = :absent else # Collect all of the environment lines, and mark the records to be skipped, # since their data is included in our crontab record. record[:environment] = envs # And turn off env collection again envs = nil end end }.reject { |record| record[:skip] } result end
Read a plist, whether its format is XML or in Apple’s “binary1” format.
# File lib/puppet/provider/service/launchd.rb, line 182 def self.read_plist(path) begin Plist::parse_xml(plutil('-convert', 'xml1', '-o', '/dev/stdout', path)) rescue Puppet::ExecutionFailure => detail Puppet.warning("Cannot read file #{path}; Puppet is skipping it. \n" + "Details: #{detail}") return nil end end
This method will return a list of files in the passed directory. This method does not go recursively down the tree and does not return directories
@param path [String] The directory to glob
@api private
@return [Array] of String instances modeling file paths
# File lib/puppet/provider/service/launchd.rb, line 108 def self.return_globbed_list_of_file_paths(path) array_of_files = Dir.glob(File.join(path, '*')).collect do |filepath| File.file?(filepath) ? filepath : nil end array_of_files.compact end
# File lib/puppet/type/zone.rb, line 69 def self.seqvalue(name, hash) fsm.insert_state(name, hash) self.newvalue name end
# File lib/puppet/provider/package/aix.rb, line 20 def self.srclistcmd(source) [ command(:installp), "-L", "-d", source ] end
# File lib/puppet/type/zone.rb, line 85 def self.state_sequence(first, second) fsm.sequence(first, second) end
# File lib/puppet/util/log/destinations.rb, line 2 def self.suitable?(obj) Puppet.features.syslog? end
# File lib/puppet/type/file.rb, line 36 def self.title_patterns [ [ /^(.*?)\/*\Z/, [ [ :path ] ] ] ] end
# File lib/puppet/provider/cron/crontab.rb, line 177 def self.to_file(records) text = super # Apparently Freebsd will "helpfully" add a new TZ line to every # single cron line, but not in all cases (e.g., it doesn't do it # on my machine). This is my attempt to fix it so the TZ lines don't # multiply. if text =~ /(^TZ=.+\n)/ tz = $1 text.sub!(tz, '') text = tz + text end text end
# File lib/puppet/provider/package/windows.rb, line 37 def self.to_hash(pkg) { :name => pkg.name, # we're not versionable, so we can't set the ensure # parameter to the currently installed version :ensure => :installed, :provider => :windows } end
The UFOXI field is the field present in the older pkg (solaris 2009.06 - snv151a) similar to IFO, UFOXI is also an either letter or - u_pdate indicates that an update for the package is available. f_rozen(n/i) o_bsolete x_cluded(n/i) i_constrained(n/i) note that u_pdate flag may not be trustable due to constraints. so we dont rely on it Frozen was never implemented in UFOXI so skipping frozen here.
# File lib/puppet/provider/package/pkg.rb, line 68 def self.ufoxi_flag(flags) {} end
Override how parameters are handled so that we support the extra parameters that are used with defined resource types.
# File lib/puppet/type/component.rb, line 16 def [](param) return super if self.class.valid_parameter?(param) @extra_parameters[param.to_sym] end
Override how parameters are handled so that we support the extra parameters that are used with defined resource types.
# File lib/puppet/type/component.rb, line 23 def []=(param, value) return super if self.class.valid_parameter?(param) @extra_parameters[param.to_sym] = value end
# File lib/puppet/type/resources.rb, line 77 def able_to_ensure_absent?(resource) resource[:ensure] = :absent rescue ArgumentError, Puppet::Error => detail err "The 'ensure' attribute on #{self[:name]} resources does not accept 'absent' as a value" false end
# File lib/puppet/provider/zone/solaris.rb, line 130 def add_cmd(cmd) @cmds = [] if @cmds.nil? @cmds << cmd end
# File lib/puppet/provider/service/upstart.rb, line 328 def add_default_start_to(text) text + "\nstart on runlevel [2,3,4,5]" end
must override this to hand the keyvalue pairs
# File lib/puppet/provider/user/user_role_add.rb, line 31 def add_properties cmd = [] Puppet::Type.type(:user).validproperties.each do |property| #skip the password because we can't create it with the solaris useradd next if [:ensure, :password, :password_min_age, :password_max_age].include?(property) # 1680 Now you can set the hashed passwords on solaris:lib/puppet/provider/user/user_role_add.rb # the value needs to be quoted, mostly because -c might # have spaces in it if value = @resource.should(property) and value != "" if property == :keys cmd += build_keys_cmd(value) else cmd << flag(property) << value end end end cmd end
# File lib/puppet/provider/group/aix.rb, line 69 def addcmd(extra_attrs = []) # Here we use the @resource.to_hash to get the list of provided parameters # Puppet does not call to self.<parameter>= method if it does not exists. # # It gets an extra list of arguments to add to the user. [self.class.command(:add) ] + self.get_ia_module_args + self.hash2args(@resource.to_hash) + extra_attrs + [@resource[:name]] end
# File lib/puppet/provider/maillist/mailman.rb, line 31 def aliases mailman = self.class.command(:mailman) name = self.name.downcase aliases = {name => "| #{mailman} post #{name}"} %w{admin bounces confirm join leave owner request subscribe unsubscribe}.each do |address| aliases["#{name}-#{address}"] = "| #{mailman} #{address} #{name}" end aliases end
Return a list of all applications (both legacy and Face applications), along with a summary
of their functionality.
@returns [Array] An Array of Arrays. The outer array contains one entry per application; each
element in the outer array is a pair whose first element is a String containing the application name, and whose second element is a String containing the summary for that application.
# File lib/puppet/face/help.rb, line 135 def all_application_summaries() Puppet::Application.available_application_names.sort.inject([]) do |result, appname| next result if exclude_from_docs?(appname) if (is_face_app?(appname)) begin face = Puppet::Face[appname, :current] result << [appname, face.summary] rescue Puppet::Error => detail result << [ "! #{appname}", "! Subcommand unavailable due to error. Check error logs." ] end else result << [appname, horribly_extract_summary_from(appname)] end end end
# File lib/puppet/type/cron.rb, line 256 def alpha %w{sunday monday tuesday wednesday thursday friday saturday} end
# File lib/puppet/type/file.rb, line 382 def ancestors ancestors = Pathname.new(self[:path]).enum_for(:ascend).map(&:to_s) ancestors.delete(self[:path]) ancestors end
# File lib/puppet/provider/package/aptitude.rb, line 11 def aptget(*args) args.flatten! # Apparently aptitude hasn't always supported a -q flag. args.delete("-q") if args.include?("-q") args.delete("--force-yes") if args.include?("--force-yes") output = aptitude(*args) # Yay, stupid aptitude doesn't throw an error when the package is missing. if args.include?(:install) and output =~ /Couldn't find any package/ raise Puppet::Error.new( "Could not find package #{self.name}" ) end end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 56 def arguments task.parameters end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 151 def arguments=(value) task.parameters = value end
Determine the user to write files as.
# File lib/puppet/type/file.rb, line 314 def asuser if self.should(:owner) and ! self.should(:owner).is_a?(Symbol) writeable = Puppet::Util::SUIDManager.asuser(self.should(:owner)) { FileTest.writable?(::File.dirname(self[:path])) } # If the parent directory is writeable, then we execute # as the user in question. Otherwise we'll rely on # the 'owner' property to do things. asuser = self.should(:owner) if writeable end asuser end
# File lib/puppet/provider/group/aix.rb, line 118 def attributes filter_attributes(getosinfo(refresh = false)) end
# File lib/puppet/provider/group/aix.rb, line 122 def attributes=(attr_hash) #self.class.validate(param, value) param = :attributes cmd = modifycmd({param => filter_attributes(attr_hash)}) if cmd begin execute(cmd) rescue Puppet::ExecutionFailure => detail raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}" end end end
# File lib/puppet/provider/macauthorization/macauthorization.rb, line 288 def auth_type if resource.should(:auth_type) != nil return resource.should(:auth_type) elsif self.exists? # this is here just for ralsh, so it can work out what type it is. if self.class.rights.has_key?(resource[:name]) return :right elsif self.class.rules.has_key?(resource[:name]) return :rule else raise Puppet::Error.new("#{resource[:name]} is unknown type.") end else raise Puppet::Error.new("auth_type required for new resources.") end end
# File lib/puppet/provider/macauthorization/macauthorization.rb, line 305 def auth_type=(value) @property_hash[:auth_type] = value end
# File lib/puppet/provider/user/user_role_add.rb, line 109 def auths user_attributes[:auths] if user_attributes end
This method accepts an argument of a hex password hash, and base64 decodes it into a format that OS X 10.7 and 10.8 will store in the user’s plist.
# File lib/puppet/provider/user/directoryservice.rb, line 584 def base64_decode_string(value) Base64.decode64([[value].pack("H*")].pack("m").strip) end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 393 def bitfield_from_days(days) bitfield = 0 days = [days] unless days.is_a?(Array) days.each do |day| # The special "day" of 'last' is represented by day "number" # 32. 'last' has the special meaning of "the last day of the # month", no matter how many days there are in the month. day = 32 if day == 'last' integer_day = Integer(day) self.fail "Day must be specified as an integer in the range 1-31, or as 'last'" unless integer_day = day.to_f and integer_day.between?(1,32) bitfield |= 1 << integer_day - 1 end bitfield end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 412 def bitfield_from_days_of_week(days_of_week) bitfield = 0 days_of_week = [days_of_week] unless days_of_week.is_a?(Array) days_of_week.each do |day_of_week| bitfield |= day_of_week_name_to_constant(day_of_week) end bitfield end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 379 def bitfield_from_months(months) bitfield = 0 months = [months] unless months.is_a?(Array) months.each do |month| integer_month = Integer(month) rescue nil self.fail 'Month must be specified as an integer in the range 1-12' unless integer_month == month.to_f and integer_month.between?(1,12) bitfield |= scheduler_months[integer_month - 1] end bitfield end
# File lib/puppet/type/file.rb, line 329 def bucket return @bucket if @bucket backup = self[:backup] return nil unless backup return nil if backup =~ /^\./ unless catalog or backup == "puppet" fail "Can not find filebucket for backups without a catalog" end unless catalog and filebucket = catalog.resource(:filebucket, backup) or backup == "puppet" fail "Could not find filebucket #{backup} specified in backup" end return default_bucket unless filebucket @bucket = filebucket.bucket @bucket end
# File lib/puppet/provider/user/user_role_add.rb, line 137 def build_keys_cmd(keys_hash) cmd = [] keys_hash.each do |k,v| cmd << "-K" << "#{k}=#{v}" end cmd end
Adds log and spare
# File lib/puppet/provider/zpool/zpool.rb, line 69 def build_named(name) if prop = @resource[name.intern] [name] + prop.collect { |p| p.split(' ') }.flatten else [] end end
builds up the vdevs for create command
# File lib/puppet/provider/zpool/zpool.rb, line 83 def build_vdevs if disk = @resource[:disk] disk.collect { |d| d.split(' ') }.flatten elsif mirror = @resource[:mirror] ["mirror"] + mirror elsif raidz = @resource[:raidz] [raidzarity] + raidz end end
Make output a bit prettier
# File lib/puppet/type/augeas.rb, line 201 def change_to_s(currentvalue, newvalue) "executed successfully" end
# File lib/puppet/type/resources.rb, line 67 def check(resource) @checkmethod ||= "#{self[:name]}_check" @hascheck ||= respond_to?(@checkmethod) if @hascheck return send(@checkmethod, resource) else return true end end
# File lib/puppet/provider/user/useradd.rb, line 29 def check_allow_dup @resource.allowdupe? ? ["-o"] : [] end
# File lib/puppet/provider/user/useradd.rb, line 43 def check_manage_expiry cmd = [] if @resource[:expiry] cmd << "-e #{@resource[:expiry]}" end cmd end
# File lib/puppet/provider/user/useradd.rb, line 33 def check_manage_home cmd = [] if @resource.managehome? cmd << "-m" elsif Facter.value(:osfamily) == 'RedHat' cmd << "-M" end cmd end
(Un)install may “fail” because the package requested a reboot, the system requested a reboot, or something else entirely. Reboot requests mean the package was installed successfully, but we warn since we don’t have a good reboot strategy.
# File lib/puppet/provider/package/msi.rb, line 98 def check_result(hr) operation = resource[:ensure] == :absent ? 'uninstall' : 'install' # http://msdn.microsoft.com/en-us/library/windows/desktop/aa368542(v=vs.85).aspx case hr when 0 # yeah when 194 warning("The package requested a reboot to finish the operation.") when 1641 warning("The package #{operation}ed successfully and the system is rebooting now.") when 3010 warning("The package #{operation}ed successfully, but the system must be rebooted.") else raise Puppet::Util::Windows::Error.new("Failed to #{operation}", hr) end end
# File lib/puppet/provider/user/useradd.rb, line 52 def check_system_users if self.class.system_users? and resource.system? ["-r"] else [] end end
Verify that we have the executable
# File lib/puppet/provider/exec/posix.rb, line 15 def checkexe(command) exe = extractexe(command) if File.expand_path(exe) == exe if !File.exists?(exe) raise ArgumentError, "Could not find command '#{exe}'" elsif !File.file?(exe) raise ArgumentError, "'#{exe}' is a #{File.ftype(exe)}, not a file" elsif !File.executable?(exe) raise ArgumentError, "'#{exe}' is not executable" end return end if resource[:path] Puppet::Util.withenv :PATH => resource[:path].join(File::PATH_SEPARATOR) do return if which(exe) end end # 'which' will only return the command if it's executable, so we can't # distinguish not found from not executable raise ArgumentError, "Could not find command '#{exe}'" end
A derivative of DPKG; this is how most people actually manage Debian boxes, and the only thing that differs is that it can install packages from remote sites.
# File lib/puppet/provider/package/apt.rb, line 25 def checkforcdrom have_cdrom = begin !!(File.read("/etc/apt/sources.list") =~ /^[^#]*cdrom:/) rescue # This is basically pathological... false end if have_cdrom and @resource[:allowcdrom] != :true raise Puppet::Error, "/etc/apt/sources.list contains a cdrom source; not installing. Use 'allowcdrom' to override this failure." end end
Defines an instance method within a class
# File lib/puppet/util/metaid.rb, line 17 def class_def(name, &blk) class_eval { define_method name, &blk } end
clean facts for host
# File lib/puppet/face/node/clean.rb, line 80 def clean_cached_facts(node) Puppet::Node::Facts.indirection.destroy(node) Puppet.info "#{node}'s facts removed" end
clean cached node host
# File lib/puppet/face/node/clean.rb, line 86 def clean_cached_node(node) Puppet::Node.indirection.destroy(node) Puppet.info "#{node}'s cached node removed" end
clean signed cert for host
# File lib/puppet/face/node/clean.rb, line 69 def clean_cert(node) if Puppet::SSL::CertificateAuthority.ca? Puppet::Face[:ca, :current].revoke(node) Puppet::Face[:ca, :current].destroy(node) Puppet.info "#{node} certificates removed from ca" else Puppet.info "Not managing #{node} certs as this host is not a CA" end end
clean node reports for host
# File lib/puppet/face/node/clean.rb, line 92 def clean_reports(node) Puppet::Transaction::Report.indirection.destroy(node) Puppet.info "#{node}'s reports removed" end
clean storeconfig for node
# File lib/puppet/face/node/clean.rb, line 98 def clean_storeconfigs(node, do_unexport=false) return unless Puppet[:storeconfigs] && Puppet.features.rails? require 'puppet/rails' Puppet::Rails.connect unless rails_node = Puppet::Rails::Host.find_by_name(node) Puppet.notice "No entries found for #{node} in storedconfigs." return end if do_unexport unexport(rails_node) Puppet.notice "Force #{node}'s exported resources to absent" Puppet.warning "Please wait until all other hosts have checked out their configuration before finishing the cleanup with:" Puppet.warning "$ puppet node clean #{node}" else rails_node.destroy Puppet.notice "#{node} storeconfigs removed" end end
# File lib/puppet/face/node/clean.rb, line 60 def cleanup(node, unexport) clean_cert(node) clean_cached_facts(node) clean_cached_node(node) clean_reports(node) clean_storeconfigs(node, unexport) end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 43 def clear_task @task = nil @triggers = nil end
# File lib/puppet/util/log/destinations.rb, line 6 def close Syslog.close end
# File lib/puppet/provider/augeas/augeas.rb, line 194 def close_augeas if @aug @aug.close debug("Closed the augeas connection") @aug = nil end end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 52 def command task.application_name end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 147 def command=(value) task.application_name = value end
# File lib/puppet/provider/user/windows_adsi.rb, line 57 def comment user['Description'] end
# File lib/puppet/provider/user/windows_adsi.rb, line 61 def comment=(value) user['Description'] = value end
# File lib/puppet/provider/service/upstart.rb, line 293 def comment_start_block_in(text) parens = 0 text.lines.map do |line| if line.match(START_ON) || parens > 0 # If there are more opening parens than closing parens, we need to comment out a multiline 'start on' stanza parens += unbalanced_parens_on(remove_trailing_comments_from(line)) "#" + line else line end end.join('') end
Turn the results of getconfig into status information.
# File lib/puppet/provider/zone/solaris.rb, line 317 def config_status config = getconfig result = {} result[:autoboot] = config[:autoboot] ? config[:autoboot].intern : :true result[:pool] = config[:pool] result[:shares] = config[:shares] if dir = config["inherit-pkg-dir"] result[:inherit] = dir.collect { |dirs| dirs[:dir] } end if datasets = config["dataset"] result[:dataset] = datasets.collect { |dataset| dataset[:name] } end result[:iptype] = config[:'ip-type'] if config[:'ip-type'] if net = config["net"] result[:ip] = net.collect do |params| if params[:defrouter] "#{params[:physical]}:#{params[:address]}:#{params[:defrouter]}" elsif params[:address] "#{params[:physical]}:#{params[:address]}" else params[:physical] end end end result end
Perform all of our configuration steps.
# File lib/puppet/provider/zone/solaris.rb, line 112 def configure self.fail "Path is required" unless @resource[:path] arr = ["create -b #{@resource[:create_args]}"] # Then perform all of our configuration steps. It's annoying # that we need this much internal info on the resource. self.resource.properties.each do |property| next unless my_properties.include? property.name method = (property.name.to_s + '_conf').intern arr << self.send(method ,@resource[property.name]) unless property.safe_insync?(properties[property.name]) end setconfig(arr.join("\n")) end
# File lib/puppet/provider/mcx/mcxcontent.rb, line 91 def content ds_parms = get_dsparams self.class.mcxexport(ds_parms[:ds_type], ds_parms[:ds_name]) end
# File lib/puppet/provider/mcx/mcxcontent.rb, line 97 def content=(value) # dscl localhost -mcximport ds_parms = get_dsparams mcximport(ds_parms[:ds_type], ds_parms[:ds_name], resource[:content]) end
# File lib/puppet/type/tidy.rb, line 112 def convert(unit, multi) if num = AgeConvertors[unit] return num * multi else self.fail "Invalid age unit '#{unit}'" end end
# File lib/puppet/provider/macauthorization/macauthorization.rb, line 214 def convert_plist_to_native_attributes(propertylist) # This mainly converts the keys from the puppet attributes to the # 'native' ones, but also enforces that the keys are all Strings # rather than Symbols so that any merges of the resultant Hash are # sane. The exception is booleans, where we coerce to a proper bool # if they come in as a symbol. newplist = {} propertylist.each_pair do |key, value| next if key == :ensure # not part of the auth db schema. next if key == :auth_type # not part of the auth db schema. case value when true, :true value = true when false, :false value = false end new_key = key if PuppetToNativeAttributeMap.has_key?(key) new_key = PuppetToNativeAttributeMap[key].to_s elsif not key.is_a?(String) new_key = key.to_s end newplist[new_key] = value end newplist end
# File lib/puppet/provider/group/windows_adsi.rb, line 23 def create @group = Puppet::Util::ADSI::Group.create(@resource[:name]) @group.commit self.members = @resource[:members] end
Create the new user with dscl
# File lib/puppet/provider/user/directoryservice.rb, line 494 def create_new_user(username) dscl '.', '-create', "/Users/#{username}" end
# File lib/puppet/provider/user/user_role_add.rb, line 97 def create_role if exists? and !is_role? run(transition("role"), "transition user to") else run(addcmd, "create role") end end
# File lib/puppet/provider/zpool/zpool.rb, line 59 def current_pool @current_pool = process_zpool_data(get_pool_data) unless (defined?(@current_pool) and @current_pool) @current_pool end
returns the full path to the current daemon directory note that this path can be overriden in the resource definition
# File lib/puppet/provider/service/daemontools.rb, line 111 def daemon File.join(resource[:path], resource[:name]) end
ActiveSupport 2.3.x mixes in a dangerous method that can cause rspec to fork bomb and other strange things like that.
# File lib/puppet/util/monkey_patches.rb, line 80 def daemonize raise NotImplementedError, "Kernel.daemonize is too dangerous, please don't try to use it." end
# File lib/puppet/util/instrumentation/listeners/log.rb, line 24 def data @last_logs.synchronize { @last_logs.dup } end
If they pass class information, we want to ignore it. By default, we’ll include class information but we won’t rely on it - we don’t want class names to be required because we then can’t change our internal class names, which is bad.
# File lib/puppet/network/formats.rb, line 123 def data_to_instance(klass, data) if data.is_a?(Hash) and d = data['data'] data = d end return data if data.is_a?(klass) klass.from_pson(data) end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 514 def day_of_week_constant_to_name(constant) case constant when Win32::TaskScheduler::SUNDAY; 'sun' when Win32::TaskScheduler::MONDAY; 'mon' when Win32::TaskScheduler::TUESDAY; 'tues' when Win32::TaskScheduler::WEDNESDAY; 'wed' when Win32::TaskScheduler::THURSDAY; 'thurs' when Win32::TaskScheduler::FRIDAY; 'fri' when Win32::TaskScheduler::SATURDAY; 'sat' end end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 526 def day_of_week_name_to_constant(name) case name when 'sun'; Win32::TaskScheduler::SUNDAY when 'mon'; Win32::TaskScheduler::MONDAY when 'tues'; Win32::TaskScheduler::TUESDAY when 'wed'; Win32::TaskScheduler::WEDNESDAY when 'thurs'; Win32::TaskScheduler::THURSDAY when 'fri'; Win32::TaskScheduler::FRIDAY when 'sat'; Win32::TaskScheduler::SATURDAY end end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 435 def days_from_bitfield(bitfield) days = [] i = 0 while bitfield > 0 if bitfield & 1 > 0 # Day 32 has the special meaning of "the last day of the # month", no matter how many days there are in the month. days << (i == 31 ? 'last' : i + 1) end bitfield = bitfield >> 1 i += 1 end days end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 453 def days_of_week_from_bitfield(bitfield) days_of_week = [] scheduler_days_of_week.each do |day_of_week| if bitfield & day_of_week != 0 days_of_week << day_of_week_constant_to_name(day_of_week) end end days_of_week end
# File lib/puppet/network/formats.rb, line 73 def decode(yaml) requiring_zlib do YAML.safely_load(Zlib::Inflate.inflate(Base64.decode64(yaml))) end end
# File lib/puppet/type/file.rb, line 351 def default_bucket Puppet::Type.type(:filebucket).mkdefaultbucket.bucket end
# File lib/puppet/provider/group/windows_adsi.rb, line 34 def delete Puppet::Util::ADSI::Group.delete(@resource[:name]) end
# File lib/puppet/provider/group/aix.rb, line 89 def deletecmd [self.class.command(:delete)] + self.get_ia_module_args + [@resource[:name]] end
# File lib/puppet/type/tidy.rb, line 205 def depthfirst? true end
# File lib/puppet/provider/macauthorization/macauthorization.rb, line 99 def destroy # We explicitly delete here rather than in the flush method. case resource[:auth_type] when :right destroy_right when :rule destroy_rule else raise Puppet::Error.new("Must specify auth_type when destroying.") end end
utility methods below
# File lib/puppet/provider/macauthorization/macauthorization.rb, line 134 def destroy_right security "authorizationdb", :remove, resource[:name] end
# File lib/puppet/provider/macauthorization/macauthorization.rb, line 138 def destroy_rule authdb = Plist::parse_xml(AuthDB) authdb_rules = authdb["rules"].dup if authdb_rules[resource[:name]] begin authdb["rules"].delete(resource[:name]) Plist::Emit.save_plist(authdb, AuthDB) rescue Errno::EACCES => e raise Puppet::Error.new("Error saving #{AuthDB}: #{e}") end end end
# File lib/puppet/provider/ssh_authorized_key/parsed.rb, line 35 def dir_perm 0700 end
remove service file from rc.conf.d to disable it
# File lib/puppet/provider/service/bsd.rb, line 21 def disable rcfile = File.join(rcconf_dir, @model[:name]) File.delete(rcfile) if File.exists?(rcfile) end
# File lib/puppet/provider/service/upstart.rb, line 261 def disable_post_0_9_0(over_text) write_script_to(overscript, ensure_disabled_with_manual(over_text)) end
# File lib/puppet/provider/service/upstart.rb, line 252 def disable_pre_0_6_7(script_text) disabled_script = comment_start_block_in(script_text) write_script_to(initscript, disabled_script) end
# File lib/puppet/provider/service/upstart.rb, line 257 def disable_pre_0_9_0(script_text) write_script_to(initscript, ensure_disabled_with_manual(script_text)) end
Actually execute the augeas changes.
# File lib/puppet/provider/augeas/augeas.rb, line 422 def do_execute_changes commands = parse_commands(resource[:changes]) commands.each do |cmd_array| fail("invalid command #{cmd_array.join[" "]}") if cmd_array.length < 2 command = cmd_array[0] cmd_array.shift begin case command when "set" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.set(cmd_array[0], cmd_array[1]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv) when "setm" if aug.respond_to?(command) debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.setm(cmd_array[0], cmd_array[1], cmd_array[2]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1) else fail("command '#{command}' not supported in installed version of ruby-augeas") end when "rm", "remove" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.rm(cmd_array[0]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1) when "clear" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.clear(cmd_array[0]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv) when "clearm" # Check command exists ... doesn't currently in ruby-augeas 0.4.1 if aug.respond_to?(command) debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.clearm(cmd_array[0], cmd_array[1]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv) else fail("command '#{command}' not supported in installed version of ruby-augeas") end when "insert", "ins" label = cmd_array[0] where = cmd_array[1] path = cmd_array[2] case where when "before"; before = true when "after"; before = false else fail("Invalid value '#{where}' for where param") end debug("sending command '#{command}' with params #{[label, where, path].inspect}") rv = aug.insert(path, label, before) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1) when "defvar" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.defvar(cmd_array[0], cmd_array[1]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv) when "defnode" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.defnode(cmd_array[0], cmd_array[1], cmd_array[2]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv) when "mv", "move" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.mv(cmd_array[0], cmd_array[1]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1) else fail("Command '#{command}' is not supported") end rescue SystemExit,NoMemoryError raise rescue Exception => e fail("Error sending command '#{command}' with params #{cmd_array.inspect}/#{e.message}") end end end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 262 def dummy_time_trigger now = Time.now { 'flags' => 0, 'random_minutes_interval' => 0, 'end_day' => 0, "end_year" => 0, "trigger_type" => 0, "minutes_interval" => 0, "end_month" => 0, "minutes_duration" => 0, 'start_year' => now.year, 'start_month' => now.month, 'start_day' => now.day, 'start_hour' => now.hour, 'start_minute' => now.min, 'trigger_type' => Win32::TaskScheduler::ONCE, } end
enable service by creating a service file under rc.conf.d with the proper contents
# File lib/puppet/provider/service/bsd.rb, line 36 def enable Dir.mkdir(rcconf_dir) if not File.exists?(rcconf_dir) rcfile = File.join(rcconf_dir, @model[:name]) open(rcfile, 'w') { |f| f << "%s_enable=\"YES\"\n" % @model[:name] } end
# File lib/puppet/provider/service/upstart.rb, line 238 def enable_post_0_9_0(script_text, over_text) over_text = remove_manual_from(over_text) if enabled_post_0_9_0?(script_text, over_text) == :false if script_text.match(START_ON) over_text << extract_start_on_block_from(script_text) else over_text << "\nstart on runlevel [2,3,4,5]" end end write_script_to(overscript, over_text) end
# File lib/puppet/provider/service/upstart.rb, line 220 def enable_pre_0_9_0(text) # We also need to remove any manual stanzas to ensure that it is enabled text = remove_manual_from(text) if enabled_pre_0_9_0?(text) == :false enabled_script = if text.match(COMMENTED_START_ON) uncomment_start_block_in(text) else add_default_start_to(text) end else enabled_script = text end write_script_to(initscript, enabled_script) end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 48 def enabled task.flags & Win32::TaskScheduler::DISABLED == 0 ? :true : :false end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 159 def enabled=(value) if value == :true task.flags = task.flags & ~Win32::TaskScheduler::DISABLED else task.flags = task.flags | Win32::TaskScheduler::DISABLED end end
if the service file exists in rc.conf.d then it’s already enabled
# File lib/puppet/provider/service/bsd.rb, line 27 def enabled? rcfile = File.join(rcconf_dir, @model[:name]) return :true if File.exists?(rcfile) :false end
# File lib/puppet/provider/service/upstart.rb, line 197 def enabled_post_0_9_0?(script_text, over_text) # This version has manual stanzas and override files # So we check to see if an uncommented start on or manual stanza is the last one in the # conf file and any override files. The last one in the file wins. enabled = :false script_text.each_line do |line| if line.match(START_ON) enabled = :true elsif line.match(MANUAL) enabled = :false end end over_text.each_line do |line| if line.match(START_ON) enabled = :true elsif line.match(MANUAL) enabled = :false end end if over_text enabled end
# File lib/puppet/provider/service/upstart.rb, line 173 def enabled_pre_0_6_7?(script_text) # Upstart version < 0.6.7 means no manual stanza. if script_text.match(START_ON) return :true else return :false end end
# File lib/puppet/provider/service/upstart.rb, line 182 def enabled_pre_0_9_0?(script_text) # Upstart version < 0.9.0 means no override files # So we check to see if an uncommented start on or manual stanza is the last one in the file # The last one in the file wins. enabled = :false script_text.each_line do |line| if line.match(START_ON) enabled = :true elsif line.match(MANUAL) enabled = :false end end enabled end
# File lib/puppet/network/formats.rb, line 67 def encode(text) requiring_zlib do Base64.encode64(Zlib::Deflate.deflate(text, Zlib::BEST_COMPRESSION)) end end
# File lib/puppet/provider/service/upstart.rb, line 332 def ensure_disabled_with_manual(text) remove_manual_from(text) + "\nmanual" end
# File lib/puppet/face/node/clean.rb, line 146 def environment @environment ||= Puppet::Node::Environment.new end
# File lib/puppet/face/help.rb, line 116 def erb(name) template = (Pathname(__FILE__).dirname + "help" + name) erb = ERB.new(template.read, nil, '-') erb.filename = template.to_s return erb end
# File lib/puppet/provider/service/freebsd.rb, line 16 def error(msg) raise Puppet::Error, msg end
Create any children via recursion or whatever.
# File lib/puppet/type/file.rb, line 370 def eval_generate return [] unless self.recurse? recurse #recurse.reject do |resource| # catalog.resource(:file, resource[:path]) #end.each do |child| # catalog.add_resource child # catalog.relationship_graph.add_edge self, child #end end
This should absolutely be a private method, but for some reason it appears that you can't use the 'private' keyword inside of a Face definition. See #14205.
private :horribly_extract_summary_from
# File lib/puppet/face/help.rb, line 175 def exclude_from_docs?(appname) %w{face_base indirection_base}.include? appname end
# File lib/puppet/provider/package/pkg.rb, line 186 def exec_cmd(*cmd) output = Puppet::Util::Execution.execute(cmd, :failonfail => false, :combine => true) {:out => output, :exit => $CHILD_STATUS.exitstatus} end
Required workaround, since SELinux policy prevents setsebool from writing to any files, even tmp, preventing the standard ‘setsebool(“…”)’ construct from working.
# File lib/puppet/provider/selboolean/getsetsebool.rb, line 36 def execoutput (cmd) output = '' begin execpipe(cmd) do |out| output = out.readlines.join('').chomp! end rescue Puppet::ExecutionFailure raise Puppet::ExecutionFailure, output.split("\n")[0] end output end
# File lib/puppet/provider/augeas/augeas.rb, line 400 def execute_changes # Workaround Augeas bug where changing the save mode doesn't trigger a # reload of the previously saved file(s) when we call Augeas#load @aug.match("/augeas/events/saved").each do |file| @aug.rm("/augeas#{@aug.get(file)}/mtime") end # Reload augeas, and execute the changes for real set_augeas_save_mode(SAVE_OVERWRITE) if versioncmp(get_augeas_version, "0.3.6") >= 0 @aug.load do_execute_changes unless @aug.save print_put_errors fail("Save failed with return code #{success}, see debug") end :executed ensure close_augeas end
Does the file currently exist? Just checks for whether we have a stat
# File lib/puppet/type/file.rb, line 357 def exist? stat ? true : false end
# File lib/puppet/provider/group/windows_adsi.rb, line 30 def exists? Puppet::Util::ADSI::Group.exists?(@resource[:name]) end
# File lib/puppet/provider/package/msi.rb, line 91 def exit_status $CHILD_STATUS.exitstatus end
Get expiry from system and convert to Puppet-style date
# File lib/puppet/provider/user/pw.rb, line 89 def expiry expiry = self.get(:expiry) expiry = :absent if expiry == 0 if expiry != :absent t = Time.at(expiry) expiry = "%4d-%02d-%02d" % [t.year, t.month, t.mday] end expiry end
# File lib/puppet/provider/user/aix.rb, line 201 def expiry_from_attr(value) if value =~ /(..)(..)(..)(..)(..)/ #d= DateTime.parse("20#{$5}-#{$1}-#{$2} #{$3}:#{$4}") #expiry_date = d.strftime("%Y-%m-%d %H:%M") #expiry_date = d.strftime("%Y-%m-%d") expiry_date = "20#{$5}-#{$1}-#{$2}" else Puppet.warn("Could not convert AIX expires date '#{value}' on #{@resource.class.name}[#{@resource.name}]") unless value == '0' expiry_date = :absent end expiry_date end
The expiry date for this user. Must be provided in a zero padded YYYY-MM-DD HH:MM format
# File lib/puppet/provider/user/aix.rb, line 190 def expiry_to_attr(value) # For chuser the expires parameter is a 10-character string in the MMDDhhmmyy format # that is,"%m%d%H%M%y" newdate = '0' if value.is_a? String and value!="0000-00-00" d = DateTime.parse(value, "%Y-%m-%d %H:%M") newdate = d.strftime("%m%d%H%M%y") end newdate end
# File lib/puppet/provider/service/upstart.rb, line 318 def extract_start_on_block_from(text) parens = 0 text.lines.map do |line| if line.match(START_ON) || parens > 0 parens += unbalanced_parens_on(remove_trailing_comments_from(line)) line end end.join('') end
Make sure the file we wrote out is what we think it is.
# File lib/puppet/type/file.rb, line 755 def fail_if_checksum_is_wrong(path, content_checksum) newsum = parameter(:checksum).sum_file(path) return if [:absent, nil, content_checksum].include?(newsum) self.fail "File written to disk did not match checksum; discarding changes (#{content_checksum} vs #{newsum})" end
# File lib/puppet/provider/ssh_authorized_key/parsed.rb, line 39 def file_perm 0600 end
# File lib/puppet/provider/group/aix.rb, line 108 def filter_attributes(hash) # Return only not managed attributtes. hash.select { |k,v| !self.class.attribute_mapping_from.include?(k) and !self.class.attribute_ignore.include?(k) }.inject({}) { |hash, array| hash[array[0]] = array[1]; hash } end
We have to do some extra finishing, to retrieve our bucket if there is one.
# File lib/puppet/type/file.rb, line 363 def finish # Look up our bucket, if there is one bucket super end
A derivative of DPKG; this is how most people actually manage Debian boxes, and the only thing that differs is that it can install packages from remote sites.
# File lib/puppet/provider/package/fink.rb, line 18 def finkcmd(*args) fink(*args) end
Only flush if we created or modified a group, not deleted
# File lib/puppet/provider/group/windows_adsi.rb, line 39 def flush @group.commit if @group end
# File lib/puppet/provider/user/directoryservice.rb, line 539 def flush_dscl_cache dscacheutil '-flushcache' end
# File lib/puppet/provider/macauthorization/macauthorization.rb, line 151 def flush_right # first we re-read the right just to make sure we're in sync for # values that weren't specified in the manifest. As we're supplying # the whole plist when specifying the right it seems safest to be # paranoid given the low cost of quering the db once more. cmds = [] cmds << :security << "authorizationdb" << "read" << resource[:name] output = execute(cmds, :failonfail => false, :combine => false) current_values = Plist::parse_xml(output) current_values ||= {} specified_values = convert_plist_to_native_attributes(@property_hash) # take the current values, merge the specified values to obtain a # complete description of the new values. new_values = current_values.merge(specified_values) set_right(resource[:name], new_values) end
# File lib/puppet/provider/macauthorization/macauthorization.rb, line 169 def flush_rule authdb = Plist::parse_xml(AuthDB) authdb_rules = authdb["rules"].dup current_values = {} current_values = authdb_rules[resource[:name]] if authdb_rules[resource[:name]] specified_values = convert_plist_to_native_attributes(@property_hash) new_values = current_values.merge(specified_values) set_rule(resource[:name], new_values) end
Generate any new resources we need to manage. This is pretty hackish right now, because it only supports purging.
# File lib/puppet/type/resources.rb, line 86 def generate return [] unless self.purge? resource_type.instances. reject { |r| catalog.resource_refs.include? r.ref }. select { |r| check(r) }. select { |r| r.class.validproperty?(:ensure) }. select { |r| able_to_ensure_absent?(r) }. each { |resource| @parameters.each do |name, param| resource[name] = param.value if param.metaparam? end # Mark that we're purging, so transactions can handle relationships # correctly resource.purging } end
# File lib/puppet/provider/group/aix.rb, line 98 def get_arguments(key, value, mapping, objectinfo) # In the case of attributes, return a list of key=vlaue if key == :attributes raise Puppet::Error, "Attributes must be a list of pairs key=value on #{@resource.class.name}[#{@resource.name}]" unless value and value.is_a? Hash return value.select { |k,v| true }.map { |pair| pair.join("=") } end super(key, value, mapping, objectinfo) end
# File lib/puppet/provider/augeas/augeas.rb, line 303 def get_augeas_version @aug.get("/augeas/version") || "" end
Gather ds_type and ds_name from resource or parse it out of the name.
# File lib/puppet/provider/mcx/mcxcontent.rb, line 152 def get_dsparams ds_type = resource[:ds_type] ds_type ||= parse_type(resource[:name]) raise MCXContentProviderException unless TypeMap.keys.include? ds_type.to_sym ds_name = resource[:ds_name] ds_name ||= parse_name(resource[:name]) { :ds_type => ds_type.to_sym, :ds_name => ds_name, } end
Return the IA module arguments based on the resource param ia_load_module
# File lib/puppet/provider/group/aix.rb, line 51 def get_ia_module_args if @resource[:ia_load_module] ["-R", @resource[:ia_load_module].to_s] else [] end end
Generate lens load paths from user given paths and local pluginsync dir
# File lib/puppet/provider/augeas/augeas.rb, line 286 def get_load_path(resource) load_path = [] # Permits colon separated strings or arrays if resource[:load_path] load_path = [resource[:load_path]].flatten load_path.map! { |path| path.split(/:/) } load_path.flatten! end if File.exists?("#{Puppet[:libdir]}/augeas/lenses") load_path << "#{Puppet[:libdir]}/augeas/lenses" end load_path.join(":") end
# File lib/puppet/provider/zpool/zpool.rb, line 50 def get_pool_data # http://docs.oracle.com/cd/E19082-01/817-2271/gbcve/index.html # we could also use zpool iostat -v mypool for a (little bit) cleaner output out = execute("zpool status #{@resource[:pool]}", :failonfail => false, :combine => false) zpool_data = out.lines.select { |line| line.index("\t") == 0 }.collect { |l| l.strip.split("\s")[0] } zpool_data.shift zpool_data end
This method will return the binary plist that’s embedded in the ShadowHashData key of a user’s plist, or false if it doesn’t exist.
# File lib/puppet/provider/user/directoryservice.rb, line 551 def get_shadow_hash_data(users_plist) if users_plist['ShadowHashData'] password_hash_plist = users_plist['ShadowHashData'][0].string self.class.convert_binary_to_xml(password_hash_plist) else false end end
# File lib/puppet/provider/service/debian.rb, line 60 def get_start_link_count Dir.glob("/etc/rc*.d/S*#{@resource[:name]}").length end
# File lib/puppet/provider/user/directoryservice.rb, line 543 def get_users_plist(username) # This method will retrieve the data stored in a user's plist and # return it as a native Ruby hash. Plist::parse_xml(plutil('-convert', 'xml1', '-o', '/dev/stdout', "#{users_plist_dir}/#{username}.plist")) end
# File lib/puppet/provider/package/openbsd.rb, line 88 def get_version execpipe([command(:pkginfo), "-I", @resource[:name]]) do |process| # our regex for matching pkg_info output regex = /^(.*)-(\d[^-]*)[-]?(\D*)(.*)$/ fields = [ :name, :version, :flavor ] master_version = 0 version = -1 process.each_line do |line| if match = regex.match(line.split[0]) # now we return the first version, unless ensure is latest version = match.captures[1] return version unless @resource[:ensure] == "latest" master_version = version unless master_version > version end end return master_version unless master_version == 0 return '' if version == -1 raise Puppet::Error, "#{version} is not available for this package" end rescue Puppet::ExecutionFailure return nil end
Collect the configuration of the zone. The output looks like: zonename: z1 zonepath: /export/z1 brand: native autoboot: true bootargs: pool: limitpriv: scheduling-class: ip-type: shared hostid: net:
address: 192.168.1.1 physical: eg0001 defrouter not specified
net:
address: 192.168.1.3 physical: eg0002 defrouter not specified
# File lib/puppet/provider/zone/solaris.rb, line 216 def getconfig output = zonecfg :info name = nil current = nil hash = {} output.split("\n").each do |line| case line when /^(\S+):\s*$/ name = $1 current = nil # reset it when /^(\S+):\s*(\S+)$/ hash[$1.intern] = $2 when /^\s+(\S+):\s*(.+)$/ if name hash[name] ||= [] unless current current = {} hash[name] << current end current[$1.intern] = $2 else err "Ignoring '#{line}'" end else debug "Ignoring zone output '#{line}'" end end hash end
Get the process ID for a running process. Requires the ‘pattern’ parameter.
# File lib/puppet/provider/service/base.rb, line 16 def getpid @resource.fail "Either stop/status commands or a pattern must be specified" unless @resource[:pattern] ps = Facter["ps"].value @resource.fail "You must upgrade Facter to a version that includes 'ps'" unless ps and ps != "" regex = Regexp.new(@resource[:pattern]) self.debug "Executing '#{ps}'" IO.popen(ps) { |table| table.each_line { |line| if regex.match(line) self.debug "Process matched: #{line}" ary = line.sub(/^\s+/, '').split(/\s+/) return ary[1] end } } nil end
# File lib/puppet/provider/group/windows_adsi.rb, line 43 def gid Puppet::Util::Windows::Security.name_to_sid(@resource[:name]) end
# File lib/puppet/provider/file/posix.rb, line 33 def gid2name(id) return id.to_s if id.is_a?(Symbol) or id.is_a?(String) return nil if id > Puppet[:maximum_uid].to_i begin group = Etc.getgrgid(id) rescue TypeError, ArgumentError return nil end if group.gid == "" return nil else return group.name end end
# File lib/puppet/provider/group/windows_adsi.rb, line 47 def gid=(value) fail "gid is read-only" end
Get the group gid from its name
# File lib/puppet/provider/user/aix.rb, line 184 def gid_from_attr(value) groupid_by_name(value) end
The user’s primary group. Can be specified numerically or by name.
# File lib/puppet/provider/user/aix.rb, line 179 def gid_to_attr(value) verify_group(value) end
# File lib/puppet/provider/file/posix.rb, line 87 def group return :absent unless stat = resource.stat currentvalue = stat.gid # On OS X, files that are owned by -2 get returned as really # large GIDs instead of negative ones. This isn't a Ruby bug, # it's an OS X bug, since it shows up in perl, too. if currentvalue > Puppet[:maximum_uid].to_i self.warning "Apparently using negative GID (#{currentvalue}) on a platform that does not consistently handle them" currentvalue = :silly end currentvalue end
Convert a gropu name to an id.
# File lib/puppet/provider/user/ldap.rb, line 112 def group2id(group) Puppet::Type.type(:group).provider(:ldap).name2id(group) end
# File lib/puppet/provider/file/posix.rb, line 103 def group=(should) # Set our method appropriately, depending on links. if resource[:links] == :manage method = :lchown else method = :chown end begin File.send(method, nil, should, resource[:path]) rescue => detail raise Puppet::Error, "Failed to set group to '#{should}': #{detail}" end end
# File lib/puppet/provider/user/ldap.rb, line 118 def group_manager Puppet::Type.type(:group).provider(:ldap).manager end
# File lib/puppet/provider/user/ldap.rb, line 122 def group_properties(values) if values.empty? or values == :absent {:ensure => :present} else {:ensure => :present, :members => values} end end
Get the groupname from its id
# File lib/puppet/provider/user/aix.rb, line 161 def groupid_by_name(groupname) attrs = self.parse_attr_list(execute(lsgroupscmd(groupname)).split("\n")[0], nil) attrs ? attrs[:id].to_i : nil end
Find all groups this user is a member of in ldap.
# File lib/puppet/provider/user/ldap.rb, line 56 def groups # We want to cache the current result, so we know if we # have to remove old values. unless @property_hash[:groups] unless result = group_manager.search("memberUid=#{name}") return @property_hash[:groups] = :absent end return @property_hash[:groups] = result.collect { |r| r[:name] }.sort.join(",") end @property_hash[:groups] end
In the setter method we’re only going to take action on groups for which the user is not currently a member.
# File lib/puppet/provider/user/directoryservice.rb, line 342 def groups=(value) guid = self.class.get_attribute_from_dscl('Users', @resource.name, 'GeneratedUID')['dsAttrTypeStandard:GeneratedUID'][0] groups_to_add = value.split(',') - groups.split(',') groups_to_add.each do |group| merge_attribute_with_dscl('Groups', group, 'GroupMembership', @resource.name) merge_attribute_with_dscl('Groups', group, 'GroupMembers', guid) end end
# File lib/puppet/util/log/destinations.rb, line 27 def handle(msg) # XXX Syslog currently has a bug that makes it so you # cannot log a message with a '%' in it. So, we get rid # of them. if msg.source == "Puppet" msg.to_s.split("\n").each do |line| @syslog.send(msg.level, line.gsub("%", '%%')) end else msg.to_s.split("\n").each do |line| @syslog.send(msg.level, "(%s) %s" % [msg.source.to_s.gsub("%", ""), line.gsub("%", '%%') ] ) end end end
Launchd implemented plist overrides in version 10.6. This method checks the major_version of OS X and returns true if it is 10.6 or greater. This allows us to implement different plist behavior for versions >= 10.6
# File lib/puppet/provider/service/launchd.rb, line 172 def has_macosx_plist_overrides? @product_version ||= self.class.get_macosx_version_major # (#11593) Remove support for OS X 10.4 & earlier # leaving this as is because 10.5 still didn't have plist support return true unless /^10\.[0-5]/.match(@product_version) return false end
# File lib/puppet/provider/mcx/mcxcontent.rb, line 106 def has_mcx? !content.empty? end
Mark that our init script supports ‘status’ commands.
# File lib/puppet/provider/service/init.rb, line 53 def hasstatus=(value) case value when true, "true"; @parameters[:hasstatus] = true when false, "false"; @parameters[:hasstatus] = false else raise Puppet::Error, "Invalid 'hasstatus' value #{value.inspect}" end end
# File lib/puppet/provider/package/dpkg.rb, line 135 def hold self.install Tempfile.open('puppet_dpkg_set_selection') do |tmpfile| tmpfile.write("#{@resource[:name]} hold\n") tmpfile.flush execute([:dpkg, "--set-selections"], :failonfail => false, :combine => false, :stdinfile => tmpfile.path.to_s) end end
# File lib/puppet/provider/user/windows_adsi.rb, line 65 def home user['HomeDirectory'] end
# File lib/puppet/provider/user/windows_adsi.rb, line 69 def home=(value) user['HomeDirectory'] = value end
# File lib/puppet/face/help.rb, line 152 def horribly_extract_summary_from(appname) begin help = Puppet::Application[appname].help.split("\n") # Now we find the line with our summary, extract it, and return it. This # depends on the implementation coincidence of how our pages are # formatted. If we can't match the pattern we expect we return the empty # string to ensure we don't blow up in the summary. --daniel 2011-04-11 while line = help.shift do if md = /^puppet-#{appname}\([^\)]+\) -- (.*)$/.match(line) then return md[1] end end rescue Exception # Damn, but I hate this: we just ignore errors here, no matter what # class they are. Meh. end return '' end
# File lib/puppet/reports/rrdgraph.rb, line 23 def hostdir @hostdir ||= File.join(Puppet[:rrddir], self.host) end
# File lib/puppet/reports/rrdgraph.rb, line 27 def htmlfile(type, graphs, field) file = File.join(hostdir, "#{type}.html") File.open(file, "w") do |of| of.puts "<html><head><title>#{type.capitalize} graphs for #{host}</title></head><body>" graphs.each do |graph| if field == :first name = graph.sub(/-\w+.png/, '').capitalize else name = graph.sub(/\w+-/, '').sub(".png", '').capitalize end of.puts "<img src=#{graph}><br>" end of.puts "</body></html>" end file end
If it’s a valid SID, get the name. Otherwise, it’s already a name, so just return it.
# File lib/puppet/provider/file/windows.rb, line 21 def id2name(id) if Puppet::Util::Windows::Security.valid_sid?(id) Puppet::Util::Windows::Security.sid_to_name(id) else id end end
# File lib/puppet/provider/package/sun.rb, line 114 def if_have_value(prefix, value) if value [prefix, value] else [] end end
Get info on a package, optionally specifying a device.
# File lib/puppet/provider/package/sun.rb, line 60 def info2hash(device = nil) cmd = [command(:pkginfo), '-l'] cmd << '-d' << device if device cmd << @resource[:name] pkgs = self.class.parse_pkginfo(execute(cmd, :failonfail => false, :combine => false)) errmsg = case pkgs.size when 0; 'No message' when 1; pkgs[0]['ERROR'] end return self.class.namemap(pkgs[0]) if errmsg.nil? return {:ensure => :absent} if errmsg =~ /information for "#{Regexp.escape(@resource[:name])}"/ raise Puppet::Error, "Unable to get information about package #{@resource[:name]} because of: #{errmsg}" end
Where is our init script?
# File lib/puppet/provider/service/init.rb, line 63 def initscript @initscript ||= self.search(@resource[:name]) end
# File lib/puppet/provider/package/aix.rb, line 65 def install(useversion = true) unless source = @resource[:source] self.fail "A directory is required which will be used to find packages" end pkg = @resource[:name] pkg << " #{@resource.should(:ensure)}" if (! @resource.should(:ensure).is_a? Symbol) and useversion installp "-acgwXY", "-d", source, pkg end
# File lib/puppet/provider/package/pacman.rb, line 44 def install_from_file source = @resource[:source] begin source_uri = URI.parse source rescue => detail fail "Invalid source '#{source}': #{detail}" end source = case source_uri.scheme when nil then source when /https?/ then source when /ftp/ then source when /file/ then source_uri.path when /puppet/ fail "puppet:// URL is not supported by pacman" else fail "Source #{source} is not supported by pacman" end pacman "--noconfirm", "--noprogressbar", "-Sy" pacman "--noconfirm", "--noprogressbar", "-U", source end
# File lib/puppet/provider/package/pacman.rb, line 35 def install_from_repo if yaourt? yaourt "--noconfirm", "-S", @resource[:name] else pacman "--noconfirm", "--noprogressbar", "-Sy", @resource[:name] end end
# File lib/puppet/provider/package/msi.rb, line 120 def install_options join_options(resource[:install_options]) end
# File lib/puppet/util/monkey_patches.rb, line 259 def instance_variables puppet_original_instance_variables.map(&:to_sym) end
# File lib/puppet/type/cron.rb, line 303 def insync?(is) if is.is_a? Array return is.sort == @should.sort else return is == @should end end
Yaml doesn’t need the class name; it’s serialized.
# File lib/puppet/network/formats.rb, line 5 def intern(klass, text) YAML.safely_load(text) end
Yaml doesn’t need the class name; it’s serialized.
# File lib/puppet/network/formats.rb, line 10 def intern_multiple(klass, text) YAML.safely_load(text) end
This should absolutely be a private method, but for some reason it appears that you can't use the 'private' keyword inside of a Face definition. See #14205.
private :exclude_from_docs?
# File lib/puppet/face/help.rb, line 183 def is_face_app?(appname) clazz = Puppet::Application.find(appname) clazz.ancestors.include?(Puppet::Application::FaceBase) end
# File lib/puppet/provider/user/user_role_add.rb, line 63 def is_role? user_attributes and user_attributes[:type] == "role" end
# File lib/puppet/type/cron.rb, line 311 def is_to_s(newvalue) if newvalue if newvalue.is_a?(Array) newvalue.join(",") else newvalue end else nil end end
# File lib/puppet/provider/service/upstart.rb, line 157 def is_upstart?(script = initscript) File.exists?(script) && script.match(/\/etc\/init\/\S+\.conf/) end
The iterations and salt properties, like the password property, can only be modified by directly changing the user’s plist. Because of this fact, we have to treat the ds cache just like you would in the password= method.
# File lib/puppet/provider/user/directoryservice.rb, line 406 def iterations=(value) if (Puppet::Util::Package.versioncmp(self.class.get_os_version, '10.7') > 0) sleep 2 flush_dscl_cache users_plist = get_users_plist(@resource.name) shadow_hash_data = get_shadow_hash_data(users_plist) set_salted_pbkdf2(users_plist, shadow_hash_data, 'iterations', value) flush_dscl_cache end end
# File lib/puppet/provider/package/msi.rb, line 132 def join_options(options) return unless options options.collect do |val| case val when Hash val.keys.sort.collect do |k| "#{k}=#{val[k]}" end.join(' ') else val end end end
# File lib/puppet/network/formats.rb, line 139 def json @json ||= Puppet::Network::FormatHandler.format(:pson) end
# File lib/puppet/provider/user/user_role_add.rb, line 130 def keys if user_attributes #we have to get rid of all the keys we are managing another way remove_managed_attributes end end
# File lib/puppet/provider/user/user_role_add.rb, line 145 def keys=(keys_hash) run([command(:modify)] + build_keys_cmd(keys_hash) << @resource[:name], "modify attribute key pairs") end
# File lib/puppet/provider/package/aix.rb, line 109 def latest upd = latest_info unless upd.nil? return "#{upd[:version]}" else raise Puppet::DevError, "Tried to get latest on a missing package" if properties[:ensure] == :absent return properties[:ensure] end end
# File lib/puppet/provider/package/pip.rb, line 109 def lazy_pip(*args) pip *args rescue NoMethodError => e if pathname = which(self.class.cmd) self.class.commands :pip => pathname pip *args else raise e, 'Could not locate the pip command.' end end
Return a list of applications that are not simply just stubs for Faces.
# File lib/puppet/face/help.rb, line 124 def legacy_applications Puppet::Application.available_application_names.reject do |appname| (is_face_app?(appname)) or (exclude_from_docs?(appname)) end.sort end
Prepare a module object for print in a tree view. Each node in the tree must be a Hash in the following format:
{ :text => "puppetlabs-mysql (v1.0.0)" }
The value of a module’s :text is affected by three (3) factors: the format of the tree, it’s dependency status, and the location in the modulepath relative to it’s parent.
Returns a Hash
# File lib/puppet/face/module/list.rb, line 244 def list_build_node(mod, parent, params) str = '' str << (mod.forge_name ? mod.forge_name.gsub('/', '-') : mod.name) str << ' (' + colorize(:cyan, mod.version ? "v#{mod.version}" : '???') + ')' unless File.dirname(mod.path) == params[:path] str << " [#{File.dirname(mod.path)}]" end if @unmet_deps[:version_mismatch].include?(mod.forge_name) if params[:label_invalid] str << ' ' + colorize(:red, 'invalid') elsif parent.respond_to?(:forge_name) unmet_parent = @unmet_deps[:version_mismatch][mod.forge_name][:parent] if (unmet_parent[:name] == parent.forge_name && unmet_parent[:version] == "v#{parent.version}") str << ' ' + colorize(:red, 'invalid') end end end { :text => str } end
Prepare a list of module objects and their dependencies for print in a tree view.
Returns an Array of Hashes
Example:
[
{
:text => "puppetlabs-bacula (v0.0.2)",
:dependencies=> [
{ :text => "puppetlabs-stdlib (v2.2.1)", :dependencies => [] },
{
:text => "puppetlabs-mysql (v1.0.0)"
:dependencies => [
{
:text => "bodepd-create_resources (v0.0.1)",
:dependencies => []
}
]
},
{ :text => "puppetlabs-sqlite (v0.0.1)", :dependencies => [] },
]
}
]
When the above data structure is passed to Puppet::ModuleTool.build_tree you end up with something like this:
/usr/pkg/etc/puppet/modules └─┬ puppetlabs-bacula (v0.0.2) ├── puppetlabs-stdlib (v2.2.1) ├─┬ puppetlabs-mysql (v1.0.0) │ └── bodepd-create_resources (v0.0.1) └── puppetlabs-sqlite (v0.0.1)
# File lib/puppet/face/module/list.rb, line 209 def list_build_tree(list, ancestors=[], parent=nil, params={}) list.map do |mod| next if @seen[(mod.forge_name or mod.name)] node = list_build_node(mod, parent, params) @seen[(mod.forge_name or mod.name)] = true unless ancestors.include?(mod) node[:dependencies] ||= [] missing_deps = mod.unmet_dependencies.select do |dep| dep[:reason] == :missing end missing_deps.map do |mis_mod| str = "#{colorize(:bg_red, 'UNMET DEPENDENCY')} #{mis_mod[:name].gsub('/', '-')} " str << "(#{colorize(:cyan, mis_mod[:version_constraint])})" node[:dependencies] << { :text => str } end node[:dependencies] += list_build_tree(mod.dependencies_as_modules, ancestors + [mod], mod, params) end node end.compact end
# File lib/puppet/face/help.rb, line 87 def load_face_help(facename, actionname, version) begin face = Puppet::Face[facename.to_sym, version] rescue Puppet::Error => detail fail ArgumentError, <<-MSG Could not load help for the face #{facename}. Please check the error logs for more information. Detail: "#{detail.message}" MSG end if actionname action = face.get_action(actionname.to_sym) if not action fail ArgumentError, "Unable to load action #{actionname} from #{face}" end end [face, action] end
# File lib/puppet/provider/group/aix.rb, line 65 def lsallcmd() lscmd("ALL") end
# File lib/puppet/provider/group/aix.rb, line 59 def lscmd(value=@resource[:name]) [self.class.command(:list)] + self.get_ia_module_args + [ value] end
List groups and Ids
# File lib/puppet/provider/user/aix.rb, line 90 def lsgroupscmd(value=@resource[:name]) [command(:lsgroup)] + self.get_ia_module_args + ["-a", "id", value] end
# File lib/puppet/face/instrumentation_listener.rb, line 47 def manage(name, activate) Puppet::Util::Instrumentation::Listener.indirection.terminus_class = :rest listener = Puppet::Face[:instrumentation_listener, '0.0.1'].find(name) if listener listener.enabled = activate Puppet::Face[:instrumentation_listener, '0.0.1'].save(listener) end end
# File lib/puppet/provider/user/user_role_add.rb, line 121 def managed_attributes [:name, :type, :roles, :auths, :profiles, :project] end
# File lib/puppet/provider/service/windows.rb, line 35 def manual_start w32ss = Win32::Service.configure( 'service_name' => @resource[:name], 'start_type' => Win32::Service::SERVICE_DEMAND_START ) raise Puppet::Error.new("Win32 service manual enable of #{@resource[:name]} failed" ) if( w32ss.nil? ) rescue Win32::Service::Error => detail raise Puppet::Error.new("Cannot enable #{@resource[:name]} for manual start, error was: #{detail}" ) end
Configure discovered resources to be purged.
# File lib/puppet/type/file.rb, line 416 def mark_children_for_purging(children) children.each do |name, child| next if child[:source] child[:ensure] = :absent end end
Find all matching messages.
# File lib/puppet/reports/tagmail.rb, line 42 def match(taglists) matching_logs = [] taglists.each do |emails, pos, neg| # First find all of the messages matched by our positive tags messages = nil if pos.include?("all") messages = self.logs else # Find all of the messages that are tagged with any of our # tags. messages = self.logs.find_all do |log| pos.detect { |tag| log.tagged?(tag) } end end # Now go through and remove any messages that match our negative tags messages = messages.reject do |log| true if neg.detect do |tag| log.tagged?(tag) end end if messages.empty? Puppet.info "No messages to report to #{emails.join(",")}" next else matching_logs << [emails, messages.collect { |m| m.to_report }.join("\n")] end end matching_logs end
Does a given path match our glob patterns, if any? Return true if no patterns have been provided.
# File lib/puppet/type/tidy.rb, line 278 def matches?(path) return true unless self[:matches] basename = File.basename(path) flags = File::FNM_DOTMATCH | File::FNM_PATHNAME if self[:matches].find {|pattern| File.fnmatch(pattern, basename, flags) } return true else debug "No specified patterns match #{path}, not tidying" return false end end
# File lib/puppet/provider/mcx/mcxcontent.rb, line 110 def mcximport(ds_type, ds_name, val) ds_t = TypeMap[ds_type] ds_path = "/Local/Default/#{ds_t}/#{ds_name}" tmp = Tempfile.new('puppet_mcx') begin tmp << val tmp.flush dscl 'localhost', '-mcximport', ds_path, tmp.path ensure tmp.close tmp.unlink end end
# File lib/puppet/provider/group/windows_adsi.rb, line 15 def members group.members end
# File lib/puppet/provider/group/windows_adsi.rb, line 19 def members=(members) group.set_members(members) end
This method will merge in a given value using dscl
# File lib/puppet/provider/user/directoryservice.rb, line 485 def merge_attribute_with_dscl(path, username, keyname, value) begin dscl '.', '-merge', "/#{path}/#{username}", keyname, value rescue Puppet::ExecutionFailure => detail raise Puppet::Error, "Could not set the dscl #{keyname} key with value: #{value} - #{detail.inspect}" end end
Adds methods to a #singleton_class
# File lib/puppet/util/metaid.rb, line 7 def meta_def(name, &blk) meta_eval { define_method name, &blk } end
# File lib/puppet/util/metaid.rb, line 4 def meta_eval(&blk); singleton_class.instance_eval(&blk); end
Remove #singleton_class methods.
# File lib/puppet/util/metaid.rb, line 12 def meta_undef(name, &blk) meta_eval { remove_method name } end
Make a file resource to remove a given file.
# File lib/puppet/type/tidy.rb, line 217 def mkfile(path) # Force deletion, so directories actually get deleted. Puppet::Type.type(:file).new :path => path, :backup => self[:backup], :ensure => :absent, :force => true end
# File lib/puppet/reports/rrdgraph.rb, line 46 def mkhtml images = Dir.entries(hostdir).find_all { |d| d =~ /\.png/ } periodorder = %w{daily weekly monthly yearly} periods = {} types = {} images.each do |n| type, period = n.sub(".png", '').split("-") periods[period] ||= [] types[type] ||= [] periods[period] << n types[type] << n end files = [] # Make the period html files periodorder.each do |period| unless ary = periods[period] raise Puppet::Error, "Could not find graphs for #{period}" end files << htmlfile(period, ary, :first) end # make the type html files types.sort { |a,b| a[0] <=> b[0] }.each do |type, ary| newary = [] periodorder.each do |period| if graph = ary.find { |g| g.include?("-#{period}.png") } newary << graph else raise "Could not find #{type}-#{period} graph" end end files << htmlfile(type, newary, :second) end File.open(File.join(hostdir, "index.html"), "w") do |of| of.puts "<html><head><title>Report graphs for #{host}</title></head><body>" files.each do |file| of.puts "<a href='#{File.basename(file)}'>#{File.basename(file).sub(".html",'').capitalize}</a><br/>" end of.puts "</body></html>" end end
# File lib/puppet/provider/file/posix.rb, line 118 def mode if stat = resource.stat return (stat.mode & 007777).to_s(8) else return :absent end end
# File lib/puppet/provider/file/posix.rb, line 126 def mode=(value) begin File.chmod(value.to_i(8), resource[:path]) rescue => detail error = Puppet::Error.new("failed to set mode #{mode} on #{resource[:path]}: #{detail.message}") error.set_backtrace detail.backtrace raise error end end
# File lib/puppet/provider/group/aix.rb, line 80 def modifycmd(hash = property_hash) args = self.hash2args(hash) return nil if args.empty? [self.class.command(:modify)] + self.get_ia_module_args + args + [@resource[:name]] end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 538 def month_constant_to_number(constant) month_num = 1 while constant >> month_num - 1 > 1 month_num += 1 end month_num end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 423 def months_from_bitfield(bitfield) months = [] scheduler_months.each do |month| if bitfield & month != 0 months << month_constant_to_number(month) end end months end
# File lib/puppet/provider/zone/solaris.rb, line 32 def multi_conf(name, should, &action) has = properties[name] has = [] if has == :absent rms = has - should adds = should - has (rms.map{|o| action.call(:rm,o)} + adds.map{|o| action.call(:add,o)}).join("\n") end
# File lib/puppet/type/macauthorization.rb, line 20 def munge_boolean(value) case value when true, "true", :true :true when false, "false", :false :false else fail("munge_boolean only takes booleans") end end
# File lib/puppet/type/macauthorization.rb, line 31 def munge_integer(value) Integer(value) rescue ArgumentError fail("munge_integer only takes integers") end
# File lib/puppet/provider/zone/solaris.rb, line 107 def my_properties [:path, :iptype, :autoboot, :pool, :shares, :ip, :dataset, :inherit] end
# File lib/puppet/provider/file/posix.rb, line 50 def name2gid(value) Integer(value) rescue gid(value) || false end
Determine if the account is valid, and if so, return the UID
# File lib/puppet/provider/file/windows.rb, line 15 def name2id(value) Puppet::Util::Windows::Security.name_to_sid(value) end
Determine if the user is valid, and if so, return the UID
# File lib/puppet/provider/file/posix.rb, line 29 def name2uid(value) Integer(value) rescue uid(value) || false end
Determines if augeas acutally needs to run.
# File lib/puppet/provider/augeas/augeas.rb, line 339 def need_to_run? force = resource[:force] return_value = true begin open_augeas filter = resource[:onlyif] unless filter == "" cmd_array = parse_commands(filter)[0] command = cmd_array[0]; begin case command when "get"; return_value = process_get(cmd_array) when "match"; return_value = process_match(cmd_array) end rescue SystemExit,NoMemoryError raise rescue Exception => e fail("Error sending command '#{command}' with params #{cmd_array[1..-1].inspect}/#{e.message}") end end unless force # If we have a verison of augeas which is at least 0.3.6 then we # can make the changes now and see if changes were made. if return_value and versioncmp(get_augeas_version, "0.3.6") >= 0 debug("Will attempt to save and only run if files changed") # Execute in NEWFILE mode so we can show a diff set_augeas_save_mode(SAVE_NEWFILE) do_execute_changes save_result = @aug.save unless save_result print_put_errors fail("Save failed with return code #{save_result}, see debug") end saved_files = @aug.match("/augeas/events/saved") if saved_files.size > 0 root = resource[:root].sub(/^\/$/, "") saved_files.map! {|key| @aug.get(key).sub(/^\/files/, root) } saved_files.uniq.each do |saved_file| if Puppet[:show_diff] notice "\n" + diff(saved_file, saved_file + ".augnew") end File.delete(saved_file + ".augnew") end debug("Files changed, should execute") return_value = true else debug("Skipping because no files were changed") return_value = false end end end ensure if not return_value or resource.noop? or not save_result close_augeas end end return_value end
This method returns a new StringIO object. Why does it exist? Well, StringIO objects have their own ‘serial number’, so when writing rspec tests it’s difficult to compare StringIO objects due to this serial number. If this action is wrapped in its own method, it can be mocked for easier testing.
# File lib/puppet/provider/user/directoryservice.rb, line 577 def new_stringio_object(value = '') StringIO.new(value) end
Create a new file or directory object as a child to the current object.
# File lib/puppet/type/file.rb, line 425 def newchild(path) full_path = ::File.join(self[:path], path) # Add some new values to our original arguments -- these are the ones # set at initialization. We specifically want to exclude any param # values set by the :source property or any default values. # LAK:NOTE This is kind of silly, because the whole point here is that # the values set at initialization should live as long as the resource # but values set by default or by :source should only live for the transaction # or so. Unfortunately, we don't have a straightforward way to manage # the different lifetimes of this data, so we kludge it like this. # The right-side hash wins in the merge. options = @original_parameters.merge(:path => full_path).reject { |param, value| value.nil? } # These should never be passed to our children. [:parent, :ensure, :recurse, :recurselimit, :target, :alias, :source].each do |param| options.delete(param) if options.include?(param) end self.class.new(options) end
Get the next available uid on the system by getting a list of user ids, sorting them, grabbing the last one, and adding a 1. Scientific stuff here.
# File lib/puppet/provider/user/directoryservice.rb, line 500 def next_system_id(min_id=20) dscl_output = dscl '.', '-list', '/Users', 'uid' # We're ok with throwing away negative uids here. Also, remove nil values. user_ids = dscl_output.split.compact.collect { |l| l.to_i if l.match(/^\d+$/) } ids = user_ids.compact!.sort! { |a,b| a.to_f <=> b.to_f } # We're just looking for an unused id in our sorted array. ids.each_index do |i| next_id = ids[i] + 1 return next_id if ids[i+1] != next_id and next_id >= min_id end end
# File lib/puppet/util/instrumentation/listeners/log.rb, line 15 def notify(label, event, data) return if event == :start log_line = "#{label} took #{data[:finished] - data[:started]}" @last_logs.synchronize { (@last_logs[label] ||= []) << log_line @last_logs[label].shift if @last_logs[label].length > SIZE } end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 546 def occurrence_constant_to_name(constant) case constant when Win32::TaskScheduler::FIRST_WEEK; 'first' when Win32::TaskScheduler::SECOND_WEEK; 'second' when Win32::TaskScheduler::THIRD_WEEK; 'third' when Win32::TaskScheduler::FOURTH_WEEK; 'fourth' when Win32::TaskScheduler::LAST_WEEK; 'last' end end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 556 def occurrence_name_to_constant(name) case name when 'first'; Win32::TaskScheduler::FIRST_WEEK when 'second'; Win32::TaskScheduler::SECOND_WEEK when 'third'; Win32::TaskScheduler::THIRD_WEEK when 'fourth'; Win32::TaskScheduler::FOURTH_WEEK when 'last'; Win32::TaskScheduler::LAST_WEEK end end
# File lib/puppet/provider/augeas/augeas.rb, line 145 def open_augeas unless @aug flags = Augeas::NONE flags = Augeas::TYPE_CHECK if resource[:type_check] == :true if resource[:incl] flags |= Augeas::NO_MODL_AUTOLOAD else flags |= Augeas::NO_LOAD end root = resource[:root] load_path = get_load_path(resource) debug("Opening augeas with root #{root}, lens path #{load_path}, flags #{flags}") @aug = Augeas::open(root, load_path,flags) debug("Augeas version #{get_augeas_version} is installed") if versioncmp(get_augeas_version, "0.3.6") >= 0 # Optimize loading if the context is given and it's a simple path, # requires the glob function from Augeas 0.8.2 or up glob_avail = !aug.match("/augeas/version/pathx/functions/glob").empty? opt_ctx = resource[:context].match("^/files/[^'\"\\[\\]]+$") if resource[:context] restricted = false if resource[:incl] aug.set("/augeas/load/Xfm/lens", resource[:lens]) aug.set("/augeas/load/Xfm/incl", resource[:incl]) restricted = true elsif glob_avail and opt_ctx restricted = true # Optimize loading if the context is given, requires the glob function # from Augeas 0.8.2 or up ctx_path = resource[:context].sub(/^\/files(.*?)\/?$/, '\1/') load_path = "/augeas/load/*['%s' !~ glob(incl) + regexp('/.*')]" % ctx_path if aug.match(load_path).size < aug.match("/augeas/load/*").size aug.rm(load_path) restricted = true else # This will occur if the context is less specific than any glob debug("Unable to optimize files loaded by context path, no glob matches") end end aug.load print_load_errors(:warning => restricted) end @aug end
Where is our override script?
# File lib/puppet/provider/service/upstart.rb, line 71 def overscript @overscript ||= initscript.gsub(/\.conf$/,".override") end
# File lib/puppet/provider/file/posix.rb, line 54 def owner unless stat = resource.stat return :absent end currentvalue = stat.uid # On OS X, files that are owned by -2 get returned as really # large UIDs instead of negative ones. This isn't a Ruby bug, # it's an OS X bug, since it shows up in perl, too. if currentvalue > Puppet[:maximum_uid].to_i self.warning "Apparently using negative UID (#{currentvalue}) on a platform that does not consistently handle them" currentvalue = :silly end currentvalue end
# File lib/puppet/provider/file/posix.rb, line 72 def owner=(should) # Set our method appropriately, depending on links. if resource[:links] == :manage method = :lchown else method = :chown end begin File.send(method, should, nil, resource[:path]) rescue => detail raise Puppet::Error, "Failed to set owner to '#{should}': #{detail}" end end
The common package name format.
# File lib/puppet/provider/package/portage.rb, line 60 def package_name @resource[:category] ? "#{@resource[:category]}/#{@resource[:name]}" : @resource[:name] end
Load the config file
# File lib/puppet/reports/tagmail.rb, line 74 def parse(text) taglists = [] text.split("\n").each do |line| taglist = emails = nil case line.chomp when /^\s*#/; next when /^\s*$/; next when /^\s*(.+)\s*:\s*(.+)\s*$/ taglist = $1 emails = $2.sub(/#.*$/,'') else raise ArgumentError, "Invalid tagmail config file" end pos = [] neg = [] taglist.sub(/\s+$/,'').split(/\s*,\s*/).each do |tag| unless tag =~ /^!?[-\w\.]+$/ raise ArgumentError, "Invalid tag #{tag.inspect}" end case tag when /^\w+/; pos << tag when /^!\w+/; neg << tag.sub("!", '') else raise Puppet::Error, "Invalid tag '#{tag}'" end end # Now split the emails emails = emails.sub(/\s+$/,'').split(/\s*,\s*/) taglists << [emails, pos, neg] end taglists end
Extracts an 2 dimensional array of commands which are in the form of command path value. The input can be
A string with one command
A string with many commands per line
An array of strings.
# File lib/puppet/provider/augeas/augeas.rb, line 67 def parse_commands(data) context = resource[:context] # Add a trailing / if it is not there if (context.length > 0) context << "/" if context[-1, 1] != "/" end data = data.split($/) if data.is_a?(String) data = data.flatten args = [] data.each do |line| line.strip! next if line.nil? || line.empty? argline = [] sc = StringScanner.new(line) cmd = sc.scan(/\w+|==|!=/) formals = COMMANDS[cmd] fail("Unknown command #{cmd}") unless formals argline << cmd narg = 0 formals.each do |f| sc.skip(/\s+/) narg += 1 if f == :path start = sc.pos nbracket = 0 inSingleTick = false inDoubleTick = false begin sc.skip(/([^\]\[\s\'"]|\.)+/) ch = sc.getch nbracket += 1 if ch == "[" nbracket -= 1 if ch == "]" inSingleTick = !inSingleTick if ch == "'" inDoubleTick = !inDoubleTick if ch == "\"" fail("unmatched [") if nbracket < 0 end until ((nbracket == 0 && !inSingleTick && !inDoubleTick && (ch =~ /\s/)) || sc.eos?) len = sc.pos - start len -= 1 unless sc.eos? unless p = sc.string[start, len] fail("missing path argument #{narg} for #{cmd}") end # Rip off any ticks if they are there. p = p[1, (p.size - 2)] if p[0,1] == "'" || p[0,1] == "\"" p.chomp!("/") if p[0,1] != '$' && p[0,1] != "/" argline << context + p else argline << p end elsif f == :string delim = sc.peek(1) if delim == "'" || delim == "\"" sc.getch argline << sc.scan(/([^\#{delim}]|(\.))*/) sc.getch else argline << sc.scan(/[^\s]+/) end fail("missing string argument #{narg} for #{cmd}") unless argline[-1] elsif f == :comparator argline << sc.scan(/(==|!=|=~|<|<=|>|>=)/) unless argline[-1] puts sc.rest fail("invalid comparator for command #{cmd}") end elsif f == :int argline << sc.scan(/\d+/).to_i elsif f== :glob argline << sc.rest end end args << argline end args end
Given the resource name string, parse ds_name out.
# File lib/puppet/provider/mcx/mcxcontent.rb, line 142 def parse_name(name) ds_name = name.split('/')[2] unless ds_name raise MCXContentProviderException, "Could not parse ds_name from resource name '#{name}'. Specify with ds_name parameter." end ds_name end
Given the resource name string, parse ds_type out.
# File lib/puppet/provider/mcx/mcxcontent.rb, line 126 def parse_type(name) ds_type = name.split('/')[1] unless ds_type raise MCXContentProviderException, "Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter." end # De-pluralize and downcase. ds_type = ds_type.chop.downcase.to_sym unless TypeMap.key? ds_type raise MCXContentProviderException, "Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter." end ds_type end
# File lib/puppet/provider/user/useradd.rb, line 90 def passcmd age_limits = [:password_min_age, :password_max_age].select { |property| @resource.should(property) } if age_limits.empty? nil else [command(:password),age_limits.collect { |property| [flag(property), @resource.should(property)]}, @resource[:name]].flatten end end
*password*
The user's password, in whatever encrypted format the local machine
requires. Be sure to enclose any value that includes a dollar sign ($)
in single quotes ('). Requires features manages_passwords.
Retrieve the password parsing directly the /etc/security/passwd
# File lib/puppet/provider/user/aix.rb, line 227 def password password = :absent user = @resource[:name] f = File.open("/etc/security/passwd", 'r') # Skip to the user f.each_line { |l| break if l =~ /^#{user}:\s*$/ } if ! f.eof? f.each_line { |l| # If there is a new user stanza, stop break if l =~ /^\S*:\s*$/ # If the password= entry is found, return it if l =~ /^\s*password\s*=\s*(.*)$/ password = $1; break; end } end f.close() return password end
# File lib/puppet/provider/user/aix.rb, line 247 def password=(value) user = @resource[:name] # Puppet execute does not support strings as input, only files. tmpfile = Tempfile.new('puppet_#{user}_pw') tmpfile << "#{user}:#{value}\n" tmpfile.close() # Options '-e', '-c', use encrypted password and clear flags # Must receive "user:enc_password" as input # command, arguments = {:failonfail => true, :combine => true} # Fix for bugs #11200 and #10915 cmd = [self.class.command(:chpasswd), get_ia_module_args, '-e', '-c', user].flatten begin output = execute(cmd, {:failonfail => false, :combine => true, :stdinfile => tmpfile.path }) # chpasswd can return 1, even on success (at least on AIX 6.1); empty output indicates success if output != "" raise Puppet::ExecutionFailure, "chpasswd said #{output}" end rescue Puppet::ExecutionFailure => detail raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}" ensure tmpfile.delete() end end
# File lib/puppet/provider/user/user_role_add.rb, line 175 def password_max_age return :absent unless shadow_entry shadow_entry[4] || -1 end
# File lib/puppet/provider/user/user_role_add.rb, line 171 def password_min_age shadow_entry ? shadow_entry[3] : :absent end
Component paths are special because they function as containers.
# File lib/puppet/type/component.rb, line 37 def pathbuilder if reference.type == "Class" # 'main' is the top class, so we want to see '//' instead of # its name. if reference.title.to_s.downcase == "main" myname = "" else myname = reference.title end else myname = reference.to_s end if p = self.parent return [p.pathbuilder, myname] else return [myname] end end
# File lib/puppet/provider/service/init.rb, line 67 def paths @paths ||= @resource[:path].find_all do |path| if File.directory?(path) true else if File.exist?(path) and ! File.directory?(path) self.debug "Search path #{path} is not a directory" else self.debug "Search path #{path} does not exist" end false end end end
# File lib/puppet/type/file.rb, line 588 def perform_recursion(path) Puppet::FileServing::Metadata.indirection.search( path, :links => self[:links], :recurse => (self[:recurse] == :remote ? true : self[:recurse]), :recurselimit => self[:recurselimit], :ignore => self[:ignore], :checksum_type => (self[:source] || self[:content]) ? self[:checksum] : :none, :environment => catalog.environment ) end
# File lib/puppet/provider/package/blastwave.rb, line 11 def pkgget_with_cat(*args) Puppet::Util.withenv(:PAGER => "/usr/bin/cat") { pkgget(*args) } end
Turn our pkgutil -c listing into a hash for a single package.
# File lib/puppet/provider/package/pkgutil.rb, line 79 def pkgsingle(resource) # The --single option speeds up the execution, because it queries # the package managament system for one package only. command = ["-c", "--single", resource[:name]] self.class.parse_pkglist(run_pkgutil(resource, command), { :justme => resource[:name] }) end
finds the path for a given label and returns the path and parsed plist as an array of [path, plist]. Note plist is really a Hash here.
# File lib/puppet/provider/service/launchd.rb, line 221 def plist_from_label(label) job = self.class.jobsearch(label) job_path = job[label] if FileTest.file?(job_path) job_plist = self.class.read_plist(job_path) else raise Puppet::Error.new("Unable to parse launchd plist at path: #{job_path}") end [job_path, job_plist] end
# File lib/puppet/provider/mailalias/aliases.rb, line 15 def post_parse(record) # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com] # It's not sufficient to assign to an existing hash. recipient = record[:recipient].split(/\s*,\s*/).collect { |d| d.gsub(/^['"]|['"]$/, '') } record[:recipient] = recipient record end
# File lib/puppet/provider/package/sun.rb, line 106 def prepare_cmd(opt) [if_have_value('-a', opt[:adminfile]), if_have_value('-r', opt[:responsefile]), if_have_value('-d', opt[:source]), opt[:cmd_options] || [], ['-n', @resource[:name]]].flatten end
Return the principals
# File lib/puppet/type/k5login.rb, line 58 def principals(dummy_argument=:work_arround_for_ruby_GC_bug) if File.exists?(@resource[:name]) File.readlines(@resource[:name]).collect { |line| line.chomp } else :absent end end
Write the principals out to the k5login file
# File lib/puppet/type/k5login.rb, line 67 def principals=(value) write(value) end
# File lib/puppet/provider/augeas/augeas.rb, line 329 def print_errors(errors) errors.each do |errnode| @aug.match("#{errnode}/*").each do |subnode| subvalue = @aug.get(subnode) debug("#{subnode} = #{subvalue}") end end end
# File lib/puppet/provider/augeas/augeas.rb, line 311 def print_load_errors(args={}) errors = @aug.match("/augeas//error") unless errors.empty? if args[:warning] warning("Loading failed for one or more files, see debug for /augeas//error output") else debug("Loading failed for one or more files, output from /augeas//error:") end end print_errors(errors) end
# File lib/puppet/provider/augeas/augeas.rb, line 323 def print_put_errors errors = @aug.match("/augeas//error[. = 'put_failed']") debug("Put failed on one or more files, output from /augeas//error:") unless errors.empty? print_errors(errors) end
# File lib/puppet/provider/mailalias/aliases.rb, line 23 def process(line) ret = {} records = line.split(':',2) ret[:name] = records[0].strip ret[:recipient] = records[1].strip ret end
Used by the need_to_run? method to process get filters. Returns true if there is a match, false if otherwise Assumes a syntax of get /files/path [COMPARATOR] value
# File lib/puppet/provider/augeas/augeas.rb, line 205 def process_get(cmd_array) return_value = false #validate and tear apart the command fail ("Invalid command: #{cmd_array.join(" ")}") if cmd_array.length < 4 cmd = cmd_array.shift path = cmd_array.shift comparator = cmd_array.shift arg = cmd_array.join(" ") #check the value in augeas result = @aug.get(path) || '' case comparator when "!=" return_value = (result != arg) when "=~" regex = Regexp.new(arg) return_value = (result =~ regex) else return_value = (result.send(comparator, arg)) end !!return_value end
Used by the need_to_run? method to process match filters. Returns true if there is a match, false if otherwise
# File lib/puppet/provider/augeas/augeas.rb, line 231 def process_match(cmd_array) return_value = false #validate and tear apart the command fail("Invalid command: #{cmd_array.join(" ")}") if cmd_array.length < 3 cmd = cmd_array.shift path = cmd_array.shift # Need to break apart the clause clause_array = parse_commands(cmd_array.shift)[0] verb = clause_array.shift #Get the values from augeas result = @aug.match(path) || [] fail("Error trying to match path '#{path}'") if (result == -1) # Now do the work case verb when "size" fail("Invalid command: #{cmd_array.join(" ")}") if clause_array.length != 2 comparator = clause_array.shift arg = clause_array.shift case comparator when "!=" return_value = !(result.size.send(:==, arg)) else return_value = (result.size.send(comparator, arg)) end when "include" arg = clause_array.shift return_value = result.include?(arg) when "not_include" arg = clause_array.shift return_value = !result.include?(arg) when "==" begin arg = clause_array.shift new_array = eval arg return_value = (result == new_array) rescue fail("Invalid array in command: #{cmd_array.join(" ")}") end when "!=" begin arg = clause_array.shift new_array = eval arg return_value = (result != new_array) rescue fail("Invalid array in command: #{cmd_array.join(" ")}") end end !!return_value end
# File lib/puppet/provider/zpool/zpool.rb, line 14 def process_zpool_data(pool_array) if pool_array == [] return Hash.new(:absent) end #get the name and get rid of it pool = Hash.new pool[:pool] = pool_array[0] pool_array.shift tmp = [] #order matters here :( pool_array.reverse.each do |value| sym = nil case value when "spares"; sym = :spare when "logs"; sym = :log when /^mirror|^raidz1|^raidz2/; sym = value =~ /^mirror/ ? :mirror : :raidz pool[:raid_parity] = "raidz2" if value =~ /^raidz2/ else tmp << value sym = :disk if value == pool_array.first end if sym pool[sym] = pool[sym] ? pool[sym].unshift(tmp.reverse.join(' ')) : [tmp.reverse.join(' ')] tmp.clear end end pool end
We need a way to test whether a zone is in process. Our ‘ensure’ property models the static states, but we need to handle the temporary ones.
# File lib/puppet/provider/zone/solaris.rb, line 190 def processing? hash = status return false unless hash ["incomplete", "ready", "shutting_down"].include? hash[:ensure] end
# File lib/puppet/provider/user/user_role_add.rb, line 113 def profiles user_attributes[:profiles] if user_attributes end
# File lib/puppet/provider/user/user_role_add.rb, line 117 def project user_attributes[:project] if user_attributes end
Look up the current status.
# File lib/puppet/provider/maillist/mailman.rb, line 84 def properties if @property_hash.empty? @property_hash = query || {:ensure => :absent} @property_hash[:ensure] = :absent if @property_hash.empty? end @property_hash.dup end
There are some cases where all of the work does not get done on file creation/modification, so we have to do some extra checking.
# File lib/puppet/type/file.rb, line 779 def property_fix properties.each do |thing| next unless [:mode, :owner, :group, :seluser, :selrole, :seltype, :selrange].include?(thing.name) # Make sure we get a new stat objct @stat = :needs_stat currentvalue = thing.retrieve thing.sync unless thing.safe_insync?(currentvalue) end end
# File lib/puppet/type/zone.rb, line 96 def provider_sync_send(method) warned = false while provider.processing? next if warned info "Waiting for zone to finish processing" warned = true sleep 1 end provider.send(method) provider.flush() end
Remove the list and its archives.
# File lib/puppet/provider/maillist/mailman.rb, line 93 def purge destroy(true) end
Should we be purging?
# File lib/puppet/type/file.rb, line 470 def purge? @parameters.include?(:purge) and (self[:purge] == :true or self[:purge] == "true") end
Pull the current state of the list from the full list. We’re getting some double entendre here.…
# File lib/puppet/provider/maillist/mailman.rb, line 99 def query self.class.instances.each do |list| if list.name == self.name or list.name.downcase == self.name return list.properties end end nil end
query for parity and set the right string
# File lib/puppet/provider/zpool/zpool.rb, line 78 def raidzarity @resource[:raid_parity] ? @resource[:raid_parity] : "raidz1" end
Add a new setting to the rc files
# File lib/puppet/provider/service/freebsd.rb, line 87 def rc_add(service, rcvar, yesno) append = "\# Added by Puppet\n#{rcvar}_enable=\"#{yesno}\"\n" if Facter.value(:operatingsystem) == "NetBSD" append = "\# Added by Puppet\n#{rcvar}=\"#{yesno}\"\n" end # First, try the one-file-per-service style if File.exists?(rcconf_dir) File.open(rcconf_dir + "/#{service}", File::WRONLY | File::APPEND | File::CREAT, 0644) { |f| f << append self.debug("Appended to #{f.path}") } else # Else, check the local rc file first, but don't create it if File.exists?(rcconf_local) File.open(rcconf_local, File::WRONLY | File::APPEND) { |f| f << append self.debug("Appended to #{f.path}") } else # At last use the standard rc.conf file File.open(rcconf, File::WRONLY | File::APPEND | File::CREAT, 0644) { |f| f << append self.debug("Appended to #{f.path}") } end end end
Edit rc files and set the service to yes/no
# File lib/puppet/provider/service/freebsd.rb, line 61 def rc_edit(yesno) service = self.service_name rcvar = self.rcvar_name self.debug("Editing rc files: setting #{rcvar} to #{yesno} for #{service}") self.rc_add(service, rcvar, yesno) if not self.rc_replace(service, rcvar, yesno) end
Try to find an existing setting in the rc files and replace the value
# File lib/puppet/provider/service/freebsd.rb, line 70 def rc_replace(service, rcvar, yesno) success = false # Replace in all files, not just in the first found with a match [rcconf, rcconf_local, rcconf_dir + "/#{service}"].each do |filename| if File.exists?(filename) s = File.read(filename) if s.gsub!(/(#{rcvar}(_enable)?)=\"?(YES|NO)\"?/, "\\1=\"#{yesno}\"") File.open(filename, File::WRONLY) { |f| f << s } self.debug("Replaced in #{filename}") success = true end end end success end
# File lib/puppet/provider/service/freebsd.rb, line 8 def rcconf() '/etc/rc.conf' end
# File lib/puppet/provider/service/bsd.rb, line 12 def rcconf_dir '/etc/rc.conf.d' end
# File lib/puppet/provider/service/freebsd.rb, line 9 def rcconf_local() '/etc/rc.conf.local' end
Executing an init script with the ‘rcvar’ argument returns the service name, rcvar name and whether it’s enabled/disabled
# File lib/puppet/provider/service/freebsd.rb, line 22 def rcvar rcvar = execute([self.initscript, :rcvar], :failonfail => true, :combine => false, :squelch => false) rcvar = rcvar.split("\n") rcvar.delete_if {|str| str =~ /^#\s*$/} rcvar[1] = rcvar[1].gsub(/^\$/, '') rcvar end
Extract rcvar name
# File lib/puppet/provider/service/freebsd.rb, line 41 def rcvar_name name = self.rcvar[1] self.error("No rcvar name found in rcvar") if name.nil? name = name.gsub!(/(.*)(_enable)?=(.*)/, '\1') self.error("rcvar name is empty") if name.nil? self.debug("rcvar name is #{name}") name end
Extract rcvar value
# File lib/puppet/provider/service/freebsd.rb, line 51 def rcvar_value value = self.rcvar[1] self.error("No rcvar value found in rcvar") if value.nil? value = value.gsub!(/(.*)(_enable)?="?(\w+)"?/, '\3') self.error("rcvar value is empty") if value.nil? self.debug("rcvar value is #{value}") value end
# File lib/puppet/provider/service/upstart.rb, line 265 def read_override_file if File.exists?(overscript) read_script_from(overscript) else "" end end
# File lib/puppet/provider/service/upstart.rb, line 336 def read_script_from(filename) File.open(filename) do |file| file.read end end
# File lib/puppet/provider/zone/solaris.rb, line 298 def ready zoneadm :ready end
Recursively generate a list of file resources, which will be used to copy remote files, manage local files, and/or make links to map to another directory.
# File lib/puppet/type/file.rb, line 477 def recurse children = (self[:recurse] == :remote) ? {} : recurse_local if self[:target] recurse_link(children) elsif self[:source] recurse_remote(children) end # If we're purging resources, then delete any resource that isn't on the # remote system. mark_children_for_purging(children) if self.purge? # REVISIT: sort_by is more efficient? result = children.values.sort { |a, b| a[:path] <=> b[:path] } remove_less_specific_files(result) end
A simple method for determining whether we should be recursing.
# File lib/puppet/type/file.rb, line 516 def recurse? self[:recurse] == true or self[:recurse] == :remote end
Recurse the target of the link.
# File lib/puppet/type/file.rb, line 521 def recurse_link(children) perform_recursion(self[:target]).each do |meta| if meta.relative_path == "." self[:ensure] = :directory next end children[meta.relative_path] ||= newchild(meta.relative_path) if meta.ftype == "directory" children[meta.relative_path][:ensure] = :directory else children[meta.relative_path][:ensure] = :link children[meta.relative_path][:target] = meta.full_path end end children end
Recurse the file itself, returning a Metadata instance for every found file.
# File lib/puppet/type/file.rb, line 540 def recurse_local result = perform_recursion(self[:path]) return {} unless result result.inject({}) do |hash, meta| next hash if meta.relative_path == "." hash[meta.relative_path] = newchild(meta.relative_path) hash end end
Recurse against our remote file.
# File lib/puppet/type/file.rb, line 552 def recurse_remote(children) sourceselect = self[:sourceselect] total = self[:source].collect do |source| next unless result = perform_recursion(source) return if top = result.find { |r| r.relative_path == "." } and top.ftype != "directory" result.each { |data| data.source = "#{source}/#{data.relative_path}" } break result if result and ! result.empty? and sourceselect == :first result end.flatten.compact # This only happens if we have sourceselect == :all unless sourceselect == :first found = [] total.reject! do |data| result = found.include?(data.relative_path) found << data.relative_path unless found.include?(data.relative_path) result end end total.each do |meta| if meta.relative_path == "." parameter(:source).metadata = meta next end children[meta.relative_path] ||= newchild(meta.relative_path) children[meta.relative_path][:source] = meta.source children[meta.relative_path][:checksum] = :md5 if meta.ftype == "file" children[meta.relative_path].parameter(:source).metadata = meta end children end
# File lib/puppet/type/component.rb, line 56 def ref reference.to_s end
# File lib/puppet/type/component.rb, line 69 def refresh catalog.adjacent(self).each do |child| if child.respond_to?(:refresh) child.refresh child.log "triggering #{:refresh}" end end end
Remove any existing data. This is only used when dealing with links or directories.
# File lib/puppet/type/file.rb, line 602 def remove_existing(should) return unless s = stat self.fail "Could not back up; will not replace" unless perform_backup unless should.to_s == "link" return if s.ftype.to_s == should.to_s end case s.ftype when "directory" if self[:force] == :true debug "Removing existing directory for replacement with #{should}" FileUtils.rmtree(self[:path]) else notice "Not removing directory; use 'force' to override" return end when "link", "file" debug "Removing existing #{s.ftype} for replacement with #{should}" ::File.unlink(self[:path]) else self.fail "Could not back up files of type #{s.ftype}" end @stat = :needs_stat true end
This is to fix bug #2296, where two files recurse over the same set of files. It’s a rare case, and when it does happen you’re not likely to have many actual conflicts, which is good, because this is a pretty inefficient implementation.
# File lib/puppet/type/file.rb, line 499 def remove_less_specific_files(files) # REVISIT: is this Windows safe? AltSeparator? mypath = self[:path].split(::File::Separator) other_paths = catalog.vertices. select { |r| r.is_a?(self.class) and r[:path] != self[:path] }. collect { |r| r[:path].split(::File::Separator) }. select { |p| p[0,mypath.length] == mypath } return files if other_paths.empty? files.reject { |file| path = file[:path].split(::File::Separator) other_paths.any? { |p| path[0,p.length] == p } } end
# File lib/puppet/provider/user/user_role_add.rb, line 125 def remove_managed_attributes managed = managed_attributes user_attributes.select { |k,v| !managed.include?(k) }.inject({}) { |hash, array| hash[array[0]] = array[1]; hash } end
# File lib/puppet/provider/service/upstart.rb, line 289 def remove_manual_from(text) text.gsub(MANUAL, "") end
# File lib/puppet/provider/service/upstart.rb, line 281 def remove_trailing_comments_from(line) line.gsub(/^(\s*[^#]*).*/, '\1') end
# File lib/puppet/provider/service/upstart.rb, line 277 def remove_trailing_comments_from_commented_line_of(line) line.gsub(/^(\s*#+\s*[^#]*).*/, '\1') end
# File lib/puppet/network/formats.rb, line 14 def render(instance) instance.to_yaml end
# File lib/puppet/face/help.rb, line 78 def render_application_help(applicationname) return Puppet::Application[applicationname].help end
# File lib/puppet/face/help.rb, line 82 def render_face_help(facename, actionname, version) face, action = load_face_help(facename, actionname, version) return template_for(face, action).result(binding) end
Yaml monkey-patches Array, so this works.
# File lib/puppet/network/formats.rb, line 19 def render_multiple(instances) instances.to_yaml end
# File lib/puppet/network/formats.rb, line 39 def requiring_zlib if use_zlib? yield else raise Puppet::Error, "the zlib library is not installed or is disabled." end end
# File lib/puppet/type/resources.rb, line 104 def resource_type unless defined?(@resource_type) unless type = Puppet::Type.type(self[:name]) raise Puppet::DevError, "Could not find resource type" end @resource_type = type end @resource_type end
# File lib/puppet/provider/service/daemontools.rb, line 182 def restart svc "-t", self.service end
# File lib/puppet/provider/service/init.rb, line 123 def restartcmd (@resource[:hasrestart] == :true) && [initscript, :restart] end
if the onlyif resource is provided, then the value is parsed. a return value of 0 will stop exection because it matches the default value.
# File lib/puppet/type/augeas.rb, line 208 def retrieve if @resource.provider.need_to_run?() :need_to_run else 0 end end
# File lib/puppet/provider/macauthorization/macauthorization.rb, line 241 def retrieve_value(resource_name, attribute) # We set boolean values to symbols when retrieving values raise Puppet::Error.new("Cannot find #{resource_name} in auth db") if not self.class.parsed_auth_db.has_key?(resource_name) if PuppetToNativeAttributeMap.has_key?(attribute) native_attribute = PuppetToNativeAttributeMap[attribute] else native_attribute = attribute.to_s end if self.class.parsed_auth_db[resource_name].has_key?(native_attribute) value = self.class.parsed_auth_db[resource_name][native_attribute] case value when true, :true value = :true when false, :false value = :false end @property_hash[attribute] = value return value else @property_hash.delete(attribute) return "" # so ralsh doesn't display it. end end
# File lib/puppet/provider/user/user_role_add.rb, line 105 def roles user_attributes[:roles] if user_attributes end
# File lib/puppet/provider/exec/shell.rb, line 18 def run(command, check = false) super(['/bin/sh', '-c', command], check) end
# File lib/puppet/provider/package/pkgutil.rb, line 150 def run_pkgutil(resource, *args) # Allow source to be one or more URLs pointing to a repository that all # get passed to pkgutil via one or more -t options if resource[:source] sources = [resource[:source]].flatten pkguti *[sources.map{|src| [ "-t", src ]}, *args].flatten else pkguti *args.flatten end end
preseeds answers to dpkg-set-selection from the “responsefile”
# File lib/puppet/provider/package/apt.rb, line 87 def run_preseed if response = @resource[:responsefile] and FileTest.exist?(response) self.info("Preseeding #{response} to debconf-set-selections") preseed response else self.info "No responsefile specified or non existant, not preseeding anything" end end
The iterations and salt properties, like the password property, can only be modified by directly changing the user’s plist. Because of this fact, we have to treat the ds cache just like you would in the password= method.
# File lib/puppet/provider/user/directoryservice.rb, line 421 def salt=(value) if (Puppet::Util::Package.versioncmp(self.class.get_os_version, '10.7') > 0) sleep 2 flush_dscl_cache users_plist = get_users_plist(@resource.name) shadow_hash_data = get_shadow_hash_data(users_plist) set_salted_pbkdf2(users_plist, shadow_hash_data, 'salt', value) flush_dscl_cache end end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 475 def scheduler_days_of_week [ Win32::TaskScheduler::SUNDAY, Win32::TaskScheduler::MONDAY, Win32::TaskScheduler::TUESDAY, Win32::TaskScheduler::WEDNESDAY, Win32::TaskScheduler::THURSDAY, Win32::TaskScheduler::FRIDAY, Win32::TaskScheduler::SATURDAY ] end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 487 def scheduler_months [ Win32::TaskScheduler::JANUARY, Win32::TaskScheduler::FEBRUARY, Win32::TaskScheduler::MARCH, Win32::TaskScheduler::APRIL, Win32::TaskScheduler::MAY, Win32::TaskScheduler::JUNE, Win32::TaskScheduler::JULY, Win32::TaskScheduler::AUGUST, Win32::TaskScheduler::SEPTEMBER, Win32::TaskScheduler::OCTOBER, Win32::TaskScheduler::NOVEMBER, Win32::TaskScheduler::DECEMBER ] end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 504 def scheduler_occurrences [ Win32::TaskScheduler::FIRST_WEEK, Win32::TaskScheduler::SECOND_WEEK, Win32::TaskScheduler::THIRD_WEEK, Win32::TaskScheduler::FOURTH_WEEK, Win32::TaskScheduler::LAST_WEEK ] end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 465 def scheduler_trigger_types [ Win32::TaskScheduler::TASK_TIME_TRIGGER_DAILY, Win32::TaskScheduler::TASK_TIME_TRIGGER_WEEKLY, Win32::TaskScheduler::TASK_TIME_TRIGGER_MONTHLYDATE, Win32::TaskScheduler::TASK_TIME_TRIGGER_MONTHLYDOW, Win32::TaskScheduler::TASK_TIME_TRIGGER_ONCE ] end
# File lib/puppet/provider/service/init.rb, line 82 def search(name) paths.each { |path| fqname = File.join(path,name) begin stat = File.stat(fqname) rescue # should probably rescue specific errors... self.debug("Could not find #{name} in #{path}") next end # if we've gotten this far, we found a valid script return fqname } paths.each { |path| fqname_sh = File.join(path,"#{name}.sh") begin stat = File.stat(fqname_sh) rescue # should probably rescue specific errors... self.debug("Could not find #{name}.sh in #{path}") next end # if we've gotten this far, we found a valid script return fqname_sh } raise Puppet::Error, "Could not find init script for '#{name}'" end
# File lib/puppet/provider/selmodule/semodule.rb, line 67 def selmod_name_to_filename if @resource[:selmodulepath] return @resource[:selmodulepath] else return "#{@resource[:selmoduledir]}/#{@resource[:name]}.pp" end end
# File lib/puppet/provider/selmodule/semodule.rb, line 75 def selmod_readnext (handle) len = handle.read(4).unpack('L')[0] handle.read(len) end
# File lib/puppet/provider/selmodule/semodule.rb, line 80 def selmodversion_file magic = 0xF97CFF8F filename = selmod_name_to_filename mod = File.new(filename, "r") (hdr, ver, numsec) = mod.read(12).unpack('LLL') raise Puppet::Error, "Found #{hdr} instead of magic #{magic} in #{filename}" if hdr != magic raise Puppet::Error, "Unknown policy file version #{ver} in #{filename}" if ver != 1 # Read through (and throw away) the file section offsets, and also # the magic header for the first section. mod.read((numsec + 1) * 4) ## Section 1 should be "SE Linux Module" selmod_readnext(mod) selmod_readnext(mod) # Skip past the section headers mod.read(14) # Module name selmod_readnext(mod) # At last! the version v = selmod_readnext(mod) self.debug "file version #{v}" v end
# File lib/puppet/provider/selmodule/semodule.rb, line 116 def selmodversion_loaded lines = () begin execpipe("#{command(:semodule)} --list") do |output| output.each_line do |line| line.chomp! bits = line.split if bits[0] == @resource[:name] self.debug "load version #{bits[1]}" return bits[1] end end end rescue Puppet::ExecutionFailure raise Puppet::ExecutionFailure, "Could not list policy modules: #{lines.join(' ').chomp!}" end nil end
Send the email reports.
# File lib/puppet/reports/tagmail.rb, line 132 def send(reports) pid = Puppet::Util.safe_posix_fork do if Puppet[:smtpserver] != "none" begin Net::SMTP.start(Puppet[:smtpserver]) do |smtp| reports.each do |emails, messages| smtp.open_message_stream(Puppet[:reportfrom], *emails) do |p| p.puts "From: #{Puppet[:reportfrom]}" p.puts "Subject: Puppet Report for #{self.host}" p.puts "To: " + emails.join(", ") p.puts "Date: #{Time.now.rfc2822}" p.puts p.puts messages end end end rescue => detail message = "Could not send report emails through smtp: #{detail}" Puppet.log_exception(detail, message) raise Puppet::Error, message end elsif Puppet[:sendmail] != "" begin reports.each do |emails, messages| # We need to open a separate process for every set of email addresses IO.popen(Puppet[:sendmail] + " " + emails.join(" "), "w") do |p| p.puts "From: #{Puppet[:reportfrom]}" p.puts "Subject: Puppet Report for #{self.host}" p.puts "To: " + emails.join(", ") p.puts messages end end rescue => detail message = "Could not send report emails via sendmail: #{detail}" Puppet.log_exception(detail, message) raise Puppet::Error, message end else raise Puppet::Error, "SMTP server is unset and could not find sendmail" end end # Don't bother waiting for the pid to return. Process.detach(pid) end
returns the full path of this service when enabled (ie in the service directory)
# File lib/puppet/provider/service/daemontools.rb, line 104 def service File.join(self.servicedir, resource[:name]) end
Extract service name
# File lib/puppet/provider/service/freebsd.rb, line 31 def service_name name = self.rcvar[0] self.error("No service name found in rcvar") if name.nil? name = name.gsub!(/# (.*)/, '\1') self.error("Service name is empty") if name.nil? self.debug("Service name is #{name}") name end
find the service dir on this node
# File lib/puppet/provider/service/daemontools.rb, line 89 def servicedir unless @servicedir ["/service", "/etc/service","/var/lib/svscan"].each do |path| if FileTest.exist?(path) @servicedir = path break end end raise "Could not find service directory" unless @servicedir end @servicedir end
# File lib/puppet/provider/augeas/augeas.rb, line 307 def set_augeas_save_mode(mode) @aug.set("/augeas/save", mode) end
# File lib/puppet/provider/macauthorization/macauthorization.rb, line 179 def set_right(name, values) # Both creates and modifies rights as it simply overwrites them. # The security binary only allows for writes using stdin, so we # dump the values to a tempfile. values = convert_plist_to_native_attributes(values) tmp = Tempfile.new('puppet_macauthorization') begin Plist::Emit.save_plist(values, tmp.path) cmds = [] cmds << :security << "authorizationdb" << "write" << name output = execute(cmds, :failonfail => false, :combine => false, :stdinfile => tmp.path.to_s) rescue Errno::EACCES => e raise Puppet::Error.new("Cannot save right to #{tmp.path}: #{e}") ensure tmp.close tmp.unlink end end
# File lib/puppet/provider/macauthorization/macauthorization.rb, line 198 def set_rule(name, values) # Both creates and modifies rules as it overwrites the entry in the # rules dictionary. Unfortunately the security binary doesn't # support modifying rules at all so we have to twiddle the whole # plist... :( See Apple Bug #6386000 values = convert_plist_to_native_attributes(values) authdb = Plist::parse_xml(AuthDB) authdb["rules"][name] = values begin Plist::Emit.save_plist(authdb, AuthDB) rescue raise Puppet::Error.new("Error writing to: #{AuthDB}") end end
This method accepts a passed value and one of three fields: ‘salt’, ‘entropy’, or ‘iterations’. These fields correspond with the fields utilized in a PBKDF2 password hashing system (see en.wikipedia.org/wiki/PBKDF2 ) where ‘entropy’ is the password hash, ‘salt’ is the password hash salt value, and ‘iterations’ is an integer recommended to be > 10,000. The remaining arguments are the user’s plist itself, and the shadow_hash_data hash containing the existing PBKDF2 values.
# File lib/puppet/provider/user/directoryservice.rb, line 610 def set_salted_pbkdf2(users_plist, shadow_hash_data, field, value) shadow_hash_data = Hash.new unless shadow_hash_data shadow_hash_data['SALTED-SHA512-PBKDF2'] = Hash.new unless shadow_hash_data['SALTED-SHA512-PBKDF2'] case field when 'salt', 'entropy' shadow_hash_data['SALTED-SHA512-PBKDF2'][field] = new_stringio_object unless shadow_hash_data['SALTED-SHA512-PBKDF2'][field] shadow_hash_data['SALTED-SHA512-PBKDF2'][field].string = base64_decode_string(value) when 'iterations' shadow_hash_data['SALTED-SHA512-PBKDF2'][field] = Integer(value) else raise Puppet::Error "Puppet has tried to set an incorrect field for the 'SALTED-SHA512-PBKDF2' hash. Acceptable fields are 'salt', 'entropy', or 'iterations'." end # on 10.8, this field *must* contain 8 stars, or authentication will # fail. users_plist['passwd'] = ('*' * 8) # Convert shadow_hash_data to a binary plist, and call the # set_shadow_hash_data method to serialize and write the data # back to the user's plist. binary_plist = self.class.convert_xml_to_binary(shadow_hash_data) set_shadow_hash_data(users_plist, binary_plist) end
Puppet requires a salted-sha512 password hash for 10.7 users to be passed in Hex, but the embedded plist stores that value as a Base64 encoded string. This method converts the string and calls the #set_shadow_hash_data method to serialize and write the plist to disk.
# File lib/puppet/provider/user/directoryservice.rb, line 592 def set_salted_sha512(users_plist, shadow_hash_data, value) unless shadow_hash_data shadow_hash_data = Hash.new shadow_hash_data['SALTED-SHA512'] = new_stringio_object end shadow_hash_data['SALTED-SHA512'].string = base64_decode_string(value) binary_plist = self.class.convert_xml_to_binary(shadow_hash_data) set_shadow_hash_data(users_plist, binary_plist) end
This method will embed the binary plist data comprising the user’s password hash (and Salt/Iterations value if the OS is 10.8 or greater) into the ShadowHashData key of the user’s plist.
# File lib/puppet/provider/user/directoryservice.rb, line 563 def set_shadow_hash_data(users_plist, binary_plist) if users_plist.has_key?('ShadowHashData') users_plist['ShadowHashData'][0].string = binary_plist else users_plist['ShadowHashData'] = [new_stringio_object(binary_plist)] end write_users_plist_to_disk(users_plist) end
Set the checksum, from another property. There are multiple properties that modify the contents of a file, and they need the ability to make sure that the checksum value is in sync.
# File lib/puppet/type/file.rb, line 640 def setchecksum(sum = nil) if @parameters.include? :checksum if sum @parameters[:checksum].checksum = sum else # If they didn't pass in a sum, then tell checksum to # figure it out. currentvalue = @parameters[:checksum].retrieve @parameters[:checksum].checksum = currentvalue end end end
Execute a configuration string. Can’t be private because it’s called by the properties.
# File lib/puppet/provider/zone/solaris.rb, line 250 def setconfig(str) add_cmd str end
Take the results of a listing and set everything appropriately.
# File lib/puppet/type/zone.rb, line 360 def setstatus(hash) prophash = {} hash.each do |param, value| next if param == :name case self.class.attrtype(param) when :property # Only try to provide values for the properties we're managing prop = self.property(param) prophash[prop] = value if prop else self[param] = value end end prophash end
JJM Yes, this is not DRY at all. Because of the code blocks autorequire must be done this way. I think.
# File lib/puppet/type/mcx.rb, line 74 def setup_autorequire(type) # value returns a Symbol name = value(:name) ds_type = value(:ds_type) ds_name = value(:ds_name) if ds_type == type rval = [ ds_name.to_s ] else rval = [ ] end rval end
# File lib/puppet/provider/service/daemontools.rb, line 127 def setupservice if resource[:manifest] Puppet.notice "Configuring #{resource[:name]}" command = [ resource[:manifest], resource[:name] ] #texecute("setupservice", command) rv = system("#{command}") end rescue Puppet::ExecutionFailure => detail raise Puppet::Error.new( "Cannot config #{self.service} to enable it: #{detail}" ) end
Read in /etc/shadow, find the line for this user (skipping comments, because who knows) and return it No abstraction, all esoteric knowledge of file formats, yay
# File lib/puppet/provider/user/user_role_add.rb, line 159 def shadow_entry return @shadow_entry if defined? @shadow_entry @shadow_entry = File.readlines(target_file_path). reject { |r| r =~ /^[^\w]/ }. collect { |l| l.chomp.split(':') }. find { |user, _| user == @resource[:name] } end
# File lib/puppet/provider/package/msi.rb, line 128 def shell_quote(value) value.include?(' ') ? %Q["#{value.gsub(/"/, '\"')}"] : value end
# File lib/puppet/type/cron.rb, line 216 def should if @should if @should.is_a? Array @should[0] else devfail "command is not an array" end else nil end end
Should this thing be a normal file? This is a relatively complex way of determining whether we’re trying to create a normal file, and it’s here so that the logic isn’t visible in the content property.
# File lib/puppet/type/file.rb, line 656 def should_be_file? return true if self[:ensure] == :file # I.e., it's set to something like "directory" return false if e = self[:ensure] and e != :present # The user doesn't really care, apparently if self[:ensure] == :present return true unless s = stat return(s.ftype == "file" ? true : false) end # If we've gotten here, then :ensure isn't set return true if self[:content] return true if stat and stat.ftype == "file" false end
# File lib/puppet/type/cron.rb, line 327 def should_to_s(newvalue = @should) if newvalue newvalue.join(",") else nil end end
The hidden singleton lurks behind everyone
# File lib/puppet/util/metaid.rb, line 3 def singleton_class; class << self; self; end; end
# File lib/puppet/type/cron.rb, line 234 def specials %w{reboot yearly annually monthly weekly daily midnight hourly} end
# File lib/puppet/provider/package/hpux.rb, line 41 def standard_args ["-x", "mount_all_filesystems=false"] end
Run the ‘start’ parameter command, or the specified ‘startcmd’.
# File lib/puppet/provider/service/base.rb, line 64 def start ucommand(:start) end
The command used to start. Generated if the ‘binary’ argument is passed.
# File lib/puppet/provider/service/base.rb, line 70 def startcmd if @resource[:binary] return @resource[:binary] else raise Puppet::Error, "Services must specify a start command or a binary" end end
Stat our file. Depending on the value of the ‘links’ attribute, we use either ‘stat’ or ‘lstat’, and we expect the properties to use the resulting stat object accordingly (mostly by testing the ‘ftype’ value).
We use the initial value :needs_stat to ensure we only stat the file once, but can also keep track of a failed stat (@stat == nil). This also allows us to re-stat on demand by setting @stat = :needs_stat.
# File lib/puppet/type/file.rb, line 682 def stat return @stat unless @stat == :needs_stat method = :stat # Files are the only types that support links if (self.class.name == :file and self[:links] != :follow) or self.class.name == :tidy method = :lstat end @stat = begin ::File.send(method, self[:path]) rescue Errno::ENOENT => error nil rescue Errno::ENOTDIR => error nil rescue Errno::EACCES => error warning "Could not stat; permission denied" nil end end
Check if the process is running. Prefer the ‘status’ parameter, then ‘statuscmd’ method, then look in the process table. We give the object the option to not return a status command, which might happen if, for instance, it has an init script (and thus responds to ‘statuscmd’) but does not have ‘hasstatus’ enabled.
# File lib/puppet/provider/service/base.rb, line 40 def status if @resource[:status] or statuscmd # Don't fail when the exit status is not 0. ucommand(:status, false) # Expicitly calling exitstatus to facilitate testing if $CHILD_STATUS.exitstatus == 0 return :running else return :stopped end elsif pid = self.getpid self.debug "PID is #{pid}" return :running else return :stopped end end
There is no default command, which causes other methods to be used
# File lib/puppet/provider/service/base.rb, line 60 def statuscmd end
Stop the service. If a ‘stop’ parameter is specified, it takes precedence; otherwise checks if the object responds to a ‘stopcmd’ method, and if so runs that; otherwise, looks for the process in the process table. This method will generally not be overridden by submodules.
# File lib/puppet/provider/service/base.rb, line 84 def stop if @resource[:stop] or stopcmd ucommand(:stop) else pid = getpid unless pid self.info "#{self.name} is not running" return false end begin output = kill pid rescue Puppet::ExecutionFailure => detail @resource.fail "Could not kill #{self.name}, PID #{pid}: #{output}" end return true end end
There is no default command, which causes other methods to be used
# File lib/puppet/provider/service/base.rb, line 103 def stopcmd end
# File lib/puppet/type/file/checksum.rb, line 16 def sum(content) type = value || :md5 # because this might be called before defaults are set "{#{type}}" + send(type, content) end
# File lib/puppet/type/file/checksum.rb, line 21 def sum_file(path) type = value || :md5 # because this might be called before defaults are set method = type.to_s + "_file" "{#{type}}" + send(method, path).to_s end
# File lib/puppet/type/file/checksum.rb, line 27 def sum_stream(&block) type = value || :md5 # same comment as above method = type.to_s + "_stream" checksum = send(method, &block) "{#{type}}#{checksum}" end
Unlike core’s yaml, ZAML should support 1.8.1 just fine
# File lib/puppet/network/formats.rb, line 24 def supported?(klass) true end
Actually execute the command.
# File lib/puppet/type/augeas.rb, line 217 def sync @resource.provider.execute_changes end
# File lib/puppet/provider/selmodule/semodule.rb, line 33 def syncversion self.debug "Checking syncversion on #{@resource[:name]}" loadver = selmodversion_loaded if(loadver) then filever = selmodversion_file if (filever == loadver) return :true end end :false end
# File lib/puppet/provider/selmodule/semodule.rb, line 47 def syncversion= (dosync) execoutput("#{command(:semodule)} --upgrade #{selmod_name_to_filename}") rescue Puppet::ExecutionFailure => detail raise Puppet::Error, "Could not upgrade policy module: #{detail}"; end
# File lib/puppet/type/resources.rb, line 128 def system_users %w{root nobody bin noaccess daemon sys} end
This helper makes it possible to test this on stub data without having to do too many crazy things!
# File lib/puppet/provider/user/user_role_add.rb, line 152 def target_file_path "/etc/shadow" end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 34 def task return @task if @task @task ||= Win32::TaskScheduler.new @task.activate(resource[:name] + '.job') if exists? @task end
# File lib/puppet/face/help.rb, line 108 def template_for(face, action) if action.nil? erb('face.erb') else erb('action.erb') end end
A simple wrapper so execution failures are a bit more informative.
# File lib/puppet/provider/service/service.rb, line 23 def texecute(type, command, fof = true) begin # #565: Services generally produce no output, so squelch them. execute(command, :failonfail => fof, :override_locale => false, :squelch => true) rescue Puppet::ExecutionFailure => detail @resource.fail "Could not #{type} #{@resource.ref}: #{detail}" end nil end
Does a given path match our glob patterns, if any? Return true if no patterns have been provided.
# File lib/puppet/type/tidy.rb, line 83 def tidy?(path, stat) basename = File.basename(path) flags = File::FNM_DOTMATCH | File::FNM_PATHNAME return(value.find {|pattern| File.fnmatch(pattern, basename, flags) } ? true : false) end
Unfortunately, RRD does not deal well with changing lists of values, so we have to pick a list of values and stick with it. In this case, that means we record the total time, the config time, and that’s about it. We should probably send each type’s time as a separate metric.
# File lib/puppet/reports/rrdgraph.rb, line 124 def timeclean(metric) metric.values = metric.values.find_all { |name, label, value| ['total', 'config_retrieval'].include?(name.to_s) } end
We want our title to just be the whole reference, rather than @title.
# File lib/puppet/type/component.rb, line 61 def title ref end
# File lib/puppet/type/component.rb, line 65 def title=(str) @reference = Puppet::Resource.new(str) end
# File lib/puppet/provider/mailalias/aliases.rb, line 31 def to_line(record) dest = record[:recipient].collect do |d| # Quote aliases that have non-alpha chars if d =~ /[^-\w@.]/ '"%s"' % d else d end end.join(",") "#{record[:name]}: #{dest}" end
# File lib/puppet/util/log/destinations.rb, line 228 def to_native(level) case level when :debug,:info,:notice [Win32::EventLog::INFO, 0x01] when :warning [Win32::EventLog::WARN, 0x02] when :err,:alert,:emerg,:crit [Win32::EventLog::ERROR, 0x03] end end
# File lib/puppet/type/file.rb, line 704 def to_resource resource = super resource.delete(:target) if resource[:target] == :notlink resource end
# File lib/puppet/type/component.rb, line 78 def to_s reference.to_s end
# File lib/puppet/util/monkey_patches.rb, line 38 def to_yaml(ignored=nil) ZAML.dump(self) end
# File lib/puppet/util/zaml.rb, line 173 def to_yaml_properties instance_variables # default YAML behaviour. end
# File lib/puppet/util/zaml.rb, line 183 def to_zaml(z) z.first_time_only(self) { z.emit(zamlized_class_name(Object)) z.nested { instance_variables = to_yaml_properties if instance_variables.empty? z.emit(" {}") else instance_variables.each { |v| z.nl v.to_s[1..-1].to_zaml(z) # Remove leading '@' z.emit(': ') yaml_property_munge(instance_variable_get(v)).to_zaml(z) } end } } end
# File lib/puppet/provider/user/user_role_add.rb, line 73 def transition(type) cmd = [command(:modify)] cmd << "-K" << "type=#{type}" cmd += add_properties cmd << @resource[:name] end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 283 def translate_hash_to_trigger(puppet_trigger, user_provided_input=false) trigger = dummy_time_trigger if user_provided_input self.fail "'enabled' is read-only on triggers" if puppet_trigger.has_key?('enabled') self.fail "'index' is read-only on triggers" if puppet_trigger.has_key?('index') end puppet_trigger.delete('index') if puppet_trigger.delete('enabled') == false trigger['flags'] |= Win32::TaskScheduler::TASK_TRIGGER_FLAG_DISABLED else trigger['flags'] &= ~Win32::TaskScheduler::TASK_TRIGGER_FLAG_DISABLED end extra_keys = puppet_trigger.keys.sort - ['schedule', 'start_date', 'start_time', 'every', 'months', 'on', 'which_occurrence', 'day_of_week'] self.fail "Unknown trigger option(s): #{Puppet::Parameter.format_value_for_display(extra_keys)}" unless extra_keys.empty? self.fail "Must specify 'start_time' when defining a trigger" unless puppet_trigger['start_time'] case puppet_trigger['schedule'] when 'daily' trigger['trigger_type'] = Win32::TaskScheduler::DAILY trigger['type'] = { 'days_interval' => Integer(puppet_trigger['every'] || 1) } when 'weekly' trigger['trigger_type'] = Win32::TaskScheduler::WEEKLY trigger['type'] = { 'weeks_interval' => Integer(puppet_trigger['every'] || 1) } trigger['type']['days_of_week'] = if puppet_trigger['day_of_week'] bitfield_from_days_of_week(puppet_trigger['day_of_week']) else scheduler_days_of_week.inject(0) {|day_flags,day| day_flags |= day} end when 'monthly' trigger['type'] = { 'months' => bitfield_from_months(puppet_trigger['months'] || (1..12).to_a), } if puppet_trigger.keys.include?('on') if puppet_trigger.has_key?('day_of_week') or puppet_trigger.has_key?('which_occurrence') self.fail "Neither 'day_of_week' nor 'which_occurrence' can be specified when creating a monthly date-based trigger" end trigger['trigger_type'] = Win32::TaskScheduler::MONTHLYDATE trigger['type']['days'] = bitfield_from_days(puppet_trigger['on']) elsif puppet_trigger.keys.include?('which_occurrence') or puppet_trigger.keys.include?('day_of_week') self.fail 'which_occurrence cannot be specified as an array' if puppet_trigger['which_occurrence'].is_a?(Array) %w{day_of_week which_occurrence}.each do |field| self.fail "#{field} must be specified when creating a monthly day-of-week based trigger" unless puppet_trigger.has_key?(field) end trigger['trigger_type'] = Win32::TaskScheduler::MONTHLYDOW trigger['type']['weeks'] = occurrence_name_to_constant(puppet_trigger['which_occurrence']) trigger['type']['days_of_week'] = bitfield_from_days_of_week(puppet_trigger['day_of_week']) else self.fail "Don't know how to create a 'monthly' schedule with the options: #{puppet_trigger.keys.sort.join(', ')}" end when 'once' self.fail "Must specify 'start_date' when defining a one-time trigger" unless puppet_trigger['start_date'] trigger['trigger_type'] = Win32::TaskScheduler::ONCE else self.fail "Unknown schedule type: #{puppet_trigger["schedule"].inspect}" end if start_date = puppet_trigger['start_date'] start_date = Date.parse(start_date) self.fail "start_date must be on or after 1753-01-01" unless start_date >= Date.new(1753, 1, 1) trigger['start_year'] = start_date.year trigger['start_month'] = start_date.month trigger['start_day'] = start_date.day end start_time = Time.parse(puppet_trigger['start_time']) trigger['start_hour'] = start_time.hour trigger['start_minute'] = start_time.min trigger end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 70 def trigger return @triggers if @triggers @triggers = [] task.trigger_count.times do |i| trigger = begin task.trigger(i) rescue Win32::TaskScheduler::Error => e # Win32::TaskScheduler can't handle all of the # trigger types Windows uses, so we need to skip the # unhandled types to prevent "puppet resource" from # blowing up. nil end next unless trigger and scheduler_trigger_types.include?(trigger['trigger_type']) puppet_trigger = {} case trigger['trigger_type'] when Win32::TaskScheduler::TASK_TIME_TRIGGER_DAILY puppet_trigger['schedule'] = 'daily' puppet_trigger['every'] = trigger['type']['days_interval'].to_s when Win32::TaskScheduler::TASK_TIME_TRIGGER_WEEKLY puppet_trigger['schedule'] = 'weekly' puppet_trigger['every'] = trigger['type']['weeks_interval'].to_s puppet_trigger['on'] = days_of_week_from_bitfield(trigger['type']['days_of_week']) when Win32::TaskScheduler::TASK_TIME_TRIGGER_MONTHLYDATE puppet_trigger['schedule'] = 'monthly' puppet_trigger['months'] = months_from_bitfield(trigger['type']['months']) puppet_trigger['on'] = days_from_bitfield(trigger['type']['days']) when Win32::TaskScheduler::TASK_TIME_TRIGGER_MONTHLYDOW puppet_trigger['schedule'] = 'monthly' puppet_trigger['months'] = months_from_bitfield(trigger['type']['months']) puppet_trigger['which_occurrence'] = occurrence_constant_to_name(trigger['type']['weeks']) puppet_trigger['day_of_week'] = days_of_week_from_bitfield(trigger['type']['days_of_week']) when Win32::TaskScheduler::TASK_TIME_TRIGGER_ONCE puppet_trigger['schedule'] = 'once' end puppet_trigger['start_date'] = self.class.normalized_date("#{trigger['start_year']}-#{trigger['start_month']}-#{trigger['start_day']}") puppet_trigger['start_time'] = self.class.normalized_time("#{trigger['start_hour']}:#{trigger['start_minute']}") puppet_trigger['enabled'] = trigger['flags'] & Win32::TaskScheduler::TASK_TRIGGER_FLAG_DISABLED == 0 puppet_trigger['index'] = i @triggers << puppet_trigger end @triggers = @triggers[0] if @triggers.length == 1 @triggers end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 167 def trigger=(value) desired_triggers = value.is_a?(Array) ? value : [value] current_triggers = trigger.is_a?(Array) ? trigger : [trigger] extra_triggers = [] desired_to_search = desired_triggers.dup current_triggers.each do |current| if found = desired_to_search.find {|desired| triggers_same?(current, desired)} desired_to_search.delete(found) else extra_triggers << current['index'] end end needed_triggers = [] current_to_search = current_triggers.dup desired_triggers.each do |desired| if found = current_to_search.find {|current| triggers_same?(current, desired)} current_to_search.delete(found) else needed_triggers << desired end end extra_triggers.reverse_each do |index| task.delete_trigger(index) end needed_triggers.each do |trigger_hash| # Even though this is an assignment, the API for # Win32::TaskScheduler ends up appending this trigger to the # list of triggers for the task, while #add_trigger is only able # to replace existing triggers. *shrug* task.trigger = translate_hash_to_trigger(trigger_hash) end end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 131 def trigger_insync?(current, should) should = [should] unless should.is_a?(Array) current = [current] unless current.is_a?(Array) return false unless current.length == should.length current_in_sync = current.all? do |c| should.any? {|s| triggers_same?(c, s)} end should_in_sync = should.all? do |s| current.any? {|c| triggers_same?(c,s)} end current_in_sync && should_in_sync end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 239 def triggers_same?(current_trigger, desired_trigger) return false unless current_trigger['schedule'] == desired_trigger['schedule'] return false if current_trigger.has_key?('enabled') && !current_trigger['enabled'] desired = desired_trigger.dup desired['every'] ||= current_trigger['every'] if current_trigger.has_key?('every') desired['months'] ||= current_trigger['months'] if current_trigger.has_key?('months') desired['on'] ||= current_trigger['on'] if current_trigger.has_key?('on') desired['day_of_week'] ||= current_trigger['day_of_week'] if current_trigger.has_key?('day_of_week') translate_hash_to_trigger(current_trigger) == translate_hash_to_trigger(desired) end
# File lib/puppet/face/node/clean.rb, line 150 def type_is_ensurable(resource) if (type = Puppet::Type.type(resource.restype)) && type.validattr?(:ensure) return true else type = environment.known_resource_types.find_definition('', resource.restype) return true if type && type.arguments.keys.include?('ensure') end return false end
Use either a specified command or the default for our provider.
# File lib/puppet/provider/service/service.rb, line 34 def ucommand(type, fof = true) if c = @resource[type] cmd = [c] else cmd = [send("#{type}cmd")].flatten end texecute(type, cmd, fof) end
# File lib/puppet/provider/user/windows_adsi.rb, line 81 def uid Puppet::Util::Windows::Security.name_to_sid(@resource[:name]) end
We use users and groups interchangeably, so use the same methods for both (the type expects different methods, so we have to oblige).
# File lib/puppet/provider/file/posix.rb, line 11 def uid2name(id) return id.to_s if id.is_a?(Symbol) or id.is_a?(String) return nil if id > Puppet[:maximum_uid].to_i begin user = Etc.getpwuid(id) rescue TypeError, ArgumentError return nil end if user.uid == "" return nil else return user.name end end
# File lib/puppet/provider/user/windows_adsi.rb, line 85 def uid=(value) fail "uid is read-only" end
# File lib/puppet/provider/service/upstart.rb, line 285 def unbalanced_parens_on(line) line.count('(') - line.count(')') end
# File lib/puppet/provider/service/upstart.rb, line 273 def uncomment(line) line.gsub(/^(\s*)#+/, '\1') end
# File lib/puppet/provider/service/upstart.rb, line 306 def uncomment_start_block_in(text) parens = 0 text.lines.map do |line| if line.match(COMMENTED_START_ON) || parens > 0 parens += unbalanced_parens_on(remove_trailing_comments_from_commented_line_of(line)) uncomment(line) else line end end.join('') end
# File lib/puppet/provider/zone/solaris.rb, line 306 def unconfigure zonecfg :delete, "-F" end
# File lib/puppet/face/node/clean.rb, line 118 def unexport(node) # fetch all exported resource query = {:include => {:param_values => :param_name}} query[:conditions] = [ "exported=? AND host_id=?", true, node.id ] Puppet::Rails::Resource.find(:all, query).each do |resource| if type_is_ensurable(resource) line = 0 param_name = Puppet::Rails::ParamName.find_or_create_by_name("ensure") if ensure_param = resource.param_values.find( :first, :conditions => [ 'param_name_id = ?', param_name.id ] ) line = ensure_param.line.to_i Puppet::Rails::ParamValue.delete(ensure_param.id); end # force ensure parameter to "absent" resource.param_values.create( :value => "absent", :line => line, :param_name => param_name ) Puppet.info("#{resource.name} has been marked as \"absent\"") end end end
# File lib/puppet/provider/package/dpkg.rb, line 144 def unhold Tempfile.open('puppet_dpkg_set_selection') do |tmpfile| tmpfile.write("#{@resource[:name]} install\n") tmpfile.flush execute([:dpkg, "--set-selections"], :failonfail => false, :combine => false, :stdinfile => tmpfile.path.to_s) end end
# File lib/puppet/provider/package/aix.rb, line 59 def uninstall # Automatically process dependencies when installing/uninstalling # with the -g option to installp. installp "-gu", @resource[:name] end
# File lib/puppet/provider/package/msi.rb, line 124 def uninstall_options join_options(resource[:uninstall_options]) end
Are we moving up the property tree?
# File lib/puppet/type/zone.rb, line 124 def up? self.class.fsm.cmp?(self.retrieve, self.should) end
# File lib/puppet/provider/package/aix.rb, line 125 def update self.install(false) end
# File lib/puppet/provider/service/upstart.rb, line 66 def upstart_version @upstart_version ||= initctl("--version").match(/initctl \(upstart ([^\)]*)\)/)[1] end
# File lib/puppet/network/formats.rb, line 35 def use_zlib? Puppet.features.zlib? && Puppet[:zlib] end
# File lib/puppet/provider/cron/crontab.rb, line 196 def user @property_hash[:user] || @property_hash[:target] end
# File lib/puppet/provider/cron/crontab.rb, line 191 def user=(user) @property_hash[:user] = user @property_hash[:target] = user end
# File lib/puppet/provider/user/user_role_add.rb, line 50 def user_attributes @user_attributes ||= UserAttr.get_attributes_by_name(@resource[:name]) end
Make sure we don’t purge users below a certain uid, if the check is enabled.
# File lib/puppet/type/resources.rb, line 116 def user_check(resource) return true unless self[:name] == "user" return true unless self[:unless_system_user] resource[:audit] = :uid return false if system_users.include?(resource[:name]) current_values = resource.retrieve_resource current_values[resource.property(:uid)] > self[:unless_system_user] end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 119 def user_insync?(current, should) return false unless current # Win32::TaskScheduler can return the 'SYSTEM' account as the # empty string. current = 'system' if current == '' # By comparing account SIDs we don't have to worry about case # sensitivity, or canonicalization of the account name. Puppet::Util::Windows::Security.name_to_sid(current) == Puppet::Util::Windows::Security.name_to_sid(should[0]) end
Force convert users it a list.
# File lib/puppet/provider/group/aix.rb, line 136 def users_from_attr(value) (value.is_a? String) ? value.split(',') : value end
##
Helper Methods ##
##
# File lib/puppet/provider/user/directoryservice.rb, line 476 def users_plist_dir '/var/db/dslocal/nodes/Default/users' end
# File lib/puppet/provider/file/windows.rb, line 83 def validate if [:owner, :group, :mode].any?{|p| resource[p]} and !supports_acl?(resource[:path]) resource.fail("Can only manage owner, group, and mode on filesystems that support Windows ACLs, such as NTFS") end end
Should we validate the checksum of the file we’re writing?
# File lib/puppet/type/file.rb, line 750 def validate_checksum? self[:checksum] !~ /time/ end
# File lib/puppet/type/zone.rb, line 326 def validate_exclusive(interface, address, router) return if !interface.nil? and address.nil? self.fail "only interface may be specified when using exclusive IP stack: #{interface}:#{address}" end
# File lib/puppet/reports/store.rb, line 67 def validate_host(host) if host =~ Regexp.union(/[#{SEPARATOR}]/, /\A\.\.?\Z/) raise ArgumentError, "Invalid node name #{host.inspect}" end end
# File lib/puppet/type/zone.rb, line 320 def validate_ip(ip, name) IPAddr.new(ip) if ip rescue ArgumentError self.fail "'#{ip}' is an invalid #{name}" end
# File lib/puppet/provider/package/msi.rb, line 116 def validate_source(value) fail("The source parameter cannot be empty when using the MSI provider.") if value.empty? end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 367 def validate_trigger(value) value = [value] unless value.is_a?(Array) # translate_hash_to_trigger handles the same validation that we # would be doing here at the individual trigger level. value.each {|t| translate_hash_to_trigger(t, true)} true end
# File lib/puppet/provider/exec/shell.rb, line 22 def validatecmd(command) true end
# File lib/puppet/provider/selboolean/getsetsebool.rb, line 7 def value self.debug "Retrieving value of selboolean #{@resource[:name]}" status = getsebool(@resource[:name]) if status =~ / off$/ return :off elsif status =~ / on$/ then return :on else status.chomp! raise Puppet::Error, "Invalid response '#{status}' returned from getsebool" end end
# File lib/puppet/provider/selboolean/getsetsebool.rb, line 22 def value=(new) persist = "" if @resource[:persistent] == :true self.debug "Enabling persistence" persist = "-P" end execoutput("#{command(:setsebool)} #{persist} #{@resource[:name]} #{new}") :file_changed end
# File lib/puppet/type/interface.rb, line 101 def value_to_s(value) value = [value] unless value.is_a?(Array) value.map{ |v| "#{v[1].to_s}/#{v[0]} #{v[2]}"}.join(",") end
Check that a group exists and is valid
# File lib/puppet/provider/user/aix.rb, line 167 def verify_group(value) if value.is_a? Integer or value.is_a? Fixnum groupname = self.groupname_by_id(value) raise ArgumentError, "AIX group must be a valid existing group" unless groupname else raise ArgumentError, "AIX group must be a valid existing group" unless groupid_by_name(value) groupname = value end groupname end
# File lib/puppet/provider/service/upstart.rb, line 169 def version_is_post_0_9_0 Puppet::Util::Package.versioncmp(upstart_version, "0.9.0") >= 0 end
# File lib/puppet/provider/service/upstart.rb, line 161 def version_is_pre_0_6_7 Puppet::Util::Package.versioncmp(upstart_version, "0.6.7") == -1 end
# File lib/puppet/provider/service/upstart.rb, line 165 def version_is_pre_0_9_0 Puppet::Util::Package.versioncmp(upstart_version, "0.9.0") == -1 end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 60 def working_dir task.working_directory end
# File lib/puppet/provider/scheduled_task/win32_taskscheduler.rb, line 155 def working_dir=(value) task.working_directory = value end
Write out the file. Requires the property name for logging. Write will be done by the content property, along with checksum computation
# File lib/puppet/type/file.rb, line 712 def write(property) remove_existing(:file) use_temporary_file = write_temporary_file? if use_temporary_file path = "#{self[:path]}.puppettmp_#{rand(10000)}" path = "#{self[:path]}.puppettmp_#{rand(10000)}" while ::File.exists?(path) or ::File.symlink?(path) else path = self[:path] end mode = self.should(:mode) # might be nil umask = mode ? 000 : 022 mode_int = mode ? symbolic_mode_to_int(mode, 0644) : nil content_checksum = Puppet::Util.withumask(umask) { ::File.open(path, 'wb', mode_int ) { |f| write_content(f) } } # And put our new file in place if use_temporary_file # This is only not true when our file is empty. begin fail_if_checksum_is_wrong(path, content_checksum) if validate_checksum? ::File.rename(path, self[:path]) rescue => detail fail "Could not rename temporary file #{path} to #{self[:path]}: #{detail}" ensure # Make sure the created file gets removed ::File.unlink(path) if FileTest.exists?(path) end end # make sure all of the modes are actually correct property_fix end
write the current content. Note that if there is no content property simply opening the file with ‘w’ as done in write is enough to truncate or write an empty length file.
# File lib/puppet/type/file.rb, line 765 def write_content(file) (content = property(:content)) && content.write(file) end
This method is only called on version 10.7 or greater. On 10.7 machines, passwords are set using a salted-SHA512 hash, and on 10.8 machines, passwords are set using PBKDF2. It’s possible to have users on 10.8 who have upgraded from 10.7 and thus have a salted-SHA512 password hash. If we encounter this, do what 10.8 does - remove that key and give them a 10.8-style PBKDF2 password.
# File lib/puppet/provider/user/directoryservice.rb, line 518 def write_password_to_users_plist(value) users_plist = get_users_plist(@resource.name) shadow_hash_data = get_shadow_hash_data(users_plist) if self.class.get_os_version == '10.7' set_salted_sha512(users_plist, shadow_hash_data, value) else # It's possible that a user could exist on the system and NOT have # a ShadowHashData key (especially if the system was upgraded from 10.6). # In this case, a conditional check is needed to determine if the # shadow_hash_data variable is a Hash (it would be false if the key # didn't exist for this user on the system). If the shadow_hash_data # variable IS a Hash and contains the 'SALTED-SHA512' key (indicating an # older 10.7-style password hash), it will be deleted and a newer # 10.8-style (PBKDF2) password hash will be generated. if (shadow_hash_data.class == Hash) && (shadow_hash_data.has_key?('SALTED-SHA512')) shadow_hash_data.delete('SALTED-SHA512') end set_salted_pbkdf2(users_plist, shadow_hash_data, 'entropy', value) end end
# File lib/puppet/provider/service/upstart.rb, line 342 def write_script_to(file, text) Puppet::Util.replace_file(file, 0644) do |file| file.write(text) end end
# File lib/puppet/provider/user/directoryservice.rb, line 650 def write_sha1_hash(value) users_guid = self.class.get_attribute_from_dscl('Users', @resource.name, 'GeneratedUID')['dsAttrTypeStandard:GeneratedUID'][0] password_hash_file = "#{self.class.password_hash_dir}/#{users_guid}" write_to_file(password_hash_file, value) # NBK: For shadow hashes, the user AuthenticationAuthority must contain a value of # ";ShadowHash;". The LKDC in 10.5 makes this more interesting though as it # will dynamically generate ;Kerberosv5;;username@LKDC:SHA1 attributes if # missing. Thus we make sure we only set ;ShadowHash; if it is missing, and # we can do this with the merge command. This allows people to continue to # use other custom AuthenticationAuthority attributes without stomping on them. # # There is a potential problem here in that we're only doing this when setting # the password, and the attribute could get modified at other times while the # hash doesn't change and so this doesn't get called at all... but # without switching all the other attributes to merge instead of create I can't # see a simple enough solution for this that doesn't modify the user record # every single time. This should be a rather rare edge case. (famous last words) merge_attribute_with_dscl('Users', @resource.name, 'AuthenticationAuthority', ';ShadowHash;') end
# File lib/puppet/type/file.rb, line 771 def write_temporary_file? # unfortunately we don't know the source file size before fetching it # so let's assume the file won't be empty (c = property(:content) and c.length) || (s = @parameters[:source] and 1) end
This is a simple wrapper method for writing values to a file.
# File lib/puppet/provider/user/directoryservice.rb, line 642 def write_to_file(filename, value) begin File.open(filename, 'w') { |f| f.write(value)} rescue Errno::EACCES => detail raise Puppet::Error, "Could not write to file #{filename}: #{detail}" end end
This method will accept a plist in XML format, save it to disk, convert the plist to a binary format, and flush the dscl cache.
# File lib/puppet/provider/user/directoryservice.rb, line 636 def write_users_plist_to_disk(users_plist) Plist::Emit.save_plist(users_plist, "#{users_plist_dir}/#{@resource.name}.plist") plutil'-convert', 'binary1', "#{users_plist_dir}/#{@resource.name}.plist" end
# File lib/puppet/util/zaml.rb, line 176 def yaml_property_munge(x) x end
If yaourt is installed, we can make use of it
# File lib/puppet/provider/package/pacman.rb, line 16 def yaourt? return File.exists? '/usr/bin/yaourt' end
# File lib/puppet/util/zaml.rb, line 179 def zamlized_class_name(root) cls = self.class "!ruby/#{root.name.downcase}#{cls == root ? '' : ":#{cls.respond_to?(:name) ? cls.name : cls}"}" end
# File lib/puppet/provider/zone/solaris.rb, line 346 def zoneadm(*cmd) adm("-z", @resource[:name], *cmd) rescue Puppet::ExecutionFailure => detail self.fail "Could not #{cmd[0]} zone: #{detail}" end
# File lib/puppet/provider/zone/solaris.rb, line 352 def zonecfg(*cmd) # You apparently can't get the configuration of the global zone (strictly in solaris11) return "" if self.name == "global" begin cfg("-z", self.name, *cmd) rescue Puppet::ExecutionFailure => detail self.fail "Could not #{cmd[0]} zone: #{detail}" end end
on zypper versions <1.0, the version option returns 1 some versions of zypper output on stderr
# File lib/puppet/provider/package/zypper.rb, line 12 def zypper_version cmd = [self.class.command(:zypper),"--version"] execute(cmd, { :failonfail => false, :combine => true}) end