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,525 @@
|
|
1
|
+
require_relative 'stack_file_loader'
|
2
|
+
require_relative 'service_extender'
|
3
|
+
require_relative '../service_generator_v2'
|
4
|
+
require_relative 'validator_v3'
|
5
|
+
require 'opto'
|
6
|
+
require 'liquid'
|
7
|
+
require_relative 'opto'
|
8
|
+
|
9
|
+
module Kontena::Cli::Stacks
|
10
|
+
module YAML
|
11
|
+
module Opto
|
12
|
+
module Resolvers; end
|
13
|
+
module Setters; end
|
14
|
+
end
|
15
|
+
|
16
|
+
class LiquidNull
|
17
|
+
# Workaround for nil-valued variables in Liquid templates:
|
18
|
+
# https://github.com/Shopify/liquid/issues/749
|
19
|
+
# This is something that we can pass in to `Liquid::Template.render` that gets evaluated as nil.
|
20
|
+
# If we pass in a nil value directly, then Liquid ignores it and considers the variable to be undefined.
|
21
|
+
def to_liquid
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Reader
|
27
|
+
# The kontena Stack YAML reader
|
28
|
+
|
29
|
+
include Kontena::Util
|
30
|
+
include Kontena::Cli::Common
|
31
|
+
|
32
|
+
attr_reader :file, :loader, :errors, :notifications
|
33
|
+
|
34
|
+
# @param stack_origin [String] a filename, pointer to registry or an URL
|
35
|
+
# @return [Reader]
|
36
|
+
def initialize(file)
|
37
|
+
if file.kind_of?(StackFileLoader)
|
38
|
+
@file = file.source
|
39
|
+
@loader = file
|
40
|
+
else
|
41
|
+
@file = file
|
42
|
+
@loader = StackFileLoader.for(file)
|
43
|
+
end
|
44
|
+
|
45
|
+
@errors = []
|
46
|
+
@notifications = []
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param without_defaults [TrueClass,FalseClass] strip the GRID, STACK, etc from response
|
50
|
+
# @param without_vault [TrueClass,FalseClass] strip out any values that are going to or coming from VAULT
|
51
|
+
# @return [Hash] a hash of key value pairs representing the values of stack variables
|
52
|
+
def variable_values(without_defaults: false, without_vault: false, with_errors: false)
|
53
|
+
result = variables.to_h(values_only: true, with_errors: with_errors)
|
54
|
+
if without_defaults
|
55
|
+
result.delete_if { |k, _| default_envs.key?(k.to_s) || k.to_s == 'PARENT_STACK' }
|
56
|
+
end
|
57
|
+
if without_vault
|
58
|
+
result.delete_if { |k, _| variables.option(k).from.include?('vault') || variables.option(k).to.include?('vault') }
|
59
|
+
end
|
60
|
+
result
|
61
|
+
end
|
62
|
+
|
63
|
+
# Values that are set always when parsing stacks
|
64
|
+
# @return [Hash] a hash of key value pairs
|
65
|
+
def default_envs
|
66
|
+
{
|
67
|
+
'GRID' => env['GRID'],
|
68
|
+
'STACK' => env['STACK'],
|
69
|
+
'PLATFORM' => env['PLATFORM'] || env['GRID']
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
# Only uses the values from #default_envs to provide a hash from minimally interpolated
|
74
|
+
# YAML file. Useful for accessing some parts of the YAML without asking any questions.
|
75
|
+
#
|
76
|
+
# @return [Hash] minimally interpolated YAMl from the stack file.
|
77
|
+
def internals_interpolated_yaml
|
78
|
+
@internals_interpolated_yaml ||= ::YAML.safe_load(
|
79
|
+
replace_dollar_dollars(
|
80
|
+
interpolate(
|
81
|
+
raw_content,
|
82
|
+
use_opto: false,
|
83
|
+
substitutions: default_envs,
|
84
|
+
warnings: false
|
85
|
+
)
|
86
|
+
), [], [], true, file
|
87
|
+
)
|
88
|
+
rescue Psych::SyntaxError => ex
|
89
|
+
raise ex, "Error while parsing #{file} : #{ex.message}"
|
90
|
+
end
|
91
|
+
|
92
|
+
# Uses variable interpolation, prompts as needed, liquid interpolation
|
93
|
+
#
|
94
|
+
# @return [Hash] the most commplete stack parsing outcome
|
95
|
+
def fully_interpolated_yaml
|
96
|
+
return @fully_interpolated_yaml if @fully_interpolated_yaml
|
97
|
+
@fully_interpolated_yaml = ::YAML.safe_load(
|
98
|
+
replace_dollar_dollars(
|
99
|
+
interpolate(
|
100
|
+
interpolate_liquid(
|
101
|
+
raw_content,
|
102
|
+
variable_values
|
103
|
+
),
|
104
|
+
use_opto: true,
|
105
|
+
raise_on_unknown: true
|
106
|
+
)
|
107
|
+
), [], [], true, file
|
108
|
+
)
|
109
|
+
rescue Psych::SyntaxError => ex
|
110
|
+
raise ex, "Error while parsing #{file} : #{ex.message}"
|
111
|
+
end
|
112
|
+
|
113
|
+
# The YAML file raw content
|
114
|
+
def raw_content
|
115
|
+
loader.content
|
116
|
+
end
|
117
|
+
|
118
|
+
# @return [Hash] with zero interpolation/processing. Will mostly fail
|
119
|
+
def raw_yaml
|
120
|
+
loader.yaml
|
121
|
+
end
|
122
|
+
|
123
|
+
# Creates an opto option definition compatible hash from the #default_envs hash
|
124
|
+
# @return [Hash]
|
125
|
+
def default_envs_to_options
|
126
|
+
default_envs.each_with_object({}) { |env, obj| obj[env[0]] = { type: :string, value: env[1] } }
|
127
|
+
end
|
128
|
+
|
129
|
+
# Accessor to the Opto variable handler
|
130
|
+
# @return [Opto::Group]
|
131
|
+
def variables
|
132
|
+
@variables ||= ::Opto::Group.new(
|
133
|
+
internals_interpolated_yaml.fetch('variables', {}).merge(default_envs_to_options),
|
134
|
+
defaults: { from: :env }
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Accepts a hash of variable_name => variable_value pairs and sets the values as variable default values
|
139
|
+
# Used when previous answers are read from master and passed as default values for upgrade.
|
140
|
+
# @param defaults [Hash] { 'variable_name' => 'variable_value' }
|
141
|
+
def set_variable_defaults(defaults)
|
142
|
+
defaults.each do |key, val|
|
143
|
+
var = variables.option(key.to_s)
|
144
|
+
var.default = val if var
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Set values from a hash to values of the variables.
|
149
|
+
# Used when variable values are read from a file or command line parameters or dependency variable injection
|
150
|
+
# @param [Hash] a hash of variable_name => variable_value pairs
|
151
|
+
def set_variable_values(values)
|
152
|
+
values.each do |key, val|
|
153
|
+
var = variables.option(key.to_s)
|
154
|
+
var.set(val) if var
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Creates a set of variables using the 'depends' section. The variable name is the name of the dependency
|
159
|
+
# and the variable value is the generated child stack name. For example,.have something like:
|
160
|
+
# depends:
|
161
|
+
# redis:
|
162
|
+
# stack: foo/redis
|
163
|
+
# you will get a new variable called "redis" and its value will be "this-stack-name-redis".
|
164
|
+
# This variable can be used to interpolate for example a hostname to some environment variable:
|
165
|
+
# environment:
|
166
|
+
# - "REDIS_HOST=redis.${REDIS}"
|
167
|
+
def create_dependency_variables(dependencies, name)
|
168
|
+
return if dependencies.nil?
|
169
|
+
dependencies.each do |options|
|
170
|
+
variables.build_option(name: options['name'].to_s, type: :string, value: "#{name}-#{options['name']}")
|
171
|
+
create_dependency_variables(options['depends'], "#{name}.#{options['name']}")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# If this stack is a part of a dependency chain and has a parent, the variable $PARENT_STACK will
|
176
|
+
# interpolate to the name of the parent stack.
|
177
|
+
def create_parent_variable(parent_name)
|
178
|
+
variables.build_option(name: 'PARENT_STACK', type: :string, value: parent_name)
|
179
|
+
end
|
180
|
+
|
181
|
+
# @return [Boolean] did this stack come from a local file?
|
182
|
+
def from_file?
|
183
|
+
loader.origin == 'file'
|
184
|
+
end
|
185
|
+
|
186
|
+
# @param [String] service_name (set when using extends)
|
187
|
+
# @param name [String] override stackname (default is to parse it from the YAML, but if you set it through -n it needs to be overriden)
|
188
|
+
# @param parent_name [String] parent stack name
|
189
|
+
# @param skip_validation [Boolean] skip running validations
|
190
|
+
# @param values [Hash] force-set variable values using variable_name => variable_value key pairs
|
191
|
+
# @param defaults [Hash] set variable defaults from variable_name => variable_value key pairs
|
192
|
+
# @return [Hash]
|
193
|
+
def execute(service_name = nil, name: loader.stack_name.stack, parent_name: nil, skip_validation: false, values: nil, defaults: nil)
|
194
|
+
set_variable_defaults(defaults) if defaults
|
195
|
+
set_variable_values(values) if values
|
196
|
+
create_dependency_variables(dependencies, name)
|
197
|
+
create_parent_variable(parent_name) if parent_name
|
198
|
+
|
199
|
+
variables.run
|
200
|
+
|
201
|
+
if !skip_validation && !variables.valid?
|
202
|
+
stringify_keys(variables.errors).each do |k,v|
|
203
|
+
errors << { 'variables' => { k => v } }
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
validate unless skip_validation
|
208
|
+
|
209
|
+
result = {}
|
210
|
+
Dir.chdir(from_file? ? File.dirname(File.expand_path(file)) : Dir.pwd) do
|
211
|
+
result['stack'] = raw_yaml['stack']
|
212
|
+
result['version'] = loader.stack_name.version || '0.0.1'
|
213
|
+
result['name'] = name
|
214
|
+
result['labels'] = fully_interpolated_yaml['labels'] || []
|
215
|
+
result['registry'] = loader.registry
|
216
|
+
result['expose'] = fully_interpolated_yaml['expose']
|
217
|
+
result['services'] = errors.empty? ? parse_services(service_name) : {}
|
218
|
+
result['volumes'] = errors.empty? ? parse_volumes : {}
|
219
|
+
result['dependencies'] = dependencies
|
220
|
+
result['source'] = raw_content
|
221
|
+
result['variables'] = variable_values(without_defaults: true, without_vault: true)
|
222
|
+
result['metadata'] = raw_yaml['meta'] || {}
|
223
|
+
end
|
224
|
+
|
225
|
+
if parent_name
|
226
|
+
result['parent'] = { 'name' => parent_name }
|
227
|
+
else
|
228
|
+
result['parent'] = nil
|
229
|
+
end
|
230
|
+
if service_name.nil?
|
231
|
+
result['services'].each do |service|
|
232
|
+
errors << { 'services' => { service['name'] => { 'image' => "image is missing" } } } if service['image'].to_s.empty?
|
233
|
+
end
|
234
|
+
errors << { file => { 'stack' => 'Required field missing' } } if result['stack'].nil?
|
235
|
+
end
|
236
|
+
result
|
237
|
+
end
|
238
|
+
|
239
|
+
# Returns an array of hashes containing the dependency tree starting from this file
|
240
|
+
# @return [Array<Hash>]]
|
241
|
+
def dependencies
|
242
|
+
@dependencies ||= loader.dependencies
|
243
|
+
end
|
244
|
+
|
245
|
+
# Interpolate any Liquid templating in the YAML content
|
246
|
+
# @param content [String] file content
|
247
|
+
# @param vars [Hash] key-value pairs
|
248
|
+
# @return [String]
|
249
|
+
# @raise [Liquid::Error]
|
250
|
+
def interpolate_liquid(content, vars)
|
251
|
+
Liquid::Template.error_mode = :strict
|
252
|
+
template = Liquid::Template.parse(content)
|
253
|
+
|
254
|
+
# Wrap nil values in LiquidNull to not have Liquid consider them as undefined
|
255
|
+
vars = vars.map {|key, value| [key, value.nil? ? LiquidNull.new : value]}.to_h
|
256
|
+
|
257
|
+
template.render!(vars, strict_variables: true, strict_filters: true)
|
258
|
+
end
|
259
|
+
|
260
|
+
# @return [Array<Hash>] array of validation errors
|
261
|
+
def validate
|
262
|
+
result = validator.validate(fully_interpolated_yaml)
|
263
|
+
store_failures(result)
|
264
|
+
result
|
265
|
+
end
|
266
|
+
|
267
|
+
# @return [Kontena::Cli::Stacks::YAML::ValidatorV3]
|
268
|
+
def validator
|
269
|
+
@validator ||= YAML::ValidatorV3.new
|
270
|
+
end
|
271
|
+
|
272
|
+
def parse_volumes
|
273
|
+
volumes.each do |name, config|
|
274
|
+
if process_hash?(config)
|
275
|
+
volumes[name].delete('only_if')
|
276
|
+
volumes[name].delete('skip_if')
|
277
|
+
volumes[name] = process_volume(name, config)
|
278
|
+
else
|
279
|
+
volumes.delete(name)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
volumes.map { |name, vol| vol.merge('name' => name) }
|
283
|
+
end
|
284
|
+
|
285
|
+
##
|
286
|
+
# @param [String] service_name - optional service to parse
|
287
|
+
# @return [Hash]
|
288
|
+
def parse_services(service_name = nil)
|
289
|
+
services = self.services.dup # do not modify the fully_interpolated_yaml['services'] hash in-place
|
290
|
+
if service_name.nil?
|
291
|
+
services.each do |name, config|
|
292
|
+
services[name] = process_config(config, name)
|
293
|
+
if process_hash?(config)
|
294
|
+
services[name].delete('only_if')
|
295
|
+
services[name].delete('skip_if')
|
296
|
+
else
|
297
|
+
services.delete(name)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
services.map { |name, svc| svc.merge('name' => name) }
|
301
|
+
else
|
302
|
+
raise ("Service '#{service_name}' not found in #{file}") unless services.key?(service_name)
|
303
|
+
process_config(services[service_name], service_name)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
# If the supplied hash contains skip_if/only_if conditionals, process that conditional and return true/false
|
308
|
+
#
|
309
|
+
# @param [Hash]
|
310
|
+
# @return [Boolean]
|
311
|
+
def process_hash?(hash)
|
312
|
+
return true unless hash['skip_if'] || hash['only_if']
|
313
|
+
|
314
|
+
skip_lambdas = normalize_ifs(hash['skip_if'])
|
315
|
+
only_lambdas = normalize_ifs(hash['only_if'])
|
316
|
+
|
317
|
+
if skip_lambdas
|
318
|
+
return false if skip_lambdas.any? { |s| s.call }
|
319
|
+
end
|
320
|
+
|
321
|
+
if only_lambdas
|
322
|
+
return false unless only_lambdas.all? { |s| s.call }
|
323
|
+
end
|
324
|
+
|
325
|
+
true
|
326
|
+
end
|
327
|
+
|
328
|
+
# @param [Hash] service_config
|
329
|
+
def process_config(service_config, name=nil)
|
330
|
+
normalize_env_vars(service_config)
|
331
|
+
merge_env_vars(service_config)
|
332
|
+
expand_build_context(service_config)
|
333
|
+
normalize_build_args(service_config)
|
334
|
+
if service_config.key?('extends')
|
335
|
+
service_config = extend_config(service_config)
|
336
|
+
service_config.delete('extends')
|
337
|
+
end
|
338
|
+
if name
|
339
|
+
ServiceGeneratorV2.new(service_config).generate.merge('name' => name)
|
340
|
+
else
|
341
|
+
ServiceGeneratorV2.new(service_config).generate
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def process_volume(name, volume_config)
|
346
|
+
return [] if volume_config.nil? || volume_config.empty?
|
347
|
+
if volume_config['external'].is_a?(TrueClass)
|
348
|
+
volume_config['external'] = name
|
349
|
+
elsif volume_config['external']['name']
|
350
|
+
volume_config['external'] = volume_config['external']['name']
|
351
|
+
end
|
352
|
+
volume_config['name'] = name
|
353
|
+
volume_config
|
354
|
+
end
|
355
|
+
|
356
|
+
def volumes
|
357
|
+
@volumes ||= fully_interpolated_yaml.fetch('volumes', {})
|
358
|
+
end
|
359
|
+
|
360
|
+
# @return [Hash] - services from YAML file
|
361
|
+
def services
|
362
|
+
@services ||= fully_interpolated_yaml.fetch('services', {})
|
363
|
+
end
|
364
|
+
|
365
|
+
def from_external_stack(name, service_name)
|
366
|
+
external_reader = StackFileLoader.for(name, loader).reader
|
367
|
+
variables.to_a(with_value: true).each do |var|
|
368
|
+
external_reader.variables.build_option(var)
|
369
|
+
end
|
370
|
+
outcome = external_reader.execute(service_name)
|
371
|
+
errors.concat external_reader.errors unless external_reader.errors.empty? || errors.include?(external_reader.errors)
|
372
|
+
notifications.concat external_reader.notifications unless external_reader.notifications.empty? || notifications.include?(external_reader.notifications)
|
373
|
+
outcome['services']
|
374
|
+
end
|
375
|
+
|
376
|
+
private
|
377
|
+
|
378
|
+
##
|
379
|
+
# @param [String] content - content of YAML file
|
380
|
+
def interpolate(content, use_opto: true, substitutions: {}, raise_on_unknown: false, warnings: true)
|
381
|
+
content.split(/[\r\n]/).map.with_index do |row, line_num|
|
382
|
+
# skip lines that opto may be interpolating
|
383
|
+
if row.strip.start_with?('interpolate:') || row.strip.start_with?('evaluate:')
|
384
|
+
row
|
385
|
+
else
|
386
|
+
row.gsub(/(?<!\$)\$(?!\$)\{?\w+\}?/) do |v| # searches $VAR and ${VAR} and not $$VAR
|
387
|
+
var = v.tr('${}', '')
|
388
|
+
|
389
|
+
if use_opto
|
390
|
+
opt = variables.option(var)
|
391
|
+
if opt.nil?
|
392
|
+
to_env = variables.find { |opt| Array(opt.to[:env]).include?(var) }
|
393
|
+
if to_env
|
394
|
+
val = to_env.value
|
395
|
+
else
|
396
|
+
raise RuntimeError, "Undeclared variable '#{var}' in #{file}:#{line_num} -- #{row}" if raise_on_unknown
|
397
|
+
end
|
398
|
+
else
|
399
|
+
val = opt.value
|
400
|
+
end
|
401
|
+
else
|
402
|
+
val = substitutions[var]
|
403
|
+
end
|
404
|
+
|
405
|
+
if val && !val.to_s.empty?
|
406
|
+
val.to_s =~ /[\r\n\"\'\|]/ ? val.inspect : val.to_s
|
407
|
+
else
|
408
|
+
puts "Value for #{var} is not set. Substituting with an empty string." if warnings
|
409
|
+
''
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end.join("\n")
|
414
|
+
end
|
415
|
+
|
416
|
+
##
|
417
|
+
# @param [String] text - content of yaml file
|
418
|
+
def replace_dollar_dollars(text)
|
419
|
+
text.gsub('$$', '$')
|
420
|
+
end
|
421
|
+
|
422
|
+
# Generates an array of lambdas that return true if a condition is true
|
423
|
+
# Possible syntaxes:
|
424
|
+
# @example
|
425
|
+
# normalize_ifs( 'wp' ) # lambdas return true if variable wp is not null or false or 'false'
|
426
|
+
# normalize_ifs( wp: 1 ) # lambdas return true if value of wp is 1
|
427
|
+
# normalize_ifs( ['wp, :ws'] ) # lambdas return true if wp and ws are not not null or false or 'false'
|
428
|
+
# normalize_ifs( wp: 1, ws: 1) # lambdas return true if wp and ws are 1
|
429
|
+
# normalize_ifs(nil) # returns nil
|
430
|
+
def normalize_ifs(ifs)
|
431
|
+
case ifs
|
432
|
+
when NilClass
|
433
|
+
nil
|
434
|
+
when Array
|
435
|
+
ifs.map do |iff|
|
436
|
+
lambda { val = variables.value_of(iff.to_s); !val.nil? && !val.kind_of?(FalseClass) && val != 'false' }
|
437
|
+
end
|
438
|
+
when Hash
|
439
|
+
ifs.each_with_object([]) do |(k, v), arr|
|
440
|
+
arr << lambda { variables.value_of(k.to_s) == v }
|
441
|
+
end
|
442
|
+
when String, Symbol
|
443
|
+
[lambda { val = variables.value_of(ifs.to_s); !val.nil? && !val.kind_of?(FalseClass) && val != 'false' }]
|
444
|
+
else
|
445
|
+
raise TypeError, "Invalid syntax for if: #{ifs.inspect}"
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
# @param [Hash] service_config
|
450
|
+
# @return [Hash] updated service config
|
451
|
+
def extend_config(service_config)
|
452
|
+
extends = service_config['extends']
|
453
|
+
case extends
|
454
|
+
when NilClass
|
455
|
+
return
|
456
|
+
when String
|
457
|
+
raise ("Service '#{extends}' not found in #{file}") unless services.key?(extends)
|
458
|
+
parent_config = process_config(services[extends])
|
459
|
+
when Hash
|
460
|
+
target = extends['file'] || extends['stack']
|
461
|
+
raise ("Service '#{extends}' does not define file: or stack: source") if target.nil?
|
462
|
+
parent_config = from_external_stack(target, extends['service'])
|
463
|
+
else
|
464
|
+
raise TypeError, "Extends must be a hash or string"
|
465
|
+
end
|
466
|
+
ServiceExtender.new(service_config).extend_from(parent_config)
|
467
|
+
end
|
468
|
+
|
469
|
+
def store_failures(data)
|
470
|
+
data['errors'] ||= data[:errors] || []
|
471
|
+
data['notifications'] ||= data[:notifications] || []
|
472
|
+
errors << { File.basename(file) => data['errors'] } unless data['errors'].empty?
|
473
|
+
notifications << { File.basename(file) => data['notifications'] } unless data['notifications'].empty?
|
474
|
+
end
|
475
|
+
|
476
|
+
# @param [Hash] options - service config
|
477
|
+
def normalize_env_vars(options)
|
478
|
+
if options['environment'].kind_of?(Hash)
|
479
|
+
options['environment'] = options['environment'].map { |k, v| "#{k}=#{v}" }
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
# @param [Hash] options
|
484
|
+
def merge_env_vars(options)
|
485
|
+
return options['environment'] unless options['env_file']
|
486
|
+
|
487
|
+
options['env_file'] = [options['env_file']] if options['env_file'].kind_of?(String)
|
488
|
+
options['environment'] = [] unless options['environment']
|
489
|
+
options['env_file'].each do |env_file|
|
490
|
+
options['environment'].concat(read_env_file(env_file))
|
491
|
+
end
|
492
|
+
options.delete('env_file')
|
493
|
+
options['environment'].uniq! { |s| s.split('=').first }
|
494
|
+
end
|
495
|
+
|
496
|
+
# @param [String] path
|
497
|
+
def read_env_file(path)
|
498
|
+
File.readlines(path).map { |line| line.strip }.reject { |line| line.start_with?('#') || line.empty? }
|
499
|
+
end
|
500
|
+
|
501
|
+
def expand_build_context(options)
|
502
|
+
if options['build'].kind_of?(String)
|
503
|
+
options['build'] = File.expand_path(options['build'])
|
504
|
+
elsif context = safe_dig(options, 'build', 'context')
|
505
|
+
options['build']['context'] = File.expand_path(context)
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
# @param [Hash] options - service config
|
510
|
+
def normalize_build_args(options)
|
511
|
+
build = options['build']
|
512
|
+
return unless build.kind_of?(Hash)
|
513
|
+
args = build['args']
|
514
|
+
return unless args
|
515
|
+
return unless args.kind_of?(Array)
|
516
|
+
build.delete('args')
|
517
|
+
build['args'] = args.map { |arg| arg.split('=', 2) }.to_h
|
518
|
+
end
|
519
|
+
|
520
|
+
def env
|
521
|
+
ENV
|
522
|
+
end
|
523
|
+
end
|
524
|
+
end
|
525
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Kontena::Cli::Stacks
|
2
|
+
module YAML
|
3
|
+
class ServiceExtender
|
4
|
+
include Kontena::Util
|
5
|
+
attr_reader :service_config
|
6
|
+
|
7
|
+
# @param [Hash] service_config
|
8
|
+
def initialize(service_config)
|
9
|
+
@service_config = service_config
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param [Hash] from
|
13
|
+
# @return [Hash]
|
14
|
+
def extend_from(from)
|
15
|
+
service_config['environment'] = extend_env_vars(from['env'], service_config['environment'])
|
16
|
+
service_config['secrets'] = extend_secrets( from['secrets'], service_config['secrets'])
|
17
|
+
build_args = extend_build_args(safe_dig(from, 'build', 'args'), safe_dig(service_config, 'build', 'args'))
|
18
|
+
unless build_args.empty?
|
19
|
+
service_config['build'] ||= {}
|
20
|
+
service_config['build']['args'] = build_args
|
21
|
+
end
|
22
|
+
from.merge(service_config)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def env_to_hash(env_array)
|
28
|
+
env_array.map { |env| env.split('=', 2) }.to_h
|
29
|
+
end
|
30
|
+
|
31
|
+
# Takes two arrays of "key=value" pairs and merges them. Keys in "from"-array
|
32
|
+
# will not overwrite keys that already exist in "to"-array.
|
33
|
+
#
|
34
|
+
# @param [Array] from
|
35
|
+
# @param [Array] to
|
36
|
+
# @return [Array]
|
37
|
+
def extend_env_vars(from, to)
|
38
|
+
env_to_hash(from || []).merge(env_to_hash(to || [])).map { |k,v| [k.to_s, v.to_s].join('=') }
|
39
|
+
end
|
40
|
+
|
41
|
+
# Takes two arrays of hashes containing { 'secret' => 'str', 'type' => 'str', 'name' => 'str' }
|
42
|
+
# and merges them. 'secret' is the primary key, secrets found in "to" are not overwritten.
|
43
|
+
#
|
44
|
+
# @param [Array] from
|
45
|
+
# @param [Array] to
|
46
|
+
# @return [Array]
|
47
|
+
def extend_secrets(from, to)
|
48
|
+
from ||= []
|
49
|
+
to ||= []
|
50
|
+
uniq_from = []
|
51
|
+
from.each do |from_hash|
|
52
|
+
uniq_from << from_hash unless to.find {|to_hash| from_hash['secret'] == to_hash['secret'] }
|
53
|
+
end
|
54
|
+
to + uniq_from
|
55
|
+
end
|
56
|
+
|
57
|
+
# Basic merge of two hashes, "to" is dominant.
|
58
|
+
def extend_build_args(from, to)
|
59
|
+
from ||= {}
|
60
|
+
to ||= {}
|
61
|
+
from.merge(to)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Kontena::Cli::Stacks
|
4
|
+
module YAML
|
5
|
+
class FileLoader < StackFileLoader
|
6
|
+
def self.match?(source, parent = nil)
|
7
|
+
::File.exist?(with_context(source, parent))
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.is_file?(parent)
|
11
|
+
parent.is_a?(FileLoader)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.with_context(source, parent = nil)
|
15
|
+
if is_file?(parent)
|
16
|
+
File.join(File.dirname(parent.source), source)
|
17
|
+
else
|
18
|
+
File.absolute_path(source)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(*args)
|
23
|
+
super
|
24
|
+
@source = self.class.with_context(@source, @parent)
|
25
|
+
end
|
26
|
+
|
27
|
+
def read_content
|
28
|
+
::File.read(source)
|
29
|
+
end
|
30
|
+
|
31
|
+
def origin
|
32
|
+
"file"
|
33
|
+
end
|
34
|
+
|
35
|
+
def registry
|
36
|
+
"file://"
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Kontena::Cli::Stacks
|
2
|
+
module YAML
|
3
|
+
class RegistryLoader < StackFileLoader
|
4
|
+
def self.match?(source, parent = nil)
|
5
|
+
source =~ /\A[a-zA-Z0-9\_\.\-]+\/[a-zA-Z0-9\_\.\-]+(?::.*)?\z/ && !FileLoader.match?(source, parent)
|
6
|
+
end
|
7
|
+
|
8
|
+
def read_content
|
9
|
+
Kontena::StacksCache.pull(Kontena::Cli::Stacks::StackName.new(source))
|
10
|
+
end
|
11
|
+
|
12
|
+
def origin
|
13
|
+
"registry"
|
14
|
+
end
|
15
|
+
|
16
|
+
def registry
|
17
|
+
account = Kontena::Cli::Config.current_account
|
18
|
+
raise "Current account not set" if account.nil?
|
19
|
+
account.stacks_url
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Kontena::Cli::Stacks
|
2
|
+
module YAML
|
3
|
+
class UriLoader < StackFileLoader
|
4
|
+
def self.match?(source, parent = nil)
|
5
|
+
source.include?('://') && !FileLoader.match?(source, parent)
|
6
|
+
end
|
7
|
+
|
8
|
+
def read_content
|
9
|
+
require 'open-uri'
|
10
|
+
stream = open(source)
|
11
|
+
stream.read
|
12
|
+
end
|
13
|
+
|
14
|
+
def origin
|
15
|
+
"uri"
|
16
|
+
end
|
17
|
+
|
18
|
+
def registry
|
19
|
+
"file://"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|