2019-09-04 23:37:13 +00:00
package main
import (
2021-02-06 01:45:28 +00:00
"log"
2019-12-04 21:44:35 +00:00
"os"
2021-02-06 01:45:28 +00:00
"os/signal"
"syscall"
2021-05-19 02:29:15 +00:00
"time"
2020-10-30 15:30:03 +00:00
2021-10-08 01:28:04 +00:00
"github.com/TwiN/gatus/v3/config"
"github.com/TwiN/gatus/v3/controller"
2021-10-28 23:35:46 +00:00
"github.com/TwiN/gatus/v3/storage/store"
2021-10-08 01:28:04 +00:00
"github.com/TwiN/gatus/v3/watchdog"
2019-09-04 23:37:13 +00:00
)
func main ( ) {
2021-05-19 02:29:15 +00:00
cfg , err := loadConfiguration ( )
if err != nil {
panic ( err )
}
2021-10-28 23:35:46 +00:00
initializeStorage ( cfg )
2021-05-19 02:29:15 +00:00
start ( cfg )
2021-02-06 01:45:28 +00:00
// Wait for termination signal
2021-05-19 02:29:15 +00:00
signalChannel := make ( chan os . Signal , 1 )
2021-02-06 01:45:28 +00:00
done := make ( chan bool , 1 )
2021-05-19 02:29:15 +00:00
signal . Notify ( signalChannel , os . Interrupt , syscall . SIGTERM )
2021-02-06 01:45:28 +00:00
go func ( ) {
2021-05-19 02:29:15 +00:00
<- signalChannel
2021-03-04 03:31:55 +00:00
log . Println ( "Received termination signal, attempting to gracefully shut down" )
2021-05-19 02:29:15 +00:00
stop ( )
save ( )
2021-02-06 01:45:28 +00:00
done <- true
} ( )
<- done
log . Println ( "Shutting down" )
2019-09-07 01:59:50 +00:00
}
2021-07-09 03:39:12 +00:00
func start ( cfg * config . Config ) {
2021-09-11 05:51:14 +00:00
go controller . Handle ( cfg . Security , cfg . Web , cfg . UI , cfg . Metrics )
2021-07-09 03:39:12 +00:00
watchdog . Monitor ( cfg )
go listenToConfigurationFileChanges ( cfg )
}
2021-05-19 02:29:15 +00:00
func stop ( ) {
watchdog . Shutdown ( )
controller . Shutdown ( )
}
func save ( ) {
2021-10-28 23:35:46 +00:00
if err := store . Get ( ) . Save ( ) ; err != nil {
2021-05-19 02:29:15 +00:00
log . Println ( "Failed to save storage provider:" , err . Error ( ) )
}
}
func loadConfiguration ( ) ( cfg * config . Config , err error ) {
2020-03-08 22:16:39 +00:00
customConfigFile := os . Getenv ( "GATUS_CONFIG_FILE" )
if len ( customConfigFile ) > 0 {
2021-05-19 02:29:15 +00:00
cfg , err = config . Load ( customConfigFile )
2019-12-04 21:44:35 +00:00
} else {
2021-05-19 02:29:15 +00:00
cfg , err = config . LoadDefaultConfiguration ( )
2019-12-04 21:44:35 +00:00
}
2021-05-19 02:29:15 +00:00
return
}
2021-10-28 23:35:46 +00:00
// initializeStorage initializes the storage provider
//
// Q: "TwiN, why are you putting this here? Wouldn't it make more sense to have this in the config?!"
// A: Yes. Yes it would make more sense to have it in the config package. But I don't want to import
// the massive SQL dependencies just because I want to import the config, so here we are.
func initializeStorage ( cfg * config . Config ) {
err := store . Initialize ( cfg . Storage )
if err != nil {
panic ( err )
}
// Remove all EndpointStatus that represent endpoints which no longer exist in the configuration
var keys [ ] string
for _ , endpoint := range cfg . Endpoints {
keys = append ( keys , endpoint . Key ( ) )
}
numberOfEndpointStatusesDeleted := store . Get ( ) . DeleteAllEndpointStatusesNotInKeys ( keys )
if numberOfEndpointStatusesDeleted > 0 {
log . Printf ( "[config][validateStorageConfig] Deleted %d endpoint statuses because their matching endpoints no longer existed" , numberOfEndpointStatusesDeleted )
}
}
2021-05-19 02:29:15 +00:00
func listenToConfigurationFileChanges ( cfg * config . Config ) {
for {
time . Sleep ( 30 * time . Second )
if cfg . HasLoadedConfigurationFileBeenModified ( ) {
log . Println ( "[main][listenToConfigurationFileChanges] Configuration file has been modified" )
2021-12-03 23:20:09 +00:00
stop ( )
time . Sleep ( time . Second ) // Wait a bit to make sure everything is done.
2021-05-19 02:29:15 +00:00
save ( )
updatedConfig , err := loadConfiguration ( )
if err != nil {
if cfg . SkipInvalidConfigUpdate {
log . Println ( "[main][listenToConfigurationFileChanges] Failed to load new configuration:" , err . Error ( ) )
log . Println ( "[main][listenToConfigurationFileChanges] The configuration file was updated, but it is not valid. The old configuration will continue being used." )
// Update the last file modification time to avoid trying to process the same invalid configuration again
cfg . UpdateLastFileModTime ( )
continue
} else {
panic ( err )
}
}
2021-12-03 23:20:09 +00:00
initializeStorage ( updatedConfig )
2021-05-19 02:29:15 +00:00
start ( updatedConfig )
return
}
2019-12-04 21:44:35 +00:00
}
}