Don't instantiate vmmgr on every request. Only reload config.

This commit is contained in:
Disassembler 2018-10-21 11:04:48 +02:00
parent 7abe6af068
commit 867a5d4d69
No known key found for this signature in database
GPG Key ID: 524BD33A0EE29499
2 changed files with 41 additions and 25 deletions

View File

@ -6,6 +6,9 @@ CONF_FILE = '/srv/vm/config.json'
class Config: class Config:
def __init__(self): def __init__(self):
self.load()
def load(self):
with open(CONF_FILE, 'r') as f: with open(CONF_FILE, 'r') as f:
self.data = json.load(f) self.data = json.load(f)

View File

@ -20,7 +20,9 @@ SESSION_KEY = os.urandom(26)
class WSGIApp(object): class WSGIApp(object):
def __init__(self): def __init__(self):
self.vmmgr = VMMgr()
self.jinja_env = Environment(loader=FileSystemLoader('/srv/vm/templates'), autoescape=True, lstrip_blocks=True, trim_blocks=True) self.jinja_env = Environment(loader=FileSystemLoader('/srv/vm/templates'), autoescape=True, lstrip_blocks=True, trim_blocks=True)
self.jinja_env.globals.update(is_app_visible=self.is_app_visible)
self.jinja_env.globals.update(is_service_autostarted=tools.is_service_autostarted) self.jinja_env.globals.update(is_service_autostarted=tools.is_service_autostarted)
self.jinja_env.globals.update(is_service_started=tools.is_service_started) self.jinja_env.globals.update(is_service_started=tools.is_service_started)
@ -29,8 +31,9 @@ class WSGIApp(object):
def wsgi_app(self, environ, start_response): def wsgi_app(self, environ, start_response):
request = Request(environ) request = Request(environ)
# Reload VM Manager config in case it has changed
self.vmmgr.conf.load()
# Enhance request # Enhance request
request.mgr = VMMgr()
request.session = WSGISession(request.cookies, SESSION_KEY) request.session = WSGISession(request.cookies, SESSION_KEY)
request.session.lang = WSGILang() request.session.lang = WSGILang()
# Dispatch request # Dispatch request
@ -81,7 +84,7 @@ class WSGIApp(object):
def render_template(self, template_name, request, **context): def render_template(self, template_name, request, **context):
# Enhance context # Enhance context
context['conf'] = request.mgr.conf context['conf'] = self.vmmgr.conf
context['session'] = request.session context['session'] = request.session
# Render template # Render template
t = self.jinja_env.get_template(template_name) t = self.jinja_env.get_template(template_name)
@ -95,7 +98,7 @@ class WSGIApp(object):
def login_action(self, request): def login_action(self, request):
password = request.form['password'] password = request.form['password']
if tools.adminpwd_verify(password, request.mgr.conf['host']['adminpwd']): if tools.adminpwd_verify(password, self.vmmgr.conf['host']['adminpwd']):
request.session['admin'] = True request.session['admin'] = True
return redirect('/') return redirect('/')
else: else:
@ -106,13 +109,22 @@ class WSGIApp(object):
return redirect('/') return redirect('/')
def portal_view(self, request): def portal_view(self, request):
# Default view. If domain is set to the default dummy domain, redirects to first-run setup instead. # Default portal view. If this is the first run, perform first-run setup.
if self.vmmgr.conf['host']['firstrun']:
# Set user as admin
request.session['admin'] = True
# Disable and save first-run flag
self.vmmgr.conf['host']['firstrun'] = False
self.vmmgr.conf.save()
# Redirect to host setup view
return redirect('/setup-host')
host = tools.compile_url(self.vmmgr.conf['host']['domain'], self.vmmgr.conf['host']['port'], None)
if request.session['admin']: if request.session['admin']:
return self.render_template('portal-admin.html', request) return self.render_template('portal-admin.html', request, host=host)
return self.render_template('portal-user.html', request) return self.render_template('portal-user.html', request, host=host)
def setup_host_view(self, request): def setup_host_view(self, request):
# First-run setup view. # Host setup view.
ex_ipv4 = tools.get_external_ipv4() ex_ipv4 = tools.get_external_ipv4()
ex_ipv6 = tools.get_external_ipv6() ex_ipv6 = tools.get_external_ipv6()
in_ipv4 = tools.get_local_ipv4() in_ipv4 = tools.get_local_ipv4()
@ -130,7 +142,7 @@ class WSGIApp(object):
try: try:
domain = request.form['domain'] domain = request.form['domain']
port = request.form['port'] port = request.form['port']
request.mgr.update_host(domain, port, False) self.vmmgr.update_host(domain, port, False)
server_name = request.environ['HTTP_X_FORWARDED_SERVER_NAME'] server_name = request.environ['HTTP_X_FORWARDED_SERVER_NAME']
url = '{}/setup-host'.format(tools.compile_url(server_name, port)) url = '{}/setup-host'.format(tools.compile_url(server_name, port))
response = self.render_json({'ok': request.session.lang.host_updated(url, url)}) response = self.render_json({'ok': request.session.lang.host_updated(url, url)})
@ -146,8 +158,7 @@ class WSGIApp(object):
def verify_dns_action(self, request): def verify_dns_action(self, request):
# Check if all FQDNs for all applications are resolvable and point to current external IP # Check if all FQDNs for all applications are resolvable and point to current external IP
mgr = request.mgr domains = [self.vmmgr.domain]+['{}.{}'.format(self.vmmgr.conf['apps'][app]['host'], self.vmmgr.domain) for app in self.vmmgr.conf['apps']]
domains = [mgr.domain]+['{}.{}'.format(mgr.conf['apps'][app]['host'], mgr.domain) for app in mgr.conf['apps']]
ipv4 = tools.get_external_ipv4() ipv4 = tools.get_external_ipv4()
ipv6 = tools.get_external_ipv6() ipv6 = tools.get_external_ipv6()
for domain in domains: for domain in domains:
@ -167,9 +178,8 @@ class WSGIApp(object):
def verify_http_action(self, request, **kwargs): def verify_http_action(self, request, **kwargs):
# Check if all applications are accessible from the internet using 3rd party ping service # Check if all applications are accessible from the internet using 3rd party ping service
proto = kwargs['proto'] proto = kwargs['proto']
mgr = request.mgr port = self.vmmgr.port if proto == 'https' else '80'
port = mgr.port if proto == 'https' else '80' domains = [self.vmmgr.domain]+['{}.{}'.format(self.vmmgr.conf['apps'][app]['host'], self.vmmgr.domain) for app in self.vmmgr.conf['apps']]
domains = [mgr.domain]+['{}.{}'.format(mgr.conf['apps'][app]['host'], mgr.domain) for app in mgr.conf['apps']]
for domain in domains: for domain in domains:
url = tools.compile_url(domain, port, proto) url = tools.compile_url(domain, port, proto)
try: try:
@ -191,22 +201,22 @@ class WSGIApp(object):
return self.render_json({'error': request.session.lang.key_file_missing()}) return self.render_json({'error': request.session.lang.key_file_missing()})
request.files['public'].save('/tmp/public.pem') request.files['public'].save('/tmp/public.pem')
request.files['private'].save('/tmp/private.pem') request.files['private'].save('/tmp/private.pem')
request.mgr.install_cert('/tmp/public.pem', '/tmp/private.pem') self.vmmgr.install_cert('/tmp/public.pem', '/tmp/private.pem')
os.unlink('/tmp/public.pem') os.unlink('/tmp/public.pem')
os.unlink('/tmp/private.pem') os.unlink('/tmp/private.pem')
else: else:
request.mgr.request_cert() self.vmmgr.request_cert()
except BadRequest: except BadRequest:
return self.render_json({'error': request.session.lang.malformed_request()}) return self.render_json({'error': request.session.lang.malformed_request()})
except: except:
return self.render_json({'error': request.session.lang.cert_request_error()}) return self.render_json({'error': request.session.lang.cert_request_error()})
url = tools.compile_url(request.mgr.domain, request.mgr.port) url = tools.compile_url(self.vmmgr.domain, self.vmmgr.port)
return self.render_json({'ok': request.session.lang.cert_installed(url, url)}) return self.render_json({'ok': request.session.lang.cert_installed(url, url)})
def update_common_action(self, request): def update_common_action(self, request):
# Update common settings shared between apps - admin e-mail address, Google Maps API key # Update common settings shared between apps - admin e-mail address, Google Maps API key
try: try:
request.mgr.update_common(request.form['email'], request.form['gmaps-api-key']) self.vmmgr.update_common(request.form['email'], request.form['gmaps-api-key'])
except BadRequest: except BadRequest:
return self.render_json({'error': request.session.lang.malformed_request()}) return self.render_json({'error': request.session.lang.malformed_request()})
return self.render_json({'ok': request.session.lang.common_updated()}) return self.render_json({'ok': request.session.lang.common_updated()})
@ -215,9 +225,9 @@ class WSGIApp(object):
# Update application visibility on portal page # Update application visibility on portal page
try: try:
if request.form['value'] == 'true': if request.form['value'] == 'true':
request.mgr.show_tiles(request.form['app']) self.vmmgr.show_tiles(request.form['app'])
else: else:
request.mgr.hide_tiles(request.form['app']) self.vmmgr.hide_tiles(request.form['app'])
except (BadRequest, InvalidValueException): except (BadRequest, InvalidValueException):
return self.render_json({'error': request.session.lang.malformed_request()}) return self.render_json({'error': request.session.lang.malformed_request()})
return self.render_json({'ok': 'ok'}) return self.render_json({'ok': 'ok'})
@ -226,9 +236,9 @@ class WSGIApp(object):
# Update value determining if the app should be automatically started after VM boot # Update value determining if the app should be automatically started after VM boot
try: try:
if request.form['value'] == 'true': if request.form['value'] == 'true':
request.mgr.enable_autostart(request.form['app']) self.vmmgr.enable_autostart(request.form['app'])
else: else:
request.mgr.disable_autostart(request.form['app']) self.vmmgr.disable_autostart(request.form['app'])
except (BadRequest, InvalidValueException): except (BadRequest, InvalidValueException):
return self.render_json({'error': request.session.lang.malformed_request()}) return self.render_json({'error': request.session.lang.malformed_request()})
return self.render_json({'ok': 'ok'}) return self.render_json({'ok': 'ok'})
@ -236,7 +246,7 @@ class WSGIApp(object):
def start_app_action(self, request): def start_app_action(self, request):
# Starts application along with its dependencies # Starts application along with its dependencies
try: try:
request.mgr.start_app(request.form['app']) self.vmmgr.start_app(request.form['app'])
except (BadRequest, InvalidValueException): except (BadRequest, InvalidValueException):
return self.render_json({'error': request.session.lang.malformed_request()}) return self.render_json({'error': request.session.lang.malformed_request()})
except: except:
@ -246,7 +256,7 @@ class WSGIApp(object):
def stop_app_action(self, request): def stop_app_action(self, request):
# Stops application along with its dependencies # Stops application along with its dependencies
try: try:
request.mgr.stop_app(request.form['app']) self.vmmgr.stop_app(request.form['app'])
except (BadRequest, InvalidValueException): except (BadRequest, InvalidValueException):
return self.render_json({'error': request.session.lang.malformed_request()}) return self.render_json({'error': request.session.lang.malformed_request()})
except: except:
@ -254,14 +264,14 @@ class WSGIApp(object):
return self.render_json({'ok': request.session.lang.app_stopped()}) return self.render_json({'ok': request.session.lang.app_stopped()})
def update_password_action(self, request): def update_password_action(self, request):
# Updates password for both HDD encryption (LUKS-on-LVM) and admin account to vmmgr # Updates password for both HDD encryption (LUKS-on-LVM) and web interface admin account
try: try:
if request.form['newpassword'] != request.form['newpassword2']: if request.form['newpassword'] != request.form['newpassword2']:
return self.render_json({'error': request.session.lang.password_mismatch()}) return self.render_json({'error': request.session.lang.password_mismatch()})
if request.form['newpassword'] == '': if request.form['newpassword'] == '':
return self.render_json({'error': request.session.lang.password_empty()}) return self.render_json({'error': request.session.lang.password_empty()})
# No need to explicitly validate old password, update_luks_password will raise exception if it's wrong # No need to explicitly validate old password, update_luks_password will raise exception if it's wrong
request.mgr.update_password(request.form['oldpassword'], request.form['newpassword']) self.vmmgr.update_password(request.form['oldpassword'], request.form['newpassword'])
except: except:
return self.render_json({'error': request.session.lang.bad_password()}) return self.render_json({'error': request.session.lang.bad_password()})
return self.render_json({'ok': request.session.lang.password_changed()}) return self.render_json({'ok': request.session.lang.password_changed()})
@ -278,5 +288,8 @@ class WSGIApp(object):
response.call_on_close(tools.shutdown_vm) response.call_on_close(tools.shutdown_vm)
return response return response
def is_app_visible(self, app):
return app in self.vmmgr.conf['apps'] and self.vmmgr.conf['apps'][app]['visible'] and tools.is_service_started(app)
class InvalidRecordException(Exception): class InvalidRecordException(Exception):
pass pass