Don't restart apps on update-common, use session messages
This commit is contained in:
parent
8f7cb14305
commit
340323a0b5
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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):
|
||||
|
@ -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 <a href="{}">{}</a> 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.',
|
||||
|
@ -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');
|
||||
|
@ -3,7 +3,7 @@
|
||||
{% block body %}
|
||||
<div class="setup-box">
|
||||
<h2>Přihlášení</h2>
|
||||
<form action="/login" method="post">
|
||||
<form method="post">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Jméno:</td>
|
||||
@ -14,12 +14,12 @@
|
||||
<td><input type="password" name="password"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="hidden" name="redirect" value="{{ redirect }}"></td>
|
||||
<td><input type="hidden" name="redir" value="{{ redir }}"></td>
|
||||
<td><input type="submit" value="Přihlásit"></td>
|
||||
</tr>
|
||||
</table>
|
||||
{% if message is defined %}
|
||||
<p class="error">{{ message }}</p>
|
||||
{% if message %}
|
||||
<p class="{{ message[1] }}">{{ message[2] }}</p>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
|
@ -40,6 +40,9 @@
|
||||
<td> </td>
|
||||
<td colspan="2">
|
||||
<input type="submit" id="repo-submit" value="Nastavit hodnoty">
|
||||
{% if message and message[0] == 'repo' %}
|
||||
<div class="{{ message[1] }}">{{ message[2] }}</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -53,23 +56,21 @@
|
||||
<table>
|
||||
<tr>
|
||||
<td>E-mail</td>
|
||||
<td><input type="text" name="email" id="email" value="{{ conf['common']['email'] }}"></td>
|
||||
<td><input type="text" name="email" value="{{ conf['common']['email'] }}"></td>
|
||||
<td class="remark">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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Google Maps API klíč</td>
|
||||
<td><input type="text" name="gmaps-api-key" id="gmaps-api-key" value="{{ conf['common']['gmaps-api-key'] }}"></td>
|
||||
<td><input type="text" name="gmaps-api-key" value="{{ conf['common']['gmaps-api-key'] }}"></td>
|
||||
<td class="remark">API klíč pro službu Google Maps, která je využita některými aplikacemi.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td colspan="2">
|
||||
<input type="submit" id="common-submit" value="Nastavit hodnoty">
|
||||
<div id="common-message"></div>
|
||||
<div id="common-wait" class="loader-wrap">
|
||||
<div class="loader"></div>
|
||||
<span>Provádí se změna nastavení, prosím čekejte...</span>
|
||||
</div>
|
||||
{% if message and message[0] == 'common' %}
|
||||
<div class="{{ message[1] }}">{{ message[2] }}</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
Loading…
Reference in New Issue
Block a user