bolt 0.18.0 → 0.18.1
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/puppetdb_fact.rb +27 -0
- data/lib/bolt/cli.rb +16 -21
- data/lib/bolt/error.rb +10 -0
- data/lib/bolt/executor.rb +13 -0
- data/lib/bolt/inventory.rb +2 -2
- data/lib/bolt/pal.rb +15 -19
- data/lib/bolt/puppetdb/client.rb +27 -0
- data/lib/bolt/transport/local.rb +0 -2
- data/lib/bolt/transport/local/shell.rb +1 -1
- data/lib/bolt/util.rb +15 -1
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_ext/puppetdb_inventory.rb +1 -1
- data/modules/puppetdb_fact/plans/init.pp +10 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0658ba25967cd7fac93e3b0c410793f2d389849f
|
4
|
+
data.tar.gz: f7a6cafb673449de219fb9bade1e672d4ff858eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3908b25652b38dd0a7e48656b3442fe6b5e85fd23942dbb2be207f4f4f39397b18d7b87706791075773b53c0d297d0b9ba8743a0070c5bcde8d8d7be11a71ce8
|
7
|
+
data.tar.gz: e837918752a7e2cc2ac2bff3aa72f480c4fcf7f498fca15cf355a9cb2b7bc24faa2e91b1684e7650ead33a06315961ceb6792148b70cff974bc0e960972454ca
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/error'
|
4
|
+
|
5
|
+
# Returns a hash of certname to facts objects for each matched Target. This
|
6
|
+
# functions accepts an array of certnames and returns a hash of target
|
7
|
+
# certnames and their corresponding facts hash.
|
8
|
+
#
|
9
|
+
# * If a node is not found in PuppetDB, it's included in the returned hash with empty facts hash.
|
10
|
+
# * Otherwise the node is included in the hash with a value that is a hash of it's facts.
|
11
|
+
#
|
12
|
+
Puppet::Functions.create_function(:puppetdb_fact) do
|
13
|
+
dispatch :puppetdb_fact do
|
14
|
+
param 'Array[String]', :targets
|
15
|
+
end
|
16
|
+
|
17
|
+
def puppetdb_fact(targets)
|
18
|
+
unless Puppet[:tasks]
|
19
|
+
raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
|
20
|
+
Puppet::Pops::Issues::TASK_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, operation: 'puppetdb_fact'
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
executor = Puppet.lookup(:bolt_executor) { nil }
|
25
|
+
executor.puppetdb_fact(targets)
|
26
|
+
end
|
27
|
+
end
|
data/lib/bolt/cli.rb
CHANGED
@@ -116,20 +116,15 @@ Available options are:
|
|
116
116
|
@options = options
|
117
117
|
|
118
118
|
@nodes = define('-n', '--nodes NODES',
|
119
|
-
'
|
120
|
-
'
|
121
|
-
'
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
'
|
128
|
-
'* nodes from a file, or \'-\' to read from stdin',
|
129
|
-
'* Windows nodes must specify protocol with winrm://',
|
130
|
-
'* protocol is `ssh` by default, may be `ssh` or `winrm`',
|
131
|
-
'* port defaults to `22` for SSH',
|
132
|
-
'* port defaults to `5985` or `5986` for WinRM, based on the --[no-]ssl setting') do |nodes|
|
119
|
+
'Identifies the nodes to target.',
|
120
|
+
'Enter a comma-separated list of node URIs or group names.',
|
121
|
+
"Or read a node list from an input file '@<file>' or stdin '-'.",
|
122
|
+
'Example: --nodes localhost,node_group,ssh://nix.com:2222,winrm://windows.puppet.com',
|
123
|
+
'URI format is [protocol://]host[:port]',
|
124
|
+
"SSH is the default protocol; may be #{TRANSPORTS.keys.join(', ')}",
|
125
|
+
'For Windows nodes, specify the winrm:// protocol if it has not be configured',
|
126
|
+
'For SSH, port defaults to `22`',
|
127
|
+
'For WinRM, port defaults to `5985` or `5986` based on the --[no-]ssl setting') do |nodes|
|
133
128
|
@options[:nodes] << get_arg_input(nodes)
|
134
129
|
end.extend(SwitchHider)
|
135
130
|
@query = define('-q', '--query QUERY',
|
@@ -137,11 +132,11 @@ Available options are:
|
|
137
132
|
@options[:query] = query
|
138
133
|
end.extend(SwitchHider)
|
139
134
|
define('-u', '--user USER',
|
140
|
-
'User to authenticate as
|
135
|
+
'User to authenticate as') do |user|
|
141
136
|
@options[:user] = user
|
142
137
|
end
|
143
138
|
define('-p', '--password [PASSWORD]',
|
144
|
-
'Password to authenticate with
|
139
|
+
'Password to authenticate with.',
|
145
140
|
'Omit the value to prompt for the password.') do |password|
|
146
141
|
if password.nil?
|
147
142
|
STDOUT.print "Please enter your password: "
|
@@ -152,25 +147,25 @@ Available options are:
|
|
152
147
|
end
|
153
148
|
end
|
154
149
|
define('--private-key KEY',
|
155
|
-
'Private ssh key to authenticate with
|
150
|
+
'Private ssh key to authenticate with') do |key|
|
156
151
|
@options[:'private-key'] = key
|
157
152
|
end
|
158
153
|
define('--tmpdir DIR',
|
159
|
-
'The directory to upload and execute temporary files on the target
|
154
|
+
'The directory to upload and execute temporary files on the target') do |tmpdir|
|
160
155
|
@options[:tmpdir] = tmpdir
|
161
156
|
end
|
162
157
|
define('-c', '--concurrency CONCURRENCY', Integer,
|
163
158
|
'Maximum number of simultaneous connections ' \
|
164
|
-
'(
|
159
|
+
'(defaults to 100)') do |concurrency|
|
165
160
|
@options[:concurrency] = concurrency
|
166
161
|
end
|
167
162
|
define('--connect-timeout TIMEOUT', Integer,
|
168
|
-
'Connection timeout (
|
163
|
+
'Connection timeout (defaults vary)') do |timeout|
|
169
164
|
@options[:'connect-timeout'] = timeout
|
170
165
|
end
|
171
166
|
define('--modulepath MODULES',
|
172
167
|
'List of directories containing modules, ' \
|
173
|
-
"separated by #{File::PATH_SEPARATOR}") do |modulepath|
|
168
|
+
"separated by '#{File::PATH_SEPARATOR}'") do |modulepath|
|
174
169
|
@options[:modulepath] = modulepath.split(File::PATH_SEPARATOR)
|
175
170
|
end
|
176
171
|
define('--params PARAMETERS',
|
data/lib/bolt/error.rb
CHANGED
@@ -63,4 +63,14 @@ module Bolt
|
|
63
63
|
@error_code = 2
|
64
64
|
end
|
65
65
|
end
|
66
|
+
|
67
|
+
class PuppetError < Error
|
68
|
+
def self.convert_puppet_errors(result)
|
69
|
+
Bolt::Util.walk_vals(result) { |v| v.is_a?(Puppet::DataTypes::Error) ? from_error(v) : v }
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.from_error(err)
|
73
|
+
new(err.msg, err.kind, err.details, err.issue_code)
|
74
|
+
end
|
75
|
+
end
|
66
76
|
end
|
data/lib/bolt/executor.rb
CHANGED
@@ -9,6 +9,7 @@ require 'bolt/result'
|
|
9
9
|
require 'bolt/config'
|
10
10
|
require 'bolt/notifier'
|
11
11
|
require 'bolt/result_set'
|
12
|
+
require 'bolt/puppetdb'
|
12
13
|
|
13
14
|
module Bolt
|
14
15
|
class Executor
|
@@ -154,5 +155,17 @@ module Bolt
|
|
154
155
|
@notifier.shutdown
|
155
156
|
results
|
156
157
|
end
|
158
|
+
|
159
|
+
def puppetdb_client
|
160
|
+
return @puppetdb_client if @puppetdb_client
|
161
|
+
puppetdb_config = Bolt::PuppetDB::Config.new(nil, @config.puppetdb)
|
162
|
+
@puppetdb_client = Bolt::PuppetDB::Client.from_config(puppetdb_config)
|
163
|
+
end
|
164
|
+
|
165
|
+
def puppetdb_fact(certnames)
|
166
|
+
puppetdb_client.facts_for_node(certnames)
|
167
|
+
rescue StandardError => e
|
168
|
+
raise Bolt::CLIError, "Could not retrieve targets from PuppetDB: #{e}"
|
169
|
+
end
|
157
170
|
end
|
158
171
|
end
|
data/lib/bolt/inventory.rb
CHANGED
@@ -93,7 +93,7 @@ module Bolt
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def vars(target)
|
96
|
-
@target_vars[target.name]
|
96
|
+
@target_vars[target.name] || {}
|
97
97
|
end
|
98
98
|
|
99
99
|
def add_facts(target, new_facts = {})
|
@@ -102,7 +102,7 @@ module Bolt
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def facts(target)
|
105
|
-
@target_facts[target.name]
|
105
|
+
@target_facts[target.name] || {}
|
106
106
|
end
|
107
107
|
|
108
108
|
#### PRIVATE ####
|
data/lib/bolt/pal.rb
CHANGED
@@ -41,14 +41,6 @@ module Bolt
|
|
41
41
|
# Now that puppet is loaded we can include puppet mixins in data types
|
42
42
|
Bolt::ResultSet.include_iterable
|
43
43
|
|
44
|
-
# TODO: This is a hack for PUP-8441 remove it once that is fixed
|
45
|
-
require_relative '../../vendored/puppet/lib/puppet/datatypes/impl/error.rb'
|
46
|
-
Puppet::DataTypes::Error.class_eval do
|
47
|
-
def to_json(opts = nil)
|
48
|
-
_pcore_init_hash.to_json(opts)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
44
|
unless Puppet.settings.global_defaults_initialized?
|
53
45
|
Puppet.initialize_settings
|
54
46
|
end
|
@@ -99,7 +91,8 @@ module Bolt
|
|
99
91
|
end
|
100
92
|
end
|
101
93
|
|
102
|
-
|
94
|
+
# Plans may return PuppetError but nothing should be throwing them
|
95
|
+
if r.is_a?(StandardError) && !r.is_a?(Bolt::PuppetError)
|
103
96
|
raise r
|
104
97
|
end
|
105
98
|
r
|
@@ -153,7 +146,7 @@ module Bolt
|
|
153
146
|
def parse_params(type, object_name, params)
|
154
147
|
in_bolt_compiler do |compiler|
|
155
148
|
if type == 'task'
|
156
|
-
param_spec = compiler.task_signature(object_name)&.task_hash
|
149
|
+
param_spec = compiler.task_signature(object_name)&.task_hash
|
157
150
|
elsif type == 'plan'
|
158
151
|
plan = compiler.plan_signature(object_name)
|
159
152
|
param_spec = plan_hash(object_name, plan) if plan
|
@@ -161,7 +154,7 @@ module Bolt
|
|
161
154
|
param_spec ||= {}
|
162
155
|
|
163
156
|
params.each_with_object({}) do |(name, str), acc|
|
164
|
-
type = param_spec.dig(name, 'type')
|
157
|
+
type = param_spec.dig('parameters', name, 'type')
|
165
158
|
begin
|
166
159
|
parsed = JSON.parse(str, quirks_mode: true)
|
167
160
|
# The type may not exist if the module is remote on orch or if a task
|
@@ -199,10 +192,11 @@ module Bolt
|
|
199
192
|
end
|
200
193
|
end
|
201
194
|
|
202
|
-
# This
|
203
|
-
#
|
195
|
+
# This converts a plan signature object into a format approximating the
|
196
|
+
# task_hash of a task_signature. Must be called from within bolt compiler
|
197
|
+
# to pickup type aliases used in the plan signature.
|
204
198
|
def plan_hash(plan_name, plan)
|
205
|
-
elements = plan.params_type.elements ||
|
199
|
+
elements = plan.params_type.elements || []
|
206
200
|
parameters = elements.each_with_object({}) do |param, acc|
|
207
201
|
acc[param.name] = { 'type' => param.value_type }
|
208
202
|
acc[param.name]['default_value'] = nil if param.key_type.is_a?(Puppet::Pops::Types::POptionalType)
|
@@ -214,14 +208,15 @@ module Bolt
|
|
214
208
|
end
|
215
209
|
|
216
210
|
def get_plan_info(plan_name)
|
217
|
-
|
218
|
-
compiler.plan_signature(plan_name)
|
211
|
+
plan_info = in_bolt_compiler do |compiler|
|
212
|
+
plan = compiler.plan_signature(plan_name)
|
213
|
+
plan_hash(plan_name, plan) if plan
|
219
214
|
end
|
220
215
|
|
221
|
-
if
|
216
|
+
if plan_info.nil?
|
222
217
|
raise Bolt::CLIError, Bolt::Error.unknown_plan(plan_name)
|
223
218
|
end
|
224
|
-
|
219
|
+
plan_info
|
225
220
|
end
|
226
221
|
|
227
222
|
def run_task(task_name, targets, params, executor, inventory, &eventblock)
|
@@ -232,7 +227,8 @@ module Bolt
|
|
232
227
|
|
233
228
|
def run_plan(plan_name, params, executor = nil, inventory = nil)
|
234
229
|
in_plan_compiler(executor, inventory) do |compiler|
|
235
|
-
compiler.call_function('run_plan', plan_name, params)
|
230
|
+
r = compiler.call_function('run_plan', plan_name, params)
|
231
|
+
Bolt::PuppetError.convert_puppet_errors(r)
|
236
232
|
end
|
237
233
|
end
|
238
234
|
end
|
data/lib/bolt/puppetdb/client.rb
CHANGED
@@ -51,6 +51,33 @@ module Bolt
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
# This method expects an array of certnames to get facts for
|
55
|
+
def facts_for_node(certnames)
|
56
|
+
return {} if certnames.empty? || certnames.nil?
|
57
|
+
|
58
|
+
# This inits a hash of {certname1 => {}, certname2 => {}} etc.
|
59
|
+
output = Hash[certnames.product([{}])]
|
60
|
+
|
61
|
+
certnames.uniq!
|
62
|
+
name_query = certnames.map { |c| ["=", "certname", c] }
|
63
|
+
name_query.insert(0, "or")
|
64
|
+
body = JSON.generate(query: name_query)
|
65
|
+
|
66
|
+
response = http_client.post("#{@uri}/pdb/query/v4/facts", body: body, header: headers)
|
67
|
+
if response.code != 200
|
68
|
+
raise Bolt::PuppetDBError, "Failed to query PuppetDB: #{response.body}"
|
69
|
+
else
|
70
|
+
parsed = JSON.parse(response.body)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Parse the data
|
74
|
+
parsed&.each do |f|
|
75
|
+
output[f['certname']][f['name']] = f['value']
|
76
|
+
end
|
77
|
+
|
78
|
+
output
|
79
|
+
end
|
80
|
+
|
54
81
|
def http_client
|
55
82
|
return @http if @http
|
56
83
|
@http = HTTPClient.new
|
data/lib/bolt/transport/local.rb
CHANGED
@@ -9,7 +9,7 @@ module Bolt
|
|
9
9
|
class Shell
|
10
10
|
def execute(*command, options)
|
11
11
|
if options[:env]
|
12
|
-
env = options[:env].each_with_object({}) { |(k, v), h| h["PT_#{k}"] = v }
|
12
|
+
env = options[:env].each_with_object({}) { |(k, v), h| h["PT_#{k}"] = v.to_s }
|
13
13
|
command = [env] + command
|
14
14
|
end
|
15
15
|
|
data/lib/bolt/util.rb
CHANGED
@@ -46,7 +46,7 @@ module Bolt
|
|
46
46
|
end
|
47
47
|
|
48
48
|
# Accepts a Data object and returns a copy with all hash keys
|
49
|
-
#
|
49
|
+
# modified by block. use &:to_s to stringify keys or &:to_sym to symbolize them
|
50
50
|
def walk_keys(data, &block)
|
51
51
|
if data.is_a? Hash
|
52
52
|
data.each_with_object({}) do |(k, v), acc|
|
@@ -60,6 +60,20 @@ module Bolt
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
+
# Accepts a Data object and returns a copy with all hash and array values
|
64
|
+
# Arrays and hashes including the initial object are modified before
|
65
|
+
# their descendants are.
|
66
|
+
def walk_vals(data, &block)
|
67
|
+
data = yield(data)
|
68
|
+
if data.is_a? Hash
|
69
|
+
map_vals(data) { |v| walk_vals(v, &block) }
|
70
|
+
elsif data.is_a? Array
|
71
|
+
data.map { |v| walk_vals(v, &block) }
|
72
|
+
else
|
73
|
+
data
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
63
77
|
# Performs a deep_clone, using an identical copy if the cloned structure contains multiple
|
64
78
|
# references to the same object and prevents endless recursion.
|
65
79
|
# Credit to Jan Molic via https://github.com/rubyworks/facets/blob/master/LICENSE.txt
|
data/lib/bolt/version.rb
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
plan puppetdb_fact(TargetSpec $nodes) {
|
2
|
+
$targets = get_targets($nodes)
|
3
|
+
$certnames = $targets.map |$target| { $target.host }
|
4
|
+
$pdb_facts = puppetdb_fact($certnames)
|
5
|
+
$targets.each |$target| {
|
6
|
+
add_facts($target, $pdb_facts[$target.host])
|
7
|
+
}
|
8
|
+
|
9
|
+
return $pdb_facts
|
10
|
+
}
|
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: 0.18.
|
4
|
+
version: 0.18.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-03-
|
11
|
+
date: 2018-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -327,6 +327,7 @@ files:
|
|
327
327
|
- bolt-modules/boltlib/lib/puppet/functions/fail_plan.rb
|
328
328
|
- bolt-modules/boltlib/lib/puppet/functions/file_upload.rb
|
329
329
|
- bolt-modules/boltlib/lib/puppet/functions/get_targets.rb
|
330
|
+
- bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb
|
330
331
|
- bolt-modules/boltlib/lib/puppet/functions/run_command.rb
|
331
332
|
- bolt-modules/boltlib/lib/puppet/functions/run_plan.rb
|
332
333
|
- bolt-modules/boltlib/lib/puppet/functions/run_script.rb
|
@@ -376,6 +377,7 @@ files:
|
|
376
377
|
- modules/canary/lib/puppet/functions/canary/random_split.rb
|
377
378
|
- modules/canary/lib/puppet/functions/canary/skip.rb
|
378
379
|
- modules/canary/plans/init.pp
|
380
|
+
- modules/puppetdb_fact/plans/init.pp
|
379
381
|
- vendored/facter/lib/facter.rb
|
380
382
|
- vendored/facter/lib/facter/Cfkey.rb
|
381
383
|
- vendored/facter/lib/facter/application.rb
|