Merge pull request #9 from swissmakers/dev

rework the reload function. we must change that to restart, because fail2ban does not apply all changes on reload only
This commit is contained in:
Swissmakers GmbH
2025-02-26 17:45:07 +01:00
committed by GitHub
10 changed files with 61 additions and 61 deletions

View File

@@ -43,7 +43,7 @@ type AppSettings struct {
Language string `json:"language"` Language string `json:"language"`
Port int `json:"port"` Port int `json:"port"`
Debug bool `json:"debug"` Debug bool `json:"debug"`
ReloadNeeded bool `json:"reloadNeeded"` RestartNeeded bool `json:"restartNeeded"`
AlertCountries []string `json:"alertCountries"` AlertCountries []string `json:"alertCountries"`
SMTP SMTPSettings `json:"smtp"` SMTP SMTPSettings `json:"smtp"`
@@ -406,25 +406,25 @@ func GetSettings() AppSettings {
return currentSettings return currentSettings
} }
// MarkReloadNeeded sets reloadNeeded = true and saves JSON // MarkRestartNeeded sets restartNeeded = true and saves JSON
func MarkReloadNeeded() error { func MarkRestartNeeded() error {
settingsLock.Lock() settingsLock.Lock()
defer settingsLock.Unlock() defer settingsLock.Unlock()
currentSettings.ReloadNeeded = true currentSettings.RestartNeeded = true
return saveSettings() return saveSettings()
} }
// MarkReloadDone sets reloadNeeded = false and saves JSON // MarkRestartDone sets restartNeeded = false and saves JSON
func MarkReloadDone() error { func MarkRestartDone() error {
settingsLock.Lock() settingsLock.Lock()
defer settingsLock.Unlock() defer settingsLock.Unlock()
currentSettings.ReloadNeeded = false currentSettings.RestartNeeded = false
return saveSettings() return saveSettings()
} }
// UpdateSettings merges new settings with old and sets reloadNeeded if needed // UpdateSettings merges new settings with old and sets restartNeeded if needed
func UpdateSettings(new AppSettings) (AppSettings, error) { func UpdateSettings(new AppSettings) (AppSettings, error) {
settingsLock.Lock() settingsLock.Lock()
defer settingsLock.Unlock() defer settingsLock.Unlock()
@@ -442,15 +442,15 @@ func UpdateSettings(new AppSettings) (AppSettings, error) {
old.Destemail != new.Destemail || old.Destemail != new.Destemail ||
//old.Sender != new.Sender { //old.Sender != new.Sender {
old.Maxretry != new.Maxretry { old.Maxretry != new.Maxretry {
new.ReloadNeeded = true new.RestartNeeded = true
} else { } else {
// preserve previous ReloadNeeded if it was already true // preserve previous RestartNeeded if it was already true
new.ReloadNeeded = new.ReloadNeeded || old.ReloadNeeded new.RestartNeeded = new.RestartNeeded || old.RestartNeeded
} }
// Countries change? Currently also requires a reload // Countries change? Currently also requires a reload
if !equalStringSlices(old.AlertCountries, new.AlertCountries) { if !equalStringSlices(old.AlertCountries, new.AlertCountries) {
new.ReloadNeeded = true new.RestartNeeded = true
} }
currentSettings = new currentSettings = new

View File

@@ -3,8 +3,8 @@
"nav.dashboard": "Dashboard", "nav.dashboard": "Dashboard",
"nav.filter_debug": "Filter-Debug", "nav.filter_debug": "Filter-Debug",
"nav.settings": "Einstellungen", "nav.settings": "Einstellungen",
"reload_banner.message": "Konfiguration geändert!", "restart_banner.message": "Fail2ban Konfiguration geändert! Um Änderungen zu übernehmen bitte: ",
"reload_banner.button": "Fail2ban neu laden", "restart_banner.button": "Service neu starten",
"dashboard.title": "Dashboard", "dashboard.title": "Dashboard",
"dashboard.overview": "Aktive Jails und Blocks Übersicht", "dashboard.overview": "Aktive Jails und Blocks Übersicht",
"dashboard.search_label": "Suche gesperrte IPs", "dashboard.search_label": "Suche gesperrte IPs",

View File

@@ -3,8 +3,8 @@
"nav.dashboard": "Dashboard", "nav.dashboard": "Dashboard",
"nav.filter_debug": "Filter Debug", "nav.filter_debug": "Filter Debug",
"nav.settings": "Istellige", "nav.settings": "Istellige",
"reload_banner.message": "D'Konfiguration isch gänderet worde!", "restart_banner.message": "Fail2ban Konfiguration gänderet! Für d'Änderige z'überneh, bitte: ",
"reload_banner.button": "Fail2ban neu lade", "restart_banner.button": "Service neu starte",
"dashboard.title": "Dashboard", "dashboard.title": "Dashboard",
"dashboard.overview": "Übersicht vo de aktive Jails und Blocks", "dashboard.overview": "Übersicht vo de aktive Jails und Blocks",
"dashboard.search_label": "Suech nach g'sperrte IPs", "dashboard.search_label": "Suech nach g'sperrte IPs",

View File

@@ -3,8 +3,8 @@
"nav.dashboard": "Dashboard", "nav.dashboard": "Dashboard",
"nav.filter_debug": "Filter Debug", "nav.filter_debug": "Filter Debug",
"nav.settings": "Settings", "nav.settings": "Settings",
"reload_banner.message": "Configuration changed!", "restart_banner.message": "Fail2ban configuration changed! To apply the changes, please: ",
"reload_banner.button": "Reload Fail2ban", "restart_banner.button": "Restart Service",
"dashboard.title": "Dashboard", "dashboard.title": "Dashboard",
"dashboard.overview": "Overview active Jails and Blocks", "dashboard.overview": "Overview active Jails and Blocks",
"dashboard.search_label": "Search Banned IPs", "dashboard.search_label": "Search Banned IPs",

View File

@@ -3,8 +3,8 @@
"nav.dashboard": "Panel de control", "nav.dashboard": "Panel de control",
"nav.filter_debug": "Depuración de filtros", "nav.filter_debug": "Depuración de filtros",
"nav.settings": "Configuración", "nav.settings": "Configuración",
"reload_banner.message": La configuración ha sido modificada!", "restart_banner.message": Configuración de Fail2ban modificada! Para aplicar los cambios, por favor: ",
"reload_banner.button": "Recargar Fail2ban", "restart_banner.button": "Reiniciar servicio",
"dashboard.title": "Panel de control", "dashboard.title": "Panel de control",
"dashboard.overview": "Resumen de Jails y Bloqueos activos", "dashboard.overview": "Resumen de Jails y Bloqueos activos",
"dashboard.search_label": "Buscar IP bloqueadas", "dashboard.search_label": "Buscar IP bloqueadas",

View File

@@ -3,8 +3,8 @@
"nav.dashboard": "Tableau de bord", "nav.dashboard": "Tableau de bord",
"nav.filter_debug": "Débogage des filtres", "nav.filter_debug": "Débogage des filtres",
"nav.settings": "Paramètres", "nav.settings": "Paramètres",
"reload_banner.message": "Configuration modifiée!", "restart_banner.message": "Configuration Fail2ban modifiée ! Pour appliquer les changements, veuillez: ",
"reload_banner.button": "Recharger Fail2ban", "restart_banner.button": "Redémarrer le service",
"dashboard.title": "Tableau de bord", "dashboard.title": "Tableau de bord",
"dashboard.overview": "Vue d'ensemble des jails et blocages actifs", "dashboard.overview": "Vue d'ensemble des jails et blocages actifs",
"dashboard.search_label": "Rechercher des IP bloquées", "dashboard.search_label": "Rechercher des IP bloquées",

View File

@@ -3,8 +3,8 @@
"nav.dashboard": "Cruscotto", "nav.dashboard": "Cruscotto",
"nav.filter_debug": "Debug Filtro", "nav.filter_debug": "Debug Filtro",
"nav.settings": "Impostazioni", "nav.settings": "Impostazioni",
"reload_banner.message": "Configurazione modificata!", "restart_banner.message": "Configurazione di Fail2ban modificata! Per applicare le modifiche, per favore: ",
"reload_banner.button": "Ricarica Fail2ban", "restart_banner.button": "Riavvia il servizio",
"dashboard.title": "Cruscotto", "dashboard.title": "Cruscotto",
"dashboard.overview": "Panoramica dei jail e dei blocchi attivi", "dashboard.overview": "Panoramica dei jail e dei blocchi attivi",
"dashboard.search_label": "Cerca IP bloccate", "dashboard.search_label": "Cerca IP bloccate",

View File

@@ -266,7 +266,7 @@ func SetJailFilterConfigHandler(c *gin.Context) {
} }
// Mark reload needed in our UI settings // Mark reload needed in our UI settings
// if err := config.MarkReloadNeeded(); err != nil { // if err := config.MarkRestartNeeded(); err != nil {
// c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) // c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
// return // return
// } // }
@@ -276,7 +276,7 @@ func SetJailFilterConfigHandler(c *gin.Context) {
// Return a simple JSON response without forcing a blocking alert // Return a simple JSON response without forcing a blocking alert
// c.JSON(http.StatusOK, gin.H{ // c.JSON(http.StatusOK, gin.H{
// "message": "Filter updated, reload needed", // "message": "Filter updated, reload needed",
// "reloadNeeded": true, // "restartNeeded": true,
// }) // })
} }
@@ -316,7 +316,7 @@ func UpdateJailManagementHandler(c *gin.Context) {
// c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to reload fail2ban: " + err.Error()}) // c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to reload fail2ban: " + err.Error()})
// return // return
//} //}
if err := config.MarkReloadNeeded(); err != nil { if err := config.MarkRestartNeeded(); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return return
} }
@@ -356,7 +356,7 @@ func UpdateSettingsHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"message": "Settings updated", "message": "Settings updated",
"reloadNeeded": newSettings.ReloadNeeded, "restartNeeded": newSettings.RestartNeeded,
}) })
} }
@@ -428,8 +428,8 @@ func ApplyFail2banSettings(jailLocalPath string) error {
return os.WriteFile(jailLocalPath, []byte(content), 0644) return os.WriteFile(jailLocalPath, []byte(content), 0644)
} }
// ReloadFail2banHandler reloads the Fail2ban service // RestartFail2banHandler reloads the Fail2ban service
func ReloadFail2banHandler(c *gin.Context) { func RestartFail2banHandler(c *gin.Context) {
config.DebugLog("----------------------------") config.DebugLog("----------------------------")
config.DebugLog("ApplyFail2banSettings called (handlers.go)") // entry point config.DebugLog("ApplyFail2banSettings called (handlers.go)") // entry point
@@ -439,18 +439,18 @@ func ReloadFail2banHandler(c *gin.Context) {
// return // return
// } // }
// Then reload // Then restart
if err := fail2ban.ReloadFail2ban(); err != nil { if err := fail2ban.RestartFail2ban(); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return return
} }
// We set reload done in config // We set restart done in config
if err := config.MarkReloadDone(); err != nil { if err := config.MarkRestartDone(); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return return
} }
c.JSON(http.StatusOK, gin.H{"message": "Fail2ban reloaded successfully"}) c.JSON(http.StatusOK, gin.H{"message": "Fail2ban restarted successfully"})
} }
// ******************************************************************* // *******************************************************************

View File

@@ -54,8 +54,8 @@ func RegisterRoutes(r *gin.Engine) {
// TODO: create or generate new filters // TODO: create or generate new filters
// api.POST("/filters/generate", GenerateFilterHandler) // api.POST("/filters/generate", GenerateFilterHandler)
// Reload endpoint // Restart endpoint
api.POST("/fail2ban/reload", ReloadFail2banHandler) api.POST("/fail2ban/restart", RestartFail2banHandler)
// Handle Fail2Ban notifications // Handle Fail2Ban notifications
api.POST("/ban", BanNotificationHandler) api.POST("/ban", BanNotificationHandler)

View File

@@ -45,8 +45,8 @@
height: 4rem; height: 4rem;
} }
/* Reload banner */ /* Restart banner */
#reloadBanner { #restartBanner {
display: none; display: none;
} }
@@ -95,10 +95,10 @@
</nav> </nav>
<!-- ******************************************************************* --> <!-- ******************************************************************* -->
<!-- Reload Banner --> <!-- Restart Banner -->
<div id="reloadBanner" class="bg-warning text-dark p-3 text-center"> <div id="restartBanner" class="bg-warning text-dark p-3 text-center">
<strong data-i18n="reload_banner.message">Configuration changed!</strong> <strong class="p-2" data-i18n="restart_banner.message">Fail2ban configuration changed! To apply the changes, please: </strong>
<button class="btn btn-dark" onclick="reloadFail2ban()" data-i18n="reload_banner.button">Reload Fail2ban</button> <button class="btn btn-dark" onclick="restartFail2ban()" data-i18n="restart_banner.button">Restart Service</button>
</div> </div>
<!-- ******************************************************************* --> <!-- ******************************************************************* -->
@@ -531,7 +531,7 @@
var currentJailForConfig = null; var currentJailForConfig = null;
window.addEventListener('DOMContentLoaded', function() { window.addEventListener('DOMContentLoaded', function() {
showLoading(true); showLoading(true);
checkReloadNeeded(); checkRestartNeeded();
fetchSummary().then(function() { fetchSummary().then(function() {
showLoading(false); showLoading(false);
initializeTooltips(); // Initialize tooltips after fetching and rendering initializeTooltips(); // Initialize tooltips after fetching and rendering
@@ -558,17 +558,17 @@
} }
// Check if there is still a reload of the fail2ban service needed // Check if there is still a reload of the fail2ban service needed
function checkReloadNeeded() { function checkRestartNeeded() {
fetch('/api/settings') fetch('/api/settings')
.then(res => res.json()) .then(res => res.json())
.then(data => { .then(data => {
if (data.reloadNeeded) { if (data.restartNeeded) {
document.getElementById('reloadBanner').style.display = 'block'; document.getElementById('restartBanner').style.display = 'block';
} else { } else {
document.getElementById('reloadBanner').style.display = 'none'; document.getElementById('restartBanner').style.display = 'none';
} }
}) })
.catch(err => console.error('Error checking reloadNeeded:', err)); .catch(err => console.error('Error checking restartNeeded:', err));
} }
// Load dynamically the other pages when navigating in nav // Load dynamically the other pages when navigating in nav
@@ -828,11 +828,11 @@
if (data.error) { if (data.error) {
alert("Error saving config: " + data.error); alert("Error saving config: " + data.error);
} else { } else {
console.log("Filter saved successfully. Reload needed? " + data.reloadNeeded); console.log("Filter saved successfully. Restart needed? " + data.restartNeeded);
var modalEl = document.getElementById('jailConfigModal'); var modalEl = document.getElementById('jailConfigModal');
var modalObj = bootstrap.Modal.getInstance(modalEl); var modalObj = bootstrap.Modal.getInstance(modalEl);
modalObj.hide(); modalObj.hide();
document.getElementById('reloadBanner').style.display = 'block'; document.getElementById('restartBanner').style.display = 'block';
} }
}) })
.catch(function(err) { .catch(function(err) {
@@ -901,7 +901,7 @@
alert("Error saving jail settings: " + data.error); alert("Error saving jail settings: " + data.error);
} else { } else {
// A restart of fail2ban is needed, to enable or disable jails - a reload is not enough // A restart of fail2ban is needed, to enable or disable jails - a reload is not enough
document.getElementById('reloadBanner').style.display = 'block'; document.getElementById('restartBanner').style.display = 'block';
} }
}) })
.catch(function(err) { .catch(function(err) {
@@ -1014,9 +1014,9 @@
} else { } else {
var selectedLang = $('#languageSelect').val(); var selectedLang = $('#languageSelect').val();
loadTranslations(selectedLang); loadTranslations(selectedLang);
console.log("Settings saved successfully. Reload needed? " + data.reloadNeeded); console.log("Settings saved successfully. Restart needed? " + data.restartNeeded);
if (data.reloadNeeded) { if (data.restartNeeded) {
document.getElementById('reloadBanner').style.display = 'block'; document.getElementById('restartBanner').style.display = 'block';
} }
} }
}) })
@@ -1133,19 +1133,19 @@
} }
//******************************************************************* //*******************************************************************
//* Reload fail2ban action : * //* Restart fail2ban action : *
//******************************************************************* //*******************************************************************
function reloadFail2ban() { function restartFail2ban() {
if (!confirm("It can happen that some logs are not parsed during the reload of fail2ban. Reload Fail2ban now?")) return; if (!confirm("Keep in mind that while fail2ban is restarting, logs are not being parsed and no IP addresses are blocked. Restart fail2ban now? This will take some time.")) return;
showLoading(true); showLoading(true);
fetch('/api/fail2ban/reload', { method: 'POST' }) fetch('/api/fail2ban/restart', { method: 'POST' })
.then(function(res) { return res.json(); }) .then(function(res) { return res.json(); })
.then(function(data) { .then(function(data) {
if (data.error) { if (data.error) {
alert("Error: " + data.error); alert("Error: " + data.error);
} else { } else {
document.getElementById('reloadBanner').style.display = 'none'; document.getElementById('restartBanner').style.display = 'none';
return fetchSummary(); return fetchSummary();
} }
}) })