class Object
Make translation methods (e.g. `_()` and `n_()`) available everywhere.
Constants
- AgeConvertors
- BLANK
- COMMENTED_START_ON
- COMMON
- CREATORS
mutually exclusive ways to create files
- DEFAULT_SECTION
- DEFAULT_SECTION_MARKER
- DPKG_QUERY_FORMAT_STRING
- DPKG_QUERY_PROVIDES_FORMAT_STRING
- DebianVersion
- ERROR_SUCCESS
- ERROR_SUCCESS_REBOOT_INITIATED
- ERROR_SUCCESS_REBOOT_REQUIRED
- FIELDS
- FIELDS_REGEX
- FIELDS_REGEX_WITH_PROVIDES
- GEM_VERSION
- GEM_VERSION_RANGE
- HEADER_LINE_REGEX
- INSTALLP_PACKAGE_REGEX
- MANUAL
- MULTIVERSION_SEPARATOR
- NEVRA_FIELDS
- NEVRA_FORMAT
- NEVRA_REGEX
- Namemap
- PACKAGE_LINE_REGEX
- PIP_VERSION
- PIP_VERSION_RANGE
- RPM_PACKAGE_REGEX
- RPM_VERSION
- RPM_VERSION_RANGE
- SEPARATOR
- SHA512_PBKDF2_AUTHENTICATION_AUTHORITY
- SOURCE_ONLY_CHECKSUMS
This is both “checksum types that can't be used with the content property” and “checksum types that are not digest based”
- SPECIALIZED
- START_ON
- STATE_CODE
- STATUSLINE
- VERSION_REGEX
- VersionRange
- WINDOWS_SYSTEM_SID_REGEXES
Public Class Methods
# File lib/puppet/type/file.rb 460 def self.[](path) 461 return nil unless path 462 super(path.gsub(/\/+/, '/').sub(/\/$/, '')) 463 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 64 def self.availlist 65 output = pkguti ["-a"] 66 67 output.split("\n").collect do |line| 68 next if line =~ /^common\s+package/ # header of package list 69 next if noise?(line) 70 71 if line =~ /\s*(\S+)\s+(\S+)\s+(.*)/ 72 { :alias => $1, :name => $2, :avail => $3 } 73 else 74 Puppet.warning _("Cannot match %{line}") % { line: line } 75 end 76 end.reject { |h| h.nil? } 77 end
Turn our blastwave listing into a bunch of hashes.
# File lib/puppet/provider/package/blastwave.rb 36 def self.blastlist(hash) 37 command = ["-c"] 38 39 command << hash[:justme] if hash[:justme] 40 41 output = Puppet::Util.withenv(:PAGER => "/usr/bin/cat") { pkgget command } 42 43 list = output.split("\n").collect do |line| 44 next if line =~ /^#/ 45 next if line =~ /^WARNING/ 46 next if line =~ /localrev\s+remoterev/ 47 48 blastsplit(line) 49 end.reject { |h| h.nil? } 50 51 if hash[:justme] 52 return list[0] 53 else 54 list.reject! { |h| 55 h[:ensure] == :absent 56 } 57 return list 58 end 59 60 end
Split the different lines into hashes.
# File lib/puppet/provider/package/blastwave.rb 63 def self.blastsplit(line) 64 if line =~ /\s*(\S+)\s+((\[Not installed\])|(\S+))\s+(\S+)/ 65 hash = {} 66 hash[:name] = $1 67 hash[:ensure] = if $2 == "[Not installed]" 68 :absent 69 else 70 $2 71 end 72 hash[:avail] = $5 73 74 hash[:avail] = hash[:ensure] if hash[:avail] == "SAME" 75 76 # Use the name method, so it works with subclasses. 77 hash[:provider] = self.name 78 79 return hash 80 else 81 Puppet.warning _("Cannot match %{line}") % { line: line } 82 return nil 83 end 84 end
# File lib/puppet/provider/package/pkgng.rb 25 def self.cached_version_list 26 @version_list ||= get_version_list 27 end
Search for all installed packages that have newer versions, given a combination of repositories to enable and disable.
@api private @param disablerepo [Array<String>] A list of repositories to disable for this query @param enablerepo [Array<String>] A list of repositories to enable for this query @param disableexcludes [Array<String>] A list of repository excludes to disable for this query @return [Hash<String, Array<Hash<String, String>>>] All packages that were
found with a list of found versions for each package.
# File lib/puppet/provider/package/yum.rb 110 def self.check_updates(disablerepo, enablerepo, disableexcludes) 111 args = [command(:cmd), 'check-update'] 112 args.concat(disablerepo.map { |repo| ["--disablerepo=#{repo}"] }.flatten) 113 args.concat(enablerepo.map { |repo| ["--enablerepo=#{repo}"] }.flatten) 114 args.concat(disableexcludes.map { |repo| ["--disableexcludes=#{repo}"] }.flatten) 115 116 output = Puppet::Util::Execution.execute(args, :failonfail => false, :combine => false) 117 118 updates = {} 119 if output.exitstatus == 100 120 updates = parse_updates(output) 121 elsif output.exitstatus == 0 122 self.debug "#{command(:cmd)} check-update exited with 0; no package updates available." 123 else 124 self.warning _("Could not check for updates, '%{cmd} check-update' exited with %{status}") % { cmd: command(:cmd), status: output.exitstatus } 125 end 126 updates 127 end
# File lib/puppet/provider/package/yum.rb 176 def self.clear 177 @latest_versions = nil 178 end
# File lib/puppet/provider/package/pip.rb 38 def self.cmd 39 if Puppet::Util::Platform.windows? 40 ["pip.exe"] 41 else 42 ["pip", "pip-python", "pip2", "pip-2"] 43 end 44 end
# File lib/puppet/provider/package/pip.rb 134 def self.compare_pip_versions(x, y) 135 begin 136 Puppet::Util::Package::Version::Pip.compare(x, y) 137 rescue PIP_VERSION::ValidationFailure => ex 138 Puppet.debug("Cannot compare #{x} and #{y}. #{ex.message} Falling through default comparison mechanism.") 139 Puppet::Util::Package.versioncmp(x, y) 140 end 141 end
This method will accept a binary plist (as a string) and convert it to a hash.
# File lib/puppet/provider/user/directoryservice.rb 194 def self.convert_binary_to_hash(plist_data) 195 Puppet.debug('Converting binary plist to hash') 196 Puppet::Util::Plist.parse_plist(plist_data) 197 end
This method will accept a hash and convert it to a binary plist (string value).
# File lib/puppet/provider/user/directoryservice.rb 188 def self.convert_hash_to_binary(plist_data) 189 Puppet.debug('Converting plist hash to binary') 190 Puppet::Util::Plist.dump_plist(plist_data, :binary) 191 end
# File lib/puppet/provider/package/dnfmodule.rb 25 def self.current_version 26 @current_version ||= dnf('--version').split.first 27 end
returns the daemon dir on this node
# File lib/puppet/provider/service/daemontools.rb 83 def self.daemondir 84 self.defpath 85 end
# File lib/puppet/provider/package/apt.rb 31 def self.defaultto_allow_virtual 32 false 33 end
# File lib/puppet/provider/service/bsd.rb 15 def self.defpath 16 superclass.defpath 17 end
removes all reports for a given host?
# File lib/puppet/reports/store.rb 48 def self.destroy(host) 49 validate_host(host) 50 51 dir = File.join(Puppet[:reportdir], host) 52 53 if Puppet::FileSystem.exist?(dir) 54 Dir.entries(dir).each do |file| 55 next if ['.','..'].include?(file) 56 file = File.join(dir, file) 57 Puppet::FileSystem.unlink(file) if File.file?(file) 58 end 59 Dir.rmdir(dir) 60 end 61 end
Performs a dpkgquery call with a pipe so that output can be processed inline in a passed block. @param args [Array<String>] any command line arguments to be appended to the command @param block expected to be passed on to execpipe @return whatever the block returns @see Puppet::Util::Execution.execpipe @api private
# File lib/puppet/provider/package/dpkg.rb 21 def self.dpkgquery_piped(*args, &block) 22 cmd = args.unshift(command(:dpkgquery)) 23 Puppet::Util::Execution.execpipe(cmd, &block) 24 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 44 def self.ds_to_ns_attribute_map 45 { 46 'RecordName' => :name, 47 'PrimaryGroupID' => :gid, 48 'NFSHomeDirectory' => :home, 49 'UserShell' => :shell, 50 'UniqueID' => :uid, 51 'RealName' => :comment, 52 'Password' => :password, 53 'GeneratedUID' => :guid, 54 'IPAddress' => :ip_address, 55 'ENetAddress' => :en_address, 56 'GroupMembership' => :members, 57 } 58 end
# File lib/puppet/provider/package/portage.rb 292 def self.eix_install_versions_format 293 '{!first}{!last},{}{}{isstable}<version>{}' 294 end
# File lib/puppet/provider/package/portage.rb 288 def self.eix_installed_versions_format 289 '{!first},{}<version>' 290 end
# File lib/puppet/provider/package/portage.rb 296 def self.eix_limit 297 '0' 298 end
# File lib/puppet/provider/package/portage.rb 275 def self.eix_result_fields 276 # ensure:[3.4.5], version_available:[3.5.2], installed_slots:[2.7.12:2.7,3.4.5:3.4], installable_versions:[2.7.10-r1,2.7.12,3.4.3-r1,3.4.5,3.5.2] slot_versions_available:[2.7.12:2.7,3.4.5:3.4,3.5.2:3.5] 277 [:category, :name, :ensure, :version_available, :installed_slots, :installed_versions, :installable_versions, :slot_versions_available, :vendor, :description] 278 end
# File lib/puppet/provider/package/portage.rb 271 def self.eix_result_format 272 /^(\S+)\s+(\S+)\s+\[(\S*)\]\s+\[(\S*)\]\s+\[(\S*)\]\s+\[(\S*)\]\s+\[(\S*)\]\s+\[(\S*)\]\s+(\S+)\s+(.*)$/ 273 end
# File lib/puppet/provider/package/portage.rb 300 def self.eix_search_arguments 301 ['--nocolor', '--pure-packages', '--format', self.eix_search_format] 302 end
# File lib/puppet/provider/package/portage.rb 267 def self.eix_search_format 268 "'<category> <name> [<installedversions:LASTVERSION>] [<bestversion:LASTVERSION>] [<installedversions:LASTSLOTVERSIONS>] [<installedversions:INSTALLEDVERSIONS>] [<availableversions:STABLEVERSIONS>] [<bestslotversions:LASTSLOTVERSIONS>] <homepage> <description>\n'" 269 end
# File lib/puppet/provider/package/portage.rb 284 def self.eix_slot_versions_format 285 '{!first},{}<version>:<slot>' 286 end
# File lib/puppet/provider/package/portage.rb 280 def self.eix_version_format 281 '{last}<version>{}' 282 end
The value to pass to DNF as its error output level. DNF differs from Yum slightly with regards to error outputting.
@param None @return [String]
# File lib/puppet/provider/package/dnf.rb 47 def self.error_level 48 '1' 49 end
some init scripts are not safe to execute, e.g. we do not want to suddenly run /etc/init.d/reboot.sh status and reboot our system. The exclude list could be platform agnostic but I assume an invalid init script on system A will never be a valid init script on system B
# File lib/puppet/provider/service/init.rb 37 def self.excludes 38 excludes = [] 39 # these exclude list was found with grep -L '\/sbin\/runscript' /etc/init.d/* on gentoo 40 excludes += %w{functions.sh reboot.sh shutdown.sh} 41 # this exclude list is all from /sbin/service (5.x), but I did not exclude kudzu 42 excludes += %w{functions halt killall single linuxconf reboot boot} 43 # 'wait-for-state' and 'portmap-wait' are excluded from instances here 44 # because they take parameters that have unclear meaning. It looks like 45 # 'wait-for-state' is a generic waiter mainly used internally for other 46 # upstart services as a 'sleep until something happens' 47 # (http://lists.debian.org/debian-devel/2012/02/msg01139.html), while 48 # 'portmap-wait' is a specific instance of a waiter. There is an open 49 # launchpad bug 50 # (https://bugs.launchpad.net/ubuntu/+source/upstart/+bug/962047) that may 51 # eventually explain how to use the wait-for-state service or perhaps why 52 # it should remain excluded. When that bug is addressed this should be 53 # reexamined. 54 excludes += %w{wait-for-state portmap-wait} 55 # these excludes were found with grep -r -L start /etc/init.d 56 excludes += %w{rcS module-init-tools} 57 # Prevent puppet failing on unsafe scripts from Yocto Linux 58 if Puppet.runtime[:facter].value('os.family') == "cisco-wrlinux" 59 excludes += %w{banner.sh bootmisc.sh checkroot.sh devpts.sh dmesg.sh 60 hostname.sh mountall.sh mountnfs.sh populate-volatile.sh 61 rmnologin.sh save-rtc.sh sendsigs sysfs.sh umountfs 62 umountnfs.sh} 63 end 64 # Prevent puppet failing to get status of the new service introduced 65 # by the fix for this (bug https://bugs.launchpad.net/ubuntu/+source/lightdm/+bug/982889) 66 # due to puppet's inability to deal with upstart services with instances. 67 excludes += %w{plymouth-ready} 68 # Prevent puppet failing to get status of these services, which need parameters 69 # passed in (see https://bugs.launchpad.net/ubuntu/+source/puppet/+bug/1276766). 70 excludes += %w{idmapd-mounting startpar-bridge} 71 # Prevent puppet failing to get status of these services, additional upstart 72 # service with instances 73 excludes += %w{cryptdisks-udev} 74 excludes += %w{statd-mounting} 75 excludes += %w{gssd-mounting} 76 excludes 77 end
CommandDefiner in provider.rb creates convenience execution methods that set failonfail, combine, and optionally, environment. And when a child provider defines its own command via commands() or has_command(), the provider-specific path is always returned by command(). But when the convenience execution method is invoked, the last convenience method to be defined is executed. This makes invoking those convenience execution methods unsuitable for inherited providers.
In this case, causing the puppet_gem provider to inherit the parent gem provider's convenience gemcmd() methods, with the wrong path.
# File lib/puppet/provider/package/gem.rb 73 def self.execute_gem_command(command, command_options, custom_environment = {}) 74 validate_command(command) 75 cmd = [command] << command_options 76 77 custom_environment = {'HOME'=>ENV['HOME']}.merge(custom_environment) 78 79 if Puppet::Util::Platform.windows? 80 custom_environment[:PATH] = windows_path_without_puppet_bin 81 end 82 83 execute(cmd, {:failonfail => true, :combine => true, :custom_environment => custom_environment}) 84 end
The puppetserver gem cli command is very slow, since it starts a JVM.
Instead, for the list subcommand (which is executed with every puppet run), use the rubygems library from puppet ruby: setting GEM_HOME and GEM_PATH to the default values, or the values in the puppetserver configuration file.
The rubygems library cannot access java platform gems, for example: json (1.8.3 java) but java platform gems should not be managed by this (or any) provider.
# File lib/puppet/provider/package/puppetserver_gem.rb 141 def self.execute_rubygems_list_command(command_options) 142 puppetserver_default_gem_home = '/opt/puppetlabs/server/data/puppetserver/jruby-gems' 143 puppetserver_default_vendored_jruby_gems = '/opt/puppetlabs/server/data/puppetserver/vendored-jruby-gems' 144 puppet_default_vendor_gems = '/opt/puppetlabs/puppet/lib/ruby/vendor_gems' 145 puppetserver_default_gem_path = [puppetserver_default_gem_home, puppetserver_default_vendored_jruby_gems, puppet_default_vendor_gems].join(':') 146 147 pe_puppetserver_conf_file = '/etc/puppetlabs/puppetserver/conf.d/pe-puppet-server.conf' 148 os_puppetserver_conf_file = '/etc/puppetlabs/puppetserver/puppetserver.conf' 149 puppetserver_conf_file = Puppet.runtime[:facter].value(:pe_server_version) ? pe_puppetserver_conf_file : os_puppetserver_conf_file 150 puppetserver_conf = Hocon.load(puppetserver_conf_file) 151 152 gem_env = {} 153 if puppetserver_conf.empty? || puppetserver_conf.key?('jruby-puppet') == false 154 gem_env['GEM_HOME'] = puppetserver_default_gem_home 155 gem_env['GEM_PATH'] = puppetserver_default_gem_path 156 else 157 gem_env['GEM_HOME'] = puppetserver_conf['jruby-puppet'].key?('gem-home') ? puppetserver_conf['jruby-puppet']['gem-home'] : puppetserver_default_gem_home 158 gem_env['GEM_PATH'] = puppetserver_conf['jruby-puppet'].key?('gem-path') ? puppetserver_conf['jruby-puppet']['gem-path'].join(':') : puppetserver_default_gem_path 159 end 160 gem_env['GEM_SPEC_CACHE'] = "/tmp/#{$$}" 161 162 # Remove the 'gem' from the command_options 163 command_options.shift 164 gem_out = execute_gem_command(Puppet::Type::Package::ProviderPuppet_gem.provider_command, command_options, gem_env) 165 166 # There is no method exclude default gems from the local gem list, 167 # for example: psych (default: 2.2.2) 168 # but default gems should not be managed by this (or any) provider. 169 gem_list = gem_out.lines.reject { |gem| gem =~ / \(default\: / } 170 gem_list.join("\n") 171 end
# File lib/puppet/provider/user/aix.rb 65 def expires_to_expiry(provider, expires) 66 return :absent if expires == '0' 67 68 unless (match_obj = /\A(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)\z/.match(expires)) 69 #TRANSLATORS 'AIX' is the name of an operating system and should not be translated 70 Puppet.warning(_("Could not convert AIX expires date '%{expires}' on %{class_name}[%{resource_name}]") % { expires: expires, class_name: provider.resource.class.name, resource_name: provider.resource.name }) 71 return :absent 72 end 73 74 month, day, year = match_obj[1], match_obj[2], match_obj[-1] 75 return "20#{year}-#{month}-#{day}" 76 end
# File lib/puppet/provider/user/aix.rb 58 def expiry_to_expires(expiry) 59 return '0' if expiry == "0000-00-00" || expiry.to_sym == :absent 60 61 DateTime.parse(expiry, "%Y-%m-%d %H:%M") 62 .strftime("%m%d%H%M%y") 63 end
# File lib/puppet/provider/package/blastwave.rb 16 def self.extended(mod) 17 unless command(:pkgget) != "pkg-get" 18 raise Puppet::Error, 19 _("The pkg-get command is missing; blastwave packaging unavailable") 20 end 21 22 unless Puppet::FileSystem.exist?("/var/pkg-get/admin") 23 Puppet.notice _("It is highly recommended you create '/var/pkg-get/admin'.") 24 Puppet.notice _("See /var/pkg-get/admin-fullauto") 25 end 26 end
Used by the AIX user provider. Returns a hash of:
{
:name => <group_name>,
:gid => <gid>
}
that matches the group, which can either be the group name or the gid. Takes an optional set of ia_module_args
# File lib/puppet/provider/group/aix.rb 33 def find(group, ia_module_args = []) 34 groups = list_all(ia_module_args) 35 36 id_property = mappings[:puppet_property][:id] 37 38 if group.is_a?(String) 39 # Find by name 40 group_hash = groups.find { |cur_group| cur_group[:name] == group } 41 else 42 # Find by gid 43 group_hash = groups.find do |cur_group| 44 id_property.convert_attribute_value(cur_group[:id]) == group 45 end 46 end 47 48 unless group_hash 49 raise ArgumentError, _("No AIX group exists with a group name or gid of %{group}!") % { group: group } 50 end 51 52 # Convert :id => :gid 53 id = group_hash.delete(:id) 54 group_hash[:gid] = id_property.convert_attribute_value(id) 55 56 group_hash 57 end
# File lib/puppet/provider/package/gem.rb 102 def self.gemlist(options) 103 command_options = ["list"] 104 105 if options[:local] 106 command_options << "--local" 107 else 108 command_options << "--remote" 109 end 110 if options[:source] 111 command_options << "--source" << options[:source] 112 end 113 name = options[:justme] 114 if name 115 command_options << '\A' + name + '\z' 116 end 117 118 begin 119 list = execute_gem_command(options[:command], command_options).lines. 120 map {|set| gemsplit(set) }. 121 reject {|x| x.nil? } 122 rescue Puppet::ExecutionFailure => detail 123 raise Puppet::Error, _("Could not list gems: %{detail}") % { detail: detail }, detail.backtrace 124 end 125 126 if options[:justme] 127 return list.shift 128 else 129 return list 130 end 131 end
# File lib/puppet/provider/package/gem.rb 133 def self.gemsplit(desc) 134 # `gem list` when output console has a line like: 135 # *** LOCAL GEMS *** 136 # but when it's not to the console that line 137 # and all blank lines are stripped 138 # so we don't need to check for them 139 140 if desc =~ /^(\S+)\s+\((.+)\)/ 141 gem_name = $1 142 versions = $2.sub('default: ', '').split(/,\s*/) 143 { 144 :name => gem_name, 145 :ensure => versions.map{|v| v.split[0]}, 146 :provider => name 147 } 148 else 149 Puppet.warning _("Could not match %{desc}") % { desc: desc } unless desc.chomp.empty? 150 nil 151 end 152 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 103 def self.generate_attribute_hash(input_hash) 104 attribute_hash = {} 105 input_hash.each_key do |key| 106 ds_attribute = key.sub("dsAttrTypeStandard:", "") 107 next unless ds_to_ns_attribute_map.keys.include?(ds_attribute) 108 ds_value = input_hash[key] 109 case ds_to_ns_attribute_map[ds_attribute] 110 when :gid, :uid 111 # OS X stores objects like uid/gid as strings. 112 # Try casting to an integer for these cases to be 113 # consistent with the other providers and the group type 114 # validation 115 begin 116 ds_value = Integer(ds_value[0]) 117 rescue ArgumentError 118 ds_value = ds_value[0] 119 end 120 else ds_value = ds_value[0] 121 end 122 attribute_hash[ds_to_ns_attribute_map[ds_attribute]] = ds_value 123 end 124 attribute_hash[:ensure] = :present 125 attribute_hash[:provider] = :directoryservice 126 attribute_hash[:shadowhashdata] = input_hash['dsAttrTypeNative:ShadowHashData'] 127 128 ############## 129 # Get Groups # 130 ############## 131 groups_array = [] 132 get_list_of_groups.each do |group| 133 if group["dsAttrTypeStandard:GroupMembership"] and group["dsAttrTypeStandard:GroupMembership"].include?(attribute_hash[:name]) 134 groups_array << group["dsAttrTypeStandard:RecordName"][0] 135 end 136 137 if group["dsAttrTypeStandard:GroupMembers"] and group["dsAttrTypeStandard:GroupMembers"].include?(attribute_hash[:guid]) 138 groups_array << group["dsAttrTypeStandard:RecordName"][0] 139 end 140 end 141 attribute_hash[:groups] = groups_array.uniq.sort.join(',') 142 143 ################################ 144 # Get Password/Salt/Iterations # 145 ################################ 146 if attribute_hash[:shadowhashdata].nil? or attribute_hash[:shadowhashdata].empty? 147 attribute_hash[:password] = '*' 148 else 149 embedded_binary_plist = get_embedded_binary_plist(attribute_hash[:shadowhashdata]) 150 if embedded_binary_plist['SALTED-SHA512-PBKDF2'] 151 attribute_hash[:password] = get_salted_sha512_pbkdf2('entropy', embedded_binary_plist, attribute_hash[:name]) 152 attribute_hash[:salt] = get_salted_sha512_pbkdf2('salt', embedded_binary_plist, attribute_hash[:name]) 153 attribute_hash[:iterations] = get_salted_sha512_pbkdf2('iterations', embedded_binary_plist, attribute_hash[:name]) 154 elsif embedded_binary_plist['SALTED-SHA512'] 155 attribute_hash[:password] = get_salted_sha512(embedded_binary_plist) 156 end 157 end 158 159 attribute_hash 160 end
Return an array of hashes containing information about every user on the system.
# File lib/puppet/provider/user/directoryservice.rb 95 def self.get_all_users 96 Puppet::Util::Plist.parse_plist(dscl '-plist', '.', 'readall', '/Users') 97 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 175 def self.get_attribute_from_dscl(path, username, keyname) 176 Puppet::Util::Plist.parse_plist(dscl '-plist', '.', 'read', "/#{path}/#{username}", keyname) 177 end
The plist embedded in the ShadowHashData key is a binary plist. The 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 182 def self.get_embedded_binary_plist(shadow_hash_data) 183 embedded_binary_plist = Array(shadow_hash_data[0].delete(' ')).pack('H*') 184 convert_binary_to_hash(embedded_binary_plist) 185 end
returns a hash of group => version of installed groups
# File lib/puppet/provider/package/pacman.rb 97 def self.get_installed_groups(installed_packages, filter = nil) 98 groups = {} 99 begin 100 # Build a hash of group name => list of packages 101 command = [command(:pacman), "-Sgg"] 102 command << filter if filter 103 execpipe(command) do |pipe| 104 pipe.each_line do |line| 105 name, package = line.split 106 packages = (groups[name] ||= []) 107 packages << package 108 end 109 end 110 111 # Remove any group that doesn't have all its packages installed 112 groups.delete_if do |_, packages| 113 !packages.all? { |package| installed_packages[package] } 114 end 115 116 # Replace the list of packages with a version string consisting of packages that make up the group 117 groups.each do |name, packages| 118 groups[name] = packages.sort.map {|package| "#{package} #{installed_packages[package]}"}.join ', ' 119 end 120 rescue Puppet::ExecutionFailure 121 # pacman returns an expected non-zero exit code when the filter name is not a group 122 raise unless filter 123 end 124 groups 125 end
returns a hash package => version of installed packages
# File lib/puppet/provider/package/pacman.rb 75 def self.get_installed_packages 76 begin 77 packages = {} 78 execpipe([command(:pacman), "-Q"]) do |pipe| 79 # pacman -Q output is 'packagename version-rel' 80 regex = %r{^(\S+)\s(\S+)} 81 pipe.each_line do |line| 82 match = regex.match(line) 83 if match 84 packages[match.captures[0]] = match.captures[1] 85 else 86 warning(_("Failed to match line '%{line}'") % { line: line }) 87 end 88 end 89 end 90 packages 91 rescue Puppet::ExecutionFailure 92 fail(_("Error getting installed packages")) 93 end 94 end
# File lib/puppet/provider/package/pkgng.rb 33 def self.get_latest_version(origin) 34 latest_version = cached_version_list.lines.find { |l| l =~ /^#{origin} / } 35 if latest_version 36 _name, compare, status = latest_version.chomp.split(' ', 3) 37 if ['!', '?'].include?(compare) 38 return nil 39 end 40 latest_version = status.split(' ').last.split(')').first 41 return latest_version 42 end 43 nil 44 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 168 def self.get_list_of_groups 169 @groups ||= Puppet::Util::Plist.parse_plist(dscl '-plist', '.', 'readall', '/Groups') 170 end
Gets the current Darwin version, example 10.6 returns 9 and 10.10 returns 14 See en.wikipedia.org/wiki/Darwin_(operating_system)#Release_history for more information.
@api private
# File lib/puppet/provider/service/launchd.rb 73 def self.get_os_version 74 @os_version ||= Facter.value('os.release.major').to_i 75 end
# File lib/puppet/provider/package/pkgng.rb 17 def self.get_query 18 pkg(['query', '-a', '%n %v %o']) 19 end
# File lib/puppet/provider/package/pkgng.rb 21 def self.get_resource_info(name) 22 pkg(['query', '%n %v %o', name]) 23 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 201 def self.get_salted_sha512(embedded_binary_plist) 202 embedded_binary_plist['SALTED-SHA512'].unpack("H*")[0] 203 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 209 def self.get_salted_sha512_pbkdf2(field, embedded_binary_plist, user_name = "") 210 case field 211 when 'salt', 'entropy' 212 value = embedded_binary_plist['SALTED-SHA512-PBKDF2'][field] 213 if value == nil 214 raise Puppet::Error, "Invalid #{field} given for user #{user_name}" 215 end 216 value.unpack('H*').first 217 when 'iterations' 218 Integer(embedded_binary_plist['SALTED-SHA512-PBKDF2'][field]) 219 else 220 raise Puppet::Error, "Puppet has tried to read an incorrect value from the user #{user_name} in the SALTED-SHA512-PBKDF2 hash. Acceptable fields are 'salt', 'entropy', or 'iterations'." 221 end 222 end
# File lib/puppet/provider/service/init.rb 84 def self.get_services(defpath, exclude = self.excludes) 85 defpath = [defpath] unless defpath.is_a? Array 86 instances = [] 87 defpath.each do |path| 88 unless Puppet::FileSystem.directory?(path) 89 Puppet.debug "Service path #{path} does not exist" 90 next 91 end 92 93 check = [:ensure] 94 95 check << :enable if public_method_defined? :enabled? 96 97 Dir.entries(path).each do |name| 98 fullpath = File.join(path, name) 99 next if name =~ /^\./ 100 next if exclude.include? name 101 next if Puppet::FileSystem.directory?(fullpath) 102 next unless Puppet::FileSystem.executable?(fullpath) 103 next unless is_init?(fullpath) 104 instances << new(:name => name, :path => path, :hasstatus => true) 105 end 106 end 107 instances 108 end
# File lib/puppet/provider/package/portage.rb 156 def self.get_sets 157 @sets ||= begin 158 @sets = emerge(*(['--list-sets'])) 159 end 160 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 226 def self.get_sha1(guid) 227 password_hash = nil 228 password_hash_file = "#{password_hash_dir}/#{guid}" 229 if Puppet::FileSystem.exist?(password_hash_file) and File.file?(password_hash_file) 230 raise Puppet::Error, "Could not read password hash file at #{password_hash_file}" if not File.readable?(password_hash_file) 231 f = File.new(password_hash_file) 232 password_hash = f.read 233 f.close 234 end 235 password_hash 236 end
# File lib/puppet/provider/package/pkgng.rb 29 def self.get_version_list 30 @version_list = pkg(['version', '-voRL=']) 31 end
Define some Puppet Property => AIX Attribute (and vice versa) conversion functions here.
# File lib/puppet/provider/user/aix.rb 46 def gid_to_pgrp(provider, gid) 47 group = group_provider.find(gid, provider.ia_module_args) 48 49 group[:name] 50 end
Checks if a given name is a group
# File lib/puppet/provider/package/pacman.rb 29 def self.group?(name) 30 begin 31 !pacman("-Sg", name).empty? 32 rescue Puppet::ExecutionFailure 33 # pacman returns an expected non-zero exit code when the name is not a group 34 false 35 end 36 end
# File lib/puppet/provider/user/aix.rb 39 def group_provider 40 @group_provider ||= Puppet::Type.type(:group).provider(:aix) 41 end
We do not directly use the groups attribute value because that will always include the primary group, even if our user is not one of its members. Instead, we retrieve our property value by parsing the etc/group file, which matches what we do on our other POSIX platforms like Linux and Solaris.
See www.ibm.com/support/knowledgecenter/en/ssw_aix_72/com.ibm.aix.files/group_security.htm
# File lib/puppet/provider/user/aix.rb 96 def groups_attribute_to_property(provider, _groups) 97 Puppet::Util::POSIX.groups_of(provider.resource[:name]).join(',') 98 end
We do some validation before-hand to ensure the value's an Array, a String, etc. in the property. This routine does a final check to ensure our value doesn't have whitespace before we convert it to an attribute.
# File lib/puppet/provider/user/aix.rb 82 def groups_property_to_attribute(groups) 83 if groups =~ /\s/ 84 raise ArgumentError, _("Invalid value %{groups}: Groups must be comma separated!") % { groups: groups } 85 end 86 87 groups 88 end
# File lib/puppet/provider/service/upstart.rb 34 def self.has_initctl? 35 # Puppet::Util::Execution.execute does not currently work on jRuby. 36 # Unfortunately, since this confine is invoked whenever we check for 37 # provider suitability and since provider suitability is still checked 38 # on the master, this confine will still be invoked on the master. Thus 39 # to avoid raising an exception, we do an early return if we're running 40 # on jRuby. 41 return false if Puppet::Util::Platform.jruby? 42 43 begin 44 initctl('version', '--quiet') 45 true 46 rescue 47 false 48 end 49 end
# File lib/puppet/provider/package/macports.rb 40 def self.hash_from_line(line, regex, fields) 41 hash = {} 42 match = regex.match(line) 43 if match 44 fields.zip(match.captures) { |field, value| 45 hash[field] = value 46 } 47 hash[:provider] = self.name 48 return hash 49 end 50 nil 51 end
# File lib/puppet/provider/package/pkgutil.rb 17 def self.healthcheck() 18 unless Puppet::FileSystem.exist?("/var/opt/csw/pkgutil/admin") 19 Puppet.notice _("It is highly recommended you create '/var/opt/csw/pkgutil/admin'.") 20 Puppet.notice _("See /var/opt/csw/pkgutil") 21 end 22 23 correct_wgetopts = false 24 [ "/opt/csw/etc/pkgutil.conf", "/etc/opt/csw/pkgutil.conf" ].each do |confpath| 25 File.open(confpath) do |conf| 26 conf.each_line {|line| correct_wgetopts = true if line =~ /^\s*wgetopts\s*=.*(-nv|-q|--no-verbose|--quiet)/ } 27 end 28 end 29 if ! correct_wgetopts 30 Puppet.notice _("It is highly recommended that you set 'wgetopts=-nv' in your pkgutil.conf.") 31 end 32 end
The IFO flag field is just what it names, the first field can have either 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 don't know what we are doing and exit with out doing more damage.
# File lib/puppet/provider/package/pkg.rb 46 def self.ifo_flag(flags) 47 ( 48 case flags[0..0] 49 when 'i' 50 {:status => 'installed'} 51 when '-' 52 {:status => 'known'} 53 else 54 raise ArgumentError, _('Unknown format %{resource_name}: %{full_flags}[%{bad_flag}]') % 55 { resource_name: self.name, full_flags: flags, bad_flag: flags[0..0] } 56 end 57 ).merge( 58 case flags[1..1] 59 when 'f' 60 {:mark => :hold} 61 when '-' 62 {} 63 else 64 raise ArgumentError, _('Unknown format %{resource_name}: %{full_flags}[%{bad_flag}]') % 65 { resource_name: self.name, full_flags: flags, bad_flag: flags[1..1] } 66 end 67 ) 68 end
# File lib/puppet/provider/package/appdmg.rb 45 def self.installapp(source, name, orig_source) 46 appname = File.basename(source); 47 ditto "--rsrc", source, "/Applications/#{appname}" 48 Puppet::FileSystem.open("/var/db/.puppet_appdmg_installed_#{name}", nil, "w:UTF-8") do |t| 49 t.print "name: '#{name}'\n" 50 t.print "source: '#{orig_source}'\n" 51 end 52 end
# File lib/puppet/provider/package/pkgdmg.rb 63 def self.installpkg(source, name, orig_source) 64 installer "-pkg", source, "-target", "/" 65 # Non-zero exit status will throw an exception. 66 Puppet::FileSystem.open("/var/db/.puppet_pkgdmg_installed_#{name}", nil, "w:UTF-8") do |t| 67 t.print "name: '#{name}'\n" 68 t.print "source: '#{orig_source}'\n" 69 end 70 end
# File lib/puppet/provider/package/appdmg.rb 54 def self.installpkgdmg(source, name) 55 require 'open-uri' 56 cached_source = source 57 tmpdir = Dir.mktmpdir 58 begin 59 if %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ cached_source 60 cached_source = File.join(tmpdir, name) 61 begin 62 curl "-o", cached_source, "-C", "-", "-L", "-s", "--url", source 63 Puppet.debug "Success: curl transferred [#{name}]" 64 rescue Puppet::ExecutionFailure 65 Puppet.debug "curl did not transfer [#{name}]. Falling back to slower open-uri transfer methods." 66 cached_source = source 67 end 68 end 69 70 open(cached_source) do |dmg| 71 xml_str = hdiutil "mount", "-plist", "-nobrowse", "-readonly", "-mountrandom", "/tmp", dmg.path 72 ptable = Puppet::Util::Plist::parse_plist(xml_str) 73 # JJM Filter out all mount-paths into a single array, discard the rest. 74 mounts = ptable['system-entities'].collect { |entity| 75 entity['mount-point'] 76 }.select { |mountloc|; mountloc } 77 begin 78 found_app = false 79 mounts.each do |fspath| 80 Dir.entries(fspath).select { |f| 81 f =~ /\.app$/i 82 }.each do |pkg| 83 found_app = true 84 installapp("#{fspath}/#{pkg}", name, source) 85 end 86 end 87 Puppet.debug "Unable to find .app in .appdmg. #{name} will not be installed." if !found_app 88 ensure 89 hdiutil "eject", mounts[0] 90 end 91 end 92 ensure 93 FileUtils.remove_entry_secure(tmpdir, true) 94 end 95 end
# File lib/puppet/provider/package/apple.rb 25 def self.instance_by_name 26 Dir.entries("/Library/Receipts").find_all { |f| 27 f =~ /\.pkg$/ 28 }.collect { |f| 29 name = f.sub(/\.pkg/, '') 30 yield name if block_given? 31 32 name 33 } 34 end
# File lib/puppet/provider/group/windows_adsi.rb 111 def self.instances 112 Puppet::Util::Windows::ADSI::Group.map { |g| new(:ensure => :present, :name => g.name) } 113 end
JJM We store a cookie for each installed .app.dmg in /var/db
# File lib/puppet/provider/package/appdmg.rb 29 def self.instances_by_name 30 Dir.entries("/var/db").find_all { |f| 31 f =~ /^\.puppet_appdmg_installed_/ 32 }.collect do |f| 33 name = f.sub(/^\.puppet_appdmg_installed_/, '') 34 yield name if block_given? 35 name 36 end 37 end
# File lib/puppet/provider/service/init.rb 191 def self.is_init?(script = initscript) 192 file = Puppet::FileSystem.pathname(script) 193 !Puppet::FileSystem.symlink?(file) || Puppet::FileSystem.readlink(file) != "/lib/init/upstart-job" 194 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 181 def self.job_list 182 @job_list = Hash.new 183 begin 184 output = launchctl :list 185 raise Puppet::Error.new("launchctl list failed to return any data.") if output.nil? 186 output.split("\n").each do |line| 187 @job_list[line.split(/\s/).last] = :running 188 end 189 rescue Puppet::ExecutionFailure 190 raise Puppet::Error.new("Unable to determine status of #{resource[:name]}", $!) 191 end 192 @job_list 193 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 158 def self.jobsearch(label=nil) 159 by_label = make_label_to_path_map 160 161 if label 162 if by_label.has_key? label 163 return { label => by_label[label] } 164 else 165 # try refreshing the map, in case a plist has been added in the interim 166 by_label = make_label_to_path_map(true) 167 if by_label.has_key? label 168 return { label => by_label[label] } 169 else 170 raise Puppet::Error, "Unable to find launchd plist for job: #{label}" 171 end 172 end 173 else 174 # caller wants the whole map 175 by_label 176 end 177 end
Retrieve the latest package version information for a given package name and combination of repos to enable and disable.
@note If multiple package versions are defined (such as in the case where a
package is built for multiple architectures), the first package found will be used.
@api private @param package [String] The name of the package to query @param disablerepo [Array<String>] A list of repositories to disable for this query @param enablerepo [Array<String>] A list of repositories to enable for this query @param disableexcludes [Array<String>] A list of repository excludes to disable for this query @return [Hash<Symbol, String>]
# File lib/puppet/provider/package/yum.rb 87 def self.latest_package_version(package, disablerepo, enablerepo, disableexcludes) 88 89 key = [disablerepo, enablerepo, disableexcludes] 90 91 @latest_versions ||= {} 92 if @latest_versions[key].nil? 93 @latest_versions[key] = check_updates(disablerepo, enablerepo, disableexcludes) 94 end 95 96 if @latest_versions[key][package] 97 @latest_versions[key][package].first 98 end 99 end
Defines the path to the overrides plist file where service enabling behavior is defined in 10.6 and greater.
With the rewrite of launchd in 10.10+, this moves and slightly changes format.
@api private
# File lib/puppet/provider/service/launchd.rb 83 def self.launchd_overrides 84 if self.get_os_version < 14 85 "/var/db/launchd.db/com.apple.launchd/overrides.plist" 86 else 87 "/var/db/com.apple.xpc.launchd/disabled.plist" 88 end 89 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 59 def self.launchd_paths 60 [ 61 "/Library/LaunchAgents", 62 "/Library/LaunchDaemons", 63 "/System/Library/LaunchAgents", 64 "/System/Library/LaunchDaemons" 65 ] 66 end
# File lib/puppet/provider/package/zypper.rb 31 def self.list_updates 32 output = zypper 'list-updates' 33 34 avail_updates = {} 35 36 # split up columns 37 output.lines.each do |line| 38 pkg_ver = line.split(/\s*\|\s*/) 39 # ignore zypper headers 40 next unless pkg_ver[0] == 'v' 41 avail_updates[pkg_ver[2]] = pkg_ver[4] 42 end 43 44 avail_updates 45 end
# File lib/puppet/provider/package/freebsd.rb 15 def self.listcmd 16 command(:pkginfo) 17 end
Get a hash of all launchd plists, keyed by label. This value is cached, but the cache will be refreshed if refresh is true.
@api private
# File lib/puppet/provider/service/launchd.rb 134 def self.make_label_to_path_map(refresh=false) 135 return @label_to_path_map if @label_to_path_map and not refresh 136 @label_to_path_map = {} 137 launchd_paths.each do |path| 138 return_globbed_list_of_file_paths(path).each do |filepath| 139 Puppet.debug("Reading launchd plist #{filepath}") 140 job = read_plist(filepath) 141 next if job.nil? 142 if job.respond_to?(:key) && job.key?("Label") 143 @label_to_path_map[job["Label"]] = filepath 144 else 145 #TRANSLATORS 'plist' and label' should not be translated 146 Puppet.debug(_("The %{file} plist does not contain a 'label' key; Puppet is skipping it") % { file: filepath }) 147 next 148 end 149 end 150 end 151 @label_to_path_map 152 end
# File lib/puppet/util/log/destinations.rb 50 def self.match?(obj) 51 obj.is_a?(String) && Puppet::Util.absolute_path?(obj) 52 end
Define some Puppet Property => AIX Attribute (and vice versa) conversion functions here. This is so we can unit test them.
# File lib/puppet/provider/group/aix.rb 62 def members_to_users(provider, members) 63 members = members.split(',') if members.is_a?(String) 64 unless provider.resource[:auth_membership] 65 current_members = provider.members 66 current_members = [] if current_members == :absent 67 members = (members + current_members).uniq 68 end 69 70 members.join(',') 71 end
Convert a group name to an id.
# File lib/puppet/provider/group/ldap.rb 41 def self.name2id(group) 42 result = manager.search("cn=#{group}") 43 return nil unless result and result.length > 0 44 45 # Only use the first result. 46 group = result[0] 47 group[:gid][0] 48 end
# File lib/puppet/provider/package/sun.rb 33 def self.namemap(hash) 34 self::Namemap.keys.inject({}) do |hsh,k| 35 hsh.merge(self::Namemap[k] => hash[k]) 36 end 37 end
@param line [String] one line of rpm package query information @return [Hash] of NEVRA_FIELDS strings parsed from package info or an empty hash if we failed to parse @api private
# File lib/puppet/provider/package/rpm.rb 202 def self.nevra_to_hash(line) 203 line.strip! 204 hash = {} 205 206 match = self::NEVRA_REGEX.match(line) 207 if match 208 self::NEVRA_FIELDS.zip(match.captures) { |f, v| hash[f] = v } 209 hash[:provider] = self.name 210 hash[:ensure] = "#{hash[:version]}-#{hash[:release]}" 211 hash[:ensure].prepend("#{hash[:epoch]}:") if hash[:epoch] != '0' 212 else 213 Puppet.debug("Failed to match rpm line #{line}") 214 end 215 216 return hash 217 end
@param line [String] multiple lines of rpm package query information @return list of [Hash] of NEVRA_FIELDS strings parsed from package info or an empty list if we failed to parse @api private
# File lib/puppet/provider/package/rpm.rb 223 def self.nevra_to_multiversion_hash(multiline) 224 list = [] 225 multiversion_hash = {} 226 multiline.each_line do |line| 227 hash = self.nevra_to_hash(line) 228 if !hash.empty? 229 if multiversion_hash.empty? 230 multiversion_hash = hash.dup 231 next 232 end 233 234 if multiversion_hash[:name] != hash[:name] 235 list << multiversion_hash 236 multiversion_hash = hash.dup 237 next 238 end 239 240 if !multiversion_hash[:ensure].include?(hash[:ensure]) 241 multiversion_hash[:ensure].concat("#{self::MULTIVERSION_SEPARATOR}#{hash[:ensure]}") 242 end 243 end 244 end 245 list << multiversion_hash if multiversion_hash 246 if list.size == 1 247 return list[0] 248 end 249 return list 250 end
# File lib/puppet/functions/match.rb 49 def initialize(closure_scope, loader) 50 super 51 52 # Make this visitor shared among all instantiations of this function since it is faster. 53 # This can be used because it is not possible to replace 54 # a puppet runtime (where this function is) without a reboot. If you model a function in a module after 55 # this class, use a regular instance variable instead to enable reloading of the module without reboot 56 # 57 @@match_visitor ||= Puppet::Pops::Visitor.new(self, "match", 1, 1) 58 end
rpm < 4.0.2 does not support –nodigest
# File lib/puppet/provider/package/rpm.rb 55 def self.nodigest 56 '--nodigest' unless Puppet::Util::Package.versioncmp(current_version, '4.0.2') < 0 57 end
Identify common types of pkgutil noise as it downloads catalogs etc
# File lib/puppet/provider/package/pkgutil.rb 116 def self.noise?(line) 117 true if line =~ /^#/ 118 true if line =~ /^Checking integrity / # use_gpg 119 true if line =~ /^gpg: / # gpg verification 120 true if line =~ /^=+> / # catalog fetch 121 true if line =~ /\d+:\d+:\d+ URL:/ # wget without -q 122 false 123 end
rpm < 4.1 does not support –nosignature
# File lib/puppet/provider/package/rpm.rb 50 def self.nosignature 51 '--nosignature' unless Puppet::Util::Package.versioncmp(current_version, '4.1') < 0 52 end
# File lib/puppet/provider/user/directoryservice.rb 60 def self.ns_to_ds_attribute_map 61 @ns_to_ds_attribute_map ||= ds_to_ns_attribute_map.invert 62 end
Parse lines of output from `pip freeze`, which are structured as: package==version or package===version
# File lib/puppet/provider/package/pip.rb 103 def self.parse(line) 104 if line.chomp =~ /^([^=]+)===?([^=]+)$/ 105 {:ensure => $2, :name => $1, :provider => name} 106 end 107 end
# File lib/puppet/provider/package/macports.rb 34 def self.parse_info_query_line(line) 35 regex = /(\S+)\s+(\S+)/ 36 fields = [:version, :revision] 37 hash_from_line(line, regex, fields) 38 end
# File lib/puppet/provider/package/macports.rb 28 def self.parse_installed_query_line(line) 29 regex = /(\S+)\s+@(\S+)_(\d+).*\(active\)/ 30 fields = [:name, :ensure, :revision] 31 hash_from_line(line, regex, fields) 32 end
@param line [String] one line of dpkg-query output @return [Hash,nil] a hash of FIELDS or nil if we failed to match @api private
# File lib/puppet/provider/package/dpkg.rb 60 def self.parse_line(line, regex=self::FIELDS_REGEX) 61 hash = nil 62 63 match = regex.match(line) 64 if match 65 hash = {} 66 67 self::FIELDS.zip(match.captures) do |field,value| 68 hash[field] = value 69 end 70 71 hash[:provider] = self.name 72 73 if hash[:status] == 'not-installed' 74 hash[:ensure] = :purged 75 elsif ['config-files', 'half-installed', 'unpacked', 'half-configured'].include?(hash[:status]) 76 hash[:ensure] = :absent 77 end 78 hash[:mark] = hash[:desired] == 'hold' ? :hold : :none 79 else 80 Puppet.debug("Failed to match dpkg-query line #{line.inspect}") 81 end 82 83 return hash 84 end
# File lib/puppet/provider/package/pkgng.rb 46 def self.parse_pkg_query_line(line) 47 name, version, origin = line.chomp.split(' ', 3) 48 latest_version = get_latest_version(origin) || version 49 50 { 51 :ensure => version, 52 :name => name, 53 :provider => self.name, 54 :origin => origin, 55 :version => version, 56 :latest => latest_version 57 } 58 end
# File lib/puppet/provider/package/pkgin.rb 13 def self.parse_pkgin_line(package) 14 15 # e.g. 16 # vim-7.2.446;Vim editor (vi clone) without GUI 17 match, name, version, status = *package.match(/([^\s;]+)-([^\s;]+)[;\s](=|>|<)?.+$/) 18 if match 19 { 20 :name => name, 21 :status => status, 22 :ensure => version 23 } 24 end 25 end
# File lib/puppet/provider/package/sun.rb 39 def self.parse_pkginfo(out) 40 # collect all the lines with : in them, and separate them out by ^$ 41 pkgs = [] 42 pkg = {} 43 out.each_line do |line| 44 case line.chomp 45 when /^\s*$/ 46 pkgs << pkg unless pkg.empty? 47 pkg = {} 48 when /^\s*([^:]+):\s+(.+)$/ 49 pkg[$1] = $2 50 end 51 end 52 pkgs << pkg unless pkg.empty? 53 pkgs 54 end
Turn our pkgutil -c listing into a bunch of hashes.
# File lib/puppet/provider/package/pkgutil.rb 88 def self.parse_pkglist(output, hash = {}) 89 output = output.split("\n") 90 91 if output[-1] == "Not in catalog" 92 Puppet.warning _("Package not in pkgutil catalog: %{package}") % { package: hash[:justme] } 93 return nil 94 end 95 96 list = output.collect do |line| 97 next if line =~ /installed\s+catalog/ # header of package list 98 next if noise?(line) 99 100 pkgsplit(line) 101 end.reject { |h| h.nil? } 102 103 if hash[:justme] 104 # Single queries may have been for an alias so return the name requested 105 if list.any? 106 list[-1][:name] = hash[:justme] 107 return list[-1] 108 end 109 else 110 list.reject! { |h| h[:ensure] == :absent } 111 return list 112 end 113 end
# File lib/puppet/provider/package/yum.rb 129 def self.parse_updates(str) 130 # Strip off all content that contains Obsoleting, Security: or Update 131 body = str.partition(/^(Obsoleting|Security:|Update)/).first 132 133 updates = Hash.new { |h, k| h[k] = [] } 134 135 body.split(/^\s*\n/).each do |line| 136 line.split.each_slice(3) do |tuple| 137 next unless tuple[0].include?('.') && tuple[1] =~ VERSION_REGEX 138 139 hash = update_to_hash(*tuple[0..1]) 140 # Create entries for both the package name without a version and a 141 # version since yum considers those as mostly interchangeable. 142 short_name = hash[:name] 143 long_name = "#{hash[:name]}.#{hash[:arch]}" 144 updates[short_name] << hash 145 updates[long_name] << hash 146 end 147 end 148 updates 149 end
# File lib/puppet/provider/user/directoryservice.rb 483 def self.password_hash_dir 484 '/var/db/shadow/hash' 485 end
# File lib/puppet/provider/user/aix.rb 52 def pgrp_to_gid(provider, pgrp) 53 group = group_provider.find(pgrp, provider.ia_module_args) 54 55 group[:gid] 56 end
# File lib/puppet/provider/package/pip.rb 46 def self.pip_version(command) 47 version = nil 48 execpipe [quote(command), '--version'] do |process| 49 process.collect do |line| 50 md = line.strip.match(/^pip (\d+\.\d+\.?\d*).*$/) 51 if md 52 version = md[1] 53 break 54 end 55 end 56 end 57 58 raise Puppet::Error, _("Cannot resolve pip version") unless version 59 60 version 61 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 88 def self.pkg_state(state) 89 case state 90 when /installed/ 91 {:status => 'installed'} 92 when /known/ 93 {:status => 'known'} 94 else 95 raise ArgumentError, _('Unknown format %{resource_name}: %{state}') % { resource_name: self.name, state: state } 96 end 97 end
# File lib/puppet/provider/package/aix.rb 117 def self.pkglist(hash = {}) 118 cmd = [command(:lslpp), "-qLc"] 119 120 name = hash[:pkgname] 121 if name 122 cmd << name 123 end 124 125 begin 126 list = execute(cmd).scan(/^[^#][^:]*:([^:]*):([^:]*):[^:]*:[^:]*:([^:])/).collect { |n,e,s| 127 e = :absent if [:broken, :inconsistent].include?(STATE_CODE[s]) 128 { :name => n, :ensure => e, :status => STATE_CODE[s], :provider => self.name } 129 } 130 rescue Puppet::ExecutionFailure => detail 131 if hash[:pkgname] 132 return nil 133 else 134 raise Puppet::Error, _("Could not list installed Packages: %{detail}") % { detail: detail }, detail.backtrace 135 end 136 end 137 138 if hash[:pkgname] 139 return list.shift 140 else 141 return list 142 end 143 end
Split the different lines into hashes.
# File lib/puppet/provider/package/pkgutil.rb 126 def self.pkgsplit(line) 127 if line =~ /\s*(\S+)\s+(\S+)\s+(.*)/ 128 hash = {} 129 hash[:name] = $1 130 hash[:ensure] = if $2 == "notinst" 131 :absent 132 else 133 $2 134 end 135 hash[:avail] = $3 136 137 if hash[:avail] =~ /^SAME\s*$/ 138 hash[:avail] = hash[:ensure] 139 end 140 141 # Use the name method, so it works with subclasses. 142 hash[:provider] = self.name 143 144 return hash 145 else 146 Puppet.warning _("Cannot match %{line}") % { line: line } 147 return nil 148 end 149 end
# File lib/puppet/provider/file/posix.rb 14 def self.post_resource_eval 15 Selinux.matchpathcon_fini if Puppet::Util::SELinux.selinux_support? 16 end
# File lib/puppet/provider/package/aix.rb 46 def self.prefetch(packages) 47 raise Puppet::Error, _("The aix provider can only be used by root") if Process.euid != 0 48 49 return unless packages.detect { |name, package| package.should(:ensure) == :latest } 50 51 sources = packages.collect { |name, package| package[:source] }.uniq.compact 52 53 updates = {} 54 sources.each do |source| 55 execute(self.srclistcmd(source)).each_line do |line| 56 if line =~ /^[^#][^:]*:([^:]*):([^:]*)/ 57 current = {} 58 current[:name] = $1 59 current[:version] = $2 60 current[:source] = source 61 62 if updates.key?(current[:name]) 63 previous = updates[current[:name]] 64 65 updates[current[:name]] = current unless Puppet::Util::Package.versioncmp(previous[:version], current[:version]) == 1 66 67 else 68 updates[current[:name]] = current 69 end 70 end 71 end 72 end 73 74 packages.each do |name, package| 75 if updates.key?(name) 76 package.provider.latest_info = updates[name] 77 end 78 end 79 end
Define the default provider package command name when the provider is targetable. Required by Puppet::Provider::Package::Targetable::resource_or_provider_command
# File lib/puppet/provider/package/gem.rb 39 def self.provider_command 40 if Puppet::Util::Platform.windows? 41 Puppet::Util.withenv(PATH: windows_path_without_puppet_bin) { command(:gemcmd) } 42 else 43 command(:gemcmd) 44 end 45 end
Quoting is required if the path to the pip command contains spaces. Required for execpipe() but not execute(), as execute() already does this.
# File lib/puppet/provider/package/pip.rb 327 def self.quote(path) 328 if path.include?(" ") 329 "\"#{path}\"" 330 else 331 path 332 end 333 end
Read overrides plist, retrying if necessary
# File lib/puppet/provider/service/launchd.rb 202 def self.read_overrides 203 i = 1 204 overrides = nil 205 loop do 206 Puppet.debug(_("Reading overrides plist, attempt %{i}") % {i: i}) if i > 1 207 overrides = read_plist(launchd_overrides) 208 break unless overrides.nil? 209 raise Puppet::Error.new(_('Unable to read overrides plist, too many attempts')) if i == 20 210 Puppet.info(_('Overrides file could not be read, trying again.')) 211 Kernel.sleep(0.1) 212 i += 1 213 end 214 overrides 215 end
Read a plist, whether its format is XML or in Apple's “binary1” format.
# File lib/puppet/provider/service/launchd.rb 197 def self.read_plist(path) 198 Puppet::Util::Plist.read_plist_file(path) 199 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 656 def self.remove_less_specific_files(files, parent_path, existing_files, &block) 657 # REVISIT: is this Windows safe? AltSeparator? 658 mypath = parent_path.split(::File::Separator) 659 other_paths = existing_files. 660 select { |r| (yield r) != parent_path}. 661 collect { |r| (yield r).split(::File::Separator) }. 662 select { |p| p[0,mypath.length] == mypath } 663 664 return files if other_paths.empty? 665 666 files.reject { |file| 667 path = (yield file).split(::File::Separator) 668 other_paths.any? { |p| path[0,p.length] == p } 669 } 670 end
@api private Reset the latest version hash to nil needed for spec tests to clear cached value
# File lib/puppet/provider/package/zypper.rb 19 def self.reset! 20 @latest_versions = nil 21 end
# File lib/puppet/type/resources.rb 184 def self.reset_system_users_max_uid! 185 @system_users_max_uid = nil 186 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 123 def self.return_globbed_list_of_file_paths(path) 124 array_of_files = Dir.glob(File.join(path, '*')).collect do |filepath| 125 File.file?(filepath) ? filepath : nil 126 end 127 array_of_files.compact 128 end
Override the specificity method to return 1 if gem is not set as default provider
# File lib/puppet/provider/package/gem.rb 27 def self.specificity 28 match = default_match 29 length = match ? match.length : 0 30 31 return 1 if length == 0 32 33 super 34 end
# File lib/puppet/provider/package/aix.rb 42 def self.srclistcmd(source) 43 [ command(:installp), "-L", "-d", source ] 44 end
# File lib/puppet/util/log/destinations.rb 3 def self.suitable?(obj) 4 Puppet.features.syslog? 5 end
# File lib/puppet/type/resources.rb 163 def self.system_users_max_uid 164 return @system_users_max_uid if @system_users_max_uid 165 166 # First try to read the minimum user id from login.defs 167 if Puppet::FileSystem.exist?('/etc/login.defs') 168 @system_users_max_uid = Puppet::FileSystem.each_line '/etc/login.defs' do |line| 169 break $1.to_i - 1 if line =~ /^\s*UID_MIN\s+(\d+)(\s*#.*)?$/ 170 end 171 end 172 173 # Otherwise, use a sensible default based on the OS family 174 @system_users_max_uid ||= case Puppet.runtime[:facter].value('os.family') 175 when 'OpenBSD', 'FreeBSD' 176 999 177 else 178 499 179 end 180 181 @system_users_max_uid 182 end
# File lib/puppet/type/file.rb 45 def self.title_patterns 46 # strip trailing slashes from path but allow the root directory, including 47 # for example "/" or "C:/" 48 [ [ %r{^(/|.+:/|.*[^/])/*\Z}m, [ [ :path ] ] ] ] 49 end
# File lib/puppet/provider/package/windows.rb 57 def self.to_hash(pkg) 58 { 59 :name => pkg.name, 60 :ensure => pkg.version || :installed, 61 :provider => :windows 62 } 63 end
# File lib/puppet/provider/package/pacman.rb 187 def self.to_resource_hash(name, version) 188 { 189 :name => name, 190 :ensure => version, 191 :provider => self.name 192 } 193 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 78 def self.ufoxi_flag(flags) 79 {} 80 end
# File lib/puppet/provider/package/dnf.rb 37 def self.update_command 38 # In DNF, update is deprecated for upgrade 39 'upgrade' 40 end
# File lib/puppet/provider/package/yum.rb 151 def self.update_to_hash(pkgname, pkgversion) 152 153 # The pkgname string has two parts: name, and architecture. Architecture 154 # is the portion of the string following the last "." character. All 155 # characters preceding the final dot are the package name. Parse out 156 # these two pieces of component data. 157 name, _, arch = pkgname.rpartition('.') 158 if name.empty? 159 raise _("Failed to parse package name and architecture from '%{pkgname}'") % { pkgname: pkgname } 160 end 161 162 match = pkgversion.match(VERSION_REGEX) 163 epoch = match[1] || '0' 164 version = match[2] 165 release = match[3] 166 167 { 168 :name => name, 169 :epoch => epoch, 170 :version => version, 171 :release => release, 172 :arch => arch, 173 } 174 end
# File lib/puppet/provider/group/aix.rb 73 def users_to_members(users) 74 users.split(',') 75 end
# File lib/puppet/provider/package/puppet_gem.rb 10 def self.windows_gemcmd 11 puppet_dir = ENV['PUPPET_DIR'] 12 if puppet_dir 13 File.join(ENV['PUPPET_DIR'].to_s, 'bin', 'gem.bat') 14 else 15 File.join(Gem.default_bindir, 'gem.bat') 16 end 17 end
Having puppet/bin in PATH makes gem provider to use puppet/bin/gem This is an utility methods that reads the PATH and returns a string that contains the content of PATH but without puppet/bin dir. This is used to pass a custom PATH and execute commands in a controlled environment
# File lib/puppet/provider/package/gem.rb 58 def self.windows_path_without_puppet_bin 59 @path ||= ENV['PATH'].split(File::PATH_SEPARATOR) 60 .reject { |dir| dir =~ /puppet\\bin$/ } 61 .join(File::PATH_SEPARATOR) 62 end
If yaourt is installed, we can make use of it
# File lib/puppet/provider/package/pacman.rb 13 def self.yaourt? 14 @yaourt ||= Puppet::FileSystem.exist?('/usr/bin/yaourt') 15 end
Public Instance Methods
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 17 def [](param) 18 return super if self.class.valid_parameter?(param) 19 @extra_parameters[param.to_sym] 20 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 24 def []=(param, value) 25 return super if self.class.valid_parameter?(param) 26 @extra_parameters[param.to_sym] = value 27 end
These stub the translation methods normally brought in by FastGettext. Used when Gettext could not be properly initialized.
# File lib/puppet/gettext/stubs.rb 5 def _(msg) 6 msg 7 end
# File lib/puppet/type/resources.rb 107 def able_to_ensure_absent?(resource) 108 resource[:ensure] = :absent 109 rescue ArgumentError, Puppet::Error 110 err _("The 'ensure' attribute on %{name} resources does not accept 'absent' as a value") % { name: self[:name] } 111 false 112 end
# File lib/puppet/provider/service/upstart.rb 367 def add_default_start_to(text) 368 text + "\nstart on runlevel [2,3,4,5]" 369 end
must override this to hand the keyvalue pairs
# File lib/puppet/provider/user/user_role_add.rb 49 def add_properties 50 cmd = [] 51 Puppet::Type.type(:user).validproperties.each do |property| 52 #skip the password because we can't create it with the solaris useradd 53 next if [:ensure, :password, :password_min_age, :password_max_age, :password_warn_days].include?(property) 54 # 1680 Now you can set the hashed passwords on solaris:lib/puppet/provider/user/user_role_add.rb 55 # the value needs to be quoted, mostly because -c might 56 # have spaces in it 57 value = @resource.should(property) 58 if value && value != "" 59 if property == :keys 60 cmd += build_keys_cmd(value) 61 else 62 cmd << flag(property) << value 63 end 64 end 65 end 66 cmd 67 end
# File lib/puppet/provider/group/groupadd.rb 61 def addcmd 62 if @resource.forcelocal? 63 cmd = [command(:localadd)] 64 @custom_environment = Puppet::Util::Libuser.getenv 65 else 66 cmd = [command(:add)] 67 end 68 69 gid = @resource.should(:gid) 70 if gid 71 unless gid == :absent 72 cmd << flag(:gid) << gid 73 end 74 end 75 cmd += check_allow_dup 76 cmd << "-r" if @resource.system? and self.class.system_groups? 77 cmd << @resource[:name] 78 cmd 79 end
# File lib/puppet/functions/alert.rb 12 def alert(scope, *values) 13 Puppet::Util::Log.log_func(scope, :alert, values) 14 end
# File lib/puppet/functions/all.rb 92 def all_Enumerable_1(enumerable) 93 Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable).all? { |e| yield(e) } 94 end
# File lib/puppet/functions/all.rb 96 def all_Enumerable_2(enumerable) 97 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 98 if enum.hash_style? 99 enum.all? { |entry| yield(*entry) } 100 else 101 enum.each_with_index { |e, i| return false unless yield(i, e) } 102 true 103 end 104 end
# File lib/puppet/functions/all.rb 84 def all_Hash_1(hash) 85 hash.each_pair.all? { |x| yield(x) } 86 end
# File lib/puppet/functions/all.rb 88 def all_Hash_2(hash) 89 hash.each_pair.all? { |x,y| yield(x,y) } 90 end
Return a list of all applications (both legacy and Face applications), along with a summary
of their functionality.
@return [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 161 def all_application_summaries() 162 available_application_names_special_sort().inject([]) do |result, appname| 163 next result if exclude_from_docs?(appname) 164 165 if (appname == COMMON || appname == SPECIALIZED || appname == BLANK) 166 result << appname 167 elsif (is_face_app?(appname)) 168 begin 169 face = Puppet::Face[appname, :current] 170 # Add deprecation message to summary if the face is deprecated 171 summary = face.deprecated? ? face.summary + ' ' + _("(Deprecated)") : face.summary 172 result << [appname, summary, ' '] 173 rescue StandardError, LoadError 174 error_message = _("!%{sub_command}! Subcommand unavailable due to error.") % { sub_command: appname } 175 error_message += ' ' + _("Check error logs.") 176 result << [ error_message, '', ' ' ] 177 end 178 else 179 begin 180 summary = Puppet::Application[appname].summary 181 if summary.empty? 182 summary = horribly_extract_summary_from(appname) 183 end 184 result << [appname, summary, ' '] 185 rescue StandardError, LoadError 186 error_message = _("!%{sub_command}! Subcommand unavailable due to error.") % { sub_command: appname } 187 error_message += ' ' + _("Check error logs.") 188 result << [ error_message, '', ' ' ] 189 end 190 end 191 end 192 end
# File lib/puppet/network/formats.rb 27 def allowed_yaml_classes 28 @allowed_yaml_classes ||= [ 29 Puppet::Node::Facts, 30 Puppet::Node, 31 Puppet::Transaction::Report, 32 Puppet::Resource, 33 Puppet::Resource::Catalog 34 ] 35 end
# File lib/puppet/type/file.rb 537 def ancestors 538 ancestors = Pathname.new(self[:path]).enum_for(:ascend).map(&:to_s) 539 ancestors.delete(self[:path]) 540 ancestors 541 end
@param type [Annotation] the annotation type @param value [Object] the value to annotate @param block [Proc] optional block to produce the annotation hash
# File lib/puppet/functions/annotate.rb 90 def annotate(type, value, &block) 91 type.implementation_class.annotate(value, &block) 92 end
@param type [Type] the Pcore type @param value [Object] the value to annotate @param annotations [Hash{Annotation => Hash{String => Object}}] hash of annotation hashes
# File lib/puppet/functions/annotate.rb 106 def annotate_multi(type, value, annotations) 107 type.implementation_class.annotate(value, annotations) 108 end
@param type [Annotation] the annotation type @param value [Object] the value to annotate @param annotation_hash [Hash{String => Object}] the annotation hash
# File lib/puppet/functions/annotate.rb 98 def annotate_new(type, value, annotation_hash) 99 type.implementation_class.annotate_new(value, annotation_hash) 100 end
# File lib/puppet/functions/any.rb 97 def any_Enumerable_1(enumerable) 98 Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable).any? { |e| yield(e) } 99 end
# File lib/puppet/functions/any.rb 101 def any_Enumerable_2(enumerable) 102 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 103 if enum.hash_style? 104 enum.any? { |entry| yield(*entry) } 105 else 106 enum.each_with_index { |e, i| return true if yield(i, e) } 107 false 108 end 109 end
# File lib/puppet/functions/any.rb 89 def any_Hash_1(hash) 90 hash.each_pair.any? { |x| yield(x) } 91 end
# File lib/puppet/functions/any.rb 93 def any_Hash_2(hash) 94 hash.each_pair.any? { |x,y| yield(x, y) } 95 end
# File lib/puppet/provider/package/aptitude.rb 12 def aptget(*args) 13 args.flatten! 14 # Apparently aptitude hasn't always supported a -q flag. 15 args.delete("-q") if args.include?("-q") 16 args.delete("--force-yes") if args.include?("--force-yes") 17 output = aptitude(*args) 18 19 # Yay, stupid aptitude doesn't throw an error when the package is missing. 20 if args.include?(:install) and output.to_s =~ /Couldn't find any package/ 21 raise Puppet::Error.new( 22 _("Could not find package %{name}") % { name: self.name } 23 ) 24 end 25 end
# File lib/puppet/functions/max.rb 247 def assert_arg_count(args) 248 raise(ArgumentError, 'max(): Wrong number of arguments need at least one') if args.empty? 249 end
##
Helper Methods ##
##
# File lib/puppet/provider/user/directoryservice.rb 471 def assert_full_pbkdf2_password 472 missing = [:password, :salt, :iterations].select { |parameter| @resource[parameter].nil? } 473 474 if !missing.empty? 475 raise Puppet::Error, "OS X versions > 10\.7 use PBKDF2 password hashes, which requires all three of salt, iterations, and password hash. This resource is missing: #{missing.join(', ')}." 476 end 477 end
@param type [Type] the type the value must be an instance of @param value [Object] the value to assert
# File lib/puppet/functions/assert_type.rb 70 def assert_type(type, value) 71 unless Puppet::Pops::Types::TypeCalculator.instance?(type,value) 72 inferred_type = Puppet::Pops::Types::TypeCalculator.infer_set(value) 73 if block_given? 74 # Give the inferred type to allow richer comparison in the given block (if generalized 75 # information is lost). 76 # 77 value = yield(type, inferred_type) 78 else 79 raise Puppet::Pops::Types::TypeAssertionError.new( 80 Puppet::Pops::Types::TypeMismatchDescriber.singleton.describe_mismatch('assert_type():', type, inferred_type), 81 type, inferred_type) 82 end 83 end 84 value 85 end
@param type_string [String] the type the value must be an instance of given in String form @param value [Object] the value to assert
# File lib/puppet/functions/assert_type.rb 90 def assert_type_s(type_string, value, &proc) 91 t = Puppet::Pops::Types::TypeParser.singleton.parse(type_string) 92 block_given? ? assert_type(t, value, &proc) : assert_type(t, value) 93 end
# File lib/puppet/functions/slice.rb 109 def asserted_slice_serving_size(pblock, slice_size) 110 if pblock 111 arity = pblock.arity 112 serving_size = arity < 0 ? slice_size : arity 113 else 114 serving_size = 1 115 end 116 if serving_size == 0 117 raise ArgumentError, _("slice(): block must define at least one parameter. Block has 0.") 118 end 119 unless serving_size == 1 || serving_size == slice_size 120 raise ArgumentError, _("slice(): block must define one parameter, or the same number of parameters as the given size of the slice (%{slice_size}). Block has %{serving_size}; %{parameter_names}") % 121 { slice_size: slice_size, serving_size: serving_size, parameter_names: pblock.parameter_names.join(', ') } 122 end 123 serving_size 124 end
Determine the user to write files as.
# File lib/puppet/type/file.rb 470 def asuser 471 if self.should(:owner) && ! self.should(:owner).is_a?(Symbol) 472 writeable = Puppet::Util::SUIDManager.asuser(self.should(:owner)) { 473 FileTest.writable?(::File.dirname(self[:path])) 474 } 475 476 # If the parent directory is writeable, then we execute 477 # as the user in question. Otherwise we'll rely on 478 # the 'owner' property to do things. 479 asuser = self.should(:owner) if writeable 480 end 481 482 asuser 483 end
# File lib/puppet/provider/user/user_role_add.rb 129 def auths 130 user_attributes[:auths] if user_attributes 131 end
# File lib/puppet/face/help.rb 197 def available_application_names_special_sort() 198 full_list = Puppet::Application.available_application_names 199 a_list = full_list & %w{apply agent config help lookup module resource} 200 a_list = a_list.sort 201 also_ran = full_list - a_list 202 also_ran = also_ran.sort 203 [[COMMON], a_list, [BLANK], [SPECIALIZED], also_ran].flatten(1) 204 end
Use pip CLI to look up versions from PyPI repositories, honoring local pip config such as custom repositories.
# File lib/puppet/provider/package/pip.rb 145 def available_versions 146 command = resource_or_provider_command 147 self.class.validate_command(command) 148 149 command_version = self.class.pip_version(command) 150 if self.class.compare_pip_versions(command_version, '1.5.4') == -1 151 available_versions_with_old_pip 152 else 153 available_versions_with_new_pip(command_version) 154 end 155 end
# File lib/puppet/provider/package/pip.rb 157 def available_versions_with_new_pip(command_version) 158 command = resource_or_provider_command 159 self.class.validate_command(command) 160 161 command_and_options = [self.class.quote(command), 'install', "#{@resource[:name]}==versionplease"] 162 extra_arg = list_extra_flags(command_version) 163 command_and_options << extra_arg if extra_arg 164 command_and_options << install_options if @resource[:install_options] 165 execpipe command_and_options do |process| 166 process.collect do |line| 167 # PIP OUTPUT: Could not find a version that satisfies the requirement example==versionplease (from versions: 1.2.3, 4.5.6) 168 if line =~ /from versions: (.+)\)/ 169 versionList = $1.split(', ').sort do |x,y| 170 self.class.compare_pip_versions(x, y) 171 end 172 return versionList 173 end 174 end 175 end 176 [] 177 end
# File lib/puppet/provider/package/pip.rb 179 def available_versions_with_old_pip 180 command = resource_or_provider_command 181 self.class.validate_command(command) 182 183 Dir.mktmpdir("puppet_pip") do |dir| 184 command_and_options = [self.class.quote(command), 'install', "#{@resource[:name]}", '-d', "#{dir}", '-v'] 185 command_and_options << install_options if @resource[:install_options] 186 execpipe command_and_options do |process| 187 process.collect do |line| 188 # PIP OUTPUT: Using version 0.10.1 (newest of versions: 1.2.3, 4.5.6) 189 if line =~ /Using version .+? \(newest of versions: (.+?)\)/ 190 versionList = $1.split(', ').sort do |x,y| 191 self.class.compare_pip_versions(x, y) 192 end 193 return versionList 194 end 195 end 196 end 197 return [] 198 end 199 end
Back up the existing file at a given prior to it being removed @api private @raise [Puppet::Error] if the file backup failed @return [void]
# File lib/puppet/type/file.rb 1057 def backup_existing 1058 unless perform_backup 1059 #TRANSLATORS refers to a file which could not be backed up 1060 raise Puppet::Error, _("Could not back up; will not remove") 1061 end 1062 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 629 def base64_decode_string(value) 630 Base64.decode64([[value].pack("H*")].pack("m").strip) 631 end
# File lib/puppet/provider/package/apt.rb 94 def best_version(should_range) 95 versions = [] 96 97 output = aptcache :madison, @resource[:name] 98 output.each_line do |line| 99 is = line.split('|')[1].strip 100 begin 101 is_version = DebianVersion.parse(is) 102 versions << is_version if should_range.include?(is_version) 103 rescue DebianVersion::ValidationFailure 104 Puppet.debug("Cannot parse #{is} as a debian version") 105 end 106 end 107 108 return versions.sort.last if versions.any? 109 110 Puppet.debug("No available version for package #{@resource[:name]} is included in range #{should_range}") 111 should_range 112 end
# File lib/puppet/functions/empty.rb 70 def binary_empty(bin) 71 bin.length == 0 72 end
# File lib/puppet/functions/binary_file.rb 25 def binary_file(scope, unresolved_path) 26 path = Puppet::Parser::Files.find_file(unresolved_path, scope.compiler.environment) 27 unless path && Puppet::FileSystem.exist?(path) 28 #TRANSLATORS the string "binary_file()" should not be translated 29 raise Puppet::ParseError, _("binary_file(): The given file '%{unresolved_path}' does not exist") % { unresolved_path: unresolved_path } 30 end 31 Puppet::Pops::Types::PBinaryType::Binary.from_binary_string(Puppet::FileSystem.binread(path)) 32 end
# File lib/puppet/functions/length.rb 41 def binary_length(bin) 42 bin.length 43 end
# File lib/puppet/functions/break.rb 39 def break_impl() 40 # get file, line if available, else they are set to nil 41 file, line = Puppet::Pops::PuppetStack.top_of_stack 42 43 # PuppetStopIteration contains file and line and is a StopIteration exception 44 # so it can break a Ruby Kernel#loop or enumeration 45 # 46 raise Puppet::Pops::Evaluator::PuppetStopIteration.new(file, line) 47 end
# File lib/puppet/type/file.rb 485 def bucket 486 return @bucket if @bucket 487 488 backup = self[:backup] 489 return nil unless backup 490 return nil if backup =~ /^\./ 491 492 unless catalog or backup == "puppet" 493 fail _("Can not find filebucket for backups without a catalog") 494 end 495 496 filebucket = catalog.resource(:filebucket, backup) if catalog 497 if !catalog || (!filebucket && backup != 'puppet') 498 fail _("Could not find filebucket %{backup} specified in backup") % { backup: backup } 499 end 500 501 return default_bucket unless filebucket 502 503 @bucket = filebucket.bucket 504 505 @bucket 506 end
# File lib/puppet/provider/user/user_role_add.rb 157 def build_keys_cmd(keys_hash) 158 cmd = [] 159 keys_hash.each do |k,v| 160 cmd << "-K" << "#{k}=#{v}" 161 end 162 cmd 163 end
# File lib/puppet/provider/service/systemd.rb 92 def cached_enabled? 93 return @cached_enabled if @cached_enabled 94 cmd = [command(:systemctl), 'is-enabled', '--', @resource[:name]] 95 result = execute(cmd, :failonfail => false) 96 @cached_enabled = { output: result.chomp, exitcode: result.exitstatus } 97 end
# File lib/puppet/functions/call.rb 77 def call_deferred(scope, deferred) 78 Puppet::Pops::Evaluator::DeferredResolver.resolve(deferred, scope.compiler) 79 end
# File lib/puppet/functions/call.rb 72 def call_impl_block(scope, function_name, *args, &block) 73 # The call function must be able to call functions loaded by any loader visible from the calling scope. 74 Puppet::Pops::Parser::EvaluatingParser.new.evaluator.external_call_function(function_name, args, scope, &block) 75 end
@return [Boolean] If the current file should be backed up and can be backed up.
# File lib/puppet/type/file.rb 1013 def can_backup?(type) 1014 if type == "directory" and force? 1015 # (#18110) Directories cannot be removed without :force, 1016 # so it doesn't make sense to back them up unless removing with :force. 1017 true 1018 elsif type == "file" or type == "link" 1019 true 1020 else 1021 # Including: “blockSpecial”, “characterSpecial”, "fifo", "socket", “unknown” 1022 false 1023 end 1024 end
# File lib/puppet/type/resources.rb 97 def check(resource) 98 @checkmethod ||= "#{self[:name]}_check" 99 @hascheck ||= respond_to?(@checkmethod) 100 if @hascheck 101 return send(@checkmethod, resource) 102 else 103 return true 104 end 105 end
# File lib/puppet/provider/group/groupadd.rb 41 def check_allow_dup 42 # We have to manually check for duplicates when using libuser 43 # because by default duplicates are allowed. This check is 44 # to ensure consistent behaviour of the useradd provider when 45 # using both useradd and luseradd 46 if not @resource.allowdupe? and @resource.forcelocal? 47 if @resource.should(:gid) and findgroup(:gid, @resource.should(:gid).to_s) 48 raise(Puppet::Error, _("GID %{resource} already exists, use allowdupe to force group creation") % { resource: @resource.should(:gid).to_s }) 49 end 50 elsif @resource.allowdupe? and not @resource.forcelocal? 51 return ["-o"] 52 end 53 [] 54 end
# File lib/puppet/provider/user/useradd.rb 249 def check_manage_home 250 cmd = [] 251 if @resource.managehome? 252 # libuser does not implement the -m flag 253 cmd << "-m" unless @resource.forcelocal? 254 else 255 osfamily = Puppet.runtime[:facter].value('os.family') 256 osversion = Puppet.runtime[:facter].value('os.release.major').to_i 257 # SLES 11 uses pwdutils instead of shadow, which does not have -M 258 # Solaris and OpenBSD use different useradd flavors 259 unless osfamily =~ /Solaris|OpenBSD/ || osfamily == 'Suse' && osversion <= 11 260 cmd << "-M" 261 end 262 end 263 cmd 264 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/windows.rb 104 def check_result(hr) 105 operation = resource[:ensure] == :absent ? 'uninstall' : 'install' 106 107 case hr 108 when self.class::ERROR_SUCCESS 109 # yeah 110 when self.class::ERROR_SUCCESS_REBOOT_INITIATED 111 warning(_("The package %{operation}ed successfully and the system is rebooting now.") % { operation: operation }) 112 when self.class::ERROR_SUCCESS_REBOOT_REQUIRED 113 warning(_("The package %{operation}ed successfully, but the system must be rebooted.") % { operation: operation }) 114 else 115 raise Puppet::Util::Windows::Error.new(_("Failed to %{operation}") % { operation: operation }, hr) 116 end 117 end
# File lib/puppet/provider/user/useradd.rb 266 def check_system_users 267 if self.class.system_users? && resource.system? 268 ["-r"] 269 else 270 [] 271 end 272 end
# File lib/puppet/provider/user/user_role_add.rb 39 def check_valid_shell 40 unless File.exist?(@resource.should(:shell)) 41 raise(Puppet::Error, "Shell #{@resource.should(:shell)} must exist") 42 end 43 unless File.executable?(@resource.should(:shell).to_s) 44 raise(Puppet::Error, "Shell #{@resource.should(:shell)} must be executable") 45 end 46 end
Verify that we have the executable
# File lib/puppet/provider/exec/posix.rb 29 def checkexe(command) 30 exe = extractexe(command) 31 32 if File.expand_path(exe) == exe 33 if !Puppet::FileSystem.exist?(exe) 34 raise ArgumentError, _("Could not find command '%{exe}'") % { exe: exe } 35 elsif !File.file?(exe) 36 raise ArgumentError, _("'%{exe}' is a %{klass}, not a file") % { exe: exe, klass: File.ftype(exe) } 37 elsif !File.executable?(exe) 38 raise ArgumentError, _("'%{exe}' is not executable") % { exe: exe } 39 end 40 return 41 end 42 43 if resource[:path] 44 Puppet::Util.withenv :PATH => resource[:path].join(File::PATH_SEPARATOR) do 45 return if which(exe) 46 end 47 end 48 49 # 'which' will only return the command if it's executable, so we can't 50 # distinguish not found from not executable 51 raise ArgumentError, _("Could not find command '%{exe}'") % { exe: exe } 52 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 80 def checkforcdrom 81 have_cdrom = begin 82 !!(File.read("/etc/apt/sources.list") =~ /^[^#]*cdrom:/) 83 rescue 84 # This is basically pathological... 85 false 86 end 87 88 if have_cdrom and @resource[:allowcdrom] != :true 89 raise Puppet::Error, 90 _("/etc/apt/sources.list contains a cdrom source; not installing. Use 'allowcdrom' to override this failure.") 91 end 92 end
Defines an instance method within a class
# File lib/puppet/util/metaid.rb 18 def class_def(name, &blk) 19 class_eval { define_method name, &blk } 20 end
clean facts for host
# File lib/puppet/face/node/clean.rb 78 def clean_cached_facts(node) 79 Puppet::Node::Facts.indirection.destroy(node) 80 Puppet.info _("%{node}'s facts removed") % { node: node } 81 end
clean cached node host
# File lib/puppet/face/node/clean.rb 84 def clean_cached_node(node) 85 Puppet::Node.indirection.destroy(node) 86 Puppet.info _("%{node}'s cached node removed") % { node: node } 87 end
clean signed cert for host
# File lib/puppet/face/node/clean.rb 69 def clean_cert(node) 70 if Puppet.features.puppetserver_ca? 71 Puppetserver::Ca::Action::Clean.new(LoggerIO.new).run({ 'certnames' => [node] }) 72 else 73 Puppet.info _("Not managing %{node} certs as this host is not a CA") % { node: node } 74 end 75 end
clean node reports for host
# File lib/puppet/face/node/clean.rb 90 def clean_reports(node) 91 Puppet::Transaction::Report.indirection.destroy(node) 92 Puppet.info _("%{node}'s reports removed") % { node: node } 93 end
# File lib/puppet/face/node/clean.rb 43 def cleanup(node) 44 clean_cert(node) 45 clean_cached_facts(node) 46 clean_cached_node(node) 47 clean_reports(node) 48 end
# File lib/puppet/util/log/destinations.rb 7 def close 8 Syslog.close 9 end
# File lib/puppet/functions/empty.rb 50 def collection_empty(coll) 51 coll.empty? 52 end
# File lib/puppet/functions/length.rb 33 def collection_length(col) 34 col.size 35 end
# File lib/puppet/provider/user/user_role_add.rb 77 def command(cmd) 78 cmd = ("role_#{cmd}").intern if is_role? or (!exists? and @resource[:ensure] == :role) 79 super(cmd) 80 end
# File lib/puppet/provider/user/useradd.rb 71 def comment 72 return localcomment if @resource.forcelocal? 73 get(:comment) 74 end
# File lib/puppet/provider/user/windows_adsi.rb 125 def comment=(value) 126 user['Description'] = value 127 end
# File lib/puppet/provider/service/upstart.rb 332 def comment_start_block_in(text) 333 parens = 0 334 text.lines.map do |line| 335 if line.match(START_ON) || parens > 0 336 # If there are more opening parens than closing parens, we need to comment out a multiline 'start on' stanza 337 parens += unbalanced_parens_on(remove_trailing_comments_from(line)) 338 "#" + line 339 else 340 line 341 end 342 end.join('') 343 end
Returns true if the service is complete. A complete service is a service that has the general/complete property defined.
# File lib/puppet/provider/service/smf.rb 110 def complete_service? 111 unless supports_incomplete_services? 112 raise Puppet::Error, _("Cannot query if the %{service} service is complete: The concept of complete/incomplete services was introduced in Solaris 11.1. You are on a Solaris %{release} machine.") % { service: @resource[:name], release: Puppet.runtime[:facter].value('os.release.full') } 113 end 114 115 return @complete_service if @complete_service 116 117 # We need to use the service's FMRI when querying its config. because 118 # general/complete is an instance-specific property. 119 fmri = service_fmri 120 121 # Check if the general/complete property is defined. If it is undefined, 122 # then svccfg will not print anything to the console. 123 property_defn = svccfg("-s", fmri, "listprop", "general/complete").chomp 124 @complete_service = ! property_defn.empty? 125 end
# File lib/puppet/network/formats.rb 229 def construct_output(data) 230 output = String.new 231 data.each do |key, value| 232 output << "#{key}=#{value}" 233 output << "\n" 234 end 235 output 236 end
# File lib/puppet/functions/contain.rb 32 def contain(scope, *classes) 33 if Puppet[:tasks] 34 raise Puppet::ParseErrorWithIssue.from_issue_and_stack( 35 Puppet::Pops::Issues::CATALOG_OPERATION_NOT_SUPPORTED_WHEN_SCRIPTING, 36 {:operation => 'contain'}) 37 end 38 39 # Make call patterns uniform and protected against nested arrays, also make 40 # names absolute if so desired. 41 classes = scope.transform_and_assert_classnames(classes.flatten) 42 43 result = classes.map {|name| Puppet::Pops::Types::TypeFactory.host_class(name) } 44 containing_resource = scope.resource 45 46 # This is the same as calling the include function but faster and does not rely on the include 47 # function. 48 (scope.compiler.evaluate_classes(classes, scope, false) || []).each do |resource| 49 if ! scope.catalog.edge?(containing_resource, resource) 50 scope.catalog.add_edge(containing_resource, resource) 51 end 52 end 53 # Result is an Array[Class, 1, n] which allows chaining other operations 54 result 55 end
# File lib/puppet/type/tidy.rb 137 def convert(unit, multi) 138 num = AgeConvertors[unit] 139 if num 140 return num * multi 141 else 142 self.fail _("Invalid age unit '%{unit}'") % { unit: unit } 143 end 144 end
# File lib/puppet/functions/convert_to.rb 31 def convert_to(value, type, *args, &block) 32 result = call_function('new', type, value, *args) 33 block_given? ? yield(result) : result 34 end
# File lib/puppet/provider/group/groupadd.rb 56 def create 57 super 58 set(:members, @resource[:members]) if @resource[:members] 59 end
This method will create a given value using dscl
# File lib/puppet/provider/user/directoryservice.rb 488 def create_attribute_with_dscl(path, username, keyname, value) 489 set_attribute_with_dscl('-create', path, username, keyname, value) 490 end
@api private
# File lib/puppet/face/epp.rb 500 def create_compiler(options) 501 if options[:node] 502 node = options[:node] 503 else 504 node = Puppet[:node_name_value] 505 506 # If we want to lookup the node we are currently on 507 # we must returning these settings to their default values 508 Puppet.settings[:facts_terminus] = 'facter' 509 Puppet.settings[:node_cache_terminus] = nil 510 end 511 512 unless node.is_a?(Puppet::Node) 513 node = Puppet::Node.indirection.find(node) 514 # Found node must be given the environment to use in some cases, use the one configured 515 # or given on the command line 516 node.environment = Puppet[:environment] 517 end 518 519 fact_file = options[:facts] 520 521 if fact_file 522 if fact_file.is_a?(Hash) # when used via the Face API 523 given_facts = fact_file 524 elsif fact_file.end_with?("json") 525 given_facts = Puppet::Util::Json.load(Puppet::FileSystem.read(fact_file, :encoding => 'utf-8')) 526 else 527 given_facts = Puppet::Util::Yaml.safe_load_file(fact_file) 528 end 529 530 unless given_facts.instance_of?(Hash) 531 raise _("Incorrect formatted data in %{fact_file} given via the --facts flag") % { fact_file: fact_file } 532 end 533 # It is difficult to add to or modify the set of facts once the node is created 534 # as changes does not show up in parameters. Rather than manually patching up 535 # a node and risking future regressions, a new node is created from scratch 536 node = Puppet::Node.new(node.name, :facts => Puppet::Node::Facts.new("facts", node.facts.values.merge(given_facts))) 537 node.environment = Puppet[:environment] 538 node.merge(node.facts.values) 539 end 540 541 compiler = Puppet::Parser::Compiler.new(node) 542 # configure compiler with facts and node related data 543 # Set all global variables from facts 544 compiler.send(:set_node_parameters) 545 546 # pretend that the main class (named '') has been evaluated 547 # since it is otherwise not possible to resolve top scope variables 548 # using '::' when rendering. (There is no harm doing this for the other actions) 549 # 550 compiler.topscope.class_set('', compiler.topscope) 551 compiler 552 end
Create the new user with dscl
# File lib/puppet/provider/user/directoryservice.rb 506 def create_new_user(username) 507 dscl '.', '-create', "/Users/#{username}" 508 end
# File lib/puppet/provider/user/user_role_add.rb 117 def create_role 118 if exists? and !is_role? 119 run(transition("role"), "transition user to") 120 else 121 run(addcmd, "create role") 122 end 123 end
# File lib/puppet/functions/crit.rb 12 def crit(scope, *values) 13 Puppet::Util::Log.log_func(scope, :crit, values) 14 end
returns the full path to the current daemon directory note that this path can be overridden in the resource definition
# File lib/puppet/provider/service/daemontools.rb 110 def daemon 111 path = resource[:path] 112 raise Puppet::Error.new("#{self.class.name} must specify a path for daemon directory") unless path 113 File.join(path, resource[:name]) 114 end
Define the daemon_reload? function to check if the unit is requiring to trigger a “systemctl daemon-reload” If the unit file is flagged with NeedDaemonReload=yes, then a systemd daemon-reload will be run. If multiple unit files have been updated, the first one flagged will trigger the daemon-reload for all of them. The others will be then flagged with NeedDaemonReload=no. So the command will run only once in a puppet run. This function is called only on start & restart unit options. Reference: (PUP-3483) Systemd provider doesn't scan for changed units
# File lib/puppet/provider/service/systemd.rb 153 def daemon_reload? 154 cmd = [command(:systemctl), 'show', '--property=NeedDaemonReload', '--', @resource[:name]] 155 daemon_reload = execute(cmd, :failonfail => false).strip.split('=').last 156 if daemon_reload == 'yes' 157 daemon_reload_cmd = [command(:systemctl), 'daemon-reload'] 158 execute(daemon_reload_cmd, :failonfail => false) 159 end 160 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 28 def daemonize 29 raise NotImplementedError, "Kernel.daemonize is too dangerous, please don't try to use it." 30 end
# File lib/puppet/network/formats.rb 57 def data_to_instance(klass, data) 58 return data if data.is_a?(klass) 59 60 unless data.is_a? Hash 61 raise Puppet::Network::FormatHandler::FormatError, _("Serialized YAML did not contain a valid instance of %{klass}") % { klass: klass } 62 end 63 64 klass.from_data_hash(data) 65 end
This method is required for Debian systems due to the way the SysVInit-Systemd compatibility layer works. When we are trying to manage a service which does not have a Systemd unit file, we need to go through the old init script to determine whether it is enabled or not. See PUP-5016 for more details.
# File lib/puppet/provider/service/systemd.rb 127 def debian_enabled? 128 status = execute(["/usr/sbin/invoke-rc.d", "--quiet", "--query", @resource[:name], "start"], :failonfail => false) 129 if [104, 106].include?(status.exitstatus) 130 return :true 131 elsif [101, 105].include?(status.exitstatus) 132 # 101 is action not allowed, which means we have to do the check manually. 133 # 105 is unknown, which generally means the initscript does not support query 134 # The debian policy states that the initscript should support methods of query 135 # For those that do not, perform the checks manually 136 # http://www.debian.org/doc/debian-policy/ch-opersys.html 137 if get_start_link_count >= 4 138 return :true 139 else 140 return :false 141 end 142 else 143 return :false 144 end 145 end
# File lib/puppet/functions/debug.rb 12 def debug(scope, *values) 13 Puppet::Util::Log.log_func(scope, :debug, values) 14 end
# File lib/puppet/functions/eyaml_lookup_key.rb 81 def decrypt(data, context, options, key) 82 if encrypted?(data) 83 # Options must be set prior to each call to #parse since they end up as static variables in 84 # the Options class. They cannot be set once before #decrypt_value is called, since each #decrypt 85 # might cause a new lookup through interpolation. That lookup in turn, might use a different eyaml 86 # config. 87 # 88 Hiera::Backend::Eyaml::Options.set(options) 89 begin 90 tokens = Hiera::Backend::Eyaml::Parser::ParserFactory.hiera_backend_parser.parse(data) 91 data = tokens.map(&:to_plain_text).join.chomp 92 rescue StandardError => ex 93 raise Puppet::DataBinding::LookupError, 94 _("hiera-eyaml backend error decrypting %{data} when looking up %{key} in %{path}. Error was %{message}") % { data: data, key: key, path: options['path'], message: ex.message } 95 end 96 end 97 context.interpolate(data) 98 end
# File lib/puppet/functions/eyaml_lookup_key.rb 66 def decrypt_value(value, context, options, key) 67 case value 68 when String 69 decrypt(value, context, options, key) 70 when Hash 71 result = {} 72 value.each_pair { |k, v| result[context.interpolate(k)] = decrypt_value(v, context, options, key) } 73 result 74 when Array 75 value.map { |v| decrypt_value(v, context, options, key) } 76 else 77 value 78 end 79 end
# File lib/puppet/provider/service/src.rb 52 def default_action 53 "once" 54 end
# File lib/puppet/type/file.rb 508 def default_bucket 509 Puppet::Type.type(:filebucket).mkdefaultbucket.bucket 510 end
# File lib/puppet/face/help.rb 83 def default_case?(args) 84 args.empty? 85 end
# File lib/puppet/provider/service/src.rb 48 def default_runlevel 49 "2" 50 end
# File lib/puppet/provider/service/windows.rb 119 def default_timeout 120 Puppet::Util::Windows::Service::DEFAULT_TIMEOUT 121 end
# File lib/puppet/provider/service/windows.rb 38 def delayed_start 39 Puppet::Util::Windows::Service.set_startup_configuration(@resource[:name], options: {startup_type: :SERVICE_AUTO_START, delayed: true}) 40 rescue => detail 41 raise Puppet::Error.new(_("Cannot enable %{resource_name} for delayed start, error was: %{detail}") % { resource_name: @resource[:name], detail: detail }, detail ) 42 end
# File lib/puppet/provider/group/windows_adsi.rb 92 def delete 93 Puppet::Util::Windows::ADSI::Group.delete(@resource[:name]) 94 95 @deleted = true 96 end
# File lib/puppet/provider/group/groupadd.rb 112 def deletecmd 113 if @resource.forcelocal? 114 @custom_environment = Puppet::Util::Libuser.getenv 115 [command(:localdelete), @resource[:name]] 116 else 117 [command(:delete), @resource[:name]] 118 end 119 end
# File lib/puppet/functions/empty.rb 81 def deprecation_warning_for(arg_type) 82 file, line = Puppet::Pops::PuppetStack.top_of_stack 83 msg = _("Calling function empty() with %{arg_type} value is deprecated.") % { arg_type: arg_type } 84 Puppet.warn_once('deprecations', "empty-from-#{file}-#{line}", msg, file, line) 85 end
# File lib/puppet/functions/tree_each.rb 195 def depth_first?(options) 196 (order = options['order']).nil? ? true : order == 'depth_first' 197 end
# File lib/puppet/type/tidy.rb 232 def depthfirst? 233 true 234 end
Return the desired checksum or nil
# File lib/puppet/type/file.rb 1080 def desired_checksum(property, path) 1081 return if SOURCE_ONLY_CHECKSUMS.include?(self[:checksum]) 1082 1083 if self[:checksum] && self[:checksum_value] 1084 "{#{self[:checksum]}}#{self[:checksum_value]}" 1085 elsif property && property.name == :source 1086 meta = property.metadata 1087 return unless meta 1088 1089 # due to HttpMetadata the checksum type may fallback to mtime, so recheck 1090 return if SOURCE_ONLY_CHECKSUMS.include?(meta.checksum_type) 1091 meta.checksum 1092 elsif property && property.name == :content 1093 str = property.actual_content 1094 str ? parameter(:checksum).sum(str) : nil 1095 end 1096 end
# File lib/puppet/provider/user/user_role_add.rb 113 def destroy 114 run(deletecmd, "delete "+ (is_role? ? "role" : "user")) 115 end
Given a blob of output from `nimclient -o showres` and a package name, this method checks to see if there are multiple versions of the package available on the lpp_source. If there are, the method returns
- package_type, latest_version
-
(where package_type is one of :installp or :rpm).
If there is only one version of the package available, it returns [package_type, nil], because the caller doesn't need to pass the version string to the command-line command if there is only one version available. If the package is not available at all, the method simply returns nil (instead of a tuple).
# File lib/puppet/provider/package/nim.rb 270 def determine_latest_version(showres_output, package_name) 271 packages = parse_showres_output(showres_output) 272 unless packages.has_key?(package_name) 273 return nil 274 end 275 if (packages[package_name].count == 1) 276 version = packages[package_name].keys[0] 277 return packages[package_name][version], nil 278 else 279 versions = packages[package_name].keys 280 latest_version = (versions.sort { |a, b| Puppet::Util::Package.versioncmp(b, a) })[0] 281 return packages[package_name][latest_version], latest_version 282 end 283 end
# File lib/puppet/provider/package/nim.rb 285 def determine_package_type(showres_output, package_name, version) 286 packages = parse_showres_output(showres_output) 287 unless (packages.has_key?(package_name) and packages[package_name].has_key?(version)) 288 return nil 289 end 290 packages[package_name][version] 291 end
# File lib/puppet/functions/dig.rb 37 def dig(data, *args) 38 walked_path = [] 39 args.reduce(data) do | d, k | 40 return nil if d.nil? || k.nil? 41 if !(d.is_a?(Array) || d.is_a?(Hash)) 42 t = Puppet::Pops::Types::TypeCalculator.infer(d) 43 msg = _("The given data does not contain a Collection at %{walked_path}, got '%{type}'") % { walked_path: walked_path, type: t } 44 error_data = Puppet::DataTypes::Error.new( 45 msg, 46 'SLICE_ERROR', 47 {'walked_path' => walked_path, 'value_type' => t}, 48 'EXPECTED_COLLECTION' 49 ) 50 raise Puppet::ErrorWithData.new(error_data, msg) 51 end 52 53 walked_path << k 54 if d.is_a?(Array) && !k.is_a?(Integer) 55 t = Puppet::Pops::Types::TypeCalculator.infer(k) 56 msg = _("The given data requires an Integer index at %{walked_path}, got '%{type}'") % { walked_path: walked_path, type: t } 57 error_data = Puppet::DataTypes::Error.new( 58 msg, 59 'SLICE_ERROR', 60 {'walked_path' => walked_path, 'index_type' => t}, 61 'EXPECTED_INTEGER_INDEX' 62 ) 63 raise Puppet::ErrorWithData.new(error_data, msg) 64 end 65 d[k] 66 end 67 end
Return the appropriate digest algorithm with fallbacks in case puppet defaults have not been initialized.
# File lib/puppet/type/file/checksum.rb 48 def digest_algorithm 49 value || Puppet[:digest_algorithm].to_sym 50 end
# File lib/puppet/provider/package/dnfmodule.rb 127 def disable(args = @resource[:name]) 128 execute([command(:dnf), 'module', 'disable', '-d', '0', '-e', self.class.error_level, '-y', args]) 129 end
# File lib/puppet/provider/service/upstart.rb 300 def disable_post_0_9_0(over_text) 301 write_script_to(overscript, ensure_disabled_with_manual(over_text)) 302 end
# File lib/puppet/provider/service/upstart.rb 291 def disable_pre_0_6_7(script_text) 292 disabled_script = comment_start_block_in(script_text) 293 write_script_to(initscript, disabled_script) 294 end
# File lib/puppet/provider/service/upstart.rb 296 def disable_pre_0_9_0(script_text) 297 write_script_to(initscript, ensure_disabled_with_manual(script_text)) 298 end
# File lib/puppet/provider/package/yum.rb 363 def disableexcludes 364 scan_options(resource[:install_options], '--disableexcludes') 365 end
# File lib/puppet/provider/package/yum.rb 359 def disablerepo 360 scan_options(resource[:install_options], '--disablerepo') 361 end
# File lib/puppet/functions/camelcase.rb 59 def do_camelcase(x) 60 # x can only be a String or Numeric because type constraints have been automatically applied 61 x.is_a?(String) ? on_string(x) : x 62 end
# File lib/puppet/functions/capitalize.rb 58 def do_capitalize(x) 59 # x can only be a String or Numeric because type constraints have been automatically applied 60 x.is_a?(String) ? x.capitalize : x 61 end
# File lib/puppet/functions/chomp.rb 54 def do_chomp(x) 55 # x can only be a String or Numeric because type constraints have been automatically applied 56 x.is_a?(String) ? x.chomp : x 57 end
# File lib/puppet/functions/chop.rb 64 def do_chop(x) 65 # x can only be a String or Numeric because type constraints have been automatically applied 66 x.is_a?(String) ? x.chop : x 67 end
# File lib/puppet/functions/downcase.rb 87 def do_downcase(x) 88 x.is_a?(String) ? x.downcase : call_function('downcase', x) 89 end
# File lib/puppet/functions/lookup.rb 210 def do_lookup(scope, name, value_type, default_value, has_default, override, default_values_hash, merge, &block) 211 Puppet::Pops::Lookup.lookup(name, value_type, default_value, has_default, merge, 212 Puppet::Pops::Lookup::Invocation.new(scope, override, default_values_hash), &block) 213 end
# File lib/puppet/functions/lstrip.rb 55 def do_lstrip(x) 56 # x can only be a String or Numeric because type constraints have been automatically applied 57 x.is_a?(String) ? x.lstrip : x 58 end
# File lib/puppet/functions/match.rb 127 def do_match(s, regexp) 128 result = regexp.match(s) 129 result.to_a if result 130 end
# File lib/puppet/functions/rstrip.rb 55 def do_rstrip(x) 56 # x can only be a String or Numeric because type constraints have been automatically applied 57 x.is_a?(String) ? x.rstrip : x 58 end
# File lib/puppet/functions/strip.rb 55 def do_strip(x) 56 # x can only be a String or Numeric because type constraints have been automatically applied 57 x.is_a?(String) ? x.strip : x 58 end
# File lib/puppet/functions/upcase.rb 87 def do_upcase(x) 88 x.is_a?(String) ? x.upcase : call_function('upcase', x) 89 end
# File lib/puppet/face/epp.rb 369 def dump_parse(source, filename, options, show_filename = true) 370 output = String.new 371 evaluating_parser = Puppet::Pops::Parser::EvaluatingParser::EvaluatingEppParser.new 372 begin 373 if options[:validate] 374 parse_result = evaluating_parser.parse_string(source, filename) 375 else 376 # side step the assert_and_report step 377 parse_result = evaluating_parser.parser.parse_string(source) 378 end 379 if show_filename && options[:header] 380 output << "--- #{filename}\n" 381 end 382 fmt = options[:format] 383 if fmt.nil? || fmt == 'old' 384 output << Puppet::Pops::Model::ModelTreeDumper.new.dump(parse_result) << "\n" 385 else 386 require_relative '../../puppet/pops/pn' 387 pn = Puppet::Pops::Model::PNTransformer.transform(parse_result) 388 case fmt 389 when 'json' 390 options[:pretty] ? JSON.pretty_unparse(pn.to_data) : JSON.dump(pn.to_data) 391 else 392 pn.format(options[:pretty] ? Puppet::Pops::PN::Indent.new(' ') : nil, output) 393 end 394 end 395 rescue Puppet::ParseError => detail 396 if show_filename 397 Puppet.err("--- #{filename}") 398 end 399 Puppet.err(detail.message) 400 "" 401 end 402 end
Produces the effective template file from a module/template or file reference @api private
# File lib/puppet/face/epp.rb 556 def effective_template(file, env) 557 template_file = Puppet::Parser::Files.find_template(file, env) 558 if !template_file.nil? 559 template_file 560 elsif Puppet::FileSystem.exist?(file) 561 file 562 else 563 nil 564 end 565 end
# File lib/puppet/provider/package/portage.rb 252 def eix_get_version_for_slot(versions_and_slots, slot) 253 # [2.7.12:2.7 3.4.5:3.4 3.5.2:3.5] 3.5 254 return nil if versions_and_slots.nil? 255 versions_and_slots = versions_and_slots.split(',') 256 # [2.7.12:2.7 3.4.5:3.4 3.5.2:3.5] 257 versions_and_slots.map! { |version_and_slot| version_and_slot.split(':') } 258 # [2.7.12: 2.7 259 # 3.4.5: 3.4 260 # 3.5.2: 3.5] 261 version_for_slot = versions_and_slots.find { |version_and_slot| version_and_slot.last == slot } 262 # [3.5.2: 3.5] 263 version_for_slot.first if version_for_slot 264 # 3.5.2 265 end
# File lib/puppet/provider/package/portage.rb 242 def eix_get_version_for_versions(versions, target) 243 # [2.7.10-r1,2.7.12,3.4.3-r1,3.4.5,3.5.2] 3.5.2 244 return nil if versions.nil? 245 versions = versions.split(',') 246 # [2.7.10-r1 2.7.12 3.4.3-r1 3.4.5 3.5.2] 247 versions.find { |version| version == target } 248 # 3.5.2 249 end
# File lib/puppet/functions/emerg.rb 12 def emerg(scope, *values) 13 Puppet::Util::Log.log_func(scope, :emerg, values) 14 end
# File lib/puppet/provider/package/dnfmodule.rb 118 def enable(args = @resource[:name]) 119 execute([command(:dnf), 'module', 'enable', '-d', '0', '-e', self.class.error_level, '-y', args]) 120 end
# File lib/puppet/provider/service/upstart.rb 277 def enable_post_0_9_0(script_text, over_text) 278 over_text = remove_manual_from(over_text) 279 280 if enabled_post_0_9_0?(script_text, over_text) == :false 281 if script_text.match(START_ON) 282 over_text << extract_start_on_block_from(script_text) 283 else 284 over_text << "\nstart on runlevel [2,3,4,5]" 285 end 286 end 287 288 write_script_to(overscript, over_text) 289 end
# File lib/puppet/provider/service/upstart.rb 259 def enable_pre_0_9_0(text) 260 # We also need to remove any manual stanzas to ensure that it is enabled 261 text = remove_manual_from(text) 262 263 if enabled_pre_0_9_0?(text) == :false 264 enabled_script = 265 if text.match(COMMENTED_START_ON) 266 uncomment_start_block_in(text) 267 else 268 add_default_start_to(text) 269 end 270 else 271 enabled_script = text 272 end 273 274 write_script_to(initscript, enabled_script) 275 end
if the service file exists in rc.conf.d then it's already enabled
# File lib/puppet/provider/service/bsd.rb 26 def enabled? 27 rcfile = File.join(rcconf_dir, @resource[:name]) 28 return :true if Puppet::FileSystem.exist?(rcfile) 29 30 :false 31 end
Static services cannot be enabled or disabled manually. Indirect services should not be enabled or disabled due to limitations in systemd (see github.com/systemd/systemd/issues/6681).
# File lib/puppet/provider/service/systemd.rb 46 def enabled_insync?(current) 47 case cached_enabled?[:output] 48 when 'static' 49 # masking static services is OK, but enabling/disabling them is not 50 if @resource[:enable] == :mask 51 current == @resource[:enable] 52 else 53 Puppet.debug("Unable to enable or disable static service #{@resource[:name]}") 54 return true 55 end 56 when 'indirect' 57 Puppet.debug("Service #{@resource[:name]} is in 'indirect' state and cannot be enabled/disabled") 58 return true 59 else 60 current == @resource[:enable] 61 end 62 end
# File lib/puppet/provider/service/upstart.rb 236 def enabled_post_0_9_0?(script_text, over_text) 237 # This version has manual stanzas and override files 238 # So we check to see if an uncommented start on or manual stanza is the last one in the 239 # conf file and any override files. The last one in the file wins. 240 enabled = :false 241 242 script_text.each_line do |line| 243 if line.match(START_ON) 244 enabled = :true 245 elsif line.match(MANUAL) 246 enabled = :false 247 end 248 end 249 over_text.each_line do |line| 250 if line.match(START_ON) 251 enabled = :true 252 elsif line.match(MANUAL) 253 enabled = :false 254 end 255 end if over_text 256 enabled 257 end
# File lib/puppet/provider/service/upstart.rb 212 def enabled_pre_0_6_7?(script_text) 213 # Upstart version < 0.6.7 means no manual stanza. 214 if script_text.match(START_ON) 215 return :true 216 else 217 return :false 218 end 219 end
# File lib/puppet/provider/service/upstart.rb 221 def enabled_pre_0_9_0?(script_text) 222 # Upstart version < 0.9.0 means no override files 223 # So we check to see if an uncommented start on or manual stanza is the last one in the file 224 # The last one in the file wins. 225 enabled = :false 226 script_text.each_line do |line| 227 if line.match(START_ON) 228 enabled = :true 229 elsif line.match(MANUAL) 230 enabled = :false 231 end 232 end 233 enabled 234 end
# File lib/puppet/provider/package/yum.rb 355 def enablerepo 356 scan_options(resource[:install_options], '--enablerepo') 357 end
# File lib/puppet/functions/eyaml_lookup_key.rb 100 def encrypted?(data) 101 /.*ENC\[.*?\]/ =~ data ? true : false 102 end
# File lib/puppet/provider/service/upstart.rb 371 def ensure_disabled_with_manual(text) 372 remove_manual_from(text) + "\nmanual" 373 end
Matches given Array against given pattern and returns an Array with mapped match results.
@param array [Array<String>] the array of strings to match @param pattern [String, Regexp, Puppet::Pops::Types::PPatternType, Puppet::Pops::PRegexpType, Array] the pattern @return [Array<Array<String, nil>>] Array with matches (see {#match}), non matching entries produce a nil entry
# File lib/puppet/functions/match.rb 75 def enumerable_match(array, pattern) 76 array.map {|s| match(s, pattern) } 77 end
# File lib/puppet/face/node/clean.rb 95 def environment 96 @environment ||= Puppet.lookup(:current_environment) 97 end
# File lib/puppet/functions/epp.rb 47 def epp(scope, path, parameters = nil) 48 Puppet::Pops::Evaluator::EppEvaluator.epp(scope, path, scope.compiler.environment, parameters) 49 end
# File lib/puppet/face/help.rb 142 def erb(name) 143 template = (Pathname(__FILE__).dirname + "help" + name) 144 erb = Puppet::Util.create_erb(template.read) 145 erb.filename = template.to_s 146 return erb 147 end
# File lib/puppet/functions/err.rb 12 def err(scope, *values) 13 Puppet::Util::Log.log_func(scope, :err, values) 14 end
# File lib/puppet/provider/service/freebsd.rb 17 def error(msg) 18 raise Puppet::Error, msg 19 end
Create any children via recursion or whatever.
# File lib/puppet/type/file.rb 531 def eval_generate 532 return [] unless self.recurse? 533 534 recurse 535 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 225 def exclude_from_docs?(appname) 226 %w{face_base indirection_base report status}.include? appname 227 end
# File lib/puppet/provider/package/pkg.rb 292 def exec_cmd(*cmd) 293 output = Puppet::Util::Execution.execute(cmd, :failonfail => false, :combine => true) 294 {:out => output, :exit => output.exitstatus} 295 end
# File lib/puppet/provider/user/hpux.rb 93 def exec_getprpw(user,opts) 94 Puppet::Util::Execution.execute("/usr/lbin/getprpw #{opts} #{user}", { :combine => true }) 95 end
# File lib/puppet/provider/service/systemd.rb 172 def exist? 173 result = execute([command(:systemctl), 'cat', '--', @resource[:name]], :failonfail => false) 174 result.exitstatus == 0 175 end
# File lib/puppet/provider/group/groupadd.rb 25 def exists? 26 return !!localgid if @resource.forcelocal? 27 super 28 end
Get expiry from system and convert to Puppet-style date
# File lib/puppet/provider/user/pw.rb 97 def expiry 98 expiry = self.get(:expiry) 99 expiry = :absent if expiry == 0 100 101 if expiry != :absent 102 t = Time.at(expiry) 103 expiry = "%4d-%02d-%02d" % [t.year, t.month, t.mday] 104 end 105 106 expiry 107 end
# File lib/puppet/provider/service/upstart.rb 357 def extract_start_on_block_from(text) 358 parens = 0 359 text.lines.map do |line| 360 if line.match(START_ON) || parens > 0 361 parens += unbalanced_parens_on(remove_trailing_comments_from(line)) 362 line 363 end 364 end.join('') 365 end
Extract value name from service or rcvar
# File lib/puppet/provider/service/freebsd.rb 32 def extract_value_name(name, rc_index, regex, regex_index) 33 value_name = self.rcvar[rc_index] 34 self.error("No #{name} name found in rcvar") if value_name.nil? 35 value_name = value_name.gsub!(regex, regex_index) 36 self.error("#{name} name is empty") if value_name.nil? 37 self.debug("#{name} name is #{value_name}") 38 value_name 39 end
# File lib/puppet/functions/eyaml_lookup_key.rb 24 def eyaml_lookup_key(key, options, context) 25 return context.cached_value(key) if context.cache_has_key(key) 26 27 # Can't do this with an argument_mismatch dispatcher since there is no way to declare a struct that at least 28 # contains some keys but may contain other arbitrary keys. 29 unless options.include?('path') 30 #TRANSLATORS 'eyaml_lookup_key':, 'path', 'paths' 'glob', 'globs', 'mapped_paths', and lookup_key should not be translated 31 raise ArgumentError, 32 _("'eyaml_lookup_key': one of 'path', 'paths' 'glob', 'globs' or 'mapped_paths' must be declared in hiera.yaml"\ 33 " when using this lookup_key function") 34 end 35 36 # nil key is used to indicate that the cache contains the raw content of the eyaml file 37 raw_data = context.cached_value(nil) 38 if raw_data.nil? 39 raw_data = load_data_hash(options, context) 40 context.cache(nil, raw_data) 41 end 42 context.not_found unless raw_data.include?(key) 43 context.cache(key, decrypt_value(raw_data[key], context, options, key)) 44 end
Make sure the file we wrote out is what we think it is. @param [Puppet::Parameter] property the param or property that wrote the file, or nil @param [String] path to the file @param [String] the checksum for the local file
@api private
# File lib/puppet/type/file.rb 1071 def fail_if_checksum_is_wrong(property, path, content_checksum) 1072 desired_checksum = desired_checksum(property, path) 1073 1074 if desired_checksum && content_checksum != desired_checksum 1075 self.fail _("File written to disk did not match desired checksum; discarding changes (%{content_checksum} vs %{desired_checksum})") % { content_checksum: content_checksum, desired_checksum: desired_checksum } 1076 end 1077 end
# File lib/puppet/provider/file/windows.rb 140 def file 141 @file ||= Puppet::FileSystem.pathname(resource[:path]) 142 end
# File lib/puppet/functions/filter.rb 109 def filter_Enumerable_1(enumerable) 110 result = [] 111 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 112 begin 113 enum.each do |value| 114 result << value if yield(value) 115 end 116 rescue StopIteration 117 end 118 result 119 end
# File lib/puppet/functions/filter.rb 121 def filter_Enumerable_2(enumerable) 122 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 123 if enum.hash_style? 124 result = {} 125 enum.each {| k, v| result[k] = v if yield(k, v) } 126 result 127 else 128 result = [] 129 begin 130 enum.each_with_index do |value, index| 131 result << value if yield(index, value) 132 end 133 rescue StopIteration 134 end 135 result 136 end 137 end
# File lib/puppet/functions/filter.rb 95 def filter_Hash_1(hash) 96 result = hash.select {|x, y| yield([x, y]) } 97 # Ruby 1.8.7 returns Array 98 result = Hash[result] unless result.is_a? Hash 99 result 100 end
# File lib/puppet/functions/filter.rb 102 def filter_Hash_2(hash) 103 result = hash.select {|x, y| yield(x, y) } 104 # Ruby 1.8.7 returns Array 105 result = Hash[result] unless result.is_a? Hash 106 result 107 end
# File lib/puppet/functions/find_file.rb 36 def find_file(scope, *args) 37 args.each do |file| 38 found = Puppet::Parser::Files.find_file(file, scope.compiler.environment) 39 if found && Puppet::FileSystem.exist?(found) 40 return found 41 end 42 end 43 nil 44 end
# File lib/puppet/functions/find_file.rb 32 def find_file_array(scope, array) 33 find_file(scope, *array) 34 end
# File lib/puppet/functions/find_template.rb 55 def find_template(scope, *args) 56 args.each do |file| 57 found = Puppet::Parser::Files.find_template(file, scope.compiler.environment) 58 if found && Puppet::FileSystem.exist?(found) 59 return found 60 end 61 end 62 nil 63 end
# File lib/puppet/functions/find_template.rb 51 def find_template_array(scope, array) 52 find_template(scope, *array) 53 end
# File lib/puppet/provider/group/groupadd.rb 136 def findgroup(key, value) 137 group_file = '/etc/group' 138 group_keys = [:group_name, :password, :gid, :user_list] 139 140 unless @groups 141 unless Puppet::FileSystem.exist?(group_file) 142 raise Puppet::Error.new("Forcelocal set for group resource '#{resource[:name]}', but #{group_file} does not exist") 143 end 144 145 @groups = [] 146 Puppet::FileSystem.each_line(group_file) do |line| 147 group = line.chomp.split(':') 148 @groups << Hash[group_keys.zip(group)] 149 end 150 end 151 152 @groups.find { |param| param[key] == value } || false 153 end
# File lib/puppet/provider/user/useradd.rb 91 def finduser(key, value) 92 passwd_file = '/etc/passwd' 93 passwd_keys = [:account, :password, :uid, :gid, :gecos, :directory, :shell] 94 95 unless @users 96 unless Puppet::FileSystem.exist?(passwd_file) 97 raise Puppet::Error.new("Forcelocal set for user resource '#{resource[:name]}', but #{passwd_file} does not exist") 98 end 99 100 @users = [] 101 Puppet::FileSystem.each_line(passwd_file) do |line| 102 user = line.chomp.split(':') 103 @users << Hash[passwd_keys.zip(user)] 104 end 105 end 106 @users.find { |param| param[key] == value } || false 107 end
We have to do some extra finishing, to retrieve our bucket if there is one.
# File lib/puppet/type/file.rb 524 def finish 525 # Look up our bucket, if there is one 526 bucket 527 super 528 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 19 def finkcmd(*args) 20 fink(*args) 21 end
Uses the wrapper to prevent failure when the service is not running; rcctl(8) return non-zero in that case.
# File lib/puppet/provider/service/openbsd.rb 88 def flags 89 output = execute([command(:rcctl), "get", @resource[:name], "flags"], 90 :failonfail => false, :combine => false, :squelch => false).chomp 91 self.debug("Flags are: \"#{output}\"") 92 output 93 end
# File lib/puppet/provider/service/openbsd.rb 95 def flags=(value) 96 self.debug("Changing flags from #{flags} to #{value}") 97 rcctl(:set, @resource[:name], :flags, value) 98 # If the service is already running, force a restart as the flags have been changed. 99 rcctl(:restart, @resource[:name]) if running? 100 end
# File lib/puppet/functions/flatten.rb 62 def flatten_args(*args) 63 args.flatten() 64 end
# File lib/puppet/network/formats.rb 215 def flatten_array(array) 216 a={} 217 array.each_with_index do |el, i| 218 if el.is_a? Hash 219 flatten_hash(el).map do |el_k, el_v| 220 a["#{i}.#{el_k}"] = el_v 221 end 222 else 223 a["#{i}"] = el 224 end 225 end 226 a 227 end
# File lib/puppet/network/formats.rb 193 def flatten_hash(hash) 194 hash.each_with_object({}) do |(k, v), h| 195 if v.is_a? Hash 196 flatten_hash(v).map do |h_k, h_v| 197 h["#{k}.#{h_k}"] = h_v 198 end 199 elsif v.is_a? Array 200 v.each_with_index do |el, i| 201 if el.is_a? Hash 202 flatten_hash(el).map do |el_k, el_v| 203 h["#{k}.#{i}.#{el_k}"] = el_v 204 end 205 else 206 h["#{k}.#{i}"] = el 207 end 208 end 209 else 210 h[k] = v 211 end 212 end 213 end
# File lib/puppet/provider/package/dnfmodule.rb 135 def flavor 136 @property_hash[:flavor] 137 end
# File lib/puppet/provider/package/dnfmodule.rb 139 def flavor=(value) 140 install if flavor != @resource.should(:flavor) 141 end
Only flush if we created or modified a group, not deleted
# File lib/puppet/provider/group/windows_adsi.rb 99 def flush 100 @group.commit if @group && !@deleted 101 end
# File lib/puppet/provider/user/directoryservice.rb 559 def flush_dscl_cache 560 dscacheutil '-flushcache' 561 end
# File lib/puppet/functions/each.rb 141 def foreach_Enumerable_1(enumerable) 142 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 143 begin 144 enum.each do |value| 145 yield value 146 end 147 rescue StopIteration 148 end 149 # produces the receiver 150 enumerable 151 end
# File lib/puppet/functions/each.rb 153 def foreach_Enumerable_2(enumerable) 154 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 155 if enum.hash_style? 156 enum.each { |entry| yield(*entry) } 157 else 158 begin 159 enum.each_with_index do |value, index| 160 yield(index, value) 161 end 162 rescue StopIteration 163 end 164 end 165 # produces the receiver 166 enumerable 167 end
# File lib/puppet/functions/each.rb 119 def foreach_Hash_1(hash) 120 begin 121 hash.each_pair do |pair| 122 yield(pair) 123 end 124 rescue StopIteration 125 end 126 # produces the receiver 127 hash 128 end
# File lib/puppet/functions/each.rb 130 def foreach_Hash_2(hash) 131 begin 132 hash.each_pair do |pair| 133 yield(*pair) 134 end 135 rescue StopIteration 136 end 137 # produces the receiver 138 hash 139 end
# File lib/puppet/util/log/destinations.rb 120 def format(msg) 121 # logstash_event format is documented at 122 # https://logstash.jira.com/browse/LOGSTASH-675 123 124 data = msg.to_hash 125 data['version'] = 1 126 data['@timestamp'] = data['time'] 127 data.delete('time') 128 129 data 130 end
# File lib/puppet/functions/strftime.rb 198 def format_timespan(time_object, format) 199 time_object.format(format) 200 end
# File lib/puppet/functions/strftime.rb 202 def format_timestamp(time_object, format, timezone = nil) 203 time_object.format(format, timezone) 204 end
# File lib/puppet/functions/unwrap.rb 52 def from_any(arg) 53 unwrapped = arg 54 if block_given? 55 yield(unwrapped) 56 else 57 unwrapped 58 end 59 end
# File lib/puppet/functions/unwrap.rb 43 def from_sensitive(arg) 44 unwrapped = arg.unwrap 45 if block_given? 46 yield(unwrapped) 47 else 48 unwrapped 49 end 50 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 116 def generate 117 return [] unless self.purge? 118 resource_type.instances. 119 reject { |r| catalog.resource_refs.include? r.ref }. 120 select { |r| check(r) }. 121 select { |r| r.class.validproperty?(:ensure) }. 122 select { |r| able_to_ensure_absent?(r) }. 123 each { |resource| 124 resource.copy_metaparams(@parameters) 125 resource.purging 126 } 127 end
# File lib/puppet/functions/size.rb 12 def generic_size(arg) 13 call_function('length', arg) 14 end
Gets a result from given value and a navigation string
# File lib/puppet/functions/get.rb 126 def get_from_value(value, navigation, default_value = nil, &block) 127 return default_value if value.nil? 128 return value if navigation.empty? 129 130 # Note: split_key always processes the initial segment as a string even if it could be an integer. 131 # This since it is designed for lookup keys. For a numeric first segment 132 # like '0.1' the wanted result is `[0,1]`, not `["0", 1]`. The workaround here is to 133 # prefix the navigation with `"x."` thus giving split_key a first segment that is a string. 134 # The fake segment is then dropped. 135 segments = split_key("x." + navigation) {|err| _("Syntax error in dotted-navigation string")} 136 segments.shift 137 138 begin 139 result = call_function('dig', value, *segments) 140 return result.nil? ? default_value : result 141 rescue Puppet::ErrorWithData => e 142 if block_given? 143 yield(e.error_data) 144 else 145 raise e 146 end 147 end 148 end
Gets a result from a $var name and a navigation string
# File lib/puppet/functions/getvar.rb 82 def get_from_var_name(scope, var_string, navigation, default_value = nil, &block) 83 catch(:undefined_variable) do 84 return call_function_with_scope(scope,'get', scope.lookupvar(var_string), navigation, default_value, &block) 85 end 86 default_value 87 end
# File lib/puppet/provider/package/openbsd.rb 175 def get_full_name(latest = false) 176 # In case of a real update (i.e., the package already exists) then 177 # pkg_add(8) can handle the flavors. However, if we're actually 178 # installing with 'latest', we do need to handle the flavors. This is 179 # done so we can feed pkg_add(8) the full package name to install to 180 # prevent ambiguity. 181 if latest && resource[:flavor] 182 "#{resource[:name]}--#{resource[:flavor]}" 183 elsif latest 184 # Don't depend on get_version for updates. 185 @resource[:name] 186 else 187 # If :ensure contains a version, use that instead of looking it up. 188 # This allows for installing packages with the same stem, but multiple 189 # version such as openldap-server. 190 if @resource[:ensure].to_s =~ /(\d[^-]*)$/ 191 use_version = @resource[:ensure] 192 else 193 use_version = get_version 194 end 195 196 [ @resource[:name], use_version, @resource[:flavor]].join('-').gsub(/-+$/, '') 197 end 198 end
# File lib/puppet/provider/package/pip.rb 216 def get_install_command_options() 217 should = @resource[:ensure] 218 command_options = %w{install -q} 219 command_options += install_options if @resource[:install_options] 220 221 if @resource[:source] 222 if String === should 223 command_options << "#{@resource[:source]}@#{should}#egg=#{@resource[:name]}" 224 else 225 command_options << "#{@resource[:source]}#egg=#{@resource[:name]}" 226 end 227 228 return command_options 229 end 230 231 if should == :latest 232 command_options << "--upgrade" << @resource[:name] 233 234 return command_options 235 end 236 237 unless String === should 238 command_options << @resource[:name] 239 240 return command_options 241 end 242 243 begin 244 should_range = PIP_VERSION_RANGE.parse(should, PIP_VERSION) 245 rescue PIP_VERSION_RANGE::ValidationFailure, PIP_VERSION::ValidationFailure 246 Puppet.debug("Cannot parse #{should} as a pip version range, falling through.") 247 command_options << "#{@resource[:name]}==#{should}" 248 249 return command_options 250 end 251 252 if should_range.is_a?(PIP_VERSION_RANGE::Eq) 253 command_options << "#{@resource[:name]}==#{should}" 254 255 return command_options 256 end 257 258 should = best_version(should_range) 259 260 if should == should_range 261 # when no suitable version for the given range was found, let pip handle 262 if should.is_a?(PIP_VERSION_RANGE::MinMax) 263 command_options << "#{@resource[:name]} #{should.split.join(',')}" 264 else 265 command_options << "#{@resource[:name]} #{should}" 266 end 267 else 268 command_options << "#{@resource[:name]}==#{should}" 269 end 270 271 command_options 272 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 572 def get_shadow_hash_data(users_plist) 573 if users_plist['ShadowHashData'] 574 password_hash_plist = users_plist['ShadowHashData'][0] 575 self.class.convert_binary_to_hash(password_hash_plist) 576 else 577 false 578 end 579 end
# File lib/puppet/provider/service/debian.rb 61 def get_start_link_count 62 Dir.glob("/etc/rc*.d/S??#{@resource[:name]}").length 63 end
# File lib/puppet/provider/user/directoryservice.rb 563 def get_users_plist(username) 564 # This method will retrieve the data stored in a user's plist and 565 # return it as a native Ruby hash. 566 path = "#{users_plist_dir}/#{username}.plist" 567 Puppet::Util::Plist.read_plist_file(path) 568 end
# File lib/puppet/provider/user/useradd.rb 290 def get_value_for_property(property) 291 return nil if property == :ensure 292 return nil if property_manages_password_age?(property) 293 return nil if property == :groups and @resource.forcelocal? 294 return nil if property == :expiry and @resource.forcelocal? 295 value = @resource.should(property) 296 return nil if !value || value == "" 297 298 value 299 end
# File lib/puppet/face/epp.rb 404 def get_values(compiler, options) 405 template_values = nil 406 values_file = options[:values_file] 407 if values_file 408 begin 409 if values_file =~ /\.yaml$/ 410 template_values = Puppet::Util::Yaml.safe_load_file(values_file, [Symbol]) 411 elsif values_file =~ /\.pp$/ 412 evaluating_parser = Puppet::Pops::Parser::EvaluatingParser.new 413 template_values = evaluating_parser.evaluate_file(compiler.topscope, values_file) 414 else 415 Puppet.err(_("Only .yaml or .pp can be used as a --values_file")) 416 end 417 rescue => e 418 Puppet.err(_("Could not load --values_file %{error}") % { error: e.message }) 419 end 420 if !(template_values.nil? || template_values.is_a?(Hash)) 421 Puppet.err(_("--values_file option must evaluate to a Hash or undef/nil, got: '%{template_class}'") % { template_class: template_values.class }) 422 end 423 end 424 425 values = options[:values] 426 if values 427 evaluating_parser = Puppet::Pops::Parser::EvaluatingParser.new 428 result = evaluating_parser.evaluate_string(compiler.topscope, values, 'values-hash') 429 case result 430 when nil 431 template_values 432 when Hash 433 template_values.nil? ? result : template_values.merge(result) 434 else 435 Puppet.err(_("--values option must evaluate to a Hash or undef, got: '%{values_class}'") % { values_class: result.class }) 436 end 437 else 438 template_values 439 end 440 end
# File lib/puppet/provider/package/openbsd.rb 200 def get_version 201 execpipe([command(:pkginfo), "-I", @resource[:name]]) do |process| 202 # our regex for matching pkg_info output 203 regex = /^(.*)-(\d[^-]*)[-]?(\w*)(.*)$/ 204 master_version = 0 205 version = -1 206 207 process.each_line do |line| 208 match = regex.match(line.split[0]) 209 if match 210 # now we return the first version, unless ensure is latest 211 version = match.captures[1] 212 return version unless @resource[:ensure] == "latest" 213 214 master_version = version unless master_version > version 215 end 216 end 217 218 return master_version unless master_version == 0 219 return '' if version == -1 220 raise Puppet::Error, _("%{version} is not available for this package") % { version: version } 221 end 222 rescue Puppet::ExecutionFailure 223 return nil 224 end
Get the process ID for a running process. Requires the 'pattern' parameter.
# File lib/puppet/provider/service/base.rb 32 def getpid 33 @resource.fail "Either stop/status commands or a pattern must be specified" unless @resource[:pattern] 34 regex = Regexp.new(@resource[:pattern]) 35 ps = getps 36 37 self.debug "Executing '#{ps}'" 38 table = Puppet::Util::Execution.execute(ps) 39 40 # The output of the PS command can be a mashup of several different 41 # encodings depending on which processes are running and what 42 # arbitrary data has been used to set their name in the process table. 43 # 44 # First, try a polite conversion to in order to match the UTF-8 encoding 45 # of our regular expression. 46 table = Puppet::Util::CharacterEncoding.convert_to_utf_8(table) 47 # If that fails, force to UTF-8 and then scrub as most uses are scanning 48 # for ACII-compatible program names. 49 table.force_encoding(Encoding::UTF_8) unless table.encoding == Encoding::UTF_8 50 table = table.scrub unless table.valid_encoding? 51 52 table.each_line { |line| 53 if regex.match(line) 54 self.debug "Process matched: #{line}" 55 ary = line.sub(/^[[:space:]]+/u, '').split(/[[:space:]]+/u) 56 return ary[1] 57 end 58 } 59 60 nil 61 end
get the proper 'ps' invocation for the platform ported from the facter 2.x implementation, since facter 3.x is dropping the fact (for which this was the only use)
# File lib/puppet/provider/service/base.rb 18 def getps 19 case Puppet.runtime[:facter].value('os.name') 20 when 'OpenWrt' 21 'ps www' 22 when 'FreeBSD', 'NetBSD', 'OpenBSD', 'Darwin', 'DragonFly' 23 'ps auxwww' 24 else 25 'ps -ef' 26 end 27 end
# File lib/puppet/provider/group/groupadd.rb 30 def gid 31 return localgid if @resource.forcelocal? 32 get(:gid) 33 end
# File lib/puppet/provider/file/posix.rb 40 def gid2name(id) 41 return id.to_s if id.is_a?(Symbol) or id.is_a?(String) 42 return nil if id > Puppet[:maximum_uid].to_i 43 44 begin 45 group = Etc.getgrgid(id) 46 rescue TypeError, ArgumentError 47 return nil 48 end 49 50 if group.gid == "" 51 return nil 52 else 53 return group.name 54 end 55 end
# File lib/puppet/provider/group/windows_adsi.rb 107 def gid=(value) 108 fail "gid is read-only" 109 end
# File lib/puppet/provider/file/posix.rb 95 def group 96 stat = resource.stat 97 return :absent unless stat 98 99 currentvalue = stat.gid 100 101 # On OS X, files that are owned by -2 get returned as really 102 # large GIDs instead of negative ones. This isn't a Ruby bug, 103 # it's an OS X bug, since it shows up in perl, too. 104 if currentvalue > Puppet[:maximum_uid].to_i 105 self.warning _("Apparently using negative GID (%{currentvalue}) on a platform that does not consistently handle them") % { currentvalue: currentvalue } 106 currentvalue = :silly 107 end 108 109 currentvalue 110 end
Convert a gropu name to an id.
# File lib/puppet/provider/user/ldap.rb 116 def group2id(group) 117 Puppet::Type.type(:group).provider(:ldap).name2id(group) 118 end
# File lib/puppet/provider/file/posix.rb 112 def group=(should) 113 # Set our method appropriately, depending on links. 114 if resource[:links] == :manage 115 method = :lchown 116 else 117 method = :chown 118 end 119 120 begin 121 File.send(method, nil, should, resource[:path]) 122 rescue => detail 123 raise Puppet::Error, _("Failed to set group to '%{should}': %{detail}") % { should: should, detail: detail }, detail.backtrace 124 end 125 end
# File lib/puppet/functions/group_by.rb 41 def group_by_1(collection) 42 collection.group_by do |item| 43 yield(item) 44 end.freeze 45 end
# File lib/puppet/functions/group_by.rb 57 def group_by_2(collection) 58 collection.group_by do |k, v| 59 yield(k, v) 60 end.freeze 61 end
# File lib/puppet/functions/group_by.rb 47 def group_by_2a(array) 48 grouped = array.size.times.zip(array).group_by do |k, v| 49 yield(k, v) 50 end 51 52 grouped.each_with_object({}) do |(k, v), hsh| 53 hsh[k] = v.map { |item| item[1] } 54 end.freeze 55 end
# File lib/puppet/provider/user/ldap.rb 122 def group_manager 123 Puppet::Type.type(:group).provider(:ldap).manager 124 end
# File lib/puppet/provider/user/ldap.rb 126 def group_properties(values) 127 if values.empty? or values == :absent 128 {:ensure => :present} 129 else 130 {:ensure => :present, :members => values} 131 end 132 end
Find all groups this user is a member of in ldap.
# File lib/puppet/provider/user/ldap.rb 58 def groups 59 # We want to cache the current result, so we know if we 60 # have to remove old values. 61 unless @property_hash[:groups] 62 result = group_manager.search("memberUid=#{name}") 63 unless result 64 return @property_hash[:groups] = :absent 65 end 66 67 return @property_hash[:groups] = result.collect { |r| r[:name] }.sort.join(",") 68 end 69 @property_hash[:groups] 70 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 327 def groups=(value) 328 guid = self.class.get_attribute_from_dscl('Users', @resource.name, 'GeneratedUID')['dsAttrTypeStandard:GeneratedUID'][0] 329 groups_to_add = value.split(',') - groups.split(',') 330 groups_to_add.each do |group| 331 merge_attribute_with_dscl('Groups', group, 'GroupMembership', @resource.name) 332 merge_attribute_with_dscl('Groups', group, 'GroupMembers', guid) 333 end 334 end
# File lib/puppet/provider/user/useradd.rb 400 def groups? 401 !!@resource[:groups] 402 end
# File lib/puppet/provider/user/windows_adsi.rb 47 def groups_insync?(current, should) 48 return false unless current 49 50 # By comparing account SIDs we don't have to worry about case 51 # sensitivity, or canonicalization of account names. 52 53 # Cannot use munge of the group property to canonicalize @should 54 # since the default array_matching comparison is not commutative 55 56 # dupes automatically weeded out when hashes built 57 current_groups = Puppet::Util::Windows::ADSI::Group.name_sid_hash(current) 58 specified_groups = Puppet::Util::Windows::ADSI::Group.name_sid_hash(should) 59 60 current_sids = current_groups.keys.to_a 61 specified_sids = specified_groups.keys.to_a 62 63 if @resource[:membership] == :inclusive 64 current_sids.sort == specified_sids.sort 65 else 66 (specified_sids & current_sids) == specified_sids 67 end 68 end
# File lib/puppet/provider/user/windows_adsi.rb 70 def groups_to_s(groups) 71 return '' if groups.nil? || !groups.kind_of?(Array) 72 groups = groups.map do |group_name| 73 sid = Puppet::Util::Windows::SID.name_to_principal(group_name) 74 if sid.account =~ /\\/ 75 account, _ = Puppet::Util::Windows::ADSI::Group.parse_name(sid.account) 76 else 77 account = sid.account 78 end 79 resource.debug("#{sid.domain}\\#{account} (#{sid.sid})") 80 "#{sid.domain}\\#{account}" 81 end 82 return groups.join(',') 83 end
# File lib/puppet/util/log/destinations.rb 28 def handle(msg) 29 # XXX Syslog currently has a bug that makes it so you 30 # cannot log a message with a '%' in it. So, we get rid 31 # of them. 32 if msg.source == "Puppet" 33 msg.to_s.split("\n").each do |line| 34 @syslog.send(msg.level, line.gsub("%", '%%')) 35 end 36 else 37 msg.to_s.split("\n").each do |line| 38 @syslog.send(msg.level, "(%s) %s" % [msg.source.to_s.delete("%"), 39 line.gsub("%", '%%') 40 ] 41 ) 42 end 43 end 44 end
# File lib/puppet/provider/user/pw.rb 87 def has_sensitive_data?(property = nil) 88 #Check for sensitive values? 89 properties = property ? [property] : Puppet::Type.type(:user).validproperties 90 properties.any? do |prop| 91 p = @resource.parameter(prop) 92 p && p.respond_to?(:is_sensitive) && p.is_sensitive 93 end 94 end
# File lib/puppet/functions/lookup.rb 215 def hash_args(options_hash) 216 [ 217 options_hash['value_type'], 218 options_hash['default_value'], 219 options_hash.include?('default_value'), 220 options_hash['override'] || {}, 221 options_hash['default_values_hash'] || {}, 222 options_hash['merge'] 223 ] 224 end
Mark that our init script supports 'status' commands.
# File lib/puppet/provider/service/init.rb 111 def hasstatus=(value) 112 case value 113 when true, "true"; @parameters[:hasstatus] = true 114 when false, "false"; @parameters[:hasstatus] = false 115 else 116 raise Puppet::Error, "Invalid 'hasstatus' value #{value.inspect}" 117 end 118 end
# File lib/puppet/face/help.rb 87 def help_for_help?(args) 88 args.length == 1 && args.first == 'help' 89 end
# File lib/puppet/functions/hocon_data.rb 28 def hocon_data(options, context) 29 path = options['path'] 30 context.cached_file_data(path) do |content| 31 begin 32 Hocon.parse(content) 33 rescue Hocon::ConfigError => ex 34 raise Puppet::DataBinding::LookupError, _("Unable to parse (%{path}): %{message}") % { path: path, message: ex.message } 35 end 36 end 37 end
# File lib/puppet/provider/package/dpkg.rb 177 def hold 178 Tempfile.open('puppet_dpkg_set_selection') do |tmpfile| 179 tmpfile.write("#{@resource[:name]} hold\n") 180 tmpfile.flush 181 execute([:dpkg, "--set-selections"], :failonfail => false, :combine => false, :stdinfile => tmpfile.path.to_s) 182 end 183 end
# File lib/puppet/provider/user/useradd.rb 81 def home 82 return localhome if @resource.forcelocal? 83 get(:home) 84 end
# File lib/puppet/provider/user/windows_adsi.rb 133 def home=(value) 134 user['HomeDirectory'] = value 135 end
# File lib/puppet/face/help.rb 206 def horribly_extract_summary_from(appname) 207 help = Puppet::Application[appname].help.split("\n") 208 # Now we find the line with our summary, extract it, and return it. This 209 # depends on the implementation coincidence of how our pages are 210 # formatted. If we can't match the pattern we expect we return the empty 211 # string to ensure we don't blow up in the summary. --daniel 2011-04-11 212 while line = help.shift do #rubocop:disable Lint/AssignmentInCondition 213 md = /^puppet-#{appname}\([^\)]+\) -- (.*)$/.match(line) 214 if md 215 return md[1] 216 end 217 end 218 return '' 219 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 22 def id2name(id) 23 if Puppet::Util::Windows::SID.valid_sid?(id) 24 Puppet::Util::Windows::SID.sid_to_name(id) 25 else 26 id 27 end 28 end
# File lib/puppet/provider/package/sun.rb 127 def if_have_value(prefix, value) 128 if value 129 [prefix, value] 130 else 131 [] 132 end 133 end
# File lib/puppet/functions/import.rb 5 def import(*args) 6 raise Puppet::Pops::SemanticError.new(Puppet::Pops::Issues::DISCONTINUED_IMPORT) 7 end
# File lib/puppet/functions/include.rb 40 def include(scope, *classes) 41 if Puppet[:tasks] 42 raise Puppet::ParseErrorWithIssue.from_issue_and_stack( 43 Puppet::Pops::Issues::CATALOG_OPERATION_NOT_SUPPORTED_WHEN_SCRIPTING, 44 {:operation => 'include'}) 45 end 46 47 classes = scope.transform_and_assert_classnames(classes.flatten) 48 result = classes.map {|name| Puppet::Pops::Types::TypeFactory.host_class(name) } 49 scope.compiler.evaluate_classes(classes, scope, false) 50 51 # Result is an Array[Class, 1, n] which allows chaining other operations 52 result 53 end
# File lib/puppet/functions/index.rb 135 def index_Enumerable_1(enumerable) 136 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 137 if enum.hash_style? 138 enum.each { |entry| return entry[0] if yield(entry[1]) } 139 else 140 enum.each_with_index { |e, i| return i if yield(e) } 141 end 142 nil 143 end
# File lib/puppet/functions/index.rb 145 def index_Enumerable_2(enumerable) 146 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 147 if enum.hash_style? 148 enum.each { |entry| return entry[0] if yield(*entry) } 149 else 150 enum.each_with_index { |e, i| return i if yield(i, e) } 151 end 152 nil 153 end
# File lib/puppet/functions/index.rb 125 def index_Hash_1(hash) 126 hash.each_pair { |x, y| return x if yield(y) } 127 nil 128 end
# File lib/puppet/functions/index.rb 130 def index_Hash_2(hash) 131 hash.each_pair.any? { |x, y| return x if yield(x, y) } 132 nil 133 end
# File lib/puppet/functions/index.rb 159 def index_value(enumerable, match) 160 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 161 if enum.hash_style? 162 enum.each { |entry| return entry[0] if entry[1] == match } 163 else 164 enum.each_with_index { |e, i| return i if e == match } 165 end 166 nil 167 end
# File lib/puppet/functions/info.rb 12 def info(scope, *values) 13 Puppet::Util::Log.log_func(scope, :info, values) 14 end
Get info on a package, optionally specifying a device.
# File lib/puppet/provider/package/sun.rb 65 def info2hash(device = nil) 66 args = ['-l'] 67 args << '-d' << device if device 68 args << @resource[:name] 69 begin 70 pkgs = self.class.parse_pkginfo(pkginfo(*args)) 71 errmsg = case pkgs.size 72 when 0 73 'No message' 74 when 1 75 pkgs[0]['ERROR'] 76 end 77 return self.class.namemap(pkgs[0]) if errmsg.nil? 78 # according to commit 41356a7 some errors do not raise an exception 79 # so even though pkginfo passed, we have to check the actual output 80 raise Puppet::Error, _("Unable to get information about package %{name} because of: %{errmsg}") % { name: @resource[:name], errmsg: errmsg } 81 rescue Puppet::ExecutionFailure 82 return {:ensure => :absent} 83 end 84 end
Where is our init script?
# File lib/puppet/provider/service/init.rb 121 def initscript 122 @initscript ||= self.search(@resource[:name]) 123 end
# File lib/puppet/functions/inline_epp.rb 58 def inline_epp(scope, template, parameters = nil) 59 Puppet::Pops::Evaluator::EppEvaluator.inline_epp(scope, template, parameters) 60 end
# File lib/puppet/functions/regsubst.rb 98 def inner_regsubst(target, re, replacement, op) 99 target.respond_to?(op) ? target.send(op, re, replacement) : target.collect { |e| e.send(op, re, replacement) } 100 end
# File lib/puppet/provider/package/aix.rb 93 def install(useversion = true) 94 source = @resource[:source] 95 unless source 96 self.fail _("A directory is required which will be used to find packages") 97 end 98 99 pkg = @resource[:name] 100 101 pkg += " #{@resource.should(:ensure)}" if (! @resource.should(:ensure).is_a? Symbol) and useversion 102 103 output = installp "-acgwXY", "-d", source, pkg 104 105 # If the package is superseded, it means we're trying to downgrade and we 106 # can't do that. 107 if output =~ /^#{Regexp.escape(@resource[:name])}\s+.*\s+Already superseded by.*$/ 108 self.fail _("aix package provider is unable to downgrade packages") 109 end 110 111 pkg_info = query 112 if pkg_info && [:broken, :inconsistent].include?(pkg_info[:status]) 113 self.fail _("Package '%{name}' is in a %{status} state and requires manual intervention") % { name: @resource[:name], status: pkg_info[:status] } 114 end 115 end
# File lib/puppet/provider/package/pacman.rb 226 def install_from_file 227 source = @resource[:source] 228 begin 229 source_uri = URI.parse source 230 rescue => detail 231 self.fail Puppet::Error, _("Invalid source '%{source}': %{detail}") % { source: source, detail: detail }, detail 232 end 233 234 source = case source_uri.scheme 235 when nil then source 236 when /https?/i then source 237 when /ftp/i then source 238 when /file/i then source_uri.path 239 when /puppet/i 240 fail _("puppet:// URL is not supported by pacman") 241 else 242 fail _("Source %{source} is not supported by pacman") % { source: source } 243 end 244 pacman "--noconfirm", "--noprogressbar", "-S" 245 pacman "--noconfirm", "--noprogressbar", "-U", source 246 end
# File lib/puppet/provider/package/pacman.rb 248 def install_from_repo 249 resource_name = @resource[:name] 250 251 # Refuse to install if not allowing virtual packages and the resource is a group 252 fail(_("Refusing to install package group %{resource_name}, because allow_virtual is false.") % { resource_name: resource_name }) if self.class.group?(resource_name) && !@resource.allow_virtual? 253 254 cmd = %w{--noconfirm --needed --noprogressbar} 255 cmd += install_options if @resource[:install_options] 256 cmd << "-S" << resource_name 257 258 if self.class.yaourt? 259 yaourt(*cmd) 260 else 261 pacman(*cmd) 262 end 263 end
# File lib/puppet/provider/package/apt.rb 227 def install_options 228 join_options(@resource[:install_options]) 229 end
# File lib/puppet/provider/package/apt.rb 231 def insync?(is) 232 # this is called after the generic version matching logic (insync? for the 233 # type), so we only get here if should != is 234 235 return false unless is && is != :absent 236 237 #if 'should' is a range and 'is' a debian version we should check if 'should' includes 'is' 238 should = @resource[:ensure] 239 240 return false unless is.is_a?(String) && should.is_a?(String) 241 242 begin 243 should_range = VersionRange.parse(should, DebianVersion) 244 rescue VersionRange::ValidationFailure, DebianVersion::ValidationFailure 245 Puppet.debug("Cannot parse #{should} as a debian version range") 246 return false 247 end 248 249 begin 250 is_version = DebianVersion.parse(is) 251 rescue DebianVersion::ValidationFailure 252 Puppet.debug("Cannot parse #{is} as a debian version") 253 return false 254 end 255 should_range.include?(is_version) 256 end
# File lib/puppet/network/formats.rb 9 def intern(klass, text) 10 data = MessagePack.unpack(text) 11 return data if data.is_a?(klass) 12 klass.from_data_hash(data) 13 end
# File lib/puppet/network/formats.rb 15 def intern_multiple(klass, text) 16 MessagePack.unpack(text).collect do |data| 17 klass.from_data_hash(data) 18 end 19 end
# File lib/puppet/functions/getvar.rb 60 def invalid_variable_error(navigation, default_value=nil, &block) 61 _("The given string does not start with a valid variable name") 62 end
# File lib/puppet/functions/defined.rb 110 def is_defined(scope, *vals) 111 vals.any? do |val| 112 case val 113 when String 114 if val =~ /^\$(.+)$/ 115 scope.exist?($1) 116 else 117 case val 118 when '' 119 next nil 120 when 'main' 121 # Find the main class (known as ''), it does not have to be in the catalog 122 Puppet::Pops::Evaluator::Runtime3ResourceSupport.find_main_class(scope) 123 else 124 # Find a resource type, definition or class definition 125 Puppet::Pops::Evaluator::Runtime3ResourceSupport.find_resource_type_or_class(scope, val) 126 end 127 end 128 when Puppet::Resource 129 # Find instance of given resource type and title that is in the catalog 130 scope.compiler.findresource(val.resource_type, val.title) 131 132 when Puppet::Pops::Types::PResourceType 133 raise ArgumentError, _('The given resource type is a reference to all kind of types') if val.type_name.nil? 134 type = Puppet::Pops::Evaluator::Runtime3ResourceSupport.find_resource_type(scope, val.type_name) 135 val.title.nil? ? type : scope.compiler.findresource(type, val.title) 136 137 when Puppet::Pops::Types::PClassType 138 raise ArgumentError, _('The given class type is a reference to all classes') if val.class_name.nil? 139 scope.compiler.findresource(:class, val.class_name) 140 141 when Puppet::Pops::Types::PTypeType 142 case val.type 143 when Puppet::Pops::Types::PResourceType 144 # It is most reasonable to take Type[File] and Type[File[foo]] to mean the same as if not wrapped in a Type 145 # Since the difference between File and File[foo] already captures the distinction of type vs instance. 146 is_defined(scope, val.type) 147 148 when Puppet::Pops::Types::PClassType 149 # Interpreted as asking if a class (and nothing else) is defined without having to be included in the catalog 150 # (this is the same as asking for just the class' name, but with the added certainty that it cannot be a defined type. 151 # 152 raise ArgumentError, _('The given class type is a reference to all classes') if val.type.class_name.nil? 153 Puppet::Pops::Evaluator::Runtime3ResourceSupport.find_hostclass(scope, val.type.class_name) 154 end 155 else 156 raise ArgumentError, _("Invalid argument of type '%{value_class}' to 'defined'") % { value_class: val.class } 157 end 158 end 159 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 233 def is_face_app?(appname) 234 clazz = Puppet::Application.find(appname) 235 236 clazz.ancestors.include?(Puppet::Application::FaceBase) 237 end
# File lib/puppet/provider/user/user_role_add.rb 82 def is_role? 83 user_attributes and user_attributes[:type] == "role" 84 end
# File lib/puppet/provider/service/upstart.rb 196 def is_upstart?(script = initscript) 197 Puppet::FileSystem.exist?(script) && script.match(/\/etc\/init\/\S+\.conf/) 198 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 389 def iterations=(value) 390 if (Puppet::Util::Package.versioncmp(self.class.get_os_version, '10.7') > 0) 391 assert_full_pbkdf2_password 392 393 sleep 3 394 flush_dscl_cache 395 users_plist = get_users_plist(@resource.name) 396 shadow_hash_data = get_shadow_hash_data(users_plist) 397 set_salted_pbkdf2(users_plist, shadow_hash_data, 'iterations', value) 398 flush_dscl_cache 399 end 400 end
# File lib/puppet/functions/tree_each.rb 187 def iterator(enum, options) 188 if depth_first?(options) 189 Puppet::Pops::Types::Iterable::DepthFirstTreeIterator.new(enum, options) 190 else 191 Puppet::Pops::Types::Iterable::BreadthFirstTreeIterator.new(enum, options) 192 end 193 end
# File lib/puppet/functions/join.rb 54 def join(arg, delimiter = '', puppet_formatting = false) 55 arg.join(delimiter) 56 end
# File lib/puppet/network/formats.rb 150 def json 151 @json ||= Puppet::Network::FormatHandler.format(:json) 152 end
# File lib/puppet/functions/json_data.rb 19 def json_data(options, context) 20 path = options['path'] 21 context.cached_file_data(path) do |content| 22 begin 23 Puppet::Util::Json.load(content) 24 rescue Puppet::Util::Json::ParseError => ex 25 # Filename not included in message, so we add it here. 26 raise Puppet::DataBinding::LookupError, "Unable to parse (%{path}): %{message}" % { path: path, message: ex.message } 27 end 28 end 29 end
# File lib/puppet/functions/keys.rb 23 def keys(hsh) 24 hsh.keys 25 end
# File lib/puppet/provider/user/user_role_add.rb 165 def keys=(keys_hash) 166 run([command(:modify)] + build_keys_cmd(keys_hash) << @resource[:name], "modify attribute key pairs") 167 end
# File lib/puppet/provider/package/aix.rb 151 def latest 152 upd = latest_info 153 154 unless upd.nil? 155 return "#{upd[:version]}" 156 else 157 raise Puppet::DevError, _("Tried to get latest on a missing package") if properties[:ensure] == :absent 158 159 return properties[:ensure] 160 end 161 end
Return a list of applications that are not simply just stubs for Faces.
# File lib/puppet/face/help.rb 150 def legacy_applications 151 Puppet::Application.available_application_names.reject do |appname| 152 (is_face_app?(appname)) or (exclude_from_docs?(appname)) 153 end.sort 154 end
# File lib/puppet/functions/strftime.rb 206 def legacy_strftime(format, timezone = nil) 207 file, line = Puppet::Pops::PuppetStack.top_of_stack 208 Puppet.warn_once('deprecations', 'legacy#strftime', 209 _('The argument signature (String format, [String timezone]) is deprecated for #strftime. See #strftime documentation and Timespan type for more info'), 210 file, line) 211 Puppet::Pops::Time::Timestamp.format_time(format, Time.now.utc, timezone) 212 end
# File lib/puppet/functions/lest.rb 49 def lest(arg) 50 if arg.nil? 51 yield() 52 else 53 arg 54 end 55 end
Lists all instances of the given object, taking in an optional set of ia_module arguments. Returns an array of hashes, each hash having the schema
{
:name => <object_name>
:home => <object_home>
}
# File lib/puppet/provider/user/aix.rb 276 def list_all_homes(ia_module_args = []) 277 cmd = [command(:list), '-c', *ia_module_args, '-a', 'home', 'ALL'] 278 parse_aix_objects(execute(cmd)).to_a.map do |object| 279 name = object[:name] 280 home = object[:attributes].delete(:home) 281 282 { name: name, home: home } 283 end 284 rescue => e 285 Puppet.debug("Could not list home of all users: #{e.message}") 286 {} 287 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, its dependency status, and the location in the modulepath relative to its parent.
Returns a Hash
# File lib/puppet/face/module/list.rb 250 def list_build_node(mod, parent, params) 251 str = String.new 252 str << (mod.forge_name ? mod.forge_name.tr('/', '-') : mod.name) 253 str << ' (' + colorize(:cyan, mod.version ? "v#{mod.version}" : '???') + ')' 254 255 unless File.dirname(mod.path) == params[:path] 256 str << " [#{File.dirname(mod.path)}]" 257 end 258 259 if @unmet_deps[:version_mismatch].include?(mod.forge_name) 260 if params[:label_invalid] 261 str << ' ' + colorize(:red, _('invalid')) 262 elsif parent.respond_to?(:forge_name) 263 unmet_parent = @unmet_deps[:version_mismatch][mod.forge_name][:parent] 264 if (unmet_parent[:name] == parent.forge_name && 265 unmet_parent[:version] == "v#{parent.version}") 266 str << ' ' + colorize(:red, _('invalid')) 267 end 268 end 269 end 270 271 { :text => str } 272 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:
/etc/puppetlabs/code/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 215 def list_build_tree(list, ancestors=[], parent=nil, params={}) 216 list.map do |mod| 217 next if @seen[(mod.forge_name or mod.name)] 218 node = list_build_node(mod, parent, params) 219 @seen[(mod.forge_name or mod.name)] = true 220 221 unless ancestors.include?(mod) 222 node[:dependencies] ||= [] 223 missing_deps = mod.unmet_dependencies.select do |dep| 224 dep[:reason] == :missing 225 end 226 missing_deps.map do |mis_mod| 227 str = "#{colorize(:bg_red, _('UNMET DEPENDENCY'))} #{mis_mod[:name].tr('/', '-')} " 228 str << "(#{colorize(:cyan, mis_mod[:version_constraint])})" 229 node[:dependencies] << { :text => str } 230 end 231 node[:dependencies] += list_build_tree(mod.dependencies_as_modules, 232 ancestors + [mod], mod, params) 233 end 234 235 node 236 end.compact 237 end
# File lib/puppet/provider/package/pip.rb 337 def list_extra_flags(command_version) 338 klass = self.class 339 if klass.compare_pip_versions(command_version, '20.2.4') == 1 && 340 klass.compare_pip_versions(command_version, '21.1') == -1 341 '--use-deprecated=legacy-resolver' 342 end 343 end
# File lib/puppet/functions/eyaml_lookup_key.rb 46 def load_data_hash(options, context) 47 path = options['path'] 48 context.cached_file_data(path) do |content| 49 begin 50 data = Puppet::Util::Yaml.safe_load(content, [Symbol], path) 51 if data.is_a?(Hash) 52 Puppet::Pops::Lookup::HieraConfig.symkeys_to_string(data) 53 else 54 msg = _("%{path}: file does not contain a valid yaml hash") % { path: path } 55 raise Puppet::DataBinding::LookupError, msg if Puppet[:strict] == :error && data != false 56 Puppet.warning(msg) 57 {} 58 end 59 rescue Puppet::Util::Yaml::YamlLoadError => ex 60 # YamlLoadErrors include the absolute path to the file, so no need to add that 61 raise Puppet::DataBinding::LookupError, _("Unable to parse %{message}") % { message: ex.message } 62 end 63 end 64 end
# File lib/puppet/face/help.rb 122 def load_face_help(facename, actionname, version) 123 face = Puppet::Face[facename.to_sym, version] 124 if actionname 125 action = face.get_action(actionname.to_sym) 126 if ! action 127 fail ArgumentError, _("Unable to load action %{actionname} from %{face}") % { actionname: actionname, face: face } 128 end 129 end 130 131 [face, action] 132 end
# File lib/puppet/provider/user/useradd.rb 109 def local_username 110 finduser(:uid, @resource.uid) 111 end
# File lib/puppet/provider/user/useradd.rb 132 def localcomment 133 user = finduser(:account, resource[:name]) 134 user[:gecos] 135 end
# File lib/puppet/provider/group/groupadd.rb 35 def localgid 36 group = findgroup(:group_name, resource[:name]) 37 return group[:gid] if group 38 false 39 end
# File lib/puppet/provider/user/useradd.rb 147 def localgroups 148 @groups_of ||= {} 149 group_file = '/etc/group' 150 user = resource[:name] 151 152 return @groups_of[user] if @groups_of[user] 153 154 @groups_of[user] = [] 155 156 unless Puppet::FileSystem.exist?(group_file) 157 raise Puppet::Error.new("Forcelocal set for user resource '#{user}', but #{group_file} does not exist") 158 end 159 160 Puppet::FileSystem.each_line(group_file) do |line| 161 data = line.chomp.split(':') 162 if !data.empty? && data.last.split(',').include?(user) 163 @groups_of[user] << data.first 164 end 165 end 166 167 @groups_of[user] 168 end
# File lib/puppet/provider/user/useradd.rb 142 def localhome 143 user = finduser(:account, resource[:name]) 144 user[:directory] 145 end
# File lib/puppet/provider/user/useradd.rb 137 def localshell 138 user = finduser(:account, resource[:name]) 139 user[:shell] 140 end
# File lib/puppet/provider/user/useradd.rb 113 def localuid 114 user = finduser(:account, resource[:name]) 115 return user[:uid] if user 116 false 117 end
# File lib/puppet/provider/user/openbsd.rb 66 def loginclass=(value) 67 set("loginclass", value) 68 end
# File lib/puppet/provider/service/windows.rb 141 def logonaccount 142 return unless Puppet::Util::Windows::Service.exists?(@resource[:name]) 143 Puppet::Util::Windows::Service.logon_account(@resource[:name]) 144 end
# File lib/puppet/provider/service/windows.rb 146 def logonaccount=(value) 147 validate_logon_credentials 148 Puppet::Util::Windows::Service.set_startup_configuration(@resource[:name], options: {logon_account: value, logon_password: @resource[:logonpassword]}) 149 restart if @resource[:ensure] == :running && [:running, :paused].include?(status) 150 end
# File lib/puppet/provider/service/windows.rb 132 def logonaccount_insync?(current) 133 @normalized_logon_account ||= normalize_logonaccount 134 @resource[:logonaccount] = @normalized_logon_account 135 136 insync = @resource[:logonaccount] == current 137 self.logonpassword = @resource[:logonpassword] if insync 138 insync 139 end
# File lib/puppet/provider/service/windows.rb 152 def logonpassword=(value) 153 validate_logon_credentials 154 Puppet::Util::Windows::Service.set_startup_configuration(@resource[:name], options: {logon_password: value}) 155 end
# File lib/puppet/functions/lookup.rb 190 def lookup_1(scope, name, value_type=nil, merge=nil) 191 do_lookup(scope, name, value_type, nil, false, {}, {}, merge) 192 end
# File lib/puppet/functions/lookup.rb 194 def lookup_2(scope, name, value_type, merge, default_value) 195 do_lookup(scope, name, value_type, default_value, true, {}, {}, merge) 196 end
# File lib/puppet/functions/lookup.rb 198 def lookup_3(scope, name, value_type=nil, merge=nil, &block) 199 do_lookup(scope, name, value_type, nil, false, {}, {}, merge, &block) 200 end
# File lib/puppet/functions/lookup.rb 202 def lookup_4(scope, options_hash, &block) 203 do_lookup(scope, options_hash['name'], *hash_args(options_hash), &block) 204 end
# File lib/puppet/functions/lookup.rb 206 def lookup_5(scope, name, options_hash, &block) 207 do_lookup(scope, name, *hash_args(options_hash), &block) 208 end
# File lib/puppet/provider/user/user_role_add.rb 141 def managed_attributes 142 [:name, :type, :roles, :auths, :profiles, :project] 143 end
# File lib/puppet/provider/service/windows.rb 32 def manual_start 33 Puppet::Util::Windows::Service.set_startup_configuration(@resource[:name], options: {startup_type: :SERVICE_DEMAND_START}) 34 rescue => detail 35 raise Puppet::Error.new(_("Cannot enable %{resource_name} for manual start, error was: %{detail}") % { resource_name: @resource[:name], detail: detail }, detail ) 36 end
# File lib/puppet/functions/map.rb 109 def map_Enumerable_1(enumerable) 110 result = [] 111 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 112 begin 113 enum.each do |val| 114 result << yield(val) 115 end 116 rescue StopIteration 117 end 118 result 119 end
# File lib/puppet/functions/map.rb 121 def map_Enumerable_2(enumerable) 122 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 123 if enum.hash_style? 124 enum.map { |entry| yield(*entry) } 125 else 126 result = [] 127 begin 128 enum.each_with_index do |val, index| 129 result << yield(index, val) 130 end 131 rescue StopIteration 132 end 133 result 134 end 135 end
# File lib/puppet/functions/map.rb 91 def map_Hash_1(hash) 92 result = [] 93 begin 94 hash.each {|x, y| result << yield([x, y]) } 95 rescue StopIteration 96 end 97 result 98 end
# File lib/puppet/functions/map.rb 100 def map_Hash_2(hash) 101 result = [] 102 begin 103 hash.each {|x, y| result << yield(x, y) } 104 rescue StopIteration 105 end 106 result 107 end
# File lib/puppet/provider/package/apt.rb 59 def mark 60 @property_flush[:mark] 61 end
# File lib/puppet/provider/package/apt.rb 63 def mark=(value) 64 @property_flush[:mark] = value 65 end
Configure discovered resources to be purged.
# File lib/puppet/type/file.rb 571 def mark_children_for_purging(children) 572 children.each do |name, child| 573 next if child[:source] 574 child[:ensure] = :absent 575 end 576 end
# File lib/puppet/provider/service/systemd.rb 167 def mask 168 disable if exist? 169 systemctl_change_enable(:mask) 170 end
Matches given string against given pattern and returns an Array with matches. @param string [String] the string to match @param pattern [String, Regexp, Puppet::Pops::Types::PPatternType, Puppet::Pops::PRegexpType, Array] the pattern @return [Array<String>] matches where first match is the entire match, and index 1-n are captures from left to right
# File lib/puppet/functions/match.rb 65 def match(string, pattern) 66 @@match_visitor.visit_this_1(self, pattern, string) 67 end
Returns the first matching entry
# File lib/puppet/functions/match.rb 119 def match_Array(array, s) 120 result = nil 121 array.flatten.find {|entry| result = match(s, entry) } 122 result 123 end
# File lib/puppet/functions/match.rb 81 def match_Object(obj, s) 82 msg = _("match() expects pattern of T, where T is String, Regexp, Regexp[r], Pattern[p], or Array[T]. Got %{klass}") % { klass: obj.class } 83 raise ArgumentError, msg 84 end
# File lib/puppet/functions/match.rb 110 def match_PPatternType(pattern_t, s) 111 # Since we want the actual match result (not just a boolean), an iteration over 112 # Pattern's regular expressions is needed. (They are of PRegexpType) 113 result = nil 114 pattern_t.patterns.find {|pattern| result = match(s, pattern) } 115 result 116 end
# File lib/puppet/functions/match.rb 105 def match_PRegexpType(regexp_t, s) 106 raise ArgumentError, _("Given Regexp Type has no regular expression") unless regexp_t.pattern 107 do_match(s, regexp_t.regexp) 108 end
# File lib/puppet/functions/match.rb 94 def match_PTypeAliasType(alias_t, s) 95 match(s, alias_t.resolved_type) 96 end
# File lib/puppet/functions/match.rb 98 def match_PVariantType(var_t, s) 99 # Find first matching type (or error out if one of the variants is not acceptable) 100 result = nil 101 var_t.types.find {|t| result = match(s, t) } 102 result 103 end
# File lib/puppet/functions/match.rb 90 def match_Regexp(regexp, s) 91 do_match(s, regexp) 92 end
# File lib/puppet/functions/match.rb 86 def match_String(pattern_string, s) 87 do_match(s, Regexp.new(pattern_string)) 88 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 323 def matches?(path) 324 return true unless self[:matches] 325 326 basename = File.basename(path) 327 flags = File::FNM_DOTMATCH | File::FNM_PATHNAME 328 if self[:matches].find {|pattern| File.fnmatch(pattern, basename, flags) } 329 return true 330 else 331 debug "No specified patterns match #{path}, not tidying" 332 return false 333 end 334 end
Helper that encapsulates the clear + svcadm [enable|disable] logic in one place. Makes it easy to test things out and also cleans up flush's code.
# File lib/puppet/provider/service/smf.rb 235 def maybe_clear_service_then_svcadm(cur_state, subcmd, flags) 236 # If the cur_state is maint or degraded, then we need to clear the service 237 # before we enable or disable it. 238 adm('clear', self.service_fmri) if [:maintenance, :degraded].include?(cur_state) 239 adm(subcmd, flags, self.service_fmri) 240 end
# File lib/puppet/provider/group/windows_adsi.rb 61 def member_valid?(user_name) 62 ! Puppet::Util::Windows::SID.name_to_principal(user_name).nil? 63 end
# File lib/puppet/provider/group/windows_adsi.rb 69 def members 70 @members ||= Puppet::Util::Windows::ADSI::Group.name_sid_hash(group.members, true) 71 72 # @members.keys returns an array of SIDs. We need to convert those SIDs into 73 # names so that `puppet resource` prints the right output. 74 members_to_s(@members.keys).split(',') 75 end
# File lib/puppet/provider/group/windows_adsi.rb 77 def members=(members) 78 group.set_members(members, @resource[:auth_membership]) 79 end
We could add this to the top-level members property since the implementation is not platform-specific; however, it is best to do it this way so that we do not accidentally break something. This is ok for now, since we do plan on moving this and the auth_membership management over to the property class in a future Puppet release.
# File lib/puppet/provider/group/aix.rb 97 def members_insync?(current, should) 98 current.sort == @resource.parameter(:members).actual_should(current, should) 99 end
# File lib/puppet/provider/group/groupadd.rb 125 def members_to_s(current) 126 return '' if current.nil? || !current.kind_of?(Array) 127 current.join(',') 128 end
This method will merge in a given value using dscl
# File lib/puppet/provider/user/directoryservice.rb 493 def merge_attribute_with_dscl(path, username, keyname, value) 494 set_attribute_with_dscl('-merge', path, username, keyname, value) 495 end
# File lib/puppet/functions/hiera_array.rb 79 def merge_type 80 :unique 81 end
Adds methods to a singleton_class
# File lib/puppet/util/metaid.rb 8 def meta_def(name, &blk) 9 meta_eval { define_method name, &blk } 10 end
# File lib/puppet/util/metaid.rb 5 def meta_eval(&blk); singleton_class.instance_eval(&blk); end
Remove singleton_class methods.
# File lib/puppet/util/metaid.rb 13 def meta_undef(name, &blk) 14 meta_eval { remove_method name } 15 end
# File lib/puppet/functions/hocon_data.rb 39 def missing_path(options, context) 40 "one of 'path', 'paths' 'glob', 'globs' or 'mapped_paths' must be declared in hiera.yaml when using this data_hash function" 41 end
Make a file resource to remove a given file.
# File lib/puppet/type/tidy.rb 244 def mkfile(path) 245 # Force deletion, so directories actually get deleted. 246 parameters = { 247 :path => path, :backup => self[:backup], 248 :ensure => :absent, :force => true 249 } 250 251 new_file = Puppet::Type.type(:file).new(parameters) 252 new_file.copy_metaparams(@parameters) 253 254 new_file 255 end
# File lib/puppet/provider/file/posix.rb 127 def mode 128 stat = resource.stat 129 if stat 130 return (stat.mode & 007777).to_s(8).rjust(4, '0') 131 else 132 return :absent 133 end 134 end
# File lib/puppet/provider/file/posix.rb 136 def mode=(value) 137 begin 138 File.chmod(value.to_i(8), resource[:path]) 139 rescue => detail 140 error = Puppet::Error.new(_("failed to set mode %{mode} on %{path}: %{message}") % { mode: mode, path: resource[:path], message: detail.message }) 141 error.set_backtrace detail.backtrace 142 raise error 143 end 144 end
# File lib/puppet/provider/group/groupadd.rb 89 def modifycmd(param, value) 90 if @resource.forcelocal? || @resource[:members] 91 cmd = [command(:localmodify)] 92 @custom_environment = Puppet::Util::Libuser.getenv 93 else 94 cmd = [command(:modify)] 95 end 96 97 if param == :members 98 validate_members(value) 99 value = members_to_s(value) 100 purge_members if @resource[:auth_membership] && !members.empty? 101 end 102 103 cmd << flag(param) << value 104 # TODO the group type only really manages gid, so there are currently no 105 # tests for this behavior 106 cmd += check_allow_dup if param == :gid 107 cmd << @resource[:name] 108 109 cmd 110 end
# File lib/puppet/functions/module_directory.rb 35 def module_directory(scope, *names) 36 names.each do |module_name| 37 found = scope.compiler.environment.module(module_name) 38 return found.path if found 39 end 40 nil 41 end
# File lib/puppet/functions/module_directory.rb 31 def module_directory_array(scope, names) 32 module_directory(scope, *names) 33 end
munge the windows group permissions if the user or group are set to SYSTEM
when SYSTEM user is the group or user and the resoure is not managing them then treat the resource as insync if System has FullControl access.
@param [String] current - the current mode returned by the resource @param [String] should - what the mode should be
@return [String, nil] munged mode or nil if the resource should be out of sync
# File lib/puppet/provider/file/windows.rb 101 def munge_windows_system_group(current, should) 102 [ 103 { 104 'type' => 'group', 105 'resource' => resource[:group], 106 'set_to_user' => group, 107 'fullcontrol' => "070".to_i(8), 108 'remove_mask' => "707".to_i(8), 109 'should_mask' => (should[0].to_i(8) & "070".to_i(8)), 110 }, 111 { 112 'type' => 'owner', 113 'resource' => resource[:owner], 114 'set_to_user' => owner, 115 'fullcontrol' => "700".to_i(8), 116 'remove_mask' => "077".to_i(8), 117 'should_mask' => (should[0].to_i(8) & "700".to_i(8)), 118 } 119 ].each do |mode_part| 120 if mode_part['resource'].nil? && (mode_part['set_to_user'] == Puppet::Util::Windows::SID::LocalSystem) 121 if (current.to_i(8) & mode_part['fullcontrol']) == mode_part['fullcontrol'] 122 # Since the group is LocalSystem, and the permissions are FullControl, 123 # replace the value returned with the value expected. This will treat 124 # this specific situation as "insync" 125 current = ( (current.to_i(8) & mode_part['remove_mask']) | mode_part['should_mask'] ).to_s(8).rjust(4, '0') 126 else 127 # If the SYSTEM account does _not_ have FullControl in this scenario, we should 128 # force the resource out of sync no matter what. 129 #TRANSLATORS 'SYSTEM' is a Windows name and should not be translated 130 Puppet.debug { _("%{resource_name}: %{mode_part_type} set to SYSTEM. SYSTEM permissions cannot be set below FullControl ('7')") % { resource_name: resource[:name], mode_part_type: mode_part['type']} } 131 return nil 132 end 133 end 134 end 135 current 136 end
# File lib/puppet/gettext/stubs.rb 9 def n_(*args, &block) 10 plural = args[2] == 1 ? args[0] : args[1] 11 block ? block.call : plural 12 end
# File lib/puppet/provider/file/posix.rb 57 def name2gid(value) 58 Integer(value) rescue gid(value) || false 59 end
Determine if the account is valid, and if so, return the UID
# File lib/puppet/provider/file/windows.rb 16 def name2id(value) 17 Puppet::Util::Windows::SID.name_to_sid(value) 18 end
Determine if the user is valid, and if so, return the UID
# File lib/puppet/provider/file/posix.rb 36 def name2uid(value) 37 Integer(value) rescue uid(value) || false 38 end
# File lib/puppet/functions/new.rb 999 def new_function_for_type(t) 1000 @new_function_cache ||= {} 1001 1002 unless @new_function_cache.key?(t) 1003 @new_function_cache[t] = t.new_function.new(nil, loader) 1004 end 1005 1006 @new_function_cache[t] 1007 end
# File lib/puppet/functions/new.rb 993 def new_instance(scope, t, *args) 994 return args[0] if args.size == 1 && !t.is_a?(Puppet::Pops::Types::PInitType) && t.instance?(args[0]) 995 result = assert_type(t, new_function_for_type(t).call(scope, *args)) 996 return block_given? ? yield(result) : result 997 end
Create a new file or directory object as a child to the current object.
# File lib/puppet/type/file.rb 580 def newchild(path) 581 full_path = ::File.join(self[:path], path) 582 583 # Add some new values to our original arguments -- these are the ones 584 # set at initialization. We specifically want to exclude any param 585 # values set by the :source property or any default values. 586 # LAK:NOTE This is kind of silly, because the whole point here is that 587 # the values set at initialization should live as long as the resource 588 # but values set by default or by :source should only live for the transaction 589 # or so. Unfortunately, we don't have a straightforward way to manage 590 # the different lifetimes of this data, so we kludge it like this. 591 # The right-side hash wins in the merge. 592 options = @original_parameters.merge(:path => full_path).reject { |param, value| value.nil? } 593 594 # These should never be passed to our children. 595 [:parent, :ensure, :recurse, :recurselimit, :max_files, :target, :alias, :source].each do |param| 596 options.delete(param) if options.include?(param) 597 end 598 599 self.class.new(options) 600 end
# File lib/puppet/functions/next.rb 29 def next_impl(value = nil) 30 file, line = Puppet::Pops::PuppetStack.top_of_stack 31 exc = Puppet::Pops::Evaluator::Next.new(value, file, line) 32 raise exc 33 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 512 def next_system_id(min_id=20) 513 dscl_output = dscl '.', '-list', '/Users', 'uid' 514 # We're ok with throwing away negative uids here. Also, remove nil values. 515 user_ids = dscl_output.split.compact.collect { |l| l.to_i if l =~ /^\d+$/ } 516 ids = user_ids.compact!.sort! { |a,b| a.to_f <=> b.to_f } 517 # We're just looking for an unused id in our sorted array. 518 ids.each_index do |i| 519 next_id = ids[i] + 1 520 return next_id if ids[i+1] != next_id and next_id >= min_id 521 end 522 end
# File lib/puppet/provider/service/windows.rb 159 def normalize_logonaccount 160 logon_account = @resource[:logonaccount].sub(/^\.\\/, "#{Puppet::Util::Windows::ADSI.computer_name}\\") 161 return 'LocalSystem' if Puppet::Util::Windows::User::localsystem?(logon_account) 162 163 @logonaccount_information ||= Puppet::Util::Windows::SID.name_to_principal(logon_account) 164 return logon_account unless @logonaccount_information 165 return ".\\#{@logonaccount_information.account}" if @logonaccount_information.domain == Puppet::Util::Windows::ADSI.computer_name 166 @logonaccount_information.domain_account 167 end
# File lib/puppet/functions/notice.rb 12 def notice(scope, *values) 13 Puppet::Util::Log.log_func(scope, :notice, values) 14 end
For compatibility reasons - return false rather than error on floats and integers (Yes, it is strange)
# File lib/puppet/functions/empty.rb 65 def numeric_empty(num) 66 deprecation_warning_for('Numeric') 67 false 68 end
Mix of data types - while only some compares are actually bad it will deprecate the entire call
# File lib/puppet/functions/max.rb 230 def on_any(*args) 231 assert_arg_count(args) 232 args.max do |a, b| 233 as = a.to_s 234 bs = b.to_s 235 if as =~ %r{\A^-?\d+([._eE]\d+)?\z} && bs =~ %r{\A-?\d+([._eE]\d+)?\z} 236 Puppet.warn_once('deprecations', 'max_function_numeric_coerce_string', 237 _("The max() function's auto conversion of String to Numeric is deprecated - change to convert input before calling, or use lambda")) 238 a.to_f <=> b.to_f 239 else 240 Puppet.warn_once('deprecations', 'max_function_string_coerce_any', 241 _("The max() function's auto conversion of Any to String is deprecated - change to convert input before calling, or use lambda")) 242 as <=> bs 243 end 244 end 245 end
# File lib/puppet/functions/max.rb 175 def on_any_with_block(*args, &block) 176 args.max {|x,y| block.call(x,y) } 177 end
# File lib/puppet/functions/downcase.rb 77 def on_array(a) 78 a.map {|x| do_downcase(x) } 79 end
# File lib/puppet/functions/compare.rb 99 def on_error(a, b, *ignore_case) 100 if !ignore_case.empty? 101 unless a.is_a?(String) && b.is_a?(String) 102 # TRANSLATORS 'compare' is a name 103 return _("compare(): The third argument (ignore case) can only be used when comparing strings") 104 end 105 unless ignore_case.size == 1 106 # TRANSLATORS 'compare' is a name 107 return _("compare(): Accepts at most 3 arguments, got %{actual_number}") % {actual_number: 2 + ignore_case.size} 108 end 109 unless ignore_case[0].is_a?(Boolean) 110 # TRANSLATORS 'compare' is a name 111 return _("compare(): The third argument (ignore case) must be a Boolean. Got %{type}") % { type: type_label(ignore_case[0]) } 112 end 113 end 114 115 if a.class != b.class 116 # TRANSLATORS 'compare' is a name 117 return _("compare(): Can only compare values of the same type (or for Timestamp/Timespan also against Numeric). Got %{type_a} and %{type_b}") % { 118 type_a: type_label(a), type_b: type_label(b) 119 } 120 end 121 end
# File lib/puppet/functions/downcase.rb 81 def on_hash(h) 82 result = {} 83 h.each_pair {|k,v| result[do_downcase(k)] = do_downcase(v) } 84 result 85 end
# File lib/puppet/functions/camelcase.rb 55 def on_iterable(a) 56 a.map {|x| do_camelcase(x) } 57 end
# File lib/puppet/functions/compare.rb 92 def on_not_comparable(a, b, *ignore_case) 93 # TRANSLATORS 'compare' is a name 94 _("compare(): Non comparable type. Only values of the types Numeric, String, Semver, Timestamp and Timestamp can be compared. Got %{type_a} and %{type_b}") % { 95 type_a: type_label(a), type_b: type_label(b) 96 } 97 end
# File lib/puppet/functions/abs.rb 43 def on_numeric(x) 44 x.abs 45 end
# File lib/puppet/functions/max.rb 160 def on_semver(*args) 161 assert_arg_count(args) 162 args.max 163 end
# File lib/puppet/functions/max.rb 219 def on_single_any_array(array, &block) 220 if block_given? 221 on_any_with_block(*array, &block) 222 else 223 on_any(*array) 224 end 225 end
# File lib/puppet/functions/max.rb 179 def on_single_numeric_array(array, &block) 180 if block_given? 181 on_any_with_block(*array, &block) 182 else 183 on_numeric(*array) 184 end 185 end
# File lib/puppet/functions/max.rb 195 def on_single_semver_array(array, &block) 196 if block_given? 197 on_any_with_block(*array, &block) 198 else 199 on_semver(*array) 200 end 201 end
# File lib/puppet/functions/max.rb 187 def on_single_string_array(array, &block) 188 if block_given? 189 on_any_with_block(*array, &block) 190 else 191 on_string(*array) 192 end 193 end
# File lib/puppet/functions/max.rb 203 def on_single_timespan_array(array, &block) 204 if block_given? 205 on_any_with_block(*array, &block) 206 else 207 on_timespan(*array) 208 end 209 end
# File lib/puppet/functions/max.rb 211 def on_single_timestamp_array(array, &block) 212 if block_given? 213 on_any_with_block(*array, &block) 214 else 215 on_timestamp(*array) 216 end 217 end
# File lib/puppet/functions/abs.rb 47 def on_string(x) 48 Puppet.warn_once('deprecations', 'abs_function_numeric_coerce_string', 49 _("The abs() function's auto conversion of String to Numeric is deprecated - change to convert input before calling")) 50 51 # These patterns for conversion are backwards compatible with the stdlib 52 # version of this function. 53 # 54 if x =~ %r{^-?(?:\d+)(?:\.\d+){1}$} 55 x.to_f.abs 56 elsif x =~ %r{^-?\d+$} 57 x.to_i.abs 58 else 59 raise(ArgumentError, 'abs(): Requires float or integer to work with - was given non decimal string') 60 end 61 end
# File lib/puppet/functions/compare.rb 78 def on_time_num_first(a, b) 79 # Time data types can compare against Numeric but not the other way around 80 # the comparison is therefore done in reverse and the answer is inverted. 81 -(b <=> a) 82 end
# File lib/puppet/functions/compare.rb 84 def on_timespan(a, b) 85 a <=> b 86 end
# File lib/puppet/functions/compare.rb 88 def on_timestamp(a, b) 89 a <=> b 90 end
# File lib/puppet/functions/compare.rb 74 def on_version(a, b) 75 a <=> b 76 end
# File lib/puppet/provider/package/pkgng.rb 166 def origin 167 @property_hash[:origin] 168 end
Where is our override script?
# File lib/puppet/provider/service/upstart.rb 106 def overscript 107 @overscript ||= initscript.gsub(/\.conf$/,".override") 108 end
# File lib/puppet/provider/file/posix.rb 61 def owner 62 stat = resource.stat 63 unless stat 64 return :absent 65 end 66 67 currentvalue = stat.uid 68 69 # On OS X, files that are owned by -2 get returned as really 70 # large UIDs instead of negative ones. This isn't a Ruby bug, 71 # it's an OS X bug, since it shows up in perl, too. 72 if currentvalue > Puppet[:maximum_uid].to_i 73 self.warning _("Apparently using negative UID (%{currentvalue}) on a platform that does not consistently handle them") % { currentvalue: currentvalue } 74 currentvalue = :silly 75 end 76 77 currentvalue 78 end
# File lib/puppet/provider/file/posix.rb 80 def owner=(should) 81 # Set our method appropriately, depending on links. 82 if resource[:links] == :manage 83 method = :lchown 84 else 85 method = :chown 86 end 87 88 begin 89 File.send(method, should, nil, resource[:path]) 90 rescue => detail 91 raise Puppet::Error, _("Failed to set owner to '%{should}': %{detail}") % { should: should, detail: detail }, detail.backtrace 92 end 93 end
# File lib/puppet/provider/package/opkg.rb 80 def package_lists 81 Dir.entries('/var/opkg-lists/') 82 end
# File lib/puppet/provider/package/nim.rb 222 def parse_installp_package_string(package_string) 223 match = package_string.match(self.class::INSTALLP_PACKAGE_REGEX) 224 unless match 225 self.fail _("Unable to parse output from nimclient showres: package string does not match expected installp package string format:\n'%{package_string}'") % { package_string: package_string } 226 end 227 package_name = match.captures[0] 228 version = match.captures[1] 229 [package_name, version, :installp] 230 end
Helper function that parses the password from the given password filehandle. This is here to make testing easier for password since we cannot configure Mocha to mock out a method and have it return a block's value, meaning we cannot test password directly (not in a simple and obvious way, at least). @api private
# File lib/puppet/provider/user/aix.rb 163 def parse_password(f) 164 # From the docs, a user stanza is formatted as (newlines are explicitly 165 # stated here for clarity): 166 # <user>:\n 167 # <attribute1>=<value1>\n 168 # <attribute2>=<value2>\n 169 # 170 # First, find our user stanza 171 stanza = f.each_line.find { |line| line =~ /\A#{@resource[:name]}:/ } 172 return :absent unless stanza 173 174 # Now find the password line, if it exists. Note our call to each_line here 175 # will pick up right where we left off. 176 match_obj = nil 177 f.each_line.find do |line| 178 # Break if we find another user stanza. This means our user 179 # does not have a password. 180 break if line =~ /^\S+:$/ 181 182 match_obj = /password\s+=\s+(\S+)/.match(line) 183 end 184 return :absent unless match_obj 185 186 match_obj[1] 187 end
# File lib/puppet/provider/package/openbsd.rb 122 def parse_pkgconf 123 unless @resource[:source] 124 if Puppet::FileSystem.exist?("/etc/pkg.conf") 125 File.open("/etc/pkg.conf", "rb").readlines.each do |line| 126 matchdata = line.match(/^installpath\s*=\s*(.+)\s*$/i) 127 if matchdata 128 @resource[:source] = matchdata[1] 129 else 130 matchdata = line.match(/^installpath\s*\+=\s*(.+)\s*$/i) 131 if matchdata 132 if @resource[:source].nil? 133 @resource[:source] = matchdata[1] 134 else 135 @resource[:source] += ":" + matchdata[1] 136 end 137 end 138 end 139 end 140 141 unless @resource[:source] 142 raise Puppet::Error, 143 _("No valid installpath found in /etc/pkg.conf and no source was set") 144 end 145 else 146 raise Puppet::Error, 147 _("You must specify a package source or configure an installpath in /etc/pkg.conf") 148 end 149 end 150 end
# File lib/puppet/provider/package/pkgin.rb 54 def parse_pkgsearch_line 55 packages = pkgin(:search, resource[:name]).split("\n") 56 57 return [] if packages.length == 1 58 59 # Remove the last three lines of help text. 60 packages.slice!(-4, 4) 61 62 pkglist = packages.map{ |line| self.class.parse_pkgin_line(line) } 63 pkglist.select{ |package| resource[:name] == package[:name] } 64 end
# File lib/puppet/provider/package/nim.rb 232 def parse_rpm_package_string(package_string) 233 match = package_string.match(self.class::RPM_PACKAGE_REGEX) 234 unless match 235 self.fail _("Unable to parse output from nimclient showres: package string does not match expected rpm package string format:\n'%{package_string}'") % { package_string: package_string } 236 end 237 package_name = match.captures[0] 238 version = match.captures[1] 239 [package_name, version, :rpm] 240 end
# File lib/puppet/provider/package/nim.rb 212 def parse_showres_header_line(line) 213 # This method doesn't produce any meaningful output; it's basically just 214 # meant to validate that the header line for the package listing output 215 # looks sane, so we know we're dealing with the kind of output that we 216 # are capable of handling. 217 unless line.match(self.class::HEADER_LINE_REGEX) 218 self.fail _("Unable to parse output from nimclient showres: line does not match expected package header format:\n'%{line}'") % { line: line } 219 end 220 end
Parse the output of a `nimclient -o showres` command. Returns a two-dimensional hash, where the first-level keys are package names, the second-level keys are version number strings for all of the available version numbers for a package, and the values indicate the package type (:rpm / :installp)
# File lib/puppet/provider/package/nim.rb 189 def parse_showres_output(showres_output) 190 paragraphs = split_into_paragraphs(showres_output) 191 packages = {} 192 paragraphs.each do |para| 193 lines = para.split(/$/) 194 parse_showres_header_line(lines.shift) 195 lines.each do |l| 196 package, version, type = parse_showres_package_line(l) 197 packages[package] ||= {} 198 packages[package][version] = type 199 end 200 end 201 packages 202 end
# File lib/puppet/provider/package/nim.rb 242 def parse_showres_package_line(line) 243 match = line.match(self.class::PACKAGE_LINE_REGEX) 244 unless match 245 self.fail _("Unable to parse output from nimclient showres: line does not match expected package line format:\n'%{line}'") % { line: line } 246 end 247 248 package_type_flag = match.captures[0] 249 package_string = match.captures[1] 250 251 case package_type_flag 252 when "I","S" 253 parse_installp_package_string(package_string) 254 when "R" 255 parse_rpm_package_string(package_string) 256 else 257 self.fail _("Unrecognized package type specifier: '%{package_type_flag}' in package line:\n'%{line}'") % { package_type_flag: package_type_flag, line: line } 258 end 259 end
# File lib/puppet/functions/partition.rb 41 def partition_1(collection) 42 collection.partition do |item| 43 yield(item) 44 end.freeze 45 end
# File lib/puppet/functions/partition.rb 57 def partition_2(collection) 58 collection.partition do |k, v| 59 yield(k, v) 60 end.freeze 61 end
# File lib/puppet/functions/partition.rb 47 def partition_2a(array) 48 partitioned = array.size.times.zip(array).partition do |k, v| 49 yield(k, v) 50 end 51 52 partitioned.map do |part| 53 part.map { |item| item[1] } 54 end.freeze 55 end
# File lib/puppet/provider/user/useradd.rb 360 def passcmd 361 if @resource.forcelocal? 362 cmd = command(:localpassword) 363 @custom_environment = Puppet::Util::Libuser.getenv 364 else 365 cmd = command(:password) 366 end 367 age_limits = [:password_min_age, :password_max_age, :password_warn_days].select { |property| @resource.should(property) } 368 if age_limits.empty? 369 nil 370 else 371 [cmd, age_limits.collect { |property| [flag(property), @resource.should(property)]}, @resource[:name]].flatten 372 end 373 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 the /etc/security/passwd file.
# File lib/puppet/provider/user/aix.rb 195 def password 196 # AIX reference indicates this file is ASCII 197 # https://www.ibm.com/support/knowledgecenter/en/ssw_aix_72/com.ibm.aix.files/passwd_security.htm 198 Puppet::FileSystem.open("/etc/security/passwd", nil, "r:ASCII") do |f| 199 parse_password(f) 200 end 201 end
# File lib/puppet/provider/user/aix.rb 203 def password=(value) 204 user = @resource[:name] 205 206 begin 207 # Puppet execute does not support strings as input, only files. 208 # The password is expected to be in an encrypted format given -e is specified: 209 # https://www.ibm.com/support/knowledgecenter/ssw_aix_71/com.ibm.aix.cmds1/chpasswd.htm 210 # /etc/security/passwd is specified as an ASCII file per the AIX documentation 211 tempfile = nil 212 tempfile = Tempfile.new("puppet_#{user}_pw", :encoding => Encoding::ASCII) 213 tempfile << "#{user}:#{value}\n" 214 tempfile.close() 215 216 # Options '-e', '-c', use encrypted password and clear flags 217 # Must receive "user:enc_password" as input 218 # command, arguments = {:failonfail => true, :combine => true} 219 # Fix for bugs #11200 and #10915 220 cmd = [self.class.command(:chpasswd), *ia_module_args, '-e', '-c'] 221 execute_options = { 222 :failonfail => false, 223 :combine => true, 224 :stdinfile => tempfile.path 225 } 226 output = execute(cmd, execute_options) 227 228 # chpasswd can return 1, even on success (at least on AIX 6.1); empty output 229 # indicates success 230 if output != "" 231 raise Puppet::ExecutionFailure, "chpasswd said #{output}" 232 end 233 rescue Puppet::ExecutionFailure => detail 234 raise Puppet::Error, "Could not set password on #{@resource.class.name}[#{@resource.name}]: #{detail}", detail.backtrace 235 ensure 236 if tempfile 237 # Extra close will noop. This is in case the write to our tempfile 238 # fails. 239 tempfile.close() 240 tempfile.delete() 241 end 242 end 243 end
# File lib/puppet/provider/user/user_role_add.rb 198 def password_max_age 199 return :absent unless shadow_entry 200 shadow_entry[4].empty? ? -1 : shadow_entry[4] 201 end
# File lib/puppet/provider/user/user_role_add.rb 193 def password_min_age 194 return :absent unless shadow_entry 195 shadow_entry[3].empty? ? -1 : shadow_entry[3] 196 end
# File lib/puppet/provider/user/user_role_add.rb 203 def password_warn_days 204 return :absent unless shadow_entry 205 shadow_entry[5].empty? ? -1 : shadow_entry[5] 206 end
Component paths are special because they function as containers.
# File lib/puppet/type/component.rb 36 def pathbuilder 37 if reference.type == "Class" 38 myname = reference.title 39 else 40 myname = reference.to_s 41 end 42 p = self.parent 43 if p 44 return [p.pathbuilder, myname] 45 else 46 return [myname] 47 end 48 end
# File lib/puppet/provider/service/init.rb 125 def paths 126 @paths ||= @resource[:path].find_all do |path| 127 if Puppet::FileSystem.directory?(path) 128 true 129 else 130 if Puppet::FileSystem.exist?(path) 131 self.debug "Search path #{path} is not a directory" 132 else 133 self.debug "Search path #{path} does not exist" 134 end 135 false 136 end 137 end 138 end
# File lib/puppet/type/file.rb 766 def perform_recursion(path) 767 Puppet::FileServing::Metadata.indirection.search( 768 path, 769 :links => self[:links], 770 :recurse => (self[:recurse] == :remote ? true : self[:recurse]), 771 :recurselimit => self[:recurselimit], 772 :max_files => self[:max_files], 773 :source_permissions => self[:source_permissions], 774 :ignore => self[:ignore], 775 :checksum_type => (self[:source] || self[:content]) ? self[:checksum] : :none, 776 :environment => catalog.environment_instance 777 ) 778 end
# File lib/puppet/provider/package/blastwave.rb 12 def pkgget_with_cat(*args) 13 Puppet::Util.withenv(:PAGER => "/usr/bin/cat") { pkgget(*args) } 14 end
Turn our pkgutil -c listing into a hash for a single package.
# File lib/puppet/provider/package/pkgutil.rb 80 def pkgsingle(resource) 81 # The --single option speeds up the execution, because it queries 82 # the package management system for one package only. 83 command = ["-c", "--single", resource[:name]] 84 self.class.parse_pkglist(run_pkgutil(resource, command), { :justme => resource[:name] }) 85 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 229 def plist_from_label(label) 230 job = self.class.jobsearch(label) 231 job_path = job[label] 232 if FileTest.file?(job_path) 233 job_plist = self.class.read_plist(job_path) 234 else 235 raise Puppet::Error.new("Unable to parse launchd plist at path: #{job_path}") 236 end 237 [job_path, job_plist] 238 end
# File lib/puppet/functions/hiera_include.rb 101 def post_lookup(scope, key, value) 102 raise Puppet::ParseError, _("Could not find data item %{key}") % { key: key } if value.nil? 103 call_function_with_scope(scope, 'include', value) unless value.empty? 104 end
# File lib/puppet/provider/package/sun.rb 119 def prepare_cmd(opt) 120 [if_have_value('-a', opt[:adminfile]), 121 if_have_value('-r', opt[:responsefile]), 122 if_have_value('-d', opt[:source]), 123 opt[:cmd_options] || [], 124 ['-n', @resource[:name]]].flatten 125 end
# File lib/puppet/provider/service/systemd.rb 224 def prepare_error_message(name, action, exception) 225 error_return = "Systemd #{action} for #{name} failed!\n" 226 journalctl_command = "journalctl -n 50 --since '5 minutes ago' -u #{name} --no-pager" 227 Puppet.debug("Running journalctl command to get logs for systemd #{action} failure: #{journalctl_command}") 228 journalctl_output = execute(journalctl_command) 229 error_return << "journalctl log for #{name}:\n#{journalctl_output}" 230 end
# File lib/puppet/type/file.rb 518 def present?(current_values) 519 super && current_values[:ensure] != :false 520 end
# File lib/puppet/reports/http.rb 17 def process 18 url = URI.parse(Puppet[:reporturl]) 19 headers = { "Content-Type" => "application/x-yaml" } 20 # This metric_id option is silently ignored by Puppet's http client 21 # (Puppet::Network::HTTP) but is used by Puppet Server's http client 22 # (Puppet::Server::HttpClient) to track metrics on the request made to the 23 # `reporturl` to store a report. 24 options = { 25 :metric_id => [:puppet, :report, :http], 26 :include_system_store => Puppet[:report_include_system_store], 27 } 28 29 # Puppet's http client implementation accepts userinfo in the URL 30 # but puppetserver's does not. So pass credentials explicitly. 31 if url.user && url.password 32 options[:basic_auth] = { 33 user: url.user, 34 password: url.password 35 } 36 end 37 38 client = Puppet.runtime[:http] 39 client.post(url, self.to_yaml, headers: headers, options: options) do |response| 40 unless response.success? 41 Puppet.err _("Unable to submit report to %{url} [%{code}] %{message}") % { url: Puppet[:reporturl].to_s, code: response.code, message: response.reason } 42 end 43 end 44 end
# File lib/puppet/provider/user/user_role_add.rb 133 def profiles 134 user_attributes[:profiles] if user_attributes 135 end
# File lib/puppet/provider/user/user_role_add.rb 137 def project 138 user_attributes[:project] if user_attributes 139 end
Hack things a bit so we only ever check the ensure property.
# File lib/puppet/type/tidy.rb 268 def properties 269 [] 270 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 1106 def property_fix 1107 properties.each do |thing| 1108 next unless [:mode, :owner, :group, :seluser, :selrole, :seltype, :selrange].include?(thing.name) 1109 1110 # Make sure we get a new stat object 1111 @stat = :needs_stat 1112 currentvalue = thing.retrieve 1113 thing.sync unless thing.safe_insync?(currentvalue) 1114 end 1115 end
# File lib/puppet/provider/user/useradd.rb 404 def property_manages_password_age?(property) 405 property.to_s =~ /password_.+_age|password_warn_days/ 406 end
# File lib/puppet/provider/package/apt.rb 217 def purge 218 self.run_preseed if @resource[:responsefile] 219 args = ['-y', '-q'] 220 args << '--allow-change-held-packages' if self.properties[:mark] == :hold 221 args << :remove << '--purge' << @resource[:name] 222 aptget(*args) 223 # workaround a "bug" in apt, that already removed packages are not purged 224 super 225 end
# File lib/puppet/provider/group/groupadd.rb 130 def purge_members 131 localmodify('-m', members_to_s(members), @resource.name) 132 end
# File lib/puppet/provider/package/portage.rb 107 def qatom 108 output_format = self.qatom_output_format 109 result_format = self.qatom_result_format 110 result_fields = self.qatom_result_fields 111 @atom ||= begin 112 package_info = {} 113 # do the search 114 should = @resource[:ensure] 115 case should 116 # The terms present, absent, purged, installed, latest in :ensure 117 # resolve as Symbols, and we do not need specific package version in this case 118 when true, false, Symbol 119 search = @resource[:name] 120 else 121 search = '=' + @resource[:name] + '-' + "#{should}" 122 end 123 search_output = qatom_bin(*([search, '--format', output_format])) 124 # verify if the search found anything 125 match = result_format.match(search_output) 126 if match 127 result_fields.zip(match.captures) do |field, value| 128 # some fields can be empty or (null) (if we are not passed a category in the package name for instance) 129 if value == '(null)' || value == '<unset>' 130 package_info[field] = nil 131 elsif !value or value.empty? 132 package_info[field] = nil 133 else 134 package_info[field] = value 135 end 136 end 137 end 138 @atom = package_info 139 rescue Puppet::ExecutionFailure => detail 140 raise Puppet::Error.new(detail) 141 end 142 end
# File lib/puppet/provider/package/portage.rb 144 def qatom_output_format 145 '"[%[CATEGORY]] [%[PN]] [%[PV]] [%[PR]] [%[SLOT]] [%[pfx]] [%[sfx]]"' 146 end
# File lib/puppet/provider/package/portage.rb 152 def qatom_result_fields 153 [:category, :pn, :pv, :pr, :slot, :pfx, :sfx] 154 end
# File lib/puppet/provider/package/portage.rb 148 def qatom_result_format 149 /^\"\[(\S*)\]\s+\[(\S*)\]\s+\[(\S*)\]\s+\[(\S*)\]\s+\[(\S*)\]\s+\[(\S*)\]\s+\[(\S*)\](.*)\"$/ 150 end
# File lib/puppet/provider/package/aix.rb 163 def query 164 self.class.pkglist(:pkgname => @resource[:name]) 165 end
Add a new setting to the rc files
# File lib/puppet/provider/service/freebsd.rb 88 def rc_add(service, rcvar, yesno) 89 append = "\# Added by Puppet\n#{rcvar}_enable=\"#{yesno}\"\n" 90 # First, try the one-file-per-service style 91 if Puppet::FileSystem.exist?(rcconf_dir) 92 File.open(rcconf_dir + "/#{service}", File::WRONLY | File::APPEND | File::CREAT, 0644) { 93 |f| f << append 94 self.debug("Appended to #{f.path}") 95 } 96 else 97 # Else, check the local rc file first, but don't create it 98 if Puppet::FileSystem.exist?(rcconf_local) 99 File.open(rcconf_local, File::WRONLY | File::APPEND) { 100 |f| f << append 101 self.debug("Appended to #{f.path}") 102 } 103 else 104 # At last use the standard rc.conf file 105 File.open(rcconf, File::WRONLY | File::APPEND | File::CREAT, 0644) { 106 |f| f << append 107 self.debug("Appended to #{f.path}") 108 } 109 end 110 end 111 end
Edit rc files and set the service to yes/no
# File lib/puppet/provider/service/freebsd.rb 62 def rc_edit(yesno) 63 service = self.service_name 64 rcvar = self.rcvar_name 65 self.debug("Editing rc files: setting #{rcvar} to #{yesno} for #{service}") 66 self.rc_add(service, rcvar, yesno) if not self.rc_replace(service, rcvar, yesno) 67 end
Try to find an existing setting in the rc files and replace the value
# File lib/puppet/provider/service/freebsd.rb 71 def rc_replace(service, rcvar, yesno) 72 success = false 73 # Replace in all files, not just in the first found with a match 74 [rcconf, rcconf_local, rcconf_dir + "/#{service}"].each do |filename| 75 if Puppet::FileSystem.exist?(filename) 76 s = File.read(filename) 77 if s.gsub!(/^(#{rcvar}(_enable)?)=\"?(YES|NO)\"?/, "\\1=\"#{yesno}\"") 78 Puppet::FileSystem.replace_file(filename) { |f| f << s } 79 self.debug("Replaced in #{filename}") 80 success = true 81 end 82 end 83 end 84 success 85 end
# File lib/puppet/provider/service/freebsd.rb 9 def rcconf() '/etc/rc.conf' end
# File lib/puppet/provider/service/bsd.rb 11 def rcconf_dir 12 '/etc/rc.conf.d' 13 end
# File lib/puppet/provider/service/freebsd.rb 10 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 23 def rcvar 24 rcvar = execute([self.initscript, :rcvar], :failonfail => true, :combine => false, :squelch => false) 25 rcvar = rcvar.split("\n") 26 rcvar.delete_if {|str| str =~ /^#\s*$/} 27 rcvar[1] = rcvar[1].gsub(/^\$/, '') 28 rcvar 29 end
Extract rcvar name
# File lib/puppet/provider/service/freebsd.rb 47 def rcvar_name 48 extract_value_name('rcvar', 1, /(.*?)(_enable)?=(.*)/, '\1') 49 end
Extract rcvar value
# File lib/puppet/provider/service/freebsd.rb 52 def rcvar_value 53 value = self.rcvar[1] 54 self.error("No rcvar value found in rcvar") if value.nil? 55 value = value.gsub!(/(.*)(_enable)?="?(\w+)"?/, '\3') 56 self.error("rcvar value is empty") if value.nil? 57 self.debug("rcvar value is #{value}") 58 value 59 end
@return [String] The type of the current file, cast to a string.
# File lib/puppet/type/file.rb 1003 def read_current_type 1004 stat_info = stat 1005 if stat_info 1006 stat_info.ftype.to_s 1007 else 1008 nil 1009 end 1010 end
# File lib/puppet/provider/service/upstart.rb 304 def read_override_file 305 if Puppet::FileSystem.exist?(overscript) 306 read_script_from(overscript) 307 else 308 "" 309 end 310 end
# File lib/puppet/provider/service/upstart.rb 375 def read_script_from(filename) 376 File.open(filename) do |file| 377 file.read 378 end 379 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 628 def recurse 629 children = (self[:recurse] == :remote) ? {} : recurse_local 630 631 if self[:target] 632 recurse_link(children) 633 elsif self[:source] 634 recurse_remote(children) 635 end 636 637 # If we're purging resources, then delete any resource that isn't on the 638 # remote system. 639 mark_children_for_purging(children) if self.purge? 640 641 result = children.values.sort_by { |a| a[:path] } 642 remove_less_specific_files(result) 643 end
A simple method for determining whether we should be recursing.
# File lib/puppet/type/file.rb 673 def recurse? 674 self[:recurse] == true or self[:recurse] == :remote 675 end
Recurse the target of the link.
# File lib/puppet/type/file.rb 678 def recurse_link(children) 679 perform_recursion(self[:target]).each do |meta| 680 if meta.relative_path == "." 681 self[:ensure] = :directory 682 next 683 end 684 685 children[meta.relative_path] ||= newchild(meta.relative_path) 686 if meta.ftype == "directory" 687 children[meta.relative_path][:ensure] = :directory 688 else 689 children[meta.relative_path][:ensure] = :link 690 children[meta.relative_path][:target] = meta.full_path 691 end 692 end 693 children 694 end
Recurse the file itself, returning a Metadata instance for every found file.
# File lib/puppet/type/file.rb 697 def recurse_local 698 result = perform_recursion(self[:path]) 699 return {} unless result 700 result.inject({}) do |hash, meta| 701 next hash if meta.relative_path == "." 702 703 hash[meta.relative_path] = newchild(meta.relative_path) 704 hash 705 end 706 end
Recurse against our remote file.
# File lib/puppet/type/file.rb 709 def recurse_remote(children) 710 recurse_remote_metadata.each do |meta| 711 if meta.relative_path == "." 712 self[:checksum] = meta.checksum_type 713 parameter(:source).metadata = meta 714 next 715 end 716 children[meta.relative_path] ||= newchild(meta.relative_path) 717 children[meta.relative_path][:source] = meta.source 718 children[meta.relative_path][:checksum] = meta.checksum_type 719 children[meta.relative_path].parameter(:source).metadata = meta 720 end 721 722 children 723 end
# File lib/puppet/type/file.rb 725 def recurse_remote_metadata 726 sourceselect = self[:sourceselect] 727 728 total = self[:source].collect do |source| 729 # For each inlined file resource, the catalog contains a hash mapping 730 # source path to lists of metadata returned by a server-side search. 731 recursive_metadata = catalog.recursive_metadata[title] 732 if recursive_metadata 733 result = recursive_metadata[source] 734 else 735 result = perform_recursion(source) 736 end 737 738 next unless result 739 top = result.find { |r| r.relative_path == "." } 740 return [] if top && top.ftype != "directory" 741 result.each do |data| 742 if data.relative_path == '.' 743 data.source = source 744 else 745 # REMIND: appending file paths to URL may not be safe, e.g. foo+bar 746 data.source = "#{source}/#{data.relative_path}" 747 end 748 end 749 break result if result and ! result.empty? and sourceselect == :first 750 result 751 end.flatten.compact 752 753 # This only happens if we have sourceselect == :all 754 unless sourceselect == :first 755 found = [] 756 total.reject! do |data| 757 result = found.include?(data.relative_path) 758 found << data.relative_path unless result 759 result 760 end 761 end 762 763 total 764 end
# File lib/puppet/functions/reduce.rb 153 def reduce_with_memo(enumerable, given_memo) 154 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 155 enum.reduce(given_memo) do |memo, x| 156 begin 157 yield(memo, x) 158 rescue StopIteration 159 return memo 160 end 161 end 162 end
# File lib/puppet/functions/reduce.rb 142 def reduce_without_memo(enumerable) 143 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 144 enum.reduce do |memo, x| 145 begin 146 yield(memo, x) 147 rescue StopIteration 148 return memo 149 end 150 end 151 end
# File lib/puppet/type/component.rb 50 def ref 51 reference.to_s 52 end
# File lib/puppet/type/component.rb 63 def refresh 64 catalog.adjacent(self).each do |child| 65 if child.respond_to?(:refresh) 66 child.refresh 67 child.log "triggering #{:refresh}" 68 end 69 end 70 end
# File lib/puppet/functions/regsubst.rb 93 def regsubst_regexp(target, pattern, replacement, flags = nil) 94 pattern = (pattern.pattern || '') if pattern.is_a?(Puppet::Pops::Types::PRegexpType) 95 inner_regsubst(target, pattern, replacement, flags == 'G' ? :gsub : :sub) 96 end
# File lib/puppet/functions/regsubst.rb 77 def regsubst_string(target, pattern, replacement, flags = nil, encoding = nil) 78 re_flags = 0 79 operation = :sub 80 if !flags.nil? 81 flags.split(//).each do |f| 82 case f 83 when 'G' then operation = :gsub 84 when 'E' then re_flags |= Regexp::EXTENDED 85 when 'I' then re_flags |= Regexp::IGNORECASE 86 when 'M' then re_flags |= Regexp::MULTILINE 87 end 88 end 89 end 90 inner_regsubst(target, Regexp.compile(pattern, re_flags, encoding), replacement, operation) 91 end
# File lib/puppet/provider/package/portage.rb 99 def reinstall 100 self.install 101 end
@return [Boolean] if the directory was removed (which is always true currently) @api private
# File lib/puppet/type/file.rb 1028 def remove_directory(wanted_type) 1029 if force? 1030 debug "Removing existing directory for replacement with #{wanted_type}" 1031 FileUtils.rmtree(self[:path]) 1032 stat_needed 1033 true 1034 else 1035 notice _("Not removing directory; use 'force' to override") 1036 false 1037 end 1038 end
Back up and remove the file or directory at `self`.
@param [Symbol] should The file type replacing the current content. @return [Boolean] True if the file was removed, else False @raises [fail???] If the file could not be backed up or could not be removed.
# File lib/puppet/type/file.rb 785 def remove_existing(should) 786 wanted_type = should.to_s 787 current_type = read_current_type 788 789 if current_type.nil? 790 return false 791 end 792 793 if self[:backup] 794 if can_backup?(current_type) 795 backup_existing 796 else 797 self.warning _("Could not back up file of type %{current_type}") % { current_type: current_type } 798 end 799 end 800 801 if wanted_type != "link" and current_type == wanted_type 802 return false 803 end 804 805 case current_type 806 when "directory" 807 return remove_directory(wanted_type) 808 when "link", "file", "fifo", "socket" 809 return remove_file(current_type, wanted_type) 810 else 811 # Including: “blockSpecial”, “characterSpecial”, “unknown” 812 self.fail _("Could not remove files of type %{current_type}") % { current_type: current_type } 813 end 814 end
@return [Boolean] if the file was removed (which is always true currently) @api private
# File lib/puppet/type/file.rb 1042 def remove_file(current_type, wanted_type) 1043 debug "Removing existing #{current_type} for replacement with #{wanted_type}" 1044 Puppet::FileSystem.unlink(self[:path]) 1045 stat_needed 1046 true 1047 end
# File lib/puppet/type/file.rb 645 def remove_less_specific_files(files) 646 existing_files = catalog.vertices.select { |r| r.is_a?(self.class) } 647 self.class.remove_less_specific_files(files, self[:path], existing_files) do |file| 648 file[:path] 649 end 650 end
# File lib/puppet/provider/user/user_role_add.rb 145 def remove_managed_attributes 146 managed = managed_attributes 147 user_attributes.select { |k,v| !managed.include?(k) }.inject({}) { |hash, array| hash[array[0]] = array[1]; hash } 148 end
# File lib/puppet/provider/service/upstart.rb 328 def remove_manual_from(text) 329 text.gsub(MANUAL, "") 330 end
# File lib/puppet/provider/service/upstart.rb 320 def remove_trailing_comments_from(line) 321 line.gsub(/^(\s*[^#]*).*/, '\1') 322 end
# File lib/puppet/provider/service/upstart.rb 316 def remove_trailing_comments_from_commented_line_of(line) 317 line.gsub(/^(\s*#+\s*[^#]*).*/, '\1') 318 end
# File lib/puppet/network/formats.rb 67 def render(instance) 68 instance.to_yaml 69 end
# File lib/puppet/face/help.rb 99 def render_application_help(applicationname) 100 return Puppet::Application[applicationname].help 101 rescue StandardError, LoadError => detail 102 message = [] 103 message << _('Could not load help for the application %{application_name}.') % { application_name: applicationname } 104 message << _('Please check the error logs for more information.') 105 message << '' 106 message << _('Detail: "%{detail}"') % { detail: detail.message } 107 fail ArgumentError, message.join("\n"), detail.backtrace 108 end
# File lib/puppet/face/help.rb 110 def render_face_help(facename, actionname, version) 111 face, action = load_face_help(facename, actionname, version) 112 return template_for(face, action).result(binding) 113 rescue StandardError, LoadError => detail 114 message = [] 115 message << _('Could not load help for the face %{face_name}.') % { face_name: facename } 116 message << _('Please check the error logs for more information.') 117 message << '' 118 message << _('Detail: "%{detail}"') % { detail: detail.message } 119 fail ArgumentError, message.join("\n"), detail.backtrace 120 end
# File lib/puppet/face/help.rb 91 def render_face_man(facename) 92 # set 'face' as it's used in the erb processing. 93 face = Puppet::Face[facename.to_sym, :current] 94 # avoid unused variable warning 95 _face = face 96 erb('man.erb').result(binding) 97 end
# File lib/puppet/face/epp.rb 452 def render_file(epp_template_name, compiler, options, show_filename, file_nbr) 453 template_args = get_values(compiler, options) 454 output = String.new 455 begin 456 if show_filename && options[:header] 457 output << "\n" unless file_nbr == 1 458 output << "--- #{epp_template_name}\n" 459 end 460 # Change to an absolute file only if reference is to a an existing file. Note that an absolute file must be used 461 # or the template must be found on the module path when calling the epp evaluator. 462 template_file = Puppet::Parser::Files.find_template(epp_template_name, compiler.environment) 463 if template_file.nil? && Puppet::FileSystem.exist?(epp_template_name) 464 epp_template_name = File.expand_path(epp_template_name) 465 end 466 result = Puppet::Pops::Evaluator::EppEvaluator.epp(compiler.topscope, epp_template_name, compiler.environment, template_args) 467 if result.instance_of?(Puppet::Pops::Types::PSensitiveType::Sensitive) 468 output << result.unwrap 469 else 470 output << result 471 end 472 rescue Puppet::ParseError => detail 473 Puppet.err("--- #{epp_template_name}") if show_filename 474 raise detail 475 end 476 output 477 end
# File lib/puppet/face/epp.rb 442 def render_inline(epp_source, compiler, options) 443 template_args = get_values(compiler, options) 444 result = Puppet::Pops::Evaluator::EppEvaluator.inline_epp(compiler.topscope, epp_source, template_args) 445 if result.instance_of?(Puppet::Pops::Types::PSensitiveType::Sensitive) 446 result.unwrap 447 else 448 result 449 end 450 end
# File lib/puppet/network/formats.rb 21 def render_multiple(instances) 22 instances.to_msgpack 23 end
# File lib/puppet/provider/package/pkgng.rb 91 def repo_tag_from_urn(urn) 92 # extract repo tag from URN: urn:freebsd:repo:<tag> 93 match = /^urn:freebsd:repo:(.+)$/.match(urn) 94 raise ArgumentError urn.inspect unless match 95 match[1] 96 end
# File lib/puppet/face/config.rb 111 def report_section_and_environment(section_name, environment_name) 112 $stderr.puts colorize(:hyellow, 113 _("Resolving settings from section '%{section_name}' in environment '%{environment_name}'") % 114 { section_name: section_name, environment_name: environment_name }) 115 end
# File lib/puppet/functions/require.rb 48 def require_impl(scope, *classes) 49 if Puppet[:tasks] 50 raise Puppet::ParseErrorWithIssue.from_issue_and_stack( 51 Puppet::Pops::Issues::CATALOG_OPERATION_NOT_SUPPORTED_WHEN_SCRIPTING, 52 {:operation => 'require'}) 53 end 54 55 # Make call patterns uniform and protected against nested arrays, also make 56 # names absolute if so desired. 57 classes = scope.transform_and_assert_classnames(classes.flatten) 58 59 result = classes.map {|name| Puppet::Pops::Types::TypeFactory.host_class(name) } 60 61 # This is the same as calling the include function (but faster) since it again 62 # would otherwise need to perform the optional absolute name transformation 63 # (for no reason since they are already made absolute here). 64 # 65 scope.compiler.evaluate_classes(classes, scope, false) 66 krt = scope.environment.known_resource_types 67 68 classes.each do |klass| 69 # lookup the class in the scopes 70 klass = (classobj = krt.find_hostclass(klass)) ? classobj.name : nil 71 raise Puppet::ParseError.new(_("Could not find class %{klass}") % { klass: klass }) unless klass 72 ref = Puppet::Resource.new(:class, klass) 73 resource = scope.resource 74 resource.set_parameter(:require, [resource[:require]].flatten.compact << ref) 75 end 76 result 77 end
# File lib/puppet/provider/package/dnfmodule.rb 131 def reset 132 execute([command(:dnf), 'module', 'reset', '-d', '0', '-e', self.class.error_level, '-y', @resource[:name]]) 133 end
# File lib/puppet/provider/file/windows.rb 144 def resolved_path 145 path = file() 146 # under POSIX, :manage means use lchown - i.e. operate on the link 147 return path.to_s if resource[:links] == :manage 148 149 # otherwise, use chown -- that will resolve the link IFF it is a link 150 # otherwise it will operate on the path 151 Puppet::FileSystem.symlink?(path) ? Puppet::FileSystem.readlink(path) : path.to_s 152 end
# File lib/puppet/type/resources.rb 129 def resource_type 130 unless defined?(@resource_type) 131 type = Puppet::Type.type(self[:name]) 132 unless type 133 raise Puppet::DevError, _("Could not find resource type") 134 end 135 @resource_type = type 136 end 137 @resource_type 138 end
# File lib/puppet/provider/service/daemontools.rb 182 def restart 183 svc "-t", self.service 184 end
# File lib/puppet/provider/service/init.rb 171 def restartcmd 172 (@resource[:hasrestart] == :true) && [initscript, :restart] 173 end
# File lib/puppet/type/file.rb 816 def retrieve 817 # This check is done in retrieve to ensure it happens before we try to use 818 # metadata in `copy_source_values`, but so it only fails the resource and not 819 # catalog validation (because that would be a breaking change from Puppet 4). 820 if Puppet::Util::Platform.windows? && parameter(:source) && 821 [:use, :use_when_creating].include?(self[:source_permissions]) 822 #TRANSLATORS "source_permissions => ignore" should not be translated 823 err_msg = _("Copying owner/mode/group from the source file on Windows is not supported; use source_permissions => ignore.") 824 if self[:owner] == nil || self[:group] == nil || self[:mode] == nil 825 # Fail on Windows if source permissions are being used and the file resource 826 # does not have mode owner, group, and mode all set (which would take precedence). 827 self.fail err_msg 828 else 829 # Warn if use source permissions is specified on Windows 830 self.warning err_msg 831 end 832 end 833 834 # `checksum_value` implies explicit management of all metadata, so skip metadata 835 # retrieval. Otherwise, if source is set, retrieve metadata for source. 836 if (source = parameter(:source)) && property(:checksum_value).nil? 837 source.copy_source_values 838 end 839 super 840 end
# File lib/puppet/functions/return.rb 12 def return_impl(value = nil) 13 file, line = Puppet::Pops::PuppetStack.top_of_stack 14 raise Puppet::Pops::Evaluator::Return.new(value, file, line) 15 end
# File lib/puppet/functions/reverse_each.rb 86 def reverse_each(iterable) 87 # produces an Iterable 88 Puppet::Pops::Types::Iterable.asserted_iterable(self, iterable, true).reverse_each 89 end
# File lib/puppet/functions/reverse_each.rb 91 def reverse_each_block(iterable, &block) 92 Puppet::Pops::Types::Iterable.asserted_iterable(self, iterable).reverse_each(&block) 93 nil 94 end
# File lib/puppet/provider/user/user_role_add.rb 125 def roles 126 user_attributes[:roles] if user_attributes 127 end
# File lib/puppet/provider/user/windows_adsi.rb 25 def roles=(value) 26 current = roles.split(',') 27 should = value.split(',') 28 29 add_list = should - current 30 Puppet::Util::Windows::User::set_rights(@resource[:name], add_list) unless add_list.empty? 31 32 if @resource[:role_membership] == :inclusive 33 remove_list = current - should 34 Puppet::Util::Windows::User::remove_rights(@resource[:name], remove_list) unless remove_list.empty? 35 end 36 end
# File lib/puppet/provider/package/gem.rb 189 def rubygem_version(command) 190 command_options = ["--version"] 191 self.class.execute_gem_command(command, command_options) 192 end
# File lib/puppet/provider/exec/posix.rb 54 def run(command, check = false) 55 if resource[:umask] 56 Puppet::Util::withumask(resource[:umask]) { super(command, check) } 57 else 58 super(command, check) 59 end 60 end
# File lib/puppet/provider/package/pkgutil.rb 151 def run_pkgutil(resource, *args) 152 # Allow source to be one or more URLs pointing to a repository that all 153 # get passed to pkgutil via one or more -t options 154 if resource[:source] 155 sources = [resource[:source]].flatten 156 pkguti(*[sources.map{|src| [ "-t", src ]}, *args].flatten) 157 else 158 pkguti(*args.flatten) 159 end 160 end
preseeds answers to dpkg-set-selection from the “responsefile”
# File lib/puppet/provider/package/apt.rb 198 def run_preseed 199 response = @resource[:responsefile] 200 if response && Puppet::FileSystem.exist?(response) 201 self.info(_("Preseeding %{response} to debconf-set-selections") % { response: response }) 202 203 preseed response 204 else 205 self.info _("No responsefile specified or non existent, not preseeding anything") 206 end 207 end
# File lib/puppet/provider/service/openbsd.rb 80 def running? 81 output = execute([command(:rcctl), "check", @resource[:name]], 82 :failonfail => false, :combine => false, :squelch => false).chomp 83 return true if output =~ /\(ok\)/ 84 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 406 def salt=(value) 407 if (Puppet::Util::Package.versioncmp(self.class.get_os_version, '10.15') >= 0) 408 if value.length != 64 409 self.fail "macOS versions 10.15 and higher require the salt to be 32-bytes. Since Puppet's user resource requires the value to be hex encoded, the length of the salt's string must be 64. Please check your salt and try again." 410 end 411 end 412 if (Puppet::Util::Package.versioncmp(self.class.get_os_version, '10.7') > 0) 413 assert_full_pbkdf2_password 414 415 sleep 3 416 flush_dscl_cache 417 users_plist = get_users_plist(@resource.name) 418 shadow_hash_data = get_shadow_hash_data(users_plist) 419 set_salted_pbkdf2(users_plist, shadow_hash_data, 'salt', value) 420 flush_dscl_cache 421 end 422 end
Scan a structure that looks like the package type 'install_options' structure for all hashes that have a specific key.
@api private @param options [Array<String | Hash>, nil] The options structure. If the
options are nil an empty array will be returned.
@param key [String] The key to look for in all contained hashes @return [Array<String>] All hash values with the given key.
# File lib/puppet/provider/package/yum.rb 375 def scan_options(options, key) 376 return [] unless options.is_a?(Enumerable) 377 values = options.map do | repo | 378 value = if repo.is_a?(String) 379 next unless repo.include?('=') 380 Hash[*repo.strip.split('=')] # make it a hash 381 else 382 repo 383 end 384 value[key] 385 end 386 values.compact.uniq 387 end
# File lib/puppet/functions/scanf.rb 38 def scanf(data, format) 39 result = data.scanf(format) 40 if block_given? 41 result = yield(result) 42 end 43 result 44 end
# File lib/puppet/provider/service/init.rb 140 def search(name) 141 paths.each do |path| 142 fqname = File.join(path,name) 143 if Puppet::FileSystem.exist? fqname 144 return fqname 145 else 146 self.debug("Could not find #{name} in #{path}") 147 end 148 end 149 150 paths.each do |path| 151 fqname_sh = File.join(path,"#{name}.sh") 152 if Puppet::FileSystem.exist? fqname_sh 153 return fqname_sh 154 else 155 self.debug("Could not find #{name}.sh in #{path}") 156 end 157 end 158 raise Puppet::Error, "Could not find init script for '#{name}'" 159 end
# File lib/puppet/functions/empty.rb 54 def sensitive_string_empty(str) 55 str.unwrap.empty? 56 end
returns the full path of this service when enabled (ie in the service directory)
# File lib/puppet/provider/service/daemontools.rb 103 def service 104 File.join(self.servicedir, resource[:name]) 105 end
Use either a specified command or the default for our provider.
@return [Puppet::Util::Execution::ProcessOutput]
# File lib/puppet/provider/service/service.rb 59 def service_command(type, fof = true) 60 c = @resource[type] 61 if c 62 cmd = [c] 63 else 64 cmd = [send("#{type}cmd")].flatten 65 end 66 service_execute(type, cmd, fof) 67 end
# File lib/puppet/provider/service/init.rb 175 def service_execute(type, command, fof = true, squelch = false, combine = true) 176 if type == :start && Puppet.runtime[:facter].value('os.family') == "Solaris" 177 command = ["/usr/bin/ctrun -l child", command].flatten.join(" ") 178 end 179 super(type, command, fof, squelch, combine) 180 end
# File lib/puppet/provider/service/smf.rb 64 def service_exists? 65 self.service_fmri 66 true 67 rescue Puppet::ExecutionFailure 68 false 69 end
Returns the service's FMRI. We fail if multiple FMRIs correspond to @resource.
If the service does not exist or we fail to get any FMRIs from svcs, this method will raise a Puppet::Error
# File lib/puppet/provider/service/smf.rb 86 def service_fmri 87 return @fmri if @fmri 88 89 # `svcs -l` is better to use because we can detect service instances 90 # that have not yet been activated or enabled (i.e. it lets us detect 91 # services that svcadm has not yet touched). `svcs -H -o fmri` is a bit 92 # more limited. 93 lines = svcs("-l", @resource[:name]).chomp.lines.to_a 94 lines.select! { |line| line =~ /^fmri/ } 95 fmris = lines.map! { |line| line.split(' ')[-1].chomp } 96 unless fmris.length == 1 97 raise Puppet::Error, _("Failed to get the FMRI of the %{service} service: The pattern '%{service}' matches multiple FMRIs! These are the FMRIs it matches: %{all_fmris}") % { service: @resource[:name], all_fmris: fmris.join(', ') } 98 end 99 100 @fmri = fmris.first 101 end
Extract service name
# File lib/puppet/provider/service/freebsd.rb 42 def service_name 43 extract_value_name('service', 0, /# (\S+).*/, '\1') 44 end
# File lib/puppet/provider/service/smf.rb 150 def service_states 151 # Gets the current and next state of the service. We have a next state because SMF 152 # manages services asynchronously. If there is no 'next' state, svcs will put a '-' 153 # to indicate as such. 154 current_state, next_state = svcs("-H", "-o", "state,nstate", self.service_fmri).chomp.split(' ') 155 156 { 157 :current => current_state, 158 :next => next_state == "-" ? nil : next_state 159 } 160 end
find the service dir on this node
# File lib/puppet/provider/service/daemontools.rb 88 def servicedir 89 unless @servicedir 90 ["/service", "/etc/service","/var/lib/svscan"].each do |path| 91 if Puppet::FileSystem.exist?(path) 92 @servicedir = path 93 break 94 end 95 end 96 raise "Could not find service directory" unless @servicedir 97 end 98 @servicedir 99 end
# File lib/puppet/provider/user/directoryservice.rb 497 def set_attribute_with_dscl(dscl_command, path, username, keyname, value) 498 begin 499 dscl '.', dscl_command, "/#{path}/#{username}", keyname, value 500 rescue Puppet::ExecutionFailure => detail 501 raise Puppet::Error, "Could not set the dscl #{keyname} key with value: #{value} - #{detail.inspect}", detail.backtrace 502 end 503 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 655 def set_salted_pbkdf2(users_plist, shadow_hash_data, field, value) 656 shadow_hash_data = Hash.new unless shadow_hash_data 657 shadow_hash_data['SALTED-SHA512-PBKDF2'] = Hash.new unless shadow_hash_data['SALTED-SHA512-PBKDF2'] 658 case field 659 when 'salt', 'entropy' 660 shadow_hash_data['SALTED-SHA512-PBKDF2'][field] = Puppet::Util::Plist.string_to_blob(base64_decode_string(value)) 661 when 'iterations' 662 shadow_hash_data['SALTED-SHA512-PBKDF2'][field] = Integer(value) 663 else 664 raise Puppet::Error "Puppet has tried to set an incorrect field for the 'SALTED-SHA512-PBKDF2' hash. Acceptable fields are 'salt', 'entropy', or 'iterations'." 665 end 666 667 # on 10.8, this field *must* contain 8 stars, or authentication will 668 # fail. 669 users_plist['passwd'] = ('*' * 8) 670 671 # Convert shadow_hash_data to a binary plist, and call the 672 # set_shadow_hash_data method to serialize and write the data 673 # back to the user's plist. 674 binary_plist = self.class.convert_hash_to_binary(shadow_hash_data) 675 set_shadow_hash_data(users_plist, binary_plist) 676 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 637 def set_salted_sha512(users_plist, shadow_hash_data, value) 638 unless shadow_hash_data 639 shadow_hash_data = Hash.new 640 shadow_hash_data['SALTED-SHA512'] = String.new 641 end 642 shadow_hash_data['SALTED-SHA512'] = base64_decode_string(value) 643 binary_plist = self.class.convert_hash_to_binary(shadow_hash_data) 644 set_shadow_hash_data(users_plist, binary_plist) 645 end
Overrides the default implementation to do nothing. This type contains data from class/define parameters, but does not have actual parameters or properties at the Type level. We can simply ignore anything flagged as sensitive here, since any contained resources will handle that sensitivity themselves. There is no risk of this information leaking into reports, since no Component instances survive the graph transmutation.
# File lib/puppet/type/component.rb 84 def set_sensitive_parameters(sensitive_parameters) 85 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 595 def set_shadow_hash_data(users_plist, binary_plist) 596 binary_plist = Puppet::Util::Plist.string_to_blob(binary_plist) 597 if users_plist.has_key?('ShadowHashData') 598 users_plist['ShadowHashData'][0] = binary_plist 599 else 600 users_plist['ShadowHashData'] = [binary_plist] 601 end 602 write_and_import_shadow_hash_data(users_plist['ShadowHashData'].first) 603 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 845 def setchecksum(sum = nil) 846 if @parameters.include? :checksum 847 if sum 848 @parameters[:checksum].checksum = sum 849 else 850 # If they didn't pass in a sum, then tell checksum to 851 # figure it out. 852 currentvalue = @parameters[:checksum].retrieve 853 @parameters[:checksum].checksum = currentvalue 854 end 855 end 856 end
# File lib/puppet/provider/service/smf.rb 71 def setup_service 72 return unless @resource[:manifest] 73 return if self.service_exists? 74 75 Puppet.notice("Importing #{@resource[:manifest]} for #{@resource[:name]}") 76 svccfg(:import, @resource[:manifest]) 77 rescue Puppet::ExecutionFailure => detail 78 raise Puppet::Error.new( "Cannot config #{@resource[:name]} to enable it: #{detail}", detail ) 79 end
# File lib/puppet/provider/service/daemontools.rb 128 def setupservice 129 if resource[:manifest] 130 Puppet.notice "Configuring #{resource[:name]}" 131 command = [ resource[:manifest], resource[:name] ] 132 system("#{command}") 133 end 134 rescue Puppet::ExecutionFailure => detail 135 raise Puppet::Error.new( "Cannot config #{self.service} to enable it: #{detail}", detail) 136 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 179 def shadow_entry 180 return @shadow_entry if defined? @shadow_entry 181 @shadow_entry = File.readlines(target_file_path). 182 reject { |r| r =~ /^[^\w]/ }. 183 # PUP-229: don't suppress the empty fields 184 collect { |l| l.chomp.split(':', -1) }. 185 find { |user, _| user == @resource[:name] } 186 end
# File lib/puppet/provider/user/useradd.rb 76 def shell 77 return localshell if @resource.forcelocal? 78 get(:shell) 79 end
# File lib/puppet/provider/user/user_role_add.rb 32 def shell=(value) 33 check_valid_shell 34 set("shell", value) 35 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 861 def should_be_file? 862 return true if self[:ensure] == :file 863 864 # I.e., it's set to something like "directory" 865 return false if self[:ensure] && self[:ensure] != :present 866 867 # The user doesn't really care, apparently 868 if self[:ensure] == :present 869 return true unless stat 870 return(stat.ftype == "file" ? true : false) 871 end 872 873 # If we've gotten here, then :ensure isn't set 874 return true if self[:content] 875 return true if stat and stat.ftype == "file" 876 false 877 end
The hidden singleton lurks behind everyone
# File lib/puppet/util/metaid.rb 4 def singleton_class; class << self; self; end; end
# File lib/puppet/functions/slice.rb 72 def slice_Common(o, slice_size, filler, pblock) 73 serving_size = asserted_slice_serving_size(pblock, slice_size) 74 75 enumerator = o.each_slice(slice_size) 76 result = [] 77 if serving_size == 1 78 begin 79 if pblock 80 loop do 81 pblock.call(enumerator.next) 82 end 83 else 84 loop do 85 result << enumerator.next 86 end 87 end 88 rescue StopIteration 89 end 90 else 91 begin 92 loop do 93 a = enumerator.next 94 if a.size < serving_size 95 a = a.dup.fill(filler, a.length...serving_size) 96 end 97 pblock.call(*a) 98 end 99 rescue StopIteration 100 end 101 end 102 if pblock 103 o 104 else 105 result 106 end 107 end
# File lib/puppet/functions/slice.rb 66 def slice_Enumerable(enumerable, slice_size, &pblock) 67 enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable) 68 result = slice_Common(enum, slice_size, nil, block_given? ? pblock : nil) 69 block_given? ? enumerable : result 70 end
# File lib/puppet/functions/slice.rb 61 def slice_Hash(hash, slice_size, &pblock) 62 result = slice_Common(hash, slice_size, [], block_given? ? pblock : nil) 63 block_given? ? hash : result 64 end
# File lib/puppet/functions/sort.rb 72 def sort_array(a, &block) 73 a.sort(&block) 74 end
# File lib/puppet/functions/sort.rb 68 def sort_string(s, &block) 69 sort_array(s.split(''), &block).join('') 70 end
# File lib/puppet/provider/package/apt.rb 260 def source 261 @source ||= @resource[:source] 262 end
# File lib/puppet/functions/split.rb 43 def split_Regexp(str, pattern) 44 str.split(pattern) 45 end
# File lib/puppet/functions/split.rb 47 def split_RegexpType(str, pattern) 48 str.split(pattern.regexp) 49 end
# File lib/puppet/functions/split.rb 39 def split_String(str, pattern) 40 str.split(Regexp.compile(pattern)) 41 end
This method basically just splits the multi-line input string into chunks based on lines that contain nothing but whitespace. It also strips any leading or trailing whitespace (including newlines) from the resulting strings and then returns them as an array.
# File lib/puppet/provider/package/nim.rb 208 def split_into_paragraphs(showres_output) 209 showres_output.split(/^\s*$/).map { |p| p.strip! } 210 end
# File lib/puppet/provider/package/hpux.rb 42 def standard_args 43 ["-x", "mount_all_filesystems=false"] 44 end
Run the 'start' parameter command, or the specified 'startcmd'.
# File lib/puppet/provider/service/base.rb 96 def start 97 service_command(:start) 98 nil 99 end
The command used to start. Generated if the 'binary' argument is passed.
# File lib/puppet/provider/service/base.rb 103 def startcmd 104 if @resource[:binary] 105 return @resource[:binary] 106 else 107 raise Puppet::Error, 108 "Services must specify a start command or a binary" 109 end 110 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 887 def stat 888 return @stat unless @stat == :needs_stat 889 890 method = :stat 891 892 # Files are the only types that support links 893 if (self.class.name == :file and self[:links] != :follow) or self.class.name == :tidy 894 method = :lstat 895 end 896 897 @stat = begin 898 Puppet::FileSystem.send(method, self[:path]) 899 rescue Errno::ENOENT 900 nil 901 rescue Errno::ENOTDIR 902 nil 903 rescue Errno::EACCES 904 warning _("Could not stat; permission denied") 905 nil 906 rescue Errno::EINVAL 907 warning _("Could not stat; invalid pathname") 908 nil 909 end 910 end
# File lib/puppet/type/file.rb 1049 def stat_needed 1050 @stat = :needs_stat 1051 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 69 def status 70 if @resource[:status] or statuscmd 71 # Don't fail when the exit status is not 0. 72 status = service_command(:status, false) 73 74 # Explicitly calling exitstatus to facilitate testing 75 if status.exitstatus == 0 76 return :running 77 else 78 return :stopped 79 end 80 else 81 pid = getpid 82 if pid 83 self.debug "PID is #{pid}" 84 return :running 85 else 86 return :stopped 87 end 88 end 89 end
There is no default command, which causes other methods to be used
# File lib/puppet/provider/service/base.rb 92 def statuscmd 93 end
# File lib/puppet/functions/step.rb 90 def step(iterable, step) 91 # produces an Iterable 92 Puppet::Pops::Types::Iterable.asserted_iterable(self, iterable, true).step(step) 93 end
# File lib/puppet/functions/step.rb 95 def step_block(iterable, step, &block) 96 Puppet::Pops::Types::Iterable.asserted_iterable(self, iterable).step(step, &block) 97 nil 98 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 117 def stop 118 if @resource[:stop] or stopcmd 119 service_command(:stop) 120 nil 121 else 122 pid = getpid 123 unless pid 124 self.info _("%{name} is not running") % { name: self.name } 125 return false 126 end 127 begin 128 output = kill pid 129 rescue Puppet::ExecutionFailure 130 @resource.fail Puppet::Error, "Could not kill #{self.name}, PID #{pid}: #{output}", $! 131 end 132 return true 133 end 134 end
There is no default command, which causes other methods to be used
# File lib/puppet/provider/service/base.rb 137 def stopcmd 138 end
# File lib/puppet/functions/empty.rb 58 def string_empty(str) 59 str.empty? 60 end
# File lib/puppet/functions/index.rb 155 def string_index(str, match) 156 str.index(match) 157 end
# File lib/puppet/functions/length.rb 37 def string_length(s) 38 s.length 39 end
# File lib/puppet/type/file/checksum.rb 25 def sum(content) 26 content = content.is_a?(Puppet::Pops::Types::PBinaryType::Binary) ? content.binary_buffer : content 27 type = digest_algorithm 28 "{#{type}}" + send(type, content) 29 end
# File lib/puppet/type/file/checksum.rb 31 def sum_file(path) 32 type = digest_algorithm 33 method = type.to_s + "_file" 34 "{#{type}}" + send(method, path).to_s 35 end
# File lib/puppet/type/file/checksum.rb 37 def sum_stream(&block) 38 type = digest_algorithm 39 method = type.to_s + "_stream" 40 checksum = send(method, &block) 41 "{#{type}}#{checksum}" 42 end
# File lib/puppet/network/formats.rb 76 def supported?(klass) 77 true 78 end
Returns true if the provider supports incomplete services.
# File lib/puppet/provider/service/smf.rb 104 def supports_incomplete_services? 105 Puppet::Util::Package.versioncmp(Puppet.runtime[:facter].value('os.release.full'), '11.1') >= 0 106 end
# File lib/puppet/type/resources.rb 159 def system_users 160 %w{root nobody bin noaccess daemon sys} 161 end
This helper ensures that the enable state cache is always reset after a systemctl enable operation. A particular service state is not guaranteed after such an operation, so the cache must be emptied to prevent inconsistencies in the provider's believed state of the service and the actual state. @param action [String,Symbol] One of 'enable', 'disable', 'mask' or 'unmask'
# File lib/puppet/provider/service/systemd.rb 69 def systemctl_change_enable(action) 70 output = systemctl(action, '--', @resource[:name]) 71 rescue 72 raise Puppet::Error, "Could not #{action} #{self.name}: #{output}", $!.backtrace 73 ensure 74 @cached_enabled = nil 75 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 172 def target_file_path 173 "/etc/shadow" 174 end
# File lib/puppet/face/help.rb 134 def template_for(face, action) 135 if action.nil? 136 erb('face.erb') 137 else 138 erb('action.erb') 139 end 140 end
@deprecated because the exit status is not returned, use service_execute instead
# File lib/puppet/provider/service/service.rb 25 def texecute(type, command, fof = true, squelch = false, combine = true) 26 begin 27 execute(command, :failonfail => fof, :override_locale => false, :squelch => squelch, :combine => combine) 28 rescue Puppet::ExecutionFailure => detail 29 @resource.fail Puppet::Error, "Could not #{type} #{@resource.ref}: #{detail}", detail 30 end 31 nil 32 end
# File lib/puppet/functions/then.rb 74 def then(arg) 75 return nil if arg.nil? 76 yield(arg) 77 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 108 def tidy?(path, stat) 109 basename = File.basename(path) 110 flags = File::FNM_DOTMATCH | File::FNM_PATHNAME 111 return(value.find {|pattern| File.fnmatch(pattern, basename, flags) } ? true : false) 112 end
We want our title to just be the whole reference, rather than @title.
# File lib/puppet/type/component.rb 55 def title 56 ref 57 end
# File lib/puppet/type/component.rb 59 def title=(str) 60 @reference = Puppet::Resource.new(str) 61 end
# File lib/puppet/util/log/destinations.rb 225 def to_native(level) 226 Puppet::Util::Windows::EventLog.to_native(level) 227 end
# File lib/puppet/type/file.rb 912 def to_resource 913 resource = super 914 resource.delete(:target) if resource[:target] == :notlink 915 resource 916 end
# File lib/puppet/type/component.rb 72 def to_s 73 reference.to_s 74 end
# File lib/puppet/provider/user/user_role_add.rb 92 def transition(type) 93 cmd = [command(:modify)] 94 cmd << "-K" << "type=#{type}" 95 cmd += add_properties 96 cmd << @resource[:name] 97 end
# File lib/puppet/functions/tree_each.rb 173 def tree_Enumerable1(enum, options = {}, &block) 174 iterator(enum, options).each {|_, v| yield(v) } 175 enum 176 end
# File lib/puppet/functions/tree_each.rb 178 def tree_Enumerable2(enum, options = {}, &block) 179 iterator(enum, options).each {|path, v| yield(path, v) } 180 enum 181 end
# File lib/puppet/functions/tree_each.rb 183 def tree_Iterable(enum, options = {}, &block) 184 Puppet::Pops::Types::Iterable.on(iterator(enum, options)) 185 end
# File lib/puppet/provider/user/hpux.rb 82 def trusted 83 # Check to see if the HP-UX box is running in trusted compute mode 84 # UID for root should always be 0 85 trusted_sys = exec_getprpw('root','-m uid') 86 if trusted_sys.chomp == "uid=0" 87 return true 88 else 89 return false 90 end 91 end
# File lib/puppet/functions/type.rb 62 def type_detailed(value, _ = nil) 63 Puppet::Pops::Types::TypeCalculator.infer_set(value) 64 end
# File lib/puppet/functions/type.rb 70 def type_generalized(value, _) 71 Puppet::Pops::Types::TypeCalculator.infer(value).generalize 72 end
# File lib/puppet/face/node/clean.rb 99 def type_is_ensurable(resource) 100 if (type = Puppet::Type.type(resource.restype)) && type.validattr?(:ensure) 101 return true 102 else 103 type = environment.known_resource_types.find_definition(resource.restype) 104 return true if type && type.arguments.keys.include?('ensure') 105 end 106 return false 107 end
# File lib/puppet/functions/compare.rb 123 def type_label(x) 124 Puppet::Pops::Model::ModelLabelProvider.new.label(x) 125 end
# File lib/puppet/functions/type.rb 66 def type_parameterized(value, _) 67 Puppet::Pops::Types::TypeCalculator.infer(value) 68 end
@deprecated because the exitstatus is not returned, use service_command instead
# File lib/puppet/provider/service/service.rb 35 def ucommand(type, fof = true) 36 c = @resource[type] 37 if c 38 cmd = [c] 39 else 40 cmd = [send("#{type}cmd")].flatten 41 end 42 texecute(type, cmd, fof) 43 end
# File lib/puppet/provider/user/useradd.rb 61 def uid 62 return localuid if @resource.forcelocal? 63 get(:uid) 64 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 18 def uid2name(id) 19 return id.to_s if id.is_a?(Symbol) or id.is_a?(String) 20 return nil if id > Puppet[:maximum_uid].to_i 21 22 begin 23 user = Etc.getpwuid(id) 24 rescue TypeError, ArgumentError 25 return nil 26 end 27 28 if user.uid == "" 29 return nil 30 else 31 return user.name 32 end 33 end
# File lib/puppet/provider/user/windows_adsi.rb 159 def uid=(value) 160 fail "uid is read-only" 161 end
# File lib/puppet/provider/service/upstart.rb 324 def unbalanced_parens_on(line) 325 line.count('(') - line.count(')') 326 end
# File lib/puppet/provider/service/upstart.rb 312 def uncomment(line) 313 line.gsub(/^(\s*)#+/, '\1') 314 end
# File lib/puppet/provider/service/upstart.rb 345 def uncomment_start_block_in(text) 346 parens = 0 347 text.lines.map do |line| 348 if line.match(COMMENTED_START_ON) || parens > 0 349 parens += unbalanced_parens_on(remove_trailing_comments_from_commented_line_of(line)) 350 uncomment(line) 351 else 352 line 353 end 354 end.join('') 355 end
For compatibility reasons - return true rather than error on undef (Yes, it is strange, but undef was passed as empty string in 3.x API)
# File lib/puppet/functions/empty.rb 77 def undef_empty(x) 78 true 79 end
# File lib/puppet/provider/package/dpkg.rb 185 def unhold 186 Tempfile.open('puppet_dpkg_set_selection') do |tmpfile| 187 tmpfile.write("#{@resource[:name]} install\n") 188 tmpfile.flush 189 execute([:dpkg, "--set-selections"], :failonfail => false, :combine => false, :stdinfile => tmpfile.path.to_s) 190 end 191 end
# File lib/puppet/provider/package/aix.rb 81 def uninstall 82 # Automatically process dependencies when installing/uninstalling 83 # with the -g option to installp. 84 installp "-gu", @resource[:name] 85 86 # installp will return an exit code of zero even if it didn't uninstall 87 # anything... so let's make sure it worked. 88 unless query().nil? 89 self.fail _("Failed to uninstall package '%{name}'") % { name: @resource[:name] } 90 end 91 end
# File lib/puppet/provider/package/gem.rb 291 def uninstall_options 292 join_options(resource[:uninstall_options]) 293 end
# File lib/puppet/functions/unique.rb 126 def unique_array(array,&block) 127 array.uniq(&block) 128 end
# File lib/puppet/functions/unique.rb 112 def unique_hash(hash, &block) 113 block = lambda {|v| v } unless block_given? 114 result = Hash.new {|h, k| h[k] = {:keys =>[], :values =>[]} } 115 hash.each_pair do |k,v| 116 rc = result[ block.call(v) ] 117 rc[:keys] << k 118 rc[:values] << v 119 end 120 # reduce the set of possibly duplicated value entries 121 inverted = {} 122 result.each_pair {|k,v| inverted[v[:keys]] = v[:values].uniq } 123 inverted 124 end
# File lib/puppet/functions/unique.rb 130 def unique_iterable(iterable, &block) 131 Puppet::Pops::Types::Iterable.on(iterable).uniq(&block) 132 end
# File lib/puppet/functions/unique.rb 108 def unique_string(string, &block) 109 string.split('').uniq(&block).join('') 110 end
# File lib/puppet/provider/service/systemd.rb 177 def unmask 178 systemctl_change_enable(:unmask) 179 end
# File lib/puppet/face/module/list.rb 110 def unmet_dependencies(environment) 111 error_types = [:non_semantic_version, :version_mismatch, :missing] 112 113 unmet_deps = {} 114 error_types.each do |type| 115 unmet_deps[type] = Hash.new do |hash, key| 116 hash[key] = { :errors => [], :parent => nil } 117 end 118 end 119 120 # Prepare the unmet dependencies for display on the console. 121 environment.modules.sort_by {|mod| mod.name}.each do |mod| 122 unmet_grouped = Hash.new { |h,k| h[k] = [] } 123 unmet_grouped = mod.unmet_dependencies.inject(unmet_grouped) do |acc, dep| 124 acc[dep[:reason]] << dep 125 acc 126 end 127 unmet_grouped.each do |type, deps| 128 unless deps.empty? 129 unmet_grouped[type].sort_by { |dep| dep[:name] }.each do |dep| 130 dep_name = dep[:name].tr('/', '-') 131 installed_version = dep[:mod_details][:installed_version] 132 version_constraint = dep[:version_constraint] 133 parent_name = dep[:parent][:name].tr('/', '-') 134 parent_version = dep[:parent][:version] 135 136 msg = _("'%{parent_name}' (%{parent_version}) requires '%{dependency_name}' (%{dependency_version})") % { parent_name: parent_name, parent_version: parent_version, dependency_name: dep_name, dependency_version: version_constraint } 137 unmet_deps[type][dep[:name]][:errors] << msg 138 unmet_deps[type][dep[:name]][:parent] = { 139 :name => dep[:parent][:name], 140 :version => parent_version 141 } 142 unmet_deps[type][dep[:name]][:version] = installed_version 143 end 144 end 145 end 146 end 147 unmet_deps 148 end
# File lib/puppet/provider/package/aix.rb 167 def update 168 self.install(false) 169 end
# File lib/puppet/provider/service/upstart.rb 101 def upstart_version 102 @upstart_version ||= initctl("--version").match(/initctl \(upstart ([^\)]*)\)/)[1] 103 end
# File lib/puppet/provider/user/windows_adsi.rb 17 def user 18 @user ||= Puppet::Util::Windows::ADSI::User.new(@resource[:name]) 19 end
# File lib/puppet/provider/user/user_role_add.rb 69 def user_attributes 70 @user_attributes ||= UserAttr.get_attributes_by_name(@resource[:name]) 71 end
Make sure we don't purge users with specific uids
# File lib/puppet/type/resources.rb 141 def user_check(resource) 142 return true unless self[:name] == "user" 143 return true unless self[:unless_system_user] 144 resource[:audit] = :uid 145 current_values = resource.retrieve_resource 146 current_uid = current_values[resource.property(:uid)] 147 unless_uids = self[:unless_uid] 148 149 return false if system_users.include?(resource[:name]) 150 return false if unless_uids && unless_uids.include?(current_uid) 151 if current_uid.is_a?(String) 152 # Windows user; is a system user if any regex matches. 153 WINDOWS_SYSTEM_SID_REGEXES.none? { |regex| current_uid =~ regex } 154 else 155 current_uid > self[:unless_system_user] 156 end 157 end
# File lib/puppet/provider/user/directoryservice.rb 479 def users_plist_dir 480 '/var/db/dslocal/nodes/Default/users' 481 end
# File lib/puppet/provider/file/windows.rb 86 def validate 87 if [:owner, :group, :mode].any?{|p| resource[p]} and !supports_acl?(resource[:path]) 88 resource.fail(_("Can only manage owner, group, and mode on filesystems that support Windows ACLs, such as NTFS")) 89 end 90 end
# File lib/puppet/reports/store.rb 63 def validate_host(host) 64 if host =~ Regexp.union(/[#{SEPARATOR}]/, /\A\.\.?\Z/) 65 raise ArgumentError, _("Invalid node name %{host}") % { host: host.inspect } 66 end 67 end
# File lib/puppet/provider/service/windows.rb 169 def validate_logon_credentials 170 unless Puppet::Util::Windows::User::localsystem?(@normalized_logon_account) 171 raise Puppet::Error.new("\"#{@normalized_logon_account}\" is not a valid account") unless @logonaccount_information && [:SidTypeUser, :SidTypeWellKnownGroup].include?(@logonaccount_information.account_type) 172 173 user_rights = Puppet::Util::Windows::User::get_rights(@logonaccount_information.domain_account) unless Puppet::Util::Windows::User::default_system_account?(@normalized_logon_account) 174 raise Puppet::Error.new("\"#{@normalized_logon_account}\" has the 'Log On As A Service' right set to denied.") if user_rights =~ /SeDenyServiceLogonRight/ 175 raise Puppet::Error.new("\"#{@normalized_logon_account}\" is missing the 'Log On As A Service' right.") unless user_rights.nil? || user_rights =~ /SeServiceLogonRight/ 176 end 177 178 is_a_predefined_local_account = Puppet::Util::Windows::User::default_system_account?(@normalized_logon_account) || @normalized_logon_account == 'LocalSystem' 179 account_info = @normalized_logon_account.split("\\") 180 able_to_logon = Puppet::Util::Windows::User.password_is?(account_info[1], @resource[:logonpassword], account_info[0]) unless is_a_predefined_local_account 181 raise Puppet::Error.new("The given password is invalid for user '#{@normalized_logon_account}'.") unless is_a_predefined_local_account || able_to_logon 182 end
@api private
# File lib/puppet/face/parser.rb 212 def validate_manifest(manifest = nil) 213 env = Puppet.lookup(:current_environment) 214 loaders = Puppet::Pops::Loaders.new(env) 215 216 Puppet.override( {:loaders => loaders } , _('For puppet parser validate')) do 217 begin 218 validation_environment = manifest ? env.override_with(:manifest => manifest) : env 219 validation_environment.check_for_reparse 220 validation_environment.known_resource_types.clear 221 rescue Puppet::ParseError => parse_error 222 return parse_error 223 end 224 end 225 226 nil 227 end
# File lib/puppet/provider/group/groupadd.rb 81 def validate_members(members) 82 members.each do |member| 83 member.split(',').each do |user| 84 Etc.getpwnam(user.strip) 85 end 86 end 87 end
This only gets called if there is a value to validate, but not if it's absent
# File lib/puppet/provider/package/windows.rb 120 def validate_source(value) 121 fail(_("The source parameter cannot be empty when using the Windows provider.")) if value.empty? 122 end
@api private
# File lib/puppet/face/epp.rb 480 def validate_template(template) 481 parser = Puppet::Pops::Parser::EvaluatingParser::EvaluatingEppParser.new() 482 parser.parse_file(template) 483 true 484 rescue => detail 485 Puppet.log_exception(detail) 486 false 487 end
@api private
# File lib/puppet/face/epp.rb 490 def validate_template_string(source) 491 parser = Puppet::Pops::Parser::EvaluatingParser::EvaluatingEppParser.new() 492 parser.parse_string(source, '<stdin>') 493 true 494 rescue => detail 495 Puppet.log_exception(detail) 496 false 497 end
# File lib/puppet/provider/exec/shell.rb 23 def validatecmd(command) 24 true 25 end
# File lib/puppet/functions/values.rb 23 def values(hsh) 24 hsh.values 25 end
# File lib/puppet/provider/package/pkgng.rb 147 def version 148 @property_hash[:version] 149 end
# File lib/puppet/provider/package/pkgng.rb 151 def version= 152 pkg(['install', '-qfy', "#{resource[:name]}-#{resource[:version]}"]) 153 end
# File lib/puppet/provider/service/upstart.rb 208 def version_is_post_0_9_0 209 Puppet::Util::Package.versioncmp(upstart_version, "0.9.0") >= 0 210 end
# File lib/puppet/provider/service/upstart.rb 200 def version_is_pre_0_6_7 201 Puppet::Util::Package.versioncmp(upstart_version, "0.6.7") == -1 202 end
# File lib/puppet/provider/service/upstart.rb 204 def version_is_pre_0_9_0 205 Puppet::Util::Package.versioncmp(upstart_version, "0.9.0") == -1 206 end
# File lib/puppet/functions/versioncmp.rb 38 def versioncmp(a, b, ignore_trailing_zeroes = false) 39 Puppet::Util::Package.versioncmp(a, b, ignore_trailing_zeroes) 40 end
Wait for the service to transition into the specified state before returning. This is necessary due to the asynchronous nature of SMF services. desired_states should include only online, offline, disabled, or uninitialized. See PUP-5474 for long-term solution to this issue.
# File lib/puppet/provider/service/smf.rb 166 def wait(*desired_states) 167 Timeout.timeout(60) do 168 loop do 169 states = self.service_states 170 break if desired_states.include?(states[:current]) && states[:next].nil? 171 Kernel.sleep(1) 172 end 173 end 174 rescue Timeout::Error 175 raise Puppet::Error.new("Timed out waiting for #{@resource[:name]} to transition states") 176 end
# File lib/puppet/face/config.rb 98 def warn_default_section(section_name) 99 messages = [] 100 messages << _("No section specified; defaulting to '%{section_name}'.") % 101 { section_name: section_name } 102 #TRANSLATORS '--section' is a command line option and should not be translated 103 messages << _("Set the config section by using the `--section` flag.") 104 #TRANSLATORS `puppet config --section user print foo` is a command line example and should not be translated 105 messages << _("For example, `puppet config --section user print foo`.") 106 messages << _("For more information, see https://puppet.com/docs/puppet/latest/configuration.html") 107 108 Puppet.warning(messages.join("\n")) 109 end
# File lib/puppet/face/module/list.rb 151 def warn_unmet_dependencies(environment) 152 @unmet_deps = unmet_dependencies(environment) 153 154 # Display unmet dependencies by category. 155 error_display_order = [:non_semantic_version, :version_mismatch, :missing] 156 error_display_order.each do |type| 157 unless @unmet_deps[type].empty? 158 @unmet_deps[type].keys.sort.each do |dep| 159 name = dep.tr('/', '-') 160 errors = @unmet_deps[type][dep][:errors] 161 version = @unmet_deps[type][dep][:version] 162 163 msg = case type 164 when :version_mismatch 165 _("Module '%{name}' (v%{version}) fails to meet some dependencies:\n") % { name: name, version: version } 166 when :non_semantic_version 167 _("Non semantic version dependency %{name} (v%{version}):\n") % { name: name, version: version } 168 else 169 _("Missing dependency '%{name}':\n") % { name: name } 170 end 171 172 errors.each { |error_string| msg << " #{error_string}\n" } 173 Puppet.warning msg.chomp 174 end 175 end 176 end 177 end
# File lib/puppet/functions/warning.rb 12 def warning(scope, *values) 13 Puppet::Util::Log.log_func(scope, :warning, values) 14 end
# File lib/puppet/functions/with.rb 30 def with(*args) 31 yield(*args) 32 end
Write out the file. To write content, pass the property as an argument to delegate writing to; must implement a write method that takes the file as an argument.
# File lib/puppet/type/file.rb 921 def write(property = nil) 922 remove_existing(:file) 923 924 mode = self.should(:mode) # might be nil 925 mode_int = mode ? symbolic_mode_to_int(mode, Puppet::Util::DEFAULT_POSIX_MODE) : nil 926 927 if write_temporary_file? 928 if self[:validate_cmd] 929 validate_callback = proc { |path| 930 output = Puppet::Util::Execution.execute(self[:validate_cmd].gsub(self[:validate_replacement], path), :failonfail => true, :combine => true) 931 output.split(/\n/).each { |line| 932 self.debug(line) 933 } 934 } 935 end 936 937 Puppet::Util.replace_file(self[:path], mode_int, staging_location: self[:staging_location], validate_callback: validate_callback) do |file| 938 file.binmode 939 devfail 'a property should have been provided if write_temporary_file? returned true' if property.nil? 940 content_checksum = property.write(file) 941 file.flush 942 begin 943 file.fsync 944 rescue NotImplementedError 945 # fsync may not be implemented by Ruby on all platforms, but 946 # there is absolutely no recovery path if we detect that. So, we just 947 # ignore the return code. 948 # 949 # However, don't be fooled: that is accepting that we are running in 950 # an unsafe fashion. If you are porting to a new platform don't stub 951 # that out. 952 end 953 954 fail_if_checksum_is_wrong(property, file.path, content_checksum) 955 end 956 else 957 umask = mode ? 000 : 022 958 Puppet::Util.withumask(umask) { ::File.open(self[:path], 'wb', mode_int ) { |f| property.write(f) if property } } 959 end 960 961 # make sure all of the modes are actually correct 962 property_fix 963 end
This method writes the ShadowHashData plist in a temporary file, then imports it using dsimport. macOS versions 10.15 and newer do not support directly managing binary plists, so we have to use an intermediary. dsimport is an archaic utilitary with hard-to-find documentation
See web.archive.org/web/20090106120111/http://support.apple.com/kb/TA21305?viewlocale=en_US for information regarding the dsimport syntax
# File lib/puppet/provider/user/directoryservice.rb 613 def write_and_import_shadow_hash_data(data_plist) 614 Tempfile.create("dsimport_#{@resource.name}", :encoding => Encoding::ASCII) do |dsimport_file| 615 dsimport_file.write <<-DSIMPORT 616 0x0A 0x5C 0x3A 0x2C dsRecTypeStandard:Users 2 dsAttrTypeStandard:RecordName base64:dsAttrTypeNative:ShadowHashData 617 #{@resource.name}:#{Base64.strict_encode64(data_plist)} 618 DSIMPORT 619 dsimport_file.flush 620 # Delete the user's existing ShadowHashData, since dsimport appends, not replaces 621 dscl('.', 'delete', "/Users/#{@resource.name}", 'ShadowHashData') 622 dsimport(dsimport_file.path, '/Local/Default', 'M') 623 end 624 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 530 def write_password_to_users_plist(value) 531 users_plist = get_users_plist(@resource.name) 532 shadow_hash_data = get_shadow_hash_data(users_plist) 533 if self.class.get_os_version == '10.7' 534 set_salted_sha512(users_plist, shadow_hash_data, value) 535 else 536 # It's possible that a user could exist on the system and NOT have 537 # a ShadowHashData key (especially if the system was upgraded from 10.6). 538 # In this case, a conditional check is needed to determine if the 539 # shadow_hash_data variable is a Hash (it would be false if the key 540 # didn't exist for this user on the system). If the shadow_hash_data 541 # variable IS a Hash and contains the 'SALTED-SHA512' key (indicating an 542 # older 10.7-style password hash), it will be deleted and a newer 543 # 10.8-style (PBKDF2) password hash will be generated. 544 if (shadow_hash_data.class == Hash) && (shadow_hash_data.has_key?('SALTED-SHA512')) 545 shadow_hash_data.delete('SALTED-SHA512') 546 end 547 548 # Starting with macOS 11 Big Sur, the AuthenticationAuthority field 549 # could be missing entirely and without it the managed user cannot log in 550 if needs_sha512_pbkdf2_authentication_authority_to_be_added?(users_plist) 551 Puppet.debug("Adding 'SALTED-SHA512-PBKDF2' AuthenticationAuthority key for ShadowHash to user '#{@resource.name}'") 552 merge_attribute_with_dscl('Users', @resource.name, 'AuthenticationAuthority', ERB::Util.html_escape(SHA512_PBKDF2_AUTHENTICATION_AUTHORITY)) 553 end 554 555 set_salted_pbkdf2(users_plist, shadow_hash_data, 'entropy', value) 556 end 557 end
# File lib/puppet/provider/service/upstart.rb 381 def write_script_to(file, text) 382 Puppet::Util.replace_file(file, 0644) do |f| 383 f.write(text) 384 end 385 end
# File lib/puppet/type/file.rb 1098 def write_temporary_file? 1099 # Unfortunately we don't know the source file size before fetching it so 1100 # let's assume the file won't be empty. Why isn't it part of the metadata? 1101 (c = property(:content) and c.length) || @parameters[:source] 1102 end
# File lib/puppet/functions/yaml_data.rb 22 def yaml_data(options, context) 23 path = options['path'] 24 context.cached_file_data(path) do |content| 25 begin 26 data = Puppet::Util::Yaml.safe_load(content, [Symbol], path) 27 if data.is_a?(Hash) 28 Puppet::Pops::Lookup::HieraConfig.symkeys_to_string(data) 29 else 30 msg = _("%{path}: file does not contain a valid yaml hash" % { path: path }) 31 raise Puppet::DataBinding::LookupError, msg if Puppet[:strict] == :error && data != false 32 Puppet.warning(msg) 33 {} 34 end 35 rescue Puppet::Util::Yaml::YamlLoadError => ex 36 # YamlLoadErrors include the absolute path to the file, so no need to add that 37 raise Puppet::DataBinding::LookupError, _("Unable to parse %{message}") % { message: ex.message } 38 end 39 end 40 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 49 def zypper_version 50 cmd = [self.class.command(:zypper),"--version"] 51 execute(cmd, { :failonfail => false, :combine => true}) 52 end