kontena-cli 1.2.0.dev1 → 1.2.0.pre1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1bb3a720a442f0537a388e074fc06d2deca0fe61
4
- data.tar.gz: abb0c04c02d70ea872693f70f972d26c06519fb7
3
+ metadata.gz: f03d83329e4ddcebc48f226b38df3d4eb9b6f96f
4
+ data.tar.gz: 451423d5bc02c8c01a18170cbb665a455d26a3d2
5
5
  SHA512:
6
- metadata.gz: e6c457fe87e24961e71867cfdf13b03bbd0b342f51d78ecaf84a1d67d61aaa55bdba02d3005604dbf92bb55db4e1a64583a396bb232703af8d96b2877c961e62
7
- data.tar.gz: 6d6502e6101bc887c366b4bdb49ac93480bf83ac23c8d411d9b294a95ce5835f9fa375b925a718653a4c06d76ca024e42a1bf2fea3042aa5fca3258757659670
6
+ metadata.gz: 24c1bd893acbaf99a21795710024e0673e79e0685f83f3478f6a708568c2f12f440f6caa463068406a22de4f232de2e6120017ca64334e8fc7dd7977932df3a1
7
+ data.tar.gz: c56ff810d3d4809d2c9d8c3c705389a0c801baf407290e89ec8ee718f3ef04b2d87112122eb379c498032da63994ee0b3f58cb609f24f45105ceeaca994819bf
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.0.dev1
1
+ 1.2.0.pre1
data/kontena-cli.gemspec CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.add_runtime_dependency "launchy", "~> 2.4.3"
30
30
  spec.add_runtime_dependency "hash_validator", "~> 0.7.0"
31
31
  spec.add_runtime_dependency "retriable", "~> 2.1.0"
32
- spec.add_runtime_dependency "opto", "1.8.3"
32
+ spec.add_runtime_dependency "opto", "1.8.4"
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"
@@ -41,6 +41,13 @@ module Kontena::Cli::Grids
41
41
  puts " exports:"
42
42
  puts " statsd: #{statsd['server']}:#{statsd['port']}"
43
43
  end
44
+ if logs = grid.dig('logs')
45
+ puts "logs:"
46
+ puts " forwarder: #{logs['forwarder']}"
47
+ logs['opts'].each do |k,v|
48
+ puts " #{k}: #{v}"
49
+ end
50
+ end
44
51
  end
45
52
 
46
53
  def grids
@@ -8,10 +8,13 @@ module Kontena::Cli::Grids
8
8
  parameter "NAME", "Grid name"
9
9
  option "--statsd-server", "STATSD_SERVER", "Statsd server address (host:port)"
10
10
  option "--default-affinity", "[AFFINITY]", "Default affinity rule for the grid", multivalued: true
11
+ option "--log-forwarder", "LOG_FORWARDER", "Set grid wide log forwarder"
12
+ option "--log-opt", "[LOG_OPT]", "Set log options (key=value)", multivalued: true
11
13
 
12
14
  def execute
13
15
  require_api_url
14
16
  token = require_token
17
+ validate_log_opts
15
18
  payload = {}
16
19
  if statsd_server
17
20
  server, port = statsd_server.split(':')
@@ -22,10 +25,33 @@ module Kontena::Cli::Grids
22
25
  }
23
26
  }
24
27
  end
28
+
29
+ if log_forwarder
30
+ payload[:logs] = {
31
+ forwarder: log_forwarder,
32
+ opts: parse_log_opts
33
+ }
34
+ end
35
+
25
36
  if default_affinity_list
26
37
  payload[:default_affinity] = default_affinity_list
27
38
  end
28
39
  client(token).put("grids/#{name}", payload)
29
40
  end
41
+
42
+ def validate_log_opts
43
+ if !log_opt_list.empty? && log_forwarder.nil?
44
+ raise Kontena::Errors::StandardError.new(1, "Need to specify --log-forwarder when using --log-opt")
45
+ end
46
+ end
47
+
48
+ def parse_log_opts
49
+ opts = {}
50
+ log_opt_list.each do |opt|
51
+ key, value = opt.split('=')
52
+ opts[key.to_sym] = value
53
+ end
54
+ opts
55
+ end
30
56
  end
31
57
  end
@@ -15,7 +15,7 @@ module Kontena::Cli::Services
15
15
  require_api_url
16
16
 
17
17
  query_params = {}
18
- query_params[:container] = parse_container_name(name, instance) if instance
18
+ query_params[:instance] = instance if instance
19
19
 
20
20
  show_logs("services/#{parse_service_id(name)}/container_logs", query_params) do |log|
21
21
  show_log(log)
@@ -53,8 +53,10 @@ module Kontena::Cli::Services
53
53
  end
54
54
 
55
55
  cpu = stat['cpu'].nil? ? 'N/A' : stat['cpu']['usage']
56
- network_in = stat['network'].nil? ? 'N/A' : filesize_to_human(stat['network']['rx_bytes'])
57
- network_out = stat['network'].nil? ? 'N/A' : filesize_to_human(stat['network']['tx_bytes'])
56
+
57
+ network_in = stat['network'].nil? ? 'N/A' : filesize_to_human(network_bytes(stat['network'], 'rx_bytes'))
58
+ network_out = stat['network'].nil? ? 'N/A' : filesize_to_human(network_bytes(stat['network'], 'tx_bytes'))
59
+
58
60
  prefix = self.name.split('/')[0]
59
61
  instance_name = stat['container_id'].gsub("#{prefix}-", "")
60
62
  puts '%-30.30s %-15s %-20s %-15s %-15s' % [ instance_name, "#{cpu}%", "#{memory} / #{memory_limit}", "#{memory_pct}", "#{network_in}/#{network_out}"]
@@ -72,5 +74,13 @@ module Kontena::Cli::Services
72
74
  rescue FloatDomainError
73
75
  'N/A'
74
76
  end
77
+
78
+ ##
79
+ # @param [Hash] network
80
+ # @param [String] key
81
+ # @return [Integer]
82
+ def network_bytes(network, key)
83
+ (network.dig('internal', key) || 0) + (network.dig('external', key) || 0)
84
+ end
75
85
  end
76
86
  end
@@ -6,10 +6,16 @@ module Kontena::Cli::Stacks::YAML::Validations::CustomValidators
6
6
 
7
7
  def validate(key, value, validations, errors)
8
8
  unless value.is_a?(Hash)
9
- errors[key] = 'hooks must be array'
9
+ errors[key] = "must be a mapping, not #{value.class}"
10
10
  return
11
11
  end
12
12
 
13
+ value.keys.each do |hook|
14
+ unless %w(pre_build post_start).include?(hook)
15
+ errors[key] = "invalid hook #{hook}"
16
+ end
17
+ end
18
+
13
19
  if value['pre_build']
14
20
  validate_pre_build_hooks(key, value['pre_build'], errors)
15
21
  end
@@ -21,7 +27,7 @@ module Kontena::Cli::Stacks::YAML::Validations::CustomValidators
21
27
 
22
28
  def validate_pre_build_hooks(key, pre_build_hooks, errors)
23
29
  unless pre_build_hooks.is_a?(Array)
24
- errors[key] = 'pre_build must be array'
30
+ errors[key] = { 'pre_build' => "must be an array" }
25
31
  return
26
32
  end
27
33
  pre_build_validation = {
@@ -36,7 +42,7 @@ module Kontena::Cli::Stacks::YAML::Validations::CustomValidators
36
42
 
37
43
  def validate_post_start_hooks(key, post_start_hooks, errors)
38
44
  unless post_start_hooks.is_a?(Array)
39
- errors[key] = 'post_start must be array'
45
+ errors[key] = { 'post_start' => 'must be an array' }
40
46
  return
41
47
  end
42
48
  post_start_validation = {
@@ -0,0 +1,8 @@
1
+
2
+ class Kontena::Cli::VolumeCommand < Kontena::Command
3
+
4
+ subcommand "create", "Create a managed volume", load_subcommand('volumes/create_command')
5
+ subcommand ["remove", "rm"], "Remove a managed volume", load_subcommand('volumes/remove_command')
6
+ subcommand ["list", "ls"], "List managed volumes", load_subcommand('volumes/list_command')
7
+
8
+ end
@@ -0,0 +1,38 @@
1
+
2
+ module Kontena::Cli::Volumes
3
+ class CreateCommand < Kontena::Command
4
+ include Kontena::Cli::Common
5
+ include Kontena::Cli::GridOptions
6
+
7
+
8
+ banner "Creates a volume"
9
+ parameter 'NAME', 'Volume name'
10
+
11
+ option '--driver', 'DRIVER', 'Volume driver to be used'
12
+ option '--driver-opt', 'DRIVER_OPT', 'Volume driver options', multivalued: true
13
+ option '--scope', 'SCOPE', 'Volume scope'
14
+
15
+ requires_current_master
16
+ requires_current_master_token
17
+
18
+ def execute
19
+ volume = {
20
+ name: name,
21
+ scope: scope,
22
+ driver: driver,
23
+ driver_opts: parse_driver_opts
24
+ }
25
+ spinner "Creating volume #{pastel.cyan(name)} " do
26
+ create_volume(volume)
27
+ end
28
+ end
29
+
30
+ def parse_driver_opts
31
+ Hash[driver_opt_list.map{|opt| opt.split '='}]
32
+ end
33
+
34
+ def create_volume(volume)
35
+ client.post("volumes/#{current_grid}", volume)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+
2
+ module Kontena::Cli::Volumes
3
+ class ListCommand < Kontena::Command
4
+ include Kontena::Cli::Common
5
+ include Kontena::Cli::GridOptions
6
+
7
+
8
+ requires_current_master
9
+ requires_current_master_token
10
+
11
+ def execute
12
+ volumes = client.get("volumes/#{current_grid}")['volumes']
13
+ columns = '%-25.25s %-25.25s %-25.25s %-25.25s'
14
+ puts columns % ['NAME', 'SCOPE', 'DRIVER', 'CREATED AT']
15
+ volumes.each do |volume|
16
+ puts columns % [volume['name'], volume['scope'], volume['driver'], volume['created_at']]
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+
2
+ module Kontena::Cli::Volumes
3
+ class RemoveCommand < Kontena::Command
4
+ include Kontena::Cli::Common
5
+ include Kontena::Cli::GridOptions
6
+
7
+
8
+ banner "Removes a volume"
9
+ parameter 'VOLUME', 'Volume'
10
+
11
+ requires_current_master
12
+ requires_current_master_token
13
+
14
+ def execute
15
+ spinner "Removing volume #{pastel.cyan(volume)} " do
16
+ remove_volume(volume)
17
+ end
18
+ end
19
+
20
+ def remove_volume(volume)
21
+ client.delete("volumes/#{current_grid}/#{volume}")
22
+ end
23
+ end
24
+ end
@@ -213,7 +213,7 @@ class Kontena::Command < Clamp::Command
213
213
  end
214
214
  rescue Kontena::Errors::StandardError => exc
215
215
  raise exc if ENV['DEBUG']
216
- puts " [#{Kontena.pastel.red('error')}] #{exc.message}"
216
+ $stderr.puts " [#{Kontena.pastel.red('error')}] #{exc.message}"
217
217
  abort
218
218
  rescue Errno::EPIPE
219
219
  # If user is piping the command outputs to some other command that might exit before CLI has outputted everything
@@ -36,6 +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
40
 
40
41
  def execute
41
42
  end
@@ -4,4 +4,4 @@ export PATH=/opt/kontena/embedded/bin:$PATH
4
4
  export GEM_HOME=/opt/kontena/embedded/lib/ruby/gems/2.1.0
5
5
  export GEM_PATH=$GEM_HOME
6
6
 
7
- exec /opt/kontena/embedded/bin/kontena $@
7
+ exec /opt/kontena/embedded/bin/kontena "$@"
@@ -0,0 +1,46 @@
1
+
2
+ require_relative "../../../spec_helper"
3
+ require 'kontena/cli/grids/update_command'
4
+
5
+ describe Kontena::Cli::Grids::UpdateCommand do
6
+
7
+ include ClientHelpers
8
+
9
+ let(:client) do
10
+ Kontena::Client.new('https://foo', {access_token: 'abcd1234'})
11
+ end
12
+
13
+ let(:subject) do
14
+ described_class.new(File.basename($0))
15
+ end
16
+
17
+ let(:server) do
18
+ Kontena::Cli::Config::Server.new(url: 'https://localhost', token: 'abcd1234')
19
+ end
20
+
21
+ describe "#update" do
22
+
23
+ context 'log options' do
24
+ it 'should fail if no driver specified' do
25
+ expect {
26
+ subject.run(['--log-opt', 'foo=bar', 'test'])
27
+ }.to exit_with_error
28
+
29
+ end
30
+
31
+ it 'should send valid options to server' do
32
+ expect(client).to receive(:put).with(
33
+ 'grids/test', hash_including({
34
+ logs: {
35
+ forwarder: 'fluentd',
36
+ opts: {
37
+ foo: 'bar'
38
+ }
39
+ }
40
+ })
41
+ )
42
+ subject.run(['--log-forwarder', 'fluentd', '--log-opt', 'foo=bar', 'test'])
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,41 @@
1
+ require_relative "../../../spec_helper"
2
+ require "kontena/cli/services/logs_command"
3
+
4
+ describe Kontena::Cli::Services::LogsCommand 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 'requires api url' do
16
+ expect(subject).to receive(:require_api_url).once
17
+ subject.run(['service-a'])
18
+ end
19
+
20
+ it 'requires token' do
21
+ expect(subject).to receive(:require_token).and_return(token)
22
+ subject.run(['service-a'])
23
+ end
24
+
25
+ it 'requests logs from master' do
26
+ expect(client).to receive(:get).with(
27
+ 'services/test-grid/null/service-a/container_logs', {limit: 100}
28
+ )
29
+ subject.run(['service-a'])
30
+ end
31
+
32
+ context 'when passing instance option ' do
33
+ it 'adds it to query params' do
34
+ expect(client).to receive(:get).with(
35
+ 'services/test-grid/null/service-a/container_logs', {instance: '1', limit: 100}
36
+ )
37
+ subject.run(['-i', '1', 'service-a'])
38
+ end
39
+ end
40
+ end
41
+ end
@@ -165,6 +165,12 @@ describe Kontena::Cli::Stacks::YAML::ValidatorV3 do
165
165
  end
166
166
 
167
167
  context 'hooks' do
168
+ context 'validates hook name' do
169
+ it 'must be valid hook' do
170
+ result = subject.validate_options('hooks' => { 'pre-build' => {} })
171
+ expect(result.errors.key?('hooks')).to be_truthy
172
+ end
173
+ end
168
174
  context 'validates pre_build' do
169
175
  it 'must be array' do
170
176
  result = subject.validate_options('hooks' => { 'pre_build' => {} })
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.dev1
4
+ version: 1.2.0.pre1
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-03-09 00:00:00.000000000 Z
11
+ date: 2017-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -142,14 +142,14 @@ dependencies:
142
142
  requirements:
143
143
  - - '='
144
144
  - !ruby/object:Gem::Version
145
- version: 1.8.3
145
+ version: 1.8.4
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.3
152
+ version: 1.8.4
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: semantic
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -456,6 +456,10 @@ files:
456
456
  - lib/kontena/cli/vault_command.rb
457
457
  - lib/kontena/cli/version.rb
458
458
  - lib/kontena/cli/version_command.rb
459
+ - lib/kontena/cli/volume_command.rb
460
+ - lib/kontena/cli/volumes/create_command.rb
461
+ - lib/kontena/cli/volumes/list_command.rb
462
+ - lib/kontena/cli/volumes/remove_command.rb
459
463
  - lib/kontena/cli/vpn/config_command.rb
460
464
  - lib/kontena/cli/vpn/create_command.rb
461
465
  - lib/kontena/cli/vpn/remove_command.rb
@@ -559,6 +563,7 @@ files:
559
563
  - spec/kontena/cli/grids/trusted_subnets/add_command_spec.rb
560
564
  - spec/kontena/cli/grids/trusted_subnets/list_command_spec.rb
561
565
  - spec/kontena/cli/grids/trusted_subnets/remove_command_spec.rb
566
+ - spec/kontena/cli/grids/update_command_spec.rb
562
567
  - spec/kontena/cli/grids/use_command_spec.rb
563
568
  - spec/kontena/cli/helpers/log_helper_spec.rb
564
569
  - spec/kontena/cli/main_command_spec.rb
@@ -576,6 +581,7 @@ files:
576
581
  - spec/kontena/cli/services/containers_command_spec.rb
577
582
  - spec/kontena/cli/services/exec_command_spec.rb
578
583
  - spec/kontena/cli/services/link_command_spec.rb
584
+ - spec/kontena/cli/services/logs_command_spec.rb
579
585
  - spec/kontena/cli/services/restart_command_spec.rb
580
586
  - spec/kontena/cli/services/secrets/link_command_spec.rb
581
587
  - spec/kontena/cli/services/secrets/unlink_command_spec.rb
@@ -695,6 +701,7 @@ test_files:
695
701
  - spec/kontena/cli/grids/trusted_subnets/add_command_spec.rb
696
702
  - spec/kontena/cli/grids/trusted_subnets/list_command_spec.rb
697
703
  - spec/kontena/cli/grids/trusted_subnets/remove_command_spec.rb
704
+ - spec/kontena/cli/grids/update_command_spec.rb
698
705
  - spec/kontena/cli/grids/use_command_spec.rb
699
706
  - spec/kontena/cli/helpers/log_helper_spec.rb
700
707
  - spec/kontena/cli/main_command_spec.rb
@@ -712,6 +719,7 @@ test_files:
712
719
  - spec/kontena/cli/services/containers_command_spec.rb
713
720
  - spec/kontena/cli/services/exec_command_spec.rb
714
721
  - spec/kontena/cli/services/link_command_spec.rb
722
+ - spec/kontena/cli/services/logs_command_spec.rb
715
723
  - spec/kontena/cli/services/restart_command_spec.rb
716
724
  - spec/kontena/cli/services/secrets/link_command_spec.rb
717
725
  - spec/kontena/cli/services/secrets/unlink_command_spec.rb