diff --git a/pkg/asset/cluster/openstack/openstack.go b/pkg/asset/cluster/openstack/openstack.go index 72e35ddf150..1394c2adb4d 100644 --- a/pkg/asset/cluster/openstack/openstack.go +++ b/pkg/asset/cluster/openstack/openstack.go @@ -40,8 +40,8 @@ func PreTerraform(ctx context.Context, tfvarsFile *asset.File, installConfig *in // upload the corresponding image to Glance if rhcosImage contains a // URL. If rhcosImage contains a name, then that points to an existing // Glance image. - if imageName, isURL := rhcos.GenerateOpenStackImageName(string(*rhcosImage), clusterID.InfraID); isURL { - if err := preprovision.UploadBaseImage(ctx, installConfig.Config.Platform.OpenStack.Cloud, string(*rhcosImage), imageName, clusterID.InfraID, installConfig.Config.Platform.OpenStack.ClusterOSImageProperties); err != nil { + if imageName, isURL := rhcos.GenerateOpenStackImageName(rhcosImage.ControlPlane, clusterID.InfraID); isURL { + if err := preprovision.UploadBaseImage(ctx, installConfig.Config.Platform.OpenStack.Cloud, rhcosImage.ControlPlane, imageName, clusterID.InfraID, installConfig.Config.Platform.OpenStack.ClusterOSImageProperties); err != nil { return err } } diff --git a/pkg/asset/cluster/tfvars/tfvars.go b/pkg/asset/cluster/tfvars/tfvars.go index c7fd2e3c4ba..71c47239984 100644 --- a/pkg/asset/cluster/tfvars/tfvars.go +++ b/pkg/asset/cluster/tfvars/tfvars.go @@ -274,7 +274,7 @@ func (t *TerraformVariables) Generate(ctx context.Context, parents asset.Parents for i, m := range workers { workerConfigs[i] = m.Spec.Template.Spec.ProviderSpec.Value.Object.(*machinev1beta1.AWSMachineProviderConfig) //nolint:errcheck // legacy, pre-linter } - osImage := strings.SplitN(string(*rhcosImage), ",", 2) + osImage := strings.SplitN(rhcosImage.ControlPlane, ",", 2) osImageID := osImage[0] osImageRegion := installConfig.Config.AWS.Region if len(osImage) == 2 { @@ -416,7 +416,7 @@ func (t *TerraformVariables) Generate(ctx context.Context, parents asset.Parents BaseDomainResourceGroupName: installConfig.Config.Azure.BaseDomainResourceGroupName, MasterConfigs: masterConfigs, WorkerConfigs: workerConfigs, - ImageURL: string(*rhcosImage), + ImageURL: rhcosImage.ControlPlane, ImageRelease: rhcosRelease.GetAzureReleaseVersion(), PreexistingNetwork: preexistingnetwork, Publish: installConfig.Config.Publish, @@ -730,7 +730,7 @@ func (t *TerraformVariables) Generate(ctx context.Context, parents asset.Parents CISInstanceCRN: cisCRN, DNSInstanceID: dnsID, EndpointsJSONFile: endpointsJSONFile, - ImageURL: string(*rhcosImage), + ImageURL: rhcosImage.ControlPlane, MasterConfigs: masterConfigs, MasterDedicatedHosts: masterDedicatedHosts, NetworkResourceGroupName: installConfig.Config.Platform.IBMCloud.NetworkResourceGroupName, @@ -756,7 +756,7 @@ func (t *TerraformVariables) Generate(ctx context.Context, parents asset.Parents installConfig, mastersAsset, workersAsset, - string(*rhcosImage), + rhcosImage.ControlPlane, clusterID, bootstrapIgn, ) @@ -828,7 +828,7 @@ func (t *TerraformVariables) Generate(ctx context.Context, parents asset.Parents installConfig.Config.Platform.Ovirt.StorageDomainID, installConfig.Config.Platform.Ovirt.NetworkName, installConfig.Config.Platform.Ovirt.VNICProfileID, - string(*rhcosImage), + rhcosImage.ControlPlane, clusterID.InfraID, masters[0].Spec.ProviderSpec.Value.Object.(*ovirtprovider.OvirtMachineProviderSpec), installConfig.Config.Platform.Ovirt.AffinityGroups, @@ -966,7 +966,7 @@ func (t *TerraformVariables) Generate(ctx context.Context, parents asset.Parents return err } - osImage := strings.SplitN(string(*rhcosImage), "/", 2) + osImage := strings.SplitN(rhcosImage.ControlPlane, "/", 2) data, err = powervstfvars.TFVars( powervstfvars.TFVarsSources{ MasterConfigs: masterConfigs, @@ -1015,7 +1015,7 @@ func (t *TerraformVariables) Generate(ctx context.Context, parents asset.Parents controlPlaneConfigs[i] = c.Spec.ProviderSpec.Value.Object.(*machinev1.NutanixMachineProviderConfig) //nolint:errcheck // legacy, pre-linter } - imgURI := string(*rhcosImage) + imgURI := rhcosImage.ControlPlane if installConfig.Config.Nutanix.ClusterOSImage != "" { imgURI = installConfig.Config.Nutanix.ClusterOSImage } diff --git a/pkg/asset/ignition/bootstrap/common.go b/pkg/asset/ignition/bootstrap/common.go index 70ad2a42d11..31938288bd3 100644 --- a/pkg/asset/ignition/bootstrap/common.go +++ b/pkg/asset/ignition/bootstrap/common.go @@ -337,7 +337,7 @@ func (a *Common) getTemplateData(dependencies asset.Parents, bootstrapInPlace bo EtcdCluster: strings.Join(etcdEndpoints, ","), Proxy: &proxy.Config.Status, Registries: registries, - BootImage: string(*rhcosImage), + BootImage: rhcosImage.ControlPlane, PlatformData: platformData, ClusterProfile: clusterProfile, BootstrapInPlace: bootstrapInPlaceConfig, diff --git a/pkg/asset/machines/clusterapi.go b/pkg/asset/machines/clusterapi.go index 44b21bc36f5..c65bbe68836 100644 --- a/pkg/asset/machines/clusterapi.go +++ b/pkg/asset/machines/clusterapi.go @@ -117,7 +117,7 @@ func (c *ClusterAPI) Generate(ctx context.Context, dependencies asset.Parents) e mpool := defaultAWSMachinePoolPlatform("master") - osImage := strings.SplitN(string(*rhcosImage), ",", 2) + osImage := strings.SplitN(rhcosImage.ControlPlane, ",", 2) osImageID := osImage[0] if len(osImage) == 2 { osImageID = "" // the AMI will be generated later on @@ -298,7 +298,7 @@ func (c *ClusterAPI) Generate(ctx context.Context, dependencies asset.Parents) e installConfig, clusterID.InfraID, &pool, - string(*rhcosImage), + rhcosImage.ControlPlane, ) if err != nil { return fmt.Errorf("failed to create master machine objects %w", err) @@ -311,7 +311,7 @@ func (c *ClusterAPI) Generate(ctx context.Context, dependencies asset.Parents) e installConfig, clusterID.InfraID, &pool, - string(*rhcosImage), + rhcosImage.ControlPlane, ) if err != nil { return fmt.Errorf("failed to create bootstrap machine objects %w", err) @@ -394,7 +394,7 @@ func (c *ClusterAPI) Generate(ctx context.Context, dependencies asset.Parents) e mpool.Set(pool.Platform.OpenStack) pool.Platform.OpenStack = &mpool - imageName, _ := rhcosutils.GenerateOpenStackImageName(string(*rhcosImage), clusterID.InfraID) + imageName, _ := rhcosutils.GenerateOpenStackImageName(rhcosImage.ControlPlane, clusterID.InfraID) for _, role := range []string{"master", "bootstrap"} { openStackMachines, err := openstack.GenerateMachines( diff --git a/pkg/asset/machines/master.go b/pkg/asset/machines/master.go index 65d5cebb435..ecdd49ef50c 100644 --- a/pkg/asset/machines/master.go +++ b/pkg/asset/machines/master.go @@ -187,7 +187,7 @@ func (m *Master) Generate(ctx context.Context, dependencies asset.Parents) error mpool := defaultAWSMachinePoolPlatform("master") - osImage := strings.SplitN(string(*rhcosImage), ",", 2) + osImage := strings.SplitN(rhcosImage.ControlPlane, ",", 2) osImageID := osImage[0] if len(osImage) == 2 { osImageID = "" // the AMI will be generated later on @@ -257,7 +257,7 @@ func (m *Master) Generate(ctx context.Context, dependencies asset.Parents) error mpool.Zones = azs } pool.Platform.GCP = &mpool - machines, controlPlaneMachineSet, err = gcp.Machines(clusterID.InfraID, ic, &pool, string(*rhcosImage), "master", masterUserDataSecretName) + machines, controlPlaneMachineSet, err = gcp.Machines(clusterID.InfraID, ic, &pool, rhcosImage.ControlPlane, "master", masterUserDataSecretName) if err != nil { return errors.Wrap(err, "failed to create master machine objects") } @@ -319,7 +319,7 @@ func (m *Master) Generate(ctx context.Context, dependencies asset.Parents) error mpool.Set(pool.Platform.OpenStack) pool.Platform.OpenStack = &mpool - imageName, _ := rhcosutils.GenerateOpenStackImageName(string(*rhcosImage), clusterID.InfraID) + imageName, _ := rhcosutils.GenerateOpenStackImageName(rhcosImage.ControlPlane, clusterID.InfraID) machines, controlPlaneMachineSet, err = openstack.Machines(ctx, clusterID.InfraID, ic, &pool, imageName, "master", masterUserDataSecretName) if err != nil { @@ -378,7 +378,7 @@ func (m *Master) Generate(ctx context.Context, dependencies asset.Parents) error return err } useImageGallery := installConfig.Azure.CloudName != azuretypes.StackCloud - machines, controlPlaneMachineSet, err = azure.Machines(clusterID.InfraID, ic, &pool, string(*rhcosImage), "master", masterUserDataSecretName, capabilities, useImageGallery) + machines, controlPlaneMachineSet, err = azure.Machines(clusterID.InfraID, ic, &pool, rhcosImage.ControlPlane, "master", masterUserDataSecretName, capabilities, useImageGallery) if err != nil { return errors.Wrap(err, "failed to create master machine objects") } @@ -430,7 +430,7 @@ func (m *Master) Generate(ctx context.Context, dependencies asset.Parents) error mpool.Set(pool.Platform.Ovirt) pool.Platform.Ovirt = &mpool - imageName, _ := rhcosutils.GenerateOpenStackImageName(string(*rhcosImage), clusterID.InfraID) + imageName, _ := rhcosutils.GenerateOpenStackImageName(rhcosImage.ControlPlane, clusterID.InfraID) machines, err = ovirt.Machines(clusterID.InfraID, ic, &pool, imageName, "master", masterUserDataSecretName) if err != nil { diff --git a/pkg/asset/machines/master_test.go b/pkg/asset/machines/master_test.go index 898fd552e9c..3bd96328123 100644 --- a/pkg/asset/machines/master_test.go +++ b/pkg/asset/machines/master_test.go @@ -164,7 +164,7 @@ spec: }, }, }), - (*rhcos.Image)(pointer.StringPtr("test-image")), + rhcos.MakeAsset("test-image"), (*rhcos.Release)(pointer.StringPtr("412.86.202208101040-0")), &machine.Master{ File: &asset.File{ @@ -223,7 +223,7 @@ func TestControlPlaneIsNotModified(t *testing.T) { InfraID: "test-infra-id", }, installConfig, - (*rhcos.Image)(pointer.StringPtr("test-image")), + rhcos.MakeAsset("test-image"), (*rhcos.Release)(pointer.StringPtr("412.86.202208101040-0")), &machine.Master{ File: &asset.File{ @@ -292,7 +292,7 @@ func TestBaremetalGeneratedAssetFiles(t *testing.T) { InfraID: "test-infra-id", }, installConfig, - (*rhcos.Image)(pointer.StringPtr("test-image")), + rhcos.MakeAsset("test-image"), (*rhcos.Release)(pointer.StringPtr("412.86.202208101040-0")), &machine.Master{ File: &asset.File{ diff --git a/pkg/asset/machines/worker.go b/pkg/asset/machines/worker.go index ba9728709db..f985e4dde78 100644 --- a/pkg/asset/machines/worker.go +++ b/pkg/asset/machines/worker.go @@ -358,7 +358,7 @@ func (w *Worker) Generate(ctx context.Context, dependencies asset.Parents) error } mpool := defaultAWSMachinePoolPlatform(pool.Name) - osImage := strings.SplitN(string(*rhcosImage), ",", 2) + osImage := strings.SplitN(rhcosImage.Compute, ",", 2) osImageID := osImage[0] if len(osImage) == 2 { osImageID = "" // the AMI will be generated later on @@ -399,7 +399,11 @@ func (w *Worker) Generate(ctx context.Context, dependencies asset.Parents) error } if mpool.InstanceType == "" { - instanceTypes := awsdefaults.InstanceTypes(installConfig.Config.Platform.AWS.Region, installConfig.Config.ControlPlane.Architecture, configv1.HighlyAvailableTopologyMode) + arch := installConfig.Config.ControlPlane.Architecture + if len(installConfig.Config.Compute) > 0 { + arch = installConfig.Config.Compute[0].Architecture + } + instanceTypes := awsdefaults.InstanceTypes(installConfig.Config.Platform.AWS.Region, arch, configv1.HighlyAvailableTopologyMode) switch pool.Name { case types.MachinePoolEdgeRoleName: ok := awsSetPreferredInstanceByEdgeZone(ctx, instanceTypes, installConfig.AWS, zones) @@ -488,7 +492,7 @@ func (w *Worker) Generate(ctx context.Context, dependencies asset.Parents) error } useImageGallery := ic.Platform.Azure.CloudName != azuretypes.StackCloud - sets, err := azure.MachineSets(clusterID.InfraID, ic, &pool, string(*rhcosImage), "worker", workerUserDataSecretName, capabilities, useImageGallery) + sets, err := azure.MachineSets(clusterID.InfraID, ic, &pool, rhcosImage.Compute, "worker", workerUserDataSecretName, capabilities, useImageGallery) if err != nil { return errors.Wrap(err, "failed to create worker machine objects") } @@ -523,7 +527,7 @@ func (w *Worker) Generate(ctx context.Context, dependencies asset.Parents) error mpool.Zones = azs } pool.Platform.GCP = &mpool - sets, err := gcp.MachineSets(clusterID.InfraID, ic, &pool, string(*rhcosImage), "worker", workerUserDataSecretName) + sets, err := gcp.MachineSets(clusterID.InfraID, ic, &pool, rhcosImage.Compute, "worker", workerUserDataSecretName) if err != nil { return errors.Wrap(err, "failed to create worker machine objects") } @@ -565,7 +569,7 @@ func (w *Worker) Generate(ctx context.Context, dependencies asset.Parents) error mpool.Set(pool.Platform.OpenStack) pool.Platform.OpenStack = &mpool - imageName, _ := rhcosutils.GenerateOpenStackImageName(string(*rhcosImage), clusterID.InfraID) + imageName, _ := rhcosutils.GenerateOpenStackImageName(rhcosImage.Compute, clusterID.InfraID) sets, err := openstack.MachineSets(ctx, clusterID.InfraID, ic, &pool, imageName, "worker", workerUserDataSecretName) if err != nil { @@ -615,7 +619,7 @@ func (w *Worker) Generate(ctx context.Context, dependencies asset.Parents) error mpool.Set(pool.Platform.Ovirt) pool.Platform.Ovirt = &mpool - imageName, _ := rhcosutils.GenerateOpenStackImageName(string(*rhcosImage), clusterID.InfraID) + imageName, _ := rhcosutils.GenerateOpenStackImageName(rhcosImage.Compute, clusterID.InfraID) sets, err := ovirt.MachineSets(clusterID.InfraID, ic, &pool, imageName, "worker", workerUserDataSecretName) if err != nil { diff --git a/pkg/asset/machines/worker_test.go b/pkg/asset/machines/worker_test.go index d3d04e07052..5b764124cb0 100644 --- a/pkg/asset/machines/worker_test.go +++ b/pkg/asset/machines/worker_test.go @@ -160,7 +160,7 @@ spec: }, }, }), - (*rhcos.Image)(pointer.StringPtr("test-image")), + rhcos.MakeAsset("test-image"), (*rhcos.Release)(pointer.StringPtr("412.86.202208101040-0")), &machine.Worker{ File: &asset.File{ @@ -222,7 +222,7 @@ func TestComputeIsNotModified(t *testing.T) { InfraID: "test-infra-id", }, installConfig, - (*rhcos.Image)(pointer.StringPtr("test-image")), + rhcos.MakeAsset("test-image"), (*rhcos.Release)(pointer.StringPtr("412.86.202208101040-0")), &machine.Worker{ File: &asset.File{ diff --git a/pkg/asset/manifests/clusterapi/cluster.go b/pkg/asset/manifests/clusterapi/cluster.go index 85cfacbbe20..33d44bf16b0 100644 --- a/pkg/asset/manifests/clusterapi/cluster.go +++ b/pkg/asset/manifests/clusterapi/cluster.go @@ -135,7 +135,7 @@ func (c *Cluster) Generate(_ context.Context, dependencies asset.Parents) error } case powervstypes.Name: var err error - osImage := strings.SplitN(string(*rhcosImage), "/", 2) + osImage := strings.SplitN(rhcosImage.ControlPlane, "/", 2) out, err = powervs.GenerateClusterAssets(installConfig, clusterID, osImage[0], osImage[1]) if err != nil { return fmt.Errorf("failed to generate PowerVS manifests %w", err) diff --git a/pkg/asset/manifests/openshift.go b/pkg/asset/manifests/openshift.go index 7e4bbe03e96..9870e7c36ac 100644 --- a/pkg/asset/manifests/openshift.go +++ b/pkg/asset/manifests/openshift.go @@ -267,7 +267,7 @@ func (o *Openshift) Generate(ctx context.Context, dependencies asset.Parents) er case baremetaltypes.Name: bmTemplateData := baremetalTemplateData{ Baremetal: installConfig.Config.Platform.BareMetal, - ProvisioningOSDownloadURL: string(*rhcosImage), + ProvisioningOSDownloadURL: rhcosImage.ControlPlane, } assetData["99_baremetal-provisioning-config.yaml"] = applyTemplateData(baremetalConfig.Files()[0].Data, bmTemplateData) } diff --git a/pkg/asset/rhcos/bootstrap_image.go b/pkg/asset/rhcos/bootstrap_image.go index 98e1433429d..10d1428cdd6 100644 --- a/pkg/asset/rhcos/bootstrap_image.go +++ b/pkg/asset/rhcos/bootstrap_image.go @@ -75,7 +75,7 @@ func (i *BootstrapImage) Generate(ctx context.Context, p asset.Parents) error { return fmt.Errorf("%s: No qemu build found", st.FormatPrefix(archName)) default: // other platforms use the same image for all nodes - *i = BootstrapImage(string(*rhcosImage)) + *i = BootstrapImage(rhcosImage.ControlPlane) return nil } } diff --git a/pkg/asset/rhcos/image.go b/pkg/asset/rhcos/image.go index ff49894a4c2..f14b55efe7b 100644 --- a/pkg/asset/rhcos/image.go +++ b/pkg/asset/rhcos/image.go @@ -32,7 +32,10 @@ import ( // Image is location of RHCOS image. // This stores the location of the image based on the platform. // eg. on AWS this contains ami-id, on Livirt this can be the URI for QEMU image etc. -type Image string +type Image struct { + ControlPlane string + Compute string +} var _ asset.Asset = (*Image)(nil) @@ -52,27 +55,35 @@ func (i *Image) Dependencies() []asset.Asset { func (i *Image) Generate(ctx context.Context, p asset.Parents) error { if oi, ok := os.LookupEnv("OPENSHIFT_INSTALL_OS_IMAGE_OVERRIDE"); ok && oi != "" { logrus.Warn("Found override for OS Image. Please be warned, this is not advised") - *i = Image(oi) + *i = *MakeAsset(oi) return nil } ic := &installconfig.InstallConfig{} p.Get(ic) config := ic.Config - osimage, err := osImage(ctx, config) + osimageControlPlane, err := osImage(ctx, config, config.ControlPlane.Architecture) + if err != nil { + return err + } + arch := config.ControlPlane.Architecture + if len(config.Compute) > 0 { + arch = config.Compute[0].Architecture + } + osimageCompute, err := osImage(ctx, config, arch) if err != nil { return err } - *i = Image(osimage) + *i = Image{osimageControlPlane, osimageCompute} return nil } //nolint:gocyclo -func osImage(ctx context.Context, config *types.InstallConfig) (string, error) { +func osImage(ctx context.Context, config *types.InstallConfig, nodeArch types.Architecture) (string, error) { ctx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() - archName := arch.RpmArch(string(config.ControlPlane.Architecture)) + archName := arch.RpmArch(string(nodeArch)) st, err := rhcos.FetchCoreOSBuild(ctx) if err != nil { @@ -88,7 +99,7 @@ func osImage(ctx context.Context, config *types.InstallConfig) (string, error) { return config.Platform.AWS.AMIID, nil } region := config.Platform.AWS.Region - if !rhcos.AMIRegions(config.ControlPlane.Architecture).Has(region) { + if !rhcos.AMIRegions(nodeArch).Has(region) { const globalResourceRegion = "us-east-1" logrus.Debugf("No AMI found in %s. Using AMI from %s.", region, globalResourceRegion) region = globalResourceRegion @@ -155,7 +166,6 @@ func osImage(ctx context.Context, config *types.InstallConfig) (string, error) { // FindArtifactURL just create the URL here. artifact := a.Formats["ova"].Disk u, err := url.Parse(artifact.Location) - if err != nil { return "", err } @@ -212,3 +222,11 @@ func osImage(ctx context.Context, config *types.InstallConfig) (string, error) { return "", fmt.Errorf("invalid platform %v", config.Platform.Name()) } } + +// MakeAsset returns an Image asset with the given os image. +func MakeAsset(osImage string) *Image { + return &Image{ + ControlPlane: osImage, + Compute: osImage, + } +} diff --git a/pkg/infrastructure/aws/clusterapi/ami.go b/pkg/infrastructure/aws/clusterapi/ami.go index 18f945e2edc..f2cacdc5915 100644 --- a/pkg/infrastructure/aws/clusterapi/ami.go +++ b/pkg/infrastructure/aws/clusterapi/ami.go @@ -15,7 +15,7 @@ import ( // copyAMIToRegion copies the AMI to the region configured in the installConfig if needed. func copyAMIToRegion(ctx context.Context, installConfig *installconfig.InstallConfig, infraID string, rhcosImage *rhcos.Image) (string, error) { - osImage := strings.SplitN(string(*rhcosImage), ",", 2) + osImage := strings.SplitN(rhcosImage.ControlPlane, ",", 2) amiID, amiRegion := osImage[0], osImage[1] logrus.Infof("Copying AMI %s to region %s", amiID, installConfig.AWS.Region) diff --git a/pkg/infrastructure/nutanix/clusterapi/clusterapi.go b/pkg/infrastructure/nutanix/clusterapi/clusterapi.go index a10c2debe52..0de60ae899e 100644 --- a/pkg/infrastructure/nutanix/clusterapi/clusterapi.go +++ b/pkg/infrastructure/nutanix/clusterapi/clusterapi.go @@ -78,7 +78,7 @@ func (p Provider) PreProvision(ctx context.Context, in infracapi.PreProvisionInp // upload the rhcos image. imgName := nutanixtypes.RHCOSImageName(in.InfraID) - imgURI := string(*in.RhcosImage) + imgURI := in.RhcosImage.ControlPlane imgReq := &nutanixclientv3.ImageIntentInput{} imgSpec := &nutanixclientv3.Image{ Name: &imgName, diff --git a/pkg/infrastructure/openstack/clusterapi/clusterapi.go b/pkg/infrastructure/openstack/clusterapi/clusterapi.go index 4dfde861f98..05bc195e9fc 100644 --- a/pkg/infrastructure/openstack/clusterapi/clusterapi.go +++ b/pkg/infrastructure/openstack/clusterapi/clusterapi.go @@ -43,7 +43,7 @@ func (p Provider) PreProvision(ctx context.Context, in clusterapi.PreProvisionIn var ( infraID = in.InfraID installConfig = in.InstallConfig - rhcosImage = string(*in.RhcosImage) + rhcosImage = in.RhcosImage.ControlPlane manifestsAsset = in.ManifestsAsset machineManifests = in.MachineManifests workersAsset = in.WorkersAsset diff --git a/pkg/infrastructure/vsphere/clusterapi/clusterapi.go b/pkg/infrastructure/vsphere/clusterapi/clusterapi.go index b30a11b1815..a02521dff67 100644 --- a/pkg/infrastructure/vsphere/clusterapi/clusterapi.go +++ b/pkg/infrastructure/vsphere/clusterapi/clusterapi.go @@ -92,7 +92,7 @@ func (p Provider) PreProvision(ctx context.Context, in clusterapi.PreProvisionIn clusterID := &installconfig.ClusterID{InfraID: in.InfraID} var tagID string - cachedImage, err := cache.DownloadImageFile(string(*in.RhcosImage), cache.InstallerApplicationName) + cachedImage, err := cache.DownloadImageFile(in.RhcosImage.ControlPlane, cache.InstallerApplicationName) if err != nil { return fmt.Errorf("failed to use cached vsphere image: %w", err) } diff --git a/pkg/types/installconfig.go b/pkg/types/installconfig.go index 1bf870c87e2..fabaa8de9fc 100644 --- a/pkg/types/installconfig.go +++ b/pkg/types/installconfig.go @@ -578,6 +578,16 @@ func ClusterAPIFeatureGateEnabled(platform string, fgs featuregates.FeatureGate) } } +// MultiArchFeatureGateEnabled checks whether feature gate enabling multi-arch clusters is enabled. +func MultiArchFeatureGateEnabled(platform string, fgs featuregates.FeatureGate) bool { + switch platform { + case aws.Name: + return fgs.Enabled(features.FeatureGateMultiArchInstallAWS) + default: + return false + } +} + // PublicAPI indicates whether the API load balancer should be public // by inspecting the cluster and operator publishing strategies. func (c *InstallConfig) PublicAPI() bool { diff --git a/pkg/types/validation/installconfig.go b/pkg/types/validation/installconfig.go index c885871340f..387122b2d81 100644 --- a/pkg/types/validation/installconfig.go +++ b/pkg/types/validation/installconfig.go @@ -124,7 +124,8 @@ func ValidateInstallConfig(c *types.InstallConfig, usingAgentMethod bool) field. } else { allErrs = append(allErrs, field.Required(field.NewPath("controlPlane"), "controlPlane is required")) } - allErrs = append(allErrs, validateCompute(&c.Platform, c.ControlPlane, c.Compute, field.NewPath("compute"))...) + multiArchEnabled := types.MultiArchFeatureGateEnabled(c.Platform.Name(), c.EnabledFeatureGates()) + allErrs = append(allErrs, validateCompute(&c.Platform, c.ControlPlane, c.Compute, field.NewPath("compute"), multiArchEnabled)...) if err := validate.ImagePullSecret(c.PullSecret); err != nil { allErrs = append(allErrs, field.Invalid(field.NewPath("pullSecret"), c.PullSecret, err.Error())) } @@ -606,7 +607,7 @@ func validateComputeEdge(platform *types.Platform, pName string, fldPath *field. return allErrs } -func validateCompute(platform *types.Platform, control *types.MachinePool, pools []types.MachinePool, fldPath *field.Path) field.ErrorList { +func validateCompute(platform *types.Platform, control *types.MachinePool, pools []types.MachinePool, fldPath *field.Path, isMultiArchEnabled bool) field.ErrorList { allErrs := field.ErrorList{} poolNames := map[string]bool{} for i, p := range pools { @@ -623,7 +624,7 @@ func validateCompute(platform *types.Platform, control *types.MachinePool, pools allErrs = append(allErrs, field.Duplicate(poolFldPath.Child("name"), p.Name)) } poolNames[p.Name] = true - if control != nil && control.Architecture != p.Architecture { + if control != nil && control.Architecture != p.Architecture && !isMultiArchEnabled { allErrs = append(allErrs, field.Invalid(poolFldPath.Child("architecture"), p.Architecture, "heteregeneous multi-arch is not supported; compute pool architecture must match control plane")) } allErrs = append(allErrs, ValidateMachinePool(platform, &p, poolFldPath)...) diff --git a/pkg/types/validation/installconfig_test.go b/pkg/types/validation/installconfig_test.go index 2e86683d4e5..3fc39bcd085 100644 --- a/pkg/types/validation/installconfig_test.go +++ b/pkg/types/validation/installconfig_test.go @@ -1413,6 +1413,16 @@ func TestValidateInstallConfig(t *testing.T) { }(), expectedError: `^compute\[0\].architecture: Invalid value: "arm64": heteregeneous multi-arch is not supported; compute pool architecture must match control plane$`, }, + { + name: "aws cluster is heteregeneous", + installConfig: func() *types.InstallConfig { + c := validInstallConfig() + c.Compute[0].Architecture = types.ArchitectureARM64 + c.FeatureSet = "CustomNoUpgrade" + c.FeatureGates = []string{"MultiArchInstallAWS=true"} + return c + }(), + }, { name: "valid cloud credentials mode", installConfig: func() *types.InstallConfig {