summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Martin <max@puppetlabs.com>2011-03-30 13:02:19 -0700
committerMax Martin <max@puppetlabs.com>2011-03-30 13:02:19 -0700
commit9c06fbd762cddcc41a7185a36f2a8e72879125eb (patch)
treebfd37ac5887307857d0b0d79a1db034010eed424
parent4196699f5fbb90ceecbb709c8502622eaad39062 (diff)
parent11309a214148abb2167c1bd0adba0e035b2d8384 (diff)
downloadpuppet-9c06fbd762cddcc41a7185a36f2a8e72879125eb.tar.gz
puppet-9c06fbd762cddcc41a7185a36f2a8e72879125eb.tar.xz
puppet-9c06fbd762cddcc41a7185a36f2a8e72879125eb.zip
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 ...
-rw-r--r--CHANGELOG5
-rw-r--r--lib/puppet/application/master.rb2
-rw-r--r--lib/puppet/defaults.rb1
-rw-r--r--lib/puppet/file_serving/fileset.rb1
-rw-r--r--lib/puppet/indirector/resource_type/parser.rb22
-rw-r--r--lib/puppet/module.rb2
-rw-r--r--lib/puppet/node/environment.rb5
-rw-r--r--lib/puppet/parser/compiler.rb16
-rw-r--r--lib/puppet/parser/functions/create_resources.rb47
-rw-r--r--lib/puppet/parser/functions/fqdn_rand.rb4
-rw-r--r--lib/puppet/parser/lexer.rb5
-rw-r--r--lib/puppet/parser/parser_support.rb1
-rw-r--r--lib/puppet/parser/type_loader.rb28
-rwxr-xr-xlib/puppet/provider/aixobject.rb393
-rw-r--r--lib/puppet/provider/augeas/augeas.rb21
-rw-r--r--lib/puppet/provider/file/posix.rb2
-rw-r--r--lib/puppet/provider/file/win32.rb2
-rwxr-xr-xlib/puppet/provider/group/aix.rb141
-rwxr-xr-xlib/puppet/provider/service/debian.rb8
-rwxr-xr-xlib/puppet/provider/service/smf.rb6
-rwxr-xr-xlib/puppet/provider/user/aix.rb353
-rw-r--r--lib/puppet/provider/zfs/solaris.rb2
-rw-r--r--lib/puppet/resource/type.rb6
-rw-r--r--lib/puppet/simple_graph.rb9
-rw-r--r--lib/puppet/transaction/event.rb2
-rwxr-xr-xlib/puppet/type/exec.rb14
-rw-r--r--lib/puppet/type/file/ctime.rb2
-rwxr-xr-xlib/puppet/type/file/ensure.rb2
-rwxr-xr-xlib/puppet/type/file/group.rb2
-rwxr-xr-xlib/puppet/type/file/mode.rb2
-rw-r--r--lib/puppet/type/file/mtime.rb2
-rw-r--r--lib/puppet/type/file/selcontext.rb2
-rwxr-xr-xlib/puppet/type/file/type.rb2
-rwxr-xr-xlib/puppet/type/group.rb36
-rwxr-xr-xlib/puppet/type/tidy.rb6
-rwxr-xr-xlib/puppet/type/user.rb39
-rw-r--r--[-rwxr-xr-x]lib/puppet/type/zfs.rb110
-rw-r--r--lib/puppet/type/zone.rb2
-rwxr-xr-xlib/puppet/type/zpool.rb1
-rwxr-xr-xlib/puppet/util/loadedfile.rb6
-rw-r--r--spec/unit/application/master_spec.rb4
-rwxr-xr-xspec/unit/file_serving/fileset_spec.rb8
-rwxr-xr-xspec/unit/indirector/active_record_spec.rb7
-rwxr-xr-xspec/unit/indirector/code_spec.rb9
-rwxr-xr-xspec/unit/indirector/direct_file_server_spec.rb9
-rwxr-xr-xspec/unit/indirector/exec_spec.rb12
-rwxr-xr-xspec/unit/indirector/file_server_spec.rb11
-rwxr-xr-xspec/unit/indirector/file_spec.rb9
-rwxr-xr-xspec/unit/indirector/ldap_spec.rb7
-rwxr-xr-xspec/unit/indirector/memory_spec.rb7
-rwxr-xr-xspec/unit/indirector/plain_spec.rb7
-rwxr-xr-xspec/unit/indirector/queue_spec.rb7
-rwxr-xr-xspec/unit/indirector/resource_type/parser_spec.rb95
-rwxr-xr-xspec/unit/indirector/rest_spec.rb18
-rwxr-xr-xspec/unit/indirector/ssl_file_spec.rb13
-rwxr-xr-xspec/unit/indirector/yaml_spec.rb13
-rwxr-xr-xspec/unit/module_spec.rb39
-rwxr-xr-xspec/unit/network/authconfig_spec.rb2
-rwxr-xr-xspec/unit/network/rest_authconfig_spec.rb2
-rwxr-xr-xspec/unit/node/environment_spec.rb29
-rwxr-xr-xspec/unit/parser/ast/casestatement_spec.rb26
-rwxr-xr-xspec/unit/parser/compiler_spec.rb24
-rwxr-xr-xspec/unit/parser/functions/create_resources_spec.rb135
-rwxr-xr-xspec/unit/parser/lexer_spec.rb12
-rw-r--r--spec/unit/parser/type_loader_spec.rb97
-rw-r--r--spec/unit/provider/augeas/augeas_spec.rb54
-rwxr-xr-xspec/unit/provider/service/debian_spec.rb16
-rwxr-xr-xspec/unit/provider/service/smf_spec.rb137
-rwxr-xr-xspec/unit/provider/zfs/solaris_spec.rb1
-rwxr-xr-xspec/unit/resource/type_spec.rb22
-rwxr-xr-xspec/unit/type/exec_spec.rb16
-rwxr-xr-xspec/unit/util/loadedfile_spec.rb7
-rwxr-xr-xspec/unit/util/rdoc/parser_spec.rb7
-rw-r--r--tasks/rake/git_workflow.rake4
-rwxr-xr-xtest/language/functions.rb2
75 files changed, 1952 insertions, 228 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 2885596e3..755dd82a8 100644
--- a/CHANGELOG
+++ b/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"
diff --git a/lib/puppet/application/master.rb b/lib/puppet/application/master.rb
index 3bfad89f4..78499a92a 100644
--- a/lib/puppet/application/master.rb
+++ b/lib/puppet/application/master.rb
@@ -222,7 +222,7 @@ License
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
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index f308d4476..989ef3f35 100644
--- a/lib/puppet/defaults.rb
+++ b/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.
diff --git a/lib/puppet/file_serving/fileset.rb b/lib/puppet/file_serving/fileset.rb
index fdbcf93a3..c020f036d 100644
--- a/lib/puppet/file_serving/fileset.rb
+++ b/lib/puppet/file_serving/fileset.rb
@@ -59,6 +59,7 @@ class Puppet::FileServing::Fileset
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
diff --git a/lib/puppet/indirector/resource_type/parser.rb b/lib/puppet/indirector/resource_type/parser.rb
index 8b1bed0a9..4bcaf3f47 100644
--- a/lib/puppet/indirector/resource_type/parser.rb
+++ b/lib/puppet/indirector/resource_type/parser.rb
@@ -10,7 +10,10 @@ class Puppet::Indirector::ResourceType::Parser < Puppet::Indirector::Code
# 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 @@ class Puppet::Indirector::ResourceType::Parser < Puppet::Indirector::Code
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
diff --git a/lib/puppet/module.rb b/lib/puppet/module.rb
index 43266b2b5..059591ed8 100644
--- a/lib/puppet/module.rb
+++ b/lib/puppet/module.rb
@@ -138,7 +138,7 @@ class Puppet::Module
# 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.
diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb
index 7877b7f73..d50530618 100644
--- a/lib/puppet/node/environment.rb
+++ b/lib/puppet/node/environment.rb
@@ -76,7 +76,7 @@ class Puppet::Node::Environment
# 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 @@ class Puppet::Node::Environment
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 @@ class Puppet::Node::Environment
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
diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb
index fdabd05c9..a891f1a11 100644
--- a/lib/puppet/parser/compiler.rb
+++ b/lib/puppet/parser/compiler.rb
@@ -20,7 +20,7 @@ class Puppet::Parser::Compiler
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 @@ class Puppet::Parser::Compiler
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 @@ class Puppet::Parser::Compiler
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
diff --git a/lib/puppet/parser/functions/create_resources.rb b/lib/puppet/parser/functions/create_resources.rb
new file mode 100644
index 000000000..430f110b4
--- /dev/null
+++ b/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
diff --git a/lib/puppet/parser/functions/fqdn_rand.rb b/lib/puppet/parser/functions/fqdn_rand.rb
index 52946f2c1..91157a148 100644
--- a/lib/puppet/parser/functions/fqdn_rand.rb
+++ b/lib/puppet/parser/functions/fqdn_rand.rb
@@ -5,8 +5,8 @@ Puppet::Parser::Functions::newfunction(:fqdn_rand, :type => :rvalue, :doc =>
$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
diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb
index 4050adeb8..2f416615e 100644
--- a/lib/puppet/parser/lexer.rb
+++ b/lib/puppet/parser/lexer.rb
@@ -312,7 +312,8 @@ class Puppet::Parser::Lexer
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 @@ class Puppet::Parser::Lexer
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)
diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb
index 746aa0f90..7888fe1dc 100644
--- a/lib/puppet/parser/parser_support.rb
+++ b/lib/puppet/parser/parser_support.rb
@@ -79,7 +79,6 @@ class Puppet::Parser::Parser
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)
diff --git a/lib/puppet/parser/type_loader.rb b/lib/puppet/parser/type_loader.rb
index 140c9f2ca..1fba73d0b 100644
--- a/lib/puppet/parser/type_loader.rb
+++ b/lib/puppet/parser/type_loader.rb
@@ -92,6 +92,34 @@ class Puppet::Parser::TypeLoader
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
diff --git a/lib/puppet/provider/aixobject.rb b/lib/puppet/provider/aixobject.rb
new file mode 100755
index 000000000..9506c67a2
--- /dev/null
+++ b/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
diff --git a/lib/puppet/provider/augeas/augeas.rb b/lib/puppet/provider/augeas/augeas.rb
index 461968245..5488c6674 100644
--- a/lib/puppet/provider/augeas/augeas.rb
+++ b/lib/puppet/provider/augeas/augeas.rb
@@ -32,10 +32,14 @@ Puppet::Type.type(:augeas).provide(:augeas) do
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 @@ Puppet::Type.type(:augeas).provide(:augeas) do
COMMANDS["ins"] = COMMANDS["insert"]
COMMANDS["remove"] = COMMANDS["rm"]
+ COMMANDS["move"] = COMMANDS["mv"]
attr_accessor :aug
@@ -334,6 +339,10 @@ Puppet::Type.type(:augeas).provide(:augeas) do
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 @@ Puppet::Type.type(:augeas).provide(:augeas) do
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
diff --git a/lib/puppet/provider/file/posix.rb b/lib/puppet/provider/file/posix.rb
index f7b8c9797..7b7336b9d 100644
--- a/lib/puppet/provider/file/posix.rb
+++ b/lib/puppet/provider/file/posix.rb
@@ -54,7 +54,7 @@ Puppet::Type.type(:file).provide :posix do
end
def retrieve(resource)
- unless stat = resource.stat(false)
+ unless stat = resource.stat
return :absent
end
diff --git a/lib/puppet/provider/file/win32.rb b/lib/puppet/provider/file/win32.rb
index 21e7ca974..9423e8f00 100644
--- a/lib/puppet/provider/file/win32.rb
+++ b/lib/puppet/provider/file/win32.rb
@@ -49,7 +49,7 @@ Puppet::Type.type(:file).provide :microsoft_windows do
end
def retrieve(resource)
- unless stat = resource.stat(false)
+ unless stat = resource.stat
return :absent
end
diff --git a/lib/puppet/provider/group/aix.rb b/lib/puppet/provider/group/aix.rb
new file mode 100755
index 000000000..ecdef6070
--- /dev/null
+++ b/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
diff --git a/lib/puppet/provider/service/debian.rb b/lib/puppet/provider/service/debian.rb
index 3d09e2849..58b808a8e 100755
--- a/lib/puppet/provider/service/debian.rb
+++ b/lib/puppet/provider/service/debian.rb
@@ -22,8 +22,12 @@ Puppet::Type.type(:service).provide :debian, :parent => :init do
# 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?
diff --git a/lib/puppet/provider/service/smf.rb b/lib/puppet/provider/service/smf.rb
index 3efb2eb37..f6f221a7c 100755
--- a/lib/puppet/provider/service/smf.rb
+++ b/lib/puppet/provider/service/smf.rb
@@ -27,7 +27,7 @@ Puppet::Type.type(:service).provide :smf, :parent => :base do
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 @@ Puppet::Type.type(:service).provide :smf, :parent => :base do
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
diff --git a/lib/puppet/provider/user/aix.rb b/lib/puppet/provider/user/aix.rb
new file mode 100755
index 000000000..032d2b536
--- /dev/null
+++ b/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
diff --git a/lib/puppet/provider/zfs/solaris.rb b/lib/puppet/provider/zfs/solaris.rb
index 9aec9d801..b783f9e01 100644
--- a/lib/puppet/provider/zfs/solaris.rb
+++ b/lib/puppet/provider/zfs/solaris.rb
@@ -31,7 +31,7 @@ Puppet::Type.type(:zfs).provide(:solaris) do
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
diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb
index b9cf6991a..48d8c1f48 100644
--- a/lib/puppet/resource/type.rb
+++ b/lib/puppet/resource/type.rb
@@ -34,13 +34,13 @@ class Puppet::Resource::Type
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
diff --git a/lib/puppet/simple_graph.rb b/lib/puppet/simple_graph.rb
index e39aa8770..27e068e30 100644
--- a/lib/puppet/simple_graph.rb
+++ b/lib/puppet/simple_graph.rb
@@ -367,7 +367,7 @@ class Puppet::SimpleGraph
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 @@ class Puppet::SimpleGraph
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 @@ class Puppet::SimpleGraph
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
diff --git a/lib/puppet/transaction/event.rb b/lib/puppet/transaction/event.rb
index cd695cff8..d3f25b71c 100644
--- a/lib/puppet/transaction/event.rb
+++ b/lib/puppet/transaction/event.rb
@@ -48,7 +48,7 @@ class Puppet::Transaction::Event
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
diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb
index 773df2bb4..3ba488f19 100755
--- a/lib/puppet/type/exec.rb
+++ b/lib/puppet/type/exec.rb
@@ -220,19 +220,17 @@ module Puppet
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
diff --git a/lib/puppet/type/file/ctime.rb b/lib/puppet/type/file/ctime.rb
index 24b098703..90d95da64 100644
--- a/lib/puppet/type/file/ctime.rb
+++ b/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
diff --git a/lib/puppet/type/file/ensure.rb b/lib/puppet/type/file/ensure.rb
index 99652ecc6..0f065da14 100755
--- a/lib/puppet/type/file/ensure.rb
+++ b/lib/puppet/type/file/ensure.rb
@@ -138,7 +138,7 @@ module Puppet
end
def retrieve
- if stat = @resource.stat(false)
+ if stat = @resource.stat
return stat.ftype.intern
else
if self.should == :false
diff --git a/lib/puppet/type/file/group.rb b/lib/puppet/type/file/group.rb
index 5ed5166bc..4d1f2f4e6 100755
--- a/lib/puppet/type/file/group.rb
+++ b/lib/puppet/type/file/group.rb
@@ -62,7 +62,7 @@ module Puppet
end
def retrieve
- return :absent unless stat = resource.stat(false)
+ return :absent unless stat = resource.stat
currentvalue = stat.gid
diff --git a/lib/puppet/type/file/mode.rb b/lib/puppet/type/file/mode.rb
index 2acd8b359..9f58e6fb0 100755
--- a/lib/puppet/type/file/mode.rb
+++ b/lib/puppet/type/file/mode.rb
@@ -63,7 +63,7 @@ module Puppet
# 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
diff --git a/lib/puppet/type/file/mtime.rb b/lib/puppet/type/file/mtime.rb
index 8ca7ed0d6..5952b4b84 100644
--- a/lib/puppet/type/file/mtime.rb
+++ b/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
diff --git a/lib/puppet/type/file/selcontext.rb b/lib/puppet/type/file/selcontext.rb
index ea385eec0..1b1a77245 100644
--- a/lib/puppet/type/file/selcontext.rb
+++ b/lib/puppet/type/file/selcontext.rb
@@ -26,7 +26,7 @@ module Puppet
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
diff --git a/lib/puppet/type/file/type.rb b/lib/puppet/type/file/type.rb
index 4da54e2cb..864d3b1a4 100755
--- a/lib/puppet/type/file/type.rb
+++ b/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
diff --git a/lib/puppet/type/group.rb b/lib/puppet/type/group.rb
index cde1cfd65..aa96bd9c3 100755
--- a/lib/puppet/type/group.rb
+++ b/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 @@ module Puppet
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
diff --git a/lib/puppet/type/tidy.rb b/lib/puppet/type/tidy.rb
index 93a7e96cf..146481fed 100755
--- a/lib/puppet/type/tidy.rb
+++ b/lib/puppet/type/tidy.rb
@@ -254,7 +254,7 @@ Puppet::Type.newtype(:tidy) do
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 @@ Puppet::Type.newtype(:tidy) do
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 @@ Puppet::Type.newtype(:tidy) do
def stat(path)
begin
- File.lstat(path)
+ ::File.lstat(path)
rescue Errno::ENOENT => error
info "File does not exist"
return nil
diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb
index f74e4266f..767959308 100755
--- a/lib/puppet/type/user.rb
+++ b/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 @@ module Puppet
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
diff --git a/lib/puppet/type/zfs.rb b/lib/puppet/type/zfs.rb
index 7123f8ac9..75f821787 100755..100644
--- a/lib/puppet/type/zfs.rb
+++ b/lib/puppet/type/zfs.rb
@@ -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
diff --git a/lib/puppet/type/zone.rb b/lib/puppet/type/zone.rb
index 1bae93120..0fc702ccf 100644
--- a/lib/puppet/type/zone.rb
+++ b/lib/puppet/type/zone.rb
@@ -409,7 +409,7 @@ Puppet::Type.newtype(:zone) do
# 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
diff --git a/lib/puppet/type/zpool.rb b/lib/puppet/type/zpool.rb
index 40ee8f286..2da713c2b 100755
--- a/lib/puppet/type/zpool.rb
+++ b/lib/puppet/type/zpool.rb
@@ -4,6 +4,7 @@ module Puppet
class VDev < Property
def flatten_and_sort(array)
+ array = [array] unless array.is_a? Array
array.collect { |a| a.split(' ') }.flatten.sort
end
diff --git a/lib/puppet/util/loadedfile.rb b/lib/puppet/util/loadedfile.rb
index 735dba459..d2f5d0923 100755
--- a/lib/puppet/util/loadedfile.rb
+++ b/lib/puppet/util/loadedfile.rb
@@ -34,10 +34,6 @@ module Puppet
# 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 @@ module Puppet
@statted = Time.now.to_i
begin
@stamp = File.stat(@file).ctime
- rescue Errno::ENOENT
+ rescue Errno::ENOENT, Errno::ENOTDIR
@stamp = Time.now
end
end
diff --git a/spec/unit/application/master_spec.rb b/spec/unit/application/master_spec.rb
index 1173752d9..14478a61a 100644
--- a/spec/unit/application/master_spec.rb
+++ b/spec/unit/application/master_spec.rb
@@ -177,8 +177,8 @@ describe Puppet::Application::Master do
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
diff --git a/spec/unit/file_serving/fileset_spec.rb b/spec/unit/file_serving/fileset_spec.rb
index 1ef9cdc50..3b12c953e 100755
--- a/spec/unit/file_serving/fileset_spec.rb
+++ b/spec/unit/file_serving/fileset_spec.rb
@@ -13,6 +13,14 @@ describe Puppet::FileServing::Fileset, " when initializing" do
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)
diff --git a/spec/unit/indirector/active_record_spec.rb b/spec/unit/indirector/active_record_spec.rb
index 4765cc5ea..4fab17da2 100755
--- a/spec/unit/indirector/active_record_spec.rb
+++ b/spec/unit/indirector/active_record_spec.rb
@@ -14,10 +14,9 @@ describe Puppet::Indirector::ActiveRecord do
@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'
diff --git a/spec/unit/indirector/code_spec.rb b/spec/unit/indirector/code_spec.rb
index 452d009f8..1c9e4d2f1 100755
--- a/spec/unit/indirector/code_spec.rb
+++ b/spec/unit/indirector/code_spec.rb
@@ -4,16 +4,15 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
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
diff --git a/spec/unit/indirector/direct_file_server_spec.rb b/spec/unit/indirector/direct_file_server_spec.rb
index 8eab4ad76..5d9af626f 100755
--- a/spec/unit/indirector/direct_file_server_spec.rb
+++ b/spec/unit/indirector/direct_file_server_spec.rb
@@ -8,16 +8,15 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
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
diff --git a/spec/unit/indirector/exec_spec.rb b/spec/unit/indirector/exec_spec.rb
index d4fb22443..5abb00ae9 100755
--- a/spec/unit/indirector/exec_spec.rb
+++ b/spec/unit/indirector/exec_spec.rb
@@ -5,17 +5,17 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
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
+ @exec_class = class Testing::MyTesting < Puppet::Indirector::Exec
attr_accessor :command
+ self
end
+ end
+ before :each do
@searcher = @exec_class.new
@searcher.command = ["/echo"]
diff --git a/spec/unit/indirector/file_server_spec.rb b/spec/unit/indirector/file_server_spec.rb
index a81d50487..079eba0ae 100755
--- a/spec/unit/indirector/file_server_spec.rb
+++ b/spec/unit/indirector/file_server_spec.rb
@@ -10,18 +10,19 @@ require 'puppet/file_serving/configuration'
describe Puppet::Indirector::FileServer 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)
- @file_server_class = Class.new(Puppet::Indirector::FileServer) do
- def self.to_s
- "Testing::Mytype"
- end
+ module Testing; end
+ @file_server_class = class Testing::MyFileServer < Puppet::Indirector::FileServer
+ self
end
+ end
+ before :each do
@file_server = @file_server_class.new
@uri = "puppet://host/my/local/file"
diff --git a/spec/unit/indirector/file_spec.rb b/spec/unit/indirector/file_spec.rb
index 8fd197eac..96d5b2ae7 100755
--- a/spec/unit/indirector/file_spec.rb
+++ b/spec/unit/indirector/file_spec.rb
@@ -5,16 +5,15 @@ require 'puppet/indirector/file'
describe Puppet::Indirector::File 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)
- @file_class = Class.new(Puppet::Indirector::File) do
- def self.to_s
- "Testing::Mytype"
- end
+ module Testing; end
+ @file_class = class Testing::MyFile < Puppet::Indirector::File
+ self
end
@searcher = @file_class.new
diff --git a/spec/unit/indirector/ldap_spec.rb b/spec/unit/indirector/ldap_spec.rb
index 2178a8709..ab5dab9ce 100755
--- a/spec/unit/indirector/ldap_spec.rb
+++ b/spec/unit/indirector/ldap_spec.rb
@@ -8,10 +8,9 @@ describe Puppet::Indirector::Ldap do
before do
@indirection = stub 'indirection', :name => :testing
Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
- @ldap_class = Class.new(Puppet::Indirector::Ldap) do
- def self.to_s
- "Testing::Mytype"
- end
+ module Testing; end
+ @ldap_class = class Testing::MyLdap < Puppet::Indirector::Ldap
+ self
end
@connection = mock 'ldap'
diff --git a/spec/unit/indirector/memory_spec.rb b/spec/unit/indirector/memory_spec.rb
index f9010326f..751adb1b6 100755
--- a/spec/unit/indirector/memory_spec.rb
+++ b/spec/unit/indirector/memory_spec.rb
@@ -14,10 +14,9 @@ describe Puppet::Indirector::Memory do
@indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model
Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
- @memory_class = Class.new(Puppet::Indirector::Memory) do
- def self.to_s
- "Mystuff::Testing"
- end
+ module Testing; end
+ @memory_class = class Testing::MyMemory < Puppet::Indirector::Memory
+ self
end
@searcher = @memory_class.new
diff --git a/spec/unit/indirector/plain_spec.rb b/spec/unit/indirector/plain_spec.rb
index 54c0233f8..dfaa701bd 100755
--- a/spec/unit/indirector/plain_spec.rb
+++ b/spec/unit/indirector/plain_spec.rb
@@ -10,10 +10,9 @@ describe Puppet::Indirector::Plain do
@indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model
Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
- @plain_class = Class.new(Puppet::Indirector::Plain) do
- def self.to_s
- "Mystuff::Testing"
- end
+ module Testing; end
+ @plain_class = class Testing::MyPlain < Puppet::Indirector::Plain
+ self
end
@searcher = @plain_class.new
diff --git a/spec/unit/indirector/queue_spec.rb b/spec/unit/indirector/queue_spec.rb
index 49e5e1015..6f5b44b4c 100755
--- a/spec/unit/indirector/queue_spec.rb
+++ b/spec/unit/indirector/queue_spec.rb
@@ -31,10 +31,9 @@ describe Puppet::Indirector::Queue, :if => Puppet.features.pson? do
@model = mock 'model'
@indirection = stub 'indirection', :name => :my_queue, :register_terminus_type => nil, :model => @model
Puppet::Indirector::Indirection.stubs(:instance).with(:my_queue).returns(@indirection)
- @store_class = Class.new(Puppet::Indirector::Queue) do
- def self.to_s
- 'MyQueue::MyType'
- end
+ module MyQueue; end
+ @store_class = class MyQueue::MyType < Puppet::Indirector::Queue
+ self
end
@store = @store_class.new
diff --git a/spec/unit/indirector/resource_type/parser_spec.rb b/spec/unit/indirector/resource_type/parser_spec.rb
index 739e58b35..f86b319f9 100755
--- a/spec/unit/indirector/resource_type/parser_spec.rb
+++ b/spec/unit/indirector/resource_type/parser_spec.rb
@@ -3,13 +3,15 @@
require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
require 'puppet/indirector/resource_type/parser'
+require 'puppet_spec/files'
describe Puppet::Indirector::ResourceType::Parser do
+ include PuppetSpec::Files
+
before do
@terminus = Puppet::Indirector::ResourceType::Parser.new
@request = Puppet::Indirector::Request.new(:resource_type, :find, "foo")
- @krt = Puppet::Resource::TypeCollection.new(@request.environment)
- @request.environment.stubs(:known_resource_types).returns @krt
+ @krt = @request.environment.known_resource_types
end
it "should be registered with the resource_type indirection" do
@@ -17,16 +19,29 @@ describe Puppet::Indirector::ResourceType::Parser do
end
describe "when finding" do
- it "should use the request's environment's list of known resource types" do
- @request.environment.known_resource_types.expects(:hostclass).returns nil
+ it "should return any found type from the request's environment" do
+ type = Puppet::Resource::Type.new(:hostclass, "foo")
+ @request.environment.known_resource_types.add(type)
- @terminus.find(@request)
+ @terminus.find(@request).should == type
end
- it "should return any found type" do
- type = @krt.add(Puppet::Resource::Type.new(:hostclass, "foo"))
+ it "should attempt to load the type if none is found in memory" do
+ dir = tmpdir("find_a_type")
+ FileUtils.mkdir_p(dir)
+ Puppet[:modulepath] = dir
- @terminus.find(@request).should == type
+ # Make a new request, since we've reset the env
+ @request = Puppet::Indirector::Request.new(:resource_type, :find, "foo::bar")
+
+ manifest_path = File.join(dir, "foo", "manifests")
+ FileUtils.mkdir_p(manifest_path)
+
+ File.open(File.join(manifest_path, "bar.pp"), "w") { |f| f.puts "class foo::bar {}" }
+
+ result = @terminus.find(@request)
+ result.should be_instance_of(Puppet::Resource::Type)
+ result.name.should == "foo::bar"
end
it "should return nil if no type can be found" do
@@ -52,8 +67,35 @@ describe Puppet::Indirector::ResourceType::Parser do
@terminus.search(@request)
end
- it "should fail if anyther other than '*' was provided as the search key" do
- @request.key = "foo*"
+ it "should return all results if '*' is provided as the search string" do
+ @request.key = "*"
+ type = @krt.add(Puppet::Resource::Type.new(:hostclass, "foo"))
+ node = @krt.add(Puppet::Resource::Type.new(:node, "bar"))
+ define = @krt.add(Puppet::Resource::Type.new(:definition, "baz"))
+
+ result = @terminus.search(@request)
+ result.should be_include(type)
+ result.should be_include(node)
+ result.should be_include(define)
+ end
+
+ it "should treat any search string not '*' as a regex" do
+ @request.key = "a"
+ foo = @krt.add(Puppet::Resource::Type.new(:hostclass, "foo"))
+ bar = @krt.add(Puppet::Resource::Type.new(:hostclass, "bar"))
+ baz = @krt.add(Puppet::Resource::Type.new(:hostclass, "baz"))
+
+ result = @terminus.search(@request)
+ result.should be_include(bar)
+ result.should be_include(baz)
+ result.should_not be_include(foo)
+ end
+
+ it "should fail if a provided search string is not '*' and is not a valid regex" do
+ @request.key = "*foo*"
+
+ # Add one instance so we don't just get an empty array"
+ @krt.add(Puppet::Resource::Type.new(:hostclass, "foo"))
lambda { @terminus.search(@request) }.should raise_error(ArgumentError)
end
@@ -68,8 +110,41 @@ describe Puppet::Indirector::ResourceType::Parser do
result.should be_include(define)
end
+ it "should not return the 'main' class" do
+ main = @krt.add(Puppet::Resource::Type.new(:hostclass, ""))
+
+ # So there is a return value
+ foo = @krt.add(Puppet::Resource::Type.new(:hostclass, "foo"))
+
+ @terminus.search(@request).should_not be_include(main)
+ end
+
it "should return nil if no types can be found" do
@terminus.search(@request).should be_nil
end
+
+ it "should load all resource types from all search paths" do
+ dir = tmpdir("searching_in_all")
+ first = File.join(dir, "first")
+ second = File.join(dir, "second")
+ FileUtils.mkdir_p(first)
+ FileUtils.mkdir_p(second)
+ Puppet[:modulepath] = "#{first}:#{second}"
+
+ # Make a new request, since we've reset the env
+ @request = Puppet::Indirector::Request.new(:resource_type, :search, "*")
+
+ onepath = File.join(first, "one", "manifests")
+ FileUtils.mkdir_p(onepath)
+ twopath = File.join(first, "two", "manifests")
+ FileUtils.mkdir_p(twopath)
+
+ File.open(File.join(onepath, "oneklass.pp"), "w") { |f| f.puts "class one::oneklass {}" }
+ File.open(File.join(twopath, "twoklass.pp"), "w") { |f| f.puts "class two::twoklass {}" }
+
+ result = @terminus.search(@request)
+ result.find { |t| t.name == "one::oneklass" }.should be_instance_of(Puppet::Resource::Type)
+ result.find { |t| t.name == "two::twoklass" }.should be_instance_of(Puppet::Resource::Type)
+ end
end
end
diff --git a/spec/unit/indirector/rest_spec.rb b/spec/unit/indirector/rest_spec.rb
index 547e68dd3..326d85f9d 100755
--- a/spec/unit/indirector/rest_spec.rb
+++ b/spec/unit/indirector/rest_spec.rb
@@ -26,19 +26,27 @@ shared_examples_for "a REST http call" do
end
describe Puppet::Indirector::REST do
- before do
+ before :all do
Puppet::Indirector::Terminus.stubs(:register_terminus_class)
@model = stub('model', :supported_formats => %w{}, :convert_from => nil)
@instance = stub('model instance', :name= => nil)
@indirection = stub('indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model)
- Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
+ Puppet::Indirector::Indirection.expects(:instance).returns(@indirection)
- @rest_class = Class.new(Puppet::Indirector::REST) do
- def self.to_s
- "This::Is::A::Test::Class"
+ module This
+ module Is
+ module A
+ module Test
+ end
+ end
end
end
+ @rest_class = class This::Is::A::Test::Class < Puppet::Indirector::REST
+ self
+ end
+ end
+ before :each do
@response = stub('mock response', :body => 'result', :code => "200")
@response.stubs(:[]).with('content-type').returns "text/plain"
@response.stubs(:[]).with('content-encoding').returns nil
diff --git a/spec/unit/indirector/ssl_file_spec.rb b/spec/unit/indirector/ssl_file_spec.rb
index 4549127f9..ca97cf49e 100755
--- a/spec/unit/indirector/ssl_file_spec.rb
+++ b/spec/unit/indirector/ssl_file_spec.rb
@@ -8,15 +8,16 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require 'puppet/indirector/ssl_file'
describe Puppet::Indirector::SslFile do
- before do
- @model = mock 'model'
+ before :all do
@indirection = stub 'indirection', :name => :testing, :model => @model
Puppet::Indirector::Indirection.expects(:instance).with(:testing).returns(@indirection)
- @file_class = Class.new(Puppet::Indirector::SslFile) do
- def self.to_s
- "Testing::Mytype"
- end
+ module Testing; end
+ @file_class = class Testing::MyType < Puppet::Indirector::SslFile
+ self
end
+ end
+ before :each do
+ @model = mock 'model'
@setting = :certdir
@file_class.store_in @setting
diff --git a/spec/unit/indirector/yaml_spec.rb b/spec/unit/indirector/yaml_spec.rb
index 35017991b..188e300d6 100755
--- a/spec/unit/indirector/yaml_spec.rb
+++ b/spec/unit/indirector/yaml_spec.rb
@@ -5,14 +5,15 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require 'puppet/indirector/yaml'
describe Puppet::Indirector::Yaml, " when choosing file location" do
- before :each do
+ before :all do
@indirection = stub 'indirection', :name => :my_yaml, :register_terminus_type => nil
- Puppet::Indirector::Indirection.stubs(:instance).with(:my_yaml).returns(@indirection)
- @store_class = Class.new(Puppet::Indirector::Yaml) do
- def self.to_s
- "MyYaml::MyType"
- end
+ Puppet::Indirector::Indirection.expects(:instance).with(:my_yaml).returns(@indirection)
+ module MyYaml; end
+ @store_class = class MyYaml::MyType < Puppet::Indirector::Yaml
+ self
end
+ end
+ before :each do
@store = @store_class.new
@subject = Object.new
diff --git a/spec/unit/module_spec.rb b/spec/unit/module_spec.rb
index 54f5444ee..f3120e16b 100755
--- a/spec/unit/module_spec.rb
+++ b/spec/unit/module_spec.rb
@@ -1,8 +1,11 @@
#!/usr/bin/env ruby
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+require 'puppet_spec/files'
describe Puppet::Module do
+ include PuppetSpec::Files
+
before do
# This is necessary because of the extra checks we have for the deprecated
# 'plugins' directory
@@ -267,17 +270,39 @@ describe Puppet::Module do
end
it "should return the path to the first found instance in its environment's module paths as its path" do
+ dir = tmpdir("deep_path")
+ first = File.join(dir, "first")
+ second = File.join(dir, "second")
+
+ FileUtils.mkdir_p(first)
+ FileUtils.mkdir_p(second)
+ Puppet[:modulepath] = "#{first}:#{second}"
+
+ modpath = File.join(first, "foo")
+ FileUtils.mkdir_p(modpath)
+
+ # Make a second one, which we shouldn't find
+ FileUtils.mkdir_p(File.join(second, "foo"))
+
mod = Puppet::Module.new("foo")
- env = mock 'environment'
- mod.stubs(:environment).returns env
+ mod.path.should == modpath
+ end
+
+ it "should be able to find itself in a directory other than the first directory in the module path" do
+ dir = tmpdir("deep_path")
+ first = File.join(dir, "first")
+ second = File.join(dir, "second")
- env.expects(:modulepath).returns %w{/a /b /c}
+ FileUtils.mkdir_p(first)
+ FileUtils.mkdir_p(second)
+ Puppet[:modulepath] = "#{first}:#{second}"
- FileTest.expects(:exist?).with("/a/foo").returns false
- FileTest.expects(:exist?).with("/b/foo").returns true
- FileTest.expects(:exist?).with("/c/foo").never
+ modpath = File.join(second, "foo")
+ FileUtils.mkdir_p(modpath)
- mod.path.should == "/b/foo"
+ mod = Puppet::Module.new("foo")
+ mod.should be_exist
+ mod.path.should == modpath
end
it "should be considered existent if it exists in at least one module path" do
diff --git a/spec/unit/network/authconfig_spec.rb b/spec/unit/network/authconfig_spec.rb
index 4367e25e6..9d69e99ac 100755
--- a/spec/unit/network/authconfig_spec.rb
+++ b/spec/unit/network/authconfig_spec.rb
@@ -12,7 +12,7 @@ describe Puppet::Network::AuthConfig do
FileTest.stubs(:exists?).returns(true)
File.stubs(:stat).returns(stub('stat', :ctime => :now))
- Time.stubs(:now).returns :now
+ Time.stubs(:now).returns Time.now
@authconfig = Puppet::Network::AuthConfig.new("dummy", false)
end
diff --git a/spec/unit/network/rest_authconfig_spec.rb b/spec/unit/network/rest_authconfig_spec.rb
index 270d1d094..e0bcb5af0 100755
--- a/spec/unit/network/rest_authconfig_spec.rb
+++ b/spec/unit/network/rest_authconfig_spec.rb
@@ -22,7 +22,7 @@ describe Puppet::Network::RestAuthConfig do
before :each do
FileTest.stubs(:exists?).returns(true)
File.stubs(:stat).returns(stub('stat', :ctime => :now))
- Time.stubs(:now).returns :now
+ Time.stubs(:now).returns Time.now
@authconfig = Puppet::Network::RestAuthConfig.new("dummy", false)
@authconfig.stubs(:read)
diff --git a/spec/unit/node/environment_spec.rb b/spec/unit/node/environment_spec.rb
index 153be5f60..05527e70f 100755
--- a/spec/unit/node/environment_spec.rb
+++ b/spec/unit/node/environment_spec.rb
@@ -6,6 +6,7 @@ require 'puppet/node/environment'
require 'puppet/util/execution'
describe Puppet::Node::Environment do
+ include PuppetSpec::Files
after do
Puppet::Node::Environment.clear
end
@@ -276,16 +277,11 @@ describe Puppet::Node::Environment do
describe "when performing initial import" do
before do
- @parser = stub 'parser', :file= => nil, :string => nil, :parse => nil
+ @parser = stub 'parser'
Puppet::Parser::Parser.stubs(:new).returns @parser
@env = Puppet::Node::Environment.new("env")
end
- it "should create a new parser instance" do
- Puppet::Parser::Parser.expects(:new).returns @parser
- @env.instance_eval { perform_initial_import }
- end
-
it "should set the parser's string to the 'code' setting and parse if code is available" do
Puppet.settings[:code] = "my code"
@parser.expects(:string=).with "my code"
@@ -294,25 +290,26 @@ describe Puppet::Node::Environment do
end
it "should set the parser's file to the 'manifest' setting and parse if no code is available and the manifest is available" do
- File.stubs(:expand_path).with("/my/file").returns "/my/file"
- File.expects(:exist?).with("/my/file").returns true
- Puppet.settings[:manifest] = "/my/file"
- @parser.expects(:file=).with "/my/file"
+ filename = tmpfile('myfile')
+ File.open(filename, 'w'){|f| }
+ Puppet.settings[:manifest] = filename
+ @parser.expects(:file=).with filename
@parser.expects(:parse)
@env.instance_eval { perform_initial_import }
end
- it "should not attempt to load a manifest if none is present" do
- File.stubs(:expand_path).with("/my/file").returns "/my/file"
- File.expects(:exist?).with("/my/file").returns false
- Puppet.settings[:manifest] = "/my/file"
- @parser.expects(:file=).never
- @parser.expects(:parse).never
+ it "should pass the manifest file to the parser even if it does not exist on disk" do
+ filename = tmpfile('myfile')
+ Puppet.settings[:code] = ""
+ Puppet.settings[:manifest] = filename
+ @parser.expects(:file=).with(filename).once
+ @parser.expects(:parse).once
@env.instance_eval { perform_initial_import }
end
it "should fail helpfully if there is an error importing" do
File.stubs(:exist?).returns true
+ @parser.expects(:file=).once
@parser.expects(:parse).raises ArgumentError
lambda { @env.instance_eval { perform_initial_import } }.should raise_error(Puppet::Error)
end
diff --git a/spec/unit/parser/ast/casestatement_spec.rb b/spec/unit/parser/ast/casestatement_spec.rb
index a77c04c43..bce3ad801 100755
--- a/spec/unit/parser/ast/casestatement_spec.rb
+++ b/spec/unit/parser/ast/casestatement_spec.rb
@@ -13,11 +13,14 @@ describe Puppet::Parser::AST::CaseStatement do
@test = stub 'test'
@test.stubs(:safeevaluate).with(@scope).returns("value")
- @option1 = stub 'option1', :eachopt => nil, :default? => false
- @option2 = stub 'option2', :eachopt => nil, :default? => false
+ @option1 = Puppet::Parser::AST::CaseOpt.new({})
+ @option1.stubs(:eachopt)
+ @option1.stubs(:default?).returns false
+ @option2 = Puppet::Parser::AST::CaseOpt.new({})
+ @option2.stubs(:eachopt)
+ @option2.stubs(:default?).returns false
- @options = stub 'options'
- @options.stubs(:each).multiple_yields(@option1, @option2)
+ @options = Puppet::Parser::AST::ASTArray.new(:children => [@option1, @option2])
@casestmt = Puppet::Parser::AST::CaseStatement.new :test => @test, :options => @options
end
@@ -29,8 +32,6 @@ describe Puppet::Parser::AST::CaseStatement do
end
it "should scan each option" do
- @options.expects(:each).multiple_yields(@option1, @option2)
-
@casestmt.evaluate(@scope)
end
@@ -137,12 +138,15 @@ describe Puppet::Parser::AST::CaseStatement do
options = tests.collect do |result, values|
values = values.collect { |v| AST::Leaf.new :value => v }
- AST::CaseOpt.new(
- :value => AST::ASTArray.new(:children => values),
-
- :statements => AST::Leaf.new(:value => result))
+ AST::CaseOpt.new(
+ :value => AST::ASTArray.new(:children => values),
+ :statements => AST::Leaf.new(:value => result)
+ )
end
- options << AST::CaseOpt.new(:value => AST::Default.new(:value => "default"), :statements => AST::Leaf.new(:value => "default"))
+ options << AST::CaseOpt.new(
+ :value => AST::Default.new(:value => "default"),
+ :statements => AST::Leaf.new(:value => "default")
+ )
ast = nil
param = AST::Variable.new(:value => "testparam")
diff --git a/spec/unit/parser/compiler_spec.rb b/spec/unit/parser/compiler_spec.rb
index 18f9a93b6..e4b18e14b 100755
--- a/spec/unit/parser/compiler_spec.rb
+++ b/spec/unit/parser/compiler_spec.rb
@@ -576,18 +576,16 @@ describe Puppet::Parser::Compiler do
proc { @compiler.evaluate_classes(%w{one two}, scope) }.should raise_error(Puppet::DevError)
end
- it "should tag the catalog with the name of each not-found class" do
- @compiler.catalog.expects(:tag).with("notfound")
+ it "should raise an error if a class is not found" do
@scope.expects(:find_hostclass).with("notfound").returns(nil)
- @compiler.evaluate_classes(%w{notfound}, @scope)
+ lambda{ @compiler.evaluate_classes(%w{notfound}, @scope) }.should raise_error(Puppet::Error, /Could not find class/)
end
- # I wish it would fail
- it "should log when it can't find class" do
+
+ it "should raise an error when it can't find class" do
klasses = {'foo'=>nil}
@node.classes = klasses
@compiler.topscope.stubs(:find_hostclass).with('foo').returns(nil)
- Puppet.expects(:info).with('Could not find class foo for testnode')
- @compiler.compile
+ lambda{ @compiler.compile }.should raise_error(Puppet::Error, /Could not find class foo for testnode/)
end
end
@@ -714,18 +712,6 @@ describe Puppet::Parser::Compiler do
Puppet::Parser::Resource.expects(:new).never
@compiler.evaluate_classes(%w{MyClass}, @scope, false)
end
-
- it "should return the list of found classes" do
- @compiler.catalog.stubs(:tag)
-
- @compiler.stubs(:add_resource)
- @scope.stubs(:find_hostclass).with("notfound").returns(nil)
- @scope.stubs(:class_scope).with(@class)
-
- Puppet::Parser::Resource.stubs(:new).returns(@resource)
- @class.stubs :ensure_in_catalog
- @compiler.evaluate_classes(%w{myclass notfound}, @scope).should == %w{myclass}
- end
end
describe "when evaluating AST nodes with no AST nodes present" do
diff --git a/spec/unit/parser/functions/create_resources_spec.rb b/spec/unit/parser/functions/create_resources_spec.rb
new file mode 100755
index 000000000..d4095b777
--- /dev/null
+++ b/spec/unit/parser/functions/create_resources_spec.rb
@@ -0,0 +1,135 @@
+require 'puppet'
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe 'function for dynamically creating resources' do
+
+ def get_scope
+ @topscope = Puppet::Parser::Scope.new
+ # This is necessary so we don't try to use the compiler to discover our parent.
+ @topscope.parent = nil
+ @scope = Puppet::Parser::Scope.new
+ @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
+ @scope.parent = @topscope
+ @compiler = @scope.compiler
+ end
+ before :each do
+ get_scope
+ Puppet::Parser::Functions.function(:create_resources)
+ end
+
+ it "should exist" do
+ Puppet::Parser::Functions.function(:create_resources).should == "function_create_resources"
+ end
+ it 'should require two arguments' do
+ lambda { @scope.function_create_resources(['foo']) }.should raise_error(ArgumentError, 'create_resources(): wrong number of arguments (1; must be 2)')
+ end
+ describe 'when creating native types' do
+ before :each do
+ Puppet[:code]='notify{test:}'
+ get_scope
+ @scope.resource=Puppet::Parser::Resource.new('class', 't', :scope => @scope)
+ end
+ it 'empty hash should not cause resources to be added' do
+ @scope.function_create_resources(['file', {}])
+ @compiler.catalog.resources.size == 1
+ end
+ it 'should be able to add' do
+ @scope.function_create_resources(['file', {'/etc/foo'=>{'ensure'=>'present'}}])
+ @compiler.catalog.resource(:file, "/etc/foo")['ensure'].should == 'present'
+ end
+ it 'should accept multiple types' do
+ type_hash = {}
+ type_hash['foo'] = {'message' => 'one'}
+ type_hash['bar'] = {'message' => 'two'}
+ @scope.function_create_resources(['notify', type_hash])
+ @compiler.catalog.resource(:notify, "foo")['message'].should == 'one'
+ @compiler.catalog.resource(:notify, "bar")['message'].should == 'two'
+ end
+ it 'should fail to add non-existing type' do
+ lambda { @scope.function_create_resources(['foo', {}]) }.should raise_error(ArgumentError, 'could not create resource of unknown type foo')
+ end
+ it 'should be able to add edges' do
+ @scope.function_create_resources(['notify', {'foo'=>{'require' => 'Notify[test]'}}])
+ @scope.compiler.compile
+ edge = @scope.compiler.catalog.to_ral.relationship_graph.edges.detect do |edge|
+ edge.source.title == 'test'
+ end
+ edge.source.title.should == 'test'
+ edge.target.title.should == 'foo'
+ end
+ end
+ describe 'when dynamically creating resource types' do
+ before :each do
+ Puppet[:code]=
+'define foo($one){notify{$name: message => $one}}
+notify{test:}
+'
+ get_scope
+ @scope.resource=Puppet::Parser::Resource.new('class', 't', :scope => @scope)
+ Puppet::Parser::Functions.function(:create_resources)
+ end
+ it 'should be able to create defined resoure types' do
+ @scope.function_create_resources(['foo', {'blah'=>{'one'=>'two'}}])
+ # still have to compile for this to work...
+ # I am not sure if this constraint ruins the tests
+ @scope.compiler.compile
+ @compiler.catalog.resource(:notify, "blah")['message'].should == 'two'
+ end
+ it 'should fail if defines are missing params' do
+ @scope.function_create_resources(['foo', {'blah'=>{}}])
+ lambda { @scope.compiler.compile }.should raise_error(Puppet::ParseError, 'Must pass one to Foo[blah] at line 1')
+ end
+ it 'should be able to add multiple defines' do
+ hash = {}
+ hash['blah'] = {'one' => 'two'}
+ hash['blaz'] = {'one' => 'three'}
+ @scope.function_create_resources(['foo', hash])
+ # still have to compile for this to work...
+ # I am not sure if this constraint ruins the tests
+ @scope.compiler.compile
+ @compiler.catalog.resource(:notify, "blah")['message'].should == 'two'
+ @compiler.catalog.resource(:notify, "blaz")['message'].should == 'three'
+ end
+ it 'should be able to add edges' do
+ @scope.function_create_resources(['foo', {'blah'=>{'one'=>'two', 'require' => 'Notify[test]'}}])
+ @scope.compiler.compile
+ edge = @scope.compiler.catalog.to_ral.relationship_graph.edges.detect do |edge|
+ edge.source.title == 'test'
+ end
+ edge.source.title.should == 'test'
+ edge.target.title.should == 'blah'
+ @compiler.catalog.resource(:notify, "blah")['message'].should == 'two'
+ end
+ end
+ describe 'when creating classes' do
+ before :each do
+ Puppet[:code]=
+'class bar($one){notify{test: message => $one}}
+notify{tester:}
+'
+ get_scope
+ @scope.resource=Puppet::Parser::Resource.new('class', 't', :scope => @scope)
+ Puppet::Parser::Functions.function(:create_resources)
+ end
+ it 'should be able to create classes' do
+ @scope.function_create_resources(['class', {'bar'=>{'one'=>'two'}}])
+ @scope.compiler.compile
+ @compiler.catalog.resource(:notify, "test")['message'].should == 'two'
+ @compiler.catalog.resource(:class, "bar").should_not be_nil#['message'].should == 'two'
+ end
+ it 'should fail to create non-existing classes' do
+ lambda { @scope.function_create_resources(['class', {'blah'=>{'one'=>'two'}}]) }.should raise_error(ArgumentError ,'could not find hostclass blah')
+ end
+ it 'should be able to add edges' do
+ @scope.function_create_resources(['class', {'bar'=>{'one'=>'two', 'require' => 'Notify[tester]'}}])
+ @scope.compiler.compile
+ edge = @scope.compiler.catalog.to_ral.relationship_graph.edges.detect do |e|
+ e.source.title == 'tester'
+ end
+ edge.source.title.should == 'tester'
+ edge.target.title.should == 'test'
+ #@compiler.catalog.resource(:notify, "blah")['message'].should == 'two'
+ end
+
+ end
+end
diff --git a/spec/unit/parser/lexer_spec.rb b/spec/unit/parser/lexer_spec.rb
index 96df61348..bc9e22e48 100755
--- a/spec/unit/parser/lexer_spec.rb
+++ b/spec/unit/parser/lexer_spec.rb
@@ -676,3 +676,15 @@ describe "Puppet::Parser::Lexer in the old tests when lexing example files" do
end
end
end
+
+describe "when trying to lex an non-existent file" do
+ include PuppetSpec::Files
+
+ it "should return an empty list of tokens" do
+ lexer = Puppet::Parser::Lexer.new
+ lexer.file = nofile = tmpfile('lexer')
+ File.exists?(nofile).should == false
+
+ lexer.fullscan.should == [[false,false]]
+ end
+end
diff --git a/spec/unit/parser/type_loader_spec.rb b/spec/unit/parser/type_loader_spec.rb
index bd41adfb6..12bc1ccd6 100644
--- a/spec/unit/parser/type_loader_spec.rb
+++ b/spec/unit/parser/type_loader_spec.rb
@@ -93,6 +93,103 @@ describe Puppet::Parser::TypeLoader do
end
end
+ describe "when importing all" do
+ before do
+ @base = tmpdir("base")
+
+ # Create two module path directories
+ @modulebase1 = File.join(@base, "first")
+ FileUtils.mkdir_p(@modulebase1)
+ @modulebase2 = File.join(@base, "second")
+ FileUtils.mkdir_p(@modulebase2)
+
+ Puppet[:modulepath] = "#{@modulebase1}:#{@modulebase2}"
+ end
+
+ def mk_module(basedir, name)
+ module_dir = File.join(basedir, name)
+
+ # Go ahead and make our manifest directory
+ FileUtils.mkdir_p(File.join(module_dir, "manifests"))
+
+ return Puppet::Module.new(name)
+ end
+
+ # We have to pass the base path so that we can
+ # write to modules that are in the second search path
+ def mk_manifests(base, mod, type, files)
+ exts = {"ruby" => ".rb", "puppet" => ".pp"}
+ files.collect do |file|
+ name = mod.name + "::" + file.gsub("/", "::")
+ path = File.join(base, mod.name, "manifests", file + exts[type])
+ FileUtils.mkdir_p(File.split(path)[0])
+
+ # write out the class
+ if type == "ruby"
+ File.open(path, "w") { |f| f.print "hostclass '#{name}' do\nend" }
+ else
+ File.open(path, "w") { |f| f.print "class #{name} {}" }
+ end
+ name
+ end
+ end
+
+ it "should load all puppet manifests from all modules in the specified environment" do
+ @module1 = mk_module(@modulebase1, "one")
+ @module2 = mk_module(@modulebase2, "two")
+
+ mk_manifests(@modulebase1, @module1, "puppet", %w{a b})
+ mk_manifests(@modulebase2, @module2, "puppet", %w{c d})
+
+ @loader.import_all
+
+ @loader.environment.known_resource_types.hostclass("one::a").should be_instance_of(Puppet::Resource::Type)
+ @loader.environment.known_resource_types.hostclass("one::b").should be_instance_of(Puppet::Resource::Type)
+ @loader.environment.known_resource_types.hostclass("two::c").should be_instance_of(Puppet::Resource::Type)
+ @loader.environment.known_resource_types.hostclass("two::d").should be_instance_of(Puppet::Resource::Type)
+ end
+
+ it "should load all ruby manifests from all modules in the specified environment" do
+ @module1 = mk_module(@modulebase1, "one")
+ @module2 = mk_module(@modulebase2, "two")
+
+ mk_manifests(@modulebase1, @module1, "ruby", %w{a b})
+ mk_manifests(@modulebase2, @module2, "ruby", %w{c d})
+
+ @loader.import_all
+
+ @loader.environment.known_resource_types.hostclass("one::a").should be_instance_of(Puppet::Resource::Type)
+ @loader.environment.known_resource_types.hostclass("one::b").should be_instance_of(Puppet::Resource::Type)
+ @loader.environment.known_resource_types.hostclass("two::c").should be_instance_of(Puppet::Resource::Type)
+ @loader.environment.known_resource_types.hostclass("two::d").should be_instance_of(Puppet::Resource::Type)
+ end
+
+ it "should not load manifests from duplicate modules later in the module path" do
+ @module1 = mk_module(@modulebase1, "one")
+
+ # duplicate
+ @module2 = mk_module(@modulebase2, "one")
+
+ mk_manifests(@modulebase1, @module1, "puppet", %w{a})
+ mk_manifests(@modulebase2, @module2, "puppet", %w{c})
+
+ @loader.import_all
+
+ @loader.environment.known_resource_types.hostclass("one::c").should be_nil
+ end
+
+ it "should load manifests from subdirectories" do
+ @module1 = mk_module(@modulebase1, "one")
+
+ mk_manifests(@modulebase1, @module1, "puppet", %w{a a/b a/b/c})
+
+ @loader.import_all
+
+ @loader.environment.known_resource_types.hostclass("one::a::b").should be_instance_of(Puppet::Resource::Type)
+ @loader.environment.known_resource_types.hostclass("one::a::b::c").should be_instance_of(Puppet::Resource::Type)
+ end
+ end
+
describe "when parsing a file" do
before do
@parser = Puppet::Parser::Parser.new(@loader.environment)
diff --git a/spec/unit/provider/augeas/augeas_spec.rb b/spec/unit/provider/augeas/augeas_spec.rb
index 9fcc85660..c65f39097 100644
--- a/spec/unit/provider/augeas/augeas_spec.rb
+++ b/spec/unit/provider/augeas/augeas_spec.rb
@@ -433,5 +433,59 @@ describe provider_class do
@augeas.expects(:close)
@provider.execute_changes.should == :executed
end
+
+ it "should handle defvar commands" do
+ command = "defvar myjar Jar/Jar"
+ context = "/foo/"
+ @resource.expects(:[]).times(2).returns(command).then.returns(context)
+ @augeas.expects(:defvar).with("myjar", "/foo/Jar/Jar").returns(true)
+ @augeas.expects(:save).returns(true)
+ @augeas.expects(:close)
+ @provider.execute_changes.should == :executed
+ end
+
+ it "should pass through augeas variables without context" do
+ command = ["defvar myjar Jar/Jar","set $myjar/Binks 1"]
+ context = "/foo/"
+ @resource.expects(:[]).times(2).returns(command).then.returns(context)
+ @augeas.expects(:defvar).with("myjar", "/foo/Jar/Jar").returns(true)
+ # this is the important bit, shouldn't be /foo/$myjar/Binks
+ @augeas.expects(:set).with("$myjar/Binks", "1").returns(true)
+ @augeas.expects(:save).returns(true)
+ @augeas.expects(:close)
+ @provider.execute_changes.should == :executed
+ end
+
+ it "should handle defnode commands" do
+ command = "defnode newjar Jar/Jar[last()+1] Binks"
+ context = "/foo/"
+ @resource.expects(:[]).times(2).returns(command).then.returns(context)
+ @augeas.expects(:defnode).with("newjar", "/foo/Jar/Jar[last()+1]", "Binks").returns(true)
+ @augeas.expects(:save).returns(true)
+ @augeas.expects(:close)
+ @provider.execute_changes.should == :executed
+ end
+
+ it "should handle mv commands" do
+ command = "mv Jar/Jar Binks"
+ context = "/foo/"
+ @resource.expects(:[]).times(2).returns(command).then.returns(context)
+ @augeas.expects(:mv).with("/foo/Jar/Jar", "/foo/Binks").returns(true)
+ @augeas.expects(:save).returns(true)
+ @augeas.expects(:close)
+ @provider.execute_changes.should == :executed
+ end
+
+ it "should handle setm commands" do
+ command = ["set test[1]/Jar/Jar Foo","set test[2]/Jar/Jar Bar","setm test Jar/Jar Binks"]
+ context = "/foo/"
+ @resource.expects(:[]).times(2).returns(command).then.returns(context)
+ @augeas.expects(:set).with("/foo/test[1]/Jar/Jar", "Foo").returns(true)
+ @augeas.expects(:set).with("/foo/test[2]/Jar/Jar", "Bar").returns(true)
+ @augeas.expects(:setm).with("/foo/test", "Jar/Jar", "Binks").returns(true)
+ @augeas.expects(:save).returns(true)
+ @augeas.expects(:close)
+ @provider.execute_changes.should == :executed
+ end
end
end
diff --git a/spec/unit/provider/service/debian_spec.rb b/spec/unit/provider/service/debian_spec.rb
index 8c9522deb..b5edf6882 100755
--- a/spec/unit/provider/service/debian_spec.rb
+++ b/spec/unit/provider/service/debian_spec.rb
@@ -52,8 +52,20 @@ describe provider_class do
end
describe "when disabling" do
- it "should call update-rc.d twice" do
- @provider.expects(:update_rc).twice
+ it "should be able to disable services with newer sysv-rc versions" do
+ @provider.stubs(:`).with("dpkg --compare-versions $(dpkg-query -W --showformat '${Version}' sysv-rc) ge 2.88 ; echo $?").returns "0"
+
+ @provider.expects(:update_rc).with(@resource[:name], "disable")
+
+ @provider.disable
+ end
+
+ it "should be able to enable services with older sysv-rc versions" do
+ @provider.stubs(:`).with("dpkg --compare-versions $(dpkg-query -W --showformat '${Version}' sysv-rc) ge 2.88 ; echo $?").returns "1"
+
+ @provider.expects(:update_rc).with("-f", @resource[:name], "remove")
+ @provider.expects(:update_rc).with(@resource[:name], "stop", "00", "1", "2", "3", "4", "5", "6", ".")
+
@provider.disable
end
end
diff --git a/spec/unit/provider/service/smf_spec.rb b/spec/unit/provider/service/smf_spec.rb
new file mode 100755
index 000000000..40e96ab23
--- /dev/null
+++ b/spec/unit/provider/service/smf_spec.rb
@@ -0,0 +1,137 @@
+#!/usr/bin/env ruby
+#
+# Unit testing for the SMF service Provider
+#
+# author Dominic Cleal
+#
+require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
+
+provider_class = Puppet::Type.type(:service).provider(:smf)
+
+describe provider_class do
+
+ before(:each) do
+ # Create a mock resource
+ @resource = Puppet::Type.type(:service).new(
+ :name => "/system/myservice", :ensure => :running, :enable => :true)
+ @provider = provider_class.new(@resource)
+
+ FileTest.stubs(:file?).with('/usr/sbin/svcadm').returns true
+ FileTest.stubs(:executable?).with('/usr/sbin/svcadm').returns true
+ FileTest.stubs(:file?).with('/usr/bin/svcs').returns true
+ FileTest.stubs(:executable?).with('/usr/bin/svcs').returns true
+ end
+
+ it "should have a restart method" do
+ @provider.should respond_to(:restart)
+ end
+
+ it "should have a restartcmd method" do
+ @provider.should respond_to(:restartcmd)
+ end
+
+ it "should have a start method" do
+ @provider.should respond_to(:start)
+ end
+
+ it "should have a stop method" do
+ @provider.should respond_to(:stop)
+ end
+
+ it "should have an enabled? method" do
+ @provider.should respond_to(:enabled?)
+ end
+
+ it "should have an enable method" do
+ @provider.should respond_to(:enable)
+ end
+
+ it "should have a disable method" do
+ @provider.should respond_to(:disable)
+ end
+
+ describe "when checking status" do
+ it "should call the external command 'svcs /system/myservice' once" do
+ @provider.expects(:svcs).with('-H', '-o', 'state,nstate', "/system/myservice").returns("online\t-")
+ @provider.status
+ end
+ it "should return stopped if svcs can't find the service" do
+ @provider.stubs(:svcs).raises(Puppet::ExecutionFailure.new("no svc found"))
+ @provider.status.should == :stopped
+ end
+ it "should return running if online in svcs output" do
+ @provider.stubs(:svcs).returns("online\t-")
+ @provider.status.should == :running
+ end
+ it "should return stopped if disabled in svcs output" do
+ @provider.stubs(:svcs).returns("disabled\t-")
+ @provider.status.should == :stopped
+ end
+ it "should return maintenance if in maintenance in svcs output" do
+ @provider.stubs(:svcs).returns("maintenance\t-")
+ @provider.status.should == :maintenance
+ end
+ it "should return target state if transitioning in svcs output" do
+ @provider.stubs(:svcs).returns("online\tdisabled")
+ @provider.status.should == :stopped
+ end
+ it "should throw error if it's a legacy service in svcs output" do
+ @provider.stubs(:svcs).returns("legacy_run\t-")
+ lambda { @provider.status }.should raise_error(Puppet::Error, "Cannot manage legacy services through SMF")
+ end
+ end
+
+ describe "when starting" do
+ it "should enable the service if it is not enabled" do
+ @provider.expects(:status).returns :stopped
+ @provider.expects(:texecute)
+ @provider.start
+ end
+
+ it "should always execute external command 'svcadm enable /system/myservice'" do
+ @provider.stubs(:status).returns :running
+ @provider.expects(:texecute).with(:start, ["/usr/sbin/svcadm", :enable, "/system/myservice"], true)
+ @provider.start
+ end
+
+ it "should execute external command 'svcadm clear /system/myservice' if in maintenance" do
+ @provider.stubs(:status).returns :maintenance
+ @provider.expects(:texecute).with(:start, ["/usr/sbin/svcadm", :clear, "/system/myservice"], true)
+ @provider.start
+ end
+ end
+
+ describe "when starting a service with a manifest" do
+ before(:each) do
+ @resource = Puppet::Type.type(:service).new(:name => "/system/myservice", :ensure => :running, :enable => :true, :manifest => "/tmp/myservice.xml")
+ @provider = provider_class.new(@resource)
+ $CHILD_STATUS.stubs(:exitstatus).returns(1)
+ end
+
+ it "should import the manifest if service is missing" do
+ @provider.expects(:svccfg).with(:import, "/tmp/myservice.xml")
+ @provider.expects(:texecute).with(:start, ["/usr/sbin/svcadm", :enable, "/system/myservice"], true)
+ @provider.start
+ end
+
+ it "should handle failures if importing a manifest" do
+ @provider.expects(:svccfg).raises(Puppet::ExecutionFailure.new("can't svccfg import"))
+ lambda { @provider.start }.should raise_error(Puppet::Error, "Cannot config /system/myservice to enable it: can't svccfg import")
+ end
+ end
+
+ describe "when stopping" do
+ it "should execute external command 'svcadm disable /system/myservice'" do
+ @provider.expects(:texecute).with(:stop, ["/usr/sbin/svcadm", :disable, "/system/myservice"], true)
+ @provider.stop
+ end
+ end
+
+ describe "when restarting" do
+ it "should call 'svcadm restart /system/myservice'" do
+ @provider.expects(:texecute).with(:restart, ["/usr/sbin/svcadm", :restart, "/system/myservice"], true)
+ @provider.restart
+ end
+ end
+
+end
diff --git a/spec/unit/provider/zfs/solaris_spec.rb b/spec/unit/provider/zfs/solaris_spec.rb
index 4998ba6fe..84a2be9f6 100755
--- a/spec/unit/provider/zfs/solaris_spec.rb
+++ b/spec/unit/provider/zfs/solaris_spec.rb
@@ -27,6 +27,7 @@ describe provider_class do
describe "when calling add_properties" do
it "should add -o and the key=value for each properties with a value" do
@resource.stubs(:[]).with(:quota).returns ""
+ @resource.stubs(:[]).with(:refquota).returns ""
@resource.stubs(:[]).with(:mountpoint).returns "/foo"
properties = @provider.add_properties
properties.include?("-o").should == true
diff --git a/spec/unit/resource/type_spec.rb b/spec/unit/resource/type_spec.rb
index e9c203526..41b5554d9 100755
--- a/spec/unit/resource/type_spec.rb
+++ b/spec/unit/resource/type_spec.rb
@@ -55,12 +55,24 @@ describe Puppet::Resource::Type do
double_convert.arguments.should == {"one" => nil, "two" => "foo"}
end
- it "should include any extra attributes" do
- @type.file = "/my/file"
- @type.line = 50
+ it "should not include arguments if none are present" do
+ @type.to_pson["arguments"].should be_nil
+ end
+
+ [:line, :doc, :file, :parent].each do |attr|
+ it "should include #{attr} when set" do
+ @type.send(attr.to_s + "=", "value")
+ double_convert.send(attr).should == "value"
+ end
+
+ it "should not include #{attr} when not set" do
+ @type.to_pson[attr.to_s].should be_nil
+ end
+ end
- double_convert.file.should == "/my/file"
- double_convert.line.should == 50
+ it "should not include docs if they are empty" do
+ @type.doc = ""
+ @type.to_pson["doc"].should be_nil
end
end
diff --git a/spec/unit/type/exec_spec.rb b/spec/unit/type/exec_spec.rb
index a1ffb1636..86b824423 100755
--- a/spec/unit/type/exec_spec.rb
+++ b/spec/unit/type/exec_spec.rb
@@ -307,7 +307,7 @@ describe Puppet::Type.type(:exec) do
end
describe "when setting timeout" do
- [-3.5, -1, 0, 0.1, 1, 10, 4294967295].each do |valid|
+ [0, 0.1, 1, 10, 4294967295].each do |valid|
it "should accept '#{valid}' as valid" do
@exec[:timeout] = valid
@exec[:timeout].should == valid
@@ -319,7 +319,7 @@ describe Puppet::Type.type(:exec) do
end
end
- ['1/2', '1_000_000', '+12', '', 'foo'].each do |invalid|
+ ['1/2', '', 'foo', '5foo'].each do |invalid|
it "should reject '#{invalid}' as invalid" do
expect { @exec[:timeout] = invalid }.
should raise_error Puppet::Error, /The timeout must be a number/
@@ -337,6 +337,18 @@ describe Puppet::Type.type(:exec) do
sleep_exec = Puppet::Type.type(:exec).new(:name => 'sleep 1', :path => ['/bin'], :timeout => '0.2')
lambda { sleep_exec.refresh }.should raise_error Puppet::Error, "Command exceeded timeout"
end
+
+ it "should convert timeout to a float" do
+ resource = Puppet::Type.type(:exec).new :command => "/bin/false", :timeout => "12"
+ resource[:timeout].should be_a(Float)
+ resource[:timeout].should == 12.0
+ end
+
+ it "should munge negative timeouts to 0.0" do
+ resource = Puppet::Type.type(:exec).new :command => "/bin/false", :timeout => "-12.0"
+ resource.parameter(:timeout).value.should be_a(Float)
+ resource.parameter(:timeout).value.should == 0.0
+ end
end
describe "when setting tries" do
diff --git a/spec/unit/util/loadedfile_spec.rb b/spec/unit/util/loadedfile_spec.rb
index 23d2766d7..92daeb953 100755
--- a/spec/unit/util/loadedfile_spec.rb
+++ b/spec/unit/util/loadedfile_spec.rb
@@ -6,6 +6,7 @@ require 'tempfile'
require 'puppet/util/loadedfile'
describe Puppet::Util::LoadedFile do
+ include PuppetSpec::Files
before(:each) do
@f = Tempfile.new('loadedfile_test')
@f.puts "yayness"
@@ -18,6 +19,12 @@ describe Puppet::Util::LoadedFile do
@fake_now = Time.now + (2 * Puppet[:filetimeout])
end
+ it "should accept files that don't exist" do
+ nofile = tmpfile('testfile')
+ File.exists?(nofile).should == false
+ lambda{ Puppet::Util::LoadedFile.new(nofile) }.should_not raise_error
+ end
+
it "should recognize when the file has not changed" do
# Use fake "now" so that we can be sure changed? actually checks, without sleeping
# for Puppet[:filetimeout] seconds.
diff --git a/spec/unit/util/rdoc/parser_spec.rb b/spec/unit/util/rdoc/parser_spec.rb
index ab54c8cd3..f118dc99b 100755
--- a/spec/unit/util/rdoc/parser_spec.rb
+++ b/spec/unit/util/rdoc/parser_spec.rb
@@ -20,8 +20,9 @@ describe RDoc::Parser do
@parser.stubs(:scan_top_level)
parser = stub 'parser'
Puppet::Parser::Parser.stubs(:new).returns(parser)
- parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new(''))
+ parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')).at_least_once
parser.expects(:file=).with("module/manifests/init.pp")
+ parser.expects(:file=).with("/dev/null/manifests/site.pp")
@parser.scan
end
@@ -29,7 +30,7 @@ describe RDoc::Parser do
it "should scan the ast for Puppet files" do
parser = stub_everything 'parser'
Puppet::Parser::Parser.stubs(:new).returns(parser)
- parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new(''))
+ parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')).at_least_once
@parser.expects(:scan_top_level)
@@ -39,7 +40,7 @@ describe RDoc::Parser do
it "should return a PuppetTopLevel to RDoc" do
parser = stub_everything 'parser'
Puppet::Parser::Parser.stubs(:new).returns(parser)
- parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new(''))
+ parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')).at_least_once
@parser.expects(:scan_top_level)
diff --git a/tasks/rake/git_workflow.rake b/tasks/rake/git_workflow.rake
index 75dc8833a..56a414568 100644
--- a/tasks/rake/git_workflow.rake
+++ b/tasks/rake/git_workflow.rake
@@ -119,12 +119,14 @@ task :mail_patches do
# If we've got more than one patch, add --compose
if files.length > 1
compose = "--compose"
+ subject = "--subject \"#{type} #{name} against #{parent}\""
else
compose = ""
+ subject = ""
end
# Now send the mail.
- sh "git send-email #{compose} --no-signed-off-by-cc --suppress-from --to puppet-dev@googlegroups.com 00*.patch"
+ sh "git send-email #{compose} #{subject} --no-signed-off-by-cc --suppress-from --to puppet-dev@googlegroups.com 00*.patch"
# Finally, clean up the patches
sh "rm 00*.patch"
diff --git a/test/language/functions.rb b/test/language/functions.rb
index 3c27f2b2b..e882b68f3 100755
--- a/test/language/functions.rb
+++ b/test/language/functions.rb
@@ -447,7 +447,7 @@ class TestLangFunctions < Test::Unit::TestCase
include = Puppet::Parser::Functions.function(:include)
- assert_raise(Puppet::ParseError, "did not throw error on missing class") do
+ assert_raise(Puppet::Error, "did not throw error on missing class") do
scope.function_include("nosuchclass")
end