Skip to content

Commit

Permalink
🧹 Add new methods for detecting and mounting in the volume mounter. (#…
Browse files Browse the repository at this point in the history
…4101)

* 🧹 Add new methods for detecting and mounting in the volume mounter. Previously that was all done in one function, we now split those.

Signed-off-by: Preslav <[email protected]>

* Drop unused file.

---------

Signed-off-by: Preslav <[email protected]>
  • Loading branch information
preslavgerchev authored May 24, 2024
1 parent d122b18 commit 9708499
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 106 deletions.
4 changes: 2 additions & 2 deletions providers/os/connection/device/device_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func NewDeviceConnection(connId uint32, conf *inventory.Config, asset *inventory
}
log.Debug().Str("manager", manager.Name()).Msg("device manager created")

blocks, err := manager.IdentifyBlockDevice(conf.Options)
blocks, err := manager.IdentifyMountTargets(conf.Options)
if err != nil {
return nil, err
}
Expand All @@ -56,7 +56,7 @@ func NewDeviceConnection(connId uint32, conf *inventory.Config, asset *inventory
return nil, errors.New("internal>blocks size is not equal to 1.")
}
block := blocks[0]
log.Debug().Str("device", block.DeviceName).Msg("identified block for mounting")
log.Debug().Str("name", block.Name).Str("type", block.FsType).Msg("identified partition for mounting")

res := &DeviceConnection{
Connection: plugin.NewConnection(connId, asset),
Expand Down
12 changes: 9 additions & 3 deletions providers/os/connection/device/device_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@

package device

import "go.mondoo.com/cnquery/v11/providers/os/connection/device/shared"
import (
"go.mondoo.com/cnquery/v11/providers/os/connection/snapshot"
)

type DeviceManager interface {
// Name returns the name of the device manager
Name() string
IdentifyBlockDevice(opts map[string]string) ([]shared.MountInfo, error)
Mount(mi shared.MountInfo) (string, error)
// IdentifyMountTargets returns a list of partitions that match the given options and can be mounted
IdentifyMountTargets(opts map[string]string) ([]*snapshot.PartitionInfo, error)
// Mounts the partition and returns the directory it was mounted to
Mount(pi *snapshot.PartitionInfo) (string, error)
// UnmountAndClose unmounts the partitions from the specified dirs and closes the device manager
UnmountAndClose()
}
74 changes: 29 additions & 45 deletions providers/os/connection/device/linux/device_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

"github.com/cockroachdb/errors"
"github.com/rs/zerolog/log"
"go.mondoo.com/cnquery/v11/providers/os/connection/device/shared"
"go.mondoo.com/cnquery/v11/providers/os/connection/snapshot"
)

Expand Down Expand Up @@ -37,7 +36,7 @@ func (d *LinuxDeviceManager) Name() string {
return "linux"
}

func (d *LinuxDeviceManager) IdentifyBlockDevice(opts map[string]string) ([]shared.MountInfo, error) {
func (d *LinuxDeviceManager) IdentifyMountTargets(opts map[string]string) ([]*snapshot.PartitionInfo, error) {
if err := validateOpts(opts); err != nil {
return nil, err
}
Expand All @@ -46,20 +45,22 @@ func (d *LinuxDeviceManager) IdentifyBlockDevice(opts map[string]string) ([]shar
if err != nil {
return nil, err
}
return d.identifyViaLun(lun)
pi, err := d.identifyViaLun(lun)
if err != nil {
return nil, err
}
return []*snapshot.PartitionInfo{pi}, nil
}

return d.identifyViaDeviceName(opts[DeviceName])
}

func (d *LinuxDeviceManager) Mount(mi shared.MountInfo) (string, error) {
// TODO: we should make the volume mounter return the scan dir from Mount()
// TODO: use the mount info to mount the volume
err := d.volumeMounter.Mount()
pi, err := d.identifyViaDeviceName(opts[DeviceName])
if err != nil {
return "", err
return nil, err
}
return d.volumeMounter.ScanDir, nil
return []*snapshot.PartitionInfo{pi}, nil
}

func (d *LinuxDeviceManager) Mount(pi *snapshot.PartitionInfo) (string, error) {
return d.volumeMounter.MountP(pi)
}

func (d *LinuxDeviceManager) UnmountAndClose() {
Expand Down Expand Up @@ -92,7 +93,7 @@ func validateOpts(opts map[string]string) error {
return nil
}

func (c *LinuxDeviceManager) identifyViaLun(lun int) ([]shared.MountInfo, error) {
func (c *LinuxDeviceManager) identifyViaLun(lun int) (*snapshot.PartitionInfo, error) {
scsiDevices, err := c.listScsiDevices()
if err != nil {
return nil, err
Expand All @@ -104,43 +105,26 @@ func (c *LinuxDeviceManager) identifyViaLun(lun int) ([]shared.MountInfo, error)
return nil, errors.New("no matching scsi devices found")
}

var target string
// if we have exactly one device present at the LUN we can directly point the volume mounter towards it
if len(filteredScsiDevices) == 1 {
return []shared.MountInfo{{DeviceName: filteredScsiDevices[0].VolumePath}}, nil
}

// we have multiple devices at the same LUN. we find the first non-mounted block devices in that list
blockDevices, err := c.volumeMounter.CmdRunner.GetBlockDevices()
if err != nil {
return nil, err
}
target, err := findMatchingDeviceByBlock(filteredScsiDevices, blockDevices)
if err != nil {
return nil, err
}
c.volumeMounter.VolumeAttachmentLoc = target
return []shared.MountInfo{{DeviceName: target}}, nil
}

func (c *LinuxDeviceManager) identifyViaDeviceName(deviceName string) ([]shared.MountInfo, error) {
blockDevices, err := c.volumeMounter.CmdRunner.GetBlockDevices()
if err != nil {
return nil, err
}
// this is a best-effort approach, we try to find the first unmounted block device as we don't have the device name
if deviceName == "" {
fsInfo, err := blockDevices.GetUnmountedBlockEntry()
target = filteredScsiDevices[0].VolumePath
} else {
// we have multiple devices at the same LUN. we find the first non-mounted block devices in that list
blockDevices, err := c.volumeMounter.CmdRunner.GetBlockDevices()
if err != nil {
return nil, err
}
target, err = findMatchingDeviceByBlock(filteredScsiDevices, blockDevices)
if err != nil {
return nil, err
}
c.volumeMounter.VolumeAttachmentLoc = deviceName
return []shared.MountInfo{{DeviceName: fsInfo.Name}}, nil
}

fsInfo, err := blockDevices.GetBlockEntryByName(deviceName)
if err != nil {
return nil, err
}
c.volumeMounter.VolumeAttachmentLoc = deviceName
return []shared.MountInfo{{DeviceName: fsInfo.Name}}, nil
return c.volumeMounter.GetDeviceForMounting(target)
}

func (c *LinuxDeviceManager) identifyViaDeviceName(deviceName string) (*snapshot.PartitionInfo, error) {
// GetDeviceForMounting also supports passing in empty strings, in that case we do a best-effort guess
return c.volumeMounter.GetDeviceForMounting(deviceName)
}
8 changes: 0 additions & 8 deletions providers/os/connection/device/shared/mountinfo.go

This file was deleted.

38 changes: 19 additions & 19 deletions providers/os/connection/snapshot/blockdevices.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type BlockDevice struct {
FsUse string `json:"fsuse%,omitempty"`
}

type fsInfo struct {
type PartitionInfo struct {
Name string
FsType string
}
Expand Down Expand Up @@ -55,7 +55,7 @@ func (cmdRunner *LocalCommandRunner) GetBlockDevices() (*BlockDevices, error) {
return blockEntries, nil
}

func (blockEntries BlockDevices) GetRootBlockEntry() (*fsInfo, error) {
func (blockEntries BlockDevices) GetRootBlockEntry() (*PartitionInfo, error) {
log.Debug().Msg("get root block entry")
for i := range blockEntries.BlockDevices {
d := blockEntries.BlockDevices[i]
Expand All @@ -64,14 +64,14 @@ func (blockEntries BlockDevices) GetRootBlockEntry() (*fsInfo, error) {
entry := d.Children[i]
if entry.IsNoBootVolume() {
devFsName := "/dev/" + entry.Name
return &fsInfo{Name: devFsName, FsType: entry.FsType}, nil
return &PartitionInfo{Name: devFsName, FsType: entry.FsType}, nil
}
}
}
return nil, errors.New("target volume not found on instance")
}

func (blockEntries BlockDevices) GetBlockEntryByName(name string) (*fsInfo, error) {
func (blockEntries BlockDevices) GetBlockEntryByName(name string) (*PartitionInfo, error) {
log.Debug().Str("name", name).Msg("get matching block entry")
var secondName string
if strings.HasPrefix(name, "/dev/sd") {
Expand All @@ -91,57 +91,57 @@ func (blockEntries BlockDevices) GetBlockEntryByName(name string) (*fsInfo, erro
continue
}
}
log.Debug().Msg("found match")
log.Debug().Str("location", d.Name).Msg("found match")
for i := range d.Children {
entry := d.Children[i]
if entry.IsNotBootOrRootVolumeAndUnmounted() {
devFsName := "/dev/" + entry.Name
return &fsInfo{Name: devFsName, FsType: entry.FsType}, nil
return &PartitionInfo{Name: devFsName, FsType: entry.FsType}, nil
}
}
}
return nil, errors.New("target volume not found on instance")
}

func (blockEntries BlockDevices) GetUnnamedBlockEntry() (*fsInfo, error) {
fsInfo, err := blockEntries.GetUnmountedBlockEntry()
if err == nil && fsInfo != nil {
return fsInfo, nil
func (blockEntries BlockDevices) GetUnnamedBlockEntry() (*PartitionInfo, error) {
pInfo, err := blockEntries.GetUnmountedBlockEntry()
if err == nil && pInfo != nil {
return pInfo, nil
} else {
// if we get here, there was no non-root, non-mounted volume on the instance
// this is expected in the "no setup" case where we start an instance with the target
// volume attached and only that volume attached
fsInfo, err = blockEntries.GetRootBlockEntry()
if err == nil && fsInfo != nil {
return fsInfo, nil
pInfo, err = blockEntries.GetRootBlockEntry()
if err == nil && pInfo != nil {
return pInfo, nil
}
}
return nil, errors.New("target volume not found on instance")
}

func (blockEntries BlockDevices) GetUnmountedBlockEntry() (*fsInfo, error) {
func (blockEntries BlockDevices) GetUnmountedBlockEntry() (*PartitionInfo, error) {
log.Debug().Msg("get unmounted block entry")
for i := range blockEntries.BlockDevices {
d := blockEntries.BlockDevices[i]
log.Debug().Str("name", d.Name).Interface("children", d.Children).Interface("mountpoint", d.MountPoint).Msg("found block device")
if d.MountPoint != "" { // empty string means it is not mounted
continue
}
if fsinfo := findVolume(d.Children); fsinfo != nil {
return fsinfo, nil
if pInfo := findVolume(d.Children); pInfo != nil {
return pInfo, nil
}
}
return nil, errors.New("target volume not found on instance")
}

func findVolume(children []BlockDevice) *fsInfo {
var fs *fsInfo
func findVolume(children []BlockDevice) *PartitionInfo {
var fs *PartitionInfo
for i := range children {
entry := children[i]
if entry.IsNotBootOrRootVolumeAndUnmounted() {
// we are NOT searching for the root volume here, so we can exclude the "sda" and "xvda" volumes
devFsName := "/dev/" + entry.Name
fs = &fsInfo{Name: devFsName, FsType: entry.FsType}
fs = &PartitionInfo{Name: devFsName, FsType: entry.FsType}
}
}
return fs
Expand Down
40 changes: 20 additions & 20 deletions providers/os/connection/snapshot/blockdevices_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,40 +21,40 @@ func TestGetMatchingBlockEntryByName(t *testing.T) {
{Name: "sdx", Children: []BlockDevice{{Uuid: "12346", FsType: "xfs", Label: "ROOT", Name: "sdh1"}, {Uuid: "12345", FsType: "", Label: "EFI"}}},
}...)

realFsInfo, err := blockEntries.GetBlockEntryByName("/dev/sdx")
realPartitionInfo, err := blockEntries.GetBlockEntryByName("/dev/sdx")
require.Nil(t, err)
require.Equal(t, fsInfo{FsType: "xfs", Name: "/dev/sdh1"}, *realFsInfo)
require.Equal(t, PartitionInfo{FsType: "xfs", Name: "/dev/sdh1"}, *realPartitionInfo)

blockEntries = BlockDevices{BlockDevices: []BlockDevice{RootDevice}}
blockEntries.BlockDevices = append(blockEntries.BlockDevices, []BlockDevice{
{Name: "nvme0n1", Children: []BlockDevice{{Uuid: "12345", FsType: "xfs", Label: "ROOT", Name: "nvmd1n1"}, {Uuid: "12345", FsType: "", Label: "EFI"}}},
{Name: "xvdx", Children: []BlockDevice{{Uuid: "12346", FsType: "xfs", Label: "ROOT", Name: "xvdh1"}, {Uuid: "12345", FsType: "", Label: "EFI"}}},
}...)

realFsInfo, err = blockEntries.GetBlockEntryByName("/dev/sdx")
realPartitionInfo, err = blockEntries.GetBlockEntryByName("/dev/sdx")
require.Nil(t, err)
require.Equal(t, fsInfo{FsType: "xfs", Name: "/dev/xvdh1"}, *realFsInfo)
require.Equal(t, PartitionInfo{FsType: "xfs", Name: "/dev/xvdh1"}, *realPartitionInfo)

blockEntries = BlockDevices{BlockDevices: []BlockDevice{RootDevice}}
blockEntries.BlockDevices = append(blockEntries.BlockDevices, []BlockDevice{
{Name: "nvme0n1", Children: []BlockDevice{{Uuid: "12345", FsType: "xfs", Label: "ROOT", Name: "nvmd1n1"}, {Uuid: "12345", FsType: "", Label: "EFI"}}},
{Name: "xvdh", Children: []BlockDevice{{Uuid: "12346", FsType: "xfs", Label: "ROOT", Name: "xvdh1"}, {Uuid: "12345", FsType: "", Label: "EFI"}}},
}...)

realFsInfo, err = blockEntries.GetBlockEntryByName("/dev/xvdh")
realPartitionInfo, err = blockEntries.GetBlockEntryByName("/dev/xvdh")
require.Nil(t, err)
require.Equal(t, fsInfo{FsType: "xfs", Name: "/dev/xvdh1"}, *realFsInfo)
require.Equal(t, PartitionInfo{FsType: "xfs", Name: "/dev/xvdh1"}, *realPartitionInfo)

blockEntries = BlockDevices{BlockDevices: []BlockDevice{RootDevice}}
blockEntries.BlockDevices = append(blockEntries.BlockDevices, []BlockDevice{
{Name: "nvme0n1", Children: []BlockDevice{{Uuid: "12345", FsType: "xfs", Label: "ROOT", Name: "nvmd1n1"}, {Uuid: "12345", FsType: "", Label: "EFI"}}},
}...)

realFsInfo, err = blockEntries.GetBlockEntryByName("/dev/sdh")
_, err = blockEntries.GetBlockEntryByName("/dev/sdh")
require.Error(t, err)

blockEntries = BlockDevices{BlockDevices: []BlockDevice{RootDevice}}
realFsInfo, err = blockEntries.GetBlockEntryByName("/dev/sdh")
_, err = blockEntries.GetBlockEntryByName("/dev/sdh")
require.Error(t, err)
}

Expand All @@ -63,16 +63,16 @@ func TestGetNonRootBlockEntry(t *testing.T) {
blockEntries.BlockDevices = append(blockEntries.BlockDevices, []BlockDevice{
{Name: "nvme0n1", Children: []BlockDevice{{Uuid: "12345", FsType: "xfs", Label: "ROOT", Name: "nvmd1n1"}, {Uuid: "12345", FsType: "", Label: "EFI"}}},
}...)
realFsInfo, err := blockEntries.GetUnmountedBlockEntry()
realPartitionInfo, err := blockEntries.GetUnmountedBlockEntry()
require.Nil(t, err)
require.Equal(t, fsInfo{FsType: "xfs", Name: "/dev/nvmd1n1"}, *realFsInfo)
require.Equal(t, PartitionInfo{FsType: "xfs", Name: "/dev/nvmd1n1"}, *realPartitionInfo)
}

func TestGetRootBlockEntry(t *testing.T) {
blockEntries := BlockDevices{BlockDevices: []BlockDevice{RootDevice}}
realFsInfo, err := blockEntries.GetRootBlockEntry()
realPartitionInfo, err := blockEntries.GetRootBlockEntry()
require.Nil(t, err)
require.Equal(t, fsInfo{FsType: "xfs", Name: "/dev/sda1"}, *realFsInfo)
require.Equal(t, PartitionInfo{FsType: "xfs", Name: "/dev/sda1"}, *realPartitionInfo)
}

func TestGetRootBlockEntryRhel8(t *testing.T) {
Expand All @@ -83,13 +83,13 @@ func TestGetRootBlockEntryRhel8(t *testing.T) {
err = json.Unmarshal(data, &blockEntries)
require.NoError(t, err)

rootFsInfo, err := blockEntries.GetRootBlockEntry()
rootPartitionInfo, err := blockEntries.GetRootBlockEntry()
require.NoError(t, err)
require.Equal(t, fsInfo{FsType: "xfs", Name: "/dev/sda2"}, *rootFsInfo)
require.Equal(t, PartitionInfo{FsType: "xfs", Name: "/dev/sda2"}, *rootPartitionInfo)

rootFsInfo, err = blockEntries.GetUnnamedBlockEntry()
rootPartitionInfo, err = blockEntries.GetUnnamedBlockEntry()
require.NoError(t, err)
require.Equal(t, fsInfo{FsType: "xfs", Name: "/dev/sdc2"}, *rootFsInfo)
require.Equal(t, PartitionInfo{FsType: "xfs", Name: "/dev/sdc2"}, *rootPartitionInfo)
}

func TestGetRootBlockEntryRhelNoLabels(t *testing.T) {
Expand All @@ -100,13 +100,13 @@ func TestGetRootBlockEntryRhelNoLabels(t *testing.T) {
err = json.Unmarshal(data, &blockEntries)
require.NoError(t, err)

rootFsInfo, err := blockEntries.GetRootBlockEntry()
rootPartitionInfo, err := blockEntries.GetRootBlockEntry()
require.NoError(t, err)
require.Equal(t, fsInfo{FsType: "xfs", Name: "/dev/sda2"}, *rootFsInfo)
require.Equal(t, PartitionInfo{FsType: "xfs", Name: "/dev/sda2"}, *rootPartitionInfo)

rootFsInfo, err = blockEntries.GetUnnamedBlockEntry()
rootPartitionInfo, err = blockEntries.GetUnnamedBlockEntry()
require.NoError(t, err)
require.Equal(t, fsInfo{FsType: "ext4", Name: "/dev/sdb1"}, *rootFsInfo)
require.Equal(t, PartitionInfo{FsType: "ext4", Name: "/dev/sdb1"}, *rootPartitionInfo)
}

func TestAttachedBlockEntry(t *testing.T) {
Expand Down
Loading

0 comments on commit 9708499

Please sign in to comment.