Skip to content

Commit d1abc07

Browse files
committed
refactor lsblk
- include error code - remove unused properties - retrieve specific columns including device size - always output as JSON
1 parent c1dd946 commit d1abc07

File tree

2 files changed

+96
-40
lines changed

2 files changed

+96
-40
lines changed

iscsi/iscsi.go

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,8 @@ type Device struct {
5656
Hctl string `json:"hctl"`
5757
Children []Device `json:"children"`
5858
Type string `json:"type"`
59-
Vendor string `json:"vendor"`
60-
Model string `json:"model"`
61-
Revision string `json:"rev"`
6259
Transport string `json:"tran"`
60+
Size string `json:"size,omitempty"`
6361
}
6462

6563
// Connector provides a struct to hold all of the needed parameters to make our iSCSI connection
@@ -216,17 +214,8 @@ func pathExists(devicePath *string, deviceTransport string) error {
216214
// getMultipathDevice returns a multipath device for the configured targets if it exists
217215
func getMultipathDevice(devices []Device) (*Device, error) {
218216
var multipathDevice *Device
219-
var devicePaths []string
220217

221218
for _, device := range devices {
222-
devicePaths = append(devicePaths, device.GetPath())
223-
}
224-
deviceInfo, err := lsblk("", devicePaths)
225-
if err != nil {
226-
return nil, err
227-
}
228-
229-
for _, device := range deviceInfo.BlockDevices {
230219
if len(device.Children) != 1 {
231220
return nil, fmt.Errorf("device is not mapped to exactly one multipath device: %v", device.Children)
232221
}
@@ -454,7 +443,7 @@ func (c *Connector) IsMultipathEnabled() bool {
454443
func GetSCSIDevices(devicePaths []string) ([]Device, error) {
455444
debug.Printf("Getting info about SCSI devices %s.\n", devicePaths)
456445

457-
deviceInfo, err := lsblk("-S", devicePaths)
446+
deviceInfo, err := lsblk(devicePaths)
458447
if err != nil {
459448
debug.Printf("An error occured while looking info about SCSI devices: %v", err)
460449
return nil, err
@@ -482,24 +471,19 @@ func GetISCSIDevices(devicePaths []string) (devices []Device, err error) {
482471
}
483472

484473
// lsblk execute the lsblk commands
485-
func lsblkRaw(flags string, devicePaths []string) ([]byte, error) {
486-
out, err := execCommand("lsblk", append([]string{flags}, devicePaths...)...).CombinedOutput()
487-
debug.Printf("lsblk %s %s", flags, strings.Join(devicePaths, " "))
488-
if err != nil {
489-
return nil, fmt.Errorf("lsblk: %s", string(out))
490-
}
491-
492-
return out, nil
493-
}
494-
495-
func lsblk(flags string, devicePaths []string) (*deviceInfo, error) {
496-
var deviceInfo deviceInfo
497-
498-
out, err := lsblkRaw("-J "+flags, devicePaths)
474+
func lsblk(devicePaths []string) (*deviceInfo, error) {
475+
flags := []string{"-J", "-o", "NAME,HCTL,TYPE,TRAN,SIZE"}
476+
command := execCommand("lsblk", append(flags, devicePaths...)...)
477+
debug.Println(command.String())
478+
out, err := command.Output()
499479
if err != nil {
480+
if ee, ok := err.(*exec.ExitError); ok {
481+
return nil, fmt.Errorf("%s, (%v)", strings.Trim(string(ee.Stderr), "\n"), ee)
482+
}
500483
return nil, err
501484
}
502485

486+
var deviceInfo deviceInfo
503487
if err = json.Unmarshal(out, &deviceInfo); err != nil {
504488
return nil, err
505489
}
@@ -589,16 +573,30 @@ func (c *Connector) Persist(filePath string) error {
589573
func GetConnectorFromFile(filePath string) (*Connector, error) {
590574
f, err := ioutil.ReadFile(filePath)
591575
if err != nil {
592-
return &Connector{}, err
593-
576+
return nil, err
594577
}
595-
data := Connector{}
596-
err = json.Unmarshal(f, &data)
578+
c := Connector{}
579+
err = json.Unmarshal([]byte(f), &c)
597580
if err != nil {
598-
return &Connector{}, err
581+
return nil, err
582+
}
583+
584+
devicePaths := []string{}
585+
for _, device := range c.Devices {
586+
devicePaths = append(devicePaths, device.GetPath())
587+
}
588+
589+
if devices, err := GetSCSIDevices([]string{c.MountTargetDevice.GetPath()}); err != nil {
590+
return nil, err
591+
} else {
592+
c.MountTargetDevice = &devices[0]
593+
}
594+
595+
if c.Devices, err = GetSCSIDevices(devicePaths); err != nil {
596+
return nil, err
599597
}
600598

601-
return &data, nil
599+
return &c, nil
602600
}
603601

604602
// Exists check if the device exists at its path and returns an error otherwise

iscsi/iscsi_test.go

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,58 @@ func Test_getMultipathDevice(t *testing.T) {
586586
}
587587
}
588588

589+
func Test_lsblk(t *testing.T) {
590+
sda := Device{Name: "sda", Children: []Device{{}}}
591+
592+
tests := map[string]struct {
593+
devicePaths []string
594+
mockedStdout string
595+
mockedDevices []Device
596+
mockedExitStatus int
597+
wantErr bool
598+
}{
599+
"Basic": {
600+
devicePaths: []string{"/dev/sda"},
601+
mockedDevices: []Device{sda},
602+
},
603+
"NotABlockDevice": {
604+
devicePaths: []string{"/dev/sdzz"},
605+
mockedStdout: "lsblk: sdzz: not a block device",
606+
mockedExitStatus: 32,
607+
},
608+
"InvalidJson": {
609+
mockedStdout: "{",
610+
mockedExitStatus: 0,
611+
wantErr: true,
612+
},
613+
}
614+
615+
for name, tt := range tests {
616+
t.Run(name, func(t *testing.T) {
617+
assert := assert.New(t)
618+
619+
mockedStdout := tt.mockedStdout
620+
if mockedStdout == "" {
621+
out, err := json.Marshal(deviceInfo{BlockDevices: tt.mockedDevices})
622+
assert.Nil(err, "could not setup test")
623+
mockedStdout = string(out)
624+
}
625+
626+
defer gostub.Stub(&execCommand, makeFakeExecCommand(tt.mockedExitStatus, mockedStdout)).Reset()
627+
deviceInfo, err := lsblk(tt.devicePaths)
628+
629+
if tt.mockedExitStatus != 0 || tt.wantErr {
630+
assert.Nil(deviceInfo)
631+
assert.NotNil(err)
632+
} else {
633+
assert.NotNil(deviceInfo)
634+
assert.Equal(tt.mockedDevices, deviceInfo.BlockDevices)
635+
assert.Nil(err)
636+
}
637+
})
638+
}
639+
}
640+
589641
func TestConnectorPersistance(t *testing.T) {
590642
assert := assert.New(t)
591643

@@ -600,19 +652,13 @@ func TestConnectorPersistance(t *testing.T) {
600652
Name: "child name",
601653
Hctl: "child hctl",
602654
Type: "child type",
603-
Vendor: "child vendor",
604-
Model: "child model",
605-
Revision: "child revision",
606655
Transport: "child transport",
607656
}
608657
device := Device{
609658
Name: "device name",
610659
Hctl: "device hctl",
611660
Children: []Device{childDevice},
612661
Type: "device type",
613-
Vendor: "device vendor",
614-
Model: "device model",
615-
Revision: "device revision",
616662
Transport: "device transport",
617663
}
618664
c := Connector{
@@ -624,13 +670,25 @@ func TestConnectorPersistance(t *testing.T) {
624670
SessionSecrets: secret,
625671
Interface: "fake interface",
626672
MountTargetDevice: &device,
627-
Devices: []Device{device, childDevice},
673+
Devices: []Device{childDevice},
628674
RetryCount: 24,
629675
CheckInterval: 13,
630676
DoDiscovery: true,
631677
DoCHAPDiscovery: true,
632678
}
633679

680+
defer gostub.Stub(&execCommand, func(cmd string, args ...string) *exec.Cmd {
681+
mockedDevice := device
682+
if args[3] == "/dev/child name" {
683+
mockedDevice = childDevice
684+
}
685+
686+
mockedOutput, err := json.Marshal(deviceInfo{BlockDevices: []Device{mockedDevice}})
687+
assert.Nil(err, "could not setup test")
688+
689+
return makeFakeExecCommand(0, string(mockedOutput))(cmd, args...)
690+
}).Reset()
691+
634692
c.Persist("/tmp/connector.json")
635693
c2, err := GetConnectorFromFile("/tmp/connector.json")
636694
assert.Nil(err)

0 commit comments

Comments
 (0)