-
Notifications
You must be signed in to change notification settings - Fork 57
/
hoster.py
146 lines (113 loc) · 4.47 KB
/
hoster.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/python3
import docker
import argparse
import shutil
import signal
import time
import sys
import os
label_name = "hoster.domains"
enclosing_pattern = "#-----------Docker-Hoster-Domains----------\n"
hosts_path = "/tmp/hosts"
hosts = {}
def signal_handler(signal, frame):
global hosts
hosts = {}
update_hosts_file()
sys.exit(0)
def main():
# register the exit signals
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
args = parse_args()
global hosts_path
hosts_path = args.file
dockerClient = docker.APIClient(base_url='unix://%s' % args.socket)
events = dockerClient.events(decode=True)
#get running containers
for c in dockerClient.containers(quiet=True, all=False):
container_id = c["Id"]
container = get_container_data(dockerClient, container_id)
hosts[container_id] = container
update_hosts_file()
#listen for events to keep the hosts file updated
for e in events:
if e["Type"]!="container":
continue
status = e["status"]
if status =="start":
container_id = e["id"]
container = get_container_data(dockerClient, container_id)
hosts[container_id] = container
update_hosts_file()
if status=="stop" or status=="die" or status=="destroy":
container_id = e["id"]
if container_id in hosts:
hosts.pop(container_id)
update_hosts_file()
if status=="rename":
container_id = e["id"]
if container_id in hosts:
container = get_container_data(dockerClient, container_id)
hosts[container_id] = container
update_hosts_file()
def get_container_data(dockerClient, container_id):
#extract all the info with the docker api
info = dockerClient.inspect_container(container_id)
container_hostname = info["Config"]["Hostname"]
container_name = info["Name"].strip("/")
container_ip = info["NetworkSettings"]["IPAddress"]
if info["Config"]["Domainname"]:
container_hostname = container_hostname + "." + info["Config"]["Domainname"]
result = []
for values in info["NetworkSettings"]["Networks"].values():
if not values["Aliases"]:
continue
result.append({
"ip": values["IPAddress"] ,
"name": container_name,
"domains": set(values["Aliases"] + [container_name, container_hostname])
})
if container_ip:
result.append({"ip": container_ip, "name": container_name, "domains": [container_name, container_hostname ]})
return result
def update_hosts_file():
if len(hosts)==0:
print("Removing all hosts before exit...")
else:
print("Updating hosts file with:")
for id,addresses in hosts.items():
for addr in addresses:
print("ip: %s domains: %s" % (addr["ip"], addr["domains"]))
#read all the lines of thge original file
lines = []
with open(hosts_path,"r+") as hosts_file:
lines = hosts_file.readlines()
#remove all the lines after the known pattern
for i,line in enumerate(lines):
if line==enclosing_pattern:
lines = lines[:i]
break;
#remove all the trailing newlines on the line list
if lines:
while lines[-1].strip()=="": lines.pop()
#append all the domain lines
if len(hosts)>0:
lines.append("\n\n"+enclosing_pattern)
for id, addresses in hosts.items():
for addr in addresses:
lines.append("%s %s\n"%(addr["ip"]," ".join(addr["domains"])))
lines.append("#-----Do-not-add-hosts-after-this-line-----\n\n")
#write it on the auxiliar file
aux_file_path = hosts_path+".aux"
with open(aux_file_path,"w") as aux_hosts:
aux_hosts.writelines(lines)
#replace etc/hosts with aux file, making it atomic
shutil.move(aux_file_path, hosts_path)
def parse_args():
parser = argparse.ArgumentParser(description='Synchronize running docker container IPs with host /etc/hosts file.')
parser.add_argument('socket', type=str, nargs="?", default="tmp/docker.sock", help='The docker socket to listen for docker events.')
parser.add_argument('file', type=str, nargs="?", default="/tmp/hosts", help='The /etc/hosts file to sync the containers with.')
return parser.parse_args()
if __name__ == '__main__':
main()