You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by "ronething (via GitHub)" <gi...@apache.org> on 2025/10/13 09:05:10 UTC
[PR] feat: add conflict detection for gateway proxy [apisix-ingress-controller]
ronething opened a new pull request, #2600:
URL: https://github.com/apache/apisix-ingress-controller/pull/2600
<!-- Please answer these questions before submitting a pull request -->
### Type of change:
<!-- Please delete options that are not relevant. -->
<!-- Select all the options from below that matches the type your PR best -->
- [ ] Bugfix
- [ ] New feature provided
- [ ] Improve performance
- [ ] Backport patches
- [ ] Documentation
- [ ] Refactor
- [ ] Chore
- [ ] CI/CD or Tests
### What this PR does / why we need it:
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
add conflict detection for GatewayProxy resources that share the same admin credentials while targeting the same service or overlapping control-plane endpoints.
### Pre-submission checklist:
<!--
Please follow the requirements:
1. Use Draft if the PR is not ready to be reviewed
2. Test is required for the feat/fix PR, unless you have a good reason
3. Doc is required for the feat PR
4. Use a new commit to resolve review instead of `push -f`
5. Use "request review" to notify the reviewer once you have resolved the review
-->
- [ ] Did you explain what problem does this PR solve? Or what new features have been added?
- [ ] Have you added corresponding test cases?
- [ ] Have you modified the corresponding document?
- [ ] Is this PR backward compatible? **If it is not backward compatible, please discuss on the [mailing list](https://github.com/apache/apisix-ingress-controller#community) first**
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@apisix.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] feat: add conflict detection for gateway proxy [apisix-ingress-controller]
Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #2600:
URL: https://github.com/apache/apisix-ingress-controller/pull/2600#discussion_r2426066583
##########
test/e2e/webhook/gatewayproxy.go:
##########
@@ -121,9 +122,151 @@ stringData:
err = s.DeleteResource("GatewayProxy", gpName)
Expect(err).ShouldNot(HaveOccurred())
- output, err = s.CreateResourceFromStringAndGetOutput(fmt.Sprintf(gpWithSecrets, gpName, missingService, missingSecret))
+ output, err = s.CreateResourceFromStringAndGetOutput(fmt.Sprintf(gatewayProxyTemplate, gpName, missingService, missingSecret))
Expect(err).ShouldNot(HaveOccurred())
Expect(output).NotTo(ContainSubstring(fmt.Sprintf("Warning: Referenced Service '%s/%s' not found", s.Namespace(), missingService)))
Expect(output).NotTo(ContainSubstring(fmt.Sprintf("Warning: Secret key 'token' not found in Secret '%s/%s'", s.Namespace(), missingSecret)))
})
+
+ Context("GatewayProxy configuration conflicts", func() {
+ It("should reject GatewayProxy that reuses the same Service and AdminKey Secret as an existing one on create and update", func() {
+ serviceTemplate := `
+apiVersion: v1
+kind: Service
+metadata:
+ name: %s
+spec:
+ selector:
+ app: dummy-control-plane
+ ports:
+ - name: admin
+ port: 9180
+ targetPort: 9180
+`
+ secretTemplate := `
+apiVersion: v1
+kind: Secret
+metadata:
+ name: %s
+type: Opaque
+stringData:
+ %s: %s
+`
+ serviceName := "gatewayproxy-shared-service"
+ secretName := "gatewayproxy-shared-secret"
+ initialProxy := "gatewayproxy-shared-primary"
+ conflictingProxy := "gatewayproxy-shared-conflict"
+
+ Expect(s.CreateResourceFromString(fmt.Sprintf(serviceTemplate, serviceName))).ShouldNot(HaveOccurred(), "creating shared Service")
+ Expect(s.CreateResourceFromString(fmt.Sprintf(secretTemplate, secretName, "token", "value"))).ShouldNot(HaveOccurred(), "creating shared Secret")
+
+ err := s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, initialProxy, serviceName, secretName))
+ Expect(err).ShouldNot(HaveOccurred(), "creating initial GatewayProxy")
+
+ time.Sleep(2 * time.Second)
Review Comment:
Hard-coded sleep statements in tests are fragile and slow down test execution. Consider using a polling mechanism or event-driven approach to wait for the resource to be properly registered in the webhook system.
```suggestion
Eventually(func() error {
// Replace with a check for GatewayProxy readiness/existence.
// If s.GetResource returns error when not found, this works.
return s.GetResource("GatewayProxy", initialProxy)
}, 10*time.Second, 500*time.Millisecond).Should(Succeed(), "waiting for initial GatewayProxy to be registered")
```
##########
test/e2e/webhook/gatewayproxy.go:
##########
@@ -121,9 +122,151 @@ stringData:
err = s.DeleteResource("GatewayProxy", gpName)
Expect(err).ShouldNot(HaveOccurred())
- output, err = s.CreateResourceFromStringAndGetOutput(fmt.Sprintf(gpWithSecrets, gpName, missingService, missingSecret))
+ output, err = s.CreateResourceFromStringAndGetOutput(fmt.Sprintf(gatewayProxyTemplate, gpName, missingService, missingSecret))
Expect(err).ShouldNot(HaveOccurred())
Expect(output).NotTo(ContainSubstring(fmt.Sprintf("Warning: Referenced Service '%s/%s' not found", s.Namespace(), missingService)))
Expect(output).NotTo(ContainSubstring(fmt.Sprintf("Warning: Secret key 'token' not found in Secret '%s/%s'", s.Namespace(), missingSecret)))
})
+
+ Context("GatewayProxy configuration conflicts", func() {
+ It("should reject GatewayProxy that reuses the same Service and AdminKey Secret as an existing one on create and update", func() {
+ serviceTemplate := `
+apiVersion: v1
+kind: Service
+metadata:
+ name: %s
+spec:
+ selector:
+ app: dummy-control-plane
+ ports:
+ - name: admin
+ port: 9180
+ targetPort: 9180
+`
+ secretTemplate := `
+apiVersion: v1
+kind: Secret
+metadata:
+ name: %s
+type: Opaque
+stringData:
+ %s: %s
+`
+ serviceName := "gatewayproxy-shared-service"
+ secretName := "gatewayproxy-shared-secret"
+ initialProxy := "gatewayproxy-shared-primary"
+ conflictingProxy := "gatewayproxy-shared-conflict"
+
+ Expect(s.CreateResourceFromString(fmt.Sprintf(serviceTemplate, serviceName))).ShouldNot(HaveOccurred(), "creating shared Service")
+ Expect(s.CreateResourceFromString(fmt.Sprintf(secretTemplate, secretName, "token", "value"))).ShouldNot(HaveOccurred(), "creating shared Secret")
+
+ err := s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, initialProxy, serviceName, secretName))
+ Expect(err).ShouldNot(HaveOccurred(), "creating initial GatewayProxy")
+
+ time.Sleep(2 * time.Second)
+
+ err = s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, conflictingProxy, serviceName, secretName))
+ Expect(err).Should(HaveOccurred(), "expecting conflict for duplicated GatewayProxy")
+ Expect(err.Error()).To(ContainSubstring("gateway proxy configuration conflict"))
+ Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("%s/%s", s.Namespace(), conflictingProxy)))
+ Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("%s/%s", s.Namespace(), initialProxy)))
+ Expect(err.Error()).To(ContainSubstring("Service"))
+ Expect(err.Error()).To(ContainSubstring("AdminKey secret"))
+
+ Expect(s.DeleteResource("GatewayProxy", initialProxy)).ShouldNot(HaveOccurred())
+ Expect(s.DeleteResource("Service", serviceName)).ShouldNot(HaveOccurred())
+ Expect(s.DeleteResource("Secret", secretName)).ShouldNot(HaveOccurred())
+ })
+
+ It("should reject GatewayProxy that overlaps endpoints when sharing inline AdminKey value", func() {
+ gatewayProxyTemplate := `
+apiVersion: apisix.apache.org/v1alpha1
+kind: GatewayProxy
+metadata:
+ name: %s
+spec:
+ provider:
+ type: ControlPlane
+ controlPlane:
+ endpoints:
+ - %s
+ - %s
+ auth:
+ type: AdminKey
+ adminKey:
+ value: "%s"
+`
+
+ existingProxy := "gatewayproxy-inline-primary"
+ conflictingProxy := "gatewayproxy-inline-conflict"
+ endpointA := "https://127.0.0.1:9443"
+ endpointB := "https://10.0.0.1:9443"
+ endpointC := "https://192.168.0.1:9443"
+ inlineKey := "inline-credential"
+
+ err := s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, existingProxy, endpointA, endpointB, inlineKey))
+ Expect(err).ShouldNot(HaveOccurred(), "creating GatewayProxy with inline AdminKey")
+
+ time.Sleep(2 * time.Second)
Review Comment:
Multiple hard-coded sleep statements suggest a systematic issue with test timing. Consider implementing a helper function that polls for resource readiness or uses the Kubernetes client's watch functionality to wait for proper resource state.
##########
test/e2e/webhook/gatewayproxy.go:
##########
@@ -121,9 +122,151 @@ stringData:
err = s.DeleteResource("GatewayProxy", gpName)
Expect(err).ShouldNot(HaveOccurred())
- output, err = s.CreateResourceFromStringAndGetOutput(fmt.Sprintf(gpWithSecrets, gpName, missingService, missingSecret))
+ output, err = s.CreateResourceFromStringAndGetOutput(fmt.Sprintf(gatewayProxyTemplate, gpName, missingService, missingSecret))
Expect(err).ShouldNot(HaveOccurred())
Expect(output).NotTo(ContainSubstring(fmt.Sprintf("Warning: Referenced Service '%s/%s' not found", s.Namespace(), missingService)))
Expect(output).NotTo(ContainSubstring(fmt.Sprintf("Warning: Secret key 'token' not found in Secret '%s/%s'", s.Namespace(), missingSecret)))
})
+
+ Context("GatewayProxy configuration conflicts", func() {
+ It("should reject GatewayProxy that reuses the same Service and AdminKey Secret as an existing one on create and update", func() {
+ serviceTemplate := `
+apiVersion: v1
+kind: Service
+metadata:
+ name: %s
+spec:
+ selector:
+ app: dummy-control-plane
+ ports:
+ - name: admin
+ port: 9180
+ targetPort: 9180
+`
+ secretTemplate := `
+apiVersion: v1
+kind: Secret
+metadata:
+ name: %s
+type: Opaque
+stringData:
+ %s: %s
+`
+ serviceName := "gatewayproxy-shared-service"
+ secretName := "gatewayproxy-shared-secret"
+ initialProxy := "gatewayproxy-shared-primary"
+ conflictingProxy := "gatewayproxy-shared-conflict"
+
+ Expect(s.CreateResourceFromString(fmt.Sprintf(serviceTemplate, serviceName))).ShouldNot(HaveOccurred(), "creating shared Service")
+ Expect(s.CreateResourceFromString(fmt.Sprintf(secretTemplate, secretName, "token", "value"))).ShouldNot(HaveOccurred(), "creating shared Secret")
+
+ err := s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, initialProxy, serviceName, secretName))
+ Expect(err).ShouldNot(HaveOccurred(), "creating initial GatewayProxy")
+
+ time.Sleep(2 * time.Second)
+
+ err = s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, conflictingProxy, serviceName, secretName))
+ Expect(err).Should(HaveOccurred(), "expecting conflict for duplicated GatewayProxy")
+ Expect(err.Error()).To(ContainSubstring("gateway proxy configuration conflict"))
+ Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("%s/%s", s.Namespace(), conflictingProxy)))
+ Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("%s/%s", s.Namespace(), initialProxy)))
+ Expect(err.Error()).To(ContainSubstring("Service"))
+ Expect(err.Error()).To(ContainSubstring("AdminKey secret"))
+
+ Expect(s.DeleteResource("GatewayProxy", initialProxy)).ShouldNot(HaveOccurred())
+ Expect(s.DeleteResource("Service", serviceName)).ShouldNot(HaveOccurred())
+ Expect(s.DeleteResource("Secret", secretName)).ShouldNot(HaveOccurred())
+ })
+
+ It("should reject GatewayProxy that overlaps endpoints when sharing inline AdminKey value", func() {
+ gatewayProxyTemplate := `
+apiVersion: apisix.apache.org/v1alpha1
+kind: GatewayProxy
+metadata:
+ name: %s
+spec:
+ provider:
+ type: ControlPlane
+ controlPlane:
+ endpoints:
+ - %s
+ - %s
+ auth:
+ type: AdminKey
+ adminKey:
+ value: "%s"
+`
+
+ existingProxy := "gatewayproxy-inline-primary"
+ conflictingProxy := "gatewayproxy-inline-conflict"
+ endpointA := "https://127.0.0.1:9443"
+ endpointB := "https://10.0.0.1:9443"
+ endpointC := "https://192.168.0.1:9443"
+ inlineKey := "inline-credential"
+
+ err := s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, existingProxy, endpointA, endpointB, inlineKey))
+ Expect(err).ShouldNot(HaveOccurred(), "creating GatewayProxy with inline AdminKey")
+
+ time.Sleep(2 * time.Second)
+
+ err = s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, conflictingProxy, endpointB, endpointC, inlineKey))
+ Expect(err).Should(HaveOccurred(), "expecting conflict for overlapping endpoints with shared AdminKey")
+ Expect(err.Error()).To(ContainSubstring("gateway proxy configuration conflict"))
+ Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("%s/%s", s.Namespace(), conflictingProxy)))
+ Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("%s/%s", s.Namespace(), existingProxy)))
+ Expect(err.Error()).To(ContainSubstring("control plane endpoints"))
+ Expect(err.Error()).To(ContainSubstring("inline AdminKey value"))
+ })
+
+ It("should reject GatewayProxy update that creates conflict with another GatewayProxy", func() {
+ serviceTemplate := `
+apiVersion: v1
+kind: Service
+metadata:
+ name: %s
+spec:
+ selector:
+ app: dummy-control-plane
+ ports:
+ - name: admin
+ port: 9180
+ targetPort: 9180
+`
+ secretTemplate := `
+apiVersion: v1
+kind: Secret
+metadata:
+ name: %s
+type: Opaque
+stringData:
+ %s: %s
+`
+ sharedServiceName := "gatewayproxy-update-shared-service"
+ sharedSecretName := "gatewayproxy-update-shared-secret"
+ uniqueServiceName := "gatewayproxy-update-unique-service"
+ proxyA := "gatewayproxy-update-a"
+ proxyB := "gatewayproxy-update-b"
+
+ Expect(s.CreateResourceFromString(fmt.Sprintf(serviceTemplate, sharedServiceName))).ShouldNot(HaveOccurred(), "creating shared Service")
+ Expect(s.CreateResourceFromString(fmt.Sprintf(serviceTemplate, uniqueServiceName))).ShouldNot(HaveOccurred(), "creating unique Service")
+ Expect(s.CreateResourceFromString(fmt.Sprintf(secretTemplate, sharedSecretName, "token", "value"))).ShouldNot(HaveOccurred(), "creating shared Secret")
+
+ err := s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, proxyA, sharedServiceName, sharedSecretName))
+ Expect(err).ShouldNot(HaveOccurred(), "creating GatewayProxy A with shared Service and Secret")
+
+ time.Sleep(2 * time.Second)
+
+ err = s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, proxyB, uniqueServiceName, sharedSecretName))
+ Expect(err).ShouldNot(HaveOccurred(), "creating GatewayProxy B with unique Service but same Secret")
+
+ time.Sleep(2 * time.Second)
Review Comment:
Multiple hard-coded sleep statements suggest a systematic issue with test timing. Consider implementing a helper function that polls for resource readiness or uses the Kubernetes client's watch functionality to wait for proper resource state.
##########
test/e2e/webhook/gatewayproxy.go:
##########
@@ -121,9 +122,151 @@ stringData:
err = s.DeleteResource("GatewayProxy", gpName)
Expect(err).ShouldNot(HaveOccurred())
- output, err = s.CreateResourceFromStringAndGetOutput(fmt.Sprintf(gpWithSecrets, gpName, missingService, missingSecret))
+ output, err = s.CreateResourceFromStringAndGetOutput(fmt.Sprintf(gatewayProxyTemplate, gpName, missingService, missingSecret))
Expect(err).ShouldNot(HaveOccurred())
Expect(output).NotTo(ContainSubstring(fmt.Sprintf("Warning: Referenced Service '%s/%s' not found", s.Namespace(), missingService)))
Expect(output).NotTo(ContainSubstring(fmt.Sprintf("Warning: Secret key 'token' not found in Secret '%s/%s'", s.Namespace(), missingSecret)))
})
+
+ Context("GatewayProxy configuration conflicts", func() {
+ It("should reject GatewayProxy that reuses the same Service and AdminKey Secret as an existing one on create and update", func() {
+ serviceTemplate := `
+apiVersion: v1
+kind: Service
+metadata:
+ name: %s
+spec:
+ selector:
+ app: dummy-control-plane
+ ports:
+ - name: admin
+ port: 9180
+ targetPort: 9180
+`
+ secretTemplate := `
+apiVersion: v1
+kind: Secret
+metadata:
+ name: %s
+type: Opaque
+stringData:
+ %s: %s
+`
+ serviceName := "gatewayproxy-shared-service"
+ secretName := "gatewayproxy-shared-secret"
+ initialProxy := "gatewayproxy-shared-primary"
+ conflictingProxy := "gatewayproxy-shared-conflict"
+
+ Expect(s.CreateResourceFromString(fmt.Sprintf(serviceTemplate, serviceName))).ShouldNot(HaveOccurred(), "creating shared Service")
+ Expect(s.CreateResourceFromString(fmt.Sprintf(secretTemplate, secretName, "token", "value"))).ShouldNot(HaveOccurred(), "creating shared Secret")
+
+ err := s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, initialProxy, serviceName, secretName))
+ Expect(err).ShouldNot(HaveOccurred(), "creating initial GatewayProxy")
+
+ time.Sleep(2 * time.Second)
+
+ err = s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, conflictingProxy, serviceName, secretName))
+ Expect(err).Should(HaveOccurred(), "expecting conflict for duplicated GatewayProxy")
+ Expect(err.Error()).To(ContainSubstring("gateway proxy configuration conflict"))
+ Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("%s/%s", s.Namespace(), conflictingProxy)))
+ Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("%s/%s", s.Namespace(), initialProxy)))
+ Expect(err.Error()).To(ContainSubstring("Service"))
+ Expect(err.Error()).To(ContainSubstring("AdminKey secret"))
+
+ Expect(s.DeleteResource("GatewayProxy", initialProxy)).ShouldNot(HaveOccurred())
+ Expect(s.DeleteResource("Service", serviceName)).ShouldNot(HaveOccurred())
+ Expect(s.DeleteResource("Secret", secretName)).ShouldNot(HaveOccurred())
+ })
+
+ It("should reject GatewayProxy that overlaps endpoints when sharing inline AdminKey value", func() {
+ gatewayProxyTemplate := `
+apiVersion: apisix.apache.org/v1alpha1
+kind: GatewayProxy
+metadata:
+ name: %s
+spec:
+ provider:
+ type: ControlPlane
+ controlPlane:
+ endpoints:
+ - %s
+ - %s
+ auth:
+ type: AdminKey
+ adminKey:
+ value: "%s"
+`
+
+ existingProxy := "gatewayproxy-inline-primary"
+ conflictingProxy := "gatewayproxy-inline-conflict"
+ endpointA := "https://127.0.0.1:9443"
+ endpointB := "https://10.0.0.1:9443"
+ endpointC := "https://192.168.0.1:9443"
+ inlineKey := "inline-credential"
+
+ err := s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, existingProxy, endpointA, endpointB, inlineKey))
+ Expect(err).ShouldNot(HaveOccurred(), "creating GatewayProxy with inline AdminKey")
+
+ time.Sleep(2 * time.Second)
+
+ err = s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, conflictingProxy, endpointB, endpointC, inlineKey))
+ Expect(err).Should(HaveOccurred(), "expecting conflict for overlapping endpoints with shared AdminKey")
+ Expect(err.Error()).To(ContainSubstring("gateway proxy configuration conflict"))
+ Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("%s/%s", s.Namespace(), conflictingProxy)))
+ Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("%s/%s", s.Namespace(), existingProxy)))
+ Expect(err.Error()).To(ContainSubstring("control plane endpoints"))
+ Expect(err.Error()).To(ContainSubstring("inline AdminKey value"))
+ })
+
+ It("should reject GatewayProxy update that creates conflict with another GatewayProxy", func() {
+ serviceTemplate := `
+apiVersion: v1
+kind: Service
+metadata:
+ name: %s
+spec:
+ selector:
+ app: dummy-control-plane
+ ports:
+ - name: admin
+ port: 9180
+ targetPort: 9180
+`
+ secretTemplate := `
+apiVersion: v1
+kind: Secret
+metadata:
+ name: %s
+type: Opaque
+stringData:
+ %s: %s
+`
+ sharedServiceName := "gatewayproxy-update-shared-service"
+ sharedSecretName := "gatewayproxy-update-shared-secret"
+ uniqueServiceName := "gatewayproxy-update-unique-service"
+ proxyA := "gatewayproxy-update-a"
+ proxyB := "gatewayproxy-update-b"
+
+ Expect(s.CreateResourceFromString(fmt.Sprintf(serviceTemplate, sharedServiceName))).ShouldNot(HaveOccurred(), "creating shared Service")
+ Expect(s.CreateResourceFromString(fmt.Sprintf(serviceTemplate, uniqueServiceName))).ShouldNot(HaveOccurred(), "creating unique Service")
+ Expect(s.CreateResourceFromString(fmt.Sprintf(secretTemplate, sharedSecretName, "token", "value"))).ShouldNot(HaveOccurred(), "creating shared Secret")
+
+ err := s.CreateResourceFromString(fmt.Sprintf(gatewayProxyTemplate, proxyA, sharedServiceName, sharedSecretName))
+ Expect(err).ShouldNot(HaveOccurred(), "creating GatewayProxy A with shared Service and Secret")
+
+ time.Sleep(2 * time.Second)
Review Comment:
Multiple hard-coded sleep statements suggest a systematic issue with test timing. Consider implementing a helper function that polls for resource readiness or uses the Kubernetes client's watch functionality to wait for proper resource state.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@apisix.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] feat: add conflict detection for gateway proxy [apisix-ingress-controller]
Posted by "ronething (via GitHub)" <gi...@apache.org>.
ronething merged PR #2600:
URL: https://github.com/apache/apisix-ingress-controller/pull/2600
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@apisix.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org