puppet 3.8.1 → 3.8.2

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 (50) hide show
  1. data/ext/build_defaults.yaml +4 -4
  2. data/ext/systemd/puppet.service +1 -1
  3. data/ext/systemd/puppetmaster.service +1 -1
  4. data/lib/hiera/puppet_function.rb +5 -5
  5. data/lib/puppet/defaults.rb +1 -5
  6. data/lib/puppet/environments.rb +85 -4
  7. data/lib/puppet/functions/hiera_include.rb +2 -2
  8. data/lib/puppet/module_tool/applications/unpacker.rb +1 -1
  9. data/lib/puppet/parser/ast/collexpr.rb +1 -1
  10. data/lib/puppet/parser/ast/pops_bridge.rb +5 -0
  11. data/lib/puppet/parser/scope.rb +43 -13
  12. data/lib/puppet/pops/evaluator/evaluator_impl.rb +5 -1
  13. data/lib/puppet/pops/evaluator/runtime3_converter.rb +1 -1
  14. data/lib/puppet/pops/evaluator/runtime3_support.rb +31 -0
  15. data/lib/puppet/pops/issues.rb +10 -2
  16. data/lib/puppet/pops/model/factory.rb +4 -3
  17. data/lib/puppet/pops/model/model_meta.rb +4 -1
  18. data/lib/puppet/pops/parser/egrammar.ra +4 -0
  19. data/lib/puppet/pops/parser/eparser.rb +1167 -1066
  20. data/lib/puppet/pops/parser/epp_support.rb +4 -2
  21. data/lib/puppet/pops/parser/lexer2.rb +6 -0
  22. data/lib/puppet/pops/patterns.rb +3 -0
  23. data/lib/puppet/pops/types/type_parser.rb +2 -2
  24. data/lib/puppet/pops/validation/checker4_0.rb +9 -1
  25. data/lib/puppet/pops/validation/validator_factory_4_0.rb +3 -1
  26. data/lib/puppet/provider/group/pw.rb +1 -0
  27. data/lib/puppet/provider/service/debian.rb +2 -1
  28. data/lib/puppet/provider/user/pw.rb +1 -0
  29. data/lib/puppet/resource.rb +3 -1
  30. data/lib/puppet/resource/type.rb +4 -2
  31. data/lib/puppet/util.rb +9 -1
  32. data/lib/puppet/util/log.rb +1 -1
  33. data/lib/puppet/version.rb +1 -1
  34. data/spec/integration/parser/compiler_spec.rb +9 -7
  35. data/spec/integration/parser/future_compiler_spec.rb +9 -7
  36. data/spec/integration/parser/scope_spec.rb +37 -0
  37. data/spec/unit/environments_spec.rb +2 -0
  38. data/spec/unit/functions/hiera_spec.rb +2 -2
  39. data/spec/unit/parser/scope_spec.rb +9 -0
  40. data/spec/unit/pops/evaluator/runtime3_converter_spec.rb +19 -0
  41. data/spec/unit/pops/evaluator/variables_spec.rb +1 -1
  42. data/spec/unit/pops/parser/lexer2_spec.rb +48 -3
  43. data/spec/unit/pops/types/type_parser_spec.rb +8 -0
  44. data/spec/unit/pops/validator/validator_spec.rb +28 -0
  45. data/spec/unit/provider/service/debian_spec.rb +11 -3
  46. data/spec/unit/provider/zone/solaris_spec.rb +45 -12
  47. data/spec/unit/util/log_spec.rb +12 -1
  48. data/spec/unit/util_spec.rb +21 -2
  49. metadata +3283 -3273
  50. checksums.yaml +0 -7
@@ -16,18 +16,18 @@ build_gem: TRUE
16
16
  build_dmg: TRUE
17
17
  build_msi:
18
18
  puppet_for_the_win:
19
- ref: '2476cd007b1b52fb1b9f22202b56218629626b5c'
19
+ ref: 'refs/tags/3.8.0'
20
20
  repo: 'git://github.com/puppetlabs/puppet_for_the_win.git'
21
21
  facter:
22
- ref: 'refs/tags/2.3.0'
22
+ ref: 'refs/tags/2.4.4'
23
23
  repo: 'git://github.com/puppetlabs/facter.git'
24
24
  hiera:
25
25
  ref: 'refs/tags/1.3.4'
26
26
  repo: 'git://github.com/puppetlabs/hiera.git'
27
27
  sys:
28
28
  ref:
29
- x86: '2f25839c5c11ec10b781debf4808095d6895a844'
30
- x64: '017c63ca11e38f74b7e011ecd2006100452c620b'
29
+ x86: 'refs/tags/1.9.3-p551.4'
30
+ x64: 'refs/tags/2.0.0.7-x64'
31
31
  repo: 'git://github.com/puppetlabs/puppet-win32-ruby.git'
32
32
  apt_host: 'apt.puppetlabs.com'
33
33
  apt_repo_url: 'http://apt.puppetlabs.com'
@@ -6,7 +6,7 @@ After=basic.target network.target puppetmaster.service
6
6
  [Service]
7
7
  EnvironmentFile=-/etc/sysconfig/puppetagent
8
8
  EnvironmentFile=-/etc/sysconfig/puppet
9
- ExecStart=/usr/bin/puppet agent ${PUPPET_EXTRA_OPTS} --no-daemonize
9
+ ExecStart=/usr/bin/puppet agent $PUPPET_EXTRA_OPTS --no-daemonize
10
10
  KillMode=process
11
11
 
12
12
  [Install]
@@ -5,7 +5,7 @@ After=basic.target network.target
5
5
 
6
6
  [Service]
7
7
  EnvironmentFile=-/etc/sysconfig/puppetmaster
8
- ExecStart=/usr/bin/puppet master ${PUPPETMASTER_EXTRA_OPTS} --no-daemonize
8
+ ExecStart=/usr/bin/puppet master $PUPPETMASTER_EXTRA_OPTS --no-daemonize
9
9
 
10
10
  [Install]
11
11
  WantedBy=multi-user.target
@@ -43,13 +43,13 @@ class Hiera::PuppetFunction < Puppet::Functions::InternalFunction
43
43
  end
44
44
 
45
45
  def hiera_no_default(scope, key)
46
- post_lookup(key, lookup(scope, key, nil, nil))
46
+ post_lookup(scope, key, lookup(scope, key, nil, nil))
47
47
  end
48
48
 
49
49
  def hiera_with_default(scope, key, default, override = nil)
50
50
  undefined = (@@undefined_value ||= Object.new)
51
51
  result = lookup(scope, key, undefined, override)
52
- post_lookup(key, result.equal?(undefined) ? default : result)
52
+ post_lookup(scope, key, result.equal?(undefined) ? default : result)
53
53
  end
54
54
 
55
55
  def hiera_block1(scope, key, &default_block)
@@ -63,20 +63,20 @@ class Hiera::PuppetFunction < Puppet::Functions::InternalFunction
63
63
  def common(scope, key, override, default_block)
64
64
  undefined = (@@undefined_value ||= Object.new)
65
65
  result = lookup(scope, key, undefined, override)
66
- post_lookup(key, result.equal?(undefined) ? default_block.call(key) : result)
66
+ post_lookup(scope, key, result.equal?(undefined) ? default_block.call(key) : result)
67
67
  end
68
68
 
69
69
  private :common
70
70
 
71
71
  def lookup(scope, key, default, override)
72
- HieraPuppet.lookup(key, default,scope, override, merge_type)
72
+ HieraPuppet.lookup(key, default, scope, override, merge_type)
73
73
  end
74
74
 
75
75
  def merge_type
76
76
  :priority
77
77
  end
78
78
 
79
- def post_lookup(key, result)
79
+ def post_lookup(scope, key, result)
80
80
  result
81
81
  end
82
82
  end
@@ -486,10 +486,6 @@ module Puppet
486
486
  :default => "stomp",
487
487
  :desc => "Which type of queue to use for asynchronous processing.",
488
488
  },
489
- :queue_type => {
490
- :default => "stomp",
491
- :desc => "Which type of queue to use for asynchronous processing.",
492
- },
493
489
  :queue_source => {
494
490
  :default => "stomp://localhost:61613/",
495
491
  :desc => "Which type of queue to use for asynchronous processing. If your stomp server requires
@@ -592,7 +588,7 @@ module Puppet
592
588
  :desc => "The module repository",
593
589
  },
594
590
  :module_working_dir => {
595
- :default => '$vardir/puppet-module',
591
+ :default => (Puppet.features.microsoft_windows? ? Dir.tmpdir() : '$vardir/puppet-module'),
596
592
  :desc => "The directory into which module tool data is stored",
597
593
  },
598
594
  :module_skeleton_dir => {
@@ -338,10 +338,29 @@ module Puppet::Environments
338
338
  @cache_expiration_service || DefaultCacheExpirationService.new
339
339
  end
340
340
 
341
+ # Returns the end of time (the next Mesoamerican Long Count cycle-end after 2012 (5125+2012) = 7137,
342
+ # of for a 32 bit machine using Ruby < 1.9.3, the year 2038.
343
+ def self.end_of_time
344
+ begin
345
+ Time.gm(7137)
346
+ rescue ArgumentError
347
+ Time.gm(2038)
348
+ end
349
+ end
350
+
351
+ END_OF_TIME = end_of_time
352
+ START_OF_TIME = Time.gm(1)
353
+
341
354
  def initialize(loader)
342
355
  @loader = loader
343
- @cache = {}
344
356
  @cache_expiration_service = Puppet::Environments::Cached.cache_expiration_service
357
+ @cache = {}
358
+
359
+ # Holds expiration times in sorted order - next to expire is first
360
+ @expirations = SortedSet.new
361
+
362
+ # Infinity since it there are no entries, this is a cache of the first to expire time
363
+ @next_expiration = END_OF_TIME
345
364
  end
346
365
 
347
366
  # @!macro loader_list
@@ -356,15 +375,34 @@ module Puppet::Environments
356
375
 
357
376
  # @!macro loader_get
358
377
  def get(name)
359
- evict_if_expired(name)
378
+ # Aggressively evict all that has expired
379
+ # This strategy favors smaller memory footprint over environment
380
+ # retrieval time.
381
+ clear_all_expired
360
382
  if result = @cache[name]
383
+ # found in cache
361
384
  return result.value
362
385
  elsif (result = @loader.get(name))
363
- @cache[name] = entry(result)
386
+ # environment loaded, cache it
387
+ cache_entry = entry(result)
388
+ @cache_expiration_service.created(result)
389
+ add_entry(name, cache_entry)
364
390
  result
365
391
  end
366
392
  end
367
393
 
394
+ # Adds a cache entry to the cache
395
+ def add_entry(name, cache_entry)
396
+ Puppet.debug("Caching environment '#{name}' #{cache_entry.label}")
397
+ @cache[name] = cache_entry
398
+ expires = cache_entry.expires
399
+ @expirations.add(expires)
400
+ if @next_expiration > expires
401
+ @next_expiration = expires
402
+ end
403
+ end
404
+ private :add_entry
405
+
368
406
  # Clears the cache of the environment with the given name.
369
407
  # (The intention is that this could be used from a MANUAL cache eviction command (TBD)
370
408
  def clear(name)
@@ -375,6 +413,25 @@ module Puppet::Environments
375
413
  # (The intention is that this could be used from a MANUAL cache eviction command (TBD)
376
414
  def clear_all()
377
415
  @cache = {}
416
+ @expirations.clear
417
+ @next_expiration = END_OF_TIME
418
+ end
419
+
420
+ # Clears all environments that have expired, either by exceeding their time to live, or
421
+ # through an explicit eviction determined by the cache expiration service.
422
+ #
423
+ def clear_all_expired()
424
+ t = Time.now
425
+ return if t < @next_expiration && ! @cache.any? {|name, _| @cache_expiration_service.expired?(name.to_sym) }
426
+ to_expire = @cache.select { |name, entry| entry.expires < t || @cache_expiration_service.expired?(name.to_sym) }
427
+ to_expire.each do |name, entry|
428
+ Puppet.debug("Evicting cache entry for environment '#{name}'")
429
+ @cache_expiration_service.evicted(name)
430
+ clear(name)
431
+ @expirations.delete(entry.expires)
432
+ Puppet.settings.clear_environment_settings(name)
433
+ end
434
+ @next_expiration = @expirations.first || END_OF_TIME
378
435
  end
379
436
 
380
437
  # This implementation evicts the cache, and always gets the current
@@ -393,7 +450,6 @@ module Puppet::Environments
393
450
  # Creates a suitable cache entry given the time to live for one environment
394
451
  #
395
452
  def entry(env)
396
- @cache_expiration_service.created(env)
397
453
  ttl = (conf = get_conf(env.name)) ? conf.environment_timeout : Puppet.settings.value(:environment_timeout)
398
454
  case ttl
399
455
  when 0
@@ -427,6 +483,14 @@ module Puppet::Environments
427
483
  def expired?
428
484
  false
429
485
  end
486
+
487
+ def label
488
+ ""
489
+ end
490
+
491
+ def expires
492
+ END_OF_TIME
493
+ end
430
494
  end
431
495
 
432
496
  # Always evicting entry
@@ -434,6 +498,14 @@ module Puppet::Environments
434
498
  def expired?
435
499
  true
436
500
  end
501
+
502
+ def label
503
+ "(ttl = 0 sec)"
504
+ end
505
+
506
+ def expires
507
+ START_OF_TIME
508
+ end
437
509
  end
438
510
 
439
511
  # Time to Live eviction policy entry
@@ -441,11 +513,20 @@ module Puppet::Environments
441
513
  def initialize(value, ttl_seconds)
442
514
  super value
443
515
  @ttl = Time.now + ttl_seconds
516
+ @ttl_seconds = ttl_seconds
444
517
  end
445
518
 
446
519
  def expired?
447
520
  Time.now > @ttl
448
521
  end
522
+
523
+ def label
524
+ "(ttl = #{@ttl_seconds} sec)"
525
+ end
526
+
527
+ def expires
528
+ @ttl
529
+ end
449
530
  end
450
531
  end
451
532
  end
@@ -43,8 +43,8 @@ Puppet::Functions.create_function(:hiera_include, Hiera::PuppetFunction) do
43
43
  :array
44
44
  end
45
45
 
46
- def post_lookup(key, value)
46
+ def post_lookup(scope, key, value)
47
47
  raise Puppet::ParseError, "Could not find data item #{key}" if value.nil?
48
- call_function('include', value) unless value.empty?
48
+ call_function_with_scope(scope, 'include', value) unless value.empty?
49
49
  end
50
50
  end
@@ -93,7 +93,7 @@ module Puppet::ModuleTool
93
93
  # @api private
94
94
  # @return [String] path to temporary unpacking location
95
95
  def tmpdir
96
- @dir ||= Dir.mktmpdir('tmp-unpacker', Puppet::Forge::Cache.base_path)
96
+ @dir ||= Dir.mktmpdir('tmp', Puppet::Forge::Cache.base_path)
97
97
  end
98
98
  end
99
99
  end
@@ -100,7 +100,7 @@ class CollExpr < AST::Branch
100
100
 
101
101
  def initialize(hash = {})
102
102
  super
103
- if Puppet[:parser] == "future"
103
+ if Puppet.future_parser?
104
104
  @@compare_operator ||= Puppet::Pops::Evaluator::CompareOperator.new
105
105
  end
106
106
  raise ArgumentError, "Invalid operator #{@oper}" unless %w{== != and or}.include?(@oper)
@@ -23,6 +23,11 @@ class Puppet::Parser::AST::PopsBridge
23
23
  Puppet::Pops::Model::ModelTreeDumper.new.dump(@value)
24
24
  end
25
25
 
26
+ def source_text
27
+ source_adapter = Puppet::Pops::Utils.find_closest_positioned(@value)
28
+ source_adapter ? source_adapter.extract_text() : nil
29
+ end
30
+
26
31
  def evaluate(scope)
27
32
  object = @@evaluator.evaluate(scope, @value)
28
33
  @@evaluator.convert_to_3x(object, scope)
@@ -499,24 +499,36 @@ class Puppet::Parser::Scope
499
499
  def lookup_qualified_variable(class_name, variable_name, position)
500
500
  begin
501
501
  if lookup_as_local_name?(class_name, variable_name)
502
- self[variable_name]
502
+ if is_topscope?
503
+ # This is the case where $::x is looked up from within the topscope itself, or from a local scope
504
+ # parented at the top scope. In this case, the lookup must ignore local and ephemeral scopes.
505
+ #
506
+ handle_not_found(class_name, variable_name, position) unless @symtable.include?(variable_name)
507
+ @symtable[variable_name]
508
+ else
509
+ self[variable_name]
510
+ end
503
511
  else
504
512
  qualified_scope(class_name).lookupvar(variable_name, position)
505
513
  end
506
514
  rescue RuntimeError => e
507
- unless Puppet[:strict_variables]
508
- # Do not issue warning if strict variables are on, as an error will be raised by variable_not_found
509
- location = if position[:lineproc]
510
- " at #{position[:lineproc].call}"
511
- elsif position[:file] && position[:line]
512
- " at #{position[:file]}:#{position[:line]}"
513
- else
514
- ""
515
- end
516
- warning "Could not look up qualified variable '#{class_name}::#{variable_name}'; #{e.message}#{location}"
517
- end
518
- variable_not_found("#{class_name}::#{variable_name}", e.message)
515
+ handle_not_found(class_name, variable_name, position, e.message)
516
+ end
517
+ end
518
+
519
+ def handle_not_found(class_name, variable_name, position, reason = nil)
520
+ unless Puppet[:strict_variables]
521
+ # Do not issue warning if strict variables are on, as an error will be raised by variable_not_found
522
+ location = if position[:lineproc]
523
+ " at #{position[:lineproc].call}"
524
+ elsif position[:file] && position[:line]
525
+ " at #{position[:file]}:#{position[:line]}"
526
+ else
527
+ ""
528
+ end
529
+ warning "Could not look up qualified variable '#{class_name}::#{variable_name}'; #{reason}#{location}"
519
530
  end
531
+ variable_not_found("#{class_name}::#{variable_name}", reason)
520
532
  end
521
533
 
522
534
  # Handles the special case of looking up fully qualified variable in not yet evaluated top scope
@@ -768,6 +780,8 @@ class Puppet::Parser::Scope
768
780
  "Scope(#{@resource})"
769
781
  end
770
782
 
783
+ alias_method :inspect, :to_s
784
+
771
785
  # remove ephemeral scope up to level
772
786
  # TODO: Who uses :all ? Remove ??
773
787
  #
@@ -911,6 +925,22 @@ class Puppet::Parser::Scope
911
925
  end
912
926
  end
913
927
 
928
+ # Calls a 3.x or 4.x function by name with arguments given in an array using the 4.x calling convention
929
+ # and returns the result.
930
+ # Note that it is the caller's responsibility to rescue the given ArgumentError and provide location information
931
+ # to aid the user find the problem. The problem is otherwise reported against the source location that
932
+ # invoked the function that ultimately called this method.
933
+ #
934
+ # @return [Object] the result of the called function
935
+ # @raise ArgumentError if the function does not exist
936
+ def call_function(func_name, args, &block)
937
+ if !Puppet.future_parser?(compiler.environment)
938
+ return self.send("function_#{func_name}", args, &block)
939
+ else
940
+ Puppet::Pops::Parser::EvaluatingParser.new.evaluator.external_call_function(func_name, args, self, &block)
941
+ end
942
+ end
943
+
914
944
  private
915
945
 
916
946
  def assert_class_and_title(type_name, title)
@@ -239,7 +239,11 @@ class Puppet::Pops::Evaluator::EvaluatorImpl
239
239
  # Reserved Words fail to evaluate
240
240
  #
241
241
  def eval_ReservedWord(o, scope)
242
- fail(Puppet::Pops::Issues::RESERVED_WORD, o, {:word => o.word})
242
+ if !o.future
243
+ fail(Puppet::Pops::Issues::RESERVED_WORD, o, {:word => o.word})
244
+ else
245
+ o.word
246
+ end
243
247
  end
244
248
 
245
249
  def eval_LiteralDefault(o, scope)
@@ -140,7 +140,7 @@ class Runtime3Converter
140
140
  when Puppet::Pops::Types::PResourceType
141
141
  type_name = split_type.type_name
142
142
  title = split_type.title
143
- if type_name =~ /^(::)?[Cc]lass/
143
+ if type_name =~ /^(::)?[Cc]lass$/
144
144
  ['class', title.nil? ? nil : title.sub(/^::/, '')]
145
145
  else
146
146
  # Ensure that title is '' if nil
@@ -229,6 +229,37 @@ module Puppet::Pops::Evaluator::Runtime3Support
229
229
  n
230
230
  end
231
231
 
232
+ # Provides the ability to call a 3.x or 4.x function from the perspective of a 3.x function or ERB template.
233
+ # The arguments to the function must be an Array containing values compliant with the 4.x calling convention.
234
+ # If the targeted function is a 3.x function, the values will be transformed.
235
+ # @param name [String] the name of the function (without the 'function_' prefix used by scope)
236
+ # @param args [Array] arguments, may be empty
237
+ # @param scope [Object] the (runtime specific) scope where evaluation takes place
238
+ # @raise ArgumentError 'unknown function' if the function does not exist
239
+ #
240
+ def external_call_function(name, args, scope, &block)
241
+ # Call via 4x API if the function exists there
242
+ loaders = scope.compiler.loaders
243
+ # Since this is a call from non puppet code, it is not possible to relate it to a module loader
244
+ # It is known where the call originates by using the scope associated module - but this is the calling scope
245
+ # and it does not defined the visibility of functions from a ruby function's perspective. Instead,
246
+ # this is done from the perspective of the environment.
247
+ loader = loaders.private_environment_loader
248
+ if loader && func = loader.load(:function, name)
249
+ return func.call(scope, *args, &block)
250
+ end
251
+
252
+ # Call via 3x API if function exists there
253
+ raise ArgumentError, "Unknown function '#{name}'" unless Puppet::Parser::Functions.function(name)
254
+
255
+ # Arguments must be mapped since functions are unaware of the new and magical creatures in 4x.
256
+ # NOTE: Passing an empty string last converts nil/:undef to empty string
257
+ mapped_args = Puppet::Pops::Evaluator::Runtime3Converter.map_args(args, scope, '')
258
+ result = scope.send("function_#{name}", mapped_args, &block)
259
+ # Prevent non r-value functions from leaking their result (they are not written to care about this)
260
+ Puppet::Parser::Functions.rvalue?(name) ? result : nil
261
+ end
262
+
232
263
  def call_function(name, args, o, scope, &block)
233
264
  # Call via 4x API if the function exists there
234
265
  loaders = scope.compiler.loaders
@@ -243,11 +243,15 @@ module Puppet::Pops::Issues
243
243
  end
244
244
 
245
245
  ILLEGAL_NAME = hard_issue :ILLEGAL_NAME, :name do
246
- "Illegal name. The given name #{name} does not conform to the naming rule /^((::)?[a-z_]\w*)(::[a-z]\w*)*$/"
246
+ "Illegal name. The given name '#{name}' does not conform to the naming rule /^((::)?[a-z_]\w*)(::[a-z]\\w*)*$/"
247
+ end
248
+
249
+ ILLEGAL_PARAM_NAME = hard_issue :ILLEGAL_PARAM_NAME, :name do
250
+ "Illegal parameter name. The given name '#{name}' does not conform to the naming rule /^[a-z_]\\w*$/"
247
251
  end
248
252
 
249
253
  ILLEGAL_VAR_NAME = hard_issue :ILLEGAL_VAR_NAME, :name do
250
- "Illegal variable name, The given name '#{name}' does not conform to the naming rule /^((::)?[a-z]\w*)*((::)?[a-z_]\w*)$/"
254
+ "Illegal variable name, The given name '#{name}' does not conform to the naming rule /^((::)?[a-z]\\w*)*((::)?[a-z_]\\w*)$/"
251
255
  end
252
256
 
253
257
  ILLEGAL_NUMERIC_VAR_NAME = hard_issue :ILLEGAL_NUMERIC_VAR_NAME, :name do
@@ -522,6 +526,10 @@ module Puppet::Pops::Issues
522
526
  "Use of reserved word: #{word}, must be quoted if intended to be a String value"
523
527
  end
524
528
 
529
+ FUTURE_RESERVED_WORD = issue :FUTURE_RESERVED_WORD, :word do
530
+ "Use of future reserved word: '#{word}', must later be quoted if intended to be a String value"
531
+ end
532
+
525
533
  RESERVED_TYPE_NAME = hard_issue :RESERVED_TYPE_NAME, :name do
526
534
  "The name: '#{name}' is already defined by Puppet and can not be used as the name of #{label.a_an(semantic)}."
527
535
  end