Change:
<!-- Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks! If the matter is security related, please disclose it privately via --What happened: We found that cloud provider tries to attach a disk, it totally costs 121s in the end one minute(disk still in being detaching state), azure cloud provider tries to delete that disk and it succeeded 121s, attach disk operation succeeded and finally azure vm has attached one non-existing disk What you expected to happen: should not delete an azure disk when that disk is being attached How to reproduce it (as minimally and precisely as possible): Anything else we need to know?: The difficulty here is when a disk is being attached or detached, the disk state is still "unattached", would be the reason why delete disk at that time would succeed: Azure disk RP would have two options to fix this issue: a new disk state: , disk delete operation when disk is being attached or detached Otherwise on azure provider(client) side, we cannot know whether that disk is being attached or detached since the second delete disk operation is done after 1 min Environment: Kubernetes version (use ): Cloud provider or hardware configuration: OS (e.g: ): Kernel (e.g. ): Install tools: Network plugin and version (if this is a network-related bug): Others: /kind bug /assign /priority important-soon /sig cloud-provider /area provider/azure

Discussion:
"fmt" "path" "strings" <ins> "sync" </ins> "time" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"

location              string storageEndpointSuffix string resourceGroup         string <del> cloud                 *Cloud </del> <ins> // store disk URI when disk is in attaching or detaching process diskAttachDetachMap sync.Map cloud               *Cloud </ins> } // getNodeVMSet gets the VMSet interface based on config.VMType and the real virtual machine type.

} klog.V(2).Infof("Trying to attach volume %q lun %d to node %q.", diskURI, lun, nodeName) <ins> c.diskAttachDetachMap.Store(strings.ToLower(diskURI), "attaching") defer c.diskAttachDetachMap.Delete(strings.ToLower(diskURI)) </ins> return lun, vmset.AttachDisk(isManagedDisk, diskName, diskURI, nodeName, lun, cachingMode, diskEncryptionSetID) }

// make the lock here as small as possible diskOpMutex.LockKey(instanceid) <ins> c.diskAttachDetachMap.Store(strings.ToLower(diskURI), "detaching") </ins> resp, err := vmset.DetachDisk(diskName, diskURI, nodeName) <ins> c.diskAttachDetachMap.Delete(strings.ToLower(diskURI)) </ins> diskOpMutex.UnlockKey(instanceid) if c.cloud.CloudProviderBackoff && shouldRetryHTTPRequest(resp, err) { klog.V(2).Infof("azureDisk - update backing off: detach disk(%s, %s), err: %v", diskName, diskURI, err) retryErr := kwait.ExponentialBackoff(c.cloud.RequestBackoff(), func() (bool, error) { diskOpMutex.LockKey(instanceid) <ins> c.diskAttachDetachMap.Store(strings.ToLower(diskURI), "detaching") </ins> resp, err := vmset.DetachDisk(diskName, diskURI, nodeName) <ins> c.diskAttachDetachMap.Delete(strings.ToLower(diskURI)) </ins> diskOpMutex.UnlockKey(instanceid) return c.cloud.processHTTPRetryResponse(nil, "", resp, err) })

if disk.Lun != nil && (disk.Name != nil && diskName != "" && strings.EqualFold(*disk.Name, diskName)) || (disk.Vhd != nil && disk.Vhd.URI != nil && diskURI != "" && strings.EqualFold(*disk.Vhd.URI, diskURI)) || (disk.ManagedDisk != nil && strings.EqualFold(*disk.ManagedDisk.ID, diskURI)) { <del> // found the disk klog.V(2).Infof("azureDisk - find disk: lun %d name %q uri %q", *disk.Lun, diskName, diskURI) return *disk.Lun, nil </del> <ins> if disk.ToBeDetached != nil && *disk.ToBeDetached { klog.Warningf("azureDisk - find disk(ToBeDetached): lun %d name %q uri %q", *disk.Lun, diskName, diskURI) } else { // found the disk klog.V(2).Infof("azureDisk - find disk: lun %d name %q uri %q", *disk.Lun, diskName, diskURI) return *disk.Lun, nil } </ins> } } return -1, fmt.Errorf("cannot find Lun for disk %s", diskName)

ctx, cancel := getContextWithCancel() defer cancel() <ins> 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) } </ins> _, err = c.common.cloud.DisksClient.Delete(ctx, resourceGroup, diskName) if err != nil { return err