Merge pull request #1146 from shirou/feature/add_missing_commits

[v3][mem] add missing files.
This commit is contained in:
shirou 2021-10-07 22:01:54 +09:00 committed by GitHub
commit 3a63fa472d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 199 additions and 0 deletions

91
v3/mem/mem_bsd.go Normal file
View File

@ -0,0 +1,91 @@
// +build freebsd openbsd
package mem
import (
"context"
"fmt"
"os/exec"
"strconv"
"strings"
)
const swapCommand = "swapctl"
// swapctl column indexes
const (
nameCol = 0
totalKiBCol = 1
usedKiBCol = 2
)
func SwapDevices() ([]*SwapDevice, error) {
return SwapDevicesWithContext(context.Background())
}
func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
swapCommandPath, err := exec.LookPath(swapCommand)
if err != nil {
return nil, fmt.Errorf("could not find command %q: %w", swapCommand, err)
}
output, err := invoke.CommandWithContext(swapCommandPath, "-lk")
if err != nil {
return nil, fmt.Errorf("could not execute %q: %w", swapCommand, err)
}
return parseSwapctlOutput(string(output))
}
func parseSwapctlOutput(output string) ([]*SwapDevice, error) {
lines := strings.Split(output, "\n")
if len(lines) == 0 {
return nil, fmt.Errorf("could not parse output of %q: no lines in %q", swapCommand, output)
}
// Check header headerFields are as expected.
header := lines[0]
header = strings.ToLower(header)
header = strings.ReplaceAll(header, ":", "")
headerFields := strings.Fields(header)
if len(headerFields) < usedKiBCol {
return nil, fmt.Errorf("couldn't parse %q: too few fields in header %q", swapCommand, header)
}
if headerFields[nameCol] != "device" {
return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[nameCol], "device")
}
if headerFields[totalKiBCol] != "1kb-blocks" && headerFields[totalKiBCol] != "1k-blocks" {
return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[totalKiBCol], "1kb-blocks")
}
if headerFields[usedKiBCol] != "used" {
return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[usedKiBCol], "used")
}
var swapDevices []*SwapDevice
for _, line := range lines[1:] {
if line == "" {
continue // the terminal line is typically empty
}
fields := strings.Fields(line)
if len(fields) < usedKiBCol {
return nil, fmt.Errorf("couldn't parse %q: too few fields", swapCommand)
}
totalKiB, err := strconv.ParseUint(fields[totalKiBCol], 10, 64)
if err != nil {
return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapCommand, err)
}
usedKiB, err := strconv.ParseUint(fields[usedKiBCol], 10, 64)
if err != nil {
return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapCommand, err)
}
swapDevices = append(swapDevices, &SwapDevice{
Name: fields[nameCol],
UsedBytes: usedKiB * 1024,
FreeBytes: (totalKiB - usedKiB) * 1024,
})
}
return swapDevices, nil
}

63
v3/mem/mem_bsd_test.go Normal file
View File

@ -0,0 +1,63 @@
// +build freebsd openbsd
package mem
import (
"testing"
"github.com/stretchr/testify/assert"
)
const validFreeBSD = `Device: 1kB-blocks Used:
/dev/gpt/swapfs 1048576 1234
/dev/md0 1048576 666
`
const validOpenBSD = `Device 1K-blocks Used Avail Capacity Priority
/dev/wd0b 655025 1234 653791 1% 0
`
const invalid = `Device: 512-blocks Used:
/dev/gpt/swapfs 1048576 1234
/dev/md0 1048576 666
`
func TestParseSwapctlOutput_FreeBSD(t *testing.T) {
assert := assert.New(t)
stats, err := parseSwapctlOutput(validFreeBSD)
assert.NoError(err)
assert.Equal(*stats[0], SwapDevice{
Name: "/dev/gpt/swapfs",
UsedBytes: 1263616,
FreeBytes: 1072478208,
})
assert.Equal(*stats[1], SwapDevice{
Name: "/dev/md0",
UsedBytes: 681984,
FreeBytes: 1073059840,
})
}
func TestParseSwapctlOutput_OpenBSD(t *testing.T) {
assert := assert.New(t)
stats, err := parseSwapctlOutput(validOpenBSD)
assert.NoError(err)
assert.Equal(*stats[0], SwapDevice{
Name: "/dev/wd0b",
UsedBytes: 1234 * 1024,
FreeBytes: 653791 * 1024,
})
}
func TestParseSwapctlOutput_Invalid(t *testing.T) {
_, err := parseSwapctlOutput(invalid)
assert.Error(t, err)
}
func TestParseSwapctlOutput_Empty(t *testing.T) {
_, err := parseSwapctlOutput("")
assert.Error(t, err)
}

View File

@ -0,0 +1,45 @@
// +build solaris
package mem
import (
"testing"
"github.com/stretchr/testify/assert"
)
const validFile = `swapfile dev swaplo blocks free
/dev/zvol/dsk/rpool/swap 256,1 16 1058800 1058800
/dev/dsk/c0t0d0s1 136,1 16 1638608 1600528`
const invalidFile = `swapfile dev swaplo INVALID free
/dev/zvol/dsk/rpool/swap 256,1 16 1058800 1058800
/dev/dsk/c0t0d0s1 136,1 16 1638608 1600528`
func TestParseSwapsCommandOutput_Valid(t *testing.T) {
assert := assert.New(t)
stats, err := parseSwapsCommandOutput(validFile)
assert.NoError(err)
assert.Equal(*stats[0], SwapDevice{
Name: "/dev/zvol/dsk/rpool/swap",
UsedBytes: 0,
FreeBytes: 1058800 * 512,
})
assert.Equal(*stats[1], SwapDevice{
Name: "/dev/dsk/c0t0d0s1",
UsedBytes: 38080 * 512,
FreeBytes: 1600528 * 512,
})
}
func TestParseSwapsCommandOutput_Invalid(t *testing.T) {
_, err := parseSwapsCommandOutput(invalidFile)
assert.Error(t, err)
}
func TestParseSwapsCommandOutput_Empty(t *testing.T) {
_, err := parseSwapsCommandOutput("")
assert.Error(t, err)
}