openbolt 5.3.0 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Puppetfile +6 -7
- data/lib/bolt/bolt_option_parser.rb +63 -1
- data/lib/bolt/cli.rb +1 -1
- data/lib/bolt/config/options.rb +14 -0
- data/lib/bolt/config/transport/choria.rb +74 -0
- data/lib/bolt/config/transport/options.rb +108 -0
- data/lib/bolt/executor.rb +2 -0
- data/lib/bolt/pal/yaml_plan/transpiler.rb +1 -1
- data/lib/bolt/plugin/puppetdb.rb +1 -1
- data/lib/bolt/plugin.rb +1 -4
- data/lib/bolt/puppetdb/config.rb +8 -0
- data/lib/bolt/puppetdb/instance.rb +1 -0
- data/lib/bolt/result_set.rb +1 -1
- data/lib/bolt/transport/choria/agent_discovery.rb +137 -0
- data/lib/bolt/transport/choria/bolt_tasks.rb +248 -0
- data/lib/bolt/transport/choria/client.rb +281 -0
- data/lib/bolt/transport/choria/command_builders.rb +199 -0
- data/lib/bolt/transport/choria/helpers.rb +197 -0
- data/lib/bolt/transport/choria/shell.rb +560 -0
- data/lib/bolt/transport/choria.rb +218 -0
- data/lib/bolt/transport/winrm/connection.rb +13 -3
- data/lib/bolt/version.rb +1 -1
- data/lib/mcollective/agent/shell.ddl +154 -0
- metadata +35 -14
- data/lib/bolt/plugin/puppet_connect_data.rb +0 -85
- data/modules/puppet_connect/plans/test_input_data.pp +0 -94
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: af114a7662dadfeb0b7a3b93bade87bd679b4d555c718ef9de2782327fb72f94
|
|
4
|
+
data.tar.gz: 212b616948e0e548f821576db50971c21ad9f9e5e9a84d9e676542078ea623d3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9a85395239d2b5de8adc4d538bf0860139ee0585c3880d8ea6ccb46a840fa0ee6371e58ce17feb2cc171b5fc47cddeabd284adedcbb3abd60675951b1b5e0169
|
|
7
|
+
data.tar.gz: f42f2da1b4ea78080c3790e2165be94105bb7a9ad9c5a16b2702f5511a8f6e9f8893c781f9fe2c63e65b3987819576ccd2e4e1b89b13e13bb7386e6d5708ed94
|
data/Puppetfile
CHANGED
|
@@ -6,27 +6,27 @@ moduledir File.join(File.dirname(__FILE__), 'modules')
|
|
|
6
6
|
|
|
7
7
|
# Core modules used by 'apply'
|
|
8
8
|
mod 'puppetlabs-service', '3.1.0'
|
|
9
|
-
mod 'puppet-openvox_bootstrap', '1.
|
|
9
|
+
mod 'puppet-openvox_bootstrap', '1.4.0'
|
|
10
10
|
mod 'puppetlabs-facts', '1.7.0'
|
|
11
11
|
|
|
12
12
|
# Other core Puppet modules
|
|
13
|
-
mod 'puppetlabs-inifile', '6.
|
|
14
|
-
mod 'puppetlabs-apt', '11.
|
|
13
|
+
mod 'puppetlabs-inifile', '6.3.1'
|
|
14
|
+
mod 'puppetlabs-apt', '11.2.0'
|
|
15
15
|
mod 'puppetlabs-stdlib', '9.7.0'
|
|
16
16
|
mod 'puppetlabs-powershell', '6.1.0'
|
|
17
|
-
mod 'puppetlabs-pwshlib', '2.0.
|
|
17
|
+
mod 'puppetlabs-pwshlib', '2.0.1'
|
|
18
18
|
|
|
19
19
|
# Core types and providers for Puppet 6
|
|
20
20
|
mod 'puppetlabs-augeas_core', '2.0.1'
|
|
21
21
|
mod 'puppetlabs-host_core', '2.0.1'
|
|
22
22
|
mod 'puppetlabs-scheduled_task', '4.0.3'
|
|
23
23
|
mod 'puppetlabs-sshkeys_core', '3.0.1'
|
|
24
|
-
mod 'puppetlabs-zfs_core', '
|
|
24
|
+
mod 'puppetlabs-zfs_core', '2.0.1'
|
|
25
25
|
mod 'puppetlabs-cron_core', '2.0.2'
|
|
26
26
|
mod 'puppetlabs-mount_core', '2.0.1'
|
|
27
27
|
mod 'puppetlabs-selinux_core', '2.0.1'
|
|
28
28
|
mod 'puppetlabs-yumrepo_core', '3.0.1'
|
|
29
|
-
mod 'puppetlabs-zone_core', '2.0.
|
|
29
|
+
mod 'puppetlabs-zone_core', '2.0.2'
|
|
30
30
|
|
|
31
31
|
# Useful additional modules
|
|
32
32
|
mod 'puppetlabs-package', '3.1.0'
|
|
@@ -55,4 +55,3 @@ mod 'puppetlabs-yaml', '0.2.0'
|
|
|
55
55
|
mod 'canary', local: true
|
|
56
56
|
mod 'aggregate', local: true
|
|
57
57
|
mod 'puppetdb_fact', local: true
|
|
58
|
-
mod 'puppet_connect', local: true
|
|
@@ -13,6 +13,11 @@ module Bolt
|
|
|
13
13
|
run_context: %w[concurrency inventoryfile save-rerun cleanup puppetdb],
|
|
14
14
|
global_config_setters: PROJECT_PATHS + %w[modulepath],
|
|
15
15
|
transports: %w[transport connect-timeout tty native-ssh ssh-command copy-command],
|
|
16
|
+
choria: %w[choria-config-file choria-mcollective-certname
|
|
17
|
+
choria-ssl-ca choria-ssl-cert choria-ssl-key
|
|
18
|
+
choria-collective choria-puppet-environment choria-rpc-timeout
|
|
19
|
+
choria-task-timeout choria-command-timeout choria-brokers
|
|
20
|
+
choria-broker-timeout],
|
|
16
21
|
display: %w[format color verbose trace stream],
|
|
17
22
|
global: %w[help version log-level clear-cache] }.freeze
|
|
18
23
|
|
|
@@ -168,7 +173,7 @@ module Bolt
|
|
|
168
173
|
when 'task'
|
|
169
174
|
case action
|
|
170
175
|
when 'run'
|
|
171
|
-
{ flags: ACTION_OPTS + %w[params tmpdir noop],
|
|
176
|
+
{ flags: ACTION_OPTS + %w[params tmpdir noop choria-task-agent],
|
|
172
177
|
banner: TASK_RUN_HELP }
|
|
173
178
|
when 'show'
|
|
174
179
|
{ flags: OPTIONS[:global] + OPTIONS[:global_config_setters] + %w[filter format],
|
|
@@ -1095,6 +1100,63 @@ module Bolt
|
|
|
1095
1100
|
define('--tmpdir DIR', 'The directory to upload and execute temporary files on the target.') do |tmpdir|
|
|
1096
1101
|
@options[:tmpdir] = tmpdir
|
|
1097
1102
|
end
|
|
1103
|
+
define('--choria-task-agent AGENT', %w[bolt_tasks shell],
|
|
1104
|
+
"Which Choria agent to use for task execution (bolt_tasks, shell).",
|
|
1105
|
+
"Defaults to 'bolt_tasks'. Set to 'shell' for tasks not on the Puppet Server.") do |agent|
|
|
1106
|
+
@options[:'task-agent'] = agent
|
|
1107
|
+
end
|
|
1108
|
+
define('--choria-config-file PATH',
|
|
1109
|
+
'Path to a Choria/MCollective client configuration file.') do |path|
|
|
1110
|
+
@options[:'config-file'] = path
|
|
1111
|
+
end
|
|
1112
|
+
define('--choria-mcollective-certname NAME',
|
|
1113
|
+
'Override the MCollective certname for Choria client identity.',
|
|
1114
|
+
'The choria-mcorpc-support library identifies non-root clients',
|
|
1115
|
+
"as '<username>.mcollective', which fails when authenticating",
|
|
1116
|
+
"with a certificate that has a different CN (e.g. the host's",
|
|
1117
|
+
'Puppet cert). Set this to the CN of the certificate being used.') do |name|
|
|
1118
|
+
@options[:'mcollective-certname'] = name
|
|
1119
|
+
end
|
|
1120
|
+
define('--choria-ssl-ca PATH',
|
|
1121
|
+
'CA certificate path for Choria TLS authentication.') do |path|
|
|
1122
|
+
@options[:'ssl-ca'] = path
|
|
1123
|
+
end
|
|
1124
|
+
define('--choria-ssl-cert PATH',
|
|
1125
|
+
'Client certificate path for Choria TLS authentication.') do |path|
|
|
1126
|
+
@options[:'ssl-cert'] = path
|
|
1127
|
+
end
|
|
1128
|
+
define('--choria-ssl-key PATH',
|
|
1129
|
+
'Client private key path for Choria TLS authentication.') do |path|
|
|
1130
|
+
@options[:'ssl-key'] = path
|
|
1131
|
+
end
|
|
1132
|
+
define('--choria-collective NAME',
|
|
1133
|
+
'Choria collective to route messages through.') do |name|
|
|
1134
|
+
@options[:collective] = name
|
|
1135
|
+
end
|
|
1136
|
+
define('--choria-puppet-environment ENV',
|
|
1137
|
+
"Puppet environment for bolt_tasks file downloads (default: 'production').") do |env|
|
|
1138
|
+
@options[:'puppet-environment'] = env
|
|
1139
|
+
end
|
|
1140
|
+
define('--choria-rpc-timeout SECONDS', Integer,
|
|
1141
|
+
'Seconds to wait for replies to individual Choria RPC calls (default: 30).') do |timeout|
|
|
1142
|
+
@options[:'rpc-timeout'] = timeout
|
|
1143
|
+
end
|
|
1144
|
+
define('--choria-task-timeout SECONDS', Integer,
|
|
1145
|
+
'Seconds to wait for task execution to complete (default: 300).') do |timeout|
|
|
1146
|
+
@options[:'task-timeout'] = timeout
|
|
1147
|
+
end
|
|
1148
|
+
define('--choria-command-timeout SECONDS', Integer,
|
|
1149
|
+
'Seconds to wait for commands and scripts to complete (default: 60).') do |timeout|
|
|
1150
|
+
@options[:'command-timeout'] = timeout
|
|
1151
|
+
end
|
|
1152
|
+
define('--choria-brokers BROKERS',
|
|
1153
|
+
'Choria broker addresses in host or host:port format (comma-separated). Port defaults to 4222 if omitted.') do |brokers|
|
|
1154
|
+
@options[:brokers] = brokers.split(',')
|
|
1155
|
+
end
|
|
1156
|
+
define('--choria-broker-timeout SECONDS', Integer,
|
|
1157
|
+
'Seconds to wait for the TCP connection to a Choria broker (default: 30).') do |timeout|
|
|
1158
|
+
@options[:'broker-timeout'] = timeout
|
|
1159
|
+
end
|
|
1098
1160
|
|
|
1099
1161
|
separator "\n#{self.class.colorize(:cyan, 'Module options')}"
|
|
1100
1162
|
define('--[no-]resolve',
|
data/lib/bolt/cli.rb
CHANGED
|
@@ -750,7 +750,7 @@ module Bolt
|
|
|
750
750
|
# built-in modules are installed.
|
|
751
751
|
#
|
|
752
752
|
private def incomplete_install?
|
|
753
|
-
builtin_module_list = %w[aggregate canary puppetdb_fact secure_env_vars
|
|
753
|
+
builtin_module_list = %w[aggregate canary puppetdb_fact secure_env_vars]
|
|
754
754
|
(Dir.children(Bolt::Config::Modulepath::MODULES_PATH) - builtin_module_list).empty?
|
|
755
755
|
end
|
|
756
756
|
|
data/lib/bolt/config/options.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../../bolt/config/transport/choria'
|
|
3
4
|
require_relative '../../bolt/config/transport/docker'
|
|
4
5
|
require_relative '../../bolt/config/transport/jail'
|
|
5
6
|
require_relative '../../bolt/config/transport/local'
|
|
@@ -15,6 +16,7 @@ module Bolt
|
|
|
15
16
|
# Transport config classes. Used to load default transport config which
|
|
16
17
|
# gets passed along to the inventory.
|
|
17
18
|
TRANSPORT_CONFIG = {
|
|
19
|
+
'choria' => Bolt::Config::Transport::Choria,
|
|
18
20
|
'docker' => Bolt::Config::Transport::Docker,
|
|
19
21
|
'jail' => Bolt::Config::Transport::Jail,
|
|
20
22
|
'local' => Bolt::Config::Transport::Local,
|
|
@@ -76,6 +78,12 @@ module Bolt
|
|
|
76
78
|
_example: 120,
|
|
77
79
|
_plugin: true
|
|
78
80
|
},
|
|
81
|
+
"headers" => {
|
|
82
|
+
description: "A map of HTTP headers to add to PuppetDB requests.",
|
|
83
|
+
type: Hash,
|
|
84
|
+
_example: { "Authorization" => "Bearer <token>" },
|
|
85
|
+
_plugin: true
|
|
86
|
+
},
|
|
79
87
|
"key" => {
|
|
80
88
|
description: "The private key for the certificate.",
|
|
81
89
|
type: String,
|
|
@@ -545,6 +553,12 @@ module Bolt
|
|
|
545
553
|
_example: "winrm",
|
|
546
554
|
_default: "ssh"
|
|
547
555
|
},
|
|
556
|
+
"choria" => {
|
|
557
|
+
description: "A map of configuration options for the choria transport.",
|
|
558
|
+
type: Hash,
|
|
559
|
+
_plugin: true,
|
|
560
|
+
_example: { "config-file" => "/etc/choria/client.conf" }
|
|
561
|
+
},
|
|
548
562
|
"docker" => {
|
|
549
563
|
description: "A map of configuration options for the docker transport.",
|
|
550
564
|
type: Hash,
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../../bolt/error'
|
|
4
|
+
require_relative '../../../bolt/config/transport/base'
|
|
5
|
+
|
|
6
|
+
module Bolt
|
|
7
|
+
class Config
|
|
8
|
+
module Transport
|
|
9
|
+
class Choria < Base
|
|
10
|
+
OPTIONS = %w[
|
|
11
|
+
cleanup
|
|
12
|
+
collective
|
|
13
|
+
command-timeout
|
|
14
|
+
config-file
|
|
15
|
+
host
|
|
16
|
+
interpreters
|
|
17
|
+
mcollective-certname
|
|
18
|
+
broker-timeout
|
|
19
|
+
brokers
|
|
20
|
+
puppet-environment
|
|
21
|
+
rpc-timeout
|
|
22
|
+
ssl-ca
|
|
23
|
+
ssl-cert
|
|
24
|
+
ssl-key
|
|
25
|
+
task-agent
|
|
26
|
+
task-timeout
|
|
27
|
+
tmpdir
|
|
28
|
+
].sort.freeze
|
|
29
|
+
|
|
30
|
+
DEFAULTS = {
|
|
31
|
+
'cleanup' => true,
|
|
32
|
+
'command-timeout' => 60,
|
|
33
|
+
'broker-timeout' => 30,
|
|
34
|
+
'puppet-environment' => 'production',
|
|
35
|
+
'rpc-timeout' => 30,
|
|
36
|
+
'task-timeout' => 300,
|
|
37
|
+
'tmpdir' => '/tmp'
|
|
38
|
+
}.freeze
|
|
39
|
+
|
|
40
|
+
VALID_AGENTS = %w[bolt_tasks shell].freeze
|
|
41
|
+
|
|
42
|
+
private def validate
|
|
43
|
+
super
|
|
44
|
+
|
|
45
|
+
if @config['task-agent'] && !VALID_AGENTS.include?(@config['task-agent'])
|
|
46
|
+
raise Bolt::ValidationError,
|
|
47
|
+
"task-agent must be one of #{VALID_AGENTS.join(', ')}, got '#{@config['task-agent']}'"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
if @config['tmpdir'] && !absolute_path?(@config['tmpdir'])
|
|
51
|
+
raise Bolt::ValidationError,
|
|
52
|
+
"Choria tmpdir must be an absolute path, got '#{@config['tmpdir']}'"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
ssl_keys = %w[ssl-ca ssl-cert ssl-key]
|
|
56
|
+
provided_ssl = ssl_keys.select { |k| @config[k] }
|
|
57
|
+
if provided_ssl.any? && provided_ssl.length < ssl_keys.length
|
|
58
|
+
missing = ssl_keys - provided_ssl
|
|
59
|
+
raise Bolt::ValidationError,
|
|
60
|
+
"When overriding Choria SSL settings, all three options must be provided " \
|
|
61
|
+
"(ssl-ca, ssl-cert, ssl-key). Missing: #{missing.join(', ')}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
@config['interpreters'] = normalize_interpreters(@config['interpreters']) if @config['interpreters']
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Accept both POSIX absolute paths (/tmp) and Windows absolute paths (C:\temp).
|
|
68
|
+
def absolute_path?(path)
|
|
69
|
+
path.start_with?('/') || path.match?(Bolt::Transport::Choria::WINDOWS_PATH_REGEX)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -51,6 +51,56 @@ module Bolt
|
|
|
51
51
|
_default: true,
|
|
52
52
|
_example: false
|
|
53
53
|
},
|
|
54
|
+
"task-agent" => {
|
|
55
|
+
type: String,
|
|
56
|
+
description: "Which Choria agent to use for task execution. Defaults to 'bolt_tasks' " \
|
|
57
|
+
"(downloads task files from a Puppet Server). Set to 'shell' for tasks " \
|
|
58
|
+
"not available on the Puppet Server.",
|
|
59
|
+
_plugin: true,
|
|
60
|
+
_example: "shell"
|
|
61
|
+
},
|
|
62
|
+
"collective" => {
|
|
63
|
+
type: String,
|
|
64
|
+
description: "The Choria collective to target. Overrides the main_collective from the Choria " \
|
|
65
|
+
"client configuration file.",
|
|
66
|
+
_plugin: true,
|
|
67
|
+
_example: "production"
|
|
68
|
+
},
|
|
69
|
+
"command-timeout" => {
|
|
70
|
+
type: Integer,
|
|
71
|
+
description: "How long to wait in seconds for commands and scripts to complete when using the " \
|
|
72
|
+
"Choria transport.",
|
|
73
|
+
minimum: 1,
|
|
74
|
+
_plugin: true,
|
|
75
|
+
_default: 60,
|
|
76
|
+
_example: 120
|
|
77
|
+
},
|
|
78
|
+
"config-file" => {
|
|
79
|
+
type: String,
|
|
80
|
+
description: "The path to the Choria or MCollective client configuration file.",
|
|
81
|
+
_plugin: true,
|
|
82
|
+
_example: "/etc/choria/client.conf"
|
|
83
|
+
},
|
|
84
|
+
"broker-timeout" => {
|
|
85
|
+
type: Integer,
|
|
86
|
+
description: "How long to wait in seconds for the initial TCP connection to a Choria broker. " \
|
|
87
|
+
"If the connection cannot be made within this time, the operation fails.",
|
|
88
|
+
minimum: 1,
|
|
89
|
+
_plugin: true,
|
|
90
|
+
_default: 30,
|
|
91
|
+
_example: 60
|
|
92
|
+
},
|
|
93
|
+
"rpc-timeout" => {
|
|
94
|
+
type: Integer,
|
|
95
|
+
description: "How long to wait in seconds for nodes to respond to an RPC request. " \
|
|
96
|
+
"Used for lightweight operations like agent discovery, shell.start, and " \
|
|
97
|
+
"shell.list polling. Distinct from command-timeout and task-timeout which " \
|
|
98
|
+
"govern the overall duration of commands and tasks.",
|
|
99
|
+
minimum: 1,
|
|
100
|
+
_plugin: true,
|
|
101
|
+
_default: 30,
|
|
102
|
+
_example: 60
|
|
103
|
+
},
|
|
54
104
|
"connect-timeout" => {
|
|
55
105
|
type: Integer,
|
|
56
106
|
description: "How long to wait in seconds when establishing connections. Set this value higher if you " \
|
|
@@ -225,6 +275,27 @@ module Bolt
|
|
|
225
275
|
_plugin: true,
|
|
226
276
|
_example: %w[defaults hmac-md5]
|
|
227
277
|
},
|
|
278
|
+
"mcollective-certname" => {
|
|
279
|
+
type: String,
|
|
280
|
+
description: "Override the MCollective certname used for Choria client identity. " \
|
|
281
|
+
"The choria-mcorpc-support library identifies non-root clients as " \
|
|
282
|
+
"'<username>.mcollective'. Set this when authenticating with a certificate " \
|
|
283
|
+
"whose CN differs from that default (e.g. the host's Puppet cert).",
|
|
284
|
+
_plugin: true,
|
|
285
|
+
_example: "primary.example.com"
|
|
286
|
+
},
|
|
287
|
+
"brokers" => {
|
|
288
|
+
type: [String, Array],
|
|
289
|
+
description: "One or more Choria broker addresses in host or host:port format. " \
|
|
290
|
+
"Port defaults to 4222 if omitted. Do not use the nats:// prefix. " \
|
|
291
|
+
"Overrides the middleware hosts from the Choria client configuration file. " \
|
|
292
|
+
"Can be a single string or an array.",
|
|
293
|
+
items: {
|
|
294
|
+
type: String
|
|
295
|
+
},
|
|
296
|
+
_plugin: true,
|
|
297
|
+
_example: ["broker1:4222", "broker2:4222"]
|
|
298
|
+
},
|
|
228
299
|
"native-ssh" => {
|
|
229
300
|
type: [TrueClass, FalseClass],
|
|
230
301
|
description: "This enables the native SSH transport, which shells out to SSH instead of using the " \
|
|
@@ -267,6 +338,14 @@ module Bolt
|
|
|
267
338
|
_plugin: true,
|
|
268
339
|
_example: "jump.example.com"
|
|
269
340
|
},
|
|
341
|
+
"puppet-environment" => {
|
|
342
|
+
type: String,
|
|
343
|
+
description: "The Puppet environment to use when constructing task file URIs for the Choria " \
|
|
344
|
+
"bolt_tasks agent.",
|
|
345
|
+
_plugin: true,
|
|
346
|
+
_default: "production",
|
|
347
|
+
_example: "staging"
|
|
348
|
+
},
|
|
270
349
|
"read-timeout" => {
|
|
271
350
|
type: Integer,
|
|
272
351
|
description: "How long to wait in seconds when making requests to the Orchestrator.",
|
|
@@ -343,6 +422,27 @@ module Bolt
|
|
|
343
422
|
_plugin: true,
|
|
344
423
|
_example: 445
|
|
345
424
|
},
|
|
425
|
+
"ssl-ca" => {
|
|
426
|
+
type: String,
|
|
427
|
+
description: "The path to the CA certificate for Choria TLS connections. Overrides the CA " \
|
|
428
|
+
"from the Choria client configuration file.",
|
|
429
|
+
_plugin: true,
|
|
430
|
+
_example: "/etc/choria/ssl/ca.pem"
|
|
431
|
+
},
|
|
432
|
+
"ssl-cert" => {
|
|
433
|
+
type: String,
|
|
434
|
+
description: "The path to the client certificate for Choria TLS connections. Overrides the " \
|
|
435
|
+
"certificate from the Choria client configuration file.",
|
|
436
|
+
_plugin: true,
|
|
437
|
+
_example: "/etc/choria/ssl/client.pem"
|
|
438
|
+
},
|
|
439
|
+
"ssl-key" => {
|
|
440
|
+
type: String,
|
|
441
|
+
description: "The path to the client private key for Choria TLS connections. Overrides the " \
|
|
442
|
+
"key from the Choria client configuration file.",
|
|
443
|
+
_plugin: true,
|
|
444
|
+
_example: "/etc/choria/ssl/client-key.pem"
|
|
445
|
+
},
|
|
346
446
|
"ssh-command" => {
|
|
347
447
|
type: [Array, String],
|
|
348
448
|
description: "The command and options to use when SSHing. This option is used when you need support for " \
|
|
@@ -393,6 +493,14 @@ module Bolt
|
|
|
393
493
|
_default: "production",
|
|
394
494
|
_example: "development"
|
|
395
495
|
},
|
|
496
|
+
"task-timeout" => {
|
|
497
|
+
type: Integer,
|
|
498
|
+
description: "How long to wait in seconds for tasks to complete when using the Choria transport.",
|
|
499
|
+
minimum: 1,
|
|
500
|
+
_plugin: true,
|
|
501
|
+
_default: 300,
|
|
502
|
+
_example: 300
|
|
503
|
+
},
|
|
396
504
|
"tmpdir" => {
|
|
397
505
|
type: String,
|
|
398
506
|
description: "The directory to upload and execute temporary files on the target.",
|
data/lib/bolt/executor.rb
CHANGED
|
@@ -13,6 +13,7 @@ require_relative '../bolt/puppetdb'
|
|
|
13
13
|
require_relative '../bolt/result'
|
|
14
14
|
require_relative '../bolt/result_set'
|
|
15
15
|
# Load transports
|
|
16
|
+
require_relative '../bolt/transport/choria'
|
|
16
17
|
require_relative '../bolt/transport/docker'
|
|
17
18
|
require_relative '../bolt/transport/jail'
|
|
18
19
|
require_relative '../bolt/transport/local'
|
|
@@ -24,6 +25,7 @@ require_relative '../bolt/transport/winrm'
|
|
|
24
25
|
|
|
25
26
|
module Bolt
|
|
26
27
|
TRANSPORTS = {
|
|
28
|
+
choria: Bolt::Transport::Choria,
|
|
27
29
|
docker: Bolt::Transport::Docker,
|
|
28
30
|
jail: Bolt::Transport::Jail,
|
|
29
31
|
local: Bolt::Transport::Local,
|
|
@@ -22,7 +22,7 @@ module Bolt
|
|
|
22
22
|
|
|
23
23
|
plan_object = parse_plan
|
|
24
24
|
param_descriptions = plan_object.parameters.map do |param|
|
|
25
|
-
str =
|
|
25
|
+
str = "# @param #{param.name}"
|
|
26
26
|
str << " #{param.description}" if param.description
|
|
27
27
|
str
|
|
28
28
|
end.join("\n")
|
data/lib/bolt/plugin/puppetdb.rb
CHANGED
|
@@ -5,7 +5,7 @@ module Bolt
|
|
|
5
5
|
class Puppetdb
|
|
6
6
|
class FactLookupError < Bolt::Error
|
|
7
7
|
def initialize(fact, err = nil)
|
|
8
|
-
m =
|
|
8
|
+
m = "Fact lookup '#{fact}' contains an invalid factname"
|
|
9
9
|
m << ": #{err}" unless err.nil?
|
|
10
10
|
super(m, 'bolt.plugin/fact-lookup-error')
|
|
11
11
|
end
|
data/lib/bolt/plugin.rb
CHANGED
|
@@ -127,7 +127,7 @@ module Bolt
|
|
|
127
127
|
end
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
-
RUBY_PLUGINS = %w[task prompt env_var puppetdb
|
|
130
|
+
RUBY_PLUGINS = %w[task prompt env_var puppetdb].freeze
|
|
131
131
|
BUILTIN_PLUGINS = %w[task terraform pkcs7 prompt vault aws_inventory puppetdb azure_inventory
|
|
132
132
|
yaml env_var gcloud_inventory].freeze
|
|
133
133
|
DEFAULT_PLUGIN_HOOKS = { 'puppet_library' => { 'plugin' => 'openvox_bootstrap', 'stop_service' => true } }.freeze
|
|
@@ -255,9 +255,6 @@ module Bolt
|
|
|
255
255
|
hooks = KNOWN_HOOKS.map { |hook| [hook, {}] }.to_h
|
|
256
256
|
|
|
257
257
|
@plugins.sort.each do |name, plugin|
|
|
258
|
-
# Don't show the Puppet Connect plugin for now.
|
|
259
|
-
next if name == 'puppet_connect_data'
|
|
260
|
-
|
|
261
258
|
case plugin
|
|
262
259
|
when Bolt::Plugin::Module
|
|
263
260
|
plugin.hook_map.each do |hook, spec|
|
data/lib/bolt/puppetdb/config.rb
CHANGED
|
@@ -149,6 +149,14 @@ module Bolt
|
|
|
149
149
|
@settings['key']
|
|
150
150
|
end
|
|
151
151
|
|
|
152
|
+
def headers
|
|
153
|
+
if @settings['headers'] && !@settings['headers'].is_a?(Hash)
|
|
154
|
+
raise Bolt::PuppetDBError, "headers must be a Hash"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
@settings['headers']
|
|
158
|
+
end
|
|
159
|
+
|
|
152
160
|
def validate_cert_and_key
|
|
153
161
|
if (@settings['cert'] && !@settings['key']) ||
|
|
154
162
|
(!@settings['cert'] && @settings['key'])
|
data/lib/bolt/result_set.rb
CHANGED
|
@@ -27,7 +27,7 @@ module Bolt
|
|
|
27
27
|
|
|
28
28
|
def iterator
|
|
29
29
|
if Object.const_defined?(:Puppet) && Puppet.const_defined?(:Pops) &&
|
|
30
|
-
self.class.
|
|
30
|
+
self.class.include?(Puppet::Pops::Types::Iterable)
|
|
31
31
|
Puppet::Pops::Types::Iterable.on(@results, Bolt::Result)
|
|
32
32
|
else
|
|
33
33
|
raise NotImplementedError, "iterator requires puppet code to be loaded."
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bolt
|
|
4
|
+
module Transport
|
|
5
|
+
class Choria
|
|
6
|
+
SHELL_MIN_VERSION = '1.2.1'
|
|
7
|
+
|
|
8
|
+
AGENT_MIN_VERSIONS = {
|
|
9
|
+
'shell' => SHELL_MIN_VERSION
|
|
10
|
+
}.freeze
|
|
11
|
+
|
|
12
|
+
# Discover agents and detect OS on targets via two batched RPC calls
|
|
13
|
+
# (agent_inventory for agents+versions, get_fact for os.family).
|
|
14
|
+
# Populates @agent_cache with { agents: [...], os: 'redhat' | 'windows' | ... }.
|
|
15
|
+
#
|
|
16
|
+
# @param targets [Array<Bolt::Target>] Targets to discover agents on
|
|
17
|
+
def discover_agents(targets)
|
|
18
|
+
uncached = targets.reject { |target| @agent_cache.key?(choria_identity(target)) }
|
|
19
|
+
return if uncached.empty?
|
|
20
|
+
|
|
21
|
+
logger.debug { "Discovering agents on #{target_count(uncached)}" }
|
|
22
|
+
discover_agent_list(uncached)
|
|
23
|
+
discover_os_family(uncached)
|
|
24
|
+
|
|
25
|
+
uncached.each do |target|
|
|
26
|
+
identity = choria_identity(target)
|
|
27
|
+
logger.warn { "No response from #{identity} during agent discovery" } unless @agent_cache.key?(identity)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def has_agent?(target, agent_name)
|
|
32
|
+
@agent_cache[choria_identity(target)]&.dig(:agents)&.include?(agent_name) || false
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def windows_target?(target)
|
|
36
|
+
@agent_cache[choria_identity(target)]&.dig(:os) == 'windows'
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Discover available agents on targets via rpcutil.agent_inventory
|
|
40
|
+
# and populate @agent_cache with agent lists.
|
|
41
|
+
#
|
|
42
|
+
# @param targets [Array<Bolt::Target>] Targets to query for agent inventory
|
|
43
|
+
def discover_agent_list(targets)
|
|
44
|
+
response = rpc_request('rpcutil', targets, 'rpcutil.agent_inventory') do |client|
|
|
45
|
+
client.agent_inventory
|
|
46
|
+
end
|
|
47
|
+
response[:errors].each { |target, output| logger.debug { "agent_inventory failed for #{target.safe_name}: #{output[:error]}" } }
|
|
48
|
+
|
|
49
|
+
response[:responded].each do |target, data|
|
|
50
|
+
sender = choria_identity(target)
|
|
51
|
+
agents = filter_agents(sender, data[:agents])
|
|
52
|
+
unless agents
|
|
53
|
+
logger.warn { "Unexpected agent_inventory response from #{sender}. This target will be treated as unreachable." }
|
|
54
|
+
next
|
|
55
|
+
end
|
|
56
|
+
@agent_cache[sender] = { agents: agents }
|
|
57
|
+
logger.debug { "Discovered agents on #{sender}: #{agents.join(', ')}" }
|
|
58
|
+
end
|
|
59
|
+
rescue StandardError => e
|
|
60
|
+
raise if e.is_a?(Bolt::Error)
|
|
61
|
+
|
|
62
|
+
logger.warn { "Agent discovery failed: #{e.class}: #{e.message}" }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Detect the OS family on targets via rpcutil.get_fact and update
|
|
66
|
+
# @agent_cache entries with the :os key.
|
|
67
|
+
#
|
|
68
|
+
# @param targets [Array<Bolt::Target>] Targets to detect OS on
|
|
69
|
+
def discover_os_family(targets)
|
|
70
|
+
# Only fetch OS for targets that responded to agent_inventory
|
|
71
|
+
responded = targets.select { |target| @agent_cache.key?(choria_identity(target)) }
|
|
72
|
+
return if responded.empty?
|
|
73
|
+
|
|
74
|
+
response = rpc_request('rpcutil', responded, 'rpcutil.get_fact') do |client|
|
|
75
|
+
client.get_fact(fact: 'os.family')
|
|
76
|
+
end
|
|
77
|
+
response[:errors].each { |target, output|
|
|
78
|
+
logger.warn {
|
|
79
|
+
"OS detection failed for #{target.safe_name}: #{output[:error]}. Defaulting to POSIX command syntax."
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
response[:responded].each do |target, data|
|
|
84
|
+
sender = choria_identity(target)
|
|
85
|
+
os_family = data[:value].to_s.downcase
|
|
86
|
+
if os_family.empty?
|
|
87
|
+
logger.warn { "os.family fact is empty on #{sender}. Defaulting to POSIX command syntax." }
|
|
88
|
+
next
|
|
89
|
+
end
|
|
90
|
+
@agent_cache[sender][:os] = os_family
|
|
91
|
+
logger.debug { "Detected OS on #{sender}: #{os_family}" }
|
|
92
|
+
end
|
|
93
|
+
rescue StandardError => e
|
|
94
|
+
raise if e.is_a?(Bolt::Error)
|
|
95
|
+
|
|
96
|
+
logger.warn { "OS detection failed: #{e.class}: #{e.message}. Defaulting to POSIX command syntax." }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Filter out agents that don't meet minimum version requirements.
|
|
100
|
+
#
|
|
101
|
+
# @param sender [String] Choria node identity (for logging)
|
|
102
|
+
# @param agent_list [Array<Hash>, nil] Agent entries from agent_inventory, each with
|
|
103
|
+
# :agent (name) and :version keys
|
|
104
|
+
# @return [Array<String>, nil] Agent names that meet version requirements, or nil
|
|
105
|
+
# if agent_list is not an Array
|
|
106
|
+
def filter_agents(sender, agent_list)
|
|
107
|
+
return nil unless agent_list.is_a?(Array)
|
|
108
|
+
|
|
109
|
+
agent_list.filter_map do |entry|
|
|
110
|
+
name = entry['agent']
|
|
111
|
+
next unless name
|
|
112
|
+
|
|
113
|
+
version = entry['version']
|
|
114
|
+
min_version = AGENT_MIN_VERSIONS[name]
|
|
115
|
+
if min_version && !meets_min_version?(version, min_version)
|
|
116
|
+
logger.warn {
|
|
117
|
+
"The '#{name}' agent on #{sender} is version #{version || 'unknown'}, " \
|
|
118
|
+
"but #{min_version} or later is required. It will be treated as unavailable."
|
|
119
|
+
}
|
|
120
|
+
next
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
name
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def meets_min_version?(version, min_version)
|
|
128
|
+
return false unless version
|
|
129
|
+
|
|
130
|
+
Gem::Version.new(version) >= Gem::Version.new(min_version)
|
|
131
|
+
rescue ArgumentError => e
|
|
132
|
+
logger.warn { "Could not parse version '#{version}': #{e.message}. Treating agent as unavailable." }
|
|
133
|
+
false
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|