Skip to content

Commit cff7010

Browse files
committed
add service warning for duplicate ports
1 parent a3f578d commit cff7010

File tree

3 files changed

+85
-2
lines changed

3 files changed

+85
-2
lines changed

pkg/api/service/util.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"fmt"
2121
"strings"
2222

23+
"k8s.io/apimachinery/pkg/util/sets"
24+
"k8s.io/apimachinery/pkg/util/validation/field"
2325
api "k8s.io/kubernetes/pkg/apis/core"
2426
utilnet "k8s.io/utils/net"
2527
)
@@ -84,3 +86,25 @@ func NeedsHealthCheck(service *api.Service) bool {
8486
}
8587
return RequestsOnlyLocalTraffic(service)
8688
}
89+
90+
func GetWarningsForService(service *api.Service) []string {
91+
if service == nil {
92+
return nil
93+
}
94+
var warnings []string
95+
ports := service.Spec.Ports
96+
if len(ports) > 1 {
97+
servicePorts := sets.NewInt64()
98+
for i, port := range ports {
99+
if servicePorts.Has(int64(port.Port)) {
100+
warnings = append(warnings, fmt.Sprintf(
101+
"%s: service has duplicate ports: %d",
102+
field.NewPath("spec").Child("ports").Index(i).Child("port"),
103+
port.Port))
104+
} else {
105+
servicePorts.Insert(int64(port.Port))
106+
}
107+
}
108+
}
109+
return warnings
110+
}

pkg/api/service/util_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"strings"
2121
"testing"
2222

23+
"k8s.io/apimachinery/pkg/util/sets"
2324
api "k8s.io/kubernetes/pkg/apis/core"
2425
utilnet "k8s.io/utils/net"
2526
)
@@ -214,3 +215,58 @@ func TestNeedsHealthCheck(t *testing.T) {
214215
},
215216
})
216217
}
218+
219+
func TestWarnings(t *testing.T) {
220+
testcases := []struct {
221+
name string
222+
template *api.Service
223+
expected []string
224+
}{
225+
{
226+
name: "null",
227+
template: nil,
228+
expected: nil,
229+
},
230+
{
231+
name: "no dup ports",
232+
template: &api.Service{Spec: api.ServiceSpec{
233+
Ports: []api.ServicePort{
234+
{Protocol: api.ProtocolTCP, Port: 443},
235+
{Protocol: api.ProtocolTCP, Port: 1443},
236+
},
237+
Type: api.ServiceTypeNodePort,
238+
},
239+
},
240+
expected: nil,
241+
},
242+
{
243+
name: "dup ports",
244+
template: &api.Service{Spec: api.ServiceSpec{
245+
Ports: []api.ServicePort{
246+
{Name: "tcp-443", Protocol: api.ProtocolTCP, Port: 443},
247+
{Protocol: api.ProtocolTCP, Port: 1443},
248+
{Name: "udp-443", Protocol: api.ProtocolUDP, Port: 443},
249+
},
250+
Type: api.ServiceTypeNodePort,
251+
},
252+
},
253+
expected: []string{
254+
`spec.ports[2].port: service has duplicate ports: 443`,
255+
},
256+
},
257+
}
258+
259+
for _, tc := range testcases {
260+
t.Run("servicespec_"+tc.name, func(t *testing.T) {
261+
actual := sets.NewString(GetWarningsForService(tc.template)...)
262+
expected := sets.NewString(tc.expected...)
263+
for _, missing := range expected.Difference(actual).List() {
264+
t.Errorf("missing: %s", missing)
265+
}
266+
for _, extra := range actual.Difference(expected).List() {
267+
t.Errorf("extra: %s", extra)
268+
}
269+
})
270+
271+
}
272+
}

pkg/registry/core/service/strategy.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"k8s.io/apiserver/pkg/storage/names"
2727
utilfeature "k8s.io/apiserver/pkg/util/feature"
2828
"k8s.io/kubernetes/pkg/api/legacyscheme"
29+
apiservice "k8s.io/kubernetes/pkg/api/service"
2930
api "k8s.io/kubernetes/pkg/apis/core"
3031
"k8s.io/kubernetes/pkg/apis/core/validation"
3132
"k8s.io/kubernetes/pkg/features"
@@ -86,7 +87,9 @@ func (svcStrategy) Validate(ctx context.Context, obj runtime.Object) field.Error
8687
}
8788

8889
// WarningsOnCreate returns warnings for the creation of the given object.
89-
func (svcStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil }
90+
func (svcStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
91+
return apiservice.GetWarningsForService(obj.(*api.Service))
92+
}
9093

9194
// Canonicalize normalizes the object after validation.
9295
func (svcStrategy) Canonicalize(obj runtime.Object) {
@@ -104,7 +107,7 @@ func (strategy svcStrategy) ValidateUpdate(ctx context.Context, obj, old runtime
104107

105108
// WarningsOnUpdate returns warnings for the given update.
106109
func (svcStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
107-
return nil
110+
return apiservice.GetWarningsForService(obj.(*api.Service))
108111
}
109112

110113
func (svcStrategy) AllowUnconditionalUpdate() bool {

0 commit comments

Comments
 (0)