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.

@@ -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::Error.new("Could not parse inventory from $#{ENVIRONMENT_VAR}", 'bolt/parse-error')
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[:inventoryfile], [config.default_inventory], 'inventory')
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.new
59
+ @config = config || Bolt::Config.default
60
60
  @data = data ||= {}
61
61
  @groups = Group.new(data.merge('name' => 'all'))
62
62
  @group_lookup = {}
@@ -27,12 +27,12 @@ module Bolt
27
27
  )
28
28
  end
29
29
 
30
- def self.configure(config)
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(config[:color]),
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
- config[:log].each_pair do |name, params|
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:')
@@ -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
@@ -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
@@ -36,7 +36,7 @@ module Bolt
36
36
  end
37
37
  end
38
38
 
39
- def initialize(config)
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
- @config = config
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: full_modulepath(@config[:modulepath]), facts: {}) do |pal|
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
- full_modulepath(@config[:modulepath]),
126
- @config.puppetdb,
127
- @config[:'hiera-config'],
128
- @config[:'compile-concurrency']
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
@@ -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(@log_level_map[log.level], log.to_s)
15
+ @external_logger.send(Bolt::Util::PuppetLogLevel::MAPPING[log.level], log.to_s)
27
16
  end
28
17
  end
@@ -7,30 +7,10 @@ require 'httpclient'
7
7
  module Bolt
8
8
  module PuppetDB
9
9
  class Client
10
- def self.from_config(config)
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
- cacert = File.expand_path(config['cacert'])
20
- token = config.token
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
@@ -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 initialize(config_file, options)
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 validate
65
- unless @settings['server_urls']
66
- raise Bolt::PuppetDBError, "server_urls must be specified"
67
- end
68
- unless @settings['cacert']
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
- validate_file_exists('cacert')
78
- validate_file_exists('cert')
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
@@ -104,9 +104,9 @@ module Bolt
104
104
  end
105
105
 
106
106
  cl.instance_variables.each do |var|
107
- v = cl.instance_eval { var }
107
+ v = cl.instance_variable_get(var)
108
108
  v_cl = deep_clone(v, cloned)
109
- cl.instance_eval { @var = v_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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bolt
4
- VERSION = '0.21.3'
4
+ VERSION = '0.21.4'
5
5
  end
@@ -71,7 +71,7 @@ query results.
71
71
 
72
72
  if @show_help
73
73
  puts @parser.help
74
- return 0
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.new(@config_file, @cli_opts)
87
- @puppetdb_client = Bolt::PuppetDB::Client.from_config(config)
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)