From c228eab00e94ed862125aa9b990d19d0190116e0 Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanino Date: Tue, 12 Sep 2017 10:19:58 -0400 Subject: [PATCH] UPSTREAM: 50334: Support iscsi volume attach and detach Fixes #48953 --- .../cmd/kube-controller-manager/app/BUILD | 1 + .../kube-controller-manager/app/plugins.go | 2 + .../attachdetach/testing/testvolumespec.go | 2 +- .../kubernetes/pkg/volume/aws_ebs/attacher.go | 3 +- .../pkg/volume/azure_dd/attacher.go | 3 +- .../kubernetes/pkg/volume/cinder/attacher.go | 3 +- .../kubernetes/pkg/volume/fc/attacher.go | 3 +- .../pkg/volume/flexvolume/attacher.go | 3 +- .../pkg/volume/flexvolume/attacher_test.go | 8 +- .../kubernetes/pkg/volume/gce_pd/attacher.go | 3 +- .../k8s.io/kubernetes/pkg/volume/iscsi/BUILD | 1 + .../kubernetes/pkg/volume/iscsi/attacher.go | 208 ++++++++++++++++++ .../pkg/volume/iscsi/disk_manager.go | 44 ++-- .../kubernetes/pkg/volume/iscsi/iscsi_test.go | 14 +- .../kubernetes/pkg/volume/iscsi/iscsi_util.go | 21 +- .../pkg/volume/iscsi/iscsi_util_test.go | 0 .../pkg/volume/photon_pd/attacher.go | 3 +- .../kubernetes/pkg/volume/testing/testing.go | 2 +- .../operationexecutor/operation_generator.go | 2 +- vendor/k8s.io/kubernetes/pkg/volume/volume.go | 2 +- .../pkg/volume/vsphere_volume/attacher.go | 3 +- 21 files changed, 279 insertions(+), 52 deletions(-) create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/iscsi/attacher.go mode change 100755 => 100644 vendor/k8s.io/kubernetes/pkg/volume/iscsi/iscsi_util.go mode change 100755 => 100644 vendor/k8s.io/kubernetes/pkg/volume/iscsi/iscsi_util_test.go diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD index 15f66dcf7e44..c1193fe8e3a3 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD @@ -85,6 +85,7 @@ go_library( "//pkg/volume/gce_pd:go_default_library", "//pkg/volume/glusterfs:go_default_library", "//pkg/volume/host_path:go_default_library", + "//pkg/volume/iscsi:go_default_library", "//pkg/volume/local:go_default_library", "//pkg/volume/nfs:go_default_library", "//pkg/volume/photon_pd:go_default_library", diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/plugins.go b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/plugins.go index 45af77beb0f1..e0460df95cd3 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/plugins.go +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/plugins.go @@ -48,6 +48,7 @@ import ( "k8s.io/kubernetes/pkg/volume/gce_pd" "k8s.io/kubernetes/pkg/volume/glusterfs" "k8s.io/kubernetes/pkg/volume/host_path" + "k8s.io/kubernetes/pkg/volume/iscsi" "k8s.io/kubernetes/pkg/volume/local" "k8s.io/kubernetes/pkg/volume/nfs" "k8s.io/kubernetes/pkg/volume/photon_pd" @@ -79,6 +80,7 @@ func ProbeAttachableVolumePlugins(config componentconfig.VolumeConfiguration) [] allPlugins = append(allPlugins, scaleio.ProbeVolumePlugins()...) allPlugins = append(allPlugins, storageos.ProbeVolumePlugins()...) allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...) + allPlugins = append(allPlugins, iscsi.ProbeVolumePlugins()...) return allPlugins } diff --git a/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/testing/testvolumespec.go b/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/testing/testvolumespec.go index 7097632dc1ad..0c45eafd5bff 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/testing/testvolumespec.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/testing/testvolumespec.go @@ -377,7 +377,7 @@ func (attacher *testPluginAttacher) VolumesAreAttached(specs []*volume.Spec, nod return nil, nil } -func (attacher *testPluginAttacher) WaitForAttach(spec *volume.Spec, devicePath string, timeout time.Duration) (string, error) { +func (attacher *testPluginAttacher) WaitForAttach(spec *volume.Spec, devicePath string, pod *v1.Pod, timeout time.Duration) (string, error) { attacher.pluginLock.Lock() defer attacher.pluginLock.Unlock() if spec == nil { diff --git a/vendor/k8s.io/kubernetes/pkg/volume/aws_ebs/attacher.go b/vendor/k8s.io/kubernetes/pkg/volume/aws_ebs/attacher.go index 735f57ed9705..335561b9677e 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/aws_ebs/attacher.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/aws_ebs/attacher.go @@ -25,6 +25,7 @@ import ( "github.com/golang/glog" "k8s.io/apimachinery/pkg/types" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/cloudprovider/providers/aws" "k8s.io/kubernetes/pkg/util/exec" "k8s.io/kubernetes/pkg/util/mount" @@ -142,7 +143,7 @@ func (attacher *awsElasticBlockStoreAttacher) BulkVerifyVolumes(volumesByNode ma return volumesAttachedCheck, nil } -func (attacher *awsElasticBlockStoreAttacher) WaitForAttach(spec *volume.Spec, devicePath string, timeout time.Duration) (string, error) { +func (attacher *awsElasticBlockStoreAttacher) WaitForAttach(spec *volume.Spec, devicePath string, _ *v1.Pod, timeout time.Duration) (string, error) { volumeSource, _, err := getVolumeSource(spec) if err != nil { return "", err diff --git a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/attacher.go b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/attacher.go index 92cb203c468e..d491356e24f9 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/attacher.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/attacher.go @@ -28,6 +28,7 @@ import ( "github.com/golang/glog" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/cloudprovider" "k8s.io/kubernetes/pkg/util/exec" "k8s.io/kubernetes/pkg/util/keymutex" @@ -151,7 +152,7 @@ func (attacher *azureDiskAttacher) VolumesAreAttached(specs []*volume.Spec, node } // WaitForAttach runs on the node to detect if the volume (referenced by LUN) is attached. If attached, the device path is returned -func (attacher *azureDiskAttacher) WaitForAttach(spec *volume.Spec, lunStr string, timeout time.Duration) (string, error) { +func (attacher *azureDiskAttacher) WaitForAttach(spec *volume.Spec, lunStr string, _ *v1.Pod, timeout time.Duration) (string, error) { volumeSource, err := getVolumeSource(spec) if err != nil { return "", err diff --git a/vendor/k8s.io/kubernetes/pkg/volume/cinder/attacher.go b/vendor/k8s.io/kubernetes/pkg/volume/cinder/attacher.go index 7c6cf470bc4c..834dbb0cd7b2 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/cinder/attacher.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/cinder/attacher.go @@ -26,6 +26,7 @@ import ( "github.com/golang/glog" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/util/exec" "k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/volume" @@ -208,7 +209,7 @@ func (attacher *cinderDiskAttacher) VolumesAreAttached(specs []*volume.Spec, nod return volumesAttachedCheck, nil } -func (attacher *cinderDiskAttacher) WaitForAttach(spec *volume.Spec, devicePath string, timeout time.Duration) (string, error) { +func (attacher *cinderDiskAttacher) WaitForAttach(spec *volume.Spec, devicePath string, _ *v1.Pod, timeout time.Duration) (string, error) { // NOTE: devicePath is is path as reported by Cinder, which may be incorrect and should not be used. See Issue #33128 volumeSource, _, err := getVolumeSource(spec) if err != nil { diff --git a/vendor/k8s.io/kubernetes/pkg/volume/fc/attacher.go b/vendor/k8s.io/kubernetes/pkg/volume/fc/attacher.go index 7471508e9fbb..85401d552b1c 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/fc/attacher.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/fc/attacher.go @@ -24,6 +24,7 @@ import ( "github.com/golang/glog" "k8s.io/apimachinery/pkg/types" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/util/exec" "k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/volume" @@ -66,7 +67,7 @@ func (attacher *fcAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName ty return volumesAttachedCheck, nil } -func (attacher *fcAttacher) WaitForAttach(spec *volume.Spec, devicePath string, timeout time.Duration) (string, error) { +func (attacher *fcAttacher) WaitForAttach(spec *volume.Spec, devicePath string, _ *v1.Pod, timeout time.Duration) (string, error) { mounter, err := volumeSpecToMounter(spec, attacher.host) if err != nil { glog.Warningf("failed to get fc mounter: %v", err) diff --git a/vendor/k8s.io/kubernetes/pkg/volume/flexvolume/attacher.go b/vendor/k8s.io/kubernetes/pkg/volume/flexvolume/attacher.go index 73575be4c4e9..1116b8161b95 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/flexvolume/attacher.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/flexvolume/attacher.go @@ -21,6 +21,7 @@ import ( "github.com/golang/glog" "k8s.io/apimachinery/pkg/types" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/volume" ) @@ -47,7 +48,7 @@ func (a *flexVolumeAttacher) Attach(spec *volume.Spec, hostName types.NodeName) } // WaitForAttach is part of the volume.Attacher interface -func (a *flexVolumeAttacher) WaitForAttach(spec *volume.Spec, devicePath string, timeout time.Duration) (string, error) { +func (a *flexVolumeAttacher) WaitForAttach(spec *volume.Spec, devicePath string, _ *v1.Pod, timeout time.Duration) (string, error) { call := a.plugin.NewDriverCallWithTimeout(waitForAttachCmd, timeout) call.Append(devicePath) call.AppendSpec(spec, a.plugin.host, nil) diff --git a/vendor/k8s.io/kubernetes/pkg/volume/flexvolume/attacher_test.go b/vendor/k8s.io/kubernetes/pkg/volume/flexvolume/attacher_test.go index 8807cc816222..e04b256bbfd5 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/flexvolume/attacher_test.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/flexvolume/attacher_test.go @@ -17,9 +17,11 @@ limitations under the License. package flexvolume import ( - "k8s.io/kubernetes/pkg/volume" "testing" "time" + + "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/volume" ) func TestAttach(t *testing.T) { @@ -37,7 +39,7 @@ func TestAttach(t *testing.T) { func TestWaitForAttach(t *testing.T) { spec := fakeVolumeSpec() - + var pod *v1.Pod plugin, _ := testPlugin() plugin.runner = fakeRunner( assertDriverCall(t, notSupportedOutput(), waitForAttachCmd, "/dev/sdx", @@ -45,7 +47,7 @@ func TestWaitForAttach(t *testing.T) { ) a, _ := plugin.NewAttacher() - a.WaitForAttach(spec, "/dev/sdx", 1*time.Second) + a.WaitForAttach(spec, "/dev/sdx", pod, 1*time.Second) } func TestMountDevice(t *testing.T) { diff --git a/vendor/k8s.io/kubernetes/pkg/volume/gce_pd/attacher.go b/vendor/k8s.io/kubernetes/pkg/volume/gce_pd/attacher.go index c5cba531a438..0877c79bb167 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/gce_pd/attacher.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/gce_pd/attacher.go @@ -27,6 +27,7 @@ import ( "github.com/golang/glog" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/cloudprovider/providers/gce" "k8s.io/kubernetes/pkg/util/exec" "k8s.io/kubernetes/pkg/util/mount" @@ -130,7 +131,7 @@ func (attacher *gcePersistentDiskAttacher) VolumesAreAttached(specs []*volume.Sp return volumesAttachedCheck, nil } -func (attacher *gcePersistentDiskAttacher) WaitForAttach(spec *volume.Spec, devicePath string, timeout time.Duration) (string, error) { +func (attacher *gcePersistentDiskAttacher) WaitForAttach(spec *volume.Spec, devicePath string, _ *v1.Pod, timeout time.Duration) (string, error) { ticker := time.NewTicker(checkSleepDuration) defer ticker.Stop() timer := time.NewTimer(timeout) diff --git a/vendor/k8s.io/kubernetes/pkg/volume/iscsi/BUILD b/vendor/k8s.io/kubernetes/pkg/volume/iscsi/BUILD index 531898f7395d..c3df7ab72619 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/iscsi/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/volume/iscsi/BUILD @@ -11,6 +11,7 @@ load( go_library( name = "go_default_library", srcs = [ + "attacher.go", "disk_manager.go", "doc.go", "iscsi.go", diff --git a/vendor/k8s.io/kubernetes/pkg/volume/iscsi/attacher.go b/vendor/k8s.io/kubernetes/pkg/volume/iscsi/attacher.go new file mode 100644 index 000000000000..7ec17614a65f --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/iscsi/attacher.go @@ -0,0 +1,208 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package iscsi + +import ( + "fmt" + "os" + "strconv" + "time" + + "github.com/golang/glog" + "k8s.io/apimachinery/pkg/types" + "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/util/exec" + "k8s.io/kubernetes/pkg/util/mount" + "k8s.io/kubernetes/pkg/volume" + volumeutil "k8s.io/kubernetes/pkg/volume/util" +) + +type iscsiAttacher struct { + host volume.VolumeHost + manager diskManager + exe exec.Interface +} + +var _ volume.Attacher = &iscsiAttacher{} + +var _ volume.AttachableVolumePlugin = &iscsiPlugin{} + +func (plugin *iscsiPlugin) NewAttacher() (volume.Attacher, error) { + return &iscsiAttacher{ + host: plugin.host, + manager: &ISCSIUtil{}, + exe: exec.New(), + }, nil +} + +func (plugin *iscsiPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) { + mounter := plugin.host.GetMounter() + return mount.GetMountRefs(mounter, deviceMountPath) +} + +func (attacher *iscsiAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string, error) { + return "", nil +} + +func (attacher *iscsiAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) { + volumesAttachedCheck := make(map[*volume.Spec]bool) + for _, spec := range specs { + volumesAttachedCheck[spec] = true + } + + return volumesAttachedCheck, nil +} + +func (attacher *iscsiAttacher) WaitForAttach(spec *volume.Spec, devicePath string, pod *v1.Pod, timeout time.Duration) (string, error) { + mounter, err := attacher.volumeSpecToMounter(spec, attacher.host, pod) + if err != nil { + glog.Warningf("failed to get iscsi mounter: %v", err) + return "", err + } + return attacher.manager.AttachDisk(*mounter) +} + +func (attacher *iscsiAttacher) GetDeviceMountPath( + spec *volume.Spec) (string, error) { + mounter, err := attacher.volumeSpecToMounter(spec, attacher.host, nil) + if err != nil { + glog.Warningf("failed to get iscsi mounter: %v", err) + return "", err + } + return attacher.manager.MakeGlobalPDName(*mounter.iscsiDisk), nil +} + +func (attacher *iscsiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { + mounter := attacher.host.GetMounter() + notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) + if err != nil { + if os.IsNotExist(err) { + if err := os.MkdirAll(deviceMountPath, 0750); err != nil { + return err + } + notMnt = true + } else { + return err + } + } + volumeSource, readOnly, err := getVolumeSource(spec) + if err != nil { + return err + } + + options := []string{} + if readOnly { + options = append(options, "ro") + } + if notMnt { + diskMounter := &mount.SafeFormatAndMount{Interface: mounter, Runner: exec.New()} + mountOptions := volume.MountOptionFromSpec(spec, options...) + err = diskMounter.FormatAndMount(devicePath, deviceMountPath, volumeSource.FSType, mountOptions) + if err != nil { + os.Remove(deviceMountPath) + return err + } + } + return nil +} + +type iscsiDetacher struct { + host volume.VolumeHost + mounter mount.Interface + manager diskManager + exe exec.Interface +} + +var _ volume.Detacher = &iscsiDetacher{} + +func (plugin *iscsiPlugin) NewDetacher() (volume.Detacher, error) { + return &iscsiDetacher{ + host: plugin.host, + mounter: plugin.host.GetMounter(), + manager: &ISCSIUtil{}, + exe: exec.New(), + }, nil +} + +func (detacher *iscsiDetacher) Detach(deviceMountPath string, nodeName types.NodeName) error { + return nil +} + +func (detacher *iscsiDetacher) UnmountDevice(deviceMountPath string) error { + unMounter := detacher.volumeSpecToUnmounter(detacher.mounter) + err := detacher.manager.DetachDisk(*unMounter, deviceMountPath) + if err != nil { + return fmt.Errorf("iscsi: failed to detach disk: %s\nError: %v", deviceMountPath, err) + } + glog.V(4).Infof("iscsi: successfully detached disk: %s", deviceMountPath) + return nil +} + +func (attacher *iscsiAttacher) volumeSpecToMounter(spec *volume.Spec, host volume.VolumeHost, pod *v1.Pod) (*iscsiDiskMounter, error) { + var secret map[string]string + var bkportal []string + iscsi, readOnly, err := getVolumeSource(spec) + if err != nil { + return nil, err + } + // Obtain secret for AttachDisk + if iscsi.SecretRef != nil && pod != nil { + if secret, err = volumeutil.GetSecretForPod(pod, iscsi.SecretRef.Name, host.GetKubeClient()); err != nil { + glog.Errorf("Couldn't get secret from %v/%v", pod.Namespace, iscsi.SecretRef) + return nil, err + } + } + lun := strconv.Itoa(int(iscsi.Lun)) + portal := portalMounter(iscsi.TargetPortal) + bkportal = append(bkportal, portal) + for _, tp := range iscsi.Portals { + bkportal = append(bkportal, portalMounter(string(tp))) + } + iface := iscsi.ISCSIInterface + + return &iscsiDiskMounter{ + iscsiDisk: &iscsiDisk{ + plugin: &iscsiPlugin{ + host: host, + exe: exec.New(), + }, + volName: spec.Name(), + Portals: bkportal, + Iqn: iscsi.IQN, + lun: lun, + Iface: iface, + chap_discovery: iscsi.DiscoveryCHAPAuth, + chap_session: iscsi.SessionCHAPAuth, + secret: secret, + manager: &ISCSIUtil{}}, + fsType: iscsi.FSType, + readOnly: readOnly, + mounter: &mount.SafeFormatAndMount{Interface: host.GetMounter(), Runner: exec.New()}, + deviceUtil: volumeutil.NewDeviceHandler(volumeutil.NewIOHandler()), + }, nil +} + +func (detacher *iscsiDetacher) volumeSpecToUnmounter(mounter mount.Interface) *iscsiDiskUnmounter { + return &iscsiDiskUnmounter{ + iscsiDisk: &iscsiDisk{ + plugin: &iscsiPlugin{ + exe: exec.New(), + }, + }, + mounter: mounter, + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/iscsi/disk_manager.go b/vendor/k8s.io/kubernetes/pkg/volume/iscsi/disk_manager.go index 2c470b9b1ba1..697efa241d85 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/iscsi/disk_manager.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/iscsi/disk_manager.go @@ -28,7 +28,7 @@ import ( type diskManager interface { MakeGlobalPDName(disk iscsiDisk) string // Attaches the disk to the kubelet's host machine. - AttachDisk(b iscsiDiskMounter) error + AttachDisk(b iscsiDiskMounter) (string, error) // Detaches the disk from the kubelet's host machine. DetachDisk(disk iscsiDiskUnmounter, mntPath string) error } @@ -38,7 +38,6 @@ func diskSetUp(manager diskManager, b iscsiDiskMounter, volPath string, mounter globalPDPath := manager.MakeGlobalPDName(*b.iscsiDisk) // TODO: handle failed mounts here. notMnt, err := mounter.IsLikelyNotMountPoint(volPath) - if err != nil && !os.IsNotExist(err) { glog.Errorf("cannot validate mountpoint: %s", volPath) return err @@ -46,10 +45,6 @@ func diskSetUp(manager diskManager, b iscsiDiskMounter, volPath string, mounter if !notMnt { return nil } - if err := manager.AttachDisk(b); err != nil { - glog.Errorf("failed to attach disk") - return err - } if err := os.MkdirAll(volPath, 0750); err != nil { glog.Errorf("failed to mkdir:%s", volPath) @@ -63,7 +58,29 @@ func diskSetUp(manager diskManager, b iscsiDiskMounter, volPath string, mounter mountOptions := volume.JoinMountOptions(b.mountOptions, options) err = mounter.Mount(globalPDPath, volPath, "", mountOptions) if err != nil { - glog.Errorf("failed to bind mount:%s", globalPDPath) + glog.Errorf("Failed to bind mount: source:%s, target:%s, err:%v", globalPDPath, volPath, err) + noMnt, mntErr := b.mounter.IsLikelyNotMountPoint(volPath) + if mntErr != nil { + glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr) + return err + } + if !noMnt { + if mntErr = b.mounter.Unmount(volPath); mntErr != nil { + glog.Errorf("Failed to unmount: %v", mntErr) + return err + } + noMnt, mntErr = b.mounter.IsLikelyNotMountPoint(volPath) + if mntErr != nil { + glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr) + return err + } + if !noMnt { + // will most likely retry on next sync loop. + glog.Errorf("%s is still mounted, despite call to unmount(). Will try again next sync loop.", volPath) + return err + } + } + os.Remove(volPath) return err } @@ -84,8 +101,7 @@ func diskTearDown(manager diskManager, c iscsiDiskUnmounter, volPath string, mou if notMnt { return os.Remove(volPath) } - - refs, err := mount.GetMountRefs(mounter, volPath) + _, err = mount.GetMountRefs(mounter, volPath) if err != nil { glog.Errorf("failed to get reference count %s", volPath) return err @@ -94,16 +110,6 @@ func diskTearDown(manager diskManager, c iscsiDiskUnmounter, volPath string, mou glog.Errorf("failed to unmount %s", volPath) return err } - // If len(refs) is 1, then all bind mounts have been removed, and the - // remaining reference is the global mount. It is safe to detach. - if len(refs) == 1 { - mntPath := refs[0] - if err := manager.DetachDisk(c, mntPath); err != nil { - glog.Errorf("failed to detach disk from %s", mntPath) - return err - } - } - notMnt, mntErr := mounter.IsLikelyNotMountPoint(volPath) if mntErr != nil { glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr) diff --git a/vendor/k8s.io/kubernetes/pkg/volume/iscsi/iscsi_test.go b/vendor/k8s.io/kubernetes/pkg/volume/iscsi/iscsi_test.go index f18b9e33f57d..36d03126b2ad 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/iscsi/iscsi_test.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/iscsi/iscsi_test.go @@ -100,18 +100,17 @@ func (fake *fakeDiskManager) Cleanup() { func (fake *fakeDiskManager) MakeGlobalPDName(disk iscsiDisk) string { return fake.tmpDir } -func (fake *fakeDiskManager) AttachDisk(b iscsiDiskMounter) error { +func (fake *fakeDiskManager) AttachDisk(b iscsiDiskMounter) (string, error) { globalPath := b.manager.MakeGlobalPDName(*b.iscsiDisk) err := os.MkdirAll(globalPath, 0750) if err != nil { - return err + return "", err } // Simulate the global mount so that the fakeMounter returns the // expected number of mounts for the attached disk. b.mounter.Mount(globalPath, globalPath, b.fsType, nil) - fake.attachCalled = true - return nil + return "/dev/sdb", nil } func (fake *fakeDiskManager) DetachDisk(c iscsiDiskUnmounter, mntPath string) error { @@ -120,7 +119,6 @@ func (fake *fakeDiskManager) DetachDisk(c iscsiDiskUnmounter, mntPath string) er if err != nil { return err } - fake.detachCalled = true return nil } @@ -172,9 +170,6 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { t.Errorf("SetUp() failed: %v", err) } } - if !fakeManager.attachCalled { - t.Errorf("Attach was not called") - } fakeManager2 := NewFakeDiskManager() defer fakeManager2.Cleanup() @@ -194,9 +189,6 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { } else if !os.IsNotExist(err) { t.Errorf("SetUp() failed: %v", err) } - if !fakeManager2.detachCalled { - t.Errorf("Detach was not called") - } } func TestPluginVolume(t *testing.T) { diff --git a/vendor/k8s.io/kubernetes/pkg/volume/iscsi/iscsi_util.go b/vendor/k8s.io/kubernetes/pkg/volume/iscsi/iscsi_util.go old mode 100755 new mode 100644 index 7190859b5422..75fad95bb203 --- a/vendor/k8s.io/kubernetes/pkg/volume/iscsi/iscsi_util.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/iscsi/iscsi_util.go @@ -29,6 +29,7 @@ import ( "github.com/golang/glog" "k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/volume" + volumeutil "k8s.io/kubernetes/pkg/volume/util" ) var ( @@ -190,7 +191,7 @@ func (util *ISCSIUtil) loadISCSI(conf *iscsiDisk, mnt string) error { return nil } -func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error { +func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) (string, error) { var devicePath string var devicePaths []string var iscsiTransport string @@ -199,7 +200,7 @@ func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error { out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "iface", "-I", b.Iface, "-o", "show"}) if err != nil { glog.Errorf("iscsi: could not read iface %s error: %s", b.Iface, string(out)) - return err + return "", err } iscsiTransport = extractTransportname(string(out)) @@ -215,7 +216,7 @@ func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error { if iscsiTransport == "" { glog.Errorf("iscsi: could not find transport name in iface %s", b.Iface) - return fmt.Errorf("Could not parse iface file for %s", b.Iface) + return "", fmt.Errorf("Could not parse iface file for %s", b.Iface) } else if iscsiTransport == "tcp" { devicePath = strings.Join([]string{"/dev/disk/by-path/ip", tp, "iscsi", b.Iqn, "lun", b.lun}, "-") } else { @@ -269,7 +270,7 @@ func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error { if len(devicePaths) == 0 { glog.Errorf("iscsi: failed to get any path for iscsi disk, last err seen:\n%v", lastErr) - return fmt.Errorf("failed to get any path for iscsi disk, last err seen:\n%v", lastErr) + return "", fmt.Errorf("failed to get any path for iscsi disk, last err seen:\n%v", lastErr) } //Make sure we use a valid devicepath to find mpio device. @@ -280,12 +281,12 @@ func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error { notMnt, err := b.mounter.IsLikelyNotMountPoint(globalPDPath) if !notMnt { glog.Infof("iscsi: %s already mounted", globalPDPath) - return nil + return "", nil } if err := os.MkdirAll(globalPDPath, 0750); err != nil { glog.Errorf("iscsi: failed to mkdir %s, error", globalPDPath) - return err + return "", err } // Persist iscsi disk config to json file for DetachDisk path @@ -308,7 +309,7 @@ func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error { glog.Errorf("iscsi: failed to mount iscsi volume %s [%s] to %s, error %v", devicePath, b.fsType, globalPDPath, err) } - return err + return devicePath, err } func (util *ISCSIUtil) DetachDisk(c iscsiDiskUnmounter, mntPath string) error { @@ -317,6 +318,12 @@ func (util *ISCSIUtil) DetachDisk(c iscsiDiskUnmounter, mntPath string) error { glog.Errorf("iscsi detach disk: failed to get device from mnt: %s\nError: %v", mntPath, err) return err } + if pathExists, pathErr := volumeutil.PathExists(mntPath); pathErr != nil { + return fmt.Errorf("Error checking if path exists: %v", pathErr) + } else if !pathExists { + glog.Warningf("Warning: Unmount skipped because path does not exist: %v", mntPath) + return nil + } if err = c.mounter.Unmount(mntPath); err != nil { glog.Errorf("iscsi detach disk: failed to unmount: %s\nError: %v", mntPath, err) return err diff --git a/vendor/k8s.io/kubernetes/pkg/volume/iscsi/iscsi_util_test.go b/vendor/k8s.io/kubernetes/pkg/volume/iscsi/iscsi_util_test.go old mode 100755 new mode 100644 diff --git a/vendor/k8s.io/kubernetes/pkg/volume/photon_pd/attacher.go b/vendor/k8s.io/kubernetes/pkg/volume/photon_pd/attacher.go index 2faf1d6e4d0b..a0f7d421b17d 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/photon_pd/attacher.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/photon_pd/attacher.go @@ -26,6 +26,7 @@ import ( "github.com/golang/glog" "k8s.io/apimachinery/pkg/types" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/cloudprovider/providers/photon" "k8s.io/kubernetes/pkg/util/exec" "k8s.io/kubernetes/pkg/util/mount" @@ -114,7 +115,7 @@ func (attacher *photonPersistentDiskAttacher) VolumesAreAttached(specs []*volume return volumesAttachedCheck, nil } -func (attacher *photonPersistentDiskAttacher) WaitForAttach(spec *volume.Spec, devicePath string, timeout time.Duration) (string, error) { +func (attacher *photonPersistentDiskAttacher) WaitForAttach(spec *volume.Spec, devicePath string, _ *v1.Pod, timeout time.Duration) (string, error) { volumeSource, _, err := getVolumeSource(spec) if err != nil { glog.Errorf("Photon Controller attacher: WaitForAttach failed to get volume source") diff --git a/vendor/k8s.io/kubernetes/pkg/volume/testing/testing.go b/vendor/k8s.io/kubernetes/pkg/volume/testing/testing.go index a5d790f60914..6e9f4774d5cd 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/testing/testing.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/testing/testing.go @@ -411,7 +411,7 @@ func (fv *FakeVolume) GetAttachCallCount() int { return fv.AttachCallCount } -func (fv *FakeVolume) WaitForAttach(spec *Spec, devicePath string, spectimeout time.Duration) (string, error) { +func (fv *FakeVolume) WaitForAttach(spec *Spec, devicePath string, pod *v1.Pod, spectimeout time.Duration) (string, error) { fv.Lock() defer fv.Unlock() fv.WaitForAttachCallCount++ diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/operationexecutor/operation_generator.go b/vendor/k8s.io/kubernetes/pkg/volume/util/operationexecutor/operation_generator.go index 4c189d96dddc..418ffcc99c5d 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/util/operationexecutor/operation_generator.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/operationexecutor/operation_generator.go @@ -404,7 +404,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc( glog.Infof(volumeToMount.GenerateMsgDetailed("MountVolume.WaitForAttach entering", fmt.Sprintf("DevicePath %q", volumeToMount.DevicePath))) devicePath, err := volumeAttacher.WaitForAttach( - volumeToMount.VolumeSpec, volumeToMount.DevicePath, waitForAttachTimeout) + volumeToMount.VolumeSpec, volumeToMount.DevicePath, volumeToMount.Pod, waitForAttachTimeout) if err != nil { // On failure, return error. Caller will log and retry. return volumeToMount.GenerateErrorDetailed("MountVolume.WaitForAttach failed", err) diff --git a/vendor/k8s.io/kubernetes/pkg/volume/volume.go b/vendor/k8s.io/kubernetes/pkg/volume/volume.go index 76c96d2e222d..13fe3a92b3cc 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/volume.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/volume.go @@ -173,7 +173,7 @@ type Attacher interface { // node. If it successfully attaches, the path to the device // is returned. Otherwise, if the device does not attach after // the given timeout period, an error will be returned. - WaitForAttach(spec *Spec, devicePath string, timeout time.Duration) (string, error) + WaitForAttach(spec *Spec, devicePath string, pod *v1.Pod, timeout time.Duration) (string, error) // GetDeviceMountPath returns a path where the device should // be mounted after it is attached. This is a global mount diff --git a/vendor/k8s.io/kubernetes/pkg/volume/vsphere_volume/attacher.go b/vendor/k8s.io/kubernetes/pkg/volume/vsphere_volume/attacher.go index 747d9d8d6988..2e913a37a4b6 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/vsphere_volume/attacher.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/vsphere_volume/attacher.go @@ -24,6 +24,7 @@ import ( "github.com/golang/glog" "k8s.io/apimachinery/pkg/types" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere" "k8s.io/kubernetes/pkg/util/exec" "k8s.io/kubernetes/pkg/util/keymutex" @@ -118,7 +119,7 @@ func (attacher *vsphereVMDKAttacher) VolumesAreAttached(specs []*volume.Spec, no return volumesAttachedCheck, nil } -func (attacher *vsphereVMDKAttacher) WaitForAttach(spec *volume.Spec, devicePath string, timeout time.Duration) (string, error) { +func (attacher *vsphereVMDKAttacher) WaitForAttach(spec *volume.Spec, devicePath string, _ *v1.Pod, timeout time.Duration) (string, error) { volumeSource, _, err := getVolumeSource(spec) if err != nil { return "", err