bolt 2.20.0 → 2.24.1
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 +3 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +6 -0
- data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +12 -6
- data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +35 -0
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +1 -1
- data/exe/bolt +1 -0
- data/guides/inventory.txt +19 -0
- data/guides/project.txt +22 -0
- data/lib/bolt/analytics.rb +5 -5
- data/lib/bolt/applicator.rb +4 -3
- data/lib/bolt/bolt_option_parser.rb +75 -25
- data/lib/bolt/catalog.rb +9 -1
- data/lib/bolt/cli.rb +226 -73
- data/lib/bolt/config.rb +7 -0
- data/lib/bolt/config/options.rb +4 -4
- data/lib/bolt/executor.rb +16 -8
- data/lib/bolt/inventory/group.rb +3 -3
- data/lib/bolt/logger.rb +3 -4
- data/lib/bolt/module.rb +2 -1
- data/lib/bolt/outputter.rb +56 -0
- data/lib/bolt/outputter/human.rb +10 -9
- data/lib/bolt/outputter/json.rb +11 -4
- data/lib/bolt/outputter/logger.rb +2 -2
- data/lib/bolt/outputter/rainbow.rb +15 -0
- data/lib/bolt/pal.rb +5 -9
- data/lib/bolt/pal/yaml_plan/evaluator.rb +4 -0
- data/lib/bolt/pal/yaml_plan/step.rb +14 -1
- data/lib/bolt/pal/yaml_plan/step/message.rb +30 -0
- data/lib/bolt/pal/yaml_plan/transpiler.rb +11 -3
- data/lib/bolt/plugin/prompt.rb +3 -3
- data/lib/bolt/project.rb +6 -4
- data/lib/bolt/project_migrate.rb +138 -0
- data/lib/bolt/shell/bash.rb +7 -7
- data/lib/bolt/transport/docker/connection.rb +9 -9
- data/lib/bolt/transport/local/connection.rb +2 -2
- data/lib/bolt/transport/orch.rb +3 -3
- data/lib/bolt/transport/ssh/connection.rb +5 -5
- data/lib/bolt/transport/ssh/exec_connection.rb +4 -4
- data/lib/bolt/transport/winrm/connection.rb +17 -8
- data/lib/bolt/util.rb +1 -1
- data/lib/bolt/util/puppet_log_level.rb +4 -3
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/base_config.rb +1 -1
- data/lib/bolt_server/pe/pal.rb +1 -1
- data/lib/bolt_server/transport_app.rb +76 -0
- data/lib/bolt_spec/plans.rb +1 -1
- data/lib/bolt_spec/plans/action_stubs.rb +1 -1
- data/libexec/apply_catalog.rb +2 -2
- data/libexec/bolt_catalog +1 -1
- data/libexec/custom_facts.rb +1 -1
- data/libexec/query_resources.rb +1 -1
- data/modules/secure_env_vars/plans/init.pp +20 -0
- metadata +8 -2
@@ -19,7 +19,7 @@ module Bolt
|
|
19
19
|
# Build set of extensions from extensions config as well as interpreters
|
20
20
|
|
21
21
|
@logger = Logging.logger[@target.safe_name]
|
22
|
-
logger.
|
22
|
+
logger.trace("Initializing winrm connection to #{@target.safe_name}")
|
23
23
|
@transport_logger = transport_logger
|
24
24
|
end
|
25
25
|
|
@@ -55,7 +55,7 @@ module Bolt
|
|
55
55
|
|
56
56
|
@session = @connection.shell(:powershell)
|
57
57
|
@session.run('$PSVersionTable.PSVersion')
|
58
|
-
@logger.
|
58
|
+
@logger.trace { "Opened session" }
|
59
59
|
end
|
60
60
|
rescue Timeout::Error
|
61
61
|
# If we're using the default port with SSL, a timeout probably means the
|
@@ -97,11 +97,11 @@ module Bolt
|
|
97
97
|
def disconnect
|
98
98
|
@session&.close
|
99
99
|
@client&.disconnect!
|
100
|
-
@logger.
|
100
|
+
@logger.trace { "Closed session" }
|
101
101
|
end
|
102
102
|
|
103
103
|
def execute(command)
|
104
|
-
@logger.
|
104
|
+
@logger.trace { "Executing command: #{command}" }
|
105
105
|
|
106
106
|
inp = StringIO.new
|
107
107
|
# This transport doesn't accept stdin, so close the stream to ensure
|
@@ -111,12 +111,21 @@ module Bolt
|
|
111
111
|
out_rd, out_wr = IO.pipe('UTF-8')
|
112
112
|
err_rd, err_wr = IO.pipe('UTF-8')
|
113
113
|
th = Thread.new do
|
114
|
+
# By default, any exception raised in a thread will be reported to
|
115
|
+
# stderr as a stacktrace. Since we know these errors are going to
|
116
|
+
# propagate to the main thread via the shell, there's no chance
|
117
|
+
# they will be unhandled, so the default stack trace is unneeded.
|
118
|
+
Thread.current.report_on_exception = false
|
114
119
|
result = @session.run(command)
|
115
120
|
out_wr << result.stdout
|
116
121
|
err_wr << result.stderr
|
117
122
|
out_wr.close
|
118
123
|
err_wr.close
|
119
124
|
result.exitcode
|
125
|
+
ensure
|
126
|
+
# Close the streams to avoid the caller deadlocking
|
127
|
+
out_wr.close
|
128
|
+
err_wr.close
|
120
129
|
end
|
121
130
|
|
122
131
|
[inp, out_rd, err_rd, th]
|
@@ -125,12 +134,12 @@ module Bolt
|
|
125
134
|
"with 'ulimit -n 1024'. See https://puppet.com/docs/bolt/latest/bolt_known_issues.html for details."
|
126
135
|
raise Bolt::Error.new(msg, 'bolt/too-many-files')
|
127
136
|
rescue StandardError
|
128
|
-
@logger.
|
137
|
+
@logger.trace { "Command aborted" }
|
129
138
|
raise
|
130
139
|
end
|
131
140
|
|
132
141
|
def upload_file(source, destination)
|
133
|
-
@logger.
|
142
|
+
@logger.trace { "Uploading #{source} to #{destination}" }
|
134
143
|
if target.options['file-protocol'] == 'smb'
|
135
144
|
upload_file_smb(source, destination)
|
136
145
|
else
|
@@ -176,7 +185,7 @@ module Bolt
|
|
176
185
|
end
|
177
186
|
|
178
187
|
def download_file(source, destination, download)
|
179
|
-
@logger.
|
188
|
+
@logger.trace { "Downloading #{source} to #{destination}" }
|
180
189
|
if target.options['file-protocol'] == 'smb'
|
181
190
|
download_file_smb(source, destination)
|
182
191
|
else
|
@@ -248,7 +257,7 @@ module Bolt
|
|
248
257
|
status = @client.login
|
249
258
|
case status
|
250
259
|
when WindowsError::NTStatus::STATUS_SUCCESS
|
251
|
-
@logger.
|
260
|
+
@logger.trace { "Connected to #{@client.dns_host_name}" }
|
252
261
|
when WindowsError::NTStatus::STATUS_LOGON_FAILURE
|
253
262
|
raise Bolt::Node::ConnectError.new(
|
254
263
|
"SMB authentication failed for #{target.safe_name}",
|
data/lib/bolt/util.rb
CHANGED
@@ -13,7 +13,7 @@ module Bolt
|
|
13
13
|
msg = "Invalid content for #{file_name} file: #{path} should be a Hash or empty, not #{content.class}"
|
14
14
|
raise Bolt::FileError.new(msg, path)
|
15
15
|
end
|
16
|
-
logger.
|
16
|
+
logger.trace("Loaded #{file_name} from #{path}")
|
17
17
|
content
|
18
18
|
rescue Errno::ENOENT
|
19
19
|
raise Bolt::FileError.new("Could not read #{file_name} file: #{path}", path)
|
@@ -4,9 +4,10 @@ module Bolt
|
|
4
4
|
module Util
|
5
5
|
module PuppetLogLevel
|
6
6
|
MAPPING = {
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
# Demote Puppet's logs by one level, since Puppet is an implementation detail of Bolt
|
8
|
+
debug: :trace,
|
9
|
+
info: :debug,
|
10
|
+
notice: :info,
|
10
11
|
warning: :warn,
|
11
12
|
err: :error,
|
12
13
|
# The following are used by Puppet functions of the same name, and are all treated as
|
data/lib/bolt/version.rb
CHANGED
data/lib/bolt_server/pe/pal.rb
CHANGED
@@ -58,7 +58,7 @@ module BoltServer
|
|
58
58
|
# Bolt::PAL::MODULES_PATH which would be more complex if we tried to use @modulepath since
|
59
59
|
# we need to append our modulepaths and exclude modules shiped in bolt gem code
|
60
60
|
modulepath_dirs = environment.modulepath
|
61
|
-
@
|
61
|
+
@user_modulepath = modulepath_dirs
|
62
62
|
@modulepath = [PE_BOLTLIB_PATH, Bolt::PAL::BOLTLIB_PATH, *modulepath_dirs]
|
63
63
|
end
|
64
64
|
end
|
@@ -221,6 +221,56 @@ module BoltServer
|
|
221
221
|
plan_info
|
222
222
|
end
|
223
223
|
|
224
|
+
def build_puppetserver_uri(file_identifier, module_name, environment)
|
225
|
+
segments = file_identifier.split('/', 3)
|
226
|
+
if segments.size == 1
|
227
|
+
{
|
228
|
+
'path' => "/puppet/v3/file_content/tasks/#{module_name}/#{file_identifier}",
|
229
|
+
'params' => {
|
230
|
+
'environment' => environment
|
231
|
+
}
|
232
|
+
}
|
233
|
+
else
|
234
|
+
module_segment, mount_segment, name_segment = *segments
|
235
|
+
{
|
236
|
+
'path' => case mount_segment
|
237
|
+
when 'files'
|
238
|
+
"/puppet/v3/file_content/modules/#{module_segment}/#{name_segment}"
|
239
|
+
when 'tasks'
|
240
|
+
"/puppet/v3/file_content/tasks/#{module_segment}/#{name_segment}"
|
241
|
+
when 'lib'
|
242
|
+
"/puppet/v3/file_content/plugins/#{name_segment}"
|
243
|
+
end,
|
244
|
+
'params' => {
|
245
|
+
'environment' => environment
|
246
|
+
}
|
247
|
+
}
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def pe_task_info(pal, module_name, task_name, environment)
|
252
|
+
# Handle case where task name is simply module name with special `init` task
|
253
|
+
task_name = if task_name == 'init' || task_name.nil?
|
254
|
+
module_name
|
255
|
+
else
|
256
|
+
"#{module_name}::#{task_name}"
|
257
|
+
end
|
258
|
+
task = pal.get_task(task_name)
|
259
|
+
files = task.files.map do |file_hash|
|
260
|
+
{
|
261
|
+
'filename' => file_hash['name'],
|
262
|
+
'sha256' => Digest::SHA256.hexdigest(File.read(file_hash['path'])),
|
263
|
+
'size_bytes' => File.size(file_hash['path']),
|
264
|
+
'uri' => build_puppetserver_uri(file_hash['name'], module_name, environment)
|
265
|
+
}
|
266
|
+
end
|
267
|
+
{
|
268
|
+
'metadata' => task.metadata,
|
269
|
+
'name' => task.name,
|
270
|
+
'files' => files
|
271
|
+
}
|
272
|
+
end
|
273
|
+
|
224
274
|
get '/' do
|
225
275
|
200
|
226
276
|
end
|
@@ -351,6 +401,16 @@ module BoltServer
|
|
351
401
|
end
|
352
402
|
end
|
353
403
|
|
404
|
+
# Fetches the metadata for a single task
|
405
|
+
#
|
406
|
+
# @param environment [String] the environment to fetch the task from
|
407
|
+
get '/tasks/:module_name/:task_name' do
|
408
|
+
in_pe_pal_env(params['environment']) do |pal|
|
409
|
+
task_info = pe_task_info(pal, params[:module_name], params[:task_name], params['environment'])
|
410
|
+
[200, task_info.to_json]
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
354
414
|
# Fetches the list of plans for an environment, optionally fetching all metadata for each plan
|
355
415
|
#
|
356
416
|
# @param environment [String] the environment to fetch the list of plans from
|
@@ -375,6 +435,22 @@ module BoltServer
|
|
375
435
|
end
|
376
436
|
end
|
377
437
|
|
438
|
+
# Fetches the list of tasks for an environment
|
439
|
+
#
|
440
|
+
# @param environment [String] the environment to fetch the list of tasks from
|
441
|
+
get '/tasks' do
|
442
|
+
in_pe_pal_env(params['environment']) do |pal|
|
443
|
+
tasks = pal.list_tasks
|
444
|
+
tasks_response = tasks.map { |task_name, _description| { 'name' => task_name } }.to_json
|
445
|
+
|
446
|
+
# We structure this array of tasks to be an array of hashes so that it matches the structure
|
447
|
+
# returned by the puppetserver API that serves data like this. Structuring the output this way
|
448
|
+
# makes switching between puppetserver and bolt-server easier, which makes changes to switch
|
449
|
+
# to bolt-server smaller/simpler.
|
450
|
+
[200, tasks_response]
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
378
454
|
error 404 do
|
379
455
|
err = Bolt::Error.new("Could not find route #{request.path}",
|
380
456
|
'boltserver/not-found')
|
data/lib/bolt_spec/plans.rb
CHANGED
@@ -206,7 +206,7 @@ module BoltSpec
|
|
206
206
|
Puppet[:tasks] = true
|
207
207
|
|
208
208
|
# Ensure logger is initialized with Puppet levels so 'notice' works when running plan specs.
|
209
|
-
Logging.init :debug, :info, :notice, :warn, :error, :fatal, :any
|
209
|
+
Logging.init :trace, :debug, :info, :notice, :warn, :error, :fatal, :any
|
210
210
|
end
|
211
211
|
|
212
212
|
# Provided as a class so expectations can be placed on it.
|
@@ -177,7 +177,7 @@ module BoltSpec
|
|
177
177
|
if data['msg'] && data['kind'] && (data.keys - %w[msg kind details issue_code]).empty?
|
178
178
|
@data[:default] = clazz.new(data['msg'], data['kind'], data['details'], data['issue_code'])
|
179
179
|
else
|
180
|
-
|
180
|
+
$stderr.puts "In the future 'error_with()' may require msg and kind, and " \
|
181
181
|
"optionally accept only details and issue_code."
|
182
182
|
@data[:default] = data
|
183
183
|
end
|
data/libexec/apply_catalog.rb
CHANGED
@@ -9,7 +9,7 @@ require 'puppet/module_tool/tar'
|
|
9
9
|
require 'securerandom'
|
10
10
|
require 'tempfile'
|
11
11
|
|
12
|
-
args = JSON.parse(ARGV[0] ? File.read(ARGV[0]) :
|
12
|
+
args = JSON.parse(ARGV[0] ? File.read(ARGV[0]) : $stdin.read)
|
13
13
|
|
14
14
|
# Create temporary directories for all core Puppet settings so we don't clobber
|
15
15
|
# existing state or read from puppet.conf. Also create a temporary modulepath.
|
@@ -110,7 +110,7 @@ ensure
|
|
110
110
|
begin
|
111
111
|
FileUtils.remove_dir(puppet_root)
|
112
112
|
rescue Errno::ENOTEMPTY => e
|
113
|
-
|
113
|
+
$stderr.puts("Could not cleanup temporary directory: #{e}")
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
data/libexec/bolt_catalog
CHANGED
data/libexec/custom_facts.rb
CHANGED
data/libexec/query_resources.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
plan secure_env_vars(
|
2
|
+
TargetSpec $targets,
|
3
|
+
Optional[String] $command = undef,
|
4
|
+
Optional[String] $script = undef
|
5
|
+
) {
|
6
|
+
$env_vars = parsejson(system::env('BOLT_ENV_VARS'))
|
7
|
+
unless type($command) == Undef or type($script) == Undef {
|
8
|
+
fail_plan('Cannot specify both script and command for secure_env_vars')
|
9
|
+
}
|
10
|
+
|
11
|
+
return if $command {
|
12
|
+
run_command($command, $targets, '_env_vars' => $env_vars)
|
13
|
+
}
|
14
|
+
elsif $script {
|
15
|
+
run_script($script, $targets, '_env_vars' => $env_vars)
|
16
|
+
}
|
17
|
+
else {
|
18
|
+
fail_plan('Must specify either script or command for secure_env_vars')
|
19
|
+
}
|
20
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bolt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.24.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -427,6 +427,7 @@ files:
|
|
427
427
|
- bolt-modules/boltlib/types/targetspec.pp
|
428
428
|
- bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb
|
429
429
|
- bolt-modules/ctrl/lib/puppet/functions/ctrl/sleep.rb
|
430
|
+
- bolt-modules/dir/lib/puppet/functions/dir/children.rb
|
430
431
|
- bolt-modules/file/lib/puppet/functions/file/exists.rb
|
431
432
|
- bolt-modules/file/lib/puppet/functions/file/join.rb
|
432
433
|
- bolt-modules/file/lib/puppet/functions/file/read.rb
|
@@ -436,6 +437,8 @@ files:
|
|
436
437
|
- bolt-modules/prompt/lib/puppet/functions/prompt.rb
|
437
438
|
- bolt-modules/system/lib/puppet/functions/system/env.rb
|
438
439
|
- exe/bolt
|
440
|
+
- guides/inventory.txt
|
441
|
+
- guides/project.txt
|
439
442
|
- lib/bolt.rb
|
440
443
|
- lib/bolt/analytics.rb
|
441
444
|
- lib/bolt/applicator.rb
|
@@ -482,6 +485,7 @@ files:
|
|
482
485
|
- lib/bolt/pal/yaml_plan/step/command.rb
|
483
486
|
- lib/bolt/pal/yaml_plan/step/download.rb
|
484
487
|
- lib/bolt/pal/yaml_plan/step/eval.rb
|
488
|
+
- lib/bolt/pal/yaml_plan/step/message.rb
|
485
489
|
- lib/bolt/pal/yaml_plan/step/plan.rb
|
486
490
|
- lib/bolt/pal/yaml_plan/step/resources.rb
|
487
491
|
- lib/bolt/pal/yaml_plan/step/script.rb
|
@@ -496,6 +500,7 @@ files:
|
|
496
500
|
- lib/bolt/plugin/puppetdb.rb
|
497
501
|
- lib/bolt/plugin/task.rb
|
498
502
|
- lib/bolt/project.rb
|
503
|
+
- lib/bolt/project_migrate.rb
|
499
504
|
- lib/bolt/puppetdb.rb
|
500
505
|
- lib/bolt/puppetdb/client.rb
|
501
506
|
- lib/bolt/puppetdb/config.rb
|
@@ -576,6 +581,7 @@ files:
|
|
576
581
|
- modules/canary/lib/puppet/functions/canary/skip.rb
|
577
582
|
- modules/canary/plans/init.pp
|
578
583
|
- modules/puppetdb_fact/plans/init.pp
|
584
|
+
- modules/secure_env_vars/plans/init.pp
|
579
585
|
homepage: https://github.com/puppetlabs/bolt
|
580
586
|
licenses:
|
581
587
|
- Apache-2.0
|