Skip to content

Commit d6467f5

Browse files
committed
fix: #181 Service processor missing IP family configuration support
- Add ipFamilyPolicy and ipFamilies fields to service templates - Add parseIPFamily function to handle IP family configuration - Update service template to include IP family spec between selector and ports - Add test coverage for IP family functionality - Update example charts to demonstrate the feature - Add IPv6 service example to test data This allows helmify to preserve IP family configuration when converting Kubernetes Service manifests that use IPv6-only or dual-stack networking.
1 parent 4f6d16b commit d6467f5

File tree

5 files changed

+127
-4
lines changed

5 files changed

+127
-4
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: v1
2+
kind: Service
3+
metadata:
4+
name: {{ include "app.fullname" . }}-myapp-ipv6-service
5+
labels:
6+
app: myapp
7+
{{- include "app.labels" . | nindent 4 }}
8+
spec:
9+
type: {{ .Values.myappIpv6Service.type }}
10+
selector:
11+
app: myapp
12+
{{- include "app.selectorLabels" . | nindent 4 }}
13+
{{- if .Values.myappIpv6Service.ipFamilyPolicy }}
14+
ipFamilyPolicy: {{ .Values.myappIpv6Service.ipFamilyPolicy }}
15+
{{- end }}
16+
{{- if .Values.myappIpv6Service.ipFamilies }}
17+
ipFamilies:
18+
{{- .Values.myappIpv6Service.ipFamilies | toYaml | nindent 2 }}
19+
{{- end }}
20+
ports:
21+
{{- .Values.myappIpv6Service.ports | toYaml | nindent 2 }}

examples/app/values.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,15 @@ myapp:
103103
revisionHistoryLimit: 5
104104
tolerations: []
105105
topologySpreadConstraints: []
106+
myappIpv6Service:
107+
ipFamilies:
108+
- IPv6
109+
ipFamilyPolicy: PreferDualStack
110+
ports:
111+
- name: https
112+
port: 8443
113+
targetPort: https
114+
type: ClusterIP
106115
myappLbService:
107116
loadBalancerSourceRanges:
108117
- 10.0.0.0/8

pkg/processor/service/service.go

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ spec:
2525
type: {{ .Values.%[1]s.type }}
2626
selector:
2727
%[2]s
28-
{{- include "%[3]s.selectorLabels" . | nindent 4 }}
28+
{{- include "%[3]s.selectorLabels" . | nindent 4 }}%[4]s
2929
ports:
3030
{{- .Values.%[1]s.ports | toYaml | nindent 2 }}`
3131
)
@@ -36,6 +36,17 @@ const (
3636
{{- .Values.%[1]s.loadBalancerSourceRanges | toYaml | nindent 2 }}`
3737
)
3838

39+
const (
40+
ipFamilyTempSpec = `
41+
{{- if .Values.%[1]s.ipFamilyPolicy }}
42+
ipFamilyPolicy: {{ .Values.%[1]s.ipFamilyPolicy }}
43+
{{- end }}
44+
{{- if .Values.%[1]s.ipFamilies }}
45+
ipFamilies:
46+
{{- .Values.%[1]s.ipFamilies | toYaml | nindent 2 }}
47+
{{- end }}`
48+
)
49+
3950
var svcGVC = schema.GroupVersionKind{
4051
Group: "",
4152
Version: "v1",
@@ -102,7 +113,9 @@ func (r svc) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured
102113
}
103114

104115
_ = unstructured.SetNestedSlice(values, ports, shortNameCamel, "ports")
105-
res := meta + fmt.Sprintf(svcTempSpec, shortNameCamel, selector, appMeta.ChartName())
116+
117+
ipFamilySpec := parseIPFamily(values, service, shortNameCamel)
118+
res := meta + fmt.Sprintf(svcTempSpec, shortNameCamel, selector, appMeta.ChartName(), ipFamilySpec)
106119

107120
res += parseLoadBalancerSourceRanges(values, service, shortNameCamel)
108121

@@ -116,6 +129,29 @@ func (r svc) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured
116129
}, nil
117130
}
118131

132+
func parseIPFamily(values helmify.Values, service corev1.Service, shortNameCamel string) string {
133+
hasIPFamilyPolicy := service.Spec.IPFamilyPolicy != nil
134+
hasIPFamilies := len(service.Spec.IPFamilies) > 0
135+
136+
if !hasIPFamilyPolicy && !hasIPFamilies {
137+
return ""
138+
}
139+
140+
if hasIPFamilyPolicy {
141+
_ = unstructured.SetNestedField(values, string(*service.Spec.IPFamilyPolicy), shortNameCamel, "ipFamilyPolicy")
142+
}
143+
144+
if hasIPFamilies {
145+
ipFamilies := make([]interface{}, len(service.Spec.IPFamilies))
146+
for i, fam := range service.Spec.IPFamilies {
147+
ipFamilies[i] = string(fam)
148+
}
149+
_ = unstructured.SetNestedSlice(values, ipFamilies, shortNameCamel, "ipFamilies")
150+
}
151+
152+
return fmt.Sprintf(ipFamilyTempSpec, shortNameCamel)
153+
}
154+
119155
func parseLoadBalancerSourceRanges(values helmify.Values, service corev1.Service, shortNameCamel string) string {
120156
if len(service.Spec.LoadBalancerSourceRanges) < 1 {
121157
return ""

pkg/processor/service/service_test.go

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ package service
33
import (
44
"testing"
55

6-
"github.com/arttor/helmify/pkg/metadata"
7-
86
"github.com/arttor/helmify/internal"
7+
"github.com/arttor/helmify/pkg/metadata"
98
"github.com/stretchr/testify/assert"
9+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1010
)
1111

1212
const svcYaml = `apiVersion: v1
@@ -24,6 +24,25 @@ spec:
2424
selector:
2525
control-plane: controller-manager`
2626

27+
const svcWithIPFamilyYaml = `apiVersion: v1
28+
kind: Service
29+
metadata:
30+
labels:
31+
control-plane: controller-manager
32+
name: my-operator-controller-manager-metrics-service
33+
namespace: my-operator-system
34+
spec:
35+
ipFamilyPolicy: PreferDualStack
36+
ipFamilies:
37+
- IPv4
38+
- IPv6
39+
ports:
40+
- name: https
41+
port: 8443
42+
targetPort: https
43+
selector:
44+
control-plane: controller-manager`
45+
2746
func Test_svc_Process(t *testing.T) {
2847
var testInstance svc
2948

@@ -39,4 +58,23 @@ func Test_svc_Process(t *testing.T) {
3958
assert.NoError(t, err)
4059
assert.Equal(t, false, processed)
4160
})
61+
62+
t.Run("processed with IP family", func(t *testing.T) {
63+
obj := internal.GenerateObj(svcWithIPFamilyYaml)
64+
processed, template, err := testInstance.Process(&metadata.Service{}, obj)
65+
assert.NoError(t, err)
66+
assert.Equal(t, true, processed)
67+
assert.NotNil(t, template)
68+
69+
values := template.Values()
70+
ipFamilyPolicy, found, err := unstructured.NestedString(values, "myOperatorControllerManagerMetricsService", "ipFamilyPolicy")
71+
assert.NoError(t, err)
72+
assert.True(t, found)
73+
assert.Equal(t, "PreferDualStack", ipFamilyPolicy)
74+
75+
ipFamilies, found, err := unstructured.NestedSlice(values, "myOperatorControllerManagerMetricsService", "ipFamilies")
76+
assert.NoError(t, err)
77+
assert.True(t, found)
78+
assert.Len(t, ipFamilies, 2)
79+
})
4280
}

test_data/sample-app.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,25 @@ spec:
156156
loadBalancerSourceRanges:
157157
- 10.0.0.0/8
158158
---
159+
apiVersion: v1
160+
kind: Service
161+
metadata:
162+
labels:
163+
app: myapp
164+
name: myapp-ipv6-service
165+
namespace: my-ns
166+
spec:
167+
ipFamilyPolicy: PreferDualStack
168+
ipFamilies:
169+
- IPv6
170+
ports:
171+
- name: https
172+
port: 8443
173+
targetPort: https
174+
selector:
175+
app: myapp
176+
---
177+
---
159178
apiVersion: networking.k8s.io/v1
160179
kind: Ingress
161180
metadata:

0 commit comments

Comments
 (0)