From 340323a0b596f2b9985a67a4155e4534efc2795a Mon Sep 17 00:00:00 2001 From: Disassembler Date: Sun, 4 Nov 2018 20:11:45 +0100 Subject: [PATCH] Don't restart apps on update-common, use session messages --- usr/lib/python3.6/vmmgr/actionqueue.py | 1 - usr/lib/python3.6/vmmgr/appmgr.py | 25 +++-- usr/lib/python3.6/vmmgr/wsgiapp.py | 124 ++++++++++++---------- usr/lib/python3.6/vmmgr/wsgilang.py | 4 +- usr/share/vmmgr/static/js/admin.js | 18 ---- usr/share/vmmgr/templates/login.html | 8 +- usr/share/vmmgr/templates/setup-apps.html | 15 +-- 7 files changed, 96 insertions(+), 99 deletions(-) diff --git a/usr/lib/python3.6/vmmgr/actionqueue.py b/usr/lib/python3.6/vmmgr/actionqueue.py index da238eb..de3376f 100644 --- a/usr/lib/python3.6/vmmgr/actionqueue.py +++ b/usr/lib/python3.6/vmmgr/actionqueue.py @@ -13,7 +13,6 @@ class ActionItem: class ActionQueue: def __init__(self): self.actions = {} - # Priority 0 = restart/shutdown, 1 = config update, 2 = apps actions self.queue = deque() self.lock = Lock() self.is_running = False diff --git a/usr/lib/python3.6/vmmgr/appmgr.py b/usr/lib/python3.6/vmmgr/appmgr.py index 2e68779..c3a6130 100644 --- a/usr/lib/python3.6/vmmgr/appmgr.py +++ b/usr/lib/python3.6/vmmgr/appmgr.py @@ -14,6 +14,7 @@ from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.serialization import load_pem_public_key from . import tools +from . import validator PUB_FILE = '/etc/vmmgr/packages.pub' LXC_ROOT = '/var/lib/lxc' @@ -234,20 +235,18 @@ class AppMgr: def update_common_settings(self, email, gmaps_api_key): # Update common configuration values - if email != None: - # Update email - if not validator.is_valid_email(email): - raise validator.InvalidValueException('email', email) - self.conf['common']['email'] = email - if gmaps_api_key != None: - # Update Google Maps API key - self.conf['common']['gmaps-api-key'] = gmaps_api_key - # Save config to file + if not validator.is_valid_email(email): + raise validator.InvalidValueException('email', email) + self.conf['common']['email'] = email + self.conf['common']['gmaps-api-key'] = gmaps_api_key + self.conf.save() + + def update_repo_settings(self, url, user, pwd): + # Update lxc repository configuration + self.conf['repo']['url'] = url + self.conf['repo']['user'] = user + self.conf['repo']['pwd'] = pwd self.conf.save() - for app in self.conf['apps'].copy(): - # Restart currently running apps in order to update their config - if tools.is_service_started(app): - tools.restart_service(app) def hash_file(file_path): sha512 = hashlib.sha512() diff --git a/usr/lib/python3.6/vmmgr/wsgiapp.py b/usr/lib/python3.6/vmmgr/wsgiapp.py index 0417ce9..8e0466f 100644 --- a/usr/lib/python3.6/vmmgr/wsgiapp.py +++ b/usr/lib/python3.6/vmmgr/wsgiapp.py @@ -31,6 +31,37 @@ class WSGIApp(object): self.appmgr.clean_pending_packages() self.jinja_env = Environment(loader=FileSystemLoader('/usr/share/vmmgr/templates'), autoescape=True, lstrip_blocks=True, trim_blocks=True) self.jinja_env.globals.update(is_app_visible=self.is_app_visible) + self.url_map = Map(( + Rule('/', endpoint='portal_view'), + Rule('/login', methods=['GET'], endpoint='login_view'), + Rule('/login', methods=['POST'], endpoint='login_action'), + Rule('/setup-host', redirect_to='/login?redir=setup-host'), + Rule('/setup-apps', redirect_to='/login?redir=setup-apps') + )) + self.admin_url_map = Map(( + Rule('/', endpoint='portal_view'), + Rule('/logout', endpoint='logout_action'), + Rule('/setup-host', endpoint='setup_host_view'), + Rule('/setup-apps', endpoint='setup_apps_view'), + Rule('/update-host', endpoint='update_host_action'), + Rule('/verify-dns', endpoint='verify_dns_action'), + Rule('/verify-https', endpoint='verify_http_action', defaults={'proto': 'https'}), + Rule('/verify-http', endpoint='verify_http_action', defaults={'proto': 'http'}), + Rule('/update-cert', endpoint='update_cert_action'), + Rule('/update-common', endpoint='update_common_action'), + Rule('/update-repo', endpoint='update_repo_action'), + Rule('/update-app-visibility', endpoint='update_app_visibility_action'), + Rule('/update-app-autostart', endpoint='update_app_autostart_action'), + Rule('/start-app', endpoint='start_app_action'), + Rule('/stop-app', endpoint='stop_app_action'), + Rule('/install-app', endpoint='install_app_action'), + Rule('/get-app-status', endpoint='get_app_status_action'), + Rule('/clear-app-status', endpoint='clear_app_status_action'), + Rule('/uninstall-app', endpoint='uninstall_app_action'), + Rule('/update-password', endpoint='update_password_action'), + Rule('/shutdown-vm', endpoint='shutdown_vm_action'), + Rule('/reboot-vm', endpoint='reboot_vm_action') + )) def __call__(self, environ, start_response): return self.wsgi_app(environ, start_response) @@ -42,15 +73,17 @@ class WSGIApp(object): request.session.lang = WSGILang() # Dispatch request response = self.dispatch_request(request) - # Save session if changed - request.session.save(response) return response(environ, start_response) def dispatch_request(self, request): - adapter = self.get_url_map(request.session).bind_to_environ(request.environ) + map = self.admin_url_map if request.session['admin'] else self.url_map + adapter = map.bind_to_environ(request.environ) try: endpoint, values = adapter.match() - return getattr(self, endpoint)(request, **values) + response = getattr(self, endpoint)(request, **values) + # Save session if changed + request.session.save(response) + return response except NotFound as e: # Return custom 404 page response = self.render_html('404.html', request) @@ -59,43 +92,6 @@ class WSGIApp(object): except HTTPException as e: return e - def get_url_map(self, session): - rules = [ - Rule('/', endpoint='portal_view'), - Rule('/login', methods=['GET'], endpoint='login_view', defaults={'redirect': '/'}), - Rule('/login', methods=['POST'], endpoint='login_action'), - Rule('/logout', endpoint='logout_action') - ] - if session['admin']: - rules += [ - Rule('/setup-host', endpoint='setup_host_view'), - Rule('/setup-apps', endpoint='setup_apps_view'), - Rule('/update-host', endpoint='update_host_action'), - Rule('/verify-dns', endpoint='verify_dns_action'), - Rule('/verify-https', endpoint='verify_http_action', defaults={'proto': 'https'}), - Rule('/verify-http', endpoint='verify_http_action', defaults={'proto': 'http'}), - Rule('/update-cert', endpoint='update_cert_action'), - Rule('/update-common', endpoint='update_common_action'), - Rule('/update-repo', endpoint='update_repo_action'), - Rule('/update-app-visibility', endpoint='update_app_visibility_action'), - Rule('/update-app-autostart', endpoint='update_app_autostart_action'), - Rule('/start-app', endpoint='start_app_action'), - Rule('/stop-app', endpoint='stop_app_action'), - Rule('/install-app', endpoint='install_app_action'), - Rule('/get-app-status', endpoint='get_app_status_action'), - Rule('/clear-app-status', endpoint='clear_app_status_action'), - Rule('/uninstall-app', endpoint='uninstall_app_action'), - Rule('/update-password', endpoint='update_password_action'), - Rule('/shutdown-vm', endpoint='shutdown_vm_action'), - Rule('/reboot-vm', endpoint='reboot_vm_action'), - ] - else: - rules += [ - Rule('/setup-host', endpoint='login_view', defaults={'redirect': '/setup-host'}), - Rule('/setup-apps', endpoint='login_view', defaults={'redirect': '/setup-apps'}), - ] - return Map(rules) - def render_template(self, template_name, request, **context): # Enhance context context['conf'] = self.conf @@ -112,17 +108,28 @@ class WSGIApp(object): def render_json(self, data): return Response(json.dumps(data), mimetype='application/json') + def get_session_message(self, request): + # Consume and retrieve message stored in session + if 'msg' not in request.session: + return None + message = request.session['msg'] + del request.session['msg'] + # Message is in format location:type:text + return message.split(':', 3) + def login_view(self, request, **kwargs): - return self.render_html('login.html', request, redirect=kwargs['redirect']) + redir = request.args.get('redir') + message = self.get_session_message(request) + return self.render_html('login.html', request, redir=redir, message=message) def login_action(self, request): password = request.form['password'] - redir_url = request.form['redirect'] + redir = request.form['redir'] if tools.adminpwd_verify(password, self.conf['host']['adminpwd']): request.session['admin'] = True - return redirect(redir_url) - else: - return self.render_html('login.html', request, message=request.session.lang.bad_password()) + return redirect('/{}'.format(redir)) + request.session['msg'] = 'login:error:{}'.format(request.session.lang.bad_password()) + return redirect('/login?redir={}'.format(redir)) if redir else redirect('/login') def logout_action(self, request): request.session.reset() @@ -152,7 +159,8 @@ class WSGIApp(object): pass repo_reachable = bool(self.appmgr.online_packages) table = self.render_setup_apps_table(request) - return self.render_html('setup-apps.html', request, repo_reachable=repo_reachable, table=table) + message = self.get_session_message(request) + return self.render_html('setup-apps.html', request, repo_reachable=repo_reachable, table=table, message=message) def render_setup_apps_table(self, request): lang = request.session.lang @@ -298,20 +306,26 @@ class WSGIApp(object): def update_common_action(self, request): # Update common settings shared between apps - admin e-mail address, Google Maps API key try: - self.appmgr.update_common_settings(request.form['email'], request.form['gmaps-api-key']) + email = request.form['email'] + gmaps_api_key = request.form['gmaps-api-key'] + self.appmgr.update_common_settings(email, gmaps_api_key) + request.session['msg'] = 'common:info:{}'.format(request.session.lang.common_updated()) except BadRequest: return self.render_json({'error': request.session.lang.malformed_request()}) - return self.render_json({'ok': request.session.lang.common_updated()}) + except InvalidValueException: + request.session['msg'] = 'common:error:{}'.format(request.session.lang.invalid_email(email)) + return redirect('/setup-apps') def update_repo_action(self, request): # Update repository URL and credentials try: - self.conf['repo']['url'] = request.form['repourl'] - self.conf['repo']['user'] = request.form['repousername'] - self.conf['repo']['pwd'] = request.form['repopassword'] - self.conf.save() - except: - pass + url = request.form['repourl'] + user = request.form['repousername'] + pwd = request.form['repopassword'] + self.appmgr.update_repo_settings(url, user, pwd) + request.session['msg'] = 'repo:info:{}'.format(request.session.lang.repo_updated()) + except BadRequest: + return self.render_json({'error': request.session.lang.malformed_request()}) return redirect('/setup-apps') def update_app_visibility_action(self, request): diff --git a/usr/lib/python3.6/vmmgr/wsgilang.py b/usr/lib/python3.6/vmmgr/wsgilang.py index f9e425a..a4fb3e5 100644 --- a/usr/lib/python3.6/vmmgr/wsgilang.py +++ b/usr/lib/python3.6/vmmgr/wsgilang.py @@ -17,7 +17,9 @@ class WSGILang: 'key_file_missing': 'Nebyl vybrán soubor se soukromým klíčem.', 'cert_request_error': 'Došlo k chybě při žádosti o certifikát. Zkontrolujte, zda je virtuální stroj dostupný z internetu na portu 80.', 'cert_installed': 'Certifikát byl úspěšně nainstalován. Přejděte na URL {} nebo restartujte webový prohlížeč pro jeho načtení.', - 'common_updated': 'Nastavení aplikací bylo úspěšně změněno.', + 'invalid_email': 'Zadaný e-mail "{}" není platný.', + 'common_updated': 'Nastavení aplikací bylo úspěšně změněno. Pokud je některá z aplikací spuštěna, změny se projeví po jejím restartu.', + 'repo_updated': 'Nastavení distribučního serveru bylo úspěšně změněno.', 'stop_start_error': 'Došlo k chybě při spouštění/zastavování. Zkuste akci opakovat nebo restartuje virtuální stroj.', 'installation_in_progress': 'Probíhá instalace jiného balíku. Vyčkejte na její dokončení.', 'package_manager_error': 'Došlo k chybě při instalaci aplikace. Zkuste akci opakovat nebo restartuje virtuální stroj.', diff --git a/usr/share/vmmgr/static/js/admin.js b/usr/share/vmmgr/static/js/admin.js index 52514d7..1f91b4f 100644 --- a/usr/share/vmmgr/static/js/admin.js +++ b/usr/share/vmmgr/static/js/admin.js @@ -8,7 +8,6 @@ $(function() { $('#verify-http').on('click', verify_http); $('#cert-method').on('change', toggle_cert_method); $('#update-cert').on('submit', update_cert); - $('#update-common').on('submit', update_common); $('#app-manager') .on('click', '.app-visible', update_app_visibility) .on('click', '.app-autostart', update_app_autostart) @@ -107,23 +106,6 @@ function update_cert() { return false; } -function update_common() { - $('#common-submit').hide(); - $('#common-message').hide(); - $('#common-wait').show(); - $.post('/update-common', {'email': $('#email').val(), 'gmaps-api-key': $('#gmaps-api-key').val()}, function(data) { - $('#common-wait').hide(); - if (data.error) { - $('#common-message').attr('class','error').html(data.error).show(); - $('#common-submit').show(); - } else { - $('#common-message').attr('class','info').html(data.ok).show(); - $('#common-submit').show(); - } - }); - return false; -} - function _update_app(item, ev) { var el = $(ev.target); var app = el.closest('tr').data('app'); diff --git a/usr/share/vmmgr/templates/login.html b/usr/share/vmmgr/templates/login.html index f739f63..72c24ac 100644 --- a/usr/share/vmmgr/templates/login.html +++ b/usr/share/vmmgr/templates/login.html @@ -3,7 +3,7 @@ {% block body %}

Přihlášení

-
+ @@ -14,12 +14,12 @@ - +
Jméno:
- {% if message is defined %} -

{{ message }}

+ {% if message %} +

{{ message[2] }}

{% endif %}
diff --git a/usr/share/vmmgr/templates/setup-apps.html b/usr/share/vmmgr/templates/setup-apps.html index b35bbb6..d705c92 100644 --- a/usr/share/vmmgr/templates/setup-apps.html +++ b/usr/share/vmmgr/templates/setup-apps.html @@ -40,6 +40,9 @@   + {% if message and message[0] == 'repo' %} +
{{ message[2] }}
+ {% endif %} @@ -53,23 +56,21 @@ - + - +
E-mail Administrativní e-mail na který budou doručovány zprávy a upozornění z aplikací. Stejná e-mailová adresa bude také využita některými aplikacemi pro odesílání zpráv uživatelům.
Google Maps API klíč API klíč pro službu Google Maps, která je využita některými aplikacemi.
  -
-
-
- Provádí se změna nastavení, prosím čekejte... -
+ {% if message and message[0] == 'common' %} +
{{ message[2] }}
+ {% endif %}