Files
troubleshoot/pkg/collect/host_block_device.go

115 lines
3.0 KiB
Go

package collect
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"os/exec"
"strings"
"github.com/pkg/errors"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
)
type BlockDeviceInfo struct {
Name string `json:"name"`
KernelName string `json:"kernel_name"`
ParentKernelName string `json:"parent_kernel_name"`
Type string `json:"type"`
Major int `json:"major"`
Minor int `json:"minor"`
Size uint64 `json:"size"`
FilesystemType string `json:"filesystem_type"`
Mountpoint string `json:"mountpoint"`
Serial string `json:"serial"`
ReadOnly bool `json:"read_only"`
Removable bool `json:"removable"`
}
const lsblkColumns = "NAME,KNAME,PKNAME,TYPE,MAJ:MIN,SIZE,FSTYPE,MOUNTPOINT,SERIAL,RO,RM"
const lsblkFormat = `NAME=%q KNAME=%q PKNAME=%q TYPE=%q MAJ:MIN="%d:%d" SIZE="%d" FSTYPE=%q MOUNTPOINT=%q SERIAL=%q RO="%d" RM="%d0"`
const HostBlockDevicesPath = `host-collectors/system/block_devices.json`
type CollectHostBlockDevices struct {
hostCollector *troubleshootv1beta2.HostBlockDevices
BundlePath string
}
func (c *CollectHostBlockDevices) Title() string {
return hostCollectorTitleOrDefault(c.hostCollector.HostCollectorMeta, "Block Devices")
}
func (c *CollectHostBlockDevices) IsExcluded() (bool, error) {
return isExcluded(c.hostCollector.Exclude)
}
func (c *CollectHostBlockDevices) Collect(progressChan chan<- interface{}) (map[string][]byte, error) {
cmd := exec.Command("lsblk", "--noheadings", "--bytes", "--pairs", "-o", lsblkColumns)
stdout, err := cmd.Output()
if err != nil {
return nil, errors.Wrapf(err, "failed to execute lsblk")
}
devices, err := parseLsblkOutput(stdout)
if err != nil {
return nil, errors.Wrap(err, "failed to parse block device output")
}
b, err := json.Marshal(devices)
if err != nil {
return nil, errors.Wrap(err, "failed to marshal block device info")
}
output := NewResult()
output.SaveResult(c.BundlePath, HostBlockDevicesPath, bytes.NewBuffer(b))
return map[string][]byte{
HostBlockDevicesPath: b,
}, nil
}
func parseLsblkOutput(output []byte) ([]BlockDeviceInfo, error) {
var devices []BlockDeviceInfo
buf := bytes.NewBuffer(output)
scanner := bufio.NewScanner(buf)
for scanner.Scan() {
bdi := BlockDeviceInfo{}
var ro int
var rm int
line := strings.ReplaceAll(scanner.Text(), "MAJ_MIN", "MAJ:MIN")
fmt.Sscanf(
line,
lsblkFormat,
&bdi.Name,
&bdi.KernelName,
&bdi.ParentKernelName,
&bdi.Type,
&bdi.Major,
&bdi.Minor,
&bdi.Size,
&bdi.FilesystemType,
&bdi.Mountpoint,
&bdi.Serial,
&ro,
&rm,
)
bdi.ReadOnly = ro == 1
bdi.Removable = rm == 1
devices = append(devices, bdi)
}
if err := scanner.Err(); err != nil {
return nil, errors.Wrap(err, "failed to scan lsblk output")
}
return devices, nil
}
func (c *CollectHostBlockDevices) RemoteCollect(progressChan chan<- interface{}) (map[string][]byte, error) {
return nil, ErrRemoteCollectorNotImplemented
}