bolt 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/bolt/cli.rb +31 -21
- data/lib/bolt/config.rb +1 -0
- data/lib/bolt/error.rb +28 -0
- data/lib/bolt/executor.rb +10 -6
- data/lib/bolt/node.rb +7 -5
- data/lib/bolt/node/errors.rb +25 -3
- data/lib/bolt/node/orch.rb +7 -16
- data/lib/bolt/node/output.rb +17 -0
- data/lib/bolt/node/ssh.rb +101 -44
- data/lib/bolt/node/winrm.rb +86 -40
- data/lib/bolt/outputter/human.rb +65 -8
- data/lib/bolt/outputter/json.rb +8 -1
- data/lib/bolt/result.rb +74 -124
- data/lib/bolt/version.rb +1 -1
- data/{vendored/puppet → modules/boltlib}/lib/puppet/functions/file_upload.rb +9 -7
- data/{vendored/puppet → modules/boltlib}/lib/puppet/functions/run_command.rb +8 -9
- data/{vendored/puppet → modules/boltlib}/lib/puppet/functions/run_plan.rb +8 -12
- data/{vendored/puppet → modules/boltlib}/lib/puppet/functions/run_script.rb +12 -8
- data/{vendored/puppet → modules/boltlib}/lib/puppet/functions/run_task.rb +10 -10
- data/vendored/puppet/lib/puppet/agent.rb +1 -1
- data/vendored/puppet/lib/puppet/application/lookup.rb +1 -3
- data/vendored/puppet/lib/puppet/configurer.rb +2 -3
- data/vendored/puppet/lib/puppet/configurer/plugin_handler.rb +25 -7
- data/vendored/puppet/lib/puppet/defaults.rb +9 -1
- data/vendored/puppet/lib/puppet/face/epp.rb +4 -2
- data/vendored/puppet/lib/puppet/face/module/build.rb +1 -1
- data/vendored/puppet/lib/puppet/face/module/list.rb +5 -16
- data/vendored/puppet/lib/puppet/face/module/uninstall.rb +14 -3
- data/vendored/puppet/lib/puppet/face/plugin.rb +1 -3
- data/vendored/puppet/lib/puppet/forge/errors.rb +17 -7
- data/vendored/puppet/lib/puppet/functions.rb +8 -6
- data/vendored/puppet/lib/puppet/functions/each.rb +10 -4
- data/vendored/puppet/lib/puppet/functions/lookup.rb +2 -2
- data/vendored/puppet/lib/puppet/functions/map.rb +12 -2
- data/vendored/puppet/lib/puppet/functions/slice.rb +2 -3
- data/vendored/puppet/lib/puppet/graph/simple_graph.rb +9 -5
- data/vendored/puppet/lib/puppet/interface.rb +1 -0
- data/vendored/puppet/lib/puppet/module_tool/errors/installer.rb +27 -17
- data/vendored/puppet/lib/puppet/module_tool/errors/shared.rb +143 -63
- data/vendored/puppet/lib/puppet/module_tool/errors/uninstaller.rb +37 -14
- data/vendored/puppet/lib/puppet/module_tool/errors/upgrader.rb +30 -18
- data/vendored/puppet/lib/puppet/network/auth_config_parser.rb +8 -8
- data/vendored/puppet/lib/puppet/network/http/error.rb +7 -7
- data/vendored/puppet/lib/puppet/network/http/rack.rb +2 -2
- data/vendored/puppet/lib/puppet/network/http/webrick.rb +1 -1
- data/vendored/puppet/lib/puppet/node.rb +10 -0
- data/vendored/puppet/lib/puppet/node/facts.rb +9 -0
- data/vendored/puppet/lib/puppet/parameter/value_collection.rb +16 -6
- data/vendored/puppet/lib/puppet/parser/resource.rb +103 -31
- data/vendored/puppet/lib/puppet/pops/evaluator/access_operator.rb +13 -0
- data/vendored/puppet/lib/puppet/pops/evaluator/evaluator_impl.rb +22 -6
- data/vendored/puppet/lib/puppet/pops/loader/static_loader.rb +1 -1
- data/vendored/puppet/lib/puppet/pops/lookup/lookup_adapter.rb +13 -4
- data/vendored/puppet/lib/puppet/pops/model/ast_transformer.rb +1 -1
- data/vendored/puppet/lib/puppet/pops/parser/eparser.rb +527 -529
- data/vendored/puppet/lib/puppet/pops/serialization/abstract_reader.rb +4 -0
- data/vendored/puppet/lib/puppet/pops/serialization/abstract_writer.rb +6 -0
- data/vendored/puppet/lib/puppet/pops/serialization/extension.rb +1 -0
- data/vendored/puppet/lib/puppet/pops/serialization/serializer.rb +2 -1
- data/vendored/puppet/lib/puppet/pops/types/execution_result.rb +8 -0
- data/vendored/puppet/lib/puppet/pops/types/iterable.rb +2 -0
- data/vendored/puppet/lib/puppet/pops/types/p_object_type.rb +3 -0
- data/vendored/puppet/lib/puppet/pops/types/p_object_type_extension.rb +6 -0
- data/vendored/puppet/lib/puppet/pops/types/p_uri_type.rb +191 -0
- data/vendored/puppet/lib/puppet/pops/types/string_converter.rb +17 -0
- data/vendored/puppet/lib/puppet/pops/types/type_calculator.rb +5 -0
- data/vendored/puppet/lib/puppet/pops/types/type_factory.rb +7 -0
- data/vendored/puppet/lib/puppet/pops/types/type_formatter.rb +16 -18
- data/vendored/puppet/lib/puppet/pops/types/type_mismatch_describer.rb +15 -5
- data/vendored/puppet/lib/puppet/pops/types/type_parser.rb +6 -0
- data/vendored/puppet/lib/puppet/pops/types/type_with_members.rb +43 -0
- data/vendored/puppet/lib/puppet/pops/types/types.rb +3 -0
- data/vendored/puppet/lib/puppet/provider/package/gem.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/nim.rb +7 -8
- data/vendored/puppet/lib/puppet/provider/package/opkg.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/pkg.rb +6 -4
- data/vendored/puppet/lib/puppet/provider/package/pkgutil.rb +3 -3
- data/vendored/puppet/lib/puppet/provider/service/init.rb +1 -1
- data/vendored/puppet/lib/puppet/syntax_checkers/base64.rb +5 -6
- data/vendored/puppet/lib/puppet/transaction.rb +1 -1
- data/vendored/puppet/lib/puppet/type.rb +1 -9
- data/vendored/puppet/lib/puppet/type/schedule.rb +1 -1
- data/vendored/puppet/lib/puppet/util/log.rb +2 -3
- data/vendored/puppet/lib/puppet/util/plist.rb +1 -1
- data/vendored/puppet/lib/puppet/util/reference.rb +2 -3
- data/vendored/puppet/lib/puppet_pal.rb +326 -53
- metadata +28 -12
- data/lib/bolt/node/result.rb +0 -115
- data/vendored/puppet/lib/puppet/configurer/downloader_factory.rb +0 -44
@@ -201,6 +201,7 @@ class TypeParser
|
|
201
201
|
'semverrange' => TypeFactory.sem_ver_range,
|
202
202
|
'timestamp' => TypeFactory.timestamp,
|
203
203
|
'timespan' => TypeFactory.timespan,
|
204
|
+
'uri' => TypeFactory.uri,
|
204
205
|
}.freeze
|
205
206
|
end
|
206
207
|
|
@@ -356,6 +357,11 @@ class TypeParser
|
|
356
357
|
raise_invalid_parameters_error('Pattern', '1 or more', parameters.size) unless parameters.size >= 1
|
357
358
|
TypeFactory.pattern(*parameters)
|
358
359
|
|
360
|
+
when 'uri'
|
361
|
+
# 1 parameter which is a string or a URI
|
362
|
+
raise_invalid_parameters_error('URI', '1', parameters.size) unless parameters.size == 1
|
363
|
+
TypeFactory.uri(parameters[0])
|
364
|
+
|
359
365
|
when 'variant'
|
360
366
|
# 1..m parameters being strings or regular expressions
|
361
367
|
raise_invalid_parameters_error('Variant', '1 or more', parameters.size) unless parameters.size >= 1
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Puppet::Pops
|
2
|
+
module Types
|
3
|
+
|
4
|
+
# Interface implemented by a type that has IvocableMembers
|
5
|
+
module TypeWithMembers
|
6
|
+
# @return [InvocableMember,nil] An invocable member if it exists, or `nil`
|
7
|
+
def [](member_name)
|
8
|
+
raise NotImplementedError, "'#{self.class.name}' should implement #[]"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Interface implemented by attribute and function members
|
13
|
+
module InvocableMember
|
14
|
+
# Performs type checking of arguments and invokes the method that corresponds to this
|
15
|
+
# method. The result of the invocation is returned
|
16
|
+
#
|
17
|
+
# @param receiver [Object] The receiver of the call
|
18
|
+
# @param scope [Puppet::Parser::Scope] The caller scope
|
19
|
+
# @param args [Array] Array of arguments.
|
20
|
+
# @return [Object] The result returned by the member function or attribute
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
def invoke(receiver, scope, args, &block)
|
24
|
+
raise NotImplementedError, "'#{self.class.name}' should implement #invoke"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Plays the same role as an PAttribute in the PObjectType. Provides
|
29
|
+
# access to known attr_readers and plain reader methods.
|
30
|
+
class AttrReader
|
31
|
+
include InvocableMember
|
32
|
+
|
33
|
+
def initialize(message)
|
34
|
+
@message = message.to_sym
|
35
|
+
end
|
36
|
+
|
37
|
+
def invoke(receiver, scope, args, &block)
|
38
|
+
receiver.send(@message)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
@@ -1414,6 +1414,8 @@ class PIterableType < PTypeWithContainedType
|
|
1414
1414
|
o >= 0
|
1415
1415
|
when PIntegerType
|
1416
1416
|
o.finite_range?
|
1417
|
+
when PTypeAliasType
|
1418
|
+
instance?(o.resolved_type, guard)
|
1417
1419
|
else
|
1418
1420
|
false
|
1419
1421
|
end
|
@@ -3623,6 +3625,7 @@ require_relative 'p_timestamp_type'
|
|
3623
3625
|
require_relative 'p_binary_type'
|
3624
3626
|
require_relative 'p_init_type'
|
3625
3627
|
require_relative 'p_object_type_extension'
|
3628
|
+
require_relative 'p_uri_type'
|
3626
3629
|
require_relative 'type_set_reference'
|
3627
3630
|
require_relative 'implementation_registry'
|
3628
3631
|
require_relative 'tree_iterators'
|
@@ -8,7 +8,7 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
|
|
8
8
|
specified source is used, also pass `--clear-sources` via `install_options`.
|
9
9
|
If source is present but is not a valid URL, it will be interpreted as the
|
10
10
|
path to a local gem file. If source is not present, the gem will be
|
11
|
-
installed from the default gem repositories.
|
11
|
+
installed from the default gem repositories. Note that to modify this for Windows, it has to be a valid URL.
|
12
12
|
|
13
13
|
This provider supports the `install_options` and `uninstall_options` attributes,
|
14
14
|
which allow command-line flags to be passed to the gem command.
|
@@ -97,14 +97,13 @@ Puppet::Type.type(:package).provide :nim, :parent => :aix, :source => :aix do
|
|
97
97
|
end
|
98
98
|
|
99
99
|
if (package_type == nil)
|
100
|
-
|
101
|
-
errmsg =
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
errmsg << "on lpp_source '#{source}'"
|
100
|
+
|
101
|
+
errmsg = if version_specified
|
102
|
+
_("Unable to find package '%{package}' with version '%{version}' on lpp_source '%{source}'") %
|
103
|
+
{ package: pkg, version: version, source: source }
|
104
|
+
else
|
105
|
+
_("Unable to find package '%{package}' on lpp_source '%{source}'") % { package: pkg, source: source }
|
106
|
+
end
|
108
107
|
self.fail errmsg
|
109
108
|
end
|
110
109
|
|
@@ -43,7 +43,8 @@ Puppet::Type.type(:package).provide :pkg, :parent => Puppet::Provider::Package d
|
|
43
43
|
when '-'
|
44
44
|
{:status => 'known'}
|
45
45
|
else
|
46
|
-
raise ArgumentError, _('Unknown format %
|
46
|
+
raise ArgumentError, _('Unknown format %{resource_name}: %{full_flags}[%{bad_flag}]') %
|
47
|
+
{ resource_name: self.name, full_flags: flags, bad_flag: flags[0..0] }
|
47
48
|
end
|
48
49
|
).merge(
|
49
50
|
case flags[1..1]
|
@@ -52,7 +53,8 @@ Puppet::Type.type(:package).provide :pkg, :parent => Puppet::Provider::Package d
|
|
52
53
|
when '-'
|
53
54
|
{}
|
54
55
|
else
|
55
|
-
raise ArgumentError, _('Unknown format %
|
56
|
+
raise ArgumentError, _('Unknown format %{resource_name}: %{full_flags}[%{bad_flag}]') %
|
57
|
+
{ resource_name: self.name, full_flags: flags, bad_flag: flags[1..1] }
|
56
58
|
end
|
57
59
|
)
|
58
60
|
end
|
@@ -82,7 +84,7 @@ Puppet::Type.type(:package).provide :pkg, :parent => Puppet::Provider::Package d
|
|
82
84
|
when /known/
|
83
85
|
{:status => 'known'}
|
84
86
|
else
|
85
|
-
raise ArgumentError, _('Unknown format %
|
87
|
+
raise ArgumentError, _('Unknown format %{resource_name}: %{state}') % { resource_name: self.name, state: state }
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
@@ -101,7 +103,7 @@ Puppet::Type.type(:package).provide :pkg, :parent => Puppet::Provider::Package d
|
|
101
103
|
{:publisher => $1, :name => $2, :ensure => $3}.merge pkg_state($4).merge(ufoxi_flag($5))
|
102
104
|
|
103
105
|
else
|
104
|
-
raise ArgumentError, _('Unknown line format %
|
106
|
+
raise ArgumentError, _('Unknown line format %{resource_name}: %{parse_line}') % { resource_name: self.name, parse_line: line }
|
105
107
|
end).merge({:provider => self.name})
|
106
108
|
end
|
107
109
|
|
@@ -70,7 +70,7 @@ Puppet::Type.type(:package).provide :pkgutil, :parent => :sun, :source => :sun d
|
|
70
70
|
if line =~ /\s*(\S+)\s+(\S+)\s+(.*)/
|
71
71
|
{ :alias => $1, :name => $2, :avail => $3 }
|
72
72
|
else
|
73
|
-
Puppet.warning _("Cannot match %
|
73
|
+
Puppet.warning _("Cannot match %{line}") % { line: line }
|
74
74
|
end
|
75
75
|
end.reject { |h| h.nil? }
|
76
76
|
end
|
@@ -88,7 +88,7 @@ Puppet::Type.type(:package).provide :pkgutil, :parent => :sun, :source => :sun d
|
|
88
88
|
output = output.split("\n")
|
89
89
|
|
90
90
|
if output[-1] == "Not in catalog"
|
91
|
-
Puppet.warning _("Package not in pkgutil catalog: %
|
91
|
+
Puppet.warning _("Package not in pkgutil catalog: %{package}") % { package: hash[:justme] }
|
92
92
|
return nil
|
93
93
|
end
|
94
94
|
|
@@ -142,7 +142,7 @@ Puppet::Type.type(:package).provide :pkgutil, :parent => :sun, :source => :sun d
|
|
142
142
|
|
143
143
|
return hash
|
144
144
|
else
|
145
|
-
Puppet.warning _("Cannot match %
|
145
|
+
Puppet.warning _("Cannot match %{line}") % { line: line }
|
146
146
|
return nil
|
147
147
|
end
|
148
148
|
end
|
@@ -171,7 +171,7 @@ Puppet::Type.type(:service).provide :init, :parent => :base do
|
|
171
171
|
|
172
172
|
def texecute(type, command, fof = true, squelch = false, combine = true)
|
173
173
|
if type == :start && Facter.value(:osfamily) == "Solaris"
|
174
|
-
command = ["/usr/bin/ctrun -l
|
174
|
+
command = ["/usr/bin/ctrun -l child", command].flatten.join(" ")
|
175
175
|
end
|
176
176
|
super(type, command, fof, squelch, combine)
|
177
177
|
end
|
@@ -24,12 +24,11 @@ class Puppet::SyntaxCheckers::Base64 < Puppet::Plugins::SyntaxCheckers::SyntaxCh
|
|
24
24
|
# simply skips all non base64 characters
|
25
25
|
Base64.strict_decode64(cleaned_text)
|
26
26
|
rescue => e
|
27
|
-
if (cleaned_text.bytes.to_a.size * 8) % 6 != 0
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
msg = _("Base64 syntax checker: Cannot parse invalid Base64 string - %{msg2}") % { msg2: msg2 }
|
27
|
+
msg = if (cleaned_text.bytes.to_a.size * 8) % 6 != 0
|
28
|
+
_("Base64 syntax checker: Cannot parse invalid Base64 string - padding is not correct")
|
29
|
+
else
|
30
|
+
_("Base64 syntax checker: Cannot parse invalid Base64 string - contains letters outside strict base 64 range (or whitespace)")
|
31
|
+
end
|
33
32
|
|
34
33
|
# TODO: improve the pops API to allow simpler diagnostic creation while still maintaining capabilities
|
35
34
|
# and the issue code. (In this case especially, where there is only a single error message being issued).
|
@@ -177,7 +177,7 @@ class Puppet::Transaction
|
|
177
177
|
else
|
178
178
|
resource.info _("Starting to evaluate the resource") if Puppet[:evaltrace] and @catalog.host_config?
|
179
179
|
seconds = thinmark { block.call(resource) }
|
180
|
-
resource.info _("Evaluated in %
|
180
|
+
resource.info _("Evaluated in %{seconds} seconds") % { seconds: "%0.2f" % seconds } if Puppet[:evaltrace] and @catalog.host_config?
|
181
181
|
end
|
182
182
|
end
|
183
183
|
|
@@ -1289,9 +1289,7 @@ class Type
|
|
1289
1289
|
end
|
1290
1290
|
|
1291
1291
|
newmetaparam(:audit) do
|
1292
|
-
desc "
|
1293
|
-
|
1294
|
-
Marks a subset of this resource's unmanaged attributes for auditing. Accepts an
|
1292
|
+
desc "Marks a subset of this resource's unmanaged attributes for auditing. Accepts an
|
1295
1293
|
attribute name, an array of attribute names, or `all`.
|
1296
1294
|
|
1297
1295
|
Auditing a resource attribute has two effects: First, whenever a catalog
|
@@ -1312,12 +1310,6 @@ class Type
|
|
1312
1310
|
and the second run will log the edit made by Puppet.)"
|
1313
1311
|
|
1314
1312
|
validate do |list|
|
1315
|
-
if Puppet.settings[:strict] != :off
|
1316
|
-
# Only warn if `audit` metaparam came from a manifest
|
1317
|
-
if file && line
|
1318
|
-
puppet_deprecation_warning(_("The `audit` metaparameter is deprecated and will be ignored in a future release."), { :line => line, :file => file })
|
1319
|
-
end
|
1320
|
-
end
|
1321
1313
|
list = Array(list).collect {|p| p.to_sym}
|
1322
1314
|
unless list == [:all]
|
1323
1315
|
list.each do |param|
|
@@ -371,7 +371,7 @@ module Puppet
|
|
371
371
|
values.each { |value|
|
372
372
|
unless value.is_a?(String) and
|
373
373
|
(value =~ /^[0-6]$/ or value =~ /^(Mon|Tues?|Wed(?:nes)?|Thu(?:rs)?|Fri|Sat(?:ur)?|Sun)(day)?$/i)
|
374
|
-
raise ArgumentError, _("%
|
374
|
+
raise ArgumentError, _("%{value} is not a valid day of the week") % { value: value }
|
375
375
|
end
|
376
376
|
}
|
377
377
|
end
|
@@ -168,10 +168,9 @@ class Puppet::Util::Log
|
|
168
168
|
def Log.coerce_string(str)
|
169
169
|
return Puppet::Util::CharacterEncoding.convert_to_utf_8(str) if str.valid_encoding?
|
170
170
|
|
171
|
-
annotated_string = _("Received a Log attribute with invalid encoding:")
|
172
|
-
annotated_string << Puppet::Util::CharacterEncoding.convert_to_utf_8(str.dump) << "\n"
|
173
171
|
# We only select the last 10 callers in the stack to avoid being spammy
|
174
|
-
|
172
|
+
_("Received a Log attribute with invalid encoding:%{log_message}\nBacktrace:\n%{backtrace}") %
|
173
|
+
{ log_message: Puppet::Util::CharacterEncoding.convert_to_utf_8(str.dump), backtrace: caller[0..10].join("\n") }
|
175
174
|
end
|
176
175
|
|
177
176
|
public
|
@@ -45,7 +45,7 @@ module Puppet::Util::Plist
|
|
45
45
|
{:failonfail => true, :combine => true})
|
46
46
|
return parse_plist(plist)
|
47
47
|
rescue Puppet::ExecutionFailure => detail
|
48
|
-
Puppet.warning(_("Cannot read file %{file_path}; Puppet is skipping it.\
|
48
|
+
Puppet.warning(_("Cannot read file %{file_path}; Puppet is skipping it.\nDetails: %{detail}") % { file_path: file_path, detail: detail })
|
49
49
|
end
|
50
50
|
end
|
51
51
|
return nil
|
@@ -13,8 +13,7 @@ class Puppet::Util::Reference
|
|
13
13
|
instance_load(:reference, 'puppet/reference')
|
14
14
|
|
15
15
|
def self.footer
|
16
|
-
|
17
|
-
"\n\n----------------\n\n*" + _("This page autogenerated on ") + "#{Time.now}*\n"
|
16
|
+
"\n\n----------------\n\n" + _("*This page autogenerated on %{current_time}*\n") % { current_time: Time.now.to_s }
|
18
17
|
end
|
19
18
|
|
20
19
|
def self.modes
|
@@ -113,7 +112,7 @@ class Puppet::Util::Reference
|
|
113
112
|
# First the header
|
114
113
|
text = markdown_header(@title, 1)
|
115
114
|
#TRANSLATORS message accompanied by date of generation
|
116
|
-
text << _("\n\n**This page is autogenerated; any changes will get overwritten** *(last generated on ")
|
115
|
+
text << _("\n\n**This page is autogenerated; any changes will get overwritten** *(last generated on %{current_time})*\n\n") % { current_time: Time.now.to_s }
|
117
116
|
|
118
117
|
text << @header
|
119
118
|
|
@@ -16,59 +16,301 @@ require 'puppet/parser/script_compiler'
|
|
16
16
|
# end
|
17
17
|
# # The result is the value 6
|
18
18
|
#
|
19
|
-
# @example
|
19
|
+
# @example Calling a function
|
20
20
|
# require 'puppet_pal'
|
21
21
|
# result = Puppet::Pal.in_tmp_environment('pal_env', modulepath: ['/tmp/testmodules']) do |pal|
|
22
|
-
# pal.
|
22
|
+
# pal.call_function('mymodule::myfunction', 10, 20)
|
23
23
|
# end
|
24
|
-
# # The result is what 'mymodule::
|
24
|
+
# # The result is what 'mymodule::myfunction' returns
|
25
25
|
#
|
26
|
-
module Puppet
|
26
|
+
module Puppet
|
27
|
+
module Pal
|
27
28
|
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
29
|
+
# @param compiler [Puppet::Pal::Compiler] a configured compiler as obtained in the callback from `with_script_compiler`
|
30
|
+
|
31
|
+
class Compiler
|
32
|
+
attr_reader :internal_compiler
|
33
|
+
protected :internal_compiler
|
34
|
+
|
35
|
+
attr_reader :internal_evaluator
|
36
|
+
protected :internal_evaluator
|
37
|
+
|
38
|
+
def initialize(internal_compiler)
|
39
|
+
@internal_compiler = internal_compiler
|
40
|
+
@internal_evaluator = Puppet::Pops::Parser::EvaluatingParser.new
|
41
|
+
end
|
42
|
+
|
43
|
+
# Calls a function given by name with arguments specified in an `Array`, and optionally accepts a code block.
|
44
|
+
# @param function_name [String] the name of the function to call
|
45
|
+
# @param args [Object] the arguments to the function
|
46
|
+
# @param block [Proc] an optional callable block that is given to the called function
|
47
|
+
# @return [Object] what the called function returns
|
48
|
+
#
|
49
|
+
def call_function(function_name, *args, &block)
|
50
|
+
# TRANSLATORS: do not translate variable name strings in these assertions
|
51
|
+
Pal::assert_non_empty_string(function_name, 'function_name', false)
|
52
|
+
Pal::assert_type(Pal::T_ANY_ARRAY, args, 'args', false)
|
53
|
+
internal_evaluator.evaluator.external_call_function(function_name, args, topscope, &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns an Array[Puppet::Pops::Types::PCallableType] describing the given function's signatures, or empty array if function not found.
|
57
|
+
# @param function_name [String] the name of the function to get a signature for
|
58
|
+
# @return [Array<Puppet::Pops::Types::PCallableType>] an array of callable signatures, or an empty array if function not found
|
59
|
+
def function_signatures(function_name)
|
60
|
+
loader = internal_compiler.loaders.private_environment_loader
|
61
|
+
if func = loader.load(:function, function_name)
|
62
|
+
t = func.class.dispatcher.to_type
|
63
|
+
return t.is_a?(Puppet::Pops::Types::PVariantType) ? t.types : [t]
|
64
|
+
end
|
65
|
+
# Could not find function
|
66
|
+
Puppet::Pops::EMPTY_ARRAY
|
67
|
+
end
|
68
|
+
|
69
|
+
# Evaluates a string of puppet language code in top scope.
|
70
|
+
# A "source_file" reference to a source can be given - if not an actual file name, by convention the name should
|
71
|
+
# be bracketed with < > to indicate it is something symbolic; for example `<commandline>` if the string was given on the
|
72
|
+
# command line.
|
73
|
+
#
|
74
|
+
# If the given `puppet_code` is `nil` or an empty string, `nil` is returned, otherwise the result of evaluating the
|
75
|
+
# puppet language string. The given string must form a complete and valid expression/statement as an error is raised
|
76
|
+
# otherwise. That is, it is not possible to divide a compound expression by line and evaluate each line individually.
|
77
|
+
#
|
78
|
+
# @param puppet_code [String, nil] the puppet language code to evaluate, must be a complete expression/statement
|
79
|
+
# @param source_file [String, nil] an optional reference to a source (a file or symbolic name/location)
|
80
|
+
# @return [Object] what the `puppet_code` evaluates to
|
81
|
+
#
|
82
|
+
def evaluate_string(puppet_code, source_file = nil)
|
83
|
+
return nil if puppet_code.nil? || puppet_code == ''
|
84
|
+
unless puppet_code.is_a?(String)
|
85
|
+
raise ArgumentError, _("The argument 'puppet_code' must be a String, got %{type}") % { type: puppet_code.class }
|
86
|
+
end
|
87
|
+
evaluate(parse_string(puppet_code, source_file))
|
88
|
+
end
|
89
|
+
|
90
|
+
# Evaluates a puppet language file in top scope.
|
91
|
+
# The file must exist and contain valid puppet language code or an error is raised.
|
92
|
+
#
|
93
|
+
# @param file [Path, String] an absolute path to a file with puppet language code, must exist
|
94
|
+
# @return [Object] what the last evaluated expression in the file evaluated to
|
95
|
+
#
|
96
|
+
def evaluate_file(file)
|
97
|
+
evaluate(parse_file(file))
|
98
|
+
end
|
99
|
+
|
100
|
+
# Evaluates an AST obtained from `parse_string` or `parse_file` in topscope.
|
101
|
+
# If the ast is a `Puppet::Pops::Model::Program` (what is returned from the `parse` methods, any definitions
|
102
|
+
# in the program (that is, any function, plan, etc. that is defined will be made available for use).
|
103
|
+
#
|
104
|
+
# @param ast [Puppet::Pops::Model::PopsObject] typically the returned `Program` from the parse methods, but can be any `Expression`
|
105
|
+
# @returns [Object] whatever the ast evaluates to
|
106
|
+
#
|
107
|
+
def evaluate(ast)
|
108
|
+
if ast.is_a?(Puppet::Pops::Model::Program)
|
109
|
+
loaders = Puppet.lookup(:loaders)
|
110
|
+
loaders.instantiate_definitions(ast, loaders.public_environment_loader)
|
111
|
+
end
|
112
|
+
internal_evaluator.evaluate(topscope, ast)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Produces a literal value if the AST obtained from `parse_string` or `parse_file` does not require any actual evaluation.
|
116
|
+
# This method is useful if obtaining an AST that represents literal values; string, integer, float, boolean, regexp, array, hash;
|
117
|
+
# for example from having read this from the command line or as values in some file.
|
118
|
+
#
|
119
|
+
# @param ast [Puppet::Pops::Model::PopsObject] typically the returned `Program` from the parse methods, but can be any `Expression`
|
120
|
+
# @returns [Object] whatever the literal value the ast evaluates to
|
121
|
+
#
|
122
|
+
def evaluate_literal(ast)
|
123
|
+
catch :not_literal do
|
124
|
+
return Puppet::Pops::Evaluator::LiteralEvaluator.new().literal(ast)
|
125
|
+
end
|
126
|
+
# TRANSLATORS, the 'ast' is the name of a parameter, do not translate
|
127
|
+
raise ArgumentError, _("The given 'ast' does not represent a literal value")
|
128
|
+
end
|
129
|
+
|
130
|
+
# Parses and validates a puppet language string and returns an instance of Puppet::Pops::Model::Program on success.
|
131
|
+
# If the content is not valid an error is raised.
|
132
|
+
#
|
133
|
+
# @param code_string [String] a puppet language string to parse and validate
|
134
|
+
# @param source_file [String] an optional reference to a file or other location in angled brackets
|
135
|
+
# @return [Puppet::Pops::Model::Program] returns a `Program` instance on success
|
136
|
+
#
|
137
|
+
def parse_string(code_string, source_file = nil)
|
138
|
+
unless code_string.is_a?(String)
|
139
|
+
raise ArgumentError, _("The argument 'code_string' must be a String, got %{type}") % { type: code_string.class }
|
140
|
+
end
|
141
|
+
internal_evaluator.parse_string(code_string, source_file)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Parses and validates a puppet language file and returns an instance of Puppet::Pops::Model::Program on success.
|
145
|
+
# If the content is not valid an error is raised.
|
146
|
+
#
|
147
|
+
# @param file [String] a file with puppet language content to parse and validate
|
148
|
+
# @return [Puppet::Pops::Model::Program] returns a `Program` instance on success
|
149
|
+
#
|
150
|
+
def parse_file(file)
|
151
|
+
unless file.is_a?(String)
|
152
|
+
raise ArgumentError, _("The argument 'file' must be a String, got %{type}") % { type: puppet_code.class }
|
153
|
+
end
|
154
|
+
internal_evaluator.parse_file(file)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Parses a puppet data type given in String format and returns that type, or raises an error.
|
158
|
+
# A type is needed in calls to `new` to create an instance of the data type, or to perform type checking
|
159
|
+
# of values - typically using `type.instance?(obj)` to check if `obj` is an instance of the type.
|
160
|
+
#
|
161
|
+
# @example Verify if obj is an instance of a data type
|
162
|
+
# # evaluates to true
|
163
|
+
# pal.type('Enum[red, blue]').instance?("blue")
|
164
|
+
#
|
165
|
+
# @example Create an instance of a data type
|
166
|
+
# # using an already create type
|
167
|
+
# t = pal.type('Car')
|
168
|
+
# pal.create(t, 'color' => 'black', 'make' => 't-ford')
|
169
|
+
#
|
170
|
+
# # letting 'new_object' parse the type from a string
|
171
|
+
# pal.create('Car', 'color' => 'black', 'make' => 't-ford')
|
172
|
+
#
|
173
|
+
# @param type_string [String] a puppet language data type
|
174
|
+
# @return [Puppet::Pops::Types::PAnyType] the data type
|
175
|
+
#
|
176
|
+
def type(type_string)
|
177
|
+
Puppet::Pops::Types::TypeParser.singleton.parse(type_string)
|
178
|
+
end
|
179
|
+
|
180
|
+
# Creates a new instance of a given data type.
|
181
|
+
# @param data_type [String, Puppet::Pops::Types::PAnyType] the data type as a data type or in String form.
|
182
|
+
# @param arguments [Object] one or more arguments to the called `new` function
|
183
|
+
# @return [Object] an instance of the given data type,
|
184
|
+
# or raises an error if it was not possible to parse data type or create an instance.
|
185
|
+
#
|
186
|
+
def create(data_type, *arguments)
|
187
|
+
t = data_type.is_a?(String) ? type(data_type) : data_type
|
188
|
+
unless t.is_a?(Puppet::Pops::Types::PAnyType)
|
189
|
+
raise ArgumentError, _("Given data_type value is not a data type, got '%{type}'") % {type: t.class}
|
190
|
+
end
|
191
|
+
call_function('new', t, *arguments)
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
def topscope
|
197
|
+
internal_compiler.topscope
|
198
|
+
end
|
36
199
|
end
|
37
200
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
201
|
+
class ScriptCompiler < Compiler
|
202
|
+
# Returns the signature callable of the given plan (the arguments it accepts, and the data type it returns)
|
203
|
+
# @param plan_name [String] the name of the plan to get the signature of
|
204
|
+
# @return [Puppet::Pops::Types::PCallableType, nil] returns a callable data type, or nil if plan is not found
|
205
|
+
#
|
206
|
+
def plan_signature(plan_name)
|
207
|
+
loader = internal_compiler.loaders.private_environment_loader
|
208
|
+
if func = loader.load(:plan, plan_name)
|
209
|
+
return func.class.dispatcher.to_type
|
210
|
+
end
|
211
|
+
# Could not find plan
|
212
|
+
nil
|
213
|
+
end
|
46
214
|
end
|
47
215
|
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
# @
|
216
|
+
# Defines a context in which multiple operations in an env with a script compiler can be performed in a given block.
|
217
|
+
# The calls that takes place to PAL inside of the given block are all with the same instance of the compiler.
|
218
|
+
# The parameter `configured_by_env` makes it possible to either use the configuration in the environment, or specify
|
219
|
+
# `manifest_file` or `code_string` manually. If neither is given, an empty `code_string` is used.
|
220
|
+
#
|
221
|
+
# @example define a script compiler without any initial logic
|
222
|
+
# pal.with_script_compiler do | compiler |
|
223
|
+
# # do things with compiler
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
# @example define a script compiler with a code_string containing initial logic
|
227
|
+
# pal.with_script_compiler(code_string: '$myglobal_var = 42') do | compiler |
|
228
|
+
# # do things with compiler
|
229
|
+
# end
|
230
|
+
#
|
231
|
+
# @param configured_by_env [Boolean] when true the environment's settings are used, otherwise the given `manifest_file` or `code_string`
|
232
|
+
# @param manifest_file [String] a Puppet Language file to load and evaluate before calling the given block, mutually exclusive with `code_string`
|
233
|
+
# @param code_string [String] a Puppet Language source string to load and evaluate before calling the given block, mutually exclusive with `manifest_file`
|
234
|
+
# @param facts [Hash] optional map of fact name to fact value - if not given will initialize the facts (which is a slow operation)
|
235
|
+
# If given at the environment level, the facts given here are merged with higher priority.
|
236
|
+
# @param variables [Hash] optional map of fully qualified variable name to value. If given at the environment level, the variables
|
237
|
+
# given here are merged with higher priority.
|
238
|
+
# @param block [Proc] the block performing operations on compiler
|
239
|
+
# @return [Object] what the block returns
|
240
|
+
# @yieldparam [Puppet::Pal::ScriptCompiler] compiler, a ScriptCompiler to perform operations on.
|
54
241
|
#
|
55
|
-
def self.
|
56
|
-
|
57
|
-
manifest_file:
|
58
|
-
code_string:
|
242
|
+
def self.with_script_compiler(
|
243
|
+
configured_by_env: false,
|
244
|
+
manifest_file: nil,
|
245
|
+
code_string: nil,
|
246
|
+
facts: nil,
|
247
|
+
variables: nil,
|
248
|
+
&block
|
59
249
|
)
|
60
|
-
# TRANSLATORS: do not translate variable name
|
250
|
+
# TRANSLATORS: do not translate variable name strings in these assertions
|
61
251
|
assert_mutually_exclusive(manifest_file, code_string, 'manifest_file', 'code_string')
|
62
252
|
assert_non_empty_string(manifest_file, 'manifest_file', true)
|
63
253
|
assert_non_empty_string(code_string, 'code_string', true)
|
254
|
+
assert_type(T_BOOLEAN, configured_by_env, "configured_by_env", false)
|
255
|
+
|
256
|
+
if configured_by_env
|
257
|
+
unless manifest_file.nil? && code_string.nil?
|
258
|
+
# TRANSLATORS: do not translate the variable names in this error message
|
259
|
+
raise ArgumentError, _("manifest_file or code_string cannot be given when configured_by_env is true")
|
260
|
+
end
|
261
|
+
# Use the manifest setting
|
262
|
+
manifest_file = Puppet[:manifest]
|
263
|
+
else
|
264
|
+
# An "undef" code_string is the only way to override Puppet[:manifest] & Puppet[:code] settings since an
|
265
|
+
# empty string is taken as Puppet[:code] not being set.
|
266
|
+
#
|
267
|
+
if manifest_file.nil? && code_string.nil?
|
268
|
+
code_string = 'undef'
|
269
|
+
end
|
270
|
+
end
|
64
271
|
|
65
272
|
Puppet[:tasks] = true
|
273
|
+
# After the assertions, if code_string is non nil - it has the highest precedence
|
66
274
|
Puppet[:code] = code_string unless code_string.nil?
|
67
|
-
|
68
|
-
|
275
|
+
overrides = {}
|
276
|
+
unless facts.nil?
|
277
|
+
overrides[:pal_facts] = Puppet.lookup(:pal_facts).merge(facts)
|
278
|
+
end
|
279
|
+
unless variables.nil?
|
280
|
+
overrides[:pal_variables] = Puppet.lookup(:pal_variables).merge(variables)
|
281
|
+
end
|
282
|
+
Puppet.override(overrides, "PAL::with_script_compiler") do # TRANSLATORS: Do not translate, symbolic name
|
283
|
+
# If manifest_file is nil, the #main method will use the env configured manifest
|
284
|
+
# do things in block while a Script Compiler is in effect
|
285
|
+
main(manifest_file, &block)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
# Evaluates a Puppet Language script string.
|
290
|
+
# @param code_string [String] a snippet of Puppet Language source code
|
291
|
+
# @return [Object] what the Puppet Language code_string evaluates to
|
292
|
+
# @deprecated Use {#with_script_compiler} and then evaluate_string on the given compiler - to be removed in 1.0 version
|
293
|
+
#
|
294
|
+
def self.evaluate_script_string(code_string)
|
295
|
+
# prevent the default loading of Puppet[:manifest] which is the environment's manifest-dir by default settings
|
296
|
+
# by setting code_string to 'undef'
|
297
|
+
with_script_compiler do |compiler|
|
298
|
+
compiler.evaluate_string(code_string)
|
69
299
|
end
|
70
300
|
end
|
71
301
|
|
302
|
+
# Evaluates a Puppet Language script (.pp) file.
|
303
|
+
# @param manifest_file [String] a file with Puppet Language source code
|
304
|
+
# @return [Object] what the Puppet Language manifest_file contents evaluates to
|
305
|
+
# @deprecated Use {#with_script_compiler} and then evaluate_file on the given compiler - to be removed in 1.0 version
|
306
|
+
#
|
307
|
+
def self.evaluate_script_manifest(manifest_file)
|
308
|
+
with_script_compiler do |compiler|
|
309
|
+
compiler.evaluate_file(manifest_file)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
|
72
314
|
# Defines the context in which to perform puppet operations (evaluation, etc)
|
73
315
|
# The code to evaluate in this context is given in a block.
|
74
316
|
#
|
@@ -76,6 +318,7 @@ module Puppet::Pal
|
|
76
318
|
# @param modulepath [Array<String>] an array of directory paths containing Puppet modules, may be empty, defaults to empty array
|
77
319
|
# @param settings_hash [Hash] a hash of settings - currently not used for anything, defaults to empty hash
|
78
320
|
# @param facts [Hash] optional map of fact name to fact value - if not given will initialize the facts (which is a slow operation)
|
321
|
+
# @param variables [Hash] optional map of fully qualified variable name to value
|
79
322
|
# @return [Object] returns what the given block returns
|
80
323
|
# @yieldparam [Puppet::Pal] context, a context that responds to Puppet::Pal methods
|
81
324
|
#
|
@@ -96,9 +339,10 @@ module Puppet::Pal
|
|
96
339
|
|
97
340
|
env = Puppet::Node::Environment.create(env_name, modulepath)
|
98
341
|
|
99
|
-
|
342
|
+
in_environment_context(
|
100
343
|
Puppet::Environments::Static.new(env), # The tmp env is the only known env
|
101
|
-
env, facts, variables, &block
|
344
|
+
env, facts, variables, &block
|
345
|
+
)
|
102
346
|
end
|
103
347
|
|
104
348
|
# Defines the context in which to perform puppet operations (evaluation, etc)
|
@@ -121,6 +365,7 @@ module Puppet::Pal
|
|
121
365
|
# @param envpath [String] a path of directories in which there are environments to search for `env_name` (mutually exclusive with `env_dir`).
|
122
366
|
# Should be a single directory, or several directories separated with platform specific `File::PATH_SEPARATOR` character.
|
123
367
|
# @param facts [Hash] optional map of fact name to fact value - if not given will initialize the facts (which is a slow operation)
|
368
|
+
# @param variables [Hash] optional map of fully qualified variable name to value
|
124
369
|
# @return [Object] returns what the given block returns
|
125
370
|
# @yieldparam [Puppet::Pal] context, a context that responds to Puppet::Pal methods
|
126
371
|
#
|
@@ -181,28 +426,27 @@ module Puppet::Pal
|
|
181
426
|
# not have the same effective modulepath).
|
182
427
|
environments = Puppet::Environments::StaticDirectory.new(env_name, env_path, env) # The env being used is the only one...
|
183
428
|
end
|
184
|
-
|
429
|
+
in_environment_context(environments, env, facts, variables, &block)
|
185
430
|
end
|
186
431
|
|
187
432
|
private
|
188
433
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
#
|
195
|
-
# pickup the new $LOAD_PATH.
|
196
|
-
Facter.reset
|
197
|
-
|
434
|
+
# Prepares the puppet context with pal information - and delegates to the block
|
435
|
+
# No set up is performed at this step - it is delayed until it is known what the
|
436
|
+
# operation is going to be (for example - using a ScriptCompiler).
|
437
|
+
#
|
438
|
+
def self.in_environment_context(environments, env, facts, variables, &block)
|
439
|
+
# Create a default node to use (may be overridden later)
|
198
440
|
node = Puppet::Node.new(Puppet[:node_name_value], :environment => env)
|
199
441
|
|
200
442
|
Puppet.override(
|
201
|
-
environments: environments,
|
202
|
-
|
203
|
-
|
443
|
+
environments: environments, # The env being used is the only one...
|
444
|
+
pal_env: env, # provide as convenience
|
445
|
+
pal_current_node: node, # to allow it to be picked up instead of created
|
446
|
+
pal_variables: variables, # common set of variables across several inner contexts
|
447
|
+
pal_facts: facts # common set of facts across several inner contexts (or nil)
|
204
448
|
) do
|
205
|
-
prepare_node_facts(node, facts)
|
449
|
+
# DELAY: prepare_node_facts(node, facts)
|
206
450
|
return block.call(self)
|
207
451
|
end
|
208
452
|
end
|
@@ -243,8 +487,24 @@ module Puppet::Pal
|
|
243
487
|
end
|
244
488
|
end
|
245
489
|
|
246
|
-
|
247
|
-
|
490
|
+
# The main routine for script compiler
|
491
|
+
# Picks up information from the puppet context and configures a script compiler which is given to
|
492
|
+
# the provided block
|
493
|
+
#
|
494
|
+
def self.main(manifest = nil, &block)
|
495
|
+
# Configure the load path
|
496
|
+
env = Puppet.lookup(:pal_env)
|
497
|
+
env.each_plugin_directory do |dir|
|
498
|
+
$LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
|
499
|
+
end
|
500
|
+
|
501
|
+
# Puppet requires Facter, which initializes its lookup paths. Reset Facter to
|
502
|
+
# pickup the new $LOAD_PATH.
|
503
|
+
Facter.reset
|
504
|
+
|
505
|
+
node = Puppet.lookup(:pal_current_node)
|
506
|
+
prepare_node_facts(node, Puppet.lookup(:pal_facts))
|
507
|
+
|
248
508
|
configured_environment = node.environment || Puppet.lookup(:current_environment)
|
249
509
|
|
250
510
|
apply_environment = manifest ?
|
@@ -287,9 +547,13 @@ module Puppet::Pal
|
|
287
547
|
# create the $settings:: variables
|
288
548
|
topscope.merge_settings(node.environment.name, false)
|
289
549
|
|
290
|
-
add_variables(topscope, Puppet.lookup(:
|
550
|
+
add_variables(topscope, Puppet.lookup(:pal_variables))
|
291
551
|
|
292
|
-
compiler.compile(&block)
|
552
|
+
# compiler.compile(&block)
|
553
|
+
compiler.compile do | internal_compiler |
|
554
|
+
# wrap the internal compiler to prevent it from leaking in the PAL API
|
555
|
+
block.call(ScriptCompiler.new(internal_compiler)) unless !block_given?
|
556
|
+
end
|
293
557
|
|
294
558
|
rescue Puppet::ParseErrorWithIssue, Puppet::Error => detail
|
295
559
|
# already logged and handled by the compiler for these two cases
|
@@ -304,6 +568,8 @@ module Puppet::Pal
|
|
304
568
|
|
305
569
|
T_STRING = Puppet::Pops::Types::PStringType::NON_EMPTY
|
306
570
|
T_STRING_ARRAY = Puppet::Pops::Types::TypeFactory.array_of(T_STRING)
|
571
|
+
T_ANY_ARRAY = Puppet::Pops::Types::TypeFactory.array_of_any
|
572
|
+
T_BOOLEAN = Puppet::Pops::Types::PBooleanType::DEFAULT
|
307
573
|
|
308
574
|
def self.assert_type(type, value, what, allow_nil=false)
|
309
575
|
Puppet::Pops::Types::TypeAsserter.assert_instance_of(nil, type, value, allow_nil) { _('Puppet Pal: %{what}') % {what: what} }
|
@@ -323,4 +589,11 @@ module Puppet::Pal
|
|
323
589
|
end
|
324
590
|
end
|
325
591
|
|
592
|
+
def self.assert_block_given(block)
|
593
|
+
if block.nil?
|
594
|
+
raise ArgumentError, _("A block must be given")
|
595
|
+
end
|
596
|
+
end
|
597
|
+
end
|
326
598
|
end
|
599
|
+
|