bolt 0.21.3 → 0.21.4
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/exe/bolt-inventory-pdb +8 -2
- data/lib/bolt/applicator.rb +89 -11
- data/lib/bolt/bolt_option_parser.rb +18 -3
- data/lib/bolt/boltdir.rb +42 -0
- data/lib/bolt/catalog.rb +7 -52
- data/lib/bolt/catalog/compiler.rb +48 -0
- data/lib/bolt/catalog/logging.rb +15 -0
- data/lib/bolt/cli.rb +146 -85
- data/lib/bolt/config.rb +121 -156
- data/lib/bolt/error.rb +25 -2
- data/lib/bolt/executor.rb +3 -4
- data/lib/bolt/inventory.rb +3 -3
- data/lib/bolt/logger.rb +3 -3
- data/lib/bolt/outputter/human.rb +10 -0
- data/lib/bolt/outputter/json.rb +6 -0
- data/lib/bolt/pal.rb +10 -11
- data/lib/bolt/pal/logging.rb +3 -14
- data/lib/bolt/puppetdb/client.rb +7 -27
- data/lib/bolt/puppetdb/config.rb +50 -23
- data/lib/bolt/r10k_log_proxy.rb +30 -0
- data/lib/bolt/util.rb +2 -2
- data/lib/bolt/util/puppet_log_level.rb +20 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_ext/puppetdb_inventory.rb +3 -9
- data/lib/bolt_spec/plans.rb +174 -0
- data/lib/bolt_spec/plans/mock_executor.rb +217 -0
- metadata +23 -3
- data/lib/bolt/util/on_access.rb +0 -26
data/lib/bolt/inventory.rb
CHANGED
@@ -41,10 +41,10 @@ module Bolt
|
|
41
41
|
begin
|
42
42
|
data = YAML.safe_load(ENV[ENVIRONMENT_VAR])
|
43
43
|
rescue Psych::Exception
|
44
|
-
raise Bolt::
|
44
|
+
raise Bolt::ParseError, "Could not parse inventory from $#{ENVIRONMENT_VAR}"
|
45
45
|
end
|
46
46
|
else
|
47
|
-
data = Bolt::Util.read_config_file(config
|
47
|
+
data = Bolt::Util.read_config_file(config.inventoryfile, config.default_inventoryfile, 'inventory')
|
48
48
|
end
|
49
49
|
|
50
50
|
inventory = new(data, config)
|
@@ -56,7 +56,7 @@ module Bolt
|
|
56
56
|
def initialize(data, config = nil)
|
57
57
|
@logger = Logging.logger[self]
|
58
58
|
# Config is saved to add config options to targets
|
59
|
-
@config = config || Bolt::Config.
|
59
|
+
@config = config || Bolt::Config.default
|
60
60
|
@data = data ||= {}
|
61
61
|
@groups = Group.new(data.merge('name' => 'all'))
|
62
62
|
@group_lookup = {}
|
data/lib/bolt/logger.rb
CHANGED
@@ -27,12 +27,12 @@ module Bolt
|
|
27
27
|
)
|
28
28
|
end
|
29
29
|
|
30
|
-
def self.configure(
|
30
|
+
def self.configure(destinations, color)
|
31
31
|
root_logger = Logging.logger[:root]
|
32
32
|
|
33
33
|
root_logger.add_appenders Logging.appenders.stderr(
|
34
34
|
'console',
|
35
|
-
layout: console_layout(
|
35
|
+
layout: console_layout(color),
|
36
36
|
level: default_level
|
37
37
|
)
|
38
38
|
|
@@ -40,7 +40,7 @@ module Bolt
|
|
40
40
|
# limit what's actually logged in every appender individually.
|
41
41
|
root_logger.level = :all
|
42
42
|
|
43
|
-
|
43
|
+
destinations.each_pair do |name, params|
|
44
44
|
appender = Logging.appenders[name]
|
45
45
|
if appender.nil?
|
46
46
|
unless name.start_with?('file:')
|
data/lib/bolt/outputter/human.rb
CHANGED
@@ -165,11 +165,21 @@ module Bolt
|
|
165
165
|
def print_plan_result(plan_result)
|
166
166
|
if plan_result.value.nil?
|
167
167
|
@stream.puts("Plan completed successfully with no result")
|
168
|
+
elsif plan_result.value.is_a? Bolt::ApplyFailure
|
169
|
+
@stream.puts(colorize(:red, plan_result.value.message))
|
168
170
|
else
|
169
171
|
@stream.puts(::JSON.pretty_generate(plan_result, quirks_mode: true))
|
170
172
|
end
|
171
173
|
end
|
172
174
|
|
175
|
+
def print_puppetfile_result(success, puppetfile, moduledir)
|
176
|
+
if success
|
177
|
+
@stream.puts("Successfully synced modules from #{puppetfile} to #{moduledir}")
|
178
|
+
else
|
179
|
+
@stream.puts(colorize(:red, "Failed to sync modules from #{puppetfile} to #{moduledir}"))
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
173
183
|
def fatal_error(err)
|
174
184
|
@stream.puts(colorize(:red, err.message))
|
175
185
|
if err.is_a? Bolt::RunFailure
|
data/lib/bolt/outputter/json.rb
CHANGED
@@ -57,6 +57,12 @@ module Bolt
|
|
57
57
|
@stream.puts result.to_json
|
58
58
|
end
|
59
59
|
|
60
|
+
def print_puppetfile_result(success, puppetfile, moduledir)
|
61
|
+
@stream.puts({ "success": success,
|
62
|
+
"puppetfile": puppetfile,
|
63
|
+
"moduledir": moduledir }.to_json)
|
64
|
+
end
|
65
|
+
|
60
66
|
def fatal_error(err)
|
61
67
|
@stream.puts "],\n" if @items_open
|
62
68
|
@stream.puts '"_error": ' if @object_open
|
data/lib/bolt/pal.rb
CHANGED
@@ -36,7 +36,7 @@ module Bolt
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
def initialize(
|
39
|
+
def initialize(modulepath, hiera_config, max_compiles = Concurrent.processor_count)
|
40
40
|
# Nothing works without initialized this global state. Reinitializing
|
41
41
|
# is safe and in practice only happen in tests
|
42
42
|
self.class.load_puppet
|
@@ -44,7 +44,9 @@ module Bolt
|
|
44
44
|
# This makes sure we don't accidentally create puppet dirs
|
45
45
|
with_puppet_settings { |_| nil }
|
46
46
|
|
47
|
-
@
|
47
|
+
@modulepath = [BOLTLIB_PATH, *modulepath, MODULES_PATH]
|
48
|
+
@hiera_config = hiera_config
|
49
|
+
@max_compiles = max_compiles
|
48
50
|
end
|
49
51
|
|
50
52
|
# Puppet logging is global so this is class method to avoid confusion
|
@@ -86,15 +88,11 @@ module Bolt
|
|
86
88
|
compiler.evaluate_string('type PlanResult = Boltlib::PlanResult')
|
87
89
|
end
|
88
90
|
|
89
|
-
def full_modulepath(modulepath)
|
90
|
-
[BOLTLIB_PATH, *modulepath, MODULES_PATH]
|
91
|
-
end
|
92
|
-
|
93
91
|
# Runs a block in a PAL script compiler configured for Bolt. Catches
|
94
92
|
# exceptions thrown by the block and re-raises them ensuring they are
|
95
93
|
# Bolt::Errors since the script compiler block will squash all exceptions.
|
96
94
|
def in_bolt_compiler
|
97
|
-
r = Puppet::Pal.in_tmp_environment('bolt', modulepath:
|
95
|
+
r = Puppet::Pal.in_tmp_environment('bolt', modulepath: @modulepath, facts: {}) do |pal|
|
98
96
|
pal.with_script_compiler do |compiler|
|
99
97
|
alias_types(compiler)
|
100
98
|
begin
|
@@ -122,10 +120,10 @@ module Bolt
|
|
122
120
|
apply_executor: Applicator.new(
|
123
121
|
inventory,
|
124
122
|
executor,
|
125
|
-
|
126
|
-
|
127
|
-
@
|
128
|
-
@
|
123
|
+
@modulepath,
|
124
|
+
pdb_client,
|
125
|
+
@hiera_config,
|
126
|
+
@max_compiles
|
129
127
|
)
|
130
128
|
}
|
131
129
|
Puppet.override(opts, &block)
|
@@ -161,6 +159,7 @@ module Bolt
|
|
161
159
|
end
|
162
160
|
Puppet.settings.send(:clear_everything_for_tests)
|
163
161
|
Puppet.initialize_settings(cli)
|
162
|
+
Puppet::GettextConfig.create_default_text_domain
|
164
163
|
self.class.configure_logging
|
165
164
|
yield
|
166
165
|
end
|
data/lib/bolt/pal/logging.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'bolt/util/puppet_log_level'
|
4
|
+
|
3
5
|
Puppet::Util::Log.newdesttype :logging do
|
4
6
|
match "Logging::Logger"
|
5
7
|
|
@@ -7,22 +9,9 @@ Puppet::Util::Log.newdesttype :logging do
|
|
7
9
|
# an explicit mapping.
|
8
10
|
def initialize(logger)
|
9
11
|
@external_logger = logger
|
10
|
-
|
11
|
-
@log_level_map = {
|
12
|
-
debug: :debug,
|
13
|
-
info: :info,
|
14
|
-
notice: :notice,
|
15
|
-
warning: :warn,
|
16
|
-
err: :error,
|
17
|
-
# Nothing in Puppet actually uses alert, emerg or crit, so it's hard to say
|
18
|
-
# what they indicate, but they sound pretty bad.
|
19
|
-
alert: :error,
|
20
|
-
emerg: :fatal,
|
21
|
-
crit: :fatal
|
22
|
-
}
|
23
12
|
end
|
24
13
|
|
25
14
|
def handle(log)
|
26
|
-
@external_logger.send(
|
15
|
+
@external_logger.send(Bolt::Util::PuppetLogLevel::MAPPING[log.level], log.to_s)
|
27
16
|
end
|
28
17
|
end
|
data/lib/bolt/puppetdb/client.rb
CHANGED
@@ -7,30 +7,10 @@ require 'httpclient'
|
|
7
7
|
module Bolt
|
8
8
|
module PuppetDB
|
9
9
|
class Client
|
10
|
-
|
11
|
-
uri = if config['server_urls'].is_a? String
|
12
|
-
config['server_urls']
|
13
|
-
else
|
14
|
-
config['server_urls'].first
|
15
|
-
end
|
16
|
-
uri = URI.parse(uri)
|
17
|
-
uri.port ||= 8081
|
10
|
+
attr_reader :config
|
18
11
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
cert = config['cert']
|
23
|
-
key = config['key']
|
24
|
-
|
25
|
-
new(uri, cacert, token: token, cert: cert, key: key)
|
26
|
-
end
|
27
|
-
|
28
|
-
def initialize(uri, cacert, token: nil, cert: nil, key: nil)
|
29
|
-
@uri = uri
|
30
|
-
@cacert = cacert
|
31
|
-
@token = token
|
32
|
-
@cert = cert
|
33
|
-
@key = key
|
12
|
+
def initialize(config)
|
13
|
+
@config = config
|
34
14
|
end
|
35
15
|
|
36
16
|
def query_certnames(query)
|
@@ -61,7 +41,7 @@ module Bolt
|
|
61
41
|
|
62
42
|
def make_query(query, path = nil)
|
63
43
|
body = JSON.generate(query: query)
|
64
|
-
url = "#{@uri}/pdb/query/v4"
|
44
|
+
url = "#{@config.uri}/pdb/query/v4"
|
65
45
|
url += "/#{path}" if path
|
66
46
|
|
67
47
|
begin
|
@@ -82,15 +62,15 @@ module Bolt
|
|
82
62
|
def http_client
|
83
63
|
return @http if @http
|
84
64
|
@http = HTTPClient.new
|
85
|
-
@http.ssl_config.set_client_cert_file(@cert, @key) if @cert
|
86
|
-
@http.ssl_config.add_trust_ca(@cacert)
|
65
|
+
@http.ssl_config.set_client_cert_file(@config.cert, @config.key) if @config.cert
|
66
|
+
@http.ssl_config.add_trust_ca(@config.cacert)
|
87
67
|
|
88
68
|
@http
|
89
69
|
end
|
90
70
|
|
91
71
|
def headers
|
92
72
|
headers = { 'Content-Type' => 'application/json' }
|
93
|
-
headers['X-Authentication'] = @token if @token
|
73
|
+
headers['X-Authentication'] = @config.token if @config.token
|
94
74
|
headers
|
95
75
|
end
|
96
76
|
end
|
data/lib/bolt/puppetdb/config.rb
CHANGED
@@ -11,14 +11,7 @@ module Bolt
|
|
11
11
|
global: '/etc/puppetlabs/client-tools/puppetdb.conf',
|
12
12
|
win_global: 'C:/ProgramData/PuppetLabs/client-tools/puppetdb.conf' }.freeze
|
13
13
|
|
14
|
-
def
|
15
|
-
@settings = load_config(config_file)
|
16
|
-
@settings.merge!(options)
|
17
|
-
expand_paths
|
18
|
-
validate
|
19
|
-
end
|
20
|
-
|
21
|
-
def load_config(filename)
|
14
|
+
def self.load_config(filename, options)
|
22
15
|
global_path = Bolt::Util.windows? ? DEFAULT_CONFIG[:win_global] : DEFAULT_CONFIG[:global]
|
23
16
|
if filename
|
24
17
|
if File.exist?(filename)
|
@@ -33,22 +26,24 @@ module Bolt
|
|
33
26
|
else
|
34
27
|
config = {}
|
35
28
|
end
|
36
|
-
config.fetch('puppetdb', {})
|
29
|
+
config = config.fetch('puppetdb', {})
|
30
|
+
new(config.merge(options))
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(settings)
|
34
|
+
@settings = settings
|
35
|
+
expand_paths
|
37
36
|
end
|
38
37
|
|
39
38
|
def token
|
40
39
|
return @token if @token
|
41
40
|
if @settings['token']
|
42
|
-
File.read(@settings['token'])
|
41
|
+
@token = File.read(@settings['token'])
|
43
42
|
elsif File.exist?(DEFAULT_TOKEN)
|
44
|
-
File.read(DEFAULT_TOKEN)
|
43
|
+
@token = File.read(DEFAULT_TOKEN)
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
48
|
-
def [](key)
|
49
|
-
@settings[key]
|
50
|
-
end
|
51
|
-
|
52
47
|
def expand_paths
|
53
48
|
%w[cacert cert key token].each do |file|
|
54
49
|
@settings[file] = File.expand_path(@settings[file]) if @settings[file]
|
@@ -59,24 +54,56 @@ module Bolt
|
|
59
54
|
if @settings[file] && !File.exist?(@settings[file])
|
60
55
|
raise Bolt::PuppetDBError, "#{file} file #{@settings[file]} does not exist"
|
61
56
|
end
|
57
|
+
true
|
62
58
|
end
|
63
59
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
60
|
+
def uri
|
61
|
+
return @uri if @uri
|
62
|
+
uri = case @settings['server_urls']
|
63
|
+
when String
|
64
|
+
@settings['server_urls']
|
65
|
+
when Array
|
66
|
+
@settings['server_urls'].first
|
67
|
+
when nil
|
68
|
+
raise Bolt::PuppetDBError, "server_urls must be specified"
|
69
|
+
else
|
70
|
+
raise Bolt::PuppetDBError, "server_urls must be a string or array"
|
71
|
+
end
|
72
|
+
|
73
|
+
@uri = URI.parse(uri)
|
74
|
+
@uri.port ||= 8081
|
75
|
+
@uri
|
76
|
+
end
|
77
|
+
|
78
|
+
def cacert
|
79
|
+
if @settings['cacert'] && validate_file_exists('cacert')
|
80
|
+
@settings['cacert']
|
81
|
+
else
|
69
82
|
raise Bolt::PuppetDBError, "cacert must be specified"
|
70
83
|
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def cert
|
87
|
+
validate_cert_and_key
|
88
|
+
validate_file_exists('cert')
|
89
|
+
@settings['cert']
|
90
|
+
end
|
71
91
|
|
92
|
+
def key
|
93
|
+
validate_cert_and_key
|
94
|
+
validate_file_exists('key')
|
95
|
+
@settings['key']
|
96
|
+
end
|
97
|
+
|
98
|
+
def validate_cert_and_key
|
72
99
|
if (@settings['cert'] && !@settings['key']) ||
|
73
100
|
(!@settings['cert'] && @settings['key'])
|
74
101
|
raise Bolt::PuppetDBError, "cert and key must be specified together"
|
75
102
|
end
|
103
|
+
end
|
76
104
|
|
77
|
-
|
78
|
-
|
79
|
-
validate_file_exists('key')
|
105
|
+
def to_hash
|
106
|
+
@settings.dup
|
80
107
|
end
|
81
108
|
end
|
82
109
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'log4r/outputter/outputter'
|
4
|
+
|
5
|
+
module Bolt
|
6
|
+
class R10KLogProxy < Log4r::Outputter
|
7
|
+
def initialize
|
8
|
+
super('bolt')
|
9
|
+
|
10
|
+
@logger = Logging.logger[self]
|
11
|
+
end
|
12
|
+
|
13
|
+
def canonical_log(event)
|
14
|
+
level = to_bolt_level(event.level)
|
15
|
+
@logger.send(level, event.data)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Convert an r10k log level to a bolt log level. These correspond 1-to-1
|
19
|
+
# except that r10k has debug, debug1, and debug2. The log event has the log
|
20
|
+
# level as an integer that we need to look up.
|
21
|
+
def to_bolt_level(level_num)
|
22
|
+
level_str = Log4r::LNAMES[level_num]&.downcase || 'debug'
|
23
|
+
if level_str =~ /debug/
|
24
|
+
:debug
|
25
|
+
else
|
26
|
+
level_str.to_sym
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/bolt/util.rb
CHANGED
@@ -104,9 +104,9 @@ module Bolt
|
|
104
104
|
end
|
105
105
|
|
106
106
|
cl.instance_variables.each do |var|
|
107
|
-
v = cl.
|
107
|
+
v = cl.instance_variable_get(var)
|
108
108
|
v_cl = deep_clone(v, cloned)
|
109
|
-
cl.
|
109
|
+
cl.instance_variable_set(var, v_cl)
|
110
110
|
end
|
111
111
|
|
112
112
|
return cl
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
module Util
|
5
|
+
module PuppetLogLevel
|
6
|
+
MAPPING = {
|
7
|
+
debug: :debug,
|
8
|
+
info: :info,
|
9
|
+
notice: :notice,
|
10
|
+
warning: :warn,
|
11
|
+
err: :error,
|
12
|
+
# The following are used by Puppet functions of the same name, and are all treated as
|
13
|
+
# error types in the Windows EventLog and log colors.
|
14
|
+
alert: :error,
|
15
|
+
emerg: :fatal,
|
16
|
+
crit: :fatal
|
17
|
+
}.freeze
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/bolt/version.rb
CHANGED
@@ -71,7 +71,7 @@ query results.
|
|
71
71
|
|
72
72
|
if @show_help
|
73
73
|
puts @parser.help
|
74
|
-
return
|
74
|
+
return
|
75
75
|
end
|
76
76
|
|
77
77
|
inventory_file = positional_args.shift
|
@@ -83,8 +83,8 @@ query results.
|
|
83
83
|
raise "Unknown argument(s) #{positional_args.join(', ')}"
|
84
84
|
end
|
85
85
|
|
86
|
-
config = Bolt::PuppetDB::Config.
|
87
|
-
@puppetdb_client = Bolt::PuppetDB::Client.
|
86
|
+
config = Bolt::PuppetDB::Config.load_config(@config_file, @cli_opts)
|
87
|
+
@puppetdb_client = Bolt::PuppetDB::Client.new(config)
|
88
88
|
|
89
89
|
unless File.readable?(inventory_file)
|
90
90
|
raise "Can't read the inventory file #{inventory_file}"
|
@@ -100,12 +100,6 @@ query results.
|
|
100
100
|
else
|
101
101
|
puts result
|
102
102
|
end
|
103
|
-
|
104
|
-
0
|
105
|
-
rescue StandardError => e
|
106
|
-
puts "Error: #{e}"
|
107
|
-
puts e.backtrace if @trace
|
108
|
-
1
|
109
103
|
end
|
110
104
|
|
111
105
|
def resolve_group(group)
|