-
Notifications
You must be signed in to change notification settings - Fork 92
/
host_block_device.go
110 lines (92 loc) · 2.84 KB
/
host_block_device.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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
}