Skip to content
This repository was archived by the owner on Apr 25, 2023. It is now read-only.

Commit fc5b459

Browse files
committed
fix: Retain service clusterIPs if set
1 parent 612f3ac commit fc5b459

File tree

4 files changed

+133
-2
lines changed

4 files changed

+133
-2
lines changed

pkg/controller/sync/dispatch/retain.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func retainServiceFields(desiredObj, clusterObj *unstructured.Unstructured) erro
5959

6060
// ClusterIP and NodePort are allocated to Service by cluster, so retain the same if any while updating
6161

62-
// Retain clusterip
62+
// Retain clusterip and clusterips
6363
clusterIP, ok, err := unstructured.NestedString(clusterObj.Object, "spec", "clusterIP")
6464
if err != nil {
6565
return errors.Wrap(err, "Error retrieving clusterIP from cluster service")
@@ -71,6 +71,17 @@ func retainServiceFields(desiredObj, clusterObj *unstructured.Unstructured) erro
7171
return errors.Wrap(err, "Error setting clusterIP for service")
7272
}
7373
}
74+
clusterIPs, ok, err := unstructured.NestedStringSlice(clusterObj.Object, "spec", "clusterIPs")
75+
if err != nil {
76+
return errors.Wrap(err, "Error retrieving clusterIPs from cluster service")
77+
}
78+
// !ok could indicate that cluster ips was not assigned
79+
if ok && len(clusterIPs) > 0 {
80+
err := unstructured.SetNestedStringSlice(desiredObj.Object, clusterIPs, "spec", "clusterIPs")
81+
if err != nil {
82+
return errors.Wrap(err, "Error setting clusterIPs for service")
83+
}
84+
}
7485

7586
// Retain nodeports
7687
clusterPorts, ok, err := unstructured.NestedSlice(clusterObj.Object, "spec", "ports")

pkg/controller/sync/dispatch/retain_test.go

+119
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package dispatch
1818

1919
import (
20+
"reflect"
2021
"testing"
2122

2223
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -171,3 +172,121 @@ func TestRetainHealthCheckNodePortInServiceFields(t *testing.T) {
171172
})
172173
}
173174
}
175+
176+
func TestRetainClusterIPsInServiceFields(t *testing.T) {
177+
tests := []struct {
178+
name string
179+
desiredObj *unstructured.Unstructured
180+
clusterObj *unstructured.Unstructured
181+
retainSucceed bool
182+
expectedClusterIPValue *string
183+
expectedClusterIPsValue []string
184+
}{
185+
{
186+
"cluster object has no clusterIP or clusterIPs",
187+
&unstructured.Unstructured{
188+
Object: map[string]interface{}{},
189+
},
190+
&unstructured.Unstructured{
191+
Object: map[string]interface{}{},
192+
},
193+
true,
194+
nil,
195+
nil,
196+
},
197+
{
198+
"cluster object has clusterIP",
199+
&unstructured.Unstructured{
200+
Object: map[string]interface{}{},
201+
},
202+
&unstructured.Unstructured{
203+
Object: map[string]interface{}{
204+
"spec": map[string]interface{}{
205+
"clusterIP": -1000,
206+
},
207+
},
208+
},
209+
false,
210+
nil,
211+
nil,
212+
},
213+
{
214+
"cluster object has clusterIP only",
215+
&unstructured.Unstructured{
216+
Object: map[string]interface{}{},
217+
},
218+
&unstructured.Unstructured{
219+
Object: map[string]interface{}{
220+
"spec": map[string]interface{}{
221+
"clusterIP": "1.2.3.4",
222+
},
223+
},
224+
},
225+
true,
226+
pointer.String("1.2.3.4"),
227+
nil,
228+
},
229+
{
230+
"cluster object has clusterIPs only",
231+
&unstructured.Unstructured{
232+
Object: map[string]interface{}{},
233+
},
234+
&unstructured.Unstructured{
235+
Object: map[string]interface{}{
236+
"spec": map[string]interface{}{
237+
"clusterIPs": []interface{}{"1.2.3.4", "5.6.7.8"},
238+
},
239+
},
240+
},
241+
true,
242+
nil,
243+
[]string{"1.2.3.4", "5.6.7.8"},
244+
},
245+
{
246+
"cluster object has both clusterIP and clusterIPs",
247+
&unstructured.Unstructured{
248+
Object: map[string]interface{}{},
249+
},
250+
&unstructured.Unstructured{
251+
Object: map[string]interface{}{
252+
"spec": map[string]interface{}{
253+
"clusterIP": "1.2.3.4",
254+
"clusterIPs": []interface{}{"5.6.7.8", "9.10.11.12"},
255+
},
256+
},
257+
},
258+
true,
259+
pointer.String("1.2.3.4"),
260+
[]string{"5.6.7.8", "9.10.11.12"},
261+
},
262+
}
263+
for _, test := range tests {
264+
t.Run(test.name, func(t *testing.T) {
265+
if err := retainServiceFields(test.desiredObj, test.clusterObj); (err == nil) != test.retainSucceed {
266+
t.Fatalf("test %s fails: unexpected returned error %v", test.name, err)
267+
}
268+
269+
currentClusterIPValue, ok, err := unstructured.NestedString(test.desiredObj.Object, "spec", "clusterIP")
270+
if err != nil {
271+
t.Fatalf("test %s fails: %v", test.name, err)
272+
}
273+
if !ok && test.expectedClusterIPValue != nil {
274+
t.Fatalf("test %s fails: expect specified clusterIP but not found", test.name)
275+
}
276+
if ok && (test.expectedClusterIPValue == nil || *test.expectedClusterIPValue != currentClusterIPValue) {
277+
t.Fatalf("test %s fails: unexpected current clusterIP %s", test.name, currentClusterIPValue)
278+
}
279+
280+
currentClusterIPsValue, ok, err := unstructured.NestedStringSlice(test.desiredObj.Object, "spec", "clusterIPs")
281+
if err != nil {
282+
t.Fatalf("test %s fails: %v", test.name, err)
283+
}
284+
if !ok && test.expectedClusterIPsValue != nil {
285+
t.Fatalf("test %s fails: expect specified clusterIPs but not found", test.name)
286+
}
287+
if ok && !reflect.DeepEqual(test.expectedClusterIPsValue, currentClusterIPsValue) {
288+
t.Fatalf("test %s fails: unexpected current clusterIPs %v", test.name, currentClusterIPsValue)
289+
}
290+
})
291+
}
292+
}

pkg/kubefedctl/federate/federate.go

+1
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ func FederatedResourceFromTargetResource(typeConfig typeconfig.Interface, resour
390390
}
391391
}
392392
unstructured.RemoveNestedField(targetResource.Object, "spec", "clusterIP")
393+
unstructured.RemoveNestedField(targetResource.Object, "spec", "clusterIPs")
393394
}
394395
}
395396

pkg/schedulingtypes/replicascheduler.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ func (s *ReplicaScheduler) Reconcile(obj runtimeclient.Object, qualifiedName ctl
198198

199199
resultClusters, err := plugin.(*Plugin).GetResourceClusters(qualifiedName, fedClusters)
200200
if err != nil {
201-
runtime.HandleError(errors.Wrapf(err, "Failed to get prefrerred clusters while reconciling RSP named %q", key))
201+
runtime.HandleError(errors.Wrapf(err, "Failed to get preferred clusters while reconciling RSP named %q", key))
202202
return ctlutil.StatusError
203203
}
204204

0 commit comments

Comments
 (0)