kontena-cli 1.2.0.pre3 → 1.2.0.rc1

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/kontena-cli.gemspec +3 -3
  4. data/lib/kontena/cli/common.rb +13 -0
  5. data/lib/kontena/cli/grid_command.rb +1 -0
  6. data/lib/kontena/cli/grids/events_command.rb +50 -0
  7. data/lib/kontena/cli/helpers/log_helper.rb +2 -2
  8. data/lib/kontena/cli/master/config/import_command.rb +2 -2
  9. data/lib/kontena/cli/master/logout_command.rb +19 -17
  10. data/lib/kontena/cli/service_command.rb +1 -0
  11. data/lib/kontena/cli/services/events_command.rb +36 -0
  12. data/lib/kontena/cli/services/remove_command.rb +28 -4
  13. data/lib/kontena/cli/services/services_helper.rb +39 -4
  14. data/lib/kontena/cli/services/show_command.rb +8 -1
  15. data/lib/kontena/cli/stack_command.rb +1 -0
  16. data/lib/kontena/cli/stacks/events_command.rb +33 -0
  17. data/lib/kontena/cli/stacks/logs_command.rb +2 -0
  18. data/lib/kontena/cli/stacks/yaml/opto/prompt_resolver.rb +1 -1
  19. data/lib/kontena/cli/vault/import_command.rb +2 -2
  20. data/lib/kontena/cli/vault/update_command.rb +9 -12
  21. data/lib/kontena/cli/vault/write_command.rb +8 -15
  22. data/lib/kontena/cli/volume_command.rb +3 -0
  23. data/lib/kontena/cli/volumes/show_command.rb +38 -0
  24. data/lib/kontena/main_command.rb +1 -1
  25. data/lib/kontena_cli.rb +5 -1
  26. data/spec/kontena/cli/grids/events_command_spec.rb +15 -0
  27. data/spec/kontena/cli/services/events_command_spec.rb +22 -0
  28. data/spec/kontena/cli/stacks/events_command_spec.rb +22 -0
  29. data/spec/kontena/cli/stacks/logs_command_spec.rb +32 -0
  30. data/spec/kontena/cli/vault/update_command_spec.rb +79 -0
  31. data/spec/kontena/cli/vault/write_command_spec.rb +60 -0
  32. data/spec/kontena/kontena_cli_spec.rb +6 -3
  33. metadata +26 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fbe93b31f3b0185a1f79d87967898a48dd6c3a8b
4
- data.tar.gz: d94145ce8dbb0289a75785293802b25f8a29e48f
3
+ metadata.gz: d1303357caabb58711e52c64fef54b12a9afc989
4
+ data.tar.gz: 8ce9069dcf068450f990cb23fddac6792a7956c6
5
5
  SHA512:
6
- metadata.gz: b6f6a68a4ef272bdc3f8ef941e155d7536eb3c429fd726dc00d98fe8ee6cd15a39f1f600ad218f7d1041a33db88d01a23f4d6d692ef0af1f2ad9b25de3a54725
7
- data.tar.gz: 1e0552a145da0f8cebebe1ef1305052385f25077b7d903d58a4bc4f4fda7622e323e712af13b2bcce79319fc0950d55e59c01ae4cd63f97b8c5876d3ff2b0c2c
6
+ metadata.gz: 7df9880f68b96488d865427015884e99af34a56c9b4b0c52df1c4614e15e5e3686f386fa672ea1310c42801cb6e8b6d82a2387dca9439800f3b2e980e06ae01a
7
+ data.tar.gz: d1447a0ac64a834660c7b4857e50e533757247af83664d875644c812075b6622bdd53397e18c2fb1bb12cc4924319e17c9b9c788d46b6dbb6de1288d034e1399
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.0.pre3
1
+ 1.2.0.rc1
data/kontena-cli.gemspec CHANGED
@@ -23,13 +23,13 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "bundler", "~> 1.7"
24
24
  spec.add_development_dependency "rake", "~> 10.0"
25
25
  spec.add_runtime_dependency "excon", "~> 0.49.0"
26
- spec.add_runtime_dependency "tty-prompt", "~> 0.11.0"
26
+ spec.add_runtime_dependency "tty-prompt", "0.12.0"
27
27
  spec.add_runtime_dependency "clamp", "~> 1.1.0"
28
28
  spec.add_runtime_dependency "ruby_dig", "~> 0.0.2"
29
29
  spec.add_runtime_dependency "launchy", "~> 2.4.3"
30
- spec.add_runtime_dependency "hash_validator", "~> 0.7.0"
30
+ spec.add_runtime_dependency "hash_validator", "~> 0.7.1"
31
31
  spec.add_runtime_dependency "retriable", "~> 2.1.0"
32
- spec.add_runtime_dependency "opto", "1.8.4"
32
+ spec.add_runtime_dependency "opto", "1.8.5"
33
33
  spec.add_runtime_dependency "semantic", "~> 1.5"
34
34
  spec.add_runtime_dependency "safe_yaml", "~> 1.0"
35
35
  spec.add_runtime_dependency "liquid", "~> 4.0.0"
@@ -22,6 +22,19 @@ module Kontena
22
22
  @pastel ||= Pastel.new(enabled: $stdout.tty?)
23
23
  end
24
24
 
25
+ # Read from STDIN. If stdin is a console, use prompt to ask.
26
+ # @param [String] message
27
+ # @param [Symbol] mode (prompt method: :ask, :multiline, etc)
28
+ def stdin_input(message = nil, mode = :ask)
29
+ if $stdin.tty?
30
+ Array(prompt.send(mode, message)).join.chomp
31
+ elsif !$stdin.eof?
32
+ $stdin.read.chomp
33
+ else
34
+ exit_with_error 'Missing input'
35
+ end
36
+ end
37
+
25
38
  def running_silent?
26
39
  self.respond_to?(:silent?) && self.silent?
27
40
  end
@@ -6,6 +6,7 @@ class Kontena::Cli::GridCommand < Kontena::Command
6
6
  subcommand "use", "Switch to use specific grid", load_subcommand('grids/use_command')
7
7
  subcommand "show", "Show grid details", load_subcommand('grids/show_command')
8
8
  subcommand "logs", "Show logs from grid containers", load_subcommand('grids/logs_command')
9
+ subcommand "events", "Show events from grid", load_subcommand('grids/events_command')
9
10
  subcommand ["remove","rm"], "Remove a grid", load_subcommand('grids/remove_command')
10
11
  subcommand "current", "Show current grid details", load_subcommand('grids/current_command')
11
12
  subcommand "env", "Show the current grid environment details", load_subcommand('grids/env_command')
@@ -0,0 +1,50 @@
1
+ require_relative '../helpers/log_helper'
2
+
3
+ module Kontena::Cli::Grids
4
+ class EventsCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::Helpers::LogHelper
7
+
8
+ SKIP_TYPES = ['grid']
9
+
10
+ option "--node", "NODE", "Filter by node name", multivalued: true
11
+ option "--service", "SERVICE", "Filter by service name", multivalued: true
12
+
13
+ def execute
14
+ require_api_url
15
+
16
+ query_params = {}
17
+ query_params[:nodes] = node_list.join(",") unless node_list.empty?
18
+ query_params[:services] = service_list.join(",") unless service_list.empty?
19
+
20
+ titles = ['TIME', 'TYPE', 'RELATIONSHIPS', 'MESSAGE']
21
+ puts "%-25s %-25s %-40s %s" % titles
22
+ show_logs("grids/#{current_grid}/event_logs", query_params) do |log|
23
+ show_log(log)
24
+ end
25
+ end
26
+
27
+ def show_log(log)
28
+ msg = log['message']
29
+ rels = log['relationships'].
30
+ delete_if { |r| SKIP_TYPES.include?(r['type']) }.
31
+ map { |r|
32
+ id = r['id'].split('/')[1..-1].delete_if{ |s| s == 'null'}.join('/')
33
+ unless id.empty?
34
+ "#{r['type']}=#{id}"
35
+ end
36
+ }.compact
37
+
38
+ time = log['created_at']
39
+ if log['severity'] == 2
40
+ time = time.colorize(:yellow)
41
+ elsif log['severity'] >= 3
42
+ time = time.colorize(:red)
43
+ end
44
+
45
+ puts '%-25s %-25s %-40s %s' % [
46
+ time, log['type'], rels.join(','), msg
47
+ ]
48
+ end
49
+ end
50
+ end
@@ -52,7 +52,7 @@ module Kontena::Cli::Helpers
52
52
 
53
53
  begin
54
54
  query_params[:from] = last_seen if last_seen
55
- result = client(token).get_stream(url, streamer, query_params)
55
+ client(token).get_stream(url, streamer, query_params)
56
56
  rescue => exc
57
57
  retry if exc.cause.is_a?(EOFError) # Excon wraps the EOFerror into SocketError
58
58
  raise
@@ -74,7 +74,7 @@ module Kontena::Cli::Helpers
74
74
  end
75
75
  @buffer = ''
76
76
  log
77
- rescue => exc
77
+ rescue
78
78
  @buffer << orig_chunk
79
79
  nil
80
80
  end
@@ -8,7 +8,7 @@ module Kontena::Cli::Master::Config
8
8
 
9
9
  banner "Updates configuration from a file into Master"
10
10
 
11
- parameter '[PATH]', "Input from file in PATH, default: STDIN", required: false
11
+ parameter '[PATH]', "Input from file in PATH (default: STDIN)", required: false
12
12
 
13
13
  option ['--preset'], '[NAME]', 'Load preset', hidden: true
14
14
 
@@ -30,7 +30,7 @@ module Kontena::Cli::Master::Config
30
30
  path = File.join(Kontena.root, 'lib/kontena/presets', "#{self.preset}.yml")
31
31
  File.read(path)
32
32
  else
33
- STDIN.read
33
+ stdin_input("Enter master configuration as #{format.upcase}", :multiline)
34
34
  end
35
35
  end
36
36
 
@@ -1,23 +1,25 @@
1
- class Kontena::Cli::Master::LogoutCommand < Kontena::Command
2
- include Kontena::Cli::Common
1
+ module Kontena::Cli::Master
2
+ class LogoutCommand < Kontena::Command
3
+ include Kontena::Cli::Common
3
4
 
4
- option ['-A', '--all'], :flag, 'Log out from all masters. By default only log out from current master.'
5
+ option ['-A', '--all'], :flag, 'Log out from all masters. By default only log out from current master.'
5
6
 
6
- def execute
7
- if self.all?
8
- config.servers.each do |server|
9
- use_refresh_token(server)
10
- server.token = nil
11
- puts "Logged out of #{server.name.colorize(:green)}"
7
+ def execute
8
+ if self.all?
9
+ config.servers.each do |server|
10
+ use_refresh_token(server)
11
+ server.token = nil
12
+ puts "Logged out of #{server.name.colorize(:green)}"
13
+ end
14
+ elsif config.current_master
15
+ use_refresh_token(config.current_master)
16
+ config.current_master.token = nil
17
+ puts "Logged out of #{config.current_master.name.colorize(:green)}"
18
+ else
19
+ warn "Current master has not been selected"
20
+ exit 0 # exiting with 0 not 1, it's not really an error situation (kontena logout && kontena master login...)
12
21
  end
13
- elsif config.current_master
14
- use_refresh_token(config.current_master)
15
- config.current_master.token = nil
16
- puts "Logged out of #{config.current_master.name.colorize(:green)}"
17
- else
18
- warn "Current master has not been selected"
19
- exit 0 # exiting with 0 not 1, it's not really an error situation (kontena logout && kontena master login...)
22
+ config.write
20
23
  end
21
- config.write
22
24
  end
23
25
  end
@@ -11,6 +11,7 @@ class Kontena::Cli::ServiceCommand < Kontena::Command
11
11
  subcommand ["remove", "rm"], "Remove service", load_subcommand('services/remove_command')
12
12
  subcommand "containers", "List service containers", load_subcommand('services/containers_command')
13
13
  subcommand "logs", "Show service logs", load_subcommand('services/logs_command')
14
+ subcommand "events", "Show service events", load_subcommand('services/events_command')
14
15
  subcommand "stats", "Show service statistics", load_subcommand('services/stats_command')
15
16
  subcommand "monitor", "Monitor", load_subcommand('services/monitor_command')
16
17
 
@@ -0,0 +1,36 @@
1
+ require_relative 'services_helper'
2
+ require_relative '../helpers/log_helper'
3
+
4
+ module Kontena::Cli::Services
5
+ class EventsCommand < Kontena::Command
6
+ include Kontena::Cli::Common
7
+ include Kontena::Cli::GridOptions
8
+ include Kontena::Cli::Helpers::LogHelper
9
+ include ServicesHelper
10
+
11
+ parameter "NAME", "Service name"
12
+
13
+ def execute
14
+ require_api_url
15
+
16
+ query_params = {}
17
+
18
+ titles = ['TIME', 'TYPE', 'MESSAGE']
19
+ puts "%-25s %-20s %s" % titles
20
+ show_logs("services/#{parse_service_id(name)}/event_logs", query_params) do |log|
21
+ show_log(log)
22
+ end
23
+ end
24
+
25
+ def show_log(log)
26
+ msg = log['message']
27
+ node = log['relationships'].find { |r| r['type'] == 'node' }
28
+ if node
29
+ msg = "#{msg} (#{node['id'].split('/')[-1]})"
30
+ end
31
+ puts '%-25s %-20s %s' % [
32
+ log['created_at'], log['type'].sub('service:'.freeze, ''.freeze), msg
33
+ ]
34
+ end
35
+ end
36
+ end
@@ -6,20 +6,32 @@ module Kontena::Cli::Services
6
6
  include ServicesHelper
7
7
 
8
8
  parameter "NAME", "Service name"
9
+ option "--instance", "INSTANCE", "Remove only given instance"
9
10
  option "--force", :flag, "Force remove", default: false, attribute_name: :forced
10
11
 
12
+ banner "Remove a service"
13
+
14
+ requires_current_master
15
+ requires_current_master_token
16
+
11
17
  def execute
12
- require_api_url
13
- token = require_token
18
+ if instance
19
+ remove_instance
20
+ else
21
+ remove
22
+ end
23
+ end
24
+
25
+ def remove
14
26
  confirm_command(name) unless forced?
15
27
 
16
28
  spinner "Removing service #{name.colorize(:cyan)} " do
17
- client(token).delete("services/#{parse_service_id(name)}")
29
+ client.delete("services/#{parse_service_id(name)}")
18
30
  removed = false
19
31
  until removed == true
20
32
  sleep 1
21
33
  begin
22
- client(token).get("services/#{parse_service_id(name)}")
34
+ client.get("services/#{parse_service_id(name)}")
23
35
  rescue Kontena::Errors::StandardError => exc
24
36
  if exc.status == 404
25
37
  removed = true
@@ -30,5 +42,17 @@ module Kontena::Cli::Services
30
42
  end
31
43
  end
32
44
  end
45
+
46
+ def remove_instance
47
+ instance_name = "#{name}/#{instance}"
48
+ confirm_command("#{name}/#{instance}") unless forced?
49
+ service_instance = client.get("services/#{parse_service_id(name)}/instances")['instances'].find{ |i|
50
+ i['instance_number'] == instance.to_i
51
+ }
52
+ exit_with_error("Instance not found") unless service_instance
53
+ spinner "Removing service instance #{instance_name.colorize(:cyan)} " do
54
+ client.delete("services/#{parse_service_id(name)}/instances/#{service_instance['id']}")
55
+ end
56
+ end
33
57
  end
34
58
  end
@@ -41,12 +41,11 @@ module Kontena
41
41
  # @param [String] service_id
42
42
  def show_service(token, service_id)
43
43
  service = get_service(token, service_id)
44
- grid = service['id'].split('/')[0]
45
44
  puts "#{service['id']}:"
46
45
  puts " created: #{service['created_at']}"
47
46
  puts " updated: #{service['updated_at']}"
48
47
  puts " stack: #{service['stack']['id'] }"
49
- puts " state: #{service['state'] }"
48
+ puts " desired_state: #{service['state'] }"
50
49
  puts " image: #{service['image']}"
51
50
  puts " revision: #{service['revision']}"
52
51
  puts " stack_revision: #{service['stack_revision']}" if service['stack_revision']
@@ -54,7 +53,9 @@ module Kontena
54
53
  puts " scaling: #{service['instances'] }"
55
54
  puts " strategy: #{service['strategy']}"
56
55
  puts " deploy_opts:"
57
- puts " min_health: #{service['deploy_opts']['min_health']}"
56
+ if service['deploy_opts']['min_health']
57
+ puts " min_health: #{service['deploy_opts']['min_health']}"
58
+ end
58
59
  if service['deploy_opts']['wait_for_port']
59
60
  puts " wait_for_port: #{service['deploy_opts']['wait_for_port']}"
60
61
  end
@@ -104,7 +105,7 @@ module Kontena
104
105
  end
105
106
  end
106
107
 
107
- unless service['net'].to_s.empty?
108
+ if service['net'].to_s != 'bridge'
108
109
  puts " net: #{service['net']}"
109
110
  end
110
111
 
@@ -188,6 +189,40 @@ module Kontena
188
189
  end
189
190
 
190
191
  def show_service_instances(token, service_id)
192
+ puts " instances:"
193
+ instances = client(token).get("services/#{parse_service_id(service_id)}/instances")['instances']
194
+ containers = client(token).get("services/#{parse_service_id(service_id)}/containers")['containers']
195
+ instances.each do |i|
196
+ puts " #{name}/#{i['instance_number']}:"
197
+ puts " scheduled_to: #{i.dig('node', 'name') || '-'}"
198
+ puts " deploy_rev: #{i['deploy_rev']}"
199
+ puts " rev: #{i['rev']}"
200
+ puts " state: #{i['state']}"
201
+ puts " error: #{i['error'] || '-'}" if i['error']
202
+ puts " containers:"
203
+ containers.select { |c|
204
+ c['instance_number'] == i['instance_number']
205
+ }.each do |container|
206
+ puts " #{container['name']} (on #{container.dig('node', 'name')}):"
207
+ puts " dns: #{container['hostname']}.#{container['domainname']}"
208
+ puts " ip: #{container['ip_address']}"
209
+ puts " public ip: #{container['node']['public_ip'] rescue 'unknown'}"
210
+ if container['health_status']
211
+ health_time = Time.now - Time.parse(container.dig('health_status', 'updated_at'))
212
+ puts " health: #{container.dig('health_status', 'status')} (#{health_time.to_i}s ago)"
213
+ end
214
+ puts " status: #{container['status']}"
215
+ if container.dig('state', 'error') != ''
216
+ puts " reason: #{container['state']['error']}"
217
+ end
218
+ if container.dig('state', 'exit_code').to_i != 0
219
+ puts " exit code: #{container['state']['exit_code']}"
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ def show_service_containers(token, service_id)
191
226
  puts " instances:"
192
227
  result = client(token).get("services/#{parse_service_id(service_id)}/containers")
193
228
  result['containers'].each do |container|
@@ -13,7 +13,14 @@ module Kontena::Cli::Services
13
13
  token = require_token
14
14
 
15
15
  show_service(token, name)
16
- show_service_instances(token, name)
16
+ begin
17
+ show_service_instances(token, name)
18
+ rescue Kontena::Errors::StandardError => exc
19
+ if exc.status == 404
20
+ # fallback to old behaviour
21
+ show_service_containers(token, name)
22
+ end
23
+ end
17
24
  end
18
25
  end
19
26
  end
@@ -6,6 +6,7 @@ class Kontena::Cli::StackCommand < Kontena::Command
6
6
  subcommand "upgrade", "Upgrade a stack in a grid", load_subcommand('stacks/upgrade_command')
7
7
  subcommand ["start", "deploy"], "Deploy an installed stack in a grid", load_subcommand('stacks/deploy_command')
8
8
  subcommand "logs", "Show logs from services in a stack", load_subcommand('stacks/logs_command')
9
+ subcommand "events", "Show events from services in a stack", load_subcommand('stacks/events_command')
9
10
  subcommand "monitor", "Monitor services in a stack", load_subcommand('stacks/monitor_command')
10
11
  subcommand "build", "Build images listed in a stack file and push them to an image registry", load_subcommand('stacks/build_command')
11
12
  subcommand ["reg", "registry"], "Stack registry related commands", load_subcommand('stacks/registry_command')
@@ -0,0 +1,33 @@
1
+ require_relative '../helpers/log_helper'
2
+
3
+ module Kontena::Cli::Stacks
4
+ class EventsCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::GridOptions
7
+ include Kontena::Cli::Helpers::LogHelper
8
+
9
+ parameter "NAME", "Service name"
10
+
11
+ def execute
12
+ require_api_url
13
+
14
+ query_params = {}
15
+ titles = ['TIME', 'TYPE', 'MESSAGE']
16
+ puts "%-25s %-25s %s" % titles
17
+ show_logs("stacks/#{current_grid}/#{name}/event_logs", query_params) do |log|
18
+ show_log(log)
19
+ end
20
+ end
21
+
22
+ def show_log(log)
23
+ msg = log['message']
24
+ node = log['relationships'].find { |r| r['type'] == 'node' }
25
+ if node
26
+ msg = "#{msg} (#{node['id'].split('/')[-1]})"
27
+ end
28
+ puts '%-25s %-25s %s' % [
29
+ log['created_at'], log['type'], msg
30
+ ]
31
+ end
32
+ end
33
+ end
@@ -1,3 +1,5 @@
1
+ require_relative '../helpers/log_helper'
2
+
1
3
  module Kontena::Cli::Stacks
2
4
  class LogsCommand < Kontena::Command
3
5
  include Kontena::Cli::Common
@@ -50,7 +50,7 @@ module Kontena::Cli::Stacks
50
50
  end
51
51
 
52
52
  def bool
53
- prompt.yes?(question_text, default: option.default == false ? false : true)
53
+ prompt.yes?(question_text, default: option.default.nil? || option.default)
54
54
  end
55
55
 
56
56
  def echo?
@@ -10,7 +10,7 @@ module Kontena::Cli::Vault
10
10
  option '--skip-null', :flag, "Do not remove keys with null values"
11
11
  option '--empty-is-null', :flag, "Treat empty values as null"
12
12
 
13
- parameter '[PATH]', "Input from file in PATH, default: STDIN"
13
+ parameter '[PATH]', "Input from file in PATH (default: STDIN)"
14
14
 
15
15
  requires_current_master
16
16
 
@@ -23,7 +23,7 @@ module Kontena::Cli::Vault
23
23
  end
24
24
 
25
25
  def input
26
- path ? File.read(path) : STDIN.read
26
+ path ? File.read(path) : stdin_input("Enter secrets YAML", :multiline)
27
27
  end
28
28
 
29
29
  def execute
@@ -1,26 +1,23 @@
1
1
  module Kontena::Cli::Vault
2
2
  class UpdateCommand < Kontena::Command
3
3
  include Kontena::Cli::Common
4
+ include Kontena::Cli::GridOptions
4
5
 
5
6
  parameter 'NAME', 'Secret name'
6
- parameter '[VALUE]', 'Secret value'
7
+ parameter '[VALUE]', 'Secret value (default: STDIN)'
7
8
 
8
9
  option ['-u', '--upsert'], :flag, 'Create secret unless already exists', default: false
9
10
  option '--silent', :flag, "Reduce output verbosity"
10
11
 
11
- def execute
12
- require_api_url
13
- require_current_grid
12
+ requires_current_master
13
+
14
+ def default_value
15
+ stdin_input("Enter value for secret '#{name}'", :mask)
16
+ end
14
17
 
15
- token = require_token
16
- value ||= STDIN.read.chomp
17
- data = {
18
- name: name,
19
- value: value,
20
- upsert: upsert?
21
- }
18
+ def execute
22
19
  vspinner "Updating #{name.colorize(:cyan)} value in the vault " do
23
- client(token).put("secrets/#{current_grid}/#{name}", data)
20
+ client.put("secrets/#{current_grid}/#{name}", {name: name, value: value, upsert: upsert? })
24
21
  end
25
22
  end
26
23
  end
@@ -4,26 +4,19 @@ module Kontena::Cli::Vault
4
4
  include Kontena::Cli::GridOptions
5
5
 
6
6
  parameter 'NAME', 'Secret name'
7
- parameter '[VALUE]', 'Secret value'
7
+ parameter '[VALUE]', 'Secret value (default: STDIN)'
8
8
 
9
9
  option '--silent', :flag, "Reduce output verbosity"
10
10
 
11
- def execute
12
- require_api_url
13
- require_current_grid
11
+ requires_current_master
14
12
 
15
- token = require_token
16
- secret = value
17
- if secret.to_s == ''
18
- secret = STDIN.read
19
- end
20
- exit_with_error('No value provided') if secret.to_s == ''
21
- data = {
22
- name: name,
23
- value: secret
24
- }
13
+ def default_value
14
+ stdin_input("Enter value for secret '#{name}'", :mask)
15
+ end
16
+
17
+ def execute
25
18
  vspinner "Writing #{name.colorize(:cyan)} to the vault " do
26
- client(token).post("grids/#{current_grid}/secrets", data)
19
+ client.post("grids/#{current_grid}/secrets", { name: name, value: value })
27
20
  end
28
21
  end
29
22
  end
@@ -1,7 +1,10 @@
1
1
 
2
2
  class Kontena::Cli::VolumeCommand < Kontena::Command
3
3
 
4
+ warn Kontena.pastel.yellow("[EXPERIMENTAL] The `kontena volume` commands are still experimental in Kontena #{Kontena.minor_version}, and may change in future releases")
5
+
4
6
  subcommand "create", "Create a managed volume", load_subcommand('volumes/create_command')
7
+ subcommand "show", "Show details of a volume", load_subcommand('volumes/show_command')
5
8
  subcommand ["remove", "rm"], "Remove a managed volume", load_subcommand('volumes/remove_command')
6
9
  subcommand ["list", "ls"], "List managed volumes", load_subcommand('volumes/list_command')
7
10
 
@@ -0,0 +1,38 @@
1
+
2
+ module Kontena::Cli::Volumes
3
+ class ShowCommand < Kontena::Command
4
+ include Kontena::Cli::Common
5
+ include Kontena::Cli::GridOptions
6
+
7
+ banner "Show details of a volume"
8
+
9
+ parameter 'VOLUME', 'Volume'
10
+
11
+ requires_current_master
12
+ requires_current_master_token
13
+
14
+ def execute
15
+ vol = client.get("volumes/#{current_grid}/#{volume}")
16
+ puts "#{vol['name']}:"
17
+ puts " id: #{vol['id']}"
18
+ puts " created: #{vol['created_at']}"
19
+ puts " scope: #{vol['scope']}"
20
+ puts " driver: #{vol['driver']}"
21
+ puts " driver_opts:"
22
+ vol['driver_opts'].each do |k,v|
23
+ puts " #{k}: #{v}"
24
+ end
25
+ puts " instances:"
26
+ vol['instances'].each do |instance|
27
+ puts " - name: #{instance['name']}"
28
+ puts " node: #{instance['node']}"
29
+ end
30
+ puts " services:"
31
+ vol['services'].each do |service|
32
+ puts " - #{service['id']}"
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+ end
@@ -36,7 +36,7 @@ class Kontena::MainCommand < Kontena::Command
36
36
  subcommand "whoami", "Shows current logged in user", load_subcommand('whoami_command')
37
37
  subcommand "plugin", "Plugin related commands", load_subcommand('plugin_command')
38
38
  subcommand "version", "Show CLI and current master version", load_subcommand('version_command')
39
- subcommand "volume", "Volume specific commands", load_subcommand('volume_command')
39
+ subcommand "volume", "Volume specific commands [EXPERIMENTAL]", load_subcommand('volume_command')
40
40
 
41
41
  def execute
42
42
  end
data/lib/kontena_cli.rb CHANGED
@@ -28,6 +28,11 @@ module Kontena
28
28
  end
29
29
 
30
30
 
31
+ # @return [String] x.y
32
+ def self.minor_version
33
+ Kontena::Cli::VERSION.split('.')[0..1].join('.')
34
+ end
35
+
31
36
  def self.version
32
37
  "kontena-cli/#{Kontena::Cli::VERSION}"
33
38
  end
@@ -111,4 +116,3 @@ require_relative 'kontena/stacks_cache'
111
116
  require_relative 'kontena/plugin_manager'
112
117
  require_relative 'kontena/main_command'
113
118
  require_relative 'kontena/cli/spinner'
114
-
@@ -0,0 +1,15 @@
1
+ require 'kontena/cli/grids/events_command'
2
+
3
+ describe Kontena::Cli::Grids::EventsCommand do
4
+ include ClientHelpers
5
+ include OutputHelpers
6
+
7
+ describe '#execute' do
8
+ it 'requests events from master' do
9
+ expect(client).to receive(:get).with(
10
+ 'grids/test-grid/event_logs', {limit: 100}
11
+ ).and_return({'logs' => []})
12
+ subject.run([])
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ require_relative "../../../spec_helper"
2
+ require "kontena/cli/services/events_command"
3
+
4
+ describe Kontena::Cli::Services::EventsCommand do
5
+
6
+ include ClientHelpers
7
+
8
+ describe '#execute' do
9
+ before(:each) do
10
+ allow(client).to receive(:get).and_return({
11
+ 'logs' => []
12
+ })
13
+ end
14
+
15
+ it 'requests logs from master' do
16
+ expect(client).to receive(:get).with(
17
+ 'services/test-grid/null/service-a/event_logs', {limit: 100}
18
+ )
19
+ subject.run(['service-a'])
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ require_relative "../../../spec_helper"
2
+ require "kontena/cli/stacks/events_command"
3
+
4
+ describe Kontena::Cli::Stacks::EventsCommand do
5
+
6
+ include ClientHelpers
7
+
8
+ describe '#execute' do
9
+ before(:each) do
10
+ allow(client).to receive(:get).and_return({
11
+ 'logs' => []
12
+ })
13
+ end
14
+
15
+ it 'requests logs from master' do
16
+ expect(client).to receive(:get).with(
17
+ 'stacks/test-grid/redish/event_logs', {limit: 100}
18
+ )
19
+ subject.run(['redish'])
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ require "kontena/cli/stacks/logs_command"
2
+
3
+ describe Kontena::Cli::Stacks::LogsCommand do
4
+ include ClientHelpers
5
+ include OutputHelpers
6
+
7
+ let (:logs) do
8
+ [
9
+ {
10
+ 'id' => '57cff2e8cfee65c8b6efc8bd',
11
+ 'name' => 'test-stack.mysql-1',
12
+ 'created_at' => '2016-09-07T15:19:04.362690',
13
+ 'data' => "mysql log message 1",
14
+ },
15
+ ]
16
+ end
17
+
18
+ before(:each) do
19
+ Kontena.pastel.resolver.color.disable!
20
+ end
21
+
22
+ it "shows stack logs" do
23
+ expect(client).to receive(:get).with('stacks/test-grid/test-stack/container_logs', {
24
+ limit: 100,
25
+ }) { { 'logs' => logs } }
26
+
27
+ expect{subject.run(['test-stack'])}.to output_lines [
28
+ "2016-09-07T15:19:04.362690 [test-stack.mysql-1]: mysql log message 1",
29
+ ]
30
+ end
31
+
32
+ end
@@ -0,0 +1,79 @@
1
+ require_relative "../../../spec_helper"
2
+ require 'kontena/cli/vault/update_command'
3
+
4
+ describe Kontena::Cli::Vault::UpdateCommand do
5
+
6
+ include RequirementsHelper
7
+ include ClientHelpers
8
+
9
+ let(:subject) { described_class.new(File.basename($0)) }
10
+
11
+ describe '#execute' do
12
+
13
+ context 'without value parameter' do
14
+
15
+ let(:stdin) { double(:stdin) }
16
+
17
+ before(:each) do
18
+ @old_stdin = $stdin
19
+ $stdin = stdin
20
+ end
21
+
22
+ after(:each) { $stdin = @old_stdin }
23
+
24
+ context 'without tty' do
25
+ before(:each) { allow(stdin).to receive(:tty?).and_return(false) }
26
+ after(:each) { $stdin = @old_stdin }
27
+
28
+ context 'nothing in stdin' do
29
+ before(:each) do
30
+ allow(stdin).to receive(:eof?).and_return(true)
31
+ end
32
+
33
+ it 'returns error if value not provided' do
34
+ expect{subject.run(['mysql_password'])}.to exit_with_error.and output(/Missing/).to_stderr
35
+ end
36
+ end
37
+
38
+ context 'value in stdin' do
39
+ it 'sends update request' do
40
+ expect(stdin).to receive(:eof?).and_return(false)
41
+ expect(stdin).to receive(:read).and_return('secret')
42
+ expect(client).to receive(:put).with('secrets/test-grid/mysql_password', { name: 'mysql_password', value: 'secret', upsert: false})
43
+ expect{subject.run(['mysql_password'])}.not_to exit_with_error
44
+ end
45
+ end
46
+ end
47
+
48
+ context 'with tty' do
49
+ before(:each) do
50
+ allow(stdin).to receive(:tty?).and_return(true)
51
+ end
52
+
53
+ context 'when value not given' do
54
+ let(:prompt) { double(:prompt) }
55
+ it 'prompts for value' do
56
+ expect(subject).to receive(:prompt).and_return(prompt)
57
+ expect(prompt).to receive(:mask).once.and_return('very-secret')
58
+ expect(client).to receive(:put).with('secrets/test-grid/mysql_password', { name: 'mysql_password', value: 'very-secret', upsert: false})
59
+ expect{subject.run(['mysql_password'])}.not_to exit_with_error
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ context 'with value parameter' do
66
+ it 'sends update request' do
67
+ expect(client).to receive(:put).with('secrets/test-grid/mysql_password', { name: 'mysql_password', value: 'secret', upsert: false})
68
+ expect{subject.run(['mysql_password', 'secret'])}.not_to exit_with_error
69
+ end
70
+
71
+ context 'when giving --upsert flag' do
72
+ it 'sets upsert true' do
73
+ expect(client).to receive(:put).with('secrets/test-grid/mysql_password', { name: 'mysql_password', value: 'secret', upsert: true})
74
+ subject.run(['-u', 'mysql_password', 'secret'])
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,60 @@
1
+ require_relative "../../../spec_helper"
2
+ require 'kontena/cli/vault/write_command'
3
+
4
+ describe Kontena::Cli::Vault::WriteCommand do
5
+
6
+ include RequirementsHelper
7
+ include ClientHelpers
8
+
9
+ let(:subject) { described_class.new(File.basename($0)) }
10
+
11
+ describe '#execute' do
12
+ context 'without value parameter' do
13
+
14
+ let(:stdin) { double(:stdin) }
15
+
16
+ before(:each) do
17
+ @old_stdin = $stdin
18
+ $stdin = stdin
19
+ end
20
+
21
+ after(:each) { $stdin = @old_stdin }
22
+
23
+ context 'no tty' do
24
+ context 'stdin empty' do
25
+ it 'returns an error' do
26
+ expect(stdin).to receive(:tty?).and_return(false)
27
+ expect(stdin).to receive(:eof?).and_return(true)
28
+ expect{subject.run(['mysql_password'])}.to exit_with_error.and output(/Missing/).to_stderr
29
+ end
30
+ end
31
+
32
+ context 'stdin has a value' do
33
+ it 'sends create request' do
34
+ expect(stdin).to receive(:tty?).and_return(false)
35
+ expect(stdin).to receive(:eof?).and_return(false)
36
+ expect(stdin).to receive(:read).and_return('secret')
37
+ expect(client).to receive(:post).with('grids/test-grid/secrets', { name: 'mysql_password', value: 'secret'})
38
+ expect{subject.run(['mysql_password'])}.not_to exit_with_error
39
+ end
40
+ end
41
+ end
42
+
43
+ context 'with tty' do
44
+ let(:prompt) { double(:prompt) }
45
+ it 'prompts value from STDIN' do
46
+ expect(stdin).to receive(:tty?).and_return(true)
47
+ expect(subject).to receive(:prompt).and_return(prompt)
48
+ expect(prompt).to receive(:mask).and_return('secret')
49
+ expect(client).to receive(:post).with('grids/test-grid/secrets', { name: 'mysql_password', value: 'secret'})
50
+ expect{subject.run(['mysql_password'])}.not_to exit_with_error
51
+ end
52
+ end
53
+ end
54
+
55
+ it 'sends create request' do
56
+ expect(client).to receive(:post).with('grids/test-grid/secrets', { name: 'mysql_password', value: 'secret'})
57
+ subject.run(['mysql_password', 'secret'])
58
+ end
59
+ end
60
+ end
@@ -18,6 +18,12 @@ describe Kontena do
18
18
  end
19
19
  end
20
20
 
21
+ describe '#minor_version' do
22
+ it "returns a version string" do
23
+ expect(Kontena.minor_version).to match /^\d+\.\d+$/
24
+ end
25
+ end
26
+
21
27
  describe '#run' do
22
28
  let(:whoami) { double(:whoami) }
23
29
 
@@ -39,6 +45,3 @@ describe Kontena do
39
45
  end
40
46
  end
41
47
  end
42
-
43
-
44
-
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.2.0.pre3
4
+ version: 1.2.0.rc1
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-04-06 00:00:00.000000000 Z
11
+ date: 2017-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -56,16 +56,16 @@ dependencies:
56
56
  name: tty-prompt
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: 0.11.0
61
+ version: 0.12.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: 0.11.0
68
+ version: 0.12.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: clamp
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 0.7.0
117
+ version: 0.7.1
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 0.7.0
124
+ version: 0.7.1
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: retriable
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -142,14 +142,14 @@ dependencies:
142
142
  requirements:
143
143
  - - '='
144
144
  - !ruby/object:Gem::Version
145
- version: 1.8.4
145
+ version: 1.8.5
146
146
  type: :runtime
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - '='
151
151
  - !ruby/object:Gem::Version
152
- version: 1.8.4
152
+ version: 1.8.5
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: semantic
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -309,6 +309,7 @@ files:
309
309
  - lib/kontena/cli/grids/create_command.rb
310
310
  - lib/kontena/cli/grids/current_command.rb
311
311
  - lib/kontena/cli/grids/env_command.rb
312
+ - lib/kontena/cli/grids/events_command.rb
312
313
  - lib/kontena/cli/grids/health_command.rb
313
314
  - lib/kontena/cli/grids/list_command.rb
314
315
  - lib/kontena/cli/grids/logs_command.rb
@@ -390,6 +391,7 @@ files:
390
391
  - lib/kontena/cli/services/envs/add_command.rb
391
392
  - lib/kontena/cli/services/envs/list_command.rb
392
393
  - lib/kontena/cli/services/envs/remove_command.rb
394
+ - lib/kontena/cli/services/events_command.rb
393
395
  - lib/kontena/cli/services/exec_command.rb
394
396
  - lib/kontena/cli/services/link_command.rb
395
397
  - lib/kontena/cli/services/list_command.rb
@@ -413,6 +415,7 @@ files:
413
415
  - lib/kontena/cli/stacks/build_command.rb
414
416
  - lib/kontena/cli/stacks/common.rb
415
417
  - lib/kontena/cli/stacks/deploy_command.rb
418
+ - lib/kontena/cli/stacks/events_command.rb
416
419
  - lib/kontena/cli/stacks/install_command.rb
417
420
  - lib/kontena/cli/stacks/list_command.rb
418
421
  - lib/kontena/cli/stacks/logs_command.rb
@@ -461,6 +464,7 @@ files:
461
464
  - lib/kontena/cli/volumes/create_command.rb
462
465
  - lib/kontena/cli/volumes/list_command.rb
463
466
  - lib/kontena/cli/volumes/remove_command.rb
467
+ - lib/kontena/cli/volumes/show_command.rb
464
468
  - lib/kontena/cli/vpn/config_command.rb
465
469
  - lib/kontena/cli/vpn/create_command.rb
466
470
  - lib/kontena/cli/vpn/remove_command.rb
@@ -561,6 +565,7 @@ files:
561
565
  - spec/kontena/cli/containers/list_command_spec.rb
562
566
  - spec/kontena/cli/containers/logs_command_spec.rb
563
567
  - spec/kontena/cli/etcd/health_command_spec.rb
568
+ - spec/kontena/cli/grids/events_command_spec.rb
564
569
  - spec/kontena/cli/grids/health_command_spec.rb
565
570
  - spec/kontena/cli/grids/trusted_subnets/add_command_spec.rb
566
571
  - spec/kontena/cli/grids/trusted_subnets/list_command_spec.rb
@@ -581,6 +586,7 @@ files:
581
586
  - spec/kontena/cli/nodes/health_command_spec.rb
582
587
  - spec/kontena/cli/nodes/list_command_spec.rb
583
588
  - spec/kontena/cli/services/containers_command_spec.rb
589
+ - spec/kontena/cli/services/events_command_spec.rb
584
590
  - spec/kontena/cli/services/exec_command_spec.rb
585
591
  - spec/kontena/cli/services/link_command_spec.rb
586
592
  - spec/kontena/cli/services/logs_command_spec.rb
@@ -592,8 +598,10 @@ files:
592
598
  - spec/kontena/cli/services/update_command_spec.rb
593
599
  - spec/kontena/cli/stacks/build_command_spec.rb
594
600
  - spec/kontena/cli/stacks/deploy_command_spec.rb
601
+ - spec/kontena/cli/stacks/events_command_spec.rb
595
602
  - spec/kontena/cli/stacks/install_command_spec.rb
596
603
  - spec/kontena/cli/stacks/list_command_spec.rb
604
+ - spec/kontena/cli/stacks/logs_command_spec.rb
597
605
  - spec/kontena/cli/stacks/remove_command_spec.rb
598
606
  - spec/kontena/cli/stacks/service_generator_spec.rb
599
607
  - spec/kontena/cli/stacks/service_generator_v2_spec.rb
@@ -607,6 +615,8 @@ files:
607
615
  - spec/kontena/cli/stacks/yaml/validator_v3_spec.rb
608
616
  - spec/kontena/cli/vault/export_spec.rb
609
617
  - spec/kontena/cli/vault/import_spec.rb
618
+ - spec/kontena/cli/vault/update_command_spec.rb
619
+ - spec/kontena/cli/vault/write_command_spec.rb
610
620
  - spec/kontena/cli/version_command_spec.rb
611
621
  - spec/kontena/cli/vpn/create_command_spec.rb
612
622
  - spec/kontena/client_spec.rb
@@ -700,6 +710,7 @@ test_files:
700
710
  - spec/kontena/cli/containers/list_command_spec.rb
701
711
  - spec/kontena/cli/containers/logs_command_spec.rb
702
712
  - spec/kontena/cli/etcd/health_command_spec.rb
713
+ - spec/kontena/cli/grids/events_command_spec.rb
703
714
  - spec/kontena/cli/grids/health_command_spec.rb
704
715
  - spec/kontena/cli/grids/trusted_subnets/add_command_spec.rb
705
716
  - spec/kontena/cli/grids/trusted_subnets/list_command_spec.rb
@@ -720,6 +731,7 @@ test_files:
720
731
  - spec/kontena/cli/nodes/health_command_spec.rb
721
732
  - spec/kontena/cli/nodes/list_command_spec.rb
722
733
  - spec/kontena/cli/services/containers_command_spec.rb
734
+ - spec/kontena/cli/services/events_command_spec.rb
723
735
  - spec/kontena/cli/services/exec_command_spec.rb
724
736
  - spec/kontena/cli/services/link_command_spec.rb
725
737
  - spec/kontena/cli/services/logs_command_spec.rb
@@ -731,8 +743,10 @@ test_files:
731
743
  - spec/kontena/cli/services/update_command_spec.rb
732
744
  - spec/kontena/cli/stacks/build_command_spec.rb
733
745
  - spec/kontena/cli/stacks/deploy_command_spec.rb
746
+ - spec/kontena/cli/stacks/events_command_spec.rb
734
747
  - spec/kontena/cli/stacks/install_command_spec.rb
735
748
  - spec/kontena/cli/stacks/list_command_spec.rb
749
+ - spec/kontena/cli/stacks/logs_command_spec.rb
736
750
  - spec/kontena/cli/stacks/remove_command_spec.rb
737
751
  - spec/kontena/cli/stacks/service_generator_spec.rb
738
752
  - spec/kontena/cli/stacks/service_generator_v2_spec.rb
@@ -746,6 +760,8 @@ test_files:
746
760
  - spec/kontena/cli/stacks/yaml/validator_v3_spec.rb
747
761
  - spec/kontena/cli/vault/export_spec.rb
748
762
  - spec/kontena/cli/vault/import_spec.rb
763
+ - spec/kontena/cli/vault/update_command_spec.rb
764
+ - spec/kontena/cli/vault/write_command_spec.rb
749
765
  - spec/kontena/cli/version_command_spec.rb
750
766
  - spec/kontena/cli/vpn/create_command_spec.rb
751
767
  - spec/kontena/client_spec.rb