kontena-cli 1.3.5 → 1.4.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/VERSION +1 -1
- data/lib/kontena/cli/etcd/health_command.rb +1 -1
- data/lib/kontena/cli/grids/common.rb +51 -0
- data/lib/kontena/cli/grids/create_command.rb +13 -9
- data/lib/kontena/cli/grids/update_command.rb +11 -44
- data/lib/kontena/cli/node_command.rb +3 -0
- data/lib/kontena/cli/nodes/create_command.rb +25 -0
- data/lib/kontena/cli/nodes/env_command.rb +32 -0
- data/lib/kontena/cli/nodes/health_command.rb +2 -2
- data/lib/kontena/cli/nodes/labels/add_command.rb +3 -3
- data/lib/kontena/cli/nodes/labels/list_command.rb +2 -2
- data/lib/kontena/cli/nodes/labels/remove_command.rb +3 -3
- data/lib/kontena/cli/nodes/remove_command.rb +9 -7
- data/lib/kontena/cli/nodes/reset_token_command.rb +31 -0
- data/lib/kontena/cli/nodes/show_command.rb +4 -4
- data/lib/kontena/cli/nodes/ssh_command.rb +4 -4
- data/lib/kontena/cli/nodes/update_command.rb +13 -8
- data/lib/kontena/cli/services/create_command.rb +4 -0
- data/lib/kontena/cli/services/services_helper.rb +2 -0
- data/lib/kontena/cli/services/update_command.rb +2 -0
- data/lib/kontena/cli/stacks/service_generator.rb +2 -0
- data/lib/kontena/cli/stacks/show_command.rb +1 -0
- data/lib/kontena/cli/stacks/stacks_helper.rb +2 -3
- data/lib/kontena/cli/stacks/yaml/validations.rb +3 -1
- data/lib/kontena/machine/cloud_config/cloudinit.yml +17 -4
- data/omnibus/package-scripts/kontena/postinst +0 -4
- data/omnibus/package-scripts/kontena/postrm +1 -1
- data/omnibus/package-scripts/kontena/preinst +0 -2
- data/spec/fixtures/api/node.json +93 -0
- data/spec/kontena/cli/containers/logs_command_spec.rb +0 -4
- data/spec/kontena/cli/etcd/health_command_spec.rb +128 -63
- data/spec/kontena/cli/nodes/create_command_spec.rb +24 -0
- data/spec/kontena/cli/nodes/env_command_spec.rb +49 -0
- data/spec/kontena/cli/nodes/health_command_spec.rb +15 -173
- data/spec/kontena/cli/nodes/labels/add_command_spec.rb +56 -0
- data/spec/kontena/cli/nodes/labels/list_command_spec.rb +43 -0
- data/spec/kontena/cli/nodes/labels/remove_command_spec.rb +57 -0
- data/spec/kontena/cli/nodes/list_command_spec.rb +0 -2
- data/spec/kontena/cli/nodes/remove_command_spec.rb +76 -0
- data/spec/kontena/cli/nodes/reset_token_command_spec.rb +38 -0
- data/spec/kontena/cli/nodes/show_command_spec.rb +46 -0
- data/spec/kontena/cli/nodes/ssh_command_spec.rb +5 -0
- data/spec/kontena/cli/nodes/update_command_spec.rb +24 -0
- data/spec/kontena/cli/stacks/deploy_command_spec.rb +21 -0
- data/spec/kontena/cli/stacks/logs_command_spec.rb +0 -4
- data/spec/kontena/cli/table_generator_spec.rb +0 -4
- data/spec/spec_helper.rb +5 -0
- data/spec/support/output_helpers.rb +3 -14
- data/tasks/release.rake +2 -2
- metadata +28 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 69a344212c91c304c80efd5073e2b3d3e9003b66
|
4
|
+
data.tar.gz: 04ba668d77961f031b6bdd1bad7cbeacab5dfac9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5fb80753ebfd53b27841cedaa60b2de9af188b6448691b7cc5e9f02410e644d44115b8f873295c7cf2eef823fa929911069d7032ebe5334ffbadd46b52d18b35
|
7
|
+
data.tar.gz: 32129fc7dd6d6ba258238a47799d085d639d5ae0168ee64a90de78756c8984dbfc88885324ce06f5cb4ffe8a76286cb97f119479c3c41e7e4430b6fa6241befc
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.4.0.pre1
|
@@ -26,7 +26,7 @@ module Kontena::Cli::Etcd
|
|
26
26
|
nodes = client.get("grids/#{current_grid}/nodes")['nodes']
|
27
27
|
|
28
28
|
nodes.each do |node|
|
29
|
-
node_health = client.get("nodes/#{
|
29
|
+
node_health = client.get("nodes/#{node['id']}/health")
|
30
30
|
|
31
31
|
if !show_node_health(node_health)
|
32
32
|
health = false
|
@@ -117,5 +117,56 @@ module Kontena::Cli::Grids
|
|
117
117
|
exit_with_error "No grid given or selected"
|
118
118
|
end
|
119
119
|
end
|
120
|
+
|
121
|
+
module Parameters
|
122
|
+
def self.included(base)
|
123
|
+
base.option "--default-affinity", "[AFFINITY]", "Default affinity rule for the grid", multivalued: true
|
124
|
+
base.option "--statsd-server", "STATSD_SERVER", "Statsd server address (host:port)"
|
125
|
+
base.option "--log-forwarder", "LOG_FORWARDER", "Set grid wide log forwarder (set to 'none' to disable)"
|
126
|
+
base.option "--log-opt", "[LOG_OPT]", "Set log options (key=value)", multivalued: true
|
127
|
+
end
|
128
|
+
|
129
|
+
def validate_log_opts
|
130
|
+
if !log_opt_list.empty? && log_forwarder.nil?
|
131
|
+
raise Kontena::Errors::StandardError.new(1, "Need to specify --log-forwarder when using --log-opt")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def parse_log_opts
|
136
|
+
opts = {}
|
137
|
+
log_opt_list.each do |opt|
|
138
|
+
key, value = opt.split('=')
|
139
|
+
opts[key.to_sym] = value
|
140
|
+
end
|
141
|
+
opts
|
142
|
+
end
|
143
|
+
|
144
|
+
def validate_grid_parameters
|
145
|
+
validate_log_opts
|
146
|
+
end
|
147
|
+
|
148
|
+
def build_grid_parameters(payload)
|
149
|
+
if statsd_server
|
150
|
+
server, port = statsd_server.split(':')
|
151
|
+
payload[:stats] = {
|
152
|
+
statsd: {
|
153
|
+
server: server,
|
154
|
+
port: port || 8125
|
155
|
+
}
|
156
|
+
}
|
157
|
+
end
|
158
|
+
|
159
|
+
if log_forwarder
|
160
|
+
payload[:logs] = {
|
161
|
+
forwarder: log_forwarder,
|
162
|
+
opts: parse_log_opts
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
166
|
+
unless default_affinity_list.empty?
|
167
|
+
payload[:default_affinity] = default_affinity_list
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
120
171
|
end
|
121
172
|
end
|
@@ -10,28 +10,32 @@ module Kontena::Cli::Grids
|
|
10
10
|
option "--initial-size", "INITIAL_SIZE", "Initial grid size (number of nodes)", default: 1
|
11
11
|
option "--silent", :flag, "Reduce output verbosity"
|
12
12
|
option "--token", "[TOKEN]", "Set grid token"
|
13
|
-
option "--default-affinity", "[AFFINITY]", "Default affinity rule for the grid", multivalued: true
|
14
13
|
option "--subnet", "[CIDR]", "Configure grid overlay subnet"
|
15
14
|
option "--supernet", "[CIDR]", "Configure grid IPAM supernet"
|
16
15
|
|
16
|
+
include Common::Parameters
|
17
|
+
|
17
18
|
requires_current_master_token
|
18
19
|
|
19
20
|
def execute
|
21
|
+
validate_grid_parameters
|
22
|
+
|
23
|
+
if initial_size == 1
|
24
|
+
warning "Option --initial-size=1 is only recommended for test/dev usage" unless running_silent?
|
25
|
+
end
|
26
|
+
|
20
27
|
payload = {
|
21
28
|
name: name
|
22
29
|
}
|
23
30
|
payload[:token] = self.token if self.token
|
24
31
|
payload[:initial_size] = self.initial_size if self.initial_size
|
25
|
-
payload[:default_affinity] = self.default_affinity_list unless self.default_affinity_list.empty?
|
26
32
|
payload[:subnet] = subnet if subnet
|
27
33
|
payload[:supernet] = supernet if supernet
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
spinner "Creating #{pastel.cyan(name)} grid " do
|
34
|
-
grid = client.post('grids', payload)
|
34
|
+
|
35
|
+
build_grid_parameters(payload)
|
36
|
+
|
37
|
+
grid = spinner "Creating #{pastel.cyan(name)} grid " do
|
38
|
+
client.post('grids', payload)
|
35
39
|
end
|
36
40
|
if grid
|
37
41
|
spinner "Switching scope to #{pastel.cyan(name)} grid " do
|
@@ -6,63 +6,30 @@ module Kontena::Cli::Grids
|
|
6
6
|
include Common
|
7
7
|
|
8
8
|
parameter "NAME", "Grid name"
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
|
10
|
+
include Common::Parameters
|
11
|
+
|
12
12
|
option "--no-default-affinity", :flag, "Unset grid default affinity"
|
13
|
-
option "--
|
14
|
-
|
13
|
+
option "--no-statsd-server", :flag, "Unset statsd server setting"
|
14
|
+
|
15
|
+
requires_current_master_token
|
15
16
|
|
16
17
|
def execute
|
17
|
-
|
18
|
-
|
19
|
-
validate_log_opts
|
18
|
+
validate_grid_parameters
|
19
|
+
|
20
20
|
payload = {}
|
21
|
-
|
22
|
-
|
23
|
-
payload[:stats] = {
|
24
|
-
statsd: {
|
25
|
-
server: server,
|
26
|
-
port: port || 8125
|
27
|
-
}
|
28
|
-
}
|
29
|
-
end
|
21
|
+
|
22
|
+
build_grid_parameters(payload)
|
30
23
|
|
31
24
|
if no_statsd_server?
|
32
25
|
payload[:stats] = { statsd: nil }
|
33
26
|
end
|
34
27
|
|
35
|
-
if log_forwarder
|
36
|
-
payload[:logs] = {
|
37
|
-
forwarder: log_forwarder,
|
38
|
-
opts: parse_log_opts
|
39
|
-
}
|
40
|
-
end
|
41
|
-
|
42
|
-
unless default_affinity_list.empty?
|
43
|
-
payload[:default_affinity] = default_affinity_list
|
44
|
-
end
|
45
|
-
|
46
28
|
if no_default_affinity?
|
47
29
|
payload[:default_affinity] = []
|
48
30
|
end
|
49
31
|
|
50
|
-
client
|
51
|
-
end
|
52
|
-
|
53
|
-
def validate_log_opts
|
54
|
-
if !log_opt_list.empty? && log_forwarder.nil?
|
55
|
-
raise Kontena::Errors::StandardError.new(1, "Need to specify --log-forwarder when using --log-opt")
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def parse_log_opts
|
60
|
-
opts = {}
|
61
|
-
log_opt_list.each do |opt|
|
62
|
-
key, value = opt.split('=')
|
63
|
-
opts[key.to_sym] = value
|
64
|
-
end
|
65
|
-
opts
|
32
|
+
client.put("grids/#{name}", payload)
|
66
33
|
end
|
67
34
|
end
|
68
35
|
end
|
@@ -3,10 +3,13 @@ class Kontena::Cli::NodeCommand < Kontena::Command
|
|
3
3
|
subcommand ["list","ls"], "List grid nodes", load_subcommand('nodes/list_command')
|
4
4
|
subcommand "show", "Show node", load_subcommand('nodes/show_command')
|
5
5
|
subcommand "ssh", "Ssh into node", load_subcommand('nodes/ssh_command')
|
6
|
+
subcommand "create", "Create node", load_subcommand('nodes/create_command')
|
6
7
|
subcommand "update", "Update node", load_subcommand('nodes/update_command')
|
8
|
+
subcommand "reset-token", "Reset node token for agent websocket connection", load_subcommand('nodes/reset_token_command')
|
7
9
|
subcommand ["remove","rm"], "Remove node", load_subcommand('nodes/remove_command')
|
8
10
|
subcommand "label", "Node label specific commands", load_subcommand('nodes/label_command')
|
9
11
|
subcommand "health", "Check node health", load_subcommand('nodes/health_command')
|
12
|
+
subcommand "env", "Generate kontena-agent.env configuration", load_subcommand('nodes/env_command')
|
10
13
|
|
11
14
|
def execute
|
12
15
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Kontena::Cli::Nodes
|
2
|
+
class CreateCommand < Kontena::Command
|
3
|
+
include Kontena::Cli::Common
|
4
|
+
include Kontena::Cli::GridOptions
|
5
|
+
|
6
|
+
requires_current_master
|
7
|
+
requires_current_master_token
|
8
|
+
requires_current_grid
|
9
|
+
|
10
|
+
parameter "NAME", "Node name"
|
11
|
+
option ["--token"], "TOKEN", "Node token"
|
12
|
+
option ["-l", "--label"], "LABEL", "Node label", multivalued: true
|
13
|
+
|
14
|
+
def execute
|
15
|
+
data = { name: name }
|
16
|
+
|
17
|
+
data[:token] = token if token
|
18
|
+
data[:labels] = label_list
|
19
|
+
|
20
|
+
spinner "Creating #{name.colorize(:cyan)} node " do
|
21
|
+
client.post("grids/#{current_grid}/nodes", data)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Kontena::Cli::Nodes
|
2
|
+
class EnvCommand < Kontena::Command
|
3
|
+
include Kontena::Cli::Common
|
4
|
+
include Kontena::Cli::GridOptions
|
5
|
+
|
6
|
+
requires_current_master
|
7
|
+
requires_current_master_token
|
8
|
+
requires_current_grid
|
9
|
+
|
10
|
+
parameter "NAME", "Node name"
|
11
|
+
option ['--token'], :flag, 'Only show token', default: false
|
12
|
+
|
13
|
+
def grid_uri
|
14
|
+
grid_uri = self.current_master['url'].sub('http', 'ws')
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute
|
18
|
+
token_node = client.get("nodes/#{current_grid}/#{name}/token")
|
19
|
+
|
20
|
+
unless token_node['token']
|
21
|
+
exit_with_error "Node #{name} was not created with a node token. Use `kontena grid env` instead"
|
22
|
+
end
|
23
|
+
|
24
|
+
if self.token?
|
25
|
+
puts token_node['token']
|
26
|
+
else
|
27
|
+
puts "KONTENA_URI=#{grid_uri}"
|
28
|
+
puts "KONTENA_NODE_TOKEN=#{token_node['token']}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -6,14 +6,14 @@ module Kontena::Cli::Nodes
|
|
6
6
|
include Kontena::Cli::GridOptions
|
7
7
|
include Kontena::Cli::Helpers::HealthHelper
|
8
8
|
|
9
|
-
parameter "
|
9
|
+
parameter "NODE", "Node name"
|
10
10
|
|
11
11
|
def execute
|
12
12
|
require_api_url
|
13
13
|
require_current_grid
|
14
14
|
token = require_token
|
15
15
|
|
16
|
-
node = client(token).get("nodes/#{current_grid}/#{
|
16
|
+
node = client(token).get("nodes/#{current_grid}/#{self.node}")
|
17
17
|
|
18
18
|
return show_node_health(node)
|
19
19
|
end
|
@@ -2,7 +2,7 @@ module Kontena::Cli::Nodes::Labels
|
|
2
2
|
class AddCommand < Kontena::Command
|
3
3
|
include Kontena::Cli::Common
|
4
4
|
|
5
|
-
parameter "
|
5
|
+
parameter "NODE", "Node name"
|
6
6
|
parameter "LABEL ...", "Labels"
|
7
7
|
|
8
8
|
requires_current_master
|
@@ -10,9 +10,9 @@ module Kontena::Cli::Nodes::Labels
|
|
10
10
|
requires_current_grid
|
11
11
|
|
12
12
|
def execute
|
13
|
-
node = client.get("nodes/#{current_grid}/#{
|
13
|
+
node = client.get("nodes/#{current_grid}/#{self.node}")
|
14
14
|
data = { labels: (Array(node['labels']) + label_list).uniq }
|
15
|
-
client.put("nodes/#{
|
15
|
+
client.put("nodes/#{node['id']}", data)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -2,7 +2,7 @@ module Kontena::Cli::Nodes::Labels
|
|
2
2
|
class ListCommand < Kontena::Command
|
3
3
|
include Kontena::Cli::Common
|
4
4
|
|
5
|
-
parameter "
|
5
|
+
parameter "NODE", "Node name"
|
6
6
|
|
7
7
|
# the command outputs id info only anyway, this is here strictly for ignoring purposes
|
8
8
|
option ['-q', '--quiet'], :flag, "Output the identifying column only", hidden: true
|
@@ -12,7 +12,7 @@ module Kontena::Cli::Nodes::Labels
|
|
12
12
|
requires_current_grid
|
13
13
|
|
14
14
|
def execute
|
15
|
-
node = client.get("nodes/#{current_grid}/#{
|
15
|
+
node = client.get("nodes/#{current_grid}/#{self.node}")
|
16
16
|
puts Array(node['labels']).join("\n")
|
17
17
|
end
|
18
18
|
end
|
@@ -2,7 +2,7 @@ module Kontena::Cli::Nodes::Labels
|
|
2
2
|
class RemoveCommand < Kontena::Command
|
3
3
|
include Kontena::Cli::Common
|
4
4
|
|
5
|
-
parameter "
|
5
|
+
parameter "NODE", "Node name"
|
6
6
|
parameter "LABEL ...", "Labels"
|
7
7
|
|
8
8
|
requires_current_master
|
@@ -10,9 +10,9 @@ module Kontena::Cli::Nodes::Labels
|
|
10
10
|
requires_current_grid
|
11
11
|
|
12
12
|
def execute
|
13
|
-
node = client.get("nodes/#{current_grid}/#{
|
13
|
+
node = client.get("nodes/#{current_grid}/#{self.node}")
|
14
14
|
data = { labels: Array(node['labels']).reject {|label| label_list.include?(label) } }
|
15
|
-
client.put("nodes/#{
|
15
|
+
client.put("nodes/#{node['id']}", data)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -3,7 +3,7 @@ module Kontena::Cli::Nodes
|
|
3
3
|
include Kontena::Cli::Common
|
4
4
|
include Kontena::Cli::GridOptions
|
5
5
|
|
6
|
-
parameter "
|
6
|
+
parameter "NODE", "Node name"
|
7
7
|
option "--force", :flag, "Force remove", default: false, attribute_name: :forced
|
8
8
|
|
9
9
|
def execute
|
@@ -11,16 +11,18 @@ module Kontena::Cli::Nodes
|
|
11
11
|
require_current_grid
|
12
12
|
token = require_token
|
13
13
|
|
14
|
-
node = client(token).get("nodes/#{current_grid}/#{
|
14
|
+
node = client(token).get("nodes/#{current_grid}/#{self.node}")
|
15
15
|
|
16
|
-
if node['connected']
|
17
|
-
|
16
|
+
if node['has_token'] && node['connected']
|
17
|
+
warning "Node #{node['name']} is still connected using a node token, but will be force-disconnected"
|
18
|
+
elsif node['connected']
|
19
|
+
exit_with_error "Node #{node['name']} is still connected using a grid token. You must terminate the node before removing it."
|
18
20
|
end
|
19
21
|
|
20
|
-
confirm_command(
|
22
|
+
confirm_command(self.node) unless forced?
|
21
23
|
|
22
|
-
spinner "Removing #{
|
23
|
-
client(token).delete("nodes/#{
|
24
|
+
spinner "Removing #{self.node.colorize(:cyan)} node from #{current_grid.colorize(:cyan)} grid " do
|
25
|
+
client(token).delete("nodes/#{node['id']}")
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Kontena::Cli::Nodes
|
2
|
+
class ResetTokenCommand < Kontena::Command
|
3
|
+
include Kontena::Cli::Common
|
4
|
+
include Kontena::Cli::GridOptions
|
5
|
+
|
6
|
+
requires_current_master
|
7
|
+
requires_current_master_token
|
8
|
+
requires_current_grid
|
9
|
+
|
10
|
+
parameter "NODE", "Node name"
|
11
|
+
|
12
|
+
option ["--token"], "TOKEN", "Use given node token instead of generating a random token"
|
13
|
+
option ["--clear-token"], :flag, "Clear node token, reverting to grid token"
|
14
|
+
option "--[no-]reset-connection", :flag, "Reset agent websocket connection", default: true
|
15
|
+
option "--force", :flag, "Force token update"
|
16
|
+
|
17
|
+
def execute
|
18
|
+
confirm("Resetting the node token will disconnect the agent (unless using --no-reset-connection), and require you to reconfigure the kontena-agent using the new `kontena node env` values before it will be able to reconnect. Are you sure?")
|
19
|
+
|
20
|
+
data = {}
|
21
|
+
|
22
|
+
data[:token] = self.token
|
23
|
+
data[:token] = '' if self.clear_token?
|
24
|
+
data[:reset_connection] = self.reset_connection?
|
25
|
+
|
26
|
+
spinner "Resetting node #{self.node.colorize(:cyan)} websocket connection token" do
|
27
|
+
client.put("nodes/#{current_grid}/#{self.node}/token", data)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -4,16 +4,16 @@ module Kontena::Cli::Nodes
|
|
4
4
|
include Kontena::Cli::GridOptions
|
5
5
|
include Kontena::Cli::BytesHelper
|
6
6
|
|
7
|
-
parameter "
|
7
|
+
parameter "NODE", "Node name"
|
8
8
|
|
9
9
|
def execute
|
10
10
|
require_api_url
|
11
11
|
require_current_grid
|
12
12
|
token = require_token
|
13
13
|
|
14
|
-
node = client(token).get("nodes/#{current_grid}/#{
|
15
|
-
puts "#{node['
|
16
|
-
puts " id: #{node['
|
14
|
+
node = client(token).get("nodes/#{current_grid}/#{self.node}")
|
15
|
+
puts "#{node['id']}:"
|
16
|
+
puts " id: #{node['node_id']}"
|
17
17
|
puts " agent version: #{node['agent_version']}"
|
18
18
|
puts " docker version: #{node['docker_version']}"
|
19
19
|
puts " connected: #{node['connected'] ? 'yes': 'no'}"
|