From 84ccc2bd8428e2b3a46d17f313594d3678580e68 Mon Sep 17 00:00:00 2001 From: Disassembler Date: Fri, 15 Feb 2019 14:19:01 +0100 Subject: [PATCH] Implement resilient register_app config reload --- usr/bin/vmmgr | 9 +++++---- usr/lib/python3.6/vmmgr/appmgr.py | 3 +++ usr/lib/python3.6/vmmgr/vmmgr.py | 12 +++++++++--- usr/lib/python3.6/vmmgr/wsgiapp.py | 15 ++++++++++++++- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/usr/bin/vmmgr b/usr/bin/vmmgr index ebb2f2d..acd9bc3 100755 --- a/usr/bin/vmmgr +++ b/usr/bin/vmmgr @@ -9,9 +9,10 @@ subparsers = parser.add_subparsers() parser_register_app = subparsers.add_parser('register-app') parser_register_app.set_defaults(action='register-app') -parser_register_app.add_argument('app') -parser_register_app.add_argument('login', nargs='?') -parser_register_app.add_argument('password', nargs='?') +parser_register_app.add_argument('app', help='Application name') +parser_register_app.add_argument('host', help='Application subdomain') +parser_register_app.add_argument('login', nargs='?', help='Admin login') +parser_register_app.add_argument('password', nargs='?', help='Admin password') parser_rebuild_issue = subparsers.add_parser('rebuild-issue') parser_rebuild_issue.set_defaults(action='rebuild-issue') @@ -43,7 +44,7 @@ vmmgr = VMMgr(conf) lxcmgr = LXCMgr(conf) if args.action == 'register-app': # Used by app install scripts - vmmgr.register_app(args.app, args.login, args.password) + vmmgr.register_app(args.app, args.host, args.login, args.password) elif args.action == 'rebuild-issue': # Used on VM startup vmmgr.rebuild_issue() diff --git a/usr/lib/python3.6/vmmgr/appmgr.py b/usr/lib/python3.6/vmmgr/appmgr.py index e0a1d21..1c79d2c 100644 --- a/usr/lib/python3.6/vmmgr/appmgr.py +++ b/usr/lib/python3.6/vmmgr/appmgr.py @@ -70,15 +70,18 @@ class AppMgr: with subprocess.Popen(['apk', '--progress-fd', str(pipe_wfd), '--no-cache', 'add', 'vm-{}@vm'.format(item.key)], pass_fds=[pipe_wfd]) as p: while p.poll() == None: time.sleep(0.1) + # Read pipe data = b'' while True: chunk = os.read(pipe_rfd, 8192) data += chunk if len(chunk) < 8192: break + # Parse last apk progress line progress = data.decode().splitlines()[-1].split('/') item.data.bytes_downloaded = progress[0] item.data.bytes_total = progress[1] + # Close pipe os.close(pipe_rfd) os.close(pipe_wfd) diff --git a/usr/lib/python3.6/vmmgr/vmmgr.py b/usr/lib/python3.6/vmmgr/vmmgr.py index eea2e94..b683609 100644 --- a/usr/lib/python3.6/vmmgr/vmmgr.py +++ b/usr/lib/python3.6/vmmgr/vmmgr.py @@ -17,12 +17,18 @@ class VMMgr: self.domain = conf['host']['domain'] self.port = conf['host']['port'] - def register_app(self, app, login, password): - # Register newly installed application and its credentials - self.conf['apps'][app] = {'login': login if login else 'N/A', + def register_app(self, app, host, login, password): + # Register newly installed application, its subdomain and credentials + self.conf['apps'][app] = {'host': host, + 'login': login if login else 'N/A', 'password': password if password else 'N/A', 'visible': False} self.conf.save() + # Attempt to contact running vmmgr WSGI application to reload config + try: + requests.get('https://127.0.0.1/reload-config', timeout=3) + except: + pass def update_host(self, domain, port): # Update domain and port and rebuild all configuration. Web interface calls restart_nginx() in WSGI close handler diff --git a/usr/lib/python3.6/vmmgr/wsgiapp.py b/usr/lib/python3.6/vmmgr/wsgiapp.py index 26256cd..5b050a7 100644 --- a/usr/lib/python3.6/vmmgr/wsgiapp.py +++ b/usr/lib/python3.6/vmmgr/wsgiapp.py @@ -62,6 +62,9 @@ class WSGIApp: Rule('/shutdown-vm', endpoint='shutdown_vm_action'), Rule('/reboot-vm', endpoint='reboot_vm_action') )) + self.localhost_url_map = Map(( + Rule('/reload-config', endpoint='reload_config_action') + )) def __call__(self, environ, start_response): return self.wsgi_app(environ, start_response) @@ -76,7 +79,12 @@ class WSGIApp: return response(environ, start_response) def dispatch_request(self, request): - url_map = self.admin_url_map if request.session['admin'] else self.url_map + if request.session['admin']: + url_map = self.admin_url_map + elif request.remote_addr in ('127.0.0.1', '::1'): + url_map = self.localhost_url_map + else: + url_map = self.url_map adapter = url_map.bind_to_environ(request.environ) try: endpoint, values = adapter.match() @@ -386,5 +394,10 @@ class WSGIApp: response.call_on_close(self.appmgr.shutdown_vm) return response + def reload_config_action(self, request): + # Reload configuration (called by vmmgr.register_app()) + self.config.load() + return Response(status=204) + def is_app_visible(self, app): return app in self.conf['apps'] and self.conf['apps'][app]['visible'] and self.appmgr.is_service_started(app)