diff --git a/configure-ambassadors.py b/configure-ambassadors.py new file mode 100755 index 00000000..50979378 --- /dev/null +++ b/configure-ambassadors.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +import os +import subprocess +import sys +import yaml + +stack = yaml.load(open(sys.argv[1])) + +project_name = os.path.basename(os.path.realpath(".")) + +# Get all services and backends in our compose application +containers_data = subprocess.check_output([ + "docker", "ps", + "--filter", "label=com.docker.compose.project={}".format(project_name), + "--format", '{{ .ID }} ' + '{{ .Label "com.docker.compose.service" }} ' + '{{ .Ports }}', +]) + +# Build list of backends +frontend_ports = dict() +backends = dict() +for container in containers_data.split('\n'): + if not container: + continue + # TODO: support services with multiple ports! + container_id, service_name, port = container.split(' ') + if not port: + continue + backend, frontend = port.split("->") + backend_addr, backend_port = backend.split(':') + frontend_port, frontend_proto = frontend.split('/') + # TODO: deal with udp (mostly skip it?) + assert frontend_proto == "tcp" + # TODO: check inconsistencies between port mappings + frontend_ports[service_name] = frontend_port + if service_name not in backends: + backends[service_name] = [] + backends[service_name].append((backend_addr, backend_port)) + +# Get all existing ambassadors for this application +ambassadors_data = subprocess.check_output([ + "docker", "ps", + "--filter", "label=ambassador.project={}".format(project_name), + "--format", '{{ .ID }} ' + '{{ .Label "ambassador.service" }} ' + '{{ .Label "ambassador.bindaddr" }}', +]) + +# Update ambassadors +for ambassador in ambassadors_data.split('\n'): + if not ambassador: + continue + ambassador_id, service_name, bind_address = ambassador.split() + print("Updating configuration for {}/{} -> {}:{} -> {}" + .format(service_name, ambassador_id, + bind_address, frontend_ports[service_name], + backends[service_name])) + command = [ + "docker", "run", "--rm", "--volumes-from", ambassador_id, + "jpetazzo/hamba", "reconfigure", + "{}:{}".format(bind_address, frontend_ports[service_name]) + ] + for backend_addr, backend_port in backends[service_name]: + command.extend([backend_addr, backend_port]) + print command + subprocess.check_call(command) diff --git a/connect-services.py b/connect-services.py deleted file mode 100755 index 35422253..00000000 --- a/connect-services.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python - -import os -import subprocess -import sys -import yaml - -stack = yaml.load(open(sys.argv[1])) - -ports = yaml.load(open("ports.yml")) - -project_name = os.path.basename(os.path.realpath(".")) - -ambassadors = [] - -service_instances = {} - -# Generate container names for all instances -for service_name in stack: - service_instances[service_name] = [] - n = 0 - while True: - n += 1 - try: - container_name = "{}_{}_{}".format(project_name, service_name, n) - subprocess.check_call( - [ "docker", "inspect", container_name ], - stdout=-1, stderr=-1 - ) - service_instances[service_name].append(container_name) - except subprocess.CalledProcessError: - break - -for service_name, service in stack.items(): - extra_hosts = service.get("extra_hosts", {}) - for link_name, link_addr in extra_hosts.items(): - if link_name not in ports: - print("# Skipping link {} in service {} " - "(no port mapping defined). " - "Your code will probably break." - .format(link, service_name)) - continue - port = str(ports[link_name]) - endpoints = [] - for container_name in service_instances[link_name]: - endpoint = subprocess.check_output( - ["docker", "port", container_name, port] - ) - endpoints.append(endpoint.strip()) - for container_name in service_instances[service_name]: - ambassador = {} - ambassador["image"] = "jpetazzo/hamba" - ambassador["net"] = "container:"+container_name - command = "{}:{}".format(link_addr, port) - for endpoint in endpoints: - command = command + " {} {}".format(*endpoint.split(':')) - ambassador["command"] = command - n = len(ambassadors) - ambassador["name"] = "amba{}".format(n) - ambassadors.append(ambassador) - -for service_name, service in stack.items(): - for container_name in service_instances[service_name]: - print("docker exec {} sh -c 'sed /^127.127/d /etc/hosts >/tmp/hosts && cat /tmp/hosts >/etc/hosts && rm /tmp/hosts'" - .format(container_name)) - extra_hosts = service.get("extra_hosts", {}) - for link_name, link_addr in extra_hosts.items(): - print("docker exec {} sh -c 'echo {} {} >> /etc/hosts'" - .format(container_name, link_addr, link_name)) - -for amba in ambassadors: - print("docker run -d --name {name} --net {net} {image} {command}".format(**amba)) - diff --git a/create-ambassadors.py b/create-ambassadors.py new file mode 100755 index 00000000..6c2e7870 --- /dev/null +++ b/create-ambassadors.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +import os +import subprocess +import sys +import yaml + +stack = yaml.load(open(sys.argv[1])) + +project_name = os.path.basename(os.path.realpath(".")) + +# Get all services in our compose application +containers_data = subprocess.check_output([ + "docker", "ps", + "--filter", "label=com.docker.compose.project={}".format(project_name), + "--format", '{{ .ID }} {{ .Label "com.docker.compose.service" }}', +]) + +# Get all existing ambassadors for this application +ambassadors_data = subprocess.check_output([ + "docker", "ps", + "--filter", "label=ambassador.project={}".format(project_name), + "--format", '{{ .ID }} ' + '{{ .Label "ambassador.container" }} ' + '{{ .Label "ambassador.service" }}', +]) + +# Build a set of existing ambassadors +ambassadors = dict() +for ambassador in ambassadors_data.split('\n'): + if not ambassador: + continue + ambassador_id, container_id, linked_service = ambassador.split() + ambassadors[container_id, linked_service] = ambassador_id + +# Start the missing ambassadors +for container in containers_data.split('\n'): + if not container: + continue + container_id, service_name = container.split() + extra_hosts = stack[service_name].get("extra_hosts", {}) + for linked_service, bind_address in extra_hosts.items(): + description = "Ambassador {}/{}/{}".format( + service_name, container_id, linked_service) + ambassador_id = ambassadors.get((container_id, linked_service)) + if ambassador_id: + print("{} already exists: {}".format(description, ambassador_id)) + else: + print("{} not found, creating it:".format(description)) + subprocess.check_call([ + "docker", "run", "-d", + "--net", "container:{}".format(container_id), + "--label", "ambassador.project={}".format(project_name), + "--label", "ambassador.container={}".format(container_id), + "--label", "ambassador.service={}".format(linked_service), + "--label", "ambassador.bindaddr={}".format(bind_address), + "jpetazzo/hamba", "run" + ]) + diff --git a/delete-ambassadors.sh b/delete-ambassadors.sh new file mode 100755 index 00000000..ae5c637a --- /dev/null +++ b/delete-ambassadors.sh @@ -0,0 +1,3 @@ +#!/bin/sh +docker ps -q --filter label=ambassador.project=dockercoins | +xargs docker rm -f diff --git a/destroy-amba.sh b/destroy-amba.sh deleted file mode 100755 index 5aeb2c29..00000000 --- a/destroy-amba.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -N=0 -while docker rm -f amba$N; do - N=$(($N+1)) -done diff --git a/unlink-services.py b/link-to-ambassadors.py similarity index 100% rename from unlink-services.py rename to link-to-ambassadors.py