puppet 3.3.0 → 3.3.1.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/lib/puppet/configurer.rb +1 -7
  3. data/lib/puppet/defaults.rb +18 -6
  4. data/lib/puppet/file_bucket/file.rb +10 -1
  5. data/lib/puppet/forge/repository.rb +8 -2
  6. data/lib/puppet/graph/simple_graph.rb +1 -1
  7. data/lib/puppet/indirector/request.rb +18 -0
  8. data/lib/puppet/indirector/rest.rb +22 -1
  9. data/lib/puppet/indirector/status/local.rb +3 -1
  10. data/lib/puppet/indirector/yaml.rb +4 -18
  11. data/lib/puppet/network/http.rb +1 -0
  12. data/lib/puppet/network/http/handler.rb +11 -6
  13. data/lib/puppet/parser/yaml_trimmer.rb +1 -3
  14. data/lib/puppet/provider/package/dpkg.rb +2 -1
  15. data/lib/puppet/provider/package/rpm.rb +4 -2
  16. data/lib/puppet/provider/parsedfile.rb +9 -6
  17. data/lib/puppet/resource/status.rb +1 -1
  18. data/lib/puppet/status.rb +8 -0
  19. data/lib/puppet/transaction/additional_resource_generator.rb +1 -1
  20. data/lib/puppet/transaction/event.rb +1 -1
  21. data/lib/puppet/transaction/report.rb +6 -2
  22. data/lib/puppet/util/monkey_patches.rb +0 -52
  23. data/lib/puppet/util/storage.rb +5 -8
  24. data/lib/puppet/util/yaml.rb +23 -0
  25. data/lib/puppet/util/zaml.rb +14 -2
  26. data/lib/puppet/version.rb +1 -1
  27. data/spec/unit/agent_spec.rb +2 -0
  28. data/spec/unit/file_bucket/file_spec.rb +19 -13
  29. data/spec/unit/indirector/certificate/rest_spec.rb +1 -0
  30. data/spec/unit/indirector/report/rest_spec.rb +1 -0
  31. data/spec/unit/indirector/request_spec.rb +9 -0
  32. data/spec/unit/indirector/rest_spec.rb +22 -2
  33. data/spec/unit/indirector/run/local_spec.rb +3 -1
  34. data/spec/unit/indirector/status/local_spec.rb +11 -0
  35. data/spec/unit/indirector/status/rest_spec.rb +1 -1
  36. data/spec/unit/indirector/yaml_spec.rb +16 -40
  37. data/spec/unit/network/http/handler_spec.rb +17 -3
  38. data/spec/unit/pops/adaptable_spec.rb +0 -2
  39. data/spec/unit/provider/package/dpkg_spec.rb +31 -23
  40. data/spec/unit/provider/package/rpm_spec.rb +16 -8
  41. data/spec/unit/provider/parsedfile_spec.rb +86 -47
  42. data/spec/unit/transaction/report_spec.rb +5 -1
  43. data/spec/unit/transaction/resource_harness_spec.rb +1 -1
  44. data/spec/unit/util/monkey_patches_spec.rb +0 -13
  45. data/spec/unit/util/storage_spec.rb +49 -49
  46. data/spec/unit/util/yaml_spec.rb +41 -0
  47. metadata +2746 -2749
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2a2479879d8532a3fb936537d8abaf317c563a49
4
+ data.tar.gz: 42bfd1c583faee771a10dfdd3f697bb91a30b734
5
+ SHA512:
6
+ metadata.gz: 78443b0f2e01f6fc4fb71b6e58df58bef370054815519fa468b7af5c5511cebf2ec69d7794425a4de7713d4734292c752cb8db875cd899330047dec4213b4362
7
+ data.tar.gz: 8026eecbf7556115c83c2bb3ec04c8755ca8766312b22fdb4a7da51aaca63ef5488a88e590b3b028e7c6e6788f9209228b8900d69a3d8a2e6c422025a920e3fb
@@ -142,6 +142,7 @@ class Puppet::Configurer
142
142
  init_storage
143
143
 
144
144
  Puppet::Util::Log.newdestination(report)
145
+
145
146
  begin
146
147
  unless Puppet[:node_name_fact].empty?
147
148
  query_options = get_facts(options)
@@ -210,13 +211,6 @@ class Puppet::Configurer
210
211
  Puppet::Transaction::Report.indirection.save(report, nil, :environment => @environment) if Puppet[:report]
211
212
  rescue => detail
212
213
  Puppet.log_exception(detail, "Could not send report: #{detail}")
213
- if detail.message =~ /Could not intern from pson.*Puppet::Transaction::Report/
214
- Puppet.notice("There was an error sending the report.")
215
- Puppet.notice("This error is possibly caused by sending the report in a format the master can not handle.")
216
- Puppet.notice("A puppet master older than 3.2.2 can not handle pson reports.")
217
- Puppet.notice("Set report_serialization_format=yaml on the agent to send reports to older masters.")
218
- Puppet.notice("See http://links.puppetlabs.com/deprecate_yaml_on_network for more information.")
219
- end
220
214
  end
221
215
 
222
216
  def save_last_run_summary(report)
@@ -1092,12 +1092,24 @@ EOT
1092
1092
 
1093
1093
  This should almost always be set to `pson`. It can be temporarily set to
1094
1094
  `yaml` to let agents using this Puppet version connect to a puppet master
1095
- running Puppet 3.0.0 through 3.2.4.",
1096
- :hook => proc do |value|
1097
- if value == "yaml"
1098
- Puppet.deprecation_warning("Sending reports in 'yaml' is deprecated; use 'pson' instead.")
1099
- end
1100
- end
1095
+ running Puppet 3.0.0 through 3.2.x.
1096
+
1097
+ Note that this is set to 'yaml' automatically if the agent detects an
1098
+ older master, so should never need to be set explicitly."
1099
+ },
1100
+ :legacy_query_parameter_serialization => {
1101
+ :default => false,
1102
+ :type => :boolean,
1103
+ :desc => "The serialization format to use when sending file_metadata
1104
+ query parameters. Older versions of puppet master expect certain query
1105
+ parameters to be serialized as yaml, which is deprecated.
1106
+
1107
+ This should almost always be false. It can be temporarily set to true
1108
+ to let agents using this Puppet version connect to a puppet master
1109
+ running Puppet 3.0.0 through 3.2.x.
1110
+
1111
+ Note that this is set to true automatically if the agent detects an
1112
+ older master, so should never need to be set explicitly."
1101
1113
  },
1102
1114
  :agent_catalog_run_lockfile => {
1103
1115
  :default => "$statedir/agent_catalog_run.lock",
@@ -14,12 +14,16 @@ class Puppet::FileBucket::File
14
14
  attr :bucket_path
15
15
 
16
16
  def self.supported_formats
17
+ [:s, :pson]
18
+ end
19
+
20
+ def self.default_format
17
21
  # This should really be :raw, like is done for Puppet::FileServing::Content
18
22
  # but this class hasn't historically supported `from_raw`, so switching
19
23
  # would break compatibility between newer 3.x agents talking to older 3.x
20
24
  # masters. However, to/from_s has been supported and achieves the desired
21
25
  # result without breaking compatibility.
22
- [:s]
26
+ :s
23
27
  end
24
28
 
25
29
  def initialize(contents, options = {})
@@ -54,6 +58,11 @@ class Puppet::FileBucket::File
54
58
  self.new(contents)
55
59
  end
56
60
 
61
+ def to_pson
62
+ Puppet.deprecation_warning("Serializing Puppet::FileBucket::File objects to pson is deprecated.")
63
+ { "contents" => contents }.to_pson
64
+ end
65
+
57
66
  # This method is deprecated, but cannot be removed for awhile, otherwise
58
67
  # older agents sending pson couldn't backup to filebuckets on newer masters
59
68
  def self.from_pson(pson)
@@ -1,10 +1,13 @@
1
1
  require 'net/https'
2
- require 'zlib'
3
2
  require 'digest/sha1'
4
3
  require 'uri'
5
4
  require 'puppet/util/http_proxy'
6
5
  require 'puppet/forge/errors'
7
6
 
7
+ if Puppet.features.zlib? && Puppet[:zlib]
8
+ require 'zlib'
9
+ end
10
+
8
11
  class Puppet::Forge
9
12
  # = Repository
10
13
  #
@@ -26,9 +29,12 @@ class Puppet::Forge
26
29
  Net::HTTPHeaderSyntaxError,
27
30
  Net::ProtocolError,
28
31
  SocketError,
29
- Zlib::GzipFile::Error,
30
32
  ]
31
33
 
34
+ if Puppet.features.zlib? && Puppet[:zlib]
35
+ NET_HTTP_EXCEPTIONS << Zlib::GzipFile::Error
36
+ end
37
+
32
38
  # Instantiate a new repository instance rooted at the +url+.
33
39
  # The agent will report +consumer_version+ in the User-Agent to
34
40
  # the repository.
@@ -530,7 +530,7 @@ class Puppet::Graph::SimpleGraph
530
530
  end
531
531
 
532
532
  def to_yaml_properties
533
- (instance_variables + [:@vertices, :@edges] -
533
+ (super + [:@vertices, :@edges] -
534
534
  [:@in_to, :@out_from, :@upstream_from, :@downstream_from]).uniq
535
535
  end
536
536
 
@@ -159,9 +159,27 @@ class Puppet::Indirector::Request
159
159
  # Create the query string, if options are present.
160
160
  def query_string
161
161
  return "" if options.nil? || options.empty?
162
+
163
+ # For backward compatibility with older (pre-3.3) masters,
164
+ # this puppet option allows serialization of query parameter
165
+ # arrays as yaml. This can be removed when we remove yaml
166
+ # support entirely.
167
+ if Puppet.settings[:legacy_query_parameter_serialization]
168
+ replace_arrays_with_yaml
169
+ end
170
+
162
171
  "?" + encode_params(expand_into_parameters(options.to_a))
163
172
  end
164
173
 
174
+ def replace_arrays_with_yaml
175
+ options.each do |key, value|
176
+ case value
177
+ when Array
178
+ options[key] = YAML.dump(value)
179
+ end
180
+ end
181
+ end
182
+
165
183
  def expand_into_parameters(data)
166
184
  data.inject([]) do |params, key_value|
167
185
  key, value = key_value
@@ -98,6 +98,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
98
98
  end
99
99
 
100
100
  if is_http_200?(response)
101
+ check_master_version(response)
101
102
  content_type, body = parse_response(response)
102
103
  result = deserialize_find(content_type, body)
103
104
  result.name = request.key if result.respond_to?(:name=)
@@ -112,7 +113,12 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
112
113
  http_head(request, indirection2uri(request), headers)
113
114
  end
114
115
 
115
- !!is_http_200?(response)
116
+ if is_http_200?(response)
117
+ check_master_version(response)
118
+ true
119
+ else
120
+ false
121
+ end
116
122
  end
117
123
 
118
124
  def search(request)
@@ -121,6 +127,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
121
127
  end
122
128
 
123
129
  if is_http_200?(response)
130
+ check_master_version(response)
124
131
  content_type, body = parse_response(response)
125
132
  deserialize_search(content_type, body) || []
126
133
  else
@@ -136,6 +143,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
136
143
  end
137
144
 
138
145
  if is_http_200?(response)
146
+ check_master_version(response)
139
147
  content_type, body = parse_response(response)
140
148
  deserialize_destroy(content_type, body)
141
149
  else
@@ -151,6 +159,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
151
159
  end
152
160
 
153
161
  if is_http_200?(response)
162
+ check_master_version(response)
154
163
  content_type, body = parse_response(response)
155
164
  deserialize_save(content_type, body)
156
165
  else
@@ -191,6 +200,18 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
191
200
  Net::HTTPError.new(message, response)
192
201
  end
193
202
 
203
+ def check_master_version response
204
+ if !response[Puppet::Network::HTTP::HEADER_PUPPET_VERSION] &&
205
+ (Puppet[:legacy_query_parameter_serialization] == false || Puppet[:report_serialization_format] != "yaml")
206
+ Puppet.notice "Using less secure serialization of reports and query parameters for compatibility"
207
+ Puppet.notice "with older puppet master. To remove this notice, please upgrade your master(s) "
208
+ Puppet.notice "to Puppet 3.3 or newer."
209
+ Puppet.notice "See http://links.puppetlabs.com/deprecate_yaml_on_network for more information."
210
+ Puppet[:legacy_query_parameter_serialization] = true
211
+ Puppet[:report_serialization_format] = "yaml"
212
+ end
213
+ end
214
+
194
215
  # Returns the content_type, stripping any appended charset, and the
195
216
  # body, decompressed if necessary (content-encoding is checked inside
196
217
  # uncompress_body)
@@ -5,6 +5,8 @@ class Puppet::Indirector::Status::Local < Puppet::Indirector::Code
5
5
  desc "Get status locally. Only used internally."
6
6
 
7
7
  def find( *anything )
8
- model.new
8
+ status = model.new
9
+ status.version= Puppet.version
10
+ status
9
11
  end
10
12
  end
@@ -1,28 +1,16 @@
1
1
  require 'puppet/indirector/terminus'
2
+ require 'puppet/util/yaml'
2
3
 
3
4
  # The base class for YAML indirection termini.
4
5
  class Puppet::Indirector::Yaml < Puppet::Indirector::Terminus
5
- if defined?(::Psych::SyntaxError)
6
- YamlLoadExceptions = [::StandardError, ::ArgumentError, ::Psych::SyntaxError]
7
- else
8
- YamlLoadExceptions = [::StandardError, ::ArgumentError]
9
- end
10
-
11
6
  # Read a given name's file in and convert it from YAML.
12
7
  def find(request)
13
8
  file = path(request.key)
14
9
  return nil unless FileTest.exist?(file)
15
10
 
16
- yaml = nil
17
- begin
18
- yaml = ::File.read(file)
19
- rescue => detail
20
- raise Puppet::Error, "Could not read YAML data for #{indirection.name} #{request.key}: #{detail}"
21
- end
22
-
23
11
  begin
24
- return from_yaml(yaml)
25
- rescue *YamlLoadExceptions => detail
12
+ return Puppet::Util::Yaml.load_file(file)
13
+ rescue Puppet::Util::Yaml::YamlLoadError => detail
26
14
  raise Puppet::Error, "Could not parse YAML data for #{indirection.name} #{request.key}: #{detail}"
27
15
  end
28
16
  end
@@ -39,9 +27,7 @@ class Puppet::Indirector::Yaml < Puppet::Indirector::Terminus
39
27
  Dir.mkdir(basedir) unless FileTest.exist?(basedir)
40
28
 
41
29
  begin
42
- Puppet::Util.replace_file(file, 0660) do |f|
43
- f.print to_yaml(request.instance)
44
- end
30
+ Puppet::Util::Yaml.dump(request.instance, file)
45
31
  rescue TypeError => detail
46
32
  Puppet.err "Could not save #{self.name} #{request.key}: #{detail}"
47
33
  end
@@ -1,3 +1,4 @@
1
1
  module Puppet::Network::HTTP
2
2
  HEADER_ENABLE_PROFILING = "X-Puppet-Profiling"
3
+ HEADER_PUPPET_VERSION = "X-Puppet-Version"
3
4
  end
@@ -84,6 +84,8 @@ module Puppet::Network::HTTP::Handler
84
84
  request_method = http_method(request)
85
85
  request_path = path(request)
86
86
 
87
+ response[Puppet::Network::HTTP::HEADER_PUPPET_VERSION] = Puppet.version
88
+
87
89
  configure_profiler(request_headers, request_params)
88
90
 
89
91
  Puppet::Util::Profiler.profile("Processed request #{request_method} #{request_path}") do
@@ -97,7 +99,7 @@ module Puppet::Network::HTTP::Handler
97
99
  rescue SystemExit,NoMemoryError
98
100
  raise
99
101
  rescue HTTPError => e
100
- return do_exception(response, e.message, e.status)
102
+ return do_http_control_exception(response, e)
101
103
  rescue Exception => e
102
104
  return do_exception(response, e)
103
105
  ensure
@@ -121,11 +123,7 @@ module Puppet::Network::HTTP::Handler
121
123
  status = 403 if status == 400
122
124
  end
123
125
 
124
- if exception.is_a?(Exception)
125
- Puppet.log_exception(exception)
126
- else
127
- Puppet.notice(exception.to_s)
128
- end
126
+ Puppet.log_exception(exception)
129
127
 
130
128
  set_content_type(response, "text/plain")
131
129
  set_response(response, exception.to_s, status)
@@ -219,6 +217,13 @@ module Puppet::Network::HTTP::Handler
219
217
 
220
218
  private
221
219
 
220
+ def do_http_control_exception(response, exception)
221
+ msg = exception.message
222
+ Puppet.info(msg)
223
+ set_content_type(response, "text/plain")
224
+ set_response(response, msg, exception.status)
225
+ end
226
+
222
227
  def report_if_deprecated(format)
223
228
  if format.name == :yaml || format.name == :b64_zlib_yaml
224
229
  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")
@@ -2,8 +2,6 @@ module Puppet::Parser::YamlTrimmer
2
2
  REMOVE = [:@scope, :@source]
3
3
 
4
4
  def to_yaml_properties
5
- r = instance_variables - REMOVE
6
- r -= skip_for_yaml if respond_to?(:skip_for_yaml)
7
- r
5
+ super - REMOVE
8
6
  end
9
7
  end
@@ -44,6 +44,7 @@ Puppet::Type.type(:package).provide :dpkg, :parent => Puppet::Provider::Package
44
44
  self::DPKG_DESCRIPTION_DELIMITER = ':DESC:'
45
45
  self::DPKG_QUERY_FORMAT_STRING = %Q{'${Status} ${Package} ${Version} #{self::DPKG_DESCRIPTION_DELIMITER} ${Description}\\n#{self::DPKG_DESCRIPTION_DELIMITER}\\n'}
46
46
  self::FIELDS_REGEX = %r{^(\S+) +(\S+) +(\S+) (\S+) (\S*) #{self::DPKG_DESCRIPTION_DELIMITER} (.*)$}
47
+ self::DPKG_PACKAGE_NOT_FOUND_REGEX = /No packages found matching/
47
48
  self::FIELDS= [:desired, :error, :status, :name, :ensure, :description]
48
49
  self::END_REGEX = %r{^#{self::DPKG_DESCRIPTION_DELIMITER}$}
49
50
 
@@ -59,7 +60,7 @@ Puppet::Type.type(:package).provide :dpkg, :parent => Puppet::Provider::Package
59
60
 
60
61
  line = pipe.gets
61
62
  unless hash = parse_line(line)
62
- Puppet.warning "Failed to match dpkg-query line #{line.inspect}"
63
+ Puppet.warning "Failed to match dpkg-query line #{line.inspect}" if !self::DPKG_PACKAGE_NOT_FOUND_REGEX.match(line)
63
64
  return nil
64
65
  end
65
66
 
@@ -13,6 +13,7 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr
13
13
  # The query format by which we identify installed packages
14
14
  self::NEVRA_FORMAT = %Q{'%{NAME} %|EPOCH?{%{EPOCH}}:{0}| %{VERSION} %{RELEASE} %{ARCH} #{self::RPM_DESCRIPTION_DELIMITER} %{SUMMARY}\\n'}
15
15
  self::NEVRA_REGEX = %r{^(\S+) (\S+) (\S+) (\S+) (\S+)(?: #{self::RPM_DESCRIPTION_DELIMITER} ?(.*))?$}
16
+ self::RPM_PACKAGE_NOT_FOUND_REGEX = /package .+ is not installed/
16
17
  self::NEVRA_FIELDS = [:name, :epoch, :version, :release, :arch, :description]
17
18
 
18
19
  commands :rpm => "rpm"
@@ -76,7 +77,6 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr
76
77
  rescue Puppet::ExecutionFailure
77
78
  return nil
78
79
  end
79
-
80
80
  # FIXME: We could actually be getting back multiple packages
81
81
  # for multilib and this will only return the first such package
82
82
  @property_hash.update(self.class.nevra_to_hash(output))
@@ -150,7 +150,9 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr
150
150
  line.strip!
151
151
  hash = {}
152
152
 
153
- if match = self::NEVRA_REGEX.match(line)
153
+ if self::RPM_PACKAGE_NOT_FOUND_REGEX.match(line)
154
+ # pass through, package was not found
155
+ elsif match = self::NEVRA_REGEX.match(line)
154
156
  self::NEVRA_FIELDS.zip(match.captures) { |f, v| hash[f] = v }
155
157
  hash[:provider] = self.name
156
158
  hash[:ensure] = "#{hash[:version]}-#{hash[:release]}"
@@ -64,13 +64,15 @@ class Puppet::Provider::ParsedFile < Puppet::Provider
64
64
  return unless defined?(@modified) and ! @modified.empty?
65
65
 
66
66
  flushed = []
67
- @modified.sort { |a,b| a.to_s <=> b.to_s }.uniq.each do |target|
68
- Puppet.debug "Flushing #{@resource_type.name} provider target #{target}"
69
- flush_target(target)
70
- flushed << target
67
+ begin
68
+ @modified.sort { |a,b| a.to_s <=> b.to_s }.uniq.each do |target|
69
+ Puppet.debug "Flushing #{@resource_type.name} provider target #{target}"
70
+ flushed << target
71
+ flush_target(target)
72
+ end
73
+ ensure
74
+ @modified.reject! { |t| flushed.include?(t) }
71
75
  end
72
-
73
- @modified.reject! { |t| flushed.include?(t) }
74
76
  end
75
77
 
76
78
  # 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
92
94
  records = target_records(target).reject { |r|
93
95
  r[:ensure] == :absent
94
96
  }
97
+
95
98
  target_object(target).write(to_file(records))
96
99
  end
97
100
 
@@ -135,7 +135,7 @@ module Puppet
135
135
  end
136
136
 
137
137
  def to_yaml_properties
138
- YAML_ATTRIBUTES & instance_variables
138
+ YAML_ATTRIBUTES & super
139
139
  end
140
140
 
141
141
  private
data/lib/puppet/status.rb CHANGED
@@ -29,4 +29,12 @@ class Puppet::Status
29
29
  def name=(name)
30
30
  # NOOP
31
31
  end
32
+
33
+ def version
34
+ @status['version']
35
+ end
36
+
37
+ def version=(version)
38
+ @status['version'] = version
39
+ end
32
40
  end
@@ -38,7 +38,7 @@ class Puppet::Transaction::AdditionalResourceGenerator
38
38
  generated = replace_duplicates_with_catalog_resources(resource.eval_generate)
39
39
  return false if generated.empty?
40
40
  rescue => detail
41
- resource.log_exception(detail, "Failed to generate additional resources using 'eval_generate: #{detail}")
41
+ resource.log_exception(detail, "Failed to generate additional resources using 'eval_generate': #{detail}")
42
42
  return false
43
43
  end
44
44
  add_resources(generated, resource)