sigs.k8s.io/cluster-api-provider-azure@v1.17.0/azure/converters/vmss.go (about)

     1  /*
     2  Copyright 2020 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package converters
    18  
    19  import (
    20  	"regexp"
    21  
    22  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
    23  	"k8s.io/utils/ptr"
    24  	azprovider "sigs.k8s.io/cloud-provider-azure/pkg/provider"
    25  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    26  	"sigs.k8s.io/cluster-api-provider-azure/azure"
    27  )
    28  
    29  const (
    30  	// RegExpStrCommunityGalleryID is a regexp string used for matching community gallery IDs and capturing specific values.
    31  	RegExpStrCommunityGalleryID = `/CommunityGalleries/(?P<gallery>.*)/Images/(?P<name>.*)/Versions/(?P<version>.*)`
    32  	// RegExpStrComputeGalleryID is a regexp string used for matching compute gallery IDs and capturing specific values.
    33  	RegExpStrComputeGalleryID = `/subscriptions/(?P<subID>.*)/resourceGroups/(?P<rg>.*)/providers/Microsoft.Compute/galleries/(?P<gallery>.*)/images/(?P<name>.*)/versions/(?P<version>.*)`
    34  )
    35  
    36  // SDKToVMSS converts an Azure SDK VirtualMachineScaleSet to the AzureMachinePool type.
    37  func SDKToVMSS(sdkvmss armcompute.VirtualMachineScaleSet, sdkinstances []armcompute.VirtualMachineScaleSetVM) azure.VMSS {
    38  	vmss := azure.VMSS{
    39  		ID:    ptr.Deref(sdkvmss.ID, ""),
    40  		Name:  ptr.Deref(sdkvmss.Name, ""),
    41  		State: infrav1.ProvisioningState(ptr.Deref(sdkvmss.Properties.ProvisioningState, "")),
    42  	}
    43  
    44  	if sdkvmss.SKU != nil {
    45  		vmss.Sku = ptr.Deref(sdkvmss.SKU.Name, "")
    46  		vmss.Capacity = ptr.Deref[int64](sdkvmss.SKU.Capacity, 0)
    47  	}
    48  
    49  	for _, zone := range sdkvmss.Zones {
    50  		vmss.Zones = append(vmss.Zones, *zone)
    51  	}
    52  
    53  	if len(sdkvmss.Tags) > 0 {
    54  		vmss.Tags = MapToTags(sdkvmss.Tags)
    55  	}
    56  
    57  	if len(sdkinstances) > 0 {
    58  		vmss.Instances = make([]azure.VMSSVM, len(sdkinstances))
    59  		orchestrationMode := ptr.Deref(sdkvmss.Properties.OrchestrationMode, "")
    60  		for i, vm := range sdkinstances {
    61  			vmss.Instances[i] = *SDKToVMSSVM(vm)
    62  			vmss.Instances[i].OrchestrationMode = infrav1.OrchestrationModeType(orchestrationMode)
    63  		}
    64  	}
    65  
    66  	if sdkvmss.Properties.VirtualMachineProfile != nil &&
    67  		sdkvmss.Properties.VirtualMachineProfile.StorageProfile != nil &&
    68  		sdkvmss.Properties.VirtualMachineProfile.StorageProfile.ImageReference != nil {
    69  		imageRef := sdkvmss.Properties.VirtualMachineProfile.StorageProfile.ImageReference
    70  		vmss.Image = SDKImageToImage(imageRef, sdkvmss.Plan != nil)
    71  	}
    72  
    73  	return vmss
    74  }
    75  
    76  // SDKVMToVMSSVM converts an Azure SDK VM to a VMSS VM.
    77  func SDKVMToVMSSVM(sdkInstance armcompute.VirtualMachine, mode infrav1.OrchestrationModeType) *azure.VMSSVM {
    78  	instance := azure.VMSSVM{
    79  		ID: ptr.Deref(sdkInstance.ID, ""),
    80  	}
    81  
    82  	if sdkInstance.Properties == nil {
    83  		return &instance
    84  	}
    85  
    86  	instance.State = infrav1.Creating
    87  	if sdkInstance.Properties.ProvisioningState != nil {
    88  		instance.State = infrav1.ProvisioningState(ptr.Deref(sdkInstance.Properties.ProvisioningState, ""))
    89  	}
    90  
    91  	if sdkInstance.Properties.OSProfile != nil && sdkInstance.Properties.OSProfile.ComputerName != nil {
    92  		instance.Name = *sdkInstance.Properties.OSProfile.ComputerName
    93  	}
    94  
    95  	if sdkInstance.Properties.StorageProfile != nil && sdkInstance.Properties.StorageProfile.ImageReference != nil {
    96  		imageRef := sdkInstance.Properties.StorageProfile.ImageReference
    97  		instance.Image = SDKImageToImage(imageRef, sdkInstance.Plan != nil)
    98  	}
    99  
   100  	if len(sdkInstance.Zones) > 0 {
   101  		// An instance should have only 1 zone, so use the first item of the slice.
   102  		instance.AvailabilityZone = *sdkInstance.Zones[0]
   103  	}
   104  
   105  	instance.OrchestrationMode = mode
   106  
   107  	return &instance
   108  }
   109  
   110  // SDKToVMSSVM converts an Azure SDK VirtualMachineScaleSetVM into an infrav1exp.VMSSVM.
   111  func SDKToVMSSVM(sdkInstance armcompute.VirtualMachineScaleSetVM) *azure.VMSSVM {
   112  	// Convert resourceGroup Name ID ( ProviderID in capz objects )
   113  	var convertedID string
   114  	convertedID, err := azprovider.ConvertResourceGroupNameToLower(ptr.Deref(sdkInstance.ID, ""))
   115  	if err != nil {
   116  		convertedID = ptr.Deref(sdkInstance.ID, "")
   117  	}
   118  
   119  	instance := azure.VMSSVM{
   120  		ID:         convertedID,
   121  		InstanceID: ptr.Deref(sdkInstance.InstanceID, ""),
   122  	}
   123  
   124  	if sdkInstance.Properties == nil {
   125  		return &instance
   126  	}
   127  
   128  	instance.State = infrav1.Creating
   129  	if sdkInstance.Properties.ProvisioningState != nil {
   130  		instance.State = infrav1.ProvisioningState(ptr.Deref(sdkInstance.Properties.ProvisioningState, ""))
   131  	}
   132  
   133  	if sdkInstance.Properties.OSProfile != nil && sdkInstance.Properties.OSProfile.ComputerName != nil {
   134  		instance.Name = *sdkInstance.Properties.OSProfile.ComputerName
   135  	}
   136  
   137  	if sdkInstance.Resources != nil {
   138  		for _, r := range sdkInstance.Resources {
   139  			if r.Properties.ProvisioningState != nil && r.Name != nil &&
   140  				(*r.Name == azure.BootstrappingExtensionLinux || *r.Name == azure.BootstrappingExtensionWindows) {
   141  				instance.BootstrappingState = infrav1.ProvisioningState(ptr.Deref(r.Properties.ProvisioningState, ""))
   142  				break
   143  			}
   144  		}
   145  	}
   146  
   147  	if sdkInstance.Properties.StorageProfile != nil && sdkInstance.Properties.StorageProfile.ImageReference != nil {
   148  		imageRef := sdkInstance.Properties.StorageProfile.ImageReference
   149  		instance.Image = SDKImageToImage(imageRef, sdkInstance.Plan != nil)
   150  	}
   151  
   152  	if len(sdkInstance.Zones) > 0 {
   153  		// an instance should only have 1 zone, so we select the first item of the slice
   154  		instance.AvailabilityZone = *sdkInstance.Zones[0]
   155  	}
   156  
   157  	return &instance
   158  }
   159  
   160  // SDKImageToImage converts a SDK image reference to infrav1.Image.
   161  func SDKImageToImage(sdkImageRef *armcompute.ImageReference, isThirdPartyImage bool) infrav1.Image {
   162  	if sdkImageRef.ID != nil {
   163  		return IDImageRefToImage(*sdkImageRef.ID)
   164  	}
   165  	// community gallery image
   166  	if sdkImageRef.CommunityGalleryImageID != nil {
   167  		return cgImageRefToImage(*sdkImageRef.CommunityGalleryImageID)
   168  	}
   169  	// shared gallery image
   170  	if sdkImageRef.SharedGalleryImageID != nil {
   171  		return sgImageRefToImage(*sdkImageRef.SharedGalleryImageID)
   172  	}
   173  	// marketplace image
   174  	return mpImageRefToImage(sdkImageRef, isThirdPartyImage)
   175  }
   176  
   177  // GetOrchestrationMode returns the compute.OrchestrationMode for the given infrav1.OrchestrationModeType.
   178  func GetOrchestrationMode(modeType infrav1.OrchestrationModeType) armcompute.OrchestrationMode {
   179  	if modeType == infrav1.FlexibleOrchestrationMode {
   180  		return armcompute.OrchestrationModeFlexible
   181  	}
   182  	return armcompute.OrchestrationModeUniform
   183  }
   184  
   185  // IDImageRefToImage converts an ID to a infrav1.Image with ComputerGallery set or ID, depending on the structure of the ID.
   186  func IDImageRefToImage(id string) infrav1.Image {
   187  	// compute gallery image
   188  	if ok, params := getParams(RegExpStrComputeGalleryID, id); ok {
   189  		return infrav1.Image{
   190  			ComputeGallery: &infrav1.AzureComputeGalleryImage{
   191  				Gallery:        params["gallery"],
   192  				Name:           params["name"],
   193  				Version:        params["version"],
   194  				SubscriptionID: ptr.To(params["subID"]),
   195  				ResourceGroup:  ptr.To(params["rg"]),
   196  			},
   197  		}
   198  	}
   199  
   200  	// specific image
   201  	return infrav1.Image{
   202  		ID: &id,
   203  	}
   204  }
   205  
   206  // mpImageRefToImage converts a marketplace gallery ImageReference to an infrav1.Image.
   207  func mpImageRefToImage(sdkImageRef *armcompute.ImageReference, isThirdPartyImage bool) infrav1.Image {
   208  	return infrav1.Image{
   209  		Marketplace: &infrav1.AzureMarketplaceImage{
   210  			ImagePlan: infrav1.ImagePlan{
   211  				Publisher: ptr.Deref(sdkImageRef.Publisher, ""),
   212  				Offer:     ptr.Deref(sdkImageRef.Offer, ""),
   213  				SKU:       ptr.Deref(sdkImageRef.SKU, ""),
   214  			},
   215  			Version:         ptr.Deref(sdkImageRef.Version, ""),
   216  			ThirdPartyImage: isThirdPartyImage,
   217  		},
   218  	}
   219  }
   220  
   221  // cgImageRefToImage converts a community gallery ImageReference to an infrav1.Image.
   222  func cgImageRefToImage(id string) infrav1.Image {
   223  	if ok, params := getParams(RegExpStrCommunityGalleryID, id); ok {
   224  		return infrav1.Image{
   225  			ComputeGallery: &infrav1.AzureComputeGalleryImage{
   226  				Gallery: params["gallery"],
   227  				Name:    params["name"],
   228  				Version: params["version"],
   229  			},
   230  		}
   231  	}
   232  	return infrav1.Image{}
   233  }
   234  
   235  // sgImageRefToImage converts a shared gallery ImageReference to an infrav1.Image.
   236  func sgImageRefToImage(id string) infrav1.Image {
   237  	if ok, params := getParams(RegExpStrComputeGalleryID, id); ok {
   238  		return infrav1.Image{
   239  			SharedGallery: &infrav1.AzureSharedGalleryImage{
   240  				SubscriptionID: params["subID"],
   241  				ResourceGroup:  params["rg"],
   242  				Gallery:        params["gallery"],
   243  				Name:           params["name"],
   244  				Version:        params["version"],
   245  			},
   246  		}
   247  	}
   248  	return infrav1.Image{}
   249  }
   250  
   251  func getParams(regStr, str string) (matched bool, params map[string]string) {
   252  	re := regexp.MustCompile(regStr)
   253  	match := re.FindAllStringSubmatch(str, -1)
   254  
   255  	if len(match) == 1 {
   256  		params = make(map[string]string)
   257  		for i, name := range re.SubexpNames() {
   258  			if i > 0 && i <= len(match[0]) {
   259  				params[name] = match[0][i]
   260  			}
   261  		}
   262  		matched = true
   263  	}
   264  
   265  	return matched, params
   266  }