1 use anyhow
::{bail, Error}
;
4 use proxmox
::api
::{api, cli::*, RpcEnvironment, ApiHandler}
;
6 use proxmox_backup
::tools
::disks
::{
12 use proxmox_backup
::api2
::node
::disks
::{
13 zfs
::DISK_LIST_SCHEMA
,
14 zfs
::ZFS_ASHIFT_SCHEMA
,
16 zfs
::ZfsCompressionType
,
19 use proxmox_backup
::api2
::{self, types::* }
;
25 schema
: OUTPUT_FORMAT
,
32 fn list_disks(mut param
: Value
, rpcenv
: &mut dyn RpcEnvironment
) -> Result
<Value
, Error
> {
34 let output_format
= get_output_format(¶m
);
36 param
["node"] = "localhost".into();
38 let info
= &api2
::node
::disks
::API_METHOD_LIST_DISKS
;
39 let mut data
= match info
.handler
{
40 ApiHandler
::Sync(handler
) => (handler
)(param
, info
, rpcenv
)?
,
44 let render_wearout
= |value
: &Value
, _record
: &Value
| -> Result
<String
, Error
> {
45 match value
.as_f64() {
46 Some(value
) => Ok(format
!("{:.2} %", if value
<= 100.0 { 100.0 - value }
else { 0.0 }
)),
47 None
=> Ok(String
::from("-")),
51 let options
= default_table_format_options()
52 .column(ColumnConfig
::new("name"))
53 .column(ColumnConfig
::new("used"))
54 .column(ColumnConfig
::new("gpt"))
55 .column(ColumnConfig
::new("disk-type"))
56 .column(ColumnConfig
::new("size"))
57 .column(ColumnConfig
::new("model"))
58 .column(ColumnConfig
::new("wearout").renderer(render_wearout
))
59 .column(ColumnConfig
::new("status"))
62 format_and_print_result_full(&mut data
, info
.returns
, &output_format
, &options
);
71 schema
: BLOCKDEVICE_NAME_SCHEMA
,
74 schema
: OUTPUT_FORMAT
,
80 description
: "SMART attributes.",
87 /// Show SMART attributes.
88 fn smart_attributes(mut param
: Value
, rpcenv
: &mut dyn RpcEnvironment
) -> Result
<Value
, Error
> {
90 let output_format
= get_output_format(¶m
);
92 param
["node"] = "localhost".into();
94 let info
= &api2
::node
::disks
::API_METHOD_SMART_STATUS
;
95 let mut data
= match info
.handler
{
96 ApiHandler
::Sync(handler
) => (handler
)(param
, info
, rpcenv
)?
,
100 let mut data
= data
["attributes"].take();
102 let options
= default_table_format_options();
103 format_and_print_result_full(&mut data
, API_METHOD_SMART_ATTRIBUTES
.returns
, &output_format
, &options
);
112 schema
: BLOCKDEVICE_NAME_SCHEMA
,
115 description
: "UUID for the GPT table.",
123 /// Initialize empty Disk with GPT
124 async
fn initialize_disk(
126 rpcenv
: &mut dyn RpcEnvironment
,
127 ) -> Result
<Value
, Error
> {
129 param
["node"] = "localhost".into();
131 let info
= &api2
::node
::disks
::API_METHOD_INITIALIZE_DISK
;
132 let result
= match info
.handler
{
133 ApiHandler
::Sync(handler
) => (handler
)(param
, info
, rpcenv
)?
,
137 crate::wait_for_local_worker(result
.as_str().unwrap()).await?
;
146 schema
: DATASTORE_SCHEMA
,
149 schema
: DISK_LIST_SCHEMA
,
155 schema
: ZFS_ASHIFT_SCHEMA
,
159 type: ZfsCompressionType
,
163 description
: "Configure a datastore using the zpool.",
170 /// create a zfs pool
171 async
fn create_zpool(
173 rpcenv
: &mut dyn RpcEnvironment
,
174 ) -> Result
<Value
, Error
> {
176 param
["node"] = "localhost".into();
178 let info
= &api2
::node
::disks
::zfs
::API_METHOD_CREATE_ZPOOL
;
179 let result
= match info
.handler
{
180 ApiHandler
::Sync(handler
) => (handler
)(param
, info
, rpcenv
)?
,
184 crate::wait_for_local_worker(result
.as_str().unwrap()).await?
;
193 schema
: OUTPUT_FORMAT
,
200 fn list_zpools(mut param
: Value
, rpcenv
: &mut dyn RpcEnvironment
) -> Result
<Value
, Error
> {
202 let output_format
= get_output_format(¶m
);
204 param
["node"] = "localhost".into();
206 let info
= &api2
::node
::disks
::zfs
::API_METHOD_LIST_ZPOOLS
;
207 let mut data
= match info
.handler
{
208 ApiHandler
::Sync(handler
) => (handler
)(param
, info
, rpcenv
)?
,
212 let render_usage
= |value
: &Value
, record
: &Value
| -> Result
<String
, Error
> {
213 let value
= value
.as_u64().unwrap_or(0);
214 let size
= match record
["size"].as_u64() {
216 None
=> bail
!("missing size property"),
219 bail
!("got zero size");
221 Ok(format
!("{:.2} %", (value
as f64)/(size
as f64)))
224 let options
= default_table_format_options()
225 .column(ColumnConfig
::new("name"))
226 .column(ColumnConfig
::new("size"))
227 .column(ColumnConfig
::new("alloc").right_align(true).renderer(render_usage
))
228 .column(ColumnConfig
::new("health"));
230 format_and_print_result_full(&mut data
, info
.returns
, &output_format
, &options
);
235 pub fn zpool_commands() -> CommandLineInterface
{
237 let cmd_def
= CliCommandMap
::new()
238 .insert("list", CliCommand
::new(&API_METHOD_LIST_ZPOOLS
))
240 CliCommand
::new(&API_METHOD_CREATE_ZPOOL
)
241 .arg_param(&["name"])
242 .completion_cb("devices", complete_disk_name
) // fixme: complete the list
252 schema
: OUTPUT_FORMAT
,
258 /// List systemd datastore mount units.
259 fn list_datastore_mounts(mut param
: Value
, rpcenv
: &mut dyn RpcEnvironment
) -> Result
<Value
, Error
> {
261 let output_format
= get_output_format(¶m
);
263 param
["node"] = "localhost".into();
265 let info
= &api2
::node
::disks
::directory
::API_METHOD_LIST_DATASTORE_MOUNTS
;
266 let mut data
= match info
.handler
{
267 ApiHandler
::Sync(handler
) => (handler
)(param
, info
, rpcenv
)?
,
271 let options
= default_table_format_options()
272 .column(ColumnConfig
::new("path"))
273 .column(ColumnConfig
::new("device"))
274 .column(ColumnConfig
::new("filesystem"))
275 .column(ColumnConfig
::new("options"));
277 format_and_print_result_full(&mut data
, info
.returns
, &output_format
, &options
);
286 schema
: DATASTORE_SCHEMA
,
289 schema
: BLOCKDEVICE_NAME_SCHEMA
,
292 description
: "Configure a datastore using the directory.",
297 type: FileSystemType
,
303 /// Create a Filesystem on an unused disk. Will be mounted under '/mnt/datastore/<name>'.
304 async
fn create_datastore_disk(
306 rpcenv
: &mut dyn RpcEnvironment
,
307 ) -> Result
<Value
, Error
> {
309 param
["node"] = "localhost".into();
311 let info
= &api2
::node
::disks
::directory
::API_METHOD_CREATE_DATASTORE_DISK
;
312 let result
= match info
.handler
{
313 ApiHandler
::Sync(handler
) => (handler
)(param
, info
, rpcenv
)?
,
317 crate::wait_for_local_worker(result
.as_str().unwrap()).await?
;
322 pub fn filesystem_commands() -> CommandLineInterface
{
324 let cmd_def
= CliCommandMap
::new()
325 .insert("list", CliCommand
::new(&API_METHOD_LIST_DATASTORE_MOUNTS
))
327 CliCommand
::new(&API_METHOD_CREATE_DATASTORE_DISK
)
328 .arg_param(&["name"])
329 .completion_cb("disk", complete_disk_name
)
335 pub fn disk_commands() -> CommandLineInterface
{
337 let cmd_def
= CliCommandMap
::new()
338 .insert("list", CliCommand
::new(&API_METHOD_LIST_DISKS
))
339 .insert("smart-attributes",
340 CliCommand
::new(&API_METHOD_SMART_ATTRIBUTES
)
341 .arg_param(&["disk"])
342 .completion_cb("disk", complete_disk_name
)
344 .insert("fs", filesystem_commands())
345 .insert("zpool", zpool_commands())
346 .insert("initialize",
347 CliCommand
::new(&API_METHOD_INITIALIZE_DISK
)
348 .arg_param(&["disk"])
349 .completion_cb("disk", complete_disk_name
)