mirror of https://github.com/k3s-io/k3s
Fix reconstruction of FC volumes
It should reconstruct all WWNs or WWIDs instead of just the first one. On-disk directory name format had to be changed to contain all WWNs/WWIDs.pull/564/head
parent
40c91a0951
commit
662b683de4
|
@ -19,6 +19,7 @@ package fc
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -257,40 +258,20 @@ func (plugin *fcPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volu
|
||||||
if len(globalPDPath) == 0 {
|
if len(globalPDPath) == 0 {
|
||||||
return nil, fmt.Errorf("couldn't fetch globalPDPath. failed to obtain volume spec")
|
return nil, fmt.Errorf("couldn't fetch globalPDPath. failed to obtain volume spec")
|
||||||
}
|
}
|
||||||
arr := strings.Split(globalPDPath, "/")
|
|
||||||
if len(arr) < 1 {
|
wwns, lun, wwids, err := parsePDName(globalPDPath)
|
||||||
return nil, fmt.Errorf("failed to retrieve volume plugin information from globalPDPath: %v", globalPDPath)
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to retrieve volume plugin information from globalPDPath: %s", err)
|
||||||
}
|
}
|
||||||
volumeInfo := arr[len(arr)-1]
|
|
||||||
// Create volume from wwn+lun or wwid
|
// Create volume from wwn+lun or wwid
|
||||||
var fcVolume *v1.Volume
|
fcVolume := &v1.Volume{
|
||||||
if strings.Contains(volumeInfo, "-lun-") {
|
Name: volumeName,
|
||||||
wwnLun := strings.Split(volumeInfo, "-lun-")
|
VolumeSource: v1.VolumeSource{
|
||||||
if len(wwnLun) < 2 {
|
FC: &v1.FCVolumeSource{WWIDs: wwids, Lun: &lun, TargetWWNs: wwns},
|
||||||
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},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
klog.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}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
klog.V(5).Infof("ConstructVolumeSpec: WWIDs: %v", fcVolume.VolumeSource.FC.WWIDs)
|
|
||||||
}
|
}
|
||||||
|
klog.V(5).Infof("ConstructVolumeSpec: TargetWWNs: %v, Lun: %v, WWIDs: %v",
|
||||||
|
fcVolume.VolumeSource.FC.TargetWWNs, *fcVolume.VolumeSource.FC.Lun, fcVolume.VolumeSource.FC.WWIDs)
|
||||||
return volume.NewSpecFromVolume(fcVolume), nil
|
return volume.NewSpecFromVolume(fcVolume), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,36 +291,23 @@ func (plugin *fcPlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName, m
|
||||||
}
|
}
|
||||||
klog.V(5).Infof("globalMapPathUUID: %v, err: %v", globalMapPathUUID, err)
|
klog.V(5).Infof("globalMapPathUUID: %v, err: %v", globalMapPathUUID, err)
|
||||||
|
|
||||||
// Retrieve volumePluginDependentPath from globalMapPathUUID
|
// Retrieve globalPDPath from globalMapPathUUID
|
||||||
// globalMapPathUUID examples:
|
// globalMapPathUUID examples:
|
||||||
// wwn+lun: plugins/kubernetes.io/fc/volumeDevices/50060e801049cfd1-lun-0/{pod uuid}
|
// wwn+lun: plugins/kubernetes.io/fc/volumeDevices/50060e801049cfd1-lun-0/{pod uuid}
|
||||||
// wwid: plugins/kubernetes.io/fc/volumeDevices/3600508b400105e210000900000490000/{pod uuid}
|
// wwid: plugins/kubernetes.io/fc/volumeDevices/3600508b400105e210000900000490000/{pod uuid}
|
||||||
arr := strings.Split(globalMapPathUUID, "/")
|
globalPDPath := filepath.Dir(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
|
// Create volume from wwn+lun or wwid
|
||||||
var fcPV *v1.PersistentVolume
|
wwns, lun, wwids, err := parsePDName(globalPDPath)
|
||||||
if strings.Contains(volumeInfo, "-lun-") {
|
if err != nil {
|
||||||
wwnLun := strings.Split(volumeInfo, "-lun-")
|
return nil, fmt.Errorf("failed to retrieve volume plugin information from globalPDPath: %s", err)
|
||||||
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})
|
|
||||||
klog.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}})
|
|
||||||
klog.V(5).Infof("ConstructBlockVolumeSpec: WWIDs: %v", fcPV.Spec.PersistentVolumeSource.FC.WWIDs)
|
|
||||||
}
|
}
|
||||||
|
fcPV := createPersistentVolumeFromFCVolumeSource(volumeName,
|
||||||
|
v1.FCVolumeSource{TargetWWNs: wwns, Lun: &lun, WWIDs: wwids})
|
||||||
|
klog.V(5).Infof("ConstructBlockVolumeSpec: TargetWWNs: %v, Lun: %v, WWIDs: %v",
|
||||||
|
fcPV.Spec.PersistentVolumeSource.FC.TargetWWNs,
|
||||||
|
*fcPV.Spec.PersistentVolumeSource.FC.Lun,
|
||||||
|
fcPV.Spec.PersistentVolumeSource.FC.WWIDs)
|
||||||
|
|
||||||
return volume.NewSpecFromPersistentVolume(fcPV, false), nil
|
return volume.NewSpecFromPersistentVolume(fcPV, false), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
|
@ -131,20 +132,47 @@ func scsiHostRescan(io ioHandler) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a directory like /var/lib/kubelet/plugins/kubernetes.io/fc/target-lun-0
|
// make a directory like /var/lib/kubelet/plugins/kubernetes.io/fc/target1-target2-lun-0
|
||||||
func makePDNameInternal(host volume.VolumeHost, wwns []string, lun string, wwids []string) string {
|
func makePDNameInternal(host volume.VolumeHost, wwns []string, lun string, wwids []string) string {
|
||||||
if len(wwns) != 0 {
|
if len(wwns) != 0 {
|
||||||
return path.Join(host.GetPluginDir(fcPluginName), wwns[0]+"-lun-"+lun)
|
w := strings.Join(wwns, "-")
|
||||||
|
return path.Join(host.GetPluginDir(fcPluginName), w+"-lun-"+lun)
|
||||||
}
|
}
|
||||||
return path.Join(host.GetPluginDir(fcPluginName), wwids[0])
|
return path.Join(host.GetPluginDir(fcPluginName), strings.Join(wwids, "-"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a directory like /var/lib/kubelet/plugins/kubernetes.io/fc/volumeDevices/target-lun-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 {
|
func makeVDPDNameInternal(host volume.VolumeHost, wwns []string, lun string, wwids []string) string {
|
||||||
if len(wwns) != 0 {
|
if len(wwns) != 0 {
|
||||||
return path.Join(host.GetVolumeDevicePluginDir(fcPluginName), wwns[0]+"-lun-"+lun)
|
w := strings.Join(wwns, "-")
|
||||||
|
return path.Join(host.GetVolumeDevicePluginDir(fcPluginName), w+"-lun-"+lun)
|
||||||
}
|
}
|
||||||
return path.Join(host.GetVolumeDevicePluginDir(fcPluginName), wwids[0])
|
return path.Join(host.GetVolumeDevicePluginDir(fcPluginName), strings.Join(wwids, "-"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsePDName(path string) (wwns []string, lun int32, wwids []string, err error) {
|
||||||
|
// parse directory name created by makePDNameInternal or makeVDPDNameInternal
|
||||||
|
dirname := filepath.Base(path)
|
||||||
|
components := strings.Split(dirname, "-")
|
||||||
|
l := len(components)
|
||||||
|
if l == 1 {
|
||||||
|
// No '-', it must be single WWID
|
||||||
|
return nil, 0, components, nil
|
||||||
|
}
|
||||||
|
if components[l-2] == "lun" {
|
||||||
|
// it has -lun-, it's list of WWNs + lun number as the last component
|
||||||
|
if l == 2 {
|
||||||
|
return nil, 0, nil, fmt.Errorf("no wwn in: %s", dirname)
|
||||||
|
}
|
||||||
|
lun, err := strconv.Atoi(components[l-1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return components[:l-2], int32(lun), nil, nil
|
||||||
|
}
|
||||||
|
// no -lun-, it's just list of WWIDs
|
||||||
|
return nil, 0, components, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type fcUtil struct{}
|
type fcUtil struct{}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package fc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -116,3 +117,68 @@ func TestSearchDiskWWID(t *testing.T) {
|
||||||
t.Errorf("no fc disk found")
|
t.Errorf("no fc disk found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParsePDName(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
path string
|
||||||
|
wwns []string
|
||||||
|
lun int32
|
||||||
|
wwids []string
|
||||||
|
expectError bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "single WWID",
|
||||||
|
path: "/var/lib/kubelet/plugins/kubernetes.io/fc/60050763008084e6e0000000000001ae",
|
||||||
|
wwids: []string{"60050763008084e6e0000000000001ae"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple WWID",
|
||||||
|
path: "/var/lib/kubelet/plugins/kubernetes.io/fc/60050763008084e6e0000000000001ae-60050763008084e6e0000000000001af",
|
||||||
|
wwids: []string{"60050763008084e6e0000000000001ae", "60050763008084e6e0000000000001af"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single WWN",
|
||||||
|
path: "/var/lib/kubelet/plugins/kubernetes.io/fc/50050768030539b6-lun-0",
|
||||||
|
wwns: []string{"50050768030539b6"},
|
||||||
|
lun: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple WWNs",
|
||||||
|
path: "/var/lib/kubelet/plugins/kubernetes.io/fc/50050768030539b6-50050768030539b7-lun-0",
|
||||||
|
wwns: []string{"50050768030539b6", "50050768030539b7"},
|
||||||
|
lun: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no WWNs",
|
||||||
|
path: "/var/lib/kubelet/plugins/kubernetes.io/fc/lun-0",
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid lun",
|
||||||
|
path: "/var/lib/kubelet/plugins/kubernetes.io/fc/50050768030539b6-lun-x",
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
wwns, lun, wwids, err := parsePDName(test.path)
|
||||||
|
if test.expectError && err == nil {
|
||||||
|
t.Errorf("expected error but got none")
|
||||||
|
}
|
||||||
|
if !test.expectError && err != nil {
|
||||||
|
t.Errorf("got unexpected error: %s", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(wwns, test.wwns) {
|
||||||
|
t.Errorf("expected WWNs %+v, got %+v", test.wwns, wwns)
|
||||||
|
}
|
||||||
|
if lun != test.lun {
|
||||||
|
t.Errorf("expected lun %d, got %d", test.lun, lun)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(wwids, test.wwids) {
|
||||||
|
t.Errorf("expected WWIDs %+v, got %+v", test.wwids, wwids)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue