Copilot commented on code in PR #2551: URL: https://github.com/apache/apisix-ingress-controller/pull/2551#discussion_r2335197670
########## test/e2e/scaffold/scaffold.go: ########## @@ -63,23 +63,41 @@ type Scaffold struct { dataplaneService *corev1.Service httpbinService *corev1.Service - finalizers []func() - - apisixHttpTunnel *k8s.Tunnel - apisixHttpsTunnel *k8s.Tunnel + finalizers []func() + apisixTunnels *Tunnels additionalGateways map[string]*GatewayResources runtimeOpts Options Deployer Deployer } +type Tunnels struct { + HTTP *k8s.Tunnel + HTTPS *k8s.Tunnel + TCP *k8s.Tunnel +} + +func (t *Tunnels) Close() { + if t.HTTP != nil { + t.HTTP.Close() + t.HTTP = nil + } + if t.HTTPS != nil { + t.HTTPS.Close() + t.HTTPS = nil + } + if t.TCP != nil { + t.TCP.Close() + t.TCP = nil + } +} Review Comment: [nitpick] The Close method should handle panic scenarios. Consider using defer or recover to ensure all tunnels are closed even if one Close() call panics. ########## test/e2e/crds/v2/streamroute.go: ########## @@ -0,0 +1,222 @@ +// 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 v2 + +import ( + "fmt" + "time" + + mqtt "github.com/eclipse/paho.mqtt.golang" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/apache/apisix-ingress-controller/test/e2e/framework" + "github.com/apache/apisix-ingress-controller/test/e2e/scaffold" +) + +var _ = Describe("Test ApisixRoute With StreamRoute", Label("apisix.apache.org", "v2", "apisixroute"), func() { + s := scaffold.NewDefaultScaffold() + + BeforeEach(func() { + if framework.ProviderType != framework.ProviderTypeAPISIX { + Skip("only support APISIX provider") + } + By("create GatewayProxy") + gatewayProxy := s.GetGatewayProxyYaml() + err := s.CreateResourceFromString(gatewayProxy) + Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy") + time.Sleep(5 * time.Second) + + By("create IngressClass") + err = s.CreateResourceFromStringWithNamespace(s.GetIngressClassYaml(), "") + Expect(err).NotTo(HaveOccurred(), "creating IngressClass") + time.Sleep(5 * time.Second) + }) + + Context("TCP Proxy", func() { + apisixRoute := ` +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + name: httpbin-tcp-route +spec: + ingressClassName: %s + stream: + - name: rule1 + protocol: TCP + match: + ingressPort: 9100 + backend: + serviceName: httpbin-service-e2e-test + servicePort: 80 +` + It("stream tcp proxy", func() { + err := s.CreateResourceFromString(fmt.Sprintf(apisixRoute, s.Namespace())) + Expect(err).NotTo(HaveOccurred(), "creating ApisixRoute") + + s.RequestAssert(&scaffold.RequestAssert{ + Client: s.NewAPISIXClientWithTCPProxy(), + Method: "GET", + Path: "/ip", + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(200), + scaffold.WithExpectedBodyContains("origin"), + }, + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Client: s.NewAPISIXClientWithTCPProxy(), + Method: "GET", + Path: "/get", + Headers: map[string]string{ + "x-my-header": "x-my-value", + }, + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(200), + scaffold.WithExpectedBodyContains("x-my-value"), + }, + }) + }) + }) + + Context("UDP Proxy", func() { + apisixRoute := ` +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + name: httpbin-udp-route +spec: + ingressClassName: %s + stream: + - name: rule1 + protocol: UDP + match: + ingressPort: 9200 + backend: + serviceName: %s + servicePort: %d +` + It("stream udp proxy", func() { + dnsSvc := s.NewCoreDNSService() + err := s.CreateResourceFromString(fmt.Sprintf(apisixRoute, s.Namespace(), dnsSvc.Name, dnsSvc.Spec.Ports[0].Port)) + Expect(err).NotTo(HaveOccurred(), "creating ApisixRoute") + time.Sleep(20 * time.Second) + + svc := s.GetDataplaneService() + + // test dns query + output, err := s.RunDigDNSClientFromK8s(fmt.Sprintf("@%s", svc.Name), "-p", "9200", "github.com") Review Comment: [nitpick] Consider using a constant for the UDP port number (9200) instead of hardcoding it, since it's also used in the APISIX configuration and route definition. ########## test/e2e/crds/v2/streamroute.go: ########## @@ -0,0 +1,222 @@ +// 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 v2 + +import ( + "fmt" + "time" + + mqtt "github.com/eclipse/paho.mqtt.golang" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/apache/apisix-ingress-controller/test/e2e/framework" + "github.com/apache/apisix-ingress-controller/test/e2e/scaffold" +) + +var _ = Describe("Test ApisixRoute With StreamRoute", Label("apisix.apache.org", "v2", "apisixroute"), func() { + s := scaffold.NewDefaultScaffold() + + BeforeEach(func() { + if framework.ProviderType != framework.ProviderTypeAPISIX { + Skip("only support APISIX provider") + } + By("create GatewayProxy") + gatewayProxy := s.GetGatewayProxyYaml() + err := s.CreateResourceFromString(gatewayProxy) + Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy") + time.Sleep(5 * time.Second) + + By("create IngressClass") + err = s.CreateResourceFromStringWithNamespace(s.GetIngressClassYaml(), "") + Expect(err).NotTo(HaveOccurred(), "creating IngressClass") + time.Sleep(5 * time.Second) + }) + + Context("TCP Proxy", func() { + apisixRoute := ` +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + name: httpbin-tcp-route +spec: + ingressClassName: %s + stream: + - name: rule1 + protocol: TCP + match: + ingressPort: 9100 + backend: + serviceName: httpbin-service-e2e-test + servicePort: 80 +` + It("stream tcp proxy", func() { + err := s.CreateResourceFromString(fmt.Sprintf(apisixRoute, s.Namespace())) + Expect(err).NotTo(HaveOccurred(), "creating ApisixRoute") + + s.RequestAssert(&scaffold.RequestAssert{ + Client: s.NewAPISIXClientWithTCPProxy(), + Method: "GET", + Path: "/ip", + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(200), + scaffold.WithExpectedBodyContains("origin"), + }, + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Client: s.NewAPISIXClientWithTCPProxy(), + Method: "GET", + Path: "/get", + Headers: map[string]string{ + "x-my-header": "x-my-value", + }, + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(200), + scaffold.WithExpectedBodyContains("x-my-value"), + }, + }) + }) + }) + + Context("UDP Proxy", func() { + apisixRoute := ` +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + name: httpbin-udp-route +spec: + ingressClassName: %s + stream: + - name: rule1 + protocol: UDP + match: + ingressPort: 9200 + backend: + serviceName: %s + servicePort: %d +` + It("stream udp proxy", func() { + dnsSvc := s.NewCoreDNSService() + err := s.CreateResourceFromString(fmt.Sprintf(apisixRoute, s.Namespace(), dnsSvc.Name, dnsSvc.Spec.Ports[0].Port)) + Expect(err).NotTo(HaveOccurred(), "creating ApisixRoute") + time.Sleep(20 * time.Second) + + svc := s.GetDataplaneService() + + // test dns query + output, err := s.RunDigDNSClientFromK8s(fmt.Sprintf("@%s", svc.Name), "-p", "9200", "github.com") + Expect(err).NotTo(HaveOccurred(), "dig github.com via apisix udp proxy") + Expect(output).To(ContainSubstring("ADDITIONAL SECTION")) + + time.Sleep(3 * time.Second) + output = s.GetDeploymentLogs(scaffold.CoreDNSDeployment) + Expect(output).To(ContainSubstring("github.com. udp")) + }) + }) + + Context("Plugins", func() { + It("MQTT", func() { + //nolint:misspell // eclipse-mosquitto is the correct image name + mqttDeploy := ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mosquito Review Comment: The deployment name should be 'mosquitto' (with double 't') to match the correct spelling of the Eclipse Mosquitto MQTT broker. ########## internal/adc/translator/apisixroute.go: ########## @@ -341,6 +349,20 @@ func (t *Translator) translateApisixRouteBackendResolveGranularityService(tctx * }, nil } +func (t *Translator) translateApisixRouteStreamBackendResolveGranularity(tctx *provider.TranslateContext, arNN types.NamespacedName, backend apiv2.ApisixRouteStreamBackend) (adc.UpstreamNodes, error) { + tsBakcnd := apiv2.ApisixRouteHTTPBackend{ Review Comment: Variable name 'tsBakcnd' contains a typo. It should be 'tsBackend' for better readability. ########## api/adc/types.go: ########## @@ -195,15 +195,14 @@ type Timeout struct { // +k8s:deepcopy-gen=true type StreamRoute struct { - Description string `json:"description,omitempty"` - ID string `json:"id,omitempty"` - Labels map[string]string `json:"labels,omitempty"` - Name string `json:"name"` - Plugins Plugins `json:"plugins,omitempty"` - RemoteAddr string `json:"remote_addr,omitempty"` - ServerAddr string `json:"server_addr,omitempty"` - ServerPort *int64 `json:"server_port,omitempty"` - Sni string `json:"sni,omitempty"` + Metadata `json:",inline" yaml:",inline"` + + Labels map[string]string `json:"labels,omitempty"` + Plugins Plugins `json:"plugins,omitempty"` + RemoteAddr string `json:"remote_addr,omitempty"` + ServerAddr string `json:"server_addr,omitempty"` + ServerPort int32 `json:"server_port,omitempty"` Review Comment: [nitpick] The ServerPort field type changed from *int64 to int32. This could be a breaking change if existing code expects the pointer type or int64 range. Consider documenting this change or using the same type for consistency. ########## test/e2e/scaffold/assertion.go: ########## @@ -194,8 +212,10 @@ func (s *Scaffold) RequestAssert(r *RequestAssert) bool { r.Checks = append(r.Checks, r.Check) } - return EventuallyWithOffset(1, func() error { - req := r.request(r.Method, r.Path, r.Body) + return EventuallyWithOffset(1, func() (err error) { + reporter := &ErrorReporter{} + + req := r.request(r.Method, r.Path, r.Body).WithReporter(reporter) Review Comment: [nitpick] The ErrorReporter is created inside the retry loop. Consider creating it once outside the loop and resetting its error state in each iteration to avoid unnecessary allocations. -- 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-unsubscr...@apisix.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org