import os from pathlib import Path import signal import subprocess import time import click import sysrsync def _run_shell(cmd): out = subprocess.run( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True ) return out.returncode == 0, out.stdout def quit_on_err(out, print_always=False, additional_info=""): if (not out[0] or print_always) and len(out[1].strip()) > 0: # print out nginx warnings click.echo(out[1], err=True) if not out[0]: if additional_info: click.secho(additional_info, err=True, fg="red") exit(1) def is_keepalived_master(): keepalived_data = Path("/tmp/keepalived.data") keepalived_data.unlink(missing_ok=True) # do not read old data sig = int(os.getenv("KEEPALIVED_DATA_SIGNAL", signal.SIGUSR1)) os.kill(int(Path("/run/keepalived.pid").read_text()), sig) # wait for keepalived for _ in range(10): time.sleep(0.05) if keepalived_data.exists(): break else: raise Exception(f"keepalived did not produce data on signal {sig}") # TODO: could we do better? return "State = MASTER" in Path("/tmp/keepalived.data").read_text() def reload_nginx(): return _run_shell(("nginx", "-s", "reload")) def check_nginx_config(nginx_dir: Path): return _run_shell(("nginx", "-t", "-c", str(nginx_dir / "nginx.conf"))) def run_dehydrated(dehydrated_bin: str): return _run_shell((dehydrated_bin, "-c")) def remote_replication(remote, ssh_key): # Copy nginx config to second server sysrsync.run( source="/etc/nginx/", destination="/etc/nginx/", destination_ssh=remote, private_key=ssh_key, options=["-a", "--delete"], ) # Copy certificates to second server sysrsync.run( source="/etc/autossl/", destination="/etc/autossl/", destination_ssh=remote, private_key=ssh_key, options=["-a", "--delete"], ) def remote_check_nginx_config(remote, ssh_key, nginx_dir: Path): # Check and reload nginx on second server nc = str(nginx_dir / "nginx.conf") return _run_shell(("ssh", "-i", ssh_key, remote, "nginx", "-t", "-c", nc)) def remote_reload_nginx(remote, ssh_key): return _run_shell(("ssh", "-i", ssh_key, remote, "nginx", "-s", "reload"))