Change:
During iscsi volume cleanup, kubelet reads from and retrieves a list of device paths where iscsi volume mounts on. The device path was expected to be in the form of . But currently the device path in is in the form of , thus iscsi panicked . I suspect this panic started to happen after switched to use from . seems to always resolve device path (see output below), and thus the expected iscsi configuration in the device path no longer exists.

Discussion:
import ( "errors" <ins> "fmt" </ins> "os" "path" "strings"

// Find the number of references to the device. refCount := 0 for i := range mps { <del> if strings.HasPrefix(mps[i].Device, deviceNamePrefix) { </del> <ins> if strings.HasPrefix(mps[i].Path, deviceNamePrefix) { </ins> refCount++ } }

} func (util *ISCSIUtil) DetachDisk(c iscsiDiskCleaner, mntPath string) error { <del> device, cnt, err := mount.GetDeviceNameFromMount(c.mounter, mntPath) </del> <ins> _, cnt, err := mount.GetDeviceNameFromMount(c.mounter, mntPath) </ins> if err != nil { glog.Errorf("iscsi detach disk: failed to get device from mnt: %snError: %v", mntPath, err) return err

cnt-- // if device is no longer used, see if need to logout the target if cnt == 0 { <del> // strip -lun- from device path ind := strings.LastIndex(device, "-lun-") prefix := device[:(ind - 1)] </del> <ins> device, prefix, err := extractDeviceAndPrefix(mntPath) if err != nil { return err } </ins> refCount, err := getDevicePrefixRefCount(c.mounter, prefix) if err == nil && refCount == 0 { // this portal/iqn are no longer referenced, log out // extract portal and iqn from device path <del> ind1 := strings.LastIndex(device, "-iscsi-") portal := device[(len("/dev/disk/by-path/ip-")):ind1] iqn := device[ind1+len("-iscsi-") : ind] </del> <ins> portal, iqn, err := extractPortalAndIqn(device) if err != nil { return err } </ins> glog.Infof("iscsi: log out target %s iqn %s", portal, iqn) out, err := c.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", portal, "-T", iqn, "--logout"}) if err != nil {

} return nil } <ins> func extractDeviceAndPrefix(mntPath string) (string, string, error) { ind := strings.LastIndex(mntPath, "/") if ind < 0 { return "", "", fmt.Errorf("iscsi detach disk: malformatted mnt path: %s", mntPath) } device := mntPath[(ind + 1):] // strip -lun- from device path ind = strings.LastIndex(device, "-lun-") if ind < 0 { return "", "", fmt.Errorf("iscsi detach disk: malformatted mnt path: %s", mntPath) } prefix := device[:ind] return device, prefix, nil } func extractPortalAndIqn(device string) (string, string, error) { ind1 := strings.Index(device, "-") if ind1 < 0 { return "", "", fmt.Errorf("iscsi detach disk: no portal in %s", device) } portal := device[0:ind1] ind2 := strings.Index(device, "iqn.") if ind2 < 0 { return "", "", fmt.Errorf("iscsi detach disk: no iqn in %s", device) } ind := strings.LastIndex(device, "-lun-") iqn := device[ind2:ind] return portal, iqn, nil } </ins>

func TestGetDevicePrefixRefCount(t *testing.T) { fm := &mount.FakeMounter{ MountPoints: []mount.MountPoint{ <del> {Device: "/dev/disk/by-path/prefix-lun-1", Path: "/mnt/111"}, {Device: "/dev/disk/by-path/prefix-lun-1", Path: "/mnt/222"}, {Device: "/dev/disk/by-path/prefix-lun-0", Path: "/mnt/333"}, {Device: "/dev/disk/by-path/prefix-lun-0", Path: "/mnt/444"}, </del> <ins> {Device: "/dev/sdb", Path: "/127.0.0.1:3260-iqn.2014-12.com.example:test.tgt00-lun-0"}, {Device: "/dev/sdb", Path: "/127.0.0.1:3260-iqn.2014-12.com.example:test.tgt00-lun-1"}, {Device: "/dev/sdb", Path: "/127.0.0.1:3260-iqn.2014-12.com.example:test.tgt00-lun-2"}, {Device: "/dev/sdb", Path: "/127.0.0.1:3260-iqn.2014-12.com.example:test.tgt00-lun-3"}, </ins> }, }

expectedRefs int }{ { <del> "/dev/disk/by-path/prefix", </del> <ins> "/127.0.0.1:3260-iqn.2014-12.com.example:test.tgt00", </ins> 4, }, }

} } } <ins> func TestExtractDeviceAndPrefix(t *testing.T) { devicePath := "127.0.0.1:3260-iqn.2014-12.com.example:test.tgt00" lun := "-lun-0" device, prefix, err := extractDeviceAndPrefix("/var/lib/kubelet/plugins/kubernetes.io/iscsi/" + devicePath + lun) if err != nil || device != (devicePath+lun) || prefix != devicePath { t.Errorf("extractDeviceAndPrefix: expected %s and %s, got %v %s and %s", devicePath+lun, devicePath, err, device, prefix) } } func TestExtractPortalAndIqn(t *testing.T) { devicePath := "127.0.0.1:3260-iqn.2014-12.com.example:test.tgt00-lun-0" portal, iqn, err := extractPortalAndIqn(devicePath) if err != nil || portal != "127.0.0.1:3260" || iqn != "iqn.2014-12.com.example:test.tgt00" { t.Errorf("extractPortalAndIqn: got %v %s %s", err, portal, iqn) } } </ins>