Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: explicitly set ip family and family policy in gateway spec #5019

Merged
merged 3 commits into from
Jan 7, 2025
Merged
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
14 changes: 14 additions & 0 deletions internal/infrastructure/kubernetes/proxy/resource_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,20 @@ func (r *ResourceRender) Service() (*corev1.Service, error) {
serviceSpec.ExternalIPs = r.infra.Addresses
}

// Set IP family policy and families based on proxy config request
ipFamily := r.infra.GetProxyConfig().Spec.IPFamily
if ipFamily != nil {
// SingleStack+IPv4 is default behavior from K8s and so is omitted
switch *ipFamily {
case egv1a1.IPv6:
serviceSpec.IPFamilies = []corev1.IPFamily{corev1.IPv6Protocol}
serviceSpec.IPFamilyPolicy = ptr.To(corev1.IPFamilyPolicySingleStack)
case egv1a1.DualStack:
serviceSpec.IPFamilies = []corev1.IPFamily{corev1.IPv4Protocol, corev1.IPv6Protocol}
serviceSpec.IPFamilyPolicy = ptr.To(corev1.IPFamilyPolicyRequireDualStack)
}
}

svc := &corev1.Service{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ func newTestInfra() *ir.Infra {
return newTestInfraWithAnnotations(nil)
}

func newTestInfraWithIPFamily(family *egv1a1.IPFamily) *ir.Infra {
i := newTestInfra()
i.Proxy.Config = &egv1a1.EnvoyProxy{
Spec: egv1a1.EnvoyProxySpec{
IPFamily: family,
},
}
return i
}

func newTestIPv6Infra() *ir.Infra {
i := newTestInfra()
i.Proxy.Config = &egv1a1.EnvoyProxy{
Expand Down Expand Up @@ -1165,6 +1175,21 @@ func TestService(t *testing.T) {
Name: ptr.To("custom-service-name"),
},
},
{
caseName: "dualstack",
infra: newTestInfraWithIPFamily(ptr.To(egv1a1.DualStack)),
service: nil,
},
{
caseName: "ipv4-singlestack",
infra: newTestInfraWithIPFamily(ptr.To(egv1a1.IPv4)),
service: nil,
},
{
caseName: "ipv6-singlestack",
infra: newTestInfraWithIPFamily(ptr.To(egv1a1.IPv6)),
service: nil,
},
}
for _, tc := range cases {
t.Run(tc.caseName, func(t *testing.T) {
Expand Down Expand Up @@ -1536,3 +1561,48 @@ func TestOwningGatewayLabelsAbsent(t *testing.T) {
})
}
}

func TestIPFamilyPresentInSpec(t *testing.T) {
cases := []struct {
name string
requestedFamily *egv1a1.IPFamily
expectedFamilies []corev1.IPFamily
expectedPolicy *corev1.IPFamilyPolicy
}{
{
"no family specified",
nil,
nil,
nil,
},
{
"ipv4 specified",
ptr.To(egv1a1.IPv4),
nil,
nil,
},
{
"ipv6 specified",
ptr.To(egv1a1.IPv6),
[]corev1.IPFamily{corev1.IPv6Protocol},
ptr.To(corev1.IPFamilyPolicySingleStack),
},
{
"dual stack",
ptr.To(egv1a1.DualStack),
[]corev1.IPFamily{corev1.IPv4Protocol, corev1.IPv6Protocol},
ptr.To(corev1.IPFamilyPolicyRequireDualStack),
},
}

for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
r := ResourceRender{infra: newTestInfraWithIPFamily(tc.requestedFamily).Proxy}
svc, err := r.Service()
require.NoError(t, err, "service render func")

assert.ElementsMatch(t, tc.expectedFamilies, svc.Spec.IPFamilies, "families slice")
assert.Equal(t, tc.expectedPolicy, svc.Spec.IPFamilyPolicy, "policy")
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: envoy
app.kubernetes.io/component: proxy
app.kubernetes.io/managed-by: envoy-gateway
gateway.envoyproxy.io/owning-gateway-name: default
gateway.envoyproxy.io/owning-gateway-namespace: default
name: envoy-default-37a8eec1
namespace: envoy-gateway-system
spec:
externalTrafficPolicy: Local
ipFamilies:
- IPv4
- IPv6
ipFamilyPolicy: RequireDualStack
ports:
- name: EnvoyHTTPPort
port: 0
protocol: TCP
targetPort: 8080
- name: EnvoyHTTPSPort
port: 0
protocol: TCP
targetPort: 8443
selector:
app.kubernetes.io/name: envoy
app.kubernetes.io/component: proxy
app.kubernetes.io/managed-by: envoy-gateway
gateway.envoyproxy.io/owning-gateway-name: default
gateway.envoyproxy.io/owning-gateway-namespace: default
sessionAffinity: None
type: LoadBalancer
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: envoy
app.kubernetes.io/component: proxy
app.kubernetes.io/managed-by: envoy-gateway
gateway.envoyproxy.io/owning-gateway-name: default
gateway.envoyproxy.io/owning-gateway-namespace: default
name: envoy-default-37a8eec1
namespace: envoy-gateway-system
spec:
externalTrafficPolicy: Local
ports:
- name: EnvoyHTTPPort
port: 0
protocol: TCP
targetPort: 8080
- name: EnvoyHTTPSPort
port: 0
protocol: TCP
targetPort: 8443
selector:
app.kubernetes.io/name: envoy
app.kubernetes.io/component: proxy
app.kubernetes.io/managed-by: envoy-gateway
gateway.envoyproxy.io/owning-gateway-name: default
gateway.envoyproxy.io/owning-gateway-namespace: default
sessionAffinity: None
type: LoadBalancer
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: envoy
app.kubernetes.io/component: proxy
app.kubernetes.io/managed-by: envoy-gateway
gateway.envoyproxy.io/owning-gateway-name: default
gateway.envoyproxy.io/owning-gateway-namespace: default
name: envoy-default-37a8eec1
namespace: envoy-gateway-system
spec:
externalTrafficPolicy: Local
ipFamilies:
- IPv6
ipFamilyPolicy: SingleStack
ports:
- name: EnvoyHTTPPort
port: 0
protocol: TCP
targetPort: 8080
- name: EnvoyHTTPSPort
port: 0
protocol: TCP
targetPort: 8443
selector:
app.kubernetes.io/name: envoy
app.kubernetes.io/component: proxy
app.kubernetes.io/managed-by: envoy-gateway
gateway.envoyproxy.io/owning-gateway-name: default
gateway.envoyproxy.io/owning-gateway-namespace: default
sessionAffinity: None
type: LoadBalancer
Loading