]> git.proxmox.com Git - proxmox-backup.git/blob - src/api2/node/disks/mod.rs
use new proxmox-sys crate
[proxmox-backup.git] / src / api2 / node / disks / mod.rs
1 use anyhow::{bail, Error};
2 use serde_json::{json, Value};
3
4 use proxmox::{sortable, identity};
5 use proxmox_router::{
6 list_subdirs_api_method, Router, RpcEnvironment, RpcEnvironmentType, SubdirMap, Permission,
7 };
8 use proxmox_schema::api;
9 use proxmox_sys::task_log;
10
11 use pbs_api_types::{
12 UPID_SCHEMA, NODE_SCHEMA, BLOCKDEVICE_NAME_SCHEMA,
13 PRIV_SYS_AUDIT, PRIV_SYS_MODIFY,
14 };
15
16 use crate::tools::disks::{
17 DiskUsageInfo, DiskUsageType, DiskManage, SmartData,
18 get_disks, get_smart_data, get_disk_usage_info, inititialize_gpt_disk,
19 };
20 use proxmox_rest_server::WorkerTask;
21
22 pub mod directory;
23 pub mod zfs;
24
25 #[api(
26 protected: true,
27 input: {
28 properties: {
29 node: {
30 schema: NODE_SCHEMA,
31 },
32 skipsmart: {
33 description: "Skip smart checks.",
34 type: bool,
35 optional: true,
36 default: false,
37 },
38 "usage-type": {
39 type: DiskUsageType,
40 optional: true,
41 },
42 },
43 },
44 returns: {
45 description: "Local disk list.",
46 type: Array,
47 items: {
48 type: DiskUsageInfo,
49 },
50 },
51 access: {
52 permission: &Permission::Privilege(&["system", "disks"], PRIV_SYS_AUDIT, false),
53 },
54 )]
55 /// List local disks
56 pub fn list_disks(
57 skipsmart: bool,
58 usage_type: Option<DiskUsageType>,
59 ) -> Result<Vec<DiskUsageInfo>, Error> {
60
61 let mut list = Vec::new();
62
63 for (_, info) in get_disks(None, skipsmart)? {
64 if let Some(ref usage_type) = usage_type {
65 if info.used == *usage_type {
66 list.push(info);
67 }
68 } else {
69 list.push(info);
70 }
71 }
72
73 list.sort_by(|a, b| a.name.cmp(&b.name));
74
75 Ok(list)
76 }
77
78 #[api(
79 protected: true,
80 input: {
81 properties: {
82 node: {
83 schema: NODE_SCHEMA,
84 },
85 disk: {
86 schema: BLOCKDEVICE_NAME_SCHEMA,
87 },
88 healthonly: {
89 description: "If true returns only the health status.",
90 type: bool,
91 optional: true,
92 },
93 },
94 },
95 returns: {
96 type: SmartData,
97 },
98 access: {
99 permission: &Permission::Privilege(&["system", "disks"], PRIV_SYS_AUDIT, false),
100 },
101 )]
102 /// Get SMART attributes and health of a disk.
103 pub fn smart_status(
104 disk: String,
105 healthonly: Option<bool>,
106 ) -> Result<SmartData, Error> {
107
108 let healthonly = healthonly.unwrap_or(false);
109
110 let manager = DiskManage::new();
111 let disk = manager.disk_by_name(&disk)?;
112 get_smart_data(&disk, healthonly)
113 }
114
115 #[api(
116 protected: true,
117 input: {
118 properties: {
119 node: {
120 schema: NODE_SCHEMA,
121 },
122 disk: {
123 schema: BLOCKDEVICE_NAME_SCHEMA,
124 },
125 uuid: {
126 description: "UUID for the GPT table.",
127 type: String,
128 optional: true,
129 max_length: 36,
130 },
131 },
132 },
133 returns: {
134 schema: UPID_SCHEMA,
135 },
136 access: {
137 permission: &Permission::Privilege(&["system", "disks"], PRIV_SYS_MODIFY, false),
138 },
139 )]
140 /// Initialize empty Disk with GPT
141 pub fn initialize_disk(
142 disk: String,
143 uuid: Option<String>,
144 rpcenv: &mut dyn RpcEnvironment,
145 ) -> Result<Value, Error> {
146
147 let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
148
149 let auth_id = rpcenv.get_auth_id().unwrap();
150
151 let info = get_disk_usage_info(&disk, true)?;
152
153 if info.used != DiskUsageType::Unused {
154 bail!("disk '{}' is already in use.", disk);
155 }
156
157 let upid_str = WorkerTask::new_thread(
158 "diskinit", Some(disk.clone()), auth_id, to_stdout, move |worker|
159 {
160 task_log!(worker, "initialize disk {}", disk);
161
162 let disk_manager = DiskManage::new();
163 let disk_info = disk_manager.disk_by_name(&disk)?;
164
165 inititialize_gpt_disk(&disk_info, uuid.as_deref())?;
166
167 Ok(())
168 })?;
169
170 Ok(json!(upid_str))
171 }
172
173 #[sortable]
174 const SUBDIRS: SubdirMap = &sorted!([
175 // ("lvm", &lvm::ROUTER),
176 ("directory", &directory::ROUTER),
177 ("zfs", &zfs::ROUTER),
178 (
179 "initgpt", &Router::new()
180 .post(&API_METHOD_INITIALIZE_DISK)
181 ),
182 (
183 "list", &Router::new()
184 .get(&API_METHOD_LIST_DISKS)
185 ),
186 (
187 "smart", &Router::new()
188 .get(&API_METHOD_SMART_STATUS)
189 ),
190 ]);
191
192 pub const ROUTER: Router = Router::new()
193 .get(&list_subdirs_api_method!(SUBDIRS))
194 .subdirs(SUBDIRS);