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

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

commit b2ff6c0f90bbd92d00fdafce39c6cd5ad5cf2cfe
Author: Ashing Zheng <[email protected]>
AuthorDate: Wed Sep 17 18:16:09 2025 +0800

    fix: r
    
    Signed-off-by: Ashing Zheng <[email protected]>
---
 PROJECT                                          |  18 +-
 config/certmanager/certificate-metrics.yaml      |  20 +++
 config/certmanager/certificate-webhook.yaml      |  20 +++
 config/certmanager/issuer.yaml                   |  13 ++
 config/certmanager/kustomization.yaml            |   7 +
 config/certmanager/kustomizeconfig.yaml          |   8 +
 config/crd/kustomization.yaml                    |   4 +-
 config/default/kustomization.yaml                | 211 ++++++++++++-----------
 config/default/manager_webhook_patch.yaml        |  26 +++
 config/default/webhookcainjection_patch.yaml     |   8 +
 config/network-policy/allow-webhook-traffic.yaml |  27 +++
 config/network-policy/kustomization.yaml         |   2 +
 config/webhook/kustomization.yaml                |   6 +
 config/webhook/kustomizeconfig.yaml              |  22 +++
 config/webhook/manifests.yaml                    |  26 +++
 config/webhook/service.yaml                      |  16 ++
 internal/webhook/v1/ingress_webhook.go           |  96 +++++++++++
 internal/webhook/v1/ingress_webhook_test.go      |  70 ++++++++
 internal/webhook/v1/webhook_suite_test.go        | 162 +++++++++++++++++
 test/e2e/e2e_test.go                             |   1 +
 20 files changed, 645 insertions(+), 118 deletions(-)

diff --git a/PROJECT b/PROJECT
index 6c8ff968..d5bb57a8 100644
--- a/PROJECT
+++ b/PROJECT
@@ -2,7 +2,6 @@
 # This file is used to track the info used to scaffold your project
 # and allow the plugins properly work.
 # More info: https://book.kubebuilder.io/reference/project-config.html
-domain: github.com
 layout:
 - go.kubebuilder.io/v4
 projectName: apisix-ingress-controller
@@ -70,20 +69,11 @@ resources:
   kind: ApisixPluginConfig
   path: github.com/apache/apisix-ingress-controller/api/v2
   version: v2
-- api:
-    crdVersion: v1
-    namespaced: true
-  controller: true
-  group: networking.k8s.io
+- group: networking.k8s.io
   kind: Ingress
   path: k8s.io/api/networking/v1
   version: v1
-- api:
-    crdVersion: v1
-    namespaced: false
-  controller: true
-  group: networking.k8s.io
-  kind: IngressClass
-  path: k8s.io/api/networking/v1
-  version: v1
+  webhooks:
+    validation: true
+    webhookVersion: v1
 version: "3"
diff --git a/config/certmanager/certificate-metrics.yaml 
b/config/certmanager/certificate-metrics.yaml
new file mode 100644
index 00000000..b47c8989
--- /dev/null
+++ b/config/certmanager/certificate-metrics.yaml
@@ -0,0 +1,20 @@
+# The following manifests contain a self-signed issuer CR and a metrics 
certificate CR.
+# More document can be found at https://docs.cert-manager.io
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+  labels:
+    app.kubernetes.io/name: apisix-ingress-controller
+    app.kubernetes.io/managed-by: kustomize
+  name: metrics-certs  # this name should match the one appeared in 
kustomizeconfig.yaml
+  namespace: system
+spec:
+  dnsNames:
+  # SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize
+  # replacements in the config/default/kustomization.yaml file.
+  - SERVICE_NAME.SERVICE_NAMESPACE.svc
+  - SERVICE_NAME.SERVICE_NAMESPACE.svc.cluster.local
+  issuerRef:
+    kind: Issuer
+    name: selfsigned-issuer
+  secretName: metrics-server-cert
diff --git a/config/certmanager/certificate-webhook.yaml 
b/config/certmanager/certificate-webhook.yaml
new file mode 100644
index 00000000..c390d091
--- /dev/null
+++ b/config/certmanager/certificate-webhook.yaml
@@ -0,0 +1,20 @@
+# The following manifests contain a self-signed issuer CR and a certificate CR.
+# More document can be found at https://docs.cert-manager.io
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+  labels:
+    app.kubernetes.io/name: apisix-ingress-controller
+    app.kubernetes.io/managed-by: kustomize
+  name: serving-cert  # this name should match the one appeared in 
kustomizeconfig.yaml
+  namespace: system
+spec:
+  # SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize
+  # replacements in the config/default/kustomization.yaml file.
+  dnsNames:
+  - SERVICE_NAME.SERVICE_NAMESPACE.svc
+  - SERVICE_NAME.SERVICE_NAMESPACE.svc.cluster.local
+  issuerRef:
+    kind: Issuer
+    name: selfsigned-issuer
+  secretName: webhook-server-cert
diff --git a/config/certmanager/issuer.yaml b/config/certmanager/issuer.yaml
new file mode 100644
index 00000000..8af548bf
--- /dev/null
+++ b/config/certmanager/issuer.yaml
@@ -0,0 +1,13 @@
+# The following manifest contains a self-signed issuer CR.
+# More information can be found at https://docs.cert-manager.io
+# WARNING: Targets CertManager v1.0. Check 
https://cert-manager.io/docs/installation/upgrading/ for breaking changes.
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+  labels:
+    app.kubernetes.io/name: apisix-ingress-controller
+    app.kubernetes.io/managed-by: kustomize
+  name: selfsigned-issuer
+  namespace: system
+spec:
+  selfSigned: {}
diff --git a/config/certmanager/kustomization.yaml 
b/config/certmanager/kustomization.yaml
new file mode 100644
index 00000000..fcb7498e
--- /dev/null
+++ b/config/certmanager/kustomization.yaml
@@ -0,0 +1,7 @@
+resources:
+- issuer.yaml
+- certificate-webhook.yaml
+- certificate-metrics.yaml
+
+configurations:
+- kustomizeconfig.yaml
diff --git a/config/certmanager/kustomizeconfig.yaml 
b/config/certmanager/kustomizeconfig.yaml
new file mode 100644
index 00000000..cf6f89e8
--- /dev/null
+++ b/config/certmanager/kustomizeconfig.yaml
@@ -0,0 +1,8 @@
+# This configuration is for teaching kustomize how to update name ref 
substitution
+nameReference:
+- kind: Issuer
+  group: cert-manager.io
+  fieldSpecs:
+  - kind: Certificate
+    group: cert-manager.io
+    path: spec/issuerRef/name
diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml
index 2f12a658..4148a24d 100644
--- a/config/crd/kustomization.yaml
+++ b/config/crd/kustomization.yaml
@@ -42,5 +42,5 @@ patches:
 # [WEBHOOK] To enable webhook, uncomment the following section
 # the following config is for teaching kustomize how to do kustomization for 
CRDs.
 
-#configurations:
-#- kustomizeconfig.yaml
+configurations:
+- kustomizeconfig.yaml
diff --git a/config/default/kustomization.yaml 
b/config/default/kustomization.yaml
index 87b8a237..b822a150 100644
--- a/config/default/kustomization.yaml
+++ b/config/default/kustomization.yaml
@@ -20,17 +20,18 @@ resources:
 - ../manager
 # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] 
prefix including the one in
 # crd/kustomization.yaml
-#- ../webhook
+- ../webhook
 # [CERTMANAGER] To enable cert-manager, uncomment all sections with 
'CERTMANAGER'. 'WEBHOOK' components are required.
-#- ../certmanager
+- ../certmanager
 # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 
'PROMETHEUS'.
 #- ../prometheus
 # [METRICS] Expose the controller manager metrics service.
 - metrics_service.yaml
 - ../samples
+- ../network-policy
 
 # Uncomment the patches line if you enable Metrics, and/or are using webhooks 
and cert-manager
-#patches:
+patches:
 # [METRICS] The following patch will enable the metrics endpoint using HTTPS 
and the port :8443.
 # More info: https://book.kubebuilder.io/reference/metrics
 #- path: manager_patch.yaml
@@ -39,109 +40,115 @@ resources:
 
 # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] 
prefix including the one in
 # crd/kustomization.yaml
-#- path: manager_webhook_patch.yaml
+- path: manager_webhook_patch.yaml
+  target:
+    kind: Deployment
+    name: controller-manager
 
 # [CERTMANAGER] To enable cert-manager, uncomment all sections with 
'CERTMANAGER'.
 # Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA 
injection in the admission webhooks.
 # 'CERTMANAGER' needs to be enabled to use ca injection
-#- path: webhookcainjection_patch.yaml
+- path: webhookcainjection_patch.yaml
+  target:
+    kind: ValidatingWebhookConfiguration
+    name: validating-webhook-configuration
 
 # [CERTMANAGER] To enable cert-manager, uncomment all sections with 
'CERTMANAGER' prefix.
 # Uncomment the following replacements to add the cert-manager CA injection 
annotations
-#replacements:
-#  - source: # Add cert-manager annotation to ValidatingWebhookConfiguration, 
MutatingWebhookConfiguration and CRDs
-#      kind: Certificate
-#      group: cert-manager.io
-#      version: v1
-#      name: serving-cert # this name should match the one in certificate.yaml
-#      fieldPath: .metadata.namespace # namespace of the certificate CR
-#    targets:
-#      - select:
-#          kind: ValidatingWebhookConfiguration
-#        fieldPaths:
-#          - .metadata.annotations.[cert-manager.io/inject-ca-from]
-#        options:
-#          delimiter: '/'
-#          index: 0
-#          create: true
-#      - select:
-#          kind: MutatingWebhookConfiguration
-#        fieldPaths:
-#          - .metadata.annotations.[cert-manager.io/inject-ca-from]
-#        options:
-#          delimiter: '/'
-#          index: 0
-#          create: true
-#      - select:
-#          kind: CustomResourceDefinition
-#        fieldPaths:
-#          - .metadata.annotations.[cert-manager.io/inject-ca-from]
-#        options:
-#          delimiter: '/'
-#          index: 0
-#          create: true
-#  - source:
-#      kind: Certificate
-#      group: cert-manager.io
-#      version: v1
-#      name: serving-cert # this name should match the one in certificate.yaml
-#      fieldPath: .metadata.name
-#    targets:
-#      - select:
-#          kind: ValidatingWebhookConfiguration
-#        fieldPaths:
-#          - .metadata.annotations.[cert-manager.io/inject-ca-from]
-#        options:
-#          delimiter: '/'
-#          index: 1
-#          create: true
-#      - select:
-#          kind: MutatingWebhookConfiguration
-#        fieldPaths:
-#          - .metadata.annotations.[cert-manager.io/inject-ca-from]
-#        options:
-#          delimiter: '/'
-#          index: 1
-#          create: true
-#      - select:
-#          kind: CustomResourceDefinition
-#        fieldPaths:
-#          - .metadata.annotations.[cert-manager.io/inject-ca-from]
-#        options:
-#          delimiter: '/'
-#          index: 1
-#          create: true
-#  - source: # Add cert-manager annotation to the webhook Service
-#      kind: Service
-#      version: v1
-#      name: webhook-service
-#      fieldPath: .metadata.name # namespace of the service
-#    targets:
-#      - select:
-#          kind: Certificate
-#          group: cert-manager.io
-#          version: v1
-#        fieldPaths:
-#          - .spec.dnsNames.0
-#          - .spec.dnsNames.1
-#        options:
-#          delimiter: '.'
-#          index: 0
-#          create: true
-#  - source:
-#      kind: Service
-#      version: v1
-#      name: webhook-service
-#      fieldPath: .metadata.namespace # namespace of the service
-#    targets:
-#      - select:
-#          kind: Certificate
-#          group: cert-manager.io
-#          version: v1
-#        fieldPaths:
-#          - .spec.dnsNames.0
-#          - .spec.dnsNames.1
-#        options:
-#          delimiter: '.'
-#          index: 1
-#          create: true
+replacements:
+  - source: # Add cert-manager annotation to ValidatingWebhookConfiguration, 
MutatingWebhookConfiguration and CRDs
+      kind: Certificate
+      group: cert-manager.io
+      version: v1
+      name: serving-cert # this name should match the one in certificate.yaml
+      fieldPath: .metadata.namespace # namespace of the certificate CR
+    targets:
+      - select:
+          kind: ValidatingWebhookConfiguration
+        fieldPaths:
+          - .metadata.annotations.[cert-manager.io/inject-ca-from]
+        options:
+          delimiter: '/'
+          index: 0
+          create: true
+      - select:
+          kind: MutatingWebhookConfiguration
+        fieldPaths:
+          - .metadata.annotations.[cert-manager.io/inject-ca-from]
+        options:
+          delimiter: '/'
+          index: 0
+          create: true
+      - select:
+          kind: CustomResourceDefinition
+        fieldPaths:
+          - .metadata.annotations.[cert-manager.io/inject-ca-from]
+        options:
+          delimiter: '/'
+          index: 0
+          create: true
+  - source:
+      kind: Certificate
+      group: cert-manager.io
+      version: v1
+      name: serving-cert # this name should match the one in certificate.yaml
+      fieldPath: .metadata.name
+    targets:
+      - select:
+          kind: ValidatingWebhookConfiguration
+        fieldPaths:
+          - .metadata.annotations.[cert-manager.io/inject-ca-from]
+        options:
+          delimiter: '/'
+          index: 1
+          create: true
+      - select:
+          kind: MutatingWebhookConfiguration
+        fieldPaths:
+          - .metadata.annotations.[cert-manager.io/inject-ca-from]
+        options:
+          delimiter: '/'
+          index: 1
+          create: true
+      - select:
+          kind: CustomResourceDefinition
+        fieldPaths:
+          - .metadata.annotations.[cert-manager.io/inject-ca-from]
+        options:
+          delimiter: '/'
+          index: 1
+          create: true
+  - source: # Add cert-manager annotation to the webhook Service
+      kind: Service
+      version: v1
+      name: webhook-service
+      fieldPath: .metadata.name # namespace of the service
+    targets:
+      - select:
+          kind: Certificate
+          group: cert-manager.io
+          version: v1
+        fieldPaths:
+          - .spec.dnsNames.0
+          - .spec.dnsNames.1
+        options:
+          delimiter: '.'
+          index: 0
+          create: true
+  - source:
+      kind: Service
+      version: v1
+      name: webhook-service
+      fieldPath: .metadata.namespace # namespace of the service
+    targets:
+      - select:
+          kind: Certificate
+          group: cert-manager.io
+          version: v1
+        fieldPaths:
+          - .spec.dnsNames.0
+          - .spec.dnsNames.1
+        options:
+          delimiter: '.'
+          index: 1
+          create: true
diff --git a/config/default/manager_webhook_patch.yaml 
b/config/default/manager_webhook_patch.yaml
new file mode 100644
index 00000000..7c12cdb4
--- /dev/null
+++ b/config/default/manager_webhook_patch.yaml
@@ -0,0 +1,26 @@
+# This patch ensures the webhook certificates are properly mounted in the 
manager container.
+# It configures the necessary arguments, volumes, volume mounts, and container 
ports.
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: controller-manager
+  namespace: system
+spec:
+  template:
+    spec:
+      containers:
+      - name: manager
+        args:
+        - --webhook-cert-path=/tmp/k8s-webhook-server/serving-certs
+        ports:
+        - containerPort: 9443
+          name: webhook-server
+          protocol: TCP
+        volumeMounts:
+        - mountPath: /tmp/k8s-webhook-server/serving-certs
+          name: webhook-certs
+          readOnly: true
+      volumes:
+      - name: webhook-certs
+        secret:
+          secretName: webhook-server-cert
diff --git a/config/default/webhookcainjection_patch.yaml 
b/config/default/webhookcainjection_patch.yaml
new file mode 100644
index 00000000..74f12b3e
--- /dev/null
+++ b/config/default/webhookcainjection_patch.yaml
@@ -0,0 +1,8 @@
+# This patch adds the cert-manager CA injection annotation to the webhook 
configuration.
+# This file is auto-generated; do not edit directly.
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+  name: validating-webhook-configuration
+  annotations:
+    cert-manager.io/inject-ca-from: 
$(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
\ No newline at end of file
diff --git a/config/network-policy/allow-webhook-traffic.yaml 
b/config/network-policy/allow-webhook-traffic.yaml
new file mode 100644
index 00000000..e3f2f408
--- /dev/null
+++ b/config/network-policy/allow-webhook-traffic.yaml
@@ -0,0 +1,27 @@
+# This NetworkPolicy allows ingress traffic to your webhook server running
+# as part of the controller-manager from specific namespaces and pods. CR(s) 
which uses webhooks
+# will only work when applied in namespaces labeled with 'webhook: enabled'
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  labels:
+    app.kubernetes.io/name: apisix-ingress-controller
+    app.kubernetes.io/managed-by: kustomize
+  name: allow-webhook-traffic
+  namespace: system
+spec:
+  podSelector:
+    matchLabels:
+      control-plane: controller-manager
+      app.kubernetes.io/name: apisix-ingress-controller
+  policyTypes:
+    - Ingress
+  ingress:
+    # This allows ingress traffic from any namespace with the label webhook: 
enabled
+    - from:
+      - namespaceSelector:
+          matchLabels:
+            webhook: enabled # Only from namespaces with this label
+      ports:
+        - port: 443
+          protocol: TCP
diff --git a/config/network-policy/kustomization.yaml 
b/config/network-policy/kustomization.yaml
new file mode 100644
index 00000000..d6957493
--- /dev/null
+++ b/config/network-policy/kustomization.yaml
@@ -0,0 +1,2 @@
+resources:
+- allow-webhook-traffic.yaml
\ No newline at end of file
diff --git a/config/webhook/kustomization.yaml 
b/config/webhook/kustomization.yaml
new file mode 100644
index 00000000..9cf26134
--- /dev/null
+++ b/config/webhook/kustomization.yaml
@@ -0,0 +1,6 @@
+resources:
+- manifests.yaml
+- service.yaml
+
+configurations:
+- kustomizeconfig.yaml
diff --git a/config/webhook/kustomizeconfig.yaml 
b/config/webhook/kustomizeconfig.yaml
new file mode 100644
index 00000000..206316e5
--- /dev/null
+++ b/config/webhook/kustomizeconfig.yaml
@@ -0,0 +1,22 @@
+# the following config is for teaching kustomize where to look at when 
substituting nameReference.
+# It requires kustomize v2.1.0 or newer to work properly.
+nameReference:
+- kind: Service
+  version: v1
+  fieldSpecs:
+  - kind: MutatingWebhookConfiguration
+    group: admissionregistration.k8s.io
+    path: webhooks/clientConfig/service/name
+  - kind: ValidatingWebhookConfiguration
+    group: admissionregistration.k8s.io
+    path: webhooks/clientConfig/service/name
+
+namespace:
+- kind: MutatingWebhookConfiguration
+  group: admissionregistration.k8s.io
+  path: webhooks/clientConfig/service/namespace
+  create: true
+- kind: ValidatingWebhookConfiguration
+  group: admissionregistration.k8s.io
+  path: webhooks/clientConfig/service/namespace
+  create: true
diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml
new file mode 100644
index 00000000..8632054a
--- /dev/null
+++ b/config/webhook/manifests.yaml
@@ -0,0 +1,26 @@
+---
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+  name: validating-webhook-configuration
+webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: webhook-service
+      namespace: system
+      path: /validate-networking-k8s-io-v1-ingress
+  failurePolicy: Fail
+  name: vingress-v1.kb.io
+  rules:
+  - apiGroups:
+    - networking.k8s.io
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - ingresses
+  sideEffects: None
diff --git a/config/webhook/service.yaml b/config/webhook/service.yaml
new file mode 100644
index 00000000..1f0b7c34
--- /dev/null
+++ b/config/webhook/service.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    app.kubernetes.io/name: apisix-ingress-controller
+    app.kubernetes.io/managed-by: kustomize
+  name: webhook-service
+  namespace: system
+spec:
+  ports:
+    - port: 443
+      protocol: TCP
+      targetPort: 9443
+  selector:
+    control-plane: controller-manager
+    app.kubernetes.io/name: apisix-ingress-controller
diff --git a/internal/webhook/v1/ingress_webhook.go 
b/internal/webhook/v1/ingress_webhook.go
new file mode 100644
index 00000000..30c24f7c
--- /dev/null
+++ b/internal/webhook/v1/ingress_webhook.go
@@ -0,0 +1,96 @@
+// 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"
+
+       networkingk8siov1 "k8s.io/api/networking/v1"
+       "k8s.io/apimachinery/pkg/runtime"
+       ctrl "sigs.k8s.io/controller-runtime"
+       logf "sigs.k8s.io/controller-runtime/pkg/log"
+       "sigs.k8s.io/controller-runtime/pkg/webhook"
+       "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+// nolint:unused
+// log is for logging in this package.
+var ingresslog = logf.Log.WithName("ingress-resource")
+
+// SetupIngressWebhookWithManager registers the webhook for Ingress in the 
manager.
+func SetupIngressWebhookWithManager(mgr ctrl.Manager) error {
+       return ctrl.NewWebhookManagedBy(mgr).For(&networkingk8siov1.Ingress{}).
+               WithValidator(&IngressCustomValidator{}).
+               Complete()
+}
+
+// TODO(user): EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
+
+// TODO(user): change verbs to "verbs=create;update;delete" if you want to 
enable deletion validation.
+// NOTE: The 'path' attribute must follow a specific pattern and should not be 
modified directly here.
+// Modifying the path for an invalid path can cause API server errors; failing 
to locate the webhook.
+// 
+kubebuilder:webhook:path=/validate-networking-k8s-io-v1-ingress,mutating=false,failurePolicy=fail,sideEffects=None,groups=networking.k8s.io,resources=ingresses,verbs=create;update,versions=v1,name=vingress-v1.kb.io,admissionReviewVersions=v1
+
+// IngressCustomValidator struct is responsible for validating the Ingress 
resource
+// when it is created, updated, or deleted.
+//
+// NOTE: The +kubebuilder:object:generate=false marker prevents controller-gen 
from generating DeepCopy methods,
+// as this struct is used only for temporary operations and does not need to 
be deeply copied.
+type IngressCustomValidator struct {
+       // TODO(user): Add more fields as needed for validation
+}
+
+var _ webhook.CustomValidator = &IngressCustomValidator{}
+
+// ValidateCreate implements webhook.CustomValidator so a webhook will be 
registered for the type Ingress.
+func (v *IngressCustomValidator) ValidateCreate(_ context.Context, obj 
runtime.Object) (admission.Warnings, error) {
+       ingress, ok := obj.(*networkingk8siov1.Ingress)
+       if !ok {
+               return nil, fmt.Errorf("expected a Ingress object but got %T", 
obj)
+       }
+       ingresslog.Info("Validation for Ingress upon creation", "name", 
ingress.GetName())
+
+       // TODO(user): fill in your validation logic upon object creation.
+
+       return nil, nil
+}
+
+// ValidateUpdate implements webhook.CustomValidator so a webhook will be 
registered for the type Ingress.
+func (v *IngressCustomValidator) ValidateUpdate(_ context.Context, oldObj, 
newObj runtime.Object) (admission.Warnings, error) {
+       ingress, ok := newObj.(*networkingk8siov1.Ingress)
+       if !ok {
+               return nil, fmt.Errorf("expected a Ingress object for the 
newObj but got %T", newObj)
+       }
+       ingresslog.Info("Validation for Ingress upon update", "name", 
ingress.GetName())
+
+       // TODO(user): fill in your validation logic upon object update.
+
+       return nil, nil
+}
+
+// ValidateDelete implements webhook.CustomValidator so a webhook will be 
registered for the type Ingress.
+func (v *IngressCustomValidator) ValidateDelete(ctx context.Context, obj 
runtime.Object) (admission.Warnings, error) {
+       ingress, ok := obj.(*networkingk8siov1.Ingress)
+       if !ok {
+               return nil, fmt.Errorf("expected a Ingress object but got %T", 
obj)
+       }
+       ingresslog.Info("Validation for Ingress upon deletion", "name", 
ingress.GetName())
+
+       // TODO(user): fill in your validation logic upon object deletion.
+
+       return nil, nil
+}
diff --git a/internal/webhook/v1/ingress_webhook_test.go 
b/internal/webhook/v1/ingress_webhook_test.go
new file mode 100644
index 00000000..3e3fb809
--- /dev/null
+++ b/internal/webhook/v1/ingress_webhook_test.go
@@ -0,0 +1,70 @@
+// 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 (
+       . "github.com/onsi/ginkgo/v2"
+       . "github.com/onsi/gomega"
+
+       networkingk8siov1 "k8s.io/api/networking/v1"
+       // TODO (user): Add any additional imports if needed
+)
+
+var _ = Describe("Ingress Webhook", func() {
+       var (
+               obj       *networkingk8siov1.Ingress
+               oldObj    *networkingk8siov1.Ingress
+               validator IngressCustomValidator
+       )
+
+       BeforeEach(func() {
+               obj = &networkingk8siov1.Ingress{}
+               oldObj = &networkingk8siov1.Ingress{}
+               validator = IngressCustomValidator{}
+               Expect(validator).NotTo(BeNil(), "Expected validator to be 
initialized")
+               Expect(oldObj).NotTo(BeNil(), "Expected oldObj to be 
initialized")
+               Expect(obj).NotTo(BeNil(), "Expected obj to be initialized")
+               // TODO (user): Add any setup logic common to all tests
+       })
+
+       AfterEach(func() {
+               // TODO (user): Add any teardown logic common to all tests
+       })
+
+       Context("When creating or updating Ingress under Validating Webhook", 
func() {
+               // TODO (user): Add logic for validating webhooks
+               // Example:
+               // It("Should deny creation if a required field is missing", 
func() {
+               //     By("simulating an invalid creation scenario")
+               //     obj.SomeRequiredField = ""
+               //     Expect(validator.ValidateCreate(ctx, 
obj)).Error().To(HaveOccurred())
+               // })
+               //
+               // It("Should admit creation if all required fields are 
present", func() {
+               //     By("simulating an invalid creation scenario")
+               //     obj.SomeRequiredField = "valid_value"
+               //     Expect(validator.ValidateCreate(ctx, obj)).To(BeNil())
+               // })
+               //
+               // It("Should validate updates correctly", func() {
+               //     By("simulating a valid update scenario")
+               //     oldObj.SomeRequiredField = "updated_value"
+               //     obj.SomeRequiredField = "updated_value"
+               //     Expect(validator.ValidateUpdate(ctx, oldObj, 
obj)).To(BeNil())
+               // })
+       })
+
+})
diff --git a/internal/webhook/v1/webhook_suite_test.go 
b/internal/webhook/v1/webhook_suite_test.go
new file mode 100644
index 00000000..549cf79e
--- /dev/null
+++ b/internal/webhook/v1/webhook_suite_test.go
@@ -0,0 +1,162 @@
+// 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"
+       "crypto/tls"
+       "fmt"
+       "net"
+       "os"
+       "path/filepath"
+       "testing"
+       "time"
+
+       . "github.com/onsi/ginkgo/v2"
+       . "github.com/onsi/gomega"
+
+       networkingk8siov1 "k8s.io/api/networking/v1"
+       "k8s.io/client-go/kubernetes/scheme"
+       "k8s.io/client-go/rest"
+       ctrl "sigs.k8s.io/controller-runtime"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+       "sigs.k8s.io/controller-runtime/pkg/envtest"
+       logf "sigs.k8s.io/controller-runtime/pkg/log"
+       "sigs.k8s.io/controller-runtime/pkg/log/zap"
+       metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
+       "sigs.k8s.io/controller-runtime/pkg/webhook"
+       // +kubebuilder:scaffold:imports
+)
+
+// These tests use Ginkgo (BDD-style Go testing framework). Refer to
+// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
+
+var (
+       ctx       context.Context
+       cancel    context.CancelFunc
+       k8sClient client.Client
+       cfg       *rest.Config
+       testEnv   *envtest.Environment
+)
+
+func TestAPIs(t *testing.T) {
+       RegisterFailHandler(Fail)
+
+       RunSpecs(t, "Webhook Suite")
+}
+
+var _ = BeforeSuite(func() {
+       logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+
+       ctx, cancel = context.WithCancel(context.TODO())
+
+       var err error
+       err = networkingk8siov1.AddToScheme(scheme.Scheme)
+       Expect(err).NotTo(HaveOccurred())
+
+       // +kubebuilder:scaffold:scheme
+
+       By("bootstrapping test environment")
+       testEnv = &envtest.Environment{
+               CRDDirectoryPaths:     []string{filepath.Join("..", "..", "..", 
"config", "crd", "bases")},
+               ErrorIfCRDPathMissing: false,
+
+               WebhookInstallOptions: envtest.WebhookInstallOptions{
+                       Paths: []string{filepath.Join("..", "..", "..", 
"config", "webhook")},
+               },
+       }
+
+       // Retrieve the first found binary directory to allow running tests 
from IDEs
+       if getFirstFoundEnvTestBinaryDir() != "" {
+               testEnv.BinaryAssetsDirectory = getFirstFoundEnvTestBinaryDir()
+       }
+
+       // cfg is defined in this file globally.
+       cfg, err = testEnv.Start()
+       Expect(err).NotTo(HaveOccurred())
+       Expect(cfg).NotTo(BeNil())
+
+       k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
+       Expect(err).NotTo(HaveOccurred())
+       Expect(k8sClient).NotTo(BeNil())
+
+       // start webhook server using Manager.
+       webhookInstallOptions := &testEnv.WebhookInstallOptions
+       mgr, err := ctrl.NewManager(cfg, ctrl.Options{
+               Scheme: scheme.Scheme,
+               WebhookServer: webhook.NewServer(webhook.Options{
+                       Host:    webhookInstallOptions.LocalServingHost,
+                       Port:    webhookInstallOptions.LocalServingPort,
+                       CertDir: webhookInstallOptions.LocalServingCertDir,
+               }),
+               LeaderElection: false,
+               Metrics:        metricsserver.Options{BindAddress: "0"},
+       })
+       Expect(err).NotTo(HaveOccurred())
+
+       err = SetupIngressWebhookWithManager(mgr)
+       Expect(err).NotTo(HaveOccurred())
+
+       // +kubebuilder:scaffold:webhook
+
+       go func() {
+               defer GinkgoRecover()
+               err = mgr.Start(ctx)
+               Expect(err).NotTo(HaveOccurred())
+       }()
+
+       // wait for the webhook server to get ready.
+       dialer := &net.Dialer{Timeout: time.Second}
+       addrPort := fmt.Sprintf("%s:%d", 
webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort)
+       Eventually(func() error {
+               conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, 
&tls.Config{InsecureSkipVerify: true})
+               if err != nil {
+                       return err
+               }
+
+               return conn.Close()
+       }).Should(Succeed())
+})
+
+var _ = AfterSuite(func() {
+       By("tearing down the test environment")
+       cancel()
+       err := testEnv.Stop()
+       Expect(err).NotTo(HaveOccurred())
+})
+
+// getFirstFoundEnvTestBinaryDir locates the first binary in the specified 
path.
+// ENVTEST-based tests depend on specific binaries, usually located in paths 
set by
+// controller-runtime. When running tests directly (e.g., via an IDE) without 
using
+// Makefile targets, the 'BinaryAssetsDirectory' must be explicitly configured.
+//
+// This function streamlines the process by finding the required binaries, 
similar to
+// setting the 'KUBEBUILDER_ASSETS' environment variable. To ensure the 
binaries are
+// properly set up, run 'make setup-envtest' beforehand.
+func getFirstFoundEnvTestBinaryDir() string {
+       basePath := filepath.Join("..", "..", "..", "bin", "k8s")
+       entries, err := os.ReadDir(basePath)
+       if err != nil {
+               logf.Log.Error(err, "Failed to read directory", "path", 
basePath)
+               return ""
+       }
+       for _, entry := range entries {
+               if entry.IsDir() {
+                       return filepath.Join(basePath, entry.Name())
+               }
+       }
+       return ""
+}
diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go
new file mode 100644
index 00000000..df8caf70
--- /dev/null
+++ b/test/e2e/e2e_test.go
@@ -0,0 +1 @@
+package e2e

Reply via email to