kontena-cli 1.0.6 → 1.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/VERSION +1 -1
  4. data/bin/kontena +4 -1
  5. data/kontena-cli.gemspec +1 -1
  6. data/lib/kontena/callback.rb +1 -1
  7. data/lib/kontena/callbacks/master/01_clear_current_master_after_terminate.rb +1 -1
  8. data/lib/kontena/callbacks/master/deploy/50_authenticate_after_deploy.rb +5 -5
  9. data/lib/kontena/callbacks/master/deploy/55_create_initial_grid_after_deploy.rb +1 -1
  10. data/lib/kontena/callbacks/master/deploy/56_set_server_provider_after_deploy.rb +25 -0
  11. data/lib/kontena/callbacks/master/deploy/70_invite_self_after_deploy.rb +1 -1
  12. data/lib/kontena/cli/common.rb +3 -3
  13. data/lib/kontena/cli/config.rb +1 -1
  14. data/lib/kontena/cli/grid_command.rb +2 -0
  15. data/lib/kontena/cli/grids/common.rb +12 -0
  16. data/lib/kontena/cli/grids/health_command.rb +69 -0
  17. data/lib/kontena/cli/helpers/health_helper.rb +53 -0
  18. data/lib/kontena/cli/localhost_web_server.rb +3 -3
  19. data/lib/kontena/cli/master/users/invite_command.rb +1 -1
  20. data/lib/kontena/cli/node_command.rb +2 -0
  21. data/lib/kontena/cli/nodes/health_command.rb +32 -0
  22. data/lib/kontena/cli/nodes/list_command.rb +40 -26
  23. data/lib/kontena/cli/nodes/show_command.rb +0 -1
  24. data/lib/kontena/cli/plugins/install_command.rb +28 -30
  25. data/lib/kontena/cli/plugins/search_command.rb +6 -14
  26. data/lib/kontena/cli/plugins/uninstall_command.rb +7 -11
  27. data/lib/kontena/cli/services/stats_command.rb +4 -2
  28. data/lib/kontena/cli/spinner.rb +20 -4
  29. data/lib/kontena/cli/stacks/show_command.rb +5 -1
  30. data/lib/kontena/cli/stacks/yaml/opto/service_instances_resolver.rb +22 -0
  31. data/lib/kontena/cli/stacks/yaml/opto/vault_setter.rb +1 -1
  32. data/lib/kontena/cli/stacks/yaml/reader.rb +1 -0
  33. data/lib/kontena/cli/vault/export_command.rb +22 -0
  34. data/lib/kontena/cli/vault/import_command.rb +80 -0
  35. data/lib/kontena/cli/vault/list_command.rb +4 -0
  36. data/lib/kontena/cli/vault/read_command.rb +8 -3
  37. data/lib/kontena/cli/vault/remove_command.rb +2 -1
  38. data/lib/kontena/cli/vault/update_command.rb +5 -7
  39. data/lib/kontena/cli/vault_command.rb +5 -1
  40. data/lib/kontena/client.rb +25 -2
  41. data/lib/kontena/command.rb +1 -1
  42. data/lib/kontena/debug_instrumentor.rb +70 -0
  43. data/lib/kontena/light_prompt.rb +103 -0
  44. data/lib/kontena/plugin_manager.rb +167 -6
  45. data/lib/kontena/stacks_cache.rb +1 -1
  46. data/lib/kontena_cli.rb +23 -6
  47. data/spec/kontena/cli/grids/health_command_spec.rb +390 -0
  48. data/spec/kontena/cli/nodes/health_command_spec.rb +206 -0
  49. data/spec/kontena/cli/nodes/list_command_spec.rb +205 -0
  50. data/spec/kontena/cli/vault/export_spec.rb +32 -0
  51. data/spec/kontena/cli/vault/import_spec.rb +69 -0
  52. data/spec/kontena/client_spec.rb +39 -0
  53. data/spec/kontena/plugin_manager_spec.rb +7 -7
  54. data/spec/spec_helper.rb +1 -0
  55. data/spec/support/output_helpers.rb +51 -0
  56. metadata +27 -6
@@ -0,0 +1,206 @@
1
+ require 'kontena/cli/nodes/health_command'
2
+
3
+ describe Kontena::Cli::Nodes::HealthCommand do
4
+ include ClientHelpers
5
+ include OutputHelpers
6
+
7
+ before do
8
+ allow(subject).to receive(:health_icon) {|health| health.inspect }
9
+ end
10
+
11
+ context "for an online node" do
12
+ let :node do
13
+ {
14
+ "connected" => true,
15
+ "name" => "node-4",
16
+ "node_number" => 4,
17
+ "initial_member" => false,
18
+ }
19
+ end
20
+
21
+ let :grid_health do
22
+ :ok
23
+ end
24
+
25
+ describe '#node_health' do
26
+ it "returns ok" do
27
+ expect(subject.node_health(node, grid_health)).to eq(:ok)
28
+ end
29
+ end
30
+
31
+ describe '#show_node_health' do
32
+ it "returns true" do
33
+ expect{subject.show_node_health(node)}.to return_and_output true,
34
+ ":ok Node is online"
35
+ end
36
+ end
37
+ end
38
+
39
+ context "for an offline node" do
40
+ let :node do
41
+ {
42
+ "connected" => false,
43
+ "name" => "node-4",
44
+ "node_number" => 4,
45
+ "initial_member" => false,
46
+ }
47
+ end
48
+
49
+ let :grid_health do
50
+ :ok
51
+ end
52
+
53
+ describe '#node_health' do
54
+ it "returns offline" do
55
+ expect(subject.node_health(node, grid_health)).to eq(:offline)
56
+ end
57
+ end
58
+
59
+ describe '#show_node_health' do
60
+ it "returns false" do
61
+ expect{subject.show_node_health(node)}.to return_and_output false,
62
+ ":offline Node is offline"
63
+ end
64
+ end
65
+ end
66
+
67
+ context "for an online initial node in an ok grid" do
68
+ let :node do
69
+ {
70
+ "connected" => true,
71
+ "name" => "node-1",
72
+ "node_number" => 1,
73
+ "initial_member" => true,
74
+ }
75
+ end
76
+
77
+ let :grid_health do
78
+ :ok
79
+ end
80
+
81
+ describe '#node_health' do
82
+ it "returns ok" do
83
+ expect(subject.node_health(node, grid_health)).to eq(:ok)
84
+ end
85
+ end
86
+
87
+ describe '#show_node_health' do
88
+ it "returns true" do
89
+ expect{subject.show_node_health(node)}.to return_and_output true,
90
+ ":ok Node is online"
91
+ end
92
+ end
93
+ end
94
+
95
+ context "for an online initial node in a warning grid" do
96
+ let :node do
97
+ {
98
+ "connected" => true,
99
+ "name" => "node-1",
100
+ "node_number" => 1,
101
+ "initial_member" => true,
102
+ }
103
+ end
104
+
105
+ let :grid_health do
106
+ :warning
107
+ end
108
+
109
+ describe '#node_health' do
110
+ it "returns ok" do
111
+ expect(subject.node_health(node, grid_health)).to eq(:warning)
112
+ end
113
+ end
114
+
115
+ describe '#show_node_health' do
116
+ it "returns true" do
117
+ expect{subject.show_node_health(node)}.to return_and_output true,
118
+ ":ok Node is online"
119
+ end
120
+ end
121
+ end
122
+
123
+ context "for an online initial node in an error grid" do
124
+ let :node do
125
+ {
126
+ "connected" => true,
127
+ "name" => "node-1",
128
+ "node_number" => 1,
129
+ "initial_member" => true,
130
+ }
131
+ end
132
+
133
+ let :grid_health do
134
+ :error
135
+ end
136
+
137
+ describe '#node_health' do
138
+ it "returns ok" do
139
+ expect(subject.node_health(node, grid_health)).to eq(:error)
140
+ end
141
+ end
142
+
143
+ describe '#show_node_health' do
144
+ it "returns true" do
145
+ expect{subject.show_node_health(node)}.to return_and_output true,
146
+ ":ok Node is online"
147
+ end
148
+ end
149
+ end
150
+
151
+ context "for an offline initial node in a warning grid" do
152
+ let :node do
153
+ {
154
+ "connected" => false,
155
+ "name" => "node-1",
156
+ "node_number" => 1,
157
+ "initial_member" => true,
158
+ }
159
+ end
160
+
161
+ let :grid_health do
162
+ :warning
163
+ end
164
+
165
+ describe '#node_health' do
166
+ it "returns offline" do
167
+ expect(subject.node_health(node, grid_health)).to eq(:offline)
168
+ end
169
+ end
170
+
171
+ describe '#show_node_health' do
172
+ it "returns false" do
173
+ expect{subject.show_node_health(node)}.to return_and_output false,
174
+ ":offline Node is offline"
175
+ end
176
+ end
177
+ end
178
+
179
+ context "for an offline initial node in a error grid" do
180
+ let :node do
181
+ {
182
+ "connected" => false,
183
+ "name" => "node-1",
184
+ "node_number" => 1,
185
+ "initial_member" => true,
186
+ }
187
+ end
188
+
189
+ let :grid_health do
190
+ :error
191
+ end
192
+
193
+ describe '#node_health' do
194
+ it "returns offline" do
195
+ expect(subject.node_health(node, grid_health)).to eq(:offline)
196
+ end
197
+ end
198
+
199
+ describe '#show_node_health' do
200
+ it "returns false" do
201
+ expect{subject.show_node_health(node)}.to return_and_output false,
202
+ ":offline Node is offline"
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,205 @@
1
+ describe Kontena::Cli::Nodes::ListCommand do
2
+ include ClientHelpers
3
+ include OutputHelpers
4
+
5
+ before do
6
+ allow(subject).to receive(:health_icon) {|health| health.inspect }
7
+ end
8
+
9
+ describe '#show_grid_nodes' do
10
+ context "For a initial_size=3 grid" do
11
+ let :grid do
12
+ {
13
+ "id" => "test",
14
+ "name" => "test",
15
+ "initial_size" => 3,
16
+ "node_count" => 1,
17
+ }
18
+ end
19
+
20
+ context "with a single node" do
21
+ let :grid_nodes do
22
+ { "nodes" => [
23
+ {
24
+ "connected" => true,
25
+ "name" => "node-1",
26
+ "node_number" => 1,
27
+ "initial_member" => true,
28
+ 'agent_version' => '1.1-dev',
29
+ },
30
+ ] }
31
+ end
32
+
33
+ it "outputs node with error" do
34
+ expect{subject.show_grid_nodes(grid, grid_nodes['nodes'])}.to output_table [
35
+ [':error node-1', '1.1-dev', 'online', '1 / 3', '-'],
36
+ ]
37
+ end
38
+ end
39
+
40
+ context "with a single online node" do
41
+ let :grid_nodes do
42
+ { "nodes" => [
43
+ {
44
+ "connected" => true,
45
+ "name" => "node-1",
46
+ "node_number" => 1,
47
+ "initial_member" => true,
48
+ 'agent_version' => '1.1-dev',
49
+ },
50
+ {
51
+ "connected" => false,
52
+ "name" => "node-2",
53
+ "node_number" => 2,
54
+ "initial_member" => true,
55
+ 'agent_version' => '1.1-dev',
56
+ },
57
+ ] }
58
+ end
59
+
60
+ it "outputs online node with error" do
61
+ expect{subject.show_grid_nodes(grid, grid_nodes['nodes'])}.to output_table [
62
+ [':error node-1', '1.1-dev', 'online', '1 / 3', '-'],
63
+ [':offline node-2', '1.1-dev', 'offline', '2 / 3', '-'],
64
+ ]
65
+ end
66
+ end
67
+
68
+ context "with two online nodes" do
69
+ let :grid_nodes do
70
+ { "nodes" => [
71
+ {
72
+ "connected" => true,
73
+ "name" => "node-1",
74
+ "node_number" => 1,
75
+ "initial_member" => true,
76
+ 'agent_version' => '1.1-dev',
77
+ },
78
+ {
79
+ "connected" => true,
80
+ "name" => "node-2",
81
+ "node_number" => 2,
82
+ "initial_member" => true,
83
+ 'agent_version' => '1.1-dev',
84
+ },
85
+ ] }
86
+ end
87
+
88
+ it "outputs both nodes with warning" do
89
+ expect{subject.show_grid_nodes(grid, grid_nodes['nodes'])}.to output_table [
90
+ [':warning node-1', '1.1-dev', 'online', '1 / 3', '-'],
91
+ [':warning node-2', '1.1-dev', 'online', '2 / 3', '-'],
92
+ ]
93
+ end
94
+ end
95
+
96
+ context "with two online nodes and one offline node" do
97
+ let :grid_nodes do
98
+ { "nodes" => [
99
+ {
100
+ "connected" => true,
101
+ "name" => "node-1",
102
+ "node_number" => 1,
103
+ "initial_member" => true,
104
+ 'agent_version' => '1.1-dev',
105
+ },
106
+ {
107
+ "connected" => true,
108
+ "name" => "node-2",
109
+ "node_number" => 2,
110
+ "initial_member" => true,
111
+ 'agent_version' => '1.1-dev',
112
+ },
113
+ {
114
+ "connected" => false,
115
+ "name" => "node-3",
116
+ "node_number" => 3,
117
+ "initial_member" => true,
118
+ 'agent_version' => '1.1-dev',
119
+ },
120
+ ] }
121
+ end
122
+
123
+ it "outputs two nodes with warning and one offline" do
124
+ expect{subject.show_grid_nodes(grid, grid_nodes['nodes'])}.to output_table [
125
+ [':warning node-1', '1.1-dev', 'online', '1 / 3', '-'],
126
+ [':warning node-2', '1.1-dev', 'online', '2 / 3', '-'],
127
+ [':offline node-3', '1.1-dev', 'offline', '3 / 3', '-'],
128
+ ]
129
+ end
130
+ end
131
+
132
+ context "with two online initial nodes and one non-initial node" do
133
+ let :grid_nodes do
134
+ { "nodes" => [
135
+ {
136
+ "connected" => true,
137
+ "name" => "node-1",
138
+ "node_number" => 1,
139
+ "initial_member" => true,
140
+ 'agent_version' => '1.1-dev',
141
+ },
142
+ {
143
+ "connected" => true,
144
+ "name" => "node-2",
145
+ "node_number" => 2,
146
+ "initial_member" => true,
147
+ 'agent_version' => '1.1-dev',
148
+ },
149
+ {
150
+ "connected" => true,
151
+ "name" => "node-4",
152
+ "node_number" => 4,
153
+ "initial_member" => false,
154
+ 'agent_version' => '1.1-dev',
155
+ },
156
+ ] }
157
+ end
158
+
159
+ it "outputs two nodes with warning and one online" do
160
+ expect{subject.show_grid_nodes(grid, grid_nodes['nodes'])}.to output_table [
161
+ [':warning node-1', '1.1-dev', 'online', '1 / 3', '-'],
162
+ [':warning node-2', '1.1-dev', 'online', '2 / 3', '-'],
163
+ [':ok node-4', '1.1-dev', 'online', '-', '-'],
164
+ ]
165
+ end
166
+ end
167
+
168
+ context "with three online initial nodes" do
169
+ let :grid_nodes do
170
+ { "nodes" => [
171
+ {
172
+ "connected" => true,
173
+ "name" => "node-1",
174
+ "node_number" => 1,
175
+ "initial_member" => true,
176
+ 'agent_version' => '1.1-dev',
177
+ },
178
+ {
179
+ "connected" => true,
180
+ "name" => "node-2",
181
+ "node_number" => 2,
182
+ "initial_member" => true,
183
+ 'agent_version' => '1.1-dev',
184
+ },
185
+ {
186
+ "connected" => true,
187
+ "name" => "node-3",
188
+ "node_number" => 3,
189
+ "initial_member" => true,
190
+ 'agent_version' => '1.1-dev',
191
+ },
192
+ ] }
193
+ end
194
+
195
+ it "outputs three nodes with ok" do
196
+ expect{subject.show_grid_nodes(grid, grid_nodes['nodes'])}.to output_table [
197
+ [':ok node-1', '1.1-dev', 'online', '1 / 3', '-'],
198
+ [':ok node-2', '1.1-dev', 'online', '2 / 3', '-'],
199
+ [':ok node-3', '1.1-dev', 'online', '3 / 3', '-'],
200
+ ]
201
+ end
202
+ end
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,32 @@
1
+ require_relative "../../../spec_helper"
2
+ require 'kontena/cli/vault/export_command'
3
+
4
+ describe Kontena::Cli::Vault::ExportCommand do
5
+
6
+ include RequirementsHelper
7
+
8
+ let(:subject) do
9
+ described_class.new(File.basename($0))
10
+ end
11
+
12
+ expect_to_require_current_master
13
+
14
+ before(:each) do
15
+ allow(Kontena::Cli::Config.instance).to receive(:current_master).and_return(Kontena::Cli::Config::Server.new)
16
+ end
17
+
18
+ it 'goes through the list of vault keys and outputs a yaml' do
19
+ expect(Kontena).to receive(:run).with(/^vault ls/, returning: :result).and_return(['foo', 'bar'])
20
+ expect(Kontena).to receive(:run).with(/^vault read.*bar/, returning: :result).and_return('barbar')
21
+ expect(Kontena).to receive(:run).with(/^vault read.*foo/, returning: :result).and_return('foofoo')
22
+ expect{subject.run([])}.to output(/bar: barbar\nfoo: foofoo/).to_stdout
23
+ end
24
+
25
+ it 'goes through the list of vault keys and outputs a json' do
26
+ expect(Kontena).to receive(:run).with(/^vault ls/, returning: :result).and_return(['foo', 'bar'])
27
+ expect(Kontena).to receive(:run).with(/^vault read.*bar/, returning: :result).and_return('barbar')
28
+ expect(Kontena).to receive(:run).with(/^vault read.*foo/, returning: :result).and_return('foofoo')
29
+ expect{subject.run(['--json'])}.to output(/\"bar\":\"barbar\",\"foo\":\"foofoo\"/).to_stdout
30
+ end
31
+
32
+ end
@@ -0,0 +1,69 @@
1
+ require_relative "../../../spec_helper"
2
+ require 'kontena/cli/vault/import_command'
3
+
4
+
5
+ describe Kontena::Cli::Vault::ImportCommand do
6
+
7
+ include RequirementsHelper
8
+
9
+ let(:subject) do
10
+ described_class.new(File.basename($0))
11
+ end
12
+
13
+ before(:each) do
14
+ allow(Kontena::Cli::Config.instance).to receive(:current_master).and_return(Kontena::Cli::Config::Server.new)
15
+ allow(Kontena::Cli::Config.instance).to receive(:current_grid).and_return("foofoo")
16
+ end
17
+
18
+ expect_to_require_current_master
19
+
20
+ it 'asks for confirmation' do
21
+ expect(subject).to receive(:confirm).and_raise(RuntimeError, 'confirm')
22
+ expect(File).to receive(:read).with('foo.yml').and_return("foo: bar\n")
23
+ expect{subject.run(['foo.yml'])}.to raise_error(RuntimeError, 'confirm')
24
+ end
25
+
26
+ it 'dies if the yml contains something odd' do
27
+ expect(File).to receive(:read).with('foo.yml').and_return({foo: 'bar', bar: { foo: ["bar"] }}.to_yaml)
28
+ expect(subject).to receive(:exit_with_error).with(/Invalid value/).and_raise(RuntimeError, 'invalid')
29
+ expect{subject.run(['foo.yml'])}.to raise_error(RuntimeError, 'invalid')
30
+ end
31
+
32
+ it 'runs vault write for kv-pairs in yaml' do
33
+ expect(File).to receive(:read).with('foo.yml').and_return("foo: bar\nbar: foo\n")
34
+ expect(Kontena).to receive(:run).with(/vault update.*foo bar/).and_return(0)
35
+ expect(Kontena).to receive(:run).with(/vault update.*bar foo/).and_return(0)
36
+ subject.run(['--force', 'foo.yml'])
37
+ end
38
+
39
+ it 'runs vault rm for kv-pairs with null value in yaml' do
40
+ expect(File).to receive(:read).with('foo.yml').and_return("foo: bar\nbar: null\n")
41
+ expect(Kontena).to receive(:run).with(/vault update.*foo bar/).and_return(0)
42
+ expect(Kontena).to receive(:run).with(/vault rm.*bar/).and_return(0)
43
+ subject.run(['--force', 'foo.yml'])
44
+ end
45
+
46
+ it 'runs vault rm for kv-pairs with empty value in yaml when --empty-is-null' do
47
+ expect(File).to receive(:read).with('foo.yml').and_return("foo: bar\nbar:\n")
48
+ expect(Kontena).to receive(:run).with(/vault update.*foo bar/).and_return(0)
49
+ expect(Kontena).to receive(:run).with(/vault rm.*bar/).and_return(0)
50
+ subject.run(['--force', '--empty-is-null', 'foo.yml'])
51
+ end
52
+
53
+ it 'does not run vault rm for kv-pairs with empty value in yaml when no --empty-is-null' do
54
+ expect(File).to receive(:read).with('foo.yml').and_return("foo: bar\nbar: \"\"\n")
55
+ expect(Kontena).to receive(:run).with(/vault update.*foo bar/).and_return(0)
56
+ expect(Kontena).to receive(:run).with(/vault update.*bar ''/).and_return(0)
57
+ expect(Kontena).not_to receive(:run).with(/vault rm.*bar/)
58
+ subject.run(['--force', 'foo.yml'])
59
+ end
60
+
61
+ it 'doesnt vault rm for kv-pairs with null value in yaml when --skip-null used' do
62
+ expect(File).to receive(:read).with('foo.yml').and_return("foo: bar\nbar: null\n")
63
+ expect(Kontena).to receive(:run).with(/vault update.*foo bar/).and_return(0)
64
+ expect(Kontena).not_to receive(:run).with(/vault rm.*bar/)
65
+ subject.run(['--force', '--skip-null', 'foo.yml'])
66
+ end
67
+
68
+ end
69
+