puppet 4.5.2-universal-darwin → 4.5.3-universal-darwin

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.

@@ -34,22 +34,24 @@ gem_platform_dependencies:
34
34
  gem_runtime_dependencies:
35
35
  # Pinning versions that require native extensions
36
36
  ffi: '~> 1.9.6'
37
- win32-dir: '~> 0.4.9'
38
- win32-eventlog: '~> 0.6.2'
39
- win32-process: '~> 0.7.4'
37
+ # win32-xxxx gems are pinned due to PUP-6445
38
+ win32-dir: '= 0.4.9'
39
+ win32-eventlog: '= 0.6.5'
40
+ win32-process: '= 0.7.5'
40
41
  # Use of win32-security is deprecated
41
- win32-security: '~> 0.2.5'
42
- win32-service: '~> 0.8.6'
42
+ win32-security: '= 0.2.5'
43
+ win32-service: '= 0.8.7'
43
44
  minitar: '~> 0.5.4'
44
45
  x64-mingw32:
45
46
  gem_runtime_dependencies:
46
47
  ffi: '~> 1.9.6'
47
- win32-dir: '~> 0.4.9'
48
- win32-eventlog: '~> 0.6.2'
49
- win32-process: '~> 0.7.4'
48
+ # win32-xxxx gems are pinned due to PUP-6445
49
+ win32-dir: '= 0.4.9'
50
+ win32-eventlog: '= 0.6.5'
51
+ win32-process: '= 0.7.5'
50
52
  # Use of win32-security is deprecated
51
- win32-security: '~> 0.2.5'
52
- win32-service: '~> 0.8.6'
53
+ win32-security: '= 0.2.5'
54
+ win32-service: '= 0.8.7'
53
55
  minitar: '~> 0.5.4'
54
56
  bundle_platforms:
55
57
  universal-darwin: ruby
@@ -201,7 +201,7 @@ class Puppet::Parser::Scope
201
201
  scope.new_match_scope(nil)
202
202
  return as_read_only { expression.safeevaluate(scope) }
203
203
  end
204
- raise Puppet::Error, "default expression for $#{name} tries to illegally access not yet evaluated $#{bad}"
204
+ parameter_reference_failure(name, bad)
205
205
  end
206
206
  end
207
207
 
@@ -211,12 +211,21 @@ class Puppet::Parser::Scope
211
211
  scope.new_match_scope(nil)
212
212
  return as_read_only { evaluator.evaluate(expression, scope) }
213
213
  end
214
- raise Puppet::Error, "default expression for $#{name} tries to illegally access not yet evaluated $#{bad}"
214
+ parameter_reference_failure(name, bad)
215
215
  end
216
216
  end
217
217
 
218
- def initialize(parent, param_names)
218
+ def parameter_reference_failure(from, to)
219
+ # Parameters are evaluated in the order they have in the @params hash.
220
+ keys = @params.keys
221
+ raise Puppet::Error, "#{@callee_name}: expects a value for parameter $#{to}" if keys.index(to) < keys.index(from)
222
+ raise Puppet::Error, "#{@callee_name}: default expression for $#{from} tries to illegally access not yet evaluated $#{to}"
223
+ end
224
+ private :parameter_reference_failure
225
+
226
+ def initialize(parent, callee_name, param_names)
219
227
  super(parent)
228
+ @callee_name = callee_name
220
229
  @params = {}
221
230
  param_names.each { |name| @params[name] = Access.new }
222
231
  end
@@ -913,9 +922,12 @@ class Puppet::Parser::Scope
913
922
  end
914
923
 
915
924
  # Nests a parameter scope
925
+ # @param [String] callee_name the name of the function, template, or resource that defines the parameters
926
+ # @param [Array<String>] param_names list of parameter names
927
+ # @yieldparam [ParameterScope] param_scope the nested scope
916
928
  # @api private
917
- def with_parameter_scope(param_names)
918
- param_scope = ParameterScope.new(@ephemeral.last, param_names)
929
+ def with_parameter_scope(callee_name, param_names)
930
+ param_scope = ParameterScope.new(@ephemeral.last, callee_name, param_names)
919
931
  with_guarded_scope do
920
932
  @ephemeral.push(param_scope)
921
933
  yield(param_scope)
@@ -44,7 +44,7 @@ class Closure < CallableSignature
44
44
  def call_by_name(args_hash, enforce_parameters)
45
45
  if enforce_parameters
46
46
  # Push a temporary parameter scope used while resolving the parameter defaults
47
- @enclosing_scope.with_parameter_scope(parameter_names) do |param_scope|
47
+ @enclosing_scope.with_parameter_scope(closure_name, parameter_names) do |param_scope|
48
48
  # Assign all non-nil values, even those that represent non-existent paramaters.
49
49
  args_hash.each { |k, v| param_scope[k] = v unless v.nil? }
50
50
  parameters.each do |p|
@@ -146,7 +146,7 @@ class Closure < CallableSignature
146
146
  end
147
147
 
148
148
  def combine_values_with_parameters(scope, args)
149
- scope.with_parameter_scope(parameter_names) do |param_scope|
149
+ scope.with_parameter_scope(closure_name, parameter_names) do |param_scope|
150
150
  parameters.each_with_index do |parameter, index|
151
151
  param_captures = parameter.captures_rest
152
152
  default_expression = parameter.value
@@ -14,6 +14,10 @@ module Puppet::Pops::Patterns
14
14
  #
15
15
  NUMERIC = %r{\A[[:blank:]]*([-+]?)[[:blank:]]*((0[xX][0-9A-Fa-f]+)|(0?\d+)((?:\.\d+)?(?:[eE]-?\d+)?))[[:blank:]]*\z}
16
16
 
17
+ # Special expression that tests if there is whitespace between sign and number. The expression is used
18
+ # to strip such whitespace when normal Float or Integer conversion fails.
19
+ WS_BETWEEN_SIGN_AND_NUMBER = %r{\A([+-])[[:blank:]]+(.*)\z}
20
+
17
21
  # ILLEGAL_P3_1_HOSTNAME matches if a hostname contains illegal characters.
18
22
  # This check does not prevent pathological names like 'a....b', '.....', "---". etc.
19
23
  ILLEGAL_HOSTNAME_CHARS = %r{[^-\w.]}
@@ -452,10 +452,10 @@ class StringConverter
452
452
  def convert(value, string_formats = :default)
453
453
  options = DEFAULT_STRING_FORMATS
454
454
 
455
+ value_type = TypeCalculator.infer_set(value)
455
456
  if string_formats.is_a?(String)
456
457
  # add the format given for the exact type
457
- t = TypeCalculator.infer_set(value)
458
- string_formats = { t => string_formats }
458
+ string_formats = { value_type => string_formats }
459
459
  end
460
460
 
461
461
  case string_formats
@@ -471,7 +471,7 @@ class StringConverter
471
471
  raise ArgumentError, "string conversion expects a Default value or a Hash of type to format mappings, got a '#{string_formats.class}'"
472
472
  end
473
473
 
474
- _convert(TypeCalculator.infer_set(value), value, options, DEFAULT_INDENTATION)
474
+ _convert(value_type, value, options, DEFAULT_INDENTATION)
475
475
  end
476
476
 
477
477
  # # A method only used for manual debugging as the default output of the formatting rules is
@@ -557,21 +557,20 @@ class StringConverter
557
557
 
558
558
  def string_PDefaultType(val_type, val, format_map, _)
559
559
  f = get_format(val_type, format_map)
560
- case f.format
560
+ apply_string_flags(f, case f.format
561
561
  when :d, :s, :p
562
562
  f.alt? ? '"default"' : 'default'
563
563
  when :D
564
564
  f.alt? ? '"Default"' : 'Default'
565
565
  else
566
566
  raise FormatError.new('Default', f.format, 'dDsp')
567
- end
567
+ end)
568
568
  end
569
569
 
570
570
  # @api private
571
571
  def string_PUndefType(val_type, val, format_map, _)
572
572
  f = get_format(val_type, format_map)
573
- undef_str =
574
- case f.format
573
+ apply_string_flags(f, case f.format
575
574
  when :n
576
575
  f.alt? ? 'null' : 'nil'
577
576
  when :u
@@ -588,12 +587,7 @@ class StringConverter
588
587
  f.alt? ? '"undef"' : 'undef'
589
588
  else
590
589
  raise FormatError.new('Undef', f.format, 'nudxXobBeEfgGaAvVsp')
591
- end
592
- fmt = "%#{f.left ? '-' : ''}"
593
- fmt << "#{f.width}" if f.width
594
- fmt << ".#{f.prec}" if f.prec
595
- fmt << "s"
596
- Kernel.format(fmt,undef_str)
590
+ end)
597
591
  end
598
592
 
599
593
  # @api private
@@ -603,22 +597,22 @@ class StringConverter
603
597
  when :t
604
598
  # 'true'/'false' or 't'/'f' if in alt mode
605
599
  str_bool = val.to_s
606
- f.alt? ? str_bool[0] : str_bool
600
+ apply_string_flags(f, f.alt? ? str_bool[0] : str_bool)
607
601
 
608
602
  when :T
609
603
  # 'True'/'False' or 'T'/'F' if in alt mode
610
604
  str_bool = val.to_s.capitalize
611
- f.alt? ? str_bool[0] : str_bool
605
+ apply_string_flags(f, f.alt? ? str_bool[0] : str_bool)
612
606
 
613
607
  when :y
614
608
  # 'yes'/'no' or 'y'/'n' if in alt mode
615
609
  str_bool = val ? 'yes' : 'no'
616
- f.alt? ? str_bool[0] : str_bool
610
+ apply_string_flags(f, f.alt? ? str_bool[0] : str_bool)
617
611
 
618
612
  when :Y
619
613
  # 'Yes'/'No' or 'Y'/'N' if in alt mode
620
614
  str_bool = val ? 'Yes' : 'No'
621
- f.alt? ? str_bool[0] : str_bool
615
+ apply_string_flags(f, f.alt? ? str_bool[0] : str_bool)
622
616
 
623
617
  when :d, :x, :X, :o, :b, :B
624
618
  # Boolean in numeric form, formated by integer rule
@@ -633,16 +627,31 @@ class StringConverter
633
627
  _convert(TypeCalculator.infer_set(numeric_bool), numeric_bool, string_formats, indentation)
634
628
 
635
629
  when :s
636
- val.to_s
630
+ apply_string_flags(f, val.to_s)
637
631
 
638
632
  when :p
639
- val.inspect
633
+ apply_string_flags(f, val.inspect)
640
634
 
641
635
  else
642
636
  raise FormatError.new('Boolean', f.format, 'tTyYdxXobBeEfgGaAsp')
643
637
  end
644
638
  end
645
639
 
640
+ # Performs post-processing of literals to apply width and precision flags
641
+ def apply_string_flags(f, literal_str)
642
+ if f.left || f.width || f.prec
643
+ fmt = '%'
644
+ fmt << '-' if f.left
645
+ fmt << f.width.to_s if f.width
646
+ fmt << '.' << f.prec.to_s if f.prec
647
+ fmt << 's'
648
+ Kernel.format(fmt, literal_str)
649
+ else
650
+ literal_str
651
+ end
652
+ end
653
+ private :apply_string_flags
654
+
646
655
  # @api private
647
656
  def string_PIntegerType(val_type, val, format_map, _)
648
657
  f = get_format(val_type, format_map)
@@ -691,37 +700,77 @@ class StringConverter
691
700
  def string_PStringType(val_type, val, format_map, _)
692
701
  f = get_format(val_type, format_map)
693
702
  case f.format
694
- when :s, :p
703
+ when :s
695
704
  Kernel.format(f.orig_fmt, val)
696
705
 
706
+ when :p
707
+ apply_string_flags(f, puppet_quote(val))
708
+
697
709
  when :c
698
710
  c_val = val.capitalize
699
- substitute = f.alt? ? 'p' : 's'
700
- Kernel.format(f.orig_fmt.gsub('c', substitute), c_val)
711
+ f.alt? ? apply_string_flags(f, puppet_quote(c_val)) : Kernel.format(f.orig_fmt.gsub('c', 's'), c_val)
701
712
 
702
713
  when :C
703
714
  c_val = val.split('::').map {|s| s.capitalize }.join('::')
704
- substitute = f.alt? ? 'p' : 's'
705
- Kernel.format(f.orig_fmt.gsub('C', substitute), c_val)
715
+ f.alt? ? apply_string_flags(f, puppet_quote(c_val)) : Kernel.format(f.orig_fmt.gsub('C', 's'), c_val)
706
716
 
707
717
  when :u
708
- substitute = f.alt? ? 'p' : 's'
709
- Kernel.format(f.orig_fmt.gsub('u', substitute), val).upcase
718
+ c_val = val.upcase
719
+ f.alt? ? apply_string_flags(f, puppet_quote(c_val)) : Kernel.format(f.orig_fmt.gsub('u', 's'), c_val)
710
720
 
711
721
  when :d
712
- substitute = f.alt? ? 'p' : 's'
713
- Kernel.format(f.orig_fmt.gsub('d', substitute), val).downcase
722
+ c_val = val.downcase
723
+ f.alt? ? apply_string_flags(f, puppet_quote(c_val)) : Kernel.format(f.orig_fmt.gsub('d', 's'), c_val)
714
724
 
715
725
  when :t # trim
716
726
  c_val = val.strip
717
- substitute = f.alt? ? 'p' : 's'
718
- Kernel.format(f.orig_fmt.gsub('t', substitute), c_val)
727
+ f.alt? ? apply_string_flags(f, puppet_quote(c_val)) : Kernel.format(f.orig_fmt.gsub('t', 's'), c_val)
719
728
 
720
729
  else
721
730
  raise FormatError.new('String', f.format, 'cCudspt')
722
731
  end
723
732
  end
724
733
 
734
+ # Performs a '%p' formatting of the given _str_ such that the output conforms to Puppet syntax. An ascii string
735
+ # without control characters, dollar, single-qoute, or backslash, will be quoted using single quotes. All other
736
+ # strings will be quoted using double quotes.
737
+ #
738
+ # @param [String] str the string that should be formatted
739
+ # @return [String] the formatted string
740
+ #
741
+ # @api public
742
+ def puppet_quote(str)
743
+ if str.ascii_only? && (str =~ /(?:'|\$|\p{Cntrl}|\\)/).nil?
744
+ "'#{str}'"
745
+ else
746
+ bld = '"'
747
+ str.codepoints do |codepoint|
748
+ case codepoint
749
+ when 0x09
750
+ bld << '\\t'
751
+ when 0x0a
752
+ bld << '\\n'
753
+ when 0x0d
754
+ bld << '\\r'
755
+ when 0x22
756
+ bld << '\\"'
757
+ when 0x24
758
+ bld << '\\$'
759
+ when 0x5c
760
+ bld << '\\\\'
761
+ else
762
+ if codepoint < 0x20 || codepoint > 0x7f
763
+ bld << sprintf('\\u{%X}', codepoint)
764
+ else
765
+ bld.concat(codepoint)
766
+ end
767
+ end
768
+ end
769
+ bld << '"'
770
+ bld
771
+ end
772
+ end
773
+
725
774
  # @api private
726
775
  def string_PRegexpType(val_type, val, format_map, _)
727
776
  f = get_format(val_type, format_map)
@@ -434,8 +434,7 @@ class TypeFormatter
434
434
  # @api private
435
435
  def string_String(t)
436
436
  # Use single qoute on strings that does not contain single quotes, control characters, or backslashes.
437
- # TODO: This should move to StringConverter when this formatter is changed to take advantage of it
438
- @bld << (t.ascii_only? && (t =~ /^(?:'|\p{Cntrl}|\\)$/).nil? ? "'#{t}'" : t.inspect)
437
+ @bld << StringConverter.singleton.puppet_quote(t)
439
438
  end
440
439
 
441
440
  # @api private
@@ -877,6 +877,16 @@ class PIntegerType < PNumericType
877
877
  rescue TypeError => e
878
878
  raise TypeConversionError.new(e.message)
879
879
  rescue ArgumentError => e
880
+ # Test for special case where there is whitespace between sign and number
881
+ match = Patterns::WS_BETWEEN_SIGN_AND_NUMBER.match(from)
882
+ if match
883
+ begin
884
+ # Try again, this time with whitespace removed
885
+ return from_args(match[1] + match[2], radix)
886
+ rescue TypeConversionError
887
+ # Ignored to retain original error
888
+ end
889
+ end
880
890
  raise TypeConversionError.new(e.message)
881
891
  end
882
892
  else
@@ -972,6 +982,16 @@ class PFloatType < PNumericType
972
982
  rescue TypeError => e
973
983
  raise TypeConversionError.new(e.message)
974
984
  rescue ArgumentError => e
985
+ # Test for special case where there is whitespace between sign and number
986
+ match = Patterns::WS_BETWEEN_SIGN_AND_NUMBER.match(from)
987
+ if match
988
+ begin
989
+ # Try again, this time with whitespace removed
990
+ return from_args(match[1] + match[2])
991
+ rescue TypeConversionError
992
+ # Ignored to retain original error
993
+ end
994
+ end
975
995
  raise TypeConversionError.new(e.message)
976
996
  end
977
997
  else
@@ -27,10 +27,13 @@ Puppet::Type.type(:group).provide :windows_adsi do
27
27
  current_users = Puppet::Util::Windows::ADSI::Group.name_sid_hash(current)
28
28
  specified_users = Puppet::Util::Windows::ADSI::Group.name_sid_hash(should)
29
29
 
30
+ current_sids = current_users.keys.to_a
31
+ specified_sids = specified_users.keys.to_a
32
+
30
33
  if @resource[:auth_membership]
31
- current_users.keys.to_a == specified_users.keys.to_a
34
+ current_sids.sort == specified_sids.sort
32
35
  else
33
- (specified_users.keys.to_a & current_users.keys.to_a) == specified_users.keys.to_a
36
+ (specified_sids & current_sids) == specified_sids
34
37
  end
35
38
  end
36
39
 
@@ -28,7 +28,7 @@ Puppet::Type.type(:package).provide :dnf, :parent => :yum do
28
28
  end
29
29
  end
30
30
 
31
- defaultfor :operatingsystem => :fedora, :operatingsystemmajrelease => ['22', '23']
31
+ defaultfor :operatingsystem => :fedora, :operatingsystemmajrelease => ['22', '23', '24']
32
32
 
33
33
  # The value to pass to DNF as its error output level.
34
34
  # DNF differs from Yum slightly with regards to error outputting.
@@ -226,6 +226,13 @@ Puppet::Type.type(:scheduled_task).provide(:win32_taskscheduler) do
226
226
  def flush
227
227
  unless resource[:ensure] == :absent
228
228
  self.fail('Parameter command is required.') unless resource[:command]
229
+ # HACK: even though the user may actually be insync?, for task changes to
230
+ # fully propagate, it is necessary to explicitly set the user for the task,
231
+ # even when it is SYSTEM (and has a nil password)
232
+ # this is a Windows security feature with the v1 COM APIs that prevent
233
+ # arbitrary reassignment of a task scheduler command to run as SYSTEM
234
+ # without the authorization to do so
235
+ self.user = resource[:user]
229
236
  task.save
230
237
  @task = nil
231
238
  end
@@ -36,13 +36,16 @@ Puppet::Type.type(:user).provide :windows_adsi do
36
36
  # since the default array_matching comparison is not commutative
37
37
 
38
38
  # dupes automatically weeded out when hashes built
39
- current_users = Puppet::Util::Windows::ADSI::Group.name_sid_hash(current)
40
- specified_users = Puppet::Util::Windows::ADSI::Group.name_sid_hash(should)
39
+ current_groups = Puppet::Util::Windows::ADSI::Group.name_sid_hash(current)
40
+ specified_groups = Puppet::Util::Windows::ADSI::Group.name_sid_hash(should)
41
+
42
+ current_sids = current_groups.keys.to_a
43
+ specified_sids = specified_groups.keys.to_a
41
44
 
42
45
  if @resource[:membership] == :inclusive
43
- current_users.keys.to_a == specified_users.keys.to_a
46
+ current_sids.sort == specified_sids.sort
44
47
  else
45
- (specified_users.keys.to_a & current_users.keys.to_a) == specified_users.keys.to_a
48
+ (specified_sids & current_sids) == specified_sids
46
49
  end
47
50
  end
48
51
 
@@ -32,6 +32,8 @@ config = Puppet::Util::Reference.newreference(:configuration, :depth => 1, :doc
32
32
  val = 'Unix/Linux: /var/run/puppetlabs -- Windows: C:\ProgramData\PuppetLabs\puppet\var\run -- Non-root user: ~/.puppetlabs/var/run'
33
33
  elsif name.to_s == 'logdir'
34
34
  val = 'Unix/Linux: /var/log/puppetlabs/puppet -- Windows: C:\ProgramData\PuppetLabs\puppet\var\log -- Non-root user: ~/.puppetlabs/var/log'
35
+ elsif name.to_s == 'hiera.yaml'
36
+ val = '$confdir/hiera.yaml. However, if a file exists at $codedir/hiera.yaml, Puppet uses that instead.'
35
37
  end
36
38
 
37
39
  # Leave out the section information; it was apparently confusing people.
@@ -369,7 +369,7 @@ class Puppet::Resource::Type
369
369
  end
370
370
  scope.class_set(self.name,scope) if hostclass? || node?
371
371
 
372
- param_hash = scope.with_parameter_scope(arguments.keys) do |param_scope|
372
+ param_hash = scope.with_parameter_scope(resource.to_s, arguments.keys) do |param_scope|
373
373
  # Assign directly to the parameter scope to avoid scope parameter validation at this point. It
374
374
  # will happen anyway when the values are assigned to the scope after the parameter scoped has
375
375
  # been popped.