bolt 2.37.0 → 2.44.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 +17 -17
- data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +6 -8
- data/lib/bolt/analytics.rb +3 -2
- data/lib/bolt/applicator.rb +11 -1
- data/lib/bolt/bolt_option_parser.rb +20 -13
- data/lib/bolt/catalog.rb +10 -29
- data/lib/bolt/cli.rb +58 -40
- data/lib/bolt/config.rb +134 -119
- data/lib/bolt/config/options.rb +142 -77
- data/lib/bolt/config/transport/base.rb +2 -2
- data/lib/bolt/config/transport/local.rb +1 -0
- data/lib/bolt/config/transport/options.rb +18 -68
- data/lib/bolt/config/transport/orch.rb +1 -0
- data/lib/bolt/config/transport/ssh.rb +0 -5
- data/lib/bolt/executor.rb +15 -5
- data/lib/bolt/inventory.rb +26 -0
- data/lib/bolt/inventory/group.rb +35 -12
- data/lib/bolt/inventory/inventory.rb +1 -1
- data/lib/bolt/inventory/options.rb +130 -0
- data/lib/bolt/inventory/target.rb +10 -11
- data/lib/bolt/logger.rb +114 -10
- data/lib/bolt/module.rb +10 -2
- data/lib/bolt/module_installer.rb +25 -15
- data/lib/bolt/module_installer/resolver.rb +65 -12
- data/lib/bolt/module_installer/specs/forge_spec.rb +8 -2
- data/lib/bolt/module_installer/specs/git_spec.rb +17 -2
- data/lib/bolt/outputter.rb +19 -5
- data/lib/bolt/outputter/human.rb +24 -1
- data/lib/bolt/outputter/json.rb +1 -1
- data/lib/bolt/outputter/logger.rb +1 -1
- data/lib/bolt/outputter/rainbow.rb +12 -1
- data/lib/bolt/pal.rb +93 -14
- data/lib/bolt/pal/yaml_plan.rb +8 -2
- data/lib/bolt/pal/yaml_plan/evaluator.rb +2 -2
- data/lib/bolt/pal/yaml_plan/transpiler.rb +6 -1
- data/lib/bolt/plugin.rb +3 -3
- data/lib/bolt/plugin/cache.rb +8 -8
- data/lib/bolt/plugin/module.rb +1 -1
- data/lib/bolt/plugin/puppet_connect_data.rb +35 -0
- data/lib/bolt/plugin/puppetdb.rb +2 -2
- data/lib/bolt/project.rb +76 -50
- data/lib/bolt/project_manager.rb +2 -0
- data/lib/bolt/project_manager/config_migrator.rb +9 -1
- data/lib/bolt/project_manager/module_migrator.rb +2 -0
- data/lib/bolt/puppetdb/client.rb +8 -0
- data/lib/bolt/rerun.rb +1 -1
- data/lib/bolt/shell/bash.rb +1 -1
- data/lib/bolt/shell/bash/tmpdir.rb +4 -1
- data/lib/bolt/shell/powershell.rb +7 -5
- data/lib/bolt/target.rb +4 -0
- data/lib/bolt/task.rb +1 -1
- data/lib/bolt/transport/docker/connection.rb +2 -2
- data/lib/bolt/transport/local.rb +13 -0
- data/lib/bolt/transport/orch/connection.rb +1 -1
- data/lib/bolt/transport/ssh.rb +1 -2
- data/lib/bolt/transport/ssh/connection.rb +1 -1
- data/lib/bolt/validator.rb +227 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/config.rb +1 -1
- data/lib/bolt_server/schemas/partials/task.json +1 -1
- data/lib/bolt_server/transport_app.rb +28 -27
- data/libexec/bolt_catalog +1 -1
- metadata +27 -11
- data/lib/bolt/config/validator.rb +0 -231
@@ -111,11 +111,6 @@ module Bolt
|
|
111
111
|
@config['interpreters'] = normalize_interpreters(@config['interpreters'])
|
112
112
|
end
|
113
113
|
|
114
|
-
if @config['login-shell'] && !LOGIN_SHELLS.include?(@config['login-shell'])
|
115
|
-
raise Bolt::ValidationError,
|
116
|
-
"Unsupported login-shell #{@config['login-shell']}. Supported shells are #{LOGIN_SHELLS.join(', ')}"
|
117
|
-
end
|
118
|
-
|
119
114
|
if @config['login-shell'] == 'powershell'
|
120
115
|
%w[tty run-as].each do |key|
|
121
116
|
if @config[key]
|
data/lib/bolt/executor.rb
CHANGED
@@ -100,6 +100,8 @@ module Bolt
|
|
100
100
|
# that type of event, publish the event
|
101
101
|
next unless types.nil? || types.include?(event[:type])
|
102
102
|
@publisher.post(subscriber) do |sub|
|
103
|
+
# Wait for user to input to prompt before printing anything
|
104
|
+
sleep(0.1) while @prompting
|
103
105
|
sub.handle_event(event)
|
104
106
|
end
|
105
107
|
end
|
@@ -119,11 +121,12 @@ module Bolt
|
|
119
121
|
def queue_execute(targets)
|
120
122
|
if @warn_concurrency && targets.length > @concurrency
|
121
123
|
@warn_concurrency = false
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
124
|
+
msg = "The ulimit is low, which may cause file limit issues. Default concurrency has been set to "\
|
125
|
+
"'#{@concurrency}' to mitigate those issues, which may cause Bolt to run slow. "\
|
126
|
+
"Disable this warning by configuring ulimit using 'ulimit -n <limit>' in your shell "\
|
127
|
+
"configuration, or by configuring Bolt's concurrency. "\
|
128
|
+
"See https://puppet.com/docs/bolt/latest/bolt_known_issues.html for details."
|
129
|
+
Bolt::Logger.warn("low_ulimit", msg)
|
127
130
|
end
|
128
131
|
|
129
132
|
targets.group_by(&:transport).flat_map do |protocol, protocol_targets|
|
@@ -258,7 +261,9 @@ module Bolt
|
|
258
261
|
|
259
262
|
def with_node_logging(description, batch, log_level = :info)
|
260
263
|
@logger.send(log_level, "#{description} on #{batch.map(&:safe_name)}")
|
264
|
+
publish_event(type: :start_spin)
|
261
265
|
result = yield
|
266
|
+
publish_event(type: :stop_spin)
|
262
267
|
@logger.send(log_level, result.to_json)
|
263
268
|
result
|
264
269
|
end
|
@@ -410,6 +415,7 @@ module Bolt
|
|
410
415
|
subscribe(self, [:node_result])
|
411
416
|
results = Array.new(skein.length)
|
412
417
|
@in_parallel = true
|
418
|
+
publish_event(type: :stop_spin)
|
413
419
|
|
414
420
|
until skein.empty?
|
415
421
|
@thread_completed = false
|
@@ -417,6 +423,7 @@ module Bolt
|
|
417
423
|
|
418
424
|
skein.each do |yarn|
|
419
425
|
if yarn.alive?
|
426
|
+
publish_event(type: :stop_spin)
|
420
427
|
r = yarn.resume
|
421
428
|
else
|
422
429
|
results[yarn.index] = yarn.value
|
@@ -428,6 +435,7 @@ module Bolt
|
|
428
435
|
sleep(0.1) until @thread_completed || skein.empty?
|
429
436
|
end
|
430
437
|
|
438
|
+
publish_event(type: :stop_spin)
|
431
439
|
@in_parallel = false
|
432
440
|
unsubscribe(self, [:node_result])
|
433
441
|
results
|
@@ -469,6 +477,7 @@ module Bolt
|
|
469
477
|
end
|
470
478
|
|
471
479
|
def prompt(prompt, options)
|
480
|
+
@prompting = true
|
472
481
|
unless $stdin.tty?
|
473
482
|
raise Bolt::Error.new('STDIN is not a tty, unable to prompt', 'bolt/no-tty-error')
|
474
483
|
end
|
@@ -480,6 +489,7 @@ module Bolt
|
|
480
489
|
else
|
481
490
|
$stdin.gets.to_s.chomp
|
482
491
|
end
|
492
|
+
@prompting = false
|
483
493
|
|
484
494
|
$stderr.puts if options[:sensitive]
|
485
495
|
|
data/lib/bolt/inventory.rb
CHANGED
@@ -4,13 +4,17 @@ require 'set'
|
|
4
4
|
require 'bolt/config'
|
5
5
|
require 'bolt/inventory/group'
|
6
6
|
require 'bolt/inventory/inventory'
|
7
|
+
require 'bolt/inventory/options'
|
7
8
|
require 'bolt/target'
|
8
9
|
require 'bolt/util'
|
9
10
|
require 'bolt/plugin'
|
11
|
+
require 'bolt/validator'
|
10
12
|
require 'yaml'
|
11
13
|
|
12
14
|
module Bolt
|
13
15
|
class Inventory
|
16
|
+
include Bolt::Inventory::Options
|
17
|
+
|
14
18
|
ENVIRONMENT_VAR = 'BOLT_INVENTORY'
|
15
19
|
|
16
20
|
class ValidationError < Bolt::Error
|
@@ -45,11 +49,26 @@ module Bolt
|
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
52
|
+
# Builds the schema used by the validator.
|
53
|
+
#
|
54
|
+
def self.schema
|
55
|
+
schema = {
|
56
|
+
type: Hash,
|
57
|
+
properties: OPTIONS.map { |opt| [opt, _ref: opt] }.to_h,
|
58
|
+
definitions: DEFINITIONS,
|
59
|
+
_plugin: true
|
60
|
+
}
|
61
|
+
|
62
|
+
schema[:definitions]['config'][:properties] = Bolt::Config.transport_definitions
|
63
|
+
schema
|
64
|
+
end
|
65
|
+
|
48
66
|
def self.from_config(config, plugins)
|
49
67
|
logger = Bolt::Logger.logger(self)
|
50
68
|
|
51
69
|
if ENV.include?(ENVIRONMENT_VAR)
|
52
70
|
begin
|
71
|
+
source = ENVIRONMENT_VAR
|
53
72
|
data = YAML.safe_load(ENV[ENVIRONMENT_VAR])
|
54
73
|
raise Bolt::ParseError, "Could not parse inventory from $#{ENVIRONMENT_VAR}" unless data.is_a?(Hash)
|
55
74
|
logger.debug("Loaded inventory from environment variable #{ENVIRONMENT_VAR}")
|
@@ -57,9 +76,11 @@ module Bolt
|
|
57
76
|
raise Bolt::ParseError, "Could not parse inventory from $#{ENVIRONMENT_VAR}"
|
58
77
|
end
|
59
78
|
elsif config.inventoryfile
|
79
|
+
source = config.inventoryfile
|
60
80
|
data = Bolt::Util.read_yaml_hash(config.inventoryfile, 'inventory')
|
61
81
|
logger.debug("Loaded inventory from #{config.inventoryfile}")
|
62
82
|
else
|
83
|
+
source = config.default_inventoryfile
|
63
84
|
data = Bolt::Util.read_optional_yaml_hash(config.default_inventoryfile, 'inventory')
|
64
85
|
|
65
86
|
if config.default_inventoryfile.exist?
|
@@ -74,6 +95,11 @@ module Bolt
|
|
74
95
|
t.resolve(plugins) unless t.resolved?
|
75
96
|
end
|
76
97
|
|
98
|
+
Bolt::Validator.new.tap do |validator|
|
99
|
+
validator.validate(data, schema, source)
|
100
|
+
validator.warnings.each { |warning| Bolt::Logger.warn(warning[:id], warning[:msg]) }
|
101
|
+
end
|
102
|
+
|
77
103
|
inventory = create_version(data, config.transport, config.transports, plugins)
|
78
104
|
inventory.validate
|
79
105
|
inventory
|
data/lib/bolt/inventory/group.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'bolt/config/options'
|
3
4
|
require 'bolt/inventory/group'
|
4
5
|
require 'bolt/inventory/inventory'
|
5
6
|
require 'bolt/inventory/target'
|
@@ -18,12 +19,23 @@ module Bolt
|
|
18
19
|
GROUP_KEYS = DATA_KEYS + %w[name groups targets]
|
19
20
|
CONFIG_KEYS = Bolt::Config::INVENTORY_OPTIONS.keys
|
20
21
|
|
21
|
-
def initialize(input, plugins)
|
22
|
+
def initialize(input, plugins, all_group: false)
|
22
23
|
@logger = Bolt::Logger.logger(self)
|
23
24
|
@plugins = plugins
|
24
25
|
|
25
26
|
input = @plugins.resolve_top_level_references(input) if @plugins.reference?(input)
|
26
27
|
|
28
|
+
if all_group
|
29
|
+
if input.key?('name') && input['name'] != 'all'
|
30
|
+
Bolt::Logger.warn(
|
31
|
+
"top_level_group_name",
|
32
|
+
"Top-level group '#{input['name']}' cannot specify a name, using 'all' instead."
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
input = input.merge('name' => 'all')
|
37
|
+
end
|
38
|
+
|
27
39
|
raise ValidationError.new("Group does not have a name", nil) unless input.key?('name')
|
28
40
|
|
29
41
|
@name = @plugins.resolve_references(input['name'])
|
@@ -125,7 +137,7 @@ module Bolt
|
|
125
137
|
|
126
138
|
unless (unexpected_keys = target.keys - TARGET_KEYS).empty?
|
127
139
|
msg = "Found unexpected key(s) #{unexpected_keys.join(', ')} in target #{t_name}"
|
128
|
-
|
140
|
+
Bolt::Logger.warn("unknown_target_keys", msg)
|
129
141
|
end
|
130
142
|
|
131
143
|
validate_data_keys(target, t_name)
|
@@ -252,15 +264,7 @@ module Bolt
|
|
252
264
|
|
253
265
|
unless (unexpected_keys = input.keys - GROUP_KEYS).empty?
|
254
266
|
msg = "Found unexpected key(s) #{unexpected_keys.join(', ')} in group #{@name}"
|
255
|
-
|
256
|
-
end
|
257
|
-
|
258
|
-
Bolt::Util.walk_keys(input) do |key|
|
259
|
-
if @plugins.reference?(key)
|
260
|
-
raise ValidationError.new("Group keys cannot be specified as _plugin references", @name)
|
261
|
-
else
|
262
|
-
key
|
263
|
-
end
|
267
|
+
Bolt::Logger.warn("unknown_group_keys", msg)
|
264
268
|
end
|
265
269
|
end
|
266
270
|
|
@@ -323,7 +327,26 @@ module Bolt
|
|
323
327
|
'features' => @plugins.resolve_references(data.fetch('features', [])),
|
324
328
|
'plugin_hooks' => @plugins.resolve_references(data.fetch('plugin_hooks', {}))
|
325
329
|
}
|
330
|
+
|
326
331
|
validate_data_keys(result, target)
|
332
|
+
|
333
|
+
Bolt::Config::Options::TRANSPORT_CONFIG.each_key do |transport|
|
334
|
+
next unless result['config'].key?(transport)
|
335
|
+
transport_config = result['config'][transport]
|
336
|
+
next unless transport_config.is_a?(Hash)
|
337
|
+
transport_config = Bolt::Util.postwalk_vals(transport_config) do |val|
|
338
|
+
if val.is_a?(Hash)
|
339
|
+
val = val.compact
|
340
|
+
val = nil if val.empty?
|
341
|
+
end
|
342
|
+
val
|
343
|
+
end
|
344
|
+
# the transport config is user-specified data so we
|
345
|
+
# still want to preserve it even if it exclusively
|
346
|
+
# contains nil-resolved keys
|
347
|
+
result['config'][transport] = transport_config || {}
|
348
|
+
end
|
349
|
+
|
327
350
|
result['features'] = Set.new(result['features'].flatten)
|
328
351
|
result
|
329
352
|
end
|
@@ -348,7 +371,7 @@ module Bolt
|
|
348
371
|
msg = +"Found unexpected key(s) #{unexpected_keys.join(', ')} in config for"
|
349
372
|
msg << " target #{target} in" if target
|
350
373
|
msg << " group #{@name}"
|
351
|
-
|
374
|
+
Bolt::Logger.warn("unknown_config_keys", msg)
|
352
375
|
end
|
353
376
|
end
|
354
377
|
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/config/options'
|
4
|
+
|
5
|
+
module Bolt
|
6
|
+
class Inventory
|
7
|
+
module Options
|
8
|
+
# Top-level options available in the inventory.
|
9
|
+
OPTIONS = %w[
|
10
|
+
config
|
11
|
+
facts
|
12
|
+
features
|
13
|
+
groups
|
14
|
+
targets
|
15
|
+
vars
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
# Definitions used to validate the data.
|
19
|
+
# https://github.com/puppetlabs/bolt/blob/main/schemas/README.md
|
20
|
+
DEFINITIONS = {
|
21
|
+
"alias" => {
|
22
|
+
description: "A unique alias to refer to the target. Aliases cannot conflict "\
|
23
|
+
"with the name of a group, the name of a target, or another alias.",
|
24
|
+
type: [String, Array],
|
25
|
+
uniqueItems: true,
|
26
|
+
items: {
|
27
|
+
type: String,
|
28
|
+
_plugin: true
|
29
|
+
},
|
30
|
+
_plugin: true
|
31
|
+
},
|
32
|
+
"config" => {
|
33
|
+
description: "A map of configuration options.",
|
34
|
+
type: Hash,
|
35
|
+
# These properties are populated as part of Bolt::Inventory.schema
|
36
|
+
properties: {},
|
37
|
+
_plugin: true
|
38
|
+
},
|
39
|
+
"facts" => {
|
40
|
+
description: "A map of system information, also known as facts, for the target.",
|
41
|
+
type: Hash,
|
42
|
+
_plugin: true
|
43
|
+
},
|
44
|
+
"features" => {
|
45
|
+
description: "A list of available features for the target.",
|
46
|
+
type: Array,
|
47
|
+
uniqueItems: true,
|
48
|
+
items: {
|
49
|
+
type: String,
|
50
|
+
_plugin: true
|
51
|
+
},
|
52
|
+
_plugin: true
|
53
|
+
},
|
54
|
+
"groups" => {
|
55
|
+
description: "A list of groups and their associated configuration.",
|
56
|
+
type: Array,
|
57
|
+
items: {
|
58
|
+
type: Hash,
|
59
|
+
required: ["name"],
|
60
|
+
properties: {
|
61
|
+
"config" => { _ref: "config" },
|
62
|
+
"facts" => { _ref: "facts" },
|
63
|
+
"features" => { _ref: "features" },
|
64
|
+
"groups" => { _ref: "groups" },
|
65
|
+
"name" => { _ref: "name" },
|
66
|
+
"plugin_hooks" => { _ref: "plugin_hooks" },
|
67
|
+
"targets" => { _ref: "targets" },
|
68
|
+
"vars" => { _ref: "vars" }
|
69
|
+
},
|
70
|
+
_plugin: true
|
71
|
+
},
|
72
|
+
_plugin: true
|
73
|
+
},
|
74
|
+
"name" => {
|
75
|
+
description: "A human-readable name to refer to the group or target. Names "\
|
76
|
+
"cannot conflict with the name of a group, the name of a target, "\
|
77
|
+
"or the alias of a target. A name is required for a group and is "\
|
78
|
+
"required for a target unless the uri option is set.",
|
79
|
+
type: String,
|
80
|
+
_plugin: true
|
81
|
+
},
|
82
|
+
"plugin_hooks" => {
|
83
|
+
description: "Configuration for the Puppet library plugin used to install the "\
|
84
|
+
"Puppet agent on the target. For more information, see "\
|
85
|
+
"https://pup.pt/bolt-plugin-hooks",
|
86
|
+
type: Hash,
|
87
|
+
properties: {
|
88
|
+
"puppet_library" => {
|
89
|
+
description: "Configuration for the Puppet library plugin.",
|
90
|
+
type: Hash,
|
91
|
+
_plugin: true
|
92
|
+
}
|
93
|
+
},
|
94
|
+
_plugin: true
|
95
|
+
},
|
96
|
+
"targets" => {
|
97
|
+
description: "A list of targets and their associated configuration.",
|
98
|
+
type: Array,
|
99
|
+
items: {
|
100
|
+
type: [String, Hash],
|
101
|
+
properties: {
|
102
|
+
"alias" => { _ref: "alias" },
|
103
|
+
"config" => { _ref: "config" },
|
104
|
+
"facts" => { _ref: "facts" },
|
105
|
+
"features" => { _ref: "features" },
|
106
|
+
"name" => { _ref: "name" },
|
107
|
+
"plugin_hooks" => { _ref: "plugin_hooks" },
|
108
|
+
"uri" => { _ref: "uri" },
|
109
|
+
"vars" => { _ref: "vars" }
|
110
|
+
},
|
111
|
+
_plugin: true
|
112
|
+
},
|
113
|
+
_plugin: true
|
114
|
+
},
|
115
|
+
"uri" => {
|
116
|
+
description: "The URI of the target. This option is required unless the name "\
|
117
|
+
"option is set.",
|
118
|
+
type: String,
|
119
|
+
format: "uri",
|
120
|
+
_plugin: true
|
121
|
+
},
|
122
|
+
"vars" => {
|
123
|
+
description: "A map of variables for the group or target.",
|
124
|
+
type: Hash,
|
125
|
+
_plugin: true
|
126
|
+
}
|
127
|
+
}.freeze
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -31,7 +31,8 @@ module Bolt
|
|
31
31
|
end
|
32
32
|
|
33
33
|
if @name == 'localhost'
|
34
|
-
|
34
|
+
default = { 'config' => { 'transport' => 'local' } }
|
35
|
+
target_data = Bolt::Util.deep_merge(default, target_data)
|
35
36
|
end
|
36
37
|
|
37
38
|
@config = target_data['config'] || {}
|
@@ -49,18 +50,16 @@ module Bolt
|
|
49
50
|
validate
|
50
51
|
end
|
51
52
|
|
52
|
-
def
|
53
|
+
def set_local_defaults
|
54
|
+
return if @set_local_default
|
53
55
|
defaults = {
|
54
|
-
'
|
55
|
-
'transport' => 'local',
|
56
|
-
'local' => { 'interpreters' => { '.rb' => RbConfig.ruby } }
|
57
|
-
},
|
58
|
-
'features' => ['puppet-agent']
|
56
|
+
'local' => { 'interpreters' => { '.rb' => RbConfig.ruby } }
|
59
57
|
}
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
58
|
+
old_config = @config
|
59
|
+
@config = Bolt::Util.deep_merge(defaults, @config)
|
60
|
+
invalidate_config_cache! if old_config != @config
|
61
|
+
set_feature('puppet-agent')
|
62
|
+
@set_local_default = true
|
64
63
|
end
|
65
64
|
|
66
65
|
# rubocop:disable Naming/AccessorMethodName
|
data/lib/bolt/logger.rb
CHANGED
@@ -5,8 +5,14 @@ require 'logging'
|
|
5
5
|
module Bolt
|
6
6
|
module Logger
|
7
7
|
LEVELS = %w[trace debug info notice warn error fatal].freeze
|
8
|
-
|
9
|
-
|
8
|
+
|
9
|
+
# This module is treated as a global singleton so that multiple classes
|
10
|
+
# in Bolt can log warnings with IDs. Access to the following variables
|
11
|
+
# are controlled by a mutex.
|
12
|
+
@mutex = Mutex.new
|
13
|
+
@warnings = Set.new
|
14
|
+
@disable_warnings = Set.new
|
15
|
+
@message_queue = []
|
10
16
|
|
11
17
|
# This method provides a single point-of-entry to setup logging for both
|
12
18
|
# the CLI and for tests. This is necessary because we define custom log
|
@@ -36,7 +42,7 @@ module Bolt
|
|
36
42
|
end
|
37
43
|
end
|
38
44
|
|
39
|
-
def self.configure(destinations, color)
|
45
|
+
def self.configure(destinations, color, disable_warnings = nil)
|
40
46
|
root_logger = Bolt::Logger.logger(:root)
|
41
47
|
|
42
48
|
root_logger.add_appenders Logging.appenders.stderr(
|
@@ -73,6 +79,16 @@ module Bolt
|
|
73
79
|
|
74
80
|
appender.level = params[:level] if params[:level]
|
75
81
|
end
|
82
|
+
|
83
|
+
# Set the list of disabled warnings and mark the logger as configured.
|
84
|
+
# Log all messages in the message queue and flush the queue.
|
85
|
+
if disable_warnings
|
86
|
+
@mutex.synchronize { @disable_warnings = disable_warnings }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.configured?
|
91
|
+
Logging.logger[:root].appenders.any?
|
76
92
|
end
|
77
93
|
|
78
94
|
# A helper to ensure the Logging library is always initialized with our
|
@@ -123,18 +139,106 @@ module Bolt
|
|
123
139
|
Logging.reset
|
124
140
|
end
|
125
141
|
|
126
|
-
|
142
|
+
# The following methods are used in place of the Logging.logger
|
143
|
+
# methods of the same name when logging warning messages or logging
|
144
|
+
# any messages prior to the logger being configured. If the logger
|
145
|
+
# is not configured when any of these methods are called, the message
|
146
|
+
# will be added to a queue, otherwise they are logged immediately.
|
147
|
+
# The message queue is flushed by calling #flush_queue, which is
|
148
|
+
# called from Bolt::CLI after configuring the logger.
|
149
|
+
#
|
150
|
+
def self.warn(id, msg)
|
151
|
+
log(type: :warn, msg: "#{msg} [ID: #{id}]", id: id)
|
152
|
+
end
|
153
|
+
|
154
|
+
def self.warn_once(id, msg)
|
155
|
+
log(type: :warn_once, msg: "#{msg} [ID: #{id}]", id: id)
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.deprecate(id, msg)
|
159
|
+
log(type: :deprecate, msg: "#{msg} [ID: #{id}]", id: id)
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.deprecate_once(id, msg)
|
163
|
+
log(type: :deprecate_once, msg: "#{msg} [ID: #{id}]", id: id)
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.debug(msg)
|
167
|
+
log(type: :debug, msg: msg)
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.info(msg)
|
171
|
+
log(type: :info, msg: msg)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Logs a message. If the logger has not been configured, this will queue
|
175
|
+
# the message to be logged later. Once the logger is configured, the
|
176
|
+
# queue will be flushed of all messages and new messages will be logged
|
177
|
+
# immediately.
|
178
|
+
#
|
179
|
+
# Logging with this method is controlled by a mutex, as the Bolt::Logger
|
180
|
+
# module is treated as a global singleton to allow multiple classes
|
181
|
+
# access to its methods.
|
182
|
+
#
|
183
|
+
private_class_method def self.log(type:, msg:, id: nil)
|
184
|
+
@mutex.synchronize do
|
185
|
+
if configured?
|
186
|
+
log_message(type: type, msg: msg, id: id)
|
187
|
+
else
|
188
|
+
@message_queue << { type: type, msg: msg, id: id }
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Logs all messages in the message queue and then flushes the queue.
|
194
|
+
#
|
195
|
+
def self.flush_queue
|
127
196
|
@mutex.synchronize do
|
128
|
-
@
|
129
|
-
|
130
|
-
@logger.warn(msg)
|
197
|
+
@message_queue.each do |message|
|
198
|
+
log_message(message)
|
131
199
|
end
|
200
|
+
|
201
|
+
@message_queue.clear
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Handles the actual logging of a message.
|
206
|
+
#
|
207
|
+
private_class_method def self.log_message(type:, msg:, id: nil)
|
208
|
+
case type
|
209
|
+
when :warn
|
210
|
+
do_warn(msg, id)
|
211
|
+
when :warn_once
|
212
|
+
do_warn_once(msg, id)
|
213
|
+
when :deprecate
|
214
|
+
do_deprecate(msg, id)
|
215
|
+
when :deprecate_once
|
216
|
+
do_deprecate_once(msg, id)
|
217
|
+
else
|
218
|
+
logger(self).send(type, msg)
|
132
219
|
end
|
133
220
|
end
|
134
221
|
|
135
|
-
|
136
|
-
|
137
|
-
|
222
|
+
# The following methods do the actual warning.
|
223
|
+
#
|
224
|
+
private_class_method def self.do_warn(msg, id)
|
225
|
+
return if @disable_warnings.include?(id)
|
226
|
+
logger(self).warn(msg)
|
227
|
+
end
|
228
|
+
|
229
|
+
private_class_method def self.do_warn_once(msg, id)
|
230
|
+
return unless @warnings.add?(id)
|
231
|
+
do_warn(msg, id)
|
232
|
+
end
|
233
|
+
|
234
|
+
private_class_method def self.do_deprecate(msg, id)
|
235
|
+
@analytics&.event('Warn', 'deprecation', label: id)
|
236
|
+
do_warn(msg, id)
|
237
|
+
end
|
238
|
+
|
239
|
+
private_class_method def self.do_deprecate_once(msg, id)
|
240
|
+
@analytics&.event('Warn', 'deprecation', label: id)
|
241
|
+
do_warn_once(msg, id)
|
138
242
|
end
|
139
243
|
end
|
140
244
|
end
|