This is an automated email from the ASF dual-hosted git repository.

ronething pushed a commit to branch feat/add_resource_verify
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git

commit 22da8f7091950de04f683b87554815611ac4399e
Author: Ashing Zheng <[email protected]>
AuthorDate: Fri Sep 26 16:36:03 2025 +0800

    feat: add apisix route and apisix consumer
    
    Signed-off-by: Ashing Zheng <[email protected]>
---
 config/webhook/manifests.yaml                   |  40 ++++++
 internal/manager/webhooks.go                    |   6 +
 internal/webhook/v1/apisixroute_webhook.go      | 139 +++++++++++++++++++++
 internal/webhook/v1/apisixroute_webhook_test.go | 158 ++++++++++++++++++++++++
 internal/webhook/v1/consumer_webhook.go         | 105 ++++++++++++++++
 internal/webhook/v1/consumer_webhook_test.go    | 130 +++++++++++++++++++
 6 files changed, 578 insertions(+)

diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml
index de7ced0e..b5b33201 100644
--- a/config/webhook/manifests.yaml
+++ b/config/webhook/manifests.yaml
@@ -24,6 +24,26 @@ webhooks:
     resources:
     - apisixconsumers
   sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: webhook-service
+      namespace: system
+      path: /validate-apisix-apache-org-v2-apisixroute
+  failurePolicy: Fail
+  name: vapisixroute-v2.kb.io
+  rules:
+  - apiGroups:
+    - apisix.apache.org
+    apiVersions:
+    - v2
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - apisixroutes
+  sideEffects: None
 - admissionReviewVersions:
   - v1
   clientConfig:
@@ -44,6 +64,26 @@ webhooks:
     resources:
     - apisixtlses
   sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: webhook-service
+      namespace: system
+      path: /validate-apisix-apache-org-v1alpha1-consumer
+  failurePolicy: Fail
+  name: vconsumer-v1alpha1.kb.io
+  rules:
+  - apiGroups:
+    - apisix.apache.org
+    apiVersions:
+    - v1alpha1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - consumers
+  sideEffects: None
 - admissionReviewVersions:
   - v1
   clientConfig:
diff --git a/internal/manager/webhooks.go b/internal/manager/webhooks.go
index 91242972..6907d762 100644
--- a/internal/manager/webhooks.go
+++ b/internal/manager/webhooks.go
@@ -44,5 +44,11 @@ func setupWebhooks(_ context.Context, mgr manager.Manager) 
error {
        if err := webhookv1.SetupApisixTlsWebhookWithManager(mgr); err != nil {
                return err
        }
+       if err := webhookv1.SetupApisixRouteWebhookWithManager(mgr); err != nil 
{
+               return err
+       }
+       if err := webhookv1.SetupConsumerWebhookWithManager(mgr); err != nil {
+               return err
+       }
        return nil
 }
diff --git a/internal/webhook/v1/apisixroute_webhook.go 
b/internal/webhook/v1/apisixroute_webhook.go
new file mode 100644
index 00000000..a651f913
--- /dev/null
+++ b/internal/webhook/v1/apisixroute_webhook.go
@@ -0,0 +1,139 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package v1
+
+import (
+       "context"
+       "fmt"
+
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/types"
+       ctrl "sigs.k8s.io/controller-runtime"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+       logf "sigs.k8s.io/controller-runtime/pkg/log"
+       "sigs.k8s.io/controller-runtime/pkg/webhook"
+       "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+
+       apisixv2 "github.com/apache/apisix-ingress-controller/api/v2"
+       
"github.com/apache/apisix-ingress-controller/internal/webhook/v1/reference"
+)
+
+var apisixRouteLog = logf.Log.WithName("apisixroute-resource")
+
+func SetupApisixRouteWebhookWithManager(mgr ctrl.Manager) error {
+       return ctrl.NewWebhookManagedBy(mgr).
+               For(&apisixv2.ApisixRoute{}).
+               WithValidator(&ApisixRouteCustomValidator{Client: 
mgr.GetClient()}).
+               Complete()
+}
+
+// 
+kubebuilder:webhook:path=/validate-apisix-apache-org-v2-apisixroute,mutating=false,failurePolicy=fail,sideEffects=None,groups=apisix.apache.org,resources=apisixroutes,verbs=create;update,versions=v2,name=vapisixroute-v2.kb.io,admissionReviewVersions=v1
+
+type ApisixRouteCustomValidator struct {
+       Client client.Client
+}
+
+var _ webhook.CustomValidator = &ApisixRouteCustomValidator{}
+
+func (v *ApisixRouteCustomValidator) ValidateCreate(ctx context.Context, obj 
runtime.Object) (admission.Warnings, error) {
+       route, ok := obj.(*apisixv2.ApisixRoute)
+       if !ok {
+               return nil, fmt.Errorf("expected an ApisixRoute object but got 
%T", obj)
+       }
+       apisixRouteLog.Info("Validation for ApisixRoute upon creation", "name", 
route.GetName(), "namespace", route.GetNamespace())
+
+       return v.collectWarnings(ctx, route), nil
+}
+
+func (v *ApisixRouteCustomValidator) ValidateUpdate(ctx context.Context, 
oldObj, newObj runtime.Object) (admission.Warnings, error) {
+       route, ok := newObj.(*apisixv2.ApisixRoute)
+       if !ok {
+               return nil, fmt.Errorf("expected an ApisixRoute object for the 
newObj but got %T", newObj)
+       }
+       apisixRouteLog.Info("Validation for ApisixRoute upon update", "name", 
route.GetName(), "namespace", route.GetNamespace())
+
+       return v.collectWarnings(ctx, route), nil
+}
+
+func (*ApisixRouteCustomValidator) ValidateDelete(context.Context, 
runtime.Object) (admission.Warnings, error) {
+       return nil, nil
+}
+
+func (v *ApisixRouteCustomValidator) collectWarnings(ctx context.Context, 
route *apisixv2.ApisixRoute) admission.Warnings {
+       checker := reference.NewChecker(v.Client, apisixRouteLog)
+       namespace := route.GetNamespace()
+
+       serviceVisited := make(map[types.NamespacedName]struct{})
+       secretVisited := make(map[types.NamespacedName]struct{})
+
+       var warnings admission.Warnings
+
+       addServiceWarning := func(nn types.NamespacedName) {
+               if nn.Name == "" || nn.Namespace == "" {
+                       return
+               }
+               if _, seen := serviceVisited[nn]; seen {
+                       return
+               }
+               serviceVisited[nn] = struct{}{}
+               warnings = append(warnings, checker.Service(ctx, 
reference.ServiceRef{
+                       Object:         route,
+                       NamespacedName: nn,
+               })...)
+       }
+
+       addSecretWarning := func(nn types.NamespacedName) {
+               if nn.Name == "" || nn.Namespace == "" {
+                       return
+               }
+               if _, seen := secretVisited[nn]; seen {
+                       return
+               }
+               secretVisited[nn] = struct{}{}
+               warnings = append(warnings, checker.Secret(ctx, 
reference.SecretRef{
+                       Object:         route,
+                       NamespacedName: nn,
+               })...)
+       }
+
+       for _, rule := range route.Spec.HTTP {
+               for _, backend := range rule.Backends {
+                       addServiceWarning(types.NamespacedName{Namespace: 
namespace, Name: backend.ServiceName})
+               }
+               for _, plugin := range rule.Plugins {
+                       if !plugin.Enable {
+                               continue
+                       }
+                       if plugin.SecretRef != "" {
+                               
addSecretWarning(types.NamespacedName{Namespace: namespace, Name: 
plugin.SecretRef})
+                       }
+               }
+       }
+
+       for _, rule := range route.Spec.Stream {
+               addServiceWarning(types.NamespacedName{Namespace: namespace, 
Name: rule.Backend.ServiceName})
+               for _, plugin := range rule.Plugins {
+                       if !plugin.Enable {
+                               continue
+                       }
+                       if plugin.SecretRef != "" {
+                               
addSecretWarning(types.NamespacedName{Namespace: namespace, Name: 
plugin.SecretRef})
+                       }
+               }
+       }
+
+       return warnings
+}
diff --git a/internal/webhook/v1/apisixroute_webhook_test.go 
b/internal/webhook/v1/apisixroute_webhook_test.go
new file mode 100644
index 00000000..3ea88e46
--- /dev/null
+++ b/internal/webhook/v1/apisixroute_webhook_test.go
@@ -0,0 +1,158 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package v1
+
+import (
+       "context"
+       "testing"
+
+       "github.com/stretchr/testify/require"
+       corev1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/runtime"
+       clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+       "sigs.k8s.io/controller-runtime/pkg/client/fake"
+
+       apisixv2 "github.com/apache/apisix-ingress-controller/api/v2"
+)
+
+func buildApisixRouteValidator(t *testing.T, objects ...runtime.Object) 
*ApisixRouteCustomValidator {
+       t.Helper()
+
+       scheme := runtime.NewScheme()
+       require.NoError(t, clientgoscheme.AddToScheme(scheme))
+       require.NoError(t, apisixv2.AddToScheme(scheme))
+
+       builder := fake.NewClientBuilder().WithScheme(scheme)
+       if len(objects) > 0 {
+               builder = builder.WithRuntimeObjects(objects...)
+       }
+
+       return &ApisixRouteCustomValidator{Client: builder.Build()}
+}
+
+func TestApisixRouteValidator_MissingHTTPService(t *testing.T) {
+       route := &apisixv2.ApisixRoute{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      "demo",
+                       Namespace: "default",
+               },
+               Spec: apisixv2.ApisixRouteSpec{
+                       HTTP: []apisixv2.ApisixRouteHTTP{{
+                               Name: "rule",
+                               Backends: []apisixv2.ApisixRouteHTTPBackend{{
+                                       ServiceName: "backend",
+                               }},
+                       }},
+               },
+       }
+
+       validator := buildApisixRouteValidator(t)
+
+       warnings, err := validator.ValidateCreate(context.Background(), route)
+       require.NoError(t, err)
+       require.Len(t, warnings, 1)
+       require.Contains(t, warnings[0], "Referenced Service 'default/backend' 
not found")
+}
+
+func TestApisixRouteValidator_MissingPluginSecret(t *testing.T) {
+       route := &apisixv2.ApisixRoute{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      "demo",
+                       Namespace: "default",
+               },
+               Spec: apisixv2.ApisixRouteSpec{
+                       HTTP: []apisixv2.ApisixRouteHTTP{{
+                               Name: "rule",
+                               Backends: []apisixv2.ApisixRouteHTTPBackend{{
+                                       ServiceName: "backend",
+                               }},
+                               Plugins: []apisixv2.ApisixRoutePlugin{{
+                                       Name:      "jwt-auth",
+                                       Enable:    true,
+                                       SecretRef: "jwt-secret",
+                               }},
+                       }},
+               },
+       }
+
+       backendSvc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: 
"backend", Namespace: "default"}}
+
+       validator := buildApisixRouteValidator(t, backendSvc)
+
+       warnings, err := validator.ValidateCreate(context.Background(), route)
+       require.NoError(t, err)
+       require.Len(t, warnings, 1)
+       require.Contains(t, warnings[0], "Referenced Secret 
'default/jwt-secret' not found")
+}
+
+func TestApisixRouteValidator_MissingStreamService(t *testing.T) {
+       route := &apisixv2.ApisixRoute{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      "demo",
+                       Namespace: "default",
+               },
+               Spec: apisixv2.ApisixRouteSpec{
+                       Stream: []apisixv2.ApisixRouteStream{{
+                               Name:     "stream",
+                               Protocol: "TCP",
+                               Backend: apisixv2.ApisixRouteStreamBackend{
+                                       ServiceName: "stream-svc",
+                               },
+                       }},
+               },
+       }
+
+       validator := buildApisixRouteValidator(t)
+
+       warnings, err := validator.ValidateCreate(context.Background(), route)
+       require.NoError(t, err)
+       require.Len(t, warnings, 1)
+       require.Contains(t, warnings[0], "Referenced Service 
'default/stream-svc' not found")
+}
+
+func TestApisixRouteValidator_NoWarnings(t *testing.T) {
+       route := &apisixv2.ApisixRoute{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      "demo",
+                       Namespace: "default",
+               },
+               Spec: apisixv2.ApisixRouteSpec{
+                       HTTP: []apisixv2.ApisixRouteHTTP{{
+                               Name: "rule",
+                               Backends: []apisixv2.ApisixRouteHTTPBackend{{
+                                       ServiceName: "backend",
+                               }},
+                               Plugins: []apisixv2.ApisixRoutePlugin{{
+                                       Name:      "jwt-auth",
+                                       Enable:    true,
+                                       SecretRef: "jwt-secret",
+                               }},
+                       }},
+               },
+       }
+
+       objs := []runtime.Object{
+               &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "backend", 
Namespace: "default"}},
+               &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: 
"jwt-secret", Namespace: "default"}},
+       }
+
+       validator := buildApisixRouteValidator(t, objs...)
+
+       warnings, err := validator.ValidateCreate(context.Background(), route)
+       require.NoError(t, err)
+       require.Empty(t, warnings)
+}
diff --git a/internal/webhook/v1/consumer_webhook.go 
b/internal/webhook/v1/consumer_webhook.go
new file mode 100644
index 00000000..c640cdfe
--- /dev/null
+++ b/internal/webhook/v1/consumer_webhook.go
@@ -0,0 +1,105 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package v1
+
+import (
+       "context"
+       "fmt"
+
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/types"
+       ctrl "sigs.k8s.io/controller-runtime"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+       logf "sigs.k8s.io/controller-runtime/pkg/log"
+       "sigs.k8s.io/controller-runtime/pkg/webhook"
+       "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+
+       apisixv1alpha1 
"github.com/apache/apisix-ingress-controller/api/v1alpha1"
+       
"github.com/apache/apisix-ingress-controller/internal/webhook/v1/reference"
+)
+
+var consumerLog = logf.Log.WithName("consumer-resource")
+
+func SetupConsumerWebhookWithManager(mgr ctrl.Manager) error {
+       return ctrl.NewWebhookManagedBy(mgr).
+               For(&apisixv1alpha1.Consumer{}).
+               WithValidator(&ConsumerCustomValidator{Client: 
mgr.GetClient()}).
+               Complete()
+}
+
+// 
+kubebuilder:webhook:path=/validate-apisix-apache-org-v1alpha1-consumer,mutating=false,failurePolicy=fail,sideEffects=None,groups=apisix.apache.org,resources=consumers,verbs=create;update,versions=v1alpha1,name=vconsumer-v1alpha1.kb.io,admissionReviewVersions=v1
+
+type ConsumerCustomValidator struct {
+       Client client.Client
+}
+
+var _ webhook.CustomValidator = &ConsumerCustomValidator{}
+
+func (v *ConsumerCustomValidator) ValidateCreate(ctx context.Context, obj 
runtime.Object) (admission.Warnings, error) {
+       consumer, ok := obj.(*apisixv1alpha1.Consumer)
+       if !ok {
+               return nil, fmt.Errorf("expected a Consumer object but got %T", 
obj)
+       }
+       consumerLog.Info("Validation for Consumer upon creation", "name", 
consumer.GetName(), "namespace", consumer.GetNamespace())
+
+       return v.collectWarnings(ctx, consumer), nil
+}
+
+func (v *ConsumerCustomValidator) ValidateUpdate(ctx context.Context, oldObj, 
newObj runtime.Object) (admission.Warnings, error) {
+       consumer, ok := newObj.(*apisixv1alpha1.Consumer)
+       if !ok {
+               return nil, fmt.Errorf("expected a Consumer object for the 
newObj but got %T", newObj)
+       }
+       consumerLog.Info("Validation for Consumer upon update", "name", 
consumer.GetName(), "namespace", consumer.GetNamespace())
+
+       return v.collectWarnings(ctx, consumer), nil
+}
+
+func (*ConsumerCustomValidator) ValidateDelete(context.Context, 
runtime.Object) (admission.Warnings, error) {
+       return nil, nil
+}
+
+func (v *ConsumerCustomValidator) collectWarnings(ctx context.Context, 
consumer *apisixv1alpha1.Consumer) admission.Warnings {
+       checker := reference.NewChecker(v.Client, consumerLog)
+       defaultNamespace := consumer.GetNamespace()
+
+       visited := make(map[types.NamespacedName]struct{})
+       var warnings admission.Warnings
+
+       for _, credential := range consumer.Spec.Credentials {
+               if credential.SecretRef == nil || credential.SecretRef.Name == 
"" {
+                       continue
+               }
+
+               namespace := defaultNamespace
+               if credential.SecretRef.Namespace != nil && 
*credential.SecretRef.Namespace != "" {
+                       namespace = *credential.SecretRef.Namespace
+               }
+
+               nn := types.NamespacedName{Namespace: namespace, Name: 
credential.SecretRef.Name}
+               if _, ok := visited[nn]; ok {
+                       continue
+               }
+               visited[nn] = struct{}{}
+
+               warnings = append(warnings, checker.Secret(ctx, 
reference.SecretRef{
+                       Object:         consumer,
+                       NamespacedName: nn,
+               })...)
+       }
+
+       return warnings
+}
diff --git a/internal/webhook/v1/consumer_webhook_test.go 
b/internal/webhook/v1/consumer_webhook_test.go
new file mode 100644
index 00000000..90ea0ae8
--- /dev/null
+++ b/internal/webhook/v1/consumer_webhook_test.go
@@ -0,0 +1,130 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package v1
+
+import (
+       "context"
+       "testing"
+
+       "github.com/stretchr/testify/require"
+       corev1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/runtime"
+       clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+       "sigs.k8s.io/controller-runtime/pkg/client/fake"
+
+       apisixv1alpha1 
"github.com/apache/apisix-ingress-controller/api/v1alpha1"
+)
+
+func buildConsumerValidator(t *testing.T, objects ...runtime.Object) 
*ConsumerCustomValidator {
+       t.Helper()
+
+       scheme := runtime.NewScheme()
+       require.NoError(t, clientgoscheme.AddToScheme(scheme))
+       require.NoError(t, apisixv1alpha1.AddToScheme(scheme))
+
+       builder := fake.NewClientBuilder().WithScheme(scheme)
+       if len(objects) > 0 {
+               builder = builder.WithRuntimeObjects(objects...)
+       }
+
+       return &ConsumerCustomValidator{Client: builder.Build()}
+}
+
+func TestConsumerValidator_MissingSecretDefaultNamespace(t *testing.T) {
+       consumer := &apisixv1alpha1.Consumer{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      "demo",
+                       Namespace: "default",
+               },
+               Spec: apisixv1alpha1.ConsumerSpec{
+                       Credentials: []apisixv1alpha1.Credential{{
+                               Type: "jwt-auth",
+                               SecretRef: &apisixv1alpha1.SecretReference{
+                                       Name: "jwt-secret",
+                               },
+                       }},
+               },
+       }
+
+       validator := buildConsumerValidator(t)
+
+       warnings, err := validator.ValidateCreate(context.Background(), 
consumer)
+       require.NoError(t, err)
+       require.Len(t, warnings, 1)
+       require.Contains(t, warnings[0], "Referenced Secret 
'default/jwt-secret' not found")
+}
+
+func TestConsumerValidator_MissingSecretCustomNamespace(t *testing.T) {
+       ns := "auth"
+       consumer := &apisixv1alpha1.Consumer{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      "demo",
+                       Namespace: "default",
+               },
+               Spec: apisixv1alpha1.ConsumerSpec{
+                       Credentials: []apisixv1alpha1.Credential{{
+                               Type: "jwt-auth",
+                               SecretRef: &apisixv1alpha1.SecretReference{
+                                       Name:      "jwt-secret",
+                                       Namespace: &ns,
+                               },
+                       }},
+               },
+       }
+
+       validator := buildConsumerValidator(t)
+
+       warnings, err := validator.ValidateCreate(context.Background(), 
consumer)
+       require.NoError(t, err)
+       require.Len(t, warnings, 1)
+       require.Contains(t, warnings[0], "Referenced Secret 'auth/jwt-secret' 
not found")
+}
+
+func TestConsumerValidator_NoWarnings(t *testing.T) {
+       ns := "auth"
+       consumer := &apisixv1alpha1.Consumer{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      "demo",
+                       Namespace: "default",
+               },
+               Spec: apisixv1alpha1.ConsumerSpec{
+                       Credentials: []apisixv1alpha1.Credential{{
+                               Type: "jwt-auth",
+                               SecretRef: &apisixv1alpha1.SecretReference{
+                                       Name:      "jwt-secret",
+                                       Namespace: &ns,
+                               },
+                       }, {
+                               Type: "key-auth",
+                               SecretRef: &apisixv1alpha1.SecretReference{
+                                       Name: "key-secret",
+                               },
+                       }},
+               },
+       }
+
+       objs := []runtime.Object{
+               &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: 
"jwt-secret", Namespace: "auth"}},
+               &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: 
"key-secret", Namespace: "default"}},
+       }
+
+       validator := buildConsumerValidator(t, objs...)
+
+       warnings, err := validator.ValidateCreate(context.Background(), 
consumer)
+       require.NoError(t, err)
+       require.Empty(t, warnings)
+}

Reply via email to