Skip to content

Commit 7f1cebe

Browse files
Merge pull request openshift#7860 from vr4manta/OCPBUGS-25453
OCPBUGS-25453: duplicate failure domains in CMPS
2 parents 0d56a06 + e96d431 commit 7f1cebe

File tree

6 files changed

+121
-6
lines changed

6 files changed

+121
-6
lines changed

pkg/asset/machines/vsphere/machines.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,11 @@ func Machines(clusterID string, config *types.InstallConfig, pool *types.Machine
8383
"machine.openshift.io/cluster-api-machine-type": role,
8484
}
8585

86-
failureDomains = append(failureDomains, machinev1.VSphereFailureDomain{
87-
Name: failureDomain.Name,
88-
})
86+
if !hasFailureDomain(failureDomains, failureDomain.Name) {
87+
failureDomains = append(failureDomains, machinev1.VSphereFailureDomain{
88+
Name: failureDomain.Name,
89+
})
90+
}
8991

9092
osImageForZone := failureDomain.Topology.Template
9193
if failureDomain.Topology.Template == "" {
@@ -255,3 +257,12 @@ func provider(clusterID string, vcenter *vsphere.VCenter, failureDomain vsphere.
255257
// ConfigMasters sets the PublicIP flag and assigns a set of load balancers to the given machines
256258
func ConfigMasters(machines []machineapi.Machine, clusterID string) {
257259
}
260+
261+
func hasFailureDomain(failureDomains []machinev1.VSphereFailureDomain, failureDomain string) bool {
262+
for _, fd := range failureDomains {
263+
if fd.Name == failureDomain {
264+
return true
265+
}
266+
}
267+
return false
268+
}

pkg/asset/machines/vsphere/machines_test.go

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,26 @@ var machinePoolReducedZones = types.MachinePool{
215215
Architecture: types.ArchitectureAMD64,
216216
}
217217

218+
var machinePoolSingleZones = types.MachinePool{
219+
Name: "master",
220+
Replicas: &machinePoolReplicas,
221+
Platform: types.MachinePoolPlatform{
222+
VSphere: &vsphere.MachinePool{
223+
NumCPUs: 4,
224+
NumCoresPerSocket: 2,
225+
MemoryMiB: 16384,
226+
OSDisk: vsphere.OSDisk{
227+
DiskSizeGB: 60,
228+
},
229+
Zones: []string{
230+
"deployzone-us-east-1a",
231+
},
232+
},
233+
},
234+
Hyperthreading: "true",
235+
Architecture: types.ArchitectureAMD64,
236+
}
237+
218238
var machinePoolUndefinedZones = types.MachinePool{
219239
Name: "master",
220240
Replicas: &machinePoolReplicas,
@@ -344,6 +364,21 @@ func TestConfigMasters(t *testing.T) {
344364
},
345365
},
346366
},
367+
{
368+
testCase: "all masters in single zone / pool",
369+
machinePool: &machinePoolSingleZones,
370+
maxAllowedWorkspaceMatches: 3,
371+
installConfig: installConfig,
372+
workspaces: []machineapi.Workspace{
373+
{
374+
Server: "your.vcenter.example.com",
375+
Datacenter: "dc1",
376+
Folder: "/dc1/vm/folder1",
377+
Datastore: "/dc1/datastore/datastore1",
378+
ResourcePool: "/dc1/host/c1/Resources/rp1",
379+
},
380+
},
381+
},
347382
{
348383
testCase: "full path to cluster resource pool when no pool provided via placement constraint",
349384
machinePool: &machinePoolValidZones,
@@ -378,7 +413,7 @@ func TestConfigMasters(t *testing.T) {
378413

379414
for _, tc := range testCases {
380415
t.Run(tc.testCase, func(t *testing.T) {
381-
machines, _, err := Machines(clusterID, tc.installConfig, tc.machinePool, "", "", "")
416+
machines, cpms, err := Machines(clusterID, tc.installConfig, tc.machinePool, "", "", "")
382417
assertOnUnexpectedErrorState(t, tc.expectedError, err)
383418

384419
if len(tc.workspaces) > 0 {
@@ -404,6 +439,14 @@ func TestConfigMasters(t *testing.T) {
404439
t.Errorf("machine workspace was enountered too few times[min: %d]", tc.minAllowedWorkspaceMatches)
405440
}
406441
}
442+
443+
if cpms != nil {
444+
// Make sure FDs equal same quantity as config
445+
fds := cpms.Spec.Template.OpenShiftMachineV1Beta1Machine.FailureDomains
446+
if len(fds.VSphere) != len(tc.workspaces) {
447+
t.Errorf("machine workspace count %d does not equal number of failure domains [count: %d] in CPMS", len(tc.workspaces), len(fds.VSphere))
448+
}
449+
}
407450
}
408451
})
409452
}

pkg/types/vsphere/validation/machinepool.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55

66
"k8s.io/apimachinery/pkg/util/validation/field"
7+
"k8s.io/utils/strings/slices"
78

89
"github.com/openshift/installer/pkg/types"
910
"github.com/openshift/installer/pkg/types/vsphere"
@@ -51,14 +52,24 @@ func ValidateMachinePool(platform *vsphere.Platform, machinePool *types.MachineP
5152
}
5253

5354
if len(vspherePool.Zones) > 0 {
55+
var zoneRefs []string
5456
if len(platform.FailureDomains) == 0 {
5557
return append(allErrs, field.Required(fldPath.Child("zones"), "failureDomains must be defined if zones are defined"))
5658
}
57-
for _, zone := range vspherePool.Zones {
59+
for index, zone := range vspherePool.Zones {
5860
err := validate.ClusterName1035(zone)
5961
if err != nil {
6062
allErrs = append(allErrs, field.Invalid(fldPath.Child("zones"), vspherePool.Zones, err.Error()))
6163
}
64+
65+
// This checks to make sure ref is not duplicated
66+
if slices.Contains(zoneRefs, zone) {
67+
allErrs = append(allErrs, field.Duplicate(fldPath.Child("zones").Index(index), zone))
68+
} else {
69+
zoneRefs = append(zoneRefs, zone)
70+
}
71+
72+
// Verify zone references a valid failure domain
6273
zoneDefined := false
6374
for _, failureDomain := range platform.FailureDomains {
6475
if failureDomain.Name == zone {

pkg/types/vsphere/validation/machinepool_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,22 @@ func TestValidateMachinePool(t *testing.T) {
154154
expectedZones: &[]string{"test-east-1a", "test-east-2a"},
155155
expectedErrMsg: "",
156156
},
157+
{
158+
name: "multi-zone duplicate zones defined for control plane pool",
159+
platform: validPlatform(),
160+
pool: &types.MachinePool{
161+
Name: types.MachinePoolControlPlaneRoleName,
162+
Platform: types.MachinePoolPlatform{
163+
VSphere: &vsphere.MachinePool{
164+
Zones: []string{
165+
"test-east-1a",
166+
"test-east-1a",
167+
},
168+
},
169+
},
170+
},
171+
expectedErrMsg: `test-path.zones\[1]: Duplicate value: "test-east-1a"`,
172+
},
157173
{
158174
name: "multi-zone no zones defined for compute pool",
159175
platform: validPlatform(),
@@ -166,6 +182,22 @@ func TestValidateMachinePool(t *testing.T) {
166182
expectedZones: &[]string{"test-east-1a", "test-east-2a"},
167183
expectedErrMsg: "",
168184
},
185+
{
186+
name: "multi-zone duplicate zones defined for compute pool",
187+
platform: validPlatform(),
188+
pool: &types.MachinePool{
189+
Name: types.MachinePoolComputeRoleName,
190+
Platform: types.MachinePoolPlatform{
191+
VSphere: &vsphere.MachinePool{
192+
Zones: []string{
193+
"test-east-1a",
194+
"test-east-1a",
195+
},
196+
},
197+
},
198+
},
199+
expectedErrMsg: `test-path.zones\[1]: Duplicate value: "test-east-1a"`,
200+
},
169201
{
170202
name: "multi-zone undefined zone",
171203
platform: validPlatform(),

pkg/types/vsphere/validation/platform.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/sirupsen/logrus"
1010
"k8s.io/apimachinery/pkg/util/sets"
1111
"k8s.io/apimachinery/pkg/util/validation/field"
12+
"k8s.io/utils/strings/slices"
1213

1314
configv1 "github.com/openshift/api/config/v1"
1415
"github.com/openshift/installer/pkg/types"
@@ -115,12 +116,20 @@ func validateVCenters(p *vsphere.Platform, fldPath *field.Path) field.ErrorList
115116
}
116117

117118
func validateFailureDomains(p *vsphere.Platform, fldPath *field.Path, isLegacyUpi bool) field.ErrorList {
119+
var fdNames []string
118120
allErrs := field.ErrorList{}
119121
topologyFld := fldPath.Child("topology")
120122
var associatedVCenter *vsphere.VCenter
121-
for _, failureDomain := range p.FailureDomains {
123+
for index, failureDomain := range p.FailureDomains {
122124
if len(failureDomain.Name) == 0 {
123125
allErrs = append(allErrs, field.Required(fldPath.Child("name"), "must specify the name"))
126+
} else {
127+
// Check and make sure the name is not duplicated w/ any other Failure Domains
128+
if slices.Contains(fdNames, failureDomain.Name) {
129+
allErrs = append(allErrs, field.Duplicate(fldPath.Child("name").Index(index), failureDomain.Name))
130+
} else {
131+
fdNames = append(fdNames, failureDomain.Name)
132+
}
124133
}
125134
if len(failureDomain.Server) > 0 {
126135
for i, vcenter := range p.VCenters {

pkg/types/vsphere/validation/platform_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,15 @@ func TestValidatePlatform(t *testing.T) {
319319
}(),
320320
expectedError: `^test-path\.failureDomains\.name: Required value: must specify the name`,
321321
},
322+
{
323+
name: "Multi-zone platform failureDomain duplicate names",
324+
platform: func() *vsphere.Platform {
325+
p := validPlatform()
326+
p.FailureDomains[1].Name = p.FailureDomains[0].Name
327+
return p
328+
}(),
329+
expectedError: `test-path\.failureDomains\.name\[1\]: Duplicate value: "test-east-1a"`,
330+
},
322331
{
323332
name: "Multi-zone platform failureDomain zone missing tag category",
324333
platform: func() *vsphere.Platform {

0 commit comments

Comments
 (0)