kontena-cli 1.3.5 → 1.4.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.
Files changed (51) hide show
  1. checksums.yaml +5 -5
  2. data/VERSION +1 -1
  3. data/lib/kontena/cli/etcd/health_command.rb +1 -1
  4. data/lib/kontena/cli/grids/common.rb +51 -0
  5. data/lib/kontena/cli/grids/create_command.rb +13 -9
  6. data/lib/kontena/cli/grids/update_command.rb +11 -44
  7. data/lib/kontena/cli/node_command.rb +3 -0
  8. data/lib/kontena/cli/nodes/create_command.rb +25 -0
  9. data/lib/kontena/cli/nodes/env_command.rb +32 -0
  10. data/lib/kontena/cli/nodes/health_command.rb +2 -2
  11. data/lib/kontena/cli/nodes/labels/add_command.rb +3 -3
  12. data/lib/kontena/cli/nodes/labels/list_command.rb +2 -2
  13. data/lib/kontena/cli/nodes/labels/remove_command.rb +3 -3
  14. data/lib/kontena/cli/nodes/remove_command.rb +9 -7
  15. data/lib/kontena/cli/nodes/reset_token_command.rb +31 -0
  16. data/lib/kontena/cli/nodes/show_command.rb +4 -4
  17. data/lib/kontena/cli/nodes/ssh_command.rb +4 -4
  18. data/lib/kontena/cli/nodes/update_command.rb +13 -8
  19. data/lib/kontena/cli/services/create_command.rb +4 -0
  20. data/lib/kontena/cli/services/services_helper.rb +2 -0
  21. data/lib/kontena/cli/services/update_command.rb +2 -0
  22. data/lib/kontena/cli/stacks/service_generator.rb +2 -0
  23. data/lib/kontena/cli/stacks/show_command.rb +1 -0
  24. data/lib/kontena/cli/stacks/stacks_helper.rb +2 -3
  25. data/lib/kontena/cli/stacks/yaml/validations.rb +3 -1
  26. data/lib/kontena/machine/cloud_config/cloudinit.yml +17 -4
  27. data/omnibus/package-scripts/kontena/postinst +0 -4
  28. data/omnibus/package-scripts/kontena/postrm +1 -1
  29. data/omnibus/package-scripts/kontena/preinst +0 -2
  30. data/spec/fixtures/api/node.json +93 -0
  31. data/spec/kontena/cli/containers/logs_command_spec.rb +0 -4
  32. data/spec/kontena/cli/etcd/health_command_spec.rb +128 -63
  33. data/spec/kontena/cli/nodes/create_command_spec.rb +24 -0
  34. data/spec/kontena/cli/nodes/env_command_spec.rb +49 -0
  35. data/spec/kontena/cli/nodes/health_command_spec.rb +15 -173
  36. data/spec/kontena/cli/nodes/labels/add_command_spec.rb +56 -0
  37. data/spec/kontena/cli/nodes/labels/list_command_spec.rb +43 -0
  38. data/spec/kontena/cli/nodes/labels/remove_command_spec.rb +57 -0
  39. data/spec/kontena/cli/nodes/list_command_spec.rb +0 -2
  40. data/spec/kontena/cli/nodes/remove_command_spec.rb +76 -0
  41. data/spec/kontena/cli/nodes/reset_token_command_spec.rb +38 -0
  42. data/spec/kontena/cli/nodes/show_command_spec.rb +46 -0
  43. data/spec/kontena/cli/nodes/ssh_command_spec.rb +5 -0
  44. data/spec/kontena/cli/nodes/update_command_spec.rb +24 -0
  45. data/spec/kontena/cli/stacks/deploy_command_spec.rb +21 -0
  46. data/spec/kontena/cli/stacks/logs_command_spec.rb +0 -4
  47. data/spec/kontena/cli/table_generator_spec.rb +0 -4
  48. data/spec/spec_helper.rb +5 -0
  49. data/spec/support/output_helpers.rb +3 -14
  50. data/tasks/release.rake +2 -2
  51. metadata +28 -5
@@ -3,7 +3,7 @@ module Kontena::Cli::Nodes
3
3
  include Kontena::Cli::Common
4
4
  include Kontena::Cli::GridOptions
5
5
 
6
- parameter "[NODE_ID]", "SSH to Grid node. Use --any to connect to the first available node"
6
+ parameter "[NODE]", "SSH to Grid node. Use --any to connect to the first available node"
7
7
  parameter "[COMMANDS] ...", "Run command on host"
8
8
  option ["-a", "--any"], :flag, "Connect to first available node"
9
9
  option ["-i", "--identity-file"], "IDENTITY_FILE", "Path to ssh private key"
@@ -15,10 +15,10 @@ module Kontena::Cli::Nodes
15
15
  requires_current_grid
16
16
 
17
17
  def execute
18
- exit_with_error "Cannot combine --any with a node name" if node_id && any?
18
+ exit_with_error "Cannot combine --any with a node name" if self.node && any?
19
19
 
20
- if node_id
21
- node = client.get("nodes/#{current_grid}/#{node_id}")
20
+ if self.node
21
+ node = client.get("nodes/#{current_grid}/#{self.node}")
22
22
  elsif any?
23
23
  nodes = client.get("grids/#{current_grid}/nodes")['nodes']
24
24
  node = nodes.select{ |node| node['connected'] }.first
@@ -3,18 +3,23 @@ module Kontena::Cli::Nodes
3
3
  include Kontena::Cli::Common
4
4
  include Kontena::Cli::GridOptions
5
5
 
6
- parameter "NODE_ID", "Node id"
6
+ requires_current_master
7
+ requires_current_master_token
8
+ requires_current_grid
9
+
10
+ parameter "NODE", "Node name"
11
+
7
12
  option ["-l", "--label"], "LABEL", "Node label", multivalued: true
13
+ option "--clear-labels", :flag, "Clear node labels"
8
14
 
9
15
  def execute
10
- require_api_url
11
- require_current_grid
12
- token = require_token
13
-
14
16
  data = {}
15
- data[:labels] = label_list if label_list
16
- spinner "Updating #{node_id.colorize(:cyan)} node " do
17
- client.put("nodes/#{current_grid}/#{node_id}", data)
17
+
18
+ data[:labels] = self.label_list unless self.label_list.empty?
19
+ data[:labels] = [] if self.clear_labels?
20
+
21
+ spinner "Updating #{self.node.colorize(:cyan)} node " do
22
+ client.put("nodes/#{current_grid}/#{self.node}", data)
18
23
  end
19
24
  end
20
25
  end
@@ -41,6 +41,8 @@ module Kontena::Cli::Services
41
41
  option "--health-check-initial-delay", "DELAY", "Initial delay for health check"
42
42
  option "--health-check-port", "PORT", "Port for health check"
43
43
  option "--health-check-protocol", "PROTOCOL", "Protocol of health check"
44
+ option "--stop-timeout", "STOP_TIMEOUT", "Timeout (duration) to stop a container"
45
+ option "--read-only", :flag, "Read-only root fs for the container", default: false
44
46
 
45
47
  def execute
46
48
  require_api_url
@@ -87,6 +89,8 @@ module Kontena::Cli::Services
87
89
  health_check = parse_health_check
88
90
  data[:health_check] = health_check unless health_check.empty?
89
91
  data[:pid] = pid if pid
92
+ data[:stop_grace_period] = stop_timeout if stop_timeout
93
+ data[:read_only] = read_only?
90
94
  data
91
95
  end
92
96
  end
@@ -52,6 +52,8 @@ module Kontena
52
52
  puts " stateful: #{service['stateful'] == true ? 'yes' : 'no' }"
53
53
  puts " scaling: #{service['instances'] }"
54
54
  puts " strategy: #{service['strategy']}"
55
+ puts " read_only: #{service['read_only'] == true ? 'yes' : 'no'}"
56
+ puts " stop_grace_period: #{service['stop_grace_period']}s"
55
57
  puts " deploy_opts:"
56
58
  if service['deploy_opts']['min_health']
57
59
  puts " min_health: #{service['deploy_opts']['min_health']}"
@@ -38,6 +38,7 @@ module Kontena::Cli::Services
38
38
  option "--health-check-initial-delay", "DELAY", "Initial for HTTP health check"
39
39
  option "--health-check-port", "PORT", "Port for HTTP health check"
40
40
  option "--health-check-protocol", "PROTOCOL", "Protocol of health check"
41
+ option "--stop-timeout", "STOP_TIMEOUT", "Timeout (duration) to stop a container"
41
42
 
42
43
  def execute
43
44
  require_api_url
@@ -78,6 +79,7 @@ module Kontena::Cli::Services
78
79
  health_check = parse_health_check
79
80
  data[:health_check] = health_check unless health_check.empty?
80
81
  data[:pid] = pid if pid
82
+ data[:stop_grace_period] = stop_timeout if stop_timeout
81
83
  data
82
84
  end
83
85
  end
@@ -63,6 +63,8 @@ module Kontena::Cli::Stacks
63
63
  data['secrets'] = options['secrets'] if options['secrets']
64
64
  data['build'] = parse_build_options(options) if options['build']
65
65
  data['health_check'] = parse_health_check(options)
66
+ data['stop_grace_period'] = options['stop_grace_period'] if options['stop_grace_period']
67
+ data['read_only'] = options['read_only'] || false
66
68
  data
67
69
  end
68
70
 
@@ -57,6 +57,7 @@ module Kontena::Cli::Stacks
57
57
  puts "#{pad} stateful: #{service['stateful'] == true ? 'yes' : 'no' }"
58
58
  puts "#{pad} scaling: #{service['instances'] }"
59
59
  puts "#{pad} strategy: #{service['strategy']}"
60
+ puts "#{pad} read_only: #{service['read_only'] == true ? 'yes' : 'no'}"
60
61
  puts "#{pad} deploy_opts:"
61
62
  puts "#{pad} min_health: #{service['deploy_opts']['min_health']}"
62
63
  if service['deploy_opts']['wait_for_port']
@@ -4,10 +4,9 @@ module Kontena::Cli::Stacks
4
4
  def wait_for_deployment_to_start(deployment, timeout = 600)
5
5
  started = false
6
6
  Timeout::timeout(timeout) do
7
- until started
8
- deployment = client.get("stacks/#{deployment['stack_id']}/deploys/#{deployment['id']}")
9
- started = true if deployment['service_deploys'].size > 0
7
+ while deployment['state'] == 'created'
10
8
  sleep 1
9
+ deployment = client.get("stacks/#{deployment['stack_id']}/deploys/#{deployment['id']}")
11
10
  end
12
11
  if deployment['state'] == 'error'
13
12
  deployment['service_deploys'].each do |service_deploy|
@@ -74,7 +74,9 @@ module Kontena::Cli::Stacks::YAML
74
74
  'timeout' => optional('integer'),
75
75
  'interval' => optional('integer'),
76
76
  'initial_delay' => optional('integer')
77
- })
77
+ }),
78
+ 'stop_grace_period' => optional(/(\d+(?:\.\d+)?)([hms])/),
79
+ 'read_only' => optional('boolean')
78
80
  }
79
81
  end
80
82
 
@@ -19,10 +19,23 @@ write_files:
19
19
  fs.inotify.max_user_instances = 8192
20
20
  coreos:
21
21
  units:
22
- - name: 50-docker.network
23
- mask: true
24
- - name: 50-docker-veth.network
25
- mask: true
22
+ - name: 50-weave.network
23
+ content: |
24
+ [Match]
25
+ Name=weave datapath vxlan-6784
26
+
27
+ [Network]
28
+ Description=Network interfaces managed by weave
29
+
30
+ [Link]
31
+ Unmanaged=true
32
+ - name: 90-dummy.network
33
+ content: |
34
+ [Match]
35
+ Name=dummy0
36
+
37
+ [Link]
38
+ Unmanaged=true
26
39
  - name: zz-default.network
27
40
  content: |
28
41
  # default should not match virtual Docker/weave bridge/veth network interfaces
@@ -12,11 +12,7 @@ error_exit()
12
12
  exit 1
13
13
  }
14
14
 
15
- chown $USER /opt/kontena/embedded/bin
16
- chown $USER -R /opt/kontena/embedded/lib/ruby/gems/2.1.0
17
15
  mkdir -p /usr/local/bin
18
16
  ln -s /opt/kontena/bin/kontena /usr/local/bin/kontena
19
17
 
20
- echo "Thank you for installing Kontena!"
21
-
22
18
  exit 0
@@ -4,6 +4,6 @@
4
4
  # after package is uninstalled.
5
5
  #
6
6
 
7
- echo "Kontena has been uninstalled!"
7
+ [ -L /usr/local/bin/kontena ] && rm /usr/local/bin/kontena
8
8
 
9
9
  exit 0
@@ -3,5 +3,3 @@
3
3
  # Perform necessary kontena setup steps
4
4
  # before package is installed.
5
5
  #
6
-
7
- echo "You're about to install Kontena!"
@@ -0,0 +1,93 @@
1
+ {
2
+ "initial_member" : true,
3
+ "peer_ips" : [
4
+ "192.168.66.102"
5
+ ],
6
+ "last_seen_at" : "2017-07-04T08:36:02.280Z",
7
+ "updated_at" : "2017-07-04T08:35:09.455Z",
8
+ "node_number" : 1,
9
+ "volume_drivers" : [
10
+ {
11
+ "version" : null,
12
+ "name" : "local"
13
+ }
14
+ ],
15
+ "resource_usage" : {
16
+ "memory" : {
17
+ "free" : 194068480,
18
+ "inactive" : 225415168,
19
+ "buffers" : 37978112,
20
+ "cached" : 390828032,
21
+ "total" : 1045561344,
22
+ "used" : 851492864,
23
+ "active" : 521949184
24
+ },
25
+ "cpu" : null,
26
+ "usage" : null,
27
+ "load" : {
28
+ "5m" : 0.33642578125,
29
+ "1m" : 1.48779296875,
30
+ "15m" : 0.10888671875
31
+ },
32
+ "filesystem" : [
33
+ {
34
+ "total" : 16718393344,
35
+ "used" : 3104915456,
36
+ "name" : "/var/lib/docker",
37
+ "free" : 13613477888,
38
+ "available" : 12730281984
39
+ }
40
+ ]
41
+ },
42
+ "overlay_ip" : "10.81.0.1",
43
+ "labels" : [
44
+ "test"
45
+ ],
46
+ "engine_root_dir" : "/var/lib/docker",
47
+ "cpus" : 1,
48
+ "os" : "Container Linux by CoreOS 1409.5.0 (Ladybug)",
49
+ "public_ip" : "91.150.10.190",
50
+ "kernel_version" : "4.11.6-coreos-r1",
51
+ "node_id" : "XI4K:NPOL:EQJ4:S4V7:EN3B:DHC5:KZJD:F3U2:PCAN:46EV:IO4A:63S5",
52
+ "created_at" : "2016-10-27T08:15:31.084Z",
53
+ "id" : "development/core-01",
54
+ "name" : "core-01",
55
+ "network_drivers" : [
56
+ {
57
+ "version" : null,
58
+ "name" : "bridge"
59
+ },
60
+ {
61
+ "version" : null,
62
+ "name" : "host"
63
+ },
64
+ {
65
+ "version" : null,
66
+ "name" : "overlay"
67
+ },
68
+ {
69
+ "name" : "null",
70
+ "version" : null
71
+ }
72
+ ],
73
+ "driver" : "overlay",
74
+ "mem_limit" : 0,
75
+ "docker_version" : "1.12.6",
76
+ "agent_version" : "1.4.0.dev",
77
+ "private_ip" : "192.168.66.101",
78
+ "connected_at" : "2017-07-04T08:36:02.235Z",
79
+ "grid" : {
80
+ "supernet" : "10.80.0.0/12",
81
+ "trusted_subnets" : [],
82
+ "stats" : {
83
+ "statsd" : null
84
+ },
85
+ "token" : "tBsoco4sBClMtIOD/bHeIqS1KYM0kZMG7B960jNWWQXMOxqhOf8W1QgiNJlW9u6B/qS+rfS2ZLpC/ZJsyPNj0A==",
86
+ "id" : "development",
87
+ "name" : "development",
88
+ "subnet" : "10.81.0.0/16",
89
+ "initial_size" : 1
90
+ },
91
+ "mem_total" : 1045032960,
92
+ "connected" : true
93
+ }
@@ -27,10 +27,6 @@ describe Kontena::Cli::Containers::LogsCommand do
27
27
  ]
28
28
  end
29
29
 
30
- before(:each) do
31
- Kontena.pastel.resolver.color.disable!
32
- end
33
-
34
30
  it "shows all logs" do
35
31
  allow(client).to receive(:get).with('containers/test-grid/node-1/test-mysql-1/logs', {
36
32
  limit: 100,
@@ -8,82 +8,147 @@ describe Kontena::Cli::Etcd::HealthCommand do
8
8
  allow(subject).to receive(:health_icon) {|health| health.inspect }
9
9
  end
10
10
 
11
- describe '#show_node_health' do
12
- context "For an offline node" do
13
- let :node_health do
14
- {
15
- "connected" => false,
16
- "name" => "node-1",
17
- 'etcd_health' => {
18
- 'health' => nil,
19
- 'error' => nil,
20
- },
21
- }
22
- end
11
+ let :node1_health do
12
+ {
13
+ "id" => 'test-grid/node-1',
14
+ "connected" => false,
15
+ "name" => "node-1",
16
+ 'etcd_health' => {
17
+ 'health' => nil,
18
+ 'error' => nil,
19
+ },
20
+ }
21
+ end
22
+ let :node2_health do
23
+ {
24
+ "id" => 'test-grid/node-2',
25
+ "name" => "node-2",
26
+ "connected" => true,
27
+ 'etcd_health' => {
28
+ 'health' => nil,
29
+ 'error' => "timeout",
30
+ },
31
+ }
32
+ end
33
+ let :node3_health do
34
+ {
35
+ "id" => 'test-grid/node-3',
36
+ "name" => "node-3",
37
+ "connected" => true,
38
+ 'etcd_health' => {
39
+ 'health' => false,
40
+ 'error' => nil,
41
+ },
42
+ }
43
+ end
44
+ let :node4_health do
45
+ {
46
+ "id" => 'test-grid/node-4',
47
+ "name" => "node-4",
48
+ "connected" => true,
49
+ 'etcd_health' => {
50
+ 'health' => true,
51
+ 'error' => nil,
52
+ },
53
+ }
54
+ end
23
55
 
24
- it "shows offline and returns false" do
25
- expect{subject.show_node_health(node_health)}.to return_and_output false, [
26
- ":offline Node node-1 is offline",
27
- ]
28
- end
56
+ before do
57
+ allow(client).to receive(:get).with('nodes/test-grid/node-1/health').and_return(node1_health)
58
+ allow(client).to receive(:get).with('nodes/test-grid/node-2/health').and_return(node2_health)
59
+ allow(client).to receive(:get).with('nodes/test-grid/node-3/health').and_return(node3_health)
60
+ allow(client).to receive(:get).with('nodes/test-grid/node-4/health').and_return(node4_health)
61
+ end
62
+
63
+ context "For an offline node-1" do
64
+ it "shows offline and returns false" do
65
+ expect{subject.run(['node-1'])}.to exit_with_error.and output_lines [
66
+ ":offline Node node-1 is offline",
67
+ ]
29
68
  end
69
+ end
30
70
 
31
- context "For a node with health errors" do
32
- let :node_health do
33
- {
34
- "name" => "node-1",
35
- "connected" => true,
36
- 'etcd_health' => {
37
- 'health' => nil,
38
- 'error' => "timeout",
39
- },
40
- }
41
- end
71
+ context "For a node-2 with health errors" do
72
+ it "shows errored and returns false" do
73
+ expect{subject.run(['node-2'])}.to exit_with_error.and output_lines [
74
+ ":error Node node-2 is unhealthy: timeout",
75
+ ]
76
+ end
77
+ end
78
+
79
+ context "For a node-3 that returns health=false" do
80
+ it "shows unhealthy and returns false" do
81
+ expect{subject.run(['node-3'])}.to exit_with_error.and output_lines [
82
+ ":error Node node-3 is unhealthy",
83
+ ]
84
+ end
85
+ end
42
86
 
43
- it "shows errored and returns false" do
44
- expect{subject.show_node_health(node_health)}.to return_and_output false, [
45
- ":error Node node-1 is unhealthy: timeout",
46
- ]
47
- end
87
+ context "For a healthy node-4" do
88
+ it "shows healthy and returns true" do
89
+ expect{subject.run(['node-4'])}.to output_lines [
90
+ ":ok Node node-4 is healthy",
91
+ ]
48
92
  end
93
+ end
49
94
 
50
- context "For a node that returns health=false" do
51
- let :node_health do
95
+ context "For a grid of mixed nodes" do
96
+ let :grid_nodes do
97
+ [
98
+ {
99
+ 'id' => 'test-grid/node-1',
100
+ },
52
101
  {
53
- "name" => "node-1",
54
- "connected" => true,
55
- 'etcd_health' => {
56
- 'health' => false,
57
- 'error' => nil,
58
- },
59
- }
60
- end
102
+ 'id' => 'test-grid/node-2',
103
+ },
104
+ {
105
+ 'id' => 'test-grid/node-3',
106
+ },
107
+ {
108
+ 'id' => 'test-grid/node-4',
109
+ },
110
+ ]
111
+ end
61
112
 
62
- it "shows unhealthy and returns false" do
63
- expect{subject.show_node_health(node_health)}.to return_and_output false, [
64
- ":error Node node-1 is unhealthy",
65
- ]
66
- end
113
+ before do
114
+ allow(client).to receive(:get).with('grids/test-grid/nodes').and_return(
115
+ 'nodes' => grid_nodes,
116
+ )
67
117
  end
68
118
 
69
- context "For a healthy node" do
70
- let :node_health do
119
+ it 'shows all nodes and exits with an error' do
120
+ expect{subject.run([])}.to exit_with_error.and output_lines [
121
+ ":offline Node node-1 is offline",
122
+ ":error Node node-2 is unhealthy: timeout",
123
+ ":error Node node-3 is unhealthy",
124
+ ":ok Node node-4 is healthy",
125
+ ]
126
+ end
127
+ end
128
+
129
+ context 'for a grid with healthy nodes' do
130
+ let :grid_nodes do
131
+ [
71
132
  {
72
- "name" => "node-1",
73
- "connected" => true,
74
- 'etcd_health' => {
75
- 'health' => true,
76
- 'error' => nil,
77
- },
78
- }
79
- end
133
+ 'id' => 'test-grid/node-4',
134
+ },
135
+ {
136
+ 'id' => 'test-grid/node-4',
137
+ },
138
+ ]
139
+ end
80
140
 
141
+ before do
142
+ allow(client).to receive(:get).with('grids/test-grid/nodes').and_return(
143
+ 'nodes' => grid_nodes,
144
+ )
145
+ end
81
146
 
82
- it "shows healthy and returns true" do
83
- expect{subject.show_node_health(node_health)}.to return_and_output true, [
84
- ":ok Node node-1 is healthy",
85
- ]
86
- end
147
+ it 'shows nodes as healthy anddoes not and exit with an error' do
148
+ expect{subject.run([])}.to output_lines [
149
+ ":ok Node node-4 is healthy",
150
+ ":ok Node node-4 is healthy",
151
+ ]
87
152
  end
88
153
  end
89
154
  end