@@ -25,6 +25,7 @@ import (
25
25
"strings"
26
26
"time"
27
27
28
+ "github.com/awslabs/operatorpkg/object"
28
29
"github.com/awslabs/operatorpkg/status"
29
30
. "github.com/onsi/ginkgo/v2"
30
31
. "github.com/onsi/gomega"
@@ -931,6 +932,74 @@ func (env *Environment) ExpectBlockNodeRegistration() {
931
932
}).Should (Succeed ())
932
933
}
933
934
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
+
934
1003
func (env * Environment ) ConsistentlyExpectNodeClaimsNotDrifted (duration time.Duration , nodeClaims ... * v1.NodeClaim ) {
935
1004
GinkgoHelper ()
936
1005
nodeClaimNames := lo .Map (nodeClaims , func (nc * v1.NodeClaim , _ int ) string { return nc .Name })
0 commit comments