implmementing type checking
with multi-type support.
This commit is contained in:
@@ -2611,6 +2611,26 @@ func withPolicyExistsLabels(labels []string, policy *admissionregistrationv1alph
|
||||
return policy
|
||||
}
|
||||
|
||||
func withGVRMatch(groups []string, versions []string, resources []string, policy *admissionregistrationv1alpha1.ValidatingAdmissionPolicy) *admissionregistrationv1alpha1.ValidatingAdmissionPolicy {
|
||||
policy.Spec.MatchConstraints = &admissionregistrationv1alpha1.MatchResources{
|
||||
ResourceRules: []admissionregistrationv1alpha1.NamedRuleWithOperations{
|
||||
{
|
||||
RuleWithOperations: admissionregistrationv1alpha1.RuleWithOperations{
|
||||
Operations: []admissionregistrationv1.OperationType{
|
||||
"*",
|
||||
},
|
||||
Rule: admissionregistrationv1.Rule{
|
||||
APIGroups: groups,
|
||||
APIVersions: versions,
|
||||
Resources: resources,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return policy
|
||||
}
|
||||
|
||||
func withValidations(validations []admissionregistrationv1alpha1.Validation, policy *admissionregistrationv1alpha1.ValidatingAdmissionPolicy) *admissionregistrationv1alpha1.ValidatingAdmissionPolicy {
|
||||
policy.Spec.Validations = validations
|
||||
return policy
|
||||
@@ -2885,3 +2905,114 @@ rules:
|
||||
resources: ["configmaps"]
|
||||
`
|
||||
)
|
||||
|
||||
func TestValidatingAdmissionPolicyTypeChecking(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.ValidatingAdmissionPolicy, true)()
|
||||
server, err := apiservertesting.StartTestServer(t, nil, []string{
|
||||
"--enable-admission-plugins", "ValidatingAdmissionPolicy",
|
||||
}, framework.SharedEtcd())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer server.TearDownFn()
|
||||
|
||||
config := server.ClientConfig
|
||||
|
||||
client, err := clientset.NewForConfig(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
policy *admissionregistrationv1alpha1.ValidatingAdmissionPolicy
|
||||
assertFieldRef func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) // warning.fieldRef
|
||||
assertWarnings func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) // warning.warning
|
||||
}{
|
||||
{
|
||||
name: "deployment with correct expression",
|
||||
policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1alpha1.Validation{
|
||||
{
|
||||
Expression: "object.spec.replicas > 1",
|
||||
},
|
||||
}, makePolicy("replicated-deployment"))),
|
||||
assertFieldRef: toHasLengthOf(0),
|
||||
assertWarnings: toHasLengthOf(0),
|
||||
},
|
||||
{
|
||||
name: "deployment with type confusion",
|
||||
policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1alpha1.Validation{
|
||||
{
|
||||
Expression: "object.spec.replicas < 100", // this one passes
|
||||
},
|
||||
{
|
||||
Expression: "object.spec.replicas > '1'", // '1' should be int
|
||||
},
|
||||
}, makePolicy("confused-deployment"))),
|
||||
assertFieldRef: toBe("spec.validations[1].expression"),
|
||||
assertWarnings: toHasSubstring(`found no matching overload for '_>_' applied to '(int, string)'`),
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
policy, err := client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Create(ctx, tc.policy, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Delete(context.Background(), policy.Name, metav1.DeleteOptions{})
|
||||
err = wait.PollImmediateWithContext(ctx, time.Second, time.Minute, func(ctx context.Context) (done bool, err error) {
|
||||
name := policy.Name
|
||||
// wait until the typeChecking is set, which means the type checking
|
||||
// is complete.
|
||||
updated, err := client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Get(ctx, name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if updated.Status.TypeChecking != nil {
|
||||
policy = updated
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tc.assertFieldRef(policy.Status.TypeChecking.ExpressionWarnings, t)
|
||||
tc.assertWarnings(policy.Status.TypeChecking.ExpressionWarnings, t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func toBe(expected ...string) func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) {
|
||||
return func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) {
|
||||
if len(expected) != len(warnings) {
|
||||
t.Fatalf("mismatched length, expect %d, got %d", len(expected), len(warnings))
|
||||
}
|
||||
for i := range expected {
|
||||
if expected[i] != warnings[i].FieldRef {
|
||||
t.Errorf("expected %q but got %q", expected[i], warnings[i].FieldRef)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toHasSubstring(substrings ...string) func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) {
|
||||
return func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) {
|
||||
if len(substrings) != len(warnings) {
|
||||
t.Fatalf("mismatched length, expect %d, got %d", len(substrings), len(warnings))
|
||||
}
|
||||
for i := range substrings {
|
||||
if !strings.Contains(warnings[i].Warning, substrings[i]) {
|
||||
t.Errorf("missing expected substring %q in %v", substrings[i], warnings[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toHasLengthOf(n int) func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) {
|
||||
return func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) {
|
||||
if n != len(warnings) {
|
||||
t.Fatalf("mismatched length, expect %d, got %d", n, len(warnings))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user