github.com/openshift/installer@v1.4.17/pkg/asset/machines/azure/machines.go (about) 1 // Package azure generates Machine objects for azure. 2 package azure 3 4 import ( 5 "fmt" 6 "sort" 7 "strings" 8 9 "github.com/pkg/errors" 10 "github.com/sirupsen/logrus" 11 corev1 "k8s.io/api/core/v1" 12 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 "k8s.io/apimachinery/pkg/runtime" 14 15 v1 "github.com/openshift/api/config/v1" 16 machinev1 "github.com/openshift/api/machine/v1" 17 machineapi "github.com/openshift/api/machine/v1beta1" 18 icazure "github.com/openshift/installer/pkg/asset/installconfig/azure" 19 "github.com/openshift/installer/pkg/types" 20 "github.com/openshift/installer/pkg/types/azure" 21 ) 22 23 const ( 24 cloudsSecret = "azure-cloud-credentials" 25 cloudsSecretNamespace = "openshift-machine-api" 26 ) 27 28 // Machines returns a list of machines for a machinepool. 29 func Machines(clusterID string, config *types.InstallConfig, pool *types.MachinePool, osImage, role, userDataSecret string, capabilities map[string]string, useImageGallery bool) ([]machineapi.Machine, *machinev1.ControlPlaneMachineSet, error) { 30 if configPlatform := config.Platform.Name(); configPlatform != azure.Name { 31 return nil, nil, fmt.Errorf("non-Azure configuration: %q", configPlatform) 32 } 33 if poolPlatform := pool.Platform.Name(); poolPlatform != azure.Name { 34 return nil, nil, fmt.Errorf("non-Azure machine-pool: %q", poolPlatform) 35 } 36 platform := config.Platform.Azure 37 mpool := pool.Platform.Azure 38 39 if len(mpool.Zones) == 0 { 40 // if no azs are given we set to []string{""} for convenience over later operations. 41 // It means no-zoned for the machine API 42 mpool.Zones = []string{""} 43 } 44 azs := mpool.Zones 45 46 total := int64(1) 47 if pool.Replicas != nil { 48 total = *pool.Replicas 49 } 50 var machines []machineapi.Machine 51 machineSetProvider := &machineapi.AzureMachineProviderSpec{} 52 for idx := int64(0); idx < total; idx++ { 53 var azIndex int 54 if len(azs) > 0 { 55 azIndex = int(idx) % len(azs) 56 } 57 provider, err := provider(platform, mpool, osImage, userDataSecret, clusterID, role, &azIndex, capabilities, useImageGallery) 58 if err != nil { 59 return nil, nil, errors.Wrap(err, "failed to create provider") 60 } 61 machine := machineapi.Machine{ 62 TypeMeta: metav1.TypeMeta{ 63 APIVersion: "machine.openshift.io/v1beta1", 64 Kind: "Machine", 65 }, 66 ObjectMeta: metav1.ObjectMeta{ 67 Namespace: "openshift-machine-api", 68 Name: fmt.Sprintf("%s-%s-%d", clusterID, pool.Name, idx), 69 Labels: map[string]string{ 70 "machine.openshift.io/cluster-api-cluster": clusterID, 71 "machine.openshift.io/cluster-api-machine-role": role, 72 "machine.openshift.io/cluster-api-machine-type": role, 73 }, 74 }, 75 Spec: machineapi.MachineSpec{ 76 ProviderSpec: machineapi.ProviderSpec{ 77 Value: &runtime.RawExtension{Object: provider}, 78 }, 79 // we don't need to set Versions, because we control those via operators. 80 }, 81 } 82 *machineSetProvider = *provider 83 machines = append(machines, machine) 84 } 85 replicas := int32(total) 86 87 failureDomains := []machinev1.AzureFailureDomain{} 88 if len(mpool.Zones) > 1 { 89 sort.Strings(mpool.Zones) 90 for _, zone := range mpool.Zones { 91 domain := machinev1.AzureFailureDomain{ 92 Zone: zone, 93 } 94 95 failureDomains = append(failureDomains, domain) 96 } 97 machineSetProvider.Zone = "" 98 } else if len(mpool.Zones) == 1 { 99 machineSetProvider.Zone = mpool.Zones[0] 100 } 101 102 controlPlaneMachineSet := &machinev1.ControlPlaneMachineSet{ 103 TypeMeta: metav1.TypeMeta{ 104 APIVersion: "machine.openshift.io/v1", 105 Kind: "ControlPlaneMachineSet", 106 }, 107 ObjectMeta: metav1.ObjectMeta{ 108 Namespace: "openshift-machine-api", 109 Name: "cluster", 110 Labels: map[string]string{ 111 "machine.openshift.io/cluster-api-cluster": clusterID, 112 }, 113 }, 114 Spec: machinev1.ControlPlaneMachineSetSpec{ 115 Replicas: &replicas, 116 State: machinev1.ControlPlaneMachineSetStateActive, 117 Selector: metav1.LabelSelector{ 118 MatchLabels: map[string]string{ 119 "machine.openshift.io/cluster-api-machine-role": role, 120 "machine.openshift.io/cluster-api-machine-type": role, 121 "machine.openshift.io/cluster-api-cluster": clusterID, 122 }, 123 }, 124 Template: machinev1.ControlPlaneMachineSetTemplate{ 125 MachineType: machinev1.OpenShiftMachineV1Beta1MachineType, 126 OpenShiftMachineV1Beta1Machine: &machinev1.OpenShiftMachineV1Beta1MachineTemplate{ 127 ObjectMeta: machinev1.ControlPlaneMachineSetTemplateObjectMeta{ 128 Labels: map[string]string{ 129 "machine.openshift.io/cluster-api-cluster": clusterID, 130 "machine.openshift.io/cluster-api-machine-role": role, 131 "machine.openshift.io/cluster-api-machine-type": role, 132 }, 133 }, 134 Spec: machineapi.MachineSpec{ 135 ProviderSpec: machineapi.ProviderSpec{ 136 Value: &runtime.RawExtension{Object: machineSetProvider}, 137 }, 138 }, 139 }, 140 }, 141 }, 142 } 143 144 if len(failureDomains) > 0 { 145 controlPlaneMachineSet.Spec.Template.OpenShiftMachineV1Beta1Machine.FailureDomains = &machinev1.FailureDomains{ 146 Platform: v1.AzurePlatformType, 147 Azure: &failureDomains, 148 } 149 } 150 151 return machines, controlPlaneMachineSet, nil 152 } 153 154 func provider(platform *azure.Platform, mpool *azure.MachinePool, osImage string, userDataSecret string, clusterID string, role string, azIdx *int, capabilities map[string]string, useImageGallery bool) (*machineapi.AzureMachineProviderSpec, error) { 155 var az string 156 if len(mpool.Zones) > 0 && azIdx != nil { 157 az = mpool.Zones[*azIdx] 158 } 159 160 hyperVGen, err := icazure.GetHyperVGenerationVersion(capabilities, "") 161 if err != nil { 162 return nil, err 163 } 164 165 if mpool.VMNetworkingType == "" { 166 acceleratedNetworking := icazure.GetVMNetworkingCapability(capabilities) 167 if acceleratedNetworking { 168 mpool.VMNetworkingType = string(azure.VMnetworkingTypeAccelerated) 169 } else { 170 logrus.Infof("Instance type %s does not support Accelerated Networking. Using Basic Networking instead.", mpool.InstanceType) 171 } 172 } 173 rg := platform.ClusterResourceGroupName(clusterID) 174 175 var image machineapi.Image 176 if mpool.OSImage.Publisher != "" { 177 image.Type = machineapi.AzureImageTypeMarketplaceWithPlan 178 if mpool.OSImage.Plan == azure.ImageNoPurchasePlan { 179 image.Type = machineapi.AzureImageTypeMarketplaceNoPlan 180 } 181 image.Publisher = mpool.OSImage.Publisher 182 image.Offer = mpool.OSImage.Offer 183 image.SKU = mpool.OSImage.SKU 184 image.Version = mpool.OSImage.Version 185 } else if useImageGallery { 186 // image gallery names cannot have dashes 187 galleryName := strings.ReplaceAll(clusterID, "-", "_") 188 id := clusterID 189 if hyperVGen == "V2" { 190 id += "-gen2" 191 } 192 imageID := fmt.Sprintf("/resourceGroups/%s/providers/Microsoft.Compute/galleries/gallery_%s/images/%s/versions/latest", rg, galleryName, id) 193 image.ResourceID = imageID 194 } else { 195 imageID := fmt.Sprintf("/resourceGroups/%s/providers/Microsoft.Compute/images/%s", rg, clusterID) 196 if hyperVGen == "V2" && platform.CloudName != azure.StackCloud { 197 imageID += "-gen2" 198 } 199 image.ResourceID = imageID 200 } 201 202 networkResourceGroup, virtualNetwork, subnet, err := getNetworkInfo(platform, clusterID, role) 203 if err != nil { 204 return nil, err 205 } 206 207 if mpool.OSDisk.DiskType == "" { 208 mpool.OSDisk.DiskType = "Premium_LRS" 209 } 210 211 publicLB := clusterID 212 if platform.OutboundType == azure.UserDefinedRoutingOutboundType { 213 publicLB = "" 214 } 215 216 managedIdentity := fmt.Sprintf("%s-identity", clusterID) 217 if platform.IsARO() || platform.CloudName == azure.StackCloud { 218 managedIdentity = "" 219 } 220 221 var diskEncryptionSet *machineapi.DiskEncryptionSetParameters 222 if mpool.OSDisk.DiskEncryptionSet != nil { 223 diskEncryptionSet = &machineapi.DiskEncryptionSetParameters{ 224 ID: mpool.OSDisk.DiskEncryptionSet.ToID(), 225 } 226 } 227 228 var diskSecurityProfile machineapi.VMDiskSecurityProfile 229 if mpool.OSDisk.SecurityProfile != nil && mpool.OSDisk.SecurityProfile.SecurityEncryptionType != "" { 230 diskSecurityProfile = machineapi.VMDiskSecurityProfile{ 231 SecurityEncryptionType: machineapi.SecurityEncryptionTypes(mpool.OSDisk.SecurityProfile.SecurityEncryptionType), 232 } 233 234 if mpool.OSDisk.SecurityProfile.DiskEncryptionSet != nil { 235 diskSecurityProfile.DiskEncryptionSet = machineapi.DiskEncryptionSetParameters{ 236 ID: mpool.OSDisk.SecurityProfile.DiskEncryptionSet.ToID(), 237 } 238 } 239 } 240 241 securityProfile := generateSecurityProfile(mpool) 242 243 ultraSSDCapability := machineapi.AzureUltraSSDCapabilityState(mpool.UltraSSDCapability) 244 245 spec := &machineapi.AzureMachineProviderSpec{ 246 TypeMeta: metav1.TypeMeta{ 247 APIVersion: "machine.openshift.io/v1beta1", 248 Kind: "AzureMachineProviderSpec", 249 }, 250 UserDataSecret: &corev1.SecretReference{Name: userDataSecret}, 251 CredentialsSecret: &corev1.SecretReference{Name: cloudsSecret, Namespace: cloudsSecretNamespace}, 252 Location: platform.Region, 253 VMSize: mpool.InstanceType, 254 Image: image, 255 OSDisk: machineapi.OSDisk{ 256 OSType: "Linux", 257 DiskSizeGB: mpool.OSDisk.DiskSizeGB, 258 ManagedDisk: machineapi.OSDiskManagedDiskParameters{ 259 StorageAccountType: mpool.OSDisk.DiskType, 260 DiskEncryptionSet: diskEncryptionSet, 261 SecurityProfile: diskSecurityProfile, 262 }, 263 }, 264 SecurityProfile: securityProfile, 265 UltraSSDCapability: ultraSSDCapability, 266 Zone: az, 267 Subnet: subnet, 268 ManagedIdentity: managedIdentity, 269 Vnet: virtualNetwork, 270 ResourceGroup: rg, 271 NetworkResourceGroup: networkResourceGroup, 272 PublicLoadBalancer: publicLB, 273 AcceleratedNetworking: getVMNetworkingType(mpool.VMNetworkingType), 274 Tags: platform.UserTags, 275 } 276 277 if platform.CloudName == azure.StackCloud { 278 spec.AvailabilitySet = fmt.Sprintf("%s-cluster", clusterID) 279 } 280 281 return spec, nil 282 } 283 284 // ConfigMasters sets the PublicIP flag and assigns a set of load balancers to the given machines 285 func ConfigMasters(machines []machineapi.Machine, controlPlane *machinev1.ControlPlaneMachineSet, clusterID string) error { 286 internalLB := fmt.Sprintf("%s-internal", clusterID) 287 288 for _, machine := range machines { 289 providerSpec := machine.Spec.ProviderSpec.Value.Object.(*machineapi.AzureMachineProviderSpec) 290 providerSpec.InternalLoadBalancer = internalLB 291 } 292 providerSpec, ok := controlPlane.Spec.Template.OpenShiftMachineV1Beta1Machine.Spec.ProviderSpec.Value.Object.(*machineapi.AzureMachineProviderSpec) 293 if !ok { 294 return errors.New("Unable to set internal load balancers to control plane machine set") 295 } 296 providerSpec.InternalLoadBalancer = internalLB 297 return nil 298 } 299 300 func getNetworkInfo(platform *azure.Platform, clusterID, role string) (string, string, string, error) { 301 networkResourceGroupName := platform.NetworkResourceGroupName 302 if platform.VirtualNetwork == "" { 303 networkResourceGroupName = platform.ClusterResourceGroupName(clusterID) 304 } 305 306 switch role { 307 case "worker": 308 return networkResourceGroupName, platform.VirtualNetworkName(clusterID), platform.ComputeSubnetName(clusterID), nil 309 case "master": 310 return networkResourceGroupName, platform.VirtualNetworkName(clusterID), platform.ControlPlaneSubnetName(clusterID), nil 311 default: 312 return "", "", "", fmt.Errorf("unrecognized machine role %s", role) 313 } 314 } 315 316 // getVMNetworkingType should set the correct capability for instance type 317 func getVMNetworkingType(value string) bool { 318 return value == string(azure.VMnetworkingTypeAccelerated) 319 } 320 321 func generateSecurityProfile(mpool *azure.MachinePool) *machineapi.SecurityProfile { 322 securityProfile := &machineapi.SecurityProfile{} 323 324 if mpool.EncryptionAtHost { 325 securityProfile.EncryptionAtHost = &mpool.EncryptionAtHost 326 } 327 328 if mpool.Settings != nil && mpool.Settings.SecurityType != "" { 329 securityProfile.Settings = machineapi.SecuritySettings{ 330 SecurityType: machineapi.SecurityTypes(mpool.Settings.SecurityType), 331 } 332 333 var uefiSettings machineapi.UEFISettings 334 if securityProfile.Settings.SecurityType == machineapi.SecurityTypesTrustedLaunch { 335 if mpool.Settings.TrustedLaunch != nil && mpool.Settings.TrustedLaunch.UEFISettings != nil { 336 if sb := mpool.Settings.TrustedLaunch.UEFISettings.SecureBoot; sb != nil { 337 uefiSettings.SecureBoot = machineapi.SecureBootPolicy(*sb) 338 } 339 if vtpm := mpool.Settings.TrustedLaunch.UEFISettings.VirtualizedTrustedPlatformModule; vtpm != nil { 340 uefiSettings.VirtualizedTrustedPlatformModule = machineapi.VirtualizedTrustedPlatformModulePolicy(*vtpm) 341 } 342 343 securityProfile.Settings.TrustedLaunch = &machineapi.TrustedLaunch{ 344 UEFISettings: uefiSettings, 345 } 346 } 347 } else if securityProfile.Settings.SecurityType == machineapi.SecurityTypesConfidentialVM { 348 if mpool.Settings.ConfidentialVM != nil && mpool.Settings.ConfidentialVM.UEFISettings != nil { 349 if sb := mpool.Settings.ConfidentialVM.UEFISettings.SecureBoot; sb != nil { 350 uefiSettings.SecureBoot = machineapi.SecureBootPolicy(*sb) 351 } 352 if vtpm := mpool.Settings.ConfidentialVM.UEFISettings.VirtualizedTrustedPlatformModule; vtpm != nil { 353 uefiSettings.VirtualizedTrustedPlatformModule = machineapi.VirtualizedTrustedPlatformModulePolicy(*vtpm) 354 } 355 356 securityProfile.Settings.ConfidentialVM = &machineapi.ConfidentialVM{ 357 UEFISettings: uefiSettings, 358 } 359 } 360 } 361 } 362 363 return securityProfile 364 }