diff --git a/pkg/registry/softwarecomposition/applicationprofile/strategy.go b/pkg/registry/softwarecomposition/applicationprofile/strategy.go index 89ac508c9..0bf21ab91 100644 --- a/pkg/registry/softwarecomposition/applicationprofile/strategy.go +++ b/pkg/registry/softwarecomposition/applicationprofile/strategy.go @@ -12,7 +12,9 @@ import ( "k8s.io/apiserver/pkg/storage" "k8s.io/apiserver/pkg/storage/names" + "github.com/kubescape/k8s-interface/instanceidhandler/v1/helpers" "github.com/kubescape/storage/pkg/apis/softwarecomposition" + "github.com/kubescape/storage/pkg/utils" ) // NewStrategy creates and returns a applicationProfileStrategy instance @@ -57,10 +59,31 @@ func (applicationProfileStrategy) PrepareForCreate(ctx context.Context, obj runt } func (applicationProfileStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { + newAP := obj.(*softwarecomposition.ApplicationProfile) + oldAP := old.(*softwarecomposition.ApplicationProfile) + + // completion status cannot be transitioned from 'complete' -> 'partial' + // in such case, we reject status updates + if oldAP.Annotations[helpers.CompletionMetadataKey] == helpers.Complete && newAP.Annotations[helpers.CompletionMetadataKey] == helpers.Partial { + newAP.Annotations[helpers.CompletionMetadataKey] = helpers.Complete + newAP.Annotations[helpers.StatusMetadataKey] = oldAP.Annotations[helpers.StatusMetadataKey] + } } func (applicationProfileStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { - return field.ErrorList{} + ap := obj.(*softwarecomposition.ApplicationProfile) + + allErrors := field.ErrorList{} + + if err := utils.ValidateCompletionAnnotation(ap.Annotations); err != nil { + allErrors = append(allErrors, err) + } + + if err := utils.ValidateStatusAnnotation(ap.Annotations); err != nil { + allErrors = append(allErrors, err) + } + + return allErrors } // WarningsOnCreate returns warnings for the creation of the given object. @@ -80,7 +103,19 @@ func (applicationProfileStrategy) Canonicalize(obj runtime.Object) { } func (applicationProfileStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { - return field.ErrorList{} + ap := obj.(*softwarecomposition.ApplicationProfile) + + allErrors := field.ErrorList{} + + if err := utils.ValidateCompletionAnnotation(ap.Annotations); err != nil { + allErrors = append(allErrors, err) + } + + if err := utils.ValidateStatusAnnotation(ap.Annotations); err != nil { + allErrors = append(allErrors, err) + } + + return allErrors } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/softwarecomposition/networkneighbors/strategy.go b/pkg/registry/softwarecomposition/networkneighbors/strategy.go index a44073153..8cec3ebda 100644 --- a/pkg/registry/softwarecomposition/networkneighbors/strategy.go +++ b/pkg/registry/softwarecomposition/networkneighbors/strategy.go @@ -4,7 +4,9 @@ import ( "context" "fmt" + "github.com/kubescape/k8s-interface/instanceidhandler/v1/helpers" "github.com/kubescape/storage/pkg/apis/softwarecomposition" + "github.com/kubescape/storage/pkg/utils" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -53,11 +55,32 @@ func (networkNeighborsStrategy) NamespaceScoped() bool { func (networkNeighborsStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { } -func (networkNeighborsStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { +func (s networkNeighborsStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { + newNN := obj.(*softwarecomposition.NetworkNeighbors) + oldNN := old.(*softwarecomposition.NetworkNeighbors) + + // completion status cannot be transitioned from 'complete' -> 'partial' + // in such case, we reject status updates + if oldNN.Annotations[helpers.CompletionMetadataKey] == helpers.Complete && newNN.Annotations[helpers.CompletionMetadataKey] == helpers.Partial { + newNN.Annotations[helpers.CompletionMetadataKey] = helpers.Complete + newNN.Annotations[helpers.StatusMetadataKey] = oldNN.Annotations[helpers.StatusMetadataKey] + } } func (networkNeighborsStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { - return field.ErrorList{} + nn := obj.(*softwarecomposition.NetworkNeighbors) + + allErrors := field.ErrorList{} + + if err := utils.ValidateCompletionAnnotation(nn.Annotations); err != nil { + allErrors = append(allErrors, err) + } + + if err := utils.ValidateStatusAnnotation(nn.Annotations); err != nil { + allErrors = append(allErrors, err) + } + + return allErrors } // WarningsOnCreate returns warnings for the creation of the given object. @@ -77,7 +100,19 @@ func (networkNeighborsStrategy) Canonicalize(obj runtime.Object) { } func (networkNeighborsStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { - return field.ErrorList{} + nn := obj.(*softwarecomposition.NetworkNeighbors) + + allErrors := field.ErrorList{} + + if err := utils.ValidateCompletionAnnotation(nn.Annotations); err != nil { + allErrors = append(allErrors, err) + } + + if err := utils.ValidateStatusAnnotation(nn.Annotations); err != nil { + allErrors = append(allErrors, err) + } + + return allErrors } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/utils/validations.go b/pkg/utils/validations.go new file mode 100644 index 000000000..d6ee36238 --- /dev/null +++ b/pkg/utils/validations.go @@ -0,0 +1,32 @@ +package utils + +import ( + "github.com/kubescape/k8s-interface/instanceidhandler/v1/helpers" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func ValidateCompletionAnnotation(annotations map[string]string) *field.Error { + if v, ok := annotations[helpers.CompletionMetadataKey]; ok { + switch v { + case helpers.Complete, helpers.Partial: + return nil + default: + return field.Invalid(field.NewPath("metadata").Child("annotations").Child(helpers.CompletionMetadataKey), v, "invalid value") + } + } + return nil +} + +func ValidateStatusAnnotation(annotations map[string]string) *field.Error { + if v, ok := annotations[helpers.StatusMetadataKey]; ok { + switch v { + case helpers.Initializing, helpers.Ready, helpers.Completed, helpers.Incomplete, helpers.Unauthorize, helpers.MissingRuntime, helpers.TooLarge: + return nil + default: + return field.Invalid(field.NewPath("metadata").Child("annotations").Child(helpers.StatusMetadataKey), v, "invalid value") + } + } + + return nil + +}