From 5e6a2919bfdeeae70a1b4cbdf6341e688e9a575e Mon Sep 17 00:00:00 2001 From: David Darias Date: Mon, 2 Nov 2015 21:27:37 -0500 Subject: [PATCH] Initial commit --- Dockerfile | 14 +++++++ hoster.py | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 Dockerfile create mode 100644 hoster.py diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8110305 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM debian:8.0 + +RUN apt-get update \ + && apt-get install -y --no-install-recommends python3.4 python3-pip \ + && pip3 install docker-py \ + && rm -rf /var/lib/apt/lists/* + +VOLUME ["/dockerfiles"] +ENTRYPOINT ["/dockerfiles/entrypoint.sh"] + +CMD ["python3"] + + + diff --git a/hoster.py b/hoster.py new file mode 100644 index 0000000..304b04e --- /dev/null +++ b/hoster.py @@ -0,0 +1,117 @@ +#!/usr/bin/python3 +from docker import Client +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 + + docker = Client(base_url='unix://%s'%args.socket) + events = docker.events(decode=True) + #get running containers + for c in docker.containers(quiet=True,all=False): + container_id = c["Id"] + container = get_container_data(docker, container_id) + hosts[container_id] = container + + update_hosts_file() + + #listen for events to keep the hosts file updated + for e in events: + + if e["status"]=="start": + container_id = e["id"] + container = get_container_data(docker, container_id) + hosts[container_id] = container + update_hosts_file() + + if e["status"]=="stop": + container_id = e["id"] + hosts.pop(container_id) + update_hosts_file() + + +def get_container_data(docker, container_id): + #extract all the info with the docker api + info = docker.inspect_container(container_id) + container_ip = info["NetworkSettings"]["IPAddress"] + container_name = info["Name"].strip("/") + labels = info["Config"]["Labels"] + domains = set() + if label_name in labels: + domains = domains.union([d.strip() for d in labels[label_name].split()]) + + domains.add("%s.local"%container_name) + + return { "ip": container_ip, "name": container_name, "domains": domains} + + +def update_hosts_file(): + if len(hosts)==0: + print("Removing all hosts before exit...") + else: + print("Updating hosts file with:") + + for k,v in hosts.items(): + print("ip: %s domains: %s"%(v["ip"],v["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 + while lines[-1].strip()=="": lines.pop() + + #append all the domain lines + if len(hosts)>0: + lines.append("\n\n"+enclosing_pattern) + for k,v in hosts.items(): + lines.append("%s %s\n"%(v["ip"]," ".join(v["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() +