Skip to content

Commit 3494876

Browse files
test: add validating admission policy for nodeclass status (kubernetes-sigs#2251)
Co-authored-by: Jonathan Innis <[email protected]>
1 parent 8f3f479 commit 3494876

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

test/pkg/environment/common/expectations.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"strings"
2626
"time"
2727

28+
"github.com/awslabs/operatorpkg/object"
2829
"github.com/awslabs/operatorpkg/status"
2930
. "github.com/onsi/ginkgo/v2"
3031
. "github.com/onsi/gomega"
@@ -931,6 +932,74 @@ func (env *Environment) ExpectBlockNodeRegistration() {
931932
}).Should(Succeed())
932933
}
933934

935+
// ExpectBlockNodeClassStatus sets up a nodeclass status update blocking mechanism using ValidatingAdmissionPolicy.
936+
// It creates a policy that prevents nodeclassess from updating their status
937+
//
938+
// The function performs the following steps:
939+
// 1. Verifies the cluster version is 1.28 or higher (requirement for ValidatingAdmissionPolicy)
940+
// 2. Creates an admission policy that specifically targets nodeclass status updates
941+
// 3. Creates a binding for the admission policy to enforce the validation
942+
//
943+
// Note: Requires Kubernetes version 1.28+ to function properly.
944+
func (env *Environment) ExpectBlockNodeClassStatus(obj *unstructured.Unstructured) {
945+
GinkgoHelper()
946+
947+
version, err := env.KubeClient.Discovery().ServerVersion()
948+
Expect(err).To(BeNil())
949+
if version.Minor < "28" {
950+
Skip("This test is only valid for K8s >= 1.28")
951+
}
952+
953+
// Define the ValidatingAdmissionPolicy that will inspect node creation requests
954+
// The policy's validation expression checks if the 'registration' label equals 'fail'
955+
admissionspolicy := &admissionregistrationv1.ValidatingAdmissionPolicy{
956+
ObjectMeta: metav1.ObjectMeta{
957+
Name: "admission-policy",
958+
Labels: map[string]string{
959+
test.DiscoveryLabel: "unspecified",
960+
},
961+
},
962+
Spec: admissionregistrationv1.ValidatingAdmissionPolicySpec{
963+
FailurePolicy: lo.ToPtr(admissionregistrationv1.Fail),
964+
MatchConstraints: &admissionregistrationv1.MatchResources{
965+
ResourceRules: []admissionregistrationv1.NamedRuleWithOperations{
966+
{
967+
RuleWithOperations: admissionregistrationv1.RuleWithOperations{
968+
Operations: []admissionregistrationv1.OperationType{admissionregistrationv1.Update},
969+
Rule: admissionregistrationv1.Rule{
970+
APIGroups: []string{object.GVK(obj).Group},
971+
APIVersions: []string{object.GVK(obj).Version},
972+
Resources: []string{strings.ToLower(object.GVK(obj).Kind) + "es/status"},
973+
},
974+
},
975+
},
976+
},
977+
},
978+
Validations: []admissionregistrationv1.Validation{
979+
{
980+
Expression: "false",
981+
},
982+
},
983+
},
984+
}
985+
986+
// Create the binding that connects the admission policy to the cluster's admission chain
987+
admissionspolicybinding := &admissionregistrationv1.ValidatingAdmissionPolicyBinding{
988+
ObjectMeta: metav1.ObjectMeta{
989+
Name: "admission-policy-binding",
990+
Labels: map[string]string{
991+
test.DiscoveryLabel: "unspecified",
992+
},
993+
},
994+
Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{
995+
PolicyName: admissionspolicy.Name,
996+
ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny},
997+
},
998+
}
999+
// Create both the policy and binding in the cluster
1000+
env.ExpectCreated(admissionspolicy, admissionspolicybinding)
1001+
}
1002+
9341003
func (env *Environment) ConsistentlyExpectNodeClaimsNotDrifted(duration time.Duration, nodeClaims ...*v1.NodeClaim) {
9351004
GinkgoHelper()
9361005
nodeClaimNames := lo.Map(nodeClaims, func(nc *v1.NodeClaim, _ int) string { return nc.Name })

test/suites/regression/nodeclaim_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ var _ = Describe("NodeClaim", func() {
258258
},
259259
})
260260
env.ExpectStatusUpdated(nodeClass)
261+
env.ExpectBlockNodeClassStatus(nodeClass)
262+
// TODO: better not to have this but this suite runs quickly as is and this solves for multiple cloudproviders
263+
time.Sleep(10 * time.Second)
261264
nodeClaim := test.NodeClaim(v1.NodeClaim{
262265
Spec: v1.NodeClaimSpec{
263266
Requirements: requirements,

0 commit comments

Comments
 (0)