Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: load check config on startup #115

Merged
merged 15 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ repos:
- id: go-generate-repo
name: go generate
entry: go
args: [ generate, ./... ]
args: [generate, ./...]
language: system
types: [ go ]
types: [go]
pass_filenames: false
always_run: true
- repo: https://github.com/tekwizely/pre-commit-golang
rev: v1.0.0-rc.1
hooks:
- id: go-mod-tidy-repo
- id: go-test-repo-mod
args: [ -race, -count=1 ]
args: [-race, -count=1, -timeout 30s]
- id: go-vet-repo-mod
- id: go-fumpt-repo
args: [ -l, -w ]
args: [-l, -w]
- id: golangci-lint-repo-mod
args: [ --config, .golangci.yaml, --, --fix ]
args: [--config, .golangci.yaml, --, --fix]
- repo: https://github.com/norwoodj/helm-docs
rev: v1.13.0
hooks:
Expand Down
9 changes: 3 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,17 @@ module github.com/caas-team/sparrow
go 1.22

require (
github.com/aeden/traceroute v0.0.0-20210211061815-03f5f7cb7908
github.com/getkin/kin-openapi v0.120.0
github.com/go-chi/chi/v5 v5.0.10
github.com/google/go-cmp v0.6.0
github.com/jarcoal/httpmock v1.3.1
github.com/spf13/cobra v1.8.0
github.com/spf13/viper v1.18.0
github.com/stretchr/testify v1.8.4
gopkg.in/yaml.v3 v3.0.1
)

require github.com/google/go-cmp v0.6.0

require github.com/aeden/traceroute v0.0.0-20210211061815-03f5f7cb7908

require github.com/mitchellh/mapstructure v1.5.0 // indirect

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
Expand All @@ -34,6 +30,7 @@ require (
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect
Expand Down
6 changes: 3 additions & 3 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (a *api) RegisterRoutes(ctx context.Context, routes ...Route) error {

// Handles requests with simple http ok
// Required for global tarMan in checks
a.router.Handle("/", okHandler(ctx))
a.router.Handle("/", OkHandler(ctx))

return nil
}
Expand All @@ -148,8 +148,8 @@ func (a *api) registerDefaultRoute(route Route) (err error) {
return nil
}

// okHandler returns a handler that will serve status ok
func okHandler(ctx context.Context) http.Handler {
// OkHandler returns a handler that will serve status ok
func OkHandler(ctx context.Context) http.Handler {
log := logger.FromContext(ctx)

return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
Expand Down
4 changes: 2 additions & 2 deletions pkg/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func TestAPI_ShutdownWhenContextCanceled(t *testing.T) {
}
}

func Test_okHandler(t *testing.T) {
func TestAPI_OkHandler(t *testing.T) {
ctx := context.Background()

req, err := http.NewRequestWithContext(ctx, "GET", "/okHandler", http.NoBody)
Expand All @@ -221,7 +221,7 @@ func Test_okHandler(t *testing.T) {
}

rr := httptest.NewRecorder()
handler := okHandler(ctx)
handler := OkHandler(ctx)

handler.ServeHTTP(rr, req)

Expand Down
2 changes: 1 addition & 1 deletion pkg/checks/dns/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ func (d *DNS) Run(ctx context.Context, cResult chan checks.ResultDTO) error {
ctx, cancel := logger.NewContextWithLogger(ctx)
defer cancel()
log := logger.FromContext(ctx)
log.Info("Starting dns check", "interval", d.config.Interval.String())

log.Info("Starting dns check", "interval", d.config.Interval.String())
for {
select {
case <-ctx.Done():
Expand Down
2 changes: 1 addition & 1 deletion pkg/checks/health/health.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ func (h *Health) Run(ctx context.Context, cResult chan checks.ResultDTO) error {
ctx, cancel := logger.NewContextWithLogger(ctx)
defer cancel()
log := logger.FromContext(ctx)
log.Info("Starting healthcheck", "interval", h.config.Interval.String())

log.Info("Starting healthcheck", "interval", h.config.Interval.String())
for {
select {
case <-ctx.Done():
Expand Down
2 changes: 1 addition & 1 deletion pkg/checks/latency/latency.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ func (l *Latency) Run(ctx context.Context, cResult chan checks.ResultDTO) error
ctx, cancel := logger.NewContextWithLogger(ctx)
defer cancel()
log := logger.FromContext(ctx)
log.Info("Starting latency check", "interval", l.config.Interval.String())

log.Info("Starting latency check", "interval", l.config.Interval.String())
for {
select {
case <-ctx.Done():
Expand Down
6 changes: 3 additions & 3 deletions pkg/checks/traceroute/traceroute.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ type Target struct {

func NewCheck() checks.Check {
return &Traceroute{
config: Config{},
traceroute: newTraceroute,
CheckBase: checks.CheckBase{
Mu: sync.Mutex{},
DoneChan: make(chan struct{}),
},
config: Config{},
traceroute: newTraceroute,
}
}

Expand Down Expand Up @@ -69,8 +69,8 @@ func (tr *Traceroute) Run(ctx context.Context, cResult chan checks.ResultDTO) er
ctx, cancel := logger.NewContextWithLogger(ctx)
defer cancel()
log := logger.FromContext(ctx)
log.Info("Starting traceroute check", "interval", tr.config.Interval.String())

log.Info("Starting traceroute check", "interval", tr.config.Interval.String())
for {
select {
case <-ctx.Done():
Expand Down
18 changes: 10 additions & 8 deletions pkg/config/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,23 @@ func NewFileLoader(cfg *Config, cRuntime chan<- runtime.Config) *FileLoader {

// Run gets the runtime configuration from the local file.
// The config will be loaded periodically defined by the loader interval configuration.
// If the interval is 0, the configuration is only fetched once and the loader is disabled.
func (f *FileLoader) Run(ctx context.Context) error {
ctx, cancel := logger.NewContextWithLogger(ctx)
defer cancel()
log := logger.FromContext(ctx)

if f.config.Interval == 0 {
cfg, err := f.getRuntimeConfig(ctx)
if err != nil {
log.Warn("Could not get local runtime configuration", "error", err)
return fmt.Errorf("could not get local runtime configuration: %w", err)
}
// Get the runtime configuration once on startup
cfg, err := f.getRuntimeConfig(ctx)
if err != nil {
log.Warn("Could not get local runtime configuration", "error", err)
err = fmt.Errorf("could not get local runtime configuration: %w", err)
}
f.cRuntime <- cfg

f.cRuntime <- cfg
if f.config.Interval == 0 {
log.Info("File Loader disabled")
return nil
return err
}

tick := time.NewTicker(f.config.Interval)
Expand Down
64 changes: 33 additions & 31 deletions pkg/config/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package config

import (
"context"
"errors"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -51,61 +52,62 @@ func NewHttpLoader(cfg *Config, cRuntime chan<- runtime.Config) *HttpLoader {

// Run gets the runtime configuration from the remote file of the configured http endpoint.
// The config will be loaded periodically defined by the loader interval configuration.
// Returns an error if the loader is shutdown or the context is done.
func (hl *HttpLoader) Run(ctx context.Context) error {
// If the interval is 0, the configuration is only fetched once and the loader is disabled.
func (h *HttpLoader) Run(ctx context.Context) error {
ctx, cancel := logger.NewContextWithLogger(ctx)
defer cancel()
log := logger.FromContext(ctx)

var runtimeCfg *runtime.Config
var cfg runtime.Config
getConfigRetry := helper.Retry(func(ctx context.Context) (err error) {
runtimeCfg, err = hl.getRuntimeConfig(ctx)
cfg, err = h.getRuntimeConfig(ctx)
return err
}, hl.cfg.Http.RetryCfg)
}, h.cfg.Http.RetryCfg)

if hl.cfg.Interval == 0 {
err := getConfigRetry(ctx)
if err != nil {
log.Warn("Could not get remote runtime configuration", "error", err)
return fmt.Errorf("could not get remote runtime configuration: %w", err)
}
// Get the runtime configuration once on startup
err := getConfigRetry(ctx)
if err != nil {
log.Warn("Could not get remote runtime configuration", "error", err)
err = fmt.Errorf("could not get remote runtime configuration: %w", err)
}
h.cRuntime <- cfg

hl.cRuntime <- *runtimeCfg
if h.cfg.Interval == 0 {
log.Info("HTTP Loader disabled")
return nil
return err
}

tick := time.NewTicker(hl.cfg.Interval)
tick := time.NewTicker(h.cfg.Interval)
defer tick.Stop()

for {
select {
case <-hl.done:
case <-h.done:
log.Info("HTTP Loader terminated")
return nil
case <-ctx.Done():
return ctx.Err()
case <-tick.C:
if err := getConfigRetry(ctx); err != nil {
log.Warn("Could not get remote runtime configuration", "error", err)
tick.Reset(hl.cfg.Interval)
tick.Reset(h.cfg.Interval)
continue
}

log.Info("Successfully got remote runtime configuration")
hl.cRuntime <- *runtimeCfg
tick.Reset(hl.cfg.Interval)
h.cRuntime <- cfg
tick.Reset(h.cfg.Interval)
}
}
}

// GetRuntimeConfig gets the remote runtime configuration
func (hl *HttpLoader) getRuntimeConfig(ctx context.Context) (*runtime.Config, error) {
func (hl *HttpLoader) getRuntimeConfig(ctx context.Context) (cfg runtime.Config, err error) {
log := logger.FromContext(ctx).With("url", hl.cfg.Http.Url)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, hl.cfg.Http.Url, http.NoBody)
if err != nil {
log.Error("Could not create http GET request", "error", err.Error())
return nil, err
return cfg, err
}
if hl.cfg.Http.Token != "" {
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", hl.cfg.Http.Token))
Expand All @@ -114,34 +116,34 @@ func (hl *HttpLoader) getRuntimeConfig(ctx context.Context) (*runtime.Config, er
res, err := hl.client.Do(req) //nolint:bodyclose
if err != nil {
log.Error("Http get request failed", "error", err.Error())
return nil, err
return cfg, err
}
defer func(Body io.ReadCloser) {
err = Body.Close()
if err != nil {
log.Error("Failed to close response body", "error", err.Error())
cErr := Body.Close()
if cErr != nil {
log.Error("Failed to close response body", "error", cErr)
err = errors.Join(cErr, err)
}
}(res.Body)

if res.StatusCode != http.StatusOK {
log.Error("Http get request failed", "status", res.Status)
return nil, fmt.Errorf("request failed, status is %s", res.Status)
return cfg, fmt.Errorf("request failed, status is %s", res.Status)
}

body, err := io.ReadAll(res.Body)
b, err := io.ReadAll(res.Body)
if err != nil {
log.Error("Could not read response body", "error", err.Error())
return nil, err
return cfg, err
}
log.Debug("Successfully got response")

runtimeCfg := &runtime.Config{}
if err := yaml.Unmarshal(body, &runtimeCfg); err != nil {
if err := yaml.Unmarshal(b, &cfg); err != nil {
log.Error("Could not unmarshal response", "error", err.Error())
return nil, err
return cfg, err
}

return runtimeCfg, nil
return cfg, nil
}

// Shutdown stops the loader
Expand Down
Loading
Loading