Merge pull request #48940 from rootfs/fc-fencing

Automatic merge from submit-queue (batch tested with PRs 48377, 48940, 49144, 49062, 49148)

support fc volume attach and detach

**What this PR does / why we need it**:
Support FC volume attach and detach to enforce RWO access

**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #48953

**Special notes for your reviewer**:

**Release note**:

```release-note
NONE
```
pull/6/head
Kubernetes Submit Queue 2017-07-19 19:10:12 -07:00 committed by GitHub
commit 25d3523359
7 changed files with 185 additions and 22 deletions

View File

@ -74,6 +74,7 @@ go_library(
"//pkg/volume/azure_dd:go_default_library", "//pkg/volume/azure_dd:go_default_library",
"//pkg/volume/azure_file:go_default_library", "//pkg/volume/azure_file:go_default_library",
"//pkg/volume/cinder:go_default_library", "//pkg/volume/cinder:go_default_library",
"//pkg/volume/fc:go_default_library",
"//pkg/volume/flexvolume:go_default_library", "//pkg/volume/flexvolume:go_default_library",
"//pkg/volume/flocker:go_default_library", "//pkg/volume/flocker:go_default_library",
"//pkg/volume/gce_pd:go_default_library", "//pkg/volume/gce_pd:go_default_library",

View File

@ -41,6 +41,7 @@ import (
"k8s.io/kubernetes/pkg/volume/azure_dd" "k8s.io/kubernetes/pkg/volume/azure_dd"
"k8s.io/kubernetes/pkg/volume/azure_file" "k8s.io/kubernetes/pkg/volume/azure_file"
"k8s.io/kubernetes/pkg/volume/cinder" "k8s.io/kubernetes/pkg/volume/cinder"
"k8s.io/kubernetes/pkg/volume/fc"
"k8s.io/kubernetes/pkg/volume/flexvolume" "k8s.io/kubernetes/pkg/volume/flexvolume"
"k8s.io/kubernetes/pkg/volume/flocker" "k8s.io/kubernetes/pkg/volume/flocker"
"k8s.io/kubernetes/pkg/volume/gce_pd" "k8s.io/kubernetes/pkg/volume/gce_pd"
@ -77,6 +78,7 @@ func ProbeAttachableVolumePlugins(config componentconfig.VolumeConfiguration) []
allPlugins = append(allPlugins, photon_pd.ProbeVolumePlugins()...) allPlugins = append(allPlugins, photon_pd.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, scaleio.ProbeVolumePlugins()...) allPlugins = append(allPlugins, scaleio.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, storageos.ProbeVolumePlugins()...) allPlugins = append(allPlugins, storageos.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...)
return allPlugins return allPlugins
} }

View File

@ -11,6 +11,7 @@ load(
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"attacher.go",
"disk_manager.go", "disk_manager.go",
"doc.go", "doc.go",
"fc.go", "fc.go",

170
pkg/volume/fc/attacher.go Normal file
View File

@ -0,0 +1,170 @@
/*
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 fc
import (
"fmt"
"os"
"strconv"
"time"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/types"
"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 fcAttacher struct {
host volume.VolumeHost
manager diskManager
exe exec.Interface
}
var _ volume.Attacher = &fcAttacher{}
var _ volume.AttachableVolumePlugin = &fcPlugin{}
func (plugin *fcPlugin) NewAttacher() (volume.Attacher, error) {
return &fcAttacher{
host: plugin.host,
manager: &FCUtil{},
exe: exec.New(),
}, nil
}
func (plugin *fcPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) {
mounter := plugin.host.GetMounter()
return mount.GetMountRefs(mounter, deviceMountPath)
}
func (attacher *fcAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string, error) {
return "", nil
}
func (attacher *fcAttacher) 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 *fcAttacher) WaitForAttach(spec *volume.Spec, devicePath string, timeout time.Duration) (string, error) {
mounter, err := volumeSpecToMounter(spec, attacher.host)
if err != nil {
glog.Warningf("failed to get fc mounter: %v", err)
return "", err
}
return attacher.manager.AttachDisk(*mounter)
}
func (attacher *fcAttacher) GetDeviceMountPath(
spec *volume.Spec) (string, error) {
mounter, err := volumeSpecToMounter(spec, attacher.host)
if err != nil {
glog.Warningf("failed to get fc mounter: %v", err)
return "", err
}
return attacher.manager.MakeGlobalPDName(*mounter.fcDisk), nil
}
func (attacher *fcAttacher) 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 fcDetacher struct {
mounter mount.Interface
manager diskManager
exe exec.Interface
}
var _ volume.Detacher = &fcDetacher{}
func (plugin *fcPlugin) NewDetacher() (volume.Detacher, error) {
return &fcDetacher{
mounter: plugin.host.GetMounter(),
manager: &FCUtil{},
exe: exec.New(),
}, nil
}
func (detacher *fcDetacher) Detach(deviceMountPath string, nodeName types.NodeName) error {
return nil
}
func (detacher *fcDetacher) UnmountDevice(deviceMountPath string) error {
return volumeutil.UnmountPath(deviceMountPath, detacher.mounter)
}
func volumeSpecToMounter(spec *volume.Spec, host volume.VolumeHost) (*fcDiskMounter, error) {
fc, readOnly, err := getVolumeSource(spec)
if err != nil {
return nil, err
}
if fc.Lun == nil {
return nil, fmt.Errorf("empty lun")
}
lun := strconv.Itoa(int(*fc.Lun))
return &fcDiskMounter{
fcDisk: &fcDisk{
plugin: &fcPlugin{
host: host,
},
wwns: fc.TargetWWNs,
lun: lun,
io: &osIOHandler{},
},
fsType: fc.FSType,
readOnly: readOnly,
mounter: &mount.SafeFormatAndMount{Interface: host.GetMounter(), Runner: exec.New()},
}, nil
}

View File

@ -28,7 +28,7 @@ import (
type diskManager interface { type diskManager interface {
MakeGlobalPDName(disk fcDisk) string MakeGlobalPDName(disk fcDisk) string
// Attaches the disk to the kubelet's host machine. // Attaches the disk to the kubelet's host machine.
AttachDisk(b fcDiskMounter) error AttachDisk(b fcDiskMounter) (string, error)
// Detaches the disk from the kubelet's host machine. // Detaches the disk from the kubelet's host machine.
DetachDisk(disk fcDiskUnmounter, mntPath string) error DetachDisk(disk fcDiskUnmounter, mntPath string) error
} }
@ -46,11 +46,6 @@ func diskSetUp(manager diskManager, b fcDiskMounter, volPath string, mounter mou
if !noMnt { if !noMnt {
return nil 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 { if err := os.MkdirAll(volPath, 0750); err != nil {
glog.Errorf("failed to mkdir:%s", volPath) glog.Errorf("failed to mkdir:%s", volPath)
return err return err

View File

@ -100,18 +100,18 @@ func (fake *fakeDiskManager) Cleanup() {
func (fake *fakeDiskManager) MakeGlobalPDName(disk fcDisk) string { func (fake *fakeDiskManager) MakeGlobalPDName(disk fcDisk) string {
return fake.tmpDir return fake.tmpDir
} }
func (fake *fakeDiskManager) AttachDisk(b fcDiskMounter) error { func (fake *fakeDiskManager) AttachDisk(b fcDiskMounter) (string, error) {
globalPath := b.manager.MakeGlobalPDName(*b.fcDisk) globalPath := b.manager.MakeGlobalPDName(*b.fcDisk)
err := os.MkdirAll(globalPath, 0750) err := os.MkdirAll(globalPath, 0750)
if err != nil { if err != nil {
return err return "", err
} }
// Simulate the global mount so that the fakeMounter returns the // Simulate the global mount so that the fakeMounter returns the
// expected number of mounts for the attached disk. // expected number of mounts for the attached disk.
b.mounter.Mount(globalPath, globalPath, b.fsType, nil) b.mounter.Mount(globalPath, globalPath, b.fsType, nil)
fake.attachCalled = true fake.attachCalled = true
return nil return "", nil
} }
func (fake *fakeDiskManager) DetachDisk(c fcDiskUnmounter, mntPath string) error { func (fake *fakeDiskManager) DetachDisk(c fcDiskUnmounter, mntPath string) error {
@ -172,9 +172,6 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) {
t.Errorf("SetUp() failed: %v", err) t.Errorf("SetUp() failed: %v", err)
} }
} }
if !fakeManager.attachCalled {
t.Errorf("Attach was not called")
}
fakeManager2 := NewFakeDiskManager() fakeManager2 := NewFakeDiskManager()
defer fakeManager2.Cleanup() defer fakeManager2.Cleanup()
@ -194,9 +191,6 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) {
} else if !os.IsNotExist(err) { } else if !os.IsNotExist(err) {
t.Errorf("SetUp() failed: %v", err) t.Errorf("SetUp() failed: %v", err)
} }
if !fakeManager2.detachCalled {
t.Errorf("Detach was not called")
}
} }
func TestPluginVolume(t *testing.T) { func TestPluginVolume(t *testing.T) {

View File

@ -140,7 +140,7 @@ func searchDisk(wwns []string, lun string, io ioHandler) (string, string) {
return disk, dm return disk, dm
} }
func (util *FCUtil) AttachDisk(b fcDiskMounter) error { func (util *FCUtil) AttachDisk(b fcDiskMounter) (string, error) {
devicePath := "" devicePath := ""
wwns := b.wwns wwns := b.wwns
lun := b.lun lun := b.lun
@ -148,7 +148,7 @@ func (util *FCUtil) AttachDisk(b fcDiskMounter) error {
disk, dm := searchDisk(wwns, lun, io) disk, dm := searchDisk(wwns, lun, io)
// if no disk matches input wwn and lun, exit // if no disk matches input wwn and lun, exit
if disk == "" && dm == "" { if disk == "" && dm == "" {
return fmt.Errorf("no fc disk found") return "", fmt.Errorf("no fc disk found")
} }
// if multipath devicemapper device is found, use it; otherwise use raw disk // if multipath devicemapper device is found, use it; otherwise use raw disk
@ -158,23 +158,23 @@ func (util *FCUtil) AttachDisk(b fcDiskMounter) error {
devicePath = disk devicePath = disk
} }
// mount it // mount it
globalPDPath := b.manager.MakeGlobalPDName(*b.fcDisk) globalPDPath := util.MakeGlobalPDName(*b.fcDisk)
noMnt, err := b.mounter.IsLikelyNotMountPoint(globalPDPath) noMnt, err := b.mounter.IsLikelyNotMountPoint(globalPDPath)
if !noMnt { if !noMnt {
glog.Infof("fc: %s already mounted", globalPDPath) glog.Infof("fc: %s already mounted", globalPDPath)
return nil return devicePath, nil
} }
if err := os.MkdirAll(globalPDPath, 0750); err != nil { if err := os.MkdirAll(globalPDPath, 0750); err != nil {
return fmt.Errorf("fc: failed to mkdir %s, error", globalPDPath) return devicePath, fmt.Errorf("fc: failed to mkdir %s, error", globalPDPath)
} }
err = b.mounter.FormatAndMount(devicePath, globalPDPath, b.fsType, nil) err = b.mounter.FormatAndMount(devicePath, globalPDPath, b.fsType, nil)
if err != nil { if err != nil {
return fmt.Errorf("fc: failed to mount fc volume %s [%s] to %s, error %v", devicePath, b.fsType, globalPDPath, err) return devicePath, fmt.Errorf("fc: failed to mount fc volume %s [%s] to %s, error %v", devicePath, b.fsType, globalPDPath, err)
} }
return err return devicePath, err
} }
func (util *FCUtil) DetachDisk(c fcDiskUnmounter, mntPath string) error { func (util *FCUtil) DetachDisk(c fcDiskUnmounter, mntPath string) error {