func TestVolumeActions(t *testing.T) { client, err := newClient(t) th.AssertNoErr(t, err) cv, err := volumes.Create(client, &volumes.CreateOpts{ Size: 1, Name: "blockv2-volume", }).Extract() th.AssertNoErr(t, err) defer func() { err = volumes.WaitForStatus(client, cv.ID, "available", 60) th.AssertNoErr(t, err) err = volumes.Delete(client, cv.ID).ExtractErr() th.AssertNoErr(t, err) }() err = volumes.WaitForStatus(client, cv.ID, "available", 60) th.AssertNoErr(t, err) _, err = volumeactions.Attach(client, cv.ID, &volumeactions.AttachOpts{ MountPoint: "/mnt", Mode: "rw", InstanceUUID: "50902f4f-a974-46a0-85e9-7efc5e22dfdd", }).Extract() th.AssertNoErr(t, err) err = volumes.WaitForStatus(client, cv.ID, "in-use", 60) th.AssertNoErr(t, err) _, err = volumeactions.Detach(client, cv.ID).Extract() th.AssertNoErr(t, err) }
func (client *cinderClient) detach(id string) error { detachResult := volumeactions.Detach(client.cinder, id) if detachResult.Err != nil && detachResult.Err.Error() != "EOF" { glog.Warningf("Detach cinder volume %s failed: %v", id, detachResult.Err) return detachResult.Err } return nil }
func TestVolumeAttach(t *testing.T) { client, err := newClient(t) th.AssertNoErr(t, err) t.Logf("Creating volume") cv, err := volumes.Create(client, &volumes.CreateOpts{ Size: 1, Name: "blockv2-volume", }).Extract() th.AssertNoErr(t, err) defer func() { err = volumes.WaitForStatus(client, cv.ID, "available", 60) th.AssertNoErr(t, err) t.Logf("Deleting volume") err = volumes.Delete(client, cv.ID).ExtractErr() th.AssertNoErr(t, err) }() err = volumes.WaitForStatus(client, cv.ID, "available", 60) th.AssertNoErr(t, err) instanceID := os.Getenv("OS_INSTANCE_ID") if instanceID == "" { t.Fatal("Environment variable OS_INSTANCE_ID is required") } t.Logf("Attaching volume") err = volumeactions.Attach(client, cv.ID, &volumeactions.AttachOpts{ MountPoint: "/mnt", Mode: "rw", InstanceUUID: instanceID, }).ExtractErr() th.AssertNoErr(t, err) err = volumes.WaitForStatus(client, cv.ID, "in-use", 60) th.AssertNoErr(t, err) t.Logf("Detaching volume") err = volumeactions.Detach(client, cv.ID).ExtractErr() th.AssertNoErr(t, err) }
func (d CinderDriver) Unmount(r volume.Request) volume.Response { log.Infof("Unmounting volume: %+v", r) d.Mutex.Lock() defer d.Mutex.Unlock() vol, err := d.getByName(r.Name) if vol.ID == "" { log.Errorf("Request to Unmount failed because volume `%s` could not be found", r.Name) err := errors.New("Volume Not Found") return volume.Response{Err: err.Error()} } if err != nil { log.Errorf("Failed to retrieve volume named: `", r.Name, "` during Unmount operation", err) return volume.Response{Err: err.Error()} } if umountErr := Umount(d.Conf.MountPoint + "/" + r.Name); umountErr != nil { if umountErr.Error() == "Volume is not mounted" { log.Warning("Request to unmount volume, but it's not mounted") return volume.Response{} } else { return volume.Response{Err: umountErr.Error()} } } // NOTE(jdg): So there's a couple issues with how Docker works here. If // you are trying to attach and it fails, it kindly goes through and does // an Unmount to clean up anything that went bad, BUT that creates a // problem here. Say for example you try to attach an in-use volume, we // don't want to rip that out from under wherever it's currently being used // NOTE(jdg): Don't rely on things like `df --output=source mounpoint` // that's no good for error situations. tgt, portal := getTgtInfo(vol) iscsiDetachVolume(tgt, portal) log.Debug("Terminate Connection") iface := d.Conf.InitiatorIFace netDev, _ := net.InterfaceByName(iface) IPs, _ := net.InterfaceAddrs() log.Debugf("iface: %+v\n Addrs: %+v", netDev, IPs) initiators, err := GetInitiatorIqns() if err != nil { log.Error("Failed to retrieve Initiator name!") return volume.Response{Err: err.Error()} } hostname, _ := os.Hostname() // TODO(ebalduf): Change assumption that we have only one Initiator defined // TODO(jdg): For now we're only supporting linux, but in the future we'll // need to get rid of the hard coded Platform/OSType and fix this up for // things like say Windows log.Debugf("IPs=%+v\n", IPs) connectorOpts := volumeactions.ConnectorOpts{ IP: d.Conf.InitiatorIP, Host: hostname, Initiator: initiators[0], Wwpns: []string{}, Wwnns: "", Multipath: false, Platform: "x86", OSType: "linux", } log.Debugf("Unreserve volume: %s", vol.ID) volumeactions.Unreserve(d.Client, vol.ID) log.Debugf("Terminate connection for volume: %s", vol.ID) volumeactions.TerminateConnection(d.Client, vol.ID, &connectorOpts) log.Debugf("Detach volume: %s", vol.ID) volumeactions.Detach(d.Client, vol.ID) return volume.Response{} }