summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Robinson <matt@puppetlabs.com>2011-08-15 10:36:03 -0700
committerMatt Robinson <matt@puppetlabs.com>2011-08-15 10:36:03 -0700
commite7d5c7c1cd4109d7bb061a503f5da8777a1be66d (patch)
tree6aace815f8c3fe30d4ad7eefbda8af141b78482f
parenta71573cb32f01e5bf5f1a5030c6a291ce5b63370 (diff)
parentfa1ec4dd93f015c2943271c9ae107991c6d3c90e (diff)
downloadpuppet-e7d5c7c1cd4109d7bb061a503f5da8777a1be66d.tar.gz
Merge branch '2.7.x'
* 2.7.x: (25 commits) (#4411) Explain that runinterval = 0 does not mean "never run" Maint: Fix missing option text in puppet agent and arrange options alphabetically (#8302) Improve documentation of exec providers (#7853) Clarify and complete docs for the tagmail report processor Maint: Mention that audit metaparameter will accept "all" Maint: Adjust wording for file type's content parameter Maint: Fix poor documentation for versioncmp function. maint: Fix case sensitive require maint: Add inspect app options to help maint: Fix inspect help Increment lib/puppet.rb VERSION string Updated CHANGELOG for 2.7.3rc1 (#4762) Ensure that clients on the moon can successfully connect. Add document outlining preferred contribution methods Add document outlining preferred contribution methods Add document outlining preferred contribution methods Revert "Merge branch 'vcsrepo'" Revert "Merge branch 'vcsrepo'" Updating CHANGELOG for 2.7.2rc3 (#8704) Give better errors for invalid fileserver.conf ... Manually Resolved Conflicts: lib/puppet/parser/functions/versioncmp.rb spec/integration/node/facts_spec.rb
-rw-r--r--CHANGELOG66
-rw-r--r--lib/puppet.rb2
-rw-r--r--lib/puppet/application.rb9
-rw-r--r--lib/puppet/application/agent.rb58
-rw-r--r--lib/puppet/application/inspect.rb10
-rw-r--r--lib/puppet/defaults.rb5
-rw-r--r--lib/puppet/face/ca.rb30
-rw-r--r--lib/puppet/face/node/clean.rb154
-rw-r--r--lib/puppet/indirector/report/processor.rb45
-rw-r--r--lib/puppet/indirector/yaml.rb5
-rw-r--r--lib/puppet/interface/action.rb2
-rwxr-xr-xlib/puppet/network/handler/fileserver.rb3
-rw-r--r--lib/puppet/network/http/webrick.rb2
-rw-r--r--lib/puppet/parser/functions/versioncmp.rb18
-rw-r--r--lib/puppet/provider/exec/posix.rb9
-rw-r--r--lib/puppet/provider/exec/shell.rb13
-rw-r--r--lib/puppet/provider/vcsrepo.rb34
-rw-r--r--lib/puppet/provider/vcsrepo/bzr.rb64
-rw-r--r--lib/puppet/provider/vcsrepo/cvs.rb80
-rw-r--r--lib/puppet/provider/vcsrepo/git.rb264
-rw-r--r--lib/puppet/provider/vcsrepo/hg.rb101
-rw-r--r--lib/puppet/provider/vcsrepo/svn.rb82
-rw-r--r--lib/puppet/reports/store.rb15
-rw-r--r--lib/puppet/reports/tagmail.rb26
-rw-r--r--lib/puppet/type.rb2
-rwxr-xr-xlib/puppet/type/file/content.rb10
-rw-r--r--lib/puppet/type/vcsrepo.rb138
-rwxr-xr-xspec/unit/application/apply_spec.rb2
-rwxr-xr-xspec/unit/application_spec.rb4
-rwxr-xr-xspec/unit/face/node_spec.rb262
-rwxr-xr-xspec/unit/indirector/report/processor_spec.rb27
-rwxr-xr-xspec/unit/indirector/yaml_spec.rb18
-rwxr-xr-xspec/unit/interface/action_spec.rb8
-rwxr-xr-xspec/unit/network/handler/fileserver_spec.rb32
34 files changed, 730 insertions, 870 deletions
diff --git a/CHANGELOG b/CHANGELOG
index de4c5addd..04641088f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,10 +1,68 @@
-2.7.2rc2
+2.7.3rc1
===
-8ec0804 (#8301) Red Hat spec file for 2.7.2rc1 won't work
-2263be6 (#5108) Update service type docs for new hasstatus default
+7113448 (#4762) Ensure that clients on the moon can successfully connect.
+c8835ad Add document outlining preferred contribution methods
+b85f57c Add document outlining preferred contribution methods
+ea0f2bf Revert "Merge branch 'vcsrepo'"
+a5716e4 Revert "Merge branch 'vcsrepo'"
+94f0b93 (#8704) Give better errors for invalid fileserver.conf
+38801dd (Maint.) Disable cleaning of storeconfigs.
+023d959 (#8690) Accept 'global' options in Puppet Faces
+bff817c (Maint.) Fix spec failures related to leaking state.
+ccd622a (#1886) Clean up `node clean` for merge.
+c315da0 Fix #1886 - Add node cleanup capability
+7e6fc0d Deprecate RestAuthConfig#allowed? in favor of #check_authorization
+6401dfe Fix #6026 - security file should support inline comments
+0c385f1 Fix #5010 - Allow leading whitespace in auth.conf
+8da0486 Fix #5777 - rule interpolation broke auth.conf CIDR rules
+1d4acb5 maint: Suggest where to start troubleshooting SSL error message
+fb2ffd6 (#8596) Detect resource alias conflicts when titles do not match
+778127d maint: Fix cert app to print help and exit if no subcommand
+0366b18 (#7293) Set default format for SSL-related faces.
+cc2c3ed (Maint.) Unquoting HEREDOCs.
+89c021c (#8418) Fix inspect app to have the correct run_mode
+3165364 maint: Adding logging to include environment when source fails
+f484851 maint: Add debug logging when the master receives a report
+10e05ad (#7266) Move Certificate option validation into face.
+d522b0b maint: Fix Face testing bug 1.9.2 revealed.
+ae36003 (#7290) Update indirected Faces to avoid unknown options.
+88e9cd2 maint: don't print inside action implementations.
+82e5fa9 (#8561, #7290) Implement the option contract fully.
+77441be (#8561) Unify validation and modification of action arguments.
+69b4e70 (#7290) Fail on unknown options.
+6bec2df (#8561) Use canonical names for options to actions.
+532c4f3 (#7184) Load the core of obsolete versions of Faces.
+2cd3bc4 (#7184) Find actions bound to other versions of Faces.
+1e0655e (#7184) Centralize "find action for face" into Puppet::Face
+0396611 maint: better error reporting when test fails
+e639868 Confine password disclosure acceptance test to hosts with required libraries
+395c174 (#7123) Make `find` the default action...
+fd6a653 (#7123) Support runtime setting of 'default' on actions.
+b75b1c1 (#6787) Add `default_to` for options.
+8820a78 Replace calls to Array#count with #length
+bdd6a17 Fix order-dependent test failure in certificate_status/file spec
+c830ab0 (#6789) Port SSL::CertificateAuthority::Interface to a Face
+cc311ad maint: SSL::Inventory.serial should report missing names.
+72abe6c (#7204) Consolidate Semantic Versioning code.
+d02000b (#8401) Document that --detailed-exitcodes is a bitmask
+a109c90 (maint) Cleanup and strengthen acceptance tests
+c4848d2 maint: Fix documentation link for fileserver configuration
+b268fb3 (#7144) Update Settings#writesub to convert mode to Fixnum
+b82f29c (#7699) Help command should only list options once
+4a2f22c (maint) Fix platform dection for RHEL
+45b3908 (#4142) Fix module check not to fail when empty metadata.json
+1feccc3 Revert "Merge branch 'ticket/2.7.x/7699_fix_help_listing_options_twice' into 2.7.x"
+ae3ef42 (#7699) - Help should only show options once
+5826f73 (#8032) Add containment to create_resources
+98cd89b (#8147) Update test for default reporturl
+f6882d6 (#8147) Change default reporturl to match newer Dashboard versions
+111a4b5 (#6857) Password disclosure when changing a user's password
-2.7.2rc1
+2.7.2rc series (never released)
===
+Fix cross branch confusion on 2.7.2rc2
+8ec0804 (#8301) Red Hat spec file for 2.7.2rc1 won't work
+2263be6 (#5108) Update service type docs for new hasstatus default
902c414 Update configurer_spec.rb to work with Ruby 1.8.5
7ad1b04 Clean up indentation, whitespace, and commented out code
014d952 Remove order dependency from functions integration spec
diff --git a/lib/puppet.rb b/lib/puppet.rb
index 765c95cbf..5ccdd41f2 100644
--- a/lib/puppet.rb
+++ b/lib/puppet.rb
@@ -24,7 +24,7 @@ require 'puppet/util/run_mode'
# it's also a place to find top-level commands like 'debug'
module Puppet
- PUPPETVERSION = '2.7.2'
+ PUPPETVERSION = '2.7.3'
def Puppet.version
PUPPETVERSION
diff --git a/lib/puppet/application.rb b/lib/puppet/application.rb
index 374dc850b..b7cb1169d 100644
--- a/lib/puppet/application.rb
+++ b/lib/puppet/application.rb
@@ -215,11 +215,10 @@ class Application
def find(name)
klass = name.to_s.capitalize
- # const_defined? is used before const_get since const_defined? will only
- # check within our namespace, whereas const_get will check ancestor
- # trees as well, resulting in unexpected behaviour.
- if !self.const_defined?(klass)
- puts "Unable to find application '#{name.to_s}'."
+ begin
+ require File.join('puppet', 'application', name.to_s.downcase)
+ rescue LoadError => e
+ puts "Unable to find application '#{name}'. #{e}"
Kernel::exit(1)
end
diff --git a/lib/puppet/application/agent.rb b/lib/puppet/application/agent.rb
index ea7cbdfb5..b8645c3ce 100644
--- a/lib/puppet/application/agent.rb
+++ b/lib/puppet/application/agent.rb
@@ -100,12 +100,11 @@ similar), or run interactively for testing purposes.
USAGE
-----
-puppet agent [-D|--daemonize|--no-daemonize] [-d|--debug]
- [--detailed-exitcodes] [--disable] [--enable] [-h|--help]
- [--certname <host name>] [-l|--logdest syslog|<file>|console]
- [-o|--onetime] [--serve <handler>] [-t|--test] [--noop]
- [--digest <digest>] [--fingerprint] [-V|--version]
- [-v|--verbose] [-w|--waitforcert <seconds>]
+puppet agent [--certname <name>] [-D|--daemonize|--no-daemonize]
+ [-d|--debug] [--detailed-exitcodes] [--digest <digest>] [--disable] [--enable]
+ [--fingerprint] [-h|--help] [-l|--logdest syslog|<file>|console]
+ [--no-client] [--noop] [-o|--onetime] [--serve <handler>] [-t|--test]
+ [-v|--verbose] [-V|--version] [-w|--waitforcert <seconds>]
DESCRIPTION
@@ -172,6 +171,13 @@ full list of acceptable parameters. A commented list of all
configuration options can also be generated by running puppet agent with
'--genconfig'.
+* --certname:
+ Set the certname (unique ID) of the client. The master reads this
+ unique identifying string, which is usually set to the node's
+ fully-qualified domain name, to determine which configurations the
+ node will receive. Use this option to debug setup problems or
+ implement unusual node identification schemes.
+
* --daemonize:
Send the process into the background. This is the default.
@@ -181,17 +187,17 @@ configuration options can also be generated by running puppet agent with
* --debug:
Enable full debugging.
-* --digest:
- Change the certificate fingerprinting digest algorithm. The default is
- MD5. Valid values depends on the version of OpenSSL installed, but
- should always at least contain MD5, MD2, SHA1 and SHA256.
-
* --detailed-exitcodes:
Provide transaction information via exit codes. If this is enabled, an exit
code of '2' means there were changes, an exit code of '4' means there were
failures during the transaction, and an exit code of '6' means there were both
changes and failures.
+* --digest:
+ Change the certificate fingerprinting digest algorithm. The default is
+ MD5. Valid values depends on the version of OpenSSL installed, but
+ should always at least contain MD5, MD2, SHA1 and SHA256.
+
* --disable:
Disable working on the local system. This puts a lock file in place,
causing 'puppet agent' not to work on the system until the lock file
@@ -212,12 +218,10 @@ configuration options can also be generated by running puppet agent with
'puppet agent' exits after executing this.
-* --certname:
- Set the certname (unique ID) of the client. The master reads this
- unique identifying string, which is usually set to the node's
- fully-qualified domain name, to determine which configurations the
- node will receive. Use this option to debug setup problems or
- implement unusual node identification schemes.
+* --fingerprint:
+ Display the current certificate or certificate signing request
+ fingerprint and then exit. Use the '--digest' option to change the
+ digest algorithm used.
* --help:
Print this help message
@@ -230,18 +234,19 @@ configuration options can also be generated by running puppet agent with
* --no-client:
Do not create a config client. This will cause the daemon to run
without ever checking for its configuration automatically, and only
- makes sense
+ makes sense when puppet agent is being run with listen = true in puppet.conf
+ or was started with the `--listen` option.
+
+* --noop:
+ Use 'noop' mode where the daemon runs in a no-op or dry-run mode. This
+ is useful for seeing what changes Puppet will make without actually
+ executing the changes.
* --onetime:
Run the configuration once. Runs a single (normally daemonized) Puppet
run. Useful for interactively running puppet agent when used in
conjunction with the --no-daemonize option.
-* --fingerprint:
- Display the current certificate or certificate signing request
- fingerprint and then exit. Use the '--digest' option to change the
- digest algorithm used.
-
* --serve:
Start another type of server. By default, 'puppet agent' will start a
service handler that allows authenticated and authorized remote nodes
@@ -256,11 +261,6 @@ configuration options can also be generated by running puppet agent with
'verbose', 'ignorecache', 'no-daemonize', 'no-usecacheonfailure',
'detailed-exit-codes', 'no-splay', and 'show_diff'.
-* --noop:
- Use 'noop' mode where the daemon runs in a no-op or dry-run mode. This
- is useful for seeing what changes Puppet will make without actually
- executing the changes.
-
* --verbose:
Turn on verbose reporting.
@@ -290,7 +290,7 @@ Puppet agent accepts the following signals:
Restart the puppet agent daemon.
* SIGINT and SIGTERM:
Shut down the puppet agent daemon.
-* SIGUSR1:
+* SIGUSR1:
Immediately retrieve and apply configurations from the puppet master.
AUTHOR
diff --git a/lib/puppet/application/inspect.rb b/lib/puppet/application/inspect.rb
index b5a4ac872..6737128aa 100644
--- a/lib/puppet/application/inspect.rb
+++ b/lib/puppet/application/inspect.rb
@@ -31,7 +31,7 @@ Prepares and submits an inspection report to the puppet master.
USAGE
-----
-puppet inspect
+puppet inspect [--archive_files] [--archive_file_server]
DESCRIPTION
@@ -57,6 +57,14 @@ configuration file documentation at
http://docs.puppetlabs.com/references/latest/configuration.html for
the full list of acceptable settings.
+* --archive_files:
+ During an inspect run, whether to archive files whose contents are audited to
+ a file bucket.
+
+* --archive_file_server:
+ During an inspect run, the file bucket server to archive files to if
+ archive_files is set. The default value is '$server'.
+
AUTHOR
------
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index 637ee8fdd..106e94b02 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -551,7 +551,10 @@ module Puppet
:puppetport => [8139, "Which port puppet agent listens on."],
:noop => [false, "Whether puppet agent should be run in noop mode."],
:runinterval => [1800, # 30 minutes
- "How often puppet agent applies the client configuration; in seconds."],
+ "How often puppet agent applies the client configuration; in seconds.
+ Note that a runinterval of 0 means \"run continuously\" rather than
+ \"never run.\" If you want puppet agent to never run, you should start
+ it with the `--no-client` option."],
:listen => [false, "Whether puppet agent should listen for
connections. If this is true, then puppet agent will accept incoming
REST API requests, subject to the default ACLs and the ACLs set in
diff --git a/lib/puppet/face/ca.rb b/lib/puppet/face/ca.rb
index e643530f0..00591d637 100644
--- a/lib/puppet/face/ca.rb
+++ b/lib/puppet/face/ca.rb
@@ -6,21 +6,21 @@ Puppet::Face.define(:ca, '0.1.0') do
summary "Local Puppet Certificate Authority management."
- description <<TEXT
-This provides local management of the Puppet Certificate Authority.
+ description <<-TEXT
+ This provides local management of the Puppet Certificate Authority.
-You can use this subcommand to sign outstanding certificate requests, list
-and manage local certificates, and inspect the state of the CA.
-TEXT
+ You can use this subcommand to sign outstanding certificate requests, list
+ and manage local certificates, and inspect the state of the CA.
+ TEXT
action :list do
summary "List certificates and/or certificate requests."
- description <<-end
-This will list the current certificates and certificate signing requests
-in the Puppet CA. You will also get the fingerprint, and any certificate
-verification failure reported.
- end
+ description <<-TEXT
+ This will list the current certificates and certificate signing requests
+ in the Puppet CA. You will also get the fingerprint, and any certificate
+ verification failure reported.
+ TEXT
option "--[no-]all" do
summary "Include all certificates and requests."
@@ -37,12 +37,12 @@ verification failure reported.
option "--subject PATTERN" do
summary "Only list if the subject matches PATTERN."
- description <<TEXT
-Only include certificates or requests where subject matches PATTERN.
+ description <<-TEXT
+ Only include certificates or requests where subject matches PATTERN.
-PATTERN is interpreted as a regular expression, allowing complex
-filtering of the content.
-TEXT
+ PATTERN is interpreted as a regular expression, allowing complex
+ filtering of the content.
+ TEXT
end
when_invoked do |options|
diff --git a/lib/puppet/face/node/clean.rb b/lib/puppet/face/node/clean.rb
new file mode 100644
index 000000000..d2852de04
--- /dev/null
+++ b/lib/puppet/face/node/clean.rb
@@ -0,0 +1,154 @@
+Puppet::Face.define(:node, '0.0.1') do
+ action(:clean) do
+ option "--[no-]unexport" do
+ summary "Unexport exported resources"
+ end
+
+ summary "Clean up everything a puppetmaster knows about a node"
+ arguments "<host1> [<host2> ...]"
+ description <<-EOT
+ This includes
+
+ * Signed certificates ($vardir/ssl/ca/signed/node.domain.pem)
+ * Cached facts ($vardir/yaml/facts/node.domain.yaml)
+ * Cached node stuff ($vardir/yaml/node/node.domain.yaml)
+ * Reports ($vardir/reports/node.domain)
+ * Stored configs: it can either remove all data from an host in your
+ storedconfig database, or with --unexport turn every exported resource
+ supporting ensure to absent so that any other host checking out their
+ config can remove those exported configurations.
+
+ This will unexport exported resources of a
+ host, so that consumers of these resources can remove the exported
+ resources and we will safely remove the node from our
+ infrastructure.
+ EOT
+
+ when_invoked do |*args|
+ nodes = args[0..-2]
+ options = args.last
+ raise "At least one node should be passed" if nodes.empty? || nodes == options
+
+ # TODO: this is a hack and should be removed if faces provide the proper
+ # infrastructure to set the run mode.
+ require 'puppet/util/run_mode'
+ $puppet_application_mode = Puppet::Util::RunMode[:master]
+
+ if Puppet::SSL::CertificateAuthority.ca?
+ Puppet::SSL::Host.ca_location = :local
+ else
+ Puppet::SSL::Host.ca_location = :none
+ end
+
+ Puppet::Node::Facts.indirection.terminus_class = :yaml
+ Puppet::Node::Facts.indirection.cache_class = :yaml
+ Puppet::Node.indirection.terminus_class = :yaml
+ Puppet::Node.indirection.cache_class = :yaml
+
+ nodes.each { |node| cleanup(node.downcase, options[:unexport]) }
+ end
+ end
+
+ def cleanup(node, unexport)
+ clean_cert(node)
+ clean_cached_facts(node)
+ clean_cached_node(node)
+ clean_reports(node)
+
+ # This is roughly functional, but seems to introduce order-dependent test
+ # failures; this can be re-added when those issues are resolved.
+ # clean_storeconfigs(node, unexport)
+ end
+
+ # clean signed cert for +host+
+ def clean_cert(node)
+ if Puppet::SSL::CertificateAuthority.ca?
+ Puppet::Face[:ca, :current].revoke(node)
+ Puppet::Face[:ca, :current].destroy(node)
+ Puppet.info "#{node} certificates removed from ca"
+ else
+ Puppet.info "Not managing #{node} certs as this host is not a CA"
+ end
+ end
+
+ # clean facts for +host+
+ def clean_cached_facts(node)
+ Puppet::Node::Facts.indirection.destroy(node)
+ Puppet.info "#{node}'s facts removed"
+ end
+
+ # clean cached node +host+
+ def clean_cached_node(node)
+ Puppet::Node.indirection.destroy(node)
+ Puppet.info "#{node}'s cached node removed"
+ end
+
+ # clean node reports for +host+
+ def clean_reports(node)
+ Puppet::Transaction::Report.indirection.destroy(node)
+ Puppet.info "#{node}'s reports removed"
+ end
+
+ # clean storeconfig for +node+
+ def clean_storeconfigs(node, do_unexport=false)
+ return unless Puppet[:storeconfigs] && Puppet.features.rails?
+ require 'puppet/rails'
+ Puppet::Rails.connect
+ unless rails_node = Puppet::Rails::Host.find_by_name(node)
+ Puppet.notice "No entries found for #{node} in storedconfigs."
+ return
+ end
+
+ if do_unexport
+ unexport(rails_node)
+ Puppet.notice "Force #{node}'s exported resources to absent"
+ Puppet.warning "Please wait until all other hosts have checked out their configuration before finishing the cleanup with:"
+ Puppet.warning "$ puppet node clean #{node}"
+ else
+ rails_node.destroy
+ Puppet.notice "#{node} storeconfigs removed"
+ end
+ end
+
+ def unexport(node)
+ # fetch all exported resource
+ query = {:include => {:param_values => :param_name}}
+ query[:conditions] = [ "exported=? AND host_id=?", true, node.id ]
+ Puppet::Rails::Resource.find(:all, query).each do |resource|
+ if type_is_ensurable(resource)
+ line = 0
+ param_name = Puppet::Rails::ParamName.find_or_create_by_name("ensure")
+
+ if ensure_param = resource.param_values.find(
+ :first,
+ :conditions => [ 'param_name_id = ?', param_name.id ]
+ )
+ line = ensure_param.line.to_i
+ Puppet::Rails::ParamValue.delete(ensure_param.id);
+ end
+
+ # force ensure parameter to "absent"
+ resource.param_values.create(
+ :value => "absent",
+ :line => line,
+ :param_name => param_name
+ )
+ Puppet.info("#{resource.name} has been marked as \"absent\"")
+ end
+ end
+ end
+
+ def environment
+ @environment ||= Puppet::Node::Environment.new
+ end
+
+ def type_is_ensurable(resource)
+ if (type = Puppet::Type.type(resource.restype)) && type.validattr?(:ensure)
+ return true
+ else
+ type = environment.known_resource_types.find_definition('', resource.restype)
+ return true if type && type.arguments.keys.include?('ensure')
+ end
+ return false
+ end
+end
diff --git a/lib/puppet/indirector/report/processor.rb b/lib/puppet/indirector/report/processor.rb
index 81b379eb8..7bdadcb36 100644
--- a/lib/puppet/indirector/report/processor.rb
+++ b/lib/puppet/indirector/report/processor.rb
@@ -14,6 +14,12 @@ class Puppet::Transaction::Report::Processor < Puppet::Indirector::Code
process(request.instance)
end
+ def destroy(request)
+ processors do |mod|
+ mod.destroy(request.key) if mod.respond_to?(:destroy)
+ end
+ end
+
private
# Process the report with each of the configured report types.
@@ -21,23 +27,17 @@ class Puppet::Transaction::Report::Processor < Puppet::Indirector::Code
# compatible and that's good enough for now.
def process(report)
Puppet.debug "Recieved report to process from #{report.host}"
- return if Puppet[:reports] == "none"
-
- reports.each do |name|
- Puppet.debug "Processing report from #{report.host} with processor #{name}"
- if mod = Puppet::Reports.report(name)
- # We have to use a dup because we're including a module in the
- # report.
- newrep = report.dup
- begin
- newrep.extend(mod)
- newrep.process
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Report #{name} failed: #{detail}"
- end
- else
- Puppet.warning "No report named '#{name}'"
+ processors do |mod|
+ Puppet.debug "Processing report from #{report.host} with processor #{mod}"
+ # We have to use a dup because we're including a module in the
+ # report.
+ newrep = report.dup
+ begin
+ newrep.extend(mod)
+ newrep.process
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Report #{name} failed: #{detail}"
end
end
end
@@ -47,4 +47,15 @@ class Puppet::Transaction::Report::Processor < Puppet::Indirector::Code
# LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
x = Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/)
end
+
+ def processors(&blk)
+ return if Puppet[:reports] == "none"
+ reports.each do |name|
+ if mod = Puppet::Reports.report(name)
+ yield(mod)
+ else
+ Puppet.warning "No report named '#{name}'"
+ end
+ end
+ end
end
diff --git a/lib/puppet/indirector/yaml.rb b/lib/puppet/indirector/yaml.rb
index 23997e97a..7b12d25e2 100644
--- a/lib/puppet/indirector/yaml.rb
+++ b/lib/puppet/indirector/yaml.rb
@@ -47,6 +47,11 @@ class Puppet::Indirector::Yaml < Puppet::Indirector::Terminus
File.join(base, self.class.indirection_name.to_s, name.to_s + ext)
end
+ def destroy(request)
+ file_path = path(request.key)
+ File.unlink(file_path) if File.exists?(file_path)
+ end
+
def search(request)
Dir.glob(path(request.key,'')).collect do |file|
YAML.load_file(file)
diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb
index bd47a36ea..60ddb2ca3 100644
--- a/lib/puppet/interface/action.rb
+++ b/lib/puppet/interface/action.rb
@@ -269,6 +269,8 @@ WRAPPER
else
result[canonical] = original[name]
end
+ elsif Puppet.settings.include? name
+ result[name] = original[name]
else
unknown << name
end
diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb
index 5b4b17a32..5da4cedef 100755
--- a/lib/puppet/network/handler/fileserver.rb
+++ b/lib/puppet/network/handler/fileserver.rb
@@ -269,6 +269,7 @@ class Puppet::Network::Handler
value = $2
case var
when "path"
+ raise FileServerError.new("No mount specified for argument #{var} #{value}") unless mount
if mount.name == MODULES
Puppet.warning "The '#{mount.name}' module can not have a path. Ignoring attempt to set it"
else
@@ -280,6 +281,7 @@ class Puppet::Network::Handler
end
end
when "allow"
+ raise FileServerError.new("No mount specified for argument #{var} #{value}") unless mount
value.split(/\s*,\s*/).each { |val|
begin
mount.info "allowing #{val} access"
@@ -294,6 +296,7 @@ class Puppet::Network::Handler
end
}
when "deny"
+ raise FileServerError.new("No mount specified for argument #{var} #{value}") unless mount
value.split(/\s*,\s*/).each { |val|
begin
mount.info "denying #{val} access"
diff --git a/lib/puppet/network/http/webrick.rb b/lib/puppet/network/http/webrick.rb
index 54bcf30c2..52aec1bf1 100644
--- a/lib/puppet/network/http/webrick.rb
+++ b/lib/puppet/network/http/webrick.rb
@@ -40,7 +40,7 @@ class Puppet::Network::HTTP::WEBrick
@listening = true
@thread = Thread.new {
@server.start { |sock|
- raise "Client disconnected before connection could be established" unless IO.select([sock],nil,nil,0.1)
+ raise "Client disconnected before connection could be established" unless IO.select([sock],nil,nil,6.2)
sock.accept
@server.run(sock)
}
diff --git a/lib/puppet/parser/functions/versioncmp.rb b/lib/puppet/parser/functions/versioncmp.rb
index e4edb151e..a7905a6d0 100644
--- a/lib/puppet/parser/functions/versioncmp.rb
+++ b/lib/puppet/parser/functions/versioncmp.rb
@@ -1,20 +1,19 @@
require 'puppet/util/package'
-
-Puppet::Parser::Functions::newfunction( :versioncmp, :type => :rvalue,
-:doc => "Compares two versions
+Puppet::Parser::Functions::newfunction( :versioncmp, :type => :rvalue, :doc =>
+"Compares two version numbers.
Prototype:
\$result = versioncmp(a, b)
-Where a and b are arbitrary version strings
+Where a and b are arbitrary version strings.
-This functions returns a number:
+This function returns:
-* Greater than 0 if version a is greater than version b
-* Equal to 0 if both version are equals
-* Less than 0 if version a is less than version b
+* `1` if version a is greater than version b
+* `0` if the versions are equal
+* `-1` if version a is less than version b
Example:
@@ -22,6 +21,9 @@ Example:
notice('2.6-1 is > than 2.4.5')
}
+This function uses the same version comparison algorithm used by Puppet's
+`package` type.
+
") do |args|
unless args.length == 2
diff --git a/lib/puppet/provider/exec/posix.rb b/lib/puppet/provider/exec/posix.rb
index 92dbd8c98..157d0f28d 100644
--- a/lib/puppet/provider/exec/posix.rb
+++ b/lib/puppet/provider/exec/posix.rb
@@ -4,9 +4,12 @@ Puppet::Type.type(:exec).provide :posix do
confine :feature => :posix
defaultfor :feature => :posix
- desc "Execute external binaries directly, on POSIX systems.
-This does not pass through a shell, or perform any interpolation, but
-only directly calls the command with the arguments given."
+ desc <<-EOT
+ Executes external binaries directly, without passing through a shell or
+ performing any interpolation. This is a safer and more predictable way
+ to execute most commands, but prevents the use of globbing and shell
+ built-ins (including control logic like "for" and "if" statements).
+ EOT
def run(command, check = false)
output = nil
diff --git a/lib/puppet/provider/exec/shell.rb b/lib/puppet/provider/exec/shell.rb
index 98f309e8f..ad2171005 100644
--- a/lib/puppet/provider/exec/shell.rb
+++ b/lib/puppet/provider/exec/shell.rb
@@ -3,8 +3,17 @@ Puppet::Type.type(:exec).provide :shell, :parent => :posix do
confine :feature => :posix
- desc "Execute external binaries directly, on POSIX systems.
-passing through a shell so that shell built ins are available."
+ desc <<-EOT
+ Passes the provided command through `/bin/sh`; only available on
+ POSIX systems. This allows the use of shell globbing and built-ins, and
+ does not require that the path to a command be fully-qualified. Although
+ this can be more convenient than the `posix` provider, it also means that
+ you need to be more careful with escaping; as ever, with great power comes
+ etc. etc.
+
+ This provider closely resembles the behavior of the `exec` type
+ in Puppet 0.25.x.
+ EOT
def run(command, check = false)
command = %Q{/bin/sh -c "#{command.gsub(/"/,'\"')}"}
diff --git a/lib/puppet/provider/vcsrepo.rb b/lib/puppet/provider/vcsrepo.rb
deleted file mode 100644
index 2c026ba86..000000000
--- a/lib/puppet/provider/vcsrepo.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'tmpdir'
-require 'digest/md5'
-require 'fileutils'
-
-# Abstract
-class Puppet::Provider::Vcsrepo < Puppet::Provider
-
- private
-
- def set_ownership
- owner = @resource.value(:owner) || nil
- group = @resource.value(:group) || nil
- FileUtils.chown_R(owner, group, @resource.value(:path))
- end
-
- def path_exists?
- File.directory?(@resource.value(:path))
- end
-
- # Note: We don't rely on Dir.chdir's behavior of automatically returning the
- # value of the last statement -- for easier stubbing.
- def at_path(&block) #:nodoc:
- value = nil
- Dir.chdir(@resource.value(:path)) do
- value = yield
- end
- value
- end
-
- def tempdir
- @tempdir ||= File.join(Dir.tmpdir, 'vcsrepo-' + Digest::MD5.hexdigest(@resource.value(:path)))
- end
-
-end
diff --git a/lib/puppet/provider/vcsrepo/bzr.rb b/lib/puppet/provider/vcsrepo/bzr.rb
deleted file mode 100644
index a0605624b..000000000
--- a/lib/puppet/provider/vcsrepo/bzr.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-require File.join(File.dirname(__FILE__), '..', 'vcsrepo')
-
-Puppet::Type.type(:vcsrepo).provide(:bzr, :parent => Puppet::Provider::Vcsrepo) do
- desc "Supports Bazaar repositories"
-
- commands :bzr => 'bzr'
- defaultfor :bzr => :exists
- has_features :reference_tracking
-
- def create
- if !@resource.value(:source)
- create_repository(@resource.value(:path))
- else
- clone_repository(@resource.value(:revision))
- end
- end
-
- def exists?
- File.directory?(File.join(@resource.value(:path), '.bzr'))
- end
-
- def destroy
- FileUtils.rm_rf(@resource.value(:path))
- end
-
- def revision
- at_path do
- current_revid = bzr('version-info')[/^revision-id:\s+(\S+)/, 1]
- desired = @resource.value(:revision)
- begin
- desired_revid = bzr('revision-info', desired).strip.split(/\s+/).last
- rescue Puppet::ExecutionFailure
- # Possible revid available during update (but definitely not current)
- desired_revid = nil
- end
- if current_revid == desired_revid
- desired
- else
- current_revid
- end
- end
- end
-
- def revision=(desired)
- bzr('update', '-r', desired, @resource.value(:path))
- end
-
- private
-
- def create_repository(path)
- bzr('init', path)
- end
-
- def clone_repository(revision)
- args = ['branch']
- if revision
- args.push('-r', revision)
- end
- args.push(@resource.value(:source),
- @resource.value(:path))
- bzr(*args)
- end
-
-end
diff --git a/lib/puppet/provider/vcsrepo/cvs.rb b/lib/puppet/provider/vcsrepo/cvs.rb
deleted file mode 100644
index e82c23afe..000000000
--- a/lib/puppet/provider/vcsrepo/cvs.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-require File.join(File.dirname(__FILE__), '..', 'vcsrepo')
-
-Puppet::Type.type(:vcsrepo).provide(:cvs, :parent => Puppet::Provider::Vcsrepo) do
- desc "Supports CVS repositories/workspaces"
-
- commands :cvs => 'cvs'
- defaultfor :cvs => :exists
- has_features :gzip_compression, :reference_tracking
-
- def create
- if !@resource.value(:source)
- create_repository(@resource.value(:path))
- else
- checkout_repository
- end
- end
-
- def exists?
- if @resource.value(:source)
- directory = File.join(@resource.value(:path), 'CVS')
- else
- directory = File.join(@resource.value(:path), 'CVSROOT')
- end
- File.directory?(directory)
- end
-
- def destroy
- FileUtils.rm_rf(@resource.value(:path))
- end
-
- def revision
- if File.exist?(tag_file)
- contents = File.read(tag_file)
- # Note: Doesn't differentiate between N and T entries
- contents[1..-1]
- else
- 'MAIN'
- end
- end
-
- def revision=(desired)
- at_path do
- cvs('update', '-r', desired, '.')
- end
- end
-
- private
-
- def tag_file
- File.join(@resource.value(:path), 'CVS', 'Tag')
- end
-
- def checkout_repository
- dirname, basename = File.split(@resource.value(:path))
- Dir.chdir(dirname) do
- args = ['-d', @resource.value(:source)]
- if @resource.value(:compression)
- args.push('-z', @resource.value(:compression))
- end
- args.push('checkout', '-d', basename, module_name)
- cvs(*args)
- end
- if @resource.value(:revision)
- self.revision = @resource.value(:revision)
- end
- end
-
- # When the source:
- # * Starts with ':' (eg, :pserver:...)
- def module_name
- if (source = @resource.value(:source))
- source[0, 1] == ':' ? File.basename(source) : '.'
- end
- end
-
- def create_repository(path)
- cvs('-d', path, 'init')
- end
-
-end
diff --git a/lib/puppet/provider/vcsrepo/git.rb b/lib/puppet/provider/vcsrepo/git.rb
deleted file mode 100644
index fa7e492cf..000000000
--- a/lib/puppet/provider/vcsrepo/git.rb
+++ /dev/null
@@ -1,264 +0,0 @@
-require File.join(File.dirname(__FILE__), '..', 'vcsrepo')
-
-Puppet::Type.type(:vcsrepo).provide(:git, :parent => Puppet::Provider::Vcsrepo) do
- desc "Supports Git repositories"
-
- ##TODO modify the commands below so that the su - is included
- commands :git => 'git'
- defaultfor :git => :exists
- has_features :bare_repositories, :reference_tracking
-
- def create
- if !@resource.value(:source)
- init_repository(@resource.value(:path))
- else
- clone_repository(@resource.value(:source), @resource.value(:path))
- if @resource.value(:revision)
- if @resource.value(:ensure) == :bare
- notice "Ignoring revision for bare repository"
- else
- checkout_or_reset
- end
- end
- if @resource.value(:ensure) != :bare
- update_submodules
- end
- end
- update_owner_and_excludes
- end
-
- def destroy
- FileUtils.rm_rf(@resource.value(:path))
- end
-
- def latest?
- at_path do
- return self.revision == self.latest
- end
- end
-
- def latest
- branch = on_branch?
- if branch == 'master'
- return get_revision('origin/HEAD')
- else
- return get_revision('origin/%s' % branch)
- end
- end
-
- def revision
- update_references
- current = at_path { git('rev-parse', 'HEAD') }
- canonical = at_path { git('rev-parse', @resource.value(:revision)) }
- if current == canonical
- @resource.value(:revision)
- else
- current
- end
- end
-
- def revision=(desired)
- checkout_or_reset(desired)
- if local_branch_revision?(desired)
- # reset instead of pull to avoid merge conflicts. assuming remote is
- # authoritative.
- # might be worthwhile to have an allow_local_changes param to decide
- # whether to reset or pull when we're ensuring latest.
- at_path { git('reset', '--hard', "origin/#{desired}") }
- end
- if @resource.value(:ensure) != :bare
- update_submodules
- end
- update_owner_and_excludes
- end
-
- def bare_exists?
- bare_git_config_exists? && !working_copy_exists?
- end
-
- def working_copy_exists?
- File.directory?(File.join(@resource.value(:path), '.git'))
- end
-
- def exists?
- working_copy_exists? || bare_exists?
- end
-
- def update_references
- at_path do
- git('fetch', '--tags', 'origin')
- end
- end
-
- private
-
- def bare_git_config_exists?
- File.exist?(File.join(@resource.value(:path), 'config'))
- end
-
- def clone_repository(source, path)
- check_force
- args = ['clone']
- if @resource.value(:ensure) == :bare
- args << '--bare'
- end
- if !File.exist?(File.join(@resource.value(:path), '.git'))
- args.push(source, path)
- git(*args)
- else
- notice "Repo has already been cloned"
- end
- end
-
- def check_force
- if path_exists?
- if @resource.value(:force)
- notice "Removing %s to replace with vcsrepo." % @resource.value(:path)
- destroy
- else
- raise Puppet::Error, "Could not create repository (non-repository at path)"
- end
- end
- end
-
- def init_repository(path)
- check_force
- if @resource.value(:ensure) == :bare && working_copy_exists?
- convert_working_copy_to_bare
- elsif @resource.value(:ensure) == :present && bare_exists?
- convert_bare_to_working_copy
- else
- # normal init
- FileUtils.mkdir(@resource.value(:path))
- args = ['init']
- if @resource.value(:ensure) == :bare
- args << '--bare'
- end
- at_path do
- git(*args)
- end
- end
- end
-
- # Convert working copy to bare
- #
- # Moves:
- # <path>/.git
- # to:
- # <path>/
- def convert_working_copy_to_bare
- notice "Converting working copy repository to bare repository"
- FileUtils.mv(File.join(@resource.value(:path), '.git'), tempdir)
- FileUtils.rm_rf(@resource.value(:path))
- FileUtils.mv(tempdir, @resource.value(:path))
- end
-
- # Convert bare to working copy
- #
- # Moves:
- # <path>/
- # to:
- # <path>/.git
- def convert_bare_to_working_copy
- notice "Converting bare repository to working copy repository"
- FileUtils.mv(@resource.value(:path), tempdir)
- FileUtils.mkdir(@resource.value(:path))
- FileUtils.mv(tempdir, File.join(@resource.value(:path), '.git'))
- if commits_in?(File.join(@resource.value(:path), '.git'))
- reset('HEAD')
- git('checkout', '-f')
- update_owner_and_excludes
- end
- end
-
- def commits_in?(dot_git)
- Dir.glob(File.join(dot_git, 'objects/info/*'), File::FNM_DOTMATCH) do |e|
- return true unless %w(. ..).include?(File::basename(e))
- end
- false
- end
-
- def checkout_or_reset(revision = @resource.value(:revision))
- if local_branch_revision?
- reset(revision)
- elsif tag_revision?
- at_path { git('checkout', '-b', revision) }
- elsif remote_branch_revision?
- at_path { git('checkout', '-b', revision, '--track', "origin/#{revision}") }
- end
- end
-
- def reset(desired)
- at_path do
- git('reset', '--hard', desired)
- end
- end
-
- def update_submodules
- at_path do
- git('submodule', 'init')
- git('submodule', 'update')
- git('submodule', 'foreach', 'git', 'submodule', 'init')
- git('submodule', 'foreach', 'git', 'submodule', 'update')
- end
- end
-
- def remote_branch_revision?(revision = @resource.value(:revision))
- # git < 1.6 returns 'origin/#{revision}'
- # git 1.6+ returns 'remotes/origin/#{revision}'
- at_path { branches.grep /(remotes\/)?origin\/#{revision}/ }
- end
-
- def local_branch_revision?(revision = @resource.value(:revision))
- at_path { branches.include?(revision) }
- end
-
- def tag_revision?(revision = @resource.value(:revision))
- at_path { tags.include?(revision) }
- end
-
- def branches
- at_path { git('branch', '-a') }.gsub('*', ' ').split(/\n/).map { |line| line.strip }
- end
-
- def on_branch?
- at_path { git('branch', '-a') }.split(/\n/).grep(/\*/).to_s.gsub('*', '').strip
- end
-
- def tags
- at_path { git('tag', '-l') }.split(/\n/).map { |line| line.strip }
- end
-
- def set_excludes
- at_path { open('.git/info/exclude', 'w') { |f| @resource.value(:excludes).each { |ex| f.write(ex + "\n") }}}
- end
-
- def get_revision(rev)
- if !working_copy_exists?
- create
- end
- at_path do
- git('fetch', 'origin')
- git('fetch', '--tags', 'origin')
- end
- current = at_path { git('rev-parse', rev).strip }
- if @resource.value(:revision)
- if local_branch_revision?
- canonical = at_path { git('rev-parse', @resource.value(:revision)).strip }
- elsif remote_branch_revision?
- canonical = at_path { git('rev-parse', 'origin/' + @resource.value(:revision)).strip }
- end
- current = @resource.value(:revision) if current == canonical
- end
- return current
- end
-
- def update_owner_and_excludes
- if @resource.value(:owner) or @resource.value(:group)
- set_ownership
- end
- if @resource.value(:excludes)
- set_excludes
- end
- end
-end
diff --git a/lib/puppet/provider/vcsrepo/hg.rb b/lib/puppet/provider/vcsrepo/hg.rb
deleted file mode 100644
index f96758612..000000000
--- a/lib/puppet/provider/vcsrepo/hg.rb
+++ /dev/null
@@ -1,101 +0,0 @@
-require File.join(File.dirname(__FILE__), '..', 'vcsrepo')
-
-Puppet::Type.type(:vcsrepo).provide(:hg, :parent => Puppet::Provider::Vcsrepo) do
- desc "Supports Mercurial repositories"
-
- commands :hg => 'hg'
- defaultfor :hg => :exists
- has_features :reference_tracking
-
- def create
- if !@resource.value(:source)
- create_repository(@resource.value(:path))
- else
- clone_repository(@resource.value(:revision))
- end
- update_owner
- end
-
- def working_copy_exists?
- File.directory?(File.join(@resource.value(:path), '.hg'))
- end
-
- def exists?
- working_copy_exists?
- end
-
- def destroy
- FileUtils.rm_rf(@resource.value(:path))
- end
-
- def latest?
- at_path do
- return self.revision == self.latest
- end
- end
-
- def latest
- at_path do
- begin
- hg('incoming', '--branch', '.', '--newest-first', '--limit', '1')[/^changeset:\s+(?:-?\d+):(\S+)/m, 1]
- rescue Puppet::ExecutionFailure
- # If there are no new changesets, return the current nodeid
- self.revision
- end
- end
- end
-
- def revision
- at_path do
- current = hg('parents')[/^changeset:\s+(?:-?\d+):(\S+)/m, 1]
- desired = @resource.value(:revision)
- if desired
- # Return the tag name if it maps to the current nodeid
- mapped = hg('tags')[/^#{Regexp.quote(desired)}\s+\d+:(\S+)/m, 1]
- if current == mapped
- desired
- else
- current
- end
- else
- current
- end
- end
- end
-
- def revision=(desired)
- at_path do
- hg('pull')
- begin
- hg('merge')
- rescue Puppet::ExecutionFailure
- # If there's nothing to merge, just skip
- end
- hg('update', '--clean', '-r', desired)
- end
- update_owner
- end
-
- private
-
- def create_repository(path)
- hg('init', path)
- end
-
- def clone_repository(revision)
- args = ['clone']
- if revision
- args.push('-u', revision)
- end
- args.push(@resource.value(:source),
- @resource.value(:path))
- hg(*args)
- end
-
- def update_owner
- if @resource.value(:owner) or @resource.value(:group)
- set_ownership
- end
- end
-
-end
diff --git a/lib/puppet/provider/vcsrepo/svn.rb b/lib/puppet/provider/vcsrepo/svn.rb
deleted file mode 100644
index 680188c1e..000000000
--- a/lib/puppet/provider/vcsrepo/svn.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-require File.join(File.dirname(__FILE__), '..', 'vcsrepo')
-
-Puppet::Type.type(:vcsrepo).provide(:svn, :parent => Puppet::Provider::Vcsrepo) do
- desc "Supports Subversion repositories"
-
- commands :svn => 'svn',
- :svnadmin => 'svnadmin'
-
- defaultfor :svn => :exists
- has_features :filesystem_types, :reference_tracking
-
- def create
- if !@resource.value(:source)
- create_repository(@resource.value(:path))
- else
- checkout_repository(@resource.value(:source),
- @resource.value(:path),
- @resource.value(:revision))
- end
- end
-
- def working_copy_exists?
- File.directory?(File.join(@resource.value(:path), '.svn'))
- end
-
- def exists?
- working_copy_exists?
- end
-
- def destroy
- FileUtils.rm_rf(@resource.value(:path))
- end
-
- def latest?
- at_path do
- if self.revision < self.latest then
- return false
- else
- return true
- end
- end
- end
-
- def latest
- at_path do
- svn('info', '-r', 'HEAD')[/^Revision:\s+(\d+)/m, 1]
- end
- end
-
- def revision
- at_path do
- svn('info')[/^Revision:\s+(\d+)/m, 1]
- end
- end
-
- def revision=(desired)
- at_path do
- svn('update', '-r', desired)
- end
- end
-
- private
-
- def checkout_repository(source, path, revision = nil)
- args = ['checkout']
- if revision
- args.push('-r', revision)
- end
- args.push(source, path)
- svn(*args)
- end
-
- def create_repository(path)
- args = ['create']
- if @resource.value(:fstype)
- args.push('--fs-type', @resource.value(:fstype))
- end
- args << path
- svnadmin(*args)
- end
-
-end
diff --git a/lib/puppet/reports/store.rb b/lib/puppet/reports/store.rb
index 625a263b3..997206ec4 100644
--- a/lib/puppet/reports/store.rb
+++ b/lib/puppet/reports/store.rb
@@ -41,5 +41,20 @@ Puppet::Reports.register_report(:store) do
# Only testing cares about the return value
file
end
+
+ # removes all reports for a given host
+ def self.destroy(host)
+ client = host.gsub("..",".")
+ dir = File.join(Puppet[:reportdir], client)
+
+ if File.exists?(dir)
+ Dir.entries(dir).each do |file|
+ next if ['.','..'].include?(file)
+ file = File.join(dir, file)
+ File.unlink(file) if File.file?(file)
+ end
+ Dir.rmdir(dir)
+ end
+ end
end
diff --git a/lib/puppet/reports/tagmail.rb b/lib/puppet/reports/tagmail.rb
index e17143e2f..c37341e11 100644
--- a/lib/puppet/reports/tagmail.rb
+++ b/lib/puppet/reports/tagmail.rb
@@ -8,21 +8,24 @@ Puppet::Reports.register_report(:tagmail) do
desc "This report sends specific log messages to specific email addresses
based on the tags in the log messages.
- See the [UsingTags tag documentation](http://projects.puppetlabs.com/projects/puppet/wiki/Using_Tags) for more information on tags.
+ See the [documentation on tags](http://projects.puppetlabs.com/projects/puppet/wiki/Using_Tags) for more information.
- To use this report, you must create a `tagmail.conf` (in the location
- specified by `tagmap`). This is a simple file that maps tags to
+ To use this report, you must create a `tagmail.conf` file in the location
+ specified by the `tagmap` setting. This is a simple file that maps tags to
email addresses: Any log messages in the report that match the specified
tags will be sent to the specified email addresses.
- Tags must be comma-separated, and they can be negated so that messages
- only match when they do not have that tag. The tags are separated from
- the email addresses by a colon, and the email addresses should also
- be comma-separated.
+ Lines in the `tagmail.conf` file consist of a comma-separated list
+ of tags, a colon, and a comma-separated list of email addresses.
+ Tags can be !negated with a leading exclamation mark, which will
+ subtract any messages with that tag from the set of events handled
+ by that line.
- Lastly, there is an `all` tag that will always match all log messages.
+ Puppet's log levels (`debug`, `info`, `notice`, `warning`, `err`,
+ `alert`, `emerg`, `crit`, and `verbose`) can also be used as tags,
+ and there is an `all` tag that will always match all log messages.
- Here is an example `tagmail.conf`:
+ An example `tagmail.conf`:
all: me@domain.com
webserver, !mailserver: httpadmins@domain.com
@@ -30,8 +33,9 @@ Puppet::Reports.register_report(:tagmail) do
This will send all messages to `me@domain.com`, and all messages from
webservers that are not also from mailservers to `httpadmins@domain.com`.
- If you are using anti-spam controls, such as grey-listing, on your mail
- server you should whitelist the sending email (controlled by `reportform` configuration option) to ensure your email is not discarded as spam.
+ If you are using anti-spam controls such as grey-listing on your mail
+ server, you should whitelist the sending email address (controlled by
+ `reportform` configuration option) to ensure your email is not discarded as spam.
"
# Find all matching messages.
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 963b925bf..803b5c6a0 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -972,7 +972,7 @@ class Type
newmetaparam(:audit) do
desc "Marks a subset of this resource's unmanaged attributes for auditing. Accepts an
- attribute name or a list of attribute names.
+ attribute name, an array of attribute names, or `all`.
Auditing a resource attribute has two effects: First, whenever a catalog
is applied with puppet apply or puppet agent, Puppet will check whether
diff --git a/lib/puppet/type/file/content.rb b/lib/puppet/type/file/content.rb
index 827183213..93b8e6913 100755
--- a/lib/puppet/type/file/content.rb
+++ b/lib/puppet/type/file/content.rb
@@ -16,8 +16,10 @@ module Puppet
attr_reader :actual_content
desc "Specify the contents of a file as a string. Newlines, tabs, and
- spaces can be specified using the escaped syntax (e.g., \\n for a newline). The primary purpose of this parameter is to provide a
- kind of limited templating:
+ spaces can be specified using standard escaped syntax in
+ double-quoted strings (e.g., \\n for a newline).
+
+ With very small files, you can construct strings directly...
define resolve(nameserver1, nameserver2, domain, search) {
$str = \"search $search
@@ -31,7 +33,9 @@ module Puppet
}
}
- This attribute is especially useful when used with templating."
+ ...but for larger files, this attribute is more useful when combined with the
+ [template](http://docs.puppetlabs.com/references/latest/function.html#template)
+ function."
# Store a checksum as the value, rather than the actual content.
# Simplifies everything.
diff --git a/lib/puppet/type/vcsrepo.rb b/lib/puppet/type/vcsrepo.rb
deleted file mode 100644
index f0d2613ca..000000000
--- a/lib/puppet/type/vcsrepo.rb
+++ /dev/null
@@ -1,138 +0,0 @@
-require 'pathname'
-
-Puppet::Type.newtype(:vcsrepo) do
- desc "A local version control repository"
-
- feature :gzip_compression,
- "The provider supports explicit GZip compression levels"
-
- feature :bare_repositories,
- "The provider differentiates between bare repositories
- and those with working copies",
- :methods => [:bare_exists?, :working_copy_exists?]
-
- feature :filesystem_types,
- "The provider supports different filesystem types"
-
- feature :reference_tracking,
- "The provider supports tracking revision references that can change
- over time (eg, some VCS tags and branch names)"
-
- ensurable do
- attr_accessor :latest
-
- def insync?(is)
- @should ||= []
-
- case should
- when :present
- return true unless [:absent, :purged, :held].include?(is)
- when :latest
- if is == :latest
- return true
- else
- self.debug "%s repo revision is %s, latest is %s" %
- [@resource.name, provider.revision, provider.latest]
- return false
- end
- end
- end
-
- newvalue :present do
- provider.create
- end
-
- newvalue :bare, :required_features => [:bare_repositories] do
- provider.create
- end
-
- newvalue :absent do
- provider.destroy
- end
-
- newvalue :latest, :required_features => [:reference_tracking] do
- if provider.exists?
- if provider.respond_to?(:update_references)
- provider.update_references
- end
- if provider.respond_to?(:latest?)
- reference = provider.latest || provider.revision
- else
- reference = resource.value(:revision) || provider.revision
- end
- notice "Updating to latest '#{reference}' revision"
- provider.revision = reference
- else
- provider.create
- end
- end
-
- def retrieve
- prov = @resource.provider
- if prov
- if prov.working_copy_exists?
- prov.latest? ? :latest : :present
- elsif prov.class.feature?(:bare_repositories) and prov.bare_exists?
- :bare
- else
- :absent
- end
- else
- raise Puppet::Error, "Could not find provider"
- end
- end
-
- end
-
- newparam(:path) do
- desc "Absolute path to repository"
- isnamevar
- validate do |value|
- path = Pathname.new(value)
- unless path.absolute?
- raise ArgumentError, "Path must be absolute: #{path}"
- end
- end
- end
-
- newparam(:source) do
- desc "The source URI for the repository"
- end
-
- newparam(:fstype, :required_features => [:filesystem_types]) do
- desc "Filesystem type"
- end
-
- newproperty(:revision) do
- desc "The revision of the repository"
- newvalue(/^\S+$/)
- end
-
- newparam(:owner) do
- desc "The user/uid that owns the repository files"
- end
-
- newparam(:group) do
- desc "The group/gid that owns the repository files"
- end
-
- newparam(:excludes) do
- desc "Files to be excluded from the repository"
- end
-
- newparam(:force) do
- desc "Force repository creation, destroying any files on the path in the process."
- newvalues(:true, :false)
- defaultto false
- end
-
- newparam :compression, :required_features => [:gzip_compression] do
- desc "Compression level"
- validate do |amount|
- unless Integer(amount).between?(0, 6)
- raise ArgumentError, "Unsupported compression level: #{amount} (expected 0-6)"
- end
- end
- end
-
-end
diff --git a/spec/unit/application/apply_spec.rb b/spec/unit/application/apply_spec.rb
index c9555157c..489f4db36 100755
--- a/spec/unit/application/apply_spec.rb
+++ b/spec/unit/application/apply_spec.rb
@@ -134,7 +134,9 @@ describe Puppet::Application::Apply do
Puppet[:postrun_command] = ''
Puppet::Node::Facts.indirection.terminus_class = :memory
+ Puppet::Node::Facts.indirection.cache_class = :memory
Puppet::Node.indirection.terminus_class = :memory
+ Puppet::Node.indirection.cache_class = :memory
@facts = Puppet::Node::Facts.new(Puppet[:node_name_value])
Puppet::Node::Facts.indirection.save(@facts)
diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb
index aed80e3e6..fd93ceb00 100755
--- a/spec/unit/application_spec.rb
+++ b/spec/unit/application_spec.rb
@@ -31,6 +31,10 @@ describe Puppet::Application do
end
it "should exit if it can't find a class" do
+ reg = "Unable to find application 'ThisShallNeverEverEverExist'. "
+ reg += "no such file to load -- puppet/application/thisshallneverevereverexist"
+ @klass.expects(:puts).with(reg)
+
expect { @klass.find("ThisShallNeverEverEverExist") }.to exit_with 1
end
end
diff --git a/spec/unit/face/node_spec.rb b/spec/unit/face/node_spec.rb
index 027a4cce0..6f6edc6cc 100755
--- a/spec/unit/face/node_spec.rb
+++ b/spec/unit/face/node_spec.rb
@@ -3,5 +3,265 @@ require 'spec_helper'
require 'puppet/face'
describe Puppet::Face[:node, '0.0.1'] do
- it "REVISIT: really should have some tests"
+ describe '#cleanup' do
+ it "should clean everything" do
+ {
+ "cert" => ['hostname'],
+ "cached_facts" => ['hostname'],
+ "cached_node" => ['hostname'],
+ "reports" => ['hostname'],
+
+ # Support for cleaning storeconfigs has been temporarily suspended.
+ # "storeconfigs" => ['hostname', :unexport]
+ }.each { |k, v| subject.expects("clean_#{k}".to_sym).with(*v) }
+ subject.cleanup('hostname', :unexport)
+ end
+ end
+
+ describe 'when running #clean' do
+ before :each do
+ Puppet::Node::Facts.indirection.stubs(:terminus_class=)
+ Puppet::Node::Facts.indirection.stubs(:cache_class=)
+ Puppet::Node.stubs(:terminus_class=)
+ Puppet::Node.stubs(:cache_class=)
+ end
+
+ it 'should invoke #cleanup' do
+ subject.expects(:cleanup).with('hostname', nil)
+ subject.clean('hostname')
+ end
+ end
+
+ describe "clean action" do
+ before :each do
+ Puppet::Node::Facts.indirection.stubs(:terminus_class=)
+ Puppet::Node::Facts.indirection.stubs(:cache_class=)
+ Puppet::Node.stubs(:terminus_class=)
+ Puppet::Node.stubs(:cache_class=)
+ subject.stubs(:cleanup)
+ end
+
+ it "should have a clean action" do
+ subject.should be_action :clean
+ end
+
+ it "should not accept a call with no arguments" do
+ expect { subject.clean() }.should raise_error
+ end
+
+ it "should accept a node name" do
+ expect { subject.clean('hostname') }.should_not raise_error
+ end
+
+ it "should accept more than one node name" do
+ expect do
+ subject.clean('hostname', 'hostname2', {})
+ end.should_not raise_error
+
+ expect do
+ subject.clean('hostname', 'hostname2', 'hostname3', { :unexport => true })
+ end.should_not raise_error
+ end
+
+ it "should accept the option --unexport" do
+ expect { subject.help('hostname', :unexport => true) }.
+ should_not raise_error ArgumentError
+ end
+
+ context "clean action" do
+ subject { Puppet::Face[:node, :current] }
+ before :each do
+ Puppet::Util::Log.stubs(:newdestination)
+ Puppet::Util::Log.stubs(:level=)
+ end
+
+ describe "during setup" do
+ it "should set facts terminus and cache class to yaml" do
+ Puppet::Node::Facts.indirection.expects(:terminus_class=).with(:yaml)
+ Puppet::Node::Facts.indirection.expects(:cache_class=).with(:yaml)
+
+ subject.clean('hostname')
+ end
+
+ it "should run in master mode" do
+ subject.clean('hostname')
+ $puppet_application_mode.name.should == :master
+ end
+
+ it "should set node cache as yaml" do
+ Puppet::Node.indirection.expects(:terminus_class=).with(:yaml)
+ Puppet::Node.indirection.expects(:cache_class=).with(:yaml)
+
+ subject.clean('hostname')
+ end
+
+ it "should manage the certs if the host is a CA" do
+ Puppet::SSL::CertificateAuthority.stubs(:ca?).returns(true)
+ Puppet::SSL::Host.expects(:ca_location=).with(:local)
+ subject.clean('hostname')
+ end
+
+ it "should not manage the certs if the host is not a CA" do
+ Puppet::SSL::CertificateAuthority.stubs(:ca?).returns(false)
+ Puppet::SSL::Host.expects(:ca_location=).with(:none)
+ subject.clean('hostname')
+ end
+ end
+
+ describe "when cleaning certificate" do
+ before :each do
+ Puppet::SSL::Host.stubs(:destroy)
+ @ca = mock()
+ Puppet::SSL::CertificateAuthority.stubs(:instance).returns(@ca)
+ end
+
+ it "should send the :destroy order to the ca if we are a CA" do
+ Puppet::SSL::CertificateAuthority.stubs(:ca?).returns(true)
+ @ca.expects(:revoke).with(@host)
+ @ca.expects(:destroy).with(@host)
+ subject.clean_cert(@host)
+ end
+
+ it "should not destroy the certs if we are not a CA" do
+ Puppet::SSL::CertificateAuthority.stubs(:ca?).returns(false)
+ @ca.expects(:revoke).never
+ @ca.expects(:destroy).never
+ subject.clean_cert(@host)
+ end
+ end
+
+ describe "when cleaning cached facts" do
+ it "should destroy facts" do
+ @host = 'node'
+ Puppet::Node::Facts.indirection.expects(:destroy).with(@host)
+
+ subject.clean_cached_facts(@host)
+ end
+ end
+
+ describe "when cleaning cached node" do
+ it "should destroy the cached node" do
+ Puppet::Node::Yaml.any_instance.expects(:destroy)
+ subject.clean_cached_node(@host)
+ end
+ end
+
+ describe "when cleaning archived reports" do
+ it "should tell the reports to remove themselves" do
+ Puppet::Transaction::Report.indirection.stubs(:destroy).with(@host)
+
+ subject.clean_reports(@host)
+ end
+ end
+
+ # describe "when cleaning storeconfigs entries for host", :if => Puppet.features.rails? do
+ # before :each do
+ # # Stub this so we don't need access to the DB
+ # require 'puppet/rails/host'
+ #
+ # Puppet.stubs(:[]).with(:storeconfigs).returns(true)
+ #
+ # Puppet::Rails.stubs(:connect)
+ # @rails_node = stub_everything 'rails_node'
+ # Puppet::Rails::Host.stubs(:find_by_name).returns(@rails_node)
+ # end
+ #
+ # it "should connect to the database" do
+ # Puppet::Rails.expects(:connect)
+ # subject.clean_storeconfigs(@host, false)
+ # end
+ #
+ # it "should find the right host entry" do
+ # Puppet::Rails::Host.expects(:find_by_name).with(@host).returns(@rails_node)
+ # subject.clean_storeconfigs(@host, false)
+ # end
+ #
+ # describe "without unexport" do
+ # it "should remove the host and it's content" do
+ # @rails_node.expects(:destroy)
+ # subject.clean_storeconfigs(@host, false)
+ # end
+ # end
+ #
+ # describe "with unexport" do
+ # before :each do
+ # @rails_node.stubs(:id).returns(1234)
+ #
+ # @type = stub_everything 'type'
+ # @type.stubs(:validattr?).with(:ensure).returns(true)
+ #
+ # @ensure_name = stub_everything 'ensure_name', :id => 23453
+ # Puppet::Rails::ParamName.stubs(:find_or_create_by_name).returns(@ensure_name)
+ #
+ # @param_values = stub_everything 'param_values'
+ # @resource = stub_everything 'resource', :param_values => @param_values, :restype => "File"
+ # Puppet::Rails::Resource.stubs(:find).returns([@resource])
+ # end
+ #
+ # it "should find all resources" do
+ # Puppet::Rails::Resource.expects(:find).with(:all, {:include => {:param_values => :param_name}, :conditions => ["exported=? AND host_id=?", true, 1234]}).returns([])
+ #
+ # subject.clean_storeconfigs(@host, true)
+ # end
+ #
+ # describe "with an exported native type" do
+ # before :each do
+ # Puppet::Type.stubs(:type).returns(@type)
+ # @type.expects(:validattr?).with(:ensure).returns(true)
+ # end
+ #
+ # it "should test a native type for ensure as an attribute" do
+ # subject.clean_storeconfigs(@host, true)
+ # end
+ #
+ # it "should delete the old ensure parameter" do
+ # ensure_param = stub 'ensure_param', :id => 12345, :line => 12
+ # @param_values.stubs(:find).returns(ensure_param)
+ # Puppet::Rails::ParamValue.expects(:delete).with(12345);
+ # subject.clean_storeconfigs(@host, true)
+ # end
+ #
+ # it "should add an ensure => absent parameter" do
+ # @param_values.expects(:create).with(:value => "absent",
+ # :line => 0,
+ # :param_name => @ensure_name)
+ # subject.clean_storeconfigs(@host, true)
+ # end
+ # end
+ #
+ # describe "with an exported definition" do
+ # it "should try to lookup a definition and test it for the ensure argument" do
+ # Puppet::Type.stubs(:type).returns(nil)
+ # definition = stub_everything 'definition', :arguments => { 'ensure' => 'present' }
+ # Puppet::Resource::TypeCollection.any_instance.expects(:find_definition).with('', "File").returns(definition)
+ # subject.clean_storeconfigs(@host, true)
+ # end
+ # end
+ #
+ # it "should not unexport the resource of an unknown type" do
+ # Puppet::Type.stubs(:type).returns(nil)
+ # Puppet::Resource::TypeCollection.any_instance.expects(:find_definition).with('', "File").returns(nil)
+ # Puppet::Rails::ParamName.expects(:find_or_create_by_name).never
+ # subject.clean_storeconfigs(@host)
+ # end
+ #
+ # it "should not unexport the resource of a not ensurable native type" do
+ # Puppet::Type.stubs(:type).returns(@type)
+ # @type.expects(:validattr?).with(:ensure).returns(false)
+ # Puppet::Resource::TypeCollection.any_instance.expects(:find_definition).with('', "File").returns(nil)
+ # Puppet::Rails::ParamName.expects(:find_or_create_by_name).never
+ # subject.clean_storeconfigs(@host, true)
+ # end
+ #
+ # it "should not unexport the resource of a not ensurable definition" do
+ # Puppet::Type.stubs(:type).returns(nil)
+ # definition = stub_everything 'definition', :arguments => { 'foobar' => 'someValue' }
+ # Puppet::Resource::TypeCollection.any_instance.expects(:find_definition).with('', "File").returns(definition)
+ # Puppet::Rails::ParamName.expects(:find_or_create_by_name).never
+ # subject.clean_storeconfigs(@host, true)
+ # end
+ # end
+ # end
+ end
+ end
end
diff --git a/spec/unit/indirector/report/processor_spec.rb b/spec/unit/indirector/report/processor_spec.rb
index fbc70a104..c64cc7eff 100755
--- a/spec/unit/indirector/report/processor_spec.rb
+++ b/spec/unit/indirector/report/processor_spec.rb
@@ -15,15 +15,21 @@ describe Puppet::Transaction::Report::Processor do
it "should provide a method for saving reports" do
Puppet::Transaction::Report::Processor.new.should respond_to(:save)
end
+
+ it "should provide a method for cleaning reports" do
+ Puppet::Transaction::Report::Processor.new.should respond_to(:destroy)
+ end
+
end
-describe Puppet::Transaction::Report::Processor, " when saving a report" do
+describe Puppet::Transaction::Report::Processor, " when processing a report" do
before do
Puppet.settings.stubs(:use)
@reporter = Puppet::Transaction::Report::Processor.new
+ @request = stub 'request', :instance => stub("report", :host => 'hostname'), :key => 'node'
end
- it "should not process the report if reports are set to 'none'" do
+ it "should not save the report if reports are set to 'none'" do
Puppet::Reports.expects(:report).never
Puppet[:reports] = 'none'
@@ -34,9 +40,24 @@ describe Puppet::Transaction::Report::Processor, " when saving a report" do
@reporter.save(request)
end
- it "should process the report with each configured report type" do
+ it "should save the report with each configured report type" do
Puppet.settings.stubs(:value).with(:reports).returns("one,two")
@reporter.send(:reports).should == %w{one two}
+
+ Puppet::Reports.expects(:report).with('one')
+ Puppet::Reports.expects(:report).with('two')
+
+ @reporter.save(@request)
+ end
+
+ it "should destroy reports for each processor that responds to destroy" do
+ Puppet.settings.stubs(:value).with(:reports).returns("http,store")
+ http_report = mock()
+ store_report = mock()
+ store_report.expects(:destroy).with(@request.key)
+ Puppet::Reports.expects(:report).with('http').returns(http_report)
+ Puppet::Reports.expects(:report).with('store').returns(store_report)
+ @reporter.destroy(@request)
end
end
diff --git a/spec/unit/indirector/yaml_spec.rb b/spec/unit/indirector/yaml_spec.rb
index c43dbcaf6..29f6d466f 100755
--- a/spec/unit/indirector/yaml_spec.rb
+++ b/spec/unit/indirector/yaml_spec.rb
@@ -154,5 +154,23 @@ describe Puppet::Indirector::Yaml, " when choosing file location" do
Dir.expects(:glob).with(:glob).returns []
@store.search(@request).should == []
end
+
+ describe Puppet::Indirector::Yaml, " when destroying" do
+ it "should unlink the right yaml file if it exists" do
+ path = File.join("/what/ever", @store.class.indirection_name.to_s, @request.key.to_s + ".yaml")
+ File.expects(:exists?).with(path).returns true
+ File.expects(:unlink).with(path)
+
+ @store.destroy(@request)
+ end
+
+ it "should not unlink the yaml file if it does not exists" do
+ path = File.join("/what/ever", @store.class.indirection_name.to_s, @request.key.to_s + ".yaml")
+ File.expects(:exists?).with(path).returns false
+ File.expects(:unlink).with(path).never
+
+ @store.destroy(@request)
+ end
+ end
end
end
diff --git a/spec/unit/interface/action_spec.rb b/spec/unit/interface/action_spec.rb
index c3f08e817..6b68eb149 100755
--- a/spec/unit/interface/action_spec.rb
+++ b/spec/unit/interface/action_spec.rb
@@ -552,7 +552,7 @@ describe Puppet::Interface::Action do
context "#validate_and_clean" do
subject do
Puppet::Interface.new(:validate_args, '1.0.0') do
- script :test do |options| true end
+ script :test do |options| options end
end
end
@@ -576,6 +576,12 @@ describe Puppet::Interface::Action do
expect { subject.test :unknown => true, :unseen => false }.
to raise_error ArgumentError, /Unknown options passed: unknown, unseen/
end
+
+ it "should accept 'global' options from settings" do
+ expect {
+ subject.test(:certname => "true").should == { :certname => "true" }
+ }.not_to raise_error
+ end
end
context "default option values" do
diff --git a/spec/unit/network/handler/fileserver_spec.rb b/spec/unit/network/handler/fileserver_spec.rb
index 93f124882..2b8094b8b 100755
--- a/spec/unit/network/handler/fileserver_spec.rb
+++ b/spec/unit/network/handler/fileserver_spec.rb
@@ -25,6 +25,38 @@ describe Puppet::Network::Handler::FileServer do
@mount = Puppet::Network::Handler::FileServer::Mount.new("some_path", @basedir)
end
+ describe "when parsing the fileserver.conf" do
+ it "should create a valid mount when a valid conf is read" do
+ config_file = tmpfile('fileserver.conf')
+ mountdir = tmpdir('mountdir')
+
+ conf_text = <<-HEREDOC
+ [mymount]
+ path #{mountdir}
+ allow anyone.com
+ deny nobody.com
+ HEREDOC
+ File.open(config_file, 'w') { |f| f.write conf_text }
+
+ fs = Puppet::Network::Handler::FileServer.new(:Config => config_file)
+ mounts = fs.instance_variable_get(:@mounts)
+ mount = mounts["mymount"]
+ mount.path == mountdir
+ mount.instance_variable_get(:@declarations).map {|d| d.pattern}.should =~ [["com", "nobody"], ["com", "anyone"]]
+ end
+
+ ['path', 'allow', 'deny'].each do |arg|
+ it "should error if config file doesn't specify a mount for #{arg} argument" do
+ config_file = tmpfile('fileserver.conf')
+ File.open(config_file, 'w') { |f| f.puts "#{arg} 127.0.0.1/24" }
+
+ expect {
+ Puppet::Network::Handler::FileServer.new(:Config => config_file)
+ }.should raise_error(Puppet::Network::Handler::FileServerError, "No mount specified for argument #{arg} 127.0.0.1/24")
+ end
+ end
+ end
+
it "should list a single directory" do
@mount.list("/", false, false).should == [["/", "directory"]]
end