kontena-cli 1.4.0.pre1 → 1.4.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,57 +1,9 @@
1
- require 'kontena/websocket/client'
2
1
  require 'kontena/cli/services/exec_command'
3
2
 
4
3
  describe Kontena::Cli::Services::ExecCommand do
5
4
  include ClientHelpers
6
5
  include OutputHelpers
7
6
 
8
- let(:ws_client_class) do
9
- Class.new do
10
-
11
- Event = Struct.new(:data)
12
-
13
- def initialize
14
- @callbacks = {}
15
- end
16
-
17
- def on(callback, &block)
18
- @callbacks[callback] = block
19
- if callback == :open
20
- Thread.new {
21
- sleep 0.01
22
- @callbacks[:open].call
23
- }
24
- end
25
- end
26
-
27
- def connect ; end
28
-
29
- def receive_message(msg)
30
- @callbacks[:message].call(Event.new(JSON.dump(msg)))
31
- rescue => exc
32
- STDERR.puts exc.message
33
- end
34
- end
35
- end
36
-
37
- let(:ws_client) do
38
- ws_client_class.new
39
- end
40
-
41
- let(:master_url) do
42
- subject.require_current_master.url.gsub('http', 'ws')
43
- end
44
-
45
- def respond_ok(ws_client)
46
- ws_client.receive_message({'stream' => 'stdout', 'chunk' => "ok\n"})
47
- ws_client.receive_message({'exit' => 0})
48
- end
49
-
50
- def respond_error(ws_client)
51
- ws_client.receive_message({'stream' => 'stderr', 'chunk' => "error\n"})
52
- ws_client.receive_message({'exit' => 1})
53
- end
54
-
55
7
  context "For a service with one running instance" do
56
8
  let :service_containers do
57
9
  { 'containers' => [
@@ -69,21 +21,16 @@ describe Kontena::Cli::Services::ExecCommand do
69
21
  end
70
22
 
71
23
  it "Executes on the running container by default" do
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|
74
- ws_client.receive_message({'stream' => 'stdout', 'chunk' => "ok\n"})
75
- ws_client.receive_message({'exit' => 0})
76
- end
77
-
78
- expect {
79
- subject.run(['test-service', 'test'])
80
- }.to output("ok\n").to_stdout
24
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-1', ['test'],
25
+ interactive: false, shell: false, tty: false,
26
+ ).and_return(0)
27
+ expect{subject.run(['test-service', 'test'])}.to_not exit_with_error
81
28
  end
82
29
  end
83
30
 
84
31
  context "For a service with multiple running instances" do
85
32
  let :service_containers do
86
- { 'containers' => [
33
+ [
87
34
  {
88
35
  'id' => 'test-grid/host/test-service.container-1',
89
36
  'name' => 'test-service.container-1',
@@ -102,126 +49,108 @@ describe Kontena::Cli::Services::ExecCommand do
102
49
  'instance_number' => 3,
103
50
  'status' => 'running',
104
51
  },
105
- ] }
52
+ ]
106
53
  end
107
54
 
108
55
  it "Executes on the first running container by default" do
109
- expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return(service_containers)
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
112
- respond_ok(ws_client)
56
+ expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return('containers' => service_containers)
57
+
58
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-1', ['test'],
59
+ interactive: false, shell: false, tty: false,
60
+ ) do
61
+ puts 'ok 1'
62
+ 0
113
63
  end
114
- expect {
64
+
65
+ expect{
115
66
  subject.run(['test-service', 'test'])
116
- }.to output("ok\n").to_stdout
67
+ }.to output_lines [ 'ok 1' ]
117
68
  end
118
69
 
119
70
  it "Executes on the first running container, even if they are ordered differently" do
120
- expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return({'containers' => service_containers['containers'].reverse })
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
123
- respond_ok(ws_client)
124
- end
125
- expect {
126
- subject.run(['test-service', 'test'])
127
- }.to output("ok\n").to_stdout
71
+ expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return('containers' => service_containers.reverse)
72
+
73
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-1', ['test'],
74
+ interactive: false, shell: false, tty: false,
75
+ ).and_return(0)
76
+ expect{subject.run(['test-service', 'test'])}.to_not exit_with_error
128
77
  end
129
78
 
130
- it "Executes on the first running container if given" do
131
- expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return(service_containers)
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
134
- respond_ok(ws_client)
79
+ context do
80
+ before do
81
+ expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return('containers' => service_containers)
135
82
  end
136
- expect {
137
- subject.run(['test-service', 'test'])
138
- }.to output("ok\n").to_stdout
139
- end
140
83
 
141
- it "Executes on the second running container if given" do
142
- expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return(service_containers)
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
145
- respond_ok(ws_client)
84
+ it "Executes on the first running container if given" do
85
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-1', ['test'],
86
+ interactive: false, shell: false, tty: false,
87
+ ).and_return(0)
88
+ expect{subject.run(['--instance=1', 'test-service', 'test'])}.to_not exit_with_error
146
89
  end
147
- expect {
148
- subject.run(['--instance', '2', 'test-service', 'test'])
149
- }.to output("ok\n").to_stdout
150
- end
151
90
 
152
- it "Errors on a nonexistant container if given" do
153
- expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return(service_containers)
91
+ it "Executes on the second running container if given" do
92
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-2', ['test'],
93
+ interactive: false, shell: false, tty: false,
94
+ ).and_return(0)
95
+ expect{subject.run(['--instance=2', 'test-service', 'test'])}.to_not exit_with_error
96
+ end
154
97
 
155
- expect{subject.run(['--instance=4', 'test-service', 'test'])}.to exit_with_error.and output(/Service test-service does not have container instance 4/).to_stderr
156
- end
98
+ it "Errors on a nonexistant container if given" do
99
+ expect{subject.run(['--instance=4', 'test-service', 'test'])}.to exit_with_error.and output(/Service test-service does not have container instance 4/).to_stderr
100
+ end
157
101
 
158
- it "Executes on each running container" do
159
- expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return(service_containers)
102
+ it "Executes on each running container" do
103
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-1', ['test'],
104
+ interactive: false, shell: false, tty: false,
105
+ ).and_return(0)
106
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-2', ['test'],
107
+ interactive: false, shell: false, tty: false,
108
+ ).and_return(0)
109
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-3', ['test'],
110
+ interactive: false, shell: false, tty: false,
111
+ ).and_return(0)
160
112
 
161
- 3.times do |i|
162
- ws_client = ws_client_class.new
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
165
- ws_client.receive_message({'stream' => 'stdout', 'chunk' => "test#{i + 1}\n"})
166
- ws_client.receive_message({'exit' => 0})
167
- end
113
+ subject.run(['--silent', '--all', 'test-service', 'test'])
168
114
  end
169
115
 
170
- expect {
171
- subject.run(['--silent', '--all', 'test-service', 'test'])
172
- }.to output("test1\ntest2\ntest3\n").to_stdout
173
- end
116
+ it "Stops if the first container fails" do
117
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-1', ['test'],
118
+ interactive: false, shell: false, tty: false,
119
+ ) { $stderr << 'error'; 1 }
174
120
 
175
- it "Stops if the first container fails" do
176
- expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return(service_containers)
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
179
- respond_error(ws_client)
121
+ expect {
122
+ subject.run(['--silent', '--all', 'test-service', 'test'])
123
+ }.to exit_with_error.and output("error").to_stderr
180
124
  end
181
- expect {
182
- subject.run(['--silent', '--all', 'test-service', 'test'])
183
- }.to output("error\n").to_stderr
184
- end
185
125
 
186
- it "Stops if the second container fails" do
187
- expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return(service_containers)
188
- i = 1
189
- [:ok, :err].each do |status|
190
- ws_client = ws_client_class.new
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
193
- if status == :ok
194
- respond_ok(ws_client)
195
- else
196
- respond_error(ws_client)
197
- end
198
- end
199
- i += 1
126
+ it "Stops if the second container fails" do
127
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-1', ['test'],
128
+ interactive: false, shell: false, tty: false,
129
+ ) { $stdout << 'ok 1'; 0 }
130
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-2', ['test'],
131
+ interactive: false, shell: false, tty: false,
132
+ ) { $stderr << 'error 2'; 1 }
133
+
134
+ expect {
135
+ subject.run(['--silent', '--all', 'test-service', 'test'])
136
+ }.to exit_with_error.and output("ok 1").to_stdout.and output("error 2").to_stderr
200
137
  end
201
- expect {
202
- subject.run(['--silent', '--all', 'test-service', 'test'])
203
- }.to output("ok\n").to_stdout.and output("error\n").to_stderr
204
- end
205
-
206
- it "Keeps going if the second container fails when using --skip" do
207
- expect(client).to receive(:get).with('services/test-grid/null/test-service/containers').and_return(service_containers)
208
138
 
209
- i = 1
210
- [:ok, :err, :ok].each do |status|
211
- ws_client = ws_client_class.new
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
214
- if status == :ok
215
- respond_ok(ws_client)
216
- else
217
- respond_error(ws_client)
218
- end
219
- end
220
- i += 1
139
+ it "Keeps going if the second container fails when using --skip" do
140
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-1', ['test'],
141
+ interactive: false, shell: false, tty: false,
142
+ ) { puts 'ok 1'; 0}
143
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-2', ['test'],
144
+ interactive: false, shell: false, tty: false,
145
+ ) { puts 'err 2'; 2 }
146
+ expect(subject).to receive(:container_exec).with('test-grid/host/test-service.container-3', ['test'],
147
+ interactive: false, shell: false, tty: false,
148
+ ) { puts 'ok 3'; 0 }
149
+
150
+ expect {
151
+ subject.run(['--silent', '--all', '--skip', 'test-service', 'test'])
152
+ }.to exit_with_error.and output_lines ['ok 1', 'err 2', 'ok 3']
221
153
  end
222
- expect {
223
- subject.run(['--silent', '--all', '--skip', 'test-service', 'test'])
224
- }.to output("ok\nok\n").to_stdout.and output("error\n").to_stderr
225
154
  end
226
155
  end
227
156
  end
@@ -9,6 +9,8 @@ module ClientHelpers
9
9
  instance_double(Kontena::Client, :client)
10
10
  end
11
11
 
12
+ base.let(:master_url) { 'http://someurl.example.com/' }
13
+
12
14
  base.let(:token) do
13
15
  '1234567'
14
16
  end
@@ -21,17 +23,18 @@ module ClientHelpers
21
23
  {'current_server' => 'alias',
22
24
  'current_account' => 'kontena',
23
25
  'servers' => [
24
- {'name' => 'some_master', 'url' => 'http://someurl.example.com'},
25
- {'name' => 'alias', 'url' => 'http://someurl.example.com/', 'token' => token, 'account' => 'master', 'grid' => current_grid},
26
+ {'name' => 'some_master', 'url' => master_url },
27
+ {'name' => 'alias', 'url' => master_url, 'token' => token, 'account' => 'master', 'grid' => current_grid},
26
28
  ]
27
29
  }
28
30
  end
29
31
 
30
32
  base.before(:each) do
33
+ master_host = URI(master_url).host
31
34
  RSpec::Mocks.space.proxy_for(File).reset
32
35
  allow(subject).to receive(:client).and_return(client)
33
36
  allow(subject).to receive(:current_grid).and_return(current_grid)
34
- allow(File).to receive(:exist?).with(File.join(Dir.home, '.kontena/certs/someurl.example.com.pem')).and_return(false)
37
+ allow(File).to receive(:exist?).with(File.join(Dir.home, ".kontena/certs/#{master_host}.pem")).and_return(false)
35
38
  allow(File).to receive(:exist?).with(File.join(Dir.home, '.kontena_client.json')).and_return(true)
36
39
  allow(File).to receive(:readable?).with(File.join(Dir.home, '.kontena_client.json')).and_return(true)
37
40
  allow(File).to receive(:read).and_call_original
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.4.0.pre1
4
+ version: 1.4.0.pre2
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-07-26 00:00:00.000000000 Z
11
+ date: 2017-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -193,19 +193,19 @@ dependencies:
193
193
  - !ruby/object:Gem::Version
194
194
  version: 0.8.0
195
195
  - !ruby/object:Gem::Dependency
196
- name: websocket-driver-kontena
196
+ name: kontena-websocket-client
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
- - - '='
199
+ - - "~>"
200
200
  - !ruby/object:Gem::Version
201
- version: 0.6.5
201
+ version: 0.1.0
202
202
  type: :runtime
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
- - - '='
206
+ - - "~>"
207
207
  - !ruby/object:Gem::Version
208
- version: 0.6.5
208
+ version: 0.1.0
209
209
  description: Command-line client for the Kontena container and microservices platform
210
210
  email:
211
211
  - info@kontena.io
@@ -517,8 +517,6 @@ files:
517
517
  - lib/kontena/stacks_cache.rb
518
518
  - lib/kontena/stacks_client.rb
519
519
  - lib/kontena/util.rb
520
- - lib/kontena/websocket/client.rb
521
- - lib/kontena/websocket/client/connection.rb
522
520
  - lib/kontena_cli.rb
523
521
  - omnibus/.gitignore
524
522
  - omnibus/.kitchen.yml
@@ -590,6 +588,7 @@ files:
590
588
  - spec/kontena/cli/cloud/logout_command_spec.rb
591
589
  - spec/kontena/cli/cloud/master/add_command_spec.rb
592
590
  - spec/kontena/cli/common_spec.rb
591
+ - spec/kontena/cli/containers/exec_command_spec.rb
593
592
  - spec/kontena/cli/containers/list_command_spec.rb
594
593
  - spec/kontena/cli/containers/logs_command_spec.rb
595
594
  - spec/kontena/cli/etcd/health_command_spec.rb
@@ -756,6 +755,7 @@ test_files:
756
755
  - spec/kontena/cli/cloud/logout_command_spec.rb
757
756
  - spec/kontena/cli/cloud/master/add_command_spec.rb
758
757
  - spec/kontena/cli/common_spec.rb
758
+ - spec/kontena/cli/containers/exec_command_spec.rb
759
759
  - spec/kontena/cli/containers/list_command_spec.rb
760
760
  - spec/kontena/cli/containers/logs_command_spec.rb
761
761
  - spec/kontena/cli/etcd/health_command_spec.rb
@@ -1,12 +0,0 @@
1
- require 'websocket/driver'
2
- module Kontena
3
- module Websocket
4
- module Client
5
- def self.new(*args)
6
- Connection.new(*args)
7
- end
8
- end
9
- end
10
- end
11
-
12
- require_relative 'client/connection'
@@ -1,65 +0,0 @@
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
-