diff --git a/pkg/cloudprovider/providers/azure/BUILD b/pkg/cloudprovider/providers/azure/BUILD index df856b22d50..8a87451e89c 100644 --- a/pkg/cloudprovider/providers/azure/BUILD +++ b/pkg/cloudprovider/providers/azure/BUILD @@ -30,6 +30,7 @@ go_library( "//pkg/cloudprovider:go_default_library", "//pkg/types:go_default_library", "//pkg/util/errors:go_default_library", + "//pkg/volume:go_default_library", "//vendor:github.com/Azure/azure-sdk-for-go/arm/compute", "//vendor:github.com/Azure/azure-sdk-for-go/arm/network", "//vendor:github.com/Azure/azure-sdk-for-go/arm/storage", diff --git a/pkg/cloudprovider/providers/azure/azure_blob.go b/pkg/cloudprovider/providers/azure/azure_blob.go index 4804877c171..5cca3bd7761 100644 --- a/pkg/cloudprovider/providers/azure/azure_blob.go +++ b/pkg/cloudprovider/providers/azure/azure_blob.go @@ -19,6 +19,7 @@ package azure import ( "fmt" "regexp" + "strings" azs "github.com/Azure/azure-sdk-for-go/storage" ) @@ -40,9 +41,20 @@ func (az *Cloud) createVhdBlob(accountName, accountKey, name string, sizeGB int6 // Blob name in URL must end with '.vhd' extension. name = name + ".vhd" err = blobClient.PutPageBlob(vhdContainerName, name, vhdSize, tags) + if err != nil { + // if container doesn't exist, create one and retry PutPageBlob + detail := err.Error() + if strings.Contains(detail, errContainerNotFound) { + err = blobClient.CreateContainer(vhdContainerName, azs.ContainerAccessTypeContainer) + if err == nil { + err = blobClient.PutPageBlob(vhdContainerName, name, vhdSize, tags) + } + } + } if err != nil { return "", "", fmt.Errorf("failed to put page blob: %v", err) } + // add VHD signature to the blob h, err := createVHDHeader(uint64(size)) if err != nil { diff --git a/pkg/cloudprovider/providers/azure/azure_storage.go b/pkg/cloudprovider/providers/azure/azure_storage.go index b69e3cdffb4..bf7b11eec2c 100644 --- a/pkg/cloudprovider/providers/azure/azure_storage.go +++ b/pkg/cloudprovider/providers/azure/azure_storage.go @@ -24,10 +24,14 @@ import ( "github.com/golang/glog" "k8s.io/kubernetes/pkg/cloudprovider" "k8s.io/kubernetes/pkg/types" + "k8s.io/kubernetes/pkg/volume" ) const ( - maxLUN = 64 // max number of LUNs per VM + maxLUN = 64 // max number of LUNs per VM + errLeaseFailed = "AcquireDiskLeaseFailed" + errLeaseIDMissing = "LeaseIdMissing" + errContainerNotFound = "ContainerNotFound" ) // AttachDisk attaches a vhd to vm @@ -64,7 +68,7 @@ func (az *Cloud) AttachDisk(diskName, diskURI string, nodeName types.NodeName, l if err != nil { glog.Errorf("azure attach failed, err: %v", err) detail := err.Error() - if strings.Contains(detail, "Code=\"AcquireDiskLeaseFailed\"") { + if strings.Contains(detail, errLeaseFailed) { // if lease cannot be acquired, immediately detach the disk and return the original error glog.Infof("failed to acquire disk lease, try detach") az.DetachDiskByName(diskName, diskURI, nodeName) @@ -235,6 +239,12 @@ func (az *Cloud) DeleteVolume(name, uri string) error { err = az.deleteVhdBlob(accountName, key, blob) if err != nil { glog.Warningf("failed to delete blob %s err: %v", uri, err) + detail := err.Error() + if strings.Contains(detail, errLeaseIDMissing) { + // disk is still being used + // see https://msdn.microsoft.com/en-us/library/microsoft.windowsazure.storage.blob.protocol.bloberrorcodestrings.leaseidmissing.aspx + return volume.NewDeletedVolumeInUseError(fmt.Sprintf("disk %q is still in use while being deleted", name)) + } return fmt.Errorf("failed to delete vhd %v, account %s, blob %s, err: %v", uri, accountName, blob, err) } glog.V(4).Infof("blob %s deleted", uri)