bolt 1.6.0 → 1.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 557353adda3a863e4f748933cb24860616848d1696d9f0914be23474616f43ca
4
- data.tar.gz: 91dc4d72ba25e2e827c5bf170574bedef50c744a4e31ac48684699ff59cdf753
3
+ metadata.gz: cd168415311b9cd4c08f4bbd2a22df94d9ba2f513fa989868507118065720ce8
4
+ data.tar.gz: c5504e881412f51be3a583bb8d091370e4b571ef1a3ed46bca436e433d98fc96
5
5
  SHA512:
6
- metadata.gz: 6a4c8b39f2c353498168cf89a5e70f7b4699e6332e2826efd24a905d94ca7b52ec76a6db98e94f83fe5f7fce4b6c7f58cbc51b56e79b3fce3acf0f014f2669f8
7
- data.tar.gz: 6bf22f4aaef6a2741b64d77b900c9a85fd3c3588feb4a071d582415afbc5ecc479048ba7aea9912131c383d5ec2e3966682f5ea8a3cade87722a927d12275c7e
6
+ metadata.gz: 6934e093666be2c77949a390411237128fd535ac2dbe86435e4a34718eb7f72f39c5ba2412085e02d875daf7b677ffea45acc391bf3a82eb41ad607b8fc8e58e
7
+ data.tar.gz: e7decf1272c8654b10dbb513a1d89cdb6b49ee90f81e562c9f234d235b75e592c0e8f4d8dcabaf7653d75e9f737eb87cac8f16e68c9453f73651edeecd95f636
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fileutils'
4
3
  require 'bolt/task'
5
4
 
6
5
  # Installs the puppet-agent package on targets if needed then collects facts, including any custom
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bolt/task'
4
+
5
+ # Query the state of resources on a list of targets using resource definitions in Bolt's modulepath.
6
+ # The results are returned as a list of hashes representing each resource.
7
+ #
8
+ # Requires the Puppet Agent be installed on the target, which can be accomplished with apply_prep
9
+ # or by directly running the puppet_agent::install task.
10
+ Puppet::Functions.create_function(:get_resources) do
11
+ # @param targets A pattern or array of patterns identifying a set of targets.
12
+ # @param resources A resource type or instance, or an array of such.
13
+ # @example Collect resource states for packages and a file
14
+ # get_resources('target1,target2', [Package, File[/etc/puppetlabs]])
15
+ dispatch :get_resources do
16
+ param 'Boltlib::TargetSpec', :targets
17
+ param 'Variant[String, Resource, Array[Variant[String, Resource]]]', :resources
18
+ end
19
+
20
+ def script_compiler
21
+ @script_compiler ||= Puppet::Pal::ScriptCompiler.new(closure_scope.compiler)
22
+ end
23
+
24
+ def run_task(executor, targets, name, args = {})
25
+ tasksig = script_compiler.task_signature(name)
26
+ raise Bolt::Error.new("#{name} could not be found", 'bolt/get-resources') unless tasksig
27
+
28
+ task = Bolt::Task.new(tasksig.task_hash)
29
+ results = executor.run_task(targets, task, args)
30
+ raise Bolt::RunFailure.new(results, 'run_task', task.name) unless results.ok?
31
+ results
32
+ end
33
+
34
+ def get_resources(target_spec, resources)
35
+ applicator = Puppet.lookup(:apply_executor) { nil }
36
+ executor = Puppet.lookup(:bolt_executor) { nil }
37
+ inventory = Puppet.lookup(:bolt_inventory) { nil }
38
+ unless applicator && executor && inventory && Puppet.features.bolt?
39
+ raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
40
+ Puppet::Pops::Issues::TASK_MISSING_BOLT, action: _('get_resources')
41
+ )
42
+ end
43
+
44
+ resources = [resources].flatten
45
+ resources.each do |resource|
46
+ if resource !~ /^\w+$/ && resource !~ /^\w+\[.+\]$/
47
+ raise Bolt::Error.new("#{resource} is not a valid resource type or type instance name", 'bolt/get-resources')
48
+ end
49
+ end
50
+
51
+ executor.report_function_call('get_resources')
52
+
53
+ targets = inventory.get_targets(target_spec)
54
+
55
+ executor.log_action('gather resources', targets) do
56
+ executor.without_default_logging do
57
+ # Gather facts, including custom facts
58
+ plugins = applicator.build_plugin_tarball do |mod|
59
+ search_dirs = []
60
+ search_dirs << mod.plugins if mod.plugins?
61
+ search_dirs << mod.pluginfacts if mod.pluginfacts?
62
+ search_dirs
63
+ end
64
+
65
+ task = applicator.query_resources_task
66
+ arguments = {
67
+ 'resources' => resources,
68
+ 'plugins' => Puppet::Pops::Types::PSensitiveType::Sensitive.new(plugins)
69
+ }
70
+ results = executor.run_task(targets, task, arguments)
71
+ raise Bolt::RunFailure.new(results, 'run_task', task.name) unless results.ok?
72
+ results
73
+ end
74
+ end
75
+ end
76
+ end
@@ -56,6 +56,15 @@ module Bolt
56
56
  end
57
57
  end
58
58
 
59
+ def query_resources_task
60
+ @query_resources_task ||= begin
61
+ path = File.join(libexec, 'query_resources.rb')
62
+ file = { 'name' => 'query_resources.rb', 'path' => path }
63
+ metadata = { 'supports_noop' => true, 'input_method' => 'stdin' }
64
+ Bolt::Task.new(name: 'apply_helpers::query_resources', files: [file], metadata: metadata)
65
+ end
66
+ end
67
+
59
68
  def compile(target, ast, plan_vars)
60
69
  trusted = Puppet::Context::TrustedInformation.new('local', target.host, {})
61
70
 
@@ -214,7 +214,7 @@ Usage: bolt apply <manifest.pp> [options]
214
214
  'Maximum number of simultaneous manifest block compiles (default: number of cores)') do |concurrency|
215
215
  @options[:'compile-concurrency'] = concurrency
216
216
  end
217
- define('--modulepath MODULES',
217
+ define('-m', '--modulepath MODULES',
218
218
  "List of directories containing modules, separated by '#{File::PATH_SEPARATOR}'") do |modulepath|
219
219
  # When specified from the CLI, modulepath entries are relative to pwd
220
220
  @options[:modulepath] = modulepath.split(File::PATH_SEPARATOR).map do |moduledir|
@@ -229,7 +229,7 @@ Usage: bolt apply <manifest.pp> [options]
229
229
  'Specify where to load config from (default: ~/.puppetlabs/bolt/bolt.yaml)') do |path|
230
230
  @options[:configfile] = path
231
231
  end
232
- define('--inventoryfile FILEPATH',
232
+ define('-i', '--inventoryfile FILEPATH',
233
233
  'Specify where to load inventory from (default: ~/.puppetlabs/bolt/inventory.yaml)') do |path|
234
234
  if ENV.include?(Bolt::Inventory::ENVIRONMENT_VAR)
235
235
  raise Bolt::CLIError, "Cannot pass inventory file when #{Bolt::Inventory::ENVIRONMENT_VAR} is set"
@@ -262,7 +262,7 @@ Usage: bolt apply <manifest.pp> [options]
262
262
  define('-h', '--help', 'Display help') do |_|
263
263
  @options[:help] = true
264
264
  end
265
- define('--verbose', 'Display verbose logging') do |_|
265
+ define('-v', '--verbose', 'Display verbose logging') do |_|
266
266
  @options[:verbose] = true
267
267
  end
268
268
  define('--debug', 'Display debug logging') do |_|
data/lib/bolt/config.rb CHANGED
@@ -146,7 +146,12 @@ module Bolt
146
146
  # Expand paths relative to the Boltdir. Any settings that came from the
147
147
  # CLI will already be absolute, so the expand will be skipped.
148
148
  if data.key?('modulepath')
149
- @modulepath = data['modulepath'].split(File::PATH_SEPARATOR).map do |moduledir|
149
+ moduledirs = if data['modulepath'].is_a?(String)
150
+ data['modulepath'].split(File::PATH_SEPARATOR)
151
+ else
152
+ data['modulepath']
153
+ end
154
+ @modulepath = moduledirs.map do |moduledir|
150
155
  File.expand_path(moduledir, @boltdir.path)
151
156
  end
152
157
  end
@@ -9,7 +9,8 @@ module Bolt
9
9
  module Transport
10
10
  class SSH < Base
11
11
  def self.options
12
- %w[port user password sudo-password private-key host-key-check connect-timeout tmpdir run-as tty run-as-command]
12
+ %w[port user password sudo-password private-key host-key-check
13
+ connect-timeout tmpdir run-as tty run-as-command proxyjump]
13
14
  end
14
15
 
15
16
  def provided_features
@@ -5,6 +5,7 @@ require 'shellwords'
5
5
  require 'bolt/node/errors'
6
6
  require 'bolt/node/output'
7
7
  require 'bolt/util'
8
+ require 'net/ssh/proxy/jump'
8
9
 
9
10
  module Bolt
10
11
  module Transport
@@ -116,6 +117,8 @@ module Bolt
116
117
  end
117
118
  options[:timeout] = target.options['connect-timeout'] if target.options['connect-timeout']
118
119
 
120
+ options[:proxy] = Net::SSH::Proxy::Jump.new(target.options['proxyjump']) if target.options['proxyjump']
121
+
119
122
  if @load_config
120
123
  # Mirroring:
121
124
  # https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh/authentication/agent.rb#L80
data/lib/bolt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bolt
4
- VERSION = '1.6.0'
4
+ VERSION = '1.7.0'
5
5
  end
@@ -211,6 +211,11 @@ module BoltSpec
211
211
  nil
212
212
  end
213
213
 
214
+ def allow_get_resources
215
+ allow_task('apply_helpers::query_resources')
216
+ nil
217
+ end
218
+
214
219
  # Example helpers to mock other run functions
215
220
  # The with_targets method makes sense for all stubs
216
221
  # with_params could be reused for options
@@ -36,7 +36,7 @@ module BoltSpec
36
36
  def initialize(expect = false)
37
37
  @calls = 0
38
38
  @expect = expect
39
- @expected_calls = 1
39
+ @expected_calls = nil
40
40
  # invocation spec
41
41
  @invocation = {}
42
42
  # return value
@@ -63,6 +63,7 @@ module BoltSpec
63
63
  # This changes the stub from an allow to an expect which will validate
64
64
  # that it has been called.
65
65
  def expect_call
66
+ @expected_calls = 1
66
67
  @expect = true
67
68
  self
68
69
  end
@@ -31,7 +31,7 @@ module BoltSpec
31
31
  end
32
32
 
33
33
  def parameters
34
- @invocation[:arguments] + @invocation[:options]
34
+ @invocation[:arguments] + @invocation[:options] if @invocation.include[:arguments]
35
35
  end
36
36
 
37
37
  def result_for(target, stdout: '', stderr: '')
@@ -30,7 +30,7 @@ module BoltSpec
30
30
  end
31
31
 
32
32
  def parameters
33
- @invocation[:arguments] + @invocation[:options]
33
+ @invocation[:arguments] + @invocation[:options] if @invocation.include?(:arguments)
34
34
  end
35
35
 
36
36
  # Allow any data.
data/lib/bolt_spec/run.rb CHANGED
@@ -9,7 +9,6 @@ require 'bolt/puppetdb'
9
9
  require 'bolt/util'
10
10
 
11
11
  # This is intended to provide a relatively stable method of executing bolt in process from tests.
12
- # Currently it provides run_task, run_plan, run_script and run_command helpers.
13
12
  module BoltSpec
14
13
  module Run
15
14
  def run_task(task_name, targets, params = nil, config: nil, inventory: nil)
@@ -49,6 +48,27 @@ module BoltSpec
49
48
  Bolt::Util.walk_keys(result, &:to_s)
50
49
  end
51
50
 
51
+ def apply_manifest(manifest, targets, execute: false, noop: false, config: nil, inventory: nil)
52
+ # The execute parameter is equivalent to the --execute option
53
+ if execute
54
+ code = manifest
55
+ else
56
+ begin
57
+ unless File.stat(manifest).readable?
58
+ raise BOLT::FileError.new("The manifest '#{manifest}' is unreadable", manifest)
59
+ end
60
+ rescue Errno::ENOENT
61
+ raise Bolt::FileError.new("The manifest '#{manifest}' does not exist", manifest)
62
+ end
63
+ code = File.read(File.expand_path(manifest))
64
+ filename = manifest
65
+ end
66
+ result = BoltRunner.with_runner(config, inventory) do |runner|
67
+ runner.apply_manifest(code, targets, filename, noop)
68
+ end
69
+ JSON.parse(result.to_json)
70
+ end
71
+
52
72
  class BoltRunner
53
73
  # Creates a temporary boltdir so no settings are picked up
54
74
  # WARNING: puppetdb config and orch config which do not use the boltdir may
@@ -107,6 +127,20 @@ module BoltSpec
107
127
  targets = inventory.get_targets(targets)
108
128
  executor.run_script(targets, script, arguments, options)
109
129
  end
130
+
131
+ def apply_manifest(code, targets, filename = nil, noop = false)
132
+ ast = pal.parse_manifest(code, filename)
133
+ executor = Bolt::Executor.new(config.concurrency, @analytics, noop)
134
+ targets = inventory.get_targets(targets)
135
+
136
+ pal.in_plan_compiler(executor, inventory, puppetdb_client) do |compiler|
137
+ compiler.call_function('apply_prep', targets)
138
+ end
139
+
140
+ pal.with_bolt_executor(executor, inventory, puppetdb_client) do
141
+ Puppet.lookup(:apply_executor).apply_ast(ast, targets, '_catch_errors' => true, '_noop' => noop)
142
+ end
143
+ end
110
144
  end
111
145
  end
112
146
  end
@@ -0,0 +1,49 @@
1
+ #! /opt/puppetlabs/puppet/bin/ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'json'
5
+ require 'puppet'
6
+ require 'puppet/module_tool/tar'
7
+ require 'tempfile'
8
+
9
+ args = JSON.parse(STDIN.read)
10
+
11
+ RESOURCE_INSTANCE = /^([^\[]+)\[([^\]]+)\]$/.freeze
12
+
13
+ def instance(type_name, resource_name)
14
+ resource = Puppet::Resource.indirection.find("#{type_name}/#{resource_name}")
15
+ stringify_resource(resource)
16
+ end
17
+
18
+ Dir.mktmpdir do |puppet_root|
19
+ # Create temporary directories for all core Puppet settings so we don't clobber
20
+ # existing state or read from puppet.conf. Also create a temporary modulepath.
21
+ moduledir = File.join(puppet_root, 'modules')
22
+ Dir.mkdir(moduledir)
23
+ cli = Puppet::Settings::REQUIRED_APP_SETTINGS.flat_map do |setting|
24
+ ["--#{setting}", File.join(puppet_root, setting.to_s.chomp('dir'))]
25
+ end
26
+ cli << '--modulepath' << moduledir
27
+ Puppet.initialize_settings(cli)
28
+
29
+ Tempfile.open('plugins.tar.gz') do |plugins|
30
+ File.binwrite(plugins, Base64.decode64(args['plugins']))
31
+ Puppet::ModuleTool::Tar.instance.unpack(plugins, moduledir, Etc.getlogin || Etc.getpwuid.name)
32
+ end
33
+
34
+ env = Puppet.lookup(:environments).get('production')
35
+ env.each_plugin_directory do |dir|
36
+ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
37
+ end
38
+
39
+ resources = args['resources'].flat_map do |resource_desc|
40
+ if (match = RESOURCE_INSTANCE.match(resource_desc))
41
+ Puppet::Resource.indirection.find("#{match[1]}/#{match[2]}", environment: env)
42
+ else
43
+ Puppet::Resource.indirection.search(resource_desc, environment: env)
44
+ end
45
+ end
46
+ puts({ 'resources' => resources }.to_json)
47
+ end
48
+
49
+ exit 0
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: 1.6.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-12-13 00:00:00.000000000 Z
11
+ date: 2018-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -301,6 +301,7 @@ files:
301
301
  - bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb
302
302
  - bolt-modules/boltlib/lib/puppet/functions/facts.rb
303
303
  - bolt-modules/boltlib/lib/puppet/functions/fail_plan.rb
304
+ - bolt-modules/boltlib/lib/puppet/functions/get_resources.rb
304
305
  - bolt-modules/boltlib/lib/puppet/functions/get_targets.rb
305
306
  - bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb
306
307
  - bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb
@@ -390,6 +391,7 @@ files:
390
391
  - libexec/apply_catalog.rb
391
392
  - libexec/bolt_catalog
392
393
  - libexec/custom_facts.rb
394
+ - libexec/query_resources.rb
393
395
  - modules/aggregate/lib/puppet/functions/aggregate/count.rb
394
396
  - modules/aggregate/lib/puppet/functions/aggregate/nodes.rb
395
397
  - modules/aggregate/plans/count.pp