bolt 2.29.0 → 2.33.2
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/Puppetfile +15 -14
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +6 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +2 -2
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +2 -2
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +44 -1
- data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +3 -0
- data/guides/logging.txt +18 -0
- data/guides/module.txt +19 -0
- data/guides/modulepath.txt +25 -0
- data/lib/bolt/bolt_option_parser.rb +48 -9
- data/lib/bolt/catalog.rb +1 -1
- data/lib/bolt/cli.rb +154 -116
- data/lib/bolt/config.rb +13 -1
- data/lib/bolt/config/modulepath.rb +30 -0
- data/lib/bolt/config/options.rb +32 -13
- data/lib/bolt/config/transport/options.rb +2 -2
- data/lib/bolt/error.rb +4 -0
- data/lib/bolt/executor.rb +13 -13
- data/lib/bolt/inventory.rb +10 -9
- data/lib/bolt/module_installer.rb +198 -0
- data/lib/bolt/{puppetfile → module_installer}/installer.rb +3 -2
- data/lib/bolt/module_installer/puppetfile.rb +117 -0
- data/lib/bolt/module_installer/puppetfile/forge_module.rb +54 -0
- data/lib/bolt/module_installer/puppetfile/git_module.rb +37 -0
- data/lib/bolt/module_installer/puppetfile/module.rb +26 -0
- data/lib/bolt/module_installer/resolver.rb +76 -0
- data/lib/bolt/module_installer/specs.rb +93 -0
- data/lib/bolt/module_installer/specs/forge_spec.rb +85 -0
- data/lib/bolt/module_installer/specs/git_spec.rb +179 -0
- data/lib/bolt/outputter.rb +2 -45
- data/lib/bolt/outputter/human.rb +78 -18
- data/lib/bolt/outputter/json.rb +22 -7
- data/lib/bolt/outputter/logger.rb +2 -2
- data/lib/bolt/pal.rb +55 -45
- data/lib/bolt/pal/yaml_plan.rb +4 -2
- data/lib/bolt/pal/yaml_plan/evaluator.rb +23 -1
- data/lib/bolt/pal/yaml_plan/loader.rb +14 -9
- data/lib/bolt/plugin.rb +1 -1
- data/lib/bolt/plugin/module.rb +1 -1
- data/lib/bolt/project.rb +32 -21
- data/lib/bolt/project_migrator.rb +80 -0
- data/lib/bolt/project_migrator/base.rb +39 -0
- data/lib/bolt/project_migrator/config.rb +67 -0
- data/lib/bolt/project_migrator/inventory.rb +67 -0
- data/lib/bolt/project_migrator/modules.rb +200 -0
- data/lib/bolt/result.rb +23 -11
- data/lib/bolt/shell/bash.rb +15 -9
- data/lib/bolt/shell/powershell.rb +11 -6
- data/lib/bolt/transport/base.rb +18 -18
- data/lib/bolt/transport/docker.rb +23 -6
- data/lib/bolt/transport/orch.rb +23 -14
- data/lib/bolt/transport/remote.rb +2 -2
- data/lib/bolt/transport/simple.rb +6 -6
- data/lib/bolt/transport/ssh/connection.rb +1 -1
- data/lib/bolt/util.rb +22 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/acl.rb +2 -2
- data/lib/bolt_server/base_config.rb +3 -3
- data/lib/bolt_server/schemas/partials/task.json +17 -2
- data/lib/bolt_server/transport_app.rb +92 -12
- data/lib/bolt_spec/bolt_context.rb +4 -2
- data/lib/bolt_spec/plans.rb +1 -1
- data/lib/bolt_spec/plans/action_stubs/command_stub.rb +1 -1
- data/lib/bolt_spec/plans/action_stubs/script_stub.rb +1 -1
- data/lib/bolt_spec/plans/mock_executor.rb +6 -6
- data/lib/bolt_spec/run.rb +1 -1
- metadata +29 -10
- data/lib/bolt/project_migrate.rb +0 -138
- data/lib/bolt/puppetfile.rb +0 -160
- data/lib/bolt/puppetfile/module.rb +0 -89
- data/lib/bolt_server/pe/pal.rb +0 -67
- data/modules/secure_env_vars/plans/init.pp +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 956382104b8c11e17fdafa4349b50ec3d7c5ce6b03eaa57ce429bbfad768f8d3
|
4
|
+
data.tar.gz: dd838e10c07c8f0f87266ff5edf3af4f5595fab45e6aab0ebf82e381226d3897
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c2b97a1c268d0fd93f1086efe623c740b74d9d1318596b9a74720e0e944455e244bfc2be2d02ba18634ed543a6ad87f6f27b88dc19189b22cd8fa495b75de02
|
7
|
+
data.tar.gz: cff4bdac98aad6247866f989f9f3814dd11497fd73d90b08ecf15824ef0ee2b36c73fffeb296ecb8a6cae19eb2e71ec7b834dfe461fdbadd06d46b05b560a758
|
data/Puppetfile
CHANGED
@@ -6,35 +6,37 @@ moduledir File.join(File.dirname(__FILE__), 'modules')
|
|
6
6
|
|
7
7
|
# Core modules used by 'apply'
|
8
8
|
mod 'puppetlabs-service', '1.3.0'
|
9
|
-
mod 'puppetlabs-puppet_agent', '4.
|
10
|
-
mod 'puppetlabs-facts', '1.
|
9
|
+
mod 'puppetlabs-puppet_agent', '4.2.0'
|
10
|
+
mod 'puppetlabs-facts', '1.2.0'
|
11
11
|
|
12
12
|
# Core types and providers for Puppet 6
|
13
|
-
mod 'puppetlabs-augeas_core', '1.
|
13
|
+
mod 'puppetlabs-augeas_core', '1.1.1'
|
14
14
|
mod 'puppetlabs-host_core', '1.0.3'
|
15
|
-
mod 'puppetlabs-scheduled_task', '2.
|
16
|
-
mod 'puppetlabs-sshkeys_core', '
|
17
|
-
mod 'puppetlabs-zfs_core', '1.0
|
18
|
-
mod 'puppetlabs-cron_core', '1.0.
|
15
|
+
mod 'puppetlabs-scheduled_task', '2.2.1'
|
16
|
+
mod 'puppetlabs-sshkeys_core', '2.2.0'
|
17
|
+
mod 'puppetlabs-zfs_core', '1.2.0'
|
18
|
+
mod 'puppetlabs-cron_core', '1.0.5'
|
19
19
|
mod 'puppetlabs-mount_core', '1.0.4'
|
20
20
|
mod 'puppetlabs-selinux_core', '1.0.4'
|
21
|
-
mod 'puppetlabs-yumrepo_core', '1.0.
|
21
|
+
mod 'puppetlabs-yumrepo_core', '1.0.7'
|
22
22
|
mod 'puppetlabs-zone_core', '1.0.3'
|
23
23
|
|
24
24
|
# Useful additional modules
|
25
|
-
mod 'puppetlabs-package', '1.
|
25
|
+
mod 'puppetlabs-package', '1.3.0'
|
26
26
|
mod 'puppetlabs-puppet_conf', '0.6.0'
|
27
27
|
mod 'puppetlabs-python_task_helper', '0.4.3'
|
28
28
|
mod 'puppetlabs-reboot', '3.0.0'
|
29
29
|
mod 'puppetlabs-ruby_task_helper', '0.5.1'
|
30
30
|
mod 'puppetlabs-ruby_plugin_helper', '0.1.0'
|
31
|
-
mod 'puppetlabs-stdlib', '6.
|
31
|
+
mod 'puppetlabs-stdlib', '6.5.0'
|
32
32
|
|
33
33
|
# Plugin modules
|
34
|
-
mod 'puppetlabs-aws_inventory', '0.5.
|
35
|
-
mod 'puppetlabs-azure_inventory', '0.
|
36
|
-
mod 'puppetlabs-gcloud_inventory', '0.1.
|
34
|
+
mod 'puppetlabs-aws_inventory', '0.5.2'
|
35
|
+
mod 'puppetlabs-azure_inventory', '0.4.1'
|
36
|
+
mod 'puppetlabs-gcloud_inventory', '0.1.3'
|
37
|
+
mod 'puppetlabs-http_request', '0.2.0'
|
37
38
|
mod 'puppetlabs-pkcs7', '0.1.1'
|
39
|
+
mod 'puppetlabs-secure_env_vars', '0.1.0'
|
38
40
|
mod 'puppetlabs-terraform', '0.5.0'
|
39
41
|
mod 'puppetlabs-vault', '0.3.0'
|
40
42
|
mod 'puppetlabs-yaml', '0.2.0'
|
@@ -43,4 +45,3 @@ mod 'puppetlabs-yaml', '0.2.0'
|
|
43
45
|
mod 'canary', local: true
|
44
46
|
mod 'aggregate', local: true
|
45
47
|
mod 'puppetdb_fact', local: true
|
46
|
-
mod 'secure_env_vars', local: true
|
@@ -112,7 +112,7 @@ Puppet::Functions.create_function(:download_file, Puppet::Functions::InternalFun
|
|
112
112
|
call_function('debug', "Simulating file download of '#{source}' - no targets given - no action taken")
|
113
113
|
r = Bolt::ResultSet.new([])
|
114
114
|
else
|
115
|
-
r = executor.download_file(targets, source, destination, options)
|
115
|
+
r = executor.download_file(targets, source, destination, options, Puppet::Pops::PuppetStack.top_of_stack)
|
116
116
|
end
|
117
117
|
|
118
118
|
if !r.ok && !options[:catch_errors]
|
@@ -3,6 +3,12 @@
|
|
3
3
|
require 'bolt/error'
|
4
4
|
|
5
5
|
# Returns the facts hash for a target.
|
6
|
+
#
|
7
|
+
# Using the `facts` function does not automatically collect facts for a target,
|
8
|
+
# and will only return facts that are currently set in the inventory. To collect
|
9
|
+
# facts from a target and set them in the inventory, run the
|
10
|
+
# [facts](writing_plans.md#collect-facts-from-targets) plan or
|
11
|
+
# [puppetdb_fact](writing_plans.md#collect-facts-from-puppetdb) plan.
|
6
12
|
Puppet::Functions.create_function(:facts) do
|
7
13
|
# @param target A target.
|
8
14
|
# @return The target's facts.
|
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
require 'bolt/error'
|
4
4
|
|
5
|
-
# Makes a query to
|
5
|
+
# Makes a query to [puppetdb](https://puppet.com/docs/puppetdb/latest/index.html)
|
6
6
|
# using Bolt's PuppetDB client.
|
7
7
|
Puppet::Functions.create_function(:puppetdb_query) do
|
8
8
|
# rubocop:disable Layout/LineLength
|
9
9
|
# @param query A PQL query.
|
10
|
-
#
|
10
|
+
# Learn more about [Puppet's query language](https://puppet.com/docs/puppetdb/latest/api/query/tutorial-pql.html), PQL.
|
11
11
|
# @return Results of the PuppetDB query.
|
12
12
|
# @example Request certnames for all nodes
|
13
13
|
# puppetdb_query('nodes[certname] {}')
|
@@ -69,7 +69,7 @@ Puppet::Functions.create_function(:run_command) do
|
|
69
69
|
call_function('debug', "Simulating run_command('#{command}') - no targets given - no action taken")
|
70
70
|
r = Bolt::ResultSet.new([])
|
71
71
|
else
|
72
|
-
r = executor.run_command(targets, command, options)
|
72
|
+
r = executor.run_command(targets, command, options, Puppet::Pops::PuppetStack.top_of_stack)
|
73
73
|
end
|
74
74
|
|
75
75
|
if !r.ok && !options[:catch_errors]
|
@@ -87,7 +87,7 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti
|
|
87
87
|
r = if targets.empty?
|
88
88
|
Bolt::ResultSet.new([])
|
89
89
|
else
|
90
|
-
executor.run_script(targets, found, arguments, options)
|
90
|
+
executor.run_script(targets, found, arguments, options, Puppet::Pops::PuppetStack.top_of_stack)
|
91
91
|
end
|
92
92
|
|
93
93
|
if !r.ok && !options[:catch_errors]
|
@@ -133,7 +133,7 @@ Puppet::Functions.create_function(:run_task) do
|
|
133
133
|
if targets.empty?
|
134
134
|
Bolt::ResultSet.new([])
|
135
135
|
else
|
136
|
-
result = executor.run_task(targets, task, params, options)
|
136
|
+
result = executor.run_task(targets, task, params, options, Puppet::Pops::PuppetStack.top_of_stack)
|
137
137
|
if !result.ok && !options[:catch_errors]
|
138
138
|
raise Bolt::RunFailure.new(result, 'run_task', task_name)
|
139
139
|
end
|
@@ -180,7 +180,7 @@ Puppet::Functions.create_function(:run_task_with) do
|
|
180
180
|
else
|
181
181
|
# Combine the results from the task run with any failing results that were
|
182
182
|
# generated earlier when creating the target mapping
|
183
|
-
task_result = executor.run_task_with(target_mapping, task, options)
|
183
|
+
task_result = executor.run_task_with(target_mapping, task, options, Puppet::Pops::PuppetStack.top_of_stack)
|
184
184
|
result = Bolt::ResultSet.new(task_result.results + error_set)
|
185
185
|
|
186
186
|
if !result.ok && !options[:catch_errors]
|
@@ -83,7 +83,7 @@ Puppet::Functions.create_function(:upload_file, Puppet::Functions::InternalFunct
|
|
83
83
|
call_function('debug', "Simulating file upload of '#{found}' - no targets given - no action taken")
|
84
84
|
r = Bolt::ResultSet.new([])
|
85
85
|
else
|
86
|
-
r = executor.upload_file(targets, found, destination, options)
|
86
|
+
r = executor.upload_file(targets, found, destination, options, Puppet::Pops::PuppetStack.top_of_stack)
|
87
87
|
end
|
88
88
|
|
89
89
|
if !r.ok && !options[:catch_errors]
|
@@ -6,15 +6,15 @@ require 'tempfile'
|
|
6
6
|
#
|
7
7
|
# > **Note:** Not available in apply block
|
8
8
|
Puppet::Functions.create_function(:write_file) do
|
9
|
-
# @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
|
10
9
|
# @param content File content to write.
|
11
10
|
# @param destination An absolute path on the target(s).
|
11
|
+
# @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
|
12
12
|
# @option options [Boolean] _catch_errors Whether to catch raised errors.
|
13
13
|
# @option options [String] _run_as User to run as using privilege escalation.
|
14
14
|
# @return A list of results, one entry per target.
|
15
15
|
# @example Write a file to a target
|
16
16
|
# $content = 'Hello, world!'
|
17
|
-
# write_file($
|
17
|
+
# write_file($content, '/Users/me/hello.txt', $targets)
|
18
18
|
dispatch :write_file do
|
19
19
|
required_param 'String', :content
|
20
20
|
required_param 'String[1]', :destination
|
@@ -26,8 +26,51 @@ Puppet::Functions.create_function(:'out::message') do
|
|
26
26
|
# Send Analytics Report
|
27
27
|
executor.report_function_call(self.class.name)
|
28
28
|
|
29
|
-
executor.publish_event(type: :message, message: message)
|
29
|
+
executor.publish_event(type: :message, message: stringify(message))
|
30
30
|
|
31
31
|
nil
|
32
32
|
end
|
33
|
+
|
34
|
+
def stringify(message)
|
35
|
+
formatted = format_message(message)
|
36
|
+
if formatted.is_a?(Hash) || formatted.is_a?(Array)
|
37
|
+
::JSON.pretty_generate(formatted)
|
38
|
+
else
|
39
|
+
formatted
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def format_message(message)
|
44
|
+
case message
|
45
|
+
when Array
|
46
|
+
message.map { |item| format_message(item) }
|
47
|
+
when Bolt::ApplyResult
|
48
|
+
format_apply_result(message)
|
49
|
+
when Bolt::Result, Bolt::ResultSet
|
50
|
+
# This is equivalent to to_s, but formattable
|
51
|
+
message.to_data
|
52
|
+
when Bolt::RunFailure
|
53
|
+
formatted_resultset = message.result_set.to_data
|
54
|
+
message.to_h.merge('result_set' => formatted_resultset)
|
55
|
+
when Hash
|
56
|
+
message.each_with_object({}) do |(k, v), h|
|
57
|
+
h[format_message(k)] = format_message(v)
|
58
|
+
end
|
59
|
+
when Integer, Float, NilClass
|
60
|
+
message
|
61
|
+
else
|
62
|
+
message.to_s
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def format_apply_result(result)
|
67
|
+
logs = result.resource_logs&.map do |log|
|
68
|
+
# Omit low-level info/debug messages
|
69
|
+
next if %w[info debug].include?(log['level'])
|
70
|
+
indent(2, format_log(log))
|
71
|
+
end
|
72
|
+
hash = result.to_data
|
73
|
+
hash['logs'] = logs unless logs.empty?
|
74
|
+
hash
|
75
|
+
end
|
33
76
|
end
|
@@ -9,11 +9,14 @@ Puppet::Functions.create_function(:prompt) do
|
|
9
9
|
# @param prompt The prompt to display.
|
10
10
|
# @param options A hash of additional options.
|
11
11
|
# @option options [Boolean] sensitive Disable echo back and mark the response as sensitive.
|
12
|
+
# The returned value will be wrapped by the `Sensitive` data type. To access the raw
|
13
|
+
# value, use the `unwrap` function (i.e. `$sensitive_value.unwrap`).
|
12
14
|
# @return The response to the prompt.
|
13
15
|
# @example Prompt the user if plan execution should continue
|
14
16
|
# $response = prompt('Continue executing plan? [Y\N]')
|
15
17
|
# @example Prompt the user for sensitive information
|
16
18
|
# $password = prompt('Enter your password', 'sensitive' => true)
|
19
|
+
# out::message("Password is: ${password.unwrap}")
|
17
20
|
dispatch :prompt do
|
18
21
|
param 'String', :prompt
|
19
22
|
optional_param 'Hash[String[1], Any]', :options
|
data/guides/logging.txt
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
TOPIC
|
2
|
+
logging
|
3
|
+
|
4
|
+
DESCRIPTION
|
5
|
+
Bolt prints messages both to the console and to log files. Messages can
|
6
|
+
either come from Bolt's 'outputter', which logs user-facing messages like
|
7
|
+
progress and results, or from the 'logger', which logs warnings, errors, and
|
8
|
+
log-structured output to log files. Both of these message streams are
|
9
|
+
configurable.
|
10
|
+
|
11
|
+
By default, Bolt logs to the console at 'warn' level and writes a log file to
|
12
|
+
'<project>/bolt-debug.log' at 'debug' level. Unless you are running a plan,
|
13
|
+
Bolt runs in verbose mode by default.
|
14
|
+
|
15
|
+
To learn more about projects, see the 'project' guide.
|
16
|
+
|
17
|
+
DOCUMENTATION
|
18
|
+
https://pup.pt/bolt-logging
|
data/guides/module.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
TOPIC
|
2
|
+
module
|
3
|
+
|
4
|
+
DESCRIPTION
|
5
|
+
Modules are shareable, reusable packages of Puppet content. They can include
|
6
|
+
tasks, plans, functions, and other types of content that you can use in your
|
7
|
+
project. You can download and install modules to your project from the
|
8
|
+
Puppet Forge or write your own modules. Bolt also ships with several helpful
|
9
|
+
modules pre-installed that are available to all of your projects.
|
10
|
+
|
11
|
+
Bolt makes it easy to manage the modules that your project depends on. You
|
12
|
+
can use Bolt commands to install a project's modules, add new modules to a
|
13
|
+
project, and view the modules that are available to the project.
|
14
|
+
|
15
|
+
To learn more about managing modules in a project, see the documentation.
|
16
|
+
To learn how modules are loaded by Bolt, see the 'modulepath' guide.
|
17
|
+
|
18
|
+
DOCUMENTATION
|
19
|
+
https://pup.pt/bolt-modules
|
@@ -0,0 +1,25 @@
|
|
1
|
+
TOPIC
|
2
|
+
modulepath
|
3
|
+
|
4
|
+
DESCRIPTION
|
5
|
+
The modulepath is an ordered list of directories that Bolt loads modules
|
6
|
+
from. When Bolt runs a command, it automatically loads modules from the
|
7
|
+
modulepath.
|
8
|
+
|
9
|
+
While Bolt has a default modulepath, you can also configure your own
|
10
|
+
modulepath, which can include directories within the project or directories
|
11
|
+
elsewhere on your system. Regardless of whether your project uses a default
|
12
|
+
or configured modulepath, Bolt automatically adds directories to the
|
13
|
+
modulepath. This includes modules containing core Bolt content, which is
|
14
|
+
added to the beginning of the modulepath, and bundled content, which is
|
15
|
+
added to the end of the modulepath.
|
16
|
+
|
17
|
+
Modules loaded from a directory listed earlier in the modulepath take
|
18
|
+
precedence over modules with the same name loaded from a directory later in
|
19
|
+
the modulepath. Bolt will not warn or error when two modules share a name
|
20
|
+
and instead will ignore modules with a lower precedence.
|
21
|
+
|
22
|
+
To learn more about modules, see the 'module' guide.
|
23
|
+
|
24
|
+
DOCUMENTATION
|
25
|
+
https://pup.pt/bolt-project-reference#modulepath
|
@@ -66,15 +66,18 @@ module Bolt
|
|
66
66
|
banner: GUIDE_HELP }
|
67
67
|
when 'module'
|
68
68
|
case action
|
69
|
+
when 'add'
|
70
|
+
{ flags: OPTIONS[:global] + %w[configfile project],
|
71
|
+
banner: MODULE_ADD_HELP }
|
72
|
+
when 'generate-types'
|
73
|
+
{ flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
|
74
|
+
banner: MODULE_GENERATETYPES_HELP }
|
69
75
|
when 'install'
|
70
|
-
{ flags: OPTIONS[:global] + %w[configfile force project],
|
76
|
+
{ flags: OPTIONS[:global] + %w[configfile force project resolve],
|
71
77
|
banner: MODULE_INSTALL_HELP }
|
72
78
|
when 'show'
|
73
79
|
{ flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
|
74
80
|
banner: MODULE_SHOW_HELP }
|
75
|
-
when 'generate-types'
|
76
|
-
{ flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
|
77
|
-
banner: MODULE_GENERATETYPES_HELP }
|
78
81
|
else
|
79
82
|
{ flags: OPTIONS[:global],
|
80
83
|
banner: MODULE_HELP }
|
@@ -184,6 +187,7 @@ module Bolt
|
|
184
187
|
group Show the list of groups in the inventory
|
185
188
|
guide View guides for Bolt concepts and features
|
186
189
|
inventory Show the list of targets an action would run on
|
190
|
+
module Manage Bolt project modules
|
187
191
|
plan Convert, create, show, and run Bolt plans
|
188
192
|
project Create and migrate Bolt projects
|
189
193
|
puppetfile Install and list modules and generate type references
|
@@ -364,27 +368,34 @@ module Bolt
|
|
364
368
|
bolt module <action> [options]
|
365
369
|
|
366
370
|
DESCRIPTION
|
367
|
-
|
371
|
+
Manage Bolt project modules
|
372
|
+
|
373
|
+
The module command is only supported when a project is configured
|
374
|
+
with the 'modules' key.
|
368
375
|
|
369
376
|
ACTIONS
|
377
|
+
add Add a module to the project
|
370
378
|
generate-types Generate type references to register in plans
|
371
379
|
install Install the project's modules
|
372
380
|
show List modules available to the Bolt project
|
373
381
|
HELP
|
374
382
|
|
375
|
-
|
383
|
+
MODULE_ADD_HELP = <<~HELP
|
376
384
|
NAME
|
377
|
-
|
385
|
+
add
|
378
386
|
|
379
387
|
USAGE
|
380
|
-
bolt module
|
388
|
+
bolt module add <module> [options]
|
381
389
|
|
382
390
|
DESCRIPTION
|
383
|
-
|
391
|
+
Add a module to the project.
|
384
392
|
|
385
393
|
Module declarations are loaded from the project's configuration
|
386
394
|
file. Bolt will automatically resolve all module dependencies,
|
387
395
|
generate a Puppetfile, and install the modules.
|
396
|
+
|
397
|
+
The module command is only supported when a project is configured
|
398
|
+
with the 'modules' key.
|
388
399
|
HELP
|
389
400
|
|
390
401
|
MODULE_GENERATETYPES_HELP = <<~HELP
|
@@ -396,6 +407,24 @@ module Bolt
|
|
396
407
|
|
397
408
|
DESCRIPTION
|
398
409
|
Generate type references to register in plans.
|
410
|
+
|
411
|
+
The module command is only supported when a project is configured
|
412
|
+
with the 'modules' key.
|
413
|
+
HELP
|
414
|
+
|
415
|
+
MODULE_INSTALL_HELP = <<~HELP
|
416
|
+
NAME
|
417
|
+
install
|
418
|
+
|
419
|
+
USAGE
|
420
|
+
bolt module install [options]
|
421
|
+
|
422
|
+
DESCRIPTION
|
423
|
+
Install the project's modules.
|
424
|
+
|
425
|
+
Module declarations are loaded from the project's configuration
|
426
|
+
file. Bolt will automatically resolve all module dependencies,
|
427
|
+
generate a Puppetfile, and install the modules.
|
399
428
|
HELP
|
400
429
|
|
401
430
|
MODULE_SHOW_HELP = <<~HELP
|
@@ -407,6 +436,9 @@ module Bolt
|
|
407
436
|
|
408
437
|
DESCRIPTION
|
409
438
|
List modules available to the Bolt project.
|
439
|
+
|
440
|
+
The module command is only supported when a project is configured
|
441
|
+
with the 'modules' key.
|
410
442
|
HELP
|
411
443
|
|
412
444
|
PLAN_HELP = <<~HELP
|
@@ -906,6 +938,13 @@ module Bolt
|
|
906
938
|
@options[:tmpdir] = tmpdir
|
907
939
|
end
|
908
940
|
|
941
|
+
separator "\nMODULE OPTIONS"
|
942
|
+
define('--[no-]resolve',
|
943
|
+
'Use --no-resolve to install modules listed in the Puppetfile without resolving modules configured',
|
944
|
+
'in Bolt project configuration') do |resolve|
|
945
|
+
@options[:resolve] = resolve
|
946
|
+
end
|
947
|
+
|
909
948
|
separator "\nDISPLAY OPTIONS"
|
910
949
|
define('--filter FILTER', 'Filter tasks and plans by a matching substring') do |filter|
|
911
950
|
unless /^[a-z0-9_:]+$/.match(filter)
|
data/lib/bolt/catalog.rb
CHANGED
@@ -97,7 +97,7 @@ module Bolt
|
|
97
97
|
}
|
98
98
|
|
99
99
|
with_puppet_settings(puppet_settings) do
|
100
|
-
Puppet::Pal.in_tmp_environment('bolt_catalog', env_conf) do |pal|
|
100
|
+
Puppet::Pal.in_tmp_environment('bolt_catalog', **env_conf) do |pal|
|
101
101
|
Puppet.override(puppet_overrides) do
|
102
102
|
Puppet.lookup(:pal_current_node).trusted_data = target['trusted']
|
103
103
|
pal.with_catalog_compiler do |compiler|
|
data/lib/bolt/cli.rb
CHANGED
@@ -20,28 +20,31 @@ require 'bolt/logger'
|
|
20
20
|
require 'bolt/outputter'
|
21
21
|
require 'bolt/puppetdb'
|
22
22
|
require 'bolt/plugin'
|
23
|
-
require 'bolt/
|
23
|
+
require 'bolt/project_migrator'
|
24
24
|
require 'bolt/pal'
|
25
25
|
require 'bolt/target'
|
26
26
|
require 'bolt/version'
|
27
27
|
require 'bolt/secret'
|
28
|
+
require 'bolt/module_installer'
|
28
29
|
|
29
30
|
module Bolt
|
30
31
|
class CLIExit < StandardError; end
|
31
32
|
class CLI
|
32
|
-
COMMANDS = {
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
33
|
+
COMMANDS = {
|
34
|
+
'command' => %w[run],
|
35
|
+
'script' => %w[run],
|
36
|
+
'task' => %w[show run],
|
37
|
+
'plan' => %w[show run convert new],
|
38
|
+
'file' => %w[download upload],
|
39
|
+
'puppetfile' => %w[install show-modules generate-types],
|
40
|
+
'secret' => %w[encrypt decrypt createkeys],
|
41
|
+
'inventory' => %w[show],
|
42
|
+
'group' => %w[show],
|
43
|
+
'project' => %w[init migrate],
|
44
|
+
'module' => %w[add generate-types install show],
|
45
|
+
'apply' => %w[],
|
46
|
+
'guide' => %w[]
|
47
|
+
}.freeze
|
45
48
|
|
46
49
|
attr_reader :config, :options
|
47
50
|
|
@@ -99,6 +102,10 @@ module Bolt
|
|
99
102
|
# This part aims to handle both `bolt <mode> --help` and `bolt help <mode>`.
|
100
103
|
remaining = handle_parser_errors { parser.permute(@argv) } unless @argv.empty?
|
101
104
|
if @argv.empty? || help?(remaining)
|
105
|
+
# If the subcommand is not enabled, display the default
|
106
|
+
# help text
|
107
|
+
options[:subcommand] = nil unless COMMANDS.include?(options[:subcommand])
|
108
|
+
|
102
109
|
# Update the parser for the subcommand (or lack thereof)
|
103
110
|
parser.update
|
104
111
|
puts parser.help
|
@@ -189,6 +196,10 @@ module Bolt
|
|
189
196
|
|
190
197
|
warn_inventory_overrides_cli(options)
|
191
198
|
|
199
|
+
# Assert whether the puppetfile/module commands are available depending
|
200
|
+
# on whether 'modules' is configured.
|
201
|
+
assert_puppetfile_or_module_command(config.project.modules)
|
202
|
+
|
192
203
|
options
|
193
204
|
rescue Bolt::Error => e
|
194
205
|
outputter.fatal_error(e)
|
@@ -216,14 +227,10 @@ module Bolt
|
|
216
227
|
end
|
217
228
|
|
218
229
|
def validate(options)
|
219
|
-
|
220
|
-
commands = COMMANDS.dup
|
221
|
-
commands.delete('module') unless ENV['BOLT_MODULE_FEATURE']
|
222
|
-
|
223
|
-
unless commands.include?(options[:subcommand])
|
230
|
+
unless COMMANDS.include?(options[:subcommand])
|
224
231
|
raise Bolt::CLIError,
|
225
232
|
"Expected subcommand '#{options[:subcommand]}' to be one of " \
|
226
|
-
"#{
|
233
|
+
"#{COMMANDS.keys.join(', ')}"
|
227
234
|
end
|
228
235
|
|
229
236
|
actions = COMMANDS[options[:subcommand]]
|
@@ -240,12 +247,6 @@ module Bolt
|
|
240
247
|
end
|
241
248
|
end
|
242
249
|
|
243
|
-
if options[:subcommand] != 'file' && options[:subcommand] != 'script' &&
|
244
|
-
!options[:leftovers].empty?
|
245
|
-
raise Bolt::CLIError,
|
246
|
-
"Unknown argument(s) #{options[:leftovers].join(', ')}"
|
247
|
-
end
|
248
|
-
|
249
250
|
if %w[task plan].include?(options[:subcommand]) && options[:action] == 'run'
|
250
251
|
if options[:object].nil?
|
251
252
|
raise Bolt::CLIError, "Must specify a #{options[:subcommand]} to run"
|
@@ -257,23 +258,6 @@ module Bolt
|
|
257
258
|
end
|
258
259
|
end
|
259
260
|
|
260
|
-
if options[:boltdir] && options[:configfile]
|
261
|
-
raise Bolt::CLIError, "Only one of '--boltdir', '--project', or '--configfile' may be specified"
|
262
|
-
end
|
263
|
-
|
264
|
-
if options[:noop] &&
|
265
|
-
!(options[:subcommand] == 'task' && options[:action] == 'run') && options[:subcommand] != 'apply'
|
266
|
-
raise Bolt::CLIError,
|
267
|
-
"Option '--noop' may only be specified when running a task or applying manifest code"
|
268
|
-
end
|
269
|
-
|
270
|
-
if options[:env_vars]
|
271
|
-
unless %w[command script].include?(options[:subcommand]) && options[:action] == 'run'
|
272
|
-
raise Bolt::CLIError,
|
273
|
-
"Option '--env-var' may only be specified when running a command or script"
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
261
|
if options[:subcommand] == 'apply' && (options[:object] && options[:code])
|
278
262
|
raise Bolt::CLIError, "--execute is unsupported when specifying a manifest file"
|
279
263
|
end
|
@@ -296,6 +280,38 @@ module Bolt
|
|
296
280
|
raise Bolt::CLIError, "Must specify a plan name."
|
297
281
|
end
|
298
282
|
|
283
|
+
if options[:subcommand] == 'module' && options[:action] == 'add' && !options[:object]
|
284
|
+
raise Bolt::CLIError, "Must specify a module name."
|
285
|
+
end
|
286
|
+
|
287
|
+
if options[:subcommand] == 'module' && options[:action] == 'install' && options[:object]
|
288
|
+
raise Bolt::CLIError, "Invalid argument '#{options[:object]}'. To add a new module to "\
|
289
|
+
"the project, run 'bolt module add #{options[:object]}'."
|
290
|
+
end
|
291
|
+
|
292
|
+
if options[:subcommand] != 'file' && options[:subcommand] != 'script' &&
|
293
|
+
!options[:leftovers].empty?
|
294
|
+
raise Bolt::CLIError,
|
295
|
+
"Unknown argument(s) #{options[:leftovers].join(', ')}"
|
296
|
+
end
|
297
|
+
|
298
|
+
if options[:boltdir] && options[:configfile]
|
299
|
+
raise Bolt::CLIError, "Only one of '--boltdir', '--project', or '--configfile' may be specified"
|
300
|
+
end
|
301
|
+
|
302
|
+
if options[:noop] &&
|
303
|
+
!(options[:subcommand] == 'task' && options[:action] == 'run') && options[:subcommand] != 'apply'
|
304
|
+
raise Bolt::CLIError,
|
305
|
+
"Option '--noop' may only be specified when running a task or applying manifest code"
|
306
|
+
end
|
307
|
+
|
308
|
+
if options[:env_vars]
|
309
|
+
unless %w[command script].include?(options[:subcommand]) && options[:action] == 'run'
|
310
|
+
raise Bolt::CLIError,
|
311
|
+
"Option '--env-var' may only be specified when running a command or script"
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
299
315
|
if options.key?(:debug) && options.key?(:log)
|
300
316
|
raise Bolt::CLIError, "Only one of '--debug' or '--log-level' may be specified"
|
301
317
|
end
|
@@ -389,7 +405,7 @@ module Bolt
|
|
389
405
|
inventory_version: inventory.version)
|
390
406
|
end
|
391
407
|
|
392
|
-
analytics.screen_view(screen, screen_view_fields)
|
408
|
+
analytics.screen_view(screen, **screen_view_fields)
|
393
409
|
|
394
410
|
case options[:action]
|
395
411
|
when 'show'
|
@@ -444,9 +460,7 @@ module Bolt
|
|
444
460
|
when 'init'
|
445
461
|
code = initialize_project
|
446
462
|
when 'migrate'
|
447
|
-
|
448
|
-
path = config.project.path
|
449
|
-
code = Bolt::ProjectMigrate.new(path, outputter, inv).migrate_project
|
463
|
+
code = Bolt::ProjectMigrator.new(config, outputter).migrate
|
450
464
|
end
|
451
465
|
when 'plan'
|
452
466
|
case options[:action]
|
@@ -457,8 +471,10 @@ module Bolt
|
|
457
471
|
end
|
458
472
|
when 'module'
|
459
473
|
case options[:action]
|
474
|
+
when 'add'
|
475
|
+
code = add_project_module(options[:object], config.project)
|
460
476
|
when 'install'
|
461
|
-
code = install_project_modules
|
477
|
+
code = install_project_modules(config.project, options[:force], options[:resolve])
|
462
478
|
when 'generate-types'
|
463
479
|
code = generate_types
|
464
480
|
end
|
@@ -467,7 +483,11 @@ module Bolt
|
|
467
483
|
when 'generate-types'
|
468
484
|
code = generate_types
|
469
485
|
when 'install'
|
470
|
-
code = install_puppetfile(
|
486
|
+
code = install_puppetfile(
|
487
|
+
config.puppetfile_config,
|
488
|
+
config.puppetfile,
|
489
|
+
config.modulepath.first
|
490
|
+
)
|
471
491
|
end
|
472
492
|
when 'secret'
|
473
493
|
code = Bolt::Secret.execute(plugins, outputter, options)
|
@@ -567,8 +587,24 @@ module Bolt
|
|
567
587
|
end
|
568
588
|
|
569
589
|
def list_targets
|
590
|
+
inventoryfile = config.inventoryfile || config.default_inventoryfile
|
591
|
+
|
592
|
+
# Retrieve the known group and target names. This needs to be done before
|
593
|
+
# updating targets, as that will add adhoc targets to the inventory.
|
594
|
+
known_names = inventory.target_names
|
595
|
+
|
570
596
|
update_targets(options)
|
571
|
-
|
597
|
+
|
598
|
+
inventory_targets, adhoc_targets = options[:targets].partition do |target|
|
599
|
+
known_names.include?(target.name)
|
600
|
+
end
|
601
|
+
|
602
|
+
target_list = {
|
603
|
+
inventory: inventory_targets,
|
604
|
+
adhoc: adhoc_targets
|
605
|
+
}
|
606
|
+
|
607
|
+
outputter.print_targets(target_list, inventoryfile)
|
572
608
|
end
|
573
609
|
|
574
610
|
def show_targets
|
@@ -597,10 +633,10 @@ module Bolt
|
|
597
633
|
message = <<~MESSAGE.chomp
|
598
634
|
Invalid plan name '#{plan_name}'. Plan names are composed of one or more name segments
|
599
635
|
separated by double colons '::'.
|
600
|
-
|
636
|
+
|
601
637
|
Each name segment must begin with a lowercase letter, and may only include lowercase
|
602
638
|
letters, digits, and underscores.
|
603
|
-
|
639
|
+
|
604
640
|
Examples of valid plan names:
|
605
641
|
- #{config.project.name}
|
606
642
|
- #{config.project.name}::my_plan
|
@@ -842,7 +878,8 @@ module Bolt
|
|
842
878
|
"project with modules."
|
843
879
|
end
|
844
880
|
|
845
|
-
|
881
|
+
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
882
|
+
installer.install(options[:modules], puppetfile, moduledir)
|
846
883
|
end
|
847
884
|
|
848
885
|
# If either bolt.yaml or bolt-project.yaml exist, the user has already
|
@@ -863,85 +900,86 @@ module Bolt
|
|
863
900
|
|
864
901
|
# Installs modules declared in the project configuration file.
|
865
902
|
#
|
866
|
-
def install_project_modules
|
867
|
-
|
868
|
-
|
869
|
-
|
903
|
+
def install_project_modules(project, force, resolve)
|
904
|
+
assert_project_file(project)
|
905
|
+
|
906
|
+
unless project.modules
|
907
|
+
outputter.print_message "Project configuration file #{project.project_file} does not "\
|
908
|
+
"specify any module dependencies. Nothing to do."
|
870
909
|
return 0
|
871
910
|
end
|
872
911
|
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
912
|
+
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
913
|
+
|
914
|
+
ok = installer.install(project.modules,
|
915
|
+
project.puppetfile,
|
916
|
+
project.managed_moduledir,
|
917
|
+
force: force,
|
918
|
+
resolve: resolve)
|
919
|
+
ok ? 0 : 1
|
879
920
|
end
|
880
921
|
|
881
|
-
#
|
922
|
+
# Adds a single module to the project.
|
882
923
|
#
|
883
|
-
def
|
884
|
-
|
885
|
-
require 'bolt/puppetfile/installer'
|
886
|
-
|
887
|
-
puppetfile = Bolt::Puppetfile.new(modules)
|
888
|
-
|
889
|
-
# If the Puppetfile exists, check if it includes specs for each declared
|
890
|
-
# module, erroring if there are any missing. Otherwise, resolve the
|
891
|
-
# module dependencies and write a new Puppetfile. Users can forcibly
|
892
|
-
# overwrite an existing Puppetfile with the '--force' option.
|
893
|
-
if puppetfile_path.exist? && !options[:force]
|
894
|
-
outputter.print_message "Parsing existing Puppetfile at #{puppetfile_path}"
|
895
|
-
existing = Bolt::Puppetfile.parse(puppetfile_path)
|
896
|
-
|
897
|
-
unless existing.modules.superset? puppetfile.modules
|
898
|
-
missing_modules = puppetfile.modules - existing.modules
|
899
|
-
|
900
|
-
message = <<~MESSAGE.chomp
|
901
|
-
Puppetfile #{puppetfile_path} is missing specifications for the following
|
902
|
-
module declarations:
|
903
|
-
|
904
|
-
#{missing_modules.map(&:to_hash).to_yaml.lines.drop(1).join.chomp}
|
905
|
-
|
906
|
-
This may not be a Puppetfile managed by Bolt. To forcibly overwrite the
|
907
|
-
Puppetfile, run 'bolt module install --force'.
|
908
|
-
MESSAGE
|
909
|
-
|
910
|
-
raise Bolt::Error.new(message, 'bolt/missing-module-specs')
|
911
|
-
end
|
912
|
-
else
|
913
|
-
outputter.print_message "Resolving module dependencies, this may take a moment"
|
914
|
-
puppetfile.resolve
|
915
|
-
outputter.print_message "Writing Puppetfile at #{puppetfile_path}"
|
916
|
-
puppetfile.write(puppetfile_path, force: true)
|
917
|
-
end
|
924
|
+
def add_project_module(name, project)
|
925
|
+
assert_project_file(project)
|
918
926
|
|
919
|
-
|
920
|
-
|
927
|
+
modules = project.modules || []
|
928
|
+
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
921
929
|
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
930
|
+
ok = installer.add(name,
|
931
|
+
modules,
|
932
|
+
project.puppetfile,
|
933
|
+
project.managed_moduledir,
|
934
|
+
project.project_file)
|
926
935
|
ok ? 0 : 1
|
927
936
|
end
|
928
937
|
|
929
|
-
#
|
938
|
+
# Asserts that there is a project configuration file.
|
930
939
|
#
|
931
|
-
def
|
932
|
-
|
933
|
-
|
934
|
-
|
940
|
+
def assert_project_file(project)
|
941
|
+
unless project.project_file?
|
942
|
+
msg = if project.config_file.exist?
|
943
|
+
"Detected Bolt configuration file #{project.config_file}, unable to install "\
|
944
|
+
"modules. To update to a project configuration file, run 'bolt project migrate'."
|
945
|
+
else
|
946
|
+
"Could not find project configuration file #{project.project_file}, unable "\
|
947
|
+
"to install modules. To create a Bolt project, run 'bolt project init'."
|
948
|
+
end
|
935
949
|
|
936
|
-
|
937
|
-
|
950
|
+
raise Bolt::Error.new(msg, 'bolt/missing-project-config-error')
|
951
|
+
end
|
952
|
+
end
|
938
953
|
|
939
|
-
|
954
|
+
# Loads a Puppetfile and installs its modules.
|
955
|
+
#
|
956
|
+
def install_puppetfile(config, puppetfile, moduledir)
|
957
|
+
outputter.print_message("Installing modules from Puppetfile")
|
958
|
+
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
959
|
+
ok = installer.install_puppetfile(puppetfile, moduledir, config)
|
940
960
|
ok ? 0 : 1
|
941
961
|
end
|
942
962
|
|
963
|
+
# Raises an error if the 'puppetfile install' command is deprecated due to
|
964
|
+
# modules being configured.
|
965
|
+
#
|
966
|
+
def assert_puppetfile_or_module_command(modules)
|
967
|
+
if modules && options[:subcommand] == 'puppetfile'
|
968
|
+
raise Bolt::CLIError,
|
969
|
+
"Unable to use command 'bolt puppetfile #{options[:action]}' when "\
|
970
|
+
"'modules' is configured in bolt-project.yaml. Use the 'module' command "\
|
971
|
+
"instead. For a list of available actions for the 'module' command, run "\
|
972
|
+
"'bolt module --help'."
|
973
|
+
elsif modules.nil? && options[:subcommand] == 'module'
|
974
|
+
raise Bolt::CLIError,
|
975
|
+
"Unable to use command 'bolt module #{options[:action]}'. To use "\
|
976
|
+
"this command, update your project configuration to manage module "\
|
977
|
+
"dependencies."
|
978
|
+
end
|
979
|
+
end
|
980
|
+
|
943
981
|
def pal
|
944
|
-
@pal ||= Bolt::PAL.new(config.modulepath,
|
982
|
+
@pal ||= Bolt::PAL.new(Bolt::Config::Modulepath.new(config.modulepath),
|
945
983
|
config.hiera_config,
|
946
984
|
config.project.resource_types,
|
947
985
|
config.compile_concurrency,
|
@@ -1040,7 +1078,7 @@ module Bolt
|
|
1040
1078
|
'Task' => [],
|
1041
1079
|
'Plugin' => Bolt::Plugin::BUILTIN_PLUGINS }
|
1042
1080
|
if %w[plan task].include?(options[:subcommand]) && options[:action] == 'run'
|
1043
|
-
default_content = Bolt::PAL.new([], nil, nil)
|
1081
|
+
default_content = Bolt::PAL.new(Bolt::Config::Modulepath.new([]), nil, nil)
|
1044
1082
|
content['Plan'] = default_content.list_plans.each_with_object([]) do |iter, col|
|
1045
1083
|
col << iter&.first
|
1046
1084
|
end
|
@@ -1055,7 +1093,7 @@ module Bolt
|
|
1055
1093
|
# Gem installs include the aggregate, canary, and puppetdb_fact modules, while
|
1056
1094
|
# package installs include modules listed in the Bolt repo Puppetfile
|
1057
1095
|
def incomplete_install?
|
1058
|
-
(Dir.children(Bolt::
|
1096
|
+
(Dir.children(Bolt::Config::Modulepath::MODULES_PATH) - %w[aggregate canary puppetdb_fact secure_env_vars]).empty?
|
1059
1097
|
end
|
1060
1098
|
|
1061
1099
|
# Mimicks the output from Outputter::Human#fatal_error. This should be used to print
|