func (client *cinderClient) terminateConnection(id string, copts *volumeactions.ConnectorOpts) error { terminateResult := volumeactions.TerminateConnection(client.cinder, id, copts) if terminateResult.Err != nil && terminateResult.Err.Error() != "EOF" { glog.Warningf("Terminate cinder volume %s failed: %v", id, terminateResult.Err) } return nil }
func TestVolumeConns(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) connOpts := &volumeactions.ConnectorOpts{ IP: "127.0.0.1", Host: "stack", Initiator: "iqn.1994-05.com.redhat:17cf566367d2", Multipath: false, Platform: "x86_64", OSType: "linux2", } t.Logf("Initializing connection") _, err = volumeactions.InitializeConnection(client, cv.ID, connOpts).Extract() th.AssertNoErr(t, err) t.Logf("Terminating connection") err = volumeactions.TerminateConnection(client, cv.ID, connOpts).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{} }