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,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logging'
|
4
|
+
require_relative '../../../bolt/node/errors'
|
5
|
+
|
6
|
+
module Bolt
|
7
|
+
module Transport
|
8
|
+
class Jail < Simple
|
9
|
+
class Connection
|
10
|
+
attr_reader :user, :target
|
11
|
+
|
12
|
+
def initialize(target)
|
13
|
+
raise Bolt::ValidationError, "Target #{target.safe_name} does not have a host" unless target.host
|
14
|
+
@target = target
|
15
|
+
@user = @target.user || ENV['USER'] || Etc.getlogin
|
16
|
+
@logger = Bolt::Logger.logger(target.safe_name)
|
17
|
+
@jail_info = {}
|
18
|
+
@logger.trace("Initializing jail connection to #{target.safe_name}")
|
19
|
+
end
|
20
|
+
|
21
|
+
def shell
|
22
|
+
@shell ||= Bolt::Shell::Bash.new(target, self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def reset_cwd?
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
def jail_id
|
30
|
+
@jail_info['jid'].to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def jail_path
|
34
|
+
@jail_info['path']
|
35
|
+
end
|
36
|
+
|
37
|
+
def connect
|
38
|
+
output = JSON.parse(`jls --libxo=json`)
|
39
|
+
@jail_info = output['jail-information']['jail'].select { |jail| jail['hostname'] == target.host }.first
|
40
|
+
raise "Could not find a jail with name matching #{target.host}" if @jail_info.nil?
|
41
|
+
@logger.trace { "Opened session" }
|
42
|
+
true
|
43
|
+
rescue StandardError => e
|
44
|
+
raise Bolt::Node::ConnectError.new(
|
45
|
+
"Failed to connect to #{target.safe_name}: #{e.message}",
|
46
|
+
'CONNECT_ERROR'
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def execute(command)
|
51
|
+
args = ['-lU', @user]
|
52
|
+
|
53
|
+
jail_command = %w[jexec] + args + [jail_id] + Shellwords.split(command)
|
54
|
+
@logger.trace { "Executing #{jail_command.join(' ')}" }
|
55
|
+
|
56
|
+
Open3.popen3({}, *jail_command)
|
57
|
+
rescue StandardError
|
58
|
+
@logger.trace { "Command aborted" }
|
59
|
+
raise
|
60
|
+
end
|
61
|
+
|
62
|
+
def upload_file(source, destination)
|
63
|
+
@logger.trace { "Uploading #{source} to #{destination}" }
|
64
|
+
jail_destination = File.join(jail_path, destination)
|
65
|
+
FileUtils.cp(source, jail_destination)
|
66
|
+
rescue StandardError => e
|
67
|
+
raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
|
68
|
+
end
|
69
|
+
|
70
|
+
def download_file(source, destination, _download)
|
71
|
+
@logger.trace { "Downloading #{source} to #{destination}" }
|
72
|
+
jail_source = File.join(jail_path, source)
|
73
|
+
FileUtils.mkdir_p(destination)
|
74
|
+
FileUtils.cp(jail_source, destination)
|
75
|
+
rescue StandardError => e
|
76
|
+
raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../bolt/transport/simple'
|
4
|
+
|
5
|
+
module Bolt
|
6
|
+
module Transport
|
7
|
+
class Jail < Simple
|
8
|
+
def provided_features
|
9
|
+
['shell']
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_connection(target)
|
13
|
+
conn = Connection.new(target)
|
14
|
+
conn.connect
|
15
|
+
yield conn
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
require_relative 'jail/connection'
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'open3'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'tempfile'
|
6
|
+
require_relative '../../../bolt/node/output'
|
7
|
+
require_relative '../../../bolt/util'
|
8
|
+
|
9
|
+
module Bolt
|
10
|
+
module Transport
|
11
|
+
class Local < Simple
|
12
|
+
class Connection
|
13
|
+
RUBY_ENV_VARS = %w[GEM_PATH GEM_HOME RUBYLIB RUBYLIB_PREFIX RUBYOPT RUBYPATH RUBYSHELL].freeze
|
14
|
+
|
15
|
+
attr_accessor :user, :logger, :target
|
16
|
+
|
17
|
+
def initialize(target)
|
18
|
+
@target = target
|
19
|
+
# The familiar problem: Etc.getlogin is broken on osx
|
20
|
+
@user = ENV['USER'] || Etc.getlogin
|
21
|
+
@logger = Bolt::Logger.logger(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def shell
|
25
|
+
@shell ||= if Bolt::Util.windows?
|
26
|
+
Bolt::Shell::Powershell.new(target, self)
|
27
|
+
else
|
28
|
+
Bolt::Shell::Bash.new(target, self)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def upload_file(source, dest)
|
33
|
+
@logger.trace { "Uploading #{source} to #{dest}" }
|
34
|
+
if source.is_a?(StringIO)
|
35
|
+
Tempfile.create(File.basename(dest)) do |f|
|
36
|
+
f.write(source.read)
|
37
|
+
f.close
|
38
|
+
FileUtils.mv(f, dest)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
# Mimic the behavior of `cp --remove-destination`
|
42
|
+
# since the flag isn't supported on MacOS
|
43
|
+
FileUtils.cp_r(source, dest, remove_destination: true)
|
44
|
+
end
|
45
|
+
rescue StandardError => e
|
46
|
+
message = "Could not copy file to #{dest}: #{e}"
|
47
|
+
raise Bolt::Node::FileError.new(message, 'COPY_ERROR')
|
48
|
+
end
|
49
|
+
|
50
|
+
def download_file(source, dest, _download)
|
51
|
+
@logger.trace { "Downloading #{source} to #{dest}" }
|
52
|
+
# Create the destination directory for the target, or the
|
53
|
+
# copied file will have the target's name
|
54
|
+
FileUtils.mkdir_p(dest)
|
55
|
+
# Mimic the behavior of `cp --remove-destination`
|
56
|
+
# since the flag isn't supported on MacOS
|
57
|
+
FileUtils.cp_r(source, dest, remove_destination: true)
|
58
|
+
rescue StandardError => e
|
59
|
+
message = "Could not download file to #{dest}: #{e}"
|
60
|
+
raise Bolt::Node::FileError.new(message, 'DOWNLOAD_ERROR')
|
61
|
+
end
|
62
|
+
|
63
|
+
def execute(command)
|
64
|
+
if Bolt::Util.windows?
|
65
|
+
# If it's already a powershell command then invoke it normally.
|
66
|
+
# Otherwise, wrap it in powershell.exe.
|
67
|
+
unless command.start_with?('powershell.exe')
|
68
|
+
cmd = Bolt::Shell::Powershell::Snippets.exit_with_code(command)
|
69
|
+
command = ['powershell.exe', *Bolt::Shell::Powershell::PS_ARGS, '-Command', cmd]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Only do this if bundled-ruby is set to false, not nil
|
74
|
+
ruby_env_vars = if target.transport_config['bundled-ruby'] == false
|
75
|
+
RUBY_ENV_VARS.each_with_object({}) do |e, acc|
|
76
|
+
if ENV["BOLT_ORIG_#{e}"] && !ENV["BOLT_ORIG_#{e}"].empty?
|
77
|
+
acc[e] = ENV["BOLT_ORIG_#{e}"]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if target.transport_config['bundled-ruby'] == false &&
|
83
|
+
Gem.loaded_specs.keys.include?('bundler')
|
84
|
+
Bundler.with_unbundled_env do
|
85
|
+
Open3.popen3(ruby_env_vars || {}, *command)
|
86
|
+
end
|
87
|
+
else
|
88
|
+
Open3.popen3(ruby_env_vars || {}, *command)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# This is used by the Bash shell to decide whether to `cd` before
|
93
|
+
# executing commands as a run-as user
|
94
|
+
def reset_cwd?
|
95
|
+
false
|
96
|
+
end
|
97
|
+
|
98
|
+
def max_command_length
|
99
|
+
if Bolt::Util.windows?
|
100
|
+
32000
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../bolt/logger'
|
4
|
+
require_relative '../../bolt/transport/simple'
|
5
|
+
|
6
|
+
module Bolt
|
7
|
+
module Transport
|
8
|
+
class Local < Simple
|
9
|
+
def connected?(_target)
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def with_connection(target)
|
14
|
+
yield Connection.new(target)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
require_relative 'local/connection'
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logging'
|
4
|
+
require_relative '../../../bolt/node/errors'
|
5
|
+
|
6
|
+
module Bolt
|
7
|
+
module Transport
|
8
|
+
class LXD < Simple
|
9
|
+
class Connection
|
10
|
+
attr_reader :user, :target
|
11
|
+
|
12
|
+
def initialize(target, options)
|
13
|
+
raise Bolt::ValidationError, "Target #{target.safe_name} does not have a host" unless target.host
|
14
|
+
|
15
|
+
@target = target
|
16
|
+
@user = ENV['USER'] || Etc.getlogin
|
17
|
+
@options = options
|
18
|
+
@logger = Bolt::Logger.logger(target.safe_name)
|
19
|
+
@logger.trace("Initializing LXD connection to #{target.safe_name}")
|
20
|
+
end
|
21
|
+
|
22
|
+
def shell
|
23
|
+
Bolt::Shell::Bash.new(target, self)
|
24
|
+
end
|
25
|
+
|
26
|
+
def reset_cwd?
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
def container_id
|
31
|
+
"#{@target.transport_config['remote']}:#{@target.host}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def connect
|
35
|
+
out, err, status = execute_local_command(%W[list #{container_id} --format json])
|
36
|
+
unless status.exitstatus.zero?
|
37
|
+
raise "Error listing available containers: #{err}"
|
38
|
+
end
|
39
|
+
containers = JSON.parse(out)
|
40
|
+
if containers.empty?
|
41
|
+
raise "Could not find a container with name or ID matching '#{container_id}'"
|
42
|
+
end
|
43
|
+
@logger.trace("Opened session")
|
44
|
+
true
|
45
|
+
rescue StandardError => e
|
46
|
+
raise Bolt::Node::ConnectError.new(
|
47
|
+
"Failed to connect to #{container_id}: #{e.message}",
|
48
|
+
'CONNECT_ERROR'
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_env_vars(env_vars)
|
53
|
+
@env_vars = env_vars.each_with_object([]) do |env_var, acc|
|
54
|
+
acc << "--env"
|
55
|
+
acc << "#{env_var[0]}=#{Shellwords.shellescape(env_var[1])}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def execute(command)
|
60
|
+
lxc_command = %W[lxc exec #{container_id}]
|
61
|
+
lxc_command += ['--mode', target.options['tty'].to_s.empty? ? 'non-interactive' : 'interactive']
|
62
|
+
lxc_command += @env_vars if @env_vars
|
63
|
+
lxc_command << '--'
|
64
|
+
|
65
|
+
if target.options['shell-command'].to_s.empty?
|
66
|
+
lxc_command += Shellwords.split(command)
|
67
|
+
else
|
68
|
+
lxc_command += Shellwords.split(target.options['shell-command'])
|
69
|
+
lxc_command << command
|
70
|
+
end
|
71
|
+
|
72
|
+
@logger.trace { "Executing: #{lxc_command.join(' ')}" }
|
73
|
+
|
74
|
+
Open3.popen3(*lxc_command)
|
75
|
+
rescue StandardError
|
76
|
+
@logger.trace { "Command aborted" }
|
77
|
+
raise
|
78
|
+
end
|
79
|
+
|
80
|
+
private def execute_local_command(command)
|
81
|
+
Open3.capture3('lxc', *command, { binmode: true })
|
82
|
+
end
|
83
|
+
|
84
|
+
def upload_file(source, destination)
|
85
|
+
@logger.trace { "Uploading #{source} to #{destination}" }
|
86
|
+
args = %w[--create-dirs]
|
87
|
+
if File.directory?(source)
|
88
|
+
args << '--recursive'
|
89
|
+
# If we don't do this, LXD will upload to
|
90
|
+
# /tmp/d2020-11/d2020-11/dir instead of /tmp/d2020-11/dir
|
91
|
+
destination = Pathname.new(destination).dirname.to_s
|
92
|
+
end
|
93
|
+
cmd = %w[file push] + args + %W[#{source} #{container_id}#{destination}]
|
94
|
+
_out, err, stat = execute_local_command(cmd)
|
95
|
+
unless stat.exitstatus.zero?
|
96
|
+
raise "Error writing to #{container_id}: #{err}"
|
97
|
+
end
|
98
|
+
rescue StandardError => e
|
99
|
+
raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
|
100
|
+
end
|
101
|
+
|
102
|
+
def download_file(source, destination, _download)
|
103
|
+
@logger.trace { "Downloading #{source} to #{destination}" }
|
104
|
+
FileUtils.mkdir_p(destination)
|
105
|
+
_out, err, stat = execute_local_command(%W[file pull --recursive #{container_id}#{source} #{destination}])
|
106
|
+
unless stat.exitstatus.zero?
|
107
|
+
raise "Error downloading content from container #{container_id}: #{err}"
|
108
|
+
end
|
109
|
+
rescue StandardError => e
|
110
|
+
raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../bolt/logger'
|
4
|
+
require_relative '../../bolt/node/errors'
|
5
|
+
require_relative '../../bolt/transport/simple'
|
6
|
+
|
7
|
+
module Bolt
|
8
|
+
module Transport
|
9
|
+
class LXD < Simple
|
10
|
+
def provided_features
|
11
|
+
['shell']
|
12
|
+
end
|
13
|
+
|
14
|
+
def with_connection(target, options = {})
|
15
|
+
Bolt::Logger.warn_once("lxd_experimental",
|
16
|
+
"The LXD transport is experimental, and might "\
|
17
|
+
"include breaking changes between minor versions.")
|
18
|
+
conn = Connection.new(target, options)
|
19
|
+
conn.connect
|
20
|
+
yield conn
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require_relative 'lxd/connection'
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
module Transport
|
5
|
+
class Orch < Base
|
6
|
+
class Connection
|
7
|
+
attr_reader :logger, :key
|
8
|
+
|
9
|
+
CONTEXT_KEYS = Set.new(%i[plan_name description params sensitive]).freeze
|
10
|
+
|
11
|
+
def self.get_key(opts)
|
12
|
+
[
|
13
|
+
opts['service-url'],
|
14
|
+
opts['task-environment'],
|
15
|
+
opts['token-file']
|
16
|
+
].join('-')
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(opts, plan_context, logger)
|
20
|
+
require 'addressable/uri'
|
21
|
+
|
22
|
+
@logger = logger
|
23
|
+
@key = self.class.get_key(opts)
|
24
|
+
client_opts = opts.slice('token-file', 'cacert', 'job-poll-interval', 'job-poll-timeout', 'read-timeout')
|
25
|
+
|
26
|
+
if opts['service-url']
|
27
|
+
uri = Addressable::URI.parse(opts['service-url'])
|
28
|
+
uri&.port ||= 8143
|
29
|
+
client_opts['service-url'] = uri.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
client_opts['User-Agent'] = "Bolt/#{VERSION}"
|
33
|
+
|
34
|
+
%w[token-file cacert].each do |f|
|
35
|
+
client_opts[f] = File.expand_path(client_opts[f]) if client_opts[f]
|
36
|
+
end
|
37
|
+
logger.debug("Creating orchestrator client for #{client_opts}")
|
38
|
+
@client = OrchestratorClient.new(client_opts, true)
|
39
|
+
@plan_context = plan_context
|
40
|
+
@plan_job = start_plan(@plan_context)
|
41
|
+
logger.debug("Started plan #{@plan_job}")
|
42
|
+
@environment = opts["task-environment"]
|
43
|
+
end
|
44
|
+
|
45
|
+
def start_plan(plan_context)
|
46
|
+
if plan_context
|
47
|
+
begin
|
48
|
+
opts = plan_context.select { |k, _| CONTEXT_KEYS.include? k }
|
49
|
+
opts[:params] = opts[:params].reject { |k, _| plan_context[:sensitive].include?(k) }
|
50
|
+
@client.command.plan_start(opts)['name']
|
51
|
+
rescue OrchestratorClient::ApiError => e
|
52
|
+
if e.code == '404'
|
53
|
+
@logger.debug("Orchestrator #{key} does not support plans")
|
54
|
+
else
|
55
|
+
@logger.error("Failed to start a plan with orchestrator #{key}: #{e.message}")
|
56
|
+
end
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def finish_plan(plan_result)
|
63
|
+
if @plan_job
|
64
|
+
@client.command.plan_finish(
|
65
|
+
plan_job: @plan_job,
|
66
|
+
result: plan_result.value || '',
|
67
|
+
status: plan_result.status
|
68
|
+
)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_certnames(targets)
|
73
|
+
targets.map { |t| t.host || t.name }
|
74
|
+
end
|
75
|
+
|
76
|
+
def build_request(targets, task, arguments, description = nil)
|
77
|
+
body = { task: task.name,
|
78
|
+
environment: @environment,
|
79
|
+
noop: arguments['_noop'],
|
80
|
+
params: arguments.reject { |k, _| k.start_with?('_') },
|
81
|
+
scope: {
|
82
|
+
nodes: get_certnames(targets)
|
83
|
+
} }
|
84
|
+
body[:description] = description if description
|
85
|
+
body[:plan_job] = @plan_job if @plan_job
|
86
|
+
body
|
87
|
+
end
|
88
|
+
|
89
|
+
def run_task(targets, task, arguments, options)
|
90
|
+
body = build_request(targets, task, arguments, options[:description])
|
91
|
+
@client.run_task(body)
|
92
|
+
rescue OrchestratorClient::ApiError => e
|
93
|
+
if e.data['kind'] == 'puppetlabs.orchestrator/plan-already-finished'
|
94
|
+
@logger.debug("Retrying the task")
|
95
|
+
# Instead of recursing, just retry once
|
96
|
+
@plan_job = start_plan(@plan_context)
|
97
|
+
# Rebuild the request with the new plan job ID
|
98
|
+
body = build_request(targets, task, arguments, options[:description])
|
99
|
+
@client.run_task(body)
|
100
|
+
else
|
101
|
+
raise e
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def query_inventory(targets)
|
106
|
+
@client.post('inventory', nodes: get_certnames(targets))
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|