bolt 2.18.0 → 2.23.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.

Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +3 -1
  3. data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +123 -0
  4. data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +6 -0
  5. data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +12 -6
  6. data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +35 -0
  7. data/bolt-modules/out/lib/puppet/functions/out/message.rb +1 -1
  8. data/lib/bolt/analytics.rb +1 -1
  9. data/lib/bolt/bolt_option_parser.rb +74 -24
  10. data/lib/bolt/catalog.rb +12 -3
  11. data/lib/bolt/cli.rb +305 -108
  12. data/lib/bolt/config.rb +18 -10
  13. data/lib/bolt/config/options.rb +14 -0
  14. data/lib/bolt/executor.rb +26 -5
  15. data/lib/bolt/inventory/group.rb +3 -2
  16. data/lib/bolt/inventory/inventory.rb +4 -3
  17. data/lib/bolt/logger.rb +9 -0
  18. data/lib/bolt/module.rb +2 -1
  19. data/lib/bolt/outputter.rb +56 -0
  20. data/lib/bolt/outputter/human.rb +0 -9
  21. data/lib/bolt/outputter/json.rb +0 -4
  22. data/lib/bolt/outputter/rainbow.rb +9 -2
  23. data/lib/bolt/pal.rb +11 -9
  24. data/lib/bolt/pal/yaml_plan/evaluator.rb +23 -2
  25. data/lib/bolt/pal/yaml_plan/step.rb +24 -2
  26. data/lib/bolt/pal/yaml_plan/step/download.rb +38 -0
  27. data/lib/bolt/pal/yaml_plan/step/message.rb +30 -0
  28. data/lib/bolt/pal/yaml_plan/step/upload.rb +3 -3
  29. data/lib/bolt/plugin/module.rb +2 -4
  30. data/lib/bolt/plugin/prompt.rb +3 -3
  31. data/lib/bolt/plugin/puppetdb.rb +3 -2
  32. data/lib/bolt/project.rb +14 -9
  33. data/lib/bolt/puppetdb/client.rb +2 -0
  34. data/lib/bolt/puppetdb/config.rb +16 -0
  35. data/lib/bolt/result.rb +7 -0
  36. data/lib/bolt/shell/bash.rb +24 -4
  37. data/lib/bolt/shell/powershell.rb +10 -4
  38. data/lib/bolt/transport/base.rb +24 -0
  39. data/lib/bolt/transport/docker.rb +8 -0
  40. data/lib/bolt/transport/docker/connection.rb +20 -2
  41. data/lib/bolt/transport/local/connection.rb +14 -1
  42. data/lib/bolt/transport/orch.rb +12 -0
  43. data/lib/bolt/transport/simple.rb +6 -0
  44. data/lib/bolt/transport/ssh/connection.rb +9 -1
  45. data/lib/bolt/transport/ssh/exec_connection.rb +22 -1
  46. data/lib/bolt/transport/winrm/connection.rb +118 -8
  47. data/lib/bolt/util.rb +26 -11
  48. data/lib/bolt/version.rb +1 -1
  49. data/lib/bolt_server/pe/pal.rb +1 -1
  50. data/lib/bolt_server/transport_app.rb +3 -2
  51. data/lib/bolt_spec/bolt_context.rb +7 -2
  52. data/lib/bolt_spec/plans.rb +15 -2
  53. data/lib/bolt_spec/plans/action_stubs.rb +3 -2
  54. data/lib/bolt_spec/plans/action_stubs/download_stub.rb +66 -0
  55. data/lib/bolt_spec/plans/mock_executor.rb +14 -1
  56. data/lib/bolt_spec/run.rb +22 -0
  57. data/libexec/apply_catalog.rb +2 -2
  58. data/libexec/bolt_catalog +4 -3
  59. data/libexec/custom_facts.rb +1 -1
  60. data/libexec/query_resources.rb +1 -1
  61. data/modules/secure_env_vars/plans/init.pp +20 -0
  62. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87eb513700afc2d9fefa9f2497e8718f0e14e511ea2004c59eecfcb19e41bdbc
4
- data.tar.gz: 499d4c8a1a3c0d4b883d83f6478019467a44999beba83712ce49a30ee2ff1fc8
3
+ metadata.gz: f58ca99a18fca1c109d531c61b55bcee45d73c14e55a074575ffaaf1d9f40aac
4
+ data.tar.gz: ea55e4c9b9ba4ccd8afed70a6c62c603a119a46f406b573f429bd2cd89983672
5
5
  SHA512:
6
- metadata.gz: 6046f666fe9bccc4df2a70b191582b14b834063caf31987c1131e7e7c57ac9280e0bf76d719f9b82f27f5de7205b744a2dd3d485f53e9aa867661b824a5b0945
7
- data.tar.gz: fc77aa2acd93b4aab739f468a2aa6a6a2da2c9c10bbc4927005f60aeb20148ecb29884d6f2c6cf86bf84d76af276a55f1a8588734157444ab5844c0b9d9878c9
6
+ metadata.gz: dc8845ebe2a171ce79b704c474594a9679e7078feaca324eb7f26b88e9e903de43361a4dbaa357de3cf47be4ae72b4db4690a76e0910c9595f52aab384768fbc
7
+ data.tar.gz: 60b30a31debf0d031902d8df21372b2524246ee98749eeccfd588c00b3458bcb9c0ed2a1fbdeab266cce86332537bde1005aead37fece867d440d88989c2486d
data/Puppetfile CHANGED
@@ -5,7 +5,7 @@ forge "http://forge.puppetlabs.com"
5
5
  moduledir File.join(File.dirname(__FILE__), 'modules')
6
6
 
7
7
  # Core modules used by 'apply'
8
- mod 'puppetlabs-service', '1.2.0'
8
+ mod 'puppetlabs-service', '1.3.0'
9
9
  mod 'puppetlabs-puppet_agent', '3.2.0'
10
10
  mod 'puppetlabs-facts', '1.0.0'
11
11
 
@@ -28,6 +28,7 @@ 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'
31
+ mod 'puppetlabs-stdlib', '6.3.0'
31
32
 
32
33
  # Plugin modules
33
34
  mod 'puppetlabs-aws_inventory', '0.5.0'
@@ -42,3 +43,4 @@ mod 'puppetlabs-yaml', '0.2.0'
42
43
  mod 'canary', local: true
43
44
  mod 'aggregate', local: true
44
45
  mod 'puppetdb_fact', local: true
46
+ mod 'secure_env_vars', local: true
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+ require 'bolt/error'
5
+
6
+ # Downloads the given file or directory from the given set of targets and saves it to a directory
7
+ # matching the target's name under the given destination directory. Returns the result from each
8
+ # download. This does nothing if the list of targets is empty.
9
+ #
10
+ # > **Note:** Existing content in the destination directory is deleted before downloading from
11
+ # > the targets.
12
+ #
13
+ # > **Note:** Not available in apply block
14
+ Puppet::Functions.create_function(:download_file, Puppet::Functions::InternalFunction) do
15
+ # Download a file or directory.
16
+ # @param source The absolute path to the file or directory on the target(s).
17
+ # @param destination The relative path to the destination directory on the local system. Expands
18
+ # relative to `<project>/downloads/`.
19
+ # @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
20
+ # @param options A hash of additional options.
21
+ # @option options [Boolean] _catch_errors Whether to catch raised errors.
22
+ # @option options [String] _run_as User to run as using privilege escalation.
23
+ # @return A list of results, one entry per target, with the path to the downloaded file under the
24
+ # `path` key.
25
+ # @example Download a file from multiple Linux targets to a destination directory
26
+ # download_file('/etc/ssh/ssh_config', '~/Downloads', $targets)
27
+ # @example Download a directory from multiple Linux targets to a project downloads directory
28
+ # download_file('/etc/ssh', 'ssh', $targets)
29
+ # @example Download a file from multiple Linux targets and compare its contents to a local file
30
+ # $results = download_file($source, $destination, $targets)
31
+ #
32
+ # $local_content = file::read($source)
33
+ #
34
+ # $mismatched_files = $results.filter |$result| {
35
+ # $remote_content = file::read($result['path'])
36
+ # $remote_content == $local_content
37
+ # }
38
+ dispatch :download_file do
39
+ param 'String[1]', :source
40
+ param 'String[1]', :destination
41
+ param 'Boltlib::TargetSpec', :targets
42
+ optional_param 'Hash[String[1], Any]', :options
43
+ return_type 'ResultSet'
44
+ end
45
+
46
+ # Download a file or directory, logging the provided description.
47
+ # @param source The absolute path to the file or directory on the target(s).
48
+ # @param destination The relative path to the destination directory on the local system. Expands
49
+ # relative to `<project>/downloads/`.
50
+ # @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
51
+ # @param description A description to be output when calling this function.
52
+ # @param options A hash of additional options.
53
+ # @option options [Boolean] _catch_errors Whether to catch raised errors.
54
+ # @option options [String] _run_as User to run as using privilege escalation.
55
+ # @return A list of results, one entry per target, with the path to the downloaded file under the
56
+ # `path` key.
57
+ # @example Download a file from multiple Linux targets to a destination directory
58
+ # download_file('/etc/ssh/ssh_config', '~/Downloads', $targets, 'Downloading remote SSH config')
59
+ dispatch :download_file_with_description do
60
+ param 'String[1]', :source
61
+ param 'String[1]', :destination
62
+ param 'Boltlib::TargetSpec', :targets
63
+ param 'String', :description
64
+ optional_param 'Hash[String[1], Any]', :options
65
+ return_type 'ResultSet'
66
+ end
67
+
68
+ def download_file(source, destination, targets, options = {})
69
+ download_file_with_description(source, destination, targets, nil, options)
70
+ end
71
+
72
+ def download_file_with_description(source, destination, targets, description = nil, options = {})
73
+ unless Puppet[:tasks]
74
+ raise Puppet::ParseErrorWithIssue
75
+ .from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'download_file')
76
+ end
77
+
78
+ options = options.select { |opt| opt.start_with?('_') }.transform_keys { |k| k.sub(/^_/, '').to_sym }
79
+ options[:description] = description if description
80
+
81
+ executor = Puppet.lookup(:bolt_executor)
82
+ inventory = Puppet.lookup(:bolt_inventory)
83
+
84
+ if (destination = destination.strip).empty?
85
+ raise Bolt::ValidationError, "Destination cannot be an empty string"
86
+ end
87
+
88
+ if (destination = Pathname.new(destination)).absolute?
89
+ raise Bolt::ValidationError, "Destination must be a relative path, received absolute path #{destination}"
90
+ end
91
+
92
+ # Prevent path traversal so downloads can't be saved outside of the project downloads directory
93
+ if (destination.each_filename.to_a & %w[. ..]).any?
94
+ raise Bolt::ValidationError, "Destination must not include path traversal, received #{destination}"
95
+ end
96
+
97
+ # Paths expand relative to the default downloads directory for the project
98
+ # e.g. ~/.puppetlabs/bolt/downloads/
99
+ destination = Puppet.lookup(:bolt_project_data).downloads + destination
100
+
101
+ # If the destination directory already exists, delete any existing contents
102
+ if Dir.exist?(destination)
103
+ FileUtils.rm_r(Dir.glob(destination + '*'), secure: true)
104
+ end
105
+
106
+ # Send Analytics Report
107
+ executor.report_function_call(self.class.name)
108
+
109
+ # Ensure that that given targets are all Target instances
110
+ targets = inventory.get_targets(targets)
111
+ if targets.empty?
112
+ call_function('debug', "Simulating file download of '#{source}' - no targets given - no action taken")
113
+ r = Bolt::ResultSet.new([])
114
+ else
115
+ r = executor.download_file(targets, source, destination, options)
116
+ end
117
+
118
+ if !r.ok && !options[:catch_errors]
119
+ raise Bolt::RunFailure.new(r, 'download_file', source)
120
+ end
121
+ r
122
+ end
123
+ end
@@ -11,6 +11,9 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
11
11
  # @param args A hash of arguments to the plan. Can also include additional options.
12
12
  # @option args [Boolean] _catch_errors Whether to catch raised errors.
13
13
  # @option args [String] _run_as User to run as using privilege escalation.
14
+ # This option sets the [run-as user](privilege_escalation.md) for all
15
+ # targets whenever Bolt connects to a target. This is set for all functions
16
+ # in the called plan, including `run_plan()`.
14
17
  # @return [PlanResult] The result of running the plan. Undef if plan does not explicitly return results.
15
18
  # @example Run a plan
16
19
  # run_plan('canary', 'command' => 'false', 'targets' => $targets, '_catch_errors' => true)
@@ -31,6 +34,9 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
31
34
  # @param args A hash of arguments to the plan. Can also include additional options.
32
35
  # @option args [Boolean] _catch_errors Whether to catch raised errors.
33
36
  # @option args [String] _run_as User to run as using privilege escalation.
37
+ # This option sets the [run-as user](privilege_escalation.md) for all
38
+ # targets whenever Bolt connects to a target. This is set for all functions
39
+ # in the called plan, including `run_plan()`.
34
40
  # @return [PlanResult] The result of running the plan. Undef if plan does not explicitly return results.
35
41
  # @example Run a plan
36
42
  # run_plan('canary', $targets, 'command' => 'false')
@@ -4,30 +4,36 @@
4
4
  Puppet::Functions.create_function(:'ctrl::do_until') do
5
5
  # @param options A hash of additional options.
6
6
  # @option options [Numeric] limit The number of times to repeat the block.
7
+ # @option options [Numeric] interval The number of seconds to wait before repeating the block.
7
8
  # @example Run a task until it succeeds
8
9
  # ctrl::do_until() || {
9
- # run_task('test', $target, _catch_errors => true).ok()
10
+ # run_task('test', $target, '_catch_errors' => true).ok()
10
11
  # }
11
- #
12
12
  # @example Run a task until it succeeds or fails 10 times
13
13
  # ctrl::do_until('limit' => 10) || {
14
- # run_task('test', $target, _catch_errors => true).ok()
14
+ # run_task('test', $target, '_catch_errors' => true).ok()
15
+ # }
16
+ # @example Run a task and wait 10 seconds before running it again
17
+ # ctrl::do_until('interval' => 10) || {
18
+ # run_task('test', $target, '_catch_errors' => true).ok()
15
19
  # }
16
- #
17
20
  dispatch :do_until do
18
21
  optional_param 'Hash[String[1], Any]', :options
19
22
  block_param
20
23
  end
21
24
 
22
- def do_until(options = { 'limit' => 0 })
25
+ def do_until(options = {})
23
26
  # Send Analytics Report
24
27
  Puppet.lookup(:bolt_executor) {}&.report_function_call(self.class.name)
25
28
 
26
- limit = options['limit']
29
+ limit = options['limit'] || 0
30
+ interval = options['interval']
31
+
27
32
  i = 0
28
33
  until (x = yield)
29
34
  i += 1
30
35
  break if limit != 0 && i >= limit
36
+ Kernel.sleep(interval) if interval
31
37
  end
32
38
  x
33
39
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+
5
+ # Returns an array containing all of the filenames except for "." and ".." in the given directory.
6
+ Puppet::Functions.create_function(:'dir::children', Puppet::Functions::InternalFunction) do
7
+ # @param dirname Absolute path or Puppet module name.
8
+ # @return Array of files in the given directory.
9
+ # @example List filenames from an absolute path.
10
+ # dir::children('/home/user/subdir/')
11
+ # @example List filenames from a Puppet file path.
12
+ # dir::children('puppet_agent')
13
+ dispatch :children do
14
+ scope_param
15
+ required_param 'String', :dirname
16
+ return_type 'Array'
17
+ end
18
+
19
+ def children(scope, dirname)
20
+ # Send Analytics Report
21
+ Puppet.lookup(:bolt_executor) {}&.report_function_call(self.class.name)
22
+ modname, subpath = dirname.split(File::SEPARATOR, 2)
23
+ mod_path = scope.compiler.environment.module(modname)&.path
24
+
25
+ full_mod_path = File.join(mod_path, subpath || '') if mod_path
26
+
27
+ # Expand relative to the project directory if path is relative
28
+ project = Puppet.lookup(:bolt_project_data)
29
+ pathname = Pathname.new(dirname)
30
+ full_dir = pathname.absolute? ? dirname : File.expand_path(File.join(project.path, dirname))
31
+
32
+ # Sort for testability
33
+ Dir.children(full_mod_path || full_dir).sort
34
+ end
35
+ end
@@ -12,7 +12,7 @@ Puppet::Functions.create_function(:'out::message') do
12
12
  # @example Print a message
13
13
  # out::message('Something went wrong')
14
14
  dispatch :output_message do
15
- param 'String', :message
15
+ param 'Any', :message
16
16
  return_type 'Undef'
17
17
  end
18
18
 
@@ -72,7 +72,7 @@ module Bolt
72
72
 
73
73
  def self.load_config(filename, logger)
74
74
  if File.exist?(filename)
75
- YAML.load_file(filename)
75
+ Bolt::Util.read_optional_yaml_hash(filename, 'analytics')
76
76
  else
77
77
  unless ENV['BOLT_DISABLE_ANALYTICS']
78
78
  logger.warn <<~ANALYTICS
@@ -25,7 +25,7 @@ module Bolt
25
25
  when 'command'
26
26
  case action
27
27
  when 'run'
28
- { flags: ACTION_OPTS,
28
+ { flags: ACTION_OPTS + %w[env-var],
29
29
  banner: COMMAND_RUN_HELP }
30
30
  else
31
31
  { flags: OPTIONS[:global],
@@ -36,6 +36,9 @@ module Bolt
36
36
  when 'upload'
37
37
  { flags: ACTION_OPTS + %w[tmpdir],
38
38
  banner: FILE_UPLOAD_HELP }
39
+ when 'download'
40
+ { flags: ACTION_OPTS,
41
+ banner: FILE_DOWNLOAD_HELP }
39
42
  else
40
43
  { flags: OPTIONS[:global],
41
44
  banner: FILE_HELP }
@@ -63,6 +66,9 @@ module Bolt
63
66
  when 'convert'
64
67
  { flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
65
68
  banner: PLAN_CONVERT_HELP }
69
+ when 'new'
70
+ { flags: OPTIONS[:global] + %w[configfile project],
71
+ banner: PLAN_NEW_HELP }
66
72
  when 'run'
67
73
  { flags: ACTION_OPTS + %w[params compile-concurrency tmpdir hiera-config],
68
74
  banner: PLAN_RUN_HELP }
@@ -103,7 +109,7 @@ module Bolt
103
109
  when 'script'
104
110
  case action
105
111
  when 'run'
106
- { flags: ACTION_OPTS + %w[tmpdir],
112
+ { flags: ACTION_OPTS + %w[tmpdir env-var],
107
113
  banner: SCRIPT_RUN_HELP }
108
114
  else
109
115
  { flags: OPTIONS[:global],
@@ -156,10 +162,10 @@ module Bolt
156
162
  SUBCOMMANDS
157
163
  apply Apply Puppet manifest code
158
164
  command Run a command remotely
159
- file Upload a local file or directory
165
+ file Copy files between the controller and targets
160
166
  group Show the list of groups in the inventory
161
167
  inventory Show the list of targets an action would run on
162
- plan Convert, show, and run Bolt plans
168
+ plan Convert, create, show, and run Bolt plans
163
169
  project Create and migrate Bolt projects
164
170
  puppetfile Install and list modules and generate type references
165
171
  script Upload a local script and run it remotely
@@ -218,10 +224,30 @@ module Bolt
218
224
  bolt file <action> [options]
219
225
 
220
226
  DESCRIPTION
221
- Upload a local file or directory
227
+ Copy files and directories between the controller and targets
222
228
 
223
229
  ACTIONS
224
- upload Upload a local file or directory
230
+ download Download a file or directory to the controller
231
+ upload Upload a local file or directory from the controller
232
+ HELP
233
+
234
+ FILE_DOWNLOAD_HELP = <<~HELP
235
+ NAME
236
+ download
237
+
238
+ USAGE
239
+ bolt file download <src> <dest> [options]
240
+
241
+ DESCRIPTION
242
+ Download a file or directory from one or more targets.
243
+
244
+ Downloaded files and directories are saved to the a subdirectory
245
+ matching the target's name under the destination directory. The
246
+ destination directory is expanded relative to the downloads
247
+ subdirectory of the project directory.
248
+
249
+ EXAMPLES
250
+ bolt file download /etc/ssh_config ssh_config -t all
225
251
  HELP
226
252
 
227
253
  FILE_UPLOAD_HELP = <<~HELP
@@ -296,10 +322,11 @@ module Bolt
296
322
  bolt plan <action> [parameters] [options]
297
323
 
298
324
  DESCRIPTION
299
- Convert, show, and run Bolt plans.
325
+ Convert, create, show, and run Bolt plans.
300
326
 
301
327
  ACTIONS
302
328
  convert Convert a YAML plan to a Bolt plan
329
+ new Create a new plan in the current project
303
330
  run Run a plan on the specified targets
304
331
  show Show available plans and plan documentation
305
332
  HELP
@@ -322,6 +349,20 @@ module Bolt
322
349
  bolt plan convert path/to/plan/myplan.yaml
323
350
  HELP
324
351
 
352
+ PLAN_NEW_HELP = <<~HELP
353
+ NAME
354
+ new
355
+
356
+ USAGE
357
+ bolt plan new <plan> [options]
358
+
359
+ DESCRIPTION
360
+ Create a new plan in the current project.
361
+
362
+ EXAMPLES
363
+ bolt plan new myproject::myplan
364
+ HELP
365
+
325
366
  PLAN_RUN_HELP = <<~HELP
326
367
  NAME
327
368
  run
@@ -379,19 +420,18 @@ module Bolt
379
420
  init
380
421
 
381
422
  USAGE
382
- bolt project init [directory] [options]
423
+ bolt project init [name] [options]
383
424
 
384
425
  DESCRIPTION
385
- Create a new Bolt project.
426
+ Create a new Bolt project in the current working directory.
386
427
 
387
- Specify a directory to create a Bolt project in. Defaults to the
388
- curent working directory.
428
+ Specify a name for the Bolt project. Defaults to the basename of the current working directory.
389
429
 
390
430
  EXAMPLES
391
- Create a new Bolt project in the current working directory.
431
+ Create a new Bolt project using the directory as the project name.
392
432
  bolt project init
393
- Create a new Bolt project at a specified path.
394
- bolt project init ~/path/to/project
433
+ Create a new Bolt project with a specified name.
434
+ bolt project init myproject
395
435
  Create a new Bolt project with existing modules.
396
436
  bolt project init --modules puppetlabs-apt,puppetlabs-ntp
397
437
  HELP
@@ -594,13 +634,13 @@ module Bolt
594
634
  bolt task show canary
595
635
  HELP
596
636
 
597
- attr_reader :warnings
637
+ attr_reader :deprecations
598
638
 
599
639
  def initialize(options)
600
640
  super()
601
641
 
602
642
  @options = options
603
- @warnings = []
643
+ @deprecations = []
604
644
 
605
645
  separator "\nINVENTORY OPTIONS"
606
646
  define('-t', '--targets TARGETS',
@@ -653,9 +693,9 @@ module Bolt
653
693
  @options[:password] = password
654
694
  end
655
695
  define('--password-prompt', 'Prompt for user to input password') do |_password|
656
- STDERR.print "Please enter your password: "
657
- @options[:password] = STDIN.noecho(&:gets).chomp
658
- STDERR.puts
696
+ $stderr.print "Please enter your password: "
697
+ @options[:password] = $stdin.noecho(&:gets).chomp
698
+ $stderr.puts
659
699
  end
660
700
  define('--private-key KEY', 'Path to private ssh key to authenticate with') do |key|
661
701
  @options[:'private-key'] = File.expand_path(key)
@@ -679,9 +719,9 @@ module Bolt
679
719
  @options[:'sudo-password'] = password
680
720
  end
681
721
  define('--sudo-password-prompt', 'Prompt for user to input escalation password') do |_password|
682
- STDERR.print "Please enter your privilege escalation password: "
683
- @options[:'sudo-password'] = STDIN.noecho(&:gets).chomp
684
- STDERR.puts
722
+ $stderr.print "Please enter your privilege escalation password: "
723
+ @options[:'sudo-password'] = $stdin.noecho(&:gets).chomp
724
+ $stderr.puts
685
725
  end
686
726
  define('--sudo-executable EXEC', "Specify an executable for running as another user.",
687
727
  "This option is experimental.") do |exec|
@@ -738,6 +778,15 @@ module Bolt
738
778
  @options[:'save-rerun'] = save
739
779
  end
740
780
 
781
+ separator "\nREMOTE ENVIRONMENT OPTIONS"
782
+ define('--env-var ENVIRONMENT_VARIABLES', 'Environment variables to set on the target') do |envvar|
783
+ unless envvar.include?('=')
784
+ raise Bolt::CLIError, "Environment variables must be specified using 'myenvvar=key' format"
785
+ end
786
+ @options[:env_vars] ||= {}
787
+ @options[:env_vars].store(*envvar.split('=', 2))
788
+ end
789
+
741
790
  separator "\nTRANSPORT OPTIONS"
742
791
  define('--transport TRANSPORT', TRANSPORTS.keys.map(&:to_s),
743
792
  "Specify a default transport: #{TRANSPORTS.keys.join(', ')}") do |t|
@@ -809,7 +858,8 @@ module Bolt
809
858
  @options[:debug] = true
810
859
  # We don't actually set '--log-level debug' here, but once the options are evaluated by
811
860
  # the config class the end result is the same.
812
- @warnings << { msg: "Command line option '--debug' is deprecated, set '--log-level debug' instead." }
861
+ msg = "Command line option '--debug' is deprecated, set '--log-level debug' instead."
862
+ @deprecations << { type: 'Using --debug instead of --log-level debug', msg: msg }
813
863
  end
814
864
  define('--log-level LEVEL',
815
865
  "Set the log level for the console. Available options are",
@@ -854,7 +904,7 @@ module Bolt
854
904
  file = value.sub(/^@/, '')
855
905
  read_arg_file(file)
856
906
  elsif value == '-'
857
- STDIN.read
907
+ $stdin.read
858
908
  else
859
909
  value
860
910
  end