kontena-cli 1.0.0.pre2 → 1.0.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
|