summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStig Sandbeck Mathisen <ssm@debian.org>2013-10-08 09:19:01 +0200
committerStig Sandbeck Mathisen <ssm@debian.org>2013-10-08 09:19:01 +0200
commit90ffd9c9413975b3e6af205b1962364c06128f31 (patch)
tree77092c11cfa0805893e5b77fdaee18b15f56f5fb
parent6a7cea9da38e05c36cfccc04de363e092b87dffb (diff)
parentae6e887eb3b09629a5e45b827ac0ca366c3100ea (diff)
downloadpuppet-upstream/3.3.1.tar.gz
Imported Upstream version 3.3.1upstream/3.3.1
-rw-r--r--ext/debian/changelog6
-rw-r--r--ext/ips/puppet.p5m4
-rw-r--r--ext/redhat/puppet.spec8
-rw-r--r--lib/puppet/configurer.rb8
-rw-r--r--lib/puppet/defaults.rb24
-rw-r--r--lib/puppet/file_bucket/file.rb11
-rw-r--r--lib/puppet/forge/repository.rb10
-rw-r--r--lib/puppet/graph/simple_graph.rb2
-rw-r--r--lib/puppet/indirector/request.rb18
-rw-r--r--lib/puppet/indirector/rest.rb23
-rw-r--r--lib/puppet/indirector/status/local.rb4
-rw-r--r--lib/puppet/indirector/yaml.rb22
-rw-r--r--lib/puppet/network/formats.rb26
-rw-r--r--lib/puppet/network/http.rb1
-rw-r--r--lib/puppet/network/http/handler.rb18
-rw-r--r--lib/puppet/network/http/rack/rest.rb18
-rw-r--r--lib/puppet/parser/functions/create_resources.rb8
-rw-r--r--lib/puppet/parser/yaml_trimmer.rb4
-rwxr-xr-xlib/puppet/provider/package/dpkg.rb3
-rwxr-xr-xlib/puppet/provider/package/rpm.rb6
-rwxr-xr-xlib/puppet/provider/parsedfile.rb15
-rw-r--r--lib/puppet/resource/status.rb2
-rw-r--r--lib/puppet/status.rb8
-rw-r--r--lib/puppet/transaction/additional_resource_generator.rb2
-rw-r--r--lib/puppet/transaction/event.rb2
-rw-r--r--lib/puppet/transaction/report.rb8
-rw-r--r--lib/puppet/util/monkey_patches.rb52
-rw-r--r--lib/puppet/util/storage.rb13
-rw-r--r--lib/puppet/util/yaml.rb23
-rw-r--r--lib/puppet/util/zaml.rb16
-rw-r--r--lib/puppet/version.rb2
-rwxr-xr-xspec/integration/type/file_spec.rb4
-rw-r--r--spec/lib/puppet_spec/matchers.rb10
-rwxr-xr-xspec/unit/agent_spec.rb2
-rwxr-xr-xspec/unit/file_bucket/file_spec.rb32
-rwxr-xr-xspec/unit/indirector/certificate/rest_spec.rb1
-rwxr-xr-xspec/unit/indirector/report/rest_spec.rb1
-rwxr-xr-xspec/unit/indirector/request_spec.rb9
-rwxr-xr-xspec/unit/indirector/rest_spec.rb25
-rwxr-xr-xspec/unit/indirector/run/local_spec.rb4
-rw-r--r--spec/unit/indirector/status/local_spec.rb11
-rwxr-xr-xspec/unit/indirector/status/rest_spec.rb2
-rwxr-xr-xspec/unit/indirector/yaml_spec.rb56
-rwxr-xr-xspec/unit/network/formats_spec.rb32
-rwxr-xr-xspec/unit/network/http/handler_spec.rb42
-rwxr-xr-xspec/unit/network/http/rack/rest_spec.rb19
-rwxr-xr-xspec/unit/node/environment_spec.rb2
-rwxr-xr-xspec/unit/parser/files_spec.rb5
-rw-r--r--spec/unit/pops/adaptable_spec.rb2
-rwxr-xr-xspec/unit/provider/package/dpkg_spec.rb66
-rwxr-xr-xspec/unit/provider/package/rpm_spec.rb24
-rwxr-xr-xspec/unit/provider/parsedfile_spec.rb133
-rwxr-xr-xspec/unit/settings/file_setting_spec.rb4
-rwxr-xr-xspec/unit/transaction/report_spec.rb6
-rwxr-xr-xspec/unit/transaction/resource_harness_spec.rb2
-rwxr-xr-xspec/unit/util/monkey_patches_spec.rb13
-rwxr-xr-xspec/unit/util/storage_spec.rb98
-rw-r--r--spec/unit/util/yaml_spec.rb41
-rwxr-xr-xspec/unit/util_spec.rb1
59 files changed, 640 insertions, 374 deletions
diff --git a/ext/debian/changelog b/ext/debian/changelog
index 13adb524f..b94c8e5b7 100644
--- a/ext/debian/changelog
+++ b/ext/debian/changelog
@@ -1,8 +1,8 @@
-puppet (3.3.0-1puppetlabs1) hardy lucid natty oneiric unstable sid squeeze wheezy precise; urgency=low
+puppet (3.3.1-1puppetlabs1) hardy lucid natty oneiric unstable sid squeeze wheezy precise; urgency=low
- * Update to version 3.3.0-1puppetlabs1
+ * Update to version 3.3.1-1puppetlabs1
- -- Puppet Labs Release <info@puppetlabs.com> Thu, 12 Sep 2013 13:57:55 -0700
+ -- Puppet Labs Release <info@puppetlabs.com> Mon, 07 Oct 2013 11:00:57 -0700
puppet (3.2.3-0.1rc0puppetlabs1) lucid unstable sid squeeze wheezy precise quantal raring; urgency=low
diff --git a/ext/ips/puppet.p5m b/ext/ips/puppet.p5m
index 64cacf8f4..06cb710ff 100644
--- a/ext/ips/puppet.p5m
+++ b/ext/ips/puppet.p5m
@@ -1,6 +1,6 @@
-set name=pkg.fmri value=pkg://puppetlabs.com/system/management/puppet@3.3.0,12.4.1-0
+set name=pkg.fmri value=pkg://puppetlabs.com/system/management/puppet@3.3.1,12.5.0-0
set name=pkg.summary value="Puppet, an automated configuration management tool"
-set name=pkg.human-version value="3.3.0"
+set name=pkg.human-version value="3.3.1"
set name=pkg.description value="Puppet, an automated configuration management tool"
set name=info.classification value="org.opensolaris.category.2008:System/Administration and Configuration"
set name=org.opensolaris.consolidation value="puppet"
diff --git a/ext/redhat/puppet.spec b/ext/redhat/puppet.spec
index 2d9bccada..b92662873 100644
--- a/ext/redhat/puppet.spec
+++ b/ext/redhat/puppet.spec
@@ -16,8 +16,8 @@
%endif
# VERSION is subbed out during rake srpm process
-%global realversion 3.3.0
-%global rpmversion 3.3.0
+%global realversion 3.3.1
+%global rpmversion 3.3.1
%global confdir ext/redhat
@@ -391,8 +391,8 @@ fi
rm -rf %{buildroot}
%changelog
-* Thu Sep 12 2013 Puppet Labs Release <info@puppetlabs.com> - 3.3.0-1
-- Build for 3.3.0
+* Mon Oct 07 2013 Puppet Labs Release <info@puppetlabs.com> - 3.3.1-1
+- Build for 3.3.1
* Thu Jun 27 2013 Matthaus Owens <matthaus@puppetlabs.com> - 3.2.3-0.1rc0
- Bump requires on ruby-rgen to 0.6.5
diff --git a/lib/puppet/configurer.rb b/lib/puppet/configurer.rb
index 921015750..6547f7458 100644
--- a/lib/puppet/configurer.rb
+++ b/lib/puppet/configurer.rb
@@ -142,6 +142,7 @@ class Puppet::Configurer
init_storage
Puppet::Util::Log.newdestination(report)
+
begin
unless Puppet[:node_name_fact].empty?
query_options = get_facts(options)
@@ -210,13 +211,6 @@ class Puppet::Configurer
Puppet::Transaction::Report.indirection.save(report, nil, :environment => @environment) if Puppet[:report]
rescue => detail
Puppet.log_exception(detail, "Could not send report: #{detail}")
- if detail.message =~ /Could not intern from pson.*Puppet::Transaction::Report/
- Puppet.notice("There was an error sending the report.")
- Puppet.notice("This error is possibly caused by sending the report in a format the master can not handle.")
- Puppet.notice("A puppet master older than 3.2.2 can not handle pson reports.")
- Puppet.notice("Set report_serialization_format=yaml on the agent to send reports to older masters.")
- Puppet.notice("See http://links.puppetlabs.com/deprecate_yaml_on_network for more information.")
- end
end
def save_last_run_summary(report)
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index 793e88c29..7a161fc57 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -1092,12 +1092,24 @@ EOT
This should almost always be set to `pson`. It can be temporarily set to
`yaml` to let agents using this Puppet version connect to a puppet master
- running Puppet 3.0.0 through 3.2.4.",
- :hook => proc do |value|
- if value == "yaml"
- Puppet.deprecation_warning("Sending reports in 'yaml' is deprecated; use 'pson' instead.")
- end
- end
+ running Puppet 3.0.0 through 3.2.x.
+
+ Note that this is set to 'yaml' automatically if the agent detects an
+ older master, so should never need to be set explicitly."
+ },
+ :legacy_query_parameter_serialization => {
+ :default => false,
+ :type => :boolean,
+ :desc => "The serialization format to use when sending file_metadata
+ query parameters. Older versions of puppet master expect certain query
+ parameters to be serialized as yaml, which is deprecated.
+
+ This should almost always be false. It can be temporarily set to true
+ to let agents using this Puppet version connect to a puppet master
+ running Puppet 3.0.0 through 3.2.x.
+
+ Note that this is set to true automatically if the agent detects an
+ older master, so should never need to be set explicitly."
},
:agent_catalog_run_lockfile => {
:default => "$statedir/agent_catalog_run.lock",
diff --git a/lib/puppet/file_bucket/file.rb b/lib/puppet/file_bucket/file.rb
index cd9f5ab5a..15e1cd76b 100644
--- a/lib/puppet/file_bucket/file.rb
+++ b/lib/puppet/file_bucket/file.rb
@@ -14,12 +14,16 @@ class Puppet::FileBucket::File
attr :bucket_path
def self.supported_formats
+ [:s, :pson]
+ end
+
+ def self.default_format
# This should really be :raw, like is done for Puppet::FileServing::Content
# but this class hasn't historically supported `from_raw`, so switching
# would break compatibility between newer 3.x agents talking to older 3.x
# masters. However, to/from_s has been supported and achieves the desired
# result without breaking compatibility.
- [:s]
+ :s
end
def initialize(contents, options = {})
@@ -54,6 +58,11 @@ class Puppet::FileBucket::File
self.new(contents)
end
+ def to_pson
+ Puppet.deprecation_warning("Serializing Puppet::FileBucket::File objects to pson is deprecated.")
+ { "contents" => contents }.to_pson
+ end
+
# This method is deprecated, but cannot be removed for awhile, otherwise
# older agents sending pson couldn't backup to filebuckets on newer masters
def self.from_pson(pson)
diff --git a/lib/puppet/forge/repository.rb b/lib/puppet/forge/repository.rb
index c0c128bcc..75b7a9f4c 100644
--- a/lib/puppet/forge/repository.rb
+++ b/lib/puppet/forge/repository.rb
@@ -1,10 +1,13 @@
require 'net/https'
-require 'zlib'
require 'digest/sha1'
require 'uri'
require 'puppet/util/http_proxy'
require 'puppet/forge/errors'
+if Puppet.features.zlib? && Puppet[:zlib]
+ require 'zlib'
+end
+
class Puppet::Forge
# = Repository
#
@@ -26,9 +29,12 @@ class Puppet::Forge
Net::HTTPHeaderSyntaxError,
Net::ProtocolError,
SocketError,
- Zlib::GzipFile::Error,
]
+ if Puppet.features.zlib? && Puppet[:zlib]
+ NET_HTTP_EXCEPTIONS << Zlib::GzipFile::Error
+ end
+
# Instantiate a new repository instance rooted at the +url+.
# The agent will report +consumer_version+ in the User-Agent to
# the repository.
diff --git a/lib/puppet/graph/simple_graph.rb b/lib/puppet/graph/simple_graph.rb
index 6c68ec617..57174ee67 100644
--- a/lib/puppet/graph/simple_graph.rb
+++ b/lib/puppet/graph/simple_graph.rb
@@ -530,7 +530,7 @@ class Puppet::Graph::SimpleGraph
end
def to_yaml_properties
- (instance_variables + [:@vertices, :@edges] -
+ (super + [:@vertices, :@edges] -
[:@in_to, :@out_from, :@upstream_from, :@downstream_from]).uniq
end
diff --git a/lib/puppet/indirector/request.rb b/lib/puppet/indirector/request.rb
index fd20d56e6..9f95b2f2e 100644
--- a/lib/puppet/indirector/request.rb
+++ b/lib/puppet/indirector/request.rb
@@ -159,9 +159,27 @@ class Puppet::Indirector::Request
# Create the query string, if options are present.
def query_string
return "" if options.nil? || options.empty?
+
+ # For backward compatibility with older (pre-3.3) masters,
+ # this puppet option allows serialization of query parameter
+ # arrays as yaml. This can be removed when we remove yaml
+ # support entirely.
+ if Puppet.settings[:legacy_query_parameter_serialization]
+ replace_arrays_with_yaml
+ end
+
"?" + encode_params(expand_into_parameters(options.to_a))
end
+ def replace_arrays_with_yaml
+ options.each do |key, value|
+ case value
+ when Array
+ options[key] = YAML.dump(value)
+ end
+ end
+ end
+
def expand_into_parameters(data)
data.inject([]) do |params, key_value|
key, value = key_value
diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/rest.rb
index c3ace6950..44c26e78b 100644
--- a/lib/puppet/indirector/rest.rb
+++ b/lib/puppet/indirector/rest.rb
@@ -98,6 +98,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
end
if is_http_200?(response)
+ check_master_version(response)
content_type, body = parse_response(response)
result = deserialize_find(content_type, body)
result.name = request.key if result.respond_to?(:name=)
@@ -112,7 +113,12 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
http_head(request, indirection2uri(request), headers)
end
- !!is_http_200?(response)
+ if is_http_200?(response)
+ check_master_version(response)
+ true
+ else
+ false
+ end
end
def search(request)
@@ -121,6 +127,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
end
if is_http_200?(response)
+ check_master_version(response)
content_type, body = parse_response(response)
deserialize_search(content_type, body) || []
else
@@ -136,6 +143,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
end
if is_http_200?(response)
+ check_master_version(response)
content_type, body = parse_response(response)
deserialize_destroy(content_type, body)
else
@@ -151,6 +159,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
end
if is_http_200?(response)
+ check_master_version(response)
content_type, body = parse_response(response)
deserialize_save(content_type, body)
else
@@ -191,6 +200,18 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
Net::HTTPError.new(message, response)
end
+ def check_master_version response
+ if !response[Puppet::Network::HTTP::HEADER_PUPPET_VERSION] &&
+ (Puppet[:legacy_query_parameter_serialization] == false || Puppet[:report_serialization_format] != "yaml")
+ Puppet.notice "Using less secure serialization of reports and query parameters for compatibility"
+ Puppet.notice "with older puppet master. To remove this notice, please upgrade your master(s) "
+ Puppet.notice "to Puppet 3.3 or newer."
+ Puppet.notice "See http://links.puppetlabs.com/deprecate_yaml_on_network for more information."
+ Puppet[:legacy_query_parameter_serialization] = true
+ Puppet[:report_serialization_format] = "yaml"
+ end
+ end
+
# Returns the content_type, stripping any appended charset, and the
# body, decompressed if necessary (content-encoding is checked inside
# uncompress_body)
diff --git a/lib/puppet/indirector/status/local.rb b/lib/puppet/indirector/status/local.rb
index e64c3ddb0..fc674eea9 100644
--- a/lib/puppet/indirector/status/local.rb
+++ b/lib/puppet/indirector/status/local.rb
@@ -5,6 +5,8 @@ class Puppet::Indirector::Status::Local < Puppet::Indirector::Code
desc "Get status locally. Only used internally."
def find( *anything )
- model.new
+ status = model.new
+ status.version= Puppet.version
+ status
end
end
diff --git a/lib/puppet/indirector/yaml.rb b/lib/puppet/indirector/yaml.rb
index c2e28391a..014994b9d 100644
--- a/lib/puppet/indirector/yaml.rb
+++ b/lib/puppet/indirector/yaml.rb
@@ -1,28 +1,16 @@
require 'puppet/indirector/terminus'
+require 'puppet/util/yaml'
# The base class for YAML indirection termini.
class Puppet::Indirector::Yaml < Puppet::Indirector::Terminus
- if defined?(::Psych::SyntaxError)
- YamlLoadExceptions = [::StandardError, ::ArgumentError, ::Psych::SyntaxError]
- else
- YamlLoadExceptions = [::StandardError, ::ArgumentError]
- end
-
# Read a given name's file in and convert it from YAML.
def find(request)
file = path(request.key)
return nil unless FileTest.exist?(file)
- yaml = nil
- begin
- yaml = ::File.read(file)
- rescue => detail
- raise Puppet::Error, "Could not read YAML data for #{indirection.name} #{request.key}: #{detail}"
- end
-
begin
- return from_yaml(yaml)
- rescue *YamlLoadExceptions => detail
+ return Puppet::Util::Yaml.load_file(file)
+ rescue Puppet::Util::Yaml::YamlLoadError => detail
raise Puppet::Error, "Could not parse YAML data for #{indirection.name} #{request.key}: #{detail}"
end
end
@@ -39,9 +27,7 @@ class Puppet::Indirector::Yaml < Puppet::Indirector::Terminus
Dir.mkdir(basedir) unless FileTest.exist?(basedir)
begin
- Puppet::Util.replace_file(file, 0660) do |f|
- f.print to_yaml(request.instance)
- end
+ Puppet::Util::Yaml.dump(request.instance, file)
rescue TypeError => detail
Puppet.err "Could not save #{self.name} #{request.key}: #{detail}"
end
diff --git a/lib/puppet/network/formats.rb b/lib/puppet/network/formats.rb
index 45d75dc6c..4aaeddedd 100644
--- a/lib/puppet/network/formats.rb
+++ b/lib/puppet/network/formats.rb
@@ -3,18 +3,28 @@ require 'puppet/network/format_handler'
Puppet::Network::FormatHandler.create_serialized_formats(:yaml) do
def intern(klass, text)
data = YAML.load(text, :safe => true, :deserialize_symbols => true)
- return data if data.is_a?(klass)
- klass.from_pson(data)
+ data_to_instance(klass, data)
end
def intern_multiple(klass, text)
- YAML.load(text, :safe => true, :deserialize_symbols => true).collect do |data|
- if data.is_a?(klass)
- data
- else
- klass.from_pson(data)
- end
+ data = YAML.load(text, :safe => true, :deserialize_symbols => true)
+ unless data.respond_to?(:collect)
+ raise Puppet::Network::FormatHandler::FormatError, "Serialized YAML did not contain a collection of instances when calling intern_multiple"
+ end
+
+ data.collect do |datum|
+ data_to_instance(klass, datum)
+ end
+ end
+
+ def data_to_instance(klass, data)
+ return data if data.is_a?(klass)
+
+ unless data.is_a? Hash
+ raise Puppet::Network::FormatHandler::FormatError, "Serialized YAML did not contain a valid instance of #{klass}"
end
+
+ klass.from_pson(data)
end
def render(instance)
diff --git a/lib/puppet/network/http.rb b/lib/puppet/network/http.rb
index 93f23eb8a..3519efd11 100644
--- a/lib/puppet/network/http.rb
+++ b/lib/puppet/network/http.rb
@@ -1,3 +1,4 @@
module Puppet::Network::HTTP
HEADER_ENABLE_PROFILING = "X-Puppet-Profiling"
+ HEADER_PUPPET_VERSION = "X-Puppet-Version"
end
diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb
index c9f7c991d..b8abd80e4 100644
--- a/lib/puppet/network/http/handler.rb
+++ b/lib/puppet/network/http/handler.rb
@@ -84,6 +84,8 @@ module Puppet::Network::HTTP::Handler
request_method = http_method(request)
request_path = path(request)
+ response[Puppet::Network::HTTP::HEADER_PUPPET_VERSION] = Puppet.version
+
configure_profiler(request_headers, request_params)
Puppet::Util::Profiler.profile("Processed request #{request_method} #{request_path}") do
@@ -97,7 +99,7 @@ module Puppet::Network::HTTP::Handler
rescue SystemExit,NoMemoryError
raise
rescue HTTPError => e
- return do_exception(response, e.message, e.status)
+ return do_http_control_exception(response, e)
rescue Exception => e
return do_exception(response, e)
ensure
@@ -121,11 +123,7 @@ module Puppet::Network::HTTP::Handler
status = 403 if status == 400
end
- if exception.is_a?(Exception)
- Puppet.log_exception(exception)
- else
- Puppet.notice(exception.to_s)
- end
+ Puppet.log_exception(exception)
set_content_type(response, "text/plain")
set_response(response, exception.to_s, status)
@@ -219,6 +217,13 @@ module Puppet::Network::HTTP::Handler
private
+ def do_http_control_exception(response, exception)
+ msg = exception.message
+ Puppet.info(msg)
+ set_content_type(response, "text/plain")
+ set_response(response, msg, exception.status)
+ end
+
def report_if_deprecated(format)
if format.name == :yaml || format.name == :b64_zlib_yaml
Puppet.deprecation_warning("YAML in network requests is deprecated and will be removed in a future version. See http://links.puppetlabs.com/deprecate_yaml_on_network")
@@ -250,7 +255,6 @@ module Puppet::Network::HTTP::Handler
def read_body_into_model(model_class, request)
data = body(request).to_s
- raise ArgumentError, "No data to save" if !data or data.empty?
format = request_format(request)
model_class.convert_from(format, data)
diff --git a/lib/puppet/network/http/rack/rest.rb b/lib/puppet/network/http/rack/rest.rb
index b2cfa078d..83d61866b 100644
--- a/lib/puppet/network/http/rack/rest.rb
+++ b/lib/puppet/network/http/rack/rest.rb
@@ -1,4 +1,5 @@
require 'openssl'
+require 'cgi'
require 'puppet/network/http/handler'
require 'puppet/network/http/rack/httphandler'
require 'puppet/util/ssl'
@@ -73,7 +74,15 @@ class Puppet::Network::HTTP::RackREST < Puppet::Network::HTTP::RackHttpHandler
# Return the query params for this request.
def params(request)
- result = decode_params(request.params)
+ if request.post?
+ params = request.params
+ else
+ # rack doesn't support multi-valued query parameters,
+ # e.g. ignore, so parse them ourselves
+ params = CGI.parse(request.query_string)
+ convert_singular_arrays_to_value(params)
+ end
+ result = decode_params(params)
result.merge(extract_client_info(request))
end
@@ -125,4 +134,11 @@ class Puppet::Network::HTTP::RackREST < Puppet::Network::HTTP::RackHttpHandler
result
end
+ def convert_singular_arrays_to_value(hash)
+ hash.each do |key, value|
+ if value.size == 1
+ hash[key] = value.first
+ end
+ end
+ end
end
diff --git a/lib/puppet/parser/functions/create_resources.rb b/lib/puppet/parser/functions/create_resources.rb
index 054b1f70c..733dc4511 100644
--- a/lib/puppet/parser/functions/create_resources.rb
+++ b/lib/puppet/parser/functions/create_resources.rb
@@ -7,11 +7,11 @@ Puppet::Parser::Functions::newfunction(:create_resources, :arity => -3, :doc =>
# A hash of user resources:
$myusers = {
'nick' => { uid => '1330',
- group => allstaff,
- groups => ['developers', 'operations', 'release'], }
+ gid => allstaff,
+ groups => ['developers', 'operations', 'release'], },
'dan' => { uid => '1308',
- group => allstaff,
- groups => ['developers', 'prosvc', 'release'], }
+ gid => allstaff,
+ groups => ['developers', 'prosvc', 'release'], },
}
create_resources(user, $myusers)
diff --git a/lib/puppet/parser/yaml_trimmer.rb b/lib/puppet/parser/yaml_trimmer.rb
index b9e6a260f..657ce9d59 100644
--- a/lib/puppet/parser/yaml_trimmer.rb
+++ b/lib/puppet/parser/yaml_trimmer.rb
@@ -2,8 +2,6 @@ module Puppet::Parser::YamlTrimmer
REMOVE = [:@scope, :@source]
def to_yaml_properties
- r = instance_variables - REMOVE
- r -= skip_for_yaml if respond_to?(:skip_for_yaml)
- r
+ super - REMOVE
end
end
diff --git a/lib/puppet/provider/package/dpkg.rb b/lib/puppet/provider/package/dpkg.rb
index 062091bec..c8528cc4b 100755
--- a/lib/puppet/provider/package/dpkg.rb
+++ b/lib/puppet/provider/package/dpkg.rb
@@ -44,6 +44,7 @@ Puppet::Type.type(:package).provide :dpkg, :parent => Puppet::Provider::Package
self::DPKG_DESCRIPTION_DELIMITER = ':DESC:'
self::DPKG_QUERY_FORMAT_STRING = %Q{'${Status} ${Package} ${Version} #{self::DPKG_DESCRIPTION_DELIMITER} ${Description}\\n#{self::DPKG_DESCRIPTION_DELIMITER}\\n'}
self::FIELDS_REGEX = %r{^(\S+) +(\S+) +(\S+) (\S+) (\S*) #{self::DPKG_DESCRIPTION_DELIMITER} (.*)$}
+ self::DPKG_PACKAGE_NOT_FOUND_REGEX = /no package.*match/i
self::FIELDS= [:desired, :error, :status, :name, :ensure, :description]
self::END_REGEX = %r{^#{self::DPKG_DESCRIPTION_DELIMITER}$}
@@ -59,7 +60,7 @@ Puppet::Type.type(:package).provide :dpkg, :parent => Puppet::Provider::Package
line = pipe.gets
unless hash = parse_line(line)
- Puppet.warning "Failed to match dpkg-query line #{line.inspect}"
+ Puppet.warning "Failed to match dpkg-query line #{line.inspect}" if !self::DPKG_PACKAGE_NOT_FOUND_REGEX.match(line)
return nil
end
diff --git a/lib/puppet/provider/package/rpm.rb b/lib/puppet/provider/package/rpm.rb
index 910669b46..e99e51c7b 100755
--- a/lib/puppet/provider/package/rpm.rb
+++ b/lib/puppet/provider/package/rpm.rb
@@ -13,6 +13,7 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr
# The query format by which we identify installed packages
self::NEVRA_FORMAT = %Q{'%{NAME} %|EPOCH?{%{EPOCH}}:{0}| %{VERSION} %{RELEASE} %{ARCH} #{self::RPM_DESCRIPTION_DELIMITER} %{SUMMARY}\\n'}
self::NEVRA_REGEX = %r{^(\S+) (\S+) (\S+) (\S+) (\S+)(?: #{self::RPM_DESCRIPTION_DELIMITER} ?(.*))?$}
+ self::RPM_PACKAGE_NOT_FOUND_REGEX = /package .+ is not installed/
self::NEVRA_FIELDS = [:name, :epoch, :version, :release, :arch, :description]
commands :rpm => "rpm"
@@ -76,7 +77,6 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr
rescue Puppet::ExecutionFailure
return nil
end
-
# FIXME: We could actually be getting back multiple packages
# for multilib and this will only return the first such package
@property_hash.update(self.class.nevra_to_hash(output))
@@ -150,7 +150,9 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr
line.strip!
hash = {}
- if match = self::NEVRA_REGEX.match(line)
+ if self::RPM_PACKAGE_NOT_FOUND_REGEX.match(line)
+ # pass through, package was not found
+ elsif match = self::NEVRA_REGEX.match(line)
self::NEVRA_FIELDS.zip(match.captures) { |f, v| hash[f] = v }
hash[:provider] = self.name
hash[:ensure] = "#{hash[:version]}-#{hash[:release]}"
diff --git a/lib/puppet/provider/parsedfile.rb b/lib/puppet/provider/parsedfile.rb
index e922d9381..1a13c8df3 100755
--- a/lib/puppet/provider/parsedfile.rb
+++ b/lib/puppet/provider/parsedfile.rb
@@ -64,13 +64,15 @@ class Puppet::Provider::ParsedFile < Puppet::Provider
return unless defined?(@modified) and ! @modified.empty?
flushed = []
- @modified.sort { |a,b| a.to_s <=> b.to_s }.uniq.each do |target|
- Puppet.debug "Flushing #{@resource_type.name} provider target #{target}"
- flush_target(target)
- flushed << target
+ begin
+ @modified.sort { |a,b| a.to_s <=> b.to_s }.uniq.each do |target|
+ Puppet.debug "Flushing #{@resource_type.name} provider target #{target}"
+ flushed << target
+ flush_target(target)
+ end
+ ensure
+ @modified.reject! { |t| flushed.include?(t) }
end
-
- @modified.reject! { |t| flushed.include?(t) }
end
# Make sure our file is backed up, but only back it up once per transaction.
@@ -92,6 +94,7 @@ class Puppet::Provider::ParsedFile < Puppet::Provider
records = target_records(target).reject { |r|
r[:ensure] == :absent
}
+
target_object(target).write(to_file(records))
end
diff --git a/lib/puppet/resource/status.rb b/lib/puppet/resource/status.rb
index 24332a599..6bfe73b2b 100644
--- a/lib/puppet/resource/status.rb
+++ b/lib/puppet/resource/status.rb
@@ -135,7 +135,7 @@ module Puppet
end
def to_yaml_properties
- YAML_ATTRIBUTES & instance_variables
+ YAML_ATTRIBUTES & super
end
private
diff --git a/lib/puppet/status.rb b/lib/puppet/status.rb
index 55bcc3d41..9ad55668b 100644
--- a/lib/puppet/status.rb
+++ b/lib/puppet/status.rb
@@ -29,4 +29,12 @@ class Puppet::Status
def name=(name)
# NOOP
end
+
+ def version
+ @status['version']
+ end
+
+ def version=(version)
+ @status['version'] = version
+ end
end
diff --git a/lib/puppet/transaction/additional_resource_generator.rb b/lib/puppet/transaction/additional_resource_generator.rb
index 60a2af2eb..ef59ce2ef 100644
--- a/lib/puppet/transaction/additional_resource_generator.rb
+++ b/lib/puppet/transaction/additional_resource_generator.rb
@@ -38,7 +38,7 @@ class Puppet::Transaction::AdditionalResourceGenerator
generated = replace_duplicates_with_catalog_resources(resource.eval_generate)
return false if generated.empty?
rescue => detail
- resource.log_exception(detail, "Failed to generate additional resources using 'eval_generate: #{detail}")
+ resource.log_exception(detail, "Failed to generate additional resources using 'eval_generate': #{detail}")
return false
end
add_resources(generated, resource)
diff --git a/lib/puppet/transaction/event.rb b/lib/puppet/transaction/event.rb
index 0af7a8f63..c832665c6 100644
--- a/lib/puppet/transaction/event.rb
+++ b/lib/puppet/transaction/event.rb
@@ -83,7 +83,7 @@ class Puppet::Transaction::Event
end
def to_yaml_properties
- YAML_ATTRIBUTES & instance_variables
+ YAML_ATTRIBUTES & super
end
private
diff --git a/lib/puppet/transaction/report.rb b/lib/puppet/transaction/report.rb
index 7223a5fba..92e685f42 100644
--- a/lib/puppet/transaction/report.rb
+++ b/lib/puppet/transaction/report.rb
@@ -312,11 +312,15 @@ class Puppet::Transaction::Report
# @api private
#
def to_yaml_properties
- instance_variables - [:@external_times]
+ super - [:@external_times]
end
def self.supported_formats
- [Puppet[:report_serialization_format].intern]
+ [:pson, :yaml]
+ end
+
+ def self.default_format
+ Puppet[:report_serialization_format].intern
end
private
diff --git a/lib/puppet/util/monkey_patches.rb b/lib/puppet/util/monkey_patches.rb
index 194331c01..b593ae3d3 100644
--- a/lib/puppet/util/monkey_patches.rb
+++ b/lib/puppet/util/monkey_patches.rb
@@ -161,58 +161,6 @@ class Range
alias_method :&, :intersection unless method_defined? :&
end
-########################################################################
-# The return type of `instance_variables` changes between Ruby 1.8 and 1.9
-# releases; it used to return an array of strings in the form "@foo", but
-# now returns an array of symbols in the form :@foo.
-#
-# Nothing else in the stack cares which form you get - you can pass the
-# string or symbol to things like `instance_variable_set` and they will work
-# transparently.
-#
-# Having the same form in all releases of Puppet is a win, though, so we
-# pick a unification and enforce than on all releases. That way developers
-# who do set math on them (eg: for YAML rendering) don't have to handle the
-# distinction themselves.
-#
-# In the sane tradition, we bring older releases into conformance with newer
-# releases, so we return symbols rather than strings, to be more like the
-# future versions of Ruby are.
-#
-# We also carefully support reloading, by only wrapping when we don't
-# already have the original version of the method aliased away somewhere.
-if RUBY_VERSION[0,3] == '1.8'
- unless Object.respond_to?(:puppet_original_instance_variables)
-
- # Add our wrapper to the method.
- class Object
- alias :puppet_original_instance_variables :instance_variables
-
- def instance_variables
- puppet_original_instance_variables.map(&:to_sym)
- end
- end
-
- # The one place that Ruby 1.8 assumes something about the return format of
- # the `instance_variables` method is actually kind of odd, because it uses
- # eval to get at instance variables of another object.
- #
- # This takes the original code and applies replaces instance_eval with
- # instance_variable_get through it. All other bugs in the original (such
- # as equality depending on the instance variables having the same order
- # without any promise from the runtime) are preserved. --daniel 2012-03-11
- require 'resolv'
- class Resolv::DNS::Resource
- def ==(other) # :nodoc:
- return self.class == other.class &&
- self.instance_variables == other.instance_variables &&
- self.instance_variables.collect {|name| self.instance_variable_get name} ==
- other.instance_variables.collect {|name| other.instance_variable_get name}
- end
- end
- end
-end
-
# (#19151) Reject all SSLv2 ciphers and handshakes
require 'openssl'
class OpenSSL::SSL::SSLContext
diff --git a/lib/puppet/util/storage.rb b/lib/puppet/util/storage.rb
index c56cdd1de..32d744862 100644
--- a/lib/puppet/util/storage.rb
+++ b/lib/puppet/util/storage.rb
@@ -1,6 +1,7 @@
require 'yaml'
require 'sync'
require 'singleton'
+require 'puppet/util/yaml'
# a class for storing state
class Puppet::Util::Storage
@@ -32,12 +33,10 @@ class Puppet::Util::Storage
def self.clear
@@state.clear
- Storage.init
end
def self.init
@@state = {}
- @@splitchar = "\t"
end
self.init
@@ -47,7 +46,7 @@ class Puppet::Util::Storage
filename = Puppet[:statefile]
unless File.exists?(filename)
- self.init unless !@@state.nil?
+ self.init if @@state.nil?
return
end
unless File.file?(filename)
@@ -56,8 +55,8 @@ class Puppet::Util::Storage
end
Puppet::Util.benchmark(:debug, "Loaded state") do
begin
- @@state = YAML.load(::File.read(filename))
- rescue => detail
+ @@state = Puppet::Util::Yaml.load_file(filename)
+ rescue Puppet::Util::Yaml::YamlLoadError => detail
Puppet.err "Checksumfile #{filename} is corrupt (#{detail}); replacing"
begin
@@ -84,9 +83,7 @@ class Puppet::Util::Storage
Puppet.info "Creating state file #{Puppet[:statefile]}" unless FileTest.exist?(Puppet[:statefile])
Puppet::Util.benchmark(:debug, "Stored state") do
- Puppet::Util.replace_file(Puppet[:statefile], 0660) do |fh|
- fh.print YAML.dump(@@state)
- end
+ Puppet::Util::Yaml.dump(@@state, Puppet[:statefile])
end
end
end
diff --git a/lib/puppet/util/yaml.rb b/lib/puppet/util/yaml.rb
new file mode 100644
index 000000000..d0c37ae77
--- /dev/null
+++ b/lib/puppet/util/yaml.rb
@@ -0,0 +1,23 @@
+require 'yaml'
+
+module Puppet::Util::Yaml
+ if defined?(::Psych::SyntaxError)
+ YamlLoadExceptions = [::StandardError, ::Psych::SyntaxError]
+ else
+ YamlLoadExceptions = [::StandardError]
+ end
+
+ class YamlLoadError < Puppet::Error; end
+
+ def self.load_file(filename)
+ YAML.load_file(filename)
+ rescue *YamlLoadExceptions => detail
+ raise YamlLoadError.new(detail.message, detail)
+ end
+
+ def self.dump(structure, filename)
+ Puppet::Util.replace_file(filename, 0660) do |fh|
+ YAML.dump(structure, fh)
+ end
+ end
+end
diff --git a/lib/puppet/util/zaml.rb b/lib/puppet/util/zaml.rb
index 1915d1468..abd36a033 100644
--- a/lib/puppet/util/zaml.rb
+++ b/lib/puppet/util/zaml.rb
@@ -171,16 +171,28 @@ end
################################################################
class Object
- def to_yaml_properties
- instance_variables # default YAML behaviour.
+ # Users of this method need to do set math consistently with the
+ # result. Since #instance_variables returns strings in 1.8 and symbols
+ # on 1.9, standardize on symbols
+ if RUBY_VERSION[0,3] == '1.8'
+ def to_yaml_properties
+ instance_variables.map(&:to_sym)
+ end
+ else
+ def to_yaml_properties
+ instance_variables
+ end
end
+
def yaml_property_munge(x)
x
end
+
def zamlized_class_name(root)
cls = self.class
"!ruby/#{root.name.downcase}#{cls == root ? '' : ":#{cls.respond_to?(:name) ? cls.name : cls}"}"
end
+
def to_zaml(z)
z.first_time_only(self) {
z.emit(zamlized_class_name(Object))
diff --git a/lib/puppet/version.rb b/lib/puppet/version.rb
index b0ace7de6..9f9f738be 100644
--- a/lib/puppet/version.rb
+++ b/lib/puppet/version.rb
@@ -7,7 +7,7 @@
module Puppet
- PUPPETVERSION = '3.3.0'
+ PUPPETVERSION = '3.3.1'
##
# version is a public API method intended to always provide a fast and
diff --git a/spec/integration/type/file_spec.rb b/spec/integration/type/file_spec.rb
index 6fa71a11d..5377251fd 100755
--- a/spec/integration/type/file_spec.rb
+++ b/spec/integration/type/file_spec.rb
@@ -1004,8 +1004,8 @@ describe Puppet::Type.type(:file) do
catalog.add_resource file
catalog.apply
- get_owner(path).should == 'S-1-5-32-544'
- get_group(path).should == 'S-1-0-0'
+ get_owner(path).should =~ /^S\-1\-5\-.*$/
+ get_group(path).should =~ /^S\-1\-0\-0.*$/
get_mode(path).should == 0644
end
end
diff --git a/spec/lib/puppet_spec/matchers.rb b/spec/lib/puppet_spec/matchers.rb
index 5725f4b6d..67a5f4779 100644
--- a/spec/lib/puppet_spec/matchers.rb
+++ b/spec/lib/puppet_spec/matchers.rb
@@ -103,3 +103,13 @@ RSpec::Matchers.define :equal_attributes_of do |expected|
end
end
end
+
+RSpec::Matchers.define :be_one_of do |*expected|
+ match do |actual|
+ expected.include? actual
+ end
+
+ failure_message_for_should do |actual|
+ "expected #{actual.inspect} to be one of #{expected.map(&:inspect).join(' or ')}"
+ end
+end
diff --git a/spec/unit/agent_spec.rb b/spec/unit/agent_spec.rb
index 83524eae8..536fb47de 100755
--- a/spec/unit/agent_spec.rb
+++ b/spec/unit/agent_spec.rb
@@ -20,6 +20,8 @@ end
describe Puppet::Agent do
before do
+ Puppet::Status.indirection.stubs(:find).returns Puppet::Status.new("version" => Puppet.version)
+
@agent = Puppet::Agent.new(AgentTestClient, false)
# So we don't actually try to hit the filesystem.
diff --git a/spec/unit/file_bucket/file_spec.rb b/spec/unit/file_bucket/file_spec.rb
index 9add6d52c..0269142a1 100755
--- a/spec/unit/file_bucket/file_spec.rb
+++ b/spec/unit/file_bucket/file_spec.rb
@@ -15,18 +15,28 @@ describe Puppet::FileBucket::File do
let(:bucketdir) { Puppet[:bucketdir] = tmpdir('bucket') }
let(:destdir) { File.join(bucketdir, "8/b/3/7/0/2/a/d/#{digest}") }
- it "defines its supported format to be `:s`" do
- expect(Puppet::FileBucket::File.supported_formats).to eq([:s])
+ it "defaults to serializing to `:s`" do
+ expect(Puppet::FileBucket::File.default_format).to eq(:s)
end
- it "serializes to `:s`" do
- expect(Puppet::FileBucket::File.new(contents).to_s).to eq(contents)
+ it "accepts s and pson" do
+ expect(Puppet::FileBucket::File.supported_formats).to include(:s, :pson)
end
- it "deserializes from `:s`" do
- file = Puppet::FileBucket::File.from_s(contents)
+ it "can make a round trip through `s`" do
+ file = Puppet::FileBucket::File.new(contents)
- expect(file.contents).to eq(contents)
+ tripped = Puppet::FileBucket::File.convert_from(:s, file.render)
+
+ expect(tripped.contents).to eq(contents)
+ end
+
+ it "can make a round trip through `pson`" do
+ file = Puppet::FileBucket::File.new(contents)
+
+ tripped = Puppet::FileBucket::File.convert_from(:pson, file.render(:pson))
+
+ expect(tripped.contents).to eq(contents)
end
it "should raise an error if changing content" do
@@ -76,12 +86,8 @@ describe Puppet::FileBucket::File do
end
it "should convert the contents to PSON" do
- # The model class no longer defines to_pson and it is not a supported
- # format, but pson monkey patches Object#to_pson to return
- # Object#to_s.to_pson, and it monkey patches String#to_pson to wrap the
- # returned string in quotes. So it works in a way that is completely
- # unexpected, and it doesn't round-trip correctly, awesome.
- Puppet::FileBucket::File.new("file contents").to_pson.should == '"file contents"'
+ Puppet.expects(:deprecation_warning).with('Serializing Puppet::FileBucket::File objects to pson is deprecated.')
+ Puppet::FileBucket::File.new("file contents").to_pson.should == '{"contents":"file contents"}'
end
it "should load from PSON" do
diff --git a/spec/unit/indirector/certificate/rest_spec.rb b/spec/unit/indirector/certificate/rest_spec.rb
index dcea747f9..c8f304a67 100755
--- a/spec/unit/indirector/certificate/rest_spec.rb
+++ b/spec/unit/indirector/certificate/rest_spec.rb
@@ -51,6 +51,7 @@ rn/G
response = stub 'response', :code => "200", :body => cert_string
response.stubs(:[]).with('content-type').returns "text/plain"
response.stubs(:[]).with('content-encoding')
+ response.stubs(:[]).with(Puppet::Network::HTTP::HEADER_PUPPET_VERSION).returns(Puppet.version)
network.stubs(:verify_callback=)
network.expects(:get).returns response
diff --git a/spec/unit/indirector/report/rest_spec.rb b/spec/unit/indirector/report/rest_spec.rb
index f2c443acf..22dfb0f0b 100755
--- a/spec/unit/indirector/report/rest_spec.rb
+++ b/spec/unit/indirector/report/rest_spec.rb
@@ -36,6 +36,7 @@ describe Puppet::Transaction::Report::Rest do
obj = stub('http 200 ok', :code => code.to_s, :body => body)
obj.stubs(:[]).with('content-type').returns(content_type)
obj.stubs(:[]).with('content-encoding').returns(encoding)
+ obj.stubs(:[]).with(Puppet::Network::HTTP::HEADER_PUPPET_VERSION).returns(Puppet.version)
obj
end
diff --git a/spec/unit/indirector/request_spec.rb b/spec/unit/indirector/request_spec.rb
index 46de7c99d..c43c46709 100755
--- a/spec/unit/indirector/request_spec.rb
+++ b/spec/unit/indirector/request_spec.rb
@@ -334,6 +334,15 @@ describe Puppet::Indirector::Request do
}
end
+ it "should convert an array of values into a single yaml entry when in legacy mode" do
+ Puppet[:legacy_query_parameter_serialization] = true
+ request = a_request_with_options(:one => %w{one two})
+
+ the_parsed_query_string_from(request).should == {
+ "one" => ["--- \n - one\n - two"]
+ }
+ end
+
it "should stringify simple data types inside an array" do
request = a_request_with_options(:one => ['one', nil])
diff --git a/spec/unit/indirector/rest_spec.rb b/spec/unit/indirector/rest_spec.rb
index 8a3fbca7f..787c4cb5e 100755
--- a/spec/unit/indirector/rest_spec.rb
+++ b/spec/unit/indirector/rest_spec.rb
@@ -4,9 +4,30 @@ require 'puppet/indirector'
require 'puppet/indirector/errors'
require 'puppet/indirector/rest'
-# Just one from each category since the code makes no real distinctions
HTTP_ERROR_CODES = [300, 400, 500]
+
+# Just one from each category since the code makes no real distinctions
shared_examples_for "a REST terminus method" do |terminus_method|
+ describe "when talking to an older master" do
+ it "should set backward compatibility settings" do
+ response.stubs(:[]).with(Puppet::Network::HTTP::HEADER_PUPPET_VERSION).returns nil
+
+ terminus.send(terminus_method, request)
+ Puppet[:report_serialization_format].should == 'yaml'
+ Puppet[:legacy_query_parameter_serialization].should == true
+ end
+ end
+
+ describe "when talking to a 3.3.1 master" do
+ it "should not set backward compatibility settings" do
+ response.stubs(:[]).with(Puppet::Network::HTTP::HEADER_PUPPET_VERSION).returns "3.3.1"
+
+ terminus.send(terminus_method, request)
+ Puppet[:report_serialization_format].should == 'pson'
+ Puppet[:legacy_query_parameter_serialization].should == false
+ end
+ end
+
HTTP_ERROR_CODES.each do |code|
describe "when the response code is #{code}" do
let(:response) { mock_response(code, 'error messaged!!!') }
@@ -115,6 +136,7 @@ describe Puppet::Indirector::REST do
obj = stub('http 200 ok', :code => code.to_s, :body => body)
obj.stubs(:[]).with('content-type').returns(content_type)
obj.stubs(:[]).with('content-encoding').returns(encoding)
+ obj.stubs(:[]).with(Puppet::Network::HTTP::HEADER_PUPPET_VERSION).returns(Puppet.version)
obj
end
@@ -174,7 +196,6 @@ describe Puppet::Indirector::REST do
terminus_class.port.should == 543
end
-
it 'should default to :puppet for the srv_service' do
Puppet::Indirector::REST.srv_service.should == :puppet
end
diff --git a/spec/unit/indirector/run/local_spec.rb b/spec/unit/indirector/run/local_spec.rb
index 41a4fd173..ffb5d8332 100755
--- a/spec/unit/indirector/run/local_spec.rb
+++ b/spec/unit/indirector/run/local_spec.rb
@@ -4,11 +4,13 @@ require 'spec_helper'
require 'puppet/indirector/run/local'
describe Puppet::Run::Local do
- it "should be a sublcass of Puppet::Indirector::Code" do
+ it "should be a subclass of Puppet::Indirector::Code" do
Puppet::Run::Local.superclass.should equal(Puppet::Indirector::Code)
end
it "should call runner.run on save and return the runner" do
+ Puppet::Status.indirection.stubs(:find).returns Puppet::Status.new
+
runner = Puppet::Run.new
runner.stubs(:run).returns(runner)
diff --git a/spec/unit/indirector/status/local_spec.rb b/spec/unit/indirector/status/local_spec.rb
new file mode 100644
index 000000000..e1f427f19
--- /dev/null
+++ b/spec/unit/indirector/status/local_spec.rb
@@ -0,0 +1,11 @@
+#! /usr/bin/env ruby
+require 'spec_helper'
+
+require 'puppet/indirector/status/local'
+
+describe Puppet::Indirector::Status::Local do
+ it "should set the puppet version" do
+ Puppet::Status.indirection.terminus_class = :local
+ expect(Puppet::Status.indirection.find('*').version).to eq(Puppet.version)
+ end
+end
diff --git a/spec/unit/indirector/status/rest_spec.rb b/spec/unit/indirector/status/rest_spec.rb
index 7a794ff21..24361e24c 100755
--- a/spec/unit/indirector/status/rest_spec.rb
+++ b/spec/unit/indirector/status/rest_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
require 'puppet/indirector/status/rest'
describe Puppet::Indirector::Status::Rest do
- it "should be a sublcass of Puppet::Indirector::REST" do
+ it "should be a subclass of Puppet::Indirector::REST" do
Puppet::Indirector::Status::Rest.superclass.should equal(Puppet::Indirector::REST)
end
end
diff --git a/spec/unit/indirector/yaml_spec.rb b/spec/unit/indirector/yaml_spec.rb
index b1be5166d..8a2753479 100755
--- a/spec/unit/indirector/yaml_spec.rb
+++ b/spec/unit/indirector/yaml_spec.rb
@@ -4,6 +4,12 @@ require 'spec_helper'
require 'puppet/indirector/yaml'
describe Puppet::Indirector::Yaml do
+ include PuppetSpec::Files
+
+ class TestSubject
+ attr_accessor :name
+ end
+
before :all do
@indirection = stub 'indirection', :name => :my_yaml, :register_terminus_type => nil
Puppet::Indirector::Indirection.expects(:instance).with(:my_yaml).returns(@indirection)
@@ -16,11 +22,10 @@ describe Puppet::Indirector::Yaml do
before :each do
@store = @store_class.new
- @subject = Object.new
- @subject.singleton_class.send(:attr_accessor, :name)
+ @subject = TestSubject.new
@subject.name = :me
- @dir = File.expand_path("/what/ever")
+ @dir = tmpdir("yaml_indirector")
Puppet[:clientyamldir] = @dir
Puppet.run_mode.stubs(:master?).returns false
@@ -87,54 +92,25 @@ describe Puppet::Indirector::Yaml do
@request.stubs(:instance).returns Object.new
proc { @store.save(@request) }.should raise_error(ArgumentError)
end
-
- it "should convert Ruby objects to YAML and write them to disk using a write lock" do
- yaml = @subject.to_yaml
- file = mock 'file'
- path = @store.send(:path, @subject.name)
- FileTest.expects(:exist?).with(File.dirname(path)).returns(true)
- Puppet::Util.expects(:replace_file).with(path, 0660).yields(file)
- file.expects(:print).with(yaml)
-
- @store.save(@request)
- end
-
- it "should create the indirection subdirectory if it does not exist" do
- yaml = @subject.to_yaml
- file = mock 'file'
- path = @store.send(:path, @subject.name)
- dir = File.dirname(path)
-
- FileTest.expects(:exist?).with(dir).returns(false)
- Dir.expects(:mkdir).with(dir)
-
- Puppet::Util.expects(:replace_file).yields(file)
- file.expects(:print).with(yaml)
-
- @store.save(@request)
- end
end
describe "when retrieving YAML" do
it "should read YAML in from disk and convert it to Ruby objects" do
- path = @store.send(:path, @subject.name)
- yaml = @subject.to_yaml
-
- FileTest.expects(:exist?).with(path).returns true
- File.expects(:read).with(path).returns yaml
+ @store.save(Puppet::Indirector::Request.new(:my_yaml, :save, "testing", @subject))
- @store.find(@request).instance_variable_get("@name").should == :me
+ @store.find(Puppet::Indirector::Request.new(:my_yaml, :find, "testing", nil)).name.should == :me
end
it "should fail coherently when the stored YAML is invalid" do
- path = @store.send(:path, @subject.name)
- FileTest.expects(:exist?).with(path).returns(true)
+ saved_structure = Struct.new(:name).new("testing")
- # Something that will fail in yaml
- File.expects(:read).returns "--- foo:\n 1,2,3\nargh"
+ @store.save(Puppet::Indirector::Request.new(:my_yaml, :save, "testing", saved_structure))
+ File.open(@store.path(saved_structure.name), "w") do |file|
+ file.puts "{ invalid"
+ end
expect {
- @store.find(@request)
+ @store.find(Puppet::Indirector::Request.new(:my_yaml, :find, "testing", nil))
}.to raise_error(Puppet::Error, /Could not parse YAML data/)
end
end
diff --git a/spec/unit/network/formats_spec.rb b/spec/unit/network/formats_spec.rb
index 6b96b2b7d..8531a541a 100755
--- a/spec/unit/network/formats_spec.rb
+++ b/spec/unit/network/formats_spec.rb
@@ -63,27 +63,31 @@ describe "Puppet Network Format" do
@yaml.intern(String, YAML.dump(:foo)).should == "foo"
end
- it "should fail when type does not match deserialized form and has no from_pson" do
- expect do
- @yaml.intern(Hash, YAML.dump("foo"))
- end.to raise_error(NoMethodError)
- end
-
it "should load from yaml when deserializing an array" do
text = YAML.dump(["foo"])
@yaml.intern_multiple(String, text).should == ["foo"]
end
- it "should fail when one element does not have a from_pson" do
+ it "fails intelligibly instead of calling to_pson with something other than a hash" do
+ expect do
+ @yaml.intern(Puppet::Node, '')
+ end.to raise_error(Puppet::Network::FormatHandler::FormatError, /did not contain a valid instance/)
+ end
+
+ it "fails intelligibly when intern_multiple is called and yaml doesn't decode to an array" do
expect do
- @yaml.intern_multiple(Hash, YAML.dump(["foo"]))
- end.to raise_error(NoMethodError)
+ @yaml.intern_multiple(Puppet::Node, '')
+ end.to raise_error(Puppet::Network::FormatHandler::FormatError, /did not contain a collection/)
+ end
+
+ it "fails intelligibly instead of calling to_pson with something other than a hash when interning multiple" do
+ expect do
+ @yaml.intern_multiple(Puppet::Node, YAML.dump(["hello"]))
+ end.to raise_error(Puppet::Network::FormatHandler::FormatError, /did not contain a valid instance/)
end
end
describe "base64 compressed yaml", :if => Puppet.features.zlib? do
- yaml = Puppet::Network::FormatHandler.format(:b64_zlib_yaml)
-
before do
@yaml = Puppet::Network::FormatHandler.format(:b64_zlib_yaml)
end
@@ -294,6 +298,12 @@ describe "Puppet Network Format" do
PsonTest.expects(:from_pson).with("baz").returns "BAZ"
@pson.intern_multiple(PsonTest, text).should == %w{BAR BAZ}
end
+
+ it "fails intelligibly when given invalid data" do
+ expect do
+ @pson.intern(Puppet::Node, '')
+ end.to raise_error(PSON::ParserError, /source did not contain any PSON/)
+ end
end
end
diff --git a/spec/unit/network/http/handler_spec.rb b/spec/unit/network/http/handler_spec.rb
index 6d16bd799..0ff087b02 100755
--- a/spec/unit/network/http/handler_spec.rb
+++ b/spec/unit/network/http/handler_spec.rb
@@ -17,6 +17,10 @@ describe Puppet::Network::HTTP::Handler do
@data = data
end
+ def self.from_raw(raw)
+ new(nil, raw)
+ end
+
def self.from_pson(pson)
new(pson["name"], pson["data"])
end
@@ -33,7 +37,6 @@ describe Puppet::Network::HTTP::Handler do
end
end
- # The subclass must not be all caps even though the superclass is
class Puppet::TestModel::Memory < Puppet::Indirector::Memory
end
@@ -146,7 +149,11 @@ describe Puppet::Network::HTTP::Handler do
end
describe "when processing a request" do
- let(:response) { mock('http response') }
+ let(:response) do
+ obj = stub "http 200 ok"
+ obj.stubs(:[]=).with(Puppet::Network::HTTP::HEADER_PUPPET_VERSION, Puppet.version)
+ obj
+ end
before do
handler.stubs(:check_authorization)
@@ -230,13 +237,13 @@ describe Puppet::Network::HTTP::Handler do
it "should set the format to text/plain when serializing an exception" do
handler.expects(:set_content_type).with(response, "text/plain")
- handler.do_exception(response, "A test", 404)
+ handler.do_exception(response, Exception.new("A test"), 404)
end
it "sends an exception string with the given status" do
handler.expects(:set_response).with(response, "A test", 404)
- handler.do_exception(response, "A test", 404)
+ handler.do_exception(response, Exception.new("A test"), 404)
end
it "sends an exception error with the exception's status" do
@@ -249,6 +256,16 @@ describe Puppet::Network::HTTP::Handler do
handler.process(request, response)
end
+ it "logs an HTTP response exception at info level (most are harmless)" do
+ data = Puppet::TestModel.new("not_found", "not found")
+ error = Puppet::Network::HTTP::Handler::HTTPNotFoundError.new("Could not find test_model not_found")
+
+ request = a_request_that_finds(data, :accept_header => "pson")
+ Puppet.expects(:info).with(error.message)
+
+ handler.process(request, response)
+ end
+
it "should raise an error if the request is formatted in an unknown format" do
handler.stubs(:content_type_header).returns "unknown format"
lambda { handler.request_format(request) }.should raise_error
@@ -429,12 +446,23 @@ describe Puppet::Network::HTTP::Handler do
end
describe "when saving a model instance" do
- it "should fail to save model if data is not specified" do
- data = Puppet::TestModel.new("my data", "some data")
+ it "allows an empty body when the format supports it" do
+ class Puppet::TestModel::Nonvalidatingmemory < Puppet::TestModel::Memory
+ def validate_key(_)
+ # nothing
+ end
+ end
+
+ indirection.terminus_class = :nonvalidatingmemory
+
+ data = Puppet::TestModel.new("test", '')
request = a_request_that_submits(data)
+ request[:content_type_header] = "application/x-raw"
request[:body] = ''
- expect { handler.do_save("my_handler", "my_result", {}, request, response) }.to raise_error(ArgumentError)
+ handler.do_save(indirection.name, "test", {}, request, response)
+
+ Puppet::TestModel.indirection.find("test").data.should == ''
end
it "saves the data sent in the request" do
diff --git a/spec/unit/network/http/rack/rest_spec.rb b/spec/unit/network/http/rack/rest_spec.rb
index 729c6c21a..e9527a460 100755
--- a/spec/unit/network/http/rack/rest_spec.rb
+++ b/spec/unit/network/http/rack/rest_spec.rb
@@ -148,6 +148,25 @@ describe "Puppet::Network::HTTP::RackREST", :if => Puppet.features.rack? do
result[:bar].should == "xyzzy"
end
+ it "should return multi-values params as an array of the values" do
+ req = mk_req('/?foo=baz&foo=xyzzy')
+ result = @handler.params(req)
+ result[:foo].should == ["baz", "xyzzy"]
+ end
+
+ it "should return parameters from the POST body" do
+ req = mk_req("/", :method => 'POST', :input => 'foo=baz&bar=xyzzy')
+ result = @handler.params(req)
+ result[:foo].should == "baz"
+ result[:bar].should == "xyzzy"
+ end
+
+ it "should not return multi-valued params in a POST body as an array of values" do
+ req = mk_req("/", :method => 'POST', :input => 'foo=baz&foo=xyzzy')
+ result = @handler.params(req)
+ result[:foo].should be_one_of("baz", "xyzzy")
+ end
+
it "should CGI-decode the HTTP parameters" do
encoding = CGI.escape("foo bar")
req = mk_req("/?foo=#{encoding}")
diff --git a/spec/unit/node/environment_spec.rb b/spec/unit/node/environment_spec.rb
index 754be7b5a..7b2d73b8a 100755
--- a/spec/unit/node/environment_spec.rb
+++ b/spec/unit/node/environment_spec.rb
@@ -143,7 +143,7 @@ describe Puppet::Node::Environment do
it "should use the current working directory to fully-qualify unqualified paths" do
FileTest.stubs(:directory?).returns true
- two = File.expand_path(File.join(Dir.getwd, "two"))
+ two = File.expand_path("two")
env.validate_dirs([@path_one, 'two']).should == [@path_one, two]
end
end
diff --git a/spec/unit/parser/files_spec.rb b/spec/unit/parser/files_spec.rb
index 24bb95005..2e84216cb 100755
--- a/spec/unit/parser/files_spec.rb
+++ b/spec/unit/parser/files_spec.rb
@@ -70,9 +70,8 @@ describe Puppet::Parser::Files do
it "should accept relative templatedirs" do
FileTest.stubs(:exist?).returns true
Puppet[:templatedir] = "my/templates"
- # We expand_path to normalize backslashes and slashes on Windows
- File.expects(:directory?).with(File.expand_path(File.join(Dir.getwd,"my/templates"))).returns(true)
- Puppet::Parser::Files.find_template("mytemplate").should == File.expand_path(File.join(Dir.getwd,"my/templates/mytemplate"))
+ File.expects(:directory?).with(File.expand_path("my/templates")).returns(true)
+ Puppet::Parser::Files.find_template("mytemplate").should == File.expand_path("my/templates/mytemplate")
end
it "should use the environment templatedir if no module is found and an environment is specified" do
diff --git a/spec/unit/pops/adaptable_spec.rb b/spec/unit/pops/adaptable_spec.rb
index e9b5b80d0..544a6c54f 100644
--- a/spec/unit/pops/adaptable_spec.rb
+++ b/spec/unit/pops/adaptable_spec.rb
@@ -92,8 +92,6 @@ describe Puppet::Pops::Adaptable::Adapter do
a.value = 10
b = Farm::FarmAdapter.get(d)
b.value.should == 10
- # Test implementation detail
- d.instance_variables.include?(:@Farm_FarmAdapter).should == true
end
it "should be able to clear the adapter" do
diff --git a/spec/unit/provider/package/dpkg_spec.rb b/spec/unit/provider/package/dpkg_spec.rb
index 6990ef454..cc0d88b02 100755
--- a/spec/unit/provider/package/dpkg_spec.rb
+++ b/spec/unit/provider/package/dpkg_spec.rb
@@ -49,7 +49,7 @@ install ok installed vim 2:7.3.547-6ubuntu5 :DESC: Vi IMproved - enhanced vi edi
end
it "should have documentation" do
- provider_class.doc.should be_instance_of(String)
+ expect(provider_class.doc).to be_instance_of(String)
end
describe "when listing all instances" do
@@ -66,7 +66,7 @@ install ok installed vim 2:7.3.547-6ubuntu5 :DESC: Vi IMproved - enhanced vi edi
installed = mock 'bash'
provider_class.expects(:new).with(:ensure => "4.2-5ubuntu3", :error => "ok", :desired => "install", :name => "bash", :status => "installed", :description => "GNU Bourne Again SHell", :provider => :dpkg).returns installed
- provider_class.instances.should == [installed]
+ expect(provider_class.instances).to eq([installed])
end
it "should parse multiple dpkg-query multi-line entries in the output" do
@@ -77,7 +77,7 @@ install ok installed vim 2:7.3.547-6ubuntu5 :DESC: Vi IMproved - enhanced vi edi
vim = mock 'vim'
provider_class.expects(:new).with(:ensure => "2:7.3.547-6ubuntu5", :error => "ok", :desired => "install", :name => "vim", :status => "installed", :description => "Vi IMproved - enhanced vi editor", :provider => :dpkg).returns vim
- provider_class.instances.should == [bash, vim]
+ expect(provider_class.instances).to eq([bash, vim])
end
it "should warn on and ignore any lines it does not understand" do
@@ -86,7 +86,7 @@ install ok installed vim 2:7.3.547-6ubuntu5 :DESC: Vi IMproved - enhanced vi edi
Puppet.expects(:warning)
provider_class.expects(:new).never
- provider_class.instances.should == []
+ expect(provider_class.instances).to eq([])
end
it "should not warn on extra multiline description lines which we are ignoring" do
@@ -105,7 +105,7 @@ install ok installed vim 2:7.3.547-6ubuntu5 :DESC: Vi IMproved - enhanced vi edi
vim = mock 'vim'
provider_class.expects(:new).twice.returns(bash, vim)
- provider_class.instances.should == [bash, vim]
+ expect(provider_class.instances).to eq([bash, vim])
end
it "should warn on a broken entry while still parsing a good one" do
@@ -122,7 +122,7 @@ install ok installed vim 2:7.3.547-6ubuntu5 :DESC: Vi IMproved - enhanced vi edi
saved = mock('saved')
provider_class.expects(:new).twice.returns(bash, vim)
- provider_class.instances.should == [bash, vim]
+ expect(provider_class.instances).to eq([bash, vim])
end
end
@@ -148,25 +148,25 @@ install ok installed vim 2:7.3.547-6ubuntu5 :DESC: Vi IMproved - enhanced vi edi
it "should consider the package purged if dpkg-query fails" do
Puppet::Util::Execution.expects(:execpipe).with(query_args).raises Puppet::ExecutionFailure.new("eh")
- provider.query[:ensure].should == :purged
+ expect(provider.query[:ensure]).to eq(:purged)
end
it "should return a hash of the found package status for an installed package" do
Puppet::Util::Execution.expects(:execpipe).with(query_args).yields bash_installed_io
- provider.query.should == {:ensure => "4.2-5ubuntu3", :error => "ok", :desired => "install", :name => "bash", :status => "installed", :provider => :dpkg, :description => "GNU Bourne Again SHell"}
+ expect(provider.query).to eq({:ensure => "4.2-5ubuntu3", :error => "ok", :desired => "install", :name => "bash", :status => "installed", :provider => :dpkg, :description => "GNU Bourne Again SHell"})
end
it "should consider the package absent if the dpkg-query result cannot be interpreted" do
Puppet::Util::Execution.expects(:execpipe).with(query_args).yields StringIO.new("somebaddata")
- provider.query[:ensure].should == :absent
+ expect(provider.query[:ensure]).to eq(:absent)
end
it "should fail if an error is discovered" do
Puppet::Util::Execution.expects(:execpipe).with(query_args).yields replace_in_bash_output("ok", "error")
- lambda { provider.query }.should raise_error(Puppet::Error)
+ expect { provider.query }.to raise_error(Puppet::Error)
end
it "should consider the package purged if it is marked 'not-installed'" do
@@ -174,32 +174,32 @@ install ok installed vim 2:7.3.547-6ubuntu5 :DESC: Vi IMproved - enhanced vi edi
not_installed_bash.gsub!(bash_version, "")
Puppet::Util::Execution.expects(:execpipe).with(query_args).yields StringIO.new(not_installed_bash)
- provider.query[:ensure].should == :purged
+ expect(provider.query[:ensure]).to eq(:purged)
end
it "should consider the package absent if it is marked 'config-files'" do
Puppet::Util::Execution.expects(:execpipe).with(query_args).yields replace_in_bash_output("installed", "config-files")
- provider.query[:ensure].should == :absent
+ expect(provider.query[:ensure]).to eq(:absent)
end
it "should consider the package absent if it is marked 'half-installed'" do
Puppet::Util::Execution.expects(:execpipe).with(query_args).yields replace_in_bash_output("installed", "half-installed")
- provider.query[:ensure].should == :absent
+ expect(provider.query[:ensure]).to eq(:absent)
end
it "should consider the package absent if it is marked 'unpacked'" do
Puppet::Util::Execution.expects(:execpipe).with(query_args).yields replace_in_bash_output("installed", "unpacked")
- provider.query[:ensure].should == :absent
+ expect(provider.query[:ensure]).to eq(:absent)
end
it "should consider the package absent if it is marked 'half-configured'" do
Puppet::Util::Execution.expects(:execpipe).with(query_args).yields replace_in_bash_output("installed", "half-configured")
- provider.query[:ensure].should == :absent
+ expect(provider.query[:ensure]).to eq(:absent)
end
it "should consider the package held if its state is 'hold'" do
Puppet::Util::Execution.expects(:execpipe).with(query_args).yields replace_in_bash_output("install", "hold")
- provider.query[:ensure].should == :held
+ expect(provider.query[:ensure]).to eq(:held)
end
end
@@ -233,12 +233,12 @@ desired ok status next-pkg ensure :DESC: next summary
Puppet.expects(:warning).times(4)
pipe = StringIO.new(broken_description)
- provider_class.parse_multi_line(pipe).should == package_hash
+ expect(provider_class.parse_multi_line(pipe)).to eq(package_hash)
next_package = package_hash.merge(:name => 'next-pkg', :description => 'next summary')
hash = provider_class.parse_multi_line(pipe) until hash # warn about bad lines
- hash.should == next_package
+ expect(hash).to eq(next_package)
end
def parser_test(dpkg_output_string, gold_hash)
@@ -246,7 +246,7 @@ desired ok status next-pkg ensure :DESC: next summary
Puppet::Util::Execution.expects(:execpipe).with(query_args).yields pipe
Puppet.expects(:warning).never
- provider.query.should == gold_hash
+ expect(provider.query).to eq(gold_hash)
end
it "should parse properly even if delimiter is in version" do
@@ -289,10 +289,30 @@ desired ok status name ensure :DESC: summary text
no_description = "desired ok status name ensure :DESC: \n:DESC:"
parser_test(no_description, package_hash.merge(:description => ''))
end
+
+ context "dpkg-query versions < 1.16" do
+ it "parses dpkg-query 1.15 reporting that package does not exist without warning about a failed match (#22529)" do
+ Puppet.expects(:warning).never
+ pipe = StringIO.new("No packages found matching non-existent-package")
+ Puppet::Util::Execution.expects(:execpipe).with(query_args).yields(pipe).raises(Puppet::ExecutionFailure.new('no package found'))
+
+ expect(provider.query).to eq({:ensure=>:purged, :status=>"missing", :name=>"name", :error=>"ok"})
+ end
+ end
+
+ context "dpkg-query versions >= 1.16" do
+ it "parses dpkg-query 1.16 reporting that package does not exist without warning about a failed match (#22529)" do
+ Puppet.expects(:warning).never
+ pipe = StringIO.new("dpkg-query: no packages found matching non-existent-package")
+ Puppet::Util::Execution.expects(:execpipe).with(query_args).yields(pipe).raises(Puppet::ExecutionFailure.new('no package found'))
+
+ expect(provider.query).to eq({:ensure=>:purged, :status=>"missing", :name=>"name", :error=>"ok"})
+ end
+ end
end
it "should be able to install" do
- provider.should respond_to(:install)
+ expect(provider).to respond_to(:install)
end
describe "when installing" do
@@ -303,7 +323,7 @@ desired ok status name ensure :DESC: summary text
it "should fail to install if no source is specified in the resource" do
resource.expects(:[]).with(:source).returns nil
- lambda { provider.install }.should raise_error(ArgumentError)
+ expect { provider.install }.to raise_error(ArgumentError)
end
it "should use 'dpkg -i' to install the package" do
@@ -373,7 +393,7 @@ desired ok status name ensure :DESC: summary text
it "should return the version found by dpkg-deb" do
resource.expects(:[]).with(:source).returns "myfile"
provider.expects(:dpkg_deb).with { |*command| command[-1] == "myfile" }.returns "package\t1.0"
- provider.latest.should == "1.0"
+ expect(provider.latest).to eq("1.0")
end
it "should warn if the package file contains a different package" do
@@ -386,7 +406,7 @@ desired ok status name ensure :DESC: summary text
resource = stub 'resource', :[] => "package++"
provider = provider_class.new(resource)
provider.expects(:dpkg_deb).returns "package++\t1.0"
- provider.latest.should == "1.0"
+ expect(provider.latest).to eq("1.0")
end
end
diff --git a/spec/unit/provider/package/rpm_spec.rb b/spec/unit/provider/package/rpm_spec.rb
index 8dd23a935..e438b51a5 100755
--- a/spec/unit/provider/package/rpm_spec.rb
+++ b/spec/unit/provider/package/rpm_spec.rb
@@ -76,7 +76,7 @@ describe provider_class do
installed_packages = subject.instances
- installed_packages[0].properties.should ==
+ expect(installed_packages[0].properties).to eq(
{
:provider => :rpm,
:name => "cracklib-dicts",
@@ -87,7 +87,8 @@ describe provider_class do
:ensure => "2.8.9-3.3",
:description => "The standard CrackLib dictionaries",
}
- installed_packages[1].properties.should ==
+ )
+ expect(installed_packages[1].properties).to eq(
{
:provider => :rpm,
:name => "basesystem",
@@ -98,7 +99,8 @@ describe provider_class do
:ensure => "8.0-5.1.1.el5.centos",
:description => "The skeleton package which defines a simple Red Hat Enterprise Linux system",
}
- installed_packages[2].properties.should ==
+ )
+ expect(installed_packages[2].properties).to eq(
{
:provider => :rpm,
:name => "chkconfig",
@@ -109,7 +111,8 @@ describe provider_class do
:ensure => "1.3.30.2-2.el5",
:description => "A system tool for maintaining the /etc/rc*.d hierarchy",
}
- installed_packages.last.properties.should ==
+ )
+ expect(installed_packages.last.properties).to eq(
{
:provider => :rpm,
:name => "mysummaryless",
@@ -120,6 +123,7 @@ describe provider_class do
:ensure => "1.2.3.4-5.el4",
:description => "",
}
+ )
end
end
@@ -157,7 +161,7 @@ describe provider_class do
it "should retrieve version string after querying rpm for version from source file" do
resource.expects(:[]).with(:source).returns('source-string')
Puppet::Util::Execution.expects(:execfail).with(["/bin/rpm", "-q", "--qf", nevra_format, "-p", "source-string"], Puppet::Error).returns("myresource 0 1.2.3.4 5.el4 noarch :DESC:\n")
- provider.latest.should == "1.2.3.4-5.el4"
+ expect(provider.latest).to eq("1.2.3.4-5.el4")
end
end
@@ -201,7 +205,7 @@ describe provider_class do
def parser_test(rpm_output_string, gold_hash, number_of_warnings = 0)
Puppet.expects(:warning).times(number_of_warnings)
Puppet::Util::Execution.expects(:execute).with(["/bin/rpm", "-q", resource_name, "--nosignature", "--nodigest", "--qf", nevra_format], execute_options).returns(rpm_output_string)
- provider.query.should == gold_hash
+ expect(provider.query).to eq(gold_hash)
end
let(:resource_name) { 'name' }
@@ -258,6 +262,10 @@ describe provider_class do
it "should warn but not fail if line is unparseable" do
parser_test('bad data', {}, 1)
end
+
+ it "should not warn and not fail if rpm returns package not found" do
+ parser_test('package foo is not installed', {}, 0)
+ end
end
describe ".nodigest" do
@@ -271,7 +279,7 @@ describe provider_class do
describe "when current version is #{version}" do
it "should return #{expected.inspect}" do
subject.stubs(:current_version).returns(version)
- subject.nodigest.should == expected
+ expect(subject.nodigest).to eq(expected)
end
end
end
@@ -287,7 +295,7 @@ describe provider_class do
describe "when current version is #{version}" do
it "should return #{expected.inspect}" do
subject.stubs(:current_version).returns(version)
- subject.nosignature.should == expected
+ expect(subject.nosignature).to eq(expected)
end
end
end
diff --git a/spec/unit/provider/parsedfile_spec.rb b/spec/unit/provider/parsedfile_spec.rb
index 1ac0c198b..f8a1773de 100755
--- a/spec/unit/provider/parsedfile_spec.rb
+++ b/spec/unit/provider/parsedfile_spec.rb
@@ -2,8 +2,14 @@
require 'spec_helper'
require 'puppet_spec/files'
+require 'puppet'
require 'puppet/provider/parsedfile'
+Puppet::Type.newtype(:parsedfile_type) do
+ newparam(:name)
+ newproperty(:target)
+end
+
# Most of the tests for this are still in test/ral/provider/parsedfile.rb.
describe Puppet::Provider::ParsedFile do
# The ParsedFile provider class is meant to be used as an abstract base class
@@ -11,64 +17,68 @@ describe Puppet::Provider::ParsedFile do
# sharing data between classes we construct an anonymous class that inherits
# the ParsedFile provider instead of directly working with the ParsedFile
# provider itself.
- subject { Puppet::Type.newtype(:parsedfile_type).provide(:parsedfile_provider, :parent => described_class) }
+ let(:parsed_type) do
+ Puppet::Type.type(:parsedfile_type)
+ end
+
+ let!(:provider) { parsed_type.provide(:parsedfile_provider, :parent => described_class) }
describe "when looking up records loaded from disk" do
it "should return nil if no records have been loaded" do
- subject.record?("foo").should be_nil
+ provider.record?("foo").should be_nil
end
end
describe "when generating a list of instances" do
it "should return an instance for each record parsed from all of the registered targets" do
- subject.expects(:targets).returns %w{/one /two}
- subject.stubs(:skip_record?).returns false
+ provider.expects(:targets).returns %w{/one /two}
+ provider.stubs(:skip_record?).returns false
one = [:uno1, :uno2]
two = [:dos1, :dos2]
- subject.expects(:prefetch_target).with("/one").returns one
- subject.expects(:prefetch_target).with("/two").returns two
+ provider.expects(:prefetch_target).with("/one").returns one
+ provider.expects(:prefetch_target).with("/two").returns two
results = []
(one + two).each do |inst|
results << inst.to_s + "_instance"
- subject.expects(:new).with(inst).returns(results[-1])
+ provider.expects(:new).with(inst).returns(results[-1])
end
- subject.instances.should == results
+ provider.instances.should == results
end
it "should ignore target when retrieve fails" do
- subject.expects(:targets).returns %w{/one /two /three}
- subject.stubs(:skip_record?).returns false
- subject.expects(:retrieve).with("/one").returns [
+ provider.expects(:targets).returns %w{/one /two /three}
+ provider.stubs(:skip_record?).returns false
+ provider.expects(:retrieve).with("/one").returns [
{:name => 'target1_record1'},
{:name => 'target1_record2'}
]
- subject.expects(:retrieve).with("/two").raises Puppet::Util::FileType::FileReadError, "some error"
- subject.expects(:retrieve).with("/three").returns [
+ provider.expects(:retrieve).with("/two").raises Puppet::Util::FileType::FileReadError, "some error"
+ provider.expects(:retrieve).with("/three").returns [
{:name => 'target3_record1'},
{:name => 'target3_record2'}
]
Puppet.expects(:err).with('Could not prefetch parsedfile_type provider \'parsedfile_provider\' target \'/two\': some error. Treating as empty')
- subject.expects(:new).with(:name => 'target1_record1', :on_disk => true, :target => '/one', :ensure => :present).returns 'r1'
- subject.expects(:new).with(:name => 'target1_record2', :on_disk => true, :target => '/one', :ensure => :present).returns 'r2'
- subject.expects(:new).with(:name => 'target3_record1', :on_disk => true, :target => '/three', :ensure => :present).returns 'r3'
- subject.expects(:new).with(:name => 'target3_record2', :on_disk => true, :target => '/three', :ensure => :present).returns 'r4'
+ provider.expects(:new).with(:name => 'target1_record1', :on_disk => true, :target => '/one', :ensure => :present).returns 'r1'
+ provider.expects(:new).with(:name => 'target1_record2', :on_disk => true, :target => '/one', :ensure => :present).returns 'r2'
+ provider.expects(:new).with(:name => 'target3_record1', :on_disk => true, :target => '/three', :ensure => :present).returns 'r3'
+ provider.expects(:new).with(:name => 'target3_record2', :on_disk => true, :target => '/three', :ensure => :present).returns 'r4'
- subject.instances.should == %w{r1 r2 r3 r4}
+ provider.instances.should == %w{r1 r2 r3 r4}
end
it "should skip specified records" do
- subject.expects(:targets).returns %w{/one}
- subject.expects(:skip_record?).with(:uno).returns false
- subject.expects(:skip_record?).with(:dos).returns true
+ provider.expects(:targets).returns %w{/one}
+ provider.expects(:skip_record?).with(:uno).returns false
+ provider.expects(:skip_record?).with(:dos).returns true
one = [:uno, :dos]
- subject.expects(:prefetch_target).returns one
+ provider.expects(:prefetch_target).returns one
- subject.expects(:new).with(:uno).returns "eh"
- subject.expects(:new).with(:dos).never
+ provider.expects(:new).with(:uno).returns "eh"
+ provider.expects(:new).with(:dos).never
- subject.instances
+ provider.instances
end
end
@@ -80,22 +90,22 @@ describe Puppet::Provider::ParsedFile do
it "returns a resource if the record name matches the resource name" do
record = {:name => :one}
- subject.resource_for_record(record, resources).should be first_resource
+ provider.resource_for_record(record, resources).should be first_resource
end
it "doesn't return a resource if the record name doesn't match any resource names" do
record = {:name => :three}
- subject.resource_for_record(record, resources).should be_nil
+ provider.resource_for_record(record, resources).should be_nil
end
end
describe "when flushing a file's records to disk" do
before do
# This way we start with some @records, like we would in real life.
- subject.stubs(:retrieve).returns []
- subject.default_target = "/foo/bar"
- subject.initvars
- subject.prefetch
+ provider.stubs(:retrieve).returns []
+ provider.default_target = "/foo/bar"
+ provider.initvars
+ provider.prefetch
@filetype = Puppet::Util::FileType.filetype(:flat).new("/my/file")
Puppet::Util::FileType.filetype(:flat).stubs(:new).with("/my/file").returns @filetype
@@ -106,7 +116,7 @@ describe Puppet::Provider::ParsedFile do
it "should back up the file being written if the filetype can be backed up" do
@filetype.expects(:backup)
- subject.flush_target("/my/file")
+ provider.flush_target("/my/file")
end
it "should not try to back up the file if the filetype cannot be backed up" do
@@ -115,22 +125,51 @@ describe Puppet::Provider::ParsedFile do
@filetype.stubs(:write)
- subject.flush_target("/my/file")
+ provider.flush_target("/my/file")
end
it "should not back up the file more than once between calls to 'prefetch'" do
@filetype.expects(:backup).once
- subject.flush_target("/my/file")
- subject.flush_target("/my/file")
+ provider.flush_target("/my/file")
+ provider.flush_target("/my/file")
end
it "should back the file up again once the file has been reread" do
@filetype.expects(:backup).times(2)
- subject.flush_target("/my/file")
- subject.prefetch
- subject.flush_target("/my/file")
+ provider.flush_target("/my/file")
+ provider.prefetch
+ provider.flush_target("/my/file")
+ end
+ end
+
+ describe "when flushing multiple files" do
+ describe "and an error is encountered" do
+ it "the other file does not fail" do
+ provider.stubs(:backup_target)
+
+ bad_file = 'broken'
+ good_file = 'writable'
+
+ bad_writer = mock 'bad'
+ bad_writer.expects(:write).raises(Exception, "Failed to write to bad file")
+
+ good_writer = mock 'good'
+ good_writer.expects(:write).returns(nil)
+
+ provider.stubs(:target_object).with(bad_file).returns(bad_writer)
+ provider.stubs(:target_object).with(good_file).returns(good_writer)
+
+ bad_resource = parsed_type.new(:name => 'one', :target => bad_file)
+ good_resource = parsed_type.new(:name => 'two', :target => good_file)
+
+ expect {
+ bad_resource.flush
+ }.to raise_error(Exception, "Failed to write to bad file")
+
+ good_resource.flush
+ end
end
end
end
@@ -141,7 +180,7 @@ describe "A very basic provider based on ParsedFile" do
let(:input_text) { File.read(my_fixture('simple.txt')) }
let(:target) { tmpfile('parsedfile_spec') }
- subject do
+ let(:provider) do
example_provider_class = Class.new(Puppet::Provider::ParsedFile)
example_provider_class.default_target = target
# Setup some record rules
@@ -158,31 +197,31 @@ describe "A very basic provider based on ParsedFile" do
context "writing file contents back to disk" do
it "should not change anything except from adding a header" do
- input_records = subject.parse(input_text)
- subject.to_file(input_records).
- should match subject.header + input_text
+ input_records = provider.parse(input_text)
+ provider.to_file(input_records).
+ should match provider.header + input_text
end
end
context "rewriting a file containing a native header" do
let(:regex) { %r/^# HEADER.*third party\.\n/ }
- let(:input_records) { subject.parse(input_text) }
+ let(:input_records) { provider.parse(input_text) }
before :each do
- subject.stubs(:native_header_regex).returns(regex)
+ provider.stubs(:native_header_regex).returns(regex)
end
it "should move the native header to the top" do
- subject.to_file(input_records).should_not match /\A#{subject.header}/
+ provider.to_file(input_records).should_not match /\A#{provider.header}/
end
context "and dropping native headers found in input" do
before :each do
- subject.stubs(:drop_native_header).returns(true)
+ provider.stubs(:drop_native_header).returns(true)
end
it "should not include the native header in the output" do
- subject.to_file(input_records).should_not match regex
+ provider.to_file(input_records).should_not match regex
end
end
end
diff --git a/spec/unit/settings/file_setting_spec.rb b/spec/unit/settings/file_setting_spec.rb
index 9782b247d..a6e3f3f12 100755
--- a/spec/unit/settings/file_setting_spec.rb
+++ b/spec/unit/settings/file_setting_spec.rb
@@ -170,9 +170,7 @@ describe Puppet::Settings::FileSetting do
it "should fully qualified returned files if necessary (#795)" do
@settings.stubs(:value).with(:myfile).returns "myfile"
- path = File.join(Dir.getwd, "myfile")
- # Dir.getwd can return windows paths with backslashes, so we normalize them using expand_path
- path = File.expand_path(path) if Puppet.features.microsoft_windows?
+ path = File.expand_path('myfile')
@file.to_resource.title.should == path
end
diff --git a/spec/unit/transaction/report_spec.rb b/spec/unit/transaction/report_spec.rb
index 59278d393..7195b0623 100755
--- a/spec/unit/transaction/report_spec.rb
+++ b/spec/unit/transaction/report_spec.rb
@@ -376,7 +376,11 @@ describe Puppet::Transaction::Report do
end
it "defaults to serializing to pson" do
- expect(Puppet::Transaction::Report.supported_formats).to eq([:pson])
+ expect(Puppet::Transaction::Report.default_format).to eq(:pson)
+ end
+
+ it "supports both yaml and pson" do
+ expect(Puppet::Transaction::Report.supported_formats).to eq([:pson, :yaml])
end
it "can make a round trip through pson" do
diff --git a/spec/unit/transaction/resource_harness_spec.rb b/spec/unit/transaction/resource_harness_spec.rb
index 812b76438..0c250ae92 100755
--- a/spec/unit/transaction/resource_harness_spec.rb
+++ b/spec/unit/transaction/resource_harness_spec.rb
@@ -68,7 +68,7 @@ describe Puppet::Transaction::ResourceHarness do
events.map do |event|
hash = {}
event.instance_variables.each do |varname|
- hash[varname] = event.instance_variable_get(varname)
+ hash[varname.to_sym] = event.instance_variable_get(varname)
end
hash
end
diff --git a/spec/unit/util/monkey_patches_spec.rb b/spec/unit/util/monkey_patches_spec.rb
index a722d8bff..cc487020c 100755
--- a/spec/unit/util/monkey_patches_spec.rb
+++ b/spec/unit/util/monkey_patches_spec.rb
@@ -260,19 +260,6 @@ describe Range do
end
end
-
-describe Object, "#instance_variables" do
- it "should work with no instance variables" do
- Object.new.instance_variables.should == []
- end
-
- it "should return symbols, not strings" do
- o = Object.new
- ["@foo", "@bar", "@baz"].map {|x| o.instance_variable_set(x, x) }
- o.instance_variables.should =~ [:@foo, :@bar, :@baz]
- end
-end
-
describe OpenSSL::SSL::SSLContext do
it 'disables SSLv2 via the SSLContext#options bitmask' do
(subject.options & OpenSSL::SSL::OP_NO_SSLv2).should == OpenSSL::SSL::OP_NO_SSLv2
diff --git a/spec/unit/util/storage_spec.rb b/spec/unit/util/storage_spec.rb
index 02bfe9490..ba1675981 100755
--- a/spec/unit/util/storage_spec.rb
+++ b/spec/unit/util/storage_spec.rb
@@ -2,22 +2,14 @@
require 'spec_helper'
require 'yaml'
+require 'fileutils'
require 'puppet/util/storage'
describe Puppet::Util::Storage do
include PuppetSpec::Files
- before(:all) do
- @basepath = make_absolute("/somepath")
- Puppet[:statedir] = tmpdir("statedir")
- end
-
- after(:all) do
- Puppet.settings.clear
- end
-
before(:each) do
- Puppet::Util::Storage.clear
+ @basepath = File.expand_path("/somepath")
end
describe "when caching a symbol" do
@@ -40,7 +32,7 @@ describe Puppet::Util::Storage do
end
describe "when caching a Puppet::Type" do
- before(:all) do
+ before(:each) do
@file_test = Puppet::Type.type(:file).new(:name => @basepath+"/yayness", :audit => %w{checksum type})
@exec_test = Puppet::Type.type(:exec).new(:name => @basepath+"/bin/ls /yayness")
end
@@ -81,17 +73,15 @@ describe Puppet::Util::Storage do
describe "when the state file/directory does not exist" do
before(:each) do
- transient = Tempfile.new('storage_test')
- @path = transient.path()
- transient.close!()
+ @path = tmpfile('storage_test')
end
- it "should not fail to load()" do
+ it "should not fail to load" do
FileTest.exists?(@path).should be_false
Puppet[:statedir] = @path
- proc { Puppet::Util::Storage.load }.should_not raise_error
+ Puppet::Util::Storage.load
Puppet[:statefile] = @path
- proc { Puppet::Util::Storage.load }.should_not raise_error
+ Puppet::Util::Storage.load
end
it "should not lose its internal state when load() is called" do
@@ -101,7 +91,7 @@ describe Puppet::Util::Storage do
Puppet::Util::Storage.state.should == {:yayness=>{}}
Puppet[:statefile] = @path
- proc { Puppet::Util::Storage.load }.should_not raise_error
+ Puppet::Util::Storage.load
Puppet::Util::Storage.state.should == {:yayness=>{}}
end
@@ -109,9 +99,13 @@ describe Puppet::Util::Storage do
describe "when the state file/directory exists" do
before(:each) do
- @state_file = Tempfile.new('storage_test')
- @saved_statefile = Puppet[:statefile]
- Puppet[:statefile] = @state_file.path
+ @state_file = tmpfile('storage_test')
+ FileUtils.touch(@state_file)
+ Puppet[:statefile] = @state_file
+ end
+
+ def write_state_file(contents)
+ File.open(@state_file, 'w') { |f| f.write(contents) }
end
it "should overwrite its internal state if load() is called" do
@@ -119,55 +113,57 @@ describe Puppet::Util::Storage do
Puppet::Util::Storage.cache(:yayness)
Puppet::Util::Storage.state.should == {:yayness=>{}}
- proc { Puppet::Util::Storage.load }.should_not raise_error
+ Puppet::Util::Storage.load
+
Puppet::Util::Storage.state.should == {}
end
it "should restore its internal state if the state file contains valid YAML" do
test_yaml = {'File["/yayness"]'=>{"name"=>{:a=>:b,:c=>:d}}}
- YAML.expects(:load).returns(test_yaml)
+ write_state_file(test_yaml.to_yaml)
+
+ Puppet::Util::Storage.load
- proc { Puppet::Util::Storage.load }.should_not raise_error
Puppet::Util::Storage.state.should == test_yaml
end
it "should initialize with a clear internal state if the state file does not contain valid YAML" do
- @state_file.write(:booness)
- @state_file.flush
+ write_state_file('{ invalid')
+
+ Puppet::Util::Storage.load
+
+ Puppet::Util::Storage.state.should == {}
+ end
+
+ it "should initialize with a clear internal state if the state file does not contain a hash of data" do
+ write_state_file("not_a_hash")
+
+ Puppet::Util::Storage.load
- proc { Puppet::Util::Storage.load }.should_not raise_error
Puppet::Util::Storage.state.should == {}
end
it "should raise an error if the state file does not contain valid YAML and cannot be renamed" do
- @state_file.write(:booness)
- @state_file.flush
- YAML.expects(:load).raises(Puppet::Error)
+ write_state_file('{ invalid')
+
File.expects(:rename).raises(SystemCallError)
- proc { Puppet::Util::Storage.load }.should raise_error
+ expect { Puppet::Util::Storage.load }.to raise_error(Puppet::Error, /Could not rename/)
end
it "should attempt to rename the state file if the file is corrupted" do
- # We fake corruption by causing YAML.load to raise an exception
- YAML.expects(:load).raises(Puppet::Error)
+ write_state_file('{ invalid')
+
File.expects(:rename).at_least_once
- proc { Puppet::Util::Storage.load }.should_not raise_error
+ Puppet::Util::Storage.load
end
it "should fail gracefully on load() if the state file is not a regular file" do
- @state_file.close!()
- Dir.mkdir(Puppet[:statefile])
-
- proc { Puppet::Util::Storage.load }.should_not raise_error
-
- Dir.rmdir(Puppet[:statefile])
- end
+ FileUtils.rm_f(@state_file)
+ Dir.mkdir(@state_file)
- after(:each) do
- @state_file.close!()
- Puppet[:statefile] = @saved_statefile
+ Puppet::Util::Storage.load
end
end
end
@@ -183,7 +179,8 @@ describe Puppet::Util::Storage do
FileTest.exists?(Puppet[:statefile]).should be_false
Puppet::Util::Storage.cache(:yayness)
- proc { Puppet::Util::Storage.store }.should_not raise_error
+ Puppet::Util::Storage.store
+
FileTest.exists?(Puppet[:statefile]).should be_true
end
@@ -191,19 +188,22 @@ describe Puppet::Util::Storage do
Dir.mkdir(Puppet[:statefile])
Puppet::Util::Storage.cache(:yayness)
- proc { Puppet::Util::Storage.store }.should raise_error
+ expect { Puppet::Util::Storage.store }.to raise_error
Dir.rmdir(Puppet[:statefile])
end
it "should load() the same information that it store()s" do
Puppet::Util::Storage.cache(:yayness)
-
Puppet::Util::Storage.state.should == {:yayness=>{}}
- proc { Puppet::Util::Storage.store }.should_not raise_error
+
+ Puppet::Util::Storage.store
Puppet::Util::Storage.clear
+
Puppet::Util::Storage.state.should == {}
- proc { Puppet::Util::Storage.load }.should_not raise_error
+
+ Puppet::Util::Storage.load
+
Puppet::Util::Storage.state.should == {:yayness=>{}}
end
end
diff --git a/spec/unit/util/yaml_spec.rb b/spec/unit/util/yaml_spec.rb
new file mode 100644
index 000000000..960388ade
--- /dev/null
+++ b/spec/unit/util/yaml_spec.rb
@@ -0,0 +1,41 @@
+require 'spec_helper'
+
+require 'puppet/util/yaml'
+
+describe Puppet::Util::Yaml do
+ include PuppetSpec::Files
+
+ let(:filename) { tmpfile("yaml") }
+
+ it "reads a YAML file from disk" do
+ write_file(filename, YAML.dump({ "my" => "data" }))
+
+ expect(Puppet::Util::Yaml.load_file(filename)).to eq({ "my" => "data" })
+ end
+
+ it "writes data formatted as YAML to disk" do
+ Puppet::Util::Yaml.dump({ "my" => "data" }, filename)
+
+ expect(Puppet::Util::Yaml.load_file(filename)).to eq({ "my" => "data" })
+ end
+
+ it "raises an error when the file is invalid YAML" do
+ write_file(filename, "{ invalid")
+
+ expect { Puppet::Util::Yaml.load_file(filename) }.to raise_error(Puppet::Util::Yaml::YamlLoadError)
+ end
+
+ it "raises an error when the file does not exist" do
+ expect { Puppet::Util::Yaml.load_file("no") }.to raise_error(Puppet::Util::Yaml::YamlLoadError, /No such file or directory/)
+ end
+
+ it "raises an error when the filename is illegal" do
+ expect { Puppet::Util::Yaml.load_file("not\0allowed") }.to raise_error(Puppet::Util::Yaml::YamlLoadError, /null byte/)
+ end
+
+ def write_file(name, contents)
+ File.open(name, "w") do |fh|
+ fh.write(contents)
+ end
+ end
+end
diff --git a/spec/unit/util_spec.rb b/spec/unit/util_spec.rb
index 22be8fa7a..48b6e6fc5 100755
--- a/spec/unit/util_spec.rb
+++ b/spec/unit/util_spec.rb
@@ -59,6 +59,7 @@ describe Puppet::Util do
it "should remove any new environment variables after the block ends" do
@new_env[:FOO] = "bar"
+ ENV["FOO"] = nil
Puppet::Util.withenv @new_env do
ENV["FOO"].should == "bar"
end