bolt 2.12.0 → 2.17.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +1 -1
  3. data/bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb +3 -2
  4. data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +1 -0
  5. data/bolt-modules/boltlib/lib/puppet/functions/add_to_group.rb +1 -0
  6. data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +1 -1
  7. data/bolt-modules/boltlib/lib/puppet/functions/catch_errors.rb +1 -0
  8. data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +1 -0
  9. data/bolt-modules/boltlib/lib/puppet/functions/fail_plan.rb +1 -0
  10. data/bolt-modules/boltlib/lib/puppet/functions/get_resources.rb +2 -1
  11. data/bolt-modules/boltlib/lib/puppet/functions/get_target.rb +1 -0
  12. data/bolt-modules/boltlib/lib/puppet/functions/get_targets.rb +1 -0
  13. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb +1 -0
  14. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +1 -0
  15. data/bolt-modules/boltlib/lib/puppet/functions/remove_from_group.rb +1 -0
  16. data/bolt-modules/boltlib/lib/puppet/functions/resolve_references.rb +1 -0
  17. data/bolt-modules/boltlib/lib/puppet/functions/resource.rb +53 -0
  18. data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +3 -0
  19. data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +7 -2
  20. data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +7 -4
  21. data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +6 -3
  22. data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +8 -2
  23. data/bolt-modules/boltlib/lib/puppet/functions/set_config.rb +1 -0
  24. data/bolt-modules/boltlib/lib/puppet/functions/set_feature.rb +1 -0
  25. data/bolt-modules/boltlib/lib/puppet/functions/set_resources.rb +66 -43
  26. data/bolt-modules/boltlib/lib/puppet/functions/set_var.rb +1 -0
  27. data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -0
  28. data/bolt-modules/boltlib/lib/puppet/functions/vars.rb +1 -0
  29. data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +1 -0
  30. data/bolt-modules/boltlib/lib/puppet/functions/without_default_logging.rb +1 -0
  31. data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +1 -0
  32. data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +2 -0
  33. data/bolt-modules/ctrl/lib/puppet/functions/ctrl/sleep.rb +2 -0
  34. data/bolt-modules/file/lib/puppet/functions/file/exists.rb +2 -1
  35. data/bolt-modules/file/lib/puppet/functions/file/join.rb +2 -0
  36. data/bolt-modules/file/lib/puppet/functions/file/read.rb +3 -1
  37. data/bolt-modules/file/lib/puppet/functions/file/readable.rb +3 -1
  38. data/bolt-modules/file/lib/puppet/functions/file/write.rb +2 -0
  39. data/bolt-modules/out/lib/puppet/functions/out/message.rb +2 -0
  40. data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +1 -0
  41. data/bolt-modules/system/lib/puppet/functions/system/env.rb +2 -0
  42. data/lib/bolt/applicator.rb +20 -7
  43. data/lib/bolt/apply_inventory.rb +4 -0
  44. data/lib/bolt/apply_target.rb +4 -0
  45. data/lib/bolt/bolt_option_parser.rb +20 -13
  46. data/lib/bolt/catalog.rb +81 -68
  47. data/lib/bolt/cli.rb +16 -8
  48. data/lib/bolt/config.rb +150 -138
  49. data/lib/bolt/config/options.rb +473 -0
  50. data/lib/bolt/config/transport/base.rb +16 -16
  51. data/lib/bolt/config/transport/docker.rb +9 -23
  52. data/lib/bolt/config/transport/local.rb +6 -44
  53. data/lib/bolt/config/transport/options.rb +454 -0
  54. data/lib/bolt/config/transport/orch.rb +9 -18
  55. data/lib/bolt/config/transport/remote.rb +3 -6
  56. data/lib/bolt/config/transport/ssh.rb +59 -114
  57. data/lib/bolt/config/transport/winrm.rb +18 -47
  58. data/lib/bolt/executor.rb +14 -1
  59. data/lib/bolt/inventory/group.rb +1 -1
  60. data/lib/bolt/inventory/inventory.rb +4 -14
  61. data/lib/bolt/inventory/target.rb +22 -5
  62. data/lib/bolt/logger.rb +3 -1
  63. data/lib/bolt/outputter.rb +3 -0
  64. data/lib/bolt/outputter/rainbow.rb +84 -0
  65. data/lib/bolt/pal.rb +24 -9
  66. data/lib/bolt/project.rb +64 -55
  67. data/lib/bolt/resource_instance.rb +10 -3
  68. data/lib/bolt/shell/bash.rb +30 -42
  69. data/lib/bolt/shell/powershell.rb +13 -8
  70. data/lib/bolt/shell/powershell/snippets.rb +8 -0
  71. data/lib/bolt/transport/docker.rb +9 -5
  72. data/lib/bolt/transport/local/connection.rb +2 -1
  73. data/lib/bolt/transport/orch.rb +8 -0
  74. data/lib/bolt/transport/ssh/connection.rb +35 -0
  75. data/lib/bolt/version.rb +1 -1
  76. data/lib/bolt_spec/bolt_context.rb +1 -1
  77. data/lib/bolt_spec/run.rb +1 -1
  78. metadata +22 -18
@@ -115,7 +115,12 @@ module Bolt
115
115
  Bolt::Config.from_file(options[:configfile], options)
116
116
  else
117
117
  project = if options[:boltdir]
118
- Bolt::Project.new(options[:boltdir])
118
+ dir = Pathname.new(options[:boltdir])
119
+ if (dir + Bolt::Project::BOLTDIR_NAME).directory?
120
+ Bolt::Project.create_project(dir + Bolt::Project::BOLTDIR_NAME)
121
+ else
122
+ Bolt::Project.create_project(dir)
123
+ end
119
124
  else
120
125
  Bolt::Project.find_boltdir(Dir.pwd)
121
126
  end
@@ -219,7 +224,7 @@ module Bolt
219
224
  end
220
225
 
221
226
  if options[:boltdir] && options[:configfile]
222
- raise Bolt::CLIError, "Only one of '--boltdir' or '--configfile' may be specified"
227
+ raise Bolt::CLIError, "Only one of '--boltdir', '--project', or '--configfile' may be specified"
223
228
  end
224
229
 
225
230
  if options[:noop] &&
@@ -245,6 +250,10 @@ module Bolt
245
250
  !options[:object]
246
251
  raise Bolt::CLIError, "Must specify a value to #{options[:action]}"
247
252
  end
253
+
254
+ if options.key?(:debug) && options.key?(:log)
255
+ raise Bolt::CLIError, "Only one of '--debug' or '--log-level' may be specified"
256
+ end
248
257
  end
249
258
 
250
259
  def handle_parser_errors
@@ -392,7 +401,7 @@ module Bolt
392
401
  end
393
402
  code = apply_manifest(options[:code], options[:targets], options[:object], options[:noop])
394
403
  else
395
- executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop])
404
+ executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop], config.modified_concurrency)
396
405
  targets = options[:targets]
397
406
 
398
407
  results = nil
@@ -512,8 +521,8 @@ module Bolt
512
521
  params: plan_arguments }
513
522
  plan_context[:description] = options[:description] if options[:description]
514
523
 
515
- executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop])
516
- if options.fetch(:format, 'human') == 'human'
524
+ executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop], config.modified_concurrency)
525
+ if %w[human rainbow].include?(options.fetch(:format, 'human'))
517
526
  executor.subscribe(outputter)
518
527
  else
519
528
  # Only subscribe to out::message events for JSON outputter
@@ -548,7 +557,7 @@ module Bolt
548
557
  @logger.warn(message)
549
558
  end
550
559
 
551
- executor = Bolt::Executor.new(config.concurrency, analytics, noop)
560
+ executor = Bolt::Executor.new(config.concurrency, analytics, noop, config.modified_concurrency)
552
561
  executor.subscribe(outputter) if options.fetch(:format, 'human') == 'human'
553
562
  executor.subscribe(log_outputter)
554
563
  # apply logging looks like plan logging, so tell the outputter we're in a
@@ -771,14 +780,13 @@ module Bolt
771
780
  end
772
781
 
773
782
  def pal
774
- project = config.project.load_as_module? ? config.project : nil
775
783
  @pal ||= Bolt::PAL.new(config.modulepath,
776
784
  config.hiera_config,
777
785
  config.project.resource_types,
778
786
  config.compile_concurrency,
779
787
  config.trusted_external,
780
788
  config.apply_settings,
781
- project)
789
+ config.project)
782
790
  end
783
791
 
784
792
  def convert_plan(plan)
@@ -6,13 +6,7 @@ require 'pathname'
6
6
  require 'bolt/project'
7
7
  require 'bolt/logger'
8
8
  require 'bolt/util'
9
- # Transport config objects
10
- require 'bolt/config/transport/ssh'
11
- require 'bolt/config/transport/winrm'
12
- require 'bolt/config/transport/orch'
13
- require 'bolt/config/transport/local'
14
- require 'bolt/config/transport/docker'
15
- require 'bolt/config/transport/remote'
9
+ require 'bolt/config/options'
16
10
 
17
11
  module Bolt
18
12
  class UnknownTransportError < Bolt::Error
@@ -23,146 +17,165 @@ module Bolt
23
17
  end
24
18
 
25
19
  class Config
26
- attr_reader :config_files, :warnings, :data, :transports, :project
27
-
28
- TRANSPORT_CONFIG = {
29
- 'ssh' => Bolt::Config::Transport::SSH,
30
- 'winrm' => Bolt::Config::Transport::WinRM,
31
- 'pcp' => Bolt::Config::Transport::Orch,
32
- 'local' => Bolt::Config::Transport::Local,
33
- 'docker' => Bolt::Config::Transport::Docker,
34
- 'remote' => Bolt::Config::Transport::Remote
35
- }.freeze
36
-
37
- # NOTE: All configuration options should have a corresponding schema property
38
- # in schemas/bolt-config.schema.json
39
- OPTIONS = {
40
- "apply_settings" => "A map of Puppet settings to use when applying Puppet code",
41
- "color" => "Whether to use colored output when printing messages to the console.",
42
- "compile-concurrency" => "The maximum number of simultaneous manifest block compiles.",
43
- "concurrency" => "The number of threads to use when executing on remote targets.",
44
- "format" => "The format to use when printing results. Options are `human` and `json`.",
45
- "hiera-config" => "The path to your Hiera config.",
46
- "inventoryfile" => "The path to a structured data inventory file used to refer to groups of "\
47
- "targets on the command line and from plans.",
48
- "log" => "The configuration of the logfile output. Configuration can be set for "\
49
- "`console` and the path to a log file, such as `~/.puppetlabs/bolt/debug.log`.",
50
- "modulepath" => "The module path for loading tasks and plan code. This is either an array "\
51
- "of directories or a string containing a list of directories separated by the "\
52
- "OS-specific PATH separator.",
53
- "plugin_hooks" => "Which plugins a specific hook should use.",
54
- "plugins" => "A map of plugins and their configuration data.",
55
- "puppetdb" => "A map containing options for configuring the Bolt PuppetDB client.",
56
- "puppetfile" => "A map containing options for the `bolt puppetfile install` command.",
57
- "save-rerun" => "Whether to update `.rerun.json` in the Bolt project directory. If "\
58
- "your target names include passwords, set this value to `false` to avoid "\
59
- "writing passwords to disk.",
60
- "transport" => "The default transport to use when the transport for a target is not "\
61
- "specified in the URL or inventory.",
62
- "trusted-external-command" => "The path to an executable on the Bolt controller that can produce "\
63
- "external trusted facts. **External trusted facts are experimental in both "\
64
- "Puppet and Bolt and this API may change or be removed.**"
65
- }.freeze
66
-
67
- DEFAULT_OPTIONS = {
68
- "color" => true,
69
- "compile-concurrency" => "Number of cores",
70
- "concurrency" => "100 or one-third of the ulimit, whichever is lower",
71
- "format" => "human",
72
- "hiera-config" => "Boltdir/hiera.yaml",
73
- "inventoryfile" => "Boltdir/inventory.yaml",
74
- "modulepath" => ["Boltdir/modules", "Boltdir/site-modules", "Boltdir/site"],
75
- "save-rerun" => true
76
- }.freeze
77
-
78
- PUPPETFILE_OPTIONS = {
79
- "forge" => "A subsection that can have its own `proxy` setting to set an HTTP proxy for Forge operations "\
80
- "only, and a `baseurl` setting to specify a different Forge host.",
81
- "proxy" => "The HTTP proxy to use for Git and Forge operations."
82
- }.freeze
83
-
84
- LOG_OPTIONS = {
85
- "append" => "Add output to an existing log file. Available only for logs output to a "\
86
- "filepath.",
87
- "level" => "The type of information in the log. Either `debug`, `info`, `notice`, "\
88
- "`warn`, or `error`."
89
- }.freeze
90
-
91
- DEFAULT_LOG_OPTIONS = {
92
- "append" => true,
93
- "level" => "`warn` for console, `notice` for file"
94
- }.freeze
95
-
96
- APPLY_SETTINGS = {
97
- "show_diff" => "Whether to log and report a contextual diff when files are being replaced. "\
98
- "See [Puppet documentation](https://puppet.com/docs/puppet/latest/configuration.html#showdiff) "\
99
- "for details"
100
- }.freeze
101
-
102
- DEFAULT_APPLY_SETTINGS = {
103
- "show_diff" => false
104
- }.freeze
20
+ include Bolt::Config::Options
105
21
 
22
+ attr_reader :config_files, :warnings, :data, :transports, :project, :modified_concurrency
23
+
24
+ BOLT_CONFIG_NAME = 'bolt.yaml'
25
+ BOLT_DEFAULTS_NAME = 'bolt-defaults.yaml'
26
+
27
+ # The default concurrency value that is used when the ulimit is not low (i.e. < 700)
106
28
  DEFAULT_DEFAULT_CONCURRENCY = 100
107
29
 
108
30
  def self.default
109
- new(Bolt::Project.new('.'), {})
31
+ new(Bolt::Project.create_project('.'), {})
110
32
  end
111
33
 
112
34
  def self.from_project(project, overrides = {})
113
- data = {
114
- filepath: project.config_file,
115
- data: Bolt::Util.read_optional_yaml_hash(project.config_file, 'config')
116
- }
35
+ conf = if project.project_file == project.config_file
36
+ project.data
37
+ else
38
+ Bolt::Util.read_optional_yaml_hash(project.config_file, 'config')
39
+ end
117
40
 
118
- data = load_defaults(project).push(data).select { |config| config[:data]&.any? }
41
+ data = load_defaults(project).push(
42
+ filepath: project.config_file,
43
+ data: conf,
44
+ warnings: []
45
+ )
119
46
 
120
47
  new(project, data, overrides)
121
48
  end
122
49
 
123
50
  def self.from_file(configfile, overrides = {})
124
- project = Bolt::Project.new(Pathname.new(configfile).expand_path.dirname)
51
+ project = Bolt::Project.create_project(Pathname.new(configfile).expand_path.dirname)
125
52
 
126
- data = {
53
+ conf = if project.project_file == project.config_file
54
+ project.data
55
+ else
56
+ Bolt::Util.read_yaml_hash(configfile, 'config')
57
+ end
58
+
59
+ data = load_defaults(project).push(
127
60
  filepath: project.config_file,
128
- data: Bolt::Util.read_yaml_hash(configfile, 'config')
129
- }
130
- data = load_defaults(project).push(data).select { |config| config[:data]&.any? }
61
+ data: conf,
62
+ warnings: []
63
+ )
131
64
 
132
65
  new(project, data, overrides)
133
66
  end
134
67
 
135
- def self.load_defaults(project)
68
+ def self.system_path
136
69
  # Lazy-load expensive gem code
137
70
  require 'win32/dir' if Bolt::Util.windows?
138
71
 
139
- # Don't load /etc/puppetlabs/bolt/bolt.yaml twice
140
- confs = if project.path == Bolt::Project.system_path
141
- []
142
- else
143
- system_path = Pathname.new(File.join(Bolt::Project.system_path, 'bolt.yaml'))
144
- [{ filepath: system_path, data: Bolt::Util.read_optional_yaml_hash(system_path, 'config') }]
145
- end
146
-
147
- user_path = begin
148
- Pathname.new(File.expand_path(File.join('~', '.puppetlabs', 'etc', 'bolt', 'bolt.yaml')))
149
- rescue ArgumentError
150
- nil
151
- end
152
-
153
- confs << { filepath: user_path, data: Bolt::Util.read_optional_yaml_hash(user_path, 'config') } if user_path
72
+ if Bolt::Util.windows?
73
+ Pathname.new(File.join(Dir::COMMON_APPDATA, 'PuppetLabs', 'bolt', 'etc'))
74
+ else
75
+ Pathname.new(File.join('/etc', 'puppetlabs', 'bolt'))
76
+ end
77
+ end
78
+
79
+ def self.user_path
80
+ Pathname.new(File.expand_path(File.join('~', '.puppetlabs', 'etc', 'bolt')))
81
+ rescue StandardError
82
+ nil
83
+ end
84
+
85
+ # Loads a 'bolt-defaults.yaml' file, which contains default configuration that applies to all
86
+ # projects. This file does not allow project-specific configuration such as 'hiera-config' and
87
+ # 'inventoryfile', and nests all default inventory configuration under an 'inventory-config' key.
88
+ def self.load_bolt_defaults_yaml(dir)
89
+ filepath = dir + BOLT_DEFAULTS_NAME
90
+ data = Bolt::Util.read_yaml_hash(filepath, 'config')
91
+ warnings = []
92
+
93
+ # Warn if 'bolt.yaml' detected in same directory.
94
+ if File.exist?(bolt_yaml = dir + BOLT_CONFIG_NAME)
95
+ warnings.push(
96
+ msg: "Detected multiple configuration files: ['#{bolt_yaml}', '#{filepath}']. '#{bolt_yaml}' "\
97
+ "will be ignored."
98
+ )
99
+ end
100
+
101
+ # Remove project-specific config such as hiera-config, etc.
102
+ project_config = data.slice(*(BOLT_PROJECT_OPTIONS - BOLT_DEFAULTS_OPTIONS))
103
+
104
+ if project_config.any?
105
+ data.reject! { |key, _| project_config.include?(key) }
106
+ warnings.push(
107
+ msg: "Unsupported project configuration detected in '#{filepath}': #{project_config.keys}. "\
108
+ "Project configuration should be set in 'bolt-project.yaml'."
109
+ )
110
+ end
111
+
112
+ # Remove top-level transport config such as transport, ssh, etc.
113
+ transport_config = data.slice(*INVENTORY_OPTIONS.keys)
114
+
115
+ if transport_config.any?
116
+ data.reject! { |key, _| transport_config.include?(key) }
117
+ warnings.push(
118
+ msg: "Unsupported inventory configuration detected in '#{filepath}': #{transport_config.keys}. "\
119
+ "Transport configuration should be set under the 'inventory-config' option or "\
120
+ "in 'inventory.yaml'."
121
+ )
122
+ end
123
+
124
+ # Move data under transport-config to top-level so it can be easily merged with
125
+ # config from other sources.
126
+ if data.key?('inventory-config')
127
+ data = data.merge(data.delete('inventory-config'))
128
+ end
129
+
130
+ { filepath: filepath, data: data, warnings: warnings }
131
+ end
132
+
133
+ # Loads a 'bolt.yaml' file, the legacy configuration file. There's no special munging needed
134
+ # here since Bolt::Config will just ignore any invalid keys.
135
+ def self.load_bolt_yaml(dir)
136
+ filepath = dir + BOLT_CONFIG_NAME
137
+ data = Bolt::Util.read_yaml_hash(filepath, 'config')
138
+ warnings = [msg: "Configuration file #{filepath} is deprecated and will be removed in a future version "\
139
+ "of Bolt. Use '#{dir + BOLT_DEFAULTS_NAME}' instead."]
140
+
141
+ { filepath: filepath, data: data, warnings: warnings }
142
+ end
143
+
144
+ def self.load_defaults(project)
145
+ confs = []
146
+
147
+ # Load system-level config. Prefer a 'bolt-defaults.yaml' file, but fall back to the
148
+ # legacy 'bolt.yaml' file. If the project-level config file is also the system-level
149
+ # config file, don't load it a second time.
150
+ if File.exist?(system_path + BOLT_DEFAULTS_NAME)
151
+ confs << load_bolt_defaults_yaml(system_path)
152
+ elsif File.exist?(system_path + BOLT_CONFIG_NAME) &&
153
+ (system_path + BOLT_CONFIG_NAME) != project.config_file
154
+ confs << load_bolt_yaml(system_path)
155
+ end
156
+
157
+ # Load user-level config if there is a homedir. Prefer a 'bolt-defaults.yaml' file, but
158
+ # fall back to the legacy 'bolt.yaml' file.
159
+ if user_path
160
+ if File.exist?(user_path + BOLT_DEFAULTS_NAME)
161
+ confs << load_bolt_defaults_yaml(user_path)
162
+ elsif File.exist?(user_path + BOLT_CONFIG_NAME)
163
+ confs << load_bolt_yaml(user_path)
164
+ end
165
+ end
166
+
154
167
  confs
155
168
  end
156
169
 
157
170
  def initialize(project, config_data, overrides = {})
158
171
  unless config_data.is_a?(Array)
159
- config_data = [{ filepath: project.config_file, data: config_data }]
172
+ config_data = [{ filepath: project.config_file, data: config_data, warnings: [] }]
160
173
  end
161
174
 
162
- @logger = Logging.logger[self]
163
- @warnings = []
164
- @project = project
165
- @transports = {}
175
+ @logger = Logging.logger[self]
176
+ @project = project
177
+ @warnings = @project.warnings.dup
178
+ @transports = {}
166
179
  @config_files = []
167
180
 
168
181
  default_data = {
@@ -180,24 +193,22 @@ module Bolt
180
193
  'transport' => 'ssh'
181
194
  }
182
195
 
183
- loaded_data = config_data.map do |config|
184
- @config_files.push(config[:filepath])
185
- config[:data]
196
+ loaded_data = config_data.each_with_object([]) do |data, acc|
197
+ @warnings.concat(data[:warnings]) if data[:warnings].any?
198
+
199
+ if data[:data].any?
200
+ @config_files.push(data[:filepath])
201
+ acc.push(data[:data])
202
+ end
186
203
  end
187
204
 
188
205
  override_data = normalize_overrides(overrides)
189
206
 
190
207
  # If we need to lower concurrency and concurrency is not configured
191
208
  ld_concurrency = loaded_data.map(&:keys).flatten.include?('concurrency')
192
- if default_concurrency != DEFAULT_DEFAULT_CONCURRENCY &&
193
- !ld_concurrency &&
194
- !override_data.key?('concurrency')
195
- concurrency_warning = { option: 'concurrency',
196
- msg: "Concurrency will default to #{default_concurrency} because ulimit "\
197
- "is low: #{Etc.sysconf(Etc::SC_OPEN_MAX)}. Set concurrency with "\
198
- "'--concurrency', or set your ulimit with 'ulimit -n <limit>'" }
199
- @warnings << concurrency_warning
200
- end
209
+ @modified_concurrency = default_concurrency != DEFAULT_DEFAULT_CONCURRENCY &&
210
+ !ld_concurrency &&
211
+ !override_data.key?('concurrency')
201
212
 
202
213
  @data = merge_config_layers(default_data, *loaded_data, override_data)
203
214
 
@@ -214,12 +225,13 @@ module Bolt
214
225
  def normalize_overrides(options)
215
226
  opts = options.transform_keys(&:to_s)
216
227
 
217
- # Pull out config options
218
- overrides = opts.slice(*OPTIONS.keys)
228
+ # Pull out config options. We need to add 'transport' as it's not part of the
229
+ # OPTIONS hash but is a valid option that can be set with the --transport CLI option
230
+ overrides = opts.slice(*OPTIONS.keys, 'transport')
219
231
 
220
232
  # Pull out transport config options
221
233
  TRANSPORT_CONFIG.each do |transport, config|
222
- overrides[transport] = opts.slice(*config.options.keys)
234
+ overrides[transport] = opts.slice(*config.options)
223
235
  end
224
236
 
225
237
  # Set console log to debug if in debug mode
@@ -286,8 +298,8 @@ module Bolt
286
298
  end
287
299
 
288
300
  # Filter hashes to only include valid options
289
- @data['apply_settings'] = @data['apply_settings'].slice(*APPLY_SETTINGS.keys)
290
- @data['puppetfile'] = @data['puppetfile'].slice(*PUPPETFILE_OPTIONS.keys)
301
+ @data['apply_settings'] = @data['apply_settings'].slice(*OPTIONS['apply_settings'][:properties].keys)
302
+ @data['puppetfile'] = @data['puppetfile'].slice(*OPTIONS['puppetfile'][:properties].keys)
291
303
  end
292
304
 
293
305
  private def normalize_log(target)
@@ -301,7 +313,7 @@ module Bolt
301
313
  next unless val.is_a?(Hash)
302
314
 
303
315
  name = normalize_log(key)
304
- acc[name] = val.slice(*LOG_OPTIONS.keys)
316
+ acc[name] = val.slice('append', 'level')
305
317
  .transform_keys(&:to_sym)
306
318
 
307
319
  if (v = acc[name][:level])
@@ -353,7 +365,7 @@ module Bolt
353
365
  raise Bolt::ValidationError, "Compilation is CPU-intensive, set concurrency less than #{compile_limit}"
354
366
  end
355
367
 
356
- unless %w[human json].include? format
368
+ if (format == 'rainbow' && Bolt::Util.windows?) || !(%w[human json rainbow].include? format)
357
369
  raise Bolt::ValidationError, "Unsupported format: '#{format}'"
358
370
  end
359
371
 
@@ -485,7 +497,7 @@ module Bolt
485
497
  @default_concurrency ||= if !sc_open_max_available? || Etc.sysconf(Etc::SC_OPEN_MAX) >= 300
486
498
  DEFAULT_DEFAULT_CONCURRENCY
487
499
  else
488
- Etc.sysconf(Etc::SC_OPEN_MAX) / 3
500
+ Etc.sysconf(Etc::SC_OPEN_MAX) / 7
489
501
  end
490
502
  end
491
503
  end