feat: Implement push-based external endpoints (#724)

* refactor: Move SSH outside of endpoint.go
* refactor: Use pointers for Alert receivers
* feat: Implement push-based external endpoints
* Fix failing tests
* Validate external endpoints on start
* Add tests for external endpoints
* refactor some error equality checks
* Improve docs and refactor some code
* Fix UI-related issues with external endpoints
This commit is contained in:
TwiN
2024-04-08 21:00:40 -04:00
committed by GitHub
parent cacfbc0185
commit f54c45e20e
28 changed files with 808 additions and 189 deletions

View File

@ -67,15 +67,18 @@ type Config struct {
// Disabling this may lead to inaccurate response times
DisableMonitoringLock bool `yaml:"disable-monitoring-lock,omitempty"`
// Security Configuration for securing access to Gatus
// Security is the configuration for securing access to Gatus
Security *security.Config `yaml:"security,omitempty"`
// Alerting Configuration for alerting
// Alerting is the configuration for alerting providers
Alerting *alerting.Config `yaml:"alerting,omitempty"`
// Endpoints List of endpoints to monitor
// Endpoints is the list of endpoints to monitor
Endpoints []*core.Endpoint `yaml:"endpoints,omitempty"`
// ExternalEndpoints is the list of all external endpoints
ExternalEndpoints []*core.ExternalEndpoint `yaml:"external-endpoints,omitempty"`
// Storage is the configuration for how the data is stored
Storage *storage.Config `yaml:"storage,omitempty"`
@ -100,7 +103,6 @@ type Config struct {
}
func (config *Config) GetEndpointByKey(key string) *core.Endpoint {
// TODO: Should probably add a mutex here to prevent concurrent access
for i := 0; i < len(config.Endpoints); i++ {
ep := config.Endpoints[i]
if util.ConvertGroupAndEndpointNameToKey(ep.Group, ep.Name) == key {
@ -110,9 +112,19 @@ func (config *Config) GetEndpointByKey(key string) *core.Endpoint {
return nil
}
func (config *Config) GetExternalEndpointByKey(key string) *core.ExternalEndpoint {
for i := 0; i < len(config.ExternalEndpoints); i++ {
ee := config.ExternalEndpoints[i]
if util.ConvertGroupAndEndpointNameToKey(ee.Group, ee.Name) == key {
return ee
}
}
return nil
}
// HasLoadedConfigurationBeenModified returns whether one of the file that the
// configuration has been loaded from has been modified since it was last read
func (config Config) HasLoadedConfigurationBeenModified() bool {
func (config *Config) HasLoadedConfigurationBeenModified() bool {
lastMod := config.lastFileModTime.Unix()
fileInfo, err := os.Stat(config.configPath)
if err != nil {
@ -125,7 +137,7 @@ func (config Config) HasLoadedConfigurationBeenModified() bool {
}
return nil
})
return err == errEarlyReturn
return errors.Is(err, errEarlyReturn)
}
return !fileInfo.ModTime().IsZero() && config.lastFileModTime.Unix() < fileInfo.ModTime().Unix()
}
@ -135,7 +147,7 @@ func (config *Config) UpdateLastFileModTime() {
config.lastFileModTime = time.Now()
}
// LoadConfiguration loads the full configuration composed from the main configuration file
// LoadConfiguration loads the full configuration composed of the main configuration file
// and all composed configuration files
func LoadConfiguration(configPath string) (*Config, error) {
var configBytes []byte
@ -241,6 +253,9 @@ func parseAndValidateConfigBytes(yamlBytes []byte) (config *Config, err error) {
if err := validateEndpointsConfig(config); err != nil {
return nil, err
}
if err := validateExternalEndpointsConfig(config); err != nil {
return nil, err
}
if err := validateWebConfig(config); err != nil {
return nil, err
}
@ -336,6 +351,19 @@ func validateEndpointsConfig(config *Config) error {
return nil
}
func validateExternalEndpointsConfig(config *Config) error {
for _, externalEndpoint := range config.ExternalEndpoints {
if config.Debug {
log.Printf("[config.validateExternalEndpointsConfig] Validating external endpoint '%s'", externalEndpoint.Name)
}
if err := externalEndpoint.ValidateAndSetDefaults(); err != nil {
return fmt.Errorf("invalid external endpoint %s: %w", externalEndpoint.DisplayName(), err)
}
}
log.Printf("[config.validateExternalEndpointsConfig] Validated %d external endpoints", len(config.ExternalEndpoints))
return nil
}
func validateSecurityConfig(config *Config) error {
if config.Security != nil {
if config.Security.IsValid() {