bolt 2.8.0 → 2.12.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/Puppetfile +2 -2
- data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +2 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb +27 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +2 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resultset.rb +2 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/target.rb +4 -3
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +61 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_resources.rb +122 -0
- data/bolt-modules/boltlib/types/planresult.pp +12 -1
- data/bolt-modules/file/lib/puppet/functions/file/exists.rb +3 -1
- data/bolt-modules/file/lib/puppet/functions/file/join.rb +1 -1
- data/bolt-modules/file/lib/puppet/functions/file/read.rb +2 -1
- data/bolt-modules/file/lib/puppet/functions/file/readable.rb +3 -1
- data/bolt-modules/file/lib/puppet/functions/file/write.rb +3 -1
- data/lib/bolt/analytics.rb +21 -2
- data/lib/bolt/applicator.rb +3 -1
- data/lib/bolt/apply_result.rb +1 -1
- data/lib/bolt/apply_target.rb +3 -2
- data/lib/bolt/bolt_option_parser.rb +18 -8
- data/lib/bolt/cli.rb +35 -5
- data/lib/bolt/config.rb +45 -13
- data/lib/bolt/config/transport/docker.rb +2 -0
- data/lib/bolt/config/transport/local.rb +2 -0
- data/lib/bolt/config/transport/orch.rb +2 -0
- data/lib/bolt/config/transport/remote.rb +2 -0
- data/lib/bolt/config/transport/ssh.rb +50 -1
- data/lib/bolt/config/transport/winrm.rb +2 -0
- data/lib/bolt/inventory.rb +2 -1
- data/lib/bolt/inventory/group.rb +1 -0
- data/lib/bolt/inventory/inventory.rb +5 -0
- data/lib/bolt/inventory/target.rb +17 -1
- data/lib/bolt/node/output.rb +1 -1
- data/lib/bolt/outputter/human.rb +5 -4
- data/lib/bolt/outputter/json.rb +1 -1
- data/lib/bolt/pal.rb +4 -1
- data/lib/bolt/pal/yaml_plan.rb +1 -0
- data/lib/bolt/plugin.rb +13 -7
- data/lib/bolt/plugin/puppetdb.rb +5 -2
- data/lib/bolt/project.rb +25 -7
- data/lib/bolt/puppetdb/config.rb +14 -26
- data/lib/bolt/rerun.rb +1 -1
- data/lib/bolt/resource_instance.rb +126 -0
- data/lib/bolt/result.rb +46 -23
- data/lib/bolt/result_set.rb +2 -5
- data/lib/bolt/shell/bash.rb +1 -1
- data/lib/bolt/shell/powershell.rb +12 -4
- data/lib/bolt/target.rb +12 -1
- data/lib/bolt/transport/ssh.rb +6 -2
- data/lib/bolt/transport/ssh/connection.rb +4 -0
- data/lib/bolt/transport/ssh/exec_connection.rb +110 -0
- data/lib/bolt/transport/winrm/connection.rb +6 -2
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/pe/pal.rb +1 -38
- data/lib/bolt_server/transport_app.rb +7 -7
- data/lib/bolt_spec/bolt_context.rb +1 -4
- data/lib/bolt_spec/plans/mock_executor.rb +1 -0
- data/lib/bolt_spec/run.rb +2 -5
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c36dc3edc9637ac83eab0734e6143961ff7c97f4cbc0866ce8e1b5a0b5d318c2
|
4
|
+
data.tar.gz: c52ea03e1354361836c6d76c108735e2f8525aa5e8132f87cf895b5a0f2d802d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ded5edab2a28a3a50d2eb9c9d2a1ccad43eae0272b09a609b219a78516bd32f8bff0e35751a95629d4d918cf3a22883d47a90c5c0f402c5aeedaffaab5dfc546
|
7
|
+
data.tar.gz: acde1204c706c49926a33b074da9b5262d1e6d11d27137bec55d7ea80a3ec7e009a1defc309e1f9a7fe824db9c0d4ce92963ddc6d3ae3d2619550fc5c4164ed3
|
data/Puppetfile
CHANGED
@@ -6,7 +6,7 @@ moduledir File.join(File.dirname(__FILE__), 'modules')
|
|
6
6
|
|
7
7
|
# Core modules used by 'apply'
|
8
8
|
mod 'puppetlabs-service', '1.2.0'
|
9
|
-
mod 'puppetlabs-puppet_agent', '3.0
|
9
|
+
mod 'puppetlabs-puppet_agent', '3.2.0'
|
10
10
|
mod 'puppetlabs-facts', '1.0.0'
|
11
11
|
|
12
12
|
# Core types and providers for Puppet 6
|
@@ -24,7 +24,7 @@ mod 'puppetlabs-zone_core', '1.0.3'
|
|
24
24
|
# Useful additional modules
|
25
25
|
mod 'puppetlabs-package', '1.1.0'
|
26
26
|
mod 'puppetlabs-puppet_conf', '0.6.0'
|
27
|
-
mod 'puppetlabs-python_task_helper', '0.4.
|
27
|
+
mod 'puppetlabs-python_task_helper', '0.4.3'
|
28
28
|
mod 'puppetlabs-reboot', '3.0.0'
|
29
29
|
mod 'puppetlabs-ruby_task_helper', '0.5.1'
|
30
30
|
mod 'puppetlabs-ruby_plugin_helper', '0.1.0'
|
@@ -17,5 +17,7 @@ Puppet::DataTypes.create_type('ApplyResult') do
|
|
17
17
|
|
18
18
|
load_file('bolt/apply_result')
|
19
19
|
|
20
|
+
# Needed for Puppet to recognize Bolt::ApplyResult as a Puppet object when deserializing
|
21
|
+
Bolt::ApplyResult.include(Puppet::Pops::Types::PuppetObject)
|
20
22
|
implementation_class Bolt::ApplyResult
|
21
23
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Puppet::DataTypes.create_type('ResourceInstance') do
|
4
|
+
interface <<-PUPPET
|
5
|
+
attributes => {
|
6
|
+
'target' => Target,
|
7
|
+
'type' => Variant[String[1], Type[Resource]],
|
8
|
+
'title' => String[1],
|
9
|
+
'state' => Optional[Hash[String[1], Data]],
|
10
|
+
'desired_state' => Optional[Hash[String[1], Data]],
|
11
|
+
'events' => Optional[Array[Hash[String[1], Data]]]
|
12
|
+
},
|
13
|
+
functions => {
|
14
|
+
add_event => Callable[[Hash[String[1], Data]], [Hash[String[1], Data]]],
|
15
|
+
set_state => Callable[[Hash[String[1], Data]], Hash[String[1], Data]],
|
16
|
+
overwrite_state => Callable[[Hash[String[1], Data]], Hash[String[1], Data]],
|
17
|
+
set_desired_state => Callable[[Hash[String[1], Data]], Hash[String[1], Data]],
|
18
|
+
overwrite_desired_state => Callable[[Hash[String[1], Data]], Hash[String[1], Data]],
|
19
|
+
reference => Callable[[], String]
|
20
|
+
}
|
21
|
+
PUPPET
|
22
|
+
|
23
|
+
load_file('bolt/resource_instance')
|
24
|
+
# Needed for Puppet to recognize Bolt::ResourceInstance as a Puppet object when deserializing
|
25
|
+
Bolt::ResourceInstance.include(Puppet::Pops::Types::PuppetObject)
|
26
|
+
implementation_class Bolt::ResourceInstance
|
27
|
+
end
|
@@ -19,5 +19,7 @@ Puppet::DataTypes.create_type('Result') do
|
|
19
19
|
|
20
20
|
load_file('bolt/result')
|
21
21
|
|
22
|
+
# Needed for Puppet to recognize Bolt::Result as a Puppet object when deserializing
|
23
|
+
Bolt::Result.include(Puppet::Pops::Types::PuppetObject)
|
22
24
|
implementation_class Bolt::Result
|
23
25
|
end
|
@@ -25,5 +25,7 @@ Puppet::DataTypes.create_type('ResultSet') do
|
|
25
25
|
|
26
26
|
load_file('bolt/result_set')
|
27
27
|
|
28
|
+
# Needed for Puppet to recognize Bolt::ResultSet as a Puppet object when deserializing
|
29
|
+
Bolt::ResultSet.include(Puppet::Pops::Types::PuppetObject)
|
28
30
|
implementation_class Bolt::ResultSet
|
29
31
|
end
|
@@ -8,8 +8,6 @@ Puppet::DataTypes.create_type('Target') do
|
|
8
8
|
target_implementation_class = Bolt::Target
|
9
9
|
end
|
10
10
|
|
11
|
-
require 'bolt/target'
|
12
|
-
|
13
11
|
interface <<-PUPPET
|
14
12
|
attributes => {
|
15
13
|
uri => { type => Optional[String[1]], kind => given_or_derived },
|
@@ -20,7 +18,8 @@ Puppet::DataTypes.create_type('Target') do
|
|
20
18
|
vars => { type => Optional[Hash[String[1], Data]], kind => given_or_derived },
|
21
19
|
facts => { type => Optional[Hash[String[1], Data]], kind => given_or_derived },
|
22
20
|
features => { type => Optional[Array[String[1]]], kind => given_or_derived },
|
23
|
-
plugin_hooks => { type => Optional[Hash[String[1], Data]], kind => given_or_derived }
|
21
|
+
plugin_hooks => { type => Optional[Hash[String[1], Data]], kind => given_or_derived },
|
22
|
+
resources => { type => Optional[Hash[String[1], ResourceInstance]], kind => given_or_derived }
|
24
23
|
},
|
25
24
|
functions => {
|
26
25
|
host => Callable[[], Optional[String]],
|
@@ -33,5 +32,7 @@ Puppet::DataTypes.create_type('Target') do
|
|
33
32
|
}
|
34
33
|
PUPPET
|
35
34
|
|
35
|
+
# Needed for Puppet to recognize targets as Puppet objects when deserializing
|
36
|
+
target_implementation_class.include(Puppet::Pops::Types::PuppetObject)
|
36
37
|
implementation_class target_implementation_class
|
37
38
|
end
|
@@ -109,6 +109,15 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
112
|
+
# Wrap Sensitive parameters for plans that are run from the CLI, as it's impossible to pass
|
113
|
+
# a Sensitive value that way. We don't do this for plans run from the run_plan function, as
|
114
|
+
# it can receive Sensitive values as arguments.
|
115
|
+
# This should only happen after expanding target params, otherwise things will blow up if
|
116
|
+
# the targets are wrapped as Sensitive. Hopefully nobody does that, though...
|
117
|
+
if options[:bolt_api_call]
|
118
|
+
params = wrap_sensitive_parameters(params, closure.parameters)
|
119
|
+
end
|
120
|
+
|
112
121
|
# wrap plan execution in logging messages
|
113
122
|
executor.log_plan(plan_name) do
|
114
123
|
result = nil
|
@@ -169,6 +178,58 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
|
|
169
178
|
end
|
170
179
|
end
|
171
180
|
|
181
|
+
# Wrap any Sensitive parameters in the Sensitive wrapper type, unless they are already
|
182
|
+
# wrapped as Sensitive. This will also raise a helpful warning if the type expression
|
183
|
+
# is a complex data type using Sensitive, as we don't handle those cases.
|
184
|
+
def wrap_sensitive_parameters(params, param_models)
|
185
|
+
models = param_models.each_with_object({}) { |param, acc| acc[param.name] = param }
|
186
|
+
|
187
|
+
params.each_with_object({}) do |(name, value), acc|
|
188
|
+
model = models[name]
|
189
|
+
|
190
|
+
if sensitive_type?(model.type_expr)
|
191
|
+
acc[name] = Puppet::Pops::Types::PSensitiveType::Sensitive.new(value)
|
192
|
+
else
|
193
|
+
if model.type_expr.to_s.include?('Sensitive')
|
194
|
+
# Include the location for regular plans. YAML plans don't have this info, so
|
195
|
+
# the location will be suppressed.
|
196
|
+
file = defined?(model.file) ? model.file : :default
|
197
|
+
line = defined?(model.line) ? model.line : :default
|
198
|
+
|
199
|
+
Puppet.warn_once(
|
200
|
+
'unsupported_sensitive_type',
|
201
|
+
name,
|
202
|
+
"Parameter '#{name}' is a complex type using Sensitive, unable to automatically wrap as Sensitive",
|
203
|
+
file,
|
204
|
+
line
|
205
|
+
)
|
206
|
+
end
|
207
|
+
|
208
|
+
acc[name] = value
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Whether the type is a supported Sensitive type. We only support wrapping parameterized
|
214
|
+
# and non-parameterized Sensitive types (e.g. Sensitive, Sensitive[String])
|
215
|
+
def sensitive_type?(type_expr)
|
216
|
+
# Parameterized Sensitive type (e.g. Sensitive[String])
|
217
|
+
# left_expr is defined whenever the type is parameterized. If this is a parameterized
|
218
|
+
# Sensitive type, then we check the cased_value, which is the stringified version of
|
219
|
+
# the left expression's type.
|
220
|
+
(defined?(type_expr.left_expr) && type_expr.left_expr.cased_value == 'Sensitive') ||
|
221
|
+
# Non-parameterized Sensitive type (Sensitive)
|
222
|
+
# cased_value is defined whenever the type is non-parameterized. If the type expression
|
223
|
+
# defines cased_value, then this is a simple type and we just need to check that it's
|
224
|
+
# Sensitive.
|
225
|
+
(defined?(type_expr.cased_value) && type_expr.cased_value == 'Sensitive') ||
|
226
|
+
# Sensitive type from YAML plans
|
227
|
+
# Type expressions from YAML plans are a different class than those from regular plans.
|
228
|
+
# As long as the type expression is PSensitiveType we can be sure that the type is
|
229
|
+
# either a parameterized or non-parameterized Sensitive type.
|
230
|
+
type_expr.instance_of?(Puppet::Pops::Types::PSensitiveType)
|
231
|
+
end
|
232
|
+
|
172
233
|
def targets_to_param(targets, params, param_types)
|
173
234
|
nodes_param = param_types.include?('nodes')
|
174
235
|
targets_param = param_types['targets']&.any? { |p| p.match?(/TargetSpec/) }
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/error'
|
4
|
+
|
5
|
+
# Sets one or more ResourceInstances on a Target. This function does not apply or modify
|
6
|
+
# resources on a target.
|
7
|
+
#
|
8
|
+
# For more information about resources see [the
|
9
|
+
# documentation](https://puppet.com/docs/puppet/latest/lang_resources.html).
|
10
|
+
#
|
11
|
+
# > **Note:** The `ResourceInstance` data type is under active development and is subject to
|
12
|
+
# change. You can read more about the data type in the [experimental features
|
13
|
+
# documentation](experimental_features.md#resourceinstance-data-type).
|
14
|
+
#
|
15
|
+
# > **Note:** Not available in apply block
|
16
|
+
Puppet::Functions.create_function(:set_resources) do
|
17
|
+
# Set multiple resources
|
18
|
+
# @param target The `Target` object to add resources to. See {get_targets}.
|
19
|
+
# @param resources The resources to set on the target.
|
20
|
+
# @return The added `ResourceInstance` objects.
|
21
|
+
# @example Add multiple resources to a target with an array of `ResourceInstance` objects.
|
22
|
+
# $resource1 = ResourceInstance.new(
|
23
|
+
# 'target' => $target,
|
24
|
+
# 'type' => 'file',
|
25
|
+
# 'title' => '/etc/puppetlabs',
|
26
|
+
# 'state' => { 'ensure' => 'present' }
|
27
|
+
# )
|
28
|
+
# $resource2 = ResourceInstance.new(
|
29
|
+
# 'target' => $target,
|
30
|
+
# 'type' => 'package',
|
31
|
+
# 'title' => 'openssl',
|
32
|
+
# 'state' => { 'ensure' => 'installed' }
|
33
|
+
# )
|
34
|
+
# $target.set_resources([$resource1, $resource2])
|
35
|
+
# @example Add resources retrieved with [`get_resources`](#get_resources) to a target.
|
36
|
+
# $target.apply_prep
|
37
|
+
# $resources = $target.get_resources(Package).first['resources']
|
38
|
+
# $target.set_resources($resources)
|
39
|
+
dispatch :set_resources do
|
40
|
+
param 'Target', :target
|
41
|
+
param 'Array[Variant[Hash, ResourceInstance]]', :resources
|
42
|
+
return_type 'Array[ResourceInstance]'
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set a single resource
|
46
|
+
# @param target The `Target` object to add resources to. See {get_targets}.
|
47
|
+
# @param resource The resource to set on the target.
|
48
|
+
# @return The added `ResourceInstance` object.
|
49
|
+
# @example Add a single resource to a target with a resource data hash.
|
50
|
+
# $resource = {
|
51
|
+
# 'type' => 'file',
|
52
|
+
# 'title' => '/etc/puppetlabs',
|
53
|
+
# 'state' => { 'ensure' => 'present' }
|
54
|
+
# }
|
55
|
+
# $target.set_resources($resource)
|
56
|
+
dispatch :set_resource do
|
57
|
+
param 'Target', :target
|
58
|
+
param 'Variant[Hash, ResourceInstance]', :resource
|
59
|
+
return_type 'Array[ResourceInstance]'
|
60
|
+
end
|
61
|
+
|
62
|
+
def set_resources(target, resources)
|
63
|
+
unless Puppet[:tasks]
|
64
|
+
raise Puppet::ParseErrorWithIssue
|
65
|
+
.from_issue_and_stack(
|
66
|
+
Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING,
|
67
|
+
action: 'set_resources'
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
inventory = Puppet.lookup(:bolt_inventory)
|
72
|
+
executor = Puppet.lookup(:bolt_executor)
|
73
|
+
executor.report_function_call(self.class.name)
|
74
|
+
|
75
|
+
inventory_target = inventory.get_target(target)
|
76
|
+
|
77
|
+
resources.uniq.map do |resource|
|
78
|
+
if resource.is_a?(Hash)
|
79
|
+
# ResourceInstance expects a Target object, so either get a specified target from
|
80
|
+
# the inventory or use the target this function was called on.
|
81
|
+
resource_target = if resource.key?('target')
|
82
|
+
inventory.get_target(resource['target'])
|
83
|
+
else
|
84
|
+
inventory_target
|
85
|
+
end
|
86
|
+
|
87
|
+
# Observed state from get_resources() is under the 'parameters' key
|
88
|
+
resource_state = resource['state'] || resource['parameters']
|
89
|
+
|
90
|
+
init_hash = {
|
91
|
+
'target' => resource_target,
|
92
|
+
'type' => resource['type'],
|
93
|
+
'title' => resource['title'],
|
94
|
+
'state' => resource_state,
|
95
|
+
'desired_state' => resource['desired_state'],
|
96
|
+
'events' => resource['events']
|
97
|
+
}
|
98
|
+
|
99
|
+
# Calling Bolt::ResourceInstance.new or Bolt::ResourceInstance.from_asserted_hash
|
100
|
+
# will not perform any validation on the parameters. Instead, we need to use the
|
101
|
+
# Puppet constructor to initialize the object, which will first validate the parameters
|
102
|
+
# and then call Bolt::ResourceInstance.from_asserted_hash internally. To do this we
|
103
|
+
# first need to get the Puppet datatype and then call the new function on that type.
|
104
|
+
type = Puppet::Pops::Types::TypeParser.singleton.parse('ResourceInstance')
|
105
|
+
resource = call_function('new', type, init_hash)
|
106
|
+
end
|
107
|
+
|
108
|
+
unless resource.target == inventory_target
|
109
|
+
file, line = Puppet::Pops::PuppetStack.top_of_stack
|
110
|
+
raise Bolt::ValidationError, "Cannot set resource #{resource.reference} for target "\
|
111
|
+
"#{resource.target} on target #{inventory_target}. "\
|
112
|
+
"#{Puppet::Util::Errors.error_location(file, line)}"
|
113
|
+
end
|
114
|
+
|
115
|
+
inventory_target.set_resource(resource)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def set_resource(target, resource)
|
120
|
+
set_resources(target, [resource])
|
121
|
+
end
|
122
|
+
end
|
@@ -2,4 +2,15 @@
|
|
2
2
|
# should be used as the return type of functions that run plans and return the
|
3
3
|
# results.
|
4
4
|
|
5
|
-
type Boltlib::PlanResult = Variant[Boolean,
|
5
|
+
type Boltlib::PlanResult = Variant[Boolean,
|
6
|
+
Numeric,
|
7
|
+
String,
|
8
|
+
Undef,
|
9
|
+
Error,
|
10
|
+
Result,
|
11
|
+
ApplyResult,
|
12
|
+
ResultSet,
|
13
|
+
Target,
|
14
|
+
ResourceInstance,
|
15
|
+
Array[Boltlib::PlanResult],
|
16
|
+
Hash[String, Boltlib::PlanResult]]
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Check if a file exists
|
3
|
+
# Check if a local file exists using Puppet's
|
4
|
+
# `Puppet::Parser::Files.find_file()` function. This will only check files that
|
5
|
+
# are on the machine Bolt is run on.
|
4
6
|
Puppet::Functions.create_function(:'file::exists', Puppet::Functions::InternalFunction) do
|
5
7
|
# @param filename Absolute path or Puppet file path.
|
6
8
|
# @return Whether the file exists.
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Read a file and return its contents.
|
3
|
+
# Read a file on localhost and return its contents using ruby's `File.read`. This will
|
4
|
+
# only read files on the machine you run Bolt on.
|
4
5
|
Puppet::Functions.create_function(:'file::read', Puppet::Functions::InternalFunction) do
|
5
6
|
# @param filename Absolute path or Puppet file path.
|
6
7
|
# @return The file's contents.
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Check if a file is readable
|
3
|
+
# Check if a local file is readable using Puppet's
|
4
|
+
# `Puppet::Parser::Files.find_file()` function. This will only check files on the
|
5
|
+
# machine you run Bolt on.
|
4
6
|
Puppet::Functions.create_function(:'file::readable', Puppet::Functions::InternalFunction) do
|
5
7
|
# @param filename Absolute path or Puppet file path.
|
6
8
|
# @return Whether the file is readable.
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Write a string to a file.
|
3
|
+
# Write a string to a file on localhost using ruby's `File.write`. This will
|
4
|
+
# only write files to the machine you run Bolt on. Use `write_file()` to write
|
5
|
+
# to remote targets.
|
4
6
|
Puppet::Functions.create_function(:'file::write') do
|
5
7
|
# @param filename Absolute path.
|
6
8
|
# @param content File content to write.
|
data/lib/bolt/analytics.rb
CHANGED
@@ -29,7 +29,7 @@ module Bolt
|
|
29
29
|
def self.build_client
|
30
30
|
logger = Logging.logger[self]
|
31
31
|
begin
|
32
|
-
config_file =
|
32
|
+
config_file = config_path(logger)
|
33
33
|
config = load_config(config_file, logger)
|
34
34
|
rescue ArgumentError
|
35
35
|
config = { 'disabled' => true }
|
@@ -51,6 +51,25 @@ module Bolt
|
|
51
51
|
NoopClient.new
|
52
52
|
end
|
53
53
|
|
54
|
+
def self.config_path(logger)
|
55
|
+
path = File.expand_path(File.join('~', '.puppetlabs', 'etc', 'bolt', 'analytics.yaml'))
|
56
|
+
old_path = File.expand_path(File.join('~', '.puppetlabs', 'bolt', 'analytics.yaml'))
|
57
|
+
|
58
|
+
if File.exist?(path)
|
59
|
+
if File.exist?(old_path)
|
60
|
+
message = "Detected analytics configuration files at '#{old_path}' and '#{path}'. Loading "\
|
61
|
+
"analytics configuration from '#{path}'."
|
62
|
+
logger.warn(message)
|
63
|
+
end
|
64
|
+
|
65
|
+
path
|
66
|
+
elsif File.exist?(old_path)
|
67
|
+
old_path
|
68
|
+
else
|
69
|
+
path
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
54
73
|
def self.load_config(filename, logger)
|
55
74
|
if File.exist?(filename)
|
56
75
|
YAML.load_file(filename)
|
@@ -59,7 +78,7 @@ module Bolt
|
|
59
78
|
logger.warn <<~ANALYTICS
|
60
79
|
Bolt collects data about how you use it. You can opt out of providing this data.
|
61
80
|
|
62
|
-
To disable analytics data collection, add this line to ~/.puppetlabs/bolt/analytics.yaml :
|
81
|
+
To disable analytics data collection, add this line to ~/.puppetlabs/etc/bolt/analytics.yaml :
|
63
82
|
disabled: true
|
64
83
|
|
65
84
|
Read more about what data Bolt collects and why here:
|
data/lib/bolt/applicator.rb
CHANGED
@@ -34,6 +34,8 @@ module Bolt
|
|
34
34
|
search_dirs << mod.plugins if mod.plugins?
|
35
35
|
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
36
36
|
search_dirs << mod.files if mod.files?
|
37
|
+
type_files = "#{mod.path}/types"
|
38
|
+
search_dirs << type_files if File.exist?(type_files)
|
37
39
|
search_dirs
|
38
40
|
end
|
39
41
|
end
|
@@ -181,7 +183,7 @@ module Bolt
|
|
181
183
|
rich_data: true,
|
182
184
|
symbol_as_string: true,
|
183
185
|
type_by_reference: true,
|
184
|
-
local_reference:
|
186
|
+
local_reference: true)
|
185
187
|
|
186
188
|
scope = {
|
187
189
|
code_ast: ast,
|
data/lib/bolt/apply_result.rb
CHANGED
@@ -57,7 +57,7 @@ module Bolt
|
|
57
57
|
msg = "Report result contains an '_output' key. Catalog application may have printed extraneous output to stdout: #{result['_output']}"
|
58
58
|
# rubocop:enable Layout/LineLength
|
59
59
|
else
|
60
|
-
msg = "Report did not contain all expected keys missing: #{missing_keys.join('
|
60
|
+
msg = "Report did not contain all expected keys missing: #{missing_keys.join(', ')}"
|
61
61
|
end
|
62
62
|
|
63
63
|
{ 'msg' => msg,
|