Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'next'

* next: (39 commits)
  (#5908) Add support for new update-rc.d disable API
  (#6830) Fix tests that depended on special inherited behavior
  (#6830) Fix overly stubbed tests
  (#6830) Fix instance_variables now comes back as symbols
  (#6830) Fix badly stubbed Time object in test
  (#6830) Fix MD5 handling to work with Ruby 1.9
  (#6830) Fix File class scoping
  (#6830) Handle case where array is actually a string
  (#6830) Fix case where instance_variables returns symbols in Ruby 1.9
  (#6862) Add a default subject for the mail_patches rake task
  Fixed #6256 - Creation of rrd directory.
  (#6855) ResourceType#search now accepts a regex
  (#5477) Allow watch_file to watch non-existent files, especially site.pp
  (#5477) Allow watch_file to watch non-existent files, especially site.pp
  Fixing #6851 - ResourceType#find/search loads types
  Fixing Module#path detection
  Fixed #6850 - Clean up ResourceType#to_pson
  (#6830) Fix stat method calls to not use an unneeded argument
  (#4576) Raise an error when a node is classified into a non-existent class
  Update CHANGELOG for 2.6.7
  ...
  • Loading branch information...
commit 9c06fbd762cddcc41a7185a36f2a8e72879125eb 2 parents 4196699 + 11309a2
@MaxMartin MaxMartin authored
Showing with 1,952 additions and 228 deletions.
  1. +3 −2 CHANGELOG
  2. +1 −1  lib/puppet/application/master.rb
  3. +1 −0  lib/puppet/defaults.rb
  4. +1 −0  lib/puppet/file_serving/fileset.rb
  5. +19 −3 lib/puppet/indirector/resource_type/parser.rb
  6. +1 −1  lib/puppet/module.rb
  7. +2 −3 lib/puppet/node/environment.rb
  8. +6 −10 lib/puppet/parser/compiler.rb
  9. +47 −0 lib/puppet/parser/functions/create_resources.rb
  10. +2 −2 lib/puppet/parser/functions/fqdn_rand.rb
  11. +3 −2 lib/puppet/parser/lexer.rb
  12. +0 −1  lib/puppet/parser/parser_support.rb
  13. +28 −0 lib/puppet/parser/type_loader.rb
  14. +393 −0 lib/puppet/provider/aixobject.rb
  15. +21 −0 lib/puppet/provider/augeas/augeas.rb
  16. +1 −1  lib/puppet/provider/file/posix.rb
  17. +1 −1  lib/puppet/provider/file/win32.rb
  18. +141 −0 lib/puppet/provider/group/aix.rb
  19. +6 −2 lib/puppet/provider/service/debian.rb
  20. +3 −3 lib/puppet/provider/service/smf.rb
  21. +353 −0 lib/puppet/provider/user/aix.rb
  22. +1 −1  lib/puppet/provider/zfs/solaris.rb
  23. +3 −3 lib/puppet/resource/type.rb
  24. +6 −3 lib/puppet/simple_graph.rb
  25. +1 −1  lib/puppet/transaction/event.rb
  26. +6 −8 lib/puppet/type/exec.rb
  27. +1 −1  lib/puppet/type/file/ctime.rb
  28. +1 −1  lib/puppet/type/file/ensure.rb
  29. +1 −1  lib/puppet/type/file/group.rb
  30. +1 −1  lib/puppet/type/file/mode.rb
  31. +1 −1  lib/puppet/type/file/mtime.rb
  32. +1 −1  lib/puppet/type/file/selcontext.rb
  33. +1 −1  lib/puppet/type/file/type.rb
  34. +36 −0 lib/puppet/type/group.rb
  35. +3 −3 lib/puppet/type/tidy.rb
  36. +38 −1 lib/puppet/type/user.rb
  37. +91 −19 lib/puppet/type/zfs.rb
  38. +1 −1  lib/puppet/type/zone.rb
  39. +1 −0  lib/puppet/type/zpool.rb
  40. +1 −5 lib/puppet/util/loadedfile.rb
  41. +2 −2 spec/unit/application/master_spec.rb
  42. +8 −0 spec/unit/file_serving/fileset_spec.rb
  43. +3 −4 spec/unit/indirector/active_record_spec.rb
  44. +4 −5 spec/unit/indirector/code_spec.rb
  45. +4 −5 spec/unit/indirector/direct_file_server_spec.rb
  46. +6 −6 spec/unit/indirector/exec_spec.rb
  47. +6 −5 spec/unit/indirector/file_server_spec.rb
  48. +4 −5 spec/unit/indirector/file_spec.rb
  49. +3 −4 spec/unit/indirector/ldap_spec.rb
  50. +3 −4 spec/unit/indirector/memory_spec.rb
  51. +3 −4 spec/unit/indirector/plain_spec.rb
  52. +3 −4 spec/unit/indirector/queue_spec.rb
  53. +85 −10 spec/unit/indirector/resource_type/parser_spec.rb
  54. +13 −5 spec/unit/indirector/rest_spec.rb
  55. +7 −6 spec/unit/indirector/ssl_file_spec.rb
  56. +7 −6 spec/unit/indirector/yaml_spec.rb
  57. +32 −7 spec/unit/module_spec.rb
  58. +1 −1  spec/unit/network/authconfig_spec.rb
  59. +1 −1  spec/unit/network/rest_authconfig_spec.rb
  60. +13 −16 spec/unit/node/environment_spec.rb
  61. +15 −11 spec/unit/parser/ast/casestatement_spec.rb
  62. +5 −19 spec/unit/parser/compiler_spec.rb
  63. +135 −0 spec/unit/parser/functions/create_resources_spec.rb
  64. +12 −0 spec/unit/parser/lexer_spec.rb
  65. +97 −0 spec/unit/parser/type_loader_spec.rb
  66. +54 −0 spec/unit/provider/augeas/augeas_spec.rb
  67. +14 −2 spec/unit/provider/service/debian_spec.rb
  68. +137 −0 spec/unit/provider/service/smf_spec.rb
  69. +1 −0  spec/unit/provider/zfs/solaris_spec.rb
  70. +17 −5 spec/unit/resource/type_spec.rb
  71. +14 −2 spec/unit/type/exec_spec.rb
  72. +7 −0 spec/unit/util/loadedfile_spec.rb
  73. +4 −3 spec/unit/util/rdoc/parser_spec.rb
  74. +3 −1 tasks/rake/git_workflow.rake
  75. +1 −1  test/language/functions.rb
View
5 CHANGELOG
@@ -1,5 +1,6 @@
-2.6.7rc1
-========
+2.6.7
+=====
+17f673d Updated CHANGELOG for 2.6.7rc1
852fb97 (#5073) Download plugins even if you're filtering on tags
4f34dbf Fix #5610: Prevent unnecessary RAL lookups
9781032 Revert "Merge branch 'ticket/2.6.x/5605' of git://github.com/stschulte/puppet into 2.6.next"
View
2  lib/puppet/application/master.rb
@@ -222,7 +222,7 @@ def setup
exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
- Puppet.settings.use :main, :master, :ssl
+ Puppet.settings.use :main, :master, :ssl, :metrics
# Cache our nodes in yaml. Currently not configurable.
Puppet::Node.indirection.cache_class = :yaml
View
1  lib/puppet/defaults.rb
@@ -474,6 +474,7 @@ module Puppet
setdefaults(:metrics,
:rrddir => {:default => "$vardir/rrd",
+ :mode => 0750,
:owner => "service",
:group => "service",
:desc => "The directory where RRD database files are stored.
View
1  lib/puppet/file_serving/fileset.rb
@@ -59,6 +59,7 @@ def ignore=(values)
end
def initialize(path, options = {})
+ path = path.chomp(File::SEPARATOR)
raise ArgumentError.new("Fileset paths must be fully qualified") unless File.expand_path(path) == path
@path = path
View
22 lib/puppet/indirector/resource_type/parser.rb
@@ -10,7 +10,10 @@ def find(request)
# This is a bit ugly.
[:hostclass, :definition, :node].each do |type|
- if r = krt.send(type, request.key)
+ # We have to us 'find_<type>' here because it will
+ # load any missing types from disk, whereas the plain
+ # '<type>' method only returns from memory.
+ if r = krt.send("find_#{type}", [""], request.key)
return r
end
end
@@ -18,9 +21,22 @@ def find(request)
end
def search(request)
- raise ArgumentError, "Only '*' is acceptable as a search request" unless request.key == "*"
krt = request.environment.known_resource_types
- result = [krt.hostclasses.values, krt.definitions.values, krt.nodes.values].flatten
+ # Make sure we've got all of the types loaded.
+ krt.loader.import_all
+ result = [krt.hostclasses.values, krt.definitions.values, krt.nodes.values].flatten.reject { |t| t.name == "" }
+ return nil if result.empty?
+ return result if request.key == "*"
+
+ # Strip the regex of any wrapping slashes that might exist
+ key = request.key.sub(/^\//, '').sub(/\/$/, '')
+ begin
+ regex = Regexp.new(key)
+ rescue => detail
+ raise ArgumentError, "Invalid regex '#{request.key}': #{detail}"
+ end
+
+ result.reject! { |t| t.name.to_s !~ regex }
return nil if result.empty?
result
end
View
2  lib/puppet/module.rb
@@ -138,7 +138,7 @@ def metadata_file
# Find this module in the modulepath.
def path
- environment.modulepath.collect { |path| File.join(path, name) }.find { |d| FileTest.exist?(d) }
+ environment.modulepath.collect { |path| File.join(path, name) }.find { |d| FileTest.directory?(d) }
end
# Find all plugin directories. This is used by the Plugins fileserving mount.
View
5 lib/puppet/node/environment.rb
@@ -76,7 +76,7 @@ def known_resource_types
# per environment semantics with an efficient most common cases; we almost
# always just return our thread's known-resource types. Only at the start
# of a compilation (after our thread var has been set to nil) or when the
- # environment has changed do we delve deeper.
+ # environment has changed do we delve deeper.
Thread.current[:known_resource_types] = nil if (krt = Thread.current[:known_resource_types]) && krt.environment != self
Thread.current[:known_resource_types] ||= synchronize {
if @known_resource_types.nil? or @known_resource_types.stale?
@@ -128,7 +128,7 @@ def to_sym
to_s.to_sym
end
- # The only thing we care about when serializing an environment is its
+ # The only thing we care about when serializing an environment is its
# identity; everything else is ephemeral and should not be stored or
# transmitted.
def to_zaml(z)
@@ -156,7 +156,6 @@ def perform_initial_import
parser.string = code
else
file = Puppet.settings.value(:manifest, name.to_s)
- return empty_parse_result unless File.exist?(file)
parser.file = file
end
parser.parse
View
16 lib/puppet/parser/compiler.rb
@@ -20,7 +20,7 @@ def self.compile(node)
puts detail.backtrace if Puppet[:trace]
raise Puppet::Error, "#{detail} on node #{node.name}"
ensure
- # We get these from the environment and only cache them in a thread
+ # We get these from the environment and only cache them in a thread
# variable for the duration of the compilation.
Thread.current[:known_resource_types] = nil
Thread.current[:env_module_directories] = nil
@@ -133,12 +133,11 @@ def evaluate_node_classes
end
# Evaluate each specified class in turn. If there are any classes we can't
- # find, just tag the catalog and move on. This method really just
- # creates resource objects that point back to the classes, and then the
- # resources are themselves evaluated later in the process.
+ # find, raise an error. This method really just creates resource objects
+ # that point back to the classes, and then the resources are themselves
+ # evaluated later in the process.
def evaluate_classes(classes, scope, lazy_evaluate = true)
raise Puppet::DevError, "No source for scope passed to evaluate_classes" unless scope.source
- found = []
param_classes = nil
# if we are a param class, save the classes hash
# and transform classes to be the keys
@@ -153,20 +152,17 @@ def evaluate_classes(classes, scope, lazy_evaluate = true)
if param_classes
resource = klass.ensure_in_catalog(scope, param_classes[name] || {})
else
- found << name and next if scope.class_scope(klass)
+ next if scope.class_scope(klass)
resource = klass.ensure_in_catalog(scope)
end
# If they've disabled lazy evaluation (which the :include function does),
# then evaluate our resource immediately.
resource.evaluate unless lazy_evaluate
- found << name
else
- Puppet.info "Could not find class #{name} for #{node.name}"
- @catalog.tag(name)
+ raise Puppet::Error, "Could not find class #{name} for #{node.name}"
end
end
- found
end
def evaluate_relationships
View
47 lib/puppet/parser/functions/create_resources.rb
@@ -0,0 +1,47 @@
+Puppet::Parser::Functions::newfunction(:create_resources, :doc => '
+Converts a hash into a set of resources and adds them to the catalog.
+Takes two parameters:
+ create_resource($type, $resources)
+ Creates resources of type $type from the $resources hash. Assumes that
+ hash is in the following form:
+ {title=>{parameters}}
+ This is currently tested for defined resources, classes, as well as native types
+') do |args|
+ raise ArgumentError, ("create_resources(): wrong number of arguments (#{args.length}; must be 2)") if args.length != 2
+ #raise ArgumentError, 'requires resource type and param hash' if args.size < 2
+ # figure out what kind of resource we are
+ type_of_resource = nil
+ type_name = args[0].downcase
+ if type_name == 'class'
+ type_of_resource = :class
+ else
+ if resource = Puppet::Type.type(type_name.to_sym)
+ type_of_resource = :type
+ elsif resource = find_definition(type_name.downcase)
+ type_of_resource = :define
+ else
+ raise ArgumentError, "could not create resource of unknown type #{type_name}"
+ end
+ end
+ # iterate through the resources to create
+ args[1].each do |title, params|
+ raise ArgumentError, 'params should not contain title' if(params['title'])
+ case type_of_resource
+ when :type
+ res = resource.hash2resource(params.merge(:title => title))
+ catalog.add_resource(res)
+ when :define
+ p_resource = Puppet::Parser::Resource.new(type_name, title, :scope => self, :source => resource)
+ params.merge(:name => title).each do |k,v|
+ p_resource.set_parameter(k,v)
+ end
+ resource.instantiate_resource(self, p_resource)
+ compiler.add_resource(self, p_resource)
+ when :class
+ klass = find_hostclass(title)
+ raise ArgumentError, "could not find hostclass #{title}" unless klass
+ klass.ensure_in_catalog(self, params)
+ compiler.catalog.add_class([title])
+ end
+ end
+end
View
4 lib/puppet/parser/functions/fqdn_rand.rb
@@ -5,8 +5,8 @@
$random_number = fqdn_rand(30)
$random_number_seed = fqdn_rand(30,30)") do |args|
- require 'md5'
+ require 'digest/md5'
max = args.shift
- srand MD5.new([lookupvar('fqdn'),args].join(':')).to_s.hex
+ srand(Digest::MD5.hexdigest([lookupvar('fqdn'),args].join(':')).hex)
rand(max).to_s
end
View
5 lib/puppet/parser/lexer.rb
@@ -312,7 +312,8 @@ def fullscan
def file=(file)
@file = file
@line = 1
- @scanner = StringScanner.new(File.read(file))
+ contents = File.exists?(file) ? File.read(file) : ""
+ @scanner = StringScanner.new(contents)
end
def shift_token
@@ -547,7 +548,7 @@ def tokenize_interpolated_string(token_type,preamble='')
value,terminator = slurpstring('"$')
token_queue << [TOKENS[token_type[terminator]],preamble+value]
if terminator != '$' or @scanner.scan(/\{/)
- token_queue.shift
+ token_queue.shift
elsif var_name = @scanner.scan(%r{(\w*::)*\w+|[0-9]})
token_queue << [TOKENS[:VARIABLE],var_name]
tokenize_interpolated_string(DQ_continuation_token_types)
View
1  lib/puppet/parser/parser_support.rb
@@ -79,7 +79,6 @@ def file=(file)
unless file =~ /\.pp$/
file = file + ".pp"
end
- raise Puppet::Error, "Could not find file #{file}" unless FileTest.exist?(file)
end
raise Puppet::AlreadyImportedError, "Import loop detected" if known_resource_types.watching_file?(file)
View
28 lib/puppet/parser/type_loader.rb
@@ -92,6 +92,34 @@ def import(file, current_file = nil)
end
end
+ def import_all
+ require 'find'
+
+ module_names = []
+ # Collect the list of all known modules
+ environment.modulepath.each do |path|
+ Dir.chdir(path) do
+ Dir.glob("*").each do |dir|
+ next unless FileTest.directory?(dir)
+ module_names << dir
+ end
+ end
+ end
+
+ module_names.uniq!
+ # And then load all files from each module, but (relying on system
+ # behavior) only load files from the first module of a given name. E.g.,
+ # given first/foo and second/foo, only files from first/foo will be loaded.
+ module_names.each do |name|
+ mod = Puppet::Module.new(name, environment)
+ Find.find(File.join(mod.path, "manifests")) do |path|
+ if path =~ /\.pp$/ or path =~ /\.rb$/
+ import(path)
+ end
+ end
+ end
+ end
+
def known_resource_types
environment.known_resource_types
end
View
393 lib/puppet/provider/aixobject.rb
@@ -0,0 +1,393 @@
+#
+# Common code for AIX providers. This class implements basic structure for
+# AIX resources.
+# Author:: Hector Rivas Gandara <keymon@gmail.com>
+#
+class Puppet::Provider::AixObject < Puppet::Provider
+ desc "Generic AIX resource provider"
+
+ # The real provider must implement these functions.
+ def lscmd(value=@resource[:name])
+ raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: #{detail}"
+ end
+
+ def lscmd(value=@resource[:name])
+ raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: #{detail}"
+ end
+
+ def addcmd(extra_attrs = [])
+ raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: #{detail}"
+ end
+
+ def modifycmd(attributes_hash)
+ raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: #{detail}"
+ end
+
+ def deletecmd
+ raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: #{detail}"
+ end
+
+ # Valid attributes to be managed by this provider.
+ # It is a list of hashes
+ # :aix_attr AIX command attribute name
+ # :puppet_prop Puppet propertie name
+ # :to Optional. Method name that adapts puppet property to aix command value.
+ # :from Optional. Method to adapt aix command line value to puppet property. Optional
+ class << self
+ attr_accessor :attribute_mapping
+ end
+
+ # Mapping from Puppet property to AIX attribute.
+ def self.attribute_mapping_to
+ if ! @attribute_mapping_to
+ @attribute_mapping_to = {}
+ attribute_mapping.each { |elem|
+ attribute_mapping_to[elem[:puppet_prop]] = {
+ :key => elem[:aix_attr],
+ :method => elem[:to]
+ }
+ }
+ end
+ @attribute_mapping_to
+ end
+
+ # Mapping from AIX attribute to Puppet property.
+ def self.attribute_mapping_from
+ if ! @attribute_mapping_from
+ @attribute_mapping_from = {}
+ attribute_mapping.each { |elem|
+ attribute_mapping_from[elem[:aix_attr]] = {
+ :key => elem[:puppet_prop],
+ :method => elem[:from]
+ }
+ }
+ end
+ @attribute_mapping_from
+ end
+
+ # This functions translates a key and value using the given mapping.
+ # Mapping can be nil (no translation) or a hash with this format
+ # {:key => new_key, :method => translate_method}
+ # It returns a list with the pair [key, value]
+ def translate_attr(key, value, mapping)
+ return [key, value] unless mapping
+ return nil unless mapping[key]
+
+ if mapping[key][:method]
+ new_value = method(mapping[key][:method]).call(value)
+ else
+ new_value = value
+ end
+ [mapping[key][:key], new_value]
+ end
+
+ # Loads an AIX attribute (key=value) and stores it in the given hash with
+ # puppet semantics. It translates the pair using the given mapping.
+ #
+ # This operation works with each property one by one,
+ # subclasses must reimplement this if more complex operations are needed
+ def load_attribute(key, value, mapping, objectinfo)
+ if mapping.nil?
+ objectinfo[key] = value
+ elsif mapping[key].nil?
+ # is not present in mapping, ignore it.
+ true
+ elsif mapping[key][:method].nil?
+ objectinfo[mapping[key][:key]] = value
+ elsif
+ objectinfo[mapping[key][:key]] = method(mapping[key][:method]).call(value)
+ end
+
+ return objectinfo
+ end
+
+ # Gets the given command line argument for the given key and value,
+ # using the given mapping to translate key and value.
+ # All the objectinfo hash (@resource or @property_hash) is passed.
+ #
+ # This operation works with each property one by one,
+ # and default behaviour is return the arguments as key=value pairs.
+ # Subclasses must reimplement this if more complex operations/arguments
+ # are needed
+ #
+ def get_arguments(key, value, mapping, objectinfo)
+ if mapping.nil?
+ new_key = key
+ new_value = value
+ elsif mapping[key].nil?
+ # is not present in mapping, ignore it.
+ new_key = nil
+ new_value = nil
+ elsif mapping[key][:method].nil?
+ new_key = mapping[key][:key]
+ new_value = value
+ elsif
+ new_key = mapping[key][:key]
+ new_value = method(mapping[key][:method]).call(value)
+ end
+
+ # convert it to string
+ new_value = Array(new_value).join(',')
+
+ if new_key
+ return [ "#{new_key}=#{new_value}" ]
+ else
+ return []
+ end
+ end
+
+ # Convert the provider properties (hash) to AIX command arguments
+ # (list of strings)
+ # This function will translate each value/key and generate the argument using
+ # the get_arguments function.
+ def hash2args(hash, mapping=self.class.attribute_mapping_to)
+ return "" unless hash
+ arg_list = []
+ hash.each {|key, val|
+ arg_list += self.get_arguments(key, val, mapping, hash)
+ }
+ arg_list
+ end
+
+ # Parse AIX command attributes from the output of an AIX command, that
+ # which format is a list of space separated of key=value pairs:
+ # "uid=100 groups=a,b,c".
+ # It returns an hash.
+ #
+ # If a mapping is provided, the keys are translated as defined in the
+ # mapping hash. And only values included in mapping will be added
+ #
+ # NOTE: it will ignore the items not including '='
+ def parse_attr_list(str, mapping=self.class.attribute_mapping_from)
+ properties = {}
+ attrs = []
+ if !str or (attrs = str.split()).empty?
+ return nil
+ end
+
+ attrs.each { |i|
+ if i.include? "=" # Ignore if it does not include '='
+ (key_str, val) = i.split('=')
+ # Check the key
+ if !key_str or key_str.empty?
+ info "Empty key in string 'i'?"
+ continue
+ end
+ key = key_str.to_sym
+
+ properties = self.load_attribute(key, val, mapping, properties)
+ end
+ }
+ properties.empty? ? nil : properties
+ end
+
+ # Parse AIX command output in a colon separated list of attributes,
+ # This function is useful to parse the output of commands like lsfs -c:
+ # #MountPoint:Device:Vfs:Nodename:Type:Size:Options:AutoMount:Acct
+ # /:/dev/hd4:jfs2::bootfs:557056:rw:yes:no
+ # /home:/dev/hd1:jfs2:::2129920:rw:yes:no
+ # /usr:/dev/hd2:jfs2::bootfs:9797632:rw:yes:no
+ #
+ # If a mapping is provided, the keys are translated as defined in the
+ # mapping hash. And only values included in mapping will be added
+ def parse_colon_list(str, key_list, mapping=self.class.attribute_mapping_from)
+ properties = {}
+ attrs = []
+ if !str or (attrs = str.split(':')).empty?
+ return nil
+ end
+
+ attrs.each { |val|
+ key = key_list.shift.downcase.to_sym
+ properties = self.load_attribute(key, val, mapping, properties)
+ }
+ properties.empty? ? nil : properties
+
+ end
+
+ # Default parsing function for AIX commands.
+ # It will choose the method depending of the first line.
+ # For the colon separated list it will:
+ # 1. Get keys from first line.
+ # 2. Parse next line.
+ def parse_command_output(output, mapping=self.class.attribute_mapping_from)
+ lines = output.split("\n")
+ # if it begins with #something:... is a colon separated list.
+ if lines[0] =~ /^#.*:/
+ self.parse_colon_list(lines[1], lines[0][1..-1].split(':'), mapping)
+ else
+ self.parse_attr_list(lines[0], mapping)
+ end
+ end
+
+ # Retrieve all the information of an existing resource.
+ # It will execute 'lscmd' command and parse the output, using the mapping
+ # 'attribute_mapping_from' to translate the keys and values.
+ def getinfo(refresh = false)
+ if @objectinfo.nil? or refresh == true
+ # Execute lsuser, split all attributes and add them to a dict.
+ begin
+ output = execute(self.lscmd)
+ @objectinfo = self.parse_command_output(execute(self.lscmd))
+ # All attributtes without translation
+ @objectosinfo = self.parse_command_output(execute(self.lscmd), nil)
+ rescue Puppet::ExecutionFailure => detail
+ # Print error if needed. FIXME: Do not check the user here.
+ Puppet.debug "aix.getinfo(): Could not find #{@resource.class.name} #{@resource.name}: #{detail}"
+ end
+ end
+ @objectinfo
+ end
+
+ # Like getinfo, but it will not use the mapping to translate the keys and values.
+ # It might be usefult to retrieve some raw information.
+ def getosinfo(refresh = false)
+ if @objectosinfo .nil? or refresh == true
+ getinfo(refresh)
+ end
+ @objectosinfo
+ end
+
+
+ # List all elements of given type. It works for colon separated commands and
+ # list commands.
+ # It returns a list of names.
+ def list_all
+ names = []
+ begin
+ output = execute(self.lsallcmd()).split('\n')
+ (output.select{ |l| l != /^#/ }).each { |v|
+ name = v.split(/[ :]/)
+ names << name if not name.empty?
+ }
+ rescue Puppet::ExecutionFailure => detail
+ # Print error if needed
+ Puppet.debug "aix.list_all(): Could not get all resources of type #{@resource.class.name}: #{detail}"
+ end
+ names
+ end
+
+
+ #-------------
+ # Provider API
+ # ------------
+
+ # Clear out the cached values.
+ def flush
+ @property_hash.clear if @property_hash
+ @objectinfo.clear if @objectinfo
+ end
+
+ # Check that the user exists
+ def exists?
+ !!getinfo(true) # !! => converts to bool
+ end
+
+ # Return all existing instances
+ # The method for returning a list of provider instances. Note that it returns
+ # providers, preferably with values already filled in, not resources.
+ def self.instances
+ objects=[]
+ self.list_all().each { |entry|
+ objects << new(:name => entry, :ensure => :present)
+ }
+ objects
+ end
+
+ #- **ensure**
+ # The basic state that the object should be in. Valid values are
+ # `present`, `absent`, `role`.
+ # From ensurable: exists?, create, delete
+ def ensure
+ if exists?
+ :present
+ else
+ :absent
+ end
+ end
+
+ # Create a new instance of the resource
+ def create
+ if exists?
+ info "already exists"
+ # The object already exists
+ return nil
+ end
+
+ begin
+ execute(self.addcmd)
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not create #{@resource.class.name} #{@resource.name}: #{detail}"
+ end
+ end
+
+ # Delete this instance of the resource
+ def delete
+ unless exists?
+ info "already absent"
+ # the object already doesn't exist
+ return nil
+ end
+
+ begin
+ execute(self.deletecmd)
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not delete #{@resource.class.name} #{@resource.name}: #{detail}"
+ end
+ end
+
+ #--------------------------------
+ # Call this method when the object is initialized.
+ # It creates getter/setter methods for each property our resource type supports.
+ # If setter or getter already defined it will not be overwritten
+ def self.mk_resource_methods
+ [resource_type.validproperties, resource_type.parameters].flatten.each do |prop|
+ next if prop == :ensure
+ define_method(prop) { get(prop) || :absent} unless public_method_defined?(prop)
+ define_method(prop.to_s + "=") { |*vals| set(prop, *vals) } unless public_method_defined?(prop.to_s + "=")
+ end
+ end
+
+ # Define the needed getters and setters as soon as we know the resource type
+ def self.resource_type=(resource_type)
+ super
+ mk_resource_methods
+ end
+
+ # Retrieve a specific value by name.
+ def get(param)
+ (hash = getinfo(false)) ? hash[param] : nil
+ end
+
+ # Set a property.
+ def set(param, value)
+ @property_hash[symbolize(param)] = value
+
+ if getinfo().nil?
+ # This is weird...
+ raise Puppet::Error, "Trying to update parameter '#{param}' to '#{value}' for a resource that does not exists #{@resource.class.name} #{@resource.name}: #{detail}"
+ end
+ if value == getinfo()[param.to_sym]
+ return
+ end
+
+ #self.class.validate(param, value)
+ if cmd = modifycmd({param =>value})
+ begin
+ execute(cmd)
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}"
+ end
+ end
+
+ # Refresh de info.
+ hash = getinfo(true)
+ end
+
+ def initialize(resource)
+ super
+ @objectinfo = nil
+ @objectosinfo = nil
+ end
+
+end
View
21 lib/puppet/provider/augeas/augeas.rb
@@ -32,10 +32,14 @@
COMMANDS = {
"set" => [ :path, :string ],
+ "setm" => [ :path, :string, :string ],
"rm" => [ :path ],
"clear" => [ :path ],
+ "mv" => [ :path, :path ],
"insert" => [ :string, :string, :path ],
"get" => [ :path, :comparator, :string ],
+ "defvar" => [ :string, :path ],
+ "defnode" => [ :string, :path, :string ],
"match" => [ :path, :glob ],
"size" => [:comparator, :int],
"include" => [:string],
@@ -46,6 +50,7 @@
COMMANDS["ins"] = COMMANDS["insert"]
COMMANDS["remove"] = COMMANDS["rm"]
+ COMMANDS["move"] = COMMANDS["mv"]
attr_accessor :aug
@@ -334,6 +339,10 @@ def do_execute_changes
debug("sending command '#{command}' with params #{cmd_array.inspect}")
rv = aug.set(cmd_array[0], cmd_array[1])
fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv)
+ when "setm"
+ debug("sending command '#{command}' with params #{cmd_array.inspect}")
+ rv = aug.setm(cmd_array[0], cmd_array[1], cmd_array[2])
+ fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1)
when "rm", "remove"
debug("sending command '#{command}' with params #{cmd_array.inspect}")
rv = aug.rm(cmd_array[0])
@@ -354,6 +363,18 @@ def do_execute_changes
debug("sending command '#{command}' with params #{[label, where, path].inspect}")
rv = aug.insert(path, label, before)
fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1)
+ when "defvar"
+ debug("sending command '#{command}' with params #{cmd_array.inspect}")
+ rv = aug.defvar(cmd_array[0], cmd_array[1])
+ fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv)
+ when "defnode"
+ debug("sending command '#{command}' with params #{cmd_array.inspect}")
+ rv = aug.defnode(cmd_array[0], cmd_array[1], cmd_array[2])
+ fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv)
+ when "mv", "move"
+ debug("sending command '#{command}' with params #{cmd_array.inspect}")
+ rv = aug.mv(cmd_array[0], cmd_array[1])
+ fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1)
else fail("Command '#{command}' is not supported")
end
rescue SystemExit,NoMemoryError
View
2  lib/puppet/provider/file/posix.rb
@@ -54,7 +54,7 @@ def validuser?(value)
end
def retrieve(resource)
- unless stat = resource.stat(false)
+ unless stat = resource.stat
return :absent
end
View
2  lib/puppet/provider/file/win32.rb
@@ -49,7 +49,7 @@ def validuser?(value)
end
def retrieve(resource)
- unless stat = resource.stat(false)
+ unless stat = resource.stat
return :absent
end
View
141 lib/puppet/provider/group/aix.rb
@@ -0,0 +1,141 @@
+#
+# Group Puppet provider for AIX. It uses standard commands to manage groups:
+# mkgroup, rmgroup, lsgroup, chgroup
+#
+# Author:: Hector Rivas Gandara <keymon@gmail.com>
+#
+require 'puppet/provider/aixobject'
+
+Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject do
+ desc "Group management for AIX! Users are managed with mkgroup, rmgroup, lsgroup, chgroup"
+
+ # This will the the default provider for this platform
+ defaultfor :operatingsystem => :aix
+ confine :operatingsystem => :aix
+
+ # Provider features
+ has_features :manages_aix_lam
+ has_features :manages_members
+
+ # Commands that manage the element
+ commands :list => "/usr/sbin/lsgroup"
+ commands :add => "/usr/bin/mkgroup"
+ commands :delete => "/usr/sbin/rmgroup"
+ commands :modify => "/usr/bin/chgroup"
+
+ # Group attributes to ignore
+ def self.attribute_ignore
+ []
+ end
+
+ # AIX attributes to properties mapping.
+ #
+ # Valid attributes to be managed by this provider.
+ # It is a list with of hash
+ # :aix_attr AIX command attribute name
+ # :puppet_prop Puppet propertie name
+ # :to Method to adapt puppet property to aix command value. Optional.
+ # :from Method to adapt aix command value to puppet property. Optional
+ self.attribute_mapping = [
+ #:name => :name,
+ {:aix_attr => :id, :puppet_prop => :gid },
+ {:aix_attr => :users, :puppet_prop => :members,
+ :from => :users_from_attr},
+ {:aix_attr => :attributes, :puppet_prop => :attributes},
+ ]
+
+ #--------------
+ # Command definition
+
+ # Return the IA module arguments based on the resource param ia_load_module
+ def get_ia_module_args
+ if @resource[:ia_load_module]
+ ["-R", @resource[:ia_load_module].to_s]
+ else
+ []
+ end
+ end
+
+ def lscmd(value=@resource[:name])
+ [self.class.command(:list)] +
+ self.get_ia_module_args +
+ [ value]
+ end
+
+ def lsallcmd()
+ lscmd("ALL")
+ end
+
+ def addcmd(extra_attrs = [])
+ # Here we use the @resource.to_hash to get the list of provided parameters
+ # Puppet does not call to self.<parameter>= method if it does not exists.
+ #
+ # It gets an extra list of arguments to add to the user.
+ [self.class.command(:add) ] +
+ self.get_ia_module_args +
+ self.hash2args(@resource.to_hash) +
+ extra_attrs + [@resource[:name]]
+ end
+
+ def modifycmd(hash = property_hash)
+ args = self.hash2args(hash)
+ return nil if args.empty?
+
+ [self.class.command(:modify)] +
+ self.get_ia_module_args +
+ args + [@resource[:name]]
+ end
+
+ def deletecmd
+ [self.class.command(:delete)] +
+ self.get_ia_module_args +
+ [@resource[:name]]
+ end
+
+
+ #--------------
+ # Overwrite get_arguments to add the attributes arguments
+ def get_arguments(key, value, mapping, objectinfo)
+ # In the case of attributes, return a list of key=vlaue
+ if key == :attributes
+ raise Puppet::Error, "Attributes must be a list of pairs key=value on #{@resource.class.name}[#{@resource.name}]" \
+ unless value and value.is_a? Hash
+ return value.select { |k,v| true }.map { |pair| pair.join("=") }
+ end
+ super(key, value, mapping, objectinfo)
+ end
+
+ def filter_attributes(hash)
+ # Return only not managed attributtes.
+ hash.select {
+ |k,v| !self.class.attribute_mapping_from.include?(k) and
+ !self.class.attribute_ignore.include?(k)
+ }.inject({}) {
+ |hash, array| hash[array[0]] = array[1]; hash
+ }
+ end
+
+ def attributes
+ filter_attributes(getosinfo(refresh = false))
+ end
+
+ def attributes=(attr_hash)
+ #self.class.validate(param, value)
+ param = :attributes
+ cmd = modifycmd({param => filter_attributes(attr_hash)})
+ if cmd
+ begin
+ execute(cmd)
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}"
+ end
+ end
+ end
+
+ # Force convert users it a list.
+ def users_from_attr(value)
+ (value.is_a? String) ? value.split(',') : value
+ end
+
+
+end
View
8 lib/puppet/provider/service/debian.rb
@@ -22,8 +22,12 @@ def self.defpath
# Remove the symlinks
def disable
- update_rc "-f", @resource[:name], "remove"
- update_rc @resource[:name], "stop", "00", "1", "2", "3", "4", "5", "6", "."
+ if `dpkg --compare-versions $(dpkg-query -W --showformat '${Version}' sysv-rc) ge 2.88 ; echo $?`.to_i == 0
+ update_rc @resource[:name], "disable"
+ else
+ update_rc "-f", @resource[:name], "remove"
+ update_rc @resource[:name], "stop", "00", "1", "2", "3", "4", "5", "6", "."
+ end
end
def enabled?
View
6 lib/puppet/provider/service/smf.rb
@@ -27,7 +27,7 @@ def setupservice
end
end
rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error.new( "Cannot config #{self.service} to enable it: #{detail}" )
+ raise Puppet::Error.new( "Cannot config #{self.name} to enable it: #{detail}" )
end
def enable
@@ -54,10 +54,10 @@ def restartcmd
def startcmd
self.setupservice
case self.status
- when :stopped
- [command(:adm), :enable, @resource[:name]]
when :maintenance
[command(:adm), :clear, @resource[:name]]
+ else
+ [command(:adm), :enable, @resource[:name]]
end
end
View
353 lib/puppet/provider/user/aix.rb
@@ -0,0 +1,353 @@
+#
+# User Puppet provider for AIX. It uses standard commands to manage users:
+# mkuser, rmuser, lsuser, chuser
+#
+# Notes:
+# - AIX users can have expiry date defined with minute granularity,
+# but puppet does not allow it. There is a ticket open for that (#5431)
+# - AIX maximum password age is in WEEKs, not days
+#
+# See http://projects.puppetlabs.com/projects/puppet/wiki/Development_Provider_Development
+# for more information
+#
+# Author:: Hector Rivas Gandara <keymon@gmail.com>
+#
+require 'puppet/provider/aixobject'
+require 'tempfile'
+require 'date'
+
+Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do
+ desc "User management for AIX! Users are managed with mkuser, rmuser, chuser, lsuser"
+
+ # This will the the default provider for this platform
+ defaultfor :operatingsystem => :aix
+ confine :operatingsystem => :aix
+
+ # Commands that manage the element
+ commands :list => "/usr/sbin/lsuser"
+ commands :add => "/usr/bin/mkuser"
+ commands :delete => "/usr/sbin/rmuser"
+ commands :modify => "/usr/bin/chuser"
+
+ commands :lsgroup => "/usr/sbin/lsgroup"
+ commands :chpasswd => "/bin/chpasswd"
+
+ # Provider features
+ has_features :manages_aix_lam
+ has_features :manages_homedir, :manages_passwords
+ has_features :manages_expiry, :manages_password_age
+
+ # Attribute verification (TODO)
+ #verify :gid, "GID must be an string or int of a valid group" do |value|
+ # value.is_a? String || value.is_a? Integer
+ #end
+ #
+ #verify :groups, "Groups must be comma-separated" do |value|
+ # value !~ /\s/
+ #end
+
+ # User attributes to ignore from AIX output.
+ def self.attribute_ignore
+ []
+ end
+
+ # AIX attributes to properties mapping.
+ #
+ # Valid attributes to be managed by this provider.
+ # It is a list with of hash
+ # :aix_attr AIX command attribute name
+ # :puppet_prop Puppet propertie name
+ # :to Method to adapt puppet property to aix command value. Optional.
+ # :from Method to adapt aix command value to puppet property. Optional
+ self.attribute_mapping = [
+ #:name => :name,
+ {:aix_attr => :pgrp, :puppet_prop => :gid,
+ :to => :gid_to_attr, :from => :gid_from_attr},
+ {:aix_attr => :id, :puppet_prop => :uid},
+ {:aix_attr => :groups, :puppet_prop => :groups},
+ {:aix_attr => :home, :puppet_prop => :home},
+ {:aix_attr => :shell, :puppet_prop => :shell},
+ {:aix_attr => :expires, :puppet_prop => :expiry,
+ :to => :expiry_to_attr, :from => :expiry_from_attr},
+ {:aix_attr => :maxage, :puppet_prop => :password_max_age},
+ {:aix_attr => :minage, :puppet_prop => :password_min_age},
+ {:aix_attr => :attributes, :puppet_prop => :attributes},
+ ]
+
+ #--------------
+ # Command definition
+
+ # Return the IA module arguments based on the resource param ia_load_module
+ def get_ia_module_args
+ if @resource[:ia_load_module]
+ ["-R", @resource[:ia_load_module].to_s]
+ else
+ []
+ end
+ end
+
+ # List groups and Ids
+ def lsgroupscmd(value=@resource[:name])
+ [command(:lsgroup)] +
+ self.get_ia_module_args +
+ ["-a", "id", value]
+ end
+
+ def lscmd(value=@resource[:name])
+ [self.class.command(:list)] + self.get_ia_module_args + [ value]
+ end
+
+ def lsallcmd()
+ lscmd("ALL")
+ end
+
+ def addcmd(extra_attrs = [])
+ # Here we use the @resource.to_hash to get the list of provided parameters
+ # Puppet does not call to self.<parameter>= method if it does not exists.
+ #
+ # It gets an extra list of arguments to add to the user.
+ [self.class.command(:add)] + self.get_ia_module_args +
+ self.hash2args(@resource.to_hash) +
+ extra_attrs + [@resource[:name]]
+ end
+
+ # Get modify command. Set translate=false if no mapping must be used.
+ # Needed for special properties like "attributes"
+ def modifycmd(hash = property_hash)
+ args = self.hash2args(hash)
+ return nil if args.empty?
+
+ [self.class.command(:modify)] + self.get_ia_module_args +
+ args + [@resource[:name]]
+ end
+
+ def deletecmd
+ [self.class.command(:delete)] + self.get_ia_module_args + [@resource[:name]]
+ end
+
+ #--------------
+ # We overwrite the create function to change the password after creation.
+ def create
+ super
+ # Reset the password if needed
+ self.password = @resource[:password] if @resource[:password]
+ end
+
+
+ def get_arguments(key, value, mapping, objectinfo)
+ # In the case of attributes, return a list of key=vlaue
+ if key == :attributes
+ raise Puppet::Error, "Attributes must be a list of pairs key=value on #{@resource.class.name}[#{@resource.name}]" \
+ unless value and value.is_a? Hash
+ return value.select { |k,v| true }.map { |pair| pair.join("=") }
+ end
+
+ super(key, value, mapping, objectinfo)
+ end
+
+ # Get the groupname from its id
+ def self.groupname_by_id(gid)
+ groupname=nil
+ execute(lsgroupscmd("ALL")).each { |entry|
+ attrs = self.parse_attr_list(entry, nil)
+ if attrs and attrs.include? :id and gid == attrs[:id].to_i
+ groupname = entry.split(" ")[0]
+ end
+ }
+ groupname
+ end
+
+ # Get the groupname from its id
+ def groupid_by_name(groupname)
+ attrs = self.parse_attr_list(execute(lsgroupscmd(groupname)).split("\n")[0], nil)
+ attrs ? attrs[:id].to_i : nil
+ end
+
+ # Check that a group exists and is valid
+ def verify_group(value)
+ if value.is_a? Integer or value.is_a? Fixnum
+ groupname = self.groupname_by_id(value)
+ raise ArgumentError, "AIX group must be a valid existing group" unless groupname
+ else
+ raise ArgumentError, "AIX group must be a valid existing group" unless groupid_by_name(value)
+ groupname = value
+ end
+ groupname
+ end
+
+ # The user's primary group. Can be specified numerically or by name.
+ def gid_to_attr(value)
+ verify_group(value)
+ end
+
+ # Get the group gid from its name
+ def gid_from_attr(value)
+ groupid_by_name(value)
+ end
+
+ # The expiry date for this user. Must be provided in
+ # a zero padded YYYY-MM-DD HH:MM format
+ def expiry_to_attr(value)
+ # For chuser the expires parameter is a 10-character string in the MMDDhhmmyy format
+ # that is,"%m%d%H%M%y"
+ newdate = '0'
+ if value.is_a? String and value!="0000-00-00"
+ d = DateTime.parse(value, "%Y-%m-%d %H:%M")
+ newdate = d.strftime("%m%d%H%M%y")
+ end
+ newdate
+ end
+
+ def expiry_from_attr(value)
+ if value =~ /(..)(..)(..)(..)(..)/
+ #d= DateTime.parse("20#{$5}-#{$1}-#{$2} #{$3}:#{$4}")
+ #expiry_date = d.strftime("%Y-%m-%d %H:%M")
+ #expiry_date = d.strftime("%Y-%m-%d")
+ expiry_date = "20#{$5}-#{$1}-#{$2}"
+ else
+ Puppet.warn("Could not convert AIX expires date '#{value}' on #{@resource.class.name}[#{@resource.name}]") \
+ unless value == '0'
+ expiry_date = :absent
+ end
+ expiry_date
+ end
+
+ #--------------------------------
+ # Getter and Setter
+ # When the provider is initialized, create getter/setter methods for each
+ # property our resource type supports.
+ # If setter or getter already defined it will not be overwritten
+
+ #- **password**
+ # The user's password, in whatever encrypted format the local machine
+ # requires. Be sure to enclose any value that includes a dollar sign ($)
+ # in single quotes ('). Requires features manages_passwords.
+ #
+ # Retrieve the password parsing directly the /etc/security/passwd
+ def password
+ password = :absent
+ user = @resource[:name]
+ f = File.open("/etc/security/passwd", 'r')
+ # Skip to the user
+ f.each { |l| break if l =~ /^#{user}:\s*$/ }
+ if ! f.eof?
+ f.each { |l|
+ # If there is a new user stanza, stop
+ break if l =~ /^\S*:\s*$/
+ # If the password= entry is found, return it
+ if l =~ /^\s*password\s*=\s*(.*)$/
+ password = $1; break;
+ end
+ }
+ end
+ f.close()
+ return password
+ end
+
+ def password=(value)
+ user = @resource[:name]
+
+ # Puppet execute does not support strings as input, only files.
+ tmpfile = Tempfile.new('puppet_#{user}_pw')
+ tmpfile << "#{user}:#{value}\n"
+ tmpfile.close()
+
+ # Options '-e', '-c', use encrypted password and clear flags
+ # Must receibe "user:enc_password" as input
+ # command, arguments = {:failonfail => true, :combine => true}
+ cmd = [self.class.command(:chpasswd),"-R", self.class.ia_module,
+ '-e', '-c', user]
+ begin
+ execute(cmd, {:failonfail => true, :combine => true, :stdinfile => tmpfile.path })
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}"
+ ensure
+ tmpfile.delete()
+ end
+ end
+
+ def filter_attributes(hash)
+ # Return only not managed attributtes.
+ hash.select {
+ |k,v| !self.class.attribute_mapping_from.include?(k) and
+ !self.class.attribute_ignore.include?(k)
+ }.inject({}) {
+ |hash, array| hash[array[0]] = array[1]; hash
+ }
+ end
+
+ def attributes
+ filter_attributes(getosinfo(refresh = false))
+ end
+
+ def attributes=(attr_hash)
+ #self.class.validate(param, value)
+ param = :attributes
+ cmd = modifycmd({param => filter_attributes(attr_hash)})
+ if cmd
+ begin
+ execute(cmd)
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}"
+ end
+ end
+ end
+
+ #- **comment**
+ # A description of the user. Generally is a user's full name.
+ #def comment=(value)
+ #end
+ #
+ #def comment
+ #end
+ # UNSUPPORTED
+ #- **profile_membership**
+ # Whether specified roles should be treated as the only roles
+ # of which the user is a member or whether they should merely
+ # be treated as the minimum membership list. Valid values are
+ # `inclusive`, `minimum`.
+ # UNSUPPORTED
+ #- **profiles**
+ # The profiles the user has. Multiple profiles should be
+ # specified as an array. Requires features manages_solaris_rbac.
+ # UNSUPPORTED
+ #- **project**
+ # The name of the project associated with a user Requires features
+ # manages_solaris_rbac.
+ # UNSUPPORTED
+ #- **role_membership**
+ # Whether specified roles should be treated as the only roles
+ # of which the user is a member or whether they should merely
+ # be treated as the minimum membership list. Valid values are
+ # `inclusive`, `minimum`.
+ # UNSUPPORTED
+ #- **roles**
+ # The roles the user has. Multiple roles should be
+ # specified as an array. Requires features manages_solaris_rbac.
+ # UNSUPPORTED
+ #- **key_membership**
+ # Whether specified key value pairs should be treated as the only
+ # attributes
+ # of the user or whether they should merely
+ # be treated as the minimum list. Valid values are `inclusive`,
+ # `minimum`.
+ # UNSUPPORTED
+ #- **keys**
+ # Specify user attributes in an array of keyvalue pairs Requires features
+ # manages_solaris_rbac.
+ # UNSUPPORTED
+ #- **allowdupe**
+ # Whether to allow duplicate UIDs. Valid values are `true`, `false`.
+ # UNSUPPORTED
+ #- **auths**
+ # The auths the user has. Multiple auths should be
+ # specified as an array. Requires features manages_solaris_rbac.
+ # UNSUPPORTED
+ #- **auth_membership**
+ # Whether specified auths should be treated as the only auths
+ # of which the user is a member or whether they should merely
+ # be treated as the minimum membership list. Valid values are
+ # `inclusive`, `minimum`.
+ # UNSUPPORTED
+
+end
View
2  lib/puppet/provider/zfs/solaris.rb
@@ -31,7 +31,7 @@ def exists?
end
end
- [:mountpoint, :recordsize, :aclmode, :aclinherit, :primarycache, :secondarycache, :compression, :copies, :quota, :reservation, :sharenfs, :snapdir].each do |field|
+ [:aclinherit, :aclmode, :atime, :canmount, :checksum, :compression, :copies, :devices, :exec, :logbias, :mountpoint, :nbmand, :primarycache, :quota, :readonly, :recordsize, :refquota, :refreservation, :reservation, :secondarycache, :setuid, :shareiscsi, :sharenfs, :sharesmb, :snapdir, :version, :volsize, :vscan, :xattr, :zoned, :vscan].each do |field|
define_method(field) do
zfs(:get, "-H", "-o", "value", field, @resource[:name]).strip
end
View
6 lib/puppet/resource/type.rb
@@ -34,13 +34,13 @@ def self.from_pson(data)
end
def to_pson_data_hash
- data = [:code, :doc, :line, :file, :parent].inject({}) do |hash, param|
- next hash unless value = self.send(param)
+ data = [:doc, :line, :file, :parent].inject({}) do |hash, param|
+ next hash unless (value = self.send(param)) and (value != "")
hash[param.to_s] = value
hash
end
- data['arguments'] = arguments.dup
+ data['arguments'] = arguments.dup unless arguments.empty?
data['name'] = name
data['type'] = type
View
9 lib/puppet/simple_graph.rb
@@ -367,7 +367,7 @@ def adjacent(v, options = {})
return [] unless ns = (options[:direction] == :in) ? @in_to[v] : @out_from[v]
(options[:type] == :edges) ? ns.values.flatten : ns.keys
end
-
+
# Take container information from another graph and use it
# to replace any container vertices with their respective leaves.
# This creates direct relationships where there were previously
@@ -387,7 +387,7 @@ def splice!(other, type)
children = other.adjacent(container, :direction => :out)
# MQR TODO: Luke suggests that it should be possible to refactor the system so that
- # container nodes are retained, thus obviating the need for the whit.
+ # container nodes are retained, thus obviating the need for the whit.
children = [whit_class.new(:name => container.name, :catalog => other)] if children.empty?
# First create new edges for each of the :in edges
@@ -570,7 +570,10 @@ def instance_variable_get(v)
end
def to_yaml_properties
- other_vars = instance_variables.reject { |v| %w{@in_to @out_from @upstream_from @downstream_from}.include?(v) }
+ other_vars = instance_variables.
+ map {|v| v.to_s}.
+ reject { |v| %w{@in_to @out_from @upstream_from @downstream_from}.include?(v) }
+
(other_vars + %w{@vertices @edges}).sort.uniq
end
View
2  lib/puppet/transaction/event.rb
@@ -48,7 +48,7 @@ def to_s
end
def to_yaml_properties
- (YAML_ATTRIBUTES & instance_variables).sort
+ (YAML_ATTRIBUTES.map {|ya| ya.to_s} & instance_variables.map{|iv| iv.to_s}).sort
end
private
View
14 lib/puppet/type/exec.rb
@@ -220,19 +220,17 @@ def value=(*values)
newparam(:timeout) do
desc "The maximum time the command should take. If the command takes
longer than the timeout, the command is considered to have failed
- and will be stopped. Use any negative number to disable the timeout.
+ and will be stopped. Use 0 to disable the timeout.
The time is specified in seconds."
munge do |value|
value = value.shift if value.is_a?(Array)
- if value.is_a?(String)
- unless value =~ /^[-\d.]+$/
- raise ArgumentError, "The timeout must be a number."
- end
- Float(value)
- else
- value
+ begin
+ value = Float(value)
+ rescue ArgumentError => e
+ raise ArgumentError, "The timeout must be a number."
end
+ [value, 0.0].max
end
defaultto 300
View
2  lib/puppet/type/file/ctime.rb
@@ -4,7 +4,7 @@ module Puppet
def retrieve
current_value = :absent
- if stat = @resource.stat(false)
+ if stat = @resource.stat
current_value = stat.ctime
end
current_value
View
2  lib/puppet/type/file/ensure.rb
@@ -138,7 +138,7 @@ def insync?(currentvalue)
end
def retrieve
- if stat = @resource.stat(false)
+ if stat = @resource.stat
return stat.ftype.intern
else
if self.should == :false
View
2  lib/puppet/type/file/group.rb
@@ -62,7 +62,7 @@ def insync?(current)
end
def retrieve
- return :absent unless stat = resource.stat(false)
+ return :absent unless stat = resource.stat
currentvalue = stat.gid
View
2  lib/puppet/type/file/mode.rb
@@ -63,7 +63,7 @@ def retrieve
# If we're not following links and we're a link, then we just turn
# off mode management entirely.
- if stat = @resource.stat(false)
+ if stat = @resource.stat
unless defined?(@fixed)
@should &&= @should.collect { |s| self.dirmask(s) }
end
View
2  lib/puppet/type/file/mtime.rb
@@ -4,7 +4,7 @@ module Puppet
def retrieve
current_value = :absent
- if stat = @resource.stat(false)
+ if stat = @resource.stat
current_value = stat.mtime
end
current_value
View
2  lib/puppet/type/file/selcontext.rb
@@ -26,7 +26,7 @@ class SELFileContext < Puppet::Property
include Puppet::Util::SELinux
def retrieve
- return :absent unless @resource.stat(false)
+ return :absent unless @resource.stat
context = self.get_selinux_current_context(@resource[:path])
parse_selinux_context(name, context)
end
View
2  lib/puppet/type/file/type.rb
@@ -5,7 +5,7 @@ module Puppet
def retrieve
current_value = :absent
- if stat = @resource.stat(false)
+ if stat = @resource.stat
current_value = stat.ftype
end
current_value
View
36 lib/puppet/type/group.rb
@@ -15,6 +15,9 @@ module Puppet
feature :manages_members,
"For directories where membership is an attribute of groups not users."
+ feature :manages_aix_lam,
+ "The provider can manage AIX Loadable Authentication Module (LAM) system."
+
ensurable do
desc "Create or remove the group."
@@ -95,5 +98,38 @@ def change_to_s(currentvalue, newvalue)
defaultto false
end
+
+ newparam(:ia_load_module, :required_features => :manages_aix_lam) do
+ desc "The name of the I&A module to use to manage this user"
+
+ defaultto "compat"
+ end
+
+ newproperty(:attributes, :parent => Puppet::Property::KeyValue, :required_features => :manages_aix_lam) do
+ desc "Specify group AIX attributes in an array of keyvalue pairs"
+
+ def membership
+ :attribute_membership
+ end
+
+ def delimiter
+ " "
+ end
+
+ validate do |value|
+ raise ArgumentError, "Attributes value pairs must be seperated by an =" unless value.include?("=")
+ end
+ end
+
+ newparam(:attribute_membership) do
+ desc "Whether specified attribute value pairs should be treated as the only attributes
+ of the user or whether they should merely
+ be treated as the minimum list."
+
+ newvalues(:inclusive, :minimum)
+
+ defaultto :minimum
+ end
+
end
end
View
6 lib/puppet/type/tidy.rb
@@ -254,7 +254,7 @@ def generate
if parameter
files = Puppet::FileServing::Fileset.new(self[:path], parameter).files.collect do |f|
- f == "." ? self[:path] : File.join(self[:path], f)
+ f == "." ? self[:path] : ::File.join(self[:path], f)
end
else
files = [self[:path]]
@@ -270,7 +270,7 @@ def generate
files_by_name = result.inject({}) { |hash, file| hash[file[:path]] = file; hash }
files_by_name.keys.sort { |a,b| b <=> b }.each do |path|
- dir = File.dirname(path)
+ dir = ::File.dirname(path)
next unless resource = files_by_name[dir]
if resource[:require]
resource[:require] << Puppet::Resource.new(:file, path)
@@ -321,7 +321,7 @@ def tidy?(path)
def stat(path)
begin
- File.lstat(path)
+ ::File.lstat(path)
rescue Errno::ENOENT => error
info "File does not exist"
return nil
View
39 lib/puppet/type/user.rb
@@ -13,7 +13,7 @@ module Puppet
This resource type uses the prescribed native tools for creating
groups and generally uses POSIX APIs for retrieving information
about them. It does not directly modify `/etc/passwd` or anything.
-
+
**Autorequires:** If Puppet is managing the user's primary group (as provided in the `gid` attribute), the user resource will autorequire that group. If Puppet is managing any role accounts corresponding to the user's roles, the user resource will autorequire those role accounts."
feature :allows_duplicates,
@@ -39,6 +39,9 @@ module Puppet
feature :system_users,
"The provider allows you to create system users with lower UIDs."
+ feature :manages_aix_lam,
+ "The provider can manage AIX Loadable Authentication Module (LAM) system."
+
newproperty(:ensure, :parent => Puppet::Property::Ensure) do
newvalue(:present, :event => :user_created) do
provider.create
@@ -445,5 +448,39 @@ def membership
newproperty(:project, :required_features => :manages_solaris_rbac) do
desc "The name of the project associated with a user"
end
+
+ newparam(:ia_load_module, :required_features => :manages_aix_lam) do
+ desc "The name of the I&A module to use to manage this user"
+
+ defaultto "compat"
+ end
+
+ newproperty(:attributes, :parent => Puppet::Property::KeyValue, :required_features => :manages_aix_lam) do
+ desc "Specify user AIX attributes in an array of keyvalue pairs"
+
+ def membership
+ :attribute_membership
+ end
+
+ def delimiter
+ " "
+ end
+
+ validate do |value|
+ raise ArgumentError, "Attributes value pairs must be seperated by an =" unless value.include?("=")
+ end
+ end
+
+ newparam(:attribute_membership) do
+ desc "Whether specified attribute value pairs should be treated as the only attributes
+ of the user or whether they should merely
+ be treated as the minimum list."
+
+ newvalues(:inclusive, :minimum)
+
+ defaultto :minimum
+ end
+
+
end
end
View
110 lib/puppet/type/zfs.rb 100755 → 100644
@@ -10,52 +10,124 @@ module Puppet
desc "The full name for this filesystem. (including the zpool)"
end
- newproperty(:mountpoint) do
- desc "The mountpoint property."
- end
-
- newproperty(:recordsize) do
- desc "The recordsize property."
+ newproperty(:aclinherit) do
+ desc "The aclinherit property. Values: discard | noallow | restricted | passthrough | passthrough-x"
end
newproperty(:aclmode) do
- desc "The aclmode property."
+ desc "The aclmode property. Values: discard | groupmask | passthrough"
end
- newproperty(:aclinherit) do
- desc "The aclinherit property."
+ newproperty(:atime) do
+ desc "The atime property. Values: on | off"
end
- newproperty(:primarycache) do
- desc "The primarycache property."
+ newproperty(:canmount) do
+ desc "The canmount property. Values: on | off | noauto"
end
- newproperty(:secondarycache) do
- desc "The secondarycache property."
+ newproperty(:checksum) do
+ desc "The checksum property. Values: on | off | fletcher2 | fletcher4 | sha256"
end
newproperty(:compression) do
- desc "The compression property."
+ desc "The compression property. Values: on | off | lzjb | gzip | gzip-[1-9] | zle"
end
newproperty(:copies) do
- desc "The copies property."
+ desc "The copies property. Values: 1 | 2 | 3"
+ end
+
+ newproperty(:devices) do
+ desc "The devices property. Values: on | off"
+ end
+
+ newproperty(:exec) do
+ desc "The exec property. Values: on | off"
+ end
+
+ newproperty(:logbias) do
+ desc "The logbias property. Values: latency | throughput"
+ end
+
+ newproperty(:mountpoint) do
+ desc "The mountpoint property. Values: <path> | legacy | none"
+ end
+
+ newproperty(:nbmand) do
+ desc "The nbmand property. Values: on | off"
+ end
+
+ newproperty(:primarycache) do
+ desc "The primarycache property. Values: all | none | metadata"
end
newproperty(:quota) do
- desc "The quota property."
+ desc "The quota property. Values: <size> | none"
+ end
+
+ newproperty(:readonly) do
+ desc "The readonly property. Values: on | off"
+ end
+
+ newproperty(:recordsize) do
+ desc "The recordsize property. Values: 512 to 128k, power of 2"
+ end
+
+ newproperty(:refquota) do
+ desc "The refquota property. Values: <size> | none"
+ end
+
+ newproperty(:refreservation) do
+ desc "The refreservation property. Values: <size> | none"
end
newproperty(:reservation) do
- desc "The reservation property."
+ desc "The reservation property. Values: <size> | none"
+ end
+
+ newproperty(:secondarycache) do
+ desc "The secondarycache property. Values: all | none | metadata"
+ end
+
+ newproperty(:setuid) do
+ desc "The setuid property. Values: on | off"
+ end
+
+ newproperty(:shareiscsi) do
+ desc "The shareiscsi property. Values: on | off | type=<type>"
end
newproperty(:sharenfs) do
- desc "The sharenfs property."
+ desc "The sharenfs property. Values: on | off | share(1M) options"
+ end
+
+ newproperty(:sharesmb) do
+ desc "The sharesmb property. Values: on | off | sharemgr(1M) options"
end
newproperty(:snapdir) do
- desc "The snapdir property."
+ desc "The snapdir property. Values: hidden | visible"
+ end
+
+ newproperty(:version) do
+ desc "The version property. Values: 1 | 2 | 3 | 4 | current"
+ end
+
+ newproperty(:volsize) do
+ desc "The volsize property. Values: <size>"
+ end
+
+ newproperty(:vscan) do
+ desc "The vscan property. Values: on | off"
+ end
+
+ newproperty(:xattr) do
+ desc "The xattr property. Values: on | off"
+ end
+
+ newproperty(:zoned) do
+ desc "The zoned property. Values: on | off"
end
autorequire(:zpool) do
View
2  lib/puppet/type/zone.rb
@@ -409,7 +409,7 @@ def should
# both as prerequisites.
autorequire(:file) do
if @parameters.include? :path
- [@parameters[:path].value, File.dirname(@parameters[:path].value)]
+ [@parameters[:path].value, ::File.dirname(@parameters[:path].value)]
else
nil
end
View
1  lib/puppet/type/zpool.rb
@@ -4,6 +4,7 @@ class Property
class VDev < Property
def flatten_and_sort(array)
+ array = [array] unless array.is_a? Array
array.collect { |a| a.split(' ') }.flatten.sort
end
View
6 lib/puppet/util/loadedfile.rb
@@ -34,10 +34,6 @@ def changed?
# Create the file. Must be passed the file path.
def initialize(file)
@file = file
- unless FileTest.exists?(@file)
- raise Puppet::NoSuchFile,
- "Can not use a non-existent file for parsing"
- end
@statted = 0
@stamp = nil
@tstamp = stamp
@@ -50,7 +46,7 @@ def stamp
@statted = Time.now.to_i
begin
@stamp = File.stat(@file).ctime
- rescue Errno::ENOENT
+ rescue Errno::ENOENT, Errno::ENOTDIR
@stamp = Time.now
end
end
View
4 spec/unit/application/master_spec.rb
@@ -177,8 +177,8 @@
lambda { @master.setup }.should raise_error(SystemExit)
end
- it "should tell Puppet.settings to use :main,:ssl and :master category" do
- Puppet.settings.expects(:use).with(:main,:master,:ssl)
+ it "should tell Puppet.settings to use :main,:ssl,:master and :metrics category" do
+ Puppet.settings.expects(:use).with(:main,:master,:ssl,:metrics)
@master.setup
end
View
8 spec/unit/file_serving/fileset_spec.rb
@@ -13,6 +13,14 @@
proc { Puppet::FileServing::Fileset.new("some/file") }.should raise_error(ArgumentError)
end
+ it "should not fail if the path is fully qualified, with a trailing separator" do
+ path = "/some/path/with/trailing/separator"
+ path_with_separator = "#{path}#{File::SEPARATOR}"
+ File.stubs(:lstat).with(path).returns stub('stat')
+ fileset = Puppet::FileServing::Fileset.new(path_with_separator)
+ fileset.path.should == path
+ end
+
it "should fail if its path does not exist" do
File.expects(:lstat).with("/some/file").returns nil
proc { Puppet::FileServing::Fileset.new("/some/file") }.should raise_error(ArgumentError)
View
7 spec/unit/indirector/active_record_spec.rb
@@ -14,10 +14,9 @@
@indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model
Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
- @active_record_class = Class.new(Puppet::Indirector::ActiveRecord) do
- def self.to_s
- "Mystuff::Testing"
- end
+ module Testing; end
+ @active_record_class = class Testing::MyActiveRecord < Puppet::Indirector::ActiveRecord
+ self
end
@ar_model = mock 'ar_model'
View
9 spec/unit/indirector/code_spec.rb
@@ -4,16 +4,15 @@
require 'puppet/indirector/code'
describe Puppet::Indirector::Code do
- before do
+ before :all do
Puppet::Indirector::Terminus.stubs(:register_terminus_class)
@model = mock 'model'
@indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model
Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
- @code_class = Class.new(Puppet::Indirector::Code) do
- def self.to_s
- "Mystuff::Testing"
- end
+ module Testing; end
+ @code_class = class Testing::MyCode < Puppet::Indirector::Code
+ self
end
@searcher = @code_class.new
View
9 spec/unit/indirector/direct_file_server_spec.rb
@@ -8,16 +8,15 @@
require 'puppet/indirector/direct_file_server'
describe Puppet::Indirector::DirectFileServer do
- before :each do
+ before :all do
Puppet::Indirector::Terminus.stubs(:register_terminus_class)
@model = mock 'model'
@indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model
Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
- @direct_file_class = Class.new(Puppet::Indirector::DirectFileServer) do
- def self.to_s
- "Testing::Mytype"
- end
+ module Testing; end
+ @direct_file_class = class Testing::Mytype < Puppet::Indirector::DirectFileServer
+ self
end
@server = @direct_file_class.new
View
12 spec/unit/indirector/exec_spec.rb
@@ -5,17 +5,17 @@
require 'puppet/indirector/exec'
describe Puppet::Indirector::Exec do
- before do
+ before :all do
@indirection = stub 'indirection', :name => :testing
Puppet::Indirector::Indirection.expects(:instance).with(:testing).returns(@indirection)
- @exec_class = Class.new(Puppet::Indirector::Exec) do
- def self.to_s
- "Testing::Mytype"
- end
-
+ module Testing; end