func (c *Cloud) GetLabelsForVolume(ctx context.Context, pv *v1.PersistentVolume) (map[string]string, error) {
	if pv.Spec.AzureDisk == nil {
		return nil, nil
	}
	if pv.Spec.AzureDisk.DiskName == cloudvolume.ProvisionedVolumeName {
		return nil, nil
	}
	return c.GetAzureDiskLabels(pv.Spec.AzureDisk.DataDiskURI)
}
GetLabelsForVolume implements PVLabeler.GetLabelsForVolume
package azure
import (
	"context"
	"fmt"
	"net/http"
	"path"
	"strconv"
	"strings"
	"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute"
	"github.com/Azure/go-autorest/autorest/to"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	kwait "k8s.io/apimachinery/pkg/util/wait"
	cloudvolume "k8s.io/cloud-provider/volume"
	volumehelpers "k8s.io/cloud-provider/volume/helpers"
	"k8s.io/klog/v2"
)
const (
	defaultDiskIOPSReadWrite = 500
	defaultDiskMBpsReadWrite = 100
	diskEncryptionSetIDFormat = "/subscriptions/{subs-id}/resourceGroups/{rg-name}/providers/Microsoft.Compute/diskEncryptionSets/{diskEncryptionSet-name}"
)
type ManagedDiskController struct {
	common *controllerCommon
}
type ManagedDiskOptions struct {
	DiskName string
	SizeGB int
	PVCName string
	ResourceGroup string
	AvailabilityZone string
	Tags map[string]string
	StorageAccountType compute.DiskStorageAccountTypes
	DiskIOPSReadWrite string
	DiskMBpsReadWrite string
	SourceResourceID string
	SourceType string
	DiskEncryptionSetID string
	MaxShares int32
}
func (c *ManagedDiskController) CreateManagedDisk(options *ManagedDiskOptions) (string, error) {
	var err error
	klog.V(4).Infof("azureDisk - creating new managed Name:%s StorageAccountType:%s Size:%v", options.DiskName, options.StorageAccountType, options.SizeGB)
	var createZones []string
	if len(options.AvailabilityZone) > 0 {
		requestedZone := c.common.cloud.GetZoneID(options.AvailabilityZone)
		if requestedZone != "" {
			createZones = append(createZones, requestedZone)
		}
	}
	newTags := make(map[string]*string)
	azureDDTag := "kubernetes-azure-dd"
	newTags["created-by"] = &azureDDTag
	if options.Tags != nil {
		for k, v := range options.Tags {
			newKey := strings.Replace(k, "/", "-", -1)
			newValue := strings.Replace(v, "/", "-", -1)
			newTags[newKey] = &newValue
		}
	}
	diskSizeGB := int32(options.SizeGB)
	diskSku := compute.DiskStorageAccountTypes(options.StorageAccountType)
	creationData, err := getValidCreationData(c.common.subscriptionID, options.ResourceGroup, options.SourceResourceID, options.SourceType)
	if err != nil {
		return "", err
	}
	diskProperties := compute.DiskProperties{
		DiskSizeGB:   &diskSizeGB,
		CreationData: &creationData,
	}
	if diskSku == compute.UltraSSDLRS {
		diskIOPSReadWrite := int64(defaultDiskIOPSReadWrite)
		if options.DiskIOPSReadWrite != "" {
			v, err := strconv.Atoi(options.DiskIOPSReadWrite)
			if err != nil {
				return "", fmt.Errorf("AzureDisk - failed to parse DiskIOPSReadWrite: %v", err)
			}
			diskIOPSReadWrite = int64(v)
		}
		diskProperties.DiskIOPSReadWrite = to.Int64Ptr(diskIOPSReadWrite)
		diskMBpsReadWrite := int64(defaultDiskMBpsReadWrite)
		if options.DiskMBpsReadWrite != "" {
			v, err := strconv.Atoi(options.DiskMBpsReadWrite)
			if err != nil {
				return "", fmt.Errorf("AzureDisk - failed to parse DiskMBpsReadWrite: %v", err)
			}
			diskMBpsReadWrite = int64(v)
		}
		diskProperties.DiskMBpsReadWrite = to.Int64Ptr(diskMBpsReadWrite)
	} else {
		if options.DiskIOPSReadWrite != "" {
			return "", fmt.Errorf("AzureDisk - DiskIOPSReadWrite parameter is only applicable in UltraSSD_LRS disk type")
		}
		if options.DiskMBpsReadWrite != "" {
			return "", fmt.Errorf("AzureDisk - DiskMBpsReadWrite parameter is only applicable in UltraSSD_LRS disk type")
		}
	}
	if options.DiskEncryptionSetID != "" {
		if strings.Index(strings.ToLower(options.DiskEncryptionSetID), "/subscriptions/") != 0 {
			return "", fmt.Errorf("AzureDisk - format of DiskEncryptionSetID(%s) is incorrect, correct format: %s", options.DiskEncryptionSetID, diskEncryptionSetIDFormat)
		}
		diskProperties.Encryption = &compute.Encryption{
			DiskEncryptionSetID: &options.DiskEncryptionSetID,
			Type:                compute.EncryptionAtRestWithCustomerKey,
		}
	}
	if options.MaxShares > 1 {
		diskProperties.MaxShares = &options.MaxShares
	}
	model := compute.Disk{
		Location: &c.common.location,
		Tags:     newTags,
		Sku: &compute.DiskSku{
			Name: diskSku,
		},
		DiskProperties: &diskProperties,
	}
	if len(createZones) > 0 {
		model.Zones = &createZones
	}
	if options.ResourceGroup == "" {
		options.ResourceGroup = c.common.resourceGroup
	}
	ctx, cancel := getContextWithCancel()
	defer cancel()
	rerr := c.common.cloud.DisksClient.CreateOrUpdate(ctx, options.ResourceGroup, options.DiskName, model)
	if rerr != nil {
		return "", rerr.Error()
	}
	diskID := ""
	err = kwait.ExponentialBackoff(defaultBackOff, func() (bool, error) {
		provisionState, id, err := c.GetDisk(options.ResourceGroup, options.DiskName)
		diskID = id
		if err != nil {
			return false, err
		}
		if strings.ToLower(provisionState) == "succeeded" {
			return true, nil
		}
		return false, nil
	})
	if err != nil {
		klog.V(2).Infof("azureDisk - created new MD Name:%s StorageAccountType:%s Size:%v but was unable to confirm provisioningState in poll process", options.DiskName, options.StorageAccountType, options.SizeGB)
	} else {
		klog.V(2).Infof("azureDisk - created new MD Name:%s StorageAccountType:%s Size:%v", options.DiskName, options.StorageAccountType, options.SizeGB)
	}
	return diskID, nil
}
func (c *ManagedDiskController) DeleteManagedDisk(diskURI string) error {
	diskName := path.Base(diskURI)
	resourceGroup, err := getResourceGroupFromDiskURI(diskURI)
	if err != nil {
		return err
	}
	ctx, cancel := getContextWithCancel()
	defer cancel()
	if _, ok := c.common.diskAttachDetachMap.Load(strings.ToLower(diskURI)); ok {
		return fmt.Errorf("failed to delete disk(%s) since it's in attaching or detaching state", diskURI)
	}
	disk, rerr := c.common.cloud.DisksClient.Get(ctx, resourceGroup, diskName)
	if rerr != nil {
		return rerr.Error()
	}
	if disk.ManagedBy != nil {
		return fmt.Errorf("disk(%s) already attached to node(%s), could not be deleted", diskURI, *disk.ManagedBy)
	}
	rerr = c.common.cloud.DisksClient.Delete(ctx, resourceGroup, diskName)
	if rerr != nil {
		if rerr.HTTPStatusCode == http.StatusNotFound {
			klog.V(2).Infof("azureDisk - disk(%s) is already deleted", diskURI)
			return nil
		}
		return rerr.Error()
	}
	klog.V(2).Infof("azureDisk - deleted a managed disk: %s", diskURI)
	return nil
}
func (c *ManagedDiskController) GetDisk(resourceGroup, diskName string) (string, string, error) {
	ctx, cancel := getContextWithCancel()
	defer cancel()
	result, rerr := c.common.cloud.DisksClient.Get(ctx, resourceGroup, diskName)
	if rerr != nil {
		return "", "", rerr.Error()
	}
	if result.DiskProperties != nil && (*result.DiskProperties).ProvisioningState != nil {
		return *(*result.DiskProperties).ProvisioningState, *result.ID, nil
	}
	return "", "", nil
}
func (c *ManagedDiskController) ResizeDisk(diskURI string, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) {
	ctx, cancel := getContextWithCancel()
	defer cancel()
	diskName := path.Base(diskURI)
	resourceGroup, err := getResourceGroupFromDiskURI(diskURI)
	if err != nil {
		return oldSize, err
	}
	result, rerr := c.common.cloud.DisksClient.Get(ctx, resourceGroup, diskName)
	if rerr != nil {
		return oldSize, rerr.Error()
	}
	if result.DiskProperties == nil || result.DiskProperties.DiskSizeGB == nil {
		return oldSize, fmt.Errorf("DiskProperties of disk(%s) is nil", diskName)
	}
	requestGiB, err := volumehelpers.RoundUpToGiBInt32(newSize)
	if err != nil {
		return oldSize, err
	}
	newSizeQuant := resource.MustParse(fmt.Sprintf("%dGi", requestGiB))
	klog.V(2).Infof("azureDisk - begin to resize disk(%s) with new size(%d), old size(%v)", diskName, requestGiB, oldSize)
	if *result.DiskProperties.DiskSizeGB >= requestGiB {
		return newSizeQuant, nil
	}
	if result.DiskProperties.DiskState != compute.Unattached {
		return oldSize, fmt.Errorf("azureDisk - disk resize is only supported on Unattached disk, current disk state: %s, already attached to %s", result.DiskProperties.DiskState, to.String(result.ManagedBy))
	}
	diskParameter := compute.DiskUpdate{
		DiskUpdateProperties: &compute.DiskUpdateProperties{
			DiskSizeGB: &requestGiB,
		},
	}
	ctx, cancel = getContextWithCancel()
	defer cancel()
	if rerr := c.common.cloud.DisksClient.Update(ctx, resourceGroup, diskName, diskParameter); rerr != nil {
		return oldSize, rerr.Error()
	}
	klog.V(2).Infof("azureDisk - resize disk(%s) with new size(%d) completed", diskName, requestGiB)
	return newSizeQuant, nil
}
func getResourceGroupFromDiskURI(diskURI string) (string, error) {
	fields := strings.Split(diskURI, "/")
	if len(fields) != 9 || strings.ToLower(fields[3]) != "resourcegroups" {
		return "", fmt.Errorf("invalid disk URI: %s", diskURI)
	}
	return fields[4], nil
}