From 8ef04a842518b7759b65d43471be3c4535b7a45b Mon Sep 17 00:00:00 2001 From: Paul Morie Date: Wed, 4 Mar 2015 13:29:01 -0500 Subject: [PATCH] Factor mount utility code out gce_pd volume plugin --- pkg/kubelet/volume/gce_pd/gce_pd.go | 12 +-- pkg/kubelet/volume/gce_pd/gce_pd_test.go | 5 +- pkg/kubelet/volume/gce_pd/gce_util.go | 2 +- pkg/kubelet/volume/gce_pd/mount_util.go | 48 --------- pkg/kubelet/volume/gce_pd/mount_util_test.go | 99 ------------------- pkg/util/mount/fake.go | 34 +++++++ pkg/util/mount/mount.go | 27 +++++ pkg/util/mount/{linux.go => mount_linux.go} | 0 .../{linux_test.go => mount_linux_test.go} | 60 +++++++++++ .../{unsupported.go => mount_unsupported.go} | 0 .../mount/mountpoint_unix.go} | 4 +- .../mount/mountpoint_unsupported.go} | 4 +- 12 files changed, 135 insertions(+), 160 deletions(-) delete mode 100644 pkg/kubelet/volume/gce_pd/mount_util.go delete mode 100644 pkg/kubelet/volume/gce_pd/mount_util_test.go create mode 100644 pkg/util/mount/fake.go rename pkg/util/mount/{linux.go => mount_linux.go} (100%) rename pkg/util/mount/{linux_test.go => mount_linux_test.go} (59%) rename pkg/util/mount/{unsupported.go => mount_unsupported.go} (100%) rename pkg/{kubelet/volume/gce_pd/mount_util_unix.go => util/mount/mountpoint_unix.go} (94%) rename pkg/{kubelet/volume/gce_pd/mount_util_unsupported.go => util/mount/mountpoint_unsupported.go} (91%) diff --git a/pkg/kubelet/volume/gce_pd/gce_pd.go b/pkg/kubelet/volume/gce_pd/gce_pd.go index 413514a24f31f..cd01fde3faa18 100644 --- a/pkg/kubelet/volume/gce_pd/gce_pd.go +++ b/pkg/kubelet/volume/gce_pd/gce_pd.go @@ -170,7 +170,7 @@ func (pd *gcePersistentDisk) SetUp() error { } // TODO: handle failed mounts here. - mountpoint, err := isMountPoint(pd.GetPath()) + mountpoint, err := mount.IsMountPoint(pd.GetPath()) glog.V(4).Infof("PersistentDisk set up: %s %v %v", pd.GetPath(), mountpoint, err) if err != nil && !os.IsNotExist(err) { return err @@ -199,7 +199,7 @@ func (pd *gcePersistentDisk) SetUp() error { // Perform a bind mount to the full path to allow duplicate mounts of the same PD. err = pd.mounter.Mount(globalPDPath, pd.GetPath(), "", mount.FlagBind|flags, "") if err != nil { - mountpoint, mntErr := isMountPoint(pd.GetPath()) + mountpoint, mntErr := mount.IsMountPoint(pd.GetPath()) if mntErr != nil { glog.Errorf("isMountpoint check failed: %v", mntErr) return err @@ -209,7 +209,7 @@ func (pd *gcePersistentDisk) SetUp() error { glog.Errorf("Failed to unmount: %v", mntErr) return err } - mountpoint, mntErr := isMountPoint(pd.GetPath()) + mountpoint, mntErr := mount.IsMountPoint(pd.GetPath()) if mntErr != nil { glog.Errorf("isMountpoint check failed: %v", mntErr) return err @@ -244,7 +244,7 @@ func (pd *gcePersistentDisk) GetPath() string { // Unmounts the bind mount, and detaches the disk only if the PD // resource was the last reference to that disk on the kubelet. func (pd *gcePersistentDisk) TearDown() error { - mountpoint, err := isMountPoint(pd.GetPath()) + mountpoint, err := mount.IsMountPoint(pd.GetPath()) if err != nil { return err } @@ -252,7 +252,7 @@ func (pd *gcePersistentDisk) TearDown() error { return os.Remove(pd.GetPath()) } - refs, err := getMountRefs(pd.mounter, pd.GetPath()) + refs, err := mount.GetMountRefs(pd.mounter, pd.GetPath()) if err != nil { return err } @@ -269,7 +269,7 @@ func (pd *gcePersistentDisk) TearDown() error { return err } } - mountpoint, mntErr := isMountPoint(pd.GetPath()) + mountpoint, mntErr := mount.IsMountPoint(pd.GetPath()) if mntErr != nil { glog.Errorf("isMountpoint check failed: %v", mntErr) return err diff --git a/pkg/kubelet/volume/gce_pd/gce_pd_test.go b/pkg/kubelet/volume/gce_pd/gce_pd_test.go index 1ee50b49862da..9ebb13d81e980 100644 --- a/pkg/kubelet/volume/gce_pd/gce_pd_test.go +++ b/pkg/kubelet/volume/gce_pd/gce_pd_test.go @@ -23,6 +23,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume" "github.com/GoogleCloudPlatform/kubernetes/pkg/types" + "github.com/GoogleCloudPlatform/kubernetes/pkg/util/mount" ) func TestCanSupport(t *testing.T) { @@ -80,7 +81,7 @@ func TestPlugin(t *testing.T) { }, }, } - builder, err := plug.(*gcePersistentDiskPlugin).newBuilderInternal(spec, types.UID("poduid"), &fakePDManager{}, &fakeMounter{}) + builder, err := plug.(*gcePersistentDiskPlugin).newBuilderInternal(spec, types.UID("poduid"), &fakePDManager{}, &mount.FakeMounter{}) if err != nil { t.Errorf("Failed to make a new Builder: %v", err) } @@ -111,7 +112,7 @@ func TestPlugin(t *testing.T) { } } - cleaner, err := plug.(*gcePersistentDiskPlugin).newCleanerInternal("vol1", types.UID("poduid"), &fakePDManager{}, &fakeMounter{}) + cleaner, err := plug.(*gcePersistentDiskPlugin).newCleanerInternal("vol1", types.UID("poduid"), &fakePDManager{}, &mount.FakeMounter{}) if err != nil { t.Errorf("Failed to make a new Cleaner: %v", err) } diff --git a/pkg/kubelet/volume/gce_pd/gce_util.go b/pkg/kubelet/volume/gce_pd/gce_util.go index 881f3e3dcb884..845b27ac7fabf 100644 --- a/pkg/kubelet/volume/gce_pd/gce_util.go +++ b/pkg/kubelet/volume/gce_pd/gce_util.go @@ -68,7 +68,7 @@ func (util *GCEDiskUtil) AttachAndMountDisk(pd *gcePersistentDisk, globalPDPath } // Only mount the PD globally once. - mountpoint, err := isMountPoint(globalPDPath) + mountpoint, err := mount.IsMountPoint(globalPDPath) if err != nil { if os.IsNotExist(err) { if err := os.MkdirAll(globalPDPath, 0750); err != nil { diff --git a/pkg/kubelet/volume/gce_pd/mount_util.go b/pkg/kubelet/volume/gce_pd/mount_util.go deleted file mode 100644 index 8e6ebbce449f6..0000000000000 --- a/pkg/kubelet/volume/gce_pd/mount_util.go +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright 2014 Google Inc. All rights reserved. - -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 gce_pd - -import ( - "github.com/GoogleCloudPlatform/kubernetes/pkg/util/mount" -) - -// Examines /proc/mounts to find all other references to the device referenced -// by mountPath. -func getMountRefs(mounter mount.Interface, mountPath string) ([]string, error) { - mps, err := mounter.List() - if err != nil { - return nil, err - } - - // Find the device name. - deviceName := "" - for i := range mps { - if mps[i].Path == mountPath { - deviceName = mps[i].Device - break - } - } - - // Find all references to the device. - var refs []string - for i := range mps { - if mps[i].Device == deviceName && mps[i].Path != mountPath { - refs = append(refs, mps[i].Path) - } - } - return refs, nil -} diff --git a/pkg/kubelet/volume/gce_pd/mount_util_test.go b/pkg/kubelet/volume/gce_pd/mount_util_test.go deleted file mode 100644 index 7001939ba0e45..0000000000000 --- a/pkg/kubelet/volume/gce_pd/mount_util_test.go +++ /dev/null @@ -1,99 +0,0 @@ -/* -Copyright 2015 Google Inc. All rights reserved. - -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 gce_pd - -import ( - "testing" - - "github.com/GoogleCloudPlatform/kubernetes/pkg/util/mount" -) - -type fakeMounter struct { - mountPoints []mount.MountPoint -} - -func (f *fakeMounter) Mount(source string, target string, fstype string, flags uintptr, data string) error { - return nil -} - -func (f *fakeMounter) Unmount(target string, flags int) error { - return nil -} - -func (f *fakeMounter) List() ([]mount.MountPoint, error) { - return f.mountPoints, nil -} - -func TestGetMountRefs(t *testing.T) { - fm := &fakeMounter{ - []mount.MountPoint{ - {Device: "/dev/sdb", Path: "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd"}, - {Device: "/dev/sdb", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd-in-pod"}, - {Device: "/dev/sdc", Path: "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd2"}, - {Device: "/dev/sdc", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod"}, - {Device: "/dev/sdc", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod2"}, - }, - } - - tests := []struct { - mountPath string - expectedRefs []string - }{ - { - "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd-in-pod", - []string{ - "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd", - }, - }, - { - "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod", - []string{ - "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod2", - "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd2", - }, - }, - } - - for i, test := range tests { - if refs, err := getMountRefs(fm, test.mountPath); err != nil || !setEquivalent(test.expectedRefs, refs) { - t.Errorf("%d. getMountRefs(%q) = %v, %v; expected %v, nil", i, test.mountPath, refs, err, test.expectedRefs) - } - } -} - -func setEquivalent(set1, set2 []string) bool { - map1 := make(map[string]bool) - map2 := make(map[string]bool) - for _, s := range set1 { - map1[s] = true - } - for _, s := range set2 { - map2[s] = true - } - - for s := range map1 { - if !map2[s] { - return false - } - } - for s := range map2 { - if !map1[s] { - return false - } - } - return true -} diff --git a/pkg/util/mount/fake.go b/pkg/util/mount/fake.go new file mode 100644 index 0000000000000..733510674c2a8 --- /dev/null +++ b/pkg/util/mount/fake.go @@ -0,0 +1,34 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +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 mount + +// FakeMounter implements mount.Interface. +type FakeMounter struct { + mountPoints []MountPoint +} + +func (f *FakeMounter) Mount(source string, target string, fstype string, flags uintptr, data string) error { + return nil +} + +func (f *FakeMounter) Unmount(target string, flags int) error { + return nil +} + +func (f *FakeMounter) List() ([]MountPoint, error) { + return f.mountPoints, nil +} diff --git a/pkg/util/mount/mount.go b/pkg/util/mount/mount.go index d5cd7a65df89a..68b9316b62932 100644 --- a/pkg/util/mount/mount.go +++ b/pkg/util/mount/mount.go @@ -49,3 +49,30 @@ type MountPoint struct { Freq int Pass int } + +// Examines /proc/mounts to find all other references to the device referenced +// by mountPath. +func GetMountRefs(mounter Interface, mountPath string) ([]string, error) { + mps, err := mounter.List() + if err != nil { + return nil, err + } + + // Find the device name. + deviceName := "" + for i := range mps { + if mps[i].Path == mountPath { + deviceName = mps[i].Device + break + } + } + + // Find all references to the device. + var refs []string + for i := range mps { + if mps[i].Device == deviceName && mps[i].Path != mountPath { + refs = append(refs, mps[i].Path) + } + } + return refs, nil +} diff --git a/pkg/util/mount/linux.go b/pkg/util/mount/mount_linux.go similarity index 100% rename from pkg/util/mount/linux.go rename to pkg/util/mount/mount_linux.go diff --git a/pkg/util/mount/linux_test.go b/pkg/util/mount/mount_linux_test.go similarity index 59% rename from pkg/util/mount/linux_test.go rename to pkg/util/mount/mount_linux_test.go index 9f2f1d432110e..98a8094583433 100644 --- a/pkg/util/mount/linux_test.go +++ b/pkg/util/mount/mount_linux_test.go @@ -91,3 +91,63 @@ func slicesEqual(a, b []string) bool { } return true } + +func TestGetMountRefs(t *testing.T) { + fm := &FakeMounter{ + []MountPoint{ + {Device: "/dev/sdb", Path: "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd"}, + {Device: "/dev/sdb", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd-in-pod"}, + {Device: "/dev/sdc", Path: "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd2"}, + {Device: "/dev/sdc", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod"}, + {Device: "/dev/sdc", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod2"}, + }, + } + + tests := []struct { + mountPath string + expectedRefs []string + }{ + { + "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd-in-pod", + []string{ + "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd", + }, + }, + { + "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod", + []string{ + "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod2", + "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd2", + }, + }, + } + + for i, test := range tests { + if refs, err := GetMountRefs(fm, test.mountPath); err != nil || !setEquivalent(test.expectedRefs, refs) { + t.Errorf("%d. getMountRefs(%q) = %v, %v; expected %v, nil", i, test.mountPath, refs, err, test.expectedRefs) + } + } +} + +func setEquivalent(set1, set2 []string) bool { + map1 := make(map[string]bool) + map2 := make(map[string]bool) + for _, s := range set1 { + map1[s] = true + } + for _, s := range set2 { + map2[s] = true + } + + for s := range map1 { + if !map2[s] { + return false + } + } + for s := range map2 { + if !map1[s] { + return false + } + } + return true +} diff --git a/pkg/util/mount/unsupported.go b/pkg/util/mount/mount_unsupported.go similarity index 100% rename from pkg/util/mount/unsupported.go rename to pkg/util/mount/mount_unsupported.go diff --git a/pkg/kubelet/volume/gce_pd/mount_util_unix.go b/pkg/util/mount/mountpoint_unix.go similarity index 94% rename from pkg/kubelet/volume/gce_pd/mount_util_unix.go rename to pkg/util/mount/mountpoint_unix.go index e7570e99c7590..cf0d82def44be 100644 --- a/pkg/kubelet/volume/gce_pd/mount_util_unix.go +++ b/pkg/util/mount/mountpoint_unix.go @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package gce_pd +package mount import ( "os" @@ -26,7 +26,7 @@ import ( // Determine if a directory is a mountpoint, by comparing the device for the directory // with the device for it's parent. If they are the same, it's not a mountpoint, if they're // different, it is. -func isMountPoint(file string) (bool, error) { +func IsMountPoint(file string) (bool, error) { stat, err := os.Stat(file) if err != nil { return false, err diff --git a/pkg/kubelet/volume/gce_pd/mount_util_unsupported.go b/pkg/util/mount/mountpoint_unsupported.go similarity index 91% rename from pkg/kubelet/volume/gce_pd/mount_util_unsupported.go rename to pkg/util/mount/mountpoint_unsupported.go index 03b4bc6e2ddd8..714f843397c6e 100644 --- a/pkg/kubelet/volume/gce_pd/mount_util_unsupported.go +++ b/pkg/util/mount/mountpoint_unsupported.go @@ -16,13 +16,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -package gce_pd +package mount import ( "fmt" ) // Dummy implementation for Windows -func isMountPoint(file string) (bool, error) { +func IsMountPoint(file string) (bool, error) { return false, fmt.Errorf("unimplemented") }