Skip to content

Commit 6661dac

Browse files
Merge pull request #10076 from patrickdillon/az-mkt
CORS-3657: Default Azure Installs to Marketplace Images
2 parents e22009c + 8fa9860 commit 6661dac

File tree

18 files changed

+328
-258
lines changed

18 files changed

+328
-258
lines changed

.golangci.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ linters:
3333
- revive
3434
- staticcheck
3535
- stylecheck
36-
- tenv
3736
- thelper
3837
- typecheck
3938
- unconvert
@@ -148,6 +147,8 @@ linters-settings:
148147
- name: redefines-builtin-id
149148
- name: bool-literal-in-expr
150149
- name: constant-logical-expr
150+
gocyclo:
151+
min-complexity: 45
151152
issues:
152153
include:
153154
- EXC0012 # EXC0012 revive: issue about not having a comment on exported.

pkg/asset/cluster/tfvars/tfvars.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -373,14 +373,6 @@ func (t *TerraformVariables) Generate(ctx context.Context, parents asset.Parents
373373
for i, w := range workers {
374374
workerConfigs[i] = w.Spec.Template.Spec.ProviderSpec.Value.Object.(*machinev1beta1.AzureMachineProviderSpec) //nolint:errcheck // legacy, pre-linter
375375
}
376-
client, err := installConfig.Azure.Client()
377-
if err != nil {
378-
return err
379-
}
380-
hyperVGeneration, err := client.GetHyperVGenerationVersion(ctx, masterConfigs[0].VMSize, masterConfigs[0].Location, "")
381-
if err != nil {
382-
return err
383-
}
384376

385377
preexistingnetwork := installConfig.Config.Azure.VirtualNetwork != ""
386378

@@ -427,7 +419,6 @@ func (t *TerraformVariables) Generate(ctx context.Context, parents asset.Parents
427419
OutboundType: installConfig.Config.Azure.OutboundType,
428420
BootstrapIgnStub: bootstrapIgnStub,
429421
BootstrapIgnitionURLPlaceholder: bootstrapIgnURLPlaceholder,
430-
HyperVGeneration: hyperVGeneration,
431422
VMArchitecture: installConfig.Config.ControlPlane.Architecture,
432423
InfrastructureName: clusterID.InfraID,
433424
KeyVault: managedKeys.KeyVault,

pkg/asset/installconfig/azure/client.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ type API interface {
3838
ListResourceIDsByGroup(ctx context.Context, groupName string) ([]string, error)
3939
GetStorageEndpointSuffix(ctx context.Context) (string, error)
4040
GetDiskEncryptionSet(ctx context.Context, subscriptionID, groupName string, diskEncryptionSetName string) (*azenc.DiskEncryptionSet, error)
41-
GetHyperVGenerationVersion(ctx context.Context, instanceType string, region string, imageHyperVGen string) (string, error)
4241
GetMarketplaceImage(ctx context.Context, region, publisher, offer, sku, version string) (azenc.VirtualMachineImage, error)
4342
AreMarketplaceImageTermsAccepted(ctx context.Context, publisher, offer, sku string) (bool, error)
4443
GetVMCapabilities(ctx context.Context, instanceType, region string) (map[string]string, error)
@@ -364,17 +363,6 @@ func (c *Client) GetVMCapabilities(ctx context.Context, instanceType, region str
364363
return capabilities, nil
365364
}
366365

367-
// GetHyperVGenerationVersion gets the HyperVGeneration version for the given instance type and marketplace image version, if specified. Defaults to V2 if either V1 or V2
368-
// available.
369-
func (c *Client) GetHyperVGenerationVersion(ctx context.Context, instanceType string, region string, imageHyperVGen string) (version string, err error) {
370-
capabilities, err := c.GetVMCapabilities(ctx, instanceType, region)
371-
if err != nil {
372-
return "", err
373-
}
374-
375-
return GetHyperVGenerationVersion(capabilities, imageHyperVGen)
376-
}
377-
378366
// GetMarketplaceImage get the specified marketplace VM image.
379367
func (c *Client) GetMarketplaceImage(ctx context.Context, region, publisher, offer, sku, version string) (azenc.VirtualMachineImage, error) {
380368
client := azenc.NewVirtualMachineImagesClientWithBaseURI(c.ssn.Environment.ResourceManagerEndpoint, c.ssn.Credentials.SubscriptionID)

pkg/asset/installconfig/azure/metadata.go

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import (
88

99
"sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
1010

11+
"github.com/openshift/installer/pkg/types"
1112
typesazure "github.com/openshift/installer/pkg/types/azure"
13+
azuredefaults "github.com/openshift/installer/pkg/types/azure/defaults"
1214
)
1315

1416
// Metadata holds additional metadata for InstallConfig resources that
@@ -23,6 +25,13 @@ type Metadata struct {
2325
region string
2426
ZonesSubnetMap map[string][]string
2527

28+
controlPlane *types.MachinePool
29+
compute *types.MachinePool
30+
defaultPlatform *typesazure.MachinePool
31+
32+
controlPlaneCapabilities map[string]string
33+
computeCapabilities map[string]string
34+
2635
// CloudName indicates the Azure cloud environment (e.g. public, gov't).
2736
CloudName typesazure.CloudEnvironment `json:"cloudName,omitempty"`
2837

@@ -42,18 +51,21 @@ type Metadata struct {
4251
}
4352

4453
// NewMetadata initializes a new Metadata object.
45-
func NewMetadata(cloudName typesazure.CloudEnvironment, armEndpoint string, region string) *Metadata {
46-
return NewMetadataWithCredentials(cloudName, armEndpoint, nil, region)
54+
func NewMetadata(az *typesazure.Platform, controlPlane, compute *types.MachinePool) *Metadata {
55+
return NewMetadataWithCredentials(az, controlPlane, compute, nil)
4756
}
4857

4958
// NewMetadataWithCredentials initializes a new Metadata object
5059
// with prepopulated Azure credentials.
51-
func NewMetadataWithCredentials(cloudName typesazure.CloudEnvironment, armEndpoint string, credentials *Credentials, region string) *Metadata {
60+
func NewMetadataWithCredentials(az *typesazure.Platform, controlPlane, compute *types.MachinePool, credentials *Credentials) *Metadata {
5261
return &Metadata{
53-
CloudName: cloudName,
54-
ARMEndpoint: armEndpoint,
55-
Credentials: credentials,
56-
region: region,
62+
CloudName: az.CloudName,
63+
ARMEndpoint: az.ARMEndpoint,
64+
Credentials: credentials,
65+
controlPlane: controlPlane,
66+
compute: compute,
67+
region: az.Region,
68+
defaultPlatform: az.DefaultMachinePlatform,
5769
}
5870
}
5971

@@ -198,3 +210,73 @@ func (m *Metadata) GenerateZonesSubnetMap(subnetSpec []typesazure.SubnetSpec, de
198210
}
199211
return m.ZonesSubnetMap, nil
200212
}
213+
214+
// ControlPlaneCapabilities returns the capabilities for the instance type of control-plane
215+
// nodes from the Azure API.
216+
func (m *Metadata) ControlPlaneCapabilities() (map[string]string, error) {
217+
if m.controlPlaneCapabilities == nil {
218+
caps, err := m.getCapabilities(m.controlPlane, azuredefaults.ControlPlaneInstanceType)
219+
if err != nil {
220+
return nil, fmt.Errorf("failed to get control plane capabilities: %w", err)
221+
}
222+
m.controlPlaneCapabilities = caps
223+
}
224+
return m.controlPlaneCapabilities, nil
225+
}
226+
227+
// ComputeCapabilities returns the capabilities for the instance type of compute nodes
228+
// from the Azure API.
229+
func (m *Metadata) ComputeCapabilities() (map[string]string, error) {
230+
if m.computeCapabilities == nil {
231+
caps, err := m.getCapabilities(m.compute, azuredefaults.ComputeInstanceType)
232+
if err != nil {
233+
return nil, fmt.Errorf("failed to get compute capabilities: %w", err)
234+
}
235+
m.computeCapabilities = caps
236+
}
237+
return m.computeCapabilities, nil
238+
}
239+
240+
// ControlPlaneHyperVGeneration returns the HyperVGeneration for the control-plane
241+
// instances. If the instance type supports both V1 & V2, V2 is returned.
242+
func (m *Metadata) ControlPlaneHyperVGeneration() (string, error) {
243+
caps, err := m.ControlPlaneCapabilities()
244+
if err != nil {
245+
return "", fmt.Errorf("unable to get control plane capabilities: %w", err)
246+
}
247+
return GetHyperVGenerationVersion(caps, "")
248+
}
249+
250+
// ComputeHyperVGeneration returns the HyperVGeneration for the compute instances.
251+
// If the instance type supports both V1 & V2, V2 is returned.
252+
func (m *Metadata) ComputeHyperVGeneration() (string, error) {
253+
caps, err := m.ComputeCapabilities()
254+
if err != nil {
255+
return "", fmt.Errorf("unable to get compute capabilities: %w", err)
256+
}
257+
return GetHyperVGenerationVersion(caps, "")
258+
}
259+
260+
type machinePoolInstanceTypeFunc func(typesazure.CloudEnvironment, string, types.Architecture) string
261+
262+
func (m *Metadata) getCapabilities(mPool *types.MachinePool, defaultInstanceType machinePoolInstanceTypeFunc) (map[string]string, error) {
263+
if mPool == nil {
264+
return nil, fmt.Errorf("unable to get capabilities because machinepool is not populated in metadata")
265+
}
266+
instType := defaultInstanceType(m.CloudName, m.region, mPool.Architecture)
267+
if dmp := m.defaultPlatform; dmp != nil && dmp.InstanceType != "" {
268+
instType = dmp.InstanceType
269+
}
270+
if mPool.Platform.Azure != nil && mPool.Platform.Azure.InstanceType != "" {
271+
instType = mPool.Platform.Azure.InstanceType
272+
}
273+
client, err := m.Client()
274+
if err != nil {
275+
return nil, fmt.Errorf("failed to get azure client %w", err)
276+
}
277+
caps, err := client.GetVMCapabilities(context.TODO(), instType, m.region)
278+
if err != nil {
279+
return nil, err
280+
}
281+
return caps, nil
282+
}

pkg/asset/installconfig/azure/mock/azureclient_generated.go

Lines changed: 0 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/asset/installconfig/azure/validation.go

Lines changed: 17 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"net"
77
"net/url"
8-
"os"
98
"slices"
109
"sort"
1110
"strconv"
@@ -53,23 +52,23 @@ var computeReq = resourceRequirements{
5352
}
5453

5554
// Validate executes platform-specific validation.
56-
func Validate(client API, ic *types.InstallConfig) error {
55+
func Validate(client API, meta *Metadata, ic *types.InstallConfig) error {
5756
allErrs := field.ErrorList{}
5857

5958
allErrs = append(allErrs, validateNetworks(client, ic.Azure, field.NewPath("platform").Child("azure"))...)
6059
allErrs = append(allErrs, validateRegion(client, field.NewPath("platform").Child("azure").Child("region"), ic.Azure)...)
6160
if ic.Azure.CloudName == aztypes.StackCloud {
6261
allErrs = append(allErrs, validateAzureStackDiskType(client, ic)...)
6362
}
64-
allErrs = append(allErrs, validateInstanceTypes(client, ic)...)
63+
allErrs = append(allErrs, validateInstanceTypes(client, meta, ic)...)
6564
if ic.Azure.CloudName == aztypes.StackCloud && ic.Azure.ClusterOSImage != "" {
6665
StorageEndpointSuffix, err := client.GetStorageEndpointSuffix(context.TODO())
6766
if err != nil {
6867
return err
6968
}
7069
allErrs = append(allErrs, validateAzureStackClusterOSImage(StorageEndpointSuffix, ic.Azure.ClusterOSImage, field.NewPath("platform").Child("azure"))...)
7170
}
72-
allErrs = append(allErrs, validateMarketplaceImages(client, ic)...)
71+
allErrs = append(allErrs, validateMarketplaceImages(client, meta, ic)...)
7372
allErrs = append(allErrs, validateBootDiagnostics(client, ic)...)
7473
allErrs = append(allErrs, validateCustomSubnets(client, field.NewPath("platform").Child("azure").Child("subnetSpec"), ic)...)
7574
return allErrs.ToAggregate()
@@ -353,12 +352,15 @@ func validateUltraSSD(client API, fieldPath *field.Path, icZones []string, regio
353352
}
354353

355354
// ValidateInstanceType ensures the instance type has sufficient Vcpu, Memory, and a valid family type.
356-
func ValidateInstanceType(client API, fieldPath *field.Path, region, instanceType, diskType string, req resourceRequirements, ultraSSDEnabled bool, vmNetworkingType string, icZones []string, architecture types.Architecture, securityType aztypes.SecurityTypes) field.ErrorList {
355+
func ValidateInstanceType(client API, fieldPath *field.Path, region, instanceType, diskType string, req resourceRequirements, ultraSSDEnabled bool, vmNetworkingType string, icZones []string, architecture types.Architecture, securityType aztypes.SecurityTypes, capabilities map[string]string) field.ErrorList {
357356
allErrs := field.ErrorList{}
358357

359-
capabilities, err := client.GetVMCapabilities(context.TODO(), instanceType, region)
360-
if err != nil {
361-
return append(allErrs, field.Invalid(fieldPath.Child("type"), instanceType, err.Error()))
358+
var err error
359+
if capabilities == nil {
360+
capabilities, err = client.GetVMCapabilities(context.TODO(), instanceType, region)
361+
if err != nil {
362+
return append(allErrs, field.Invalid(fieldPath.Child("type"), instanceType, err.Error()))
363+
}
362364
}
363365

364366
allErrs = append(allErrs, validateMininumRequirements(fieldPath.Child("type"), req, instanceType, capabilities)...)
@@ -386,7 +388,7 @@ func ValidateInstanceType(client API, fieldPath *field.Path, region, instanceTyp
386388
}
387389

388390
// validateInstanceTypes checks that the user-provided instance types are valid.
389-
func validateInstanceTypes(client API, ic *types.InstallConfig) field.ErrorList {
391+
func validateInstanceTypes(client API, meta *Metadata, ic *types.InstallConfig) field.ErrorList {
390392
allErrs := field.ErrorList{}
391393

392394
var securityType aztypes.SecurityTypes
@@ -451,7 +453,7 @@ func validateInstanceTypes(client API, ic *types.InstallConfig) field.ErrorList
451453
zones = defaultZones
452454
}
453455
ultraSSDEnabled := strings.EqualFold(ultraSSDCapability, "Enabled")
454-
allErrs = append(allErrs, ValidateInstanceType(client, fieldPath, ic.Azure.Region, instanceType, diskType, controlPlaneReq, ultraSSDEnabled, vmNetworkingType, zones, architecture, securityType)...)
456+
allErrs = append(allErrs, ValidateInstanceType(client, fieldPath, ic.Azure.Region, instanceType, diskType, controlPlaneReq, ultraSSDEnabled, vmNetworkingType, zones, architecture, securityType, meta.controlPlaneCapabilities)...)
455457
}
456458

457459
for idx, compute := range ic.Compute {
@@ -488,7 +490,7 @@ func validateInstanceTypes(client API, ic *types.InstallConfig) field.ErrorList
488490
}
489491
ultraSSDEnabled := strings.EqualFold(ultraSSDCapability, "Enabled")
490492
allErrs = append(allErrs, ValidateInstanceType(client, fieldPath.Child("platform", "azure"),
491-
ic.Azure.Region, instanceType, diskType, computeReq, ultraSSDEnabled, vmNetworkingType, zones, architecture, securityType)...)
493+
ic.Azure.Region, instanceType, diskType, computeReq, ultraSSDEnabled, vmNetworkingType, zones, architecture, securityType, meta.computeCapabilities)...)
492494
}
493495
}
494496

@@ -507,7 +509,7 @@ func validateInstanceTypes(client API, ic *types.InstallConfig) field.ErrorList
507509
fieldPath := field.NewPath("platform", "azure", "defaultMachinePlatform")
508510
ultraSSDEnabled := strings.EqualFold(defaultUltraSSDCapability, "Enabled")
509511
allErrs = append(allErrs, ValidateInstanceType(client, fieldPath,
510-
ic.Azure.Region, defaultInstanceType, defaultDiskType, minReq, ultraSSDEnabled, defaultVMNetworkingType, defaultZones, architecture, securityType)...)
512+
ic.Azure.Region, defaultInstanceType, defaultDiskType, minReq, ultraSSDEnabled, defaultVMNetworkingType, defaultZones, architecture, securityType, nil)...)
511513
}
512514
return allErrs
513515
}
@@ -662,46 +664,12 @@ func ValidateForProvisioning(client API, ic *types.InstallConfig) error {
662664
allErrs = append(allErrs, validateResourceGroup(client, field.NewPath("platform").Child("azure"), ic.Azure)...)
663665
allErrs = append(allErrs, ValidateDiskEncryptionSet(client, ic)...)
664666
allErrs = append(allErrs, ValidateSecurityProfileDiskEncryptionSet(client, ic)...)
665-
allErrs = append(allErrs, validateSkipImageUpload(field.NewPath("image"), ic)...)
666667
if ic.Azure.CloudName == aztypes.StackCloud {
667668
allErrs = append(allErrs, checkAzureStackClusterOSImageSet(ic.Azure.ClusterOSImage, field.NewPath("platform").Child("azure"))...)
668669
}
669670
return allErrs.ToAggregate()
670671
}
671672

672-
func validateSkipImageUpload(fieldPath *field.Path, ic *types.InstallConfig) field.ErrorList {
673-
allErrs := field.ErrorList{}
674-
defaultOSImage := aztypes.OSImage{}
675-
if ic.Azure.DefaultMachinePlatform != nil {
676-
defaultOSImage = aztypes.OSImage{
677-
Plan: ic.Azure.DefaultMachinePlatform.OSImage.Plan,
678-
Publisher: ic.Azure.DefaultMachinePlatform.OSImage.Publisher,
679-
SKU: ic.Azure.DefaultMachinePlatform.OSImage.SKU,
680-
Version: ic.Azure.DefaultMachinePlatform.OSImage.Version,
681-
Offer: ic.Azure.DefaultMachinePlatform.OSImage.Offer,
682-
}
683-
}
684-
controlPlaneOSImage := defaultOSImage
685-
if ic.ControlPlane.Platform.Azure != nil {
686-
controlPlaneOSImage = ic.ControlPlane.Platform.Azure.OSImage
687-
}
688-
allErrs = append(allErrs, validateOSImage(fieldPath.Child("controlplane"), controlPlaneOSImage)...)
689-
computeOSImage := defaultOSImage
690-
if len(ic.Compute) > 0 && ic.Compute[0].Platform.Azure != nil {
691-
computeOSImage = ic.Compute[0].Platform.Azure.OSImage
692-
}
693-
allErrs = append(allErrs, validateOSImage(fieldPath.Child("compute"), computeOSImage)...)
694-
return allErrs
695-
}
696-
func validateOSImage(fieldPath *field.Path, osImage aztypes.OSImage) field.ErrorList {
697-
if _, ok := os.LookupEnv("OPENSHIFT_INSTALL_SKIP_IMAGE_UPLOAD"); ok {
698-
if len(osImage.SKU) > 0 {
699-
return nil
700-
}
701-
return field.ErrorList{field.Invalid(fieldPath, "image", "cannot skip image upload without marketplace image specified")}
702-
}
703-
return nil
704-
}
705673
func validateResourceGroup(client API, fieldPath *field.Path, platform *aztypes.Platform) field.ErrorList {
706674
allErrs := field.ErrorList{}
707675
if len(platform.ResourceGroupName) == 0 {
@@ -766,7 +734,7 @@ func validateAzureStackClusterOSImage(StorageEndpointSuffix string, ClusterOSIma
766734
return allErrs
767735
}
768736

769-
func validateMarketplaceImages(client API, installConfig *types.InstallConfig) field.ErrorList {
737+
func validateMarketplaceImages(client API, meta *Metadata, installConfig *types.InstallConfig) field.ErrorList {
770738
var allErrs field.ErrorList
771739

772740
region := installConfig.Azure.Region
@@ -796,7 +764,7 @@ func validateMarketplaceImages(client API, installConfig *types.InstallConfig) f
796764
instanceType = defaults.ControlPlaneInstanceType(cloudName, region, installConfig.ControlPlane.Architecture)
797765
}
798766

799-
capabilities, err := client.GetVMCapabilities(context.Background(), instanceType, region)
767+
capabilities, err := meta.ControlPlaneCapabilities()
800768
if err != nil {
801769
allErrs = append(allErrs, field.Invalid(fldPath.Child("platform", "azure", "type"), instanceType, err.Error()))
802770
}
@@ -838,7 +806,7 @@ func validateMarketplaceImages(client API, installConfig *types.InstallConfig) f
838806
instanceType = defaults.ComputeInstanceType(cloudName, region, compute.Architecture)
839807
}
840808

841-
capabilities, err := client.GetVMCapabilities(context.Background(), instanceType, region)
809+
capabilities, err := meta.ComputeCapabilities()
842810
if err != nil {
843811
allErrs = append(allErrs, field.Invalid(fldPath.Child("platform", "azure", "type"), instanceType, err.Error()))
844812
continue

0 commit comments

Comments
 (0)