bolt 0.21.0 → 0.21.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/add_facts.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/fail_plan.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/set_feature.rb +4 -2
- data/bolt-modules/boltlib/lib/puppet/functions/vars.rb +2 -2
- data/bolt-modules/boltlib/lib/puppet/functions/without_default_logging.rb +5 -3
- data/exe/bolt_catalog +34 -0
- data/lib/bolt/bolt_option_parser.rb +3 -0
- data/lib/bolt/catalog.rb +123 -0
- data/lib/bolt/cli.rb +1 -1
- data/lib/bolt/config.rb +2 -1
- data/lib/bolt/inventory.rb +4 -1
- data/lib/bolt/inventory/group.rb +14 -9
- data/lib/bolt/outputter.rb +5 -4
- data/lib/bolt/outputter/human.rb +6 -0
- data/lib/bolt/outputter/json.rb +8 -3
- data/lib/bolt/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7cfabedc8ddc7e9d4f1345d676f959e08d6bf5f8
|
4
|
+
data.tar.gz: d05d6c279ff68b287402b6ea1439bec634b7caed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 959a5345daf5570d015c8a4d1decde76e963840104467c56d7cc86b1322d7a06b59cecb3d2b38c3dd8acaef59950bfce8be8f2b92b752f491646e4738b3d22e0
|
7
|
+
data.tar.gz: 3d772b7542b144c6916d04ead84a310ff3484df651a11c9332b2548b177423b634dd371263002365a8ce6d93581b01ec7b116b72678499da1fb7989e1ed19710
|
@@ -5,7 +5,7 @@ require 'bolt/error'
|
|
5
5
|
# Deep merges a hash of facts with the existing facts on a target.
|
6
6
|
Puppet::Functions.create_function(:add_facts) do
|
7
7
|
# @param target A target.
|
8
|
-
# @param facts A hash of fact names to values that
|
8
|
+
# @param facts A hash of fact names to values that may include structured facts.
|
9
9
|
# @return The target's new facts.
|
10
10
|
# @example Adding facts to a target
|
11
11
|
# add_facts($target, { 'os' => { 'family' => 'windows', 'name' => 'windows' } })
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'bolt/error'
|
4
4
|
|
5
|
-
# Raises a Bolt::PlanFailure exception to signal to callers that the plan failed
|
5
|
+
# Raises a Bolt::PlanFailure exception to signal to callers that the plan failed.
|
6
6
|
#
|
7
7
|
# Plan authors should call this function when their plan is not successful. The
|
8
8
|
# error may then be caught by another plans run_plan function or in bolt itself
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'bolt/error'
|
4
4
|
|
5
|
-
# Runs the `plan` referenced by its name. A plan is autoloaded from
|
5
|
+
# Runs the `plan` referenced by its name. A plan is autoloaded from `<moduleroot>/plans`.
|
6
6
|
Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction) do
|
7
7
|
# @param plan_name The plan to run.
|
8
8
|
# @param named_args Arguments to the plan. Can also include additional options: '_catch_errors', '_run_as'.
|
@@ -2,8 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'bolt/error'
|
4
4
|
|
5
|
-
# Sets a particular feature to present on a target.
|
6
|
-
#
|
5
|
+
# Sets a particular feature to present on a target.
|
6
|
+
#
|
7
|
+
# Features are used to determine what implementation of a task should be run.
|
8
|
+
# Currently supported features are
|
7
9
|
# - powershell
|
8
10
|
# - shell
|
9
11
|
# - puppet-agent
|
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'bolt/error'
|
4
4
|
|
5
|
-
# Returns a hash of the 'vars' (variables) assigned to a target
|
6
|
-
# inventory file or `set_var` function.
|
5
|
+
# Returns a hash of the 'vars' (variables) assigned to a target.
|
7
6
|
#
|
7
|
+
# Vars can be assigned through the inventory file or `set_var` function.
|
8
8
|
# Plan authors can call this function on a target to get the variable hash
|
9
9
|
# for that target.
|
10
10
|
Puppet::Functions.create_function(:vars) do
|
@@ -1,8 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Define a block where default logging is suppressed.
|
4
|
-
#
|
5
|
-
# will
|
3
|
+
# Define a block where default logging is suppressed.
|
4
|
+
#
|
5
|
+
# Messages for actions within this block will be logged at `info` level instead
|
6
|
+
# of `notice`, so they will not be seen normally but # will still be present
|
7
|
+
# when `verbose` logging is requested.
|
6
8
|
Puppet::Functions.create_function(:without_default_logging) do
|
7
9
|
# @param block The block where action logging is suppressed.
|
8
10
|
# @return [Undef]
|
data/exe/bolt_catalog
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bolt'
|
5
|
+
require 'bolt/catalog'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
# This accepts a catalog request on stdin:
|
9
|
+
# { "code_ast": "JSON serialized Puppet AST",
|
10
|
+
# "code_string": "String of code, ignored if AST is provided,
|
11
|
+
# "modulepath": "Array of directories to use as the modulepath for catalog compilation.
|
12
|
+
# "target": {
|
13
|
+
# "name": "the name of the node usually fqdn fro url",
|
14
|
+
# "facts": "Hash of facts to use for the node",
|
15
|
+
# "variables": "Hash of variables to use for compilation"
|
16
|
+
# }
|
17
|
+
# }
|
18
|
+
|
19
|
+
command = ARGV[0]
|
20
|
+
if command == "parse"
|
21
|
+
code = File.open(ARGV[1], &:read)
|
22
|
+
puts JSON.pretty_generate(Bolt::Catalog.new.generate_ast(code))
|
23
|
+
elsif command == "compile"
|
24
|
+
request = if ARGV[1]
|
25
|
+
File.open(ARGV[1]) { |fh| JSON.parse(fh.read) }
|
26
|
+
else
|
27
|
+
JSON.parse(STDIN.read)
|
28
|
+
end
|
29
|
+
catalog = Bolt::Catalog.new.compile_catalog(request)
|
30
|
+
puts JSON.pretty_generate(catalog)
|
31
|
+
else
|
32
|
+
puts "USAGE: run 'bolt_catalog compile' with a request on STDIN " \
|
33
|
+
"or 'bolt_catalog parse manifest.pp' to generate JSON AST"
|
34
|
+
end
|
@@ -234,6 +234,9 @@ Available options are:
|
|
234
234
|
define('--debug', 'Display debug logging') do |_|
|
235
235
|
@options[:debug] = true
|
236
236
|
end
|
237
|
+
define('--trace', 'Display error stack traces') do |_|
|
238
|
+
@options[:trace] = true
|
239
|
+
end
|
237
240
|
define('--version', 'Display the version') do |_|
|
238
241
|
puts Bolt::VERSION
|
239
242
|
raise Bolt::CLIExit
|
data/lib/bolt/catalog.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/pal'
|
4
|
+
|
5
|
+
Bolt::PAL.load_puppet
|
6
|
+
|
7
|
+
# This class exists to override evaluate_main and let us inject
|
8
|
+
# AST instead of looking for the main manifest. A better option may be to set up the
|
9
|
+
# node environment so our AST is in the '' hostclass instead of doing it here.
|
10
|
+
module Puppet
|
11
|
+
module Parser
|
12
|
+
class BoltCompiler < Puppet::Parser::Compiler
|
13
|
+
def internal_evaluator
|
14
|
+
@internal_evaluator ||= Puppet::Pops::Parser::EvaluatingParser.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def dump_ast(ast)
|
18
|
+
Puppet::Pops::Serialization::ToDataConverter.convert(ast, rich_data: true, symbol_to_string: true)
|
19
|
+
end
|
20
|
+
|
21
|
+
def load_ast(ast_data)
|
22
|
+
Puppet::Pops::Serialization::FromDataConverter.convert(ast_data)
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse_string(string, file = '')
|
26
|
+
internal_evaluator.parse_string(string, file)
|
27
|
+
end
|
28
|
+
|
29
|
+
def evaluate_main
|
30
|
+
main = Puppet.lookup(:pal_main)
|
31
|
+
ast = if main.is_a?(String)
|
32
|
+
parse_string(main)
|
33
|
+
else
|
34
|
+
load_ast(main)
|
35
|
+
end
|
36
|
+
|
37
|
+
bridge = Puppet::Parser::AST::PopsBridge::Program.new(ast)
|
38
|
+
|
39
|
+
# This is more or less copypaste from the super but we don't use the
|
40
|
+
# original host_class.
|
41
|
+
krt = environment.known_resource_types
|
42
|
+
@main = krt.add(Puppet::Resource::Type.new(:hostclass, '', code: bridge))
|
43
|
+
@topscope.source = @main
|
44
|
+
@main_resource = Puppet::Parser::Resource.new('class', :main, scope: @topscope, source: @main)
|
45
|
+
@topscope.resource = @main_resource
|
46
|
+
add_resource(@topscope, @main_resource)
|
47
|
+
|
48
|
+
@main_resource.evaluate
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
module Bolt
|
55
|
+
class Catalog
|
56
|
+
def in_env
|
57
|
+
Puppet::Pal.in_tmp_environment('bolt_apply', modulepath: ['~/bolt/modules/'], facts: @scope['facts']) do |pal|
|
58
|
+
yield pal
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def with_puppet_settings
|
63
|
+
Dir.mktmpdir('bolt') do |dir|
|
64
|
+
cli = []
|
65
|
+
Puppet::Settings::REQUIRED_APP_SETTINGS.each do |setting|
|
66
|
+
cli << "--#{setting}" << dir
|
67
|
+
end
|
68
|
+
Puppet.settings.send(:clear_everything_for_tests)
|
69
|
+
Puppet.initialize_settings(cli)
|
70
|
+
# self.class.configure_logging
|
71
|
+
yield
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def setup_node(node)
|
76
|
+
facts = Puppet.lookup(:pal_facts)
|
77
|
+
node_facts = Puppet::Node::Facts.new(Puppet[:node_name_value], facts)
|
78
|
+
node.fact_merge(node_facts)
|
79
|
+
|
80
|
+
node.parameters = node.parameters.merge(Puppet.lookup(:pal_variables))
|
81
|
+
# TODO: setup server_facts
|
82
|
+
# TODO: setup trusted in params
|
83
|
+
# TODO: setup serverversion/clientversion in params
|
84
|
+
end
|
85
|
+
|
86
|
+
def compile_node(node)
|
87
|
+
compiler = Puppet::Parser::BoltCompiler.new(node)
|
88
|
+
compiler.compile(&:to_resource)
|
89
|
+
end
|
90
|
+
|
91
|
+
def generate_ast(code)
|
92
|
+
with_puppet_settings do
|
93
|
+
Puppet::Pal.in_tmp_environment("bolt_parse") do |_pal|
|
94
|
+
node = Puppet.lookup(:pal_current_node)
|
95
|
+
compiler = Puppet::Parser::BoltCompiler.new(node)
|
96
|
+
compiler.dump_ast(compiler.parse_string(code))
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def compile_catalog(request)
|
102
|
+
pal_main = request['code_ast'] || request['code_string']
|
103
|
+
target = request['target']
|
104
|
+
with_puppet_settings do
|
105
|
+
Puppet[:code] = ''
|
106
|
+
Puppet[:node_name_value] = target['name']
|
107
|
+
Puppet::Pal.in_tmp_environment(
|
108
|
+
'bolt_catalog',
|
109
|
+
modulepath: request["modulepath"] || [],
|
110
|
+
facts: target["facts"] || {},
|
111
|
+
variables: target["variables"] || {}
|
112
|
+
) do |_pal|
|
113
|
+
node = Puppet.lookup(:pal_current_node)
|
114
|
+
setup_node(node)
|
115
|
+
|
116
|
+
Puppet.override(pal_main: pal_main) do
|
117
|
+
compile_node(node)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/lib/bolt/cli.rb
CHANGED
data/lib/bolt/config.rb
CHANGED
@@ -26,6 +26,7 @@ module Bolt
|
|
26
26
|
Config = Struct.new(
|
27
27
|
:concurrency,
|
28
28
|
:format,
|
29
|
+
:trace,
|
29
30
|
:inventoryfile,
|
30
31
|
:log,
|
31
32
|
:modulepath,
|
@@ -197,7 +198,7 @@ module Bolt
|
|
197
198
|
end
|
198
199
|
|
199
200
|
def update_from_cli(options)
|
200
|
-
%i[concurrency transport format modulepath inventoryfile color].each do |key|
|
201
|
+
%i[concurrency transport format trace modulepath inventoryfile color].each do |key|
|
201
202
|
self[key] = options[key] if options.key?(key)
|
202
203
|
end
|
203
204
|
|
data/lib/bolt/inventory.rb
CHANGED
@@ -138,7 +138,9 @@ module Bolt
|
|
138
138
|
|
139
139
|
unless data
|
140
140
|
data = {}
|
141
|
-
|
141
|
+
unless Bolt::Util.windows?
|
142
|
+
data['config'] = { 'transport' => 'local' } if target.name == 'localhost'
|
143
|
+
end
|
142
144
|
end
|
143
145
|
|
144
146
|
unless data['config']
|
@@ -150,6 +152,7 @@ module Bolt
|
|
150
152
|
# been instantiated
|
151
153
|
set_vars_from_hash(target.name, data['vars']) unless @target_vars[target.name]
|
152
154
|
set_facts(target.name, data['facts']) unless @target_facts[target.name]
|
155
|
+
data['features']&.each { |feature| set_feature(target, feature) } unless @target_features[target.name]
|
153
156
|
|
154
157
|
# Use Config object to ensure config section is treated consistently with config file
|
155
158
|
conf = @config.deep_clone
|
data/lib/bolt/inventory/group.rb
CHANGED
@@ -23,6 +23,7 @@ module Bolt
|
|
23
23
|
|
24
24
|
@vars = data['vars'] || {}
|
25
25
|
@facts = data['facts'] || {}
|
26
|
+
@features = data['features'] || []
|
26
27
|
@config = data['config'] || {}
|
27
28
|
@groups = if data['groups']
|
28
29
|
data['groups'].map { |g| Group.new(g) }
|
@@ -89,7 +90,7 @@ module Bolt
|
|
89
90
|
end
|
90
91
|
|
91
92
|
# The data functions below expect and return nil or a hash of the schema
|
92
|
-
# { 'config' => Hash , 'vars' => Hash, 'facts' => Hash, groups => Array }
|
93
|
+
# { 'config' => Hash , 'vars' => Hash, 'facts' => Hash, 'features' => Array, groups => Array }
|
93
94
|
def data_for(node_name)
|
94
95
|
data_merge(group_collect(node_name), node_collect(node_name))
|
95
96
|
end
|
@@ -99,23 +100,26 @@ module Bolt
|
|
99
100
|
{ 'config' => data['config'] || {},
|
100
101
|
'vars' => data['vars'] || {},
|
101
102
|
'facts' => data['facts'] || {},
|
103
|
+
'features' => data['features'] || [],
|
102
104
|
# groups come from group_data
|
103
105
|
'groups' => [] }
|
104
106
|
end
|
105
107
|
end
|
106
108
|
|
107
109
|
def group_data
|
108
|
-
{ 'config'
|
109
|
-
'vars'
|
110
|
-
'facts'
|
111
|
-
'
|
110
|
+
{ 'config' => @config,
|
111
|
+
'vars' => @vars,
|
112
|
+
'facts' => @facts,
|
113
|
+
'features' => @features,
|
114
|
+
'groups' => [@name] }
|
112
115
|
end
|
113
116
|
|
114
117
|
def empty_data
|
115
|
-
{ 'config'
|
116
|
-
'vars'
|
117
|
-
'facts'
|
118
|
-
'
|
118
|
+
{ 'config' => {},
|
119
|
+
'vars' => {},
|
120
|
+
'facts' => {},
|
121
|
+
'features' => [],
|
122
|
+
'groups' => [] }
|
119
123
|
end
|
120
124
|
|
121
125
|
def data_merge(data1, data2)
|
@@ -130,6 +134,7 @@ module Bolt
|
|
130
134
|
# with the value meant to replace it
|
131
135
|
'vars' => data1['vars'].merge(data2['vars']),
|
132
136
|
'facts' => Bolt::Util.deep_merge(data1['facts'], data2['facts']),
|
137
|
+
'features' => data1['features'] | data2['features'],
|
133
138
|
'groups' => data2['groups'] + data1['groups']
|
134
139
|
}
|
135
140
|
end
|
data/lib/bolt/outputter.rb
CHANGED
@@ -2,19 +2,20 @@
|
|
2
2
|
|
3
3
|
module Bolt
|
4
4
|
class Outputter
|
5
|
-
def self.for_format(format, color)
|
5
|
+
def self.for_format(format, color, trace)
|
6
6
|
case format
|
7
7
|
when 'human'
|
8
|
-
Bolt::Outputter::Human.new(color)
|
8
|
+
Bolt::Outputter::Human.new(color, trace)
|
9
9
|
when 'json'
|
10
|
-
Bolt::Outputter::JSON.new(color)
|
10
|
+
Bolt::Outputter::JSON.new(color, trace)
|
11
11
|
when nil
|
12
12
|
raise "Cannot use outputter before parsing."
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
def initialize(color, stream = $stdout)
|
16
|
+
def initialize(color, trace, stream = $stdout)
|
17
17
|
@color = color
|
18
|
+
@trace = trace
|
18
19
|
@stream = stream
|
19
20
|
end
|
20
21
|
|
data/lib/bolt/outputter/human.rb
CHANGED
@@ -175,6 +175,12 @@ module Bolt
|
|
175
175
|
if err.is_a? Bolt::RunFailure
|
176
176
|
@stream.puts ::JSON.pretty_generate(err.result_set)
|
177
177
|
end
|
178
|
+
|
179
|
+
if @trace && err.backtrace
|
180
|
+
err.backtrace.each do |line|
|
181
|
+
@stream.puts(colorize(:red, "\t#{line}"))
|
182
|
+
end
|
183
|
+
end
|
178
184
|
end
|
179
185
|
end
|
180
186
|
|
data/lib/bolt/outputter/json.rb
CHANGED
@@ -3,11 +3,11 @@
|
|
3
3
|
module Bolt
|
4
4
|
class Outputter
|
5
5
|
class JSON < Bolt::Outputter
|
6
|
-
def initialize(color, stream = $stdout)
|
6
|
+
def initialize(color, trace, stream = $stdout)
|
7
7
|
@items_open = false
|
8
8
|
@object_open = false
|
9
9
|
@preceding_item = false
|
10
|
-
super(color, stream)
|
10
|
+
super(color, trace, stream)
|
11
11
|
end
|
12
12
|
|
13
13
|
def print_head
|
@@ -60,7 +60,12 @@ module Bolt
|
|
60
60
|
def fatal_error(err)
|
61
61
|
@stream.puts "],\n" if @items_open
|
62
62
|
@stream.puts '"_error": ' if @object_open
|
63
|
-
|
63
|
+
err_obj = err.to_h
|
64
|
+
if @trace && err.backtrace
|
65
|
+
err_obj[:details] ||= {}
|
66
|
+
err_obj[:details][:backtrace] = err.backtrace
|
67
|
+
end
|
68
|
+
@stream.puts err_obj.to_json
|
64
69
|
@stream.puts '}' if @object_open
|
65
70
|
end
|
66
71
|
|
data/lib/bolt/version.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: 0.21.
|
4
|
+
version: 0.21.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-06-
|
11
|
+
date: 2018-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -324,6 +324,7 @@ email:
|
|
324
324
|
executables:
|
325
325
|
- bolt
|
326
326
|
- bolt-inventory-pdb
|
327
|
+
- bolt_catalog
|
327
328
|
extensions: []
|
328
329
|
extra_rdoc_files: []
|
329
330
|
files:
|
@@ -349,9 +350,11 @@ files:
|
|
349
350
|
- bolt-modules/boltlib/types/targetspec.pp
|
350
351
|
- exe/bolt
|
351
352
|
- exe/bolt-inventory-pdb
|
353
|
+
- exe/bolt_catalog
|
352
354
|
- lib/bolt.rb
|
353
355
|
- lib/bolt/analytics.rb
|
354
356
|
- lib/bolt/bolt_option_parser.rb
|
357
|
+
- lib/bolt/catalog.rb
|
355
358
|
- lib/bolt/cli.rb
|
356
359
|
- lib/bolt/config.rb
|
357
360
|
- lib/bolt/error.rb
|