Skip to content

Commit b0ce999

Browse files
committed
use raw format in lsblk in order to support a wider range of versions
1 parent 75f4b8e commit b0ce999

File tree

2 files changed

+87
-34
lines changed

2 files changed

+87
-34
lines changed

iscsi/iscsi.go

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@ type iscsiSession struct {
3939
Name string
4040
}
4141

42-
type deviceInfo struct {
43-
BlockDevices []Device
44-
}
42+
type deviceInfo []Device
4543

4644
// Device contains informations about a device
4745
type Device struct {
@@ -483,7 +481,7 @@ func GetSCSIDevices(devicePaths []string, strict bool) ([]Device, error) {
483481
return nil, err
484482
}
485483

486-
return deviceInfo.BlockDevices, nil
484+
return deviceInfo, nil
487485
}
488486

489487
// GetISCSIDevices get iSCSI devices from device paths
@@ -505,8 +503,8 @@ func GetISCSIDevices(devicePaths []string, strict bool) (devices []Device, err e
505503
}
506504

507505
// lsblk execute the lsblk commands
508-
func lsblk(devicePaths []string, strict bool) (*deviceInfo, error) {
509-
flags := []string{"-J", "-o", "NAME,HCTL,TYPE,TRAN,SIZE"}
506+
func lsblk(devicePaths []string, strict bool) (deviceInfo, error) {
507+
flags := []string{"-rn", "-o", "NAME,KNAME,PKNAME,HCTL,TYPE,TRAN,SIZE"}
510508
command := execCommand("lsblk", append(flags, devicePaths...)...)
511509
debug.Println(command.String())
512510
out, err := command.Output()
@@ -522,12 +520,54 @@ func lsblk(devicePaths []string, strict bool) (*deviceInfo, error) {
522520
}
523521
}
524522

523+
var devices []*Device
524+
devicesMap := make(map[string]*Device)
525+
pkNames := []string{}
526+
527+
// Parse devices
528+
lines := strings.Split(strings.Trim(string(out), "\n"), "\n")
529+
for _, line := range lines {
530+
columns := strings.Split(line, " ")
531+
if len(columns) < 5 {
532+
return nil, fmt.Errorf("invalid output from lsblk: %s", line)
533+
}
534+
device := &Device{
535+
Name: columns[0],
536+
Hctl: columns[3],
537+
Type: columns[4],
538+
Transport: columns[5],
539+
Size: columns[6],
540+
}
541+
devices = append(devices, device)
542+
pkNames = append(pkNames, columns[2])
543+
devicesMap[columns[1]] = device
544+
}
545+
546+
// Reconstruct devices tree
547+
for i, pkName := range pkNames {
548+
if pkName == "" {
549+
continue
550+
}
551+
device := devices[i]
552+
parent, ok := devicesMap[pkName]
553+
if !ok {
554+
return nil, fmt.Errorf("invalid output from lsblk: parent device %q not found", pkName)
555+
}
556+
if parent.Children == nil {
557+
parent.Children = []Device{}
558+
}
559+
parent.Children = append(devicesMap[pkName].Children, *device)
560+
}
561+
562+
// Filter devices to keep only the roots of the tree
525563
var deviceInfo deviceInfo
526-
if jsonErr := json.Unmarshal(out, &deviceInfo); jsonErr != nil {
527-
return nil, jsonErr
564+
for i, device := range devices {
565+
if pkNames[i] == "" {
566+
deviceInfo = append(deviceInfo, *device)
567+
}
528568
}
529569

530-
return &deviceInfo, nil
570+
return deviceInfo, nil
531571
}
532572

533573
// writeInSCSIDeviceFile write into special devices files to change devices state

iscsi/iscsi_test.go

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,20 @@ func makeFakeExecWithTimeout(withTimeout bool, output []byte, err error) func(st
127127
}
128128
}
129129

130+
func marshalDeviceInfo(d *deviceInfo) string {
131+
var output string
132+
pkNames := map[string]string{}
133+
for _, device := range *d {
134+
for _, child := range device.Children {
135+
pkNames[child.Name] = device.Name
136+
}
137+
}
138+
for _, device := range *d {
139+
output += fmt.Sprintf("%s %s %s %s %s %s %s\n", device.Name, device.Name, pkNames[device.Name], device.Hctl, device.Type, device.Transport, device.Size)
140+
}
141+
return output
142+
}
143+
130144
func TestExecCommandHelper(t *testing.T) {
131145
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
132146
return
@@ -579,16 +593,15 @@ func Test_getMultipathDevice(t *testing.T) {
579593
}
580594

581595
func Test_lsblk(t *testing.T) {
582-
sda := Device{Name: "sda", Children: []Device{{}}}
583-
584-
sdaOutput, err := json.Marshal(deviceInfo{BlockDevices: []Device{sda}})
585-
assert.New(t).Nil(err, "could not setup test")
596+
sda1 := Device{Name: "sda1"}
597+
sda := Device{Name: "sda", Children: []Device{sda1}}
598+
sdaOutput := marshalDeviceInfo(&deviceInfo{sda, sda1})
586599

587600
tests := map[string]struct {
588601
devicePaths []string
589602
strict bool
590603
mockedStdout string
591-
mockedDevices []Device
604+
mockedDevices deviceInfo
592605
mockedExitStatus int
593606
wantErr bool
594607
}{
@@ -603,7 +616,7 @@ func Test_lsblk(t *testing.T) {
603616
mockedExitStatus: 32,
604617
wantErr: true,
605618
},
606-
"InvalidJson": {
619+
"InvalidOutput": {
607620
mockedStdout: "{",
608621
mockedExitStatus: 0,
609622
wantErr: true,
@@ -636,7 +649,7 @@ func Test_lsblk(t *testing.T) {
636649
assert.NotNil(err)
637650
} else {
638651
assert.NotNil(deviceInfo)
639-
assert.Equal(tt.mockedDevices, deviceInfo.BlockDevices)
652+
assert.Equal(tt.mockedDevices, deviceInfo)
640653
assert.Nil(err)
641654
}
642655
})
@@ -654,17 +667,17 @@ func TestConnectorPersistance(t *testing.T) {
654667
PasswordIn: "fake password in",
655668
}
656669
childDevice := Device{
657-
Name: "child name",
658-
Hctl: "child hctl",
659-
Type: "child type",
660-
Transport: "child transport",
670+
Name: "child-name",
671+
Hctl: "child-hctl",
672+
Type: "child-type",
673+
Transport: "child-transport",
661674
}
662675
device := Device{
663-
Name: "device name",
664-
Hctl: "device hctl",
676+
Name: "device-name",
677+
Hctl: "device-hctl",
665678
Children: []Device{childDevice},
666-
Type: "device type",
667-
Transport: "device transport",
679+
Type: "device-type",
680+
Transport: "device-transport",
668681
}
669682
c := Connector{
670683
VolumeName: "fake volume name",
@@ -687,32 +700,32 @@ func TestConnectorPersistance(t *testing.T) {
687700
devicesByPath[device.GetPath()] = &device
688701

689702
defer gostub.Stub(&execCommand, func(name string, arg ...string) *exec.Cmd {
690-
blockDevices := []Device{}
703+
blockDevices := deviceInfo{}
691704
for _, path := range arg[3:] {
692705
blockDevices = append(blockDevices, *devicesByPath[path])
693706
}
694707

695-
out, err := json.Marshal(deviceInfo{BlockDevices: blockDevices})
696-
assert.Nil(err, "could not setup test")
708+
out := marshalDeviceInfo(&blockDevices)
697709
return makeFakeExecCommand(0, string(out))(name, arg...)
698710
}).Reset()
699711

700712
defer gostub.Stub(&execCommand, func(cmd string, args ...string) *exec.Cmd {
701-
mockedDevice := device
702-
if args[3] == "/dev/child name" {
703-
mockedDevice = childDevice
713+
devInfo := &deviceInfo{device, childDevice}
714+
if args[3] == "/dev/child-name" {
715+
devInfo = &deviceInfo{childDevice}
704716
}
705717

706-
mockedOutput, err := json.Marshal(deviceInfo{BlockDevices: []Device{mockedDevice}})
707-
assert.Nil(err, "could not setup test")
708-
718+
mockedOutput := marshalDeviceInfo(devInfo)
709719
return makeFakeExecCommand(0, string(mockedOutput))(cmd, args...)
710720
}).Reset()
711721

712722
c.Persist("/tmp/connector.json")
713723
c2, err := GetConnectorFromFile("/tmp/connector.json")
714724
assert.Nil(err)
715-
assert.Equal(c, *c2)
725+
assert.NotNil(c2)
726+
if c2 != nil {
727+
assert.Equal(c, *c2)
728+
}
716729

717730
err = c.Persist("/tmp")
718731
assert.NotNil(err)

0 commit comments

Comments
 (0)