]>
Commit | Line | Data |
---|---|---|
707974fd DM |
1 | use anyhow::{bail, Error}; |
2 | use serde_json::{json, Value}; | |
553cd12b | 3 | |
6ef1b649 | 4 | use proxmox_router::{ |
a1c906cb | 5 | list_subdirs_api_method, Permission, Router, RpcEnvironment, RpcEnvironmentType, SubdirMap, |
6ef1b649 WB |
6 | }; |
7 | use proxmox_schema::api; | |
26f03f9e WB |
8 | use proxmox_sortable_macro::sortable; |
9 | use proxmox_sys::task_log; | |
553cd12b | 10 | |
8cc3760e | 11 | use pbs_api_types::{ |
e87deca2 MF |
12 | BLOCKDEVICE_DISK_AND_PARTITION_NAME_SCHEMA, BLOCKDEVICE_NAME_SCHEMA, NODE_SCHEMA, |
13 | PRIV_SYS_AUDIT, PRIV_SYS_MODIFY, UPID_SCHEMA, | |
8cc3760e DM |
14 | }; |
15 | ||
7fa27795 | 16 | use crate::tools::disks::{ |
e87deca2 MF |
17 | get_smart_data, inititialize_gpt_disk, wipe_blockdev, DiskManage, DiskUsageInfo, |
18 | DiskUsageQuery, DiskUsageType, SmartData, | |
7fa27795 | 19 | }; |
b9700a9f | 20 | use proxmox_rest_server::WorkerTask; |
553cd12b | 21 | |
d4f2397d | 22 | pub mod directory; |
929a13b3 | 23 | pub mod zfs; |
d4f2397d | 24 | |
553cd12b | 25 | #[api( |
7fa27795 | 26 | protected: true, |
553cd12b DM |
27 | input: { |
28 | properties: { | |
ce8e3de4 DM |
29 | node: { |
30 | schema: NODE_SCHEMA, | |
31 | }, | |
553cd12b | 32 | skipsmart: { |
08cb2038 TL |
33 | description: "Skip smart checks.", |
34 | type: bool, | |
35 | optional: true, | |
36 | default: false, | |
ff30caea | 37 | }, |
6a6ba4cd HL |
38 | "include-partitions": { |
39 | description: "Include partitions.", | |
40 | type: bool, | |
41 | optional: true, | |
42 | default: false, | |
43 | }, | |
ff30caea DM |
44 | "usage-type": { |
45 | type: DiskUsageType, | |
46 | optional: true, | |
47 | }, | |
553cd12b DM |
48 | }, |
49 | }, | |
50 | returns: { | |
51 | description: "Local disk list.", | |
52 | type: Array, | |
53 | items: { | |
54 | type: DiskUsageInfo, | |
55 | }, | |
56 | }, | |
57 | access: { | |
58 | permission: &Permission::Privilege(&["system", "disks"], PRIV_SYS_AUDIT, false), | |
59 | }, | |
60 | )] | |
61 | /// List local disks | |
62 | pub fn list_disks( | |
63 | skipsmart: bool, | |
6a6ba4cd | 64 | include_partitions: bool, |
ff30caea | 65 | usage_type: Option<DiskUsageType>, |
553cd12b | 66 | ) -> Result<Vec<DiskUsageInfo>, Error> { |
553cd12b DM |
67 | let mut list = Vec::new(); |
68 | ||
be260410 HL |
69 | for (_, info) in DiskUsageQuery::new() |
70 | .smart(!skipsmart) | |
71 | .partitions(include_partitions) | |
72 | .query()? | |
73 | { | |
ff30caea DM |
74 | if let Some(ref usage_type) = usage_type { |
75 | if info.used == *usage_type { | |
76 | list.push(info); | |
77 | } | |
78 | } else { | |
79 | list.push(info); | |
80 | } | |
553cd12b DM |
81 | } |
82 | ||
bbff317a FE |
83 | list.sort_by(|a, b| a.name.cmp(&b.name)); |
84 | ||
553cd12b DM |
85 | Ok(list) |
86 | } | |
87 | ||
7fa27795 DM |
88 | #[api( |
89 | protected: true, | |
90 | input: { | |
91 | properties: { | |
ce8e3de4 DM |
92 | node: { |
93 | schema: NODE_SCHEMA, | |
94 | }, | |
7fa27795 | 95 | disk: { |
9069debc | 96 | schema: BLOCKDEVICE_NAME_SCHEMA, |
7fa27795 DM |
97 | }, |
98 | healthonly: { | |
99 | description: "If true returns only the health status.", | |
100 | type: bool, | |
101 | optional: true, | |
102 | }, | |
103 | }, | |
104 | }, | |
105 | returns: { | |
106 | type: SmartData, | |
107 | }, | |
108 | access: { | |
109 | permission: &Permission::Privilege(&["system", "disks"], PRIV_SYS_AUDIT, false), | |
110 | }, | |
111 | )] | |
112 | /// Get SMART attributes and health of a disk. | |
a1c906cb | 113 | pub fn smart_status(disk: String, healthonly: Option<bool>) -> Result<SmartData, Error> { |
7fa27795 DM |
114 | let healthonly = healthonly.unwrap_or(false); |
115 | ||
116 | let manager = DiskManage::new(); | |
117 | let disk = manager.disk_by_name(&disk)?; | |
118 | get_smart_data(&disk, healthonly) | |
119 | } | |
120 | ||
707974fd DM |
121 | #[api( |
122 | protected: true, | |
123 | input: { | |
124 | properties: { | |
125 | node: { | |
126 | schema: NODE_SCHEMA, | |
127 | }, | |
128 | disk: { | |
129 | schema: BLOCKDEVICE_NAME_SCHEMA, | |
130 | }, | |
131 | uuid: { | |
132 | description: "UUID for the GPT table.", | |
133 | type: String, | |
134 | optional: true, | |
135 | max_length: 36, | |
136 | }, | |
137 | }, | |
138 | }, | |
139 | returns: { | |
140 | schema: UPID_SCHEMA, | |
141 | }, | |
142 | access: { | |
143 | permission: &Permission::Privilege(&["system", "disks"], PRIV_SYS_MODIFY, false), | |
144 | }, | |
145 | )] | |
146 | /// Initialize empty Disk with GPT | |
147 | pub fn initialize_disk( | |
148 | disk: String, | |
149 | uuid: Option<String>, | |
150 | rpcenv: &mut dyn RpcEnvironment, | |
151 | ) -> Result<Value, Error> { | |
39735609 | 152 | let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI; |
707974fd | 153 | |
049a22a3 | 154 | let auth_id = rpcenv.get_auth_id().unwrap(); |
707974fd | 155 | |
be260410 | 156 | let info = DiskUsageQuery::new().find(&disk)?; |
707974fd DM |
157 | |
158 | if info.used != DiskUsageType::Unused { | |
159 | bail!("disk '{}' is already in use.", disk); | |
160 | } | |
161 | ||
162 | let upid_str = WorkerTask::new_thread( | |
a1c906cb TL |
163 | "diskinit", |
164 | Some(disk.clone()), | |
165 | auth_id, | |
166 | to_stdout, | |
167 | move |worker| { | |
1ec0d70d | 168 | task_log!(worker, "initialize disk {}", disk); |
707974fd DM |
169 | |
170 | let disk_manager = DiskManage::new(); | |
2b388026 | 171 | let disk_info = disk_manager.disk_by_name(&disk)?; |
707974fd DM |
172 | |
173 | inititialize_gpt_disk(&disk_info, uuid.as_deref())?; | |
174 | ||
175 | Ok(()) | |
a1c906cb TL |
176 | }, |
177 | )?; | |
707974fd DM |
178 | |
179 | Ok(json!(upid_str)) | |
180 | } | |
181 | ||
e87deca2 MF |
182 | #[api( |
183 | protected: true, | |
184 | input: { | |
185 | properties: { | |
186 | node: { | |
187 | schema: NODE_SCHEMA, | |
188 | }, | |
189 | disk: { | |
190 | schema: BLOCKDEVICE_DISK_AND_PARTITION_NAME_SCHEMA, | |
191 | }, | |
192 | }, | |
193 | }, | |
194 | returns: { | |
195 | schema: UPID_SCHEMA, | |
196 | }, | |
197 | access: { | |
198 | permission: &Permission::Privilege(&["system", "disks"], PRIV_SYS_MODIFY, false), | |
199 | }, | |
200 | )] | |
201 | /// wipe disk | |
202 | pub fn wipe_disk(disk: String, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Error> { | |
203 | let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI; | |
204 | ||
205 | let auth_id = rpcenv.get_auth_id().unwrap(); | |
206 | ||
207 | let upid_str = WorkerTask::new_thread( | |
208 | "wipedisk", | |
209 | Some(disk.clone()), | |
210 | auth_id, | |
211 | to_stdout, | |
212 | move |worker| { | |
213 | task_log!(worker, "wipe disk {}", disk); | |
214 | ||
215 | let disk_manager = DiskManage::new(); | |
216 | let disk_info = disk_manager.partition_by_name(&disk)?; | |
217 | ||
218 | wipe_blockdev(&disk_info, worker)?; | |
219 | ||
220 | Ok(()) | |
221 | }, | |
222 | )?; | |
223 | ||
224 | Ok(json!(upid_str)) | |
225 | } | |
226 | ||
553cd12b DM |
227 | #[sortable] |
228 | const SUBDIRS: SubdirMap = &sorted!([ | |
707974fd | 229 | // ("lvm", &lvm::ROUTER), |
fb5a0665 | 230 | ("directory", &directory::ROUTER), |
929a13b3 | 231 | ("zfs", &zfs::ROUTER), |
a1c906cb TL |
232 | ("initgpt", &Router::new().post(&API_METHOD_INITIALIZE_DISK)), |
233 | ("list", &Router::new().get(&API_METHOD_LIST_DISKS)), | |
234 | ("smart", &Router::new().get(&API_METHOD_SMART_STATUS)), | |
e87deca2 | 235 | ("wipedisk", &Router::new().put(&API_METHOD_WIPE_DISK)), |
553cd12b DM |
236 | ]); |
237 | ||
238 | pub const ROUTER: Router = Router::new() | |
239 | .get(&list_subdirs_api_method!(SUBDIRS)) | |
240 | .subdirs(SUBDIRS); |