package openstack import ( "log" "time" "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes" "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images" ) // WaitForVolume waits for the given volume to become available. func WaitForVolume(blockStorageClient *gophercloud.ServiceClient, volumeID string) error { maxNumErrors := 10 numErrors := 0 for { status, err := GetVolumeStatus(blockStorageClient, volumeID) if err != nil { errCode, ok := err.(*gophercloud.ErrUnexpectedResponseCode) if ok && (errCode.Actual == 500 || errCode.Actual == 404) { numErrors++ if numErrors >= maxNumErrors { log.Printf("[ERROR] Maximum number of errors (%d) reached; failing with: %s", numErrors, err) return err } log.Printf("[ERROR] %d error received, will ignore and retry: %s", errCode.Actual, err) time.Sleep(2 * time.Second) continue } return err } if status == "available" { return nil } log.Printf("Waiting for volume creation status: %s", status) time.Sleep(2 * time.Second) } } // GetVolumeSize returns volume size in gigabytes based on the image min disk // value if it's not empty. // Or it calculates needed gigabytes size from the image bytes size. func GetVolumeSize(imageClient *gophercloud.ServiceClient, imageID string) (int, error) { sourceImage, err := images.Get(imageClient, imageID).Extract() if err != nil { return 0, err } if sourceImage.MinDiskGigabytes != 0 { return sourceImage.MinDiskGigabytes, nil } volumeSizeMB := sourceImage.SizeBytes / 1024 / 1024 volumeSizeGB := int(sourceImage.SizeBytes / 1024 / 1024 / 1024) // Increment gigabytes size if the initial size can't be divided without // remainder. if volumeSizeMB%1024 > 0 { volumeSizeGB++ } return volumeSizeGB, nil } func GetVolumeStatus(blockStorageClient *gophercloud.ServiceClient, volumeID string) (string, error) { volume, err := volumes.Get(blockStorageClient, volumeID).Extract() if err != nil { return "", err } return volume.Status, nil }