Skip to content

Commit

Permalink
feat/registration-update (#103)
Browse files Browse the repository at this point in the history
* chore: refactor added cfg internal struct

Signed-off-by: Bruno Bressi <[email protected]>

* chore: added errors & validation

Signed-off-by: Bruno Bressi <[email protected]>

* refactor: intoduce general TM config

Signed-off-by: Bruno Bressi <[email protected]>

* chore: validate only general config

Signed-off-by: Bruno Bressi <[email protected]>

* chore: added licence

Signed-off-by: Bruno Bressi <[email protected]>

---------

Signed-off-by: Bruno Bressi <[email protected]>
  • Loading branch information
puffitos authored Feb 9, 2024
1 parent ea6fdca commit b33a39f
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 60 deletions.
25 changes: 7 additions & 18 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,18 @@ package config
import (
"time"

"github.com/caas-team/sparrow/pkg/sparrow/targets"

"github.com/caas-team/sparrow/internal/helper"
"github.com/caas-team/sparrow/pkg/api"
)

type GitlabTargetManagerConfig struct {
BaseURL string `yaml:"baseUrl" mapstructure:"baseUrl"`
Token string `yaml:"token" mapstructure:"token"`
ProjectID int `yaml:"projectId" mapstructure:"projectId"`
}

type TargetManagerConfig struct {
CheckInterval time.Duration `yaml:"checkInterval" mapstructure:"checkInterval"`
RegistrationInterval time.Duration `yaml:"registrationInterval" mapstructure:"registrationInterval"`
UnhealthyThreshold time.Duration `yaml:"unhealthyThreshold" mapstructure:"unhealthyThreshold"`
Gitlab GitlabTargetManagerConfig `yaml:"gitlab" mapstructure:"gitlab"`
}

type Config struct {
// SparrowName is the DNS name of the sparrow
SparrowName string `yaml:"name" mapstructure:"name"`
Loader LoaderConfig `yaml:"loader" mapstructure:"loader"`
Api api.Config `yaml:"api" mapstructure:"api"`
TargetManager TargetManagerConfig `yaml:"targetManager" mapstructure:"targetManager"`
SparrowName string `yaml:"name" mapstructure:"name"`
Loader LoaderConfig `yaml:"loader" mapstructure:"loader"`
Api api.Config `yaml:"api" mapstructure:"api"`
TargetManager targets.TargetManagerConfig `yaml:"targetManager" mapstructure:"targetManager"`
}

// LoaderConfig is the configuration for loader
Expand All @@ -69,5 +58,5 @@ type FileLoaderConfig struct {

// HasTargetManager returns true if the config has a target manager
func (c *Config) HasTargetManager() bool {
return c.TargetManager != TargetManagerConfig{}
return c.TargetManager != targets.TargetManagerConfig{}
}
14 changes: 9 additions & 5 deletions pkg/sparrow/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
"testing"
"time"

"github.com/caas-team/sparrow/pkg/sparrow/targets"

"github.com/caas-team/sparrow/pkg/api"
"github.com/caas-team/sparrow/pkg/checks/dns"

Expand Down Expand Up @@ -193,11 +195,13 @@ func TestSparrow_Run_FullComponentStart(t *testing.T) {
File: config.FileLoaderConfig{Path: "../config/testdata/config.yaml"},
Interval: time.Second * 1,
},
TargetManager: config.TargetManagerConfig{
CheckInterval: time.Second * 1,
RegistrationInterval: time.Second * 1,
UnhealthyThreshold: time.Second * 1,
Gitlab: config.GitlabTargetManagerConfig{
TargetManager: targets.TargetManagerConfig{
Config: targets.Config{
CheckInterval: time.Second * 1,
RegistrationInterval: time.Second * 1,
UnhealthyThreshold: time.Second * 1,
},
Gitlab: targets.GitlabTargetManagerConfig{
BaseURL: "https://gitlab.com",
Token: "my-cool-token",
ProjectID: 42,
Expand Down
30 changes: 30 additions & 0 deletions pkg/sparrow/targets/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// sparrow
// (C) 2023, Deutsche Telekom IT GmbH
//
// Deutsche Telekom IT GmbH and all other contributors /
// copyright owners license this file to you under the Apache
// License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package targets

import "errors"

// ErrInvalidCheckInterval is returned when the check interval is invalid
var ErrInvalidCheckInterval = errors.New("invalid check interval")

// ErrInvalidRegistrationInterval is returned when the registration interval is invalid
var ErrInvalidRegistrationInterval = errors.New("invalid registration interval")

// ErrInvalidUnhealthyThreshold is returned when the unhealthy threshold is invalid
var ErrInvalidUnhealthyThreshold = errors.New("invalid unhealthy threshold")
44 changes: 20 additions & 24 deletions pkg/sparrow/targets/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ import (

"github.com/caas-team/sparrow/pkg/checks"

"github.com/caas-team/sparrow/pkg/config"

"github.com/caas-team/sparrow/pkg/sparrow/gitlab"

"github.com/caas-team/sparrow/internal/logger"
Expand All @@ -43,31 +41,29 @@ type gitlabTargetManager struct {
targets []checks.GlobalTarget
mu sync.RWMutex
// channel to signal the "reconcile" routine to stop
done chan struct{}
gitlab gitlab.Gitlab
done chan struct{}
// the DNS name used for self-registration
name string
// the interval for the target reconciliation process
checkInterval time.Duration
// the amount of time a target can be
// unhealthy before it is removed from the global target list
unhealthyThreshold time.Duration
// how often the instance should register itself as a global target
registrationInterval time.Duration
// whether the instance has already registered itself as a global target
registered bool
cfg Config
gitlab gitlab.Gitlab
}

type GitlabTargetManagerConfig struct {
BaseURL string `yaml:"baseUrl" mapstructure:"baseUrl"`
Token string `yaml:"token" mapstructure:"token"`
ProjectID int `yaml:"projectId" mapstructure:"projectId"`
}

// NewGitlabManager creates a new gitlabTargetManager
func NewGitlabManager(name string, gtmConfig config.TargetManagerConfig) *gitlabTargetManager {
func NewGitlabManager(name string, gtmConfig TargetManagerConfig) *gitlabTargetManager {
return &gitlabTargetManager{
gitlab: gitlab.New(gtmConfig.Gitlab.BaseURL, gtmConfig.Gitlab.Token, gtmConfig.Gitlab.ProjectID),
name: name,
checkInterval: gtmConfig.CheckInterval,
registrationInterval: gtmConfig.RegistrationInterval,
unhealthyThreshold: gtmConfig.UnhealthyThreshold,
mu: sync.RWMutex{},
done: make(chan struct{}, 1),
gitlab: gitlab.New(gtmConfig.Gitlab.BaseURL, gtmConfig.Gitlab.Token, gtmConfig.Gitlab.ProjectID),
name: name,
cfg: gtmConfig.Config,
mu: sync.RWMutex{},
done: make(chan struct{}, 1),
}
}

Expand All @@ -80,8 +76,8 @@ func (t *gitlabTargetManager) Reconcile(ctx context.Context) error {
log := logger.FromContext(ctx)
log.Info("Starting global gitlabTargetManager reconciler")

checkTimer := time.NewTimer(t.checkInterval)
registrationTimer := time.NewTimer(t.registrationInterval)
checkTimer := time.NewTimer(t.cfg.CheckInterval)
registrationTimer := time.NewTimer(t.cfg.RegistrationInterval)

defer checkTimer.Stop()
defer registrationTimer.Stop()
Expand All @@ -99,13 +95,13 @@ func (t *gitlabTargetManager) Reconcile(ctx context.Context) error {
if err != nil {
log.Warn("Failed to get global targets", "error", err)
}
checkTimer.Reset(t.checkInterval)
checkTimer.Reset(t.cfg.CheckInterval)
case <-registrationTimer.C:
err := t.updateRegistration(ctx)
if err != nil {
log.Warn("Failed to register self as global target", "error", err)
}
registrationTimer.Reset(t.registrationInterval)
registrationTimer.Reset(t.cfg.RegistrationInterval)
}
}
}
Expand Down Expand Up @@ -211,7 +207,7 @@ func (t *gitlabTargetManager) refreshTargets(ctx context.Context) error {
log.Debug("Found self as global target", "lastSeenMin", time.Since(target.LastSeen).Minutes())
t.registered = true
}
if time.Now().Add(-t.unhealthyThreshold).After(target.LastSeen) {
if time.Now().Add(-t.cfg.UnhealthyThreshold).After(target.LastSeen) {
log.Debug("Skipping unhealthy target", "target", target)
continue
}
Expand Down
28 changes: 15 additions & 13 deletions pkg/sparrow/targets/gitlab_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ func Test_gitlabTargetManager_refreshTargets(t *testing.T) {
gitlab.SetFetchFilesErr(tt.wantErr)
}
gtm := &gitlabTargetManager{
targets: nil,
gitlab: gitlab,
name: "test",
unhealthyThreshold: time.Hour,
targets: nil,
gitlab: gitlab,
name: "test",
cfg: Config{UnhealthyThreshold: time.Hour},
}
if err := gtm.refreshTargets(context.Background()); (err != nil) != (tt.wantErr != nil) {
t.Fatalf("refreshTargets() error = %v, wantErr %v", err, tt.wantErr)
Expand Down Expand Up @@ -509,14 +509,16 @@ func Test_gitlabTargetManager_Reconcile_Shutdown_Fail_Unregister(t *testing.T) {

func mockGitlabTargetManager(g *gitlabmock.MockClient, name string) *gitlabTargetManager { //nolint: unparam // irrelevant
return &gitlabTargetManager{
targets: nil,
mu: sync.RWMutex{},
done: make(chan struct{}, 1),
gitlab: g,
name: name,
checkInterval: 100 * time.Millisecond,
unhealthyThreshold: 1 * time.Second,
registrationInterval: 150 * time.Millisecond,
registered: false,
targets: nil,
mu: sync.RWMutex{},
done: make(chan struct{}, 1),
gitlab: g,
name: name,
cfg: Config{
CheckInterval: 100 * time.Millisecond,
UnhealthyThreshold: 1 * time.Second,
RegistrationInterval: 150 * time.Millisecond,
},
registered: false,
}
}
32 changes: 32 additions & 0 deletions pkg/sparrow/targets/targetmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package targets

import (
"context"
"time"

"github.com/caas-team/sparrow/pkg/checks"
)
Expand All @@ -36,3 +37,34 @@ type TargetManager interface {
// and unregisters the instance as a global target
Shutdown(ctx context.Context) error
}

// Config is the general configuration of the target manager
type Config struct {
// The interval for the target reconciliation process
CheckInterval time.Duration `yaml:"checkInterval" mapstructure:"checkInterval"`
// How often the instance should register itself as a global target.
// A duration of 0 means no registration.
RegistrationInterval time.Duration `yaml:"registrationInterval" mapstructure:"registrationInterval"`
// The amount of time a target can be unhealthy
// before it is removed from the global target list.
// A duration of 0 means no removal.
UnhealthyThreshold time.Duration `yaml:"unhealthyThreshold" mapstructure:"unhealthyThreshold"`
}

type TargetManagerConfig struct {
Config
Gitlab GitlabTargetManagerConfig `yaml:"gitlab" mapstructure:"gitlab"`
}

func (tmc *Config) Validate() error {
if tmc.CheckInterval <= 0 {
return ErrInvalidCheckInterval
}
if tmc.RegistrationInterval < 0 {
return ErrInvalidRegistrationInterval
}
if tmc.UnhealthyThreshold < 0 {
return ErrInvalidUnhealthyThreshold
}
return nil
}
78 changes: 78 additions & 0 deletions pkg/sparrow/targets/targetmanager_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// sparrow
// (C) 2023, Deutsche Telekom IT GmbH
//
// Deutsche Telekom IT GmbH and all other contributors /
// copyright owners license this file to you under the Apache
// License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package targets

import (
"testing"
"time"
)

func TestTargetManagerConfig_Validate(t *testing.T) {
tests := []struct {
name string
cfg Config
wantErr bool
}{
{
name: "empty config",
wantErr: true,
},
{
name: "valid config - non-zero values",
cfg: Config{
UnhealthyThreshold: 1 * time.Second,
CheckInterval: 1 * time.Second,
RegistrationInterval: 1 * time.Second,
},
},
{
name: "valid config - zero values",
cfg: Config{
UnhealthyThreshold: 0,
CheckInterval: 1 * time.Second,
RegistrationInterval: 0,
},
},
{
name: "invalid config - zero check interval",
cfg: Config{
UnhealthyThreshold: 1 * time.Second,
CheckInterval: 0,
RegistrationInterval: 1 * time.Second,
},
wantErr: true,
},
{
name: "invalid config - negative values",
cfg: Config{
UnhealthyThreshold: -1 * time.Second,
CheckInterval: 1 * time.Second,
RegistrationInterval: 1 * time.Second,
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := tt.cfg.Validate(); (err != nil) != tt.wantErr {
t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

0 comments on commit b33a39f

Please sign in to comment.