Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions api/v1alpha1/backendtrafficpolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,11 @@ type BackendTrafficPolicySpec struct {
LoadBalancer *LoadBalancer `json:"loadbalancer,omitempty" yaml:"loadbalancer,omitempty"`
// Scheme is the protocol used to communicate with the upstream.
// Default is `http`.
// Can be `http`, `https`, `grpc`, or `grpcs`.
// +kubebuilder:validation:Enum=http;https;grpc;grpcs;
// For L7 proxy, it can be `http`, `https`, `grpc`, or `grpcs`.
// For L4 proxy, it can be `tcp`, `tls`, or `udp`.
// The L4 values apply to stream routes only; using them for an HTTP route
// makes the upstream unreachable.
// +kubebuilder:validation:Enum=http;https;grpc;grpcs;tcp;tls;udp;
// +kubebuilder:default=http
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`

Expand Down
7 changes: 5 additions & 2 deletions api/v2/apisixupstream_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,12 @@ type ApisixUpstreamConfig struct {

// Scheme is the protocol used to communicate with the upstream.
// Default is `http`.
// Can be `http`, `https`, `grpc`, or `grpcs`.
// For L7 proxy, it can be `http`, `https`, `grpc`, or `grpcs`.
// For L4 proxy, it can be `tcp`, `tls`, or `udp`.
// The L4 values apply to stream routes only; using them for an HTTP route
// makes the upstream unreachable.
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Enum=http;https;grpc;grpcs;
// +kubebuilder:validation:Enum=http;https;grpc;grpcs;tcp;tls;udp;
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`

// Retries defines the number of retry attempts APISIX should make when a failure occurs.
Expand Down
16 changes: 14 additions & 2 deletions config/crd/bases/apisix.apache.org_apisixupstreams.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -591,12 +591,18 @@ spec:
description: |-
Scheme is the protocol used to communicate with the upstream.
Default is `http`.
Can be `http`, `https`, `grpc`, or `grpcs`.
For L7 proxy, it can be `http`, `https`, `grpc`, or `grpcs`.
For L4 proxy, it can be `tcp`, `tls`, or `udp`.
The L4 values apply to stream routes only; using them for an HTTP route
makes the upstream unreachable.
enum:
- http
- https
- grpc
- grpcs
- tcp
- tls
- udp
type: string
subsets:
description: |-
Expand Down Expand Up @@ -670,12 +676,18 @@ spec:
description: |-
Scheme is the protocol used to communicate with the upstream.
Default is `http`.
Can be `http`, `https`, `grpc`, or `grpcs`.
For L7 proxy, it can be `http`, `https`, `grpc`, or `grpcs`.
For L4 proxy, it can be `tcp`, `tls`, or `udp`.
The L4 values apply to stream routes only; using them for an HTTP route
makes the upstream unreachable.
enum:
- http
- https
- grpc
- grpcs
- tcp
- tls
- udp
type: string
subsets:
description: |-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,12 +284,18 @@ spec:
description: |-
Scheme is the protocol used to communicate with the upstream.
Default is `http`.
Can be `http`, `https`, `grpc`, or `grpcs`.
For L7 proxy, it can be `http`, `https`, `grpc`, or `grpcs`.
For L4 proxy, it can be `tcp`, `tls`, or `udp`.
The L4 values apply to stream routes only; using them for an HTTP route
makes the upstream unreachable.
enum:
- http
- https
- grpc
- grpcs
- tcp
- tls
- udp
type: string
targetRefs:
description: |-
Expand Down
8 changes: 4 additions & 4 deletions docs/en/latest/reference/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ _Appears in:_
| --- | --- |
| `targetRefs` _[BackendPolicyTargetReferenceWithSectionName](#backendpolicytargetreferencewithsectionname) array_ | TargetRef identifies an API object to apply policy to. Currently, Backends (i.e. Service, ServiceImport, or any implementation-specific backendRef) are the only valid API target references. |
| `loadbalancer` _[LoadBalancer](#loadbalancer)_ | LoadBalancer represents the load balancer configuration for Kubernetes Service. The default strategy is round robin. |
| `scheme` _string_ | Scheme is the protocol used to communicate with the upstream. Default is `http`. Can be `http`, `https`, `grpc`, or `grpcs`. |
| `scheme` _string_ | Scheme is the protocol used to communicate with the upstream. Default is `http`. For L7 proxy, it can be `http`, `https`, `grpc`, or `grpcs`. For L4 proxy, it can be `tcp`, `tls`, or `udp`. The L4 values apply to stream routes only; using them for an HTTP route makes the upstream unreachable. |
| `retries` _integer_ | Retries specify the number of times the gateway should retry sending requests when errors such as timeouts or 502 errors occur. |
| `timeout` _[Timeout](#timeout)_ | Timeout sets the read, send, and connect timeouts to the upstream. |
| `passHost` _string_ | PassHost configures how the host header should be determined when a request is forwarded to the upstream. Default is `pass`. Can be `pass`, `node` or `rewrite`:<br /> • `pass`: preserve the original Host header<br /> • `node`: use the upstream node’s host<br /> • `rewrite`: set to a custom host via `upstreamHost` |
Expand Down Expand Up @@ -1489,7 +1489,7 @@ ApisixUpstreamConfig defines configuration for upstream services.
| Field | Description |
| --- | --- |
| `loadbalancer` _[LoadBalancer](#loadbalancer)_ | LoadBalancer specifies the load balancer configuration for Kubernetes Service. |
| `scheme` _string_ | Scheme is the protocol used to communicate with the upstream. Default is `http`. Can be `http`, `https`, `grpc`, or `grpcs`. |
| `scheme` _string_ | Scheme is the protocol used to communicate with the upstream. Default is `http`. For L7 proxy, it can be `http`, `https`, `grpc`, or `grpcs`. For L4 proxy, it can be `tcp`, `tls`, or `udp`. The L4 values apply to stream routes only; using them for an HTTP route makes the upstream unreachable. |
| `retries` _integer_ | Retries defines the number of retry attempts APISIX should make when a failure occurs. Failures include timeouts, network errors, or 5xx status codes. |
| `timeout` _[UpstreamTimeout](#upstreamtimeout)_ | Timeout specifies the connection, send, and read timeouts for upstream requests. |
| `healthCheck` _[HealthCheck](#healthcheck)_ | HealthCheck defines the active and passive health check configuration for the upstream. |
Expand Down Expand Up @@ -1549,7 +1549,7 @@ definitions and custom configuration.
| `ingressClassName` _string_ | IngressClassName is the name of an IngressClass cluster resource. Controller implementations use this field to determine whether they should process this ApisixUpstream resource. |
| `externalNodes` _[ApisixUpstreamExternalNode](#apisixupstreamexternalnode) array_ | ExternalNodes defines a static list of backend nodes. These can be external hosts outside the cluster or cluster-internal Services specified by their DNS name. When this field is set, the upstream will route traffic directly to these nodes without DNS resolution or service discovery. |
| `loadbalancer` _[LoadBalancer](#loadbalancer)_ | LoadBalancer specifies the load balancer configuration for Kubernetes Service. |
| `scheme` _string_ | Scheme is the protocol used to communicate with the upstream. Default is `http`. Can be `http`, `https`, `grpc`, or `grpcs`. |
| `scheme` _string_ | Scheme is the protocol used to communicate with the upstream. Default is `http`. For L7 proxy, it can be `http`, `https`, `grpc`, or `grpcs`. For L4 proxy, it can be `tcp`, `tls`, or `udp`. The L4 values apply to stream routes only; using them for an HTTP route makes the upstream unreachable. |
| `retries` _integer_ | Retries defines the number of retry attempts APISIX should make when a failure occurs. Failures include timeouts, network errors, or 5xx status codes. |
| `timeout` _[UpstreamTimeout](#upstreamtimeout)_ | Timeout specifies the connection, send, and read timeouts for upstream requests. |
| `healthCheck` _[HealthCheck](#healthcheck)_ | HealthCheck defines the active and passive health check configuration for the upstream. |
Expand Down Expand Up @@ -1719,7 +1719,7 @@ them if they are set on the port level.
| Field | Description |
| --- | --- |
| `loadbalancer` _[LoadBalancer](#loadbalancer)_ | LoadBalancer specifies the load balancer configuration for Kubernetes Service. |
| `scheme` _string_ | Scheme is the protocol used to communicate with the upstream. Default is `http`. Can be `http`, `https`, `grpc`, or `grpcs`. |
| `scheme` _string_ | Scheme is the protocol used to communicate with the upstream. Default is `http`. For L7 proxy, it can be `http`, `https`, `grpc`, or `grpcs`. For L4 proxy, it can be `tcp`, `tls`, or `udp`. The L4 values apply to stream routes only; using them for an HTTP route makes the upstream unreachable. |
| `retries` _integer_ | Retries defines the number of retry attempts APISIX should make when a failure occurs. Failures include timeouts, network errors, or 5xx status codes. |
| `timeout` _[UpstreamTimeout](#upstreamtimeout)_ | Timeout specifies the connection, send, and read timeouts for upstream requests. |
| `healthCheck` _[HealthCheck](#healthcheck)_ | HealthCheck defines the active and passive health check configuration for the upstream. |
Expand Down
102 changes: 102 additions & 0 deletions internal/adc/translator/apisixroute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,22 @@
package translator

import (
"context"
"testing"

"github.com/go-logr/logr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
discoveryv1 "k8s.io/api/discovery/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8stypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/ptr"

adc "github.com/apache/apisix-ingress-controller/api/adc"
apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
"github.com/apache/apisix-ingress-controller/internal/provider"
)

func TestBuildRoute_HostsNotSet(t *testing.T) {
Expand Down Expand Up @@ -119,3 +127,97 @@ func TestBuildRoute_MetadataLabelsDoNotOverwriteControllerLabels(t *testing.T) {
assert.Equal(t, ar.Name, route.Labels["k8s/name"])
assert.Equal(t, "ApisixRoute/default/test-route", route.Labels["k8s/resource-key"])
}

func TestTranslateApisixRouteStreamUpstreamScheme(t *testing.T) {
const (
namespace = "default"
serviceName = "backend"
portName = "tcp"
portNumber = int32(6000)
)

tests := []struct {
scheme string
protocol string
}{
{scheme: apiv2.SchemeTLS, protocol: "TCP"},
{scheme: apiv2.SchemeTCP, protocol: "TCP"},
{scheme: apiv2.SchemeUDP, protocol: "UDP"},
}

for _, tt := range tests {
t.Run(tt.scheme, func(t *testing.T) {
translator := NewTranslator(logr.Discard(), "")
tctx := provider.NewDefaultTranslateContext(context.Background())

serviceKey := k8stypes.NamespacedName{Namespace: namespace, Name: serviceName}
tctx.Services[serviceKey] = &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: serviceName,
Namespace: namespace,
},
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{{
Name: portName,
Port: portNumber,
}},
},
}
tctx.EndpointSlices[serviceKey] = []discoveryv1.EndpointSlice{{
ObjectMeta: metav1.ObjectMeta{
Name: serviceName + "-1",
Namespace: namespace,
},
Ports: []discoveryv1.EndpointPort{{
Name: ptr.To(portName),
Port: ptr.To(portNumber),
}},
Endpoints: []discoveryv1.Endpoint{{
Addresses: []string{"10.0.0.1"},
Conditions: discoveryv1.EndpointConditions{
Ready: ptr.To(true),
},
}},
}}
tctx.Upstreams[serviceKey] = &apiv2.ApisixUpstream{
ObjectMeta: metav1.ObjectMeta{
Name: serviceName,
Namespace: namespace,
},
Spec: apiv2.ApisixUpstreamSpec{
ApisixUpstreamConfig: apiv2.ApisixUpstreamConfig{
Scheme: tt.scheme,
},
},
}

ar := &apiv2.ApisixRoute{
ObjectMeta: metav1.ObjectMeta{
Name: "test-route",
Namespace: namespace,
},
Spec: apiv2.ApisixRouteSpec{
Stream: []apiv2.ApisixRouteStream{{
Name: "rule1",
Protocol: tt.protocol,
Match: apiv2.ApisixRouteStreamMatch{
IngressPort: 8000,
},
Backend: apiv2.ApisixRouteStreamBackend{
ServiceName: serviceName,
ServicePort: intstr.FromInt32(portNumber),
},
}},
},
}

result, err := translator.TranslateApisixRoute(tctx, ar)
require.NoError(t, err)
require.Len(t, result.Services, 1)
require.NotNil(t, result.Services[0].Upstream)

assert.Equal(t, tt.scheme, result.Services[0].Upstream.Scheme)
assert.Equal(t, "10.0.0.1", result.Services[0].Upstream.Nodes[0].Host)
})
}
}
88 changes: 88 additions & 0 deletions internal/adc/translator/l4route_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,18 @@ import (
"github.com/go-logr/logr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
discoveryv1 "k8s.io/api/discovery/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8stypes "k8s.io/apimachinery/pkg/types"
"k8s.io/utils/ptr"
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"

"github.com/apache/apisix-ingress-controller/api/v1alpha1"
apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
"github.com/apache/apisix-ingress-controller/internal/provider"
internaltypes "github.com/apache/apisix-ingress-controller/internal/types"
)

func TestTranslateTCPRouteWithL4RoutePolicy(t *testing.T) {
Expand Down Expand Up @@ -267,3 +273,85 @@ func TestTranslateTLSRouteWithL4RoutePolicy(t *testing.T) {
})
}
}

func TestTranslateTCPRouteUpstreamScheme(t *testing.T) {
const (
namespace = "default"
serviceName = "backend"
portName = "tcp"
portNumber = int32(6000)
)

translator := NewTranslator(logr.Discard(), "")
tctx := provider.NewDefaultTranslateContext(context.Background())

serviceKey := k8stypes.NamespacedName{Namespace: namespace, Name: serviceName}
tctx.Services[serviceKey] = &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: serviceName,
Namespace: namespace,
},
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{{
Name: portName,
Port: portNumber,
}},
},
}
tctx.EndpointSlices[serviceKey] = []discoveryv1.EndpointSlice{{
ObjectMeta: metav1.ObjectMeta{
Name: serviceName + "-1",
Namespace: namespace,
},
Ports: []discoveryv1.EndpointPort{{
Name: ptr.To(portName),
Port: ptr.To(portNumber),
}},
Endpoints: []discoveryv1.Endpoint{{
Addresses: []string{"10.0.0.1"},
Conditions: discoveryv1.EndpointConditions{
Ready: ptr.To(true),
},
}},
}}
tctx.BackendTrafficPolicies[serviceKey] = &v1alpha1.BackendTrafficPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "backend-policy",
Namespace: namespace,
},
Spec: v1alpha1.BackendTrafficPolicySpec{
TargetRefs: []v1alpha1.BackendPolicyTargetReferenceWithSectionName{{
LocalPolicyTargetReference: gatewayv1.LocalPolicyTargetReference{
Name: gatewayv1.ObjectName(serviceName),
Kind: gatewayv1.Kind(internaltypes.KindService),
},
}},
Scheme: apiv2.SchemeTLS,
},
}

route := &gatewayv1alpha2.TCPRoute{
ObjectMeta: metav1.ObjectMeta{
Name: "my-tcp",
Namespace: namespace,
},
Spec: gatewayv1alpha2.TCPRouteSpec{
Rules: []gatewayv1alpha2.TCPRouteRule{{
BackendRefs: []gatewayv1alpha2.BackendRef{{
BackendObjectReference: gatewayv1.BackendObjectReference{
Name: gatewayv1.ObjectName(serviceName),
Port: ptr.To(portNumber),
},
}},
}},
},
}

result, err := translator.TranslateTCPRoute(tctx, route)
require.NoError(t, err)
require.Len(t, result.Services, 1)
require.NotNil(t, result.Services[0].Upstream)

assert.Equal(t, apiv2.SchemeTLS, result.Services[0].Upstream.Scheme)
assert.Equal(t, "10.0.0.1", result.Services[0].Upstream.Nodes[0].Host)
}
1 change: 0 additions & 1 deletion internal/adc/translator/tcproute.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ func (t *Translator) TranslateTCPRoute(tctx *provider.TranslateContext, tcpRoute
if len(upNodes) == 0 {
continue
}
// TODO: Confirm BackendTrafficPolicy attachment with e2e test case.
t.AttachBackendTrafficPolicyToUpstream(backend, tctx.BackendTrafficPolicies, upstream, tctx.Services)
upstream.Nodes = upNodes
var (
Expand Down
Loading
Loading