Skip to content

Commit

Permalink
Support configuring loadBalancerIP in envoy svc
Browse files Browse the repository at this point in the history
Fixes: envoyproxy#1841

Signed-off-by: Arko Dasgupta <arko@tetrate.io>
  • Loading branch information
arkodg committed Oct 19, 2023
1 parent f203fe5 commit 564d5f4
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 4 deletions.
7 changes: 7 additions & 0 deletions api/v1alpha1/shared_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,13 @@ type KubernetesServiceSpec struct {
// +optional
AllocateLoadBalancerNodePorts *bool `json:"allocateLoadBalancerNodePorts,omitempty"`

// LoadBalancerIP defines the IP Address of the underlying load balancer service. This field
// may be ignored if the load balancer provider does not support this feature.
// This field has been Deprecated, but it is still used for set the IP Address in some cloud
// providers such as GCP.
// +optional
LoadBalancerIP *string `json:"loadBalancerIP,omitempty"`

// TODO: Expose config as use cases are better understood, e.g. labels.
}

Expand Down
10 changes: 10 additions & 0 deletions api/v1alpha1/validation/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package validation
import (
"errors"
"fmt"
"net"
"reflect"

bootstrapv3 "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v3"
Expand Down Expand Up @@ -95,6 +96,15 @@ func validateService(spec *egv1a1.EnvoyProxySpec) []error {
errs = append(errs, fmt.Errorf("allocateLoadBalancerNodePorts can only be set for %v type", egv1a1.ServiceTypeLoadBalancer))
}
}
if serviceType, serviceLoadBalancerIP := spec.Provider.Kubernetes.EnvoyService.Type, spec.Provider.Kubernetes.EnvoyService.LoadBalancerIP; serviceType != nil && serviceLoadBalancerIP != nil {
if *serviceType != egv1a1.ServiceTypeLoadBalancer {
errs = append(errs, fmt.Errorf("loadBalancerIP can only be set for %v type", egv1a1.ServiceTypeLoadBalancer))
}

if net.ParseIP(*serviceLoadBalancerIP) == nil {
errs = append(errs, fmt.Errorf("loadBalancerIP:%s is an invalid IP address", *serviceLoadBalancerIP))
}
}
}
return errs
}
Expand Down
46 changes: 44 additions & 2 deletions api/v1alpha1/validation/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func TestValidateEnvoyProxy(t *testing.T) {
Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{
EnvoyService: &egv1a1.KubernetesServiceSpec{
Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeLoadBalancer),
AllocateLoadBalancerNodePorts: ptr.To[bool](false),
AllocateLoadBalancerNodePorts: ptr.To(false),
},
},
},
Expand All @@ -205,7 +205,49 @@ func TestValidateEnvoyProxy(t *testing.T) {
Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{
EnvoyService: &egv1a1.KubernetesServiceSpec{
Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeClusterIP),
AllocateLoadBalancerNodePorts: ptr.To[bool](false),
AllocateLoadBalancerNodePorts: ptr.To(false),
},
},
},
},
},
expected: false,
},
{
name: "envoy service type 'LoadBalancer' with valid loadBalancerIP",
proxy: &egv1a1.EnvoyProxy{
ObjectMeta: metav1.ObjectMeta{
Namespace: "test",
Name: "test",
},
Spec: egv1a1.EnvoyProxySpec{
Provider: &egv1a1.EnvoyProxyProvider{
Type: egv1a1.ProviderTypeKubernetes,
Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{
EnvoyService: &egv1a1.KubernetesServiceSpec{
Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeLoadBalancer),
LoadBalancerIP: ptr.To("10.11.12.13"),
},
},
},
},
},
expected: true,
},
{
name: "envoy service type 'LoadBalancer' with invalid loadBalancerIP",
proxy: &egv1a1.EnvoyProxy{
ObjectMeta: metav1.ObjectMeta{
Namespace: "test",
Name: "test",
},
Spec: egv1a1.EnvoyProxySpec{
Provider: &egv1a1.EnvoyProxyProvider{
Type: egv1a1.ProviderTypeKubernetes,
Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{
EnvoyService: &egv1a1.KubernetesServiceSpec{
Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeLoadBalancer),
LoadBalancerIP: ptr.To("invalid-ip"),
},
},
},
Expand Down
5 changes: 5 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -5258,6 +5258,14 @@ spec:
if more than one are available or is otherwise expected
to be specified
type: string
loadBalancerIP:
description: LoadBalancerIP defines the IP Address of
the underlying load balancer service. This field may
be ignored if the load balancer provider does not support
this feature. This field has been Deprecated, but it
is still used for set the IP Address in some cloud providers
such as GCP.
type: string
type:
default: LoadBalancer
description: Type determines how the Service is exposed.
Expand Down
3 changes: 3 additions & 0 deletions internal/infrastructure/kubernetes/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ func ExpectedServiceSpec(service *egv1a1.KubernetesServiceSpec) corev1.ServiceSp
if service.AllocateLoadBalancerNodePorts != nil {
serviceSpec.AllocateLoadBalancerNodePorts = service.AllocateLoadBalancerNodePorts
}
if service.LoadBalancerIP != nil {
serviceSpec.LoadBalancerIP = *service.LoadBalancerIP
}
// Preserve the client source IP and avoid a second hop for LoadBalancer.
serviceSpec.ExternalTrafficPolicy = corev1.ServiceExternalTrafficPolicyTypeLocal
}
Expand Down
17 changes: 15 additions & 2 deletions internal/infrastructure/kubernetes/resource/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,28 @@ func TestExpectedServiceSpec(t *testing.T) {
name: "LoadBalancerWithAllocateLoadBalancerNodePorts",
args: args{service: &egv1a1.KubernetesServiceSpec{
Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeLoadBalancer),
AllocateLoadBalancerNodePorts: ptr.To[bool](true),
AllocateLoadBalancerNodePorts: ptr.To(true),
}},
want: corev1.ServiceSpec{
Type: corev1.ServiceTypeLoadBalancer,
AllocateLoadBalancerNodePorts: ptr.To[bool](true),
AllocateLoadBalancerNodePorts: ptr.To(true),
SessionAffinity: corev1.ServiceAffinityNone,
ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyTypeLocal,
},
},
{
name: "LoadBalancerWithLoadBalancerIP",
args: args{service: &egv1a1.KubernetesServiceSpec{
Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeLoadBalancer),
LoadBalancerIP: ptr.To("10.11.12.13"),
}},
want: corev1.ServiceSpec{
Type: corev1.ServiceTypeLoadBalancer,
LoadBalancerIP: "10.11.12.13",
SessionAffinity: corev1.ServiceAffinityNone,
ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyTypeLocal,
},
},
{
name: "ClusterIP",
args: args{service: &egv1a1.KubernetesServiceSpec{
Expand Down
1 change: 1 addition & 0 deletions site/content/en/latest/api/extension_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,7 @@ _Appears in:_
| `type` _[ServiceType](#servicetype)_ | Type determines how the Service is exposed. Defaults to LoadBalancer. Valid options are ClusterIP, LoadBalancer and NodePort. "LoadBalancer" means a service will be exposed via an external load balancer (if the cloud provider supports it). "ClusterIP" means a service will only be accessible inside the cluster, via the cluster IP. "NodePort" means a service will be exposed on a static Port on all Nodes of the cluster. |
| `loadBalancerClass` _string_ | LoadBalancerClass, when specified, allows for choosing the LoadBalancer provider implementation if more than one are available or is otherwise expected to be specified |
| `allocateLoadBalancerNodePorts` _boolean_ | AllocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for services with type LoadBalancer. Default is "true". It may be set to "false" if the cluster load-balancer does not rely on NodePorts. If the caller requests specific NodePorts (by specifying a value), those requests will be respected, regardless of this field. This field may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. |
| `loadBalancerIP` _string_ | LoadBalancerIP defines the IP Address of the underlying load balancer service. This field may be ignored if the load balancer provider does not support this feature. This field has been Deprecated, but it is still used for set the IP Address in some cloud providers such as GCP. |


#### KubernetesWatchMode
Expand Down

0 comments on commit 564d5f4

Please sign in to comment.