2022-08-25 16:04:44 -05:00
|
|
|
package migrations
|
2022-07-19 12:42:23 -05:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-08-23 10:21:54 -05:00
|
|
|
"errors"
|
2022-08-10 14:23:55 -05:00
|
|
|
"fmt"
|
2022-07-19 12:42:23 -05:00
|
|
|
|
2022-10-19 08:02:15 -05:00
|
|
|
"github.com/grafana/grafana/pkg/infra/db"
|
2022-07-25 11:37:47 -05:00
|
|
|
"github.com/grafana/grafana/pkg/infra/kvstore"
|
2022-08-10 14:47:03 -05:00
|
|
|
"github.com/grafana/grafana/pkg/plugins"
|
2022-07-19 12:42:23 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/secrets"
|
2022-08-25 16:04:44 -05:00
|
|
|
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
2022-07-19 12:42:23 -05:00
|
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
|
|
)
|
|
|
|
|
2022-09-02 10:39:18 -05:00
|
|
|
var errSecretStoreIsNotPlugin = errors.New("SecretsKVStore is not a SecretsKVStorePlugin")
|
|
|
|
|
2022-08-24 15:24:50 -05:00
|
|
|
// MigrateToPluginService This migrator will handle migration of datasource secrets (aka Unified secrets)
|
2022-07-19 12:42:23 -05:00
|
|
|
// into the plugin secrets configured
|
2022-08-24 15:24:50 -05:00
|
|
|
type MigrateToPluginService struct {
|
2022-08-25 16:04:44 -05:00
|
|
|
secretsStore secretskvs.SecretsKVStore
|
2022-07-19 12:42:23 -05:00
|
|
|
cfg *setting.Cfg
|
2022-10-19 08:02:15 -05:00
|
|
|
sqlStore db.DB
|
2022-07-19 12:42:23 -05:00
|
|
|
secretsService secrets.Service
|
2022-07-25 11:37:47 -05:00
|
|
|
kvstore kvstore.KVStore
|
2022-08-10 14:47:03 -05:00
|
|
|
manager plugins.SecretsPluginManager
|
2022-07-19 12:42:23 -05:00
|
|
|
}
|
|
|
|
|
2022-08-24 15:24:50 -05:00
|
|
|
func ProvideMigrateToPluginService(
|
2022-08-25 16:04:44 -05:00
|
|
|
secretsStore secretskvs.SecretsKVStore,
|
2022-07-19 12:42:23 -05:00
|
|
|
cfg *setting.Cfg,
|
2022-10-19 08:02:15 -05:00
|
|
|
sqlStore db.DB,
|
2022-07-19 12:42:23 -05:00
|
|
|
secretsService secrets.Service,
|
2022-07-25 11:37:47 -05:00
|
|
|
kvstore kvstore.KVStore,
|
2022-08-10 14:47:03 -05:00
|
|
|
manager plugins.SecretsPluginManager,
|
2022-08-24 15:24:50 -05:00
|
|
|
) *MigrateToPluginService {
|
|
|
|
return &MigrateToPluginService{
|
2022-07-19 12:42:23 -05:00
|
|
|
secretsStore: secretsStore,
|
|
|
|
cfg: cfg,
|
|
|
|
sqlStore: sqlStore,
|
|
|
|
secretsService: secretsService,
|
2022-07-25 11:37:47 -05:00
|
|
|
kvstore: kvstore,
|
2022-08-10 14:47:03 -05:00
|
|
|
manager: manager,
|
2022-07-19 12:42:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-24 15:24:50 -05:00
|
|
|
func (s *MigrateToPluginService) Migrate(ctx context.Context) error {
|
2022-09-08 15:26:47 -05:00
|
|
|
err := secretskvs.EvaluateRemoteSecretsPlugin(ctx, s.manager, s.cfg)
|
|
|
|
hasStarted := secretskvs.HasPluginStarted(ctx, s.manager)
|
|
|
|
if err == nil && hasStarted {
|
2022-08-25 16:04:44 -05:00
|
|
|
logger.Debug("starting migration of unified secrets to the plugin")
|
2022-08-23 10:21:54 -05:00
|
|
|
// we need to get the fallback store since in this scenario the secrets store would be the plugin.
|
2022-09-02 10:39:18 -05:00
|
|
|
tmpStore, err := secretskvs.GetUnwrappedStoreFromCache(s.secretsStore)
|
|
|
|
if err != nil {
|
|
|
|
tmpStore = s.secretsStore
|
|
|
|
logger.Warn("secret store is not cached, this is unexpected - continuing migration anyway.")
|
2022-07-25 11:37:47 -05:00
|
|
|
}
|
2022-09-02 10:39:18 -05:00
|
|
|
pluginStore, ok := tmpStore.(*secretskvs.SecretsKVStorePlugin)
|
|
|
|
if !ok {
|
|
|
|
return errSecretStoreIsNotPlugin
|
|
|
|
}
|
|
|
|
fallbackStore := pluginStore.Fallback()
|
2022-07-25 11:37:47 -05:00
|
|
|
|
|
|
|
// before we start migrating, check see if plugin startup failures were already fatal
|
2022-08-25 16:04:44 -05:00
|
|
|
namespacedKVStore := secretskvs.GetNamespacedKVStore(s.kvstore)
|
|
|
|
wasFatal, err := secretskvs.IsPluginStartupErrorFatal(ctx, namespacedKVStore)
|
2022-07-25 11:37:47 -05:00
|
|
|
if err != nil {
|
2022-08-25 16:04:44 -05:00
|
|
|
logger.Warn("unable to determine whether plugin startup failures are fatal - continuing migration anyway.")
|
2022-07-19 12:42:23 -05:00
|
|
|
}
|
|
|
|
|
2022-09-02 10:39:18 -05:00
|
|
|
var allSec []secretskvs.Item
|
|
|
|
var totalSec int
|
|
|
|
// during migration we need to have fallback enabled while we move secrets to plugin
|
|
|
|
err = pluginStore.WithFallbackEnabled(func() error {
|
|
|
|
// get all secrets in the fallback store
|
|
|
|
allSec, err = fallbackStore.GetAll(ctx)
|
2022-07-19 12:42:23 -05:00
|
|
|
if err != nil {
|
2022-09-02 10:39:18 -05:00
|
|
|
return nil
|
2022-07-19 12:42:23 -05:00
|
|
|
}
|
2022-09-02 10:39:18 -05:00
|
|
|
totalSec := len(allSec)
|
|
|
|
logger.Debug(fmt.Sprintf("Total amount of secrets to migrate: %d", totalSec))
|
|
|
|
|
|
|
|
// We just set it again as the current secret store should be the plugin secret
|
|
|
|
for i, sec := range allSec {
|
|
|
|
logger.Debug(fmt.Sprintf("Migrating secret %d of %d", i+1, totalSec), "current", i+1, "secretCount", totalSec)
|
|
|
|
err = pluginStore.Set(ctx, *sec.OrgId, *sec.Namespace, *sec.Type, sec.Value)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2022-07-19 12:42:23 -05:00
|
|
|
}
|
2022-09-02 10:39:18 -05:00
|
|
|
|
2022-07-19 12:42:23 -05:00
|
|
|
// as no err was returned, when we delete all the secrets from the sql store
|
2022-09-02 10:39:18 -05:00
|
|
|
logger.Debug("migrated unified secrets to plugin", "number of secrets", totalSec)
|
2022-07-25 11:37:47 -05:00
|
|
|
for index, sec := range allSec {
|
2022-08-25 16:04:44 -05:00
|
|
|
logger.Debug(fmt.Sprintf("Cleaning secret %d of %d", index+1, totalSec), "current", index+1, "secretCount", totalSec)
|
2022-08-10 14:23:55 -05:00
|
|
|
|
2022-08-23 10:21:54 -05:00
|
|
|
err = fallbackStore.Del(ctx, *sec.OrgId, *sec.Namespace, *sec.Type)
|
2022-07-19 12:42:23 -05:00
|
|
|
if err != nil {
|
2022-08-25 16:04:44 -05:00
|
|
|
logger.Error("plugin migrator encountered error while deleting unified secrets")
|
2022-07-25 11:37:47 -05:00
|
|
|
if index == 0 && !wasFatal {
|
|
|
|
// old unified secrets still exists, so plugin startup errors are still not fatal, unless they were before we started
|
2022-08-25 16:04:44 -05:00
|
|
|
err := secretskvs.SetPluginStartupErrorFatal(ctx, namespacedKVStore, false)
|
2022-07-25 11:37:47 -05:00
|
|
|
if err != nil {
|
2022-08-25 16:04:44 -05:00
|
|
|
logger.Error("error reverting plugin failure fatal status", "error", err.Error())
|
2022-07-25 11:37:47 -05:00
|
|
|
} else {
|
2022-08-25 16:04:44 -05:00
|
|
|
logger.Debug("application will continue to function without the secrets plugin")
|
2022-07-25 11:37:47 -05:00
|
|
|
}
|
|
|
|
}
|
2022-07-19 12:42:23 -05:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2022-08-25 16:04:44 -05:00
|
|
|
logger.Debug("deleted unified secrets after migration", "number of secrets", totalSec)
|
2022-07-19 12:42:23 -05:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|