Implement resilient register_app config reload

This commit is contained in:
Disassembler 2019-02-15 14:19:01 +01:00
parent deb56f0c7b
commit 84ccc2bd84
No known key found for this signature in database
GPG Key ID: 524BD33A0EE29499
4 changed files with 31 additions and 8 deletions

View File

@ -9,9 +9,10 @@ subparsers = parser.add_subparsers()
parser_register_app = subparsers.add_parser('register-app') parser_register_app = subparsers.add_parser('register-app')
parser_register_app.set_defaults(action='register-app') parser_register_app.set_defaults(action='register-app')
parser_register_app.add_argument('app') parser_register_app.add_argument('app', help='Application name')
parser_register_app.add_argument('login', nargs='?') parser_register_app.add_argument('host', help='Application subdomain')
parser_register_app.add_argument('password', nargs='?') 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 = subparsers.add_parser('rebuild-issue')
parser_rebuild_issue.set_defaults(action='rebuild-issue') parser_rebuild_issue.set_defaults(action='rebuild-issue')
@ -43,7 +44,7 @@ vmmgr = VMMgr(conf)
lxcmgr = LXCMgr(conf) lxcmgr = LXCMgr(conf)
if args.action == 'register-app': if args.action == 'register-app':
# Used by app install scripts # 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': elif args.action == 'rebuild-issue':
# Used on VM startup # Used on VM startup
vmmgr.rebuild_issue() vmmgr.rebuild_issue()

View File

@ -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: 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: while p.poll() == None:
time.sleep(0.1) time.sleep(0.1)
# Read pipe
data = b'' data = b''
while True: while True:
chunk = os.read(pipe_rfd, 8192) chunk = os.read(pipe_rfd, 8192)
data += chunk data += chunk
if len(chunk) < 8192: if len(chunk) < 8192:
break break
# Parse last apk progress line
progress = data.decode().splitlines()[-1].split('/') progress = data.decode().splitlines()[-1].split('/')
item.data.bytes_downloaded = progress[0] item.data.bytes_downloaded = progress[0]
item.data.bytes_total = progress[1] item.data.bytes_total = progress[1]
# Close pipe
os.close(pipe_rfd) os.close(pipe_rfd)
os.close(pipe_wfd) os.close(pipe_wfd)

View File

@ -17,12 +17,18 @@ class VMMgr:
self.domain = conf['host']['domain'] self.domain = conf['host']['domain']
self.port = conf['host']['port'] self.port = conf['host']['port']
def register_app(self, app, login, password): def register_app(self, app, host, login, password):
# Register newly installed application and its credentials # Register newly installed application, its subdomain and credentials
self.conf['apps'][app] = {'login': login if login else 'N/A', self.conf['apps'][app] = {'host': host,
'login': login if login else 'N/A',
'password': password if password else 'N/A', 'password': password if password else 'N/A',
'visible': False} 'visible': False}
self.conf.save() 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): def update_host(self, domain, port):
# Update domain and port and rebuild all configuration. Web interface calls restart_nginx() in WSGI close handler # Update domain and port and rebuild all configuration. Web interface calls restart_nginx() in WSGI close handler

View File

@ -62,6 +62,9 @@ class WSGIApp:
Rule('/shutdown-vm', endpoint='shutdown_vm_action'), Rule('/shutdown-vm', endpoint='shutdown_vm_action'),
Rule('/reboot-vm', endpoint='reboot_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): def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response) return self.wsgi_app(environ, start_response)
@ -76,7 +79,12 @@ class WSGIApp:
return response(environ, start_response) return response(environ, start_response)
def dispatch_request(self, request): 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) adapter = url_map.bind_to_environ(request.environ)
try: try:
endpoint, values = adapter.match() endpoint, values = adapter.match()
@ -386,5 +394,10 @@ class WSGIApp:
response.call_on_close(self.appmgr.shutdown_vm) response.call_on_close(self.appmgr.shutdown_vm)
return response 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): 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) return app in self.conf['apps'] and self.conf['apps'][app]['visible'] and self.appmgr.is_service_started(app)