func (util *ISCSIUtil) DetachDisk(iscsi iscsiDisk, mntPath string) error { device, cnt, err := mount.GetDeviceNameFromMount(iscsi.mounter, mntPath) if err != nil { glog.Errorf("iscsi detach disk: failed to get device from mnt: %s\nError: %v", mntPath, err) return err } if err = iscsi.mounter.Unmount(mntPath, 0); err != nil { glog.Errorf("iscsi detach disk: failed to umount: %s\nError: %v", mntPath, err) return err } cnt-- // if device is no longer used, see if need to logout the target if cnt == 0 { // strip -lun- from device path ind := strings.LastIndex(device, "-lun-") prefix := device[:(ind - 1)] refCount, err := getDevicePrefixRefCount(iscsi.mounter, prefix) if err == nil && refCount == 0 { // this portal/iqn are no longer referenced, log out // extract portal and iqn from device path ind1 := strings.LastIndex(device, "-iscsi-") portal := device[(len("/dev/disk/by-path/ip-")):ind1] iqn := device[ind1+len("-iscsi-") : ind] glog.Infof("iscsi: log out target %s iqn %s", portal, iqn) _, err = iscsi.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", portal, "-T", iqn, "--logout"}) if err != nil { glog.Errorf("iscsi: failed to detach disk Error: %v", err) } } } return nil }
func (util *RBDUtil) DetachDisk(rbd rbd, mntPath string) error { device, cnt, err := mount.GetDeviceNameFromMount(rbd.mounter, mntPath) if err != nil { return fmt.Errorf("rbd detach disk: failed to get device from mnt: %s\nError: %v", mntPath, err) } if err = rbd.mounter.Unmount(mntPath); err != nil { return fmt.Errorf("rbd detach disk: failed to umount: %s\nError: %v", mntPath, err) } // if device is no longer used, see if can unmap if cnt <= 1 { // rbd unmap _, err = rbd.plugin.execCommand("rbd", []string{"unmap", device}) if err != nil { return fmt.Errorf("rbd: failed to unmap device %s:Error: %v", device, err) } // load ceph and image/pool info to remove fencing if err := util.loadRBD(&rbd, mntPath); err == nil { // remove rbd lock util.defencing(rbd) } glog.Infof("rbd: successfully unmap device %s", device) } return nil }
func TestSafeFormatAndMount(t *testing.T) { tests := []struct { fstype string mountOptions []string execScripts []ExecArgs mountErrs []error expectedError error }{ { // Test a read only mount fstype: "ext4", mountOptions: []string{"ro"}, }, { // Test a normal mount fstype: "ext4", }, { // Test that 'file' is called and fails fstype: "ext4", mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")}, execScripts: []ExecArgs{ {"file", []string{"-L", "--special-files", "/dev/foo"}, "ext4 filesystem", nil}, }, expectedError: fmt.Errorf("unknown filesystem type '(null)'"), }, { // Test that 'file' is called and confirms unformatted disk, format fails fstype: "ext4", mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")}, execScripts: []ExecArgs{ {"file", []string{"-L", "--special-files", "/dev/foo"}, "data", nil}, {"mkfs.ext4", []string{"-E", "lazy_itable_init=0,lazy_journal_init=0", "-F", "/dev/foo"}, "", fmt.Errorf("formatting failed")}, }, expectedError: fmt.Errorf("formatting failed"), }, { // Test that 'file' is called and confirms unformatted disk, format passes, second mount fails fstype: "ext4", mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), fmt.Errorf("Still cannot mount")}, execScripts: []ExecArgs{ {"file", []string{"-L", "--special-files", "/dev/foo"}, "data", nil}, {"mkfs.ext4", []string{"-E", "lazy_itable_init=0,lazy_journal_init=0", "-F", "/dev/foo"}, "", nil}, }, expectedError: fmt.Errorf("Still cannot mount"), }, { // Test that 'file' is called and confirms unformatted disk, format passes, second mount passes fstype: "ext4", mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil}, execScripts: []ExecArgs{ {"file", []string{"-L", "--special-files", "/dev/foo"}, "data", nil}, {"mkfs.ext4", []string{"-E", "lazy_itable_init=0,lazy_journal_init=0", "-F", "/dev/foo"}, "", nil}, }, expectedError: nil, }, { // Test that 'file' is called and confirms unformatted disk, format passes, second mount passes with ext3 fstype: "ext3", mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil}, execScripts: []ExecArgs{ {"file", []string{"-L", "--special-files", "/dev/foo"}, "data", nil}, {"mkfs.ext3", []string{"-E", "lazy_itable_init=0,lazy_journal_init=0", "-F", "/dev/foo"}, "", nil}, }, expectedError: nil, }, } for _, test := range tests { commandScripts := []exec.FakeCommandAction{} for _, expected := range test.execScripts { ecmd := expected.command eargs := expected.args output := expected.output err := expected.err commandScript := func(cmd string, args ...string) exec.Cmd { if cmd != ecmd { t.Errorf("Unexpected command %s. Expecting %s", cmd, ecmd) } for j := range args { if args[j] != eargs[j] { t.Errorf("Unexpected args %v. Expecting %v", args, eargs) } } fake := exec.FakeCmd{ CombinedOutputScript: []exec.FakeCombinedOutputAction{ func() ([]byte, error) { return []byte(output), err }, }, } return exec.InitFakeCmd(&fake, cmd, args...) } commandScripts = append(commandScripts, commandScript) } fake := exec.FakeExec{ CommandScript: commandScripts, } fakeMounter := ErrorMounter{&mount.FakeMounter{}, 0, test.mountErrs} mounter := gceSafeFormatAndMount{ Interface: &fakeMounter, runner: &fake, } device := "/dev/foo" dest := "/mnt/bar" err := mounter.Mount(device, dest, test.fstype, test.mountOptions) if test.expectedError == nil { if err != nil { t.Errorf("unexpected non-error: %v", err) } // Check that something was mounted on the directory isMountPoint, err := fakeMounter.IsMountPoint(dest) if err != nil || !isMountPoint { t.Errorf("the directory was not mounted") } //check that the correct device was mounted mountedDevice, _, err := mount.GetDeviceNameFromMount(fakeMounter.FakeMounter, dest) if err != nil || mountedDevice != device { t.Errorf("the correct device was not mounted") } } else { if err == nil || test.expectedError.Error() != err.Error() { t.Errorf("unexpected error: %v. Expecting %v", err, test.expectedError) } } } }