bolt 2.9.0 → 2.13.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +2 -2
  3. data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +2 -0
  4. data/bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb +28 -0
  5. data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +2 -0
  6. data/bolt-modules/boltlib/lib/puppet/datatypes/resultset.rb +2 -0
  7. data/bolt-modules/boltlib/lib/puppet/datatypes/target.rb +4 -3
  8. data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +1 -1
  9. data/bolt-modules/boltlib/lib/puppet/functions/get_resources.rb +1 -1
  10. data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +61 -0
  11. data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +4 -2
  12. data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +8 -2
  13. data/bolt-modules/boltlib/lib/puppet/functions/set_resources.rb +144 -0
  14. data/bolt-modules/boltlib/types/planresult.pp +1 -0
  15. data/bolt-modules/file/lib/puppet/functions/file/exists.rb +3 -1
  16. data/bolt-modules/file/lib/puppet/functions/file/join.rb +1 -1
  17. data/bolt-modules/file/lib/puppet/functions/file/read.rb +2 -1
  18. data/bolt-modules/file/lib/puppet/functions/file/readable.rb +3 -1
  19. data/bolt-modules/file/lib/puppet/functions/file/write.rb +3 -1
  20. data/lib/bolt/analytics.rb +21 -2
  21. data/lib/bolt/applicator.rb +7 -2
  22. data/lib/bolt/apply_result.rb +1 -1
  23. data/lib/bolt/apply_target.rb +3 -2
  24. data/lib/bolt/bolt_option_parser.rb +18 -8
  25. data/lib/bolt/catalog.rb +4 -1
  26. data/lib/bolt/cli.rb +15 -5
  27. data/lib/bolt/config.rb +44 -16
  28. data/lib/bolt/config/transport/ssh.rb +47 -1
  29. data/lib/bolt/inventory.rb +2 -1
  30. data/lib/bolt/inventory/inventory.rb +5 -0
  31. data/lib/bolt/inventory/target.rb +17 -1
  32. data/lib/bolt/node/output.rb +1 -1
  33. data/lib/bolt/pal.rb +3 -0
  34. data/lib/bolt/pal/yaml_plan.rb +1 -0
  35. data/lib/bolt/plugin.rb +13 -7
  36. data/lib/bolt/plugin/puppetdb.rb +5 -2
  37. data/lib/bolt/project.rb +25 -7
  38. data/lib/bolt/puppetdb/config.rb +14 -26
  39. data/lib/bolt/resource_instance.rb +129 -0
  40. data/lib/bolt/shell/bash.rb +1 -1
  41. data/lib/bolt/target.rb +12 -1
  42. data/lib/bolt/transport/ssh.rb +6 -2
  43. data/lib/bolt/transport/ssh/connection.rb +4 -0
  44. data/lib/bolt/transport/ssh/exec_connection.rb +110 -0
  45. data/lib/bolt/transport/winrm/connection.rb +4 -0
  46. data/lib/bolt/version.rb +1 -1
  47. data/lib/bolt_server/pe/pal.rb +1 -38
  48. data/lib/bolt_spec/bolt_context.rb +1 -4
  49. data/lib/bolt_spec/plans/mock_executor.rb +1 -0
  50. data/lib/bolt_spec/run.rb +2 -5
  51. metadata +6 -2
@@ -353,9 +353,9 @@ module Bolt
353
353
  # Chunks of this size will be read in one iteration
354
354
  index = 0
355
355
  timeout = 0.1
356
+ result_output = Bolt::Node::Output.new
356
357
 
357
358
  inp, out, err, t = conn.execute(command_str)
358
- result_output = Bolt::Node::Output.new
359
359
  read_streams = { out => String.new,
360
360
  err => String.new }
361
361
  write_stream = in_buffer.empty? ? [] : [inp]
@@ -31,7 +31,8 @@ module Bolt
31
31
  facts = nil,
32
32
  vars = nil,
33
33
  features = nil,
34
- plugin_hooks = nil)
34
+ plugin_hooks = nil,
35
+ resources = nil)
35
36
  from_asserted_hash('uri' => uri)
36
37
  end
37
38
  # rubocop:enable Lint/UnusedMethodArgument
@@ -75,6 +76,16 @@ module Bolt
75
76
  inventory_target.target_alias
76
77
  end
77
78
 
79
+ def resources
80
+ inventory_target.resources
81
+ end
82
+
83
+ # rubocop:disable Naming/AccessorMethodName
84
+ def set_resource(resource)
85
+ inventory_target.set_resource(resource)
86
+ end
87
+ # rubocop:enable Naming/AccessorMethodName
88
+
78
89
  def to_h
79
90
  options.to_h.merge(
80
91
  'name' => name,
@@ -16,13 +16,16 @@ module Bolt
16
16
  rescue LoadError
17
17
  logger.debug("Authentication method 'gssapi-with-mic' (Kerberos) is not available.")
18
18
  end
19
-
20
19
  @transport_logger = Logging.logger[Net::SSH]
21
20
  @transport_logger.level = :warn
22
21
  end
23
22
 
24
23
  def with_connection(target)
25
- conn = Connection.new(target, @transport_logger)
24
+ conn = if target.transport_config['ssh-command']
25
+ ExecConnection.new(target)
26
+ else
27
+ Connection.new(target, @transport_logger)
28
+ end
26
29
  conn.connect
27
30
  yield conn
28
31
  ensure
@@ -37,3 +40,4 @@ module Bolt
37
40
  end
38
41
 
39
42
  require 'bolt/transport/ssh/connection'
43
+ require 'bolt/transport/ssh/exec_connection'
@@ -207,6 +207,10 @@ module Bolt
207
207
  err_wr.close
208
208
  end
209
209
  [in_wr, out_rd, err_rd, th]
210
+ rescue Errno::EMFILE => e
211
+ msg = "#{e.message}. This may be resolved by increasing your user limit "\
212
+ "with 'ulimit -n 1024'. See https://puppet.com/docs/bolt/latest/bolt_known_issues.html for details."
213
+ raise Bolt::Error.new(msg, 'bolt/too-many-files')
210
214
  end
211
215
 
212
216
  def copy_file(source, destination)
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ module Bolt
6
+ module Transport
7
+ class SSH < Simple
8
+ class ExecConnection
9
+ attr_reader :user, :target
10
+
11
+ def initialize(target)
12
+ raise Bolt::ValidationError, "Target #{target.safe_name} does not have a host" unless target.host
13
+
14
+ @target = target
15
+ ssh_config = Net::SSH::Config.for(target.host)
16
+ @user = @target.user || ssh_config[:user] || Etc.getlogin
17
+ @logger = Logging.logger[self]
18
+ end
19
+
20
+ # This is used to verify we can connect to targets with `connected?`
21
+ def connect
22
+ cmd = build_ssh_command('exit')
23
+ _, err, stat = Open3.capture3(*cmd)
24
+ unless stat.success?
25
+ raise Bolt::Node::ConnectError.new(
26
+ "Failed to connect to #{@target.safe_name}: #{err}",
27
+ 'CONNECT_ERROR'
28
+ )
29
+ end
30
+ end
31
+
32
+ def disconnect; end
33
+
34
+ def shell
35
+ Bolt::Shell::Bash.new(@target, self)
36
+ end
37
+
38
+ def userhost
39
+ "#{@user}@#{@target.host}"
40
+ end
41
+
42
+ def ssh_opts
43
+ cmd = []
44
+ # BatchMode is SSH's noninteractive option: if key authentication
45
+ # fails it will error out instead of falling back to password prompt
46
+ cmd += %w[-o BatchMode=yes]
47
+ cmd += %W[-o Port=#{@target.port}] if @target.port
48
+
49
+ if @target.transport_config.key?('host-key-check')
50
+ hkc = @target.transport_config['host-key-check'] ? 'yes' : 'no'
51
+ cmd += %W[-o StrictHostKeyChecking=#{hkc}]
52
+ end
53
+
54
+ if (key = target.transport_config['private-key'])
55
+ cmd += ['-i', key]
56
+ end
57
+ cmd
58
+ end
59
+
60
+ def build_ssh_command(command)
61
+ ssh_conf = @target.transport_config['ssh-command']
62
+ ssh_cmd = Array(ssh_conf)
63
+ ssh_cmd += ssh_opts
64
+ ssh_cmd << userhost
65
+ ssh_cmd << command
66
+ end
67
+
68
+ def copy_file(source, dest)
69
+ @logger.debug { "Uploading #{source}, to #{userhost}:#{dest}" } unless source.is_a?(StringIO)
70
+
71
+ cp_conf = @target.transport_config['copy-command'] || ["scp", "-r"]
72
+ cp_cmd = Array(cp_conf)
73
+ cp_cmd += ssh_opts
74
+
75
+ _, err, stat = if source.is_a?(StringIO)
76
+ Tempfile.create(File.basename(dest)) do |f|
77
+ f.write(source.read)
78
+ f.close
79
+ cp_cmd << f.path
80
+ cp_cmd << "#{userhost}:#{Shellwords.escape(dest)}"
81
+ Open3.capture3(*cp_cmd)
82
+ end
83
+ else
84
+ cp_cmd << source
85
+ cp_cmd << "#{userhost}:#{Shellwords.escape(dest)}"
86
+ Open3.capture3(*cp_cmd)
87
+ end
88
+
89
+ if stat.success?
90
+ @logger.debug "Successfully uploaded #{source} to #{dest}"
91
+ else
92
+ message = "Could not copy file to #{dest}: #{err}"
93
+ raise Bolt::Node::FileError.new(message, 'COPY_ERROR')
94
+ end
95
+ end
96
+
97
+ def execute(command)
98
+ cmd_array = build_ssh_command(command)
99
+ Open3.popen3(*cmd_array)
100
+ end
101
+
102
+ # This is used by the Bash shell to decide whether to `cd` before
103
+ # executing commands as a run-as user
104
+ def reset_cwd?
105
+ true
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -120,6 +120,10 @@ module Bolt
120
120
  end
121
121
 
122
122
  [inp, out_rd, err_rd, th]
123
+ rescue Errno::EMFILE => e
124
+ msg = "#{e.message}. This may be resolved by increasing your user limit "\
125
+ "with 'ulimit -n 1024'. See https://puppet.com/docs/bolt/latest/bolt_known_issues.html for details."
126
+ raise Bolt::Error.new(msg, 'bolt/too-many-files')
123
127
  rescue StandardError
124
128
  @logger.debug { "Command aborted" }
125
129
  raise
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bolt
4
- VERSION = '2.9.0'
4
+ VERSION = '2.13.0'
5
5
  end
@@ -51,50 +51,13 @@ module BoltServer
51
51
  basemodulepath = plan_executor_config['basemodulepath'] || "#{codedir}/modules:/opt/puppetlabs/puppet/modules"
52
52
 
53
53
  with_pe_pal_init_settings(codedir, environmentpath, basemodulepath) do
54
- modulepath_dirs = []
55
- modulepath_setting_from_bolt = nil
56
54
  environment = Puppet.lookup(:environments).get!(environment_name)
57
- path_to_env = environment.configuration.path_to_env
58
-
59
- # In the instance where the environment is "production" but no production dir
60
- # exists, the lookup will succeed, but the configuration will be mostly empty.
61
- # For other environments the lookup will fail, but for production we don't
62
- # want cryptic messages sent to the user about combining `nil` with a string.
63
- # Thus if we do get here and `path_to_env` is empty, just assume it's the
64
- # default production environment and continue.
65
- #
66
- # This should hopefully match puppet's behavior for the default 'production'
67
- # environment: _technically_ that environment always exists, but if the dir
68
- # isn't there it won't find the module and fail with "plan not found" rather
69
- # than "environment doesn't exist"
70
- if path_to_env
71
- bolt_yaml = File.join(environment.configuration.path_to_env, 'bolt.yaml')
72
- modulepath_setting_from_bolt = Bolt::Util.read_optional_yaml_hash(bolt_yaml, 'config')['modulepath']
73
- end
74
-
75
- # If we loaded a bolt.yaml in the environment root and it contained a modulepath setting:
76
- # we will use that modulepath rather than the one loaded through puppet. modulepath will
77
- # be the _only_ setting that will work from bolt.yaml in plans in PE.
78
- if modulepath_setting_from_bolt
79
- modulepath_setting_from_bolt.split(File::PATH_SEPARATOR).each do |path|
80
- if Pathname.new(path).absolute? && File.exist?(path)
81
- modulepath_dirs << path
82
- elsif File.exist?(File.join(path_to_env, path))
83
- modulepath_dirs << File.join(path_to_env, path)
84
- end
85
- end
86
-
87
- # Append the basemodulepath to include "built-in" modules.
88
- modulepath_dirs.concat(basemodulepath.split(File::PATH_SEPARATOR))
89
- else
90
- modulepath_dirs = environment.modulepath
91
- end
92
-
93
55
  # A new modulepath is created from scratch (rather than using super's @modulepath)
94
56
  # so that we can have full control over all the entries in modulepath. In the future
95
57
  # it's likely we will need to preceed _both_ Bolt::PAL::BOLTLIB_PATH _and_
96
58
  # Bolt::PAL::MODULES_PATH which would be more complex if we tried to use @modulepath since
97
59
  # we need to append our modulepaths and exclude modules shiped in bolt gem code
60
+ modulepath_dirs = environment.modulepath
98
61
  @original_modulepath = modulepath_dirs
99
62
  @modulepath = [PE_BOLTLIB_PATH, Bolt::PAL::BOLTLIB_PATH, *modulepath_dirs]
100
63
  end
@@ -145,10 +145,7 @@ module BoltSpec
145
145
  end
146
146
 
147
147
  def plugins
148
- @plugins ||= Bolt::Plugin.setup(config,
149
- pal,
150
- nil,
151
- Bolt::Analytics::NoopClient.new)
148
+ @plugins ||= Bolt::Plugin.setup(config, pal)
152
149
  end
153
150
 
154
151
  def pal
@@ -230,6 +230,7 @@ module BoltSpec
230
230
  def transport(_protocol)
231
231
  Class.new do
232
232
  attr_reader :provided_features
233
+
233
234
  def initialize(features)
234
235
  @provided_features = features
235
236
  end
@@ -152,14 +152,11 @@ module BoltSpec
152
152
  end
153
153
 
154
154
  def plugins
155
- @plugins ||= Bolt::Plugin.setup(config, pal, puppetdb_client, @analytics)
155
+ @plugins ||= Bolt::Plugin.setup(config, pal)
156
156
  end
157
157
 
158
158
  def puppetdb_client
159
- @puppetdb_client ||= begin
160
- puppetdb_config = Bolt::PuppetDB::Config.load_config(nil, config.puppetdb)
161
- Bolt::PuppetDB::Client.new(puppetdb_config)
162
- end
159
+ plugins.puppetdb_client
163
160
  end
164
161
 
165
162
  def pal
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bolt
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.0
4
+ version: 2.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-11 00:00:00.000000000 Z
11
+ date: 2020-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -390,6 +390,7 @@ extra_rdoc_files: []
390
390
  files:
391
391
  - Puppetfile
392
392
  - bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb
393
+ - bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb
393
394
  - bolt-modules/boltlib/lib/puppet/datatypes/result.rb
394
395
  - bolt-modules/boltlib/lib/puppet/datatypes/resultset.rb
395
396
  - bolt-modules/boltlib/lib/puppet/datatypes/target.rb
@@ -413,6 +414,7 @@ files:
413
414
  - bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb
414
415
  - bolt-modules/boltlib/lib/puppet/functions/set_config.rb
415
416
  - bolt-modules/boltlib/lib/puppet/functions/set_feature.rb
417
+ - bolt-modules/boltlib/lib/puppet/functions/set_resources.rb
416
418
  - bolt-modules/boltlib/lib/puppet/functions/set_var.rb
417
419
  - bolt-modules/boltlib/lib/puppet/functions/upload_file.rb
418
420
  - bolt-modules/boltlib/lib/puppet/functions/vars.rb
@@ -493,6 +495,7 @@ files:
493
495
  - lib/bolt/puppetdb/config.rb
494
496
  - lib/bolt/r10k_log_proxy.rb
495
497
  - lib/bolt/rerun.rb
498
+ - lib/bolt/resource_instance.rb
496
499
  - lib/bolt/result.rb
497
500
  - lib/bolt/result_set.rb
498
501
  - lib/bolt/secret.rb
@@ -516,6 +519,7 @@ files:
516
519
  - lib/bolt/transport/simple.rb
517
520
  - lib/bolt/transport/ssh.rb
518
521
  - lib/bolt/transport/ssh/connection.rb
522
+ - lib/bolt/transport/ssh/exec_connection.rb
519
523
  - lib/bolt/transport/winrm.rb
520
524
  - lib/bolt/transport/winrm/connection.rb
521
525
  - lib/bolt/util.rb