Skip to content

Commit

Permalink
refactor: added gitlab interface to handle interaction with the API
Browse files Browse the repository at this point in the history
Signed-off-by: Bruno Bressi <[email protected]>
  • Loading branch information
puffitos committed Dec 12, 2023
1 parent da1a983 commit d2899c1
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 90 deletions.
11 changes: 0 additions & 11 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,10 @@ import (
"github.com/caas-team/sparrow/internal/helper"
)

// TargetConfig is the configuration for the target
// reconciliation process
type TargetConfig struct {
// the interval in seconds for the target reconciliation process
Interval time.Duration
// the amount of time in seconds a target can be
// unhealthy before it is removed from the global target list
UnhealthyThreshold time.Duration
}

type Config struct {
Checks map[string]any
Loader LoaderConfig
Api ApiConfig
Target TargetConfig
}

// ApiConfig is the configuration for the data API
Expand Down
82 changes: 3 additions & 79 deletions pkg/sparrow/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,10 @@ import (
"github.com/caas-team/sparrow/pkg/checks"
"github.com/caas-team/sparrow/pkg/config"
"github.com/caas-team/sparrow/pkg/db"
targets "github.com/caas-team/sparrow/pkg/sparrow/targets"
"github.com/go-chi/chi/v5"
)

// globalTarget represents a globalTarget that can be checked
type globalTarget struct {
url string
lastSeen time.Time
}

// TargetManager handles the management of globalTargets for
// a Sparrow instance
type TargetManager interface {
Reconcile(ctx context.Context)
GetTargets()
}

// gitlabTargetManager implements TargetManager
type gitlabTargetManager struct {
targets []globalTarget
client *http.Client
cfg *config.TargetConfig
}

type Sparrow struct {
db db.DB
// the existing checks
Expand All @@ -64,7 +45,7 @@ type Sparrow struct {
cfg *config.Config
loader config.Loader
cCfgChecks chan map[string]any
targets TargetManager
targets targets.TargetManager

routingTree *api.RoutingTree
router chi.Router
Expand All @@ -82,6 +63,7 @@ func New(cfg *config.Config) *Sparrow {
cCfgChecks: make(chan map[string]any, 1),
routingTree: api.NewRoutingTree(),
router: chi.NewRouter(),
targets: targets.NewGitlabManager(targets.NewGitlabClient("targetsRepo", "gitlabToken"), 5*time.Minute, 15*time.Minute),
}

sparrow.loader = config.NewLoader(cfg, sparrow.cCfgChecks)
Expand Down Expand Up @@ -193,64 +175,6 @@ func (s *Sparrow) ReconcileChecks(ctx context.Context) {
}
}

// Reconcile reconciles the targets of the gitlabTargetManager.
// The global gitlabTargetManager are parsed from a remote endpoint.
//
// The global gitlabTargetManager are evaluated for healthiness and
// unhealthy gitlabTargetManager are removed.
func (t *gitlabTargetManager) Reconcile(ctx context.Context) {
log := logger.FromContext(ctx).With("name", "ReconcileGlobalTargets")
log.Debug("Starting global gitlabTargetManager reconciler")

for {
// start a timer
timer := time.NewTimer(t.cfg.Interval)
defer timer.Stop()

select {
case <-ctx.Done():
if err := ctx.Err(); err != nil {
log.Error("Context canceled", "error", err)
return
}
case <-timer.C:
log.Debug("Getting global gitlabTargetManager")
targets, err := t.getTargets(ctx)
t.updateTargets(targets)
if err != nil {
log.Error("Failed to get global gitlabTargetManager", "error", err)
continue
}
}
}
}

// GetTargets returns the current targets of the gitlabTargetManager
func (t *gitlabTargetManager) GetTargets() []globalTarget {
return t.targets
}

// getGlobalTargets gets the global gitlabTargetManager from the configured gitlab repository
func (t *gitlabTargetManager) getTargets(ctx context.Context) ([]globalTarget, error) {
log := logger.FromContext(ctx).With("name", "getGlobalTargets")
log.Debug("Getting global gitlabTargetManager")
var res []globalTarget
return res, nil
}

// updateTargets sets the global gitlabTargetManager
func (t *gitlabTargetManager) updateTargets(targets []globalTarget) {
var healthyTargets []globalTarget
for _, target := range targets {
if time.Now().Add(-t.cfg.UnhealthyThreshold).After(target.lastSeen) {
continue
}
healthyTargets = append(healthyTargets, target)
}

t.targets = healthyTargets
}

// This is a fan in for the checks.
//
// It allows augmenting the results with the check name which is needed by the db
Expand Down
147 changes: 147 additions & 0 deletions pkg/sparrow/targets/gitlab.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package targets

import (
"context"
"net/http"
"time"

"github.com/caas-team/sparrow/internal/logger"
)

var (
_ Gitlab = &gitlab{}
_ TargetManager = &gitlabTargetManager{}
)

// Gitlab handles interaction with a gitlab repository containing
// the global targets for the Sparrow instance
type Gitlab interface {
ReadGlobalTargets(ctx context.Context) ([]globalTarget, error)
RegisterSelf(ctx context.Context) error
}

// gitlabTargetManager implements TargetManager
type gitlabTargetManager struct {
targets []globalTarget
gitlab Gitlab
// 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
}

// NewGitlabManager creates a new gitlabTargetManager
func NewGitlabManager(g Gitlab, checkInterval, unhealthyThreshold time.Duration) TargetManager {
return &gitlabTargetManager{
targets: []globalTarget{},
gitlab: g,
checkInterval: checkInterval,
unhealthyThreshold: unhealthyThreshold,
}
}

// gitlab implements Gitlab
type gitlab struct {
url string
token string
client *http.Client
}

func NewGitlabClient(url, token string) Gitlab {
return &gitlab{
url: url,
token: token,
client: &http.Client{},
}
}

func (t *gitlabTargetManager) Register(ctx context.Context) {
log := logger.FromContext(ctx).With("name", "RegisterGlobalTargets")
log.Debug("Registering global gitlabTargetManager")

err := t.gitlab.RegisterSelf(ctx)
if err != nil {
log.Error("Failed to register global gitlabTargetManager", "error", err)
}
}

// Reconcile reconciles the targets of the gitlabTargetManager.
// The global gitlabTargetManager are parsed from a remote endpoint.
//
// The global gitlabTargetManager are evaluated for healthiness and
// unhealthy gitlabTargetManager are removed.
func (t *gitlabTargetManager) Reconcile(ctx context.Context) {
log := logger.FromContext(ctx).With("name", "ReconcileGlobalTargets")
log.Debug("Starting global gitlabTargetManager reconciler")

for {
// start a timer
timer := time.NewTimer(t.checkInterval)
defer timer.Stop()

select {
case <-ctx.Done():
if err := ctx.Err(); err != nil {
log.Error("Context canceled", "error", err)
return
}
case <-timer.C:
log.Debug("Getting global gitlabTargetManager")
err := t.updateTargets(ctx)
if err != nil {
log.Error("Failed to get global gitlabTargetManager", "error", err)
continue
}
}
}
}

// GetTargets returns the current targets of the gitlabTargetManager
func (t *gitlabTargetManager) GetTargets() []globalTarget {
return t.targets
}

// updateTargets sets the global gitlabTargetManager
func (t *gitlabTargetManager) updateTargets(ctx context.Context) error {
log := logger.FromContext(ctx).With("name", "updateGlobalTargets")
var healthyTargets []globalTarget

targets, err := t.gitlab.ReadGlobalTargets(ctx)
if err != nil {
log.Error("Failed to update global targets", "error", err)
return err
}

for _, target := range targets {
if time.Now().Add(-t.unhealthyThreshold).After(target.lastSeen) {
continue
}
healthyTargets = append(healthyTargets, target)
}

t.targets = healthyTargets
log.Debug("Updated global targets", "targets", len(t.targets))
return nil
}

// ReadGlobalTargets fetches the global gitlabTargetManager from the configured gitlab repository
func (g *gitlab) ReadGlobalTargets(ctx context.Context) ([]globalTarget, error) {
log := logger.FromContext(ctx).With("name", "ReadGlobalTargets")
log.Debug("Fetching global gitlabTargetManager")

// TODO: pull file list from repo and marshal into []globalTarget

return nil, nil
}

// RegisterSelf commits the current instance to the configured gitlab repository
// as a global target for other sparrow instances to discover
func (g *gitlab) RegisterSelf(ctx context.Context) error {
log := logger.FromContext(ctx).With("name", "RegisterSelf")
log.Debug("Registering sparrow instance to gitlab")

// TODO: update & commit self as target to gitlab

return nil
}
20 changes: 20 additions & 0 deletions pkg/sparrow/targets/targets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package targets

import (
"context"
"time"
)

// globalTarget represents a globalTarget that can be checked
type globalTarget struct {
url string
lastSeen time.Time
}

// TargetManager handles the management of globalTargets for
// a Sparrow instance
type TargetManager interface {
Reconcile(ctx context.Context)
Register(ctx context.Context)
GetTargets() []globalTarget
}

0 comments on commit d2899c1

Please sign in to comment.