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,176 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require_relative '../../bolt/util'
|
5
|
+
|
6
|
+
module Bolt
|
7
|
+
module PuppetDB
|
8
|
+
class Config
|
9
|
+
if ENV['HOME'].nil?
|
10
|
+
DEFAULT_TOKEN = Bolt::Util.windows? ? 'nul' : '/dev/null'
|
11
|
+
DEFAULT_CONFIG = { user: '/etc/puppetlabs/puppet/puppetdb.conf',
|
12
|
+
global: '/etc/puppetlabs/puppet/puppetdb.conf' }.freeze
|
13
|
+
else
|
14
|
+
DEFAULT_TOKEN = File.expand_path('~/.puppetlabs/token')
|
15
|
+
DEFAULT_CONFIG = { user: File.expand_path('~/.puppetlabs/client-tools/puppetdb.conf'),
|
16
|
+
global: '/etc/puppetlabs/client-tools/puppetdb.conf' }.freeze
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(config:, project: nil, load_defaults: false)
|
21
|
+
@settings = if load_defaults
|
22
|
+
self.class.default_config.merge(config)
|
23
|
+
else
|
24
|
+
config
|
25
|
+
end
|
26
|
+
|
27
|
+
expand_paths(project)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the path to the puppetdb.conf file on Windows.
|
31
|
+
#
|
32
|
+
# @return [String]
|
33
|
+
#
|
34
|
+
def self.default_windows_config
|
35
|
+
File.expand_path(File.join(ENV['ALLUSERSPROFILE'], 'PuppetLabs/client-tools/puppetdb.conf'))
|
36
|
+
end
|
37
|
+
|
38
|
+
# Loads default configuration from the puppetdb.conf file on system. If
|
39
|
+
# the file is not present, defaults to an empty hash.
|
40
|
+
#
|
41
|
+
# @return [Hash]
|
42
|
+
#
|
43
|
+
def self.default_config
|
44
|
+
config = {}
|
45
|
+
global_path = Bolt::Util.windows? ? default_windows_config : DEFAULT_CONFIG[:global]
|
46
|
+
|
47
|
+
if File.exist?(DEFAULT_CONFIG[:user])
|
48
|
+
filepath = DEFAULT_CONFIG[:user]
|
49
|
+
elsif File.exist?(global_path)
|
50
|
+
filepath = global_path
|
51
|
+
end
|
52
|
+
|
53
|
+
begin
|
54
|
+
config = JSON.parse(File.read(filepath)) if filepath
|
55
|
+
rescue StandardError => e
|
56
|
+
Bolt::Logger.logger(self).error("Could not load puppetdb.conf from #{filepath}: #{e.message}")
|
57
|
+
end
|
58
|
+
|
59
|
+
config.fetch('puppetdb', {})
|
60
|
+
end
|
61
|
+
|
62
|
+
def token
|
63
|
+
return @token if @token_computed
|
64
|
+
# Allow nil in config to skip loading a token
|
65
|
+
if @settings.include?('token')
|
66
|
+
if @settings['token']
|
67
|
+
@token = File.read(@settings['token'])
|
68
|
+
end
|
69
|
+
elsif File.exist?(DEFAULT_TOKEN)
|
70
|
+
@token = File.read(DEFAULT_TOKEN)
|
71
|
+
end
|
72
|
+
# Only use cert based auth in the case token and cert are both configured
|
73
|
+
if @token && cert
|
74
|
+
Bolt::Logger.logger(self).debug("Both cert and token based auth configured, using cert only")
|
75
|
+
@token = nil
|
76
|
+
end
|
77
|
+
@token_computed = true
|
78
|
+
@token = @token.strip if @token
|
79
|
+
end
|
80
|
+
|
81
|
+
def expand_paths(project_path)
|
82
|
+
%w[cacert cert key token].each do |file|
|
83
|
+
next unless @settings[file]
|
84
|
+
@settings[file] = File.expand_path(@settings[file], project_path)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def validate_file_exists(file)
|
89
|
+
if @settings[file] && !File.exist?(@settings[file])
|
90
|
+
raise Bolt::PuppetDBError, "#{file} file #{@settings[file]} does not exist"
|
91
|
+
end
|
92
|
+
true
|
93
|
+
end
|
94
|
+
|
95
|
+
def server_urls
|
96
|
+
case @settings['server_urls']
|
97
|
+
when String
|
98
|
+
[@settings['server_urls']]
|
99
|
+
when Array
|
100
|
+
@settings['server_urls']
|
101
|
+
when nil
|
102
|
+
raise Bolt::PuppetDBError, "server_urls must be specified"
|
103
|
+
else
|
104
|
+
raise Bolt::PuppetDBError, "server_urls must be a string or array"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def uri
|
109
|
+
return @uri if @uri
|
110
|
+
require 'addressable/uri'
|
111
|
+
|
112
|
+
uri = case @settings['server_urls']
|
113
|
+
when String
|
114
|
+
@settings['server_urls']
|
115
|
+
when Array
|
116
|
+
@settings['server_urls'].first
|
117
|
+
when nil
|
118
|
+
raise Bolt::PuppetDBError, "server_urls must be specified"
|
119
|
+
else
|
120
|
+
raise Bolt::PuppetDBError, "server_urls must be a string or array"
|
121
|
+
end
|
122
|
+
|
123
|
+
@uri = Addressable::URI.parse(uri)
|
124
|
+
@uri.port ||= 8081
|
125
|
+
@uri
|
126
|
+
end
|
127
|
+
|
128
|
+
def cacert
|
129
|
+
if @settings['cacert'] && validate_file_exists('cacert')
|
130
|
+
@settings['cacert']
|
131
|
+
else
|
132
|
+
raise Bolt::PuppetDBError, "cacert must be specified"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def cert
|
137
|
+
validate_cert_and_key
|
138
|
+
validate_file_exists('cert')
|
139
|
+
@settings['cert']
|
140
|
+
end
|
141
|
+
|
142
|
+
def key
|
143
|
+
validate_cert_and_key
|
144
|
+
validate_file_exists('key')
|
145
|
+
@settings['key']
|
146
|
+
end
|
147
|
+
|
148
|
+
def validate_cert_and_key
|
149
|
+
if (@settings['cert'] && !@settings['key']) ||
|
150
|
+
(!@settings['cert'] && @settings['key'])
|
151
|
+
raise Bolt::PuppetDBError, "cert and key must be specified together"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def connect_timeout
|
156
|
+
validate_timeout('connect_timeout')
|
157
|
+
@settings['connect_timeout']
|
158
|
+
end
|
159
|
+
|
160
|
+
def read_timeout
|
161
|
+
validate_timeout('read_timeout')
|
162
|
+
@settings['read_timeout']
|
163
|
+
end
|
164
|
+
|
165
|
+
def validate_timeout(timeout)
|
166
|
+
unless @settings[timeout].nil? || (@settings[timeout].is_a?(Integer) && @settings[timeout] > 0)
|
167
|
+
raise Bolt::PuppetDBError, "#{timeout} must be a positive integer, received #{@settings[timeout]}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def to_hash
|
172
|
+
@settings.dup
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'logging'
|
5
|
+
require_relative '../../bolt/puppetdb/config'
|
6
|
+
|
7
|
+
module Bolt
|
8
|
+
module PuppetDB
|
9
|
+
class Instance
|
10
|
+
attr_reader :config
|
11
|
+
|
12
|
+
def initialize(config:, project: nil, load_defaults: false)
|
13
|
+
@config = Bolt::PuppetDB::Config.new(config: config, project: project, load_defaults: load_defaults)
|
14
|
+
@bad_urls = []
|
15
|
+
@current_url = nil
|
16
|
+
@logger = Bolt::Logger.logger(self)
|
17
|
+
end
|
18
|
+
|
19
|
+
def make_query(query, path = nil)
|
20
|
+
body = JSON.generate(query: query)
|
21
|
+
url = "#{uri}/pdb/query/v4"
|
22
|
+
url += "/#{path}" if path
|
23
|
+
|
24
|
+
begin
|
25
|
+
@logger.debug("Sending PuppetDB query to #{url}")
|
26
|
+
response = http_client.post(url, body: body, header: headers)
|
27
|
+
rescue StandardError => e
|
28
|
+
raise Bolt::PuppetDBFailoverError, "Failed to query PuppetDB: #{e}"
|
29
|
+
end
|
30
|
+
|
31
|
+
@logger.debug("Got response code #{response.code} from PuppetDB")
|
32
|
+
if response.code != 200
|
33
|
+
msg = "Failed to query PuppetDB: #{response.body}"
|
34
|
+
if response.code == 400
|
35
|
+
raise Bolt::PuppetDBError, msg
|
36
|
+
else
|
37
|
+
raise Bolt::PuppetDBFailoverError, msg
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
begin
|
42
|
+
JSON.parse(response.body)
|
43
|
+
rescue JSON::ParserError
|
44
|
+
raise Bolt::PuppetDBError, "Unable to parse response as JSON: #{response.body}"
|
45
|
+
end
|
46
|
+
rescue Bolt::PuppetDBFailoverError => e
|
47
|
+
@logger.error("Request to puppetdb at #{@current_url} failed with #{e}.")
|
48
|
+
reject_url
|
49
|
+
make_query(query, path)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Sends a command to PuppetDB using version 1 of the commands API.
|
53
|
+
# https://puppet.com/docs/puppetdb/latest/api/command/v1/commands.html
|
54
|
+
#
|
55
|
+
# @param command [String] The command to invoke.
|
56
|
+
# @param version [Integer] The version of the command to invoke.
|
57
|
+
# @param payload [Hash] The payload to send with the command.
|
58
|
+
# @return A UUID identifying the submitted command.
|
59
|
+
#
|
60
|
+
def send_command(command, version, payload)
|
61
|
+
command = command.dup.force_encoding('utf-8')
|
62
|
+
body = JSON.generate(payload)
|
63
|
+
|
64
|
+
# PDB requires the following query parameters to the POST request.
|
65
|
+
# Error early if there's no certname, as PDB does not return a
|
66
|
+
# message indicating it's required.
|
67
|
+
unless payload['certname']
|
68
|
+
raise Bolt::Error.new(
|
69
|
+
"Payload must include 'certname', unable to invoke command.",
|
70
|
+
'bolt/pdb-command'
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
url = uri.tap do |u|
|
75
|
+
u.path = 'pdb/cmd/v1'
|
76
|
+
u.query_values = { 'command' => command,
|
77
|
+
'version' => version,
|
78
|
+
'certname' => payload['certname'] }
|
79
|
+
end
|
80
|
+
|
81
|
+
# Send the command to PDB
|
82
|
+
begin
|
83
|
+
@logger.debug("Sending PuppetDB command '#{command}' to #{url}")
|
84
|
+
response = http_client.post(url.to_s, body: body, header: headers)
|
85
|
+
rescue StandardError => e
|
86
|
+
raise Bolt::PuppetDBFailoverError, "Failed to invoke PuppetDB command: #{e}"
|
87
|
+
end
|
88
|
+
|
89
|
+
@logger.debug("Got response code #{response.code} from PuppetDB")
|
90
|
+
if response.code != 200
|
91
|
+
raise Bolt::PuppetDBError, "Failed to invoke PuppetDB command: #{response.body}"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Return the UUID string from the response body
|
95
|
+
begin
|
96
|
+
JSON.parse(response.body).fetch('uuid', nil)
|
97
|
+
rescue JSON::ParserError
|
98
|
+
raise Bolt::PuppetDBError, "Unable to parse response as JSON: #{response.body}"
|
99
|
+
end
|
100
|
+
rescue Bolt::PuppetDBFailoverError => e
|
101
|
+
@logger.error("Request to puppetdb at #{@current_url} failed with #{e}.")
|
102
|
+
reject_url
|
103
|
+
send_command(command, version, payload)
|
104
|
+
end
|
105
|
+
|
106
|
+
def http_client
|
107
|
+
return @http if @http
|
108
|
+
# lazy-load expensive gem code
|
109
|
+
require 'httpclient'
|
110
|
+
@logger.trace("Creating HTTP Client")
|
111
|
+
@http = HTTPClient.new
|
112
|
+
@http.ssl_config.set_client_cert_file(@config.cert, @config.key) if @config.cert
|
113
|
+
@http.ssl_config.add_trust_ca(@config.cacert)
|
114
|
+
@http.connect_timeout = @config.connect_timeout if @config.connect_timeout
|
115
|
+
@http.receive_timeout = @config.read_timeout if @config.read_timeout
|
116
|
+
|
117
|
+
@http
|
118
|
+
end
|
119
|
+
|
120
|
+
def reject_url
|
121
|
+
@bad_urls << @current_url if @current_url
|
122
|
+
@current_url = nil
|
123
|
+
end
|
124
|
+
|
125
|
+
def uri
|
126
|
+
require 'addressable/uri'
|
127
|
+
|
128
|
+
@current_url ||= (@config.server_urls - @bad_urls).first
|
129
|
+
unless @current_url
|
130
|
+
msg = "Failed to connect to all PuppetDB server_urls: #{@config.server_urls.to_a.join(', ')}."
|
131
|
+
raise Bolt::PuppetDBError, msg
|
132
|
+
end
|
133
|
+
|
134
|
+
uri = Addressable::URI.parse(@current_url)
|
135
|
+
uri.port ||= 8081
|
136
|
+
uri
|
137
|
+
end
|
138
|
+
|
139
|
+
def headers
|
140
|
+
headers = { 'Content-Type' => 'application/json' }
|
141
|
+
headers['X-Authentication'] = @config.token if @config.token
|
142
|
+
headers
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../bolt/error'
|
4
|
+
require_relative 'puppetdb/client'
|
5
|
+
require_relative 'puppetdb/config'
|
6
|
+
|
7
|
+
module Bolt
|
8
|
+
class PuppetDBError < Bolt::Error
|
9
|
+
def initialize(msg)
|
10
|
+
super(msg, "bolt/puppetdb-error")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class PuppetDBFailoverError < PuppetDBError; end
|
15
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'log4r/outputter/outputter'
|
4
|
+
|
5
|
+
module Bolt
|
6
|
+
class R10KLogProxy < Log4r::Outputter
|
7
|
+
def initialize
|
8
|
+
super('bolt')
|
9
|
+
|
10
|
+
@logger = Bolt::Logger.logger(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def canonical_log(event)
|
14
|
+
level = to_bolt_level(event.level)
|
15
|
+
@logger.send(level, event.data)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Convert an r10k log level to a bolt log level. These correspond 1-to-1
|
19
|
+
# except that r10k has debug, debug1, and debug2. The log event has the log
|
20
|
+
# level as an integer that we need to look up.
|
21
|
+
def to_bolt_level(level_num)
|
22
|
+
level_str = Log4r::LNAMES[level_num]&.downcase || 'debug'
|
23
|
+
if level_str =~ /debug/
|
24
|
+
:debug
|
25
|
+
else
|
26
|
+
level_str.to_sym
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/bolt/rerun.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'logging'
|
5
|
+
|
6
|
+
module Bolt
|
7
|
+
class Rerun
|
8
|
+
def initialize(path, save_failures)
|
9
|
+
@path = path
|
10
|
+
@save_failures = save_failures
|
11
|
+
@logger = Bolt::Logger.logger(self)
|
12
|
+
end
|
13
|
+
|
14
|
+
def data
|
15
|
+
@data ||= Bolt::Util.read_json_file(@path, 'rerun')
|
16
|
+
unless @data.is_a?(Array) && @data.all? { |r| r['target'] && r['status'] }
|
17
|
+
raise Bolt::FileError.new("Missing data in rerun file: #{@path}", @path)
|
18
|
+
end
|
19
|
+
@data
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_targets(filter)
|
23
|
+
filtered = case filter
|
24
|
+
when 'all'
|
25
|
+
data
|
26
|
+
when 'failure'
|
27
|
+
data.select { |result| result['status'] == 'failure' }
|
28
|
+
when 'success'
|
29
|
+
data.select { |result| result['status'] == 'success' }
|
30
|
+
else
|
31
|
+
raise Bolt::CLIError, "Unexpected option #{filter} for '--retry'"
|
32
|
+
end
|
33
|
+
filtered.map { |result| result['target'] }
|
34
|
+
end
|
35
|
+
|
36
|
+
def update(result_set)
|
37
|
+
unless @save_failures == false
|
38
|
+
if result_set.is_a?(Bolt::PlanResult)
|
39
|
+
result_set = result_set.value
|
40
|
+
result_set = result_set.result_set if result_set.is_a?(Bolt::RunFailure)
|
41
|
+
end
|
42
|
+
|
43
|
+
if result_set.is_a?(Bolt::ResultSet)
|
44
|
+
data = result_set.map { |res| { target: res.target.name, status: res.status } }
|
45
|
+
FileUtils.mkdir_p(File.dirname(@path))
|
46
|
+
File.write(@path, data.to_json)
|
47
|
+
elsif File.exist?(@path)
|
48
|
+
FileUtils.rm(@path)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
rescue StandardError => e
|
52
|
+
Bolt::Logger.warn_once("unwriteable_file", "Failed to save result to #{@path}: #{e.message}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Bolt
|
6
|
+
class ResourceInstance
|
7
|
+
attr_reader :target, :type, :title, :state, :desired_state
|
8
|
+
attr_accessor :events
|
9
|
+
|
10
|
+
# Needed by Puppet to recognize Bolt::ResourceInstance as a Puppet object when deserializing
|
11
|
+
def self._pcore_type
|
12
|
+
ResourceInstance
|
13
|
+
end
|
14
|
+
|
15
|
+
# Needed by Puppet to serialize with _pcore_init_hash instead of the object's attributes
|
16
|
+
def self._pcore_init_from_hash(_init_hash)
|
17
|
+
raise "ResourceInstance shouldn't be instantiated from a pcore_init class method. "\
|
18
|
+
"How did this get called?"
|
19
|
+
end
|
20
|
+
|
21
|
+
def _pcore_init_from_hash(init_hash)
|
22
|
+
initialize(init_hash)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Parameters will already be validated when calling ResourceInstance.new or
|
26
|
+
# set_resources() from a plan. We don't perform any validation in the class
|
27
|
+
# itself since Puppet will pass an empty hash to the initializer as part of
|
28
|
+
# the deserialization process before passing the _pcore_init_hash.
|
29
|
+
def initialize(resource_hash)
|
30
|
+
@target = resource_hash['target']
|
31
|
+
@type = resource_hash['type'].to_s.capitalize
|
32
|
+
@title = resource_hash['title']
|
33
|
+
@state = resource_hash['state'] || {}
|
34
|
+
@desired_state = resource_hash['desired_state'] || {}
|
35
|
+
@events = resource_hash['events'] || []
|
36
|
+
end
|
37
|
+
|
38
|
+
# Creates a ResourceInstance from a data hash in a plan when calling
|
39
|
+
# ResourceInstance.new($resource_hash) or $target.set_resources($resource_hash)
|
40
|
+
def self.from_asserted_hash(resource_hash)
|
41
|
+
new(resource_hash)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Creates a ResourceInstance from positional arguments in a plan when
|
45
|
+
# calling ResourceInstance.new(target, type, title, ...)
|
46
|
+
def self.from_asserted_args(target,
|
47
|
+
type,
|
48
|
+
title,
|
49
|
+
state = nil,
|
50
|
+
desired_state = nil,
|
51
|
+
events = nil)
|
52
|
+
new(
|
53
|
+
'target' => target,
|
54
|
+
'type' => type,
|
55
|
+
'title' => title,
|
56
|
+
'state' => state,
|
57
|
+
'desired_state' => desired_state,
|
58
|
+
'events' => events
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
def eql?(other)
|
63
|
+
self.class.equal?(other.class) &&
|
64
|
+
target == other.target &&
|
65
|
+
type == other.type &&
|
66
|
+
title == other.title
|
67
|
+
end
|
68
|
+
alias == eql?
|
69
|
+
|
70
|
+
def to_hash
|
71
|
+
{
|
72
|
+
'target' => target,
|
73
|
+
'type' => type,
|
74
|
+
'title' => title,
|
75
|
+
'state' => state,
|
76
|
+
'desired_state' => desired_state,
|
77
|
+
'events' => events
|
78
|
+
}
|
79
|
+
end
|
80
|
+
alias _pcore_init_hash to_hash
|
81
|
+
|
82
|
+
def to_json(opts = nil)
|
83
|
+
to_hash.to_json(opts)
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.format_reference(type, title)
|
87
|
+
"#{type.capitalize}[#{title}]"
|
88
|
+
end
|
89
|
+
|
90
|
+
def reference
|
91
|
+
self.class.format_reference(@type, @title)
|
92
|
+
end
|
93
|
+
alias to_s reference
|
94
|
+
|
95
|
+
def [](attribute)
|
96
|
+
@state[attribute]
|
97
|
+
end
|
98
|
+
|
99
|
+
def add_event(event)
|
100
|
+
@events << event
|
101
|
+
end
|
102
|
+
|
103
|
+
# rubocop:disable Naming/AccessorMethodName
|
104
|
+
def set_state(state)
|
105
|
+
assert_hash('state', state)
|
106
|
+
@state.merge!(state)
|
107
|
+
end
|
108
|
+
# rubocop:enable Naming/AccessorMethodName
|
109
|
+
|
110
|
+
def overwrite_state(state)
|
111
|
+
assert_hash('state', state)
|
112
|
+
@state = state
|
113
|
+
end
|
114
|
+
|
115
|
+
# rubocop:disable Naming/AccessorMethodName
|
116
|
+
def set_desired_state(desired_state)
|
117
|
+
assert_hash('desired_state', desired_state)
|
118
|
+
@desired_state.merge!(desired_state)
|
119
|
+
end
|
120
|
+
# rubocop:enable Naming/AccessorMethodName
|
121
|
+
|
122
|
+
def overwrite_desired_state(desired_state)
|
123
|
+
assert_hash('desired_state', desired_state)
|
124
|
+
@desired_state = desired_state
|
125
|
+
end
|
126
|
+
|
127
|
+
def assert_hash(loc, value)
|
128
|
+
unless value.is_a?(Hash)
|
129
|
+
raise Bolt::ValidationError, "#{loc} must be of type Hash; got #{value.class}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|