]> git.proxmox.com Git - proxmox-backup.git/blob - pbs-api-types/src/maintenance.rs
datastore: add check for maintenance in lookup
[proxmox-backup.git] / pbs-api-types / src / maintenance.rs
1 use std::borrow::Cow;
2 use anyhow::{bail, Error};
3 use serde::{Deserialize, Serialize};
4
5 use proxmox_schema::{api, ApiStringFormat, const_regex, Schema, StringSchema};
6
7 const_regex!{
8 pub MAINTENANCE_MESSAGE_REGEX = r"^[[:^cntrl:]]*$";
9 }
10
11 pub const MAINTENANCE_MESSAGE_FORMAT: ApiStringFormat =
12 ApiStringFormat::Pattern(&MAINTENANCE_MESSAGE_REGEX);
13
14
15 pub const MAINTENANCE_MESSAGE_SCHEMA: Schema =
16 StringSchema::new("Message describing the reason for the maintenance.")
17 .format(&MAINTENANCE_MESSAGE_FORMAT)
18 .max_length(64)
19 .schema();
20
21 #[derive(Clone, Copy, Debug)]
22 /// Operation requirements, used when checking for maintenance mode.
23 pub enum Operation {
24 Read,
25 Write,
26 }
27
28 #[api]
29 #[derive(Deserialize, Serialize, PartialEq)]
30 #[serde(rename_all="kebab-case")]
31 /// Maintenance type.
32 pub enum MaintenanceType {
33 /// Only read operations are allowed on the datastore.
34 ReadOnly,
35 /// Neither read nor write operations are allowed on the datastore.
36 Offline,
37 }
38
39 #[api(
40 properties: {
41 type: {
42 type: MaintenanceType,
43 },
44 message: {
45 optional: true,
46 schema: MAINTENANCE_MESSAGE_SCHEMA,
47 }
48 },
49 default_key: "type",
50 )]
51 #[derive(Deserialize, Serialize)]
52 /// Maintenance mode
53 pub struct MaintenanceMode {
54 /// Type of maintenance ("read-only" or "offline").
55 #[serde(rename = "type")]
56 ty: MaintenanceType,
57
58 /// Reason for maintenance.
59 #[serde(skip_serializing_if = "Option::is_none")]
60 message: Option<String>,
61 }
62
63 impl MaintenanceMode {
64 pub fn check(&self, operation: Option<Operation>) -> Result<(), Error> {
65 let message = percent_encoding::percent_decode_str(self.message.as_deref().unwrap_or(""))
66 .decode_utf8()
67 .unwrap_or(Cow::Borrowed(""));
68
69 if self.ty == MaintenanceType::Offline {
70 bail!("offline maintenance mode: {}", message);
71 } else if self.ty == MaintenanceType::ReadOnly {
72 if let Some(Operation::Write) = operation {
73 bail!("read-only maintenance mode: {}", message);
74 }
75 }
76 Ok(())
77 }
78 }