puppet 3.7.3 → 3.7.4

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 (57) hide show
  1. data/Gemfile +4 -0
  2. data/ext/build_defaults.yaml +2 -2
  3. data/ext/project_data.yaml +2 -2
  4. data/lib/puppet.rb +1 -1
  5. data/lib/puppet/configurer.rb +7 -4
  6. data/lib/puppet/environments.rb +68 -51
  7. data/lib/puppet/functions/scanf.rb +46 -0
  8. data/lib/puppet/network/http/webrick/rest.rb +3 -0
  9. data/lib/puppet/parser/ast/pops_bridge.rb +2 -1
  10. data/lib/puppet/parser/compiler.rb +11 -3
  11. data/lib/puppet/parser/functions/realize.rb +7 -2
  12. data/lib/puppet/parser/functions/scanf.rb +35 -0
  13. data/lib/puppet/parser/relationship.rb +21 -6
  14. data/lib/puppet/parser/resource.rb +11 -4
  15. data/lib/puppet/pops.rb +7 -0
  16. data/lib/puppet/pops/evaluator/access_operator.rb +1 -6
  17. data/lib/puppet/pops/evaluator/collector_transformer.rb +219 -0
  18. data/lib/puppet/pops/evaluator/collectors/abstract_collector.rb +86 -0
  19. data/lib/puppet/pops/evaluator/collectors/catalog_collector.rb +25 -0
  20. data/lib/puppet/pops/evaluator/collectors/exported_collector.rb +66 -0
  21. data/lib/puppet/pops/evaluator/collectors/fixed_set_collector.rb +37 -0
  22. data/lib/puppet/pops/evaluator/compare_operator.rb +8 -28
  23. data/lib/puppet/pops/evaluator/evaluator_impl.rb +4 -18
  24. data/lib/puppet/pops/evaluator/relationship_operator.rb +4 -0
  25. data/lib/puppet/pops/evaluator/runtime3_support.rb +2 -2
  26. data/lib/puppet/pops/parser/egrammar.ra +3 -3
  27. data/lib/puppet/pops/parser/eparser.rb +3 -3
  28. data/lib/puppet/pops/parser/evaluating_parser.rb +4 -0
  29. data/lib/puppet/pops/types/type_calculator.rb +19 -8
  30. data/lib/puppet/pops/types/type_parser.rb +1 -4
  31. data/lib/puppet/provider/service/redhat.rb +6 -3
  32. data/lib/puppet/resource/catalog.rb +12 -1
  33. data/lib/puppet/settings/environment_conf.rb +7 -8
  34. data/lib/puppet/type/cron.rb +5 -1
  35. data/lib/puppet/type/file/content.rb +1 -1
  36. data/lib/puppet/util/tagging.rb +21 -2
  37. data/lib/puppet/version.rb +1 -1
  38. data/spec/integration/indirector/catalog/compiler_spec.rb +11 -0
  39. data/spec/integration/parser/collector_spec.rb +41 -0
  40. data/spec/integration/parser/compiler_spec.rb +16 -0
  41. data/spec/integration/parser/future_compiler_spec.rb +1 -1
  42. data/spec/unit/environments_spec.rb +238 -118
  43. data/spec/unit/functions/scanf_spec.rb +36 -0
  44. data/spec/unit/network/http/rack/rest_spec.rb +11 -8
  45. data/spec/unit/network/http/webrick/rest_spec.rb +19 -0
  46. data/spec/unit/parser/compiler_spec.rb +0 -27
  47. data/spec/unit/pops/evaluator/access_ops_spec.rb +9 -9
  48. data/spec/unit/pops/evaluator/comparison_ops_spec.rb +14 -8
  49. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +20 -8
  50. data/spec/unit/pops/parser/parse_basic_expressions_spec.rb +10 -0
  51. data/spec/unit/pops/parser/parse_heredoc_spec.rb +30 -0
  52. data/spec/unit/pops/types/type_calculator_spec.rb +18 -0
  53. data/spec/unit/pops/types/type_parser_spec.rb +2 -2
  54. data/spec/unit/provider/service/redhat_spec.rb +2 -1
  55. data/spec/unit/type/cron_spec.rb +24 -24
  56. data/spec/unit/util/tagging_spec.rb +7 -0
  57. metadata +11 -2
@@ -4,13 +4,28 @@ class Puppet::Parser::Relationship
4
4
  PARAM_MAP = {:relationship => :before, :subscription => :notify}
5
5
 
6
6
  def arrayify(resources)
7
- case resources
8
- when Puppet::Parser::Collector
9
- resources.collected.values
10
- when Array
11
- resources
7
+ # This if statement is needed because the 3x parser cannot load
8
+ # Puppet::Pops. This logic can be removed for 4.0 when the 3x AST
9
+ # is removed (when Pops is always used).
10
+ if !(Puppet[:parser] == 'future')
11
+ case resources
12
+ when Puppet::Parser::Collector
13
+ resources.collected.values
14
+ when Array
15
+ resources
16
+ else
17
+ [resources]
18
+ end
12
19
  else
13
- [resources]
20
+ require 'puppet/pops'
21
+ case resources
22
+ when Puppet::Pops::Evaluator::Collectors::AbstractCollector
23
+ resources.collected.values
24
+ when Array
25
+ resources
26
+ else
27
+ [resources]
28
+ end
14
29
  end
15
30
  end
16
31
 
@@ -189,15 +189,22 @@ class Puppet::Parser::Resource < Puppet::Resource
189
189
  copy_as_resource.to_ral
190
190
  end
191
191
 
192
- # Is the receiver tagged with the given tags?
193
- # This match takes into account the tags that a resource will inherit from its container
192
+ # Answers if this resource is tagged with at least one of the tags given in downcased string form.
193
+ #
194
+ # The method is a faster variant of the tagged? method that does no conversion of its
195
+ # arguments.
196
+ #
197
+ # The match takes into account the tags that a resource will inherit from its container
194
198
  # but have not been set yet.
195
199
  # It does *not* take tags set via resource defaults as these will *never* be set on
196
200
  # the resource itself since all resources always have tags that are automatically
197
201
  # assigned.
198
202
  #
199
- def tagged?(*tags)
200
- super || ((scope_resource = scope.resource) && scope_resource != self && scope_resource.tagged?(tags))
203
+ # @param tag_array [Array[String]] list tags to look for
204
+ # @return [Boolean] true if this instance is tagged with at least one of the provided tags
205
+ #
206
+ def raw_tagged?(tag_array)
207
+ super || ((scope_resource = scope.resource) && !scope_resource.equal?(self) && scope_resource.raw_tagged?(tag_array))
201
208
  end
202
209
 
203
210
  private
@@ -100,6 +100,13 @@ module Puppet
100
100
  require 'puppet/pops/evaluator/evaluator_impl'
101
101
  require 'puppet/pops/evaluator/epp_evaluator'
102
102
  require 'puppet/pops/evaluator/callable_mismatch_describer'
103
+ require 'puppet/pops/evaluator/collector_transformer'
104
+ module Collectors
105
+ require 'puppet/pops/evaluator/collectors/abstract_collector'
106
+ require 'puppet/pops/evaluator/collectors/fixed_set_collector'
107
+ require 'puppet/pops/evaluator/collectors/catalog_collector'
108
+ require 'puppet/pops/evaluator/collectors/exported_collector'
109
+ end
103
110
  end
104
111
 
105
112
  # Subsystem for puppet functions defined in ruby.
@@ -330,11 +330,6 @@ class Puppet::Pops::Evaluator::AccessOperator
330
330
  end
331
331
  end
332
332
  case keys.size
333
- when 1
334
- result = Puppet::Pops::Types::PHashType.new()
335
- result.key_type = o.key_type.copy
336
- result.element_type = keys[0]
337
- result
338
333
  when 2
339
334
  result = Puppet::Pops::Types::PHashType.new()
340
335
  result.key_type = keys[0]
@@ -354,7 +349,7 @@ class Puppet::Pops::Evaluator::AccessOperator
354
349
  result
355
350
  else
356
351
  fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic, {
357
- :base_type => 'Hash-Type', :min => 1, :max => 4, :actual => keys.size
352
+ :base_type => 'Hash-Type', :min => 2, :max => 4, :actual => keys.size
358
353
  })
359
354
  end
360
355
  result.size_type = size_t if size_t
@@ -0,0 +1,219 @@
1
+ class Puppet::Pops::Evaluator::CollectorTransformer
2
+
3
+ def initialize
4
+ @@query_visitor ||= Puppet::Pops::Visitor.new(nil, "query", 1, 1)
5
+ @@match_visitor ||= Puppet::Pops::Visitor.new(nil, "match", 1, 1)
6
+ @@evaluator ||= Puppet::Pops::Evaluator::EvaluatorImpl.new
7
+ @@compare_operator ||= Puppet::Pops::Evaluator::CompareOperator.new()
8
+ end
9
+
10
+ def transform(o, scope)
11
+ raise ArgumentError, "Expected CollectExpression" unless o.is_a? Puppet::Pops::Model::CollectExpression
12
+
13
+ raise "LHS is not a type" unless o.type_expr.is_a? Puppet::Pops::Model::QualifiedReference
14
+ type = o.type_expr.value().downcase()
15
+
16
+ if type == 'class'
17
+ fail "Classes cannot be collected"
18
+ end
19
+
20
+ resource_type = scope.find_resource_type(type)
21
+ fail "Resource type #{type} doesn't exist" unless resource_type
22
+
23
+ adapter = Puppet::Pops::Adapters::SourcePosAdapter.adapt(o)
24
+ line_num = adapter.line
25
+ position = adapter.pos
26
+ file_path = adapter.locator.file
27
+
28
+ if !o.operations.empty?
29
+ overrides = {
30
+ :parameters => o.operations.map{ |x| to_3x_param(x).evaluate(scope)},
31
+ :file => file_path,
32
+ :line => [line_num, position],
33
+ :source => scope.source,
34
+ :scope => scope
35
+ }
36
+ end
37
+
38
+ code = query_unless_nop(o.query, scope)
39
+
40
+ case o.query
41
+ when Puppet::Pops::Model::VirtualQuery
42
+ newcoll = Puppet::Pops::Evaluator::Collectors::CatalogCollector.new(scope, resource_type.name, code, overrides)
43
+ when Puppet::Pops::Model::ExportedQuery
44
+ match = match_unless_nop(o.query, scope)
45
+ newcoll = Puppet::Pops::Evaluator::Collectors::ExportedCollector.new(scope, resource_type.name, match, code, overrides)
46
+ end
47
+
48
+ scope.compiler.add_collection(newcoll)
49
+
50
+ newcoll
51
+ end
52
+
53
+ protected
54
+
55
+ def query(o, scope)
56
+ @@query_visitor.visit_this_1(self, o, scope)
57
+ end
58
+
59
+ def match(o, scope)
60
+ @@match_visitor.visit_this_1(self, o, scope)
61
+ end
62
+
63
+ def query_unless_nop(query, scope)
64
+ unless query.expr.nil? || query.expr.is_a?(Puppet::Pops::Model::Nop)
65
+ query(query.expr, scope)
66
+ end
67
+ end
68
+
69
+ def match_unless_nop(query, scope)
70
+ unless query.expr.nil? || query.expr.is_a?(Puppet::Pops::Model::Nop)
71
+ match(query.expr, scope)
72
+ end
73
+ end
74
+
75
+ def query_AndExpression(o, scope)
76
+ left_code = query(o.left_expr, scope)
77
+ right_code = query(o.right_expr, scope)
78
+ proc do |resource|
79
+ left_code.call(resource) && right_code.call(resource)
80
+ end
81
+ end
82
+
83
+ def query_OrExpression(o, scope)
84
+ left_code = query(o.left_expr, scope)
85
+ right_code = query(o.right_expr, scope)
86
+ proc do |resource|
87
+ left_code.call(resource) || right_code.call(resource)
88
+ end
89
+ end
90
+
91
+ def query_ComparisonExpression(o, scope)
92
+ left_code = query(o.left_expr, scope)
93
+ right_code = query(o.right_expr, scope)
94
+
95
+ case o.operator
96
+ when :'=='
97
+ if left_code == "tag"
98
+ # Ensure that to_s and downcase is done once, i.e. outside the proc block and
99
+ # then use raw_tagged? instead of tagged?
100
+ if right_code.is_a?(Array)
101
+ tags = right_code
102
+ else
103
+ tags = [ right_code ]
104
+ end
105
+ tags = tags.collect do |t|
106
+ raise ArgumentError, 'Cannot transform a number to a tag' if t.is_a?(Numeric)
107
+ t.to_s.downcase
108
+ end
109
+ proc do |resource|
110
+ resource.raw_tagged?(tags)
111
+ end
112
+ else
113
+ proc do |resource|
114
+ if (tmp = resource[left_code]).is_a?(Array)
115
+ @@compare_operator.include?(tmp, right_code, scope)
116
+ else
117
+ @@compare_operator.equals(tmp, right_code)
118
+ end
119
+ end
120
+ end
121
+ when :'!='
122
+ proc do |resource|
123
+ !@@compare_operator.equals(resource[left_code], right_code)
124
+ end
125
+ end
126
+ end
127
+
128
+ def query_VariableExpression(o, scope)
129
+ @@evaluator.evaluate(o, scope)
130
+ end
131
+
132
+ def query_LiteralBoolean(o, scope)
133
+ @@evaluator.evaluate(o, scope)
134
+ end
135
+
136
+ def query_LiteralString(o, scope)
137
+ @@evaluator.evaluate(o, scope)
138
+ end
139
+
140
+ def query_ConcatenatedString(o, scope)
141
+ @@evaluator.evaluate(o, scope)
142
+ end
143
+
144
+ def query_LiteralNumber(o, scope)
145
+ @@evaluator.evaluate(o, scope)
146
+ end
147
+
148
+ def query_QualifiedName(o, scope)
149
+ @@evaluator.evaluate(o, scope)
150
+ end
151
+
152
+ def query_ParenthesizedExpression(o, scope)
153
+ query(o.expr, scope)
154
+ end
155
+
156
+ def query_Object(o, scope)
157
+ raise ArgumentError, "Cannot transform object of class #{o.class}"
158
+ end
159
+
160
+ def match_AndExpression(o, scope)
161
+ left_match = match(o.left_expr, scope)
162
+ right_match = match(o.right_expr, scope)
163
+ return [left_match, 'and', right_match]
164
+ end
165
+
166
+ def match_OrExpression(o, scope)
167
+ left_match = match(o.left_expr, scope)
168
+ right_match = match(o.right_expr, scope)
169
+ return [left_match, 'or', right_match]
170
+ end
171
+
172
+ def match_ComparisonExpression(o, scope)
173
+ left_match = match(o.left_expr, scope)
174
+ right_match = match(o.right_expr, scope)
175
+ return [left_match, o.operator.to_s, right_match]
176
+ end
177
+
178
+ def match_VariableExpression(o, scope)
179
+ @@evaluator.evaluate(o, scope)
180
+ end
181
+
182
+ def match_LiteralBoolean(o, scope)
183
+ @@evaluator.evaluate(o, scope)
184
+ end
185
+
186
+ def match_LiteralString(o, scope)
187
+ @@evaluator.evaluate(o, scope)
188
+ end
189
+
190
+ def match_ConcatenatedString(o, scope)
191
+ @@evaluator.evaluate(o, scope)
192
+ end
193
+
194
+ def match_LiteralNumber(o, scope)
195
+ @@evaluator.evaluate(o, scope)
196
+ end
197
+
198
+ def match_QualifiedName(o, scope)
199
+ @@evaluator.evaluate(o, scope)
200
+ end
201
+
202
+ def match_ParenthesizedExpression(o, scope)
203
+ match(o.expr, scope)
204
+ end
205
+
206
+ def match_Object(o, scope)
207
+ raise ArgumentError, "Cannot transform object of class #{o.class}"
208
+ end
209
+
210
+ # Produces (name => expr) or (name +> expr)
211
+ def to_3x_param(o)
212
+ bridge = Puppet::Parser::AST::PopsBridge::Expression.new(:value => o.value_expr)
213
+ args = { :value => bridge }
214
+ args[:add] = true if o.operator == :'+>'
215
+ args[:param] = o.attribute_name
216
+ args= Puppet::Pops::Model::AstTransformer.new().merge_location(args, o)
217
+ Puppet::Parser::AST::ResourceParam.new(args)
218
+ end
219
+ end
@@ -0,0 +1,86 @@
1
+ class Puppet::Pops::Evaluator::Collectors::AbstractCollector
2
+ attr_reader :scope
3
+
4
+ # The collector's hash of overrides {:parameters => params}
5
+ attr_reader :overrides
6
+
7
+ # The set of collected resources
8
+ attr_reader :collected
9
+
10
+ # An empty array which will be returned by the unresolved_resources
11
+ # method unless we have a FixSetCollector
12
+ EMPTY_RESOURCES = [].freeze
13
+
14
+ # Initialized the instance variables needed by the base
15
+ # collector class to perform evaluation
16
+ #
17
+ # @param [Puppet::Parser::Scope] scope
18
+ #
19
+ # @param [Hash] overrides a hash of optional overrides
20
+ # @options opts [Array] :parameters
21
+ # @options opts [String] :file
22
+ # @options opts [Array] :line
23
+ # @options opts [Puppet::Resource::Type] :source
24
+ # @options opts [Puppet::Parser::Scope] :scope
25
+ def initialize(scope, overrides = nil)
26
+ @collected = {}
27
+ @scope = scope
28
+
29
+ if !(overrides.nil? || overrides[:parameters])
30
+ raise ArgumentError, "Exported resource try to override without parameters"
31
+ end
32
+
33
+ @overrides = overrides
34
+ end
35
+
36
+ # Collects resources and marks collected objects as non-virtual. Also
37
+ # handles overrides.
38
+ #
39
+ # @return [Array] the resources we have collected
40
+ def evaluate
41
+ objects = collect.each do |obj|
42
+ obj.virtual = false
43
+ end
44
+
45
+ return false if objects.empty?
46
+
47
+ if @overrides and !objects.empty?
48
+ overrides[:source].meta_def(:child_of?) do |klass|
49
+ true
50
+ end
51
+
52
+ objects.each do |res|
53
+ unless @collected.include?(res.ref)
54
+ newres = Puppet::Parser::Resource.new(res.type, res.title, @overrides)
55
+ scope.compiler.add_override(newres)
56
+ end
57
+ end
58
+ end
59
+
60
+ objects.reject! { |o| @collected.include?(o.ref) }
61
+
62
+ return false if objects.empty?
63
+
64
+ objects.inject(@collected) { |c,o| c[o.ref]=o; c }
65
+
66
+ objects
67
+ end
68
+
69
+ # This should only return an empty array unless we have
70
+ # an FixedSetCollector, in which case it will return the
71
+ # resources that have not yet been realized
72
+ #
73
+ # @return [Array] the resources that have not been resolved
74
+ def unresolved_resources
75
+ EMPTY_RESOURCES
76
+ end
77
+
78
+ # Collect the specified resources. The way this is done depends on which type
79
+ # of collector we are dealing with. This method is implemented differently in
80
+ # each of the three child classes
81
+ #
82
+ # @return [Array] the collected resources
83
+ def collect
84
+ raise NotImplementedError, "This method must be implemented by the child class"
85
+ end
86
+ end
@@ -0,0 +1,25 @@
1
+ class Puppet::Pops::Evaluator::Collectors::CatalogCollector < Puppet::Pops::Evaluator::Collectors::AbstractCollector
2
+
3
+ # Creates a CatalogCollector using the AbstractCollector's
4
+ # constructor to set the scope and overrides
5
+ #
6
+ # param [Symbol] type the resource type to be collected
7
+ # param [Proc] query the query which defines which resources to match
8
+ def initialize(scope, type, query, overrides = nil)
9
+ super(scope, overrides)
10
+
11
+ @query = query
12
+
13
+ @type = Puppet::Resource.new(type, "whatever").type
14
+ end
15
+
16
+ # Collects virtual resources based off a collection in a manifest
17
+ def collect
18
+ t = @type
19
+ q = @query
20
+
21
+ scope.compiler.resources.find_all do |resource|
22
+ resource.type == t && (q ? q.call(resource) : true)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,66 @@
1
+ class Puppet::Pops::Evaluator::Collectors::ExportedCollector < Puppet::Pops::Evaluator::Collectors::AbstractCollector
2
+
3
+ # Creates an ExportedCollector using the AbstractCollector's
4
+ # constructor to set the scope and overrides
5
+ #
6
+ # param [Symbol] type the resource type to be collected
7
+ # param [Array] equery an array representation of the query (exported query)
8
+ # param [Proc] cquery a proc representation of the query (catalog query)
9
+ def initialize(scope, type, equery, cquery, overrides = nil)
10
+ super(scope, overrides)
11
+
12
+ @equery = equery
13
+ @cquery = cquery
14
+
15
+ @type = Puppet::Resource.new(type, "whatever").type
16
+ end
17
+
18
+ # Ensures that storeconfigs is present before calling AbstractCollector's
19
+ # evaluate method
20
+ def evaluate
21
+ if Puppet[:storeconfigs] != true
22
+ Puppet.warning "Not collecting exported resources without storeconfigs"
23
+ return false
24
+ end
25
+
26
+ super
27
+ end
28
+
29
+ # Collect exported resources as defined by an exported
30
+ # collection. Used with PuppetDB
31
+ def collect
32
+ resources = []
33
+
34
+ time = Puppet::Util.thinmark do
35
+ t = @type
36
+ q = @cquery
37
+
38
+ resources = scope.compiler.resources.find_all do |resource|
39
+ resource.type == t && resource.exported? && (q.nil? || q.call(resource))
40
+ end
41
+
42
+ found = Puppet::Resource.indirection.
43
+ search(@type, :host => @scope.compiler.node.name, :filter => @equery, :scope => @scope)
44
+
45
+ found_resources = found.map {|x| x.is_a?(Puppet::Parser::Resource) ? x : x.to_resource(@scope)}
46
+
47
+ found_resources.each do |item|
48
+ if existing = @scope.findresource(item.type, item.title)
49
+ unless existing.collector_id == item.collector_id
50
+ raise Puppet::ParseError,
51
+ "A duplicate resource was found while collecting exported resources, with the type and title #{item.ref}"
52
+ end
53
+ else
54
+ item.exported = false
55
+ @scope.compiler.add_resource(@scope, item)
56
+ resources << item
57
+ end
58
+ end
59
+ end
60
+
61
+ scope.debug("Collected %s %s resource%s in %.2f seconds" %
62
+ [resources.length, @type, resources.length == 1 ? "" : "s", time])
63
+
64
+ resources
65
+ end
66
+ end