krates 1.6.0
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/LICENSE +212 -0
- data/LOGO +10 -0
- data/VERSION +1 -0
- data/bin/krates +23 -0
- data/lib/kontena/autoload_core.rb +19 -0
- data/lib/kontena/callback.rb +60 -0
- data/lib/kontena/callbacks/.gitkeep +0 -0
- data/lib/kontena/callbacks/auth/01_list_and_select_grid_after_master_auth.rb +26 -0
- data/lib/kontena/callbacks/master/01_clear_current_master_after_terminate.rb +19 -0
- data/lib/kontena/callbacks/master/deploy/01_show_logo_before_deploy.rb +14 -0
- data/lib/kontena/callbacks/master/deploy/04_default_master_version.rb +18 -0
- data/lib/kontena/callbacks/master/deploy/05_before_deploy_configuration_wizard.rb +105 -0
- data/lib/kontena/callbacks/master/deploy/40_install_ssl_certificate_after_deploy.rb +32 -0
- data/lib/kontena/callbacks/master/deploy/50_authenticate_after_deploy.rb +66 -0
- data/lib/kontena/callbacks/master/deploy/55_create_initial_grid_after_deploy.rb +21 -0
- data/lib/kontena/callbacks/master/deploy/56_set_server_provider_after_deploy.rb +24 -0
- data/lib/kontena/callbacks/master/deploy/60_configure_auth_provider_after_deploy.rb +31 -0
- data/lib/kontena/callbacks/master/deploy/70_invite_self_after_deploy.rb +95 -0
- data/lib/kontena/callbacks/master/deploy/90_proptip_after_deploy.rb +33 -0
- data/lib/kontena/cli/browser_launcher.rb +61 -0
- data/lib/kontena/cli/bytes_helper.rb +40 -0
- data/lib/kontena/cli/certificate/authorize_command.rb +107 -0
- data/lib/kontena/cli/certificate/common.rb +16 -0
- data/lib/kontena/cli/certificate/domain_authorization/list_command.rb +24 -0
- data/lib/kontena/cli/certificate/domain_authorization/remove_authorization_command.rb +25 -0
- data/lib/kontena/cli/certificate/domain_authorize_command.rb +7 -0
- data/lib/kontena/cli/certificate/export_command.rb +28 -0
- data/lib/kontena/cli/certificate/get_command.rb +33 -0
- data/lib/kontena/cli/certificate/import_command.rb +61 -0
- data/lib/kontena/cli/certificate/list_command.rb +75 -0
- data/lib/kontena/cli/certificate/register_command.rb +30 -0
- data/lib/kontena/cli/certificate/remove_command.rb +23 -0
- data/lib/kontena/cli/certificate/request_command.rb +20 -0
- data/lib/kontena/cli/certificate/show_command.rb +22 -0
- data/lib/kontena/cli/certificate_command.rb +18 -0
- data/lib/kontena/cli/cloud/login_command.rb +186 -0
- data/lib/kontena/cli/cloud/logout_command.rb +14 -0
- data/lib/kontena/cli/cloud/master/add_command.rb +156 -0
- data/lib/kontena/cli/cloud/master/list_command.rb +35 -0
- data/lib/kontena/cli/cloud/master/remove_command.rb +68 -0
- data/lib/kontena/cli/cloud/master/show_command.rb +21 -0
- data/lib/kontena/cli/cloud/master/update_command.rb +52 -0
- data/lib/kontena/cli/cloud/master_command.rb +14 -0
- data/lib/kontena/cli/cloud_command.rb +13 -0
- data/lib/kontena/cli/common.rb +360 -0
- data/lib/kontena/cli/config.rb +662 -0
- data/lib/kontena/cli/container_command.rb +10 -0
- data/lib/kontena/cli/containers/exec_command.rb +31 -0
- data/lib/kontena/cli/containers/inspect_command.rb +16 -0
- data/lib/kontena/cli/containers/list_command.rb +51 -0
- data/lib/kontena/cli/containers/logs_command.rb +19 -0
- data/lib/kontena/cli/etcd/common.rb +8 -0
- data/lib/kontena/cli/etcd/get_command.rb +26 -0
- data/lib/kontena/cli/etcd/health_command.rb +53 -0
- data/lib/kontena/cli/etcd/list_command.rb +36 -0
- data/lib/kontena/cli/etcd/mkdir_command.rb +23 -0
- data/lib/kontena/cli/etcd/remove_command.rb +29 -0
- data/lib/kontena/cli/etcd/set_command.rb +24 -0
- data/lib/kontena/cli/etcd_command.rb +12 -0
- data/lib/kontena/cli/external_registries/add_command.rb +25 -0
- data/lib/kontena/cli/external_registries/list_command.rb +23 -0
- data/lib/kontena/cli/external_registries/remove_command.rb +17 -0
- data/lib/kontena/cli/external_registry_command.rb +9 -0
- data/lib/kontena/cli/grid_command.rb +21 -0
- data/lib/kontena/cli/grid_options.rb +12 -0
- data/lib/kontena/cli/grids/audit_log_command.rb +22 -0
- data/lib/kontena/cli/grids/cloud_config_command.rb +53 -0
- data/lib/kontena/cli/grids/common.rb +182 -0
- data/lib/kontena/cli/grids/create_command.rb +48 -0
- data/lib/kontena/cli/grids/current_command.rb +25 -0
- data/lib/kontena/cli/grids/env_command.rb +32 -0
- data/lib/kontena/cli/grids/events_command.rb +50 -0
- data/lib/kontena/cli/grids/health_command.rb +69 -0
- data/lib/kontena/cli/grids/list_command.rb +59 -0
- data/lib/kontena/cli/grids/logs_command.rb +35 -0
- data/lib/kontena/cli/grids/remove_command.rb +31 -0
- data/lib/kontena/cli/grids/show_command.rb +25 -0
- data/lib/kontena/cli/grids/trusted_subnet_command.rb +10 -0
- data/lib/kontena/cli/grids/trusted_subnets/add_command.rb +18 -0
- data/lib/kontena/cli/grids/trusted_subnets/list_command.rb +18 -0
- data/lib/kontena/cli/grids/trusted_subnets/remove_command.rb +26 -0
- data/lib/kontena/cli/grids/update_command.rb +35 -0
- data/lib/kontena/cli/grids/use_command.rb +26 -0
- data/lib/kontena/cli/grids/user_command.rb +9 -0
- data/lib/kontena/cli/grids/users/add_command.rb +18 -0
- data/lib/kontena/cli/grids/users/list_command.rb +20 -0
- data/lib/kontena/cli/grids/users/remove_command.rb +20 -0
- data/lib/kontena/cli/helpers/exec_helper.rb +209 -0
- data/lib/kontena/cli/helpers/health_helper.rb +65 -0
- data/lib/kontena/cli/helpers/log_helper.rb +113 -0
- data/lib/kontena/cli/helpers/time_helper.rb +29 -0
- data/lib/kontena/cli/localhost_web_server.rb +113 -0
- data/lib/kontena/cli/log_formatters/compact.rb +65 -0
- data/lib/kontena/cli/log_formatters/strip_color.rb +13 -0
- data/lib/kontena/cli/logout_command.rb +10 -0
- data/lib/kontena/cli/master/audit_log_command.rb +19 -0
- data/lib/kontena/cli/master/config/export_command.rb +46 -0
- data/lib/kontena/cli/master/config/get_command.rb +26 -0
- data/lib/kontena/cli/master/config/import_command.rb +67 -0
- data/lib/kontena/cli/master/config/set_command.rb +19 -0
- data/lib/kontena/cli/master/config/unset_command.rb +20 -0
- data/lib/kontena/cli/master/config_command.rb +17 -0
- data/lib/kontena/cli/master/create_command.rb +74 -0
- data/lib/kontena/cli/master/current_command.rb +25 -0
- data/lib/kontena/cli/master/init_cloud_command.rb +45 -0
- data/lib/kontena/cli/master/join_command.rb +22 -0
- data/lib/kontena/cli/master/list_command.rb +24 -0
- data/lib/kontena/cli/master/login_command.rb +331 -0
- data/lib/kontena/cli/master/logout_command.rb +25 -0
- data/lib/kontena/cli/master/remove_command.rb +55 -0
- data/lib/kontena/cli/master/ssh_command.rb +72 -0
- data/lib/kontena/cli/master/token/common.rb +29 -0
- data/lib/kontena/cli/master/token/create_command.rb +50 -0
- data/lib/kontena/cli/master/token/current_command.rb +45 -0
- data/lib/kontena/cli/master/token/list_command.rb +39 -0
- data/lib/kontena/cli/master/token/remove_command.rb +19 -0
- data/lib/kontena/cli/master/token/show_command.rb +34 -0
- data/lib/kontena/cli/master/token_command.rb +13 -0
- data/lib/kontena/cli/master/use_command.rb +31 -0
- data/lib/kontena/cli/master/user/invite_command.rb +51 -0
- data/lib/kontena/cli/master/user/list_command.rb +29 -0
- data/lib/kontena/cli/master/user/remove_command.rb +24 -0
- data/lib/kontena/cli/master/user/role/add_command.rb +29 -0
- data/lib/kontena/cli/master/user/role/remove_command.rb +27 -0
- data/lib/kontena/cli/master/user/role_command.rb +6 -0
- data/lib/kontena/cli/master/user_command.rb +9 -0
- data/lib/kontena/cli/master_command.rb +21 -0
- data/lib/kontena/cli/node_command.rb +17 -0
- data/lib/kontena/cli/nodes/create_command.rb +25 -0
- data/lib/kontena/cli/nodes/env_command.rb +37 -0
- data/lib/kontena/cli/nodes/health_command.rb +47 -0
- data/lib/kontena/cli/nodes/label_command.rb +10 -0
- data/lib/kontena/cli/nodes/labels/add_command.rb +18 -0
- data/lib/kontena/cli/nodes/labels/list_command.rb +19 -0
- data/lib/kontena/cli/nodes/labels/remove_command.rb +32 -0
- data/lib/kontena/cli/nodes/list_command.rb +97 -0
- data/lib/kontena/cli/nodes/remove_command.rb +34 -0
- data/lib/kontena/cli/nodes/reset_token_command.rb +34 -0
- data/lib/kontena/cli/nodes/show_command.rb +56 -0
- data/lib/kontena/cli/nodes/ssh_command.rb +63 -0
- data/lib/kontena/cli/nodes/update_command.rb +31 -0
- data/lib/kontena/cli/plugin_command.rb +12 -0
- data/lib/kontena/cli/plugins/common.rb +8 -0
- data/lib/kontena/cli/plugins/install_command.rb +42 -0
- data/lib/kontena/cli/plugins/list_command.rb +31 -0
- data/lib/kontena/cli/plugins/search_command.rb +25 -0
- data/lib/kontena/cli/plugins/show_command.rb +17 -0
- data/lib/kontena/cli/plugins/uninstall_command.rb +31 -0
- data/lib/kontena/cli/plugins/upgrade_command.rb +60 -0
- data/lib/kontena/cli/registry/create_command.rb +151 -0
- data/lib/kontena/cli/registry/remove_command.rb +21 -0
- data/lib/kontena/cli/registry_command.rb +8 -0
- data/lib/kontena/cli/service_command.rb +28 -0
- data/lib/kontena/cli/services/container_command.rb +8 -0
- data/lib/kontena/cli/services/containers_command.rb +39 -0
- data/lib/kontena/cli/services/create_command.rb +105 -0
- data/lib/kontena/cli/services/deploy_command.rb +25 -0
- data/lib/kontena/cli/services/env_command.rb +9 -0
- data/lib/kontena/cli/services/envs/add_command.rb +21 -0
- data/lib/kontena/cli/services/envs/list_command.rb +22 -0
- data/lib/kontena/cli/services/envs/remove_command.rb +22 -0
- data/lib/kontena/cli/services/events_command.rb +36 -0
- data/lib/kontena/cli/services/exec_command.rb +107 -0
- data/lib/kontena/cli/services/link_command.rb +35 -0
- data/lib/kontena/cli/services/list_command.rb +66 -0
- data/lib/kontena/cli/services/logs_command.rb +33 -0
- data/lib/kontena/cli/services/monitor_command.rb +58 -0
- data/lib/kontena/cli/services/remove_command.rb +60 -0
- data/lib/kontena/cli/services/restart_command.rb +19 -0
- data/lib/kontena/cli/services/scale_command.rb +21 -0
- data/lib/kontena/cli/services/secret_command.rb +8 -0
- data/lib/kontena/cli/services/secrets/link_command.rb +26 -0
- data/lib/kontena/cli/services/secrets/unlink_command.rb +28 -0
- data/lib/kontena/cli/services/services_helper.rb +579 -0
- data/lib/kontena/cli/services/show_command.rb +26 -0
- data/lib/kontena/cli/services/start_command.rb +21 -0
- data/lib/kontena/cli/services/stats_command.rb +87 -0
- data/lib/kontena/cli/services/stop_command.rb +21 -0
- data/lib/kontena/cli/services/unlink_command.rb +30 -0
- data/lib/kontena/cli/services/update_command.rb +94 -0
- data/lib/kontena/cli/spinner.rb +205 -0
- data/lib/kontena/cli/stack_command.rb +21 -0
- data/lib/kontena/cli/stacks/build_command.rb +125 -0
- data/lib/kontena/cli/stacks/common.rb +209 -0
- data/lib/kontena/cli/stacks/deploy_command.rb +37 -0
- data/lib/kontena/cli/stacks/events_command.rb +33 -0
- data/lib/kontena/cli/stacks/inspect_command.rb +17 -0
- data/lib/kontena/cli/stacks/install_command.rb +95 -0
- data/lib/kontena/cli/stacks/label_command.rb +10 -0
- data/lib/kontena/cli/stacks/labels/add_command.rb +21 -0
- data/lib/kontena/cli/stacks/labels/common.rb +19 -0
- data/lib/kontena/cli/stacks/labels/list_command.rb +21 -0
- data/lib/kontena/cli/stacks/labels/remove_command.rb +21 -0
- data/lib/kontena/cli/stacks/list_command.rb +154 -0
- data/lib/kontena/cli/stacks/logs_command.rb +35 -0
- data/lib/kontena/cli/stacks/monitor_command.rb +93 -0
- data/lib/kontena/cli/stacks/registry/create_command.rb +24 -0
- data/lib/kontena/cli/stacks/registry/make_private_command.rb +24 -0
- data/lib/kontena/cli/stacks/registry/make_public_command.rb +24 -0
- data/lib/kontena/cli/stacks/registry/pull_command.rb +28 -0
- data/lib/kontena/cli/stacks/registry/push_command.rb +40 -0
- data/lib/kontena/cli/stacks/registry/remove_command.rb +30 -0
- data/lib/kontena/cli/stacks/registry/search_command.rb +42 -0
- data/lib/kontena/cli/stacks/registry/show_command.rb +65 -0
- data/lib/kontena/cli/stacks/registry_command.rb +12 -0
- data/lib/kontena/cli/stacks/remove_command.rb +80 -0
- data/lib/kontena/cli/stacks/restart_command.rb +24 -0
- data/lib/kontena/cli/stacks/service_generator.rb +131 -0
- data/lib/kontena/cli/stacks/service_generator_v2.rb +27 -0
- data/lib/kontena/cli/stacks/show_command.rb +168 -0
- data/lib/kontena/cli/stacks/stack_name.rb +71 -0
- data/lib/kontena/cli/stacks/stacks_helper.rb +83 -0
- data/lib/kontena/cli/stacks/stop_command.rb +24 -0
- data/lib/kontena/cli/stacks/upgrade_command.rb +264 -0
- data/lib/kontena/cli/stacks/validate_command.rb +75 -0
- data/lib/kontena/cli/stacks/yaml/custom_validators/affinities_validator.rb +19 -0
- data/lib/kontena/cli/stacks/yaml/custom_validators/build_validator.rb +22 -0
- data/lib/kontena/cli/stacks/yaml/custom_validators/certificates_validator.rb +22 -0
- data/lib/kontena/cli/stacks/yaml/custom_validators/extends_validator.rb +22 -0
- data/lib/kontena/cli/stacks/yaml/custom_validators/hooks_validator.rb +102 -0
- data/lib/kontena/cli/stacks/yaml/custom_validators/secrets_validator.rb +22 -0
- data/lib/kontena/cli/stacks/yaml/opto/certificates_resolver.rb +37 -0
- data/lib/kontena/cli/stacks/yaml/opto/prompt_resolver.rb +78 -0
- data/lib/kontena/cli/stacks/yaml/opto/service_instances_resolver.rb +25 -0
- data/lib/kontena/cli/stacks/yaml/opto/service_link_resolver.rb +80 -0
- data/lib/kontena/cli/stacks/yaml/opto/vault_cert_prompt_resolver.rb +39 -0
- data/lib/kontena/cli/stacks/yaml/opto/vault_resolver.rb +13 -0
- data/lib/kontena/cli/stacks/yaml/opto/vault_setter.rb +12 -0
- data/lib/kontena/cli/stacks/yaml/opto.rb +16 -0
- data/lib/kontena/cli/stacks/yaml/reader.rb +525 -0
- data/lib/kontena/cli/stacks/yaml/service_extender.rb +65 -0
- data/lib/kontena/cli/stacks/yaml/stack_file_loader/file_loader.rb +41 -0
- data/lib/kontena/cli/stacks/yaml/stack_file_loader/registry_loader.rb +24 -0
- data/lib/kontena/cli/stacks/yaml/stack_file_loader/uri_loader.rb +23 -0
- data/lib/kontena/cli/stacks/yaml/stack_file_loader.rb +152 -0
- data/lib/kontena/cli/stacks/yaml/validations.rb +119 -0
- data/lib/kontena/cli/stacks/yaml/validator_v3.rb +164 -0
- data/lib/kontena/cli/subcommand_loader.rb +83 -0
- data/lib/kontena/cli/table_generator.rb +128 -0
- data/lib/kontena/cli/vault/export_command.rb +24 -0
- data/lib/kontena/cli/vault/import_command.rb +75 -0
- data/lib/kontena/cli/vault/list_command.rb +37 -0
- data/lib/kontena/cli/vault/read_command.rb +27 -0
- data/lib/kontena/cli/vault/remove_command.rb +23 -0
- data/lib/kontena/cli/vault/update_command.rb +24 -0
- data/lib/kontena/cli/vault/write_command.rb +23 -0
- data/lib/kontena/cli/vault_command.rb +13 -0
- data/lib/kontena/cli/version.rb +10 -0
- data/lib/kontena/cli/version_command.rb +20 -0
- data/lib/kontena/cli/volume_command.rb +9 -0
- data/lib/kontena/cli/volumes/create_command.rb +42 -0
- data/lib/kontena/cli/volumes/list_command.rb +29 -0
- data/lib/kontena/cli/volumes/remove_command.rb +29 -0
- data/lib/kontena/cli/volumes/show_command.rb +38 -0
- data/lib/kontena/cli/vpn/config_command.rb +27 -0
- data/lib/kontena/cli/vpn/create_command.rb +99 -0
- data/lib/kontena/cli/vpn/remove_command.rb +22 -0
- data/lib/kontena/cli/vpn_command.rb +9 -0
- data/lib/kontena/cli/whoami_command.rb +38 -0
- data/lib/kontena/client.rb +574 -0
- data/lib/kontena/command.rb +251 -0
- data/lib/kontena/debug_instrumentor.rb +80 -0
- data/lib/kontena/errors.rb +50 -0
- data/lib/kontena/light_prompt.rb +103 -0
- data/lib/kontena/machine/cert_helper.rb +43 -0
- data/lib/kontena/machine/cloud_config/cloudinit.yml +82 -0
- data/lib/kontena/machine/cloud_config/node_generator.rb +28 -0
- data/lib/kontena/machine/common.rb +17 -0
- data/lib/kontena/machine/random_name.rb +42 -0
- data/lib/kontena/main_command.rb +66 -0
- data/lib/kontena/plugin_manager/cleaner.rb +33 -0
- data/lib/kontena/plugin_manager/common.rb +89 -0
- data/lib/kontena/plugin_manager/installer.rb +78 -0
- data/lib/kontena/plugin_manager/loader.rb +93 -0
- data/lib/kontena/plugin_manager/rubygems_client.rb +59 -0
- data/lib/kontena/plugin_manager/uninstaller.rb +34 -0
- data/lib/kontena/plugin_manager.rb +26 -0
- data/lib/kontena/presets/github_auth_provider.yml +11 -0
- data/lib/kontena/presets/kontena_auth_provider.yml +11 -0
- data/lib/kontena/scripts/completer +9 -0
- data/lib/kontena/scripts/completer.rb +334 -0
- data/lib/kontena/scripts/init +18 -0
- data/lib/kontena/scripts/kontena.zsh +11 -0
- data/lib/kontena/scripts/krates.bash +8 -0
- data/lib/kontena/stacks/change_resolver.rb +118 -0
- data/lib/kontena/stacks/stack_data.rb +58 -0
- data/lib/kontena/stacks/stack_data_set.rb +51 -0
- data/lib/kontena/stacks_cache.rb +110 -0
- data/lib/kontena/stacks_client.rb +177 -0
- data/lib/kontena/util.rb +116 -0
- data/lib/kontena_cli.rb +190 -0
- metadata +518 -0
@@ -0,0 +1,152 @@
|
|
1
|
+
require_relative '../stack_name'
|
2
|
+
require 'yaml'
|
3
|
+
require_relative 'reader'
|
4
|
+
|
5
|
+
module Kontena::Cli::Stacks
|
6
|
+
module YAML
|
7
|
+
class StackFileLoader
|
8
|
+
# A base class for loading stack files. You can define more loaders by
|
9
|
+
# inheriting from this class.
|
10
|
+
#
|
11
|
+
# The purpose of StackFileLoader is to provide a generic interface for
|
12
|
+
# loading stack YAML's from different sources, such as local files,
|
13
|
+
# stack registry or URLs
|
14
|
+
|
15
|
+
def self.inherited(where)
|
16
|
+
loaders << where
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.loaders
|
20
|
+
@loaders ||= []
|
21
|
+
end
|
22
|
+
|
23
|
+
# The main interface for getting a new loader
|
24
|
+
#
|
25
|
+
# @param source [String] stack file source string (filename, url, ..)
|
26
|
+
# @param parent [StackFileLoader] define a parent for recursion
|
27
|
+
# @return [StackFileLoader]
|
28
|
+
def self.for(source, parent = nil)
|
29
|
+
loader = loaders.find { |l| l.match?(source, parent) }
|
30
|
+
if loader.nil?
|
31
|
+
raise RuntimeError, "Not found: no such file #{source} or invalid uri scheme"
|
32
|
+
end
|
33
|
+
loader.new(source, parent)
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :source, :parent
|
37
|
+
|
38
|
+
# @param source [String] stack file source string (filename, url, ..)
|
39
|
+
# @param parent [StackFileLoader] define a parent for recursion
|
40
|
+
# @return [StackFileLoader]
|
41
|
+
def initialize(source, parent = nil)
|
42
|
+
@source = source
|
43
|
+
@parent = parent
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [String] a stripped down version of inspect without all the yaml source
|
47
|
+
def inspect
|
48
|
+
"#<#{self.class.name}:#{object_id} @source=#{source.inspect} @parent=#{parent.nil? ? 'nil' : parent.source}>"
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [Hash] a hash parsed from the YAML content
|
52
|
+
def yaml
|
53
|
+
@yaml ||= ::YAML.safe_load(content, [], [], true, source)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @return [String] raw file content
|
57
|
+
def content
|
58
|
+
@content ||= read_content
|
59
|
+
end
|
60
|
+
|
61
|
+
def read_content
|
62
|
+
raise "Implement in inheriting class"
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [StackName] an accessor to StackName for the target file
|
66
|
+
def stack_name
|
67
|
+
@stack_name = Kontena::Cli::Stacks::StackName.new(yaml['stack'], yaml['version'])
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [Reader] an accessor to YAML::Reader for the target file
|
71
|
+
def reader(*args)
|
72
|
+
@reader ||= Reader.new(self, *args)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Builds an array of hashes that represent the dependency tree starting
|
76
|
+
# from the target file. Unless recurse is set to false, the tree will
|
77
|
+
# contain also nested dependencies from any child stacks.
|
78
|
+
#
|
79
|
+
# @param recurse [TrueClass,FalseClass] recurse child dependencies?
|
80
|
+
# @return [Array<Hash>] an array of hashes ('name', 'stack', 'variables', and 'depends')
|
81
|
+
def dependencies(recurse: true)
|
82
|
+
return @dependencies if @dependencies
|
83
|
+
if depends.nil? || depends.empty?
|
84
|
+
@dependencies = nil
|
85
|
+
else
|
86
|
+
@dependencies = depends.map do |name, dependency|
|
87
|
+
loader = StackFileLoader.for(dependency['stack'], self)
|
88
|
+
deps = { 'name' => name, 'stack' => loader.source, 'variables' => dependency.fetch('variables', Hash.new) }
|
89
|
+
if recurse
|
90
|
+
child_deps = loader.dependencies
|
91
|
+
deps['depends'] = child_deps unless child_deps.nil?
|
92
|
+
end
|
93
|
+
deps
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_h
|
99
|
+
{
|
100
|
+
'stack' => stack_name.stack_name,
|
101
|
+
:loader => self,
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns a non nested hash of all dependencies.
|
106
|
+
# Processes :variables hash and moves the related variables to children
|
107
|
+
#
|
108
|
+
# @param basename [String] installed stack name
|
109
|
+
# @param opts [Hash] extra data such as variable lists
|
110
|
+
# @return [Hash] { installation_name => { 'name' => installation-name, 'stack' => stack_name, :loader => self }, child_install_name => { ... } }
|
111
|
+
def flat_dependencies(basename, opts = {})
|
112
|
+
opt_variables = opts[:variables] || {}
|
113
|
+
|
114
|
+
result = {
|
115
|
+
basename => self.to_h.merge(opts).merge(
|
116
|
+
name: basename,
|
117
|
+
variables: opt_variables.reject { |k, _| k.include?('.') }
|
118
|
+
)
|
119
|
+
}
|
120
|
+
|
121
|
+
depends.each do |as_name, data|
|
122
|
+
variables = {}
|
123
|
+
|
124
|
+
opt_variables.select { |k, _| k.start_with?(as_name + '.') }.each do |k,v|
|
125
|
+
variables[k.split('.', 2).last] = v
|
126
|
+
end
|
127
|
+
|
128
|
+
data['variables'] ||= {}
|
129
|
+
|
130
|
+
loader = StackFileLoader.for(data['stack'], self)
|
131
|
+
result.merge!(
|
132
|
+
loader.flat_dependencies(
|
133
|
+
basename + '-' + as_name,
|
134
|
+
variables: data['variables'].merge(variables),
|
135
|
+
parent_name: basename
|
136
|
+
)
|
137
|
+
)
|
138
|
+
end
|
139
|
+
|
140
|
+
result
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def depends
|
146
|
+
yaml['depends'] || {}
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
Dir[File.expand_path('../stack_file_loader/*.rb', __FILE__)].each { |f| require f }
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Kontena::Cli::Stacks::YAML
|
2
|
+
module Validations
|
3
|
+
module CustomValidators
|
4
|
+
require_relative 'custom_validators/affinities_validator'
|
5
|
+
require_relative 'custom_validators/build_validator'
|
6
|
+
require_relative 'custom_validators/extends_validator'
|
7
|
+
require_relative 'custom_validators/hooks_validator'
|
8
|
+
require_relative 'custom_validators/secrets_validator'
|
9
|
+
require_relative 'custom_validators/certificates_validator'
|
10
|
+
|
11
|
+
def self.load
|
12
|
+
return if @loaded
|
13
|
+
HashValidator.append_validator(AffinitiesValidator.new)
|
14
|
+
HashValidator.append_validator(BuildValidator.new)
|
15
|
+
HashValidator.append_validator(ExtendsValidator.new)
|
16
|
+
HashValidator.append_validator(SecretsValidator.new)
|
17
|
+
HashValidator.append_validator(CertificatesValidator.new)
|
18
|
+
HashValidator.append_validator(HooksValidator.new)
|
19
|
+
@loaded = true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def common_validations
|
24
|
+
{
|
25
|
+
'image' => optional('string'), # it's optional because some base yml file might contain image option
|
26
|
+
'extends' => optional('stacks_valid_extends'),
|
27
|
+
'stateful' => optional('boolean'),
|
28
|
+
'affinity' => optional('stacks_valid_affinities'),
|
29
|
+
'cap_add' => optional('array'),
|
30
|
+
'cap_drop' => optional('array'),
|
31
|
+
'command' => optional('string'),
|
32
|
+
'cpus' => optional('float'),
|
33
|
+
'cpu_shares' => optional('integer'),
|
34
|
+
'external_links' => optional('array'),
|
35
|
+
'mem_limit' => optional('string'),
|
36
|
+
'mem_swaplimit' => optional('string'),
|
37
|
+
'shm_size' => optional('string'),
|
38
|
+
'environment' => optional(-> (value) {
|
39
|
+
if value.is_a?(Hash)
|
40
|
+
value.all? do |k,v|
|
41
|
+
k.kind_of?(String) && (
|
42
|
+
v.kind_of?(String) ||
|
43
|
+
v.kind_of?(Integer) ||
|
44
|
+
v.kind_of?(TrueClass) ||
|
45
|
+
v.kind_of?(FalseClass) ||
|
46
|
+
v.nil?
|
47
|
+
)
|
48
|
+
end
|
49
|
+
elsif value.is_a?(Array)
|
50
|
+
value.all? { |v| v.kind_of?(String) && v =~ /\A[^=]+=/ }
|
51
|
+
else
|
52
|
+
false
|
53
|
+
end
|
54
|
+
}),
|
55
|
+
'env_file' => optional(-> (value) { value.is_a?(String) || value.is_a?(Array) }),
|
56
|
+
'instances' => optional('integer'),
|
57
|
+
'links' => optional(-> (value) { value.is_a?(Array) || value.nil? }),
|
58
|
+
'ports' => optional(-> (value) { value.is_a?(Array) && value.all? { |v| v.is_a?(String) && v.match(/\A(\d+\.\d+\.\d+\.\d+)?:?(\d+)\:(\d+)\/?(\w+)?\z/) } }),
|
59
|
+
'pid' => optional('string'),
|
60
|
+
'privileged' => optional('boolean'),
|
61
|
+
'user' => optional('string'),
|
62
|
+
'volumes' => optional('array'),
|
63
|
+
'volumes_from' => optional('array'),
|
64
|
+
'secrets' => optional('stacks_valid_secrets'),
|
65
|
+
'certificates' => optional('stacks_valid_certificates'),
|
66
|
+
'hooks' => optional('stacks_valid_hooks'),
|
67
|
+
'only_if' => optional(-> (value) { value.is_a?(String) || value.is_a?(Hash) || value.is_a?(Array) }),
|
68
|
+
'skip_if' => optional(-> (value) { value.is_a?(String) || value.is_a?(Hash) || value.is_a?(Array) }),
|
69
|
+
'deploy' => optional({
|
70
|
+
'strategy' => optional(%w(ha daemon random)),
|
71
|
+
'wait_for_port' => optional('integer'),
|
72
|
+
'min_health' => optional('float'),
|
73
|
+
'interval' => optional(/^\d+(min|h|d|)$/)
|
74
|
+
}),
|
75
|
+
'health_check' => optional({
|
76
|
+
'protocol' => /^(http|tcp)$/,
|
77
|
+
'port' => 'integer',
|
78
|
+
'uri' => optional(/\/[\S]*/),
|
79
|
+
'timeout' => optional('integer'),
|
80
|
+
'interval' => optional('integer'),
|
81
|
+
'initial_delay' => optional('integer')
|
82
|
+
}),
|
83
|
+
'stop_signal' => optional('string'),
|
84
|
+
'stop_grace_period' => optional(/(\d+(?:\.\d+)?)([hms])/),
|
85
|
+
'read_only' => optional('boolean'),
|
86
|
+
'entrypoint' => optional('string')
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
def optional(type)
|
91
|
+
HashValidator.optional(type)
|
92
|
+
end
|
93
|
+
|
94
|
+
def validate_options(service_config)
|
95
|
+
HashValidator.validate(service_config, @schema, true)
|
96
|
+
end
|
97
|
+
|
98
|
+
def validate_volume_options(volume_config)
|
99
|
+
HashValidator.validate(volume_config, volume_schema, true)
|
100
|
+
end
|
101
|
+
|
102
|
+
def validate_dependencies(dependency_config)
|
103
|
+
HashValidator.validate(dependency_config, dependency_schema, true)
|
104
|
+
end
|
105
|
+
|
106
|
+
def volume_schema
|
107
|
+
{
|
108
|
+
'external' => optional(-> (value) { value.is_a?(TrueClass) || (value.is_a?(Hash) && value['name'].is_a?(String)) })
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
def dependency_schema
|
113
|
+
{
|
114
|
+
'stack' => optional('string'),
|
115
|
+
'variables' => optional(-> (value) { value.is_a?(Hash) })
|
116
|
+
}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'hash_validator'
|
2
|
+
|
3
|
+
module Kontena::Cli::Stacks
|
4
|
+
module YAML
|
5
|
+
class ValidatorV3
|
6
|
+
require_relative 'validations'
|
7
|
+
include Validations
|
8
|
+
|
9
|
+
KNOWN_TOP_LEVEL_KEYS = %i(
|
10
|
+
services
|
11
|
+
errors
|
12
|
+
volumes
|
13
|
+
networks
|
14
|
+
variables
|
15
|
+
stack
|
16
|
+
version
|
17
|
+
data
|
18
|
+
description
|
19
|
+
expose
|
20
|
+
depends
|
21
|
+
labels
|
22
|
+
)
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@schema = common_validations
|
26
|
+
@schema['build'] = optional('stacks_valid_build')
|
27
|
+
@schema['depends_on'] = optional('array')
|
28
|
+
@schema['network_mode'] = optional(%w(host bridge))
|
29
|
+
@schema['logging'] = optional({
|
30
|
+
'driver' => optional('string'),
|
31
|
+
'options' => optional(-> (value) { value.kind_of?(Hash) })
|
32
|
+
})
|
33
|
+
Validations::CustomValidators.load
|
34
|
+
end
|
35
|
+
|
36
|
+
# borrowed from server/app/helpers/volumes_helpers.rb
|
37
|
+
def parse_volume(vol)
|
38
|
+
elements = vol.split(':')
|
39
|
+
if elements.size >= 2 # Bind mount or volume used
|
40
|
+
if elements[0].start_with?('/') && elements[1] && elements[1].start_with?('/') # Bind mount
|
41
|
+
{bind_mount: elements[0], path: elements[1], flags: elements[2..-1].join(',')}
|
42
|
+
elsif !elements[0].start_with?('/') && elements[1].start_with?('/') # Real volume
|
43
|
+
{volume: elements[0], path: elements[1], flags: elements[2..-1].join(',')}
|
44
|
+
else
|
45
|
+
{error: "volume definition not in right format: #{vol}" }
|
46
|
+
end
|
47
|
+
elsif elements.size == 1 && elements[0].start_with?('/') # anon volume
|
48
|
+
{bind_mount: nil, path: elements[0], flags: nil} # anon vols do not support flags
|
49
|
+
else
|
50
|
+
{error: "volume definition not in right format: #{vol}" }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# @param [Hash] yaml
|
56
|
+
# @param [TrueClass|FalseClass] strict
|
57
|
+
# @return [Array] validation_errors
|
58
|
+
def validate(yaml)
|
59
|
+
result = {
|
60
|
+
errors: [],
|
61
|
+
notifications: []
|
62
|
+
}
|
63
|
+
|
64
|
+
yaml.keys.each do |key|
|
65
|
+
unless KNOWN_TOP_LEVEL_KEYS.include?(key) || KNOWN_TOP_LEVEL_KEYS.include?(key.to_sym)
|
66
|
+
result[:notifications] << { key.to_s => "unknown top level key" }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
if yaml.key?('stack')
|
71
|
+
unless yaml['stack'] =~ /\A(?:.+?\/)?(?!-)[a-z0-9\-]+\z/
|
72
|
+
result[:notifications] << { 'stack' => 'A stack name should only include a-z, 0-9 and - characters and not start with the - character' }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
if yaml.key?('services')
|
77
|
+
if yaml['services'].kind_of?(Hash)
|
78
|
+
yaml['services'].each do |service, options|
|
79
|
+
unless service =~ /\A(?!-)[a-z0-9\-]+\z/
|
80
|
+
result[:notifications] << { 'services' => { service => { 'name' => 'A service name should only include a-z, 0-9 and - characters and not start with the - character' } } }
|
81
|
+
end
|
82
|
+
unless options.kind_of?(Hash)
|
83
|
+
result[:errors] << { 'services' => { service => { 'options' => "must be a mapping not a #{options.class}"} } }
|
84
|
+
next
|
85
|
+
end
|
86
|
+
option_errors = validate_options(options)
|
87
|
+
result[:errors] << { 'services' => { service => option_errors.errors } } unless option_errors.valid?
|
88
|
+
if options['volumes']
|
89
|
+
mount_path_occurences = Hash.new(0)
|
90
|
+
options['volumes'].each do |volume|
|
91
|
+
parsed = parse_volume(volume)
|
92
|
+
if parsed[:error]
|
93
|
+
result[:errors] << { 'services' => { service => { 'volumes' => { volume => parsed[:error] } } } }
|
94
|
+
elsif parsed[:path]
|
95
|
+
mount_path_occurences[parsed[:path]] += 1
|
96
|
+
volume_name = parsed[:volume]
|
97
|
+
if volume_name && !volume_name.start_with?('/')
|
98
|
+
if yaml.key?('volumes')
|
99
|
+
unless yaml['volumes'][volume_name]
|
100
|
+
result[:errors] << { 'services' => { service => { 'volumes' => { volume_name => 'not found in top level volumes list' } } } }
|
101
|
+
end
|
102
|
+
else
|
103
|
+
result[:errors] << { 'services' => { service => { 'volumes' => { volume => 'defines volume name, but file does not contain volumes definitions' } } } }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
else
|
107
|
+
result[:errors] << { 'services' => { service => { 'volumes' => { volume => 'mount point missing' } } } }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
mount_path_occurences.select {|path, occurences| occurences > 1 }.each do |path, occurences|
|
111
|
+
result[:errors] << { 'services' => { service => { 'volumes' => { path => "mount point defined #{occurences} times" } } } }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
else
|
116
|
+
result[:errors] << { 'services' => "must be a mapping, not #{yaml['services'].class}" }
|
117
|
+
end
|
118
|
+
else
|
119
|
+
result[:notifications] << { 'file' => 'does not define any services' }
|
120
|
+
end
|
121
|
+
|
122
|
+
if yaml.key?('volumes')
|
123
|
+
if yaml['volumes'].kind_of?(Hash)
|
124
|
+
yaml['volumes'].each do |volume, options|
|
125
|
+
if options.kind_of?(Hash)
|
126
|
+
option_errors = validate_volume_options(options)
|
127
|
+
unless option_errors.valid?
|
128
|
+
result[:errors] << { 'volumes' => { volume => option_errors.errors } }
|
129
|
+
end
|
130
|
+
else
|
131
|
+
result[:errors] << { 'volumes' => { volume => { 'options' => "must be a mapping, not #{options.class}" } } }
|
132
|
+
end
|
133
|
+
end
|
134
|
+
else
|
135
|
+
result[:errors] << { 'volumes' => "must be a mapping, not #{yaml['volumes'].class}" }
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
if yaml.key?('networks')
|
140
|
+
result[:notifications] << { 'networks' => 'Kontena does not support multiple networks yet. You can reference services with Kontena\'s internal DNS (service_name.kontena.local)' }
|
141
|
+
end
|
142
|
+
|
143
|
+
if (yaml['volumes'].nil? || yaml['volumes'].empty?) && (yaml['services'].nil? || yaml['services'].empty?)
|
144
|
+
result[:errors] << { 'file' => 'does not list any services or volumes' }
|
145
|
+
end
|
146
|
+
|
147
|
+
if yaml.key?('depends')
|
148
|
+
unless yaml['depends'].kind_of?(Hash)
|
149
|
+
result[:errors] << { 'depends' => "Must be a mapping, not #{yaml['depends'].class}" }
|
150
|
+
end
|
151
|
+
|
152
|
+
yaml['depends'].each do |name, dependency_options|
|
153
|
+
validator = validate_dependencies(dependency_options)
|
154
|
+
result[:errors] << { 'depends' => { name => validator.errors } } unless validator.valid?
|
155
|
+
if yaml.key?('services') && yaml['services'][name]
|
156
|
+
result[:errors] << { 'depends' => { name => 'is defined both as service and dependency name' } }
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
result
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'kontena_cli'
|
2
|
+
module Kontena::Cli
|
3
|
+
class SubcommandLoader
|
4
|
+
attr_reader :path
|
5
|
+
|
6
|
+
# Create a subcommand loader instance
|
7
|
+
#
|
8
|
+
# @param [String] path path to command definition
|
9
|
+
def initialize(path)
|
10
|
+
@path = path
|
11
|
+
end
|
12
|
+
|
13
|
+
# Takes something like /foo/bar/cli/master/foo_coimmand and returns [:Master, :FooCommand]
|
14
|
+
#
|
15
|
+
# @param path [String]
|
16
|
+
# @return [Array<Symbol>]
|
17
|
+
def symbolize_path(path)
|
18
|
+
path.gsub(/.*\/cli\//, '').split('/').map do |path_part|
|
19
|
+
path_part.split('_').map{ |e| e.capitalize }.join
|
20
|
+
end.map(&:to_sym)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Takes an array such as [:Foo] or [:Cli, :Foo] and returns [:Kontena, :Cli, :Foo]
|
24
|
+
def prepend_kontena_cli(tree)
|
25
|
+
[:Kontena, :Cli] + (tree - [:Cli])
|
26
|
+
end
|
27
|
+
|
28
|
+
# Takes an array such as [:Master, :FooCommand] and returns Master::FooCommand
|
29
|
+
#
|
30
|
+
# @param tree [Array<Symbol]
|
31
|
+
# @return [Class]
|
32
|
+
def const_get_tree(tree)
|
33
|
+
if tree.size == 1
|
34
|
+
Object.const_get(tree.first)
|
35
|
+
else
|
36
|
+
tree[1..-1].inject(Object.const_get(tree.first)) { |new_base, part| new_base.const_get(part) }
|
37
|
+
end
|
38
|
+
rescue
|
39
|
+
raise ArgumentError, "Can't figure out command class name from path #{path} - tried #{tree}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Tries to require a file, returns false instead of raising LoadError unless succesful
|
43
|
+
#
|
44
|
+
# @param path [String]
|
45
|
+
# @return [TrueClass,FalseClass]
|
46
|
+
def safe_require(path)
|
47
|
+
require path
|
48
|
+
true
|
49
|
+
rescue LoadError
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
53
|
+
def klass
|
54
|
+
return @subcommand_class if @subcommand_class
|
55
|
+
unless safe_require(path) || safe_require(Kontena.cli_root(path))
|
56
|
+
raise ArgumentError, "Can't load #{path} or #{Kontena.cli_root(path)}"
|
57
|
+
end
|
58
|
+
@subcommand_class = const_get_tree(prepend_kontena_cli(symbolize_path(path)))
|
59
|
+
end
|
60
|
+
|
61
|
+
def new(*args)
|
62
|
+
klass.new(*args)
|
63
|
+
end
|
64
|
+
|
65
|
+
def method_missing(meth, *args)
|
66
|
+
klass.send(meth, *args)
|
67
|
+
end
|
68
|
+
|
69
|
+
def respond_to_missing?(meth)
|
70
|
+
klass.respond_to?(meth)
|
71
|
+
end
|
72
|
+
|
73
|
+
def const_get(const)
|
74
|
+
klass.const_get(const)
|
75
|
+
end
|
76
|
+
|
77
|
+
def const_defined?(const)
|
78
|
+
klass.const_defined?(const)
|
79
|
+
end
|
80
|
+
|
81
|
+
alias_method :class, :klass
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'tty-table'
|
2
|
+
|
3
|
+
module Kontena
|
4
|
+
module Cli
|
5
|
+
class TableGenerator
|
6
|
+
|
7
|
+
attr_reader :data
|
8
|
+
attr_reader :fields
|
9
|
+
attr_reader :header
|
10
|
+
attr_reader :row_format_proc, :header_format_proc, :render_options, :render_mode
|
11
|
+
|
12
|
+
DEFAULT_HEADER_FORMAT_PROC = lambda { |header| header.to_s.capitalize }
|
13
|
+
|
14
|
+
DEFAULT_RENDER_OPTS = {padding: [0,2,0,0]}
|
15
|
+
|
16
|
+
module Helper
|
17
|
+
def self.included(base)
|
18
|
+
if base.respond_to?(:option)
|
19
|
+
base.option ['-q', '--quiet'], :flag, "Output the identifying column only"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def table_generator
|
24
|
+
Kontena::Cli::TableGenerator
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_table(array, fields = nil, &block)
|
28
|
+
fields ||= self.fields if self.respond_to?(:fields)
|
29
|
+
table_generator.new(
|
30
|
+
array,
|
31
|
+
fields,
|
32
|
+
row_format_proc: block_given? ? block.to_proc : nil,
|
33
|
+
header_format_proc: lambda { |item| pastel.bold(item.to_s.upcase) },
|
34
|
+
render_options: self.respond_to?(:render_options) ? DEFAULT_RENDER_OPTS.merge(self.render_options) : DEFAULT_RENDER_OPTS
|
35
|
+
).render
|
36
|
+
end
|
37
|
+
|
38
|
+
def print_table(array, fields = nil, &block)
|
39
|
+
output = generate_table(array, fields, &block)
|
40
|
+
puts output unless output.strip.empty?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param data [Array<Hash>,Array<Array>] an array of hashes or arrays
|
45
|
+
# @param fields [Array] an array of field names found in the data hashes.
|
46
|
+
# @param fields [Hash] a hash of field_title => field_name_in_the_data_hash, for example 'Users' => 'user_count'
|
47
|
+
# @param fields [NilClass] try to auto detect fields (all fields!) from the data hashes
|
48
|
+
# @return [TTY::Table]
|
49
|
+
def initialize(data, fields = nil, row_format_proc: nil, header_format_proc: nil, render_options: nil)
|
50
|
+
@data = data
|
51
|
+
@render_options = render_options || { }
|
52
|
+
@render_mode = @render_options.delete(:mode) || :basic
|
53
|
+
@row_format_proc = row_format_proc
|
54
|
+
@header_format_proc = header_format_proc || DEFAULT_HEADER_FORMAT_PROC
|
55
|
+
@fields = parse_fields(fields)
|
56
|
+
@header = generate_header(fields || @fields)
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_table(header, rows)
|
60
|
+
TTY::Table.new(
|
61
|
+
header: header,
|
62
|
+
rows: rows
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def table
|
67
|
+
create_table(header, rows)
|
68
|
+
end
|
69
|
+
|
70
|
+
def render
|
71
|
+
if data.empty?
|
72
|
+
fields.size > 1 ? fields.map(&method(:format_header_item)).join(' ') : ''
|
73
|
+
else
|
74
|
+
table.render(render_mode, render_options).gsub(/\s+$/, '')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def format_row(row)
|
79
|
+
return row if row_format_proc.nil?
|
80
|
+
row_clone = row.dup
|
81
|
+
row_format_proc.call(row_clone)
|
82
|
+
row_clone
|
83
|
+
end
|
84
|
+
|
85
|
+
def format_header_item(field_name)
|
86
|
+
header_format_proc.call(field_name)
|
87
|
+
end
|
88
|
+
|
89
|
+
def rows
|
90
|
+
fields.empty? ? data.map { |row| format_row(row).map(&:values) } : data.map { |row| format_row(row).values_at(*fields) }
|
91
|
+
end
|
92
|
+
|
93
|
+
# Collect all the unique keys from the hashes if the data
|
94
|
+
# is an array of hashes.
|
95
|
+
def detect_fields
|
96
|
+
if data.first.respond_to?(:keys)
|
97
|
+
data.flat_map(&:keys).uniq
|
98
|
+
else
|
99
|
+
[]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def parse_fields(fields)
|
104
|
+
if fields.nil? || fields.empty?
|
105
|
+
detect_fields
|
106
|
+
elsif fields.kind_of?(Hash)
|
107
|
+
fields.values
|
108
|
+
else
|
109
|
+
fields
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def generate_header(fields)
|
114
|
+
if fields.kind_of?(Hash)
|
115
|
+
header = fields.keys
|
116
|
+
else
|
117
|
+
header = Array(fields)
|
118
|
+
end
|
119
|
+
|
120
|
+
if header.size < 2
|
121
|
+
nil
|
122
|
+
else
|
123
|
+
header.map { |head| format_header_item(head) }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Kontena::Cli::Vault
|
2
|
+
class ExportCommand < Kontena::Command
|
3
|
+
include Kontena::Cli::Common
|
4
|
+
include Kontena::Cli::GridOptions
|
5
|
+
|
6
|
+
banner "Exports secrets from Vault to STDOUT as YAML or JSON."
|
7
|
+
|
8
|
+
requires_current_master
|
9
|
+
|
10
|
+
option '--json', :flag, "Output JSON"
|
11
|
+
|
12
|
+
def execute
|
13
|
+
require 'shellwords'
|
14
|
+
require 'json'
|
15
|
+
require 'yaml'
|
16
|
+
meth = json? ? :to_json : :to_yaml
|
17
|
+
puts(
|
18
|
+
Kontena.run!(['vault', 'ls', '--return']).sort.map do |secret|
|
19
|
+
[secret, Kontena.run!(['vault', 'read', '--return', secret])]
|
20
|
+
end.to_h.send(meth)
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|