]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/node/disks/mod.rs
auth: add locking to `PbsAuthenticator` to avoid race conditions
[proxmox-backup.git] / src / api2 / node / disks / mod.rs
CommitLineData
707974fd
DM
1use anyhow::{bail, Error};
2use serde_json::{json, Value};
553cd12b 3
6ef1b649 4use proxmox_router::{
a1c906cb 5 list_subdirs_api_method, Permission, Router, RpcEnvironment, RpcEnvironmentType, SubdirMap,
6ef1b649
WB
6};
7use proxmox_schema::api;
26f03f9e
WB
8use proxmox_sortable_macro::sortable;
9use proxmox_sys::task_log;
553cd12b 10
8cc3760e 11use 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 16use crate::tools::disks::{
e87deca2
MF
17 get_smart_data, inititialize_gpt_disk, wipe_blockdev, DiskManage, DiskUsageInfo,
18 DiskUsageQuery, DiskUsageType, SmartData,
7fa27795 19};
b9700a9f 20use proxmox_rest_server::WorkerTask;
553cd12b 21
d4f2397d 22pub mod directory;
929a13b3 23pub 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
62pub 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 113pub 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
147pub 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
202pub 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]
228const 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
238pub const ROUTER: Router = Router::new()
239 .get(&list_subdirs_api_method!(SUBDIRS))
240 .subdirs(SUBDIRS);