Skip to content

Commit

Permalink
additional logic to dedup disks and only show one device for multipat…
Browse files Browse the repository at this point in the history
…h'd disks
  • Loading branch information
ibrokethecloud committed Aug 21, 2024
1 parent 7c7edc0 commit 8c25085
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 2 deletions.
6 changes: 4 additions & 2 deletions pkg/console/install_panels.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,13 @@ func getDataDiskOptions(hvstConfig *config.HarvesterConfig) ([]widgets.Option, e
}

func getDiskOptions() ([]widgets.Option, error) {
output, err := exec.Command("/bin/sh", "-c", `lsblk -r -o NAME,SIZE,TYPE | grep -w disk | cut -d ' ' -f 1,2`).CombinedOutput()
output, err := exec.Command("/bin/sh", "-c", `lsblk -J -o NAME,SIZE,TYPE,WWN,SERIAL`).CombinedOutput()
if err != nil {
return nil, err
}
lines := strings.Split(strings.TrimSuffix(string(output), "\n"), "\n")

lines, err := identifyUniqueDisks(output)

var options []widgets.Option
for _, line := range lines {
splits := strings.SplitN(line, " ", 2)
Expand Down
68 changes: 68 additions & 0 deletions pkg/console/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -986,3 +986,71 @@ func generateEnvAndConfig(g *gocui.Gui, hvstConfig *config.HarvesterConfig) ([]s
env = append(env, fmt.Sprintf("HARVESTER_STREAMDISK_CLOUDINIT_URL=%s", userDataURL))
return env, elementalConfig, nil
}

// internal objects to parse lsblk output
type BlockDevices struct {
Disks []Device `json:"blockdevices"`
}

type Device struct {
Name string `json:"name"`
Size string `json:"size"`
DiskType string `json:"type"`
WWN string `json:"wwn,omitempty"`
Serial string `json:"serial,omitempty"`
Children []Device `json:"children,omitempty"`
}

func generateDiskEntry(d Device) string {
return fmt.Sprintf("%s %s", d.Name, d.Size)
}

const (
diskType = "disk"
)

// identifyUniqueDisks parses the json output of lsblk and identifies
// unique disks by comparing their child elements
func identifyUniqueDisks(output []byte) ([]string, error) {
var returnDisks []string
disks := &BlockDevices{}
err := json.Unmarshal(output, disks)
if err != nil {
return nil, fmt.Errorf("error unmarshalling lsblk json output: %v", err)
}

// identify devices which may be unique
dedupMap := make(map[string]Device)
for _, disk := range disks.Disks {
if disk.DiskType == diskType {
// no children present so not a mpath disk
// add to list of disks
if len(disk.Children) == 0 {
returnDisks = append(returnDisks, generateDiskEntry(disk))
continue
}
// process children to identify unique disks
// childDevices can contain partition info or multipath disk info
// which does not matter since we eventually dedup the names again
for _, childDevice := range disk.Children {
_, ok := dedupMap[childDevice.Name]
if !ok {
dedupMap[childDevice.Name] = disk
}
}
}
}
// devices may have multiple children, as a result same device map appear twice in dedupMap
// as a result we need to remove duplicates of same deviceName again
resultMap := make(map[string]Device)
for _, v := range dedupMap {
resultMap[v.Name] = v
}

// generate list of disks
for _, v := range resultMap {
returnDisks = append(returnDisks, generateDiskEntry(v))
}

return returnDisks, nil
}
171 changes: 171 additions & 0 deletions pkg/console/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/harvester/harvester-installer/pkg/util"
)
Expand Down Expand Up @@ -231,3 +232,173 @@ func startMockNTPServers(quit chan interface{}) ([]string, error) {
}
return ntpServers, nil
}

const (
sampleSerialDiskOutput = `
{
"blockdevices": [
{
"name": "loop0",
"size": "768.1M",
"type": "loop",
"wwn": null,
"serial": null
},{
"name": "sda",
"size": "250G",
"type": "disk",
"wwn": null,
"serial": "serial-1",
"children": [
{
"name": "0QEMU_QEMU_HARDDISK_serial-1",
"size": "250G",
"type": "mpath",
"wwn": null,
"serial": null
}
]
},{
"name": "sdb",
"size": "250G",
"type": "disk",
"wwn": null,
"serial": "serial-1",
"children": [
{
"name": "0QEMU_QEMU_HARDDISK_serial-1",
"size": "250G",
"type": "mpath",
"wwn": null,
"serial": null
}
]
},{
"name": "sr0",
"size": "5.8G",
"type": "rom",
"wwn": null,
"serial": "QM00001"
}
]
}
`

reinstallDisks = `
{
"blockdevices": [
{
"name": "loop0",
"size": "3G",
"type": "loop",
"wwn": null,
"serial": null
},{
"name": "loop1",
"size": "10G",
"type": "loop",
"wwn": null,
"serial": null
},{
"name": "sda",
"size": "10G",
"type": "disk",
"wwn": "0x60000000000000000e00000000010001",
"serial": "beaf11",
"children": [
{
"name": "sda1",
"size": "2.5G",
"type": "part",
"wwn": "0x60000000000000000e00000000010001",
"serial": null
},{
"name": "sda14",
"size": "4M",
"type": "part",
"wwn": "0x60000000000000000e00000000010001",
"serial": null
},{
"name": "sda15",
"size": "106M",
"type": "part",
"wwn": "0x60000000000000000e00000000010001",
"serial": null
},{
"name": "sda16",
"size": "913M",
"type": "part",
"wwn": "0x60000000000000000e00000000010001",
"serial": null
}
]
},{
"name": "sr0",
"size": "364K",
"type": "rom",
"wwn": null,
"serial": "QM00001"
},{
"name": "vda",
"size": "250G",
"type": "disk",
"wwn": null,
"serial": null,
"children": [
{
"name": "vda1",
"size": "1M",
"type": "part",
"wwn": null,
"serial": null
},{
"name": "vda2",
"size": "50M",
"type": "part",
"wwn": null,
"serial": null
},{
"name": "vda3",
"size": "8G",
"type": "part",
"wwn": null,
"serial": null
},{
"name": "vda4",
"size": "15G",
"type": "part",
"wwn": null,
"serial": null
},{
"name": "vda5",
"size": "150G",
"type": "part",
"wwn": null,
"serial": null
},{
"name": "vda6",
"size": "76.9G",
"type": "part",
"wwn": null,
"serial": null
}
]
}
]
}
`
)

func Test_identifyUniqueDisksWithSerialNumber(t *testing.T) {
assert := require.New(t)
result, err := identifyUniqueDisks([]byte(sampleSerialDiskOutput))
assert.NoError(err, "expected no error while parsing disk data")
assert.Len(result, 1, "expected to find 1 disk only")
}

func Test_identifyUniqueDisksWithExistingDisks(t *testing.T) {
assert := require.New(t)
result, err := identifyUniqueDisks([]byte(reinstallDisks))
assert.NoError(err, "expected no error while parsing disk data")
assert.Len(result, 2, "expected to find 1 disk only")
}

0 comments on commit 8c25085

Please sign in to comment.