1
0
mirror of https://github.com/openshift/installer.git synced 2026-02-05 06:46:36 +01:00

pkg/asset/machines: use azure marketplace images

This commit is contained in:
Patrick Dillon
2025-11-10 21:48:40 -05:00
parent 7cf9586fae
commit a5f42476d3
6 changed files with 102 additions and 90 deletions

View File

@@ -26,16 +26,17 @@ const (
// MachineInput defines the inputs needed to generate a machine asset.
type MachineInput struct {
Subnet string
Role string
UserDataSecret string
HyperVGen string
StorageSuffix string
UseImageGallery bool
Private bool
UserTags map[string]string
Platform *aztypes.Platform
Pool *types.MachinePool
Subnet string
Role string
UserDataSecret string
HyperVGen string
StorageSuffix string
Environment aztypes.CloudEnvironment
Private bool
UserTags map[string]string
Platform *aztypes.Platform
Pool *types.MachinePool
RHCOS string
}
// GenerateMachines returns manifests and runtime objects to provision the control plane (including bootstrap, if applicable) nodes using CAPI.
@@ -59,38 +60,7 @@ func GenerateMachines(clusterID, resourceGroup, subscriptionID string, session *
if err != nil {
return nil, fmt.Errorf("failed to create machineapi.TagSpecifications from UserTags: %w", err)
}
var image *capz.Image
osImage := mpool.OSImage
galleryName := strings.ReplaceAll(clusterID, "-", "_")
switch {
case osImage.Publisher != "":
image = &capz.Image{
Marketplace: &capz.AzureMarketplaceImage{
ImagePlan: capz.ImagePlan{
Publisher: osImage.Publisher,
Offer: osImage.Offer,
SKU: osImage.SKU,
},
Version: osImage.Version,
ThirdPartyImage: osImage.Plan != aztypes.ImageNoPurchasePlan,
},
}
case in.UseImageGallery:
// image gallery names cannot have dashes
imageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/galleries/gallery_%s/images/%s", subscriptionID, resourceGroup, galleryName, clusterID)
if in.HyperVGen == "V2" && in.Platform.CloudName != aztypes.StackCloud {
imageID += genV2Suffix
}
image = &capz.Image{ID: &imageID}
default:
// AzureStack is the only use for managed images & supports only Gen1 VMs:
// https://learn.microsoft.com/en-us/azure-stack/user/azure-stack-vm-considerations?view=azs-2501&tabs=az1%2Caz2#vm-differences
imageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s", subscriptionID, resourceGroup, clusterID)
image = &capz.Image{ID: &imageID}
}
image := capzImage(mpool.OSImage, in.Environment, in.HyperVGen, resourceGroup, subscriptionID, clusterID, in.RHCOS)
// Set up OSDisk
osDisk := capz.OSDisk{
OSType: "Linux",
@@ -383,3 +353,46 @@ func bootDiagStorageURIBuilder(diag *aztypes.BootDiagnostics, storageEndpointSuf
}
return ""
}
func capzImage(osImage aztypes.OSImage, azEnv aztypes.CloudEnvironment, gen, rg, sub, infraID, rhcosImg string) *capz.Image {
switch {
case osImage.Publisher != "":
return &capz.Image{
Marketplace: &capz.AzureMarketplaceImage{
ImagePlan: capz.ImagePlan{
Publisher: osImage.Publisher,
Offer: osImage.Offer,
SKU: osImage.SKU,
},
Version: osImage.Version,
ThirdPartyImage: osImage.Plan != aztypes.ImageNoPurchasePlan,
},
}
case azEnv == aztypes.StackCloud:
// AzureStack is the only use for managed images & supports only Gen1 VMs:
// https://learn.microsoft.com/en-us/azure-stack/user/azure-stack-vm-considerations?view=azs-2501&tabs=az1%2Caz2#vm-differences
imageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s", sub, rg, infraID)
return &capz.Image{ID: &imageID}
case strings.Count(rhcosImg, ":") == 3: // Marketplace Image URN contains 3 colons
rhcosMktImg := strings.Split(rhcosImg, ":")
return &capz.Image{
Marketplace: &capz.AzureMarketplaceImage{
ImagePlan: capz.ImagePlan{
Publisher: rhcosMktImg[0],
Offer: rhcosMktImg[1],
SKU: rhcosMktImg[2],
},
Version: rhcosMktImg[3],
ThirdPartyImage: false,
},
}
default: // Installer-created image gallery, should only be OKD.
// image gallery names cannot have dashes
galleryName := strings.ReplaceAll(infraID, "-", "_")
imageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/galleries/gallery_%s/images/%s", sub, rg, galleryName, infraID)
if gen == "V2" {
imageID += genV2Suffix
}
return &capz.Image{ID: &imageID}
}
}

View File

@@ -27,7 +27,7 @@ const (
)
// Machines returns a list of machines for a machinepool.
func Machines(clusterID string, config *types.InstallConfig, pool *types.MachinePool, osImage, role, userDataSecret string, capabilities map[string]string, useImageGallery bool, session *icazure.Session) ([]machineapi.Machine, *machinev1.ControlPlaneMachineSet, error) {
func Machines(clusterID string, config *types.InstallConfig, pool *types.MachinePool, osImage, role, userDataSecret string, capabilities map[string]string, session *icazure.Session) ([]machineapi.Machine, *machinev1.ControlPlaneMachineSet, error) {
if configPlatform := config.Platform.Name(); configPlatform != azure.Name {
return nil, nil, fmt.Errorf("non-Azure configuration: %q", configPlatform)
}
@@ -62,7 +62,7 @@ func Machines(clusterID string, config *types.InstallConfig, pool *types.Machine
azIndex = int(idx) % len(azs)
}
subnetIndex := int(idx) % len(subnets)
provider, err := provider(platform, mpool, osImage, userDataSecret, clusterID, role, &azIndex, capabilities, useImageGallery, session, networkResourceGroup, virtualNetworkName, subnets[subnetIndex])
provider, err := provider(platform, mpool, osImage, userDataSecret, clusterID, role, &azIndex, capabilities, session, networkResourceGroup, virtualNetworkName, subnets[subnetIndex])
if err != nil {
return nil, nil, errors.Wrap(err, "failed to create provider")
}
@@ -159,7 +159,7 @@ func Machines(clusterID string, config *types.InstallConfig, pool *types.Machine
return machines, controlPlaneMachineSet, nil
}
func provider(platform *azure.Platform, mpool *azure.MachinePool, osImage string, userDataSecret string, clusterID string, role string, azIdx *int, capabilities map[string]string, useImageGallery bool, session *icazure.Session, networkResourceGroup, virtualNetwork, subnet string) (*machineapi.AzureMachineProviderSpec, error) {
func provider(platform *azure.Platform, mpool *azure.MachinePool, osImage string, userDataSecret string, clusterID string, role string, azIdx *int, capabilities map[string]string, session *icazure.Session, networkResourceGroup, virtualNetwork, subnet string) (*machineapi.AzureMachineProviderSpec, error) {
var az string
if len(mpool.Zones) > 0 && azIdx != nil {
az = mpool.Zones[*azIdx]
@@ -179,32 +179,7 @@ func provider(platform *azure.Platform, mpool *azure.MachinePool, osImage string
}
rg := platform.ClusterResourceGroupName(clusterID)
var image machineapi.Image
if mpool.OSImage.Publisher != "" {
image.Type = machineapi.AzureImageTypeMarketplaceWithPlan
if mpool.OSImage.Plan == azure.ImageNoPurchasePlan {
image.Type = machineapi.AzureImageTypeMarketplaceNoPlan
}
image.Publisher = mpool.OSImage.Publisher
image.Offer = mpool.OSImage.Offer
image.SKU = mpool.OSImage.SKU
image.Version = mpool.OSImage.Version
} else if useImageGallery {
// image gallery names cannot have dashes
galleryName := strings.ReplaceAll(clusterID, "-", "_")
id := clusterID
if hyperVGen == "V2" {
id += "-gen2"
}
imageID := fmt.Sprintf("/resourceGroups/%s/providers/Microsoft.Compute/galleries/gallery_%s/images/%s/versions/latest", rg, galleryName, id)
image.ResourceID = imageID
} else {
imageID := fmt.Sprintf("/resourceGroups/%s/providers/Microsoft.Compute/images/%s", rg, clusterID)
if hyperVGen == "V2" && platform.CloudName != azure.StackCloud {
imageID += "-gen2"
}
image.ResourceID = imageID
}
image := mapiImage(mpool.OSImage, platform.CloudName, hyperVGen, rg, session.Credentials.SubscriptionID, clusterID, osImage)
if mpool.OSDisk.DiskType == "" {
mpool.OSDisk.DiskType = "Premium_LRS"
@@ -454,3 +429,30 @@ func generateSecurityProfile(mpool *azure.MachinePool) *machineapi.SecurityProfi
return securityProfile
}
func mapiImage(osImage azure.OSImage, azEnv azure.CloudEnvironment, gen, rg, sub, infraID, rhcosImg string) machineapi.Image {
cImg := capzImage(osImage, azEnv, gen, rg, sub, infraID, rhcosImg)
mImg := machineapi.Image{}
if cImg.ID != nil {
mImg.ResourceID = trimSubscriptionPrefix(*cImg.ID)
} else if cImg.Marketplace != nil {
mImg.Publisher = cImg.Marketplace.Publisher
mImg.Offer = cImg.Marketplace.Offer
mImg.SKU = cImg.Marketplace.SKU
mImg.Version = cImg.Marketplace.Version
mImg.Type = machineapi.AzureImageTypeMarketplaceNoPlan
if cImg.Marketplace.ThirdPartyImage {
mImg.Type = machineapi.AzureImageTypeMarketplaceWithPlan
}
}
return mImg
}
// trimSubscriptionPrefix takes an image id string
// formatted for CAPZ and returns a string formatted
// for MAPI, by removing the /subspcription/ prefix.
func trimSubscriptionPrefix(image string) string {
rgIndex := strings.Index(image, "/resourceGroups/")
return image[rgIndex:]
}

View File

@@ -18,7 +18,7 @@ import (
)
// MachineSets returns a list of machinesets for a machinepool.
func MachineSets(clusterID string, ic *installconfig.InstallConfig, pool *types.MachinePool, osImage, role, userDataSecret string, capabilities map[string]string, useImageGallery bool, subnetZones []string, session *icazure.Session) ([]*clusterapi.MachineSet, error) {
func MachineSets(clusterID string, ic *installconfig.InstallConfig, pool *types.MachinePool, osImage, role, userDataSecret string, capabilities map[string]string, subnetZones []string, session *icazure.Session) ([]*clusterapi.MachineSet, error) {
config := ic.Config
if configPlatform := config.Platform.Name(); configPlatform != azure.Name {
return nil, fmt.Errorf("non-azure configuration: %q", configPlatform)
@@ -63,7 +63,6 @@ func MachineSets(clusterID string, ic *installconfig.InstallConfig, pool *types.
clusterID: clusterID,
role: role,
capabilities: capabilities,
useImageGallery: useImageGallery,
session: session,
subnetSpec: config.Azure.Subnets,
replicas: total,
@@ -78,7 +77,7 @@ func MachineSets(clusterID string, ic *installconfig.InstallConfig, pool *types.
replicas++
}
subnetIndex = (subnetIndex + 1) % len(subnets)
provider, err := provider(platform, mpool, osImage, userDataSecret, clusterID, role, &idx, capabilities, useImageGallery, session, networkResourceGroup, virtualNetworkName, subnets[subnetIndex])
provider, err := provider(platform, mpool, osImage, userDataSecret, clusterID, role, &idx, capabilities, session, networkResourceGroup, virtualNetworkName, subnets[subnetIndex])
if err != nil {
return nil, errors.Wrap(err, "failed to create provider")
}
@@ -137,7 +136,6 @@ type multiZoneMachineSetInput struct {
clusterID string
role string
capabilities map[string]string
useImageGallery bool
session *icazure.Session
virtualNetworkName string
subnetSpec []azure.SubnetSpec
@@ -197,7 +195,7 @@ func getMultiZoneMachineSets(in multiZoneMachineSetInput) ([]*clusterapi.Machine
currentReplica++
remainder--
}
provider, err := provider(in.platform, in.mpool, in.osImage, in.userDataSecret, in.clusterID, in.role, &idx, in.capabilities, in.useImageGallery, in.session, in.networkResourceGroup, in.virtualNetworkName, subnet)
provider, err := provider(in.platform, in.mpool, in.osImage, in.userDataSecret, in.clusterID, in.role, &idx, in.capabilities, in.session, in.networkResourceGroup, in.virtualNetworkName, subnet)
if err != nil {
return nil, errors.Wrap(err, "failed to create provider")
}

View File

@@ -296,16 +296,17 @@ func (c *ClusterAPI) Generate(ctx context.Context, dependencies asset.Parents) e
session.Credentials.SubscriptionID,
session,
&azure.MachineInput{
Subnet: subnet,
Role: "master",
UserDataSecret: "master-user-data",
HyperVGen: hyperVGen,
UseImageGallery: installConfig.Azure.CloudName != azuretypes.StackCloud,
Private: installConfig.Config.Publish == types.InternalPublishingStrategy,
UserTags: installConfig.Config.Platform.Azure.UserTags,
Platform: installConfig.Config.Platform.Azure,
Pool: &pool,
StorageSuffix: session.Environment.StorageEndpointSuffix,
Subnet: subnet,
Role: "master",
UserDataSecret: "master-user-data",
HyperVGen: hyperVGen,
Environment: installConfig.Azure.CloudName,
Private: installConfig.Config.Publish == types.InternalPublishingStrategy,
UserTags: installConfig.Config.Platform.Azure.UserTags,
Platform: installConfig.Config.Platform.Azure,
Pool: &pool,
StorageSuffix: session.Environment.StorageEndpointSuffix,
RHCOS: rhcosImage.ControlPlane,
},
)
if err != nil {

View File

@@ -405,8 +405,7 @@ func (m *Master) Generate(ctx context.Context, dependencies asset.Parents) error
if err != nil {
return err
}
useImageGallery := installConfig.Azure.CloudName != azuretypes.StackCloud
machines, controlPlaneMachineSet, err = azure.Machines(clusterID.InfraID, ic, &pool, rhcosImage.ControlPlane, "master", masterUserDataSecretName, capabilities, useImageGallery, session)
machines, controlPlaneMachineSet, err = azure.Machines(clusterID.InfraID, ic, &pool, rhcosImage.ControlPlane, "master", masterUserDataSecretName, capabilities, session)
if err != nil {
return errors.Wrap(err, "failed to create master machine objects")
}

View File

@@ -615,8 +615,7 @@ func (w *Worker) Generate(ctx context.Context, dependencies asset.Parents) error
return err
}
useImageGallery := ic.Platform.Azure.CloudName != azuretypes.StackCloud
sets, err := azure.MachineSets(clusterID.InfraID, installConfig, &pool, rhcosImage.Compute, "worker", workerUserDataSecretName, capabilities, useImageGallery, subnetZones, session)
sets, err := azure.MachineSets(clusterID.InfraID, installConfig, &pool, rhcosImage.Compute, "worker", workerUserDataSecretName, capabilities, subnetZones, session)
if err != nil {
return errors.Wrap(err, "failed to create worker machine objects")
}