mirror of
https://github.com/TwiN/gatus.git
synced 2024-11-28 10:53:20 +01:00
simplification and refactorings
This commit is contained in:
parent
f9706a98ed
commit
5f10a92c36
@ -146,7 +146,7 @@ func parseAndValidateConfigBytes(yamlBytes []byte) (config *Config, err error) {
|
|||||||
|
|
||||||
func validateWebConfig(config *Config) {
|
func validateWebConfig(config *Config) {
|
||||||
if config.Web == nil {
|
if config.Web == nil {
|
||||||
config.Web = &webConfig{Address: DefaultAddress, Port: DefaultPort}
|
config.Web = &webConfig{Address: DefaultAddress, Port: DefaultPort, ContextRoot: DefaultContextRoot}
|
||||||
} else {
|
} else {
|
||||||
config.Web.validateAndSetDefaults()
|
config.Web.validateAndSetDefaults()
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,9 @@ services:
|
|||||||
if config.Web.Port != DefaultPort {
|
if config.Web.Port != DefaultPort {
|
||||||
t.Errorf("Port should have been %d, because it is the default value", DefaultPort)
|
t.Errorf("Port should have been %d, because it is the default value", DefaultPort)
|
||||||
}
|
}
|
||||||
|
if config.Web.ContextRoot != DefaultContextRoot {
|
||||||
|
t.Errorf("ContextRoot should have been %s, because it is the default value", DefaultContextRoot)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseAndValidateConfigBytesWithAddress(t *testing.T) {
|
func TestParseAndValidateConfigBytesWithAddress(t *testing.T) {
|
||||||
@ -215,6 +218,44 @@ services:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseAndValidateConfigBytesWithPortAndHostAndContextRoot(t *testing.T) {
|
||||||
|
config, err := parseAndValidateConfigBytes([]byte(`
|
||||||
|
web:
|
||||||
|
port: 12345
|
||||||
|
address: 127.0.0.1
|
||||||
|
context-root: /deeply/nested/down=/their
|
||||||
|
services:
|
||||||
|
- name: twinnation
|
||||||
|
url: https://twinnation.org/health
|
||||||
|
conditions:
|
||||||
|
- "[STATUS] == 200"
|
||||||
|
`))
|
||||||
|
if err != nil {
|
||||||
|
t.Error("No error should've been returned")
|
||||||
|
}
|
||||||
|
if config == nil {
|
||||||
|
t.Fatal("Config shouldn't have been nil")
|
||||||
|
}
|
||||||
|
if config.Metrics {
|
||||||
|
t.Error("Metrics should've been false by default")
|
||||||
|
}
|
||||||
|
if config.Services[0].URL != "https://twinnation.org/health" {
|
||||||
|
t.Errorf("URL should have been %s", "https://twinnation.org/health")
|
||||||
|
}
|
||||||
|
if config.Services[0].Interval != 60*time.Second {
|
||||||
|
t.Errorf("Interval should have been %s, because it is the default value", 60*time.Second)
|
||||||
|
}
|
||||||
|
if config.Web.Address != "127.0.0.1" {
|
||||||
|
t.Errorf("Bind address should have been %s, because it is specified in config", "127.0.0.1")
|
||||||
|
}
|
||||||
|
if config.Web.Port != 12345 {
|
||||||
|
t.Errorf("Port should have been %d, because it is specified in config", 12345)
|
||||||
|
}
|
||||||
|
if config.Web.ContextRoot != "/deeply/nested/down=/their/" {
|
||||||
|
t.Errorf("Port should have been %s, because it is specified in config", "/deeply/nested/down=/their/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseAndValidateConfigBytesWithInvalidPort(t *testing.T) {
|
func TestParseAndValidateConfigBytesWithInvalidPort(t *testing.T) {
|
||||||
defer func() { recover() }()
|
defer func() { recover() }()
|
||||||
_, _ = parseAndValidateConfigBytes([]byte(`
|
_, _ = parseAndValidateConfigBytes([]byte(`
|
||||||
@ -260,6 +301,9 @@ services:
|
|||||||
if config.Web.Port != DefaultPort {
|
if config.Web.Port != DefaultPort {
|
||||||
t.Errorf("Port should have been %d, because it is the default value", DefaultPort)
|
t.Errorf("Port should have been %d, because it is the default value", DefaultPort)
|
||||||
}
|
}
|
||||||
|
if config.Web.ContextRoot != DefaultContextRoot {
|
||||||
|
t.Errorf("ContextRoot should have been %s, because it is the default value", DefaultContextRoot)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseAndValidateConfigBytesWithMetricsAndHostAndPort(t *testing.T) {
|
func TestParseAndValidateConfigBytesWithMetricsAndHostAndPort(t *testing.T) {
|
||||||
|
@ -16,9 +16,8 @@ type webConfig struct {
|
|||||||
// Port to listen on (default to 8080 specified by DefaultPort)
|
// Port to listen on (default to 8080 specified by DefaultPort)
|
||||||
Port int `yaml:"port"`
|
Port int `yaml:"port"`
|
||||||
|
|
||||||
|
// ContextRoot set the root context for the web application
|
||||||
ContextRoot string `yaml:"context-root"`
|
ContextRoot string `yaml:"context-root"`
|
||||||
|
|
||||||
safeContextRoot string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateAndSetDefaults checks and sets missing values based on the defaults
|
// validateAndSetDefaults checks and sets missing values based on the defaults
|
||||||
@ -33,26 +32,16 @@ func (web *webConfig) validateAndSetDefaults() {
|
|||||||
panic(fmt.Sprintf("port has an invalid: value should be between %d and %d", 0, math.MaxUint16))
|
panic(fmt.Sprintf("port has an invalid: value should be between %d and %d", 0, math.MaxUint16))
|
||||||
}
|
}
|
||||||
if len(web.ContextRoot) == 0 {
|
if len(web.ContextRoot) == 0 {
|
||||||
web.safeContextRoot = DefaultContextRoot
|
web.ContextRoot = DefaultContextRoot
|
||||||
} else {
|
} else {
|
||||||
// url.PathEscape escapes all "/", in order to build a secure path
|
url, err := url.Parse(web.ContextRoot)
|
||||||
// (1) split into path fragements using "/" as delimiter
|
|
||||||
// (2) use url.PathEscape() on each fragment
|
|
||||||
// (3) re-concatinate the path using "/" as join character
|
|
||||||
const splitJoinChar = "/"
|
|
||||||
pathes := strings.Split(web.ContextRoot, splitJoinChar)
|
|
||||||
escapedPathes := make([]string, len(pathes))
|
|
||||||
for i, path := range pathes {
|
|
||||||
escapedPathes[i] = url.PathEscape(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
web.safeContextRoot = strings.Join(escapedPathes, splitJoinChar)
|
|
||||||
|
|
||||||
// assure that we have still a valid url
|
|
||||||
_, err := url.Parse(web.safeContextRoot)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("Invalid context root %s - Error %s", web.ContextRoot, err))
|
panic(fmt.Sprintf("Invalid context root %s - error: %s.", web.ContextRoot, err))
|
||||||
}
|
}
|
||||||
|
if url.Path != web.ContextRoot {
|
||||||
|
panic(fmt.Sprintf("Invalid context root %s, simple path required.", web.ContextRoot))
|
||||||
|
}
|
||||||
|
web.ContextRoot = strings.TrimRight(url.Path, "/") + "/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,14 +50,9 @@ func (web *webConfig) SocketAddress() string {
|
|||||||
return fmt.Sprintf("%s:%d", web.Address, web.Port)
|
return fmt.Sprintf("%s:%d", web.Address, web.Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CtxRoot returns the context root
|
// AppendToContexRoot appends the given string to the context root
|
||||||
func (web *webConfig) CtxRoot() string {
|
// AppendToContexRoot takes care of having only one "/" character at
|
||||||
return web.safeContextRoot
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendToCtxRoot appends the given string to the context root
|
|
||||||
// AppendToCtxRoot takes care of having only one "/" character at
|
|
||||||
// the join point and exactly on "/" at the end
|
// the join point and exactly on "/" at the end
|
||||||
func (web *webConfig) AppendToCtxRoot(fragment string) string {
|
func (web *webConfig) AppendToContexRoot(fragment string) string {
|
||||||
return strings.TrimSuffix(web.safeContextRoot, "/") + "/" + strings.Trim(fragment, "/") + "/"
|
return web.ContextRoot + strings.Trim(fragment, "/") + "/"
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,20 @@ func TestWebConfig_SocketAddress(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWebConfig_ContextRootEmpty(t *testing.T) {
|
||||||
|
const expected = "/"
|
||||||
|
|
||||||
|
web := &webConfig{
|
||||||
|
ContextRoot: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
web.validateAndSetDefaults()
|
||||||
|
|
||||||
|
if web.ContextRoot != expected {
|
||||||
|
t.Errorf("expected %s, got %s", expected, web.ContextRoot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestWebConfig_ContextRoot(t *testing.T) {
|
func TestWebConfig_ContextRoot(t *testing.T) {
|
||||||
const expected = "/status/"
|
const expected = "/status/"
|
||||||
|
|
||||||
@ -21,13 +35,13 @@ func TestWebConfig_ContextRoot(t *testing.T) {
|
|||||||
|
|
||||||
web.validateAndSetDefaults()
|
web.validateAndSetDefaults()
|
||||||
|
|
||||||
if web.CtxRoot() != expected {
|
if web.ContextRoot != expected {
|
||||||
t.Errorf("expected %s, got %s", expected, web.CtxRoot())
|
t.Errorf("expected %s, got %s", expected, web.ContextRoot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWebConfig_ContextRootWithEscapableChars(t *testing.T) {
|
func TestWebConfig_ContextRootInvalid(t *testing.T) {
|
||||||
const expected = "/s%3F=ta%20t%20u&s/"
|
defer func() { recover() }()
|
||||||
|
|
||||||
web := &webConfig{
|
web := &webConfig{
|
||||||
ContextRoot: "/s?=ta t u&s/",
|
ContextRoot: "/s?=ta t u&s/",
|
||||||
@ -35,21 +49,19 @@ func TestWebConfig_ContextRootWithEscapableChars(t *testing.T) {
|
|||||||
|
|
||||||
web.validateAndSetDefaults()
|
web.validateAndSetDefaults()
|
||||||
|
|
||||||
if web.CtxRoot() != expected {
|
t.Fatal("Should've panicked because the configuration specifies an invalid context root")
|
||||||
t.Errorf("expected %s, got %s", expected, web.CtxRoot())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWebConfig_ContextRootMultiPath(t *testing.T) {
|
func TestWebConfig_ContextRootMultiPath(t *testing.T) {
|
||||||
const expected = "/app/status"
|
const expected = "/app/status/"
|
||||||
web := &webConfig{
|
web := &webConfig{
|
||||||
ContextRoot: "/app/status",
|
ContextRoot: "/app/status",
|
||||||
}
|
}
|
||||||
|
|
||||||
web.validateAndSetDefaults()
|
web.validateAndSetDefaults()
|
||||||
|
|
||||||
if web.CtxRoot() != expected {
|
if web.ContextRoot != expected {
|
||||||
t.Errorf("expected %s, got %s", expected, web.CtxRoot())
|
t.Errorf("expected %s, got %s", expected, web.ContextRoot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,8 +71,8 @@ func TestWebConfig_ContextRootAppendWithEmptyContextRoot(t *testing.T) {
|
|||||||
|
|
||||||
web.validateAndSetDefaults()
|
web.validateAndSetDefaults()
|
||||||
|
|
||||||
if web.AppendToCtxRoot("/bla/") != expected {
|
if web.AppendToContexRoot("/bla/") != expected {
|
||||||
t.Errorf("expected %s, got %s", expected, web.AppendToCtxRoot("/bla/"))
|
t.Errorf("expected %s, got %s", expected, web.AppendToContexRoot("/bla/"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +84,7 @@ func TestWebConfig_ContextRootAppendWithContext(t *testing.T) {
|
|||||||
|
|
||||||
web.validateAndSetDefaults()
|
web.validateAndSetDefaults()
|
||||||
|
|
||||||
if web.AppendToCtxRoot("/bla/") != expected {
|
if web.AppendToContexRoot("/bla/") != expected {
|
||||||
t.Errorf("expected %s, got %s", expected, web.AppendToCtxRoot("/bla/"))
|
t.Errorf("expected %s, got %s", expected, web.AppendToContexRoot("/bla/"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
main.go
10
main.go
@ -31,14 +31,14 @@ func main() {
|
|||||||
}
|
}
|
||||||
// favicon needs to be always served from the root
|
// favicon needs to be always served from the root
|
||||||
http.HandleFunc("/favicon.ico", favIconHandler)
|
http.HandleFunc("/favicon.ico", favIconHandler)
|
||||||
http.HandleFunc(cfg.Web.AppendToCtxRoot("/api/v1/results"), resultsHandler)
|
http.HandleFunc(cfg.Web.AppendToContexRoot("/api/v1/results"), resultsHandler)
|
||||||
http.HandleFunc(cfg.Web.AppendToCtxRoot("/health"), healthHandler)
|
http.HandleFunc(cfg.Web.AppendToContexRoot("/health"), healthHandler)
|
||||||
http.Handle(cfg.Web.CtxRoot(), GzipHandler(http.StripPrefix(cfg.Web.CtxRoot(), http.FileServer(http.Dir("./static")))))
|
http.Handle(cfg.Web.ContextRoot, GzipHandler(http.StripPrefix(cfg.Web.ContextRoot, http.FileServer(http.Dir("./static")))))
|
||||||
|
|
||||||
if cfg.Metrics {
|
if cfg.Metrics {
|
||||||
http.Handle(cfg.Web.AppendToCtxRoot("/metrics"), promhttp.Handler())
|
http.Handle(cfg.Web.AppendToContexRoot("/metrics"), promhttp.Handler())
|
||||||
}
|
}
|
||||||
log.Printf("[main][main] Listening on %s%s\n", cfg.Web.SocketAddress(), cfg.Web.CtxRoot())
|
log.Printf("[main][main] Listening on %s%s\n", cfg.Web.SocketAddress(), cfg.Web.ContextRoot)
|
||||||
go watchdog.Monitor(cfg)
|
go watchdog.Monitor(cfg)
|
||||||
log.Fatal(http.ListenAndServe(cfg.Web.SocketAddress(), nil))
|
log.Fatal(http.ListenAndServe(cfg.Web.SocketAddress(), nil))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user