-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdataset.go
148 lines (132 loc) · 3.99 KB
/
dataset.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package zfs
import (
"fmt"
"strconv"
"strings"
)
// DatasetType is the zfs dataset type
type DatasetType string
// ZFS dataset types, which can indicate if a dataset is a filesystem, snapshot, or volume.
const (
DatasetAll DatasetType = "all"
DatasetFilesystem DatasetType = "filesystem"
DatasetSnapshot DatasetType = "snapshot"
DatasetVolume DatasetType = "volume"
)
// Dataset is a ZFS dataset. A dataset could be a clone, filesystem, snapshot, or volume.
// The Type struct member can be used to determine a dataset's type.
//
// The field definitions can be found in the ZFS manual:
// https://openzfs.github.io/openzfs-docs/man/7/zfsprops.7.html.
type Dataset struct {
Name string `json:"Name"`
Type DatasetType `json:"Type"`
Origin string `json:"Origin"`
Used uint64 `json:"Used"`
Available uint64 `json:"Available"`
Mounted bool `json:"Mounted"`
Mountpoint string `json:"Mountpoint"`
Compression string `json:"Compression"`
Written uint64 `json:"Written"`
Volsize uint64 `json:"Volsize"`
Logicalused uint64 `json:"Logicalused"`
Usedbydataset uint64 `json:"Usedbydataset"`
Quota uint64 `json:"Quota"`
Refquota uint64 `json:"Refquota"`
Referenced uint64 `json:"Referenced"`
ExtraProps map[string]string `json:"ExtraProps"`
}
const (
nameField = iota
propertyField
valueField
)
func readDatasets(output [][]string, extraProps []string) ([]Dataset, error) {
multiple := len(dsPropList) + len(extraProps)
if len(output)%multiple != 0 {
return nil, fmt.Errorf("output invalid: %d lines where a multiple of %d was expected: %s",
len(output), multiple, strings.Join(output[0], " "),
)
}
count := len(output) / multiple
curDataset := 0
datasets := make([]Dataset, count)
for i, fields := range output {
if len(fields) != 3 {
return nil, fmt.Errorf("output contains line with %d fields: %s", len(fields), strings.Join(fields, " "))
}
if i > 0 && fields[nameField] != datasets[curDataset].Name {
curDataset++
}
ds := &datasets[curDataset]
ds.Name = fields[nameField]
// Init extra props if needed
if ds.ExtraProps == nil {
ds.ExtraProps = make(map[string]string, len(extraProps))
}
prop := fields[propertyField]
val := fields[valueField]
var setError error
switch prop {
case PropertyName:
ds.Name = val
case PropertyType:
ds.Type = DatasetType(val)
case PropertyOrigin:
ds.Origin = setString(val)
case PropertyUsed:
ds.Used, setError = setUint(val)
case PropertyAvailable:
ds.Available, setError = setUint(val)
case PropertyMounted:
ds.Mounted = setBool(val)
case PropertyMountPoint:
ds.Mountpoint = setString(val)
case PropertyCompression:
ds.Compression = setString(val)
case PropertyWritten:
ds.Written, setError = setUint(val)
case PropertyVolSize:
ds.Volsize, setError = setUint(val)
case PropertyLogicalUsed:
ds.Logicalused, setError = setUint(val)
case PropertyUsedByDataset:
ds.Usedbydataset, setError = setUint(val)
case PropertyQuota:
ds.Quota, setError = setUint(val)
case PropertyRefQuota:
ds.Refquota, setError = setUint(val)
case PropertyReferenced:
ds.Referenced, setError = setUint(val)
default:
if val == ValueUnset {
ds.ExtraProps[prop] = ""
continue
}
ds.ExtraProps[prop] = val
}
if setError != nil {
return nil, fmt.Errorf("error in dataset %d (%s) field %s [%s]: %w", curDataset, ds.Name, prop, val, setError)
}
}
return datasets, nil
}
func setString(val string) string {
if val == ValueUnset {
return ""
}
return val
}
func setUint(val string) (uint64, error) {
if val == ValueUnset {
return 0, nil
}
v, err := strconv.ParseUint(val, 10, 64)
if err != nil {
return 0, err
}
return v, nil
}
func setBool(val string) bool {
return strings.EqualFold(val, ValueYes) || strings.EqualFold(val, ValueOn)
}