2022-04-12 05:25:57 +00:00
|
|
|
use anyhow::{bail, Error};
|
2022-04-12 05:25:56 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2022-04-14 12:03:46 +00:00
|
|
|
use std::borrow::Cow;
|
2022-04-12 05:25:56 +00:00
|
|
|
|
2022-04-14 12:03:46 +00:00
|
|
|
use proxmox_schema::{api, const_regex, ApiStringFormat, Schema, StringSchema};
|
2022-04-12 05:25:56 +00:00
|
|
|
|
2022-04-14 12:03:46 +00:00
|
|
|
const_regex! {
|
2022-04-12 05:25:56 +00:00
|
|
|
pub MAINTENANCE_MESSAGE_REGEX = r"^[[:^cntrl:]]*$";
|
|
|
|
}
|
|
|
|
|
|
|
|
pub const MAINTENANCE_MESSAGE_FORMAT: ApiStringFormat =
|
|
|
|
ApiStringFormat::Pattern(&MAINTENANCE_MESSAGE_REGEX);
|
|
|
|
|
|
|
|
pub const MAINTENANCE_MESSAGE_SCHEMA: Schema =
|
|
|
|
StringSchema::new("Message describing the reason for the maintenance.")
|
|
|
|
.format(&MAINTENANCE_MESSAGE_FORMAT)
|
|
|
|
.max_length(64)
|
|
|
|
.schema();
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
/// Operation requirements, used when checking for maintenance mode.
|
|
|
|
pub enum Operation {
|
|
|
|
Read,
|
|
|
|
Write,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[api]
|
2022-04-12 05:25:57 +00:00
|
|
|
#[derive(Deserialize, Serialize, PartialEq)]
|
2022-04-14 12:03:46 +00:00
|
|
|
#[serde(rename_all = "kebab-case")]
|
2022-04-12 05:25:56 +00:00
|
|
|
/// Maintenance type.
|
|
|
|
pub enum MaintenanceType {
|
|
|
|
/// Only read operations are allowed on the datastore.
|
|
|
|
ReadOnly,
|
|
|
|
/// Neither read nor write operations are allowed on the datastore.
|
|
|
|
Offline,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[api(
|
|
|
|
properties: {
|
|
|
|
type: {
|
|
|
|
type: MaintenanceType,
|
|
|
|
},
|
|
|
|
message: {
|
|
|
|
optional: true,
|
|
|
|
schema: MAINTENANCE_MESSAGE_SCHEMA,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
default_key: "type",
|
|
|
|
)]
|
|
|
|
#[derive(Deserialize, Serialize)]
|
|
|
|
/// Maintenance mode
|
|
|
|
pub struct MaintenanceMode {
|
|
|
|
/// Type of maintenance ("read-only" or "offline").
|
|
|
|
#[serde(rename = "type")]
|
|
|
|
ty: MaintenanceType,
|
|
|
|
|
|
|
|
/// Reason for maintenance.
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
message: Option<String>,
|
|
|
|
}
|
2022-04-12 05:25:57 +00:00
|
|
|
|
|
|
|
impl MaintenanceMode {
|
|
|
|
pub fn check(&self, operation: Option<Operation>) -> Result<(), Error> {
|
|
|
|
let message = percent_encoding::percent_decode_str(self.message.as_deref().unwrap_or(""))
|
|
|
|
.decode_utf8()
|
|
|
|
.unwrap_or(Cow::Borrowed(""));
|
|
|
|
|
|
|
|
if self.ty == MaintenanceType::Offline {
|
|
|
|
bail!("offline maintenance mode: {}", message);
|
|
|
|
} else if self.ty == MaintenanceType::ReadOnly {
|
|
|
|
if let Some(Operation::Write) = operation {
|
|
|
|
bail!("read-only maintenance mode: {}", message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|