From 15e74e4860d9fc4b3dd018b40840fa4060265d02 Mon Sep 17 00:00:00 2001 From: bunkerity Date: Wed, 9 Dec 2020 12:00:54 +0100 Subject: [PATCH] more work on standalone autoconf --- autoconf/config.py | 95 +++++++++++++++++++++++++++------- autoconf/entrypoint.py | 113 +++++++++++++++++++++++++++++------------ 2 files changed, 158 insertions(+), 50 deletions(-) diff --git a/autoconf/config.py b/autoconf/config.py index 70e76e1..6314f89 100644 --- a/autoconf/config.py +++ b/autoconf/config.py @@ -1,25 +1,84 @@ #!/usr/bin/python3 import utils -import subprocess, shutil +import subprocess, shutil, os -def generate(vars) : - vars_defaults = vars.copy() - vars_defaults.update(os.environ) - vars_defaults.update(vars) - subprocess.run(["/opt/entrypoint/site-config.sh", vars["SERVER_NAME"]], env=vars_defaults) - utils.log("Generated config for " + vars["SERVER_NAME"]) +def generate(instances, vars) : + try : + # Get env vars from bunkerized-nginx instances + vars_instances = {} + for instance_id, instance in instances : + for var_value in instance.attrs["Config"]["Env"] : + var = var_value.split("=")[0] + value = var_value.replace(var + "=", "", 1) + vars_instances[var] = value + vars_defaults = vars.copy() + vars_defaults.update(vars_instances) + vars_defaults.update(vars) + # Call site-config.sh to generate the config + proc = subprocess.run(["/opt/site-config.sh", vars["SERVER_NAME"]], env=vars_defaults, capture_output=True) + if proc.returncode == 0 : + return True + except Exception as e : + utils.log("[!] Error while generating config : " + str(e)) + return False -def activate(vars) : - replace_in_file("/etc/nginx/nginx.conf", "}", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n}") - subprocess.run(["/usr/sbin/nginx", "-s", "reload"]) - utils.log("Activated config for " + vars["SERVER_NAME"]) +def activate(instances, vars) : + try : + # Check if file exists + if not os.path.isfile("/etc/nginx/" + vars["SERVER_NAME"] + "/server.conf") : + utils.log("[!] /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf doesn't exist") + return False -def deactivate(vars) : - replace_in_file("/etc/nginx/nginx.conf", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n", "") - subprocess.run(["/usr/sbin/nginx", "-s", "reload"]) - utils.log("Deactivated config for " + vars["SERVER_NAME"]) + # Include the server conf + utils.replace_in_file("/etc/nginx/nginx.conf", "}", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n}") -def remove(vars) : - shutil.rmtree("/etc/nginx/" + vars["SERVER_NAME"]) - utils.log("Removed config for " + vars["SERVER_NAME"]) + # Send SIGHUP to all running instances + for instance_id, instance in instances : + if instance.status == "running" : + try : + instance.kill("SIGHUP") + utils.log("[*] Sent SIGHUP signal to bunkerized-nginx instance " + instance.name + " / " + instance.id + except docker.errors.APIError as e : + utils.log("[!] Docker error while sending SIGHUP signal : " + str(e)) + return True + except Exception as e : + utils.log("[!] Error while activating config : " + str(e)) + return False + +def deactivate(instances, vars) : + try : + # Check if file exists + if not os.path.isfile("/etc/nginx/" + vars["SERVER_NAME"] + "/server.conf") : + utils.log("[!] /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf doesn't exist") + return False + + # Remove the include + utils.replace_in_file("/etc/nginx/nginx.conf", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n", "") + + # Send SIGHUP to all running instances + for instance_id, instance in instances : + if instance.status == "running" : + try : + instance.kill("SIGHUP") + utils.log("[*] Sent SIGHUP signal to bunkerized-nginx instance " + instance.name + " / " + instance.id + except docker.errors.APIError as e : + utils.log("[!] Docker error while sending SIGHUP signal : " + str(e)) + return True + except Exception as e : + utils.log("[!] Error while deactivating config : " + str(e)) + return False + +def remove(instances, vars) : + try : + # Check if file exists + if not os.path.isfile("/etc/nginx/" + vars["SERVER_NAME"] + "/server.conf") : + utils.log("[!] /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf doesn't exist") + return False + + # Remove the folder + shutil.rmtree("/etc/nginx/" + vars["SERVER_NAME"]) + return True + except Exception as e : + utils.log("[!] Error while deactivating config : " + str(e)) + return False diff --git a/autoconf/entrypoint.py b/autoconf/entrypoint.py index 3b5843a..2a601dc 100644 --- a/autoconf/entrypoint.py +++ b/autoconf/entrypoint.py @@ -3,55 +3,104 @@ import utils, config import docker, os, stat, sys -def process(id, event, vars) : - global containers - if event == "create" : - config.generate(vars) - containers.append(id) - elif event == "start" : - config.activate(vars) - elif event == "die" : - config.deactivate(vars) - elif event == "destroy" : - config.remove(vars) - containers.remove(id) +def process(container, event) : + global instances, containers + + # Process instance event + if "bunkerized-nginx.AUTOCONF" in container.labels : + if event == "create" : + instances[container.id] = container + utils.log("[*] bunkerized-nginx instance created : " + container.name + " / " + container.id) + elif event == "start" : + instances[container.id].reload() + utils.log("[*] bunkerized-nginx instance started : " + container.name + " / " + container.id) + elif event == "die" : + instances[container.id].reload() + utils.log("[*] bunkerized-nginx instance stopped : " + container.name + " / " + container.id) + elif event == "destroy" : + del instances[container.id] + utils.log("[*] bunkerized-nginx instance removed : " + container.name + " / " + container.id) + + # Process container event + elif "bunkerized-nginx.SERVER_NAME" in container.labels : + # Convert labels to env vars + vars = { k.replace("bunkerized-nginx.", "", 1) : v for k, v in container.labels.items() if k.startswith("bunkerized-nginx.")} + if event == "create" : + if config.generate(instances, vars) : + utils.log("[*] Generated config for " + vars["SERVER_NAME"]) + containers[container.id] = container + else : + utils.log("[!] Can't generate config for " + vars["SERVER_NAME"]) + elif event == "start" : + containers[container.id].reload() + if config.activate(instances, vars) : + utils.log("[*] Activated config for " + vars["SERVER_NAME"]) + else : + utils.log("[!] Can't activate config for " + vars["SERVER_NAME"]) + elif event == "die" : + containers[container.id].reload() + if config.deactivate(instances, vars) : + utils.log("[*] Deactivated config for " + vars["SERVER_NAME"]) + else : + utils.log("[!] Can't deactivate config for " + vars["SERVER_NAME"]) + elif event == "destroy" : + del containers[container.id] + if config.remove(vars) : + utils.log("[*] Removed config for " + vars["SERVER_NAME"]) + else : + utils.log("[!] Can't remove config for " + vars["SERVER_NAME"]) # Connect to the endpoint endpoint = "/var/run/docker.sock" if not os.path.exists(endpoint) or not stat.S_ISSOCK(os.stat(endpoint).st_mode) : - print("[!] /var/run/docker.sock not found (is it mounted ?)") + utils.log("[!] /var/run/docker.sock not found (is it mounted ?)") sys.exit(1) try : client = docker.DockerClient(base_url='unix:///var/run/docker.sock') except Exception as e : - print("[!] Can't instantiate DockerClient : " + str(e)) + utils.log("[!] Can't instantiate DockerClient : " + str(e)) sys.exit(2) -# Get all bunkerized-nginx instances -instances = [] +# Get all bunkerized-nginx instances and web services created before +instances = {} +containers = {} try : - instances = client.containers.list(all=True, filters={"label" : "bunkerized-nginx.AUTOCONF"}) + before = client.containers.list(all=True, filters={"label" : "bunkerized-nginx.AUTOCONF"}) + client.containers.list(all=True, filters={"label" : "bunkerized-nginx.SERVER_NAME"}) except docker.errors.APIError as e : - print("[!] Docker API error " + str(e)) + utils.log("[!] Docker API error " + str(e)) sys.exit(3) - -# Get all containers created before and do the config -containers = [] -try : - containers_before = client.containers.list(all=True, filters={"label" : "bunkerized-nginx.SERVER_NAME"}) -except docker.errors.APIerror as e : - print("[!] Docker API error " + str(e)) - sys.exit(4) -for container in containers_before : +for container in before : if container.status in ("restarting", "running", "created", "exited") : process(container, "create") - if container.status in ("restarting", "running") : + if container.status == "running" : process(container, "start") # Process events received from Docker try : for event in client.events(decode=True) : - print(event) -except docker.errors.APIerror as e : - print("[!] Docker API error " + str(e)) - sys.exit(5) + + # Process only container events + if event["Type"] != "container" : + continue + + # Get Container object + try : + container = client.containers.get(event["id"]) + except docker.errors.NotFound as e : + continue + + # Check if there is an interesting label + interesting = False + for label in container.labels : + if label in ("bunkerized-nginx.SERVER_NAME", "bunkerized-nginx.AUTOCONF") : + interesting = True + break + if not interesting : + continue + + # Process the event + process(container, event["Action"]) + +except docker.errors.APIError as e : + utils.log("[!] Docker API error " + str(e)) + sys.exit(4)