Skip to content

Commit

Permalink
feat: store cluster id in a metadata secret
Browse files Browse the repository at this point in the history
  • Loading branch information
laimonasr committed Dec 5, 2024
1 parent 01d33bb commit 8d37568
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 2 deletions.
17 changes: 15 additions & 2 deletions cmd/agent/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"runtime"
"time"

"castai-agent/internal/services/metadata"

Check failure on line 12 in cmd/agent/run.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gci`-ed with --skip-generated -s standard -s default -s prefix(castai-agent) (gci)
"github.com/samber/lo"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/runtime/serializer"
Expand Down Expand Up @@ -174,6 +175,18 @@ func runAgentMode(ctx context.Context, castaiclient castai.Client, log *logrus.E
return fmt.Errorf("getting provider: %w", err)
}

metadataStore := metadata.New(clientset, cfg)

clusterIDChangedHandler := func(clusterID string) {
if err := metadataStore.StoreMetadataSecret(ctx, &metadata.Metadata{
ClusterID: clusterID,
}); err != nil {
log.Warnf("failed to store metadata in a secret: %v", err)
}

clusterIDChanged(clusterID)
}

log.Data["provider"] = provider.Name()
log.Infof("using provider %q", provider.Name())

Expand All @@ -189,10 +202,10 @@ func runAgentMode(ctx context.Context, castaiclient castai.Client, log *logrus.E
return fmt.Errorf("registering cluster: %w", err)
}
clusterID = reg.ClusterID
clusterIDChanged(clusterID)
clusterIDChangedHandler(clusterID)
log.Infof("cluster registered: %v, clusterID: %s", reg, clusterID)
} else {
clusterIDChanged(clusterID)
clusterIDChangedHandler(clusterID)
log.Infof("clusterID: %s provided by env variable", clusterID)
}

Expand Down
12 changes: 12 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ type Config struct {
PprofPort int `mapstructure:"pprof.port"`
HealthzPort int `mapstructure:"healthz_port"`

MetadataStore *MetadataStoreConfig `mapstructure:"metadata_store"`

LeaderElection LeaderElectionConfig `mapstructure:"leader_election"`

MonitorMetadata string `mapstructure:"monitor_metadata"`
Expand Down Expand Up @@ -110,6 +112,12 @@ type Static struct {
ClusterID string `mapstructure:"cluster_id"`
}

type MetadataStoreConfig struct {
Enabled bool `mapstructure:"enabled"`
Namespace string `mapstructure:"namespace"`
SecretName string `mapstructure:"secret_name"`
}

type Anywhere struct {
ClusterName string `mapstructure:"cluster_name"`
}
Expand Down Expand Up @@ -169,6 +177,10 @@ func Get() Config {
viper.SetDefault("leader_election.lock_name", "agent-leader-election-lock")
viper.SetDefault("leader_election.namespace", "castai-agent")

viper.SetDefault("metadata_store.enabled", false)
viper.SetDefault("metadata_store.secret_name", "castai-agent-metadata")
viper.SetDefault("metadata_store.namespace", "castai-agent")

viper.AutomaticEnv()
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AllowEmptyEnv(true)
Expand Down
54 changes: 54 additions & 0 deletions internal/services/metadata/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package metadata

import (
"context"

"k8s.io/apimachinery/pkg/api/errors"

"castai-agent/internal/config"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)

type Store interface {
// StoreMetadataSecret stores relevant agent runtime metadata in a secret.
StoreMetadataSecret(ctx context.Context, metadata *Metadata) error
}

var _ Store = (*StoreImpl)(nil)

type StoreImpl struct {
clientset kubernetes.Interface
cfg config.Config
}

func New(clientset kubernetes.Interface, cfg config.Config) *StoreImpl {
return &StoreImpl{
clientset: clientset,
cfg: cfg,
}
}

func (s *StoreImpl) StoreMetadataSecret(ctx context.Context, metadata *Metadata) error {
if !s.cfg.MetadataStore.Enabled {
return nil
}

secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: s.cfg.MetadataStore.SecretName,
Namespace: s.cfg.MetadataStore.Namespace,
},
StringData: map[string]string{
"CLUSTER_ID": metadata.ClusterID,
},
}

_, err := s.clientset.CoreV1().Secrets(s.cfg.MetadataStore.Namespace).Update(ctx, secret, metav1.UpdateOptions{})
if errors.IsNotFound(err) {
_, err = s.clientset.CoreV1().Secrets(s.cfg.MetadataStore.Namespace).Create(ctx, secret, metav1.CreateOptions{})
}

return err
}
97 changes: 97 additions & 0 deletions internal/services/metadata/store_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package metadata

import (
"context"
"testing"

"castai-agent/internal/config"

Check failure on line 7 in internal/services/metadata/store_test.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gci`-ed with --skip-generated -s standard -s default -s prefix(castai-agent) (gci)
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fakeclientset "k8s.io/client-go/kubernetes/fake"
)

func TestStoreImpl_StoreMetadataSecret(t *testing.T) {
tests := []struct {
name string
cfg config.Config
metadata *Metadata
existingSecret *corev1.Secret
expectedError bool
}{
{
name: "should store metadata successfully when secret does not exist",
cfg: config.Config{
MetadataStore: &config.MetadataStoreConfig{
Enabled: true,
SecretName: "castai-agent-metadata",
Namespace: "default",
},
},
metadata: &Metadata{
ClusterID: "test-cluster-id",
},
expectedError: false,
},
{
name: "should store metadata successfully when secret exists",
cfg: config.Config{
MetadataStore: &config.MetadataStoreConfig{
Enabled: true,
SecretName: "castai-agent-metadata",
Namespace: "default",
},
},
metadata: &Metadata{
ClusterID: "test-cluster-id",
},
existingSecret: &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "castai-agent-metadata",
Namespace: "default",
},
StringData: map[string]string{
"CLUSTER_ID": "original-test-cluster-id",
},
},
expectedError: false,
},
{
name: "should not store metadata when store is disabled",
cfg: config.Config{
MetadataStore: &config.MetadataStoreConfig{
Enabled: false,
},
},
metadata: &Metadata{
ClusterID: "test-cluster-id",
},
expectedError: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := require.New(t)
clientset := fakeclientset.NewSimpleClientset()
store := New(clientset, tt.cfg)

if tt.existingSecret != nil {
_, err := clientset.CoreV1().Secrets(tt.cfg.MetadataStore.Namespace).Create(context.Background(), tt.existingSecret, metav1.CreateOptions{})
r.NoError(err)
}

err := store.StoreMetadataSecret(context.Background(), tt.metadata)
if tt.expectedError {
r.Error(err)
} else {
r.NoError(err)
if tt.cfg.MetadataStore.Enabled {
secret, err := clientset.CoreV1().Secrets(tt.cfg.MetadataStore.Namespace).Get(context.Background(), tt.cfg.MetadataStore.SecretName, metav1.GetOptions{})
r.NoError(err)
r.Equal(tt.metadata.ClusterID, secret.StringData["CLUSTER_ID"])
}
}
})
}
}
5 changes: 5 additions & 0 deletions internal/services/metadata/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package metadata

type Metadata struct {
ClusterID string
}

0 comments on commit 8d37568

Please sign in to comment.