kontena-cli 1.3.0.rc1 → 1.3.0.rc2
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/kontena-cli.gemspec +1 -1
- data/lib/kontena/cli/common.rb +23 -4
- data/lib/kontena/cli/containers/exec_command.rb +13 -8
- data/lib/kontena/cli/helpers/exec_helper.rb +12 -6
- data/lib/kontena/cli/master/join_command.rb +2 -2
- data/lib/kontena/cli/master/use_command.rb +12 -1
- data/lib/kontena/cli/nodes/list_command.rb +1 -2
- data/lib/kontena/cli/services/exec_command.rb +9 -11
- data/lib/kontena/cli/services/list_command.rb +2 -3
- data/lib/kontena/cli/stacks/list_command.rb +1 -2
- data/lib/kontena/cli/table_generator.rb +5 -3
- data/lib/kontena/errors.rb +1 -0
- data/lib/kontena/scripts/completer.rb +183 -142
- data/lib/kontena/websocket/client.rb +12 -0
- data/lib/kontena/websocket/client/connection.rb +65 -0
- data/lib/kontena_cli.rb +1 -2
- data/spec/kontena/cli/app/build_command_spec.rb +0 -12
- data/spec/kontena/cli/master/join_command_spec.rb +33 -0
- data/spec/kontena/cli/master/use_command_spec.rb +10 -0
- data/spec/kontena/cli/services/exec_command_spec.rb +21 -19
- metadata +11 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '09472d142a0b905453dae67fd9a5f773d8cacb78'
|
|
4
|
+
data.tar.gz: 0fbe77649ccdb7fcb79a5d15b093235ea1dee186
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 909d89da90b3b8101329c00bb5971200e8404368457e475620ff1a8f742ed4dcce1b1899fb6859bff861e0d7416f1b691d313ff532eb9675f3e68d2d1faa2b54
|
|
7
|
+
data.tar.gz: 542ec9dce844b9aa9e4e420c3f6dfcf610e65140f144ee531a777f8cdc3aa418eb672894287b2ffd934a2bd8af4456ed01411d00bcb00f0cbf1dee899adad79a
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.3.0.
|
|
1
|
+
1.3.0.rc2
|
data/kontena-cli.gemspec
CHANGED
|
@@ -34,5 +34,5 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
spec.add_runtime_dependency "safe_yaml", "~> 1.0"
|
|
35
35
|
spec.add_runtime_dependency "liquid", "~> 4.0.0"
|
|
36
36
|
spec.add_runtime_dependency "tty-table", "~> 0.8.0"
|
|
37
|
-
spec.add_runtime_dependency "websocket-
|
|
37
|
+
spec.add_runtime_dependency "websocket-driver-kontena", "0.6.5"
|
|
38
38
|
end
|
data/lib/kontena/cli/common.rb
CHANGED
|
@@ -1,22 +1,41 @@
|
|
|
1
1
|
require 'forwardable'
|
|
2
|
+
require 'kontena_cli'
|
|
2
3
|
|
|
3
4
|
module Kontena
|
|
4
5
|
module Cli
|
|
5
6
|
module Common
|
|
6
7
|
extend Forwardable
|
|
7
8
|
|
|
8
|
-
def_delegators :Kontena, :pastel, :prompt, :logger
|
|
9
9
|
def_delegators :prompt, :ask, :yes?
|
|
10
10
|
def_delegators :config,
|
|
11
11
|
:current_grid=, :require_current_grid, :current_master,
|
|
12
12
|
:current_master=, :require_current_master, :require_current_account,
|
|
13
13
|
:current_account
|
|
14
|
-
def_delegator Kontena::Cli::Spinner, :spin, :spinner
|
|
15
|
-
def_delegator Kontena::Cli::Config, :instance, :config
|
|
16
|
-
def_delegator Kontena::Cli::Config, :instance, :settings
|
|
17
14
|
def_delegator :config, :config_filename, :settings_filename
|
|
18
15
|
def_delegator :client, :server_version, :api_url_version
|
|
19
16
|
|
|
17
|
+
def logger
|
|
18
|
+
Kontena.logger
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def prompt
|
|
22
|
+
Kontena.prompt
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def pastel
|
|
26
|
+
Kontena.pastel
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def spinner(msg, &block)
|
|
30
|
+
require 'kontena/cli/spinner' unless Kontena::Cli.const_defined?(:Spinner)
|
|
31
|
+
Kontena::Cli::Spinner.spin(msg, &block)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def config
|
|
35
|
+
require 'kontena/cli/config' unless Kontena::Cli.const_defined?(:Config)
|
|
36
|
+
Kontena::Cli::Config.instance
|
|
37
|
+
end
|
|
38
|
+
|
|
20
39
|
# Read from STDIN. If stdin is a console, use prompt to ask.
|
|
21
40
|
# @param [String] message
|
|
22
41
|
# @param [Symbol] mode (prompt method: :ask, :multiline, etc)
|
|
@@ -13,23 +13,28 @@ module Kontena::Cli::Containers
|
|
|
13
13
|
option ["--interactive"], :flag, "Keep stdin open"
|
|
14
14
|
|
|
15
15
|
def execute
|
|
16
|
-
require 'websocket-client-simple'
|
|
17
|
-
|
|
18
16
|
require_api_url
|
|
19
17
|
token = require_token
|
|
20
18
|
cmd = JSON.dump({cmd: cmd_list})
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
url = ws_url("#{current_grid}/#{container_id}")
|
|
20
|
+
url << 'interactive=true&' if interactive?
|
|
21
|
+
url << 'shell=true' if shell?
|
|
22
|
+
ws = connect(url, token)
|
|
23
|
+
|
|
23
24
|
ws.on :message do |msg|
|
|
24
|
-
|
|
25
|
+
self.handle_message(msg)
|
|
25
26
|
end
|
|
26
27
|
ws.on :open do
|
|
27
|
-
ws.
|
|
28
|
+
ws.text(cmd)
|
|
28
29
|
end
|
|
29
30
|
ws.on :close do |e|
|
|
30
|
-
|
|
31
|
+
if e.reason.include?('code: 404')
|
|
32
|
+
exit_with_error('Not found')
|
|
33
|
+
else
|
|
34
|
+
exit 1
|
|
35
|
+
end
|
|
31
36
|
end
|
|
32
|
-
|
|
37
|
+
ws.connect
|
|
33
38
|
if interactive?
|
|
34
39
|
stream_stdin_to_ws(ws).join
|
|
35
40
|
else
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
require_relative '../../websocket/client'
|
|
2
|
+
|
|
1
3
|
module Kontena::Cli::Helpers
|
|
2
4
|
module ExecHelper
|
|
3
5
|
|
|
4
6
|
# @param [WebSocket::Client::Simple] ws
|
|
5
7
|
# @return [Thread]
|
|
6
8
|
def stream_stdin_to_ws(ws)
|
|
9
|
+
require 'io/console'
|
|
7
10
|
Thread.new {
|
|
8
11
|
STDIN.raw {
|
|
9
12
|
while char = STDIN.readpartial(1024)
|
|
10
|
-
ws.
|
|
13
|
+
ws.text(JSON.dump({ stdin: char }))
|
|
11
14
|
end
|
|
12
15
|
}
|
|
13
16
|
}
|
|
@@ -43,19 +46,22 @@ module Kontena::Cli::Helpers
|
|
|
43
46
|
def ws_url(container_id)
|
|
44
47
|
url = require_current_master.url
|
|
45
48
|
url << '/' unless url.end_with?('/')
|
|
46
|
-
"#{url.sub('http', 'ws')}v1/containers/#{container_id}/exec"
|
|
49
|
+
"#{url.sub('http', 'ws')}v1/containers/#{container_id}/exec?"
|
|
47
50
|
end
|
|
48
51
|
|
|
49
52
|
# @param [String] url
|
|
50
53
|
# @param [String] token
|
|
51
54
|
# @return [WebSocket::Client::Simple]
|
|
52
55
|
def connect(url, token)
|
|
53
|
-
|
|
56
|
+
options = {
|
|
54
57
|
headers: {
|
|
55
|
-
'Authorization' => "Bearer #{token.access_token}"
|
|
56
|
-
'Accept' => 'application/json'
|
|
58
|
+
'Authorization' => "Bearer #{token.access_token}"
|
|
57
59
|
}
|
|
58
|
-
}
|
|
60
|
+
}
|
|
61
|
+
if ENV['SSL_IGNORE_ERRORS'].to_s == 'true'
|
|
62
|
+
options[:verify_mode] = ::OpenSSL::SSL::VERIFY_NONE
|
|
63
|
+
end
|
|
64
|
+
Kontena::Websocket::Client.new(url, options)
|
|
59
65
|
end
|
|
60
66
|
end
|
|
61
67
|
end
|
|
@@ -9,9 +9,9 @@ module Kontena::Cli::Master
|
|
|
9
9
|
|
|
10
10
|
def execute
|
|
11
11
|
params = []
|
|
12
|
-
params
|
|
12
|
+
params += ["--join", self.invite_code]
|
|
13
13
|
params << "--remote" if self.remote?
|
|
14
|
-
params
|
|
14
|
+
params += ["--name", self.name] if self.name
|
|
15
15
|
params << "--verbose" if self.verbose?
|
|
16
16
|
|
|
17
17
|
cmd = ['master', 'login'] + params
|
|
@@ -2,9 +2,20 @@ module Kontena::Cli::Master
|
|
|
2
2
|
class UseCommand < Kontena::Command
|
|
3
3
|
include Kontena::Cli::Common
|
|
4
4
|
|
|
5
|
-
parameter "NAME", "Master name to use"
|
|
5
|
+
parameter "[NAME]", "Master name to use"
|
|
6
|
+
|
|
7
|
+
option '--clear', :flag, "Clear current master setting"
|
|
6
8
|
|
|
7
9
|
def execute
|
|
10
|
+
if clear?
|
|
11
|
+
config.current_master = nil
|
|
12
|
+
config.write
|
|
13
|
+
exit 0
|
|
14
|
+
elsif name.nil?
|
|
15
|
+
signal_usage_error Clamp.message(:parameter_argument_error, :param => 'NAME', :message => "missing")
|
|
16
|
+
exit 1
|
|
17
|
+
end
|
|
18
|
+
|
|
8
19
|
master = config.find_server(name)
|
|
9
20
|
if master.nil?
|
|
10
21
|
exit_with_error p"Could not resolve master by name '#{name}'." +
|
|
@@ -34,7 +34,6 @@ module Kontena::Cli::Nodes
|
|
|
34
34
|
def fields
|
|
35
35
|
return ['name'] if quiet?
|
|
36
36
|
{
|
|
37
|
-
' ' => 'health_icon',
|
|
38
37
|
name: 'name',
|
|
39
38
|
version: 'agent_version',
|
|
40
39
|
status: 'status',
|
|
@@ -67,7 +66,7 @@ module Kontena::Cli::Nodes
|
|
|
67
66
|
unless quiet?
|
|
68
67
|
grid_health = grid_health(grid, grid_nodes)
|
|
69
68
|
grid_nodes.each do |node|
|
|
70
|
-
node['
|
|
69
|
+
node['name'] = health_icon(node_health(node, grid_health)) + " " + node['name']
|
|
71
70
|
end
|
|
72
71
|
end
|
|
73
72
|
|
|
@@ -24,8 +24,6 @@ module Kontena::Cli::Services
|
|
|
24
24
|
requires_current_grid
|
|
25
25
|
|
|
26
26
|
def execute
|
|
27
|
-
require 'websocket-client-simple'
|
|
28
|
-
|
|
29
27
|
exit_with_error "--interactive cannot be used with --all" if all? && interactive?
|
|
30
28
|
|
|
31
29
|
service_containers = client.get("services/#{parse_service_id(name)}/containers")['containers']
|
|
@@ -92,7 +90,7 @@ module Kontena::Cli::Services
|
|
|
92
90
|
exit_status = nil
|
|
93
91
|
token = require_token
|
|
94
92
|
url = ws_url(container['id'])
|
|
95
|
-
url << '
|
|
93
|
+
url << 'shell=true' if shell?
|
|
96
94
|
ws = connect(url, token)
|
|
97
95
|
ws.on :message do |msg|
|
|
98
96
|
data = base.parse_message(msg)
|
|
@@ -107,11 +105,12 @@ module Kontena::Cli::Services
|
|
|
107
105
|
end
|
|
108
106
|
end
|
|
109
107
|
ws.on :open do
|
|
110
|
-
ws.
|
|
108
|
+
ws.text(cmd)
|
|
111
109
|
end
|
|
112
|
-
ws.on :close do |e|
|
|
113
|
-
exit_status = 1
|
|
110
|
+
ws.on :close do |e|s
|
|
111
|
+
exit_status = 1 if exit_status.nil? && e.code != 1000
|
|
114
112
|
end
|
|
113
|
+
ws.connect
|
|
115
114
|
|
|
116
115
|
sleep 0.01 until !exit_status.nil?
|
|
117
116
|
|
|
@@ -120,23 +119,22 @@ module Kontena::Cli::Services
|
|
|
120
119
|
|
|
121
120
|
# @param [Hash] container
|
|
122
121
|
def interactive_exec(container)
|
|
123
|
-
require 'io/console'
|
|
124
|
-
|
|
125
122
|
token = require_token
|
|
126
123
|
cmd = JSON.dump({ cmd: cmd_list })
|
|
127
124
|
base = self
|
|
128
|
-
url = ws_url(container['id']) << '
|
|
125
|
+
url = ws_url(container['id']) << 'interactive=true'
|
|
129
126
|
url << '&shell=true' if shell?
|
|
130
127
|
ws = connect(url, token)
|
|
131
128
|
ws.on :message do |msg|
|
|
132
129
|
base.handle_message(msg)
|
|
133
130
|
end
|
|
134
131
|
ws.on :open do
|
|
135
|
-
ws.
|
|
132
|
+
ws.text(cmd)
|
|
136
133
|
end
|
|
137
134
|
ws.on :close do |e|
|
|
138
|
-
exit 1
|
|
135
|
+
exit 1 if e.code != 1000
|
|
139
136
|
end
|
|
137
|
+
ws.connect
|
|
140
138
|
|
|
141
139
|
stream_stdin_to_ws(ws).join
|
|
142
140
|
end
|
|
@@ -17,7 +17,7 @@ module Kontena::Cli::Services
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def fields
|
|
20
|
-
quiet? ? ['name'] : {
|
|
20
|
+
quiet? ? ['name'] : {name: 'name', instances: 'instances', stateful: 'stateful', state: 'state', "exposed ports" => 'ports' }
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def service_port(port)
|
|
@@ -49,9 +49,8 @@ module Kontena::Cli::Services
|
|
|
49
49
|
|
|
50
50
|
def execute
|
|
51
51
|
print_table(services) do |row|
|
|
52
|
-
row['name'] = service_name(row)
|
|
52
|
+
row['name'] = quiet? ? service_name(row) : health_status_icon(health_status(row)) + " " + service_name(row)
|
|
53
53
|
next if quiet?
|
|
54
|
-
row['health_icon'] = health_status_icon(health_status(row))
|
|
55
54
|
row['stateful'] = row['stateful'] ? pastel.green('yes') : 'no'
|
|
56
55
|
row['ports'] = row['ports'].map(&method(:service_port)).join(',')
|
|
57
56
|
row['state'] = pastel.send(state_color(row['state']), row['state'])
|
|
@@ -26,7 +26,6 @@ module Kontena::Cli::Stacks
|
|
|
26
26
|
def fields
|
|
27
27
|
return ['name'] if quiet?
|
|
28
28
|
{
|
|
29
|
-
' ' => 'health_icon',
|
|
30
29
|
name: 'name',
|
|
31
30
|
stack: 'stack',
|
|
32
31
|
services: 'services_count',
|
|
@@ -38,7 +37,7 @@ module Kontena::Cli::Stacks
|
|
|
38
37
|
def execute
|
|
39
38
|
print_table(stacks) do |row|
|
|
40
39
|
next if quiet?
|
|
41
|
-
row['
|
|
40
|
+
row['name'] = health_icon(stack_health(row)) + " " + row['name']
|
|
42
41
|
row['stack'] = "#{row['stack']}:#{row['version']}"
|
|
43
42
|
row['services_count'] = row['services'].size
|
|
44
43
|
row['ports'] = stack_ports(row).join(',')
|
|
@@ -11,6 +11,8 @@ module Kontena
|
|
|
11
11
|
|
|
12
12
|
DEFAULT_HEADER_FORMAT_PROC = lambda { |header| header.to_s.capitalize }
|
|
13
13
|
|
|
14
|
+
DEFAULT_RENDER_OPTS = {padding: [0,2,0,0]}
|
|
15
|
+
|
|
14
16
|
module Helper
|
|
15
17
|
def self.included(base)
|
|
16
18
|
if base.respond_to?(:option)
|
|
@@ -28,8 +30,8 @@ module Kontena
|
|
|
28
30
|
array,
|
|
29
31
|
fields,
|
|
30
32
|
row_format_proc: block_given? ? block.to_proc : nil,
|
|
31
|
-
header_format_proc: lambda { |item| pastel.
|
|
32
|
-
render_options: self.respond_to?(:render_options) ? self.render_options :
|
|
33
|
+
header_format_proc: lambda { |item| pastel.bold(item.to_s.upcase) },
|
|
34
|
+
render_options: self.respond_to?(:render_options) ? DEFAULT_RENDER_OPTS.merge(self.render_options) : DEFAULT_RENDER_OPTS
|
|
33
35
|
).render
|
|
34
36
|
end
|
|
35
37
|
|
|
@@ -68,7 +70,7 @@ module Kontena
|
|
|
68
70
|
if data.empty?
|
|
69
71
|
fields.map(&method(:format_header_item)).join(' ')
|
|
70
72
|
else
|
|
71
|
-
table.render(render_mode, render_options)
|
|
73
|
+
table.render(render_mode, render_options).gsub(/\s+$/, '')
|
|
72
74
|
end
|
|
73
75
|
end
|
|
74
76
|
|
data/lib/kontena/errors.rb
CHANGED
|
@@ -1,18 +1,42 @@
|
|
|
1
|
-
require 'kontena/client'
|
|
2
1
|
require 'kontena/cli/common'
|
|
3
|
-
require 'yaml'
|
|
4
2
|
|
|
5
3
|
class Helper
|
|
6
4
|
include Kontena::Cli::Common
|
|
7
5
|
|
|
6
|
+
def client_config
|
|
7
|
+
require 'json'
|
|
8
|
+
config_file = File.expand_path('~/.kontena_client.json')
|
|
9
|
+
if(File.exist?(config_file))
|
|
10
|
+
JSON.parse(File.read(config_file))
|
|
11
|
+
else
|
|
12
|
+
{}
|
|
13
|
+
end
|
|
14
|
+
rescue => ex
|
|
15
|
+
logger.debug ex
|
|
16
|
+
{}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def current_grid
|
|
20
|
+
client_config['servers'].find { |s| s['name'] == client_config['current_server']}['grid']
|
|
21
|
+
rescue => ex
|
|
22
|
+
logger.debug ex
|
|
23
|
+
nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def current_master_name
|
|
27
|
+
client_config['current_server']
|
|
28
|
+
end
|
|
29
|
+
|
|
8
30
|
def client
|
|
31
|
+
$VERSION_WARNING_ADDED=true
|
|
9
32
|
token = require_token
|
|
10
33
|
super(token)
|
|
11
34
|
end
|
|
12
35
|
|
|
13
36
|
def grids
|
|
14
37
|
client.get("grids")['grids'].map{|grid| grid['id']}
|
|
15
|
-
rescue
|
|
38
|
+
rescue => ex
|
|
39
|
+
logger.debug ex
|
|
16
40
|
[]
|
|
17
41
|
end
|
|
18
42
|
|
|
@@ -28,7 +52,8 @@ class Helper
|
|
|
28
52
|
results.push stacks.map{|s| s['name']}
|
|
29
53
|
results.delete('null')
|
|
30
54
|
results
|
|
31
|
-
rescue
|
|
55
|
+
rescue => ex
|
|
56
|
+
logger.debug ex
|
|
32
57
|
[]
|
|
33
58
|
end
|
|
34
59
|
|
|
@@ -44,7 +69,8 @@ class Helper
|
|
|
44
69
|
end
|
|
45
70
|
}
|
|
46
71
|
results
|
|
47
|
-
rescue
|
|
72
|
+
rescue => ex
|
|
73
|
+
logger.debug ex
|
|
48
74
|
[]
|
|
49
75
|
end
|
|
50
76
|
|
|
@@ -56,33 +82,34 @@ class Helper
|
|
|
56
82
|
results.push(containers.map{|c| c['id'] })
|
|
57
83
|
end
|
|
58
84
|
results
|
|
59
|
-
rescue
|
|
85
|
+
rescue => ex
|
|
86
|
+
logger.debug ex
|
|
60
87
|
[]
|
|
61
88
|
end
|
|
62
89
|
|
|
63
90
|
def yml_services
|
|
91
|
+
require 'yaml'
|
|
64
92
|
if File.exist?('kontena.yml')
|
|
65
93
|
yaml = YAML.safe_load(File.read('kontena.yml'))
|
|
66
94
|
services = yaml['services']
|
|
67
95
|
services.keys
|
|
68
96
|
end
|
|
69
|
-
rescue
|
|
97
|
+
rescue => ex
|
|
98
|
+
logger.debug ex
|
|
70
99
|
[]
|
|
71
100
|
end
|
|
72
101
|
|
|
73
102
|
def yml_files
|
|
74
103
|
Dir["./*.yml"].map{|file| file.sub('./', '')}
|
|
75
|
-
rescue
|
|
104
|
+
rescue => ex
|
|
105
|
+
logger.debug ex
|
|
76
106
|
[]
|
|
77
107
|
end
|
|
78
108
|
|
|
79
109
|
def master_names
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return config['servers'].map{|s| s['name']}
|
|
84
|
-
end
|
|
85
|
-
rescue
|
|
110
|
+
client_config['servers'].map{|s| s['name']}
|
|
111
|
+
rescue => ex
|
|
112
|
+
logger.debug ex
|
|
86
113
|
[]
|
|
87
114
|
end
|
|
88
115
|
|
|
@@ -108,138 +135,152 @@ end
|
|
|
108
135
|
|
|
109
136
|
words.delete_at(0)
|
|
110
137
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
completion.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
when 'etcd'
|
|
124
|
-
completion.clear
|
|
125
|
-
sub_commands = %w(get set mkdir mk list ls rm)
|
|
126
|
-
if words[1]
|
|
127
|
-
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
128
|
-
else
|
|
129
|
-
completion.push sub_commands
|
|
130
|
-
end
|
|
131
|
-
when 'registry'
|
|
132
|
-
completion.clear
|
|
133
|
-
sub_commands = %w(create remove rm)
|
|
134
|
-
if words[1]
|
|
135
|
-
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
136
|
-
else
|
|
137
|
-
completion.push sub_commands
|
|
138
|
-
end
|
|
139
|
-
when 'grid'
|
|
140
|
-
completion.clear
|
|
141
|
-
sub_commands = %w(add-user audit-log create current list user remove show use)
|
|
142
|
-
if words[1]
|
|
143
|
-
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
144
|
-
completion.push helper.grids
|
|
145
|
-
else
|
|
146
|
-
completion.push sub_commands
|
|
147
|
-
end
|
|
148
|
-
when 'node'
|
|
149
|
-
completion.clear
|
|
150
|
-
sub_commands = %w(list show remove)
|
|
151
|
-
if words[1]
|
|
152
|
-
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
153
|
-
completion.push helper.nodes
|
|
154
|
-
else
|
|
155
|
-
completion.push sub_commands
|
|
156
|
-
end
|
|
157
|
-
when 'master'
|
|
158
|
-
completion.clear
|
|
159
|
-
sub_commands = %w(list use users current remove rm config cfg login logout token join audit-log init-cloud)
|
|
160
|
-
if words[1] && words[1] == 'use'
|
|
161
|
-
completion.push helper.master_names
|
|
162
|
-
elsif words[1] && words[1] == 'users'
|
|
163
|
-
users_sub_commands = %(invite list role)
|
|
164
|
-
completion.push users_sub_commands
|
|
165
|
-
elsif words[1] && ['config', 'cfg'].include?(words[1])
|
|
166
|
-
config_sub_commands = %(set get dump load import export unset)
|
|
167
|
-
completion.push config_sub_commands
|
|
168
|
-
elsif words[1] && words[1] == 'token'
|
|
169
|
-
token_sub_commands = %(list ls rm remove show current create)
|
|
170
|
-
completion.push token_sub_commands
|
|
171
|
-
elsif words[1]
|
|
172
|
-
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
173
|
-
else
|
|
174
|
-
completion.push sub_commands
|
|
175
|
-
end
|
|
176
|
-
when 'cloud'
|
|
177
|
-
completion.clear
|
|
178
|
-
sub_commands = %w(login logout master)
|
|
179
|
-
if words[1] && words[1] == 'master'
|
|
180
|
-
cloud_master_sub_commands = %(list ls remove rm add show update)
|
|
181
|
-
completion.push cloud_master_sub_commands
|
|
182
|
-
elsif words[1]
|
|
183
|
-
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
184
|
-
else
|
|
185
|
-
completion.push sub_commands
|
|
186
|
-
end
|
|
187
|
-
when 'service'
|
|
188
|
-
completion.clear
|
|
189
|
-
sub_commands = %w(containers create delete deploy list logs restart
|
|
190
|
-
scale show start stats stop update monitor env
|
|
191
|
-
secret link unlink)
|
|
192
|
-
if words[1]
|
|
193
|
-
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
194
|
-
completion.push helper.services
|
|
195
|
-
else
|
|
196
|
-
completion.push sub_commands
|
|
197
|
-
end
|
|
198
|
-
when 'container'
|
|
199
|
-
completion.clear
|
|
200
|
-
sub_commands = %w(exec inspect logs)
|
|
201
|
-
if words[1]
|
|
202
|
-
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
203
|
-
completion.push helper.containers
|
|
204
|
-
else
|
|
205
|
-
completion.push sub_commands
|
|
206
|
-
end
|
|
207
|
-
when 'vpn'
|
|
208
|
-
completion.clear
|
|
209
|
-
completion.push %w(config create delete)
|
|
210
|
-
when 'external-registry'
|
|
211
|
-
completion.clear
|
|
212
|
-
completion.push %w(add list delete)
|
|
213
|
-
when 'app'
|
|
214
|
-
completion.clear
|
|
215
|
-
sub_commands = %w(init build config deploy start stop remove rm ps list
|
|
216
|
-
logs monitor show)
|
|
217
|
-
if words[1]
|
|
218
|
-
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
219
|
-
completion.push helper.yml_services
|
|
220
|
-
else
|
|
221
|
-
completion.push sub_commands
|
|
222
|
-
end
|
|
223
|
-
when 'stack'
|
|
224
|
-
completion.clear
|
|
225
|
-
sub_commands = %w(build install upgrade deploy start stop remove rm ls list
|
|
226
|
-
logs monitor show registry)
|
|
227
|
-
if words[1]
|
|
228
|
-
if words[1] == 'registry'
|
|
229
|
-
registry_sub_commands = %(push pull search show rm)
|
|
230
|
-
completion.push registry_sub_commands
|
|
231
|
-
elsif %w(install).include?(words[1])
|
|
232
|
-
completion.push helper.yml_files
|
|
233
|
-
elsif words[1] == 'upgrade' && words[3]
|
|
234
|
-
completion.push helper.yml_files
|
|
138
|
+
helper.logger.debug { "Completing #{words.inspect}" }
|
|
139
|
+
|
|
140
|
+
begin
|
|
141
|
+
completion = []
|
|
142
|
+
completion.push %w(cloud logout grid app service stack vault certificate node master vpn registry container etcd external-registry whoami plugin version) if words.size < 2
|
|
143
|
+
if words.size > 0
|
|
144
|
+
case words[0]
|
|
145
|
+
when 'plugin'
|
|
146
|
+
completion.clear
|
|
147
|
+
sub_commands = %w(list ls search install uninstall)
|
|
148
|
+
if words[1]
|
|
149
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
235
150
|
else
|
|
151
|
+
completion.push sub_commands
|
|
152
|
+
end
|
|
153
|
+
when 'etcd'
|
|
154
|
+
completion.clear
|
|
155
|
+
sub_commands = %w(get set mkdir mk list ls rm)
|
|
156
|
+
if words[1]
|
|
236
157
|
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
237
|
-
|
|
158
|
+
else
|
|
159
|
+
completion.push sub_commands
|
|
238
160
|
end
|
|
239
|
-
|
|
240
|
-
completion.
|
|
241
|
-
|
|
161
|
+
when 'registry'
|
|
162
|
+
completion.clear
|
|
163
|
+
sub_commands = %w(create remove rm)
|
|
164
|
+
if words[1]
|
|
165
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
166
|
+
else
|
|
167
|
+
completion.push sub_commands
|
|
168
|
+
end
|
|
169
|
+
when 'grid'
|
|
170
|
+
completion.clear
|
|
171
|
+
sub_commands = %w(add-user audit-log create current list user remove show use)
|
|
172
|
+
if words[1] && words[1] == 'use'
|
|
173
|
+
completion.push helper.grids.reject { |g| g == helper.current_grid }
|
|
174
|
+
elsif words[1] && %w(update show rm remove env cloud-config health).include?(words[1])
|
|
175
|
+
completion.push helper.grids
|
|
176
|
+
else
|
|
177
|
+
completion.push sub_commands
|
|
178
|
+
end
|
|
179
|
+
when 'node'
|
|
180
|
+
completion.clear
|
|
181
|
+
sub_commands = %w(list show remove)
|
|
182
|
+
if words[1] && sub_commands.include?(words[1])
|
|
183
|
+
completion.push helper.nodes
|
|
184
|
+
else
|
|
185
|
+
completion.push sub_commands
|
|
186
|
+
end
|
|
187
|
+
when 'master'
|
|
188
|
+
completion.clear
|
|
189
|
+
sub_commands = %w(list use user current remove rm config cfg login logout token join audit-log init-cloud)
|
|
190
|
+
if words[1] && words[1] == 'use'
|
|
191
|
+
completion.push helper.master_names.reject { |n| n == helper.current_master_name }
|
|
192
|
+
elsif words[1] && %w(remove rm).include?(words[1])
|
|
193
|
+
completion.push helper.master_names
|
|
194
|
+
elsif words[1] && words[1] == 'user'
|
|
195
|
+
users_sub_commands = %w(invite list role)
|
|
196
|
+
if words[2] == 'role'
|
|
197
|
+
role_subcommands = %w(add remove rm)
|
|
198
|
+
if !words[3] || !role_subcommands.include?(words[3])
|
|
199
|
+
completion.push role_subcommands
|
|
200
|
+
end
|
|
201
|
+
else
|
|
202
|
+
completion.push users_sub_commands
|
|
203
|
+
end
|
|
204
|
+
elsif words[1] && ['config', 'cfg'].include?(words[1])
|
|
205
|
+
config_sub_commands = %(set get dump load import export unset)
|
|
206
|
+
completion.push config_sub_commands
|
|
207
|
+
elsif words[1] && words[1] == 'token'
|
|
208
|
+
token_sub_commands = %(list ls rm remove show current create)
|
|
209
|
+
completion.push token_sub_commands
|
|
210
|
+
elsif words[1]
|
|
211
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
212
|
+
else
|
|
213
|
+
completion.push sub_commands
|
|
214
|
+
end
|
|
215
|
+
when 'cloud'
|
|
216
|
+
completion.clear
|
|
217
|
+
sub_commands = %w(login logout master)
|
|
218
|
+
if words[1] && words[1] == 'master'
|
|
219
|
+
cloud_master_sub_commands = %(list ls remove rm add show update)
|
|
220
|
+
completion.push cloud_master_sub_commands
|
|
221
|
+
elsif words[1]
|
|
222
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
|
223
|
+
else
|
|
224
|
+
completion.push sub_commands
|
|
225
|
+
end
|
|
226
|
+
when 'service'
|
|
227
|
+
completion.clear
|
|
228
|
+
sub_commands = %w(containers create delete deploy list logs restart
|
|
229
|
+
scale show start stats stop update monitor env
|
|
230
|
+
secret link unlink)
|
|
231
|
+
if words[1] && sub_commands.include?(words[1])
|
|
232
|
+
completion.push helper.services
|
|
233
|
+
else
|
|
234
|
+
completion.push sub_commands
|
|
235
|
+
end
|
|
236
|
+
when 'container'
|
|
237
|
+
completion.clear
|
|
238
|
+
sub_commands = %w(exec inspect logs)
|
|
239
|
+
if words[1] && sub_commands.include?(words[1])
|
|
240
|
+
completion.push helper.containers
|
|
241
|
+
else
|
|
242
|
+
completion.push sub_commands
|
|
243
|
+
end
|
|
244
|
+
when 'vpn'
|
|
245
|
+
completion.clear
|
|
246
|
+
completion.push %w(config create delete)
|
|
247
|
+
when 'external-registry'
|
|
248
|
+
completion.clear
|
|
249
|
+
completion.push %w(add list delete)
|
|
250
|
+
when 'app'
|
|
251
|
+
completion.clear
|
|
252
|
+
sub_commands = %w(init build config deploy start stop remove rm ps list
|
|
253
|
+
logs monitor show)
|
|
254
|
+
if words[1] && sub_commands.include?(words[1])
|
|
255
|
+
completion.push helper.yml_services
|
|
256
|
+
else
|
|
257
|
+
completion.push sub_commands
|
|
258
|
+
end
|
|
259
|
+
when 'stack'
|
|
260
|
+
completion.clear
|
|
261
|
+
sub_commands = %w(build install upgrade deploy start stop remove rm ls list
|
|
262
|
+
logs monitor show registry)
|
|
263
|
+
if words[1]
|
|
264
|
+
if words[1] == 'registry'
|
|
265
|
+
registry_sub_commands = %(push pull search show rm)
|
|
266
|
+
completion.push registry_sub_commands
|
|
267
|
+
elsif %w(install).include?(words[1])
|
|
268
|
+
completion.push helper.yml_files
|
|
269
|
+
elsif words[1] == 'upgrade' && words[3]
|
|
270
|
+
completion.push helper.yml_files
|
|
271
|
+
elsif words[1] && sub_commands.include?(words[1])
|
|
272
|
+
completion.push helper.stacks
|
|
273
|
+
else
|
|
274
|
+
completion.push(sub_commands)
|
|
275
|
+
end
|
|
276
|
+
else
|
|
277
|
+
completion.push sub_commands
|
|
278
|
+
end
|
|
279
|
+
end
|
|
242
280
|
end
|
|
281
|
+
rescue => ex
|
|
282
|
+
helper.logger.debug ex
|
|
243
283
|
end
|
|
284
|
+
helper.logger.debug { "Returning completions: #{completion.inspect}" }
|
|
244
285
|
|
|
245
286
|
puts completion
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
require 'socket'
|
|
3
|
+
require 'openssl'
|
|
4
|
+
|
|
5
|
+
module Kontena
|
|
6
|
+
module Websocket
|
|
7
|
+
module Client
|
|
8
|
+
class Connection
|
|
9
|
+
extend Forwardable
|
|
10
|
+
|
|
11
|
+
FRAME_SIZE = 1024
|
|
12
|
+
|
|
13
|
+
attr_reader :url
|
|
14
|
+
|
|
15
|
+
# @param [String] url
|
|
16
|
+
# @param [Hash] options
|
|
17
|
+
def initialize(url, options = {})
|
|
18
|
+
@options = options
|
|
19
|
+
@url = url
|
|
20
|
+
@client = ::WebSocket::Driver.client(self)
|
|
21
|
+
if headers = options[:headers]
|
|
22
|
+
headers.each do |k, v|
|
|
23
|
+
@client.set_header(k, v)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def connect
|
|
29
|
+
uri = URI.parse(@url)
|
|
30
|
+
port = uri.port || (uri.scheme == "ws" ? 80 : 443)
|
|
31
|
+
@socket = ::TCPSocket.new(uri.host, port)
|
|
32
|
+
if uri.scheme == "wss"
|
|
33
|
+
ctx = ::OpenSSL::SSL::SSLContext.new
|
|
34
|
+
ctx.ssl_version = @options[:ssl_version] if @options[:ssl_version]
|
|
35
|
+
ctx.verify_mode = @options[:verify_mode] if @options[:verify_mode]
|
|
36
|
+
cert_store = ::OpenSSL::X509::Store.new
|
|
37
|
+
cert_store.set_default_paths
|
|
38
|
+
ctx.cert_store = cert_store
|
|
39
|
+
@socket = ::OpenSSL::SSL::SSLSocket.new(@socket, ctx)
|
|
40
|
+
@socket.connect
|
|
41
|
+
end
|
|
42
|
+
@client.start
|
|
43
|
+
Thread.new { self.read_socket }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def_delegators :@client, :text, :binary, :ping, :close, :protocol, :on
|
|
47
|
+
|
|
48
|
+
def write(buffer)
|
|
49
|
+
@socket.write buffer
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def read_socket
|
|
53
|
+
loop do
|
|
54
|
+
begin
|
|
55
|
+
@client.parse(@socket.readpartial(FRAME_SIZE))
|
|
56
|
+
rescue EOFError
|
|
57
|
+
break
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
data/lib/kontena_cli.rb
CHANGED
|
@@ -173,8 +173,7 @@ end
|
|
|
173
173
|
require 'retriable'
|
|
174
174
|
Retriable.configure do |c|
|
|
175
175
|
c.on_retry = Proc.new do |exception, try, elapsed_time, next_interval|
|
|
176
|
-
|
|
177
|
-
puts "Retriable retry: #{try} - Exception: #{exception.class.name} - #{exception.message}. Elapsed: #{elapsed_time} Next interval: #{next_interval}"
|
|
176
|
+
Kontena.logger.debug { "Retriable retry: #{try} - Exception: #{exception.class.name} - #{exception.message}. Elapsed: #{elapsed_time} Next interval: #{next_interval}" }
|
|
178
177
|
end
|
|
179
178
|
end
|
|
180
179
|
|
|
@@ -19,20 +19,8 @@ describe Kontena::Cli::Apps::BuildCommand do
|
|
|
19
19
|
fixture('docker-compose.yml')
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
let(:settings) do
|
|
23
|
-
{'current_server' => 'alias',
|
|
24
|
-
'servers' => [
|
|
25
|
-
{
|
|
26
|
-
'name' => 'some_master',
|
|
27
|
-
'url' => 'some_master'
|
|
28
|
-
}
|
|
29
|
-
]
|
|
30
|
-
}
|
|
31
|
-
end
|
|
32
|
-
|
|
33
22
|
describe '#execute' do
|
|
34
23
|
before(:each) do
|
|
35
|
-
allow(subject).to receive(:settings).and_return(settings)
|
|
36
24
|
allow(subject).to receive(:current_dir).and_return("kontena-test")
|
|
37
25
|
allow(File).to receive(:exists?).and_return(true)
|
|
38
26
|
allow(File).to receive(:read).with("#{Dir.getwd}/kontena.yml").and_return(kontena_yml)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'kontena/cli/master/join_command'
|
|
2
|
+
require 'kontena/cli/localhost_web_server'
|
|
3
|
+
require 'launchy'
|
|
4
|
+
require 'ostruct'
|
|
5
|
+
|
|
6
|
+
describe Kontena::Cli::Master::JoinCommand do
|
|
7
|
+
|
|
8
|
+
include ClientHelpers
|
|
9
|
+
|
|
10
|
+
let(:subject) do
|
|
11
|
+
described_class.new(File.basename($0))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'calls master login with proper join options' do
|
|
15
|
+
expect(Kontena).to receive(:run!).with(%w(master login --join xyz someurl))
|
|
16
|
+
subject.run(%w(someurl xyz))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'calls master login with remote option' do
|
|
20
|
+
expect(Kontena).to receive(:run!).with(%w(master login --join xyz --remote someurl))
|
|
21
|
+
subject.run(%w(--remote someurl xyz))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'calls master login with name option' do
|
|
25
|
+
expect(Kontena).to receive(:run!).with(%w(master login --join xyz --name somename someurl))
|
|
26
|
+
subject.run(%w(--name somename someurl xyz))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'calls master login with verbose option' do
|
|
30
|
+
expect(Kontena).to receive(:run!).with(%w(master login --join xyz --verbose someurl))
|
|
31
|
+
subject.run(%w(--verbose someurl xyz))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -18,5 +18,15 @@ describe Kontena::Cli::Master::UseCommand do
|
|
|
18
18
|
it 'should abort with error message if master is not configured' do
|
|
19
19
|
expect { subject.run(['not_existing']) }.to output(/Could not resolve master with name: 'not_existing'/).to_stderr
|
|
20
20
|
end
|
|
21
|
+
|
|
22
|
+
it 'should abort with error message if master is not given' do
|
|
23
|
+
expect { subject.run([]) }.to raise_error Clamp::UsageError
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'should clear current master when --clear given' do
|
|
27
|
+
expect(subject.config).to receive(:write).and_return(true)
|
|
28
|
+
subject.run(['--clear'])
|
|
29
|
+
expect(subject.config.current_server).to be_nil
|
|
30
|
+
end
|
|
21
31
|
end
|
|
22
32
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require 'websocket
|
|
1
|
+
require 'kontena/websocket/client'
|
|
2
2
|
require 'kontena/cli/services/exec_command'
|
|
3
3
|
|
|
4
4
|
describe Kontena::Cli::Services::ExecCommand do
|
|
@@ -24,6 +24,8 @@ describe Kontena::Cli::Services::ExecCommand do
|
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
def connect ; end
|
|
28
|
+
|
|
27
29
|
def receive_message(msg)
|
|
28
30
|
@callbacks[:message].call(Event.new(JSON.dump(msg)))
|
|
29
31
|
rescue => exc
|
|
@@ -67,8 +69,8 @@ describe Kontena::Cli::Services::ExecCommand do
|
|
|
67
69
|
end
|
|
68
70
|
|
|
69
71
|
it "Executes on the running container by default" do
|
|
70
|
-
expect(
|
|
71
|
-
expect(ws_client).to receive(:
|
|
72
|
+
expect(Kontena::Websocket::Client).to receive(:new).with("#{master_url}v1/containers/test-grid/host/test-service.container-1/exec?", anything).and_return(ws_client)
|
|
73
|
+
expect(ws_client).to receive(:text) do |foo|
|
|
72
74
|
ws_client.receive_message({'stream' => 'stdout', 'chunk' => "ok\n"})
|
|
73
75
|
ws_client.receive_message({'exit' => 0})
|
|
74
76
|
end
|
|
@@ -105,8 +107,8 @@ describe Kontena::Cli::Services::ExecCommand do
|
|
|
105
107
|
|
|
106
108
|
it "Executes on the first running container by default" do
|
|
107
109
|
expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return(service_containers)
|
|
108
|
-
expect(
|
|
109
|
-
expect(ws_client).to receive(:
|
|
110
|
+
expect(Kontena::Websocket::Client).to receive(:new).with("#{master_url}v1/containers/test-grid/host/test-service.container-1/exec?", anything).and_return(ws_client)
|
|
111
|
+
expect(ws_client).to receive(:text) do
|
|
110
112
|
respond_ok(ws_client)
|
|
111
113
|
end
|
|
112
114
|
expect {
|
|
@@ -116,8 +118,8 @@ describe Kontena::Cli::Services::ExecCommand do
|
|
|
116
118
|
|
|
117
119
|
it "Executes on the first running container, even if they are ordered differently" do
|
|
118
120
|
expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return({'containers' => service_containers['containers'].reverse })
|
|
119
|
-
expect(
|
|
120
|
-
expect(ws_client).to receive(:
|
|
121
|
+
expect(Kontena::Websocket::Client).to receive(:new).with("#{master_url}v1/containers/test-grid/host/test-service.container-1/exec?", anything).and_return(ws_client)
|
|
122
|
+
expect(ws_client).to receive(:text) do
|
|
121
123
|
respond_ok(ws_client)
|
|
122
124
|
end
|
|
123
125
|
expect {
|
|
@@ -127,8 +129,8 @@ describe Kontena::Cli::Services::ExecCommand do
|
|
|
127
129
|
|
|
128
130
|
it "Executes on the first running container if given" do
|
|
129
131
|
expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return(service_containers)
|
|
130
|
-
expect(
|
|
131
|
-
expect(ws_client).to receive(:
|
|
132
|
+
expect(Kontena::Websocket::Client).to receive(:new).with("#{master_url}v1/containers/test-grid/host/test-service.container-1/exec?", anything).and_return(ws_client)
|
|
133
|
+
expect(ws_client).to receive(:text) do
|
|
132
134
|
respond_ok(ws_client)
|
|
133
135
|
end
|
|
134
136
|
expect {
|
|
@@ -138,8 +140,8 @@ describe Kontena::Cli::Services::ExecCommand do
|
|
|
138
140
|
|
|
139
141
|
it "Executes on the second running container if given" do
|
|
140
142
|
expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return(service_containers)
|
|
141
|
-
expect(
|
|
142
|
-
expect(ws_client).to receive(:
|
|
143
|
+
expect(Kontena::Websocket::Client).to receive(:new).with("#{master_url}v1/containers/test-grid/host/test-service.container-2/exec?", anything).and_return(ws_client)
|
|
144
|
+
expect(ws_client).to receive(:text) do
|
|
143
145
|
respond_ok(ws_client)
|
|
144
146
|
end
|
|
145
147
|
expect {
|
|
@@ -158,8 +160,8 @@ describe Kontena::Cli::Services::ExecCommand do
|
|
|
158
160
|
|
|
159
161
|
3.times do |i|
|
|
160
162
|
ws_client = ws_client_class.new
|
|
161
|
-
expect(
|
|
162
|
-
expect(ws_client).to receive(:
|
|
163
|
+
expect(Kontena::Websocket::Client).to receive(:new).with("#{master_url}v1/containers/test-grid/host/test-service.container-#{i + 1}/exec?", anything).and_return(ws_client)
|
|
164
|
+
expect(ws_client).to receive(:text) do
|
|
163
165
|
ws_client.receive_message({'stream' => 'stdout', 'chunk' => "test#{i + 1}\n"})
|
|
164
166
|
ws_client.receive_message({'exit' => 0})
|
|
165
167
|
end
|
|
@@ -172,8 +174,8 @@ describe Kontena::Cli::Services::ExecCommand do
|
|
|
172
174
|
|
|
173
175
|
it "Stops if the first container fails" do
|
|
174
176
|
expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return(service_containers)
|
|
175
|
-
expect(
|
|
176
|
-
expect(ws_client).to receive(:
|
|
177
|
+
expect(Kontena::Websocket::Client).to receive(:new).with("#{master_url}v1/containers/test-grid/host/test-service.container-1/exec?", anything).and_return(ws_client)
|
|
178
|
+
expect(ws_client).to receive(:text) do
|
|
177
179
|
respond_error(ws_client)
|
|
178
180
|
end
|
|
179
181
|
expect {
|
|
@@ -186,8 +188,8 @@ describe Kontena::Cli::Services::ExecCommand do
|
|
|
186
188
|
i = 1
|
|
187
189
|
[:ok, :err].each do |status|
|
|
188
190
|
ws_client = ws_client_class.new
|
|
189
|
-
expect(
|
|
190
|
-
expect(ws_client).to receive(:
|
|
191
|
+
expect(Kontena::Websocket::Client).to receive(:new).with("#{master_url}v1/containers/test-grid/host/test-service.container-#{i}/exec?", anything).and_return(ws_client)
|
|
192
|
+
expect(ws_client).to receive(:text) do
|
|
191
193
|
if status == :ok
|
|
192
194
|
respond_ok(ws_client)
|
|
193
195
|
else
|
|
@@ -207,8 +209,8 @@ describe Kontena::Cli::Services::ExecCommand do
|
|
|
207
209
|
i = 1
|
|
208
210
|
[:ok, :err, :ok].each do |status|
|
|
209
211
|
ws_client = ws_client_class.new
|
|
210
|
-
expect(
|
|
211
|
-
expect(ws_client).to receive(:
|
|
212
|
+
expect(Kontena::Websocket::Client).to receive(:new).with("#{master_url}v1/containers/test-grid/host/test-service.container-#{i}/exec?", anything).and_return(ws_client)
|
|
213
|
+
expect(ws_client).to receive(:text) do
|
|
212
214
|
if status == :ok
|
|
213
215
|
respond_ok(ws_client)
|
|
214
216
|
else
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kontena-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.3.0.
|
|
4
|
+
version: 1.3.0.rc2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kontena, Inc
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-
|
|
11
|
+
date: 2017-06-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -207,19 +207,19 @@ dependencies:
|
|
|
207
207
|
- !ruby/object:Gem::Version
|
|
208
208
|
version: 0.8.0
|
|
209
209
|
- !ruby/object:Gem::Dependency
|
|
210
|
-
name: websocket-
|
|
210
|
+
name: websocket-driver-kontena
|
|
211
211
|
requirement: !ruby/object:Gem::Requirement
|
|
212
212
|
requirements:
|
|
213
|
-
- -
|
|
213
|
+
- - '='
|
|
214
214
|
- !ruby/object:Gem::Version
|
|
215
|
-
version: 0.
|
|
215
|
+
version: 0.6.5
|
|
216
216
|
type: :runtime
|
|
217
217
|
prerelease: false
|
|
218
218
|
version_requirements: !ruby/object:Gem::Requirement
|
|
219
219
|
requirements:
|
|
220
|
-
- -
|
|
220
|
+
- - '='
|
|
221
221
|
- !ruby/object:Gem::Version
|
|
222
|
-
version: 0.
|
|
222
|
+
version: 0.6.5
|
|
223
223
|
description: Command-line client for the Kontena container and microservices platform
|
|
224
224
|
email:
|
|
225
225
|
- info@kontena.io
|
|
@@ -526,6 +526,8 @@ files:
|
|
|
526
526
|
- lib/kontena/stacks_cache.rb
|
|
527
527
|
- lib/kontena/stacks_client.rb
|
|
528
528
|
- lib/kontena/util.rb
|
|
529
|
+
- lib/kontena/websocket/client.rb
|
|
530
|
+
- lib/kontena/websocket/client/connection.rb
|
|
529
531
|
- lib/kontena_cli.rb
|
|
530
532
|
- omnibus/.gitignore
|
|
531
533
|
- omnibus/.kitchen.yml
|
|
@@ -610,6 +612,7 @@ files:
|
|
|
610
612
|
- spec/kontena/cli/main_command_spec.rb
|
|
611
613
|
- spec/kontena/cli/master/current_command_spec.rb
|
|
612
614
|
- spec/kontena/cli/master/init_cloud_command_spec.rb
|
|
615
|
+
- spec/kontena/cli/master/join_command_spec.rb
|
|
613
616
|
- spec/kontena/cli/master/login_command_spec.rb
|
|
614
617
|
- spec/kontena/cli/master/logout_command_spec.rb
|
|
615
618
|
- spec/kontena/cli/master/use_command_spec.rb
|
|
@@ -762,6 +765,7 @@ test_files:
|
|
|
762
765
|
- spec/kontena/cli/main_command_spec.rb
|
|
763
766
|
- spec/kontena/cli/master/current_command_spec.rb
|
|
764
767
|
- spec/kontena/cli/master/init_cloud_command_spec.rb
|
|
768
|
+
- spec/kontena/cli/master/join_command_spec.rb
|
|
765
769
|
- spec/kontena/cli/master/login_command_spec.rb
|
|
766
770
|
- spec/kontena/cli/master/logout_command_spec.rb
|
|
767
771
|
- spec/kontena/cli/master/use_command_spec.rb
|