150 lines
4.4 KiB
Go
150 lines
4.4 KiB
Go
package apistore
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
|
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
|
secret "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
|
)
|
|
|
|
// prepareSecureValues will create any new secure values and register changes inside the provided objectForStorage
|
|
// any call to this function MUST be followed by a call to info.finish(ctx, nil, store) to ensure that the secure values are cleaned up
|
|
func prepareSecureValues(ctx context.Context, store secret.InlineSecureValueSupport, obj utils.GrafanaMetaAccessor, previousObject utils.GrafanaMetaAccessor, v *objectForStorage) (err error) {
|
|
secure, err := obj.GetSecureValues()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Owner reference for inline values
|
|
v.ref = utils.ToObjectReference(obj)
|
|
|
|
var previous common.InlineSecureValues
|
|
if previousObject == nil {
|
|
if len(secure) == 0 {
|
|
return nil // nothing needs to change
|
|
}
|
|
if store == nil {
|
|
return fmt.Errorf("secure value support is not configured (create)")
|
|
}
|
|
previous = make(common.InlineSecureValues, 0)
|
|
} else {
|
|
// Merge in any values from the previous object and handle remove
|
|
previous, err = previousObject.GetSecureValues()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, p := range previous {
|
|
if p.Name == "" || p.Remove || !p.Create.IsZero() {
|
|
return fmt.Errorf("invalid state, saved values must only have a name")
|
|
}
|
|
}
|
|
|
|
// Keep exactly what we had before
|
|
if len(secure) == 0 {
|
|
if len(previous) > 0 {
|
|
return obj.SetSecureValues(previous)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
if store == nil {
|
|
return fmt.Errorf("secure value support is not configured (update)")
|
|
}
|
|
}
|
|
|
|
for k, val := range secure {
|
|
before := previous[k]
|
|
if val.Name == "" {
|
|
if before.Name != "" { // implicitly delete previous secure value if the same field no longer references it
|
|
v.deleteSecureValues = append(v.deleteSecureValues, before.Name)
|
|
delete(previous, k)
|
|
}
|
|
if val.Remove {
|
|
if before.Name == "" {
|
|
return fmt.Errorf("cannot remove secure value '%s', it did not exist in the previous value", k)
|
|
}
|
|
delete(secure, k)
|
|
v.hasChanged = true
|
|
continue
|
|
}
|
|
if !val.Create.IsZero() {
|
|
n, err := store.CreateInline(ctx, v.ref, val.Create)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
v.createdSecureValues = append(v.createdSecureValues, n)
|
|
v.hasChanged = true
|
|
secure[k] = common.InlineSecureValue{Name: n}
|
|
continue
|
|
}
|
|
return fmt.Errorf("invalid secure value state: %s", k)
|
|
}
|
|
|
|
// The name changed from the previously stored value
|
|
if before.Name != "" && before.Name != val.Name {
|
|
// This can happen when explicitly shifting from an inline value to a shared secret
|
|
v.deleteSecureValues = append(v.deleteSecureValues, before.Name)
|
|
v.hasChanged = true
|
|
}
|
|
|
|
delete(previous, k)
|
|
}
|
|
|
|
// Keep all previous values that were not referenced in the update
|
|
for k, v := range previous {
|
|
_, found := secure[k]
|
|
if !found {
|
|
secure[k] = v // the previous value
|
|
}
|
|
}
|
|
|
|
return cleanupSecureValues(v, obj, secure)
|
|
}
|
|
|
|
// make sure the registered changes are unique and valid
|
|
func cleanupSecureValues(v *objectForStorage, obj utils.GrafanaMetaAccessor, secure common.InlineSecureValues) error {
|
|
// Make sure the deleted list is unique and does not contain any referenced values
|
|
if len(v.deleteSecureValues) > 0 && len(secure) > 0 {
|
|
confirm := v.deleteSecureValues
|
|
v.deleteSecureValues = make([]string, 0, len(v.deleteSecureValues))
|
|
used := make(map[string]bool, len(secure))
|
|
for _, v := range secure {
|
|
used[v.Name] = true
|
|
}
|
|
for _, name := range confirm {
|
|
if _, ok := used[name]; ok {
|
|
continue
|
|
}
|
|
used[name] = true
|
|
v.deleteSecureValues = append(v.deleteSecureValues, name)
|
|
}
|
|
}
|
|
|
|
if len(v.deleteSecureValues) > 0 || len(v.createdSecureValues) > 0 {
|
|
v.hasChanged = true
|
|
}
|
|
return obj.SetSecureValues(secure)
|
|
}
|
|
|
|
// Mutation hook that will delete secure values
|
|
func handleSecureValuesDelete(ctx context.Context, store secret.InlineSecureValueSupport, obj utils.GrafanaMetaAccessor) error {
|
|
secure, err := obj.GetSecureValues()
|
|
if err != nil || len(secure) == 0 {
|
|
return err
|
|
}
|
|
|
|
if store == nil {
|
|
return fmt.Errorf("secure value support is not configured (delete)")
|
|
}
|
|
|
|
owner := utils.ToObjectReference(obj)
|
|
for _, v := range secure {
|
|
if err = store.DeleteWhenOwnedByResource(ctx, owner, v.Name); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return obj.SetSecureValues(nil) // remove them from the object
|
|
}
|