Loading monitor.py +51 −20 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ import pathlib import signal import socket import subprocess import tempfile from urllib import parse from typing import Iterable, Set, TextIO, Union Loading @@ -27,6 +28,15 @@ IPAddress = Union[ipaddress.IPv4Address, ipaddress.IPv6Address] logger = logging.getLogger(__name__) class TemporaryDirectory(tempfile.TemporaryDirectory): def __enter__(self): return pathlib.Path(self.name) def __str__(self): return self.name class StreamConfig: """ Manage an Nginx stream configuration Loading Loading @@ -54,14 +64,18 @@ class StreamConfig: self.path.unlink() def add_core_config(engine, opts, nginx_dir=NGINX_BASE): @contextlib.contextmanager def add_core_config(engine, opts): """ Add a minimal Nginx configuration """ template = engine.get_template('nginx.conf') path = pathlib.Path(nginx_dir).joinpath('nginx.conf') with path.open('w') as conf: with opts.nginx_directory as _dir: path = pathlib.Path(_dir) with path.joinpath('nginx.conf').open('w') as conf: conf.writelines(template.stream(**opts.__dict__)) path.joinpath('streams').mkdir(exist_ok=True) yield path def parse_cmdline(argv=None): Loading @@ -76,6 +90,13 @@ def parse_cmdline(argv=None): parser.add_argument('--key', type=pathlib.Path, ) parser.add_argument('--nginx-directory', type=pathlib.Path, default=pathlib.Path(NGINX_BASE), ) parser.add_argument('--dry-run', action='store_true', ) mutex = parser.add_mutually_exclusive_group() mutex.add_argument('--verbose', '-v', Loading @@ -99,6 +120,9 @@ def parse_cmdline(argv=None): elif opts.cert or opts.key: parser.error("--cert and --key are not valid for {opts.monitor_url!r}") if opts.dry_run: opts.nginx_directory = TemporaryDirectory() # Set verbosity logging.root.setLevel( logging.DEBUG if opts.verbose >= 1 else Loading Loading @@ -153,19 +177,8 @@ def main(argv=None): ) env.filters['nginx_addr'] = nginx_addr_format # Minimal starting config add_core_config(env, opts) subprocess.check_call(['nginx', '-vt']) logger.info("generated minimal nginx configuration") # Begin monitoring k8s API for NodePort services cmd = ['kubectl', 'get', 'services', '--all-namespaces', '--watch', '--output', 'json'] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True) logger.info("pid %s: kubectl", proc.pid) with contextlib.ExitStack() as stack: stack.enter_context(proc) if not opts.dry_run: stack.callback(os.kill, os.getpid(), signal.SIGTERM) @stack.push Loading @@ -174,7 +187,24 @@ def main(argv=None): logger.exception("") return True if os.fork(): # Minimal starting config nginx_dir = stack.enter_context(add_core_config(env, opts)) try: subprocess.check_call(['nginx', '-vt']) except FileNotFoundError: logger.warning( "no nginx binary found, not checking configuration files") logger.info("generated minimal nginx configuration in %s", nginx_dir) # Begin monitoring k8s API for NodePort services cmd = ['kubectl', 'get', 'services', '--all-namespaces', '--watch', '--output', 'json'] proc = stack.enter_context( subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True)) stack.callback(proc.terminate) logger.info("pid %s: kubectl", proc.pid) if not opts.dry_run and os.fork(): # Parent becomes nginx logger.info("pid %s: nginx", os.getpid()) os.execvp('nginx', ['nginx']) Loading @@ -185,12 +215,13 @@ def main(argv=None): for uid, stream in filter_services(proc.stdout): if not uid: logging.info("reloading nginx") if not opts.dry_run: subprocess.check_call(['nginx', '-s', 'reload']) continue streams = streams_map[uid] if stream: stream.enable(env) stream.enable(env, nginx_base=nginx_dir) streams.append(stream) logging.info("stream added: %s", stream.name) else: Loading templates/nginx.conf +2 −2 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ error_log /dev/stderr {{ 'warn' }}; include /etc/nginx/modules-enabled/*.conf; include {{ nginx_directory }}/modules-enabled/*.conf; events { worker_connections 768; Loading Loading @@ -40,5 +40,5 @@ http { } stream { include /etc/nginx/streams/*.conf; include {{ nginx_directory }}/streams/*.conf; } Loading
monitor.py +51 −20 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ import pathlib import signal import socket import subprocess import tempfile from urllib import parse from typing import Iterable, Set, TextIO, Union Loading @@ -27,6 +28,15 @@ IPAddress = Union[ipaddress.IPv4Address, ipaddress.IPv6Address] logger = logging.getLogger(__name__) class TemporaryDirectory(tempfile.TemporaryDirectory): def __enter__(self): return pathlib.Path(self.name) def __str__(self): return self.name class StreamConfig: """ Manage an Nginx stream configuration Loading Loading @@ -54,14 +64,18 @@ class StreamConfig: self.path.unlink() def add_core_config(engine, opts, nginx_dir=NGINX_BASE): @contextlib.contextmanager def add_core_config(engine, opts): """ Add a minimal Nginx configuration """ template = engine.get_template('nginx.conf') path = pathlib.Path(nginx_dir).joinpath('nginx.conf') with path.open('w') as conf: with opts.nginx_directory as _dir: path = pathlib.Path(_dir) with path.joinpath('nginx.conf').open('w') as conf: conf.writelines(template.stream(**opts.__dict__)) path.joinpath('streams').mkdir(exist_ok=True) yield path def parse_cmdline(argv=None): Loading @@ -76,6 +90,13 @@ def parse_cmdline(argv=None): parser.add_argument('--key', type=pathlib.Path, ) parser.add_argument('--nginx-directory', type=pathlib.Path, default=pathlib.Path(NGINX_BASE), ) parser.add_argument('--dry-run', action='store_true', ) mutex = parser.add_mutually_exclusive_group() mutex.add_argument('--verbose', '-v', Loading @@ -99,6 +120,9 @@ def parse_cmdline(argv=None): elif opts.cert or opts.key: parser.error("--cert and --key are not valid for {opts.monitor_url!r}") if opts.dry_run: opts.nginx_directory = TemporaryDirectory() # Set verbosity logging.root.setLevel( logging.DEBUG if opts.verbose >= 1 else Loading Loading @@ -153,19 +177,8 @@ def main(argv=None): ) env.filters['nginx_addr'] = nginx_addr_format # Minimal starting config add_core_config(env, opts) subprocess.check_call(['nginx', '-vt']) logger.info("generated minimal nginx configuration") # Begin monitoring k8s API for NodePort services cmd = ['kubectl', 'get', 'services', '--all-namespaces', '--watch', '--output', 'json'] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True) logger.info("pid %s: kubectl", proc.pid) with contextlib.ExitStack() as stack: stack.enter_context(proc) if not opts.dry_run: stack.callback(os.kill, os.getpid(), signal.SIGTERM) @stack.push Loading @@ -174,7 +187,24 @@ def main(argv=None): logger.exception("") return True if os.fork(): # Minimal starting config nginx_dir = stack.enter_context(add_core_config(env, opts)) try: subprocess.check_call(['nginx', '-vt']) except FileNotFoundError: logger.warning( "no nginx binary found, not checking configuration files") logger.info("generated minimal nginx configuration in %s", nginx_dir) # Begin monitoring k8s API for NodePort services cmd = ['kubectl', 'get', 'services', '--all-namespaces', '--watch', '--output', 'json'] proc = stack.enter_context( subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True)) stack.callback(proc.terminate) logger.info("pid %s: kubectl", proc.pid) if not opts.dry_run and os.fork(): # Parent becomes nginx logger.info("pid %s: nginx", os.getpid()) os.execvp('nginx', ['nginx']) Loading @@ -185,12 +215,13 @@ def main(argv=None): for uid, stream in filter_services(proc.stdout): if not uid: logging.info("reloading nginx") if not opts.dry_run: subprocess.check_call(['nginx', '-s', 'reload']) continue streams = streams_map[uid] if stream: stream.enable(env) stream.enable(env, nginx_base=nginx_dir) streams.append(stream) logging.info("stream added: %s", stream.name) else: Loading
templates/nginx.conf +2 −2 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ error_log /dev/stderr {{ 'warn' }}; include /etc/nginx/modules-enabled/*.conf; include {{ nginx_directory }}/modules-enabled/*.conf; events { worker_connections 768; Loading Loading @@ -40,5 +40,5 @@ http { } stream { include /etc/nginx/streams/*.conf; include {{ nginx_directory }}/streams/*.conf; }