-
Notifications
You must be signed in to change notification settings - Fork 291
/
storage.go
239 lines (199 loc) · 7.21 KB
/
storage.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
//
// (C) Copyright 2019-2023 Intel Corporation.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
package main
import (
"strings"
"github.com/pkg/errors"
"github.com/daos-stack/daos/src/control/cmd/dmg/pretty"
"github.com/daos-stack/daos/src/control/common/cmdutil"
"github.com/daos-stack/daos/src/control/lib/control"
)
// storageCmd is the struct representing the top-level storage subcommand.
type storageCmd struct {
Scan storageScanCmd `command:"scan" description:"Scan SCM and NVMe storage attached to remote servers."`
Format storageFormatCmd `command:"format" description:"Format SCM and NVMe storage attached to remote servers."`
Query storageQueryCmd `command:"query" description:"Query storage commands, including raw NVMe SSD device health stats and internal blobstore health info."`
NvmeRebind nvmeRebindCmd `command:"nvme-rebind" description:"Detach NVMe SSD from kernel driver and rebind to userspace driver for use with DAOS."`
NvmeAddDevice nvmeAddDeviceCmd `command:"nvme-add-device" description:"Add a hot-inserted NVMe SSD to a specific engine configuration to enable the new device to be used."`
Set setFaultyCmd `command:"set" description:"Manually set the device state."`
Replace storageReplaceCmd `command:"replace" description:"Replace a storage device that has been hot-removed with a new device."`
LedManage ledManageCmd `command:"led" description:"Manage LED status for supported drives."`
}
// storageScanCmd is the struct representing the scan storage subcommand.
type storageScanCmd struct {
baseCmd
ctlInvokerCmd
hostListCmd
cmdutil.JSONOutputCmd
Verbose bool `short:"v" long:"verbose" description:"List SCM & NVMe device details"`
NvmeHealth bool `short:"n" long:"nvme-health" description:"Display NVMe device health statistics"`
}
// Execute is run when storageScanCmd activates.
//
// Runs NVMe and SCM storage scan on all connected servers.
func (cmd *storageScanCmd) Execute(_ []string) error {
if cmd.Verbose && cmd.NvmeHealth {
return errors.New("cannot use --verbose with --nvme-health")
}
req := &control.StorageScanReq{
NvmeHealth: cmd.NvmeHealth,
// Strip nvme details if verbose and health flags are unset.
NvmeBasic: !(cmd.Verbose || cmd.NvmeHealth),
}
req.SetHostList(cmd.getHostList())
cmd.Debugf("storage scan request: %+v", req)
resp, err := control.StorageScan(cmd.MustLogCtx(), cmd.ctlInvoker, req)
if err != nil {
return err
}
cmd.Debugf("storage scan response: %+v", resp.HostStorage)
if cmd.JSONOutputEnabled() {
return cmd.OutputJSON(resp, resp.Errors())
}
var outErr strings.Builder
if err := pretty.PrintResponseErrors(resp, &outErr); err != nil {
return err
}
if outErr.Len() > 0 {
cmd.Error(outErr.String())
}
var out strings.Builder
if cmd.NvmeHealth {
if err := pretty.PrintNvmeHealthMap(resp.HostStorage, &out); err != nil {
return err
}
} else {
verbose := pretty.PrintWithVerboseOutput(cmd.Verbose)
if err := pretty.PrintHostStorageMap(resp.HostStorage, &out, verbose); err != nil {
return err
}
}
cmd.Info(out.String())
return resp.Errors()
}
// storageFormatCmd is the struct representing the format storage subcommand.
type storageFormatCmd struct {
baseCmd
ctlInvokerCmd
hostListCmd
cmdutil.JSONOutputCmd
Verbose bool `short:"v" long:"verbose" description:"Show results of each SCM & NVMe device format operation"`
Force bool `long:"force" description:"Force storage format on a host, stopping any running engines (CAUTION: destructive operation)"`
}
// Execute is run when storageFormatCmd activates.
//
// Run NVMe and SCM storage format on all connected servers.
func (cmd *storageFormatCmd) Execute(args []string) (err error) {
ctx := cmd.MustLogCtx()
req := &control.StorageFormatReq{Reformat: cmd.Force}
req.SetHostList(cmd.getHostList())
resp, err := control.StorageFormat(ctx, cmd.ctlInvoker, req)
if err != nil {
return err
}
if cmd.JSONOutputEnabled() {
return cmd.OutputJSON(resp, resp.Errors())
}
return cmd.printFormatResp(resp)
}
func (cmd *storageFormatCmd) printFormatResp(resp *control.StorageFormatResp) error {
var outErr strings.Builder
if err := pretty.PrintResponseErrors(resp, &outErr); err != nil {
return err
}
if outErr.Len() > 0 {
cmd.Error(outErr.String())
}
var out strings.Builder
verbose := pretty.PrintWithVerboseOutput(cmd.Verbose)
if err := pretty.PrintStorageFormatMap(resp.HostStorage, &out, verbose); err != nil {
return err
}
cmd.Info(out.String())
return resp.Errors()
}
// nvmeRebindCmd is the struct representing the nvme-rebind storage subcommand.
type nvmeRebindCmd struct {
baseCmd
ctlInvokerCmd
hostListCmd
cmdutil.JSONOutputCmd
PCIAddr string `short:"a" long:"pci-address" required:"1" description:"NVMe SSD PCI address to rebind."`
}
// Execute is run when nvmeRebindCmd activates.
//
// Rebind NVMe SSD from kernel driver and bind to user-space driver on single server.
func (cmd *nvmeRebindCmd) Execute(args []string) error {
ctx := cmd.MustLogCtx()
if len(cmd.getHostList()) != 1 {
return errors.New("command expects a single host in hostlist")
}
req := &control.NvmeRebindReq{PCIAddr: cmd.PCIAddr}
req.SetHostList(cmd.getHostList())
resp, err := control.StorageNvmeRebind(ctx, cmd.ctlInvoker, req)
if err != nil {
return err
}
if cmd.JSONOutputEnabled() {
return cmd.OutputJSON(resp, resp.Errors())
}
var outErr strings.Builder
if err := pretty.PrintResponseErrors(resp, &outErr); err != nil {
return err
}
if outErr.Len() > 0 {
cmd.Error(outErr.String())
} else {
cmd.Info("Command completed successfully")
}
return resp.Errors()
}
// nvmeAddDeviceCmd is the struct representing the nvme-add-device storage subcommand.
//
// StorageTierIndex is by default set -1 to signal the server to add the device to the first
// configured bdev tier.
type nvmeAddDeviceCmd struct {
baseCmd
ctlInvokerCmd
hostListCmd
cmdutil.JSONOutputCmd
PCIAddr string `short:"a" long:"pci-address" required:"1" description:"NVMe SSD PCI address to add."`
EngineIndex uint32 `short:"e" long:"engine-index" required:"1" description:"Index of DAOS engine to add NVMe device to."`
StorageTierIndex int32 `short:"t" long:"tier-index" default:"-1" description:"Index of storage tier on DAOS engine to add NVMe device to."`
}
// Execute is run when nvmeAddDeviceCmd activates.
//
// Add recently inserted NVMe SSD to a running engine by updating relevant NVMe config file.
func (cmd *nvmeAddDeviceCmd) Execute(args []string) error {
ctx := cmd.MustLogCtx()
if len(cmd.getHostList()) != 1 {
return errors.New("command expects a single host in hostlist")
}
req := &control.NvmeAddDeviceReq{
PCIAddr: cmd.PCIAddr,
EngineIndex: cmd.EngineIndex,
StorageTierIndex: cmd.StorageTierIndex,
}
req.SetHostList(cmd.getHostList())
cmd.Debugf("nvme add device req: %+v", req)
resp, err := control.StorageNvmeAddDevice(ctx, cmd.ctlInvoker, req)
if err != nil {
return err
}
if cmd.JSONOutputEnabled() {
return cmd.OutputJSON(resp, resp.Errors())
}
var outErr strings.Builder
if err := pretty.PrintResponseErrors(resp, &outErr); err != nil {
return err
}
if outErr.Len() > 0 {
cmd.Error(outErr.String())
} else {
cmd.Info("Command completed successfully")
}
return resp.Errors()
}