func resourceBlockStorageVolumeV1Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) blockStorageClient, err := config.blockStorageV1Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack block storage client: %s", err) } v, err := volumes.Get(blockStorageClient, d.Id()).Extract() if err != nil { return CheckDeleted(d, err, "volume") } log.Printf("[DEBUG] Retrieved volume %s: %+v", d.Id(), v) d.Set("size", v.Size) d.Set("description", v.Description) d.Set("availability_zone", v.AvailabilityZone) d.Set("name", v.Name) d.Set("snapshot_id", v.SnapshotID) d.Set("source_vol_id", v.SourceVolID) d.Set("volume_type", v.VolumeType) d.Set("metadata", v.Metadata) attachments := make([]map[string]interface{}, len(v.Attachments)) for i, attachment := range v.Attachments { attachments[i] = make(map[string]interface{}) attachments[i]["id"] = attachment["id"] attachments[i]["instance_id"] = attachment["server_id"] attachments[i]["device"] = attachment["device"] log.Printf("[DEBUG] attachment: %v", attachment) } d.Set("attachment", attachments) return nil }
func testAccCheckBlockStorageV1VolumeExists(n string, volume *volumes.Volume) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } config := testAccProvider.Meta().(*Config) blockStorageClient, err := config.blockStorageV1Client(OS_REGION_NAME) if err != nil { return fmt.Errorf("Error creating OpenStack block storage client: %s", err) } found, err := volumes.Get(blockStorageClient, rs.Primary.ID).Extract() if err != nil { return err } if found.ID != rs.Primary.ID { return fmt.Errorf("Volume not found") } *volume = *found return nil } }
// VolumeV1StateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // an OpenStack volume. func VolumeV1StateRefreshFunc(client *gophercloud.ServiceClient, volumeID string) resource.StateRefreshFunc { return func() (interface{}, string, error) { v, err := volumes.Get(client, volumeID).Extract() if err != nil { if _, ok := err.(gophercloud.ErrDefault404); ok { return v, "deleted", nil } return nil, "", err } return v, v.Status, nil } }
func TestVolumesCreateDestroy(t *testing.T) { client, err := clients.NewBlockStorageV1Client() if err != nil { t.Fatalf("Unable to create blockstorage client: %v", err) } volume, err := CreateVolume(t, client) if err != nil { t.Fatalf("Unable to create volume: %v", err) } defer DeleteVolume(t, client, volume) newVolume, err := volumes.Get(client, volume.ID).Extract() if err != nil { t.Errorf("Unable to retrieve volume: %v", err) } PrintVolume(t, newVolume) }
// VolumeV1StateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // an OpenStack volume. func VolumeV1StateRefreshFunc(client *gophercloud.ServiceClient, volumeID string) resource.StateRefreshFunc { return func() (interface{}, string, error) { v, err := volumes.Get(client, volumeID).Extract() if err != nil { if _, ok := err.(gophercloud.ErrDefault404); ok { return v, "deleted", nil } return nil, "", err } if v.Status == "error" { return v, v.Status, fmt.Errorf("There was an error creating the volume. " + "Please check with your cloud admin or check the Block Storage " + "API logs to see why this error occurred.") } return v, v.Status, nil } }
func testAccCheckBlockStorageV1VolumeDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) blockStorageClient, err := config.blockStorageV1Client(OS_REGION_NAME) if err != nil { return fmt.Errorf("Error creating OpenStack block storage client: %s", err) } for _, rs := range s.RootModule().Resources { if rs.Type != "openstack_blockstorage_volume_v1" { continue } _, err := volumes.Get(blockStorageClient, rs.Primary.ID).Extract() if err == nil { return fmt.Errorf("Volume still exists") } } return nil }
func testAccCheckBlockStorageV1VolumeDoesNotExist(t *testing.T, n string, volume *volumes.Volume) resource.TestCheckFunc { return func(s *terraform.State) error { config := testAccProvider.Meta().(*Config) blockStorageClient, err := config.blockStorageV1Client(OS_REGION_NAME) if err != nil { return fmt.Errorf("Error creating OpenStack block storage client: %s", err) } _, err = volumes.Get(blockStorageClient, volume.ID).Extract() if err != nil { if _, ok := err.(gophercloud.ErrDefault404); ok { return nil } return err } return fmt.Errorf("Volume still exists") } }
func TestGet(t *testing.T) { th.SetupHTTP() defer th.TeardownHTTP() MockGetResponse(t) actual, err := volumes.Get(client.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract() th.AssertNoErr(t, err) expected := &volumes.Volume{ Status: "active", Name: "vol-001", Attachments: []map[string]interface{}{ { "attachment_id": "03987cd1-0ad5-40d1-9b2a-7cc48295d4fa", "id": "47e9ecc5-4045-4ee3-9a4b-d859d546a0cf", "volume_id": "6c80f8ac-e3e2-480c-8e6e-f1db92fe4bfe", "server_id": "d1c4788b-9435-42e2-9b81-29f3be1cd01f", "host_name": "mitaka", "device": "/", }, }, AvailabilityZone: "us-east1", Bootable: "false", CreatedAt: gophercloud.JSONRFC3339MilliNoZ(time.Date(2012, 2, 14, 20, 53, 07, 0, time.UTC)), Description: "Another volume.", VolumeType: "289da7f8-6440-407c-9fb4-7db01ec49164", SnapshotID: "", SourceVolID: "", Metadata: map[string]string{ "contents": "junk", }, ID: "521752a6-acf6-4b2d-bc7a-119f9148cd8c", Size: 30, } th.AssertDeepEquals(t, expected, actual) }
func resourceBlockStorageVolumeV1Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) blockStorageClient, err := config.blockStorageV1Client(GetRegion(d)) if err != nil { return fmt.Errorf("Error creating OpenStack block storage client: %s", err) } v, err := volumes.Get(blockStorageClient, d.Id()).Extract() if err != nil { return CheckDeleted(d, err, "volume") } // make sure this volume is detached from all instances before deleting if len(v.Attachments) > 0 { log.Printf("[DEBUG] detaching volumes") if computeClient, err := config.computeV2Client(GetRegion(d)); err != nil { return err } else { for _, volumeAttachment := range v.Attachments { log.Printf("[DEBUG] Attachment: %v", volumeAttachment) if err := volumeattach.Delete(computeClient, volumeAttachment["server_id"].(string), volumeAttachment["id"].(string)).ExtractErr(); err != nil { return err } } stateConf := &resource.StateChangeConf{ Pending: []string{"in-use", "attaching", "detaching"}, Target: []string{"available"}, Refresh: VolumeV1StateRefreshFunc(blockStorageClient, d.Id()), Timeout: 10 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, } _, err = stateConf.WaitForState() if err != nil { return fmt.Errorf( "Error waiting for volume (%s) to become available: %s", d.Id(), err) } } } // It's possible that this volume was used as a boot device and is currently // in a "deleting" state from when the instance was terminated. // If this is true, just move on. It'll eventually delete. if v.Status != "deleting" { if err := volumes.Delete(blockStorageClient, d.Id()).ExtractErr(); err != nil { return CheckDeleted(d, err, "volume") } } // Wait for the volume to delete before moving on. log.Printf("[DEBUG] Waiting for volume (%s) to delete", d.Id()) stateConf := &resource.StateChangeConf{ Pending: []string{"deleting", "downloading", "available"}, Target: []string{"deleted"}, Refresh: VolumeV1StateRefreshFunc(blockStorageClient, d.Id()), Timeout: 10 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, } _, err = stateConf.WaitForState() if err != nil { return fmt.Errorf( "Error waiting for volume (%s) to delete: %s", d.Id(), err) } d.SetId("") return nil }