From faf43e7a335e624ffd702d1415386cef98ad14ef Mon Sep 17 00:00:00 2001
From: Adam Janikowski <12255597+ajanikow@users.noreply.github.com>
Date: Fri, 29 Nov 2024 10:27:30 +0100
Subject: [PATCH] [Feature] [Networking] ArangoRoute Protocol (#1773)
---
CHANGELOG.md | 1 +
docs/api/ArangoRoute.V1Alpha1.md | 30 +++-
.../v1alpha1/route_spec_destination.go | 16 ++
.../v1alpha1/route_spec_protocol.go | 55 +++++++
.../v1alpha1/route_status_target.go | 3 +
.../v1alpha1/zz_generated.deepcopy.go | 5 +
.../networking-route.schema.generated.yaml | 9 ++
.../gateway/gateway_config_destination.go | 21 +--
.../gateway_config_destination_protocol.go | 101 +++++++++++++
.../route/handler_destination_endpoints.go | 1 +
.../handler_destination_endpoints_test.go | 143 ++++++++++++++++++
.../route/handler_destination_service.go | 1 +
.../route/handler_destination_service_test.go | 109 +++++++++++++
13 files changed, 475 insertions(+), 20 deletions(-)
create mode 100644 pkg/apis/networking/v1alpha1/route_spec_protocol.go
create mode 100644 pkg/deployment/resources/gateway/gateway_config_destination_protocol.go
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ee893c79c..26cd02704 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,6 +25,7 @@
- (Feature) (Platform) Chart Integration
- (Maintenance) Switch to google.golang.org/protobuf
- (Feature) Add DebugPackage to the OPS Binary
+- (Feature) (Networking) ArangoRoute Protocol
## [1.2.43](https://github.com/arangodb/kube-arangodb/tree/1.2.43) (2024-10-14)
- (Feature) ArangoRoute CRD
diff --git a/docs/api/ArangoRoute.V1Alpha1.md b/docs/api/ArangoRoute.V1Alpha1.md
index 2c358b396..3a6c98721 100644
--- a/docs/api/ArangoRoute.V1Alpha1.md
+++ b/docs/api/ArangoRoute.V1Alpha1.md
@@ -83,18 +83,34 @@ UID keeps the information about object UID
### .spec.destination.path
-Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_spec_destination.go#L39)
+Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_spec_destination.go#L46)
Path defines service path used for overrides
***
+### .spec.destination.protocol
+
+Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_spec_destination.go#L40)
+
+Protocol defines http protocol used for the route
+
+Possible Values:
+* `"http1"` (default) - HTTP 1.1 Protocol
+* `"http2"` - HTTP 2 Protocol
+
+***
+
### .spec.destination.schema
-Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_spec_destination.go#L33)
+Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_spec_destination.go#L35)
Schema defines HTTP/S schema used for connection
+Possible Values:
+* `"http"` (default) - HTTP Connection
+* `"https"` - HTTPS Connection (HTTP with TLS)
+
***
### .spec.destination.service.checksum
@@ -238,12 +254,20 @@ Type: `integer` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.
### .status.target.path
-Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_status_target.go#L43)
+Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_status_target.go#L46)
Path specifies request path override
***
+### .status.target.protocol
+
+Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_status_target.go#L40)
+
+Protocol defines http protocol used for the route
+
+***
+
### .status.target.TLS.insecure
Type: `boolean` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_status_target_tls.go#L27)
diff --git a/pkg/apis/networking/v1alpha1/route_spec_destination.go b/pkg/apis/networking/v1alpha1/route_spec_destination.go
index 1dfa0ab75..c4d32f683 100644
--- a/pkg/apis/networking/v1alpha1/route_spec_destination.go
+++ b/pkg/apis/networking/v1alpha1/route_spec_destination.go
@@ -30,8 +30,15 @@ type ArangoRouteSpecDestination struct {
Endpoints *ArangoRouteSpecDestinationEndpoints `json:"endpoints,omitempty"`
// Schema defines HTTP/S schema used for connection
+ // +doc/enum: http|HTTP Connection
+ // +doc/enum: https|HTTPS Connection (HTTP with TLS)
Schema *ArangoRouteSpecDestinationSchema `json:"schema,omitempty"`
+ // Protocol defines http protocol used for the route
+ // +doc/enum: http1|HTTP 1.1 Protocol
+ // +doc/enum: http2|HTTP 2 Protocol
+ Protocol *ArangoRouteDestinationProtocol `json:"protocol,omitempty"`
+
// TLS defines TLS Configuration
TLS *ArangoRouteSpecDestinationTLS `json:"tls,omitempty"`
@@ -58,6 +65,14 @@ func (a *ArangoRouteSpecDestination) GetEndpoints() *ArangoRouteSpecDestinationE
return a.Endpoints
}
+func (a *ArangoRouteSpecDestination) GetProtocol() *ArangoRouteDestinationProtocol {
+ if a == nil || a.Protocol == nil {
+ return nil
+ }
+
+ return a.Protocol
+}
+
func (a *ArangoRouteSpecDestination) GetSchema() *ArangoRouteSpecDestinationSchema {
if a == nil || a.Schema == nil {
return nil
@@ -100,6 +115,7 @@ func (a *ArangoRouteSpecDestination) Validate() error {
shared.ValidateOptionalInterfacePath("service", a.Service),
shared.ValidateOptionalInterfacePath("endpoints", a.Endpoints),
shared.ValidateOptionalInterfacePath("schema", a.Schema),
+ shared.ValidateOptionalInterfacePath("protocol", a.Protocol),
shared.ValidateOptionalInterfacePath("tls", a.TLS),
shared.ValidateOptionalInterfacePath("authentication", a.Authentication),
shared.PrefixResourceError("path", shared.ValidateAPIPath(a.GetPath())),
diff --git a/pkg/apis/networking/v1alpha1/route_spec_protocol.go b/pkg/apis/networking/v1alpha1/route_spec_protocol.go
new file mode 100644
index 000000000..d83fceac6
--- /dev/null
+++ b/pkg/apis/networking/v1alpha1/route_spec_protocol.go
@@ -0,0 +1,55 @@
+//
+// DISCLAIMER
+//
+// Copyright 2024 ArangoDB GmbH, Cologne, Germany
+//
+// Licensed 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.
+//
+// Copyright holder is ArangoDB GmbH, Cologne, Germany
+//
+
+package v1alpha1
+
+import (
+ "github.com/arangodb/kube-arangodb/pkg/util/errors"
+ "github.com/arangodb/kube-arangodb/pkg/util/strings"
+)
+
+type ArangoRouteDestinationProtocol string
+
+const (
+ ArangoRouteDestinationProtocolHTTP1 ArangoRouteDestinationProtocol = "http1"
+ ArangoRouteDestinationProtocolHTTP2 ArangoRouteDestinationProtocol = "http2"
+ ArangoRouteDestinationProtocolDefault = ArangoRouteDestinationProtocolHTTP1
+)
+
+func (a *ArangoRouteDestinationProtocol) Get() ArangoRouteDestinationProtocol {
+ if a == nil {
+ return ArangoRouteDestinationProtocolDefault
+ }
+
+ return ArangoRouteDestinationProtocol(strings.ToLower(string(*a)))
+}
+
+func (a *ArangoRouteDestinationProtocol) String() string {
+ return string(a.Get())
+}
+
+func (a *ArangoRouteDestinationProtocol) Validate() error {
+ switch x := a.Get(); x {
+ case ArangoRouteDestinationProtocolHTTP1, ArangoRouteDestinationProtocolHTTP2:
+ return nil
+ default:
+ return errors.Errorf("Invalid schema: %s", x.String())
+ }
+}
diff --git a/pkg/apis/networking/v1alpha1/route_status_target.go b/pkg/apis/networking/v1alpha1/route_status_target.go
index 8ec626b07..a90021de4 100644
--- a/pkg/apis/networking/v1alpha1/route_status_target.go
+++ b/pkg/apis/networking/v1alpha1/route_status_target.go
@@ -36,6 +36,9 @@ type ArangoRouteStatusTarget struct {
// TLS Keeps target TLS Settings (if not nil, TLS is enabled)
TLS *ArangoRouteStatusTargetTLS `json:"TLS,omitempty"`
+ // Protocol defines http protocol used for the route
+ Protocol ArangoRouteDestinationProtocol `json:"protocol,omitempty"`
+
// Authentication specifies the authentication details
Authentication ArangoRouteStatusTargetAuthentication `json:"authentication,omitempty"`
diff --git a/pkg/apis/networking/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/networking/v1alpha1/zz_generated.deepcopy.go
index d69bebac6..2aef9bdb2 100644
--- a/pkg/apis/networking/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/networking/v1alpha1/zz_generated.deepcopy.go
@@ -147,6 +147,11 @@ func (in *ArangoRouteSpecDestination) DeepCopyInto(out *ArangoRouteSpecDestinati
*out = new(ArangoRouteSpecDestinationSchema)
**out = **in
}
+ if in.Protocol != nil {
+ in, out := &in.Protocol, &out.Protocol
+ *out = new(ArangoRouteDestinationProtocol)
+ **out = **in
+ }
if in.TLS != nil {
in, out := &in.TLS, &out.TLS
*out = new(ArangoRouteSpecDestinationTLS)
diff --git a/pkg/crd/crds/networking-route.schema.generated.yaml b/pkg/crd/crds/networking-route.schema.generated.yaml
index 2544f6324..d8ba4e7d7 100644
--- a/pkg/crd/crds/networking-route.schema.generated.yaml
+++ b/pkg/crd/crds/networking-route.schema.generated.yaml
@@ -49,8 +49,17 @@ v1alpha1:
path:
description: Path defines service path used for overrides
type: string
+ protocol:
+ description: Protocol defines http protocol used for the route
+ enum:
+ - http1
+ - http2
+ type: string
schema:
description: Schema defines HTTP/S schema used for connection
+ enum:
+ - http
+ - https
type: string
service:
description: Service defines service upstream reference
diff --git a/pkg/deployment/resources/gateway/gateway_config_destination.go b/pkg/deployment/resources/gateway/gateway_config_destination.go
index 602ede7ac..5963c0569 100644
--- a/pkg/deployment/resources/gateway/gateway_config_destination.go
+++ b/pkg/deployment/resources/gateway/gateway_config_destination.go
@@ -24,10 +24,8 @@ import (
"time"
clusterAPI "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
- coreAPI "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
endpointAPI "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
routeAPI "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
- upstreamHttpApi "github.com/envoyproxy/go-control-plane/envoy/extensions/upstreams/http/v3"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/durationpb"
@@ -63,6 +61,8 @@ type ConfigDestination struct {
Type *ConfigDestinationType `json:"type,omitempty"`
+ Protocol *ConfigDestinationProtocol `json:"protocol,omitempty"`
+
Path *string `json:"path,omitempty"`
AuthExtension *ConfigAuthZExtension `json:"authExtension,omitempty"`
@@ -77,6 +77,7 @@ func (c *ConfigDestination) Validate() error {
return shared.WithErrors(
shared.PrefixResourceError("targets", c.Targets.Validate()),
shared.PrefixResourceError("type", c.Type.Validate()),
+ shared.PrefixResourceError("protocol", c.Protocol.Validate()),
shared.PrefixResourceError("path", shared.ValidateAPIPath(c.GetPath())),
shared.PrefixResourceError("authExtension", c.AuthExtension.Validate()),
shared.PrefixResourceError("upgradeConfigs", c.UpgradeConfigs.Validate()),
@@ -130,21 +131,7 @@ func (c *ConfigDestination) getUpgradeConfigs() ConfigDestinationsUpgrade {
}
func (c *ConfigDestination) RenderCluster(name string) (*clusterAPI.Cluster, error) {
- hpo, err := anypb.New(&upstreamHttpApi.HttpProtocolOptions{
- UpstreamProtocolOptions: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_{
- ExplicitHttpConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig{
- ProtocolConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_Http2ProtocolOptions{
- Http2ProtocolOptions: &coreAPI.Http2ProtocolOptions{
- ConnectionKeepalive: &coreAPI.KeepaliveSettings{
- Interval: durationpb.New(15 * time.Second),
- Timeout: durationpb.New(30 * time.Second),
- ConnectionIdleInterval: durationpb.New(60 * time.Second),
- },
- },
- },
- },
- },
- })
+ hpo, err := anypb.New(c.Protocol.Options())
if err != nil {
return nil, err
}
diff --git a/pkg/deployment/resources/gateway/gateway_config_destination_protocol.go b/pkg/deployment/resources/gateway/gateway_config_destination_protocol.go
new file mode 100644
index 000000000..e3c7ab06a
--- /dev/null
+++ b/pkg/deployment/resources/gateway/gateway_config_destination_protocol.go
@@ -0,0 +1,101 @@
+//
+// DISCLAIMER
+//
+// Copyright 2024 ArangoDB GmbH, Cologne, Germany
+//
+// Licensed 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.
+//
+// Copyright holder is ArangoDB GmbH, Cologne, Germany
+//
+
+package gateway
+
+import (
+ "time"
+
+ coreAPI "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
+ upstreamHttpApi "github.com/envoyproxy/go-control-plane/envoy/extensions/upstreams/http/v3"
+ "google.golang.org/protobuf/types/known/durationpb"
+
+ "github.com/arangodb/kube-arangodb/pkg/util/errors"
+)
+
+type ConfigDestinationProtocol int
+
+const (
+ ConfigDestinationProtocolHTTP1 ConfigDestinationProtocol = iota
+ ConfigDestinationProtocolHTTP2
+)
+
+func (c *ConfigDestinationProtocol) Get() ConfigDestinationProtocol {
+ if c == nil {
+ return ConfigDestinationProtocolHTTP1
+ }
+
+ switch v := *c; v {
+ case ConfigDestinationProtocolHTTP1, ConfigDestinationProtocolHTTP2:
+ return v
+ default:
+ return ConfigDestinationProtocolHTTP1
+ }
+}
+
+func (c *ConfigDestinationProtocol) Options() *upstreamHttpApi.HttpProtocolOptions {
+ switch c.Get() {
+ case ConfigDestinationProtocolHTTP1:
+ return &upstreamHttpApi.HttpProtocolOptions{
+ UpstreamProtocolOptions: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_{
+ ExplicitHttpConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig{
+ ProtocolConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_HttpProtocolOptions{
+ HttpProtocolOptions: &coreAPI.Http1ProtocolOptions{},
+ },
+ },
+ },
+ }
+ case ConfigDestinationProtocolHTTP2:
+ return &upstreamHttpApi.HttpProtocolOptions{
+ UpstreamProtocolOptions: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_{
+ ExplicitHttpConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig{
+ ProtocolConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_Http2ProtocolOptions{
+ Http2ProtocolOptions: &coreAPI.Http2ProtocolOptions{
+ ConnectionKeepalive: &coreAPI.KeepaliveSettings{
+ Interval: durationpb.New(15 * time.Second),
+ Timeout: durationpb.New(30 * time.Second),
+ ConnectionIdleInterval: durationpb.New(60 * time.Second),
+ },
+ },
+ },
+ },
+ },
+ }
+ default:
+ return &upstreamHttpApi.HttpProtocolOptions{
+ UpstreamProtocolOptions: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_{
+ ExplicitHttpConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig{
+ ProtocolConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_HttpProtocolOptions{
+ HttpProtocolOptions: &coreAPI.Http1ProtocolOptions{},
+ },
+ },
+ },
+ }
+ }
+}
+
+func (c *ConfigDestinationProtocol) Validate() error {
+ switch c.Get() {
+ case ConfigDestinationProtocolHTTP1, ConfigDestinationProtocolHTTP2:
+ return nil
+ default:
+ return errors.Errorf("Invalid destination protocol")
+ }
+}
diff --git a/pkg/handlers/networking/route/handler_destination_endpoints.go b/pkg/handlers/networking/route/handler_destination_endpoints.go
index c67a9a8a1..b6eedf8d7 100644
--- a/pkg/handlers/networking/route/handler_destination_endpoints.go
+++ b/pkg/handlers/networking/route/handler_destination_endpoints.go
@@ -120,6 +120,7 @@ func (h *handler) HandleArangoDestinationEndpoints(ctx context.Context, item ope
target.Path = dest.GetPath()
target.Type = networkingApi.ArangoRouteStatusTargetEndpointsType
+ target.Protocol = dest.GetProtocol().Get()
// Render Auth Settings
diff --git a/pkg/handlers/networking/route/handler_destination_endpoints_test.go b/pkg/handlers/networking/route/handler_destination_endpoints_test.go
index 469ce724d..3732b5dbb 100644
--- a/pkg/handlers/networking/route/handler_destination_endpoints_test.go
+++ b/pkg/handlers/networking/route/handler_destination_endpoints_test.go
@@ -96,6 +96,149 @@ func Test_Handler_Destination_Endpoints_Valid(t *testing.T) {
require.Len(t, extension.Status.Target.RenderURLs(), 1)
require.EqualValues(t, "http://127.0.0.1:10244/", extension.Status.Target.RenderURLs()[0])
+ require.EqualValues(t, "http1", extension.Status.Target.Protocol)
+
+ c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
+ require.True(t, ok)
+ require.EqualValues(t, c.Reason, "Destination Found")
+ require.EqualValues(t, c.Reason, "Destination Found")
+ require.EqualValues(t, c.Hash, extension.Status.Target.Hash())
+}
+
+func Test_Handler_Destination_Endpoints_Valid_HTTP1(t *testing.T) {
+ // Setup
+ handler := newFakeHandler()
+
+ // Arrange
+ extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
+ func(t *testing.T, obj *networkingApi.ArangoRoute) {
+ obj.Spec.Deployment = util.NewType("deployment")
+ },
+ func(t *testing.T, obj *networkingApi.ArangoRoute) {
+ obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
+ Protocol: util.NewType(networkingApi.ArangoRouteDestinationProtocolHTTP1),
+ Endpoints: &networkingApi.ArangoRouteSpecDestinationEndpoints{
+ Object: &sharedApi.Object{
+ Name: "deployment",
+ },
+ Port: util.NewType(intstr.FromInt32(10244)),
+ },
+ }
+ })
+ deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
+ svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
+ obj.Spec.Ports = []core.ServicePort{
+ {
+ Port: 10244,
+ },
+ }
+ })
+ endpoints := tests.NewMetaObject[*core.Endpoints](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Endpoints) {
+ obj.Subsets = []core.EndpointSubset{
+ {
+ Addresses: []core.EndpointAddress{
+ {
+ IP: "127.0.0.1",
+ },
+ },
+ Ports: []core.EndpointPort{
+ {
+ Name: "",
+ Port: 10244,
+ },
+ },
+ },
+ }
+ })
+
+ refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc, &endpoints)
+
+ // Test
+ require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
+
+ // Refresh
+ refresh(t)
+
+ // Assert
+ require.True(t, extension.Status.Conditions.IsTrue(networkingApi.SpecValidCondition))
+ require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
+ require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
+ require.Equal(t, networkingApi.ArangoRouteStatusTargetEndpointsType, extension.Status.Target.Type)
+
+ require.Len(t, extension.Status.Target.RenderURLs(), 1)
+ require.EqualValues(t, "http://127.0.0.1:10244/", extension.Status.Target.RenderURLs()[0])
+ require.EqualValues(t, "http1", extension.Status.Target.Protocol)
+
+ c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
+ require.True(t, ok)
+ require.EqualValues(t, c.Reason, "Destination Found")
+ require.EqualValues(t, c.Reason, "Destination Found")
+ require.EqualValues(t, c.Hash, extension.Status.Target.Hash())
+}
+
+func Test_Handler_Destination_Endpoints_Valid_HTTP2(t *testing.T) {
+ // Setup
+ handler := newFakeHandler()
+
+ // Arrange
+ extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
+ func(t *testing.T, obj *networkingApi.ArangoRoute) {
+ obj.Spec.Deployment = util.NewType("deployment")
+ },
+ func(t *testing.T, obj *networkingApi.ArangoRoute) {
+ obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
+ Protocol: util.NewType(networkingApi.ArangoRouteDestinationProtocolHTTP2),
+ Endpoints: &networkingApi.ArangoRouteSpecDestinationEndpoints{
+ Object: &sharedApi.Object{
+ Name: "deployment",
+ },
+ Port: util.NewType(intstr.FromInt32(10244)),
+ },
+ }
+ })
+ deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
+ svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
+ obj.Spec.Ports = []core.ServicePort{
+ {
+ Port: 10244,
+ },
+ }
+ })
+ endpoints := tests.NewMetaObject[*core.Endpoints](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Endpoints) {
+ obj.Subsets = []core.EndpointSubset{
+ {
+ Addresses: []core.EndpointAddress{
+ {
+ IP: "127.0.0.1",
+ },
+ },
+ Ports: []core.EndpointPort{
+ {
+ Name: "",
+ Port: 10244,
+ },
+ },
+ },
+ }
+ })
+
+ refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc, &endpoints)
+
+ // Test
+ require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
+
+ // Refresh
+ refresh(t)
+
+ // Assert
+ require.True(t, extension.Status.Conditions.IsTrue(networkingApi.SpecValidCondition))
+ require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
+ require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
+ require.Equal(t, networkingApi.ArangoRouteStatusTargetEndpointsType, extension.Status.Target.Type)
+
+ require.Len(t, extension.Status.Target.RenderURLs(), 1)
+ require.EqualValues(t, "http://127.0.0.1:10244/", extension.Status.Target.RenderURLs()[0])
+ require.EqualValues(t, "http2", extension.Status.Target.Protocol)
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)
diff --git a/pkg/handlers/networking/route/handler_destination_service.go b/pkg/handlers/networking/route/handler_destination_service.go
index de56f4efb..cc3867c9f 100644
--- a/pkg/handlers/networking/route/handler_destination_service.go
+++ b/pkg/handlers/networking/route/handler_destination_service.go
@@ -119,6 +119,7 @@ func (h *handler) HandleArangoDestinationService(ctx context.Context, item opera
target.Path = dest.GetPath()
target.Type = networkingApi.ArangoRouteStatusTargetServiceType
+ target.Protocol = dest.GetProtocol().Get()
// Render Auth Settings
diff --git a/pkg/handlers/networking/route/handler_destination_service_test.go b/pkg/handlers/networking/route/handler_destination_service_test.go
index c62b354f2..0b960be69 100644
--- a/pkg/handlers/networking/route/handler_destination_service_test.go
+++ b/pkg/handlers/networking/route/handler_destination_service_test.go
@@ -119,6 +119,115 @@ func Test_Handler_Destination_Service_Valid(t *testing.T) {
require.Len(t, extension.Status.Target.RenderURLs(), 1)
require.EqualValues(t, "http://deployment.fake.svc:10244/", extension.Status.Target.RenderURLs()[0])
+ require.EqualValues(t, "http1", extension.Status.Target.Protocol)
+
+ c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
+ require.True(t, ok)
+ require.EqualValues(t, c.Reason, "Destination Found")
+ require.EqualValues(t, c.Reason, "Destination Found")
+ require.EqualValues(t, c.Hash, extension.Status.Target.Hash())
+}
+
+func Test_Handler_Destination_Service_Valid_HTTP1(t *testing.T) {
+ // Setup
+ handler := newFakeHandler()
+
+ // Arrange
+ extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
+ func(t *testing.T, obj *networkingApi.ArangoRoute) {
+ obj.Spec.Deployment = util.NewType("deployment")
+ },
+ func(t *testing.T, obj *networkingApi.ArangoRoute) {
+ obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
+ Protocol: util.NewType(networkingApi.ArangoRouteDestinationProtocolHTTP1),
+ Service: &networkingApi.ArangoRouteSpecDestinationService{
+ Object: &sharedApi.Object{
+ Name: "deployment",
+ },
+ Port: util.NewType(intstr.FromInt32(10244)),
+ },
+ }
+ })
+ deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
+ svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
+ obj.Spec.Ports = []core.ServicePort{
+ {
+ Port: 10244,
+ },
+ }
+ })
+
+ refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc)
+
+ // Test
+ require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
+
+ // Refresh
+ refresh(t)
+
+ // Assert
+ require.True(t, extension.Status.Conditions.IsTrue(networkingApi.SpecValidCondition))
+ require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
+ require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
+ require.Equal(t, networkingApi.ArangoRouteStatusTargetServiceType, extension.Status.Target.Type)
+
+ require.Len(t, extension.Status.Target.RenderURLs(), 1)
+ require.EqualValues(t, "http://deployment.fake.svc:10244/", extension.Status.Target.RenderURLs()[0])
+ require.EqualValues(t, "http1", extension.Status.Target.Protocol)
+
+ c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
+ require.True(t, ok)
+ require.EqualValues(t, c.Reason, "Destination Found")
+ require.EqualValues(t, c.Reason, "Destination Found")
+ require.EqualValues(t, c.Hash, extension.Status.Target.Hash())
+}
+
+func Test_Handler_Destination_Service_Valid_HTTP2(t *testing.T) {
+ // Setup
+ handler := newFakeHandler()
+
+ // Arrange
+ extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
+ func(t *testing.T, obj *networkingApi.ArangoRoute) {
+ obj.Spec.Deployment = util.NewType("deployment")
+ },
+ func(t *testing.T, obj *networkingApi.ArangoRoute) {
+ obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
+ Protocol: util.NewType(networkingApi.ArangoRouteDestinationProtocolHTTP2),
+ Service: &networkingApi.ArangoRouteSpecDestinationService{
+ Object: &sharedApi.Object{
+ Name: "deployment",
+ },
+ Port: util.NewType(intstr.FromInt32(10244)),
+ },
+ }
+ })
+ deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
+ svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
+ obj.Spec.Ports = []core.ServicePort{
+ {
+ Port: 10244,
+ },
+ }
+ })
+
+ refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc)
+
+ // Test
+ require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
+
+ // Refresh
+ refresh(t)
+
+ // Assert
+ require.True(t, extension.Status.Conditions.IsTrue(networkingApi.SpecValidCondition))
+ require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
+ require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
+ require.Equal(t, networkingApi.ArangoRouteStatusTargetServiceType, extension.Status.Target.Type)
+
+ require.Len(t, extension.Status.Target.RenderURLs(), 1)
+ require.EqualValues(t, "http://deployment.fake.svc:10244/", extension.Status.Target.RenderURLs()[0])
+ require.EqualValues(t, "http2", extension.Status.Target.Protocol)
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)