Add generated file

This PR adds generated files under pkg/client and vendor folder.
This commit is contained in:
xing-yang
2018-07-12 10:55:15 -07:00
parent 36b1de0341
commit e213d1890d
17729 changed files with 5090889 additions and 0 deletions

65
vendor/k8s.io/kubernetes/pkg/volume/fc/BUILD generated vendored Normal file
View File

@@ -0,0 +1,65 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"attacher.go",
"disk_manager.go",
"doc.go",
"fc.go",
"fc_util.go",
],
importpath = "k8s.io/kubernetes/pkg/volume/fc",
deps = [
"//pkg/features:go_default_library",
"//pkg/util/mount:go_default_library",
"//pkg/util/strings:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/util:go_default_library",
"//pkg/volume/util/volumepathhandler:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"fc_test.go",
"fc_util_test.go",
],
embed = [":go_default_library"],
deps = [
"//pkg/util/mount:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/testing:go_default_library",
"//pkg/volume/util:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
"//vendor/k8s.io/client-go/util/testing:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

10
vendor/k8s.io/kubernetes/pkg/volume/fc/OWNERS generated vendored Normal file
View File

@@ -0,0 +1,10 @@
approvers:
- rootfs
- saad-ali
reviewers:
- saad-ali
- jsafrane
- rootfs
- jingxu97
- msau42
- mtanino

222
vendor/k8s.io/kubernetes/pkg/volume/fc/attacher.go generated vendored Normal file
View File

@@ -0,0 +1,222 @@
/*
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"
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/features"
"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
}
var _ volume.Attacher = &fcAttacher{}
var _ volume.AttachableVolumePlugin = &fcPlugin{}
func (plugin *fcPlugin) NewAttacher() (volume.Attacher, error) {
return &fcAttacher{
host: plugin.host,
manager: &FCUtil{},
}, nil
}
func (plugin *fcPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) {
mounter := plugin.host.GetMounter(plugin.GetPluginName())
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, _ *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)
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(fcPluginName)
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, Exec: attacher.host.GetExec(fcPluginName)}
mountOptions := volumeutil.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
}
var _ volume.Detacher = &fcDetacher{}
func (plugin *fcPlugin) NewDetacher() (volume.Detacher, error) {
return &fcDetacher{
mounter: plugin.host.GetMounter(plugin.GetPluginName()),
manager: &FCUtil{},
}, nil
}
func (detacher *fcDetacher) Detach(volumeName string, nodeName types.NodeName) error {
return nil
}
func (detacher *fcDetacher) UnmountDevice(deviceMountPath string) error {
// Specify device name for DetachDisk later
devName, _, err := mount.GetDeviceNameFromMount(detacher.mounter, deviceMountPath)
if err != nil {
glog.Errorf("fc: failed to get device from mnt: %s\nError: %v", deviceMountPath, err)
return err
}
// Unmount for deviceMountPath(=globalPDPath)
err = volumeutil.UnmountPath(deviceMountPath, detacher.mounter)
if err != nil {
return fmt.Errorf("fc: failed to unmount: %s\nError: %v", deviceMountPath, err)
}
unMounter := volumeSpecToUnmounter(detacher.mounter)
err = detacher.manager.DetachDisk(*unMounter, devName)
if err != nil {
return fmt.Errorf("fc: failed to detach disk: %s\nError: %v", devName, err)
}
glog.V(4).Infof("fc: successfully detached disk: %s", devName)
return nil
}
func volumeSpecToMounter(spec *volume.Spec, host volume.VolumeHost) (*fcDiskMounter, error) {
fc, readOnly, err := getVolumeSource(spec)
if err != nil {
return nil, err
}
var lun string
var wwids []string
if fc.Lun != nil && len(fc.TargetWWNs) != 0 {
lun = strconv.Itoa(int(*fc.Lun))
} else if len(fc.WWIDs) != 0 {
for _, wwid := range fc.WWIDs {
wwids = append(wwids, strings.Replace(wwid, " ", "_", -1))
}
} else {
return nil, fmt.Errorf("fc: no fc disk information found. failed to make a new mounter")
}
fcDisk := &fcDisk{
plugin: &fcPlugin{
host: host,
},
wwns: fc.TargetWWNs,
lun: lun,
wwids: wwids,
io: &osIOHandler{},
}
// TODO: remove feature gate check after no longer needed
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
volumeMode, err := volumeutil.GetVolumeMode(spec)
if err != nil {
return nil, err
}
glog.V(5).Infof("fc: volumeSpecToMounter volumeMode %s", volumeMode)
return &fcDiskMounter{
fcDisk: fcDisk,
fsType: fc.FSType,
volumeMode: volumeMode,
readOnly: readOnly,
mounter: volumeutil.NewSafeFormatAndMountFromHost(fcPluginName, host),
deviceUtil: volumeutil.NewDeviceHandler(volumeutil.NewIOHandler()),
}, nil
}
return &fcDiskMounter{
fcDisk: fcDisk,
fsType: fc.FSType,
readOnly: readOnly,
mounter: volumeutil.NewSafeFormatAndMountFromHost(fcPluginName, host),
deviceUtil: volumeutil.NewDeviceHandler(volumeutil.NewIOHandler()),
}, nil
}
func volumeSpecToUnmounter(mounter mount.Interface) *fcDiskUnmounter {
return &fcDiskUnmounter{
fcDisk: &fcDisk{
io: &osIOHandler{},
},
mounter: mounter,
deviceUtil: volumeutil.NewDeviceHandler(volumeutil.NewIOHandler()),
}
}

94
vendor/k8s.io/kubernetes/pkg/volume/fc/disk_manager.go generated vendored Normal file
View File

@@ -0,0 +1,94 @@
/*
Copyright 2015 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 (
"os"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
)
// Abstract interface to disk operations.
type diskManager interface {
MakeGlobalPDName(disk fcDisk) string
MakeGlobalVDPDName(disk fcDisk) string
// Attaches the disk to the kubelet's host machine.
AttachDisk(b fcDiskMounter) (string, error)
// Detaches the disk from the kubelet's host machine.
DetachDisk(disk fcDiskUnmounter, devicePath string) error
// Detaches the block disk from the kubelet's host machine.
DetachBlockFCDisk(disk fcDiskUnmapper, mntPath, devicePath string) error
}
// utility to mount a disk based filesystem
func diskSetUp(manager diskManager, b fcDiskMounter, volPath string, mounter mount.Interface, fsGroup *int64) error {
globalPDPath := manager.MakeGlobalPDName(*b.fcDisk)
noMnt, err := mounter.IsLikelyNotMountPoint(volPath)
if err != nil && !os.IsNotExist(err) {
glog.Errorf("cannot validate mountpoint: %s", volPath)
return err
}
if !noMnt {
return nil
}
if err := os.MkdirAll(volPath, 0750); err != nil {
glog.Errorf("failed to mkdir:%s", volPath)
return err
}
// Perform a bind mount to the full path to allow duplicate mounts of the same disk.
options := []string{"bind"}
if b.readOnly {
options = append(options, "ro")
}
err = mounter.Mount(globalPDPath, volPath, "", options)
if err != nil {
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
}
if !b.readOnly {
volume.SetVolumeOwnership(&b, fsGroup)
}
return nil
}

19
vendor/k8s.io/kubernetes/pkg/volume/fc/doc.go generated vendored Normal file
View File

@@ -0,0 +1,19 @@
/*
Copyright 2015 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 contains the internal representation of
// Fibre Channel (fc) volumes.
package fc // import "k8s.io/kubernetes/pkg/volume/fc"

526
vendor/k8s.io/kubernetes/pkg/volume/fc/fc.go generated vendored Normal file
View File

@@ -0,0 +1,526 @@
/*
Copyright 2015 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"
"strings"
"github.com/golang/glog"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/util/mount"
utilstrings "k8s.io/kubernetes/pkg/util/strings"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
"k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
)
// This is the primary entrypoint for volume plugins.
func ProbeVolumePlugins() []volume.VolumePlugin {
return []volume.VolumePlugin{&fcPlugin{nil}}
}
type fcPlugin struct {
host volume.VolumeHost
}
var _ volume.VolumePlugin = &fcPlugin{}
var _ volume.PersistentVolumePlugin = &fcPlugin{}
var _ volume.BlockVolumePlugin = &fcPlugin{}
const (
fcPluginName = "kubernetes.io/fc"
)
func (plugin *fcPlugin) Init(host volume.VolumeHost) error {
plugin.host = host
return nil
}
func (plugin *fcPlugin) GetPluginName() string {
return fcPluginName
}
func (plugin *fcPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
volumeSource, _, err := getVolumeSource(spec)
if err != nil {
return "", err
}
// API server validates these parameters beforehand but attach/detach
// controller creates volumespec without validation. They may be nil
// or zero length. We should check again to avoid unexpected conditions.
if len(volumeSource.TargetWWNs) != 0 && volumeSource.Lun != nil {
// TargetWWNs are the FibreChannel target worldwide names
return fmt.Sprintf("%v:%v", volumeSource.TargetWWNs, *volumeSource.Lun), nil
} else if len(volumeSource.WWIDs) != 0 {
// WWIDs are the FibreChannel World Wide Identifiers
return fmt.Sprintf("%v", volumeSource.WWIDs), nil
}
return "", err
}
func (plugin *fcPlugin) CanSupport(spec *volume.Spec) bool {
return (spec.Volume != nil && spec.Volume.FC != nil) || (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.FC != nil)
}
func (plugin *fcPlugin) RequiresRemount() bool {
return false
}
func (plugin *fcPlugin) SupportsMountOption() bool {
return false
}
func (plugin *fcPlugin) SupportsBulkVolumeVerification() bool {
return false
}
func (plugin *fcPlugin) GetAccessModes() []v1.PersistentVolumeAccessMode {
return []v1.PersistentVolumeAccessMode{
v1.ReadWriteOnce,
v1.ReadOnlyMany,
}
}
func (plugin *fcPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
// Inject real implementations here, test through the internal function.
return plugin.newMounterInternal(spec, pod.UID, &FCUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()))
}
func (plugin *fcPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec mount.Exec) (volume.Mounter, error) {
// fc volumes used directly in a pod have a ReadOnly flag set by the pod author.
// fc volumes used as a PersistentVolume gets the ReadOnly flag indirectly through the persistent-claim volume used to mount the PV
fc, readOnly, err := getVolumeSource(spec)
if err != nil {
return nil, err
}
wwns, lun, wwids, err := getWwnsLunWwids(fc)
if err != nil {
return nil, fmt.Errorf("fc: no fc disk information found. failed to make a new mounter")
}
fcDisk := &fcDisk{
podUID: podUID,
volName: spec.Name(),
wwns: wwns,
lun: lun,
wwids: wwids,
manager: manager,
io: &osIOHandler{},
plugin: plugin,
}
// TODO: remove feature gate check after no longer needed
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
volumeMode, err := util.GetVolumeMode(spec)
if err != nil {
return nil, err
}
glog.V(5).Infof("fc: newMounterInternal volumeMode %s", volumeMode)
return &fcDiskMounter{
fcDisk: fcDisk,
fsType: fc.FSType,
volumeMode: volumeMode,
readOnly: readOnly,
mounter: &mount.SafeFormatAndMount{Interface: mounter, Exec: exec},
deviceUtil: util.NewDeviceHandler(util.NewIOHandler()),
}, nil
}
return &fcDiskMounter{
fcDisk: fcDisk,
fsType: fc.FSType,
readOnly: readOnly,
mounter: &mount.SafeFormatAndMount{Interface: mounter, Exec: exec},
deviceUtil: util.NewDeviceHandler(util.NewIOHandler()),
}, nil
}
func (plugin *fcPlugin) NewBlockVolumeMapper(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.BlockVolumeMapper, error) {
// If this called via GenerateUnmapDeviceFunc(), pod is nil.
// Pass empty string as dummy uid since uid isn't used in the case.
var uid types.UID
if pod != nil {
uid = pod.UID
}
return plugin.newBlockVolumeMapperInternal(spec, uid, &FCUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()))
}
func (plugin *fcPlugin) newBlockVolumeMapperInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec mount.Exec) (volume.BlockVolumeMapper, error) {
fc, readOnly, err := getVolumeSource(spec)
if err != nil {
return nil, err
}
wwns, lun, wwids, err := getWwnsLunWwids(fc)
if err != nil {
return nil, fmt.Errorf("fc: no fc disk information found. failed to make a new mapper")
}
return &fcDiskMapper{
fcDisk: &fcDisk{
podUID: podUID,
volName: spec.Name(),
wwns: wwns,
lun: lun,
wwids: wwids,
manager: manager,
io: &osIOHandler{},
plugin: plugin},
readOnly: readOnly,
mounter: &mount.SafeFormatAndMount{Interface: mounter, Exec: exec},
deviceUtil: util.NewDeviceHandler(util.NewIOHandler()),
}, nil
}
func (plugin *fcPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
// Inject real implementations here, test through the internal function.
return plugin.newUnmounterInternal(volName, podUID, &FCUtil{}, plugin.host.GetMounter(plugin.GetPluginName()))
}
func (plugin *fcPlugin) newUnmounterInternal(volName string, podUID types.UID, manager diskManager, mounter mount.Interface) (volume.Unmounter, error) {
return &fcDiskUnmounter{
fcDisk: &fcDisk{
podUID: podUID,
volName: volName,
manager: manager,
plugin: plugin,
io: &osIOHandler{},
},
mounter: mounter,
deviceUtil: util.NewDeviceHandler(util.NewIOHandler()),
}, nil
}
func (plugin *fcPlugin) NewBlockVolumeUnmapper(volName string, podUID types.UID) (volume.BlockVolumeUnmapper, error) {
return plugin.newUnmapperInternal(volName, podUID, &FCUtil{})
}
func (plugin *fcPlugin) newUnmapperInternal(volName string, podUID types.UID, manager diskManager) (volume.BlockVolumeUnmapper, error) {
return &fcDiskUnmapper{
fcDisk: &fcDisk{
podUID: podUID,
volName: volName,
manager: manager,
plugin: plugin,
io: &osIOHandler{},
},
deviceUtil: util.NewDeviceHandler(util.NewIOHandler()),
}, nil
}
func (plugin *fcPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
// Find globalPDPath from pod volume directory(mountPath)
// examples:
// mountPath: pods/{podUid}/volumes/kubernetes.io~fc/{volumeName}
// globalPDPath : plugins/kubernetes.io/fc/50060e801049cfd1-lun-0
var globalPDPath string
mounter := plugin.host.GetMounter(plugin.GetPluginName())
paths, err := mount.GetMountRefs(mounter, mountPath)
if err != nil {
return nil, err
}
for _, path := range paths {
if strings.Contains(path, plugin.host.GetPluginDir(fcPluginName)) {
globalPDPath = path
break
}
}
// Couldn't fetch globalPDPath
if len(globalPDPath) == 0 {
return nil, fmt.Errorf("couldn't fetch globalPDPath. failed to obtain volume spec")
}
arr := strings.Split(globalPDPath, "/")
if len(arr) < 1 {
return nil, fmt.Errorf("failed to retrieve volume plugin information from globalPDPath: %v", globalPDPath)
}
volumeInfo := arr[len(arr)-1]
// Create volume from wwn+lun or wwid
var fcVolume *v1.Volume
if strings.Contains(volumeInfo, "-lun-") {
wwnLun := strings.Split(volumeInfo, "-lun-")
if len(wwnLun) < 2 {
return nil, fmt.Errorf("failed to retrieve TargetWWN and Lun. volumeInfo is invalid: %v", volumeInfo)
}
lun, err := strconv.Atoi(wwnLun[1])
if err != nil {
return nil, err
}
lun32 := int32(lun)
fcVolume = &v1.Volume{
Name: volumeName,
VolumeSource: v1.VolumeSource{
FC: &v1.FCVolumeSource{TargetWWNs: []string{wwnLun[0]}, Lun: &lun32},
},
}
glog.V(5).Infof("ConstructVolumeSpec: TargetWWNs: %v, Lun: %v",
fcVolume.VolumeSource.FC.TargetWWNs, *fcVolume.VolumeSource.FC.Lun)
} else {
fcVolume = &v1.Volume{
Name: volumeName,
VolumeSource: v1.VolumeSource{
FC: &v1.FCVolumeSource{WWIDs: []string{volumeInfo}},
},
}
glog.V(5).Infof("ConstructVolumeSpec: WWIDs: %v", fcVolume.VolumeSource.FC.WWIDs)
}
return volume.NewSpecFromVolume(fcVolume), nil
}
// ConstructBlockVolumeSpec creates a new volume.Spec with following steps.
// - Searches a file whose name is {pod uuid} under volume plugin directory.
// - If a file is found, then retreives volumePluginDependentPath from globalMapPathUUID.
// - Once volumePluginDependentPath is obtained, store volume information to VolumeSource
// examples:
// mapPath: pods/{podUid}/{DefaultKubeletVolumeDevicesDirName}/{escapeQualifiedPluginName}/{volumeName}
// globalMapPathUUID : plugins/kubernetes.io/{PluginName}/{DefaultKubeletVolumeDevicesDirName}/{volumePluginDependentPath}/{pod uuid}
func (plugin *fcPlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName, mapPath string) (*volume.Spec, error) {
pluginDir := plugin.host.GetVolumeDevicePluginDir(fcPluginName)
blkutil := volumepathhandler.NewBlockVolumePathHandler()
globalMapPathUUID, err := blkutil.FindGlobalMapPathUUIDFromPod(pluginDir, mapPath, podUID)
if err != nil {
return nil, err
}
glog.V(5).Infof("globalMapPathUUID: %v, err: %v", globalMapPathUUID, err)
// Retrieve volumePluginDependentPath from globalMapPathUUID
// globalMapPathUUID examples:
// wwn+lun: plugins/kubernetes.io/fc/volumeDevices/50060e801049cfd1-lun-0/{pod uuid}
// wwid: plugins/kubernetes.io/fc/volumeDevices/3600508b400105e210000900000490000/{pod uuid}
arr := strings.Split(globalMapPathUUID, "/")
if len(arr) < 2 {
return nil, fmt.Errorf("Fail to retrieve volume plugin information from globalMapPathUUID: %v", globalMapPathUUID)
}
l := len(arr) - 2
volumeInfo := arr[l]
// Create volume from wwn+lun or wwid
var fcPV *v1.PersistentVolume
if strings.Contains(volumeInfo, "-lun-") {
wwnLun := strings.Split(volumeInfo, "-lun-")
lun, err := strconv.Atoi(wwnLun[1])
if err != nil {
return nil, err
}
lun32 := int32(lun)
fcPV = createPersistentVolumeFromFCVolumeSource(volumeName,
v1.FCVolumeSource{TargetWWNs: []string{wwnLun[0]}, Lun: &lun32})
glog.V(5).Infof("ConstructBlockVolumeSpec: TargetWWNs: %v, Lun: %v",
fcPV.Spec.PersistentVolumeSource.FC.TargetWWNs,
*fcPV.Spec.PersistentVolumeSource.FC.Lun)
} else {
fcPV = createPersistentVolumeFromFCVolumeSource(volumeName,
v1.FCVolumeSource{WWIDs: []string{volumeInfo}})
glog.V(5).Infof("ConstructBlockVolumeSpec: WWIDs: %v", fcPV.Spec.PersistentVolumeSource.FC.WWIDs)
}
return volume.NewSpecFromPersistentVolume(fcPV, false), nil
}
type fcDisk struct {
volName string
podUID types.UID
portal string
wwns []string
lun string
wwids []string
plugin *fcPlugin
// Utility interface that provides API calls to the provider to attach/detach disks.
manager diskManager
// io handler interface
io ioHandler
volume.MetricsNil
}
func (fc *fcDisk) GetPath() string {
name := fcPluginName
// safe to use PodVolumeDir now: volume teardown occurs before pod is cleaned up
return fc.plugin.host.GetPodVolumeDir(fc.podUID, utilstrings.EscapeQualifiedNameForDisk(name), fc.volName)
}
func (fc *fcDisk) fcGlobalMapPath(spec *volume.Spec) (string, error) {
mounter, err := volumeSpecToMounter(spec, fc.plugin.host)
if err != nil {
glog.Warningf("failed to get fc mounter: %v", err)
return "", err
}
return fc.manager.MakeGlobalVDPDName(*mounter.fcDisk), nil
}
func (fc *fcDisk) fcPodDeviceMapPath() (string, string) {
name := fcPluginName
return fc.plugin.host.GetPodVolumeDeviceDir(fc.podUID, utilstrings.EscapeQualifiedNameForDisk(name)), fc.volName
}
type fcDiskMounter struct {
*fcDisk
readOnly bool
fsType string
volumeMode v1.PersistentVolumeMode
mounter *mount.SafeFormatAndMount
deviceUtil util.DeviceUtil
}
var _ volume.Mounter = &fcDiskMounter{}
func (b *fcDiskMounter) GetAttributes() volume.Attributes {
return volume.Attributes{
ReadOnly: b.readOnly,
Managed: !b.readOnly,
SupportsSELinux: true,
}
}
// Checks prior to mount operations to verify that the required components (binaries, etc.)
// to mount the volume are available on the underlying node.
// If not, it returns an error
func (b *fcDiskMounter) CanMount() error {
return nil
}
func (b *fcDiskMounter) SetUp(fsGroup *int64) error {
return b.SetUpAt(b.GetPath(), fsGroup)
}
func (b *fcDiskMounter) SetUpAt(dir string, fsGroup *int64) error {
// diskSetUp checks mountpoints and prevent repeated calls
err := diskSetUp(b.manager, *b, dir, b.mounter, fsGroup)
if err != nil {
glog.Errorf("fc: failed to setup")
}
return err
}
type fcDiskUnmounter struct {
*fcDisk
mounter mount.Interface
deviceUtil util.DeviceUtil
}
var _ volume.Unmounter = &fcDiskUnmounter{}
// Unmounts the bind mount, and detaches the disk only if the disk
// resource was the last reference to that disk on the kubelet.
func (c *fcDiskUnmounter) TearDown() error {
return c.TearDownAt(c.GetPath())
}
func (c *fcDiskUnmounter) TearDownAt(dir string) error {
return util.UnmountPath(dir, c.mounter)
}
// Block Volumes Support
type fcDiskMapper struct {
*fcDisk
readOnly bool
mounter mount.Interface
deviceUtil util.DeviceUtil
}
var _ volume.BlockVolumeMapper = &fcDiskMapper{}
func (b *fcDiskMapper) SetUpDevice() (string, error) {
return "", nil
}
func (b *fcDiskMapper) MapDevice(devicePath, globalMapPath, volumeMapPath, volumeMapName string, podUID types.UID) error {
return util.MapBlockVolume(devicePath, globalMapPath, volumeMapPath, volumeMapName, podUID)
}
type fcDiskUnmapper struct {
*fcDisk
deviceUtil util.DeviceUtil
}
var _ volume.BlockVolumeUnmapper = &fcDiskUnmapper{}
func (c *fcDiskUnmapper) TearDownDevice(mapPath, devicePath string) error {
err := c.manager.DetachBlockFCDisk(*c, mapPath, devicePath)
if err != nil {
return fmt.Errorf("fc: failed to detach disk: %s\nError: %v", mapPath, err)
}
glog.V(4).Infof("fc: %q is unmounted, deleting the directory", mapPath)
err = os.RemoveAll(mapPath)
if err != nil {
return fmt.Errorf("fc: failed to delete the directory: %s\nError: %v", mapPath, err)
}
glog.V(4).Infof("fc: successfully detached disk: %s", mapPath)
return nil
}
// GetGlobalMapPath returns global map path and error
// path: plugins/kubernetes.io/{PluginName}/volumeDevices/{WWID}/{podUid}
func (fc *fcDisk) GetGlobalMapPath(spec *volume.Spec) (string, error) {
return fc.fcGlobalMapPath(spec)
}
// GetPodDeviceMapPath returns pod device map path and volume name
// path: pods/{podUid}/volumeDevices/kubernetes.io~fc
// volumeName: pv0001
func (fc *fcDisk) GetPodDeviceMapPath() (string, string) {
return fc.fcPodDeviceMapPath()
}
func getVolumeSource(spec *volume.Spec) (*v1.FCVolumeSource, bool, error) {
// fc volumes used directly in a pod have a ReadOnly flag set by the pod author.
// fc volumes used as a PersistentVolume gets the ReadOnly flag indirectly through the persistent-claim volume used to mount the PV
if spec.Volume != nil && spec.Volume.FC != nil {
return spec.Volume.FC, spec.Volume.FC.ReadOnly, nil
} else if spec.PersistentVolume != nil &&
spec.PersistentVolume.Spec.FC != nil {
return spec.PersistentVolume.Spec.FC, spec.ReadOnly, nil
}
return nil, false, fmt.Errorf("Spec does not reference a FibreChannel volume type")
}
func createPersistentVolumeFromFCVolumeSource(volumeName string, fc v1.FCVolumeSource) *v1.PersistentVolume {
block := v1.PersistentVolumeBlock
return &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: volumeName,
},
Spec: v1.PersistentVolumeSpec{
PersistentVolumeSource: v1.PersistentVolumeSource{
FC: &fc,
},
VolumeMode: &block,
},
}
}
func getWwnsLunWwids(fc *v1.FCVolumeSource) ([]string, string, []string, error) {
var lun string
var wwids []string
if fc.Lun != nil && len(fc.TargetWWNs) != 0 {
lun = strconv.Itoa(int(*fc.Lun))
return fc.TargetWWNs, lun, wwids, nil
}
if len(fc.WWIDs) != 0 {
for _, wwid := range fc.WWIDs {
wwids = append(wwids, strings.Replace(wwid, " ", "_", -1))
}
return fc.TargetWWNs, lun, wwids, nil
}
return nil, "", nil, fmt.Errorf("fc: no fc disk information found")
}

503
vendor/k8s.io/kubernetes/pkg/volume/fc/fc_test.go generated vendored Normal file
View File

@@ -0,0 +1,503 @@
/*
Copyright 2015 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"
"runtime"
"strconv"
"strings"
"testing"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/fake"
utiltesting "k8s.io/client-go/util/testing"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
)
func TestCanSupport(t *testing.T) {
tmpDir, err := utiltesting.MkTmpdir("fc_test")
if err != nil {
t.Fatalf("error creating temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/fc")
if err != nil {
t.Errorf("Can't find the plugin by name")
}
if plug.GetPluginName() != "kubernetes.io/fc" {
t.Errorf("Wrong name: %s", plug.GetPluginName())
}
if plug.CanSupport(&volume.Spec{}) {
t.Errorf("Expected false")
}
if plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{}}}) {
t.Errorf("Expected false")
}
if !plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{FC: &v1.FCVolumeSource{}}}}) {
t.Errorf("Expected true")
}
if plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{}}}) {
t.Errorf("Expected false")
}
if plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{}}}}) {
t.Errorf("Expected false")
}
if !plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{FC: &v1.FCVolumeSource{}}}}}) {
t.Errorf("Expected true")
}
}
func TestGetAccessModes(t *testing.T) {
tmpDir, err := utiltesting.MkTmpdir("fc_test")
if err != nil {
t.Fatalf("error creating temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/fc")
if err != nil {
t.Errorf("Can't find the plugin by name")
}
if !volumetest.ContainsAccessMode(plug.GetAccessModes(), v1.ReadWriteOnce) || !volumetest.ContainsAccessMode(plug.GetAccessModes(), v1.ReadOnlyMany) {
t.Errorf("Expected two AccessModeTypes: %s and %s", v1.ReadWriteOnce, v1.ReadOnlyMany)
}
}
type fakeDiskManager struct {
tmpDir string
attachCalled bool
detachCalled bool
}
func NewFakeDiskManager() *fakeDiskManager {
return &fakeDiskManager{
tmpDir: utiltesting.MkTmpdirOrDie("fc_test"),
}
}
func (fake *fakeDiskManager) Cleanup() {
os.RemoveAll(fake.tmpDir)
}
func (fake *fakeDiskManager) MakeGlobalPDName(disk fcDisk) string {
return fake.tmpDir
}
func (fake *fakeDiskManager) MakeGlobalVDPDName(disk fcDisk) string {
return fake.tmpDir
}
func (fake *fakeDiskManager) AttachDisk(b fcDiskMounter) (string, error) {
globalPath := b.manager.MakeGlobalPDName(*b.fcDisk)
err := os.MkdirAll(globalPath, 0750)
if err != nil {
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
}
func (fake *fakeDiskManager) DetachDisk(c fcDiskUnmounter, mntPath string) error {
globalPath := c.manager.MakeGlobalPDName(*c.fcDisk)
err := os.RemoveAll(globalPath)
if err != nil {
return err
}
fake.detachCalled = true
return nil
}
func (fake *fakeDiskManager) DetachBlockFCDisk(c fcDiskUnmapper, mapPath, devicePath string) error {
err := os.RemoveAll(mapPath)
if err != nil {
return err
}
fake.detachCalled = true
return nil
}
func doTestPlugin(t *testing.T, spec *volume.Spec) {
tmpDir, err := utiltesting.MkTmpdir("fc_test")
if err != nil {
t.Fatalf("error creating temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/fc")
if err != nil {
t.Errorf("Can't find the plugin by name")
}
fakeManager := NewFakeDiskManager()
defer fakeManager.Cleanup()
fakeMounter := &mount.FakeMounter{}
fakeExec := mount.NewFakeExec(nil)
mounter, err := plug.(*fcPlugin).newMounterInternal(spec, types.UID("poduid"), fakeManager, fakeMounter, fakeExec)
if err != nil {
t.Errorf("Failed to make a new Mounter: %v", err)
}
if mounter == nil {
t.Errorf("Got a nil Mounter: %v", err)
}
path := mounter.GetPath()
expectedPath := fmt.Sprintf("%s/pods/poduid/volumes/kubernetes.io~fc/vol1", tmpDir)
if path != expectedPath {
t.Errorf("Unexpected path, expected %q, got: %q", expectedPath, path)
}
if err := mounter.SetUp(nil); err != nil {
t.Errorf("Expected success, got: %v", err)
}
if _, err := os.Stat(path); err != nil {
if os.IsNotExist(err) {
t.Errorf("SetUp() failed, volume path not created: %s", path)
} else {
t.Errorf("SetUp() failed: %v", err)
}
}
fakeManager2 := NewFakeDiskManager()
defer fakeManager2.Cleanup()
unmounter, err := plug.(*fcPlugin).newUnmounterInternal("vol1", types.UID("poduid"), fakeManager2, fakeMounter)
if err != nil {
t.Errorf("Failed to make a new Unmounter: %v", err)
}
if unmounter == nil {
t.Errorf("Got a nil Unmounter: %v", err)
}
if err := unmounter.TearDown(); err != nil {
t.Errorf("Expected success, got: %v", err)
}
if _, err := os.Stat(path); err == nil {
t.Errorf("TearDown() failed, volume path still exists: %s", path)
} else if !os.IsNotExist(err) {
t.Errorf("TearDown() failed: %v", err)
}
}
func doTestPluginNilMounter(t *testing.T, spec *volume.Spec) {
tmpDir, err := utiltesting.MkTmpdir("fc_test")
if err != nil {
t.Fatalf("error creating temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/fc")
if err != nil {
t.Errorf("Can't find the plugin by name")
}
fakeManager := NewFakeDiskManager()
defer fakeManager.Cleanup()
fakeMounter := &mount.FakeMounter{}
fakeExec := mount.NewFakeExec(nil)
mounter, err := plug.(*fcPlugin).newMounterInternal(spec, types.UID("poduid"), fakeManager, fakeMounter, fakeExec)
if err == nil {
t.Errorf("Error failed to make a new Mounter is expected: %v", err)
}
if mounter != nil {
t.Errorf("A nil Mounter is expected: %v", err)
}
}
func TestPluginVolume(t *testing.T) {
lun := int32(0)
vol := &v1.Volume{
Name: "vol1",
VolumeSource: v1.VolumeSource{
FC: &v1.FCVolumeSource{
TargetWWNs: []string{"500a0981891b8dc5"},
FSType: "ext4",
Lun: &lun,
},
},
}
doTestPlugin(t, volume.NewSpecFromVolume(vol))
}
func TestPluginPersistentVolume(t *testing.T) {
lun := int32(0)
vol := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "vol1",
},
Spec: v1.PersistentVolumeSpec{
PersistentVolumeSource: v1.PersistentVolumeSource{
FC: &v1.FCVolumeSource{
TargetWWNs: []string{"500a0981891b8dc5"},
FSType: "ext4",
Lun: &lun,
},
},
},
}
doTestPlugin(t, volume.NewSpecFromPersistentVolume(vol, false))
}
func TestPluginVolumeWWIDs(t *testing.T) {
vol := &v1.Volume{
Name: "vol1",
VolumeSource: v1.VolumeSource{
FC: &v1.FCVolumeSource{
WWIDs: []string{"3600508b400105e210000900000490000"},
FSType: "ext4",
},
},
}
doTestPlugin(t, volume.NewSpecFromVolume(vol))
}
func TestPluginPersistentVolumeWWIDs(t *testing.T) {
vol := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "vol1",
},
Spec: v1.PersistentVolumeSpec{
PersistentVolumeSource: v1.PersistentVolumeSource{
FC: &v1.FCVolumeSource{
WWIDs: []string{"3600508b400105e21 000900000490000"},
FSType: "ext4",
},
},
},
}
doTestPlugin(t, volume.NewSpecFromPersistentVolume(vol, false))
}
func TestPluginVolumeNoDiskInfo(t *testing.T) {
vol := &v1.Volume{
Name: "vol1",
VolumeSource: v1.VolumeSource{
FC: &v1.FCVolumeSource{
FSType: "ext4",
},
},
}
doTestPluginNilMounter(t, volume.NewSpecFromVolume(vol))
}
func TestPluginPersistentVolumeNoDiskInfo(t *testing.T) {
vol := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "vol1",
},
Spec: v1.PersistentVolumeSpec{
PersistentVolumeSource: v1.PersistentVolumeSource{
FC: &v1.FCVolumeSource{
FSType: "ext4",
},
},
},
}
doTestPluginNilMounter(t, volume.NewSpecFromPersistentVolume(vol, false))
}
func TestPersistentClaimReadOnlyFlag(t *testing.T) {
tmpDir, err := utiltesting.MkTmpdir("fc_test")
if err != nil {
t.Fatalf("error creating temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
lun := int32(0)
pv := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "pvA",
},
Spec: v1.PersistentVolumeSpec{
PersistentVolumeSource: v1.PersistentVolumeSource{
FC: &v1.FCVolumeSource{
TargetWWNs: []string{"some_wwn"},
FSType: "ext4",
Lun: &lun,
},
},
ClaimRef: &v1.ObjectReference{
Name: "claimA",
},
},
}
claim := &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "claimA",
Namespace: "nsA",
},
Spec: v1.PersistentVolumeClaimSpec{
VolumeName: "pvA",
},
Status: v1.PersistentVolumeClaimStatus{
Phase: v1.ClaimBound,
},
}
client := fake.NewSimpleClientset(pv, claim)
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, client, nil))
plug, _ := plugMgr.FindPluginByName(fcPluginName)
// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
spec := volume.NewSpecFromPersistentVolume(pv, true)
pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
mounter, _ := plug.NewMounter(spec, pod, volume.VolumeOptions{})
if mounter == nil {
t.Fatalf("Got a nil Mounter")
}
if !mounter.GetAttributes().ReadOnly {
t.Errorf("Expected true for mounter.IsReadOnly")
}
}
func Test_getWwnsLun(t *testing.T) {
num := int32(0)
fc := &v1.FCVolumeSource{
TargetWWNs: []string{"500a0981891b8dc5"},
FSType: "ext4",
Lun: &num,
}
wwn, lun, _, err := getWwnsLunWwids(fc)
// if no wwn and lun, exit
if (len(wwn) == 0 && lun != "0") || err != nil {
t.Errorf("no fc disk found")
}
}
func Test_getWwids(t *testing.T) {
fc := &v1.FCVolumeSource{
FSType: "ext4",
WWIDs: []string{"3600508b400105e210000900000490000"},
}
_, _, wwid, err := getWwnsLunWwids(fc)
// if no wwn and lun, exit
if len(wwid) == 0 || err != nil {
t.Errorf("no fc disk found")
}
}
func Test_getWwnsLunWwidsError(t *testing.T) {
fc := &v1.FCVolumeSource{
FSType: "ext4",
}
wwn, lun, wwid, err := getWwnsLunWwids(fc)
// expected no wwn and lun and wwid
if (len(wwn) != 0 && lun != "" && len(wwid) != 0) || err == nil {
t.Errorf("unexpected fc disk found")
}
}
func Test_ConstructVolumeSpec(t *testing.T) {
if runtime.GOOS == "darwin" {
t.Skipf("Test_ConstructVolumeSpec is not supported on GOOS=%s", runtime.GOOS)
}
fm := &mount.FakeMounter{
MountPoints: []mount.MountPoint{
{Device: "/dev/sdb", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~fc/fc-in-pod1"},
{Device: "/dev/sdb", Path: "/var/lib/kubelet/plugins/kubernetes.io/fc/50060e801049cfd1-lun-0"},
{Device: "/dev/sdc", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~fc/fc-in-pod2"},
{Device: "/dev/sdc", Path: "/var/lib/kubelet/plugins/kubernetes.io/fc/volumeDevices/3600508b400105e210000900000490000"},
},
}
mountPaths := []string{
"/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~fc/fc-in-pod1",
"/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~fc/fc-in-pod2",
}
for _, path := range mountPaths {
refs, err := mount.GetMountRefs(fm, path)
if err != nil {
t.Errorf("couldn't get mountrefs. err: %v", err)
}
var globalPDPath string
for _, ref := range refs {
if strings.Contains(ref, "kubernetes.io/fc") {
globalPDPath = ref
break
}
}
if len(globalPDPath) == 0 {
t.Errorf("couldn't fetch mountrefs")
}
arr := strings.Split(globalPDPath, "/")
if len(arr) < 1 {
t.Errorf("failed to retrieve volume plugin information from globalPDPath: %v", globalPDPath)
}
volumeInfo := arr[len(arr)-1]
if strings.Contains(volumeInfo, "-lun-") {
wwnLun := strings.Split(volumeInfo, "-lun-")
if len(wwnLun) < 2 {
t.Errorf("failed to retrieve TargetWWN and Lun. volumeInfo is invalid: %v", volumeInfo)
}
lun, _ := strconv.Atoi(wwnLun[1])
lun32 := int32(lun)
if wwnLun[0] != "50060e801049cfd1" || lun32 != 0 {
t.Errorf("failed to retrieve TargetWWN and Lun")
}
} else {
if volumeInfo != "3600508b400105e210000900000490000" {
t.Errorf("failed to retrieve WWIDs")
}
}
}
}
func Test_ConstructVolumeSpecNoRefs(t *testing.T) {
fm := &mount.FakeMounter{
MountPoints: []mount.MountPoint{
{Device: "/dev/sdd", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~fc/fc-in-pod1"},
},
}
mountPaths := []string{
"/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~fc/fc-in-pod1",
}
for _, path := range mountPaths {
refs, _ := mount.GetMountRefs(fm, path)
var globalPDPath string
for _, ref := range refs {
if strings.Contains(ref, "kubernetes.io/fc") {
globalPDPath = ref
break
}
}
if len(globalPDPath) != 0 {
t.Errorf("invalid globalPDPath")
}
}
}

409
vendor/k8s.io/kubernetes/pkg/volume/fc/fc_util.go generated vendored Normal file
View File

@@ -0,0 +1,409 @@
/*
Copyright 2015 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"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"github.com/golang/glog"
"k8s.io/api/core/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/volume"
volumeutil "k8s.io/kubernetes/pkg/volume/util"
"k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
)
type ioHandler interface {
ReadDir(dirname string) ([]os.FileInfo, error)
Lstat(name string) (os.FileInfo, error)
EvalSymlinks(path string) (string, error)
WriteFile(filename string, data []byte, perm os.FileMode) error
}
type osIOHandler struct{}
const (
byPath = "/dev/disk/by-path/"
byID = "/dev/disk/by-id/"
)
func (handler *osIOHandler) ReadDir(dirname string) ([]os.FileInfo, error) {
return ioutil.ReadDir(dirname)
}
func (handler *osIOHandler) Lstat(name string) (os.FileInfo, error) {
return os.Lstat(name)
}
func (handler *osIOHandler) EvalSymlinks(path string) (string, error) {
return filepath.EvalSymlinks(path)
}
func (handler *osIOHandler) WriteFile(filename string, data []byte, perm os.FileMode) error {
return ioutil.WriteFile(filename, data, perm)
}
// given a wwn and lun, find the device and associated devicemapper parent
func findDisk(wwn, lun string, io ioHandler, deviceUtil volumeutil.DeviceUtil) (string, string) {
fc_path := "-fc-0x" + wwn + "-lun-" + lun
dev_path := byPath
if dirs, err := io.ReadDir(dev_path); err == nil {
for _, f := range dirs {
name := f.Name()
if strings.Contains(name, fc_path) {
if disk, err1 := io.EvalSymlinks(dev_path + name); err1 == nil {
dm := deviceUtil.FindMultipathDeviceForDevice(disk)
glog.Infof("fc: find disk: %v, dm: %v", disk, dm)
return disk, dm
}
}
}
}
return "", ""
}
// given a wwid, find the device and associated devicemapper parent
func findDiskWWIDs(wwid string, io ioHandler, deviceUtil volumeutil.DeviceUtil) (string, string) {
// Example wwid format:
// 3600508b400105e210000900000490000
// <VENDOR NAME> <IDENTIFIER NUMBER>
// Example of symlink under by-id:
// /dev/by-id/scsi-3600508b400105e210000900000490000
// /dev/by-id/scsi-<VENDOR NAME>_<IDENTIFIER NUMBER>
// The wwid could contain white space and it will be replaced
// underscore when wwid is exposed under /dev/by-id.
fc_path := "scsi-" + wwid
dev_id := byID
if dirs, err := io.ReadDir(dev_id); err == nil {
for _, f := range dirs {
name := f.Name()
if name == fc_path {
disk, err := io.EvalSymlinks(dev_id + name)
if err != nil {
glog.V(2).Infof("fc: failed to find a corresponding disk from symlink[%s], error %v", dev_id+name, err)
return "", ""
}
dm := deviceUtil.FindMultipathDeviceForDevice(disk)
glog.Infof("fc: find disk: %v, dm: %v", disk, dm)
return disk, dm
}
}
}
glog.V(2).Infof("fc: failed to find a disk [%s]", dev_id+fc_path)
return "", ""
}
// Removes a scsi device based upon /dev/sdX name
func removeFromScsiSubsystem(deviceName string, io ioHandler) {
fileName := "/sys/block/" + deviceName + "/device/delete"
glog.V(4).Infof("fc: remove device from scsi-subsystem: path: %s", fileName)
data := []byte("1")
io.WriteFile(fileName, data, 0666)
}
// rescan scsi bus
func scsiHostRescan(io ioHandler) {
scsi_path := "/sys/class/scsi_host/"
if dirs, err := io.ReadDir(scsi_path); err == nil {
for _, f := range dirs {
name := scsi_path + f.Name() + "/scan"
data := []byte("- - -")
io.WriteFile(name, data, 0666)
}
}
}
// make a directory like /var/lib/kubelet/plugins/kubernetes.io/fc/target-lun-0
func makePDNameInternal(host volume.VolumeHost, wwns []string, lun string, wwids []string) string {
if len(wwns) != 0 {
return path.Join(host.GetPluginDir(fcPluginName), wwns[0]+"-lun-"+lun)
} else {
return path.Join(host.GetPluginDir(fcPluginName), wwids[0])
}
}
// make a directory like /var/lib/kubelet/plugins/kubernetes.io/fc/volumeDevices/target-lun-0
func makeVDPDNameInternal(host volume.VolumeHost, wwns []string, lun string, wwids []string) string {
if len(wwns) != 0 {
return path.Join(host.GetVolumeDevicePluginDir(fcPluginName), wwns[0]+"-lun-"+lun)
} else {
return path.Join(host.GetVolumeDevicePluginDir(fcPluginName), wwids[0])
}
}
type FCUtil struct{}
func (util *FCUtil) MakeGlobalPDName(fc fcDisk) string {
return makePDNameInternal(fc.plugin.host, fc.wwns, fc.lun, fc.wwids)
}
// Global volume device plugin dir
func (util *FCUtil) MakeGlobalVDPDName(fc fcDisk) string {
return makeVDPDNameInternal(fc.plugin.host, fc.wwns, fc.lun, fc.wwids)
}
func searchDisk(b fcDiskMounter) (string, error) {
var diskIds []string
var disk string
var dm string
io := b.io
wwids := b.wwids
wwns := b.wwns
lun := b.lun
if len(wwns) != 0 {
diskIds = wwns
} else {
diskIds = wwids
}
rescaned := false
// two-phase search:
// first phase, search existing device path, if a multipath dm is found, exit loop
// otherwise, in second phase, rescan scsi bus and search again, return with any findings
for true {
for _, diskId := range diskIds {
if len(wwns) != 0 {
disk, dm = findDisk(diskId, lun, io, b.deviceUtil)
} else {
disk, dm = findDiskWWIDs(diskId, io, b.deviceUtil)
}
// if multipath device is found, break
if dm != "" {
break
}
}
// if a dm is found, exit loop
if rescaned || dm != "" {
break
}
// rescan and search again
// rescan scsi bus
scsiHostRescan(io)
rescaned = true
}
// if no disk matches input wwn and lun, exit
if disk == "" && dm == "" {
return "", fmt.Errorf("no fc disk found")
}
// if multipath devicemapper device is found, use it; otherwise use raw disk
if dm != "" {
return dm, nil
}
return disk, nil
}
func (util *FCUtil) AttachDisk(b fcDiskMounter) (string, error) {
devicePath, err := searchDisk(b)
if err != nil {
return "", err
}
// TODO: remove feature gate check after no longer needed
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
// If the volumeMode is 'Block', plugin don't have to format the volume.
// The globalPDPath will be created by operationexecutor. Just return devicePath here.
glog.V(5).Infof("fc: AttachDisk volumeMode: %s, devicePath: %s", b.volumeMode, devicePath)
if b.volumeMode == v1.PersistentVolumeBlock {
return devicePath, nil
}
}
// mount it
globalPDPath := util.MakeGlobalPDName(*b.fcDisk)
if err := os.MkdirAll(globalPDPath, 0750); err != nil {
return devicePath, fmt.Errorf("fc: failed to mkdir %s, error", globalPDPath)
}
noMnt, err := b.mounter.IsLikelyNotMountPoint(globalPDPath)
if err != nil {
return devicePath, fmt.Errorf("Heuristic determination of mount point failed:%v", err)
}
if !noMnt {
glog.Infof("fc: %s already mounted", globalPDPath)
return devicePath, nil
}
err = b.mounter.FormatAndMount(devicePath, globalPDPath, b.fsType, nil)
if err != nil {
return devicePath, fmt.Errorf("fc: failed to mount fc volume %s [%s] to %s, error %v", devicePath, b.fsType, globalPDPath, err)
}
return devicePath, err
}
// DetachDisk removes scsi device file such as /dev/sdX from the node.
func (util *FCUtil) DetachDisk(c fcDiskUnmounter, devicePath string) error {
var devices []string
// devicePath might be like /dev/mapper/mpathX. Find destination.
dstPath, err := c.io.EvalSymlinks(devicePath)
if err != nil {
return err
}
// Find slave
if strings.HasPrefix(dstPath, "/dev/dm-") {
devices = c.deviceUtil.FindSlaveDevicesOnMultipath(dstPath)
} else {
// Add single devicepath to devices
devices = append(devices, dstPath)
}
glog.V(4).Infof("fc: DetachDisk devicePath: %v, dstPath: %v, devices: %v", devicePath, dstPath, devices)
var lastErr error
for _, device := range devices {
err := util.detachFCDisk(c.io, device)
if err != nil {
glog.Errorf("fc: detachFCDisk failed. device: %v err: %v", device, err)
lastErr = fmt.Errorf("fc: detachFCDisk failed. device: %v err: %v", device, err)
}
}
if lastErr != nil {
glog.Errorf("fc: last error occurred during detach disk:\n%v", lastErr)
return lastErr
}
return nil
}
// detachFCDisk removes scsi device file such as /dev/sdX from the node.
func (util *FCUtil) detachFCDisk(io ioHandler, devicePath string) error {
// Remove scsi device from the node.
if !strings.HasPrefix(devicePath, "/dev/") {
return fmt.Errorf("fc detach disk: invalid device name: %s", devicePath)
}
arr := strings.Split(devicePath, "/")
dev := arr[len(arr)-1]
removeFromScsiSubsystem(dev, io)
return nil
}
// DetachBlockFCDisk detaches a volume from kubelet node, removes scsi device file
// such as /dev/sdX from the node, and then removes loopback for the scsi device.
func (util *FCUtil) DetachBlockFCDisk(c fcDiskUnmapper, mapPath, devicePath string) error {
// Check if devicePath is valid
if len(devicePath) != 0 {
if pathExists, pathErr := checkPathExists(devicePath); !pathExists || pathErr != nil {
return pathErr
}
} else {
// TODO: FC plugin can't obtain the devicePath from kubelet because devicePath
// in volume object isn't updated when volume is attached to kubelet node.
glog.Infof("fc: devicePath is empty. Try to retrieve FC configuration from global map path: %v", mapPath)
}
// Check if global map path is valid
// global map path examples:
// wwn+lun: plugins/kubernetes.io/fc/volumeDevices/50060e801049cfd1-lun-0/
// wwid: plugins/kubernetes.io/fc/volumeDevices/3600508b400105e210000900000490000/
if pathExists, pathErr := checkPathExists(mapPath); !pathExists || pathErr != nil {
return pathErr
}
// Retrieve volume plugin dependent path like '50060e801049cfd1-lun-0' from global map path
arr := strings.Split(mapPath, "/")
if len(arr) < 1 {
return fmt.Errorf("Fail to retrieve volume plugin information from global map path: %v", mapPath)
}
volumeInfo := arr[len(arr)-1]
// Search symbolick link which matches volumeInfo under /dev/disk/by-path or /dev/disk/by-id
// then find destination device path from the link
searchPath := byID
if strings.Contains(volumeInfo, "-lun-") {
searchPath = byPath
}
fis, err := ioutil.ReadDir(searchPath)
if err != nil {
return err
}
for _, fi := range fis {
if strings.Contains(fi.Name(), volumeInfo) {
devicePath = path.Join(searchPath, fi.Name())
glog.V(5).Infof("fc: updated devicePath: %s", devicePath)
break
}
}
if len(devicePath) == 0 {
return fmt.Errorf("fc: failed to find corresponding device from searchPath: %v", searchPath)
}
dstPath, err := c.io.EvalSymlinks(devicePath)
if err != nil {
return err
}
glog.V(4).Infof("fc: find destination device path from symlink: %v", dstPath)
// Get loopback device which takes fd lock for device beofore detaching a volume from node.
// TODO: This is a workaround for issue #54108
// Currently local attach plugins such as FC, iSCSI, RBD can't obtain devicePath during
// GenerateUnmapDeviceFunc() in operation_generator. As a result, these plugins fail to get
// and remove loopback device then it will be remained on kubelet node. To avoid the problem,
// local attach plugins needs to remove loopback device during TearDownDevice().
var devices []string
blkUtil := volumepathhandler.NewBlockVolumePathHandler()
dm := c.deviceUtil.FindMultipathDeviceForDevice(dstPath)
if len(dm) != 0 {
dstPath = dm
}
loop, err := volumepathhandler.BlockVolumePathHandler.GetLoopDevice(blkUtil, dstPath)
if err != nil {
if err.Error() != volumepathhandler.ErrDeviceNotFound {
return fmt.Errorf("fc: failed to get loopback for destination path: %v, err: %v", dstPath, err)
}
glog.Warning("fc: loopback for destination path: %s not found", dstPath)
}
// Detach volume from kubelet node
if len(dm) != 0 {
// Find all devices which are managed by multipath
devices = c.deviceUtil.FindSlaveDevicesOnMultipath(dm)
} else {
// Add single device path to devices
devices = append(devices, dstPath)
}
var lastErr error
for _, device := range devices {
err = util.detachFCDisk(c.io, device)
if err != nil {
glog.Errorf("fc: detachFCDisk failed. device: %v err: %v", device, err)
lastErr = fmt.Errorf("fc: detachFCDisk failed. device: %v err: %v", device, err)
}
}
if lastErr != nil {
glog.Errorf("fc: last error occurred during detach disk:\n%v", lastErr)
return lastErr
}
if len(loop) != 0 {
// The volume was successfully detached from node. We can safely remove the loopback.
err = volumepathhandler.BlockVolumePathHandler.RemoveLoopDevice(blkUtil, loop)
if err != nil {
return fmt.Errorf("fc: failed to remove loopback :%v, err: %v", loop, err)
}
}
return nil
}
func checkPathExists(path string) (bool, error) {
if pathExists, pathErr := volumeutil.PathExists(path); pathErr != nil {
return pathExists, fmt.Errorf("Error checking if path exists: %v", pathErr)
} else if !pathExists {
glog.Warningf("Warning: Unmap skipped because path does not exist: %v", path)
return pathExists, nil
}
return true, nil
}

118
vendor/k8s.io/kubernetes/pkg/volume/fc/fc_util_test.go generated vendored Normal file
View File

@@ -0,0 +1,118 @@
/*
Copyright 2015 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 (
"os"
"testing"
"time"
"k8s.io/kubernetes/pkg/volume/util"
)
type fakeFileInfo struct {
name string
}
func (fi *fakeFileInfo) Name() string {
return fi.name
}
func (fi *fakeFileInfo) Size() int64 {
return 0
}
func (fi *fakeFileInfo) Mode() os.FileMode {
return 777
}
func (fi *fakeFileInfo) ModTime() time.Time {
return time.Now()
}
func (fi *fakeFileInfo) IsDir() bool {
return false
}
func (fi *fakeFileInfo) Sys() interface{} {
return nil
}
type fakeIOHandler struct{}
func (handler *fakeIOHandler) ReadDir(dirname string) ([]os.FileInfo, error) {
switch dirname {
case "/dev/disk/by-path/":
f := &fakeFileInfo{
name: "pci-0000:41:00.0-fc-0x500a0981891b8dc5-lun-0",
}
return []os.FileInfo{f}, nil
case "/sys/block/":
f := &fakeFileInfo{
name: "dm-1",
}
return []os.FileInfo{f}, nil
case "/dev/disk/by-id/":
f := &fakeFileInfo{
name: "scsi-3600508b400105e210000900000490000",
}
return []os.FileInfo{f}, nil
}
return nil, nil
}
func (handler *fakeIOHandler) Lstat(name string) (os.FileInfo, error) {
return nil, nil
}
func (handler *fakeIOHandler) EvalSymlinks(path string) (string, error) {
return "/dev/sda", nil
}
func (handler *fakeIOHandler) WriteFile(filename string, data []byte, perm os.FileMode) error {
return nil
}
func TestSearchDisk(t *testing.T) {
fakeMounter := fcDiskMounter{
fcDisk: &fcDisk{
wwns: []string{"500a0981891b8dc5"},
lun: "0",
io: &fakeIOHandler{},
},
deviceUtil: util.NewDeviceHandler(util.NewIOHandler()),
}
devicePath, error := searchDisk(fakeMounter)
// if no disk matches input wwn and lun, exit
if devicePath == "" || error != nil {
t.Errorf("no fc disk found")
}
}
func TestSearchDiskWWID(t *testing.T) {
fakeMounter := fcDiskMounter{
fcDisk: &fcDisk{
wwids: []string{"3600508b400105e210000900000490000"},
io: &fakeIOHandler{},
},
deviceUtil: util.NewDeviceHandler(util.NewIOHandler()),
}
devicePath, error := searchDisk(fakeMounter)
// if no disk matches input wwid, exit
if devicePath == "" || error != nil {
t.Errorf("no fc disk found")
}
}