Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create region-zone-sysType hierarchy #9330

Draft
wants to merge 1 commit into
base: release-4.14
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions pkg/asset/cluster/tfvars.go
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,16 @@ func (t *TerraformVariables) Generate(parents asset.Parents) error {

err = powervsconfig.ValidatePERAvailability(client, installConfig.Config)
transitGatewayEnabled := err == nil
cpStanza := installConfig.Config.ControlPlane
if cpStanza == nil || cpStanza.Platform.PowerVS == nil || cpStanza.Platform.PowerVS.SysType == "" {
sysTypes, err := powervs.AvailableSysTypes(installConfig.Config.PowerVS.Region, installConfig.Config.PowerVS.Zone)
if err != nil {
return err
}
for i := range masters {
masterConfigs[i].SystemType = sysTypes[0]
}
}

serviceInstanceCRN, err := client.ServiceInstanceIDToCRN(ctx, installConfig.Config.PowerVS.ServiceInstanceID)
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions pkg/asset/installconfig/platformprovisioncheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,11 @@ func (a *PlatformProvisionCheck) Generate(dependencies asset.Parents) error {
return err
}

err = powervsconfig.ValidateSystemTypeForZone(client, ic.Config)
if err != nil {
return err
}

err = powervsconfig.ValidateServiceInstance(client, ic.Config)
if err != nil {
return err
Expand Down
6 changes: 5 additions & 1 deletion pkg/asset/installconfig/powervs/regions.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ func IsKnownRegion(region string) bool {
}

func knownZones(region string) []string {
return powervs.Regions[region].Zones
zones := make([]string, 0, len(powervs.Regions[region].Zones))
for z := range powervs.Regions[region].Zones {
zones = append(zones, z)
}
return zones
}

// IsKnownZone return true is a specified zone is Known to the installer.
Expand Down
25 changes: 24 additions & 1 deletion pkg/asset/installconfig/powervs/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,30 @@ func ValidateResourceGroup(client API, ic *types.InstallConfig) error {
return nil
}

// ValidateServiceInstance validates the service instance in our install config.
// ValidateSystemTypeForZone checks if the specified sysType is available in the target zone.
func ValidateSystemTypeForZone(client API, ic *types.InstallConfig) error {
if ic.ControlPlane == nil || ic.ControlPlane.Platform.PowerVS == nil || ic.ControlPlane.Platform.PowerVS.SysType == "" {
return nil
}
availableOnes, err := powervstypes.AvailableSysTypes(ic.PowerVS.Region, ic.PowerVS.Zone)
if err != nil {
return fmt.Errorf("failed to obtain available SysTypes for: %s", ic.PowerVS.Zone)
}
requested := ic.ControlPlane.Platform.PowerVS.SysType
found := false
for i := range availableOnes {
if requested == availableOnes[i] {
found = true
break
}
}
if found {
return nil
}
return fmt.Errorf("%s is not available in: %s", requested, ic.PowerVS.Zone)
}

// ValidateServiceInstance validates the optional service instance GUID in our install config.
func ValidateServiceInstance(client API, ic *types.InstallConfig) error {
ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Minute)
defer cancel()
Expand Down
140 changes: 139 additions & 1 deletion pkg/asset/installconfig/powervs/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ var (
validPrivateSubnetUSSouth2ID,
}
validUserID = "[email protected]"
validZone = "dal10"
validZone = "dal12"

existingDNSRecordsResponse = []powervs.DNSRecordResponse{
{
Expand Down Expand Up @@ -134,6 +134,10 @@ var (
"disaster-recover-site": true,
"power-vpn-connections": false,
}
defaultSysType = "s922"
newSysType = "s1022"
invalidZone = "dal11"
validServiceInstanceGUID = ""
)

func validInstallConfig() *types.InstallConfig {
Expand Down Expand Up @@ -734,6 +738,140 @@ func TestValidatePERAvailability(t *testing.T) {
}
}

func TestValidateSystemTypeForZone(t *testing.T) {
cases := []struct {
name string
edits editFunctions
errorMsg string
}{
{
name: "Unknown Zone specified",
edits: editFunctions{
func(ic *types.InstallConfig) {
ic.Platform.PowerVS.Zone = invalidZone
ic.ControlPlane.Platform.PowerVS = validMachinePool()
ic.ControlPlane.Platform.PowerVS.SysType = defaultSysType
},
},
errorMsg: fmt.Sprintf("failed to obtain available SysTypes for: %s", invalidZone),
},
{
name: "No Platform block",
edits: editFunctions{
func(ic *types.InstallConfig) {
ic.ControlPlane.Platform.PowerVS = nil
},
},
errorMsg: "",
},
{
name: "Structure present, but no SysType specified",
edits: editFunctions{
func(ic *types.InstallConfig) {
ic.ControlPlane.Platform.PowerVS = validMachinePool()
},
},
errorMsg: "",
},
{
name: "Unavailable SysType specified for dal12 zone",
edits: editFunctions{
func(ic *types.InstallConfig) {
ic.Platform.PowerVS.Region = validRegion
ic.Platform.PowerVS.Zone = validZone
ic.ControlPlane.Platform.PowerVS = validMachinePool()
ic.ControlPlane.Platform.PowerVS.SysType = newSysType
},
},
errorMsg: fmt.Sprintf("%s is not available in: %s", newSysType, validZone),
},
{
name: "Good Zone/SysType combo specified",
edits: editFunctions{
func(ic *types.InstallConfig) {
ic.Platform.PowerVS.Region = validRegion
ic.Platform.PowerVS.Zone = validZone
ic.ControlPlane.Platform.PowerVS = validMachinePool()
ic.ControlPlane.Platform.PowerVS.SysType = defaultSysType
},
},
errorMsg: "",
},
}
setMockEnvVars()

mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()

powervsClient := mock.NewMockAPI(mockCtrl)

// Run tests
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
editedInstallConfig := validInstallConfig()
for _, edit := range tc.edits {
edit(editedInstallConfig)
}

aggregatedErrors := powervs.ValidateSystemTypeForZone(powervsClient, editedInstallConfig)
if tc.errorMsg != "" {
assert.Regexp(t, tc.errorMsg, aggregatedErrors)
} else {
assert.NoError(t, aggregatedErrors)
}
})
}
}

func TestValidateServiceInstance(t *testing.T) {
cases := []struct {
name string
edits editFunctions
errorMsg string
}{
{
name: "valid install config",
edits: editFunctions{},
errorMsg: "",
},
{
name: "invalid install config",
edits: editFunctions{
func(ic *types.InstallConfig) {
ic.Platform.PowerVS.ServiceInstanceGUID = "invalid-uuid"
},
},
errorMsg: "platform:powervs:serviceInstanceGUID has an invalid guid",
},
}
setMockEnvVars()

mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()

powervsClient := mock.NewMockAPI(mockCtrl)

// FIX: Unexpected call to *mock.MockAPI.ListServiceInstances([context.TODO.WithDeadline(2023-12-02 08:38:15.542340268 -0600 CST m=+300.012357408 [4m59.999979046s])]) at validation.go:289 because: there are no expected calls of the method "ListServiceInstances" for that receiver
powervsClient.EXPECT().ListServiceInstances(gomock.Any()).AnyTimes()

// Run tests
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
editedInstallConfig := validInstallConfig()
for _, edit := range tc.edits {
edit(editedInstallConfig)
}

aggregatedErrors := powervs.ValidateServiceInstance(powervsClient, editedInstallConfig)
if tc.errorMsg != "" {
assert.Regexp(t, tc.errorMsg, aggregatedErrors)
} else {
assert.NoError(t, aggregatedErrors)
}
})
}
}

func setMockEnvVars() {
os.Setenv("POWERVS_AUTH_FILEPATH", "./tmp/powervs/config.json")
os.Setenv("IBMID", "foo")
Expand Down
2 changes: 1 addition & 1 deletion pkg/asset/machines/master.go
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ func (m *Master) Generate(dependencies asset.Parents) error {
}
vsphere.ConfigMasters(machines, clusterID.InfraID)
case powervstypes.Name:
mpool := defaultPowerVSMachinePoolPlatform()
mpool := defaultPowerVSMachinePoolPlatform(ic)
mpool.Set(ic.Platform.PowerVS.DefaultMachinePlatform)
mpool.Set(pool.Platform.PowerVS)
// Only the service instance is guaranteed to exist and be passed via the install config
Expand Down
20 changes: 17 additions & 3 deletions pkg/asset/machines/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,27 @@ func defaultVSphereMachinePoolPlatform() vspheretypes.MachinePool {
}
}

func defaultPowerVSMachinePoolPlatform() powervstypes.MachinePool {
return powervstypes.MachinePool{
func defaultPowerVSMachinePoolPlatform(ic *types.InstallConfig) powervstypes.MachinePool {
var (
defaultMp powervstypes.MachinePool
sysTypes []string
err error
)

defaultMp = powervstypes.MachinePool{
MemoryGiB: 32,
Processors: intstr.FromString("0.5"),
ProcType: machinev1.PowerVSProcessorTypeShared,
SysType: "s922",
}
sysTypes, err = powervstypes.AvailableSysTypes(ic.PowerVS.Region, ic.PowerVS.Zone)
if err == nil {
defaultMp.SysType = sysTypes[0]
} else {
logrus.Warnf("For given zone %v, AvailableSysTypes returns %v", ic.PowerVS.Zone, err)
}

return defaultMp
}

func defaultNutanixMachinePoolPlatform() nutanixtypes.MachinePool {
Expand Down Expand Up @@ -653,7 +667,7 @@ func (w *Worker) Generate(dependencies asset.Parents) error {
machineSets = append(machineSets, set)
}
case powervstypes.Name:
mpool := defaultPowerVSMachinePoolPlatform()
mpool := defaultPowerVSMachinePoolPlatform(ic)
mpool.Set(ic.Platform.PowerVS.DefaultMachinePlatform)
mpool.Set(pool.Platform.PowerVS)
pool.Platform.PowerVS = &mpool
Expand Down
Loading