kontena-cli 1.0.0.pre2 → 1.0.0.pre3
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 +4 -4
- data/VERSION +1 -1
- data/lib/kontena/callbacks/master/deploy/70_invite_self_after_deploy.rb +2 -1
- data/lib/kontena/cli/master/users/invite_command.rb +6 -2
- data/lib/kontena/cli/stack_command.rb +12 -18
- data/lib/kontena/cli/stacks/build_command.rb +3 -1
- data/lib/kontena/cli/stacks/common.rb +17 -0
- data/lib/kontena/cli/stacks/deploy_command.rb +11 -10
- data/lib/kontena/cli/stacks/install_command.rb +8 -5
- data/lib/kontena/cli/stacks/list_command.rb +3 -0
- data/lib/kontena/cli/stacks/logs_command.rb +6 -4
- data/lib/kontena/cli/stacks/monitor_command.rb +10 -9
- data/lib/kontena/cli/stacks/registry/pull_command.rb +28 -0
- data/lib/kontena/cli/stacks/registry/push_command.rb +22 -0
- data/lib/kontena/cli/stacks/registry/remove_command.rb +30 -0
- data/lib/kontena/cli/stacks/registry/search_command.rb +24 -0
- data/lib/kontena/cli/stacks/registry/show_command.rb +28 -0
- data/lib/kontena/cli/stacks/registry_command.rb +17 -0
- data/lib/kontena/cli/stacks/remove_command.rb +11 -9
- data/lib/kontena/cli/stacks/show_command.rb +11 -10
- data/lib/kontena/cli/stacks/upgrade_command.rb +8 -5
- data/lib/kontena/cli/stacks/yaml/custom_validators/extends_validator.rb +2 -1
- data/lib/kontena/cli/stacks/yaml/reader.rb +24 -6
- data/lib/kontena/command.rb +9 -3
- data/lib/kontena/stacks_cache.rb +35 -9
- data/lib/kontena/stacks_client.rb +17 -13
- data/spec/fixtures/stack-with-ifs.yml +51 -0
- data/spec/kontena/cli/master/users/invite_command_spec.rb +1 -2
- data/spec/kontena/cli/stacks/deploy_command_spec.rb +2 -2
- data/spec/kontena/cli/stacks/install_command_spec.rb +2 -2
- data/spec/kontena/cli/stacks/remove_command_spec.rb +2 -2
- data/spec/kontena/cli/stacks/show_command_spec.rb +2 -2
- data/spec/kontena/cli/stacks/upgrade_command_spec.rb +2 -4
- metadata +9 -4
- data/lib/kontena/cli/stacks/pull_command.rb +0 -12
- data/lib/kontena/cli/stacks/push_command.rb +0 -17
- data/lib/kontena/cli/stacks/search_command.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ba22a3516366cf0d4cb3d9b44e4460984a0cabf
|
4
|
+
data.tar.gz: 9e220dd6c8231906600723523ca8e59badc537ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4088c0e1841b305ff61091f29adcae757045ecdf629840dd0988c83efc91e4b63d22e993c6766c3c36642c5e0fcdca3a48ef4a3e8c4ce405d73c0f1d6a9e9d9a
|
7
|
+
data.tar.gz: c15c7cee466cd4510f09616651d1ade116ba0b62e2c7dc8c6d415b630d88efbd88a665058dc2e474176dfbc1d846c454411cca16a80d0827c486d66bb10aa86d
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.0.
|
1
|
+
1.0.0.pre3
|
@@ -17,6 +17,7 @@ module Kontena
|
|
17
17
|
if response && response.kind_of?(Hash) && response.has_key?('data') && response['data'].has_key?('attributes')
|
18
18
|
user_data[:email] = response['data']['attributes']['email']
|
19
19
|
user_data[:username] = response['data']['attributes']['username']
|
20
|
+
user_data[:id] = response['data']['id']
|
20
21
|
user_data[:verified] = response['data']['attributes']['verified']
|
21
22
|
@cloud_user_data = user_data
|
22
23
|
end
|
@@ -32,7 +33,7 @@ module Kontena
|
|
32
33
|
|
33
34
|
invite_response = nil
|
34
35
|
spinner "Creating user #{cloud_user_data[:email]} into Kontena Master" do |spin|
|
35
|
-
invite_response = Kontena.run("master users invite --return #{cloud_user_data[:email].shellescape}", returning: :result)
|
36
|
+
invite_response = Kontena.run("master users invite --external-id #{cloud_user_data[:id]} --return #{cloud_user_data[:email].shellescape}", returning: :result)
|
36
37
|
unless invite_response.kind_of?(Hash) && invite_response.has_key?('invite_code')
|
37
38
|
spin.fail
|
38
39
|
end
|
@@ -9,6 +9,7 @@ module Kontena::Cli::Master::Users
|
|
9
9
|
|
10
10
|
option ['-r', '--roles'], '[ROLES]', 'Comma separated list of roles to assign to the invited users'
|
11
11
|
option ['-c', '--code'], :flag, 'Only output the invite code'
|
12
|
+
option '--external-id', '[EXTERNAL ID]', 'Assign external id to user', hidden: true
|
12
13
|
option '--return', :flag, 'Return the code', hidden: true
|
13
14
|
|
14
15
|
requires_current_master
|
@@ -20,10 +21,13 @@ module Kontena::Cli::Master::Users
|
|
20
21
|
else
|
21
22
|
roles = []
|
22
23
|
end
|
23
|
-
|
24
|
+
external_id = nil
|
25
|
+
if email_list.size == 1 && self.external_id
|
26
|
+
external_id = self.external_id
|
27
|
+
end
|
24
28
|
email_list.each do |email|
|
25
29
|
begin
|
26
|
-
data = { email: email, response_type: 'invite' }
|
30
|
+
data = { email: email, external_id: external_id, response_type: 'invite' }
|
27
31
|
response = client.post('/oauth2/authorize', data)
|
28
32
|
if self.code?
|
29
33
|
puts response['invite_code']
|
@@ -7,27 +7,21 @@ require_relative 'stacks/show_command'
|
|
7
7
|
require_relative 'stacks/build_command'
|
8
8
|
require_relative 'stacks/monitor_command'
|
9
9
|
require_relative 'stacks/logs_command'
|
10
|
-
require_relative 'stacks/
|
11
|
-
require_relative 'stacks/pull_command'
|
12
|
-
require_relative 'stacks/search_command'
|
13
|
-
require_relative 'stacks/install_command'
|
10
|
+
require_relative 'stacks/registry_command'
|
14
11
|
|
15
12
|
class Kontena::Cli::StackCommand < Kontena::Command
|
16
13
|
|
17
|
-
subcommand "install", "Install a stack", Kontena::Cli::Stacks::InstallCommand
|
18
|
-
subcommand "
|
19
|
-
subcommand ["
|
20
|
-
subcommand "show", "Show stack
|
21
|
-
subcommand "upgrade", "Upgrade
|
22
|
-
subcommand "deploy", "Deploy stack", Kontena::Cli::Stacks::DeployCommand
|
23
|
-
subcommand "logs", "Show logs from stack
|
24
|
-
subcommand "monitor", "Monitor stack
|
25
|
-
subcommand
|
26
|
-
subcommand "
|
27
|
-
|
28
|
-
subcommand "install", "Deploy a stack to Kontena Master", Kontena::Cli::Stacks::InstallCommand
|
29
|
-
subcommand "search", "Search for stacks in stacks repository", Kontena::Cli::Stacks::SearchCommand
|
30
|
-
|
14
|
+
subcommand "install", "Install a stack to a grid", Kontena::Cli::Stacks::InstallCommand
|
15
|
+
subcommand ["ls", "list"], "List installed stacks in a grid", Kontena::Cli::Stacks::ListCommand
|
16
|
+
subcommand ["remove","rm"], "Remove a deployed stack from a grid", Kontena::Cli::Stacks::RemoveCommand
|
17
|
+
subcommand "show", "Show details about a stack in a grid", Kontena::Cli::Stacks::ShowCommand
|
18
|
+
subcommand "upgrade", "Upgrade a stack in a grid", Kontena::Cli::Stacks::UpgradeCommand
|
19
|
+
subcommand ["start", "deploy"], "Deploy an installed stack in a grid", Kontena::Cli::Stacks::DeployCommand
|
20
|
+
subcommand "logs", "Show logs from services in a stack", Kontena::Cli::Stacks::LogsCommand
|
21
|
+
subcommand "monitor", "Monitor services in a stack", Kontena::Cli::Stacks::MonitorCommand
|
22
|
+
subcommand "build", "Build images listed in a stack file and push them to an image registry", Kontena::Cli::Stacks::BuildCommand
|
23
|
+
subcommand "registry", "Stack registry related commands", Kontena::Cli::Stacks::RegistryCommand
|
24
|
+
|
31
25
|
def execute
|
32
26
|
end
|
33
27
|
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
require_relative 'common'
|
2
2
|
|
3
3
|
module Kontena::Cli::Stacks
|
4
|
-
class BuildCommand <
|
4
|
+
class BuildCommand < Kontena::Command
|
5
5
|
include Kontena::Cli::Common
|
6
6
|
include Common
|
7
7
|
|
8
|
+
banner "Build images listed in a stack file and push them to your image registry"
|
9
|
+
|
8
10
|
option ['-f', '--file'], 'FILE', 'Specify an alternate Kontena compose file', attribute_name: :filename, default: 'kontena.yml'
|
9
11
|
option ['--no-cache'], :flag, 'Do not use cache when building the image', default: false
|
10
12
|
option ['--no-push'], :flag, 'Do not push images to registry', default: false
|
@@ -7,6 +7,23 @@ module Kontena::Cli::Stacks
|
|
7
7
|
module Common
|
8
8
|
include Kontena::Cli::Services::ServicesHelper
|
9
9
|
|
10
|
+
module StackNameParam
|
11
|
+
attr_accessor :stack_version
|
12
|
+
|
13
|
+
def self.included(where)
|
14
|
+
where.parameter "STACK_NAME", "Stack name, for example user/stackname or user/stackname:version" do |name|
|
15
|
+
if name.include?(':')
|
16
|
+
name, @stack_version = name.split(':',2 )
|
17
|
+
end
|
18
|
+
name
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def stack_name
|
24
|
+
@stack_name ||= self.name || stack_name_from_yaml(filename)
|
25
|
+
end
|
26
|
+
|
10
27
|
def stack_from_yaml(filename)
|
11
28
|
reader = Kontena::Cli::Stacks::YAML::Reader.new(filename)
|
12
29
|
if reader.stack_name.nil?
|
@@ -6,33 +6,34 @@ module Kontena::Cli::Stacks
|
|
6
6
|
include Kontena::Cli::GridOptions
|
7
7
|
include Common
|
8
8
|
|
9
|
+
banner "Deploys all services of a stack that has been installed in a grid on Kontena Master"
|
10
|
+
|
9
11
|
parameter "NAME", "Stack name"
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
token = require_token
|
13
|
+
requires_current_master
|
14
|
+
requires_current_master_token
|
14
15
|
|
16
|
+
def execute
|
15
17
|
deployment = nil
|
16
18
|
spinner "Deploying stack #{pastel.cyan(name)}" do
|
17
|
-
deployment = deploy_stack(
|
19
|
+
deployment = deploy_stack(name)
|
18
20
|
deployment['service_deploys'].each do |service_deploy|
|
19
|
-
wait_for_deploy_to_finish(
|
21
|
+
wait_for_deploy_to_finish(service_deploy)
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
|
-
def deploy_stack(
|
25
|
-
client
|
26
|
+
def deploy_stack(name)
|
27
|
+
client.post("stacks/#{current_grid}/#{name}/deploy", {})
|
26
28
|
end
|
27
29
|
|
28
|
-
# @param [String] token
|
29
30
|
# @param [Hash] deployment
|
30
31
|
# @return [Boolean]
|
31
|
-
def wait_for_deploy_to_finish(
|
32
|
+
def wait_for_deploy_to_finish(deployment, timeout = 600)
|
32
33
|
deployed = false
|
33
34
|
Timeout::timeout(timeout) do
|
34
35
|
until deployed
|
35
|
-
deployment = client
|
36
|
+
deployment = client.get("services/#{deployment['service_id']}/deploys/#{deployment['id']}")
|
36
37
|
deployed = true if deployment['finished_at']
|
37
38
|
sleep 1
|
38
39
|
end
|
@@ -6,25 +6,28 @@ module Kontena::Cli::Stacks
|
|
6
6
|
include Kontena::Cli::GridOptions
|
7
7
|
include Common
|
8
8
|
|
9
|
+
banner "Installs a stack to a grid on Kontena Master"
|
10
|
+
|
9
11
|
parameter "[FILE]", "Kontena stack file", default: "kontena.yml", attribute_name: :filename
|
10
12
|
|
11
13
|
option ['-n', '--name'], 'NAME', 'Define stack name (by default comes from stack file)'
|
12
14
|
option '--deploy', :flag, 'Deploy after installation'
|
13
15
|
|
16
|
+
requires_current_master
|
17
|
+
requires_current_master_token
|
18
|
+
|
14
19
|
def execute
|
15
|
-
require_api_url
|
16
|
-
token = require_token
|
17
20
|
require_config_file(filename)
|
18
21
|
stack = stack_from_yaml(filename)
|
19
22
|
stack['name'] = name if name
|
20
23
|
spinner "Creating stack #{pastel.cyan(stack['name'])} " do
|
21
|
-
create_stack(
|
24
|
+
create_stack(stack)
|
22
25
|
end
|
23
26
|
Kontena.run("stack deploy #{stack['name']}") if deploy?
|
24
27
|
end
|
25
28
|
|
26
|
-
def create_stack(
|
27
|
-
client
|
29
|
+
def create_stack(stack)
|
30
|
+
client.post("grids/#{current_grid}/stacks", stack)
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|
@@ -1,18 +1,20 @@
|
|
1
1
|
module Kontena::Cli::Stacks
|
2
|
-
class LogsCommand <
|
2
|
+
class LogsCommand < Kontena::Command
|
3
3
|
include Kontena::Cli::Common
|
4
4
|
include Kontena::Cli::GridOptions
|
5
5
|
include Kontena::Cli::Helpers::LogHelper
|
6
6
|
|
7
|
+
banner "Shows logs from services in a stack"
|
8
|
+
|
7
9
|
parameter "NAME", "Stack name"
|
8
10
|
option ["-t", "--tail"], :flag, "Tail (follow) logs", default: false
|
9
11
|
option ["-l", "--lines"], "LINES", "How many lines to show", default: '100'
|
10
12
|
option "--since", "SINCE", "Show logs since given timestamp"
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
token = require_token
|
14
|
+
requires_current_master
|
15
|
+
requires_current_master_token
|
15
16
|
|
17
|
+
def execute
|
16
18
|
query_params = {}
|
17
19
|
query_params[:limit] = lines if lines
|
18
20
|
query_params[:since] = since if since
|
@@ -1,33 +1,34 @@
|
|
1
1
|
require_relative 'common'
|
2
2
|
|
3
3
|
module Kontena::Cli::Stacks
|
4
|
-
class MonitorCommand <
|
4
|
+
class MonitorCommand < Kontena::Command
|
5
5
|
include Kontena::Cli::Common
|
6
6
|
include Kontena::Cli::GridOptions
|
7
7
|
include Common
|
8
8
|
|
9
|
+
banner "Monitor services in a stack"
|
10
|
+
|
9
11
|
parameter "NAME", "Stack name"
|
10
12
|
parameter "[SERVICES] ...", "Stack services to monitor", attribute_name: 'selected_services'
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
token = require_token
|
14
|
+
requires_current_master
|
15
|
+
requires_current_master_token
|
15
16
|
|
16
|
-
|
17
|
+
def execute
|
18
|
+
response = client.get("grids/#{current_grid}/services?stack=#{name}")
|
17
19
|
services = response['services']
|
18
20
|
if selected_services.size > 0
|
19
21
|
services.delete_if{ |s| !selected_services.include?(s['name'])}
|
20
22
|
end
|
21
|
-
show_monitor(
|
23
|
+
show_monitor(services)
|
22
24
|
end
|
23
25
|
|
24
|
-
# @param [String] token
|
25
26
|
# @param [Array<Hash>]
|
26
|
-
def show_monitor(
|
27
|
+
def show_monitor(services)
|
27
28
|
loop do
|
28
29
|
nodes = {}
|
29
30
|
services.each do |service|
|
30
|
-
result = client
|
31
|
+
result = client.get("services/#{service['id']}/containers") rescue nil
|
31
32
|
service['instances'] = 0
|
32
33
|
if result
|
33
34
|
service['instances'] = result['containers'].size
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative '../common'
|
2
|
+
|
3
|
+
module Kontena::Cli::Stacks::Registry
|
4
|
+
class PullCommand < Kontena::Command
|
5
|
+
include Kontena::Cli::Common
|
6
|
+
include Kontena::Cli::Stacks::Common
|
7
|
+
include Kontena::Cli::Stacks::Common::StackNameParam
|
8
|
+
|
9
|
+
banner "Pulls / downloads a stack from the stack registry"
|
10
|
+
|
11
|
+
option ['-F', '--file'], '[FILENAME]', "Write to file (default STDOUT)"
|
12
|
+
option '--no-cache', :flag, "Don't use local cache"
|
13
|
+
option '--return', :flag, 'Return the result', hidden: true
|
14
|
+
|
15
|
+
def execute
|
16
|
+
target = no_cache? ? stacks_client : Kontena::StacksCache
|
17
|
+
content = target.pull(stack_name, stack_version)
|
18
|
+
if return?
|
19
|
+
return content
|
20
|
+
elsif file
|
21
|
+
File.write(file, content)
|
22
|
+
puts pastel.green("Wrote #{content.bytesize} bytes to #{file}")
|
23
|
+
else
|
24
|
+
puts content
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative '../common'
|
2
|
+
|
3
|
+
module Kontena::Cli::Stacks::Registry
|
4
|
+
class PushCommand < Kontena::Command
|
5
|
+
include Kontena::Cli::Common
|
6
|
+
include Kontena::Cli::Stacks::Common
|
7
|
+
|
8
|
+
banner "Pushes (uploads) a stack to the stack registry"
|
9
|
+
|
10
|
+
parameter "FILENAME", "Stack file path"
|
11
|
+
|
12
|
+
requires_current_account_token
|
13
|
+
|
14
|
+
def execute
|
15
|
+
file = Kontena::Cli::Stacks::YAML::Reader.new(filename, skip_variables: true, replace_missing: "filler")
|
16
|
+
name = "#{file.yaml['stack']}:#{file.yaml['version']}"
|
17
|
+
spinner("Pushing #{pastel.cyan(name)} to stacks registry") do
|
18
|
+
stacks_client.push(file.yaml['stack'], file.yaml['version'], file.raw_content)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative '../common'
|
2
|
+
|
3
|
+
module Kontena::Cli::Stacks::Registry
|
4
|
+
class RemoveCommand < Kontena::Command
|
5
|
+
include Kontena::Cli::Common
|
6
|
+
include Kontena::Cli::Stacks::Common
|
7
|
+
include Kontena::Cli::Stacks::Common::StackNameParam
|
8
|
+
|
9
|
+
banner "Removes a stack (or version) from the stack registry. Use user/stack_name or user/stack_name:version."
|
10
|
+
|
11
|
+
option ['-f', '--force'], :flag, "Force delete"
|
12
|
+
|
13
|
+
requires_current_account_token
|
14
|
+
|
15
|
+
def execute
|
16
|
+
unless force?
|
17
|
+
if stack_version
|
18
|
+
puts "About to delete #{pastel.cyan("#{stack_name}:#{stack_version}")} from the stacks registry"
|
19
|
+
confirm
|
20
|
+
else
|
21
|
+
puts "About to delete an entire stack and all of its versions from the stacks registry"
|
22
|
+
confirm_command(stack_name)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
spinner "Removing #{pastel.cyan(stack_name)} from the registry" do
|
26
|
+
stacks_client.destroy(stack_name, stack_version)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative '../common'
|
2
|
+
|
3
|
+
module Kontena::Cli::Stacks::Registry
|
4
|
+
class SearchCommand < Kontena::Command
|
5
|
+
include Kontena::Cli::Common
|
6
|
+
include Kontena::Cli::Stacks::Common
|
7
|
+
|
8
|
+
banner "Search for stacks on the stack registry"
|
9
|
+
|
10
|
+
parameter "[QUERY]", "Query string"
|
11
|
+
|
12
|
+
def execute
|
13
|
+
results = stacks_client.search(query.to_s)
|
14
|
+
exit_with_error 'Nothing found' if results.empty?
|
15
|
+
titles = ['NAME', 'VERSION', 'DESCRIPTION']
|
16
|
+
columns = "%-40s %-10s %-40s"
|
17
|
+
puts columns % titles
|
18
|
+
results.each do |stack|
|
19
|
+
stack = ::YAML.load(stacks_client.show(stack['name'])) rescue nil
|
20
|
+
puts columns % [stack['stack'], stack['version'], stack['description'] || '-'] if stack
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative '../common'
|
2
|
+
|
3
|
+
module Kontena::Cli::Stacks::Registry
|
4
|
+
class ShowCommand < Kontena::Command
|
5
|
+
include Kontena::Cli::Common
|
6
|
+
include Kontena::Cli::Stacks::Common
|
7
|
+
include Kontena::Cli::Stacks::Common::StackNameParam
|
8
|
+
|
9
|
+
banner "Shows information about a stack on the stacks registry"
|
10
|
+
|
11
|
+
option ['-v', '--versions'], :flag, "Only list available versions"
|
12
|
+
|
13
|
+
requires_current_account_token
|
14
|
+
|
15
|
+
def execute
|
16
|
+
stack = ::YAML.load(stacks_client.show(stack_name))
|
17
|
+
puts "#{stack['stack']}:"
|
18
|
+
puts " latest_version: #{stack['version']}"
|
19
|
+
puts " expose: #{stack['expose'] || '-'}"
|
20
|
+
puts " description: #{stack['description'] || '-'}"
|
21
|
+
|
22
|
+
puts " available_versions:"
|
23
|
+
stacks_client.versions(stack_name).map { |s| s['version']}.sort.reverse_each do |version|
|
24
|
+
puts " - #{version}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Kontena::Cli::Stacks
|
2
|
+
|
3
|
+
require_relative 'registry/push_command'
|
4
|
+
require_relative 'registry/pull_command'
|
5
|
+
require_relative 'registry/search_command'
|
6
|
+
require_relative 'registry/show_command'
|
7
|
+
require_relative 'registry/remove_command'
|
8
|
+
|
9
|
+
class RegistryCommand < Kontena::Command
|
10
|
+
|
11
|
+
subcommand "push", "Push a stack into the stacks registry", Registry::PushCommand
|
12
|
+
subcommand "pull", "Pull a stack from the stacks registry", Registry::PullCommand
|
13
|
+
subcommand "search", "Search for stacks in the stacks registry", Registry::SearchCommand
|
14
|
+
subcommand "show", "Show info about a stack in the stacks registry", Registry::ShowCommand
|
15
|
+
subcommand ["remove", "rm"], "Remove a stack (or version) from the stacks registry", Registry::RemoveCommand
|
16
|
+
end
|
17
|
+
end
|
@@ -6,29 +6,31 @@ module Kontena::Cli::Stacks
|
|
6
6
|
include Kontena::Cli::GridOptions
|
7
7
|
include Common
|
8
8
|
|
9
|
+
banner "Removes a stack in a grid on Kontena Master"
|
10
|
+
|
9
11
|
parameter "NAME", "Stack name"
|
10
12
|
option "--force", :flag, "Force remove", default: false, attribute_name: :forced
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
token = require_token
|
14
|
+
requires_current_master
|
15
|
+
requires_current_master_token
|
15
16
|
|
17
|
+
def execute
|
16
18
|
confirm_command(name) unless forced?
|
17
19
|
spinner "Removing stack #{pastel.cyan(name)} " do
|
18
|
-
remove_stack(
|
19
|
-
wait_stack_removal(
|
20
|
+
remove_stack(name)
|
21
|
+
wait_stack_removal(name)
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
|
-
def remove_stack(
|
24
|
-
client
|
25
|
+
def remove_stack(name)
|
26
|
+
client.delete("stacks/#{current_grid}/#{name}")
|
25
27
|
end
|
26
28
|
|
27
|
-
def wait_stack_removal(
|
29
|
+
def wait_stack_removal(name)
|
28
30
|
removed = false
|
29
31
|
until removed == true
|
30
32
|
begin
|
31
|
-
client
|
33
|
+
client.get("stacks/#{current_grid}/#{name}")
|
32
34
|
sleep 1
|
33
35
|
rescue Kontena::Errors::StandardError => exc
|
34
36
|
if exc.status == 404
|
@@ -6,17 +6,19 @@ module Kontena::Cli::Stacks
|
|
6
6
|
include Kontena::Cli::GridOptions
|
7
7
|
include Common
|
8
8
|
|
9
|
+
banner "Show information and status of a stack in a grid on Kontena Master"
|
10
|
+
|
9
11
|
parameter "NAME", "Stack name"
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
token = require_token
|
13
|
+
requires_current_master
|
14
|
+
requires_current_master_token
|
14
15
|
|
15
|
-
|
16
|
+
def execute
|
17
|
+
show_stack(name)
|
16
18
|
end
|
17
19
|
|
18
|
-
def show_stack(
|
19
|
-
stack = client
|
20
|
+
def show_stack(name)
|
21
|
+
stack = client.get("stacks/#{current_grid}/#{name}")
|
20
22
|
|
21
23
|
puts "#{stack['name']}:"
|
22
24
|
puts " state: #{stack['state']}"
|
@@ -26,14 +28,13 @@ module Kontena::Cli::Stacks
|
|
26
28
|
puts " expose: #{stack['expose'] || '-'}"
|
27
29
|
puts " services:"
|
28
30
|
stack['services'].each do |service|
|
29
|
-
show_service(
|
31
|
+
show_service(service['id'])
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
|
-
# @param [String] token
|
34
35
|
# @param [String] service_id
|
35
|
-
def show_service(
|
36
|
-
service = get_service(
|
36
|
+
def show_service(service_id)
|
37
|
+
service = get_service(service_id)
|
37
38
|
pad = ' '.freeze
|
38
39
|
puts "#{pad}#{service['name']}:"
|
39
40
|
puts "#{pad} image: #{service['image']}"
|
@@ -6,23 +6,26 @@ module Kontena::Cli::Stacks
|
|
6
6
|
include Kontena::Cli::GridOptions
|
7
7
|
include Common
|
8
8
|
|
9
|
+
banner "Upgrades a stack in a grid on Kontena Master"
|
10
|
+
|
9
11
|
parameter "NAME", "Stack name"
|
10
12
|
parameter "[FILE]", "Kontena stack file", default: "kontena.yml"
|
11
13
|
option '--deploy', :flag, 'Deploy after upgrade'
|
12
14
|
|
15
|
+
requires_current_master
|
16
|
+
requires_current_master_token
|
17
|
+
|
13
18
|
def execute
|
14
|
-
require_api_url
|
15
|
-
token = require_token
|
16
19
|
require_config_file(file)
|
17
20
|
stack = stack_from_yaml(file)
|
18
21
|
spinner "Upgrading stack #{pastel.cyan(name)} " do
|
19
|
-
update_stack(
|
22
|
+
update_stack(stack)
|
20
23
|
end
|
21
24
|
Kontena.run("stack deploy #{name}") if deploy?
|
22
25
|
end
|
23
26
|
|
24
|
-
def update_stack(
|
25
|
-
client
|
27
|
+
def update_stack(stack)
|
28
|
+
client.put("stacks/#{current_grid}/#{name}", stack)
|
26
29
|
end
|
27
30
|
end
|
28
31
|
end
|
@@ -12,7 +12,8 @@ module Kontena::Cli::Stacks::YAML::Validations::CustomValidators
|
|
12
12
|
if value.is_a?(Hash)
|
13
13
|
extends_validation = {
|
14
14
|
'service' => 'string',
|
15
|
-
'file' => HashValidator.optional('string')
|
15
|
+
'file' => HashValidator.optional('string'),
|
16
|
+
'stack' => HashValidator.optional('string')
|
16
17
|
}
|
17
18
|
HashValidator.validator_for(extends_validation).validate(key, value, extends_validation, errors)
|
18
19
|
end
|
@@ -4,10 +4,11 @@ module Kontena::Cli::Stacks
|
|
4
4
|
module YAML
|
5
5
|
class Reader
|
6
6
|
include Kontena::Util
|
7
|
+
include Kontena::Cli::Common
|
7
8
|
|
8
9
|
attr_reader :file, :raw_content, :result, :errors, :notifications, :variables, :yaml
|
9
10
|
|
10
|
-
def initialize(file, skip_validation: false, skip_variables: false, replace_missing: nil)
|
11
|
+
def initialize(file, skip_validation: false, skip_variables: false, replace_missing: nil, from_registry: false)
|
11
12
|
require 'yaml'
|
12
13
|
require_relative 'service_extender'
|
13
14
|
require_relative 'validator_v3'
|
@@ -17,7 +18,16 @@ module Kontena::Cli::Stacks
|
|
17
18
|
require_relative 'opto/prompt_resolver'
|
18
19
|
|
19
20
|
@file = file
|
20
|
-
@
|
21
|
+
@from_registry = from_registry
|
22
|
+
|
23
|
+
if from_registry?
|
24
|
+
require 'shellwords'
|
25
|
+
@raw_content = Kontena::StacksCache.pull(file)
|
26
|
+
@registry = Kontena::StacksCache::RegistryClientFactory.new.stacks_client.api_url
|
27
|
+
else
|
28
|
+
@raw_content = File.read(File.expand_path(file))
|
29
|
+
end
|
30
|
+
|
21
31
|
@errors = []
|
22
32
|
@notifications = []
|
23
33
|
@skip_validation = skip_validation
|
@@ -27,6 +37,10 @@ module Kontena::Cli::Stacks
|
|
27
37
|
parse_yaml
|
28
38
|
end
|
29
39
|
|
40
|
+
def from_registry?
|
41
|
+
@from_registry == true
|
42
|
+
end
|
43
|
+
|
30
44
|
# @return [Opto::Group]
|
31
45
|
def variables
|
32
46
|
return @variables if @variables
|
@@ -49,10 +63,11 @@ module Kontena::Cli::Stacks
|
|
49
63
|
# @return [Hash]
|
50
64
|
def execute(service_name = nil)
|
51
65
|
result = {}
|
52
|
-
Dir.chdir(File.dirname(File.expand_path(file))) do
|
66
|
+
Dir.chdir(from_registry? ? Dir.pwd : File.dirname(File.expand_path(file))) do
|
53
67
|
result[:stack] = yaml['stack']
|
54
68
|
result[:version] = self.stack_version
|
55
69
|
result[:name] = self.stack_name
|
70
|
+
result[:registry] = @registry if from_registry?
|
56
71
|
result[:expose] = yaml['expose']
|
57
72
|
result[:errors] = errors unless skip_validation?
|
58
73
|
result[:notifications] = notifications
|
@@ -239,9 +254,12 @@ module Kontena::Cli::Stacks
|
|
239
254
|
def extend_config(service_config)
|
240
255
|
extended_service = extended_service(service_config['extends'])
|
241
256
|
return unless extended_service
|
242
|
-
filename
|
257
|
+
filename = service_config['extends']['file']
|
258
|
+
stackname = service_config['extends']['stack']
|
243
259
|
if filename
|
244
260
|
parent_config = from_external_file(filename, extended_service)
|
261
|
+
elsif stackname
|
262
|
+
parent_config = from_external_file(stackname, extended_service, from_registry: true)
|
245
263
|
else
|
246
264
|
raise ("Service '#{extended_service}' not found in #{file}") unless services.has_key?(extended_service)
|
247
265
|
parent_config = process_config(services[extended_service])
|
@@ -259,8 +277,8 @@ module Kontena::Cli::Stacks
|
|
259
277
|
end
|
260
278
|
end
|
261
279
|
|
262
|
-
def from_external_file(filename, service_name)
|
263
|
-
outcome = Reader.new(filename, skip_validation: @skip_validation, skip_variables: true, replace_missing: @replace_missing).execute(service_name)
|
280
|
+
def from_external_file(filename, service_name, from_registry: false)
|
281
|
+
outcome = Reader.new(filename, skip_validation: @skip_validation, skip_variables: true, replace_missing: @replace_missing, from_registry: from_registry).execute(service_name)
|
264
282
|
errors.concat outcome[:errors] unless errors.any? { |item| item.has_key?(filename) }
|
265
283
|
notifications.concat outcome[:notifications] unless notifications.any? { |item| item.has_key?(filename) }
|
266
284
|
outcome[:services]
|
data/lib/kontena/command.rb
CHANGED
@@ -91,17 +91,23 @@ class Kontena::Command < Clamp::Command
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def self.requires_current_master
|
94
|
-
|
94
|
+
unless Kontena::Cli::Config.current_master
|
95
|
+
banner "#{Kontena.pastel.green("Requires current master")}: This command requires that you have selected a current master using 'kontena master login' or 'kontena master use'. You can also use the environment variable KONTENA_URL to specify the master address or KONTENA_MASTER=master_name to override the current_master setting."
|
96
|
+
end
|
95
97
|
@requires_current_master = true
|
96
98
|
end
|
97
99
|
|
98
100
|
def self.requires_current_grid
|
99
|
-
|
101
|
+
unless Kontena::Cli::Config.current_grid
|
102
|
+
banner "#{Kontena.pastel.green("Requires current grid")}: This command requires that you have selected a grid as the current grid using 'kontena grid use' or by setting KONTENA_GRID environment variable."
|
103
|
+
end
|
100
104
|
@requires_current_grid = true
|
101
105
|
end
|
102
106
|
|
103
107
|
def self.requires_current_account_token
|
104
|
-
|
108
|
+
unless Kontena::Cli::Config.current_account && Kontena::Cli::Config.current_account.token && Kontena::Cli::Config.current_account.token.access_token
|
109
|
+
banner "#{Kontena.pastel.green("Requires account authentication")}: This command requires that you have authenticated to Kontena Cloud using 'kontena cloud auth'"
|
110
|
+
end
|
105
111
|
@requires_current_account_token = true
|
106
112
|
end
|
107
113
|
|
data/lib/kontena/stacks_cache.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
require_relative 'stacks_client'
|
2
2
|
require_relative 'cli/common'
|
3
3
|
require_relative 'cli/stacks/common'
|
4
|
+
require 'yaml'
|
4
5
|
|
5
6
|
module Kontena
|
6
7
|
class StacksCache
|
7
8
|
class CachedStack
|
8
9
|
|
9
|
-
|
10
|
-
|
10
|
+
attr_accessor :stack
|
11
|
+
attr_accessor :version
|
11
12
|
|
12
13
|
def initialize(stack, version = nil)
|
13
14
|
unless version
|
@@ -15,7 +16,6 @@ module Kontena
|
|
15
16
|
end
|
16
17
|
@stack = stack
|
17
18
|
@version = version
|
18
|
-
raise ArgumentError, "Stack name and version required" unless @stack && @version
|
19
19
|
end
|
20
20
|
|
21
21
|
def read
|
@@ -27,6 +27,11 @@ module Kontena
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def write(content)
|
30
|
+
raise ArgumentError, "Stack name and version required" unless @stack && @version
|
31
|
+
unless File.directory?(File.dirname(path))
|
32
|
+
require 'fileutils'
|
33
|
+
FileUtils.mkdir_p(File.dirname(path))
|
34
|
+
end
|
30
35
|
File.write(path, content)
|
31
36
|
end
|
32
37
|
|
@@ -35,14 +40,14 @@ module Kontena
|
|
35
40
|
end
|
36
41
|
|
37
42
|
def cached?
|
43
|
+
return false unless version
|
38
44
|
File.exist?(path)
|
39
45
|
end
|
40
46
|
|
41
47
|
def path
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
@path
|
48
|
+
path = File.expand_path(File.join(base_path, "#{stack}-#{version}.yml"))
|
49
|
+
raise "Path traversal attempted" unless path.start_with?(base_path)
|
50
|
+
path
|
46
51
|
end
|
47
52
|
|
48
53
|
private
|
@@ -58,13 +63,34 @@ module Kontena
|
|
58
63
|
end
|
59
64
|
|
60
65
|
class << self
|
61
|
-
def
|
66
|
+
def pull(stack, version = nil)
|
62
67
|
cache(stack, version).read
|
63
68
|
end
|
64
69
|
|
70
|
+
def dputs(msg)
|
71
|
+
ENV["DEBUG"] && puts(msg)
|
72
|
+
end
|
73
|
+
|
65
74
|
def cache(stack, version = nil)
|
66
75
|
stack = CachedStack.new(stack, version)
|
67
|
-
|
76
|
+
if stack.cached?
|
77
|
+
dputs "Reading from cache: #{stack.path}"
|
78
|
+
else
|
79
|
+
dputs "Retrieving #{stack.stack}:#{stack.version} from registry"
|
80
|
+
content = client.pull(stack.stack, stack.version)
|
81
|
+
yaml = ::YAML.load(content)
|
82
|
+
new_stack = CachedStack.new(yaml['stack'], yaml['version'])
|
83
|
+
if new_stack.cached?
|
84
|
+
dputs "Already cached"
|
85
|
+
stack = new_stack
|
86
|
+
else
|
87
|
+
stack.stack = yaml['stack']
|
88
|
+
stack.version = yaml['version']
|
89
|
+
dputs "Writing #{stack.path}"
|
90
|
+
stack.write(content)
|
91
|
+
dputs "#{stack.stack}:#{stack.version} cached to #{stack.path}"
|
92
|
+
end
|
93
|
+
end
|
68
94
|
stack
|
69
95
|
end
|
70
96
|
|
@@ -7,31 +7,35 @@ module Kontena
|
|
7
7
|
ACCEPT_YAML = { 'Accept' => 'application/yaml' }
|
8
8
|
CT_YAML = { 'Content-Type' => 'application/yaml' }
|
9
9
|
|
10
|
-
def path_to(
|
11
|
-
version ? "/stack/#{
|
10
|
+
def path_to(stack_name, version = nil)
|
11
|
+
version ? "/stack/#{stack_name}/version/#{version}" : "/stack/#{stack_name}"
|
12
12
|
end
|
13
13
|
|
14
|
-
def push(
|
14
|
+
def push(stack_name, version, data)
|
15
15
|
post('/stack/', data, {}, CT_YAML)
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
19
|
-
get(path_to(
|
18
|
+
def show(stack_name)
|
19
|
+
get("#{path_to(stack_name, nil)}", {}, ACCEPT_JSON)
|
20
|
+
end
|
21
|
+
|
22
|
+
def versions(stack_name)
|
23
|
+
get("#{path_to(stack_name, nil)}/versions", {}, ACCEPT_JSON)['versions']
|
24
|
+
end
|
25
|
+
|
26
|
+
def pull(stack_name, version = nil)
|
27
|
+
get(path_to(stack_name, version), {}, ACCEPT_YAML)
|
20
28
|
rescue StandardError => ex
|
21
|
-
ex.message << " : #{path_to(
|
29
|
+
ex.message << " : #{path_to(stack_name, version)}"
|
22
30
|
raise ex, ex.message
|
23
31
|
end
|
24
32
|
|
25
33
|
def search(query)
|
26
|
-
get('/search', { q: query }, {}, ACCEPT_JSON)
|
27
|
-
end
|
28
|
-
|
29
|
-
def versions(repo_name)
|
30
|
-
get("#{path_to(repo_name)}/versions", {}, ACCEPT_JSON)
|
34
|
+
get('/search', { q: query }, {}, ACCEPT_JSON)['stacks']
|
31
35
|
end
|
32
36
|
|
33
|
-
def destroy(
|
34
|
-
delete(path_to(
|
37
|
+
def destroy(stack_name, version = nil)
|
38
|
+
delete(path_to(stack_name, version), {})
|
35
39
|
end
|
36
40
|
end
|
37
41
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
stack: user/stackname
|
2
|
+
version: 0.1.1
|
3
|
+
variables:
|
4
|
+
db:
|
5
|
+
type: enum
|
6
|
+
required: true
|
7
|
+
options:
|
8
|
+
- value: mysql
|
9
|
+
label: MySQL
|
10
|
+
description: Regular MySQL
|
11
|
+
- value: galera
|
12
|
+
label: Galera cluster
|
13
|
+
description: A mega super galera cluster
|
14
|
+
from: prompt
|
15
|
+
GALERA_NODES:
|
16
|
+
type: integer
|
17
|
+
min: 1
|
18
|
+
from:
|
19
|
+
prompt: Number of Galera nodes
|
20
|
+
only_if:
|
21
|
+
db: galera
|
22
|
+
no_wp:
|
23
|
+
type: boolean
|
24
|
+
as: boolean # default boolean output is string
|
25
|
+
from:
|
26
|
+
prompt: Skip wordpress?
|
27
|
+
services:
|
28
|
+
wordpress:
|
29
|
+
skip_if: no_wp
|
30
|
+
extends:
|
31
|
+
file: docker-compose_v2.yml
|
32
|
+
service: wordpress
|
33
|
+
image: wordpress
|
34
|
+
stateful: true
|
35
|
+
deploy:
|
36
|
+
strategy: ha
|
37
|
+
mysql:
|
38
|
+
only_if:
|
39
|
+
db: mysql
|
40
|
+
extends:
|
41
|
+
file: docker-compose_v2.yml
|
42
|
+
service: mysql
|
43
|
+
image: mysql
|
44
|
+
galera:
|
45
|
+
only_if:
|
46
|
+
db: galera
|
47
|
+
extends:
|
48
|
+
file: docker-compose_v2.yml
|
49
|
+
service: mysql
|
50
|
+
image: galera
|
51
|
+
instances: $GALERA_NODES
|
@@ -12,8 +12,7 @@ describe Kontena::Cli::Master::Users::InviteCommand do
|
|
12
12
|
|
13
13
|
describe "#invite" do
|
14
14
|
it 'makes invitation request for all given users' do
|
15
|
-
expect(client).to receive(:post).with("/oauth2/authorize", {email: 'john@example.org', response_type: "invite"}).once
|
16
|
-
expect(client).to receive(:post).with("/oauth2/authorize", {email: 'jane@example.org', response_type: "invite"}).once
|
15
|
+
expect(client).to receive(:post).with("/oauth2/authorize", {email: 'john@example.org', external_id: nil, response_type: "invite"}).once
|
17
16
|
|
18
17
|
subject.run(['john@example.org', 'jane@example.org'])
|
19
18
|
end
|
@@ -7,12 +7,12 @@ describe Kontena::Cli::Stacks::DeployCommand do
|
|
7
7
|
|
8
8
|
describe '#execute' do
|
9
9
|
it 'requires api url' do
|
10
|
-
expect(
|
10
|
+
expect(described_class.requires_current_master?).to be_truthy
|
11
11
|
subject.run(['test-stack'])
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'requires token' do
|
15
|
-
expect(
|
15
|
+
expect(described_class.requires_current_master_token?).to be_truthy
|
16
16
|
subject.run(['test-stack'])
|
17
17
|
end
|
18
18
|
|
@@ -21,13 +21,13 @@ describe Kontena::Cli::Stacks::InstallCommand do
|
|
21
21
|
|
22
22
|
it 'requires api url' do
|
23
23
|
allow(subject).to receive(:stack_from_yaml).with('kontena.yml').and_return(stack)
|
24
|
-
expect(
|
24
|
+
expect(described_class.requires_current_master?).to be_truthy
|
25
25
|
subject.run([])
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'requires token' do
|
29
29
|
allow(subject).to receive(:stack_from_yaml).with('kontena.yml').and_return(stack)
|
30
|
-
expect(
|
30
|
+
expect(described_class.requires_current_master_token?).to be_truthy
|
31
31
|
subject.run([])
|
32
32
|
end
|
33
33
|
|
@@ -9,14 +9,14 @@ describe Kontena::Cli::Stacks::RemoveCommand do
|
|
9
9
|
it 'requires api url' do
|
10
10
|
allow(subject).to receive(:forced?).and_return(true)
|
11
11
|
allow(subject).to receive(:wait_stack_removal)
|
12
|
-
expect(
|
12
|
+
expect(described_class.requires_current_master?).to be_truthy
|
13
13
|
subject.run(['test-stack'])
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'requires token' do
|
17
17
|
allow(subject).to receive(:forced?).and_return(true)
|
18
18
|
allow(subject).to receive(:wait_stack_removal)
|
19
|
-
expect(
|
19
|
+
expect(described_class.requires_current_master_token?).to be_truthy
|
20
20
|
subject.run(['test-stack'])
|
21
21
|
end
|
22
22
|
|
@@ -8,13 +8,13 @@ describe Kontena::Cli::Stacks::ShowCommand do
|
|
8
8
|
describe '#execute' do
|
9
9
|
it 'requires api url' do
|
10
10
|
allow(subject).to receive(:forced?).and_return(true)
|
11
|
-
expect(
|
11
|
+
expect(described_class.requires_current_master?).to be_truthy
|
12
12
|
subject.run(['test-stack'])
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'requires token' do
|
16
16
|
allow(subject).to receive(:forced?).and_return(true)
|
17
|
-
expect(
|
17
|
+
expect(described_class.requires_current_master_token?).to be_truthy
|
18
18
|
subject.run(['test-stack'])
|
19
19
|
end
|
20
20
|
|
@@ -17,26 +17,24 @@ describe Kontena::Cli::Stacks::UpgradeCommand do
|
|
17
17
|
it 'requires api url' do
|
18
18
|
allow(subject).to receive(:require_config_file).and_return(true)
|
19
19
|
allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml').and_return(stack)
|
20
|
-
expect(
|
20
|
+
expect(described_class.requires_current_master?).to be_truthy
|
21
21
|
subject.run(['stack-name', './path/to/kontena.yml'])
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'requires token' do
|
25
25
|
allow(subject).to receive(:require_config_file).and_return(true)
|
26
26
|
allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml').and_return(stack)
|
27
|
-
expect(
|
27
|
+
expect(described_class.requires_current_master_token?).to be_truthy
|
28
28
|
subject.run(['stack-name', './path/to/kontena.yml'])
|
29
29
|
end
|
30
30
|
|
31
31
|
it 'requires stack file' do
|
32
32
|
allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml').and_return(stack)
|
33
|
-
allow(subject).to receive(:require_token).and_return(token)
|
34
33
|
expect(subject).to receive(:require_config_file).with('./path/to/kontena.yml').and_return(true)
|
35
34
|
subject.run(['stack-name', './path/to/kontena.yml'])
|
36
35
|
end
|
37
36
|
|
38
37
|
it 'uses kontena.yml as default stack file' do
|
39
|
-
allow(subject).to receive(:require_token).and_return(token)
|
40
38
|
expect(subject).to receive(:require_config_file).with('kontena.yml').and_return(true)
|
41
39
|
expect(subject).to receive(:stack_from_yaml).with('kontena.yml').and_return(stack)
|
42
40
|
subject.run(['stack-name'])
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kontena-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.pre3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kontena, Inc
|
@@ -370,10 +370,13 @@ files:
|
|
370
370
|
- lib/kontena/cli/stacks/list_command.rb
|
371
371
|
- lib/kontena/cli/stacks/logs_command.rb
|
372
372
|
- lib/kontena/cli/stacks/monitor_command.rb
|
373
|
-
- lib/kontena/cli/stacks/pull_command.rb
|
374
|
-
- lib/kontena/cli/stacks/push_command.rb
|
373
|
+
- lib/kontena/cli/stacks/registry/pull_command.rb
|
374
|
+
- lib/kontena/cli/stacks/registry/push_command.rb
|
375
|
+
- lib/kontena/cli/stacks/registry/remove_command.rb
|
376
|
+
- lib/kontena/cli/stacks/registry/search_command.rb
|
377
|
+
- lib/kontena/cli/stacks/registry/show_command.rb
|
378
|
+
- lib/kontena/cli/stacks/registry_command.rb
|
375
379
|
- lib/kontena/cli/stacks/remove_command.rb
|
376
|
-
- lib/kontena/cli/stacks/search_command.rb
|
377
380
|
- lib/kontena/cli/stacks/service_generator.rb
|
378
381
|
- lib/kontena/cli/stacks/service_generator_v2.rb
|
379
382
|
- lib/kontena/cli/stacks/show_command.rb
|
@@ -442,6 +445,7 @@ files:
|
|
442
445
|
- spec/fixtures/stack-internal-extend.yml
|
443
446
|
- spec/fixtures/stack-invalid.yml
|
444
447
|
- spec/fixtures/stack-with-env-file.yml
|
448
|
+
- spec/fixtures/stack-with-ifs.yml
|
445
449
|
- spec/fixtures/stack-with-prompted-variables.yml
|
446
450
|
- spec/fixtures/stack-with-variables.yml
|
447
451
|
- spec/fixtures/wordpress-scaled.yml
|
@@ -556,6 +560,7 @@ test_files:
|
|
556
560
|
- spec/fixtures/stack-internal-extend.yml
|
557
561
|
- spec/fixtures/stack-invalid.yml
|
558
562
|
- spec/fixtures/stack-with-env-file.yml
|
563
|
+
- spec/fixtures/stack-with-ifs.yml
|
559
564
|
- spec/fixtures/stack-with-prompted-variables.yml
|
560
565
|
- spec/fixtures/stack-with-variables.yml
|
561
566
|
- spec/fixtures/wordpress-scaled.yml
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require_relative 'common'
|
2
|
-
|
3
|
-
module Kontena::Cli::Stacks
|
4
|
-
class PushCommand < Kontena::Command
|
5
|
-
include Kontena::Cli::Common
|
6
|
-
include Common
|
7
|
-
|
8
|
-
parameter "FILENAME", "Stack file path"
|
9
|
-
|
10
|
-
requires_current_account_token
|
11
|
-
|
12
|
-
def execute
|
13
|
-
file = YAML::Reader.new(self.filename, skip_variables: true, replace_missing: "filler")
|
14
|
-
stacks_client.push(file.yaml['stack'], file.yaml['version'], file.raw_content)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require_relative 'common'
|
2
|
-
|
3
|
-
module Kontena::Cli::Stacks
|
4
|
-
class SearchCommand < Kontena::Command
|
5
|
-
include Kontena::Cli::Common
|
6
|
-
include Common
|
7
|
-
|
8
|
-
parameter '[QUERY]', "Query string"
|
9
|
-
|
10
|
-
requires_current_account_token
|
11
|
-
|
12
|
-
def execute
|
13
|
-
puts stacks_client.search(query).inspect
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|