diff options
| author | Luke Kanies <luke@madstop.com> | 2008-10-17 09:01:04 -0500 |
|---|---|---|
| committer | Luke Kanies <luke@madstop.com> | 2008-10-17 09:01:04 -0500 |
| commit | 8aee40de69e6fe8d67ab58a2e223443b15820584 (patch) | |
| tree | 89e230df3b43302a542f2cb6869f63e2fb93f6d8 /lib/puppet/util | |
| parent | 1b517d2fb048603bd1743a662bde74e8ae4b13dc (diff) | |
| parent | a74ec60d33dee1c592ec858faeccc23d7a7b79f3 (diff) | |
Merge branch '0.24.x' Removed the 'after' blocks that call Type.clear,
since that method is deprecated.
Conflicts:
CHANGELOG
bin/puppetca
lib/puppet/file_serving/fileset.rb
lib/puppet/network/xmlrpc/client.rb
lib/puppet/type/file/selcontext.rb
spec/unit/file_serving/metadata.rb
spec/unit/type/file.rb
Diffstat (limited to 'lib/puppet/util')
| -rwxr-xr-x | lib/puppet/util/filetype.rb | 7 | ||||
| -rw-r--r-- | lib/puppet/util/log.rb | 49 | ||||
| -rw-r--r-- | lib/puppet/util/metric.rb | 32 | ||||
| -rwxr-xr-x | lib/puppet/util/posix.rb | 22 | ||||
| -rw-r--r-- | lib/puppet/util/selinux.rb | 130 | ||||
| -rw-r--r-- | lib/puppet/util/settings.rb | 8 | ||||
| -rw-r--r-- | lib/puppet/util/user_attr.rb | 21 |
7 files changed, 216 insertions, 53 deletions
diff --git a/lib/puppet/util/filetype.rb b/lib/puppet/util/filetype.rb index ae078fff4..b10b50fb7 100755 --- a/lib/puppet/util/filetype.rb +++ b/lib/puppet/util/filetype.rb @@ -1,8 +1,13 @@ # Basic classes for reading, writing, and emptying files. Not much # to see here. + +require 'puppet/util/selinux' + class Puppet::Util::FileType attr_accessor :loaded, :path, :synced + include Puppet::Util::SELinux + class << self attr_accessor :name include Puppet::Util::ClassGen @@ -114,6 +119,8 @@ class Puppet::Util::FileType tf.print text; tf.flush FileUtils.cp(tf.path, @path) tf.close + # If SELinux is present, we need to ensure the file has its expected context + set_selinux_default_context(@path) end end diff --git a/lib/puppet/util/log.rb b/lib/puppet/util/log.rb index 8824a8b50..0dfd36dfa 100644 --- a/lib/puppet/util/log.rb +++ b/lib/puppet/util/log.rb @@ -1,10 +1,12 @@ require 'syslog' +require 'puppet/util/tagging' # Pass feedback to the user. Log levels are modeled after syslog's, and it is # expected that that will be the most common log destination. Supports # multiple destinations, one of which is a remote server. class Puppet::Util::Log include Puppet::Util + include Puppet::Util::Tagging @levels = [:debug,:info,:notice,:warning,:err,:alert,:emerg,:crit] @loglevel = 2 @@ -470,12 +472,12 @@ class Puppet::Util::Log @levels.include?(level) end - attr_accessor :level, :message, :time, :tags, :remote + attr_accessor :level, :message, :time, :remote attr_reader :source def initialize(args) unless args.include?(:level) && args.include?(:message) - raise Puppet::DevError, "Puppet::Util::Log called incorrectly" + raise ArgumentError, "Puppet::Util::Log called incorrectly" end if args[:level].class == String @@ -483,35 +485,27 @@ class Puppet::Util::Log elsif args[:level].class == Symbol @level = args[:level] else - raise Puppet::DevError, - "Level is not a string or symbol: #{args[:level].class}" + raise ArgumentError, "Level is not a string or symbol: #{args[:level].class}" end - # Just return unless we're actually at a level we should send - #return unless self.class.sendlevel?(@level) - @message = args[:message].to_s @time = Time.now - # this should include the host name, and probly lots of other - # stuff, at some point - unless self.class.validlevel?(level) - raise Puppet::DevError, "Invalid message level #{level}" - end - if args.include?(:tags) - @tags = args[:tags] - end + raise ArgumentError, "Invalid log level %s" % level unless self.class.validlevel?(level) - if args.include?(:source) - self.source = args[:source] - else - @source = "Puppet" + if tags = args[:tags] + tags.each { |t| self.tag(t) } end + self.source = args[:source] || "Puppet" + + # Tag myself with my log level + tag(level) + Log.newmessage(self) end - # Was the source of this log an object? + # Was the source of this log a Puppet resource or parameter? def objectsource? if defined? @objectsource and @objectsource @objectsource @@ -533,17 +527,11 @@ class Puppet::Util::Log @objectsource = false @source = source.to_s end - unless defined? @tags and @tags - if source.respond_to?(:tags) - @tags = source.tags - end + if source.respond_to?(:tags) + source.tags.each { |t| tag(t) } end end - def tagged?(tag) - @tags.detect { |t| t.to_s == tag.to_s } - end - def to_report "%s %s (%s): %s" % [self.time, self.source, self.level, self.to_s] end @@ -552,5 +540,8 @@ class Puppet::Util::Log return @message end end -Puppet::Log = Puppet::Util::Log +# This is for backward compatibility from when we changed the constant to Puppet::Util::Log +# because the reports include the constant name. Apparently the alias was created in +# March 2007, should could probably be removed soon. +Puppet::Log = Puppet::Util::Log diff --git a/lib/puppet/util/metric.rb b/lib/puppet/util/metric.rb index ca23aa87f..e6d7678aa 100644 --- a/lib/puppet/util/metric.rb +++ b/lib/puppet/util/metric.rb @@ -5,6 +5,8 @@ require 'puppet' class Puppet::Util::Metric # Load the library as a feature, so we can test its presence. + # It's only used by this class, so there's no reason to move it + # to the main feature list. Puppet.features.add :rrd, :libs => 'RRDtool' attr_accessor :type, :name, :value, :label @@ -12,6 +14,15 @@ class Puppet::Util::Metric attr_writer :basedir + # Return a specific value + def [](name) + if value = @values.find { |v| v[0] == name } + return value[2] + else + return nil + end + end + def basedir if defined? @basedir @basedir @@ -93,11 +104,7 @@ class Puppet::Util::Metric def initialize(name,label = nil) @name = name.to_s - if label - @label = label - else - @label = name.to_s.capitalize.gsub("_", " ") - end + @label = label || labelize(name) @values = [] end @@ -107,9 +114,7 @@ class Puppet::Util::Metric end def newvalue(name,value,label = nil) - unless label - label = name.to_s.capitalize.gsub("_", " ") - end + label ||= labelize(name) @values.push [name,label,value] end @@ -145,7 +150,16 @@ class Puppet::Util::Metric def values @values.sort { |a, b| a[1] <=> b[1] } end + + private + + # Convert a name into a label. + def labelize(name) + name.to_s.capitalize.gsub("_", " ") + end end +# This is necessary because we changed the class path in early 2007, +# and reports directly yaml-dump these metrics, so both client and server +# have to agree on the class name. Puppet::Metric = Puppet::Util::Metric - diff --git a/lib/puppet/util/posix.rb b/lib/puppet/util/posix.rb index aff797485..3f6c1f6e3 100755 --- a/lib/puppet/util/posix.rb +++ b/lib/puppet/util/posix.rb @@ -7,10 +7,8 @@ module Puppet::Util::POSIX # method search_posix_field in the gid and uid methods if a sanity check # fails def get_posix_field(space, field, id) - unless id - raise ArgumentError, "Did not get id" - end - prefix = "get" + space.to_s + raise Puppet::DevError, "Did not get id from caller" unless id + if id.is_a?(Integer) if id > Puppet[:maximum_uid].to_i Puppet.err "Tried to get %s field for silly id %s" % [field, id] @@ -93,16 +91,16 @@ module Puppet::Util::POSIX # Get the GID of a given group, provided either a GID or a name def gid(group) begin - group = Integer(group) + group = Integer(group) rescue ArgumentError - # pass + # pass end if group.is_a?(Integer) - name = get_posix_field(:group, :name, group) + return nil unless name = get_posix_field(:group, :name, group) gid = get_posix_field(:group, :gid, name) check_value = gid else - gid = get_posix_field(:group, :gid, group) + return nil unless gid = get_posix_field(:group, :gid, group) name = get_posix_field(:group, :name, gid) check_value = name end @@ -116,16 +114,16 @@ module Puppet::Util::POSIX # Get the UID of a given user, whether a UID or name is provided def uid(user) begin - user = Integer(user) + user = Integer(user) rescue ArgumentError - # pass + # pass end if user.is_a?(Integer) - name = get_posix_field(:passwd, :name, user) + return nil unless name = get_posix_field(:passwd, :name, user) uid = get_posix_field(:passwd, :uid, name) check_value = uid else - uid = get_posix_field(:passwd, :uid, user) + return nil unless uid = get_posix_field(:passwd, :uid, user) name = get_posix_field(:passwd, :name, uid) check_value = name end diff --git a/lib/puppet/util/selinux.rb b/lib/puppet/util/selinux.rb new file mode 100644 index 000000000..0a4af3ca1 --- /dev/null +++ b/lib/puppet/util/selinux.rb @@ -0,0 +1,130 @@ +# Provides utility functions to help interfaces Puppet to SELinux. +# +# Currently this is implemented via the command line tools. At some +# point support should be added to use the new SELinux ruby bindings +# as that will be faster and more reliable then shelling out when they +# are available. At this time (2008-09-26) these bindings aren't bundled on +# any SELinux-using distribution I know of. + +module Puppet::Util::SELinux + + def selinux_support? + FileTest.exists?("/selinux/enforce") + end + + # Retrieve and return the full context of the file. If we don't have + # SELinux support or if the stat call fails then return nil. + def get_selinux_current_context(file) + unless selinux_support? + return nil + end + context = "" + begin + execpipe("/usr/bin/stat -c %C #{file}") do |out| + out.each do |line| + context << line + end + end + rescue Puppet::ExecutionFailure + return nil + end + context.chomp! + # Handle the case that the system seems to have SELinux support but + # stat finds unlabled files. + if context == "(null)" + return nil + end + return context + end + + # Use the matchpathcon command, if present, to return the SELinux context + # which the SELinux policy on the system expects the file to have. We can + # use this to obtain a good default context. If the command does not + # exist or the call fails return nil. + # + # Note: For this command to work a full, non-relative, filesystem path + # should be given. + def get_selinux_default_context(file) + unless selinux_support? + return nil + end + unless FileTest.executable?("/usr/sbin/matchpathcon") + return nil + end + context = "" + begin + execpipe("/usr/sbin/matchpathcon #{file}") do |out| + out.each do |line| + context << line + end + end + rescue Puppet::ExecutionFailure + return nil + end + # For a successful match, matchpathcon returns two fields separated by + # a variable amount of whitespace. The second field is the full context. + context = context.split(/\s/)[1] + return context + end + + # Take the full SELinux context returned from the tools and parse it + # out to the three (or four) component parts. Supports :seluser, :selrole, + # :seltype, and on systems with range support, :selrange. + def parse_selinux_context(component, context) + if context.nil? or context == "unlabeled" + return nil + end + unless context =~ /^([a-z0-9_]+):([a-z0-9_]+):([a-z0-9_]+)(?::([a-zA-Z0-9:,._-]+))?/ + raise Puppet::Error, "Invalid context to parse: #{context}" + end + ret = { + :seluser => $1, + :selrole => $2, + :seltype => $3, + :selrange => $4, + } + return ret[component] + end + + # This updates the actual SELinux label on the file. You can update + # only a single component or update the entire context. It is just a + # wrapper around the chcon command. + def set_selinux_context(file, value, component = false) + unless selinux_support? + return nil + end + case component + when :seluser + flag = "-u" + when :selrole + flag = "-r" + when :seltype + flag = "-t" + when :selrange + flag = "-l" + else + flag = "" + end + + execute(["/usr/bin/chcon","-h",flag,value,file]) + return true + end + + # Since this call relies on get_selinux_default_context it also needs a + # full non-relative path to the file. Fortunately, that seems to be all + # Puppet uses. This will set the file's SELinux context to the policy's + # default context (if any) if it differs from the context currently on + # the file. + def set_selinux_default_context(file) + new_context = get_selinux_default_context(file) + unless new_context + return nil + end + cur_context = get_selinux_current_context(file) + if new_context != cur_context + set_selinux_context(file, new_context) + return new_context + end + return nil + end +end diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb index 64bb40b52..d0c16ec92 100644 --- a/lib/puppet/util/settings.rb +++ b/lib/puppet/util/settings.rb @@ -115,12 +115,14 @@ class Puppet::Util::Settings end # Do variable interpolation on the value. - def convert(value) + def convert(value, environment = nil) return value unless value return value unless value.is_a? String newval = value.gsub(/\$(\w+)|\$\{(\w+)\}/) do |value| varname = $2 || $1 - if pval = self.value(varname) + if varname == "environment" and environment + environment + elsif pval = self.value(varname) pval else raise Puppet::DevError, "Could not find value for %s" % value @@ -692,7 +694,7 @@ Generated on #{Time.now}. val = @config[param].default if val.nil? # Convert it if necessary - val = convert(val) + val = convert(val, environment) # And cache it @cache[environment||"none"][param] = val diff --git a/lib/puppet/util/user_attr.rb b/lib/puppet/util/user_attr.rb new file mode 100644 index 000000000..db8fb81b9 --- /dev/null +++ b/lib/puppet/util/user_attr.rb @@ -0,0 +1,21 @@ +class UserAttr + def self.get_attributes_by_name(name) + attributes = nil + + File.readlines('/etc/user_attr').each do |line| + next if line =~ /^#/ + + token = line.split(':') + + if token[0] == name + attributes = {:name => name} + token[4].split(';').each do |attr| + key_value = attr.split('=') + attributes[key_value[0].intern] = key_value[1].strip + end + break + end + end + return attributes + end +end |
