From 300ac5375db200e8b0b4ad1e9f25798d39abba20 Mon Sep 17 00:00:00 2001 From: Ashraf Fouda Date: Mon, 30 Mar 2026 11:05:55 +0200 Subject: [PATCH 1/2] adds ttl for twins cache in auth.go (#115) Signed-off-by: Ashraf Fouda --- pkg/provision/auth.go | 59 +++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/pkg/provision/auth.go b/pkg/provision/auth.go index 653b4c91..5c38633b 100644 --- a/pkg/provision/auth.go +++ b/pkg/provision/auth.go @@ -2,50 +2,55 @@ package provision import ( "context" - "crypto/ed25519" "fmt" + "time" - lru "github.com/hashicorp/golang-lru" + cache "github.com/patrickmn/go-cache" "github.com/pkg/errors" + "github.com/rs/zerolog/log" "github.com/threefoldtech/zosbase/pkg/stubs" ) +const ( + keyExpiration = 60 * time.Minute + keyCleanup = 10 * time.Minute +) + type substrateTwins struct { substrateGateway *stubs.SubstrateGatewayStub - mem *lru.Cache + mem *cache.Cache } // NewSubstrateTwins creates a substrate users db that implements the provision.Users interface. func NewSubstrateTwins(substrateGateway *stubs.SubstrateGatewayStub) (Twins, error) { - cache, err := lru.New(1024) - if err != nil { - return nil, err - } - return &substrateTwins{ substrateGateway: substrateGateway, - mem: cache, + mem: cache.New(keyExpiration, keyCleanup), }, nil } // GetKey gets twins public key func (s *substrateTwins) GetKey(id uint32) ([]byte, error) { - if value, ok := s.mem.Get(id); ok { + cacheKey := fmt.Sprint(id) + if value, ok := s.mem.Get(cacheKey); ok { return value.([]byte), nil } + + log.Debug().Uint32("twin", id).Msg("twin public key cache expired, fetching from substrate") user, err := s.substrateGateway.GetTwin(context.Background(), id) if err != nil { return nil, errors.Wrapf(err, "could not get user with id '%d'", id) } - key := user.Account.PublicKey() - s.mem.Add(id, key) - return key, nil + pk := user.Account.PublicKey() + s.mem.Set(cacheKey, pk, cache.DefaultExpiration) + return pk, nil } type substrateAdmins struct { - twin uint32 - pk ed25519.PublicKey + substrateGateway *stubs.SubstrateGatewayStub + twin uint32 + mem *cache.Cache } // NewSubstrateAdmins creates a substrate twins db that implements the provision.Users interface. @@ -56,13 +61,10 @@ func NewSubstrateAdmins(substrateGateway *stubs.SubstrateGatewayStub, farmID uin return nil, errors.Wrap(err, "failed to get farm") } - twin, err := substrateGateway.GetTwin(context.Background(), uint32(farm.TwinID)) - if err != nil { - return nil, err - } return &substrateAdmins{ - twin: uint32(farm.TwinID), - pk: twin.Account.PublicKey(), + substrateGateway: substrateGateway, + twin: uint32(farm.TwinID), + mem: cache.New(keyExpiration, keyCleanup), }, nil } @@ -72,5 +74,18 @@ func (s *substrateAdmins) GetKey(id uint32) ([]byte, error) { return nil, fmt.Errorf("twin with id '%d' is not an admin", id) } - return []byte(s.pk), nil + cacheKey := fmt.Sprint(id) + if value, ok := s.mem.Get(cacheKey); ok { + return value.([]byte), nil + } + + log.Debug().Uint32("twin", id).Msg("admin public key cache expired, fetching from substrate") + twin, err := s.substrateGateway.GetTwin(context.Background(), id) + if err != nil { + return nil, errors.Wrapf(err, "could not get admin twin with id '%d'", id) + } + + pk := twin.Account.PublicKey() + s.mem.Set(cacheKey, pk, cache.DefaultExpiration) + return pk, nil } From 063d89561797f00b51754a46eb462d2cbe39e95e Mon Sep 17 00:00:00 2001 From: Omar Abdulaziz Date: Mon, 30 Mar 2026 13:05:42 +0200 Subject: [PATCH 2/2] extract vmCheck into separate task (#116) --- pkg/perf/healthcheck/healthcheck.go | 1 - pkg/perf/provisiontest/provisiontest.go | 87 +++++++++++++++++++ pkg/perf/{healthcheck => provisiontest}/vm.go | 2 +- 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 pkg/perf/provisiontest/provisiontest.go rename pkg/perf/{healthcheck => provisiontest}/vm.go (99%) diff --git a/pkg/perf/healthcheck/healthcheck.go b/pkg/perf/healthcheck/healthcheck.go index 648b61e0..2d038292 100644 --- a/pkg/perf/healthcheck/healthcheck.go +++ b/pkg/perf/healthcheck/healthcheck.go @@ -25,7 +25,6 @@ func NewTask() perf.Task { checks := map[string]checkFunc{ "cache": cacheCheck, "network": networkCheck, - "vm": vmCheck, } return &healthcheckTask{ checks: checks, diff --git a/pkg/perf/provisiontest/provisiontest.go b/pkg/perf/provisiontest/provisiontest.go new file mode 100644 index 00000000..5a58504b --- /dev/null +++ b/pkg/perf/provisiontest/provisiontest.go @@ -0,0 +1,87 @@ +package provisiontest + +import ( + "context" + "fmt" + "time" + + "github.com/cenkalti/backoff" + "github.com/rs/zerolog/log" + "github.com/threefoldtech/zosbase/pkg/perf" + "github.com/threefoldtech/zosbase/pkg/stubs" +) + +const ( + id = "provisiontest" + schedule = "0 0 0 * * *" + description = "daily provision test that deploys a test VM to verify the node can run virtual machines and sets flags for the power daemon" +) + +type provisionTestTask struct{} + +var _ perf.Task = (*provisionTestTask)(nil) + +func NewTask() perf.Task { + return &provisionTestTask{} +} + +func (t *provisionTestTask) ID() string { + return id +} + +func (t *provisionTestTask) Cron() string { + return schedule +} + +func (t *provisionTestTask) Description() string { + return description +} + +func (t *provisionTestTask) Jitter() uint32 { + return 30 * 60 +} + +func (t *provisionTestTask) Run(ctx context.Context) (interface{}, error) { + log.Debug().Msg("starting provision test task") + + cl := perf.MustGetZbusClient(ctx) + zui := stubs.NewZUIStub(cl) + + var result []string + + op := func() error { + errs := vmCheck(ctx) + result = errorsToStrings(errs) + + if err := zui.PushErrors(ctx, "vm", result); err != nil { + return err + } + + if len(errs) != 0 { + return fmt.Errorf("provision test failed: %s", result) + } + + return nil + } + + notify := func(err error, t time.Duration) { + log.Error().Err(err).Dur("retry-in", t).Msg("failed provision test. retrying") + } + + bo := backoff.NewExponentialBackOff() + bo.InitialInterval = 3 * time.Minute + bo.MaxInterval = 30 * time.Second + bo.MaxElapsedTime = 10 * time.Minute + + _ = backoff.RetryNotify(op, bo, notify) + + return result, nil +} + +func errorsToStrings(errs []error) []string { + s := make([]string, 0, len(errs)) + for _, err := range errs { + s = append(s, err.Error()) + } + return s +} diff --git a/pkg/perf/healthcheck/vm.go b/pkg/perf/provisiontest/vm.go similarity index 99% rename from pkg/perf/healthcheck/vm.go rename to pkg/perf/provisiontest/vm.go index 73a5100e..1479efb3 100644 --- a/pkg/perf/healthcheck/vm.go +++ b/pkg/perf/provisiontest/vm.go @@ -1,4 +1,4 @@ -package healthcheck +package provisiontest import ( "context"