Skip to content

Commit fb8a6c7

Browse files
uzzzFxKu
andauthored
Compare container ports in a smarter way (zalando#1755)
* Compare ports ingoring order and considering protocol defaults Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
1 parent d8a159e commit fb8a6c7

File tree

2 files changed

+142
-1
lines changed

2 files changed

+142
-1
lines changed

pkg/cluster/cluster.go

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ func (c *Cluster) compareContainers(description string, setA, setB []v1.Containe
523523
newCheck("new statefulset %s's %s (index %d) name does not match the current one",
524524
func(a, b v1.Container) bool { return a.Name != b.Name }),
525525
newCheck("new statefulset %s's %s (index %d) ports do not match the current one",
526-
func(a, b v1.Container) bool { return !reflect.DeepEqual(a.Ports, b.Ports) }),
526+
func(a, b v1.Container) bool { return !comparePorts(a.Ports, b.Ports) }),
527527
newCheck("new statefulset %s's %s (index %d) resources do not match the current ones",
528528
func(a, b v1.Container) bool { return !compareResources(&a.Resources, &b.Resources) }),
529529
newCheck("new statefulset %s's %s (index %d) environment does not match the current one",
@@ -634,6 +634,46 @@ func compareSpiloConfiguration(configa, configb string) bool {
634634
return reflect.DeepEqual(oa, ob)
635635
}
636636

637+
func areProtocolsEqual(a, b v1.Protocol) bool {
638+
return a == b ||
639+
(a == "" && b == v1.ProtocolTCP) ||
640+
(a == v1.ProtocolTCP && b == "")
641+
}
642+
643+
func comparePorts(a, b []v1.ContainerPort) bool {
644+
if len(a) != len(b) {
645+
return false
646+
}
647+
648+
areContainerPortsEqual := func(a, b v1.ContainerPort) bool {
649+
return a.Name == b.Name &&
650+
a.HostPort == b.HostPort &&
651+
areProtocolsEqual(a.Protocol, b.Protocol) &&
652+
a.HostIP == b.HostIP
653+
}
654+
655+
findByPortValue := func(portSpecs []v1.ContainerPort, port int32) (v1.ContainerPort, bool) {
656+
for _, portSpec := range portSpecs {
657+
if portSpec.ContainerPort == port {
658+
return portSpec, true
659+
}
660+
}
661+
return v1.ContainerPort{}, false
662+
}
663+
664+
for _, portA := range a {
665+
portB, found := findByPortValue(b, portA.ContainerPort)
666+
if !found {
667+
return false
668+
}
669+
if !areContainerPortsEqual(portA, portB) {
670+
return false
671+
}
672+
}
673+
674+
return true
675+
}
676+
637677
func (c *Cluster) enforceMinResourceLimits(spec *acidv1.PostgresSpec) error {
638678

639679
var (

pkg/cluster/cluster_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"reflect"
66
"testing"
77

8+
"github.com/stretchr/testify/assert"
9+
810
"github.com/sirupsen/logrus"
911
acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
1012
fakeacidv1 "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/fake"
@@ -1088,3 +1090,102 @@ func TestValidUsernames(t *testing.T) {
10881090
}
10891091
}
10901092
}
1093+
1094+
func TestComparePorts(t *testing.T) {
1095+
testCases := []struct {
1096+
name string
1097+
setA []v1.ContainerPort
1098+
setB []v1.ContainerPort
1099+
expected bool
1100+
}{
1101+
{
1102+
name: "different ports",
1103+
setA: []v1.ContainerPort{
1104+
{
1105+
Name: "metrics",
1106+
ContainerPort: 9187,
1107+
Protocol: v1.ProtocolTCP,
1108+
},
1109+
},
1110+
1111+
setB: []v1.ContainerPort{
1112+
{
1113+
Name: "http",
1114+
ContainerPort: 80,
1115+
Protocol: v1.ProtocolTCP,
1116+
},
1117+
},
1118+
expected: false,
1119+
},
1120+
{
1121+
name: "no difference",
1122+
setA: []v1.ContainerPort{
1123+
{
1124+
Name: "metrics",
1125+
ContainerPort: 9187,
1126+
Protocol: v1.ProtocolTCP,
1127+
},
1128+
},
1129+
setB: []v1.ContainerPort{
1130+
{
1131+
Name: "metrics",
1132+
ContainerPort: 9187,
1133+
Protocol: v1.ProtocolTCP,
1134+
},
1135+
},
1136+
expected: true,
1137+
},
1138+
{
1139+
name: "same ports, different order",
1140+
setA: []v1.ContainerPort{
1141+
{
1142+
Name: "metrics",
1143+
ContainerPort: 9187,
1144+
Protocol: v1.ProtocolTCP,
1145+
},
1146+
{
1147+
Name: "http",
1148+
ContainerPort: 80,
1149+
Protocol: v1.ProtocolTCP,
1150+
},
1151+
},
1152+
setB: []v1.ContainerPort{
1153+
{
1154+
Name: "http",
1155+
ContainerPort: 80,
1156+
Protocol: v1.ProtocolTCP,
1157+
},
1158+
{
1159+
Name: "metrics",
1160+
ContainerPort: 9187,
1161+
Protocol: v1.ProtocolTCP,
1162+
},
1163+
},
1164+
expected: true,
1165+
},
1166+
{
1167+
name: "same ports, but one with default protocol",
1168+
setA: []v1.ContainerPort{
1169+
{
1170+
Name: "metrics",
1171+
ContainerPort: 9187,
1172+
Protocol: v1.ProtocolTCP,
1173+
},
1174+
},
1175+
setB: []v1.ContainerPort{
1176+
{
1177+
Name: "metrics",
1178+
ContainerPort: 9187,
1179+
},
1180+
},
1181+
expected: true,
1182+
},
1183+
}
1184+
1185+
for _, testCase := range testCases {
1186+
t.Run(testCase.name, func(t *testing.T) {
1187+
got := comparePorts(testCase.setA, testCase.setB)
1188+
assert.Equal(t, testCase.expected, got)
1189+
})
1190+
}
1191+
}

0 commit comments

Comments
 (0)