mirror of
https://github.com/outbackdingo/kubernetes.git
synced 2026-01-27 18:19:28 +00:00
Merge pull request #132467 from sdowell/ssa-terminating
fix: prevent SSA from creating CR while CRD terminating
This commit is contained in:
@@ -17,6 +17,8 @@ limitations under the License.
|
||||
package apiserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
@@ -384,17 +386,20 @@ func (r *crdHandler) serveResource(w http.ResponseWriter, req *http.Request, req
|
||||
if justCreated {
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
a := r.admission
|
||||
if terminating {
|
||||
err := apierrors.NewMethodNotSupported(schema.GroupResource{Group: requestInfo.APIGroup, Resource: requestInfo.Resource}, requestInfo.Verb)
|
||||
err.ErrStatus.Message = fmt.Sprintf("%v not allowed while custom resource definition is terminating", requestInfo.Verb)
|
||||
responsewriters.ErrorNegotiated(err, Codecs, schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion}, w, req)
|
||||
return nil
|
||||
a = &forbidCreateAdmission{delegate: a}
|
||||
}
|
||||
return handlers.CreateResource(storage, requestScope, r.admission)
|
||||
return handlers.CreateResource(storage, requestScope, a)
|
||||
case "update":
|
||||
return handlers.UpdateResource(storage, requestScope, r.admission)
|
||||
case "patch":
|
||||
return handlers.PatchResource(storage, requestScope, r.admission, supportedTypes)
|
||||
a := r.admission
|
||||
if terminating {
|
||||
a = &forbidCreateAdmission{delegate: a}
|
||||
}
|
||||
return handlers.PatchResource(storage, requestScope, a, supportedTypes)
|
||||
case "delete":
|
||||
allowsOptions := true
|
||||
return handlers.DeleteResource(storage, allowsOptions, requestScope, r.admission)
|
||||
@@ -1452,3 +1457,36 @@ func buildOpenAPIModelsForApply(staticOpenAPISpec map[string]*spec.Schema, crd *
|
||||
}
|
||||
return mergedOpenAPI.Components.Schemas, nil
|
||||
}
|
||||
|
||||
// forbidCreateAdmission is an admission.Interface wrapper that prevents a
|
||||
// CustomResource from being created while its CRD is terminating.
|
||||
type forbidCreateAdmission struct {
|
||||
delegate admission.Interface
|
||||
}
|
||||
|
||||
func (f *forbidCreateAdmission) Handles(operation admission.Operation) bool {
|
||||
if operation == admission.Create {
|
||||
return true
|
||||
}
|
||||
return f.delegate.Handles(operation)
|
||||
}
|
||||
|
||||
func (f *forbidCreateAdmission) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||
if a.GetOperation() == admission.Create {
|
||||
return apierrors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), errors.New("create not allowed while custom resource definition is terminating"))
|
||||
}
|
||||
if delegate, ok := f.delegate.(admission.MutationInterface); ok {
|
||||
return delegate.Admit(ctx, a, o)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *forbidCreateAdmission) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||
if a.GetOperation() == admission.Create {
|
||||
return apierrors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), errors.New("create not allowed while custom resource definition is terminating"))
|
||||
}
|
||||
if delegate, ok := f.delegate.(admission.ValidationInterface); ok {
|
||||
return delegate.Validate(ctx, a, o)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -163,3 +163,36 @@ func TestFinalizationAndDeletion(t *testing.T) {
|
||||
t.Fatalf("unable to delete crd: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyCRDuringCRDFinalization(t *testing.T) {
|
||||
tearDown, apiExtensionClient, dynamicClient, err := fixtures.StartDefaultServerWithClients(t)
|
||||
require.NoError(t, err)
|
||||
defer tearDown()
|
||||
|
||||
// Create a CRD with a finalizer which will stall deletion
|
||||
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
|
||||
noxuDefinition.SetFinalizers([]string{"noxu.example.com/finalizer"})
|
||||
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Delete the CRD. Since it has a finalizer it will be stuck in terminating state
|
||||
err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Delete(t.Context(), noxuDefinition.Name, metav1.DeleteOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Try to create a CR using SSA. This should fail due to the CRD validation
|
||||
ns := "not-the-default"
|
||||
name := "foo123"
|
||||
noxuResourceClient := newNamespacedCustomResourceClient(ns, dynamicClient, noxuDefinition)
|
||||
|
||||
err = wait.PollUntilContextTimeout(t.Context(), 100*time.Millisecond, wait.ForeverTestTimeout, true, func(ctx context.Context) (bool, error) {
|
||||
instance := fixtures.NewNoxuInstance(ns, name)
|
||||
_, err := noxuResourceClient.Apply(ctx, name, instance, metav1.ApplyOptions{DryRun: []string{"All"}, FieldManager: "manager"})
|
||||
if err == nil {
|
||||
t.Log("apply was not blocked, retrying...")
|
||||
return false, nil
|
||||
}
|
||||
return true, err
|
||||
})
|
||||
wantErr := `create not allowed while custom resource definition is terminating`
|
||||
require.ErrorContains(t, err, wantErr)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user