docker-swarm-api 1.2.2 → 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +42 -77
- data/lib/docker/swarm/network.rb +8 -1
- data/lib/docker/swarm/service.rb +65 -0
- data/lib/docker/swarm/swarm.rb +93 -86
- data/lib/docker/swarm/task.rb +16 -0
- data/lib/docker/swarm/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f231ed6bde66591fce70f5c3c5d653d3c21abd52
|
4
|
+
data.tar.gz: e33c69b6e3ad5a10a070d9de06f358093413780d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3885fddc8388316922b7a4371d1d10a64084a59fb8d373fd4e2a2df8fd76f241f510ce7bb4d098ed7427c95e2bf9f6702e52092b82372a6d9464a15abe033d52
|
7
|
+
data.tar.gz: 52a89eb4cede7dff51e836db236737711ceccd7e648d13ada96e18f50b5f91f7b18078194d10092306f3e21aa112d546389a81c581974bce888a1327efacbb29
|
data/README.md
CHANGED
@@ -1,120 +1,85 @@
|
|
1
1
|
# docker-swarm-api
|
2
2
|
|
3
|
-
|
3
|
+
Ruby GEM providing API for managing Docker Swarm clusters.
|
4
|
+
|
5
|
+
MIT License
|
4
6
|
|
5
|
-
|
7
|
+
Must use Docker Engine Version of 1.12 or above. Docker Engine version 1.12.5 required to make overlay networks with API.
|
6
8
|
|
7
|
-
|
9
|
+
Must use Docker API Version of 1.24 or above.
|
10
|
+
|
11
|
+
This project leverages swipely/docker-api (https://github.com/swipely/docker-api), and adds Docker Swarm capability.
|
8
12
|
|
9
13
|
Sample Usage
|
10
14
|
------------
|
11
15
|
```ruby
|
12
|
-
#
|
16
|
+
# Make a connection to the Swarm manager's API. (Assumes port 2375 exposed for API)
|
13
17
|
master_connection = Docker::Swarm::Connection.new('http://10.20.30.1:2375')
|
14
18
|
|
15
19
|
# Manager node intializes swarm
|
16
|
-
swarm_init_options = {
|
17
|
-
"ListenAddr" => "0.0.0.0:2377",
|
18
|
-
}
|
20
|
+
swarm_init_options = { "ListenAddr" => "0.0.0.0:2377" }
|
19
21
|
swarm = Docker::Swarm::Swarm.init(swarm_init_options, master_connection)
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
nodes = Docker::Swarm::Node.all({}, master_connection)
|
23
|
+
# Gather all nodes available to swarm (overlay and bridges)
|
24
|
+
nodes = swarm.nodes()
|
24
25
|
expect(nodes.length).to eq 1
|
25
26
|
|
26
27
|
# Worker joins swarm
|
27
28
|
worker_connection = Docker::Swarm::Connection.new('http://10.20.30.2:2375')
|
28
|
-
swarm.
|
29
|
+
swarm.join_worker(worker_connection)
|
30
|
+
|
31
|
+
# Join another manager to the swarm
|
32
|
+
manager_2_connection = Docker::Swarm::Connection.new('http://10.20.30.3:2375')
|
33
|
+
swarm.join_manager(manager_2_connection)
|
29
34
|
|
30
35
|
# Gather all nodes of swarm
|
31
|
-
nodes = swarm.nodes
|
36
|
+
nodes = swarm.nodes()
|
32
37
|
|
33
38
|
# Create a network which connect services
|
34
|
-
network = swarm.
|
39
|
+
network = swarm.create_overlay_network(network_name)
|
35
40
|
|
36
41
|
# Find all networks in swarm cluster
|
37
|
-
networks = swarm.networks
|
42
|
+
networks = swarm.networks()
|
38
43
|
|
39
44
|
# Create a service with 5 replicas
|
40
|
-
service_create_options = {
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
}
|
57
|
-
},
|
58
|
-
"Placement" => {},
|
59
|
-
"Resources" => {
|
60
|
-
"Limits" => {
|
61
|
-
"MemoryBytes" => 104857600
|
62
|
-
},
|
63
|
-
"Reservations" => {
|
64
|
-
}
|
65
|
-
},
|
66
|
-
"RestartPolicy" => {
|
67
|
-
"Condition" => "on-failure",
|
68
|
-
"Delay" => 1,
|
69
|
-
"MaxAttempts" => 3
|
70
|
-
}
|
71
|
-
},
|
72
|
-
"Mode" => {
|
73
|
-
"Replicated" => {
|
74
|
-
"Replicas" => 5
|
75
|
-
}
|
76
|
-
},
|
77
|
-
"UpdateConfig" => {
|
78
|
-
"Delay" => 2,
|
79
|
-
"Parallelism" => 2,
|
80
|
-
"FailureAction" => "pause"
|
81
|
-
},
|
82
|
-
"EndpointSpec" => {
|
83
|
-
"Ports" => [
|
84
|
-
{
|
85
|
-
"Protocol" => "tcp",
|
86
|
-
"PublishedPort" => 80,
|
87
|
-
"TargetPort" => 80
|
88
|
-
}
|
89
|
-
]
|
90
|
-
},
|
91
|
-
"Labels" => {
|
92
|
-
"foo" => "bar"
|
93
|
-
}
|
94
|
-
}
|
95
|
-
|
45
|
+
service_create_options = {"Name"=>"nginx",
|
46
|
+
"TaskTemplate" =>
|
47
|
+
{"ContainerSpec" =>
|
48
|
+
{"Networks" => [], "Image" => "nginx:1.11.7", "Mounts" => [], "User" => "root"},
|
49
|
+
"Env" => ["TEST_ENV=test"],
|
50
|
+
"LogDriver" => {"Name"=>"json-file", "Options"=>{"max-file"=>"3", "max-size"=>"10M"}},
|
51
|
+
"Placement" => {},
|
52
|
+
"Resources" => {"Limits"=>{"MemoryBytes"=>104857600}, "Reservations"=>{}},
|
53
|
+
"RestartPolicy" => {"Condition"=>"on-failure", "Delay"=>1, "MaxAttempts"=>3}},
|
54
|
+
"Mode"=>{"Replicated" => {"Replicas" => 5}},
|
55
|
+
"UpdateConfig" => {"Delay" => 2, "Parallelism" => 2, "FailureAction" => "pause"},
|
56
|
+
"EndpointSpec"=>
|
57
|
+
{"Ports" => [{"Protocol"=>"tcp", "PublishedPort" => 8181, "TargetPort" => 80}]},
|
58
|
+
"Labels" => {"layer" => "database"},
|
59
|
+
"Networks" => [{"Target" => "my-network"}]
|
60
|
+
}
|
96
61
|
service = swarm.create_service(service_create_options)
|
97
62
|
|
98
63
|
# Retrieve all manager nodes of swarm
|
99
|
-
manager_nodes = swarm.manager_nodes
|
64
|
+
manager_nodes = swarm.manager_nodes()
|
100
65
|
|
101
66
|
# Retrieve all worker nodes (that aren't managers)
|
102
|
-
worker_nodes = swarm.worker_nodes
|
67
|
+
worker_nodes = swarm.worker_nodes()
|
103
68
|
|
104
69
|
# Drain a worker node - stop hosting tasks/containers of services
|
105
70
|
worker_node = worker_nodes.first
|
106
|
-
worker_node.drain
|
71
|
+
worker_node.drain()
|
107
72
|
|
108
73
|
# Gather all tasks (containers for service) being hosted by the swarm cluster
|
109
|
-
tasks = swarm.tasks
|
74
|
+
tasks = swarm.tasks()
|
110
75
|
|
111
76
|
# Scale up or down the number of replicas on a service
|
112
77
|
service.scale(20)
|
113
78
|
|
114
79
|
# Worker leaves the swarm - no forcing
|
115
|
-
swarm.leave(
|
80
|
+
swarm.leave(worker_node, node)
|
116
81
|
|
117
|
-
# Manager leaves the swarm - forced because manager
|
118
|
-
swarm.leave(
|
82
|
+
# Manager leaves the swarm - forced because last manager needs to use 'force' to leave the issue.
|
83
|
+
swarm.leave(manager_node, true)
|
119
84
|
|
120
85
|
```
|
data/lib/docker/swarm/network.rb
CHANGED
@@ -20,13 +20,20 @@ class Docker::Swarm::Network
|
|
20
20
|
return @hash['Name']
|
21
21
|
end
|
22
22
|
|
23
|
+
def driver
|
24
|
+
return @hash['Driver']
|
25
|
+
end
|
26
|
+
|
23
27
|
def remove
|
28
|
+
network_name = name
|
24
29
|
response = @swarm.connection.delete("/networks/#{id()}", {}, expects: [200, 204, 500], full_response: true)
|
25
30
|
if (response.status > 204)
|
26
31
|
raise "Error deleting network (#{name}) HTTP-#{response.status} #{response.body}"
|
27
32
|
end
|
33
|
+
while (@swarm.find_network_by_name(network_name) != nil)
|
34
|
+
sleep 1
|
35
|
+
end
|
28
36
|
end
|
29
|
-
|
30
37
|
end
|
31
38
|
|
32
39
|
# EXAMPLE INSPECT OF OVERLAY NETWORK:
|
data/lib/docker/swarm/service.rb
CHANGED
@@ -17,6 +17,12 @@ class Docker::Swarm::Service
|
|
17
17
|
return @hash['ID']
|
18
18
|
end
|
19
19
|
|
20
|
+
def reload()
|
21
|
+
s = @swarm.find_service(id())
|
22
|
+
@hash = s.hash
|
23
|
+
return self
|
24
|
+
end
|
25
|
+
|
20
26
|
def network_ids
|
21
27
|
network_ids = []
|
22
28
|
@hash['Endpoint']['VirtualIPs'].each do |network_info|
|
@@ -41,6 +47,65 @@ class Docker::Swarm::Service
|
|
41
47
|
self.update(@hash['Spec'])
|
42
48
|
end
|
43
49
|
|
50
|
+
|
51
|
+
def self.DEFAULT_OPTIONS
|
52
|
+
default_service_create_options = {
|
53
|
+
"Name" => "<<Required>>",
|
54
|
+
"TaskTemplate" => {
|
55
|
+
"ContainerSpec" => {
|
56
|
+
"Image" => "<<Required>>",
|
57
|
+
"Mounts" => [],
|
58
|
+
"User" => "root"
|
59
|
+
},
|
60
|
+
"Env" => [],
|
61
|
+
"LogDriver" => {
|
62
|
+
"Name" => "json-file",
|
63
|
+
"Options" => {
|
64
|
+
"max-file" => "3",
|
65
|
+
"max-size" => "10M"
|
66
|
+
}
|
67
|
+
},
|
68
|
+
"Placement" => {},
|
69
|
+
"Resources" => {
|
70
|
+
"Limits" => {
|
71
|
+
"MemoryBytes" => 104857600
|
72
|
+
},
|
73
|
+
"Reservations" => {
|
74
|
+
# "NanoCPUs" => ?
|
75
|
+
# MemoryBytes =>
|
76
|
+
}
|
77
|
+
},
|
78
|
+
"RestartPolicy" => {
|
79
|
+
"Condition" => "on-failure",
|
80
|
+
"Delay" => 1,
|
81
|
+
"MaxAttempts" => 3
|
82
|
+
}
|
83
|
+
}, # End of TaskTemplate
|
84
|
+
"Mode" => {
|
85
|
+
"Replicated" => {
|
86
|
+
"Replicas" => 1
|
87
|
+
}
|
88
|
+
},
|
89
|
+
"UpdateConfig" => {
|
90
|
+
"Delay" => 2,
|
91
|
+
"Parallelism" => 2,
|
92
|
+
"FailureAction" => "pause"
|
93
|
+
},
|
94
|
+
"EndpointSpec" => {
|
95
|
+
"Ports" => [
|
96
|
+
{
|
97
|
+
# "Protocol" => "http",
|
98
|
+
# "PublishedPort" => 2881,
|
99
|
+
# "TargetPort" => 2881
|
100
|
+
}
|
101
|
+
]
|
102
|
+
},
|
103
|
+
"Labels" => {
|
104
|
+
"foo" => "bar"
|
105
|
+
}
|
106
|
+
}
|
107
|
+
return default_service_create_options
|
108
|
+
end
|
44
109
|
|
45
110
|
|
46
111
|
end
|
data/lib/docker/swarm/swarm.rb
CHANGED
@@ -9,61 +9,58 @@ class Docker::Swarm::Swarm
|
|
9
9
|
|
10
10
|
def initialize(hash, manager_connection, options = {})
|
11
11
|
@hash = hash
|
12
|
-
# @manager_connection = manager_connection
|
13
12
|
@id = hash['ID']
|
14
13
|
@worker_join_token = hash['JoinTokens']['Worker']
|
15
14
|
@manager_join_token = hash['JoinTokens']['Manager']
|
16
15
|
@node_hash = {}
|
17
16
|
@manager_connection = manager_connection
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
else
|
27
|
-
node.connection = Docker::Swarm::Connection.new("tcp://#{ip_address}:#{docker_port}")
|
28
|
-
end
|
29
|
-
else
|
30
|
-
ip_address = nil
|
31
|
-
begin
|
32
|
-
ip_address = Resolv::DNS.new.getaddress(node.host_name())
|
33
|
-
rescue
|
34
|
-
ip_address = Resolv::Hosts.new.getaddress(node.host_name())
|
35
|
-
if (!ip_address)
|
36
|
-
host_addresses = options[:host_addresses]
|
37
|
-
ip_address = host_addresses[node.host_name]
|
38
|
-
end
|
39
|
-
end
|
40
|
-
node.connection = Docker::Swarm::Connection.new("tcp://#{ip_address}:#{docker_port}")
|
41
|
-
end
|
42
|
-
@node_hash[node.id] = {hash: node.hash, connection: node.connection}
|
43
|
-
|
44
|
-
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def store_manager(manager_connection, listen_address_and_port)
|
20
|
+
node = nodes.find {|n|
|
21
|
+
(n.hash['ManagerStatus']) && (n.hash['ManagerStatus']['Leader'] == true) && (n.hash['ManagerStatus']['Addr'] == listen_address_and_port)
|
22
|
+
}
|
23
|
+
raise "Node not found for: #{listen_address}" if (!node)
|
24
|
+
@node_hash[node.id] = {hash: node.hash, connection: manager_connection}
|
45
25
|
end
|
46
26
|
|
47
|
-
def join(node_connection, join_token)
|
27
|
+
def join(node_connection, join_token = nil, listen_address = "0.0.0.0:2377")
|
28
|
+
join_token = @worker_join_token
|
48
29
|
node_ids_before = nodes().collect {|n| n.id}
|
49
30
|
query = {}
|
50
31
|
master_ip = self.connection.url.split("//").last.split(":").first
|
51
32
|
new_node_ip = node_connection.url.split("//").last.split(":").first
|
33
|
+
|
52
34
|
join_options = {
|
53
|
-
"ListenAddr" => "
|
35
|
+
"ListenAddr" => "#{listen_address}",
|
54
36
|
"AdvertiseAddr" => "#{new_node_ip}:2377",
|
55
37
|
"RemoteAddrs" => ["#{master_ip}:2377"],
|
56
38
|
"JoinToken" => join_token
|
57
39
|
}
|
58
40
|
new_node = nil
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
41
|
+
response = node_connection.post('/swarm/join', query, :body => join_options.to_json, expects: [200, 406, 500], full_response: true)
|
42
|
+
if (response.status == 200)
|
43
|
+
nodes.each do |node|
|
44
|
+
if (!node_ids_before.include? node.id)
|
45
|
+
new_node = node
|
46
|
+
@node_hash[node.id] = {hash: node.hash, connection: node_connection}
|
47
|
+
end
|
64
48
|
end
|
49
|
+
return new_node
|
50
|
+
elsif (response.status == 406)
|
51
|
+
puts "Node is already part of a swarm - maybe this swarm, maybe another swarm."
|
52
|
+
return nil
|
53
|
+
else
|
54
|
+
raise "Error joining (#{node_connection}): HTTP-#{response.status} #{response.body}"
|
65
55
|
end
|
66
|
-
|
56
|
+
end
|
57
|
+
|
58
|
+
def join_worker(node_connection, listen_address = "0.0.0.0:2377")
|
59
|
+
join(node_connection, @worker_join_token)
|
60
|
+
end
|
61
|
+
|
62
|
+
def join_manager(manager_connection, listen_address = "0.0.0.0:2377")
|
63
|
+
join(node_connection, @manager_join_token, listen_address)
|
67
64
|
end
|
68
65
|
|
69
66
|
def connection
|
@@ -76,14 +73,6 @@ class Docker::Swarm::Swarm
|
|
76
73
|
return @manager_connection
|
77
74
|
end
|
78
75
|
|
79
|
-
def join_worker(node_connection)
|
80
|
-
join(node_connection, @worker_join_token)
|
81
|
-
end
|
82
|
-
|
83
|
-
def join_manager(manager_connection)
|
84
|
-
join(node_connection, @manager_join_token)
|
85
|
-
end
|
86
|
-
|
87
76
|
def remove
|
88
77
|
services().each do |service|
|
89
78
|
service.remove()
|
@@ -144,46 +133,54 @@ class Docker::Swarm::Swarm
|
|
144
133
|
return all_networks
|
145
134
|
end
|
146
135
|
|
147
|
-
def create_network(
|
148
|
-
|
136
|
+
def create_network(options)
|
137
|
+
response = connection.post('/networks/create', {}, body: options.to_json, expects: [200, 201, 500], full_response: true)
|
138
|
+
if (response.status <= 201)
|
139
|
+
hash = JSON.parse(response.body)
|
140
|
+
response = connection.get("/networks/#{hash['Id']}", {}, expects: [200, 201], full_response: true)
|
141
|
+
hash = Docker::Util.parse_json(response.body)
|
142
|
+
network = Docker::Swarm::Network.new(self, hash)
|
143
|
+
return network
|
144
|
+
else
|
145
|
+
raise "Error creating network: HTTP-#{response.status} - #{response.body}"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def create_network_overlay(network_name)
|
150
|
+
max_vxlanid = 200
|
151
|
+
networks.each do |network|
|
152
|
+
if (network.driver == 'overlay')
|
153
|
+
if (network.hash['Options'])
|
154
|
+
vxlanid = network.hash['Options']["com.docker.network.driver.overlay.vxlanid_list"]
|
155
|
+
if (vxlanid) && (vxlanid.to_i > max_vxlanid)
|
156
|
+
max_vxlanid = vxlanid.to_i
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
options = {
|
149
163
|
"Name" => network_name,
|
150
164
|
"CheckDuplicate" => true,
|
151
|
-
# "Driver" => "bridge",
|
152
165
|
"Driver" => "overlay",
|
153
166
|
"EnableIPv6" => false,
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
# }
|
162
|
-
# ],
|
163
|
-
# "Options" => {
|
164
|
-
# # "foo" => "bar"
|
165
|
-
# }
|
166
|
-
# },
|
167
|
+
"IPAM" => {
|
168
|
+
"Driver" => "default",
|
169
|
+
"Config" => [
|
170
|
+
],
|
171
|
+
"Options" => {
|
172
|
+
}
|
173
|
+
},
|
167
174
|
"Internal" => false,
|
168
175
|
"Options" => {
|
169
|
-
"com.docker.network.driver.overlay.vxlanid_list" =>
|
176
|
+
"com.docker.network.driver.overlay.vxlanid_list" => (max_vxlanid + 1).to_s
|
170
177
|
},
|
171
178
|
"Labels" => {
|
172
179
|
# "com.example.some-label": "some-value",
|
173
180
|
# "com.example.some-other-label": "some-other-value"
|
174
181
|
}
|
175
182
|
}
|
176
|
-
|
177
|
-
response = connection.post('/networks/create', {}, body: opts.to_json, expects: [200, 201, 500], full_response: true)
|
178
|
-
if (response.status <= 201)
|
179
|
-
hash = JSON.parse(response.body)
|
180
|
-
response = connection.get("/networks/#{hash['Id']}", {}, expects: [200, 201], full_response: true)
|
181
|
-
hash = Docker::Util.parse_json(response.body)
|
182
|
-
network = Docker::Swarm::Network.new(self, hash)
|
183
|
-
return network
|
184
|
-
else
|
185
|
-
raise "Error creating network: HTTP-#{response.status} - #{response.body}"
|
186
|
-
end
|
183
|
+
create_network(options)
|
187
184
|
end
|
188
185
|
|
189
186
|
def find_network_by_name(network_name)
|
@@ -194,7 +191,7 @@ class Docker::Swarm::Swarm
|
|
194
191
|
end
|
195
192
|
return nil
|
196
193
|
end
|
197
|
-
|
194
|
+
|
198
195
|
# Return all of the Nodes.
|
199
196
|
def nodes
|
200
197
|
opts = {}
|
@@ -215,7 +212,7 @@ class Docker::Swarm::Swarm
|
|
215
212
|
|
216
213
|
def create_service(opts = {})
|
217
214
|
query = {}
|
218
|
-
response = self.connection.post('/services/create', query, :body => opts.to_json, expects: [201, 500], full_response: true)
|
215
|
+
response = self.connection.post('/services/create', query, :body => opts.to_json, expects: [201, 404, 409, 500], full_response: true)
|
219
216
|
if (response.status <= 201)
|
220
217
|
info = JSON.parse(response.body)
|
221
218
|
service_id = info['ID']
|
@@ -234,7 +231,7 @@ class Docker::Swarm::Swarm
|
|
234
231
|
return Docker::Swarm::Service.new(self, hash)
|
235
232
|
end
|
236
233
|
|
237
|
-
def
|
234
|
+
def find_service_by_name(name)
|
238
235
|
services.each do |service|
|
239
236
|
return service if (service.name == name)
|
240
237
|
end
|
@@ -253,23 +250,28 @@ class Docker::Swarm::Swarm
|
|
253
250
|
return items
|
254
251
|
end
|
255
252
|
|
256
|
-
def discover_nodes
|
257
|
-
# {discover_nodes: true, worker_docker_port: 2375}
|
258
|
-
|
259
|
-
end
|
260
|
-
|
261
253
|
# Initialize Swarm
|
262
254
|
def self.init(opts, connection)
|
263
255
|
query = {}
|
264
|
-
resp = connection.post('/swarm/init', query, :body => opts.to_json, full_response: true)
|
265
|
-
|
256
|
+
resp = connection.post('/swarm/init', query, :body => opts.to_json, full_response: true, expects: [200, 404, 500])
|
257
|
+
if (resp.status == 200)
|
258
|
+
swarm = Docker::Swarm::Swarm.swarm(opts, connection)
|
259
|
+
manager_node = swarm.nodes.find {|n|
|
260
|
+
(n.hash['ManagerStatus']) && (n.hash['ManagerStatus']['Leader'] == true)
|
261
|
+
}
|
262
|
+
listen_address = manager_node.hash['ManagerStatus']['Addr']
|
263
|
+
swarm.store_manager(connection, listen_address)
|
264
|
+
return swarm
|
265
|
+
else
|
266
|
+
raise "Bad response: #{resp.status} #{resp.body}"
|
267
|
+
end
|
266
268
|
end
|
267
269
|
|
268
270
|
# docker swarm join-token -q worker
|
269
271
|
def self.swarm(opts, connection)
|
270
272
|
query = {}
|
271
|
-
resp = connection.get('/swarm', query, :body => opts.to_json, expects: [200, 406], full_response: true)
|
272
|
-
if (resp.status == 406)
|
273
|
+
resp = connection.get('/swarm', query, :body => opts.to_json, expects: [200, 404, 406], full_response: true)
|
274
|
+
if (resp.status == 406) || (resp.status == 404)
|
273
275
|
return nil
|
274
276
|
elsif (resp.status == 200)
|
275
277
|
hash = JSON.parse(resp.body)
|
@@ -290,11 +292,16 @@ class Docker::Swarm::Swarm
|
|
290
292
|
|
291
293
|
def self.find(connection, options = {})
|
292
294
|
query = {}
|
293
|
-
response = connection.get('/swarm', query, expects: [200, 406], full_response: true)
|
295
|
+
response = connection.get('/swarm', query, expects: [200, 404, 406], full_response: true)
|
294
296
|
if (response.status == 200)
|
295
297
|
swarm = Docker::Swarm::Swarm.new(JSON.parse(response.body), connection, options)
|
298
|
+
manager_node = swarm.nodes.find {|n|
|
299
|
+
(n.hash['ManagerStatus']) && (n.hash['ManagerStatus']['Leader'] == true)
|
300
|
+
}
|
301
|
+
listen_address = manager_node.hash['ManagerStatus']['Addr']
|
302
|
+
swarm.store_manager(connection, listen_address)
|
296
303
|
return swarm
|
297
|
-
elsif (response.status
|
304
|
+
elsif (response.status > 200)
|
298
305
|
return nil
|
299
306
|
else
|
300
307
|
raise "Error finding swarm: HTTP-#{response.status} #{response.body}"
|
data/lib/docker/swarm/task.rb
CHANGED
@@ -19,6 +19,12 @@ class Docker::Swarm::Task
|
|
19
19
|
def service_id
|
20
20
|
@hash['ServiceID']
|
21
21
|
end
|
22
|
+
|
23
|
+
def service
|
24
|
+
return @swarm.services.find { |service|
|
25
|
+
self.service_id == service.id
|
26
|
+
}
|
27
|
+
end
|
22
28
|
|
23
29
|
def node_id
|
24
30
|
@hash['NodeID']
|
@@ -36,5 +42,15 @@ class Docker::Swarm::Task
|
|
36
42
|
@hash['Status']['State'].to_sym
|
37
43
|
end
|
38
44
|
|
45
|
+
def networks
|
46
|
+
all_networks = @swarm.networks
|
47
|
+
nets = []
|
48
|
+
self.hash['NetworksAttachments'].each do |net_hash|
|
49
|
+
hash = net_hash['Network']
|
50
|
+
network_id = hash['ID']
|
51
|
+
nets << all_networks.find {|net| net.id == network_id}
|
52
|
+
end
|
53
|
+
return nets
|
54
|
+
end
|
39
55
|
|
40
56
|
end
|
data/lib/docker/swarm/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: docker-swarm-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Moore / Rogue Wave Software
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-01-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|