72d9de3a0f
* add special handling on the plugin gathering side to check whether secrets manager plugins are enabled or not * show disabled badge in front end if the plugin is not enabled * Only show error in disabled badge hover if one is present (otherwise it shows "undefined") * refactor to make use of fields already available in the DTO * fix typo * if there is no error returned for the plugin, just show 'disabled' * fix typo * Update public/app/features/plugins/admin/components/Badges/PluginDisabledBadge.tsx Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * Update frontendsettings.go add clarifying comment * fix unit test * rework task to use new frontend property combined with plugin type to determine if the plugin should be disabled * Update helpers.test.ts revert test change * fix unit test * show custom uninstall message if the plugin is a secrets manager * bogus commit to trigger precommit * undo commit * run precommit manually * add some consts * refactor a bit to pull plugin error management up a level * re-add code squashed in merge * fix compile issues * add code to set plugin error fatal flag after secret migration * refactor to move plugin startup out of Should Check func * re-add important check * make plugin startup errors fatal the first time we set a secret on the plugin * rename func to make intent clearler * remove unnecessary duplicate code from plugin mig * fix compile error * fix more compile errors * add some extra logging to secrets migration * have remote_plugin secret service managed plugin error fatal flag directly * add blank file for eventual unit tests * fix linting issues * changes from PR review * quick bit of cleanup * add comment explaining design decision * move more common test helpers to file * slightly update to first time Get secret call * add unit tests * remove override func from provider * fix linting issues * add test cleanup step * add some comments about refactoring to hacky test function Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
108 lines
3.8 KiB
Go
108 lines
3.8 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/grafana/grafana/pkg/infra/kvstore"
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
"github.com/grafana/grafana/pkg/services/datasources"
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
|
)
|
|
|
|
const (
|
|
// Not set means migration has not happened
|
|
secretMigrationStatusKey = "secretMigrationStatus"
|
|
// Migration happened with disableSecretCompatibility set to false
|
|
compatibleSecretMigrationValue = "compatible"
|
|
// Migration happened with disableSecretCompatibility set to true
|
|
completeSecretMigrationValue = "complete"
|
|
)
|
|
|
|
type DataSourceSecretMigrationService struct {
|
|
dataSourcesService datasources.DataSourceService
|
|
kvStore *kvstore.NamespacedKVStore
|
|
features featuremgmt.FeatureToggles
|
|
log log.Logger
|
|
}
|
|
|
|
func ProvideDataSourceMigrationService(
|
|
dataSourcesService datasources.DataSourceService,
|
|
kvStore kvstore.KVStore,
|
|
features featuremgmt.FeatureToggles,
|
|
) *DataSourceSecretMigrationService {
|
|
return &DataSourceSecretMigrationService{
|
|
dataSourcesService: dataSourcesService,
|
|
kvStore: kvstore.WithNamespace(kvStore, 0, secretType),
|
|
features: features,
|
|
log: log.New("secrets.migration"),
|
|
}
|
|
}
|
|
|
|
func (s *DataSourceSecretMigrationService) Migrate(ctx context.Context) error {
|
|
migrationStatus, _, err := s.kvStore.Get(ctx, secretMigrationStatusKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.log.Debug(fmt.Sprint("secret migration status is ", migrationStatus))
|
|
// If this flag is true, delete secrets from the legacy secrets store as they are migrated
|
|
disableSecretsCompatibility := s.features.IsEnabled(featuremgmt.FlagDisableSecretsCompatibility)
|
|
// If migration hasn't happened, migrate to unified secrets and keep copy in legacy
|
|
// If a complete migration happened and now backwards compatibility is enabled, copy secrets back to legacy
|
|
needCompatibility := migrationStatus != compatibleSecretMigrationValue && !disableSecretsCompatibility
|
|
// If migration hasn't happened, migrate to unified secrets and delete from legacy
|
|
// If a compatible migration happened and now compatibility is disabled, delete secrets from legacy
|
|
needMigration := migrationStatus != completeSecretMigrationValue && disableSecretsCompatibility
|
|
|
|
if needCompatibility || needMigration {
|
|
s.log.Debug("performing secret migration", "needs migration", needMigration, "needs compatibility", needCompatibility)
|
|
query := &datasources.GetAllDataSourcesQuery{}
|
|
err := s.dataSourcesService.GetAllDataSources(ctx, query)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, ds := range query.Result {
|
|
secureJsonData, err := s.dataSourcesService.DecryptedValues(ctx, ds)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Secrets are set by the update data source function if the SecureJsonData is set in the command
|
|
// Secrets are deleted by the update data source function if the disableSecretsCompatibility flag is enabled
|
|
err = s.dataSourcesService.UpdateDataSource(ctx, &datasources.UpdateDataSourceCommand{
|
|
Id: ds.Id,
|
|
OrgId: ds.OrgId,
|
|
Uid: ds.Uid,
|
|
Name: ds.Name,
|
|
JsonData: ds.JsonData,
|
|
SecureJsonData: secureJsonData,
|
|
|
|
// These are needed by the SQL function due to UseBool and MustCols
|
|
IsDefault: ds.IsDefault,
|
|
BasicAuth: ds.BasicAuth,
|
|
WithCredentials: ds.WithCredentials,
|
|
ReadOnly: ds.ReadOnly,
|
|
User: ds.User,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
var newMigStatus string
|
|
if disableSecretsCompatibility {
|
|
newMigStatus = completeSecretMigrationValue
|
|
} else {
|
|
newMigStatus = compatibleSecretMigrationValue
|
|
}
|
|
err = s.kvStore.Set(ctx, secretMigrationStatusKey, newMigStatus)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.log.Debug(fmt.Sprint("set secret migration status to ", newMigStatus))
|
|
}
|
|
|
|
return nil
|
|
}
|