Verified Commit cb901c5e authored by Štěpán Henek's avatar Štěpán Henek 🌩

lan: more graceful network restart

parent 3793e4b0
......@@ -18,7 +18,6 @@ from datetime import datetime
import base64
import logging
import time
from urlparse import urlunsplit
from bottle import Bottle, request, template
import bottle
......@@ -31,7 +30,6 @@ from foris.config_handlers import (
)
from foris.nuci import client
from foris.nuci.client import filters
from foris.nuci.exceptions import ConfigRestoreError
from foris.nuci.helpers import make_notification_title, get_wizard_progress
from foris.nuci.preprocessors import preproc_disabled_to_agreed
from foris.utils import login_required, messages, is_safe_redirect, contract_valid
......@@ -536,7 +534,10 @@ def config_page_post(page_name):
if request.is_xhr:
if request.POST.pop("update", None):
# if update was requested, just render the page - otherwise handle actions as usual
return config_page.render(is_xhr=True)
pass
else:
config_page.save()
return config_page.render(is_xhr=True)
try:
if config_page.save():
bottle.redirect(request.fullpath)
......
......@@ -104,6 +104,7 @@ class LanHandler(BaseConfigHandler):
guest_network_section.add_field(
Textbox, name="guest_network_ipaddr", label=_("Router IP in guest network"),
default=DEFAULT_GUEST_IP,
validators=validators.IPv4(),
hint=_(
"Router's IP address in the guest network. It is necessary that "
"the guest network IPs are different from other networks "
......@@ -113,6 +114,7 @@ class LanHandler(BaseConfigHandler):
guest_network_section.add_field(
Textbox, name="guest_network_netmask", label=_("Guest network netmask"),
default=DEFAULT_GUEST_MASK,
validators=validators.IPv4(),
hint=_("Network mask of the guest network.")
).requires("guest_network_enabled", True)
......
......@@ -53,6 +53,7 @@ Foris.initialize = function () {
Foris.initParsley();
Foris.initLanChangeDetection();
Foris.initLanFormOverride();
Foris.initClickableHints();
Foris.initSmoothScrolling();
Foris.applySVGFallback();
......@@ -97,6 +98,23 @@ Foris.initParsley = function () {
};
Foris.initLanFormOverride = function () {
var lanForm = $("#form-lan-buttons").parents("form:first");
lanForm.submit(function(event) {
event.preventDefault();
$.ajax({
type: "POST",
url: lanForm.attr("action"),
data: lanForm.serialize(),
success: function(data) {
// Nothing to be done here...
},
error: function(jqXHR, textStatu, errorThrown) {
}
});
});
}
Foris.initLanChangeDetection = function () {
var lanIpChanged = false;
$(document).on("change paste", "[name=lan_ipaddr]", function () {
......@@ -156,6 +174,9 @@ Foris.applySVGFallback = function() {
Foris.WS = {
maintain: function(msg) {
Foris.handleReboot(msg.data.new_ips);
},
lan: function(msg) {
Foris.handleLanRestart(msg.data.ip);
}
};
......@@ -595,7 +616,8 @@ Foris.initNotificationTestAlert = function () {
});
};
Foris.waitForReachable = function(urls, data, handler_function) {
Foris.waitForReachable = function(urls, data, handler_function, timeout) {
var timeout = timeout || 1000;
// wait function generator
var genWaitForUrl = function(url) {
var stored_data = data;
......@@ -611,15 +633,15 @@ Foris.waitForReachable = function(urls, data, handler_function) {
headers: {'X-Requested-With': 'XMLHttpRequest'},
success: function(data, text, jqXHR) {
if (!stored_handler(url, jqXHR)) {
setTimeout(upper_function, 5000); // retry calling self later
setTimeout(upper_function, timeout); // retry calling self later
}
},
error: function(jqXHR, text, error) {
if (!stored_handler(url, jqXHR)) {
setTimeout(upper_function, 5000); // retry calling self later
setTimeout(upper_function, timeout); // retry calling self later
}
},
timeout: 5000,
timeout: timeout,
});
};
}
......@@ -630,7 +652,8 @@ Foris.waitForReachable = function(urls, data, handler_function) {
}
};
Foris.waitForUnreachable = function(url, callback) {
Foris.waitForUnreachable = function(url, callback, timeout) {
var timeout = timeout || 1000;
// wait till current address is available
var url = url;
var unreachableFunction = function() {
......@@ -642,12 +665,12 @@ Foris.waitForUnreachable = function(url, callback) {
crossDomain: true,
headers: {'X-Requested-With': 'XMLHttpRequest'},
success: function(data, text, jqXHR) {
setTimeout(unreachableFunction, 5000);
setTimeout(unreachableFunction, timeout);
},
error: function(xhr, text, error) {
callback(xhr, text, error);
},
timeout: 5000,
timeout: timeout,
});
};
unreachableFunction();
......@@ -668,6 +691,75 @@ function extractPathName(src) {
return a.pathname;
}
function extractHost(src) {
var a = document.createElement("a");
a.href = src;
return a.host;
}
Foris.handleReboot = function(ips) {
$('#rebooting-notice').show("slow");
$('#reboot-required-notice').hide("slow");
var port = window.location.port == "" ? "" : ":" + window.location.port;
var urls = [window.location.protocol + "//" + window.location.hostname + port + Foris.pingPath];
for (var i = 0; i < ips.length; i++) {
urls.push(window.location.protocol + "//" + ips[i] + port + Foris.pingPath);
}
var rebootDoneCallback = function(url, jqXHR) {
if (jqXHR.status == 0) {
return false;
}
if (jqXHR.status == 200) {
if (jqXHR.responseJSON && jqXHR.responseJSON.loginUrl) {
window.location = jqXHR.responseJSON.loginUrl;
}
}
return false;
}
// start the machinery
Foris.waitForUnreachable(window.location.pathname, function (xhr, text, error) {
var pathname = window.location.pathname;
Foris.waitForReachable(urls, {next: pathname}, rebootDoneCallback, 5000);
});
};
Foris.handleLanRestart = function(ip) {
$('#network-restart-notice').show("slow");
var port = window.location.port == "" ? "" : ":" + window.location.port;
var protocol = window.location.protocol;
var pathname = window.location.pathname;
var search = window.location.search;
var urls = [
window.location.protocol + "//" + window.location.hostname + port + Foris.pingPath,
window.location.protocol + "//" + ip + port + Foris.pingPath
];
var restartLanDoneCallback = function(url, jqXHR) {
if (jqXHR.status == 0) {
return false;
}
if (jqXHR.status == 200) {
//if (jqXHR.responseJSON && jqXHR.responseJSON.loginUrl) {
// window.location = protocol + "//" + extractHost(url) + pathname + search;
//}
if (jqXHR.responseJSON && jqXHR.responseJSON.loginUrl) {
window.location = jqXHR.responseJSON.loginUrl;
}
}
}
// start the machinery
Foris.waitForUnreachable(window.location.pathname, function (xhr, text, error) {
var pathname = window.location.pathname;
Foris.waitForReachable(urls, {next: pathname}, restartLanDoneCallback);
});
};
$(document).ready(function () {
Foris.initialize();
......
......@@ -100,7 +100,7 @@ body
.sidebar-cleaner
clear: left
#rebooting-notice
.main-warning-notice
+rounded-borders
padding: 1em 1em 1em 1em
......
......@@ -32,7 +32,11 @@
</div>
<div id="content-wrap">
<div id="content">
<div id="rebooting-notice">
<div id="network-restart-notice" class="main-warning-notice">
<img src="{{ static("img/loader.gif") }}" alt="{{ trans("Network is restarting...") }}" title="{{ trans("Network is restarting...") }}">
<span>{{ trans("Your network is being restarted. Wait, please...") }}</span>
</div>
<div id="rebooting-notice" class="main-warning-notice">
<img src="{{ static("img/loader.gif") }}" alt="{{ trans("Rebooting...") }}" title="{{ trans("Rebooting...") }}">
<span>{{ trans("Your router is being rebooted.") }}</span>
</div>
......
......@@ -26,11 +26,11 @@
%for field in form.active_fields:
%include("_field.tpl", field=field)
%end
<div class="form-buttons">
<div id="{{ 'form-%s-buttons' % form.name }}" class="form-buttons">
<a href="{{ request.fullpath }}" class="button grayed">{{ trans("Discard changes") }}</a>
<button type="submit" name="send" class="button">{{ trans("Save changes") }}</button>
</div>
</form>
%if not defined('is_xhr'):
</div>
%end
\ No newline at end of file
%end
......@@ -11,32 +11,4 @@ Foris.messages.confirmRestart = "{{ trans('Are you sure you want to restart the
Foris.messages.confirmRestartExtra = "{{ trans('\\nRemaining unread messages (%UNREAD%) will be deleted.') }}";
Foris.messages.unsavedNotificationsAlert = "{{ trans('There are some unsaved changes in the notifications settings.\\nDo you want to discard them and test the notifications with the old settings?') }}";
Foris.handleReboot = function(ips) {
$('#rebooting-notice').show("slow");
$('#reboot-required-notice').hide("slow");
var port = window.location.port == "" ? "" : ":" + window.location.port;
var ping_path = "{{ url('ping') }}"
var urls = [window.location.protocol + "//" + window.location.hostname + port + ping_path];
for (var i = 0; i < ips.length; i++) {
urls.push(window.location.protocol + "//" + ips[i] + port + ping_path);
}
var rebootDoneCallback = function(url, jqXHR) {
if (jqXHR.status == 0) {
return false;
}
if (jqXHR.status == 200) {
if (jqXHR.responseJSON && jqXHR.responseJSON.loginUrl) {
window.location = jqXHR.responseJSON.loginUrl;
}
}
return false;
}
// start the machinery
Foris.waitForUnreachable(window.location.pathname, function (xhr, text, error) {
var pathname = window.location.pathname;
Foris.waitForReachable(urls, {next: pathname}, rebootDoneCallback);
});
};
Foris.pingPath = "{{ url('ping') }}";
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment