Files
grafana/pkg/storage/secret/metadata/keeper_store_test.go
T
Matheus Macabu 2c4bbf8b1d Secrets: Reduce amount of feature toggle checks to only app entrypoint (#108110)
* Secrets: Reduce amount of feature toggle checks to only app entrypoint

* Wire: Fix merge conflict

* Wire: Fix merge conflict
2025-07-16 10:56:59 +02:00

342 lines
11 KiB
Go

package metadata_test
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/trace/noop"
"k8s.io/utils/ptr"
secretv1beta1 "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1"
"github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
"github.com/grafana/grafana/pkg/registry/apis/secret/xkube"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/storage/secret/database"
"github.com/grafana/grafana/pkg/storage/secret/metadata"
"github.com/grafana/grafana/pkg/storage/secret/migrator"
)
func Test_KeeperMetadataStorage_GetKeeperConfig(t *testing.T) {
t.Parallel()
defaultKeeperName := "kp-test"
defaultKeeperNS := "default"
testKeeper := &secretv1beta1.Keeper{
Spec: secretv1beta1.KeeperSpec{
Description: "description",
Aws: &secretv1beta1.KeeperAWSConfig{},
},
}
testKeeper.Name = defaultKeeperName
testKeeper.Namespace = defaultKeeperNS
t.Run("get the system keeper config", func(t *testing.T) {
t.Parallel()
ctx := context.Background()
keeperMetadataStorage := initStorage(t)
// get system keeper config
keeperConfig, err := keeperMetadataStorage.GetKeeperConfig(ctx, defaultKeeperNS, nil, contracts.ReadOpts{})
require.NoError(t, err)
require.IsType(t, &secretv1beta1.SystemKeeperConfig{}, keeperConfig)
})
t.Run("get test keeper config", func(t *testing.T) {
t.Parallel()
ctx := context.Background()
keeperMetadataStorage := initStorage(t)
//
_, err := keeperMetadataStorage.Create(ctx, testKeeper, "testuser")
require.NoError(t, err)
keeperConfig, err := keeperMetadataStorage.GetKeeperConfig(ctx, defaultKeeperNS, &defaultKeeperName, contracts.ReadOpts{})
require.NoError(t, err)
require.NotNil(t, keeperConfig)
require.NotEmpty(t, keeperConfig.Type())
})
t.Run("get test keeper config when listing", func(t *testing.T) {
t.Parallel()
ctx := context.Background()
keeperMetadataStorage := initStorage(t)
//
_, err := keeperMetadataStorage.Create(ctx, testKeeper, "testuser")
require.NoError(t, err)
keeperList, err := keeperMetadataStorage.List(ctx, xkube.Namespace(defaultKeeperNS))
require.NoError(t, err)
require.NotEmpty(t, keeperList)
require.Len(t, keeperList, 1)
keeper := keeperList[0]
require.Equal(t, "kp-test", keeper.Name)
require.Equal(t, "default", keeper.Namespace)
require.Equal(t, "description", keeper.Spec.Description)
})
t.Run("create a keeper and then delete it", func(t *testing.T) {
t.Parallel()
ctx := context.Background()
keeperMetadataStorage := initStorage(t)
keeperTest := "kp-test2"
keeperNamespaceTest := "ns"
testKeeper := &secretv1beta1.Keeper{
Spec: secretv1beta1.KeeperSpec{
Description: "another description",
Aws: &secretv1beta1.KeeperAWSConfig{},
},
}
testKeeper.Name = keeperTest
testKeeper.Namespace = keeperNamespaceTest
// create the keeper
_, err := keeperMetadataStorage.Create(ctx, testKeeper, "testuser")
require.NoError(t, err)
// we are able to get it
keeperConfig, err := keeperMetadataStorage.GetKeeperConfig(ctx, keeperNamespaceTest, &keeperTest, contracts.ReadOpts{})
require.NoError(t, err)
require.NotNil(t, keeperConfig)
require.NotEmpty(t, keeperConfig.Type())
// now we delete it
delErr := keeperMetadataStorage.Delete(ctx, xkube.Namespace(keeperNamespaceTest), keeperTest)
require.NoError(t, delErr)
// and we shouldn't be able to get it again
_, getErr := keeperMetadataStorage.GetKeeperConfig(ctx, keeperNamespaceTest, &keeperTest, contracts.ReadOpts{})
require.Errorf(t, getErr, "keeper not found")
})
t.Run("create, update and validate keeper", func(t *testing.T) {
t.Parallel()
ctx := context.Background()
keeperMetadataStorage := initStorage(t)
keeperTest := "kp-test3"
keeperNamespaceTest := "ns"
// Create initial keeper
initialKeeper := &secretv1beta1.Keeper{
Spec: secretv1beta1.KeeperSpec{
Description: "initial description",
Aws: &secretv1beta1.KeeperAWSConfig{},
},
}
initialKeeper.Name = keeperTest
initialKeeper.Namespace = keeperNamespaceTest
// Create the keeper
_, err := keeperMetadataStorage.Create(ctx, initialKeeper, "testuser")
require.NoError(t, err)
// Validate that the description was set
keeper, err := keeperMetadataStorage.Read(ctx, xkube.Namespace(keeperNamespaceTest), keeperTest, contracts.ReadOpts{})
require.NoError(t, err)
require.Equal(t, "initial description", keeper.Spec.Description)
// Update the keeper with new values
updatedKeeper := &secretv1beta1.Keeper{
Spec: secretv1beta1.KeeperSpec{
Description: "updated description",
Aws: &secretv1beta1.KeeperAWSConfig{},
},
}
updatedKeeper.Name = keeperTest
updatedKeeper.Namespace = keeperNamespaceTest
// Perform the update
_, err = keeperMetadataStorage.Update(ctx, updatedKeeper, "testuser")
require.NoError(t, err)
// Validate updated values
updatedConfig, err := keeperMetadataStorage.GetKeeperConfig(ctx, keeperNamespaceTest, &keeperTest, contracts.ReadOpts{})
require.NoError(t, err)
require.NotNil(t, updatedConfig)
require.NotEmpty(t, updatedConfig.Type())
// Validate that the description was updated
updatedKeeper, err = keeperMetadataStorage.Read(ctx, xkube.Namespace(keeperNamespaceTest), keeperTest, contracts.ReadOpts{})
require.NoError(t, err)
require.Equal(t, "updated description", updatedKeeper.Spec.Description)
})
t.Run("update keeper with different AWS configuration", func(t *testing.T) {
t.Parallel()
ctx := context.Background()
keeperMetadataStorage := initStorage(t)
keeperTest := "kp-test4"
keeperNamespaceTest := "ns"
// Create initial keeper with first AWS config
initialKeeper := &secretv1beta1.Keeper{
Spec: secretv1beta1.KeeperSpec{
Description: "initial description",
Aws: &secretv1beta1.KeeperAWSConfig{
AccessKeyID: secretv1beta1.KeeperCredentialValue{
ValueFromEnv: "AWS_ACCESS_KEY_ID_1",
},
SecretAccessKey: secretv1beta1.KeeperCredentialValue{
ValueFromEnv: "AWS_SECRET_ACCESS_KEY_1",
},
KmsKeyID: ptr.To("kms-key-id-1"),
},
},
}
initialKeeper.Name = keeperTest
initialKeeper.Namespace = keeperNamespaceTest
// Create the keeper
_, err := keeperMetadataStorage.Create(ctx, initialKeeper, "testuser")
require.NoError(t, err)
// Verify initial AWS config
keeper, err := keeperMetadataStorage.Read(ctx, xkube.Namespace(keeperNamespaceTest), keeperTest, contracts.ReadOpts{})
require.NoError(t, err)
require.Equal(t, "AWS_ACCESS_KEY_ID_1", keeper.Spec.Aws.AccessKeyID.ValueFromEnv)
require.Equal(t, "AWS_SECRET_ACCESS_KEY_1", keeper.Spec.Aws.SecretAccessKey.ValueFromEnv)
require.Equal(t, "kms-key-id-1", *keeper.Spec.Aws.KmsKeyID)
// Update with new AWS config
updatedKeeper := &secretv1beta1.Keeper{
Spec: secretv1beta1.KeeperSpec{
Description: "updated description",
Aws: &secretv1beta1.KeeperAWSConfig{
AccessKeyID: secretv1beta1.KeeperCredentialValue{
ValueFromEnv: "AWS_ACCESS_KEY_ID_2",
},
SecretAccessKey: secretv1beta1.KeeperCredentialValue{
ValueFromEnv: "AWS_SECRET_ACCESS_KEY_2",
},
KmsKeyID: ptr.To("kms-key-id-2"),
},
},
}
updatedKeeper.Name = keeperTest
updatedKeeper.Namespace = keeperNamespaceTest
// Perform the update
_, err = keeperMetadataStorage.Update(ctx, updatedKeeper, "testuser")
require.NoError(t, err)
// Verify updated AWS config
updatedKeeper, err = keeperMetadataStorage.Read(ctx, xkube.Namespace(keeperNamespaceTest), keeperTest, contracts.ReadOpts{})
require.NoError(t, err)
require.Equal(t, "AWS_ACCESS_KEY_ID_2", updatedKeeper.Spec.Aws.AccessKeyID.ValueFromEnv)
require.Equal(t, "AWS_SECRET_ACCESS_KEY_2", updatedKeeper.Spec.Aws.SecretAccessKey.ValueFromEnv)
require.Equal(t, "kms-key-id-2", *updatedKeeper.Spec.Aws.KmsKeyID)
})
t.Run("list keepers in empty namespace", func(t *testing.T) {
t.Parallel()
ctx := context.Background()
keeperMetadataStorage := initStorage(t)
keeperList, err := keeperMetadataStorage.List(ctx, "")
require.NoError(t, err)
require.Empty(t, keeperList)
})
t.Run("read non-existent keeper", func(t *testing.T) {
t.Parallel()
ctx := context.Background()
keeperMetadataStorage := initStorage(t)
_, err := keeperMetadataStorage.Read(ctx, "ns", "non-existent", contracts.ReadOpts{})
require.Error(t, err)
require.Equal(t, contracts.ErrKeeperNotFound, err)
})
t.Run("update keeper with different namespace", func(t *testing.T) {
t.Parallel()
ctx := context.Background()
keeperMetadataStorage := initStorage(t)
keeperTest := "kp-test5"
keeperNamespaceTest := "ns1"
// Create initial keeper
initialKeeper := &secretv1beta1.Keeper{
Spec: secretv1beta1.KeeperSpec{
Description: "initial description",
Aws: &secretv1beta1.KeeperAWSConfig{
AccessKeyID: secretv1beta1.KeeperCredentialValue{
ValueFromEnv: "AWS_ACCESS_KEY_ID",
},
SecretAccessKey: secretv1beta1.KeeperCredentialValue{
ValueFromEnv: "AWS_SECRET_ACCESS_KEY",
},
},
},
}
initialKeeper.Name = keeperTest
initialKeeper.Namespace = keeperNamespaceTest
// Create the keeper
_, err := keeperMetadataStorage.Create(ctx, initialKeeper, "testuser")
require.NoError(t, err)
// Try to update with different namespace
updatedKeeper := initialKeeper.DeepCopy()
updatedKeeper.Namespace = "ns2"
updatedKeeper.Spec.Description = "updated description"
_, err = keeperMetadataStorage.Update(ctx, updatedKeeper, "testuser")
// should this return contracts.ErrKeeperNotFound directly?
// require.Equal(t, contracts.ErrKeeperNotFound, err)
require.Error(t, err, "db failure: keeper not found")
// Verify original keeper is unchanged
keeper, err := keeperMetadataStorage.Read(ctx, xkube.Namespace(keeperNamespaceTest), keeperTest, contracts.ReadOpts{})
require.NoError(t, err)
require.Equal(t, "initial description", keeper.Spec.Description)
})
t.Run("update non-existent keeper", func(t *testing.T) {
t.Parallel()
ctx := context.Background()
keeperMetadataStorage := initStorage(t)
nonExistentKeeper := &secretv1beta1.Keeper{
Spec: secretv1beta1.KeeperSpec{
Description: "some description",
Aws: &secretv1beta1.KeeperAWSConfig{},
},
}
nonExistentKeeper.Name = "non-existent"
nonExistentKeeper.Namespace = "ns"
_, err := keeperMetadataStorage.Update(ctx, nonExistentKeeper, "testuser")
require.Error(t, err, "db failure: keeper not found")
})
}
func initStorage(t *testing.T) contracts.KeeperMetadataStorage {
testDB := sqlstore.NewTestStore(t, sqlstore.WithMigrator(migrator.New()))
tracer := noop.NewTracerProvider().Tracer("test")
db := database.ProvideDatabase(testDB, tracer)
// Initialize the keeper storage
keeperMetadataStorage, err := metadata.ProvideKeeperMetadataStorage(db, tracer, nil)
require.NoError(t, err)
return keeperMetadataStorage
}