|
| 1 | +// Package azure generates Machine objects for azure. |
| 2 | +package azure |
| 3 | + |
| 4 | +import ( |
| 5 | + "fmt" |
| 6 | + "strings" |
| 7 | + |
| 8 | + v1 "k8s.io/api/core/v1" |
| 9 | + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| 10 | + "k8s.io/apimachinery/pkg/util/sets" |
| 11 | + "k8s.io/utils/ptr" |
| 12 | + capz "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" |
| 13 | + capi "sigs.k8s.io/cluster-api/api/v1beta1" |
| 14 | + |
| 15 | + "github.com/openshift/api/machine/v1beta1" |
| 16 | + "github.com/openshift/installer/pkg/asset" |
| 17 | + "github.com/openshift/installer/pkg/asset/manifests/capiutils" |
| 18 | + "github.com/openshift/installer/pkg/types" |
| 19 | + "github.com/openshift/installer/pkg/types/azure" |
| 20 | +) |
| 21 | + |
| 22 | +const ( |
| 23 | + genV2Suffix string = "-gen2" |
| 24 | +) |
| 25 | + |
| 26 | +// GenerateMachines returns manifests and runtime objects to provision the control plane (including bootstrap, if applicable) nodes using CAPI. |
| 27 | +func GenerateMachines(platform *azure.Platform, pool *types.MachinePool, userDataSecret string, clusterID string, role string, capabilities map[string]string, useImageGallery bool, userTags map[string]string, hyperVGen string, subnet string, resourceGroup string) ([]*asset.RuntimeFile, error) { |
| 28 | + if poolPlatform := pool.Platform.Name(); poolPlatform != azure.Name { |
| 29 | + return nil, fmt.Errorf("non-Azure machine-pool: %q", poolPlatform) |
| 30 | + } |
| 31 | + mpool := pool.Platform.Azure |
| 32 | + |
| 33 | + total := int64(1) |
| 34 | + if pool.Replicas != nil { |
| 35 | + total = *pool.Replicas |
| 36 | + } |
| 37 | + |
| 38 | + if len(mpool.Zones) == 0 { |
| 39 | + // if no azs are given we set to []string{""} for convenience over later operations. |
| 40 | + // It means no-zoned for the machine API |
| 41 | + mpool.Zones = []string{""} |
| 42 | + } |
| 43 | + tags, err := CapzTagsFromUserTags(clusterID, userTags) |
| 44 | + if err != nil { |
| 45 | + return nil, fmt.Errorf("failed to create machineapi.TagSpecifications from UserTags: %w", err) |
| 46 | + } |
| 47 | + |
| 48 | + var image *capz.Image |
| 49 | + osImage := mpool.OSImage |
| 50 | + switch { |
| 51 | + case osImage.Publisher != "": |
| 52 | + image = &capz.Image{ |
| 53 | + Marketplace: &capz.AzureMarketplaceImage{ |
| 54 | + ImagePlan: capz.ImagePlan{ |
| 55 | + Publisher: osImage.Publisher, |
| 56 | + Offer: osImage.Offer, |
| 57 | + SKU: osImage.SKU, |
| 58 | + }, |
| 59 | + Version: osImage.Version, |
| 60 | + }, |
| 61 | + } |
| 62 | + case useImageGallery: |
| 63 | + // image gallery names cannot have dashes |
| 64 | + galleryName := strings.ReplaceAll(clusterID, "-", "_") |
| 65 | + id := clusterID |
| 66 | + if hyperVGen == "V2" { |
| 67 | + id += genV2Suffix |
| 68 | + } |
| 69 | + imageID := fmt.Sprintf("/resourceGroups/%s/providers/Microsoft.Compute/galleries/gallery_%s/images/%s/versions/latest", resourceGroup, galleryName, id) |
| 70 | + image = &capz.Image{ID: &imageID} |
| 71 | + default: |
| 72 | + imageID := fmt.Sprintf("/resourceGroups/%s/providers/Microsoft.Compute/images/%s", resourceGroup, clusterID) |
| 73 | + if hyperVGen == "V2" && platform.CloudName != azure.StackCloud { |
| 74 | + imageID += genV2Suffix |
| 75 | + } |
| 76 | + image = &capz.Image{ID: &imageID} |
| 77 | + } |
| 78 | + |
| 79 | + osDisk := capz.OSDisk{ |
| 80 | + OSType: "Linux", |
| 81 | + DiskSizeGB: &mpool.DiskSizeGB, |
| 82 | + ManagedDisk: &capz.ManagedDiskParameters{ |
| 83 | + StorageAccountType: mpool.DiskType, |
| 84 | + }, |
| 85 | + } |
| 86 | + ultrassd := mpool.UltraSSDCapability == "Enabled" |
| 87 | + additionalCapabilities := &capz.AdditionalCapabilities{ |
| 88 | + UltraSSDEnabled: &ultrassd, |
| 89 | + } |
| 90 | + |
| 91 | + machineProfile := generateSecurityProfile(mpool) |
| 92 | + securityProfile := &capz.SecurityProfile{ |
| 93 | + EncryptionAtHost: machineProfile.EncryptionAtHost, |
| 94 | + SecurityType: capz.SecurityTypes(machineProfile.Settings.SecurityType), |
| 95 | + } |
| 96 | + if machineProfile.Settings.ConfidentialVM != nil { |
| 97 | + securityProfile.UefiSettings = &capz.UefiSettings{ |
| 98 | + VTpmEnabled: ptr.To[bool](machineProfile.Settings.ConfidentialVM.UEFISettings.VirtualizedTrustedPlatformModule == v1beta1.VirtualizedTrustedPlatformModulePolicyEnabled), |
| 99 | + SecureBootEnabled: ptr.To[bool](machineProfile.Settings.ConfidentialVM.UEFISettings.SecureBoot == v1beta1.SecureBootPolicyEnabled), |
| 100 | + } |
| 101 | + } else if machineProfile.Settings.TrustedLaunch != nil { |
| 102 | + securityProfile.UefiSettings = &capz.UefiSettings{ |
| 103 | + VTpmEnabled: ptr.To(machineProfile.Settings.TrustedLaunch.UEFISettings.VirtualizedTrustedPlatformModule == v1beta1.VirtualizedTrustedPlatformModulePolicyEnabled), |
| 104 | + SecureBootEnabled: ptr.To(machineProfile.Settings.TrustedLaunch.UEFISettings.SecureBoot == v1beta1.SecureBootPolicyEnabled), |
| 105 | + } |
| 106 | + } |
| 107 | + |
| 108 | + var result []*asset.RuntimeFile |
| 109 | + for idx := int64(0); idx < total; idx++ { |
| 110 | + zone := mpool.Zones[int(idx)%len(mpool.Zones)] |
| 111 | + azureMachine := &capz.AzureMachine{ |
| 112 | + TypeMeta: metav1.TypeMeta{ |
| 113 | + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", |
| 114 | + Kind: "AzureMachine", |
| 115 | + }, |
| 116 | + ObjectMeta: metav1.ObjectMeta{ |
| 117 | + Name: fmt.Sprintf("%s-%s-%d", clusterID, pool.Name, idx), |
| 118 | + Labels: map[string]string{ |
| 119 | + "cluster.x-k8s.io/control-plane": "", |
| 120 | + "cluster.x-k8s.io/cluster-name": clusterID, |
| 121 | + }, |
| 122 | + }, |
| 123 | + Spec: capz.AzureMachineSpec{ |
| 124 | + VMSize: mpool.InstanceType, |
| 125 | + FailureDomain: ptr.To(zone), |
| 126 | + Image: image, |
| 127 | + OSDisk: osDisk, |
| 128 | + AdditionalTags: tags, |
| 129 | + AdditionalCapabilities: additionalCapabilities, |
| 130 | + AllocatePublicIP: false, |
| 131 | + SecurityProfile: securityProfile, |
| 132 | + }, |
| 133 | + } |
| 134 | + result = append(result, &asset.RuntimeFile{ |
| 135 | + File: asset.File{Filename: fmt.Sprintf("10_inframachine_%s.yaml", azureMachine.Name)}, |
| 136 | + Object: azureMachine, |
| 137 | + }) |
| 138 | + |
| 139 | + controlPlaneMachine := &capi.Machine{ |
| 140 | + ObjectMeta: metav1.ObjectMeta{ |
| 141 | + Name: azureMachine.Name, |
| 142 | + Labels: map[string]string{ |
| 143 | + "cluster.x-k8s.io/control-plane": "", |
| 144 | + }, |
| 145 | + }, |
| 146 | + Spec: capi.MachineSpec{ |
| 147 | + ClusterName: clusterID, |
| 148 | + Bootstrap: capi.Bootstrap{ |
| 149 | + DataSecretName: ptr.To(fmt.Sprintf("%s-%s", clusterID, role)), |
| 150 | + }, |
| 151 | + InfrastructureRef: v1.ObjectReference{ |
| 152 | + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta2", |
| 153 | + Kind: "AzureMachine", |
| 154 | + Name: azureMachine.Name, |
| 155 | + }, |
| 156 | + }, |
| 157 | + } |
| 158 | + |
| 159 | + result = append(result, &asset.RuntimeFile{ |
| 160 | + File: asset.File{Filename: fmt.Sprintf("10_machine_%s.yaml", azureMachine.Name)}, |
| 161 | + Object: controlPlaneMachine, |
| 162 | + }) |
| 163 | + } |
| 164 | + |
| 165 | + bootstrapAzureMachine := &capz.AzureMachine{ |
| 166 | + TypeMeta: metav1.TypeMeta{ |
| 167 | + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", |
| 168 | + Kind: "AzureMachine", |
| 169 | + }, |
| 170 | + ObjectMeta: metav1.ObjectMeta{ |
| 171 | + Name: capiutils.GenerateBoostrapMachineName(clusterID), |
| 172 | + Labels: map[string]string{ |
| 173 | + "cluster.x-k8s.io/control-plane": "", |
| 174 | + "install.openshift.io/bootstrap": "", |
| 175 | + "cluster.x-k8s.io/cluster-name": clusterID, |
| 176 | + }, |
| 177 | + }, |
| 178 | + Spec: capz.AzureMachineSpec{ |
| 179 | + VMSize: mpool.InstanceType, |
| 180 | + Image: image, |
| 181 | + FailureDomain: ptr.To(mpool.Zones[0]), |
| 182 | + OSDisk: osDisk, |
| 183 | + AdditionalTags: tags, |
| 184 | + AllocatePublicIP: true, |
| 185 | + AdditionalCapabilities: additionalCapabilities, |
| 186 | + SecurityProfile: securityProfile, |
| 187 | + }, |
| 188 | + } |
| 189 | + |
| 190 | + result = append(result, &asset.RuntimeFile{ |
| 191 | + File: asset.File{Filename: fmt.Sprintf("10_inframachine_%s.yaml", bootstrapAzureMachine.Name)}, |
| 192 | + Object: bootstrapAzureMachine, |
| 193 | + }) |
| 194 | + |
| 195 | + bootstrapMachine := &capi.Machine{ |
| 196 | + ObjectMeta: metav1.ObjectMeta{ |
| 197 | + Name: bootstrapAzureMachine.Name, |
| 198 | + Labels: map[string]string{ |
| 199 | + "cluster.x-k8s.io/control-plane": "", |
| 200 | + }, |
| 201 | + }, |
| 202 | + Spec: capi.MachineSpec{ |
| 203 | + ClusterName: clusterID, |
| 204 | + Bootstrap: capi.Bootstrap{ |
| 205 | + DataSecretName: ptr.To(fmt.Sprintf("%s-%s", clusterID, "bootstrap")), |
| 206 | + }, |
| 207 | + InfrastructureRef: v1.ObjectReference{ |
| 208 | + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta2", |
| 209 | + Kind: "AzureMachine", |
| 210 | + Name: bootstrapAzureMachine.Name, |
| 211 | + }, |
| 212 | + }, |
| 213 | + } |
| 214 | + |
| 215 | + result = append(result, &asset.RuntimeFile{ |
| 216 | + File: asset.File{Filename: fmt.Sprintf("10_machine_%s.yaml", bootstrapMachine.Name)}, |
| 217 | + Object: bootstrapMachine, |
| 218 | + }) |
| 219 | + |
| 220 | + return result, nil |
| 221 | +} |
| 222 | + |
| 223 | +// CapzTagsFromUserTags converts a map of user tags to a map of capz.Tags. |
| 224 | +func CapzTagsFromUserTags(clusterID string, usertags map[string]string) (capz.Tags, error) { |
| 225 | + tags := capz.Tags{} |
| 226 | + tags[fmt.Sprintf("kubernetes.io_cluster.%s", clusterID)] = "owned" |
| 227 | + |
| 228 | + forbiddenTags := sets.New[string]() |
| 229 | + for key := range tags { |
| 230 | + forbiddenTags.Insert(key) |
| 231 | + } |
| 232 | + |
| 233 | + userTagKeys := sets.New[string]() |
| 234 | + for key := range usertags { |
| 235 | + userTagKeys.Insert(key) |
| 236 | + } |
| 237 | + if clobberedTags := userTagKeys.Intersection(forbiddenTags); clobberedTags.Len() > 0 { |
| 238 | + return nil, fmt.Errorf("user tag keys %v are not allowed", sets.List(clobberedTags)) |
| 239 | + } |
| 240 | + for _, k := range sets.List(userTagKeys) { |
| 241 | + tags[k] = usertags[k] |
| 242 | + } |
| 243 | + return tags, nil |
| 244 | +} |
0 commit comments