openbolt 5.0.0.rc1
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 +7 -0
- data/Puppetfile +52 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +60 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/containerresult.rb +51 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/future.rb +25 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb +71 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +55 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resultset.rb +65 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/target.rb +93 -0
- data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +33 -0
- data/bolt-modules/boltlib/lib/puppet/functions/add_to_group.rb +38 -0
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +208 -0
- data/bolt-modules/boltlib/lib/puppet/functions/background.rb +62 -0
- data/bolt-modules/boltlib/lib/puppet/functions/catch_errors.rb +57 -0
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +130 -0
- data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +31 -0
- data/bolt-modules/boltlib/lib/puppet/functions/fail_plan.rb +52 -0
- data/bolt-modules/boltlib/lib/puppet/functions/get_resources.rb +87 -0
- data/bolt-modules/boltlib/lib/puppet/functions/get_target.rb +34 -0
- data/bolt-modules/boltlib/lib/puppet/functions/get_targets.rb +35 -0
- data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +74 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_command.rb +97 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb +47 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +52 -0
- data/bolt-modules/boltlib/lib/puppet/functions/remove_from_group.rb +40 -0
- data/bolt-modules/boltlib/lib/puppet/functions/resolve_references.rb +42 -0
- data/bolt-modules/boltlib/lib/puppet/functions/resource.rb +53 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +106 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_container.rb +162 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +291 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +145 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +164 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +211 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_config.rb +48 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_feature.rb +43 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_resources.rb +145 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_var.rb +38 -0
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +101 -0
- data/bolt-modules/boltlib/lib/puppet/functions/vars.rb +29 -0
- data/bolt-modules/boltlib/lib/puppet/functions/wait.rb +131 -0
- data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +59 -0
- data/bolt-modules/boltlib/lib/puppet/functions/without_default_logging.rb +39 -0
- data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +50 -0
- data/bolt-modules/boltlib/types/planresult.pp +18 -0
- data/bolt-modules/boltlib/types/targetspec.pp +7 -0
- data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +42 -0
- data/bolt-modules/ctrl/lib/puppet/functions/ctrl/sleep.rb +20 -0
- data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +35 -0
- data/bolt-modules/file/lib/puppet/functions/file/delete.rb +21 -0
- data/bolt-modules/file/lib/puppet/functions/file/exists.rb +28 -0
- data/bolt-modules/file/lib/puppet/functions/file/join.rb +20 -0
- data/bolt-modules/file/lib/puppet/functions/file/read.rb +33 -0
- data/bolt-modules/file/lib/puppet/functions/file/readable.rb +28 -0
- data/bolt-modules/file/lib/puppet/functions/file/write.rb +24 -0
- data/bolt-modules/log/lib/puppet/functions/log/debug.rb +39 -0
- data/bolt-modules/log/lib/puppet/functions/log/error.rb +40 -0
- data/bolt-modules/log/lib/puppet/functions/log/fatal.rb +40 -0
- data/bolt-modules/log/lib/puppet/functions/log/info.rb +39 -0
- data/bolt-modules/log/lib/puppet/functions/log/trace.rb +39 -0
- data/bolt-modules/log/lib/puppet/functions/log/warn.rb +41 -0
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +36 -0
- data/bolt-modules/out/lib/puppet/functions/out/verbose.rb +35 -0
- data/bolt-modules/prompt/lib/puppet/functions/prompt/menu.rb +103 -0
- data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +65 -0
- data/bolt-modules/system/lib/puppet/functions/system/env.rb +20 -0
- data/exe/bolt +17 -0
- data/guides/debugging.yaml +27 -0
- data/guides/inventory.yaml +23 -0
- data/guides/links.yaml +12 -0
- data/guides/logging.yaml +17 -0
- data/guides/module.yaml +18 -0
- data/guides/modulepath.yaml +24 -0
- data/guides/project.yaml +21 -0
- data/guides/targets.yaml +28 -0
- data/guides/transports.yaml +22 -0
- data/lib/bolt/analytics.rb +233 -0
- data/lib/bolt/application.rb +806 -0
- data/lib/bolt/applicator.rb +368 -0
- data/lib/bolt/apply_inventory.rb +93 -0
- data/lib/bolt/apply_result.rb +154 -0
- data/lib/bolt/apply_target.rb +90 -0
- data/lib/bolt/bolt_option_parser.rb +1226 -0
- data/lib/bolt/catalog/logging.rb +15 -0
- data/lib/bolt/catalog.rb +144 -0
- data/lib/bolt/cli.rb +949 -0
- data/lib/bolt/config/modulepath.rb +30 -0
- data/lib/bolt/config/options.rb +673 -0
- data/lib/bolt/config/transport/base.rb +133 -0
- data/lib/bolt/config/transport/docker.rb +34 -0
- data/lib/bolt/config/transport/jail.rb +33 -0
- data/lib/bolt/config/transport/local.rb +39 -0
- data/lib/bolt/config/transport/lxd.rb +34 -0
- data/lib/bolt/config/transport/options.rb +431 -0
- data/lib/bolt/config/transport/orch.rb +41 -0
- data/lib/bolt/config/transport/podman.rb +33 -0
- data/lib/bolt/config/transport/remote.rb +24 -0
- data/lib/bolt/config/transport/ssh.rb +138 -0
- data/lib/bolt/config/transport/winrm.rb +63 -0
- data/lib/bolt/config.rb +515 -0
- data/lib/bolt/container_result.rb +105 -0
- data/lib/bolt/error.rb +194 -0
- data/lib/bolt/executor.rb +539 -0
- data/lib/bolt/fiber_executor.rb +190 -0
- data/lib/bolt/inventory/group.rb +446 -0
- data/lib/bolt/inventory/inventory.rb +391 -0
- data/lib/bolt/inventory/options.rb +139 -0
- data/lib/bolt/inventory/target.rb +293 -0
- data/lib/bolt/inventory.rb +120 -0
- data/lib/bolt/logger.rb +252 -0
- data/lib/bolt/module.rb +54 -0
- data/lib/bolt/module_installer/installer.rb +44 -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/puppetfile.rb +131 -0
- data/lib/bolt/module_installer/resolver.rb +129 -0
- data/lib/bolt/module_installer/specs/forge_spec.rb +91 -0
- data/lib/bolt/module_installer/specs/git_spec.rb +150 -0
- data/lib/bolt/module_installer/specs/id/base.rb +116 -0
- data/lib/bolt/module_installer/specs/id/gitclone.rb +120 -0
- data/lib/bolt/module_installer/specs/id/github.rb +90 -0
- data/lib/bolt/module_installer/specs/id/gitlab.rb +92 -0
- data/lib/bolt/module_installer/specs.rb +95 -0
- data/lib/bolt/module_installer.rb +208 -0
- data/lib/bolt/node/errors.rb +55 -0
- data/lib/bolt/node/output.rb +29 -0
- data/lib/bolt/outputter/human.rb +958 -0
- data/lib/bolt/outputter/json.rb +205 -0
- data/lib/bolt/outputter/logger.rb +76 -0
- data/lib/bolt/outputter/rainbow.rb +118 -0
- data/lib/bolt/outputter.rb +57 -0
- data/lib/bolt/pal/issues.rb +19 -0
- data/lib/bolt/pal/logging.rb +17 -0
- data/lib/bolt/pal/yaml_plan/evaluator.rb +83 -0
- data/lib/bolt/pal/yaml_plan/loader.rb +94 -0
- data/lib/bolt/pal/yaml_plan/parameter.rb +63 -0
- data/lib/bolt/pal/yaml_plan/step/command.rb +45 -0
- data/lib/bolt/pal/yaml_plan/step/download.rb +37 -0
- data/lib/bolt/pal/yaml_plan/step/eval.rb +42 -0
- data/lib/bolt/pal/yaml_plan/step/message.rb +31 -0
- data/lib/bolt/pal/yaml_plan/step/plan.rb +42 -0
- data/lib/bolt/pal/yaml_plan/step/resources.rb +170 -0
- data/lib/bolt/pal/yaml_plan/step/script.rb +62 -0
- data/lib/bolt/pal/yaml_plan/step/task.rb +42 -0
- data/lib/bolt/pal/yaml_plan/step/upload.rb +37 -0
- data/lib/bolt/pal/yaml_plan/step/verbose.rb +31 -0
- data/lib/bolt/pal/yaml_plan/step.rb +223 -0
- data/lib/bolt/pal/yaml_plan/transpiler.rb +90 -0
- data/lib/bolt/pal/yaml_plan.rb +172 -0
- data/lib/bolt/pal.rb +847 -0
- data/lib/bolt/plan_creator.rb +219 -0
- data/lib/bolt/plan_future.rb +86 -0
- data/lib/bolt/plan_result.rb +44 -0
- data/lib/bolt/plugin/cache.rb +76 -0
- data/lib/bolt/plugin/env_var.rb +54 -0
- data/lib/bolt/plugin/module.rb +276 -0
- data/lib/bolt/plugin/prompt.rb +36 -0
- data/lib/bolt/plugin/puppet_connect_data.rb +84 -0
- data/lib/bolt/plugin/puppetdb.rb +124 -0
- data/lib/bolt/plugin/task.rb +72 -0
- data/lib/bolt/plugin.rb +380 -0
- data/lib/bolt/project.rb +219 -0
- data/lib/bolt/project_manager/config_migrator.rb +113 -0
- data/lib/bolt/project_manager/inventory_migrator.rb +67 -0
- data/lib/bolt/project_manager/migrator.rb +39 -0
- data/lib/bolt/project_manager/module_migrator.rb +203 -0
- data/lib/bolt/project_manager.rb +221 -0
- data/lib/bolt/puppetdb/client.rb +153 -0
- data/lib/bolt/puppetdb/config.rb +176 -0
- data/lib/bolt/puppetdb/instance.rb +146 -0
- data/lib/bolt/puppetdb.rb +15 -0
- data/lib/bolt/r10k_log_proxy.rb +30 -0
- data/lib/bolt/rerun.rb +55 -0
- data/lib/bolt/resource_instance.rb +133 -0
- data/lib/bolt/result.rb +247 -0
- data/lib/bolt/result_set.rb +128 -0
- data/lib/bolt/shell/bash/tmpdir.rb +62 -0
- data/lib/bolt/shell/bash.rb +516 -0
- data/lib/bolt/shell/powershell/snippets.rb +181 -0
- data/lib/bolt/shell/powershell.rb +365 -0
- data/lib/bolt/shell.rb +105 -0
- data/lib/bolt/target.rb +174 -0
- data/lib/bolt/task/puppet_server.rb +27 -0
- data/lib/bolt/task/run.rb +55 -0
- data/lib/bolt/task.rb +163 -0
- data/lib/bolt/transport/base.rb +252 -0
- data/lib/bolt/transport/docker/connection.rb +150 -0
- data/lib/bolt/transport/docker.rb +23 -0
- data/lib/bolt/transport/jail/connection.rb +81 -0
- data/lib/bolt/transport/jail.rb +21 -0
- data/lib/bolt/transport/local/connection.rb +106 -0
- data/lib/bolt/transport/local.rb +20 -0
- data/lib/bolt/transport/lxd/connection.rb +115 -0
- data/lib/bolt/transport/lxd.rb +26 -0
- data/lib/bolt/transport/orch/connection.rb +111 -0
- data/lib/bolt/transport/orch.rb +271 -0
- data/lib/bolt/transport/podman/connection.rb +102 -0
- data/lib/bolt/transport/podman.rb +19 -0
- data/lib/bolt/transport/remote.rb +41 -0
- data/lib/bolt/transport/simple.rb +54 -0
- data/lib/bolt/transport/ssh/connection.rb +321 -0
- data/lib/bolt/transport/ssh/exec_connection.rb +140 -0
- data/lib/bolt/transport/ssh.rb +48 -0
- data/lib/bolt/transport/winrm/connection.rb +378 -0
- data/lib/bolt/transport/winrm.rb +33 -0
- data/lib/bolt/util/format.rb +68 -0
- data/lib/bolt/util/puppet_log_level.rb +21 -0
- data/lib/bolt/util.rb +465 -0
- data/lib/bolt/validator.rb +227 -0
- data/lib/bolt/version.rb +5 -0
- data/lib/bolt.rb +8 -0
- data/lib/bolt_server/acl.rb +39 -0
- data/lib/bolt_server/base_config.rb +112 -0
- data/lib/bolt_server/config.rb +64 -0
- data/lib/bolt_server/file_cache.rb +200 -0
- data/lib/bolt_server/request_error.rb +11 -0
- data/lib/bolt_server/schemas/action-check_node_connections.json +14 -0
- data/lib/bolt_server/schemas/action-run_command.json +12 -0
- data/lib/bolt_server/schemas/action-run_script.json +47 -0
- data/lib/bolt_server/schemas/action-run_task.json +20 -0
- data/lib/bolt_server/schemas/action-upload_file.json +47 -0
- data/lib/bolt_server/schemas/partials/target-any.json +10 -0
- data/lib/bolt_server/schemas/partials/target-ssh.json +88 -0
- data/lib/bolt_server/schemas/partials/target-winrm.json +67 -0
- data/lib/bolt_server/schemas/partials/task.json +94 -0
- data/lib/bolt_server/schemas/transport-ssh.json +25 -0
- data/lib/bolt_server/schemas/transport-winrm.json +19 -0
- data/lib/bolt_server/transport_app.rb +554 -0
- data/lib/bolt_spec/bolt_context.rb +226 -0
- data/lib/bolt_spec/plans/action_stubs/command_stub.rb +51 -0
- data/lib/bolt_spec/plans/action_stubs/download_stub.rb +66 -0
- data/lib/bolt_spec/plans/action_stubs/plan_stub.rb +55 -0
- data/lib/bolt_spec/plans/action_stubs/script_stub.rb +59 -0
- data/lib/bolt_spec/plans/action_stubs/task_stub.rb +57 -0
- data/lib/bolt_spec/plans/action_stubs/upload_stub.rb +65 -0
- data/lib/bolt_spec/plans/action_stubs.rb +196 -0
- data/lib/bolt_spec/plans/mock_executor.rb +361 -0
- data/lib/bolt_spec/plans/publish_stub.rb +49 -0
- data/lib/bolt_spec/plans.rb +190 -0
- data/lib/bolt_spec/run.rb +246 -0
- data/lib/logging_extensions/logging.rb +13 -0
- data/libexec/apply_catalog.rb +130 -0
- data/libexec/bolt_catalog +68 -0
- data/libexec/custom_facts.rb +63 -0
- data/libexec/query_resources.rb +75 -0
- data/modules/aggregate/lib/puppet/functions/aggregate/count.rb +21 -0
- data/modules/aggregate/lib/puppet/functions/aggregate/nodes.rb +22 -0
- data/modules/aggregate/lib/puppet/functions/aggregate/targets.rb +21 -0
- data/modules/aggregate/plans/count.pp +56 -0
- data/modules/aggregate/plans/targets.pp +56 -0
- data/modules/canary/lib/puppet/functions/canary/merge.rb +13 -0
- data/modules/canary/lib/puppet/functions/canary/random_split.rb +22 -0
- data/modules/canary/lib/puppet/functions/canary/skip.rb +25 -0
- data/modules/canary/plans/init.pp +100 -0
- data/modules/puppet_connect/plans/test_input_data.pp +94 -0
- data/modules/puppetdb_fact/plans/init.pp +20 -0
- data/resources/bolt_bash_completion.sh +214 -0
- metadata +735 -0
@@ -0,0 +1,276 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../bolt/task/run'
|
4
|
+
|
5
|
+
module Bolt
|
6
|
+
class Plugin
|
7
|
+
class Module
|
8
|
+
class InvalidPluginData < Bolt::Plugin::PluginError
|
9
|
+
def initialize(msg, plugin)
|
10
|
+
msg = "Invalid Plugin Data for #{plugin}: #{msg}"
|
11
|
+
super(msg, 'bolt/invalid-plugin-data')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# mod should not be nil
|
16
|
+
def self.load(mod, opts)
|
17
|
+
if mod.plugin?
|
18
|
+
opts[:mod] = mod
|
19
|
+
plugin = Bolt::Plugin::Module.new(**opts)
|
20
|
+
plugin.setup
|
21
|
+
plugin
|
22
|
+
else
|
23
|
+
raise PluginError::Unknown, mod.name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :config, :hook_map
|
28
|
+
|
29
|
+
def initialize(mod:, context:, config:, **_opts)
|
30
|
+
@module = mod
|
31
|
+
@config = config
|
32
|
+
@context = context
|
33
|
+
end
|
34
|
+
|
35
|
+
# This method interacts with the module on disk so it's separate from initialize
|
36
|
+
def setup
|
37
|
+
@data = load_data
|
38
|
+
@hook_map = find_hooks(@data['hooks'] || {})
|
39
|
+
|
40
|
+
if @data['config']
|
41
|
+
msg = <<~MSG.chomp
|
42
|
+
Found unsupported key 'config' in bolt_plugin.json. Config for a plugin is inferred
|
43
|
+
from task parameters, with config values passed as parameters.
|
44
|
+
MSG
|
45
|
+
raise InvalidPluginData.new(msg, name)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Validate againsts the intersection of all task schemas.
|
49
|
+
@config_schema = process_schema(extract_task_parameter_schema)
|
50
|
+
|
51
|
+
validate_config(@config, @config_schema)
|
52
|
+
end
|
53
|
+
|
54
|
+
def name
|
55
|
+
@module.name
|
56
|
+
end
|
57
|
+
|
58
|
+
def hooks
|
59
|
+
(@hook_map.keys + [:validate_resolve_reference]).uniq
|
60
|
+
end
|
61
|
+
|
62
|
+
def load_data
|
63
|
+
JSON.parse(File.read(@module.plugin_data_file))
|
64
|
+
rescue JSON::ParserError => e
|
65
|
+
raise InvalidPluginData.new(e.message, name)
|
66
|
+
end
|
67
|
+
|
68
|
+
def process_schema(schema)
|
69
|
+
raise InvalidPluginData.new('config specification is not an object', name) unless schema.is_a?(Hash)
|
70
|
+
schema.each do |key, val|
|
71
|
+
unless key =~ /\A[a-z][a-z0-9_]*\z/
|
72
|
+
raise InvalidPluginData.new("config specification key, '#{key}', is not allowed", name)
|
73
|
+
end
|
74
|
+
|
75
|
+
unless val.is_a?(Hash) && (val['type'] || '').is_a?(String)
|
76
|
+
raise InvalidPluginData.new("config specification #{val.to_json} is not allowed", name)
|
77
|
+
end
|
78
|
+
|
79
|
+
type_string = val['type'] || 'Any'
|
80
|
+
begin
|
81
|
+
val['pcore_type'] = Puppet::Pops::Types::TypeParser.singleton.parse(type_string)
|
82
|
+
if val['pcore_type'].is_a? Puppet::Pops::Types::PTypeReferenceType
|
83
|
+
raise InvalidPluginData.new("Could not find type '#{type_string}' for #{key}", name)
|
84
|
+
end
|
85
|
+
rescue Puppet::ParseError
|
86
|
+
raise InvalidPluginData.new("Could not parse type '#{type_string}' for #{key}", name)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
schema
|
91
|
+
end
|
92
|
+
|
93
|
+
def validate_config(config, config_schema)
|
94
|
+
config.each_key do |key|
|
95
|
+
msg = "Config for #{name} plugin contains unexpected key #{key}"
|
96
|
+
raise Bolt::ValidationError, msg unless config_schema.include?(key)
|
97
|
+
end
|
98
|
+
|
99
|
+
config_schema.each do |key, spec|
|
100
|
+
val = config[key]
|
101
|
+
|
102
|
+
unless spec['pcore_type'].instance?(val)
|
103
|
+
raise Bolt::ValidationError, "#{name} plugin expects a #{spec['type']} for key #{key}, got: #{val}"
|
104
|
+
end
|
105
|
+
val.nil?
|
106
|
+
end
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
|
110
|
+
def find_hooks(hook_data)
|
111
|
+
raise InvalidPluginData.new("'hooks' must be a hash", name) unless hook_data.is_a?(Hash)
|
112
|
+
|
113
|
+
hooks = {}
|
114
|
+
# Load hooks specified in the config
|
115
|
+
hook_data.each do |hook_name, hook_spec|
|
116
|
+
unless hook_spec.is_a?(Hash) && hook_spec['task'].is_a?(String)
|
117
|
+
msg = "Unexpected hook specification #{hook_spec.to_json} in #{@name} for hook #{hook_name}"
|
118
|
+
raise InvalidPluginData.new(msg, name)
|
119
|
+
end
|
120
|
+
|
121
|
+
begin
|
122
|
+
task = @context.get_validated_task(hook_spec['task'])
|
123
|
+
rescue Bolt::Error => e
|
124
|
+
msg = if e.kind == 'bolt/unknown-task'
|
125
|
+
"Plugin #{name} specified an unkown task '#{hook_spec['task']}' for a hook"
|
126
|
+
else
|
127
|
+
"Plugin #{name} could not load task '#{hook_spec['task']}': #{e.message}"
|
128
|
+
end
|
129
|
+
raise InvalidPluginData.new(msg, name)
|
130
|
+
end
|
131
|
+
|
132
|
+
hooks[hook_name.to_sym] = { 'task' => task }
|
133
|
+
end
|
134
|
+
|
135
|
+
# Check for tasks for any hooks not already defined
|
136
|
+
(Set.new(KNOWN_HOOKS.map) - hooks.keys).each do |hook_name|
|
137
|
+
task_name = "#{name}::#{hook_name}"
|
138
|
+
begin
|
139
|
+
task = @context.get_validated_task(task_name)
|
140
|
+
rescue Bolt::Error => e
|
141
|
+
raise e unless e.kind == 'bolt/unknown-task'
|
142
|
+
end
|
143
|
+
hooks[hook_name] = { 'task' => task } if task
|
144
|
+
end
|
145
|
+
|
146
|
+
Bolt::Util.symbolize_top_level_keys(hooks)
|
147
|
+
end
|
148
|
+
|
149
|
+
def validate_params(task, params)
|
150
|
+
@context.validate_params(task.name, params)
|
151
|
+
end
|
152
|
+
|
153
|
+
def process_params(task, opts)
|
154
|
+
# opts are passed directly from inventory but all of the _ options are
|
155
|
+
# handled previously. That may not always be the case so filter them
|
156
|
+
# out now.
|
157
|
+
meta, params = opts.partition { |key, _val| key.start_with?('_') }.map(&:to_h)
|
158
|
+
|
159
|
+
# Reject parameters from config that are not accepted by the task and
|
160
|
+
# merge in parameter defaults
|
161
|
+
params = if task.parameters
|
162
|
+
task.parameter_defaults
|
163
|
+
.merge(config.slice(*task.parameters.keys))
|
164
|
+
.merge(params)
|
165
|
+
else
|
166
|
+
config.merge(params)
|
167
|
+
end
|
168
|
+
|
169
|
+
validate_params(task, params)
|
170
|
+
|
171
|
+
meta['_boltdir'] = @context.boltdir.to_s
|
172
|
+
|
173
|
+
[params, meta]
|
174
|
+
end
|
175
|
+
|
176
|
+
def extract_task_parameter_schema
|
177
|
+
# Get the intersection of expected types (using Set)
|
178
|
+
type_set = @hook_map.each_with_object({}) do |(_hook, task), acc|
|
179
|
+
next unless (schema = task['task'].metadata['parameters'])
|
180
|
+
schema.each do |param, scheme|
|
181
|
+
next unless scheme['type'].is_a?(String)
|
182
|
+
scheme['type'] = Set.new([scheme['type']])
|
183
|
+
if acc.dig(param, 'type').is_a?(Set)
|
184
|
+
scheme['type'].merge(acc[param]['type'])
|
185
|
+
end
|
186
|
+
end
|
187
|
+
acc.merge!(schema)
|
188
|
+
end
|
189
|
+
# Convert Set to string
|
190
|
+
type_set.each do |_param, schema|
|
191
|
+
next unless schema['type']
|
192
|
+
schema['type'] = if schema['type'].size > 1
|
193
|
+
"Optional[Variant[#{schema['type'].to_a.join(', ')}]]"
|
194
|
+
else
|
195
|
+
"Optional[#{schema['type'].to_a.first}]"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def run_task(task, opts)
|
201
|
+
opts = opts.reject { |key, _val| key.start_with?('_') }
|
202
|
+
params, metaparams = process_params(task, opts)
|
203
|
+
params = params.merge(metaparams)
|
204
|
+
|
205
|
+
# There are no executor options to pass now.
|
206
|
+
options = { catch_errors: true }
|
207
|
+
|
208
|
+
result = @context.run_local_task(task,
|
209
|
+
params,
|
210
|
+
options).first
|
211
|
+
|
212
|
+
raise Bolt::Error.new(result.error_hash['msg'], result.error_hash['kind']) unless result.ok
|
213
|
+
result.value
|
214
|
+
end
|
215
|
+
|
216
|
+
def run_hook(hook_name, opts, value = true)
|
217
|
+
hook = @hook_map[hook_name]
|
218
|
+
# This shouldn't happen if the Plugin api is used
|
219
|
+
raise PluginError::UnsupportedHook.new(name, hook_name) unless hook
|
220
|
+
result = run_task(hook['task'], opts)
|
221
|
+
|
222
|
+
if value
|
223
|
+
unless result.include?('value')
|
224
|
+
msg = "Plugin #{name} result did not include a value, got #{result}"
|
225
|
+
raise Bolt::Plugin::PluginError::ExecutionError.new(msg, name, hook_name)
|
226
|
+
end
|
227
|
+
|
228
|
+
result['value']
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def validate_resolve_reference(opts)
|
233
|
+
task = @hook_map[:resolve_reference]['task']
|
234
|
+
params, _metaparams = process_params(task, opts)
|
235
|
+
|
236
|
+
if task
|
237
|
+
validate_params(task, params)
|
238
|
+
end
|
239
|
+
|
240
|
+
if @hook_map.include?(:validate_resolve_reference)
|
241
|
+
run_hook(:validate_resolve_reference, opts, false)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# These are all the same but are defined explicitly for clarity
|
246
|
+
def resolve_reference(opts)
|
247
|
+
run_hook(__method__, opts)
|
248
|
+
end
|
249
|
+
|
250
|
+
def secret_encrypt(opts)
|
251
|
+
run_hook(__method__, opts)
|
252
|
+
end
|
253
|
+
|
254
|
+
def secret_decrypt(opts)
|
255
|
+
run_hook(__method__, opts)
|
256
|
+
end
|
257
|
+
|
258
|
+
def secret_createkeys(opts = {})
|
259
|
+
run_hook(__method__, opts)
|
260
|
+
end
|
261
|
+
|
262
|
+
def puppet_library(opts, target, apply_prep)
|
263
|
+
task = @hook_map[:puppet_library]['task']
|
264
|
+
|
265
|
+
params, meta_params = process_params(task, opts)
|
266
|
+
|
267
|
+
options = {}
|
268
|
+
options[:run_as] = meta_params['_run_as'] if meta_params['_run_as']
|
269
|
+
|
270
|
+
proc do
|
271
|
+
apply_prep.run_task([target], task, params, options).first
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class Plugin
|
5
|
+
class Prompt
|
6
|
+
def initialize(*_args); end
|
7
|
+
|
8
|
+
def name
|
9
|
+
'prompt'
|
10
|
+
end
|
11
|
+
|
12
|
+
def hooks
|
13
|
+
hook_descriptions.keys
|
14
|
+
end
|
15
|
+
|
16
|
+
def hook_descriptions
|
17
|
+
{
|
18
|
+
resolve_reference: 'Prompt the user for a sensitive value.',
|
19
|
+
validate_resolve_reference: nil
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def validate_resolve_reference(opts)
|
24
|
+
raise Bolt::ValidationError, "Prompt requires a 'message'" unless opts['message']
|
25
|
+
end
|
26
|
+
|
27
|
+
def resolve_reference(opts)
|
28
|
+
$stderr.print("#{opts['message']}: ")
|
29
|
+
value = $stdin.noecho(&:gets).to_s.chomp
|
30
|
+
$stderr.puts
|
31
|
+
|
32
|
+
value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class Plugin
|
5
|
+
class PuppetConnectData
|
6
|
+
INPUT_DATA_VAR = 'PUPPET_CONNECT_INPUT_DATA'
|
7
|
+
|
8
|
+
def initialize(context:, **_opts)
|
9
|
+
if ENV.key?(INPUT_DATA_VAR)
|
10
|
+
# The user provided input data that they will copy-paste into the Puppet Connect UI
|
11
|
+
# for inventory syncing. This environment variable will likely be set when invoking a
|
12
|
+
# general "test Puppet Connect input data" command. That command tests that parsing
|
13
|
+
# the inventory with the given input data results in connectable targets. Part of
|
14
|
+
# that requires validating that the input data contains all of the referenced keys,
|
15
|
+
# which is what this plugin will do in validate_resolve_reference.
|
16
|
+
@input_data_path = ENV[INPUT_DATA_VAR]
|
17
|
+
data_path = @input_data_path
|
18
|
+
else
|
19
|
+
# The user is using this plugin during a regular Bolt invocation, so fetch the (minimal)
|
20
|
+
# required data from the default location. This data should typically be non-autoloadable
|
21
|
+
# secrets like WinRM passwords.
|
22
|
+
#
|
23
|
+
# Note that any unspecified keys will be resolved to nil.
|
24
|
+
data_path = File.join(context.boltdir, 'puppet_connect_data.yaml')
|
25
|
+
end
|
26
|
+
|
27
|
+
@data = Bolt::Util.read_optional_yaml_hash(
|
28
|
+
data_path,
|
29
|
+
File.basename(data_path)
|
30
|
+
)
|
31
|
+
|
32
|
+
if @input_data_path
|
33
|
+
# Validate that the data does not contain any plugin-reference
|
34
|
+
# values
|
35
|
+
@data.each do |key, toplevel_value|
|
36
|
+
# Use walk_vals to check for nested plugin references
|
37
|
+
Bolt::Util.walk_vals(toplevel_value) do |current_value|
|
38
|
+
if current_value.is_a?(Hash) && current_value.key?('_plugin')
|
39
|
+
raise invalid_input_data_err("the #{key} key's value contains a plugin reference")
|
40
|
+
end
|
41
|
+
current_value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def name
|
48
|
+
'puppet_connect_data'
|
49
|
+
end
|
50
|
+
|
51
|
+
def hooks
|
52
|
+
hook_descriptions.keys
|
53
|
+
end
|
54
|
+
|
55
|
+
def hook_descriptions
|
56
|
+
{
|
57
|
+
resolve_reference: nil,
|
58
|
+
validate_resolve_reference: nil
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
def resolve_reference(opts)
|
63
|
+
key = opts['key']
|
64
|
+
@data[key]
|
65
|
+
end
|
66
|
+
|
67
|
+
def validate_resolve_reference(opts)
|
68
|
+
unless opts['key']
|
69
|
+
raise Bolt::ValidationError,
|
70
|
+
"puppet_connect_data plugin requires that 'key' be specified"
|
71
|
+
end
|
72
|
+
if @input_data_path && !@data.key?(opts['key'])
|
73
|
+
# Input data for Puppet Connect was provided and opts['key'] does not have a
|
74
|
+
# value specified. Raise an error for this case.
|
75
|
+
raise invalid_input_data_err("a value for the #{opts['key']} key is not specified")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def invalid_input_data_err(msg)
|
80
|
+
Bolt::ValidationError.new("invalid input data #{@input_data_path}: #{msg}")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class Plugin
|
5
|
+
class Puppetdb
|
6
|
+
class FactLookupError < Bolt::Error
|
7
|
+
def initialize(fact, err = nil)
|
8
|
+
m = String.new("Fact lookup '#{fact}' contains an invalid factname")
|
9
|
+
m << ": #{err}" unless err.nil?
|
10
|
+
super(m, 'bolt.plugin/fact-lookup-error')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
TEMPLATE_OPTS = %w[alias config facts features name uri vars].freeze
|
15
|
+
PLUGIN_OPTS = %w[_plugin _cache query target_mapping instance].freeze
|
16
|
+
|
17
|
+
attr_reader :puppetdb_client
|
18
|
+
|
19
|
+
def initialize(config:, context:)
|
20
|
+
@puppetdb_client = Bolt::PuppetDB::Client.new(default: config.delete('default'),
|
21
|
+
instances: config.delete('instances') || {},
|
22
|
+
config: config,
|
23
|
+
project: context.boltdir)
|
24
|
+
|
25
|
+
@logger = Bolt::Logger.logger(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def name
|
29
|
+
'puppetdb'
|
30
|
+
end
|
31
|
+
|
32
|
+
def hooks
|
33
|
+
hook_descriptions.keys
|
34
|
+
end
|
35
|
+
|
36
|
+
def hook_descriptions
|
37
|
+
{
|
38
|
+
resolve_reference: 'Query PuppetDB for a group of targets.'
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def warn_missing_fact(certname, fact)
|
43
|
+
Bolt::Logger.warn("puppetdb_missing_fact", "Could not find fact #{fact} for node #{certname}")
|
44
|
+
end
|
45
|
+
|
46
|
+
def fact_path(raw_fact)
|
47
|
+
fact_path = raw_fact.split(".")
|
48
|
+
fact_path = fact_path.map do |segment|
|
49
|
+
# Turn it into an integer if we can
|
50
|
+
Integer(segment)
|
51
|
+
rescue ArgumentError
|
52
|
+
# Otherwise return the value
|
53
|
+
segment
|
54
|
+
end
|
55
|
+
if fact_path[0] == 'facts'
|
56
|
+
fact_path.drop(1)
|
57
|
+
elsif fact_path == ['certname']
|
58
|
+
fact_path
|
59
|
+
else
|
60
|
+
raise FactLookupError.new(raw_fact, "fact lookups must start with 'facts.'")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def resolve_reference(opts)
|
65
|
+
targets = @puppetdb_client.query_certnames(opts['query'], opts['instance'])
|
66
|
+
facts = []
|
67
|
+
|
68
|
+
template = opts.delete('target_mapping') || {}
|
69
|
+
|
70
|
+
keys = Set.new(TEMPLATE_OPTS) & opts.keys
|
71
|
+
unless keys.empty?
|
72
|
+
raise Bolt::ValidationError, "PuppetDB plugin expects keys #{keys.to_a} to be set under 'target_mapping'"
|
73
|
+
end
|
74
|
+
|
75
|
+
keys = Set.new(opts.keys) - PLUGIN_OPTS
|
76
|
+
unless keys.empty?
|
77
|
+
raise Bolt::ValidationError, "Unknown keys in PuppetDB plugin: #{keys.to_a}"
|
78
|
+
end
|
79
|
+
|
80
|
+
Bolt::Util.walk_vals(template) do |value|
|
81
|
+
# This is done in parts instead of in place so that we only need to
|
82
|
+
# make one puppetDB query. Don't gather certname since we already
|
83
|
+
# have that and it's not a fact.
|
84
|
+
if value.is_a?(String) && value != 'certname'
|
85
|
+
facts << fact_path(value)
|
86
|
+
end
|
87
|
+
value
|
88
|
+
end
|
89
|
+
|
90
|
+
facts.uniq!
|
91
|
+
# Returns {'mycertname' => [{'path' => ['nested', 'fact'], 'value' => val'}], ... }
|
92
|
+
fact_values = @puppetdb_client.fact_values(targets, facts, opts['instance'])
|
93
|
+
|
94
|
+
targets.map do |certname|
|
95
|
+
target_data = fact_values[certname]
|
96
|
+
target = resolve_facts(template, certname, target_data) || {}
|
97
|
+
target['uri'] = certname unless target['uri'] || target['name']
|
98
|
+
|
99
|
+
target
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def resolve_facts(config, certname, target_data)
|
104
|
+
Bolt::Util.walk_vals(config) do |value|
|
105
|
+
case value
|
106
|
+
when String
|
107
|
+
if value == 'certname'
|
108
|
+
certname
|
109
|
+
else
|
110
|
+
data = target_data&.detect { |d| d['path'] == fact_path(value) }
|
111
|
+
warn_missing_fact(certname, value) if data.nil?
|
112
|
+
# If there's no fact data this will be nil
|
113
|
+
data&.fetch('value', nil)
|
114
|
+
end
|
115
|
+
when Array, Hash
|
116
|
+
value
|
117
|
+
else
|
118
|
+
raise FactLookupError.new(value, "fact lookups must be a string")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class Plugin
|
5
|
+
class Task
|
6
|
+
def hooks
|
7
|
+
hook_descriptions.keys
|
8
|
+
end
|
9
|
+
|
10
|
+
def hook_descriptions
|
11
|
+
{
|
12
|
+
puppet_library: 'Run a task to install the Puppet agent package.',
|
13
|
+
resolve_reference: 'Run a task as a plugin.',
|
14
|
+
validate_resolve_reference: nil
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def name
|
19
|
+
'task'
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_accessor :pal, :executor, :inventory
|
23
|
+
|
24
|
+
def initialize(context:, **_opts)
|
25
|
+
@context = context
|
26
|
+
end
|
27
|
+
|
28
|
+
def run_task(opts)
|
29
|
+
params = opts['parameters'] || {}
|
30
|
+
options = { catch_errors: true }
|
31
|
+
|
32
|
+
raise Bolt::ValidationError, "Task plugin requires that the 'task' is specified" unless opts['task']
|
33
|
+
task = @context.get_validated_task(opts['task'], params)
|
34
|
+
|
35
|
+
result = @context.run_local_task(task, params, options).first
|
36
|
+
|
37
|
+
raise Bolt::Error.new(result.error_hash['msg'], result.error_hash['kind']) if result.error_hash
|
38
|
+
result
|
39
|
+
end
|
40
|
+
|
41
|
+
def validate_options(opts)
|
42
|
+
raise Bolt::ValidationError, "Task plugin requires that the 'task' is specified" unless opts['task']
|
43
|
+
@context.get_validated_task(opts['task'], opts['parameters'] || {})
|
44
|
+
end
|
45
|
+
alias validate_resolve_reference validate_options
|
46
|
+
|
47
|
+
def resolve_reference(opts)
|
48
|
+
result = run_task(opts)
|
49
|
+
|
50
|
+
unless result.value.include?('value')
|
51
|
+
raise Bolt::ValidationError, "Task result did not return 'value': #{result.value}"
|
52
|
+
end
|
53
|
+
|
54
|
+
result['value']
|
55
|
+
end
|
56
|
+
|
57
|
+
def puppet_library(opts, target, apply_prep)
|
58
|
+
params = opts['parameters'] || {}
|
59
|
+
run_opts = {}
|
60
|
+
run_opts[:run_as] = opts['_run_as'] if opts['_run_as']
|
61
|
+
begin
|
62
|
+
task = @context.get_validated_task(opts['task'], params)
|
63
|
+
rescue Bolt::Error => e
|
64
|
+
raise Bolt::Plugin::PluginError::ExecutionError.new(e.message, name, 'puppet_library')
|
65
|
+
end
|
66
|
+
proc do
|
67
|
+
apply_prep.run_task([target], task, params, run_opts).first
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|