bolt 2.13.0 → 2.14.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/bolt-modules/boltlib/lib/puppet/functions/resource.rb +52 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +5 -1
- data/lib/bolt/applicator.rb +2 -1
- data/lib/bolt/apply_inventory.rb +4 -0
- data/lib/bolt/apply_target.rb +4 -0
- data/lib/bolt/catalog.rb +79 -69
- data/lib/bolt/cli.rb +5 -5
- data/lib/bolt/config.rb +30 -25
- data/lib/bolt/config/transport/ssh.rb +130 -91
- data/lib/bolt/executor.rb +14 -1
- data/lib/bolt/inventory/group.rb +1 -1
- data/lib/bolt/inventory/inventory.rb +4 -0
- data/lib/bolt/inventory/target.rb +4 -0
- data/lib/bolt/project.rb +45 -12
- data/lib/bolt/resource_instance.rb +5 -1
- data/lib/bolt/shell/powershell/snippets.rb +8 -0
- data/lib/bolt/transport/local/connection.rb +2 -1
- data/lib/bolt/transport/ssh/connection.rb +35 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_spec/bolt_context.rb +1 -1
- data/lib/bolt_spec/run.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbe6053f1a3801adb0f1d0684f1e4616311c93bf0513a74cde2c54c82d5de503
|
4
|
+
data.tar.gz: b51e4068dcceb096d5e6cec4a79d692b84d1472abe57065de1a219d8ed84a4ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea53a6643459311d007ad7b8c2a60e5d0d4af6b0005b037295edff063a2e1f0236054d9cb5c14cec039ee8d0eb0ffa94e887b6a1ba64c3bb196f2a10cd90ce6d
|
7
|
+
data.tar.gz: 7bfde56e613103081c5ce73095c82b897f5db8b973365e6fbd28dfc7f57873fce518d37fe55bb76e36f36ab9dc802a12e545621bbff44f3a389ff071898bbc2c
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Lookup a resource in the target's data.
|
4
|
+
#
|
5
|
+
# For more information about resources see [the
|
6
|
+
# documentation](https://puppet.com/docs/puppet/latest/lang_resources.html).
|
7
|
+
#
|
8
|
+
# > **Note:** The `ResourceInstance` data type is under active development and is subject to
|
9
|
+
# change. You can read more about the data type in the [experimental features
|
10
|
+
# documentation](experimental_features.md#resourceinstance-data-type).
|
11
|
+
Puppet::Functions.create_function(:resource) do
|
12
|
+
# Lookup a resource in the target's data.
|
13
|
+
# @param target The Target object to add resources to. See {get_targets}.
|
14
|
+
# @param type The type of the resource
|
15
|
+
# @param title The title of the resource
|
16
|
+
# @return The ResourceInstance if found, or Undef
|
17
|
+
# @example Get the openssl package resource
|
18
|
+
# $target.apply_prep
|
19
|
+
# $resources = $target.get_resources(Package).first['resources']
|
20
|
+
# $target.set_resources($resources)
|
21
|
+
# $openssl = $target.resource('Package', 'openssl')
|
22
|
+
dispatch :resource do
|
23
|
+
param 'Target', :target
|
24
|
+
param 'Type[Resource]', :type
|
25
|
+
param 'String[1]', :title
|
26
|
+
return_type 'Optional[ResourceInstance]'
|
27
|
+
end
|
28
|
+
|
29
|
+
# Lookup a resource in the target's data, referring to resource as a string
|
30
|
+
# @param target The Target object to add resources to. See {get_targets}.
|
31
|
+
# @param type The type of the resource
|
32
|
+
# @param title The title of the resource
|
33
|
+
# @return The ResourceInstance if found, or Undef
|
34
|
+
dispatch :resource_from_string do
|
35
|
+
param 'Target', :target
|
36
|
+
param 'String[1]', :type
|
37
|
+
param 'String[1]', :title
|
38
|
+
return_type 'Optional[ResourceInstance]'
|
39
|
+
end
|
40
|
+
|
41
|
+
def resource(target, type, title)
|
42
|
+
inventory = Puppet.lookup(:bolt_inventory)
|
43
|
+
executor = Puppet.lookup(:bolt_executor) { nil }
|
44
|
+
executor&.report_function_call(self.class.name)
|
45
|
+
|
46
|
+
inventory.resource(target, type, title)
|
47
|
+
end
|
48
|
+
|
49
|
+
def resource_from_string(target, type, title)
|
50
|
+
resource(target, type, title)
|
51
|
+
end
|
52
|
+
end
|
@@ -187,7 +187,11 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
|
|
187
187
|
params.each_with_object({}) do |(name, value), acc|
|
188
188
|
model = models[name]
|
189
189
|
|
190
|
-
|
190
|
+
# Parameters passed to a plan that the plan is not expecting don't have a model,
|
191
|
+
# so keep the parameter as-is.
|
192
|
+
if model.nil?
|
193
|
+
acc[name] = value
|
194
|
+
elsif sensitive_type?(model.type_expr)
|
191
195
|
acc[name] = Puppet::Pops::Types::PSensitiveType::Sensitive.new(value)
|
192
196
|
else
|
193
197
|
if model.type_expr.to_s.include?('Sensitive')
|
data/lib/bolt/applicator.rb
CHANGED
@@ -21,7 +21,7 @@ module Bolt
|
|
21
21
|
|
22
22
|
@inventory = inventory
|
23
23
|
@executor = executor
|
24
|
-
@modulepath = modulepath
|
24
|
+
@modulepath = modulepath || []
|
25
25
|
@plugin_dirs = plugin_dirs
|
26
26
|
@project = project
|
27
27
|
@pdb_client = pdb_client
|
@@ -146,6 +146,7 @@ module Bolt
|
|
146
146
|
|
147
147
|
def apply(args, apply_body, scope)
|
148
148
|
raise(ArgumentError, 'apply requires a TargetSpec') if args.empty?
|
149
|
+
raise(ArgumentError, 'apply requires at least one statement in the apply block') if apply_body.nil?
|
149
150
|
type0 = Puppet.lookup(:pal_script_compiler).type('TargetSpec')
|
150
151
|
Puppet::Pal.assert_type(type0, args[0], 'apply targets')
|
151
152
|
|
data/lib/bolt/apply_inventory.rb
CHANGED
data/lib/bolt/apply_target.rb
CHANGED
data/lib/bolt/catalog.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'bolt/apply_inventory'
|
3
4
|
require 'bolt/apply_target'
|
4
5
|
require 'bolt/config'
|
5
6
|
require 'bolt/error'
|
6
7
|
require 'bolt/inventory'
|
7
|
-
require 'bolt/apply_inventory'
|
8
8
|
require 'bolt/pal'
|
9
9
|
require 'bolt/puppetdb'
|
10
10
|
require 'bolt/util'
|
@@ -19,7 +19,7 @@ module Bolt
|
|
19
19
|
@log_level = log_level
|
20
20
|
end
|
21
21
|
|
22
|
-
def with_puppet_settings(
|
22
|
+
def with_puppet_settings(overrides = {})
|
23
23
|
Dir.mktmpdir('bolt') do |dir|
|
24
24
|
cli = []
|
25
25
|
Puppet::Settings::REQUIRED_APP_SETTINGS.each do |setting|
|
@@ -31,7 +31,9 @@ module Bolt
|
|
31
31
|
Puppet.settings.override_default(:vendormoduledir, '')
|
32
32
|
|
33
33
|
Puppet.initialize_settings(cli)
|
34
|
-
|
34
|
+
overrides.each do |setting, value|
|
35
|
+
Puppet.settings[setting] = value
|
36
|
+
end
|
35
37
|
|
36
38
|
# Use a special logdest that serializes all log messages and their level to stderr.
|
37
39
|
Puppet::Util::Log.newdestination(:stderr)
|
@@ -54,83 +56,51 @@ module Bolt
|
|
54
56
|
end
|
55
57
|
|
56
58
|
def compile_catalog(request)
|
57
|
-
pal_main = request['code_ast'] || request['code_string']
|
58
|
-
target = request['target']
|
59
59
|
pdb_client = Bolt::PuppetDB::Client.new(Bolt::PuppetDB::Config.new(request['pdb_config']))
|
60
|
-
options = request['puppet_config'] || {}
|
61
60
|
project = request['project'] || {}
|
62
61
|
bolt_project = Struct.new(:name, :path).new(project['name'], project['path']) unless project.empty?
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
62
|
+
inv = Bolt::ApplyInventory.new(request['config'])
|
63
|
+
puppet_overrides = {
|
64
|
+
bolt_pdb_client: pdb_client,
|
65
|
+
bolt_inventory: inv,
|
66
|
+
bolt_project: bolt_project
|
67
|
+
}
|
68
|
+
|
69
|
+
# Facts will be set by the catalog compiler, so we need to ensure
|
70
|
+
# that any plan or target variables with the same name are not
|
71
|
+
# passed into the apply block to avoid a redefinition error.
|
72
|
+
# Filter out plan and target vars separately and raise a Puppet
|
73
|
+
# warning if there are any collisions for either. Puppet warning
|
74
|
+
# is the only way to log a message that will make it back to Bolt
|
75
|
+
# to be printed.
|
76
|
+
target = request['target']
|
77
|
+
plan_vars = shadow_vars('plan', request['plan_vars'], target['facts'])
|
78
|
+
target_vars = shadow_vars('target', target['variables'], target['facts'])
|
79
|
+
topscope_vars = target_vars.merge(plan_vars)
|
80
|
+
env_conf = { modulepath: request['modulepath'],
|
81
|
+
facts: target['facts'],
|
82
|
+
variables: topscope_vars }
|
83
|
+
|
84
|
+
puppet_settings = {
|
85
|
+
node_name_value: target['name'],
|
86
|
+
hiera_config: request['hiera_config']
|
87
|
+
}
|
88
|
+
|
89
|
+
with_puppet_settings(puppet_settings) do
|
69
90
|
Puppet::Pal.in_tmp_environment('bolt_catalog', env_conf) do |pal|
|
70
|
-
|
71
|
-
Puppet.override(bolt_pdb_client: pdb_client,
|
72
|
-
bolt_inventory: inv,
|
73
|
-
bolt_project: bolt_project) do
|
91
|
+
Puppet.override(puppet_overrides) do
|
74
92
|
Puppet.lookup(:pal_current_node).trusted_data = target['trusted']
|
75
93
|
pal.with_catalog_compiler do |compiler|
|
76
|
-
|
77
|
-
# loaders are initialized for loading
|
78
|
-
plan_vars = Puppet::Pops::Serialization::FromDataConverter.convert(request['plan_vars'])
|
79
|
-
|
80
|
-
# Facts will be set by the catalog compiler, so we need to ensure
|
81
|
-
# that any plan or target variables with the same name are not
|
82
|
-
# passed into the apply block to avoid a redefinition error.
|
83
|
-
# Filter out plan and target vars separately and raise a Puppet
|
84
|
-
# warning if there are any collisions for either. Puppet warning
|
85
|
-
# is the only way to log a message that will make it back to Bolt
|
86
|
-
# to be printed.
|
87
|
-
pv_collisions, pv_filtered = plan_vars.partition do |k, _|
|
88
|
-
target['facts'].keys.include?(k)
|
89
|
-
end.map(&:to_h)
|
90
|
-
unless pv_collisions.empty?
|
91
|
-
print_pv = pv_collisions.keys.map { |k| "$#{k}" }.join(', ')
|
92
|
-
plural = pv_collisions.keys.length == 1 ? '' : 's'
|
93
|
-
Puppet.warning("Plan variable#{plural} #{print_pv} will be overridden by fact#{plural} " \
|
94
|
-
"of the same name in the apply block")
|
95
|
-
end
|
96
|
-
|
97
|
-
tv_collisions, tv_filtered = target['variables'].partition do |k, _|
|
98
|
-
target['facts'].keys.include?(k)
|
99
|
-
end.map(&:to_h)
|
100
|
-
unless tv_collisions.empty?
|
101
|
-
print_tv = tv_collisions.keys.map { |k| "$#{k}" }.join(', ')
|
102
|
-
plural = tv_collisions.keys.length == 1 ? '' : 's'
|
103
|
-
Puppet.warning("Target variable#{plural} #{print_tv} " \
|
104
|
-
"will be overridden by fact#{plural} of the same name in the apply block")
|
105
|
-
end
|
106
|
-
|
107
|
-
pal.send(:add_variables, compiler.send(:topscope), tv_filtered.merge(pv_filtered))
|
108
|
-
|
94
|
+
options = request['puppet_config'] || {}
|
109
95
|
# Configure language strictness in the CatalogCompiler. We want Bolt to be able
|
110
96
|
# to compile most Puppet 4+ manifests, so we default to allowing deprecated functions.
|
111
97
|
Puppet[:strict] = options['strict'] || :warning
|
112
98
|
Puppet[:strict_variables] = options['strict_variables'] || false
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
# plan. In that case, we need to discover the definitions (which
|
117
|
-
# would ordinarily be stored on the Program) and construct a Program object.
|
118
|
-
unless ast.is_a?(Puppet::Pops::Model::Program)
|
119
|
-
# Node definitions must be at the top level of the apply block.
|
120
|
-
# That means the apply body either a) consists of just a
|
121
|
-
# NodeDefinition, b) consists of a BlockExpression which may
|
122
|
-
# contain NodeDefinitions, or c) doesn't contain NodeDefinitions.
|
123
|
-
definitions = if ast.is_a?(Puppet::Pops::Model::BlockExpression)
|
124
|
-
ast.statements.select { |st| st.is_a?(Puppet::Pops::Model::NodeDefinition) }
|
125
|
-
elsif ast.is_a?(Puppet::Pops::Model::NodeDefinition)
|
126
|
-
[ast]
|
127
|
-
else
|
128
|
-
[]
|
129
|
-
end
|
130
|
-
ast = Puppet::Pops::Model::Factory.PROGRAM(ast, definitions, ast.locator).model
|
131
|
-
end
|
99
|
+
|
100
|
+
pal_main = request['code_ast'] || request['code_string']
|
101
|
+
ast = build_program(pal_main)
|
132
102
|
compiler.evaluate(ast)
|
133
|
-
compiler.
|
103
|
+
compiler.evaluate_ast_node
|
134
104
|
compiler.compile_additions
|
135
105
|
compiler.with_json_encoding(&:encode)
|
136
106
|
end
|
@@ -138,5 +108,45 @@ module Bolt
|
|
138
108
|
end
|
139
109
|
end
|
140
110
|
end
|
111
|
+
|
112
|
+
# Warn and remove variables that will be shadowed by facts of the same
|
113
|
+
# name, which are set in scope earlier.
|
114
|
+
def shadow_vars(type, vars, facts)
|
115
|
+
collisions, valid = vars.partition do |k, _|
|
116
|
+
facts.include?(k)
|
117
|
+
end
|
118
|
+
if collisions.any?
|
119
|
+
names = collisions.map { |k, _| "$#{k}" }.join(', ')
|
120
|
+
plural = collisions.length == 1 ? '' : 's'
|
121
|
+
Puppet.warning("#{type.capitalize} variable#{plural} #{names} will be overridden by fact#{plural} " \
|
122
|
+
"of the same name in the apply block")
|
123
|
+
end
|
124
|
+
valid.to_h
|
125
|
+
end
|
126
|
+
|
127
|
+
def build_program(code)
|
128
|
+
ast = Puppet::Pops::Serialization::FromDataConverter.convert(code)
|
129
|
+
|
130
|
+
# This will be a Program when running via `bolt apply`, but will
|
131
|
+
# only be a subset of the AST when compiling an apply block in a
|
132
|
+
# plan. In that case, we need to discover the definitions (which
|
133
|
+
# would ordinarily be stored on the Program) and construct a Program object.
|
134
|
+
if ast.is_a?(Puppet::Pops::Model::Program)
|
135
|
+
ast
|
136
|
+
else
|
137
|
+
# Node definitions must be at the top level of the apply block.
|
138
|
+
# That means the apply body either a) consists of just a
|
139
|
+
# NodeDefinition, b) consists of a BlockExpression which may
|
140
|
+
# contain NodeDefinitions, or c) doesn't contain NodeDefinitions.
|
141
|
+
definitions = if ast.is_a?(Puppet::Pops::Model::BlockExpression)
|
142
|
+
ast.statements.select { |st| st.is_a?(Puppet::Pops::Model::NodeDefinition) }
|
143
|
+
elsif ast.is_a?(Puppet::Pops::Model::NodeDefinition)
|
144
|
+
[ast]
|
145
|
+
else
|
146
|
+
[]
|
147
|
+
end
|
148
|
+
Puppet::Pops::Model::Factory.PROGRAM(ast, definitions, ast.locator).model
|
149
|
+
end
|
150
|
+
end
|
141
151
|
end
|
142
152
|
end
|
data/lib/bolt/cli.rb
CHANGED
@@ -115,7 +115,7 @@ module Bolt
|
|
115
115
|
Bolt::Config.from_file(options[:configfile], options)
|
116
116
|
else
|
117
117
|
project = if options[:boltdir]
|
118
|
-
Bolt::Project.
|
118
|
+
Bolt::Project.create_project(options[:boltdir])
|
119
119
|
else
|
120
120
|
Bolt::Project.find_boltdir(Dir.pwd)
|
121
121
|
end
|
@@ -392,7 +392,7 @@ module Bolt
|
|
392
392
|
end
|
393
393
|
code = apply_manifest(options[:code], options[:targets], options[:object], options[:noop])
|
394
394
|
else
|
395
|
-
executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop])
|
395
|
+
executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop], config.modified_concurrency)
|
396
396
|
targets = options[:targets]
|
397
397
|
|
398
398
|
results = nil
|
@@ -512,7 +512,7 @@ module Bolt
|
|
512
512
|
params: plan_arguments }
|
513
513
|
plan_context[:description] = options[:description] if options[:description]
|
514
514
|
|
515
|
-
executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop])
|
515
|
+
executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop], config.modified_concurrency)
|
516
516
|
if options.fetch(:format, 'human') == 'human'
|
517
517
|
executor.subscribe(outputter)
|
518
518
|
else
|
@@ -548,7 +548,7 @@ module Bolt
|
|
548
548
|
@logger.warn(message)
|
549
549
|
end
|
550
550
|
|
551
|
-
executor = Bolt::Executor.new(config.concurrency, analytics, noop)
|
551
|
+
executor = Bolt::Executor.new(config.concurrency, analytics, noop, config.modified_concurrency)
|
552
552
|
executor.subscribe(outputter) if options.fetch(:format, 'human') == 'human'
|
553
553
|
executor.subscribe(log_outputter)
|
554
554
|
# apply logging looks like plan logging, so tell the outputter we're in a
|
@@ -771,7 +771,7 @@ module Bolt
|
|
771
771
|
end
|
772
772
|
|
773
773
|
def pal
|
774
|
-
project = config.project.
|
774
|
+
project = config.project.project_file? ? config.project : nil
|
775
775
|
@pal ||= Bolt::PAL.new(config.modulepath,
|
776
776
|
config.hiera_config,
|
777
777
|
config.project.resource_types,
|
data/lib/bolt/config.rb
CHANGED
@@ -23,7 +23,7 @@ module Bolt
|
|
23
23
|
end
|
24
24
|
|
25
25
|
class Config
|
26
|
-
attr_reader :config_files, :warnings, :data, :transports, :project
|
26
|
+
attr_reader :config_files, :warnings, :data, :transports, :project, :modified_concurrency
|
27
27
|
|
28
28
|
TRANSPORT_CONFIG = {
|
29
29
|
'ssh' => Bolt::Config::Transport::SSH,
|
@@ -34,6 +34,13 @@ module Bolt
|
|
34
34
|
'remote' => Bolt::Config::Transport::Remote
|
35
35
|
}.freeze
|
36
36
|
|
37
|
+
TRANSPORT_OPTION = { 'transport' => 'The default transport to use when the '\
|
38
|
+
'transport for a target is not specified in the URL.' }.freeze
|
39
|
+
|
40
|
+
DEFAULT_TRANSPORT_OPTION = { 'transport' => 'ssh' }.freeze
|
41
|
+
|
42
|
+
CONFIG_IN_INVENTORY = TRANSPORT_CONFIG.merge(TRANSPORT_OPTION)
|
43
|
+
|
37
44
|
# NOTE: All configuration options should have a corresponding schema property
|
38
45
|
# in schemas/bolt-config.schema.json
|
39
46
|
OPTIONS = {
|
@@ -55,8 +62,8 @@ module Bolt
|
|
55
62
|
"save-rerun" => "Whether to update `.rerun.json` in the Bolt project directory. If "\
|
56
63
|
"your target names include passwords, set this value to `false` to avoid "\
|
57
64
|
"writing passwords to disk.",
|
58
|
-
"transport" => "The default transport to use when the transport for a target is not "\
|
59
|
-
"
|
65
|
+
"transport" => "The default transport to use when the transport for a target is not specified "\
|
66
|
+
"in the URL or inventory.",
|
60
67
|
"trusted-external-command" => "The path to an executable on the Bolt controller that can produce "\
|
61
68
|
"external trusted facts. **External trusted facts are experimental in both "\
|
62
69
|
"Puppet and Bolt and this API may change or be removed.**"
|
@@ -104,14 +111,17 @@ module Bolt
|
|
104
111
|
DEFAULT_DEFAULT_CONCURRENCY = 100
|
105
112
|
|
106
113
|
def self.default
|
107
|
-
new(Bolt::Project.
|
114
|
+
new(Bolt::Project.create_project('.'), {})
|
108
115
|
end
|
109
116
|
|
110
117
|
def self.from_project(project, overrides = {})
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
118
|
+
conf = if project.project_file == project.config_file
|
119
|
+
project.data
|
120
|
+
else
|
121
|
+
Bolt::Util.read_optional_yaml_hash(project.config_file, 'config')
|
122
|
+
end
|
123
|
+
|
124
|
+
data = { filepath: project.config_file, data: conf }
|
115
125
|
|
116
126
|
data = load_defaults(project).push(data).select { |config| config[:data]&.any? }
|
117
127
|
|
@@ -119,12 +129,13 @@ module Bolt
|
|
119
129
|
end
|
120
130
|
|
121
131
|
def self.from_file(configfile, overrides = {})
|
122
|
-
project = Bolt::Project.
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
132
|
+
project = Bolt::Project.create_project(Pathname.new(configfile).expand_path.dirname)
|
133
|
+
conf = if project.project_file == project.config_file
|
134
|
+
project.data
|
135
|
+
else
|
136
|
+
Bolt::Util.read_yaml_hash(configfile, 'config')
|
137
|
+
end
|
138
|
+
data = { filepath: project.config_file, data: conf }
|
128
139
|
data = load_defaults(project).push(data).select { |config| config[:data]&.any? }
|
129
140
|
|
130
141
|
new(project, data, overrides)
|
@@ -158,8 +169,8 @@ module Bolt
|
|
158
169
|
end
|
159
170
|
|
160
171
|
@logger = Logging.logger[self]
|
161
|
-
@warnings = []
|
162
172
|
@project = project
|
173
|
+
@warnings = @project.warnings.dup
|
163
174
|
@transports = {}
|
164
175
|
@config_files = []
|
165
176
|
|
@@ -187,15 +198,9 @@ module Bolt
|
|
187
198
|
|
188
199
|
# If we need to lower concurrency and concurrency is not configured
|
189
200
|
ld_concurrency = loaded_data.map(&:keys).flatten.include?('concurrency')
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
concurrency_warning = { option: 'concurrency',
|
194
|
-
msg: "Concurrency will default to #{default_concurrency} because ulimit "\
|
195
|
-
"is low: #{Etc.sysconf(Etc::SC_OPEN_MAX)}. Set concurrency with "\
|
196
|
-
"'--concurrency', or set your ulimit with 'ulimit -n <limit>'" }
|
197
|
-
@warnings << concurrency_warning
|
198
|
-
end
|
201
|
+
@modified_concurrency = default_concurrency != DEFAULT_DEFAULT_CONCURRENCY &&
|
202
|
+
!ld_concurrency &&
|
203
|
+
!override_data.key?('concurrency')
|
199
204
|
|
200
205
|
@data = merge_config_layers(default_data, *loaded_data, override_data)
|
201
206
|
|
@@ -483,7 +488,7 @@ module Bolt
|
|
483
488
|
@default_concurrency ||= if !sc_open_max_available? || Etc.sysconf(Etc::SC_OPEN_MAX) >= 300
|
484
489
|
DEFAULT_DEFAULT_CONCURRENCY
|
485
490
|
else
|
486
|
-
Etc.sysconf(Etc::SC_OPEN_MAX) /
|
491
|
+
Etc.sysconf(Etc::SC_OPEN_MAX) / 7
|
487
492
|
end
|
488
493
|
end
|
489
494
|
end
|
@@ -12,94 +12,132 @@ module Bolt
|
|
12
12
|
# NOTE: All transport configuration options should have a corresponding schema definition
|
13
13
|
# in schemas/bolt-transport-definitions.json
|
14
14
|
OPTIONS = {
|
15
|
-
"cleanup"
|
16
|
-
|
17
|
-
|
18
|
-
"connect-timeout"
|
19
|
-
|
20
|
-
"copy-command"
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
"
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
"
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
"
|
101
|
-
|
102
|
-
|
15
|
+
"cleanup" => { type: TrueClass,
|
16
|
+
external: true,
|
17
|
+
desc: "Whether to clean up temporary files created on targets." },
|
18
|
+
"connect-timeout" => { type: Integer,
|
19
|
+
desc: "How long to wait when establishing connections." },
|
20
|
+
"copy-command" => { external: true,
|
21
|
+
desc: "Command to use when copying files using ssh-command. "\
|
22
|
+
"Bolt runs `<copy-command> <src> <dest>`. **This option is "\
|
23
|
+
"experimental.**" },
|
24
|
+
"disconnect-timeout" => { type: Integer,
|
25
|
+
desc: "How long to wait before force-closing a connection." },
|
26
|
+
"encryption-algorithms" => { type: Array,
|
27
|
+
desc: "List of encryption algorithms to use when establishing a "\
|
28
|
+
"connection with a target. Supported algorithms are "\
|
29
|
+
"defined by the Ruby net-ssh library and can be viewed "\
|
30
|
+
"[here](https://github.com/net-ssh/net-ssh#supported-algorithms). "\
|
31
|
+
"All supported, non-deprecated algorithms are available by default when "\
|
32
|
+
"this option is not used. To reference all default algorithms "\
|
33
|
+
"when using this option, add 'defaults' to the list of supported "\
|
34
|
+
"algorithms." },
|
35
|
+
"extensions" => { type: Array,
|
36
|
+
desc: "List of file extensions that are accepted for scripts or tasks on "\
|
37
|
+
"Windows. Scripts with these file extensions rely on the target's file "\
|
38
|
+
"type association to run. For example, if Python is installed on the "\
|
39
|
+
"system, a `.py` script runs with `python.exe`. The extensions `.ps1`, "\
|
40
|
+
"`.rb`, and `.pp` are always allowed and run via hard-coded "\
|
41
|
+
"executables." },
|
42
|
+
"host" => { type: String,
|
43
|
+
external: true,
|
44
|
+
desc: "Host name." },
|
45
|
+
"host-key-algorithms" => { type: Array,
|
46
|
+
desc: "List of host key algorithms to use when establishing a connection "\
|
47
|
+
"with a target. Supported algorithms are defined by the Ruby net-ssh "\
|
48
|
+
"library "\
|
49
|
+
"([docs](https://github.com/net-ssh/net-ssh#supported-algorithms)). "\
|
50
|
+
"All supported, non-deprecated algorithms are available by default when "\
|
51
|
+
"this option is not used. To reference all default algorithms "\
|
52
|
+
"using this option, add 'defaults' to the list of supported "\
|
53
|
+
"algorithms." },
|
54
|
+
"host-key-check" => { type: TrueClass,
|
55
|
+
external: true,
|
56
|
+
desc: "Whether to perform host key validation when connecting." },
|
57
|
+
"interpreters" => { type: Hash,
|
58
|
+
external: true,
|
59
|
+
desc: "A map of an extension name to the absolute path of an executable, "\
|
60
|
+
"enabling you to override the shebang defined in a task executable. "\
|
61
|
+
"The extension can optionally be specified with the `.` character "\
|
62
|
+
"(`.py` and `py` both map to a task executable `task.py`) and the "\
|
63
|
+
"extension is case sensitive. When a target's name is `localhost`, "\
|
64
|
+
"Ruby tasks run with the Bolt Ruby interpreter by default." },
|
65
|
+
"kex-algorithms" => { type: Array,
|
66
|
+
desc: "List of key exchange algorithms to use when establishing a "\
|
67
|
+
"connection to a target. Supported algorithms are defined by the "\
|
68
|
+
"Ruby net-ssh library "\
|
69
|
+
"([docs](https://github.com/net-ssh/net-ssh#supported-algorithms)). "\
|
70
|
+
"All supported, non-deprecated algorithms are available by default when "\
|
71
|
+
"this option is not used. To reference all default algorithms "\
|
72
|
+
"using this option, add 'defaults' to the list of supported "\
|
73
|
+
"algorithms." },
|
74
|
+
"load-config" => { type: TrueClass,
|
75
|
+
desc: "Whether to load system SSH configuration." },
|
76
|
+
"login-shell" => { type: String,
|
77
|
+
desc: "Which login shell Bolt should expect on the target. "\
|
78
|
+
"Supported shells are #{LOGIN_SHELLS.join(', ')}. "\
|
79
|
+
"**This option is experimental.**" },
|
80
|
+
"mac-algorithms" => { type: Array,
|
81
|
+
desc: "List of message authentication code algorithms to use when "\
|
82
|
+
"establishing a connection to a target. Supported algorithms are "\
|
83
|
+
"defined by the Ruby net-ssh library "\
|
84
|
+
"([docs](https://github.com/net-ssh/net-ssh#supported-algorithms)). "\
|
85
|
+
"All supported, non-deprecated algorithms are available by default when "\
|
86
|
+
"this option is not used. To reference all default algorithms "\
|
87
|
+
"using this option, add 'defaults' to the list of supported "\
|
88
|
+
"algorithms." },
|
89
|
+
"password" => { type: String,
|
90
|
+
desc: "Login password." },
|
91
|
+
"port" => { type: Integer,
|
92
|
+
external: true,
|
93
|
+
desc: "Connection port." },
|
94
|
+
"private-key" => { external: true,
|
95
|
+
desc: "Either the path to the private key file to use for authentication, or "\
|
96
|
+
"a hash with the key `key-data` and the contents of the private key." },
|
97
|
+
"proxyjump" => { type: String,
|
98
|
+
desc: "A jump host to proxy connections through, and an optional user to "\
|
99
|
+
"connect with." },
|
100
|
+
"run-as" => { type: String,
|
101
|
+
external: true,
|
102
|
+
desc: "A different user to run commands as after login." },
|
103
|
+
"run-as-command" => { type: Array,
|
104
|
+
external: true,
|
105
|
+
desc: "The command to elevate permissions. Bolt appends the user and command "\
|
106
|
+
"strings to the configured `run-as-command` before running it on the "\
|
107
|
+
"target. This command must not require an interactive password prompt, "\
|
108
|
+
"and the `sudo-password` option is ignored when `run-as-command` is "\
|
109
|
+
"specified. The `run-as-command` must be specified as an array." },
|
110
|
+
"script-dir" => { type: String,
|
111
|
+
external: true,
|
112
|
+
desc: "The subdirectory of the tmpdir to use in place of a randomized "\
|
113
|
+
"subdirectory for uploading and executing temporary files on the "\
|
114
|
+
"target. It's expected that this directory already exists as a subdir "\
|
115
|
+
"of tmpdir, which is either configured or defaults to `/tmp`." },
|
116
|
+
"ssh-command" => { external: true,
|
117
|
+
desc: "Command and flags to use when SSHing. This enables the external "\
|
118
|
+
"SSH transport which shells out to the specified command. "\
|
119
|
+
"**This option is experimental.**" },
|
120
|
+
"sudo-executable" => { type: String,
|
121
|
+
external: true,
|
122
|
+
desc: "The executable to use when escalating to the configured `run-as` "\
|
123
|
+
"user. This is useful when you want to escalate using the configured "\
|
124
|
+
"`sudo-password`, since `run-as-command` does not use `sudo-password` "\
|
125
|
+
"or support prompting. The command executed on the target is "\
|
126
|
+
"`<sudo-executable> -S -u <user> -p custom_bolt_prompt <command>`. "\
|
127
|
+
"**This option is experimental.**" },
|
128
|
+
"sudo-password" => { type: String,
|
129
|
+
external: true,
|
130
|
+
desc: "Password to use when changing users via `run-as`." },
|
131
|
+
"tmpdir" => { type: String,
|
132
|
+
external: true,
|
133
|
+
desc: "The directory to upload and execute temporary files on the target." },
|
134
|
+
"tty" => { type: TrueClass,
|
135
|
+
desc: "Request a pseudo tty for the session. This option is generally "\
|
136
|
+
"only used in conjunction with the `run-as` option when the sudoers "\
|
137
|
+
"policy requires a `tty`." },
|
138
|
+
"user" => { type: String,
|
139
|
+
external: true,
|
140
|
+
desc: "Login user." }
|
103
141
|
}.freeze
|
104
142
|
|
105
143
|
DEFAULTS = {
|
@@ -142,10 +180,11 @@ module Bolt
|
|
142
180
|
"Unsupported login-shell #{@config['login-shell']}. Supported shells are #{LOGIN_SHELLS.join(', ')}"
|
143
181
|
end
|
144
182
|
|
145
|
-
|
146
|
-
unless
|
183
|
+
%w[encryption-algorithms host-key-algorithms kex-algorithms mac-algorithms run-as-command].each do |opt|
|
184
|
+
next unless @config.key?(opt)
|
185
|
+
unless @config[opt].all? { |n| n.is_a?(String) }
|
147
186
|
raise Bolt::ValidationError,
|
148
|
-
"
|
187
|
+
"#{opt} must be an Array of Strings, received #{@config[opt].inspect}"
|
149
188
|
end
|
150
189
|
end
|
151
190
|
|
data/lib/bolt/executor.rb
CHANGED
@@ -34,7 +34,8 @@ module Bolt
|
|
34
34
|
|
35
35
|
def initialize(concurrency = 1,
|
36
36
|
analytics = Bolt::Analytics::NoopClient.new,
|
37
|
-
noop = false
|
37
|
+
noop = false,
|
38
|
+
modified_concurrency = false)
|
38
39
|
# lazy-load expensive gem code
|
39
40
|
require 'concurrent'
|
40
41
|
|
@@ -64,6 +65,9 @@ module Bolt
|
|
64
65
|
Concurrent.global_immediate_executor
|
65
66
|
end
|
66
67
|
@logger.debug { "Started with #{concurrency} max thread(s)" }
|
68
|
+
|
69
|
+
@concurrency = concurrency
|
70
|
+
@warn_concurrency = modified_concurrency
|
67
71
|
end
|
68
72
|
|
69
73
|
def transport(transport)
|
@@ -102,6 +106,15 @@ module Bolt
|
|
102
106
|
# defined by the transport. Yields each batch, along with the corresponding
|
103
107
|
# transport, to the block in turn and returns an array of result promises.
|
104
108
|
def queue_execute(targets)
|
109
|
+
if @warn_concurrency && targets.length > @concurrency
|
110
|
+
@warn_concurrency = false
|
111
|
+
@logger.warn("The ulimit is low, which may cause file limit issues. Default concurrency has been set to "\
|
112
|
+
"'#{@concurrency}' to mitigate those issues, which may cause Bolt to run slow. "\
|
113
|
+
"Disable this warning by configuring ulimit using 'ulimit -n <limit>' in your shell "\
|
114
|
+
"configuration, or by configuring Bolt's concurrency. "\
|
115
|
+
"See https://puppet.com/docs/bolt/latest/bolt_known_issues.html for details.")
|
116
|
+
end
|
117
|
+
|
105
118
|
targets.group_by(&:transport).flat_map do |protocol, protocol_targets|
|
106
119
|
transport = transport(protocol)
|
107
120
|
report_transport(transport, protocol_targets.count)
|
data/lib/bolt/inventory/group.rb
CHANGED
@@ -16,7 +16,7 @@ module Bolt
|
|
16
16
|
DATA_KEYS = %w[config facts vars features plugin_hooks].freeze
|
17
17
|
TARGET_KEYS = DATA_KEYS + %w[name alias uri]
|
18
18
|
GROUP_KEYS = DATA_KEYS + %w[name groups targets]
|
19
|
-
CONFIG_KEYS = Bolt::Config::
|
19
|
+
CONFIG_KEYS = Bolt::Config::CONFIG_IN_INVENTORY.keys
|
20
20
|
|
21
21
|
def initialize(input, plugins)
|
22
22
|
@logger = Logging.logger[self]
|
@@ -90,6 +90,10 @@ module Bolt
|
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
|
+
def resource(type, title)
|
94
|
+
resources[Bolt::ResourceInstance.format_reference(type, title)]
|
95
|
+
end
|
96
|
+
|
93
97
|
def plugin_hooks
|
94
98
|
# Merge plugin_hooks from the config file with any defined by the group
|
95
99
|
# or assigned dynamically to the target
|
data/lib/bolt/project.rb
CHANGED
@@ -12,14 +12,14 @@ module Bolt
|
|
12
12
|
"tasks" => "An array of task names to whitelist. Whitelisted plans are included in `bolt task show` output"
|
13
13
|
}.freeze
|
14
14
|
|
15
|
-
attr_reader :path, :config_file, :inventory_file, :modulepath, :hiera_config,
|
16
|
-
:puppetfile, :rerunfile, :type, :resource_types
|
15
|
+
attr_reader :path, :data, :config_file, :inventory_file, :modulepath, :hiera_config,
|
16
|
+
:puppetfile, :rerunfile, :type, :resource_types, :warnings, :project_file
|
17
17
|
|
18
18
|
def self.default_project
|
19
|
-
|
19
|
+
create_project(File.expand_path(File.join('~', '.puppetlabs', 'bolt')), 'user')
|
20
20
|
# If homedir isn't defined use the system config path
|
21
21
|
rescue ArgumentError
|
22
|
-
|
22
|
+
create_project(system_path, 'system')
|
23
23
|
end
|
24
24
|
|
25
25
|
def self.system_path
|
@@ -37,9 +37,9 @@ module Bolt
|
|
37
37
|
def self.find_boltdir(dir)
|
38
38
|
dir = Pathname.new(dir)
|
39
39
|
if (dir + BOLTDIR_NAME).directory?
|
40
|
-
|
40
|
+
create_project(dir + BOLTDIR_NAME, 'embedded')
|
41
41
|
elsif (dir + 'bolt.yaml').file? || (dir + 'bolt-project.yaml').file?
|
42
|
-
|
42
|
+
create_project(dir, 'local')
|
43
43
|
elsif dir.root?
|
44
44
|
default_project
|
45
45
|
else
|
@@ -47,9 +47,25 @@ module Bolt
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
def
|
50
|
+
def self.create_project(path, type = 'option')
|
51
|
+
fullpath = Pathname.new(path).expand_path
|
52
|
+
project_file = File.join(fullpath, 'bolt-project.yaml')
|
53
|
+
data = Bolt::Util.read_optional_yaml_hash(File.expand_path(project_file), 'project')
|
54
|
+
new(data, path, type)
|
55
|
+
end
|
56
|
+
|
57
|
+
def initialize(raw_data, path, type = 'option')
|
51
58
|
@path = Pathname.new(path).expand_path
|
52
|
-
@
|
59
|
+
@project_file = @path + 'bolt-project.yaml'
|
60
|
+
|
61
|
+
@warnings = []
|
62
|
+
if (@path + 'bolt.yaml').file? && project_file?
|
63
|
+
msg = "Project-level configuration in bolt.yaml is deprecated if using bolt-project.yaml. "\
|
64
|
+
"Transport config should be set in inventory.yaml, all other config should be set in "\
|
65
|
+
"bolt-project.yaml."
|
66
|
+
@warnings << { msg: msg }
|
67
|
+
end
|
68
|
+
|
53
69
|
@inventory_file = @path + 'inventory.yaml'
|
54
70
|
@modulepath = [(@path + 'modules').to_s, (@path + 'site-modules').to_s, (@path + 'site').to_s]
|
55
71
|
@hiera_config = @path + 'hiera.yaml'
|
@@ -58,9 +74,26 @@ module Bolt
|
|
58
74
|
@resource_types = @path + '.resource_types'
|
59
75
|
@type = type
|
60
76
|
|
61
|
-
|
62
|
-
|
63
|
-
|
77
|
+
tc = Bolt::Config::CONFIG_IN_INVENTORY.keys & raw_data.keys
|
78
|
+
if tc.any?
|
79
|
+
msg = "Transport configuration isn't supported in bolt-project.yaml. Ignoring keys #{tc}"
|
80
|
+
@warnings << { msg: msg }
|
81
|
+
end
|
82
|
+
|
83
|
+
@data = raw_data.reject { |k, _| Bolt::Config::CONFIG_IN_INVENTORY.keys.include?(k) }
|
84
|
+
|
85
|
+
# Once bolt.yaml deprecation is removed, this attribute should be removed
|
86
|
+
# and replaced with .project_file in lib/bolt/config.rb
|
87
|
+
@config_file = if (Bolt::Config::OPTIONS.keys & @data.keys).any?
|
88
|
+
if (@path + 'bolt.yaml').file?
|
89
|
+
msg = "bolt-project.yaml contains valid config keys, bolt.yaml will be ignored"
|
90
|
+
@warnings << { msg: msg }
|
91
|
+
end
|
92
|
+
@project_file
|
93
|
+
else
|
94
|
+
@path + 'bolt.yaml'
|
95
|
+
end
|
96
|
+
validate if project_file?
|
64
97
|
end
|
65
98
|
|
66
99
|
def to_s
|
@@ -78,7 +111,7 @@ module Bolt
|
|
78
111
|
end
|
79
112
|
alias == eql?
|
80
113
|
|
81
|
-
def
|
114
|
+
def project_file?
|
82
115
|
@project_file.file?
|
83
116
|
end
|
84
117
|
|
@@ -83,8 +83,12 @@ module Bolt
|
|
83
83
|
to_hash.to_json(opts)
|
84
84
|
end
|
85
85
|
|
86
|
+
def self.format_reference(type, title)
|
87
|
+
"#{type.capitalize}[#{title}]"
|
88
|
+
end
|
89
|
+
|
86
90
|
def reference
|
87
|
-
|
91
|
+
self.class.format_reference(@type, @title)
|
88
92
|
end
|
89
93
|
alias to_s reference
|
90
94
|
|
@@ -50,7 +50,8 @@ module Bolt
|
|
50
50
|
# If it's already a powershell command then invoke it normally.
|
51
51
|
# Otherwise, wrap it in powershell.exe.
|
52
52
|
unless command.start_with?('powershell.exe')
|
53
|
-
|
53
|
+
cmd = Bolt::Shell::Powershell::Snippets.exit_with_code(command)
|
54
|
+
command = ['powershell.exe', *Bolt::Shell::Powershell::PS_ARGS, '-Command', cmd]
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
@@ -78,6 +78,28 @@ module Bolt
|
|
78
78
|
|
79
79
|
options[:proxy] = Net::SSH::Proxy::Jump.new(target.options['proxyjump']) if target.options['proxyjump']
|
80
80
|
|
81
|
+
# Override the default supported algorithms for net-ssh. By default, a subset of supported algorithms
|
82
|
+
# are enabled in 6.x, while several are deprecated and not enabled by default. The *-algorithms
|
83
|
+
# options can be used to specify a list of algorithms to enable in net-ssh. Any algorithms not in the
|
84
|
+
# list are disabled, including ones that are normally enabled by default. Support for deprecated
|
85
|
+
# algorithms will be removed in 7.x.
|
86
|
+
# https://github.com/net-ssh/net-ssh#supported-algorithms
|
87
|
+
if target.options['encryption-algorithms']
|
88
|
+
options[:encryption] = net_ssh_algorithms(:encryption, target.options['encryption-algorithms'])
|
89
|
+
end
|
90
|
+
|
91
|
+
if target.options['host-key-algorithms']
|
92
|
+
options[:host_key] = net_ssh_algorithms(:host_key, target.options['host-key-algorithms'])
|
93
|
+
end
|
94
|
+
|
95
|
+
if target.options['kex-algorithms']
|
96
|
+
options[:kex] = net_ssh_algorithms(:kex, target.options['kex-algorithms'])
|
97
|
+
end
|
98
|
+
|
99
|
+
if target.options['mac-algorithms']
|
100
|
+
options[:hmac] = net_ssh_algorithms(:hmac, target.options['mac-algorithms'])
|
101
|
+
end
|
102
|
+
|
81
103
|
# This option was to address discrepency betwen net-ssh host-key-check and ssh(1)
|
82
104
|
# For the net-ssh 5.x series it defaults to true, in 6.x it will default to false, and will be removed in 7.x
|
83
105
|
# https://github.com/net-ssh/net-ssh/pull/663#issuecomment-469979931
|
@@ -246,6 +268,19 @@ module Bolt
|
|
246
268
|
end
|
247
269
|
end
|
248
270
|
|
271
|
+
# Add all default algorithms if the 'defaults' key is present and filter
|
272
|
+
# out any unsupported algorithms.
|
273
|
+
def net_ssh_algorithms(type, algorithms)
|
274
|
+
if algorithms.include?('defaults')
|
275
|
+
defaults = Net::SSH::Transport::Algorithms::DEFAULT_ALGORITHMS[type]
|
276
|
+
algorithms += defaults
|
277
|
+
end
|
278
|
+
|
279
|
+
known = Net::SSH::Transport::Algorithms::ALGORITHMS[type]
|
280
|
+
|
281
|
+
algorithms & known
|
282
|
+
end
|
283
|
+
|
249
284
|
def shell
|
250
285
|
@shell ||= if target.options['login-shell'] == 'powershell'
|
251
286
|
Bolt::Shell::Powershell.new(target, self)
|
data/lib/bolt/version.rb
CHANGED
data/lib/bolt_spec/run.rb
CHANGED
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.
|
4
|
+
version: 2.14.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-06-
|
11
|
+
date: 2020-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -184,7 +184,7 @@ dependencies:
|
|
184
184
|
requirements:
|
185
185
|
- - ">="
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version: 6.
|
187
|
+
version: 6.16.0
|
188
188
|
- - "<"
|
189
189
|
- !ruby/object:Gem::Version
|
190
190
|
version: '7'
|
@@ -194,7 +194,7 @@ dependencies:
|
|
194
194
|
requirements:
|
195
195
|
- - ">="
|
196
196
|
- !ruby/object:Gem::Version
|
197
|
-
version: 6.
|
197
|
+
version: 6.16.0
|
198
198
|
- - "<"
|
199
199
|
- !ruby/object:Gem::Version
|
200
200
|
version: '7'
|
@@ -407,6 +407,7 @@ files:
|
|
407
407
|
- bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb
|
408
408
|
- bolt-modules/boltlib/lib/puppet/functions/remove_from_group.rb
|
409
409
|
- bolt-modules/boltlib/lib/puppet/functions/resolve_references.rb
|
410
|
+
- bolt-modules/boltlib/lib/puppet/functions/resource.rb
|
410
411
|
- bolt-modules/boltlib/lib/puppet/functions/run_command.rb
|
411
412
|
- bolt-modules/boltlib/lib/puppet/functions/run_plan.rb
|
412
413
|
- bolt-modules/boltlib/lib/puppet/functions/run_script.rb
|
@@ -588,7 +589,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
588
589
|
- !ruby/object:Gem::Version
|
589
590
|
version: '0'
|
590
591
|
requirements: []
|
591
|
-
rubygems_version: 3.0.
|
592
|
+
rubygems_version: 3.0.8
|
592
593
|
signing_key:
|
593
594
|
specification_version: 4
|
594
595
|
summary: Execute commands remotely over SSH and WinRM
|