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
data/lib/bolt/module.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Is this Bolt::Pobs::Module?
|
4
|
+
module Bolt
|
5
|
+
class Module
|
6
|
+
CONTENT_NAME_REGEX = /\A[a-z][a-z0-9_]*(::[a-z][a-z0-9_]*)*\z/.freeze
|
7
|
+
MODULE_NAME_REGEX = /\A[a-z][a-z0-9_]*\z/.freeze
|
8
|
+
|
9
|
+
def self.discover(modulepath, project)
|
10
|
+
mods = {}
|
11
|
+
|
12
|
+
if project.load_as_module?
|
13
|
+
mods[project.name] = Bolt::Module.new(project.name, project.path.to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
modulepath.each do |path|
|
17
|
+
next unless File.exist?(path) && File.directory?(path)
|
18
|
+
Dir.children(path)
|
19
|
+
.map { |dir| File.join(path, dir) }
|
20
|
+
.select { |dir| File.directory?(dir) }
|
21
|
+
.each do |dir|
|
22
|
+
module_name = File.basename(dir)
|
23
|
+
if module_name =~ MODULE_NAME_REGEX
|
24
|
+
# Puppet will load some objects from shadowed modules but this won't
|
25
|
+
mods[module_name] ||= Bolt::Module.new(module_name, dir)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
mods
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :name, :path
|
34
|
+
|
35
|
+
def initialize(name, path)
|
36
|
+
@name = name
|
37
|
+
@path = path
|
38
|
+
end
|
39
|
+
|
40
|
+
def plugin_data_file
|
41
|
+
File.join(path, 'bolt_plugin.json')
|
42
|
+
end
|
43
|
+
|
44
|
+
def plugin?
|
45
|
+
if File.exist?(File.join(path, 'bolt-plugin.json'))
|
46
|
+
msg = "Found bolt-plugin.json in module #{name} at #{path}. Bolt looks for " \
|
47
|
+
"bolt_plugin.json to determine if the module contains plugins. " \
|
48
|
+
"Rename the file for Bolt to recognize it."
|
49
|
+
Bolt::Logger.warn_once('plugin_file_name', msg)
|
50
|
+
end
|
51
|
+
File.exist?(plugin_data_file)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../bolt/r10k_log_proxy'
|
4
|
+
require_relative '../../bolt/error'
|
5
|
+
|
6
|
+
# This class is used to install modules from a Puppetfile to a module directory.
|
7
|
+
#
|
8
|
+
module Bolt
|
9
|
+
class ModuleInstaller
|
10
|
+
class Installer
|
11
|
+
def initialize(config = {})
|
12
|
+
@config = config
|
13
|
+
end
|
14
|
+
|
15
|
+
def install(path, moduledir)
|
16
|
+
require 'r10k/cli'
|
17
|
+
|
18
|
+
unless File.exist?(path)
|
19
|
+
raise Bolt::FileError.new(
|
20
|
+
"Could not find a Puppetfile at #{path}",
|
21
|
+
path
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
r10k_opts = {
|
26
|
+
root: File.dirname(path),
|
27
|
+
puppetfile: path.to_s,
|
28
|
+
moduledir: moduledir.to_s
|
29
|
+
}
|
30
|
+
|
31
|
+
settings = R10K::Settings.global_settings.evaluate(@config)
|
32
|
+
R10K::Initializers::GlobalInitializer.new(settings).call
|
33
|
+
install_action = R10K::Action::Puppetfile::Install.new(r10k_opts, nil, {})
|
34
|
+
|
35
|
+
# Override the r10k logger with a proxy to our own logger
|
36
|
+
R10K::Logging.instance_variable_set(:@outputter, Bolt::R10KLogProxy.new)
|
37
|
+
|
38
|
+
install_action.call
|
39
|
+
rescue R10K::Error => e
|
40
|
+
raise PuppetfileError, e
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'semantic_puppet'
|
4
|
+
require_relative '../../../bolt/module_installer/puppetfile/module'
|
5
|
+
|
6
|
+
# This class represents a resolved Forge module.
|
7
|
+
#
|
8
|
+
module Bolt
|
9
|
+
class ModuleInstaller
|
10
|
+
class Puppetfile
|
11
|
+
class ForgeModule < Module
|
12
|
+
attr_reader :version
|
13
|
+
|
14
|
+
def initialize(name, version)
|
15
|
+
super(name)
|
16
|
+
@version = parse_version(version)
|
17
|
+
@type = :forge
|
18
|
+
end
|
19
|
+
|
20
|
+
# Parses the version into a Semantic Puppet version.
|
21
|
+
#
|
22
|
+
private def parse_version(version)
|
23
|
+
return unless version.is_a?(String)
|
24
|
+
|
25
|
+
unless SemanticPuppet::Version.valid?(version)
|
26
|
+
raise Bolt::ValidationError,
|
27
|
+
"Invalid version for Forge module #{@full_name}: #{version.inspect}"
|
28
|
+
end
|
29
|
+
|
30
|
+
SemanticPuppet::Version.parse(version)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns a Puppetfile module specification.
|
34
|
+
#
|
35
|
+
def to_spec
|
36
|
+
if @version
|
37
|
+
"mod '#{@full_name}', '#{@version}'"
|
38
|
+
else
|
39
|
+
"mod '#{@full_name}'"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns a hash that can be used to create a module specification.
|
44
|
+
#
|
45
|
+
def to_hash
|
46
|
+
{
|
47
|
+
'name' => @full_name,
|
48
|
+
'version_requirement' => @version ? @version.to_s : nil
|
49
|
+
}.compact
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../bolt/module_installer/puppetfile/module'
|
4
|
+
|
5
|
+
# This class represents a resolved Git module.
|
6
|
+
#
|
7
|
+
module Bolt
|
8
|
+
class ModuleInstaller
|
9
|
+
class Puppetfile
|
10
|
+
class GitModule < Module
|
11
|
+
attr_reader :git, :ref
|
12
|
+
|
13
|
+
def initialize(name, git, ref)
|
14
|
+
super(name)
|
15
|
+
@git = git
|
16
|
+
@ref = ref
|
17
|
+
@type = :git
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns a Puppetfile module specification.
|
21
|
+
#
|
22
|
+
def to_spec
|
23
|
+
"mod '#{@name}',\n git: '#{@git}',\n ref: '#{@ref}'"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns a hash that can be used to create a module specification.
|
27
|
+
#
|
28
|
+
def to_hash
|
29
|
+
{
|
30
|
+
'git' => @git,
|
31
|
+
'ref' => @ref
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../bolt/error'
|
4
|
+
|
5
|
+
module Bolt
|
6
|
+
class ModuleInstaller
|
7
|
+
class Puppetfile
|
8
|
+
class Module
|
9
|
+
attr_reader :full_name, :name, :type
|
10
|
+
|
11
|
+
def initialize(name)
|
12
|
+
@full_name, @name = parse_name(name)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Formats the full name and extracts the module name.
|
16
|
+
#
|
17
|
+
protected def parse_name(name)
|
18
|
+
full_name = name.tr('-', '/')
|
19
|
+
first, second = full_name.split('/', 2)
|
20
|
+
|
21
|
+
[full_name, second || first]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../bolt/error'
|
4
|
+
require_relative 'puppetfile/forge_module'
|
5
|
+
require_relative 'puppetfile/git_module'
|
6
|
+
|
7
|
+
# This class manages the logical contents of a Puppetfile. It includes methods
|
8
|
+
# for parsing and generating a Puppetfile.
|
9
|
+
#
|
10
|
+
module Bolt
|
11
|
+
class ModuleInstaller
|
12
|
+
class Puppetfile
|
13
|
+
attr_reader :modules
|
14
|
+
|
15
|
+
def initialize(modules = [])
|
16
|
+
@modules = modules
|
17
|
+
end
|
18
|
+
|
19
|
+
# Loads a Puppetfile and parses its modules.
|
20
|
+
#
|
21
|
+
def self.parse(path, skip_unsupported_modules: false)
|
22
|
+
require 'puppetfile-resolver'
|
23
|
+
|
24
|
+
return new unless path.exist?
|
25
|
+
|
26
|
+
begin
|
27
|
+
parsed = ::PuppetfileResolver::Puppetfile::Parser::R10KEval.parse(File.read(path))
|
28
|
+
rescue StandardError => e
|
29
|
+
raise Bolt::Error.new(
|
30
|
+
"Unable to parse Puppetfile #{path}: #{e.message}",
|
31
|
+
'bolt/puppetfile-parsing'
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
unless parsed.valid?
|
36
|
+
raise Bolt::ValidationError, <<~MSG
|
37
|
+
Unable to parse Puppetfile #{path}:
|
38
|
+
#{parsed.validation_errors.join("\n\n")}.
|
39
|
+
This Puppetfile might not be managed by Bolt.
|
40
|
+
MSG
|
41
|
+
end
|
42
|
+
|
43
|
+
modules = parsed.modules.each_with_object([]) do |mod, acc|
|
44
|
+
case mod.module_type
|
45
|
+
when :forge
|
46
|
+
acc << ForgeModule.new(
|
47
|
+
mod.title,
|
48
|
+
mod.version.is_a?(String) ? mod.version[1..-1] : nil
|
49
|
+
)
|
50
|
+
when :git
|
51
|
+
acc << GitModule.new(
|
52
|
+
mod.name,
|
53
|
+
mod.remote,
|
54
|
+
mod.ref || mod.commit || mod.tag
|
55
|
+
)
|
56
|
+
else
|
57
|
+
unless skip_unsupported_modules
|
58
|
+
raise Bolt::ValidationError,
|
59
|
+
"Cannot parse Puppetfile at #{path}, module '#{mod.title}' is not a "\
|
60
|
+
"Puppet Forge or Git module."
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
new(modules)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Writes a Puppetfile that includes specifications for each of the
|
69
|
+
# modules.
|
70
|
+
#
|
71
|
+
def write(path, moduledir = nil)
|
72
|
+
File.open(path, 'w') do |file|
|
73
|
+
if moduledir
|
74
|
+
file.puts "# This Puppetfile is managed by Bolt. Do not edit."
|
75
|
+
file.puts "# For more information, see https://pup.pt/bolt-modules"
|
76
|
+
file.puts
|
77
|
+
file.puts "# The following directive installs modules to the managed moduledir."
|
78
|
+
file.puts "moduledir '#{moduledir.basename}'"
|
79
|
+
file.puts
|
80
|
+
end
|
81
|
+
|
82
|
+
@modules.each { |mod| file.puts mod.to_spec }
|
83
|
+
end
|
84
|
+
rescue SystemCallError => e
|
85
|
+
raise Bolt::FileError.new(
|
86
|
+
"#{e.message}: unable to write Puppetfile.",
|
87
|
+
path
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Asserts that the Puppetfile satisfies the given specifications.
|
92
|
+
#
|
93
|
+
def assert_satisfies(specs)
|
94
|
+
unsatisfied_specs = specs.specs.reject do |spec|
|
95
|
+
@modules.any? do |mod|
|
96
|
+
spec.satisfied_by?(mod)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
versionless_mods = @modules.select { |mod| mod.is_a?(ForgeModule) && mod.version.nil? }
|
101
|
+
command = Bolt::Util.windows? ? 'Install-BoltModule -Force' : 'bolt module install --force'
|
102
|
+
|
103
|
+
if unsatisfied_specs.any?
|
104
|
+
message = <<~MESSAGE.chomp
|
105
|
+
Puppetfile does not include modules that satisfy the following specifications:
|
106
|
+
|
107
|
+
#{unsatisfied_specs.map(&:to_hash).to_yaml.lines.drop(1).join.chomp}
|
108
|
+
|
109
|
+
This Puppetfile might not be managed by Bolt. To forcibly overwrite the
|
110
|
+
Puppetfile, run '#{command}'.
|
111
|
+
MESSAGE
|
112
|
+
|
113
|
+
raise Bolt::Error.new(message, 'bolt/missing-module-specs')
|
114
|
+
end
|
115
|
+
|
116
|
+
if versionless_mods.any?
|
117
|
+
message = <<~MESSAGE.chomp
|
118
|
+
Puppetfile includes Forge modules without a version requirement:
|
119
|
+
|
120
|
+
#{versionless_mods.map(&:to_spec).join.chomp}
|
121
|
+
|
122
|
+
This Puppetfile might not be managed by Bolt. To forcibly overwrite the
|
123
|
+
Puppetfile, run '#{command}'.
|
124
|
+
MESSAGE
|
125
|
+
|
126
|
+
raise Bolt::Error.new(message, 'bolt/missing-module-version-specs')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../bolt/error'
|
4
|
+
require_relative '../../bolt/module_installer/puppetfile'
|
5
|
+
require_relative '../../bolt/module_installer/specs'
|
6
|
+
|
7
|
+
module Bolt
|
8
|
+
class ModuleInstaller
|
9
|
+
class Resolver
|
10
|
+
# Resolves module specs and returns a Puppetfile object.
|
11
|
+
#
|
12
|
+
def resolve(specs, config = {})
|
13
|
+
require 'puppetfile-resolver'
|
14
|
+
|
15
|
+
# Build the document model from the specs.
|
16
|
+
document = PuppetfileResolver::Puppetfile::Document.new('')
|
17
|
+
unresolved = []
|
18
|
+
|
19
|
+
specs.specs.each do |spec|
|
20
|
+
if spec.resolve
|
21
|
+
document.add_module(spec.to_resolver_module)
|
22
|
+
else
|
23
|
+
unresolved << spec
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Make sure the document model is valid.
|
28
|
+
unless document.valid?
|
29
|
+
message = <<~MESSAGE.chomp
|
30
|
+
Unable to resolve module specifications:
|
31
|
+
|
32
|
+
#{document.validation_errors.map(&:message).join("\n")}
|
33
|
+
MESSAGE
|
34
|
+
|
35
|
+
raise Bolt::Error.new(message, 'bolt/module-resolver-error')
|
36
|
+
end
|
37
|
+
|
38
|
+
# Create the resolver using the Puppetfile model. nil disables Puppet
|
39
|
+
# version restrictions.
|
40
|
+
resolver = PuppetfileResolver::Resolver.new(document, nil)
|
41
|
+
|
42
|
+
# Configure and resolve the dependency graph, catching any errors
|
43
|
+
# raised by puppetfile-resolver and re-raising them as Bolt errors.
|
44
|
+
begin
|
45
|
+
result = resolver.resolve(
|
46
|
+
cache: nil,
|
47
|
+
ui: nil,
|
48
|
+
allow_missing_modules: false,
|
49
|
+
spec_searcher_configuration: spec_searcher_config(config)
|
50
|
+
)
|
51
|
+
rescue StandardError => e
|
52
|
+
raise Bolt::Error.new("Unable to resolve modules: #{e.message}", 'bolt/module-resolver-error')
|
53
|
+
end
|
54
|
+
|
55
|
+
# Create the Puppetfile object.
|
56
|
+
generate_puppetfile(specs, result.specifications.values, unresolved)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Creates a puppetfile-resolver config object.
|
60
|
+
#
|
61
|
+
private def spec_searcher_config(config)
|
62
|
+
PuppetfileResolver::SpecSearchers::Configuration.new.tap do |obj|
|
63
|
+
obj.forge.proxy = config.dig('forge', 'proxy') || config.dig('proxy')
|
64
|
+
obj.git.proxy = config.dig('proxy')
|
65
|
+
obj.forge.forge_api = config.dig('forge', 'baseurl')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Creates a Puppetfile object with Module objects created from resolved and
|
70
|
+
# unresolved specs.
|
71
|
+
#
|
72
|
+
private def generate_puppetfile(specs, resolved, unresolved)
|
73
|
+
modules = []
|
74
|
+
|
75
|
+
# Convert the resolved specs into Bolt module objects.
|
76
|
+
resolved.each do |mod|
|
77
|
+
# Skip over anything that isn't a module spec, such as a Puppet spec.
|
78
|
+
next unless mod.is_a? PuppetfileResolver::Models::ModuleSpecification
|
79
|
+
|
80
|
+
case mod.origin
|
81
|
+
when :forge
|
82
|
+
modules << Bolt::ModuleInstaller::Puppetfile::ForgeModule.new(
|
83
|
+
"#{mod.owner}/#{mod.name}",
|
84
|
+
mod.version.to_s
|
85
|
+
)
|
86
|
+
when :git
|
87
|
+
spec = specs.specs.find { |s| s.name == mod.name }
|
88
|
+
modules << Bolt::ModuleInstaller::Puppetfile::GitModule.new(
|
89
|
+
spec.name,
|
90
|
+
spec.git,
|
91
|
+
spec.sha
|
92
|
+
)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Error if there are any name conflicts between unresolved specs and
|
97
|
+
# resolved modules. r10k will error if a Puppetfile includes duplicate
|
98
|
+
# names, but we error early here to provide a more helpful message.
|
99
|
+
if (name_conflicts = modules.map(&:name) & unresolved.map(&:name)).any?
|
100
|
+
raise Bolt::Error.new(
|
101
|
+
"Detected unresolved module specifications with the same name as a resolved module "\
|
102
|
+
"dependency: #{name_conflicts.join(', ')}. Either remove the unresolved module specification "\
|
103
|
+
"or set the module with the conflicting dependency to not resolve.",
|
104
|
+
"bolt/module-name-conflict-error"
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Convert the unresolved specs into Bolt module objects.
|
109
|
+
unresolved.each do |spec|
|
110
|
+
case spec.type
|
111
|
+
when :forge
|
112
|
+
modules << Bolt::ModuleInstaller::Puppetfile::ForgeModule.new(
|
113
|
+
spec.full_name,
|
114
|
+
spec.version_requirement
|
115
|
+
)
|
116
|
+
when :git
|
117
|
+
modules << Bolt::ModuleInstaller::Puppetfile::GitModule.new(
|
118
|
+
spec.name,
|
119
|
+
spec.git,
|
120
|
+
spec.ref
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
Bolt::ModuleInstaller::Puppetfile.new(modules)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'semantic_puppet'
|
4
|
+
require 'set'
|
5
|
+
|
6
|
+
require_relative '../../../bolt/error'
|
7
|
+
|
8
|
+
# This class represents a Forge module specification.
|
9
|
+
#
|
10
|
+
module Bolt
|
11
|
+
class ModuleInstaller
|
12
|
+
class Specs
|
13
|
+
class ForgeSpec
|
14
|
+
NAME_REGEX = %r{\A[a-zA-Z0-9]+[-/](?<name>[a-z][a-z0-9_]*)\z}.freeze
|
15
|
+
REQUIRED_KEYS = Set.new(%w[name]).freeze
|
16
|
+
KNOWN_KEYS = Set.new(%w[name resolve version_requirement]).freeze
|
17
|
+
|
18
|
+
attr_reader :full_name, :name, :resolve, :semantic_version, :type, :version_requirement
|
19
|
+
|
20
|
+
def initialize(init_hash)
|
21
|
+
@resolve = init_hash.key?('resolve') ? init_hash['resolve'] : true
|
22
|
+
@full_name, @name = parse_name(init_hash['name'])
|
23
|
+
@version_requirement, @semantic_version = parse_version_requirement(init_hash['version_requirement'])
|
24
|
+
@type = :forge
|
25
|
+
|
26
|
+
unless @resolve == true || @resolve == false
|
27
|
+
raise Bolt::ValidationError,
|
28
|
+
"Option 'resolve' for module spec #{@full_name} must be a Boolean"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.implements?(hash)
|
33
|
+
KNOWN_KEYS.superset?(hash.keys.to_set) && REQUIRED_KEYS.subset?(hash.keys.to_set)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Formats the full name and extracts the module name.
|
37
|
+
#
|
38
|
+
private def parse_name(name)
|
39
|
+
unless (match = name.match(NAME_REGEX))
|
40
|
+
raise Bolt::ValidationError,
|
41
|
+
"Invalid name for Forge module specification: #{name}. Name must match "\
|
42
|
+
"'owner/name'. Owner segment can only include letters or digits. Name "\
|
43
|
+
"segment must start with a lowercase letter and can only include lowercase "\
|
44
|
+
"letters, digits, and underscores."
|
45
|
+
end
|
46
|
+
|
47
|
+
[name.tr('-', '/'), match[:name]]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Parses the version into a Semantic Puppet version range.
|
51
|
+
#
|
52
|
+
private def parse_version_requirement(version_requirement)
|
53
|
+
[version_requirement, SemanticPuppet::VersionRange.parse(version_requirement || '>= 0')]
|
54
|
+
rescue StandardError
|
55
|
+
raise Bolt::ValidationError,
|
56
|
+
"Invalid version requirement for Forge module specification #{@full_name}: "\
|
57
|
+
"#{version_requirement.inspect}"
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns true if the specification is satisfied by the module.
|
61
|
+
#
|
62
|
+
def satisfied_by?(mod)
|
63
|
+
@type == mod.type &&
|
64
|
+
@full_name.downcase == mod.full_name.downcase &&
|
65
|
+
!mod.version.nil? &&
|
66
|
+
@semantic_version.cover?(mod.version)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns a hash matching the module spec in bolt-project.yaml
|
70
|
+
#
|
71
|
+
def to_hash
|
72
|
+
{
|
73
|
+
'name' => @full_name,
|
74
|
+
'version_requirement' => @version_requirement
|
75
|
+
}.compact
|
76
|
+
end
|
77
|
+
|
78
|
+
# Creates a PuppetfileResolver::Puppetfile::ForgeModule object, which is
|
79
|
+
# used to generate a graph of resolved modules.
|
80
|
+
#
|
81
|
+
def to_resolver_module
|
82
|
+
require 'puppetfile-resolver'
|
83
|
+
|
84
|
+
PuppetfileResolver::Puppetfile::ForgeModule.new(@full_name).tap do |mod|
|
85
|
+
mod.version = @version_requirement
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|