Provisioning: concurrent deletes in finalizers and 404 handling (#113155)

* fix: concurrent deletes in finalizers and 404 handling

* chore: feedback review

* fix: broken tests
This commit is contained in:
Costa Alexoglou
2025-10-30 11:55:36 +01:00
committed by GitHub
parent cb86be2e32
commit bbfb8268d1
10 changed files with 290 additions and 53 deletions
@@ -0,0 +1,29 @@
package cuevalidator
import (
"sync"
"cuelang.org/go/cue"
cuejson "cuelang.org/go/encoding/json"
)
// Validator provides thread-safe CUE schema validation.
//
// CUE is not safe for concurrent use: https://github.com/cue-lang/cue/discussions/1205#discussioncomment-1189238
// This validator uses a mutex to protect concurrent access to the underlying CUE validation.
type Validator struct {
schema cue.Value
mu sync.Mutex
}
func NewValidator(schema cue.Value) *Validator {
return &Validator{
schema: schema,
}
}
func (v *Validator) Validate(data []byte) error {
v.mu.Lock()
defer v.mu.Unlock()
return cuejson.Validate(data, v.schema)
}
@@ -7,13 +7,13 @@ import (
"strings"
"sync"
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/cuevalidator"
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
"k8s.io/apimachinery/pkg/util/validation/field"
"cuelang.org/go/cue"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/errors"
cuejson "cuelang.org/go/encoding/json"
)
func ValidateDashboardSpec(obj *Dashboard, forceValidation bool) (field.ErrorList, field.ErrorList) {
@@ -33,7 +33,7 @@ func ValidateDashboardSpec(obj *Dashboard, forceValidation bool) (field.ErrorLis
}, schemaVersionError
}
if err := cuejson.Validate(data, getCueSchema()); err != nil {
if err := getValidator().Validate(data); err != nil {
errs := field.ErrorList{}
for _, e := range errors.Errors(err) {
@@ -71,20 +71,21 @@ func formatErrorPath(path []string) string {
}
var (
compiledSchema cue.Value
getSchemaOnce sync.Once
validator *cuevalidator.Validator
getSchemaOnce sync.Once
)
//go:embed dashboard_kind.cue
var schemaSource string
func getCueSchema() cue.Value {
func getValidator() *cuevalidator.Validator {
getSchemaOnce.Do(func() {
cueCtx := cuecontext.New()
compiledSchema = cueCtx.CompileString(schemaSource).LookupPath(
compiledSchema := cueCtx.CompileString(schemaSource).LookupPath(
cue.ParsePath("lineage.schemas[0].schema.spec"),
)
validator = cuevalidator.NewValidator(compiledSchema)
})
return compiledSchema
return validator
}
@@ -12,8 +12,8 @@ import (
"cuelang.org/go/cue"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/errors"
cuejson "cuelang.org/go/encoding/json"
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/cuevalidator"
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
)
@@ -34,7 +34,7 @@ func ValidateDashboardSpec(obj *Dashboard, forceValidation bool) (field.ErrorLis
}, schemaVersionError
}
if err := cuejson.Validate(data, getCueSchema()); err != nil {
if err := getValidator().Validate(data); err != nil {
errs := field.ErrorList{}
for _, e := range errors.Errors(err) {
@@ -72,20 +72,21 @@ func formatErrorPath(path []string) string {
}
var (
compiledSchema cue.Value
getSchemaOnce sync.Once
validator *cuevalidator.Validator
getSchemaOnce sync.Once
)
//go:embed dashboard_kind.cue
var schemaSource string
func getCueSchema() cue.Value {
func getValidator() *cuevalidator.Validator {
getSchemaOnce.Do(func() {
cueCtx := cuecontext.New()
compiledSchema = cueCtx.CompileString(schemaSource).LookupPath(
compiledSchema := cueCtx.CompileString(schemaSource).LookupPath(
cue.ParsePath("lineage.schemas[0].schema.spec"),
)
validator = cuevalidator.NewValidator(compiledSchema)
})
return compiledSchema
return validator
}
@@ -12,7 +12,8 @@ import (
"cuelang.org/go/cue"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/errors"
cuejson "cuelang.org/go/encoding/json"
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/cuevalidator"
)
func ValidateDashboardSpec(obj *Dashboard) field.ErrorList {
@@ -26,7 +27,7 @@ func ValidateDashboardSpec(obj *Dashboard) field.ErrorList {
// Custom validation for action query params and headers
validateAndTrimActionArrays(obj)
if err := cuejson.Validate(data, getCueSchema()); err != nil {
if err := getValidator().Validate(data); err != nil {
errs := field.ErrorList{}
for _, e := range errors.Errors(err) {
@@ -123,20 +124,21 @@ func formatErrorPath(path []string) string {
}
var (
compiledSchema cue.Value
getSchemaOnce sync.Once
validator *cuevalidator.Validator
getSchemaOnce sync.Once
)
//go:embed dashboard_spec.cue
var schemaSource string
func getCueSchema() cue.Value {
func getValidator() *cuevalidator.Validator {
getSchemaOnce.Do(func() {
cueCtx := cuecontext.New()
compiledSchema = cueCtx.CompileString(schemaSource).LookupPath(
compiledSchema := cueCtx.CompileString(schemaSource).LookupPath(
cue.ParsePath("DashboardSpec"),
)
validator = cuevalidator.NewValidator(compiledSchema)
})
return compiledSchema
return validator
}
@@ -12,7 +12,8 @@ import (
"cuelang.org/go/cue"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/errors"
cuejson "cuelang.org/go/encoding/json"
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/cuevalidator"
)
func ValidateDashboardSpec(obj *Dashboard) field.ErrorList {
@@ -26,7 +27,7 @@ func ValidateDashboardSpec(obj *Dashboard) field.ErrorList {
// Custom validation for action query params and headers
validateAndTrimActionArrays(obj)
if err := cuejson.Validate(data, getCueSchema()); err != nil {
if err := getValidator().Validate(data); err != nil {
errs := field.ErrorList{}
for _, e := range errors.Errors(err) {
@@ -123,20 +124,21 @@ func formatErrorPath(path []string) string {
}
var (
compiledSchema cue.Value
getSchemaOnce sync.Once
validator *cuevalidator.Validator
getSchemaOnce sync.Once
)
//go:embed dashboard_spec.cue
var schemaSource string
func getCueSchema() cue.Value {
func getValidator() *cuevalidator.Validator {
getSchemaOnce.Do(func() {
cueCtx := cuecontext.New()
compiledSchema = cueCtx.CompileString(schemaSource).LookupPath(
compiledSchema := cueCtx.CompileString(schemaSource).LookupPath(
cue.ParsePath("DashboardSpec"),
)
validator = cuevalidator.NewValidator(compiledSchema)
})
return compiledSchema
return validator
}