Skip to content

Commit

Permalink
🐛 Regularly check in with upstream (#913)
Browse files Browse the repository at this point in the history
* 🐛 Regularly check in with upstream

Fixes #894

Signed-off-by: Christian Zunker <christian@mondoo.com>
  • Loading branch information
czunker authored Oct 31, 2023
1 parent 53f4478 commit 2c4e7f5
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 69 deletions.
148 changes: 148 additions & 0 deletions apps/cnspec/cmd/backgroundjob/checkin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package backgroundjob

import (
"context"
"math/rand"
"net/http"
"sync"
"time"

"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"go.mondoo.com/cnquery/v9"
"go.mondoo.com/cnquery/v9/cli/sysinfo"
"go.mondoo.com/cnquery/v9/providers-sdk/v1/upstream"
"go.mondoo.com/ranger-rpc"
"go.mondoo.com/ranger-rpc/plugins/scope"
)

type checkinPinger struct {
ctx context.Context
interval time.Duration
quit chan struct{}
wg sync.WaitGroup
endpoint string
httpClient *http.Client
mrn string
creds *upstream.ServiceAccountCredentials
}

func NewCheckinPinger(ctx context.Context, httpClient *http.Client, endpoint string, config *upstream.UpstreamConfig, interval time.Duration) *checkinPinger {
return &checkinPinger{
ctx: ctx,
interval: interval,
quit: make(chan struct{}),
endpoint: endpoint,
httpClient: httpClient,
mrn: config.Creds.Mrn,
creds: config.Creds,
}
}

func (c *checkinPinger) Start() {
// determine information about the client
sysInfo, err := sysinfo.GatherSystemInfo()
if err != nil {
log.Error().Err(err).Msg("could not gather client information")
return
}
c.wg.Add(1)
runCheckIn := func() {
err := c.checkIn(sysInfo)
if err != nil {
log.Info().Err(err).Msg("could not perform check-in")
}
}

// run check-in once on startup
runCheckIn()

jitter := time.Duration(rand.Int63n(int64(c.interval)))
ticker := time.NewTicker(c.interval + jitter)
go func() {
defer c.wg.Done()
for {
select {
case <-ticker.C:
runCheckIn()
case <-c.quit:
ticker.Stop()
return
}
}
}()
}

func (c *checkinPinger) Stop() {
close(c.quit)
c.wg.Wait()
}

func (c *checkinPinger) checkIn(sysInfo *sysinfo.SystemInfo) error {
// gather service account
plugins := []ranger.ClientPlugin{}
plugins = append(plugins, sysInfoHeader(sysInfo, cnquery.DefaultFeatures))

credentials := c.creds
if credentials != nil && len(credentials.Mrn) > 0 {
certAuth, err := upstream.NewServiceAccountRangerPlugin(credentials)
if err != nil {
return errors.Wrap(err, "invalid credentials")
}
plugins = append(plugins, certAuth)
} else {
return errors.New("no credentials configured")
}

client, err := upstream.NewAgentManagerClient(c.endpoint, c.httpClient, plugins...)
if err != nil {
return errors.Wrap(err, "could not connect to mondoo platform")
}

_, err = client.HealthCheck(context.Background(), &upstream.AgentInfo{
Mrn: c.mrn,
Version: sysInfo.Version,
Build: sysInfo.Build,
PlatformName: sysInfo.Platform.Name,
PlatformRelease: sysInfo.Platform.Version,
PlatformArch: sysInfo.Platform.Arch,
PlatformIp: sysInfo.IP,
PlatformHostname: sysInfo.Hostname,
Labels: nil,
PlatformId: sysInfo.PlatformId,
})

if err != nil {
return errors.Wrap(err, "failed to check in upstream")
}

return nil
}

func sysInfoHeader(sysInfo *sysinfo.SystemInfo, features cnquery.Features) ranger.ClientPlugin {
const (
HttpHeaderUserAgent = "User-Agent"
HttpHeaderClientFeatures = "Mondoo-Features"
HttpHeaderPlatformID = "Mondoo-PlatformID"
)

h := http.Header{}
info := map[string]string{
"cnquery": cnquery.Version,
"build": cnquery.Build,
}
if sysInfo != nil {
info["PN"] = sysInfo.Platform.Name
info["PR"] = sysInfo.Platform.Version
info["PA"] = sysInfo.Platform.Arch
info["IP"] = sysInfo.IP
info["HN"] = sysInfo.Hostname
h.Set(HttpHeaderPlatformID, sysInfo.PlatformId)
}
h.Set(HttpHeaderUserAgent, scope.XInfoHeader(info))
h.Set(HttpHeaderClientFeatures, features.Encode())
return scope.NewCustomHeaderRangerPlugin(h)
}
66 changes: 0 additions & 66 deletions apps/cnspec/cmd/backgroundjob/healthping.go

This file was deleted.

6 changes: 3 additions & 3 deletions apps/cnspec/cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ var serveCmd = &cobra.Command{
return cli_errors.NewCommandError(errors.Wrap(err, "could not initialize upstream client"), 1)
}

hc := backgroundjob.NewHealthPinger(ctx, client.HttpClient, client.ApiEndpoint, 5*time.Minute)
hc.Start()
defer hc.Stop()
checkin := backgroundjob.NewCheckinPinger(ctx, client.HttpClient, client.ApiEndpoint, conf.runtime.UpstreamConfig, 2*time.Hour)
checkin.Start()
defer checkin.Stop()
}

bj, err := backgroundjob.New()
Expand Down

0 comments on commit 2c4e7f5

Please sign in to comment.