Skip to content

Commit f372075

Browse files
authored
Merge pull request #817 from nmaludy/bugfix/docker-swarm-facts
2 parents 5d7b9d4 + c519de9 commit f372075

File tree

4 files changed

+233
-46
lines changed

4 files changed

+233
-46
lines changed

lib/facter/docker.rb

Lines changed: 60 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ def interfaces
4141
Facter.value(:interfaces).split(',')
4242
end
4343

44+
Facter.add(:docker_version) do
45+
confine { Facter::Core::Execution.which('docker') }
46+
setcode do
47+
value = Facter::Core::Execution.execute(
48+
"#{docker_command} version --format '{{json .}}'", timeout: 90
49+
)
50+
JSON.parse(value)
51+
end
52+
end
53+
4454
Facter.add(:docker_client_version) do
4555
setcode do
4656
docker_version = Facter.value(:docker_version)
@@ -65,70 +75,77 @@ def interfaces
6575
end
6676
end
6777

68-
Facter.add(:docker_version) do
69-
setcode do
70-
if Facter::Core::Execution.which('docker')
71-
value = Facter::Core::Execution.execute(
72-
"#{docker_command} version --format '{{json .}}'", timeout: 90
73-
)
74-
val = JSON.parse(value)
75-
end
76-
val
77-
end
78-
end
79-
8078
Facter.add(:docker_worker_join_token) do
79+
confine { Facter::Core::Execution.which('docker') }
8180
setcode do
82-
if Facter::Core::Execution.which('docker')
83-
val = Facter::Core::Execution.execute(
84-
"#{docker_command} swarm join-token worker -q", timeout: 90
85-
)
81+
# only run `docker swarm` commands if this node is in active in a cluster
82+
docker_json_str = Facter::Core::Execution.execute(
83+
"#{docker_command} info --format '{{json .}}'", timeout: 90
84+
)
85+
begin
86+
docker = JSON.parse(docker_json_str)
87+
if docker.fetch('Swarm', {})['LocalNodeState'] == 'active'
88+
val = Facter::Core::Execution.execute(
89+
"#{docker_command} swarm join-token worker -q", timeout: 90
90+
)
91+
end
92+
rescue JSON::ParserError
93+
nil
8694
end
8795
val
8896
end
8997
end
9098

9199
Facter.add(:docker_manager_join_token) do
100+
confine { Facter::Core::Execution.which('docker') }
92101
setcode do
93-
if Facter::Core::Execution.which('docker')
94-
val = Facter::Core::Execution.execute(
95-
"#{docker_command} swarm join-token manager -q", timeout: 90
96-
)
102+
# only run `docker swarm` commands if this node is in active in a cluster
103+
docker_json_str = Facter::Core::Execution.execute(
104+
"#{docker_command} info --format '{{json .}}'", timeout: 90
105+
)
106+
begin
107+
docker = JSON.parse(docker_json_str)
108+
if docker.fetch('Swarm', {})['LocalNodeState'] == 'active'
109+
val = Facter::Core::Execution.execute(
110+
"#{docker_command} swarm join-token manager -q", timeout: 90
111+
)
112+
end
113+
rescue JSON::ParserError
114+
nil
97115
end
98116
val
99117
end
100118
end
101119

102120
Facter.add(:docker) do
121+
confine { Facter::Core::Execution.which('docker') }
103122
setcode do
104123
docker_version = Facter.value(:docker_client_version)
105124
if docker_version&.match?(%r{1[0-9][0-2]?[.]\w+})
106-
if Facter::Core::Execution.which('docker')
107-
docker_json_str = Facter::Core::Execution.execute(
108-
"#{docker_command} info --format '{{json .}}'", timeout: 90
109-
)
110-
begin
111-
docker = JSON.parse(docker_json_str)
112-
docker['network'] = {}
125+
docker_json_str = Facter::Core::Execution.execute(
126+
"#{docker_command} info --format '{{json .}}'", timeout: 90
127+
)
128+
begin
129+
docker = JSON.parse(docker_json_str)
130+
docker['network'] = {}
113131

114-
docker['network']['managed_interfaces'] = {}
115-
network_list = Facter::Core::Execution.execute("#{docker_command} network ls | tail -n +2", timeout: 90)
116-
docker_network_names = []
117-
network_list.each_line { |line| docker_network_names.push line.split[1] }
118-
docker_network_ids = []
119-
network_list.each_line { |line| docker_network_ids.push line.split[0] }
120-
docker_network_names.each do |network|
121-
inspect = JSON.parse(Facter::Core::Execution.execute("#{docker_command} network inspect #{network}", timeout: 90))
122-
docker['network'][network] = inspect[0]
123-
network_id = docker['network'][network]['Id'][0..11]
124-
interfaces.each do |iface|
125-
docker['network']['managed_interfaces'][iface] = network if %r{#{network_id}}.match?(iface)
126-
end
132+
docker['network']['managed_interfaces'] = {}
133+
network_list = Facter::Core::Execution.execute("#{docker_command} network ls | tail -n +2", timeout: 90)
134+
docker_network_names = []
135+
network_list.each_line { |line| docker_network_names.push line.split[1] }
136+
docker_network_ids = []
137+
network_list.each_line { |line| docker_network_ids.push line.split[0] }
138+
docker_network_names.each do |network|
139+
inspect = JSON.parse(Facter::Core::Execution.execute("#{docker_command} network inspect #{network}", timeout: 90))
140+
docker['network'][network] = inspect[0]
141+
network_id = docker['network'][network]['Id'][0..11]
142+
interfaces.each do |iface|
143+
docker['network']['managed_interfaces'][iface] = network if %r{#{network_id}}.match?(iface)
127144
end
128-
docker
129-
rescue JSON::ParserError
130-
nil
131145
end
146+
docker
147+
rescue JSON::ParserError
148+
nil
132149
end
133150
end
134151
end

spec/fixtures/facts/docker_info

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@
131131
},
132132
"ControlAvailable": false,
133133
"Error": "",
134-
"LocalNodeState": "inactive",
134+
"LocalNodeState": "active",
135135
"Managers": 0,
136136
"NodeAddr": "",
137137
"NodeID": "",
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
{
2+
"Architecture": "x86_64",
3+
"BridgeNfIp6tables": true,
4+
"BridgeNfIptables": true,
5+
"CPUSet": true,
6+
"CPUShares": true,
7+
"CgroupDriver": "cgroupfs",
8+
"ClusterAdvertise": "",
9+
"ClusterStore": "",
10+
"ContainerdCommit": {
11+
"Expected": "4ab9917febca54791c5f071a9d1f404867857fcc",
12+
"ID": "4ab9917febca54791c5f071a9d1f404867857fcc"
13+
},
14+
"Containers": 46,
15+
"ContainersPaused": 0,
16+
"ContainersRunning": 5,
17+
"ContainersStopped": 41,
18+
"CpuCfsPeriod": true,
19+
"CpuCfsQuota": true,
20+
"Debug": false,
21+
"DefaultRuntime": "runc",
22+
"DockerRootDir": "/var/lib/docker",
23+
"Driver": "aufs",
24+
"DriverStatus": [
25+
[
26+
"Root Dir",
27+
"/var/lib/docker/aufs"
28+
],
29+
[
30+
"Backing Filesystem",
31+
"extfs"
32+
],
33+
[
34+
"Dirs",
35+
"408"
36+
],
37+
[
38+
"Dirperm1 Supported",
39+
"false"
40+
]
41+
],
42+
"ExperimentalBuild": false,
43+
"HttpProxy": "",
44+
"HttpsProxy": "",
45+
"ID": "VYL2:ZOEC:PG3V:3UFK:EXBT:FR3X:6IY4:ELX4:EQ5B:35C7:6OPZ:EQC6",
46+
"IPv4Forwarding": true,
47+
"Images": 50,
48+
"IndexServerAddress": "https://index.docker.io/v1/",
49+
"InitBinary": "docker-init",
50+
"InitCommit": {
51+
"Expected": "949e6fa",
52+
"ID": "949e6fa"
53+
},
54+
"Isolation": "",
55+
"KernelMemory": true,
56+
"KernelVersion": "3.13.0-115-generic",
57+
"Labels": null,
58+
"LiveRestoreEnabled": false,
59+
"LoggingDriver": "json-file",
60+
"MemTotal": 1977839616,
61+
"MemoryLimit": true,
62+
"NCPU": 2,
63+
"NEventsListener": 0,
64+
"NFd": 52,
65+
"NGoroutines": 50,
66+
"Name": "docker00",
67+
"NoProxy": "",
68+
"OSType": "linux",
69+
"OomKillDisable": true,
70+
"OperatingSystem": "Ubuntu 14.04.5 LTS",
71+
"Plugins": {
72+
"Authorization": null,
73+
"Network": [
74+
"bridge",
75+
"host",
76+
"macvlan",
77+
"null",
78+
"overlay"
79+
],
80+
"Volume": [
81+
"local"
82+
]
83+
},
84+
"RegistryConfig": {
85+
"IndexConfigs": {
86+
"docker.io": {
87+
"Mirrors": null,
88+
"Name": "docker.io",
89+
"Official": true,
90+
"Secure": true
91+
}
92+
},
93+
"InsecureRegistryCIDRs": [
94+
"127.0.0.0/8"
95+
],
96+
"Mirrors": []
97+
},
98+
"RuncCommit": {
99+
"Expected": "54296cf40ad8143b62dbcaa1d90e520a2136ddfe",
100+
"ID": "54296cf40ad8143b62dbcaa1d90e520a2136ddfe"
101+
},
102+
"Runtimes": {
103+
"runc": {
104+
"path": "docker-runc"
105+
}
106+
},
107+
"SecurityOptions": [
108+
"name=apparmor"
109+
],
110+
"ServerVersion": "17.03.1-ce",
111+
"SwapLimit": false,
112+
"Swarm": {
113+
"Cluster": {
114+
"CreatedAt": "0001-01-01T00:00:00Z",
115+
"ID": "",
116+
"Spec": {
117+
"CAConfig": {},
118+
"Dispatcher": {},
119+
"EncryptionConfig": {
120+
"AutoLockManagers": false
121+
},
122+
"Orchestration": {},
123+
"Raft": {
124+
"ElectionTick": 0,
125+
"HeartbeatTick": 0
126+
},
127+
"TaskDefaults": {}
128+
},
129+
"UpdatedAt": "0001-01-01T00:00:00Z",
130+
"Version": {}
131+
},
132+
"ControlAvailable": false,
133+
"Error": "",
134+
"LocalNodeState": "inactive",
135+
"Managers": 0,
136+
"NodeAddr": "",
137+
"NodeID": "",
138+
"Nodes": 0,
139+
"RemoteManagers": null
140+
},
141+
"SystemStatus": null,
142+
"SystemTime": "2017-04-11T01:12:52.292117616-04:00"
143+
}

spec/unit/lib/facter/docker_spec.rb

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,24 @@
44
require 'json'
55

66
describe 'Facter::Util::Fact' do
7+
let(:docker_command) do
8+
if Facter.value(:kernel) == 'windows'
9+
'powershell -NoProfile -NonInteractive -NoLogo -ExecutionPolicy Bypass -c docker'
10+
else
11+
'docker'
12+
end
13+
end
14+
715
before :each do
816
Facter.clear
917
allow(Facter::Core::Execution).to receive(:which).and_call_original
1018
allow(Facter::Core::Execution).to receive(:execute).and_call_original
1119

1220
if Facter.value(:kernel) == 'windows'
13-
docker_command = 'powershell -NoProfile -NonInteractive -NoLogo -ExecutionPolicy Bypass -c docker'
1421
allow(Facter::Core::Execution).to receive(:which).with('dhcpcd').and_return('C:\Windows\dhcpd.exe')
1522
allow(Facter::Core::Execution).to receive(:which).with('route').and_return('C:\Windows\System32\ROUTE.EXE')
1623
allow(Facter::Core::Execution).to receive(:which).with('docker').and_return('C:\Program Files\Docker\docker.exe')
1724
else
18-
docker_command = 'docker'
1925
allow(Facter::Core::Execution).to receive(:which).with('route').and_return('/usr/bin/route')
2026
allow(Facter::Core::Execution).to receive(:which).with('dhcpcd').and_return('/usr/bin/dhcpd')
2127
allow(Facter::Core::Execution).to receive(:which).with('docker').and_return('/usr/bin/docker')
@@ -129,4 +135,25 @@
129135
)
130136
end
131137
end
138+
139+
describe 'docker swarm worker join-token with inactive swarm cluster' do
140+
before :each do
141+
docker_info = File.read(fixtures('facts', 'docker_info_swarm_inactive'))
142+
allow(Facter::Core::Execution).to receive(:execute).with("#{docker_command} info --format '{{json .}}'", timeout: 90).and_return(docker_info)
143+
end
144+
it do
145+
expect(Facter.fact(:docker_worker_join_token).value).to be_nil
146+
end
147+
end
148+
149+
describe 'docker swarm manager join-token with inactive swarm cluster' do
150+
before :each do
151+
docker_info = File.read(fixtures('facts', 'docker_info_swarm_inactive'))
152+
allow(Facter::Core::Execution).to receive(:execute).with("#{docker_command} info --format '{{json .}}'", timeout: 90).and_return(docker_info)
153+
end
154+
155+
it do
156+
expect(Facter.fact(:docker_manager_join_token).value).to be_nil
157+
end
158+
end
132159
end

0 commit comments

Comments
 (0)