]>
Commit | Line | Data |
---|---|---|
707974fd DM |
1 | use anyhow::{bail, Error}; |
2 | use serde_json::{json, Value}; | |
553cd12b | 3 | |
553cd12b | 4 | use proxmox::{sortable, identity}; |
6ef1b649 WB |
5 | use proxmox_router::{ |
6 | list_subdirs_api_method, Router, RpcEnvironment, RpcEnvironmentType, SubdirMap, Permission, | |
7 | }; | |
8 | use proxmox_schema::api; | |
553cd12b | 9 | |
8cc3760e | 10 | use pbs_api_types::{ |
049a22a3 | 11 | UPID_SCHEMA, NODE_SCHEMA, BLOCKDEVICE_NAME_SCHEMA, |
8cc3760e DM |
12 | PRIV_SYS_AUDIT, PRIV_SYS_MODIFY, |
13 | }; | |
14 | ||
7fa27795 DM |
15 | use crate::tools::disks::{ |
16 | DiskUsageInfo, DiskUsageType, DiskManage, SmartData, | |
707974fd | 17 | get_disks, get_smart_data, get_disk_usage_info, inititialize_gpt_disk, |
7fa27795 | 18 | }; |
b9700a9f | 19 | use proxmox_rest_server::WorkerTask; |
1ec0d70d | 20 | use pbs_tools::task_log; |
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 DM |
37 | }, |
38 | "usage-type": { | |
39 | type: DiskUsageType, | |
40 | optional: true, | |
41 | }, | |
553cd12b DM |
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, | |
ff30caea | 58 | usage_type: Option<DiskUsageType>, |
553cd12b DM |
59 | ) -> Result<Vec<DiskUsageInfo>, Error> { |
60 | ||
61 | let mut list = Vec::new(); | |
62 | ||
63 | for (_, info) in get_disks(None, skipsmart)? { | |
ff30caea DM |
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 | } | |
553cd12b DM |
71 | } |
72 | ||
bbff317a FE |
73 | list.sort_by(|a, b| a.name.cmp(&b.name)); |
74 | ||
553cd12b DM |
75 | Ok(list) |
76 | } | |
77 | ||
7fa27795 DM |
78 | #[api( |
79 | protected: true, | |
80 | input: { | |
81 | properties: { | |
ce8e3de4 DM |
82 | node: { |
83 | schema: NODE_SCHEMA, | |
84 | }, | |
7fa27795 | 85 | disk: { |
9069debc | 86 | schema: BLOCKDEVICE_NAME_SCHEMA, |
7fa27795 DM |
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 | ||
707974fd DM |
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 | ||
39735609 | 147 | let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI; |
707974fd | 148 | |
049a22a3 | 149 | let auth_id = rpcenv.get_auth_id().unwrap(); |
707974fd DM |
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( | |
e6dc35ac | 158 | "diskinit", Some(disk.clone()), auth_id, to_stdout, move |worker| |
707974fd | 159 | { |
1ec0d70d | 160 | task_log!(worker, "initialize disk {}", disk); |
707974fd DM |
161 | |
162 | let disk_manager = DiskManage::new(); | |
2b388026 | 163 | let disk_info = disk_manager.disk_by_name(&disk)?; |
707974fd DM |
164 | |
165 | inititialize_gpt_disk(&disk_info, uuid.as_deref())?; | |
166 | ||
167 | Ok(()) | |
168 | })?; | |
169 | ||
170 | Ok(json!(upid_str)) | |
171 | } | |
172 | ||
553cd12b DM |
173 | #[sortable] |
174 | const SUBDIRS: SubdirMap = &sorted!([ | |
707974fd | 175 | // ("lvm", &lvm::ROUTER), |
fb5a0665 | 176 | ("directory", &directory::ROUTER), |
929a13b3 | 177 | ("zfs", &zfs::ROUTER), |
707974fd DM |
178 | ( |
179 | "initgpt", &Router::new() | |
180 | .post(&API_METHOD_INITIALIZE_DISK) | |
181 | ), | |
553cd12b DM |
182 | ( |
183 | "list", &Router::new() | |
184 | .get(&API_METHOD_LIST_DISKS) | |
185 | ), | |
7fa27795 DM |
186 | ( |
187 | "smart", &Router::new() | |
188 | .get(&API_METHOD_SMART_STATUS) | |
189 | ), | |
553cd12b DM |
190 | ]); |
191 | ||
192 | pub const ROUTER: Router = Router::new() | |
193 | .get(&list_subdirs_api_method!(SUBDIRS)) | |
194 | .subdirs(SUBDIRS); |