use UPID and systemd helpers from proxmox 0.13.4
This commit is contained in:
parent
0a33fba49c
commit
81867f0539
|
@ -94,7 +94,7 @@ zstd = { version = "0.6", features = [ "bindgen" ] }
|
||||||
pathpatterns = "0.1.2"
|
pathpatterns = "0.1.2"
|
||||||
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
||||||
|
|
||||||
proxmox = { version = "0.13.3", features = [ "sortable-macro", "api-macro", "cli", "router", "tfa" ] }
|
proxmox = { version = "0.13.4", features = [ "sortable-macro", "api-macro", "cli", "router", "tfa" ] }
|
||||||
proxmox-acme-rs = "0.2.1"
|
proxmox-acme-rs = "0.2.1"
|
||||||
proxmox-apt = "0.7.0"
|
proxmox-apt = "0.7.0"
|
||||||
proxmox-http = { version = "0.4.0", features = [ "client", "http-helpers", "websocket" ] }
|
proxmox-http = { version = "0.4.0", features = [ "client", "http-helpers", "websocket" ] }
|
||||||
|
|
|
@ -14,7 +14,7 @@ openssl = "0.10"
|
||||||
regex = "1.2"
|
regex = "1.2"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
||||||
proxmox = { version = "0.13.3", default-features = false, features = [ "api-macro" ] }
|
proxmox = { version = "0.13.4", default-features = false, features = [ "api-macro" ] }
|
||||||
|
|
||||||
proxmox-systemd = { path = "../proxmox-systemd" }
|
proxmox-systemd = { path = "../proxmox-systemd" }
|
||||||
pbs-tools = { path = "../pbs-tools" }
|
pbs-tools = { path = "../pbs-tools" }
|
||||||
|
|
|
@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
|
|
||||||
use proxmox::api::api;
|
use proxmox::api::api;
|
||||||
use proxmox::api::schema::{ApiStringFormat, ArraySchema, Schema, StringSchema};
|
use proxmox::api::schema::{ApiStringFormat, ApiType, ArraySchema, Schema, StringSchema, ReturnType};
|
||||||
use proxmox::const_regex;
|
use proxmox::const_regex;
|
||||||
use proxmox::{IPRE, IPRE_BRACKET, IPV4OCTET, IPV4RE, IPV6H16, IPV6LS32, IPV6RE};
|
use proxmox::{IPRE, IPRE_BRACKET, IPV4OCTET, IPV4RE, IPV6H16, IPV6LS32, IPV6RE};
|
||||||
|
|
||||||
|
@ -60,8 +60,7 @@ pub use userid::{PROXMOX_GROUP_ID_SCHEMA, PROXMOX_TOKEN_ID_SCHEMA, PROXMOX_TOKEN
|
||||||
mod user;
|
mod user;
|
||||||
pub use user::*;
|
pub use user::*;
|
||||||
|
|
||||||
pub mod upid;
|
pub use proxmox::api::upid::*;
|
||||||
pub use upid::*;
|
|
||||||
|
|
||||||
mod crypto;
|
mod crypto;
|
||||||
pub use crypto::{CryptMode, Fingerprint};
|
pub use crypto::{CryptMode, Fingerprint};
|
||||||
|
@ -397,3 +396,57 @@ pub enum NodePowerCommand {
|
||||||
/// Shutdown the server
|
/// Shutdown the server
|
||||||
Shutdown,
|
Shutdown,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[api()]
|
||||||
|
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum TaskStateType {
|
||||||
|
/// Ok
|
||||||
|
OK,
|
||||||
|
/// Warning
|
||||||
|
Warning,
|
||||||
|
/// Error
|
||||||
|
Error,
|
||||||
|
/// Unknown
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
properties: {
|
||||||
|
upid: { schema: UPID::API_SCHEMA },
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
/// Task properties.
|
||||||
|
pub struct TaskListItem {
|
||||||
|
pub upid: String,
|
||||||
|
/// The node name where the task is running on.
|
||||||
|
pub node: String,
|
||||||
|
/// The Unix PID
|
||||||
|
pub pid: i64,
|
||||||
|
/// The task start time (Epoch)
|
||||||
|
pub pstart: u64,
|
||||||
|
/// The task start time (Epoch)
|
||||||
|
pub starttime: i64,
|
||||||
|
/// Worker type (arbitrary ASCII string)
|
||||||
|
pub worker_type: String,
|
||||||
|
/// Worker ID (arbitrary ASCII string)
|
||||||
|
pub worker_id: Option<String>,
|
||||||
|
/// The authenticated entity who started the task
|
||||||
|
pub user: String,
|
||||||
|
/// The task end time (Epoch)
|
||||||
|
#[serde(skip_serializing_if="Option::is_none")]
|
||||||
|
pub endtime: Option<i64>,
|
||||||
|
/// Task end status
|
||||||
|
#[serde(skip_serializing_if="Option::is_none")]
|
||||||
|
pub status: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const NODE_TASKS_LIST_TASKS_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
|
optional: false,
|
||||||
|
schema: &ArraySchema::new(
|
||||||
|
"A list of tasks.",
|
||||||
|
&TaskListItem::API_SCHEMA,
|
||||||
|
).schema(),
|
||||||
|
};
|
||||||
|
|
|
@ -1,204 +0,0 @@
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
||||||
|
|
||||||
use anyhow::{bail, Error};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use proxmox::api::api;
|
|
||||||
use proxmox::api::schema::{ApiStringFormat, ApiType, Schema, StringSchema, ArraySchema, ReturnType};
|
|
||||||
use proxmox::const_regex;
|
|
||||||
use proxmox::sys::linux::procfs;
|
|
||||||
|
|
||||||
/// Unique Process/Task Identifier
|
|
||||||
///
|
|
||||||
/// We use this to uniquely identify worker task. UPIDs have a short
|
|
||||||
/// string repesentaion, which gives additional information about the
|
|
||||||
/// type of the task. for example:
|
|
||||||
/// ```text
|
|
||||||
/// UPID:{node}:{pid}:{pstart}:{task_id}:{starttime}:{worker_type}:{worker_id}:{userid}:
|
|
||||||
/// UPID:elsa:00004F37:0039E469:00000000:5CA78B83:garbage_collection::root@pam:
|
|
||||||
/// ```
|
|
||||||
/// Please note that we use tokio, so a single thread can run multiple
|
|
||||||
/// tasks.
|
|
||||||
// #[api] - manually implemented API type
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct UPID {
|
|
||||||
/// The Unix PID
|
|
||||||
pub pid: libc::pid_t,
|
|
||||||
/// The Unix process start time from `/proc/pid/stat`
|
|
||||||
pub pstart: u64,
|
|
||||||
/// The task start time (Epoch)
|
|
||||||
pub starttime: i64,
|
|
||||||
/// The task ID (inside the process/thread)
|
|
||||||
pub task_id: usize,
|
|
||||||
/// Worker type (arbitrary ASCII string)
|
|
||||||
pub worker_type: String,
|
|
||||||
/// Worker ID (arbitrary ASCII string)
|
|
||||||
pub worker_id: Option<String>,
|
|
||||||
/// The authenticated entity who started the task
|
|
||||||
pub auth_id: String,
|
|
||||||
/// The node name.
|
|
||||||
pub node: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
proxmox::forward_serialize_to_display!(UPID);
|
|
||||||
proxmox::forward_deserialize_to_from_str!(UPID);
|
|
||||||
|
|
||||||
const_regex! {
|
|
||||||
pub PROXMOX_UPID_REGEX = concat!(
|
|
||||||
r"^UPID:(?P<node>[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?):(?P<pid>[0-9A-Fa-f]{8}):",
|
|
||||||
r"(?P<pstart>[0-9A-Fa-f]{8,9}):(?P<task_id>[0-9A-Fa-f]{8,16}):(?P<starttime>[0-9A-Fa-f]{8}):",
|
|
||||||
r"(?P<wtype>[^:\s]+):(?P<wid>[^:\s]*):(?P<authid>[^:\s]+):$"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const PROXMOX_UPID_FORMAT: ApiStringFormat =
|
|
||||||
ApiStringFormat::Pattern(&PROXMOX_UPID_REGEX);
|
|
||||||
|
|
||||||
pub const UPID_SCHEMA: Schema = StringSchema::new("Unique Process/Task Identifier")
|
|
||||||
.min_length("UPID:N:12345678:12345678:12345678:::".len())
|
|
||||||
.max_length(128) // arbitrary
|
|
||||||
.format(&PROXMOX_UPID_FORMAT)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
impl ApiType for UPID {
|
|
||||||
const API_SCHEMA: Schema = UPID_SCHEMA;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UPID {
|
|
||||||
/// Create a new UPID
|
|
||||||
pub fn new(
|
|
||||||
worker_type: &str,
|
|
||||||
worker_id: Option<String>,
|
|
||||||
auth_id: String,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
|
|
||||||
let pid = unsafe { libc::getpid() };
|
|
||||||
|
|
||||||
let bad: &[_] = &['/', ':', ' '];
|
|
||||||
|
|
||||||
if worker_type.contains(bad) {
|
|
||||||
bail!("illegal characters in worker type '{}'", worker_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if auth_id.contains(bad) {
|
|
||||||
bail!("illegal characters in auth_id '{}'", auth_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static WORKER_TASK_NEXT_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
let task_id = WORKER_TASK_NEXT_ID.fetch_add(1, Ordering::SeqCst);
|
|
||||||
|
|
||||||
Ok(UPID {
|
|
||||||
pid,
|
|
||||||
pstart: procfs::PidStat::read_from_pid(nix::unistd::Pid::from_raw(pid))?.starttime,
|
|
||||||
starttime: proxmox::tools::time::epoch_i64(),
|
|
||||||
task_id,
|
|
||||||
worker_type: worker_type.to_owned(),
|
|
||||||
worker_id,
|
|
||||||
auth_id,
|
|
||||||
node: proxmox::tools::nodename().to_owned(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl std::str::FromStr for UPID {
|
|
||||||
type Err = Error;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
if let Some(cap) = PROXMOX_UPID_REGEX.captures(s) {
|
|
||||||
|
|
||||||
let worker_id = if cap["wid"].is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let wid = proxmox_systemd::unescape_unit(&cap["wid"])?;
|
|
||||||
Some(wid)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(UPID {
|
|
||||||
pid: i32::from_str_radix(&cap["pid"], 16).unwrap(),
|
|
||||||
pstart: u64::from_str_radix(&cap["pstart"], 16).unwrap(),
|
|
||||||
starttime: i64::from_str_radix(&cap["starttime"], 16).unwrap(),
|
|
||||||
task_id: usize::from_str_radix(&cap["task_id"], 16).unwrap(),
|
|
||||||
worker_type: cap["wtype"].to_string(),
|
|
||||||
worker_id,
|
|
||||||
auth_id: cap["authid"].parse()?,
|
|
||||||
node: cap["node"].to_string(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
bail!("unable to parse UPID '{}'", s);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for UPID {
|
|
||||||
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
|
|
||||||
let wid = if let Some(ref id) = self.worker_id {
|
|
||||||
proxmox_systemd::escape_unit(id, false)
|
|
||||||
} else {
|
|
||||||
String::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Note: pstart can be > 32bit if uptime > 497 days, so this can result in
|
|
||||||
// more that 8 characters for pstart
|
|
||||||
|
|
||||||
write!(f, "UPID:{}:{:08X}:{:08X}:{:08X}:{:08X}:{}:{}:{}:",
|
|
||||||
self.node, self.pid, self.pstart, self.task_id, self.starttime, self.worker_type, wid, self.auth_id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api()]
|
|
||||||
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "lowercase")]
|
|
||||||
pub enum TaskStateType {
|
|
||||||
/// Ok
|
|
||||||
OK,
|
|
||||||
/// Warning
|
|
||||||
Warning,
|
|
||||||
/// Error
|
|
||||||
Error,
|
|
||||||
/// Unknown
|
|
||||||
Unknown,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api(
|
|
||||||
properties: {
|
|
||||||
upid: { schema: UPID::API_SCHEMA },
|
|
||||||
},
|
|
||||||
)]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
/// Task properties.
|
|
||||||
pub struct TaskListItem {
|
|
||||||
pub upid: String,
|
|
||||||
/// The node name where the task is running on.
|
|
||||||
pub node: String,
|
|
||||||
/// The Unix PID
|
|
||||||
pub pid: i64,
|
|
||||||
/// The task start time (Epoch)
|
|
||||||
pub pstart: u64,
|
|
||||||
/// The task start time (Epoch)
|
|
||||||
pub starttime: i64,
|
|
||||||
/// Worker type (arbitrary ASCII string)
|
|
||||||
pub worker_type: String,
|
|
||||||
/// Worker ID (arbitrary ASCII string)
|
|
||||||
pub worker_id: Option<String>,
|
|
||||||
/// The authenticated entity who started the task
|
|
||||||
pub user: String,
|
|
||||||
/// The task end time (Epoch)
|
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
|
||||||
pub endtime: Option<i64>,
|
|
||||||
/// Task end status
|
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
|
||||||
pub status: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const NODE_TASKS_LIST_TASKS_RETURN_TYPE: ReturnType = ReturnType {
|
|
||||||
optional: false,
|
|
||||||
schema: &ArraySchema::new(
|
|
||||||
"A list of tasks.",
|
|
||||||
&TaskListItem::API_SCHEMA,
|
|
||||||
).schema(),
|
|
||||||
};
|
|
|
@ -28,7 +28,7 @@ tower-service = "0.3.0"
|
||||||
xdg = "2.2"
|
xdg = "2.2"
|
||||||
|
|
||||||
pathpatterns = "0.1.2"
|
pathpatterns = "0.1.2"
|
||||||
proxmox = { version = "0.13.3", default-features = false, features = [ "cli" ] }
|
proxmox = { version = "0.13.4", default-features = false, features = [ "cli" ] }
|
||||||
proxmox-fuse = "0.1.1"
|
proxmox-fuse = "0.1.1"
|
||||||
proxmox-http = { version = "0.4.0", features = [ "client", "http-helpers", "websocket" ] }
|
proxmox-http = { version = "0.4.0", features = [ "client", "http-helpers", "websocket" ] }
|
||||||
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
||||||
|
|
|
@ -16,7 +16,7 @@ nix = "0.19.1"
|
||||||
regex = "1.2"
|
regex = "1.2"
|
||||||
once_cell = "1.3.1"
|
once_cell = "1.3.1"
|
||||||
|
|
||||||
proxmox = { version = "0.13.3", default-features = false, features = [ "cli" ] }
|
proxmox = { version = "0.13.4", default-features = false, features = [ "cli" ] }
|
||||||
|
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
||||||
|
|
|
@ -23,7 +23,7 @@ zstd = { version = "0.6", features = [ "bindgen" ] }
|
||||||
pathpatterns = "0.1.2"
|
pathpatterns = "0.1.2"
|
||||||
pxar = "0.10.1"
|
pxar = "0.10.1"
|
||||||
|
|
||||||
proxmox = { version = "0.13.3", default-features = false, features = [ "api-macro" ] }
|
proxmox = { version = "0.13.4", default-features = false, features = [ "api-macro" ] }
|
||||||
|
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
pbs-tools = { path = "../pbs-tools" }
|
pbs-tools = { path = "../pbs-tools" }
|
||||||
|
|
|
@ -14,7 +14,7 @@ nix = "0.19.1"
|
||||||
regex = "1.2"
|
regex = "1.2"
|
||||||
tokio = { version = "1.6", features = [] }
|
tokio = { version = "1.6", features = [] }
|
||||||
|
|
||||||
proxmox = "0.13.3"
|
proxmox = "0.13.4"
|
||||||
proxmox-fuse = "0.1.1"
|
proxmox-fuse = "0.1.1"
|
||||||
|
|
||||||
pbs-tools = { path = "../pbs-tools" }
|
pbs-tools = { path = "../pbs-tools" }
|
||||||
|
|
|
@ -18,7 +18,7 @@ bitflags = "1.2.1"
|
||||||
regex = "1.2"
|
regex = "1.2"
|
||||||
udev = ">= 0.3, <0.5"
|
udev = ">= 0.3, <0.5"
|
||||||
|
|
||||||
proxmox = { version = "0.13.3", default-features = false, features = [] }
|
proxmox = { version = "0.13.4", default-features = false, features = [] }
|
||||||
|
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
pbs-tools = { path = "../pbs-tools" }
|
pbs-tools = { path = "../pbs-tools" }
|
||||||
|
|
|
@ -30,7 +30,7 @@ url = "2.1"
|
||||||
walkdir = "2"
|
walkdir = "2"
|
||||||
zstd = { version = "0.6", features = [ "bindgen" ] }
|
zstd = { version = "0.6", features = [ "bindgen" ] }
|
||||||
|
|
||||||
proxmox = { version = "0.13.3", default-features = false, features = [ "tokio" ] }
|
proxmox = { version = "0.13.4", default-features = false, features = [ "tokio" ] }
|
||||||
|
|
||||||
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
||||||
pbs-runtime = { path = "../pbs-runtime" }
|
pbs-runtime = { path = "../pbs-runtime" }
|
||||||
|
|
|
@ -22,7 +22,7 @@ zstd = { version = "0.6", features = [ "bindgen" ] }
|
||||||
pathpatterns = "0.1.2"
|
pathpatterns = "0.1.2"
|
||||||
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
||||||
|
|
||||||
proxmox = { version = "0.13.3", features = [ "sortable-macro", "api-macro", "cli", "router" ] }
|
proxmox = { version = "0.13.4", features = [ "sortable-macro", "api-macro", "cli", "router" ] }
|
||||||
|
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
||||||
|
@ -31,5 +31,4 @@ pbs-client = { path = "../pbs-client" }
|
||||||
pbs-datastore = { path = "../pbs-datastore" }
|
pbs-datastore = { path = "../pbs-datastore" }
|
||||||
pbs-fuse-loop = { path = "../pbs-fuse-loop" }
|
pbs-fuse-loop = { path = "../pbs-fuse-loop" }
|
||||||
pbs-runtime = { path = "../pbs-runtime" }
|
pbs-runtime = { path = "../pbs-runtime" }
|
||||||
proxmox-systemd = { path = "../proxmox-systemd" }
|
|
||||||
pbs-tools = { path = "../pbs-tools" }
|
pbs-tools = { path = "../pbs-tools" }
|
||||||
|
|
|
@ -118,7 +118,7 @@ fn complete_mapping_names<S: BuildHasher>(_arg: &str, _param: &HashMap<String, S
|
||||||
match pbs_fuse_loop::find_all_mappings() {
|
match pbs_fuse_loop::find_all_mappings() {
|
||||||
Ok(mappings) => mappings
|
Ok(mappings) => mappings
|
||||||
.filter_map(|(name, _)| {
|
.filter_map(|(name, _)| {
|
||||||
proxmox_systemd::unescape_unit(&name).ok()
|
proxmox::tools::systemd::unescape_unit(&name).ok()
|
||||||
}).collect(),
|
}).collect(),
|
||||||
Err(_) => Vec::new()
|
Err(_) => Vec::new()
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,7 @@ async fn mount_do(param: Value, pipe: Option<Fd>) -> Result<Value, Error> {
|
||||||
let reader = CachedChunkReader::new(chunk_reader, index, 8).seekable();
|
let reader = CachedChunkReader::new(chunk_reader, index, 8).seekable();
|
||||||
|
|
||||||
let name = &format!("{}:{}/{}", repo.to_string(), path, archive_name);
|
let name = &format!("{}:{}/{}", repo.to_string(), path, archive_name);
|
||||||
let name_escaped = proxmox_systemd::escape_unit(name, false);
|
let name_escaped = proxmox::tools::systemd::escape_unit(name, false);
|
||||||
|
|
||||||
let mut session = pbs_fuse_loop::FuseLoopSession::map_loop(size, reader, &name_escaped, options).await?;
|
let mut session = pbs_fuse_loop::FuseLoopSession::map_loop(size, reader, &name_escaped, options).await?;
|
||||||
let loopdev = session.loopdev_path.clone();
|
let loopdev = session.loopdev_path.clone();
|
||||||
|
@ -341,7 +341,7 @@ fn unmap(
|
||||||
pbs_fuse_loop::cleanup_unused_run_files(None);
|
pbs_fuse_loop::cleanup_unused_run_files(None);
|
||||||
let mut any = false;
|
let mut any = false;
|
||||||
for (backing, loopdev) in pbs_fuse_loop::find_all_mappings()? {
|
for (backing, loopdev) in pbs_fuse_loop::find_all_mappings()? {
|
||||||
let name = proxmox_systemd::unescape_unit(&backing)?;
|
let name = proxmox::tools::systemd::unescape_unit(&backing)?;
|
||||||
println!("{}:\t{}", loopdev.unwrap_or_else(|| "(unmapped)".to_string()), name);
|
println!("{}:\t{}", loopdev.unwrap_or_else(|| "(unmapped)".to_string()), name);
|
||||||
any = true;
|
any = true;
|
||||||
}
|
}
|
||||||
|
@ -360,7 +360,7 @@ fn unmap(
|
||||||
if name.starts_with("/dev/loop") {
|
if name.starts_with("/dev/loop") {
|
||||||
pbs_fuse_loop::unmap_loopdev(name)?;
|
pbs_fuse_loop::unmap_loopdev(name)?;
|
||||||
} else {
|
} else {
|
||||||
let name = proxmox_systemd::escape_unit(&name, false);
|
let name = proxmox::tools::systemd::escape_unit(&name, false);
|
||||||
pbs_fuse_loop::unmap_name(name)?;
|
pbs_fuse_loop::unmap_name(name)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ tokio = { version = "1.6", features = [ "io-std", "rt", "rt-multi-thread", "time
|
||||||
|
|
||||||
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
||||||
|
|
||||||
proxmox = { version = "0.13.3", features = [ "api-macro", "cli" ] }
|
proxmox = { version = "0.13.4", features = [ "api-macro", "cli" ] }
|
||||||
|
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
||||||
|
@ -24,5 +24,4 @@ pbs-config = { path = "../pbs-config" }
|
||||||
pbs-client = { path = "../pbs-client" }
|
pbs-client = { path = "../pbs-client" }
|
||||||
pbs-datastore = { path = "../pbs-datastore" }
|
pbs-datastore = { path = "../pbs-datastore" }
|
||||||
pbs-runtime = { path = "../pbs-runtime" }
|
pbs-runtime = { path = "../pbs-runtime" }
|
||||||
proxmox-systemd = { path = "../proxmox-systemd" }
|
|
||||||
pbs-tools = { path = "../pbs-tools" }
|
pbs-tools = { path = "../pbs-tools" }
|
||||||
|
|
|
@ -80,7 +80,7 @@ impl VMStateMap {
|
||||||
|
|
||||||
fn make_name(repo: &BackupRepository, snap: &BackupDir) -> String {
|
fn make_name(repo: &BackupRepository, snap: &BackupDir) -> String {
|
||||||
let full = format!("qemu_{}/{}", repo, snap);
|
let full = format!("qemu_{}/{}", repo, snap);
|
||||||
proxmox_systemd::escape_unit(&full, false)
|
proxmox::tools::systemd::escape_unit(&full, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// remove non-responsive VMs from given map, returns 'true' if map was modified
|
/// remove non-responsive VMs from given map, returns 'true' if map was modified
|
||||||
|
@ -257,7 +257,7 @@ impl BlockRestoreDriver for QemuBlockDriver {
|
||||||
let resp = client
|
let resp = client
|
||||||
.get("api2/json/status", Some(json!({"keep-timeout": true})))
|
.get("api2/json/status", Some(json!({"keep-timeout": true})))
|
||||||
.await;
|
.await;
|
||||||
let name = proxmox_systemd::unescape_unit(n)
|
let name = proxmox::tools::systemd::unescape_unit(n)
|
||||||
.unwrap_or_else(|_| "<invalid name>".to_owned());
|
.unwrap_or_else(|_| "<invalid name>".to_owned());
|
||||||
let mut extra = json!({"pid": s.pid, "cid": s.cid});
|
let mut extra = json!({"pid": s.pid, "cid": s.cid});
|
||||||
|
|
||||||
|
@ -295,7 +295,7 @@ impl BlockRestoreDriver for QemuBlockDriver {
|
||||||
|
|
||||||
fn stop(&self, id: String) -> Async<Result<(), Error>> {
|
fn stop(&self, id: String) -> Async<Result<(), Error>> {
|
||||||
async move {
|
async move {
|
||||||
let name = proxmox_systemd::escape_unit(&id, false);
|
let name = proxmox::tools::systemd::escape_unit(&id, false);
|
||||||
let mut map = VMStateMap::load()?;
|
let mut map = VMStateMap::load()?;
|
||||||
let map_mod = cleanup_map(&mut map.map).await;
|
let map_mod = cleanup_map(&mut map.map).await;
|
||||||
match map.map.get(&name) {
|
match map.map.get(&name) {
|
||||||
|
@ -325,7 +325,7 @@ impl BlockRestoreDriver for QemuBlockDriver {
|
||||||
match VMStateMap::load_read_only() {
|
match VMStateMap::load_read_only() {
|
||||||
Ok(state) => state
|
Ok(state) => state
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(name, _)| proxmox_systemd::unescape_unit(&name).ok())
|
.filter_map(|(name, _)| proxmox::tools::systemd::unescape_unit(&name).ok())
|
||||||
.collect(),
|
.collect(),
|
||||||
Err(_) => Vec::new(),
|
Err(_) => Vec::new(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ tokio-openssl = "0.6.1"
|
||||||
tower-service = "0.3.0"
|
tower-service = "0.3.0"
|
||||||
url = "2.1"
|
url = "2.1"
|
||||||
|
|
||||||
proxmox = { version = "0.13.3", features = [ "router"] }
|
proxmox = { version = "0.13.4", features = [ "router"] }
|
||||||
|
|
||||||
# fixme: remove this dependency (pbs_tools::broadcast_future)
|
# fixme: remove this dependency (pbs_tools::broadcast_future)
|
||||||
pbs-tools = { path = "../pbs-tools" }
|
pbs-tools = { path = "../pbs-tools" }
|
||||||
|
|
|
@ -26,7 +26,7 @@ tokio-util = { version = "0.6", features = [ "codec", "io" ] }
|
||||||
pathpatterns = "0.1.2"
|
pathpatterns = "0.1.2"
|
||||||
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
||||||
|
|
||||||
proxmox = { version = "0.13.3", features = [ "router", "sortable-macro" ] }
|
proxmox = { version = "0.13.4", features = [ "router", "sortable-macro" ] }
|
||||||
|
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
pbs-runtime = { path = "../pbs-runtime" }
|
pbs-runtime = { path = "../pbs-runtime" }
|
||||||
|
|
|
@ -11,6 +11,6 @@ bitflags = "1.2.1"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
nom = "5.1"
|
nom = "5.1"
|
||||||
|
|
||||||
proxmox = { version = "0.13.3", default-features = false }
|
proxmox = { version = "0.13.4", default-features = false }
|
||||||
|
|
||||||
#pbs-tools = { path = "../pbs-tools" }
|
#pbs-tools = { path = "../pbs-tools" }
|
||||||
|
|
|
@ -34,88 +34,6 @@ fn run_command(mut command: Command) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Escape strings for usage in systemd unit names
|
|
||||||
pub fn escape_unit(mut unit: &str, is_path: bool) -> String {
|
|
||||||
if is_path {
|
|
||||||
unit = unit.trim_matches('/');
|
|
||||||
if unit.is_empty() {
|
|
||||||
return String::from("-");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let unit = unit.as_bytes();
|
|
||||||
|
|
||||||
let mut escaped = String::new();
|
|
||||||
|
|
||||||
for (i, c) in unit.iter().enumerate() {
|
|
||||||
if *c == b'/' {
|
|
||||||
escaped.push('-');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (i == 0 && *c == b'.')
|
|
||||||
|| !(*c == b'_'
|
|
||||||
|| *c == b'.'
|
|
||||||
|| (*c >= b'0' && *c <= b'9')
|
|
||||||
|| (*c >= b'A' && *c <= b'Z')
|
|
||||||
|| (*c >= b'a' && *c <= b'z'))
|
|
||||||
{
|
|
||||||
escaped.push_str(&format!("\\x{:0x}", c));
|
|
||||||
} else {
|
|
||||||
escaped.push(*c as char);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
escaped
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_hex_digit(d: u8) -> Result<u8, Error> {
|
|
||||||
if d >= b'0' && d <= b'9' {
|
|
||||||
return Ok(d - b'0');
|
|
||||||
}
|
|
||||||
if d >= b'A' && d <= b'F' {
|
|
||||||
return Ok(d - b'A' + 10);
|
|
||||||
}
|
|
||||||
if d >= b'a' && d <= b'f' {
|
|
||||||
return Ok(d - b'a' + 10);
|
|
||||||
}
|
|
||||||
bail!("got invalid hex digit");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unescape strings used in systemd unit names
|
|
||||||
pub fn unescape_unit(text: &str) -> Result<String, Error> {
|
|
||||||
let mut i = text.as_bytes();
|
|
||||||
|
|
||||||
let mut data: Vec<u8> = Vec::new();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if i.is_empty() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let next = i[0];
|
|
||||||
if next == b'\\' {
|
|
||||||
if i.len() < 4 {
|
|
||||||
bail!("short input");
|
|
||||||
}
|
|
||||||
if i[1] != b'x' {
|
|
||||||
bail!("unkwnown escape sequence");
|
|
||||||
}
|
|
||||||
let h1 = parse_hex_digit(i[2])?;
|
|
||||||
let h0 = parse_hex_digit(i[3])?;
|
|
||||||
data.push(h1 << 4 | h0);
|
|
||||||
i = &i[4..]
|
|
||||||
} else if next == b'-' {
|
|
||||||
data.push(b'/');
|
|
||||||
i = &i[1..]
|
|
||||||
} else {
|
|
||||||
data.push(next);
|
|
||||||
i = &i[1..]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let text = String::from_utf8(data)?;
|
|
||||||
|
|
||||||
Ok(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reload_daemon() -> Result<(), Error> {
|
pub fn reload_daemon() -> Result<(), Error> {
|
||||||
let mut command = std::process::Command::new("systemctl");
|
let mut command = std::process::Command::new("systemctl");
|
||||||
command.arg("daemon-reload");
|
command.arg("daemon-reload");
|
||||||
|
@ -178,6 +96,9 @@ pub fn reload_unit(unit: &str) -> Result<(), Error> {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_escape_unit() -> Result<(), Error> {
|
fn test_escape_unit() -> Result<(), Error> {
|
||||||
fn test_escape(i: &str, expected: &str, is_path: bool) {
|
fn test_escape(i: &str, expected: &str, is_path: bool) {
|
||||||
|
|
||||||
|
use proxmox::tools::systemd::{escape_unit, unescape_unit};
|
||||||
|
|
||||||
let escaped = escape_unit(i, is_path);
|
let escaped = escape_unit(i, is_path);
|
||||||
assert_eq!(escaped, expected);
|
assert_eq!(escaped, expected);
|
||||||
let unescaped = unescape_unit(&escaped).unwrap();
|
let unescaped = unescape_unit(&escaped).unwrap();
|
||||||
|
|
|
@ -16,7 +16,7 @@ serde_json = "1.0"
|
||||||
tokio = { version = "1.6", features = [ "rt", "rt-multi-thread" ] }
|
tokio = { version = "1.6", features = [ "rt", "rt-multi-thread" ] }
|
||||||
|
|
||||||
pathpatterns = "0.1.2"
|
pathpatterns = "0.1.2"
|
||||||
proxmox = { version = "0.13.3", default-features = false, features = [] }
|
proxmox = { version = "0.13.4", default-features = false, features = [] }
|
||||||
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
||||||
|
|
||||||
pbs-client = { path = "../pbs-client" }
|
pbs-client = { path = "../pbs-client" }
|
||||||
|
|
|
@ -242,7 +242,7 @@ pub fn delete_datastore_disk(name: String) -> Result<(), Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable systemd mount-unit
|
// disable systemd mount-unit
|
||||||
let mut mount_unit_name = proxmox_systemd::escape_unit(&path, true);
|
let mut mount_unit_name = proxmox::tools::systemd::escape_unit(&path, true);
|
||||||
mount_unit_name.push_str(".mount");
|
mount_unit_name.push_str(".mount");
|
||||||
proxmox_systemd::disable_unit(&mount_unit_name)?;
|
proxmox_systemd::disable_unit(&mount_unit_name)?;
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ fn create_datastore_mount_unit(
|
||||||
what: &str,
|
what: &str,
|
||||||
) -> Result<String, Error> {
|
) -> Result<String, Error> {
|
||||||
|
|
||||||
let mut mount_unit_name = proxmox_systemd::escape_unit(&mount_point, true);
|
let mut mount_unit_name = proxmox::tools::systemd::escape_unit(&mount_point, true);
|
||||||
mount_unit_name.push_str(".mount");
|
mount_unit_name.push_str(".mount");
|
||||||
|
|
||||||
let mount_unit_path = format!("/etc/systemd/system/{}", mount_unit_name);
|
let mount_unit_path = format!("/etc/systemd/system/{}", mount_unit_name);
|
||||||
|
|
|
@ -271,7 +271,7 @@ pub fn create_zpool(
|
||||||
worker.log(output);
|
worker.log(output);
|
||||||
|
|
||||||
if std::path::Path::new("/lib/systemd/system/zfs-import@.service").exists() {
|
if std::path::Path::new("/lib/systemd/system/zfs-import@.service").exists() {
|
||||||
let import_unit = format!("zfs-import@{}.service", proxmox_systemd::escape_unit(&name, false));
|
let import_unit = format!("zfs-import@{}.service", proxmox::tools::systemd::escape_unit(&name, false));
|
||||||
proxmox_systemd::enable_unit(&import_unit)?;
|
proxmox_systemd::enable_unit(&import_unit)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,9 @@ use once_cell::sync::OnceCell;
|
||||||
use proxmox::sys::linux::procfs;
|
use proxmox::sys::linux::procfs;
|
||||||
use proxmox::try_block;
|
use proxmox::try_block;
|
||||||
use proxmox::tools::fs::{create_path, replace_file, atomic_open_or_create_file, CreateOptions};
|
use proxmox::tools::fs::{create_path, replace_file, atomic_open_or_create_file, CreateOptions};
|
||||||
|
use proxmox::api::upid::UPID;
|
||||||
|
|
||||||
use pbs_tools::logrotate::{LogRotate, LogRotateFiles};
|
use pbs_tools::logrotate::{LogRotate, LogRotateFiles};
|
||||||
use pbs_api_types::UPID;
|
|
||||||
use proxmox_rest_server::{CommandoSocket, FileLogger, FileLogOptions};
|
use proxmox_rest_server::{CommandoSocket, FileLogger, FileLogOptions};
|
||||||
|
|
||||||
struct TaskListLockGuard(File);
|
struct TaskListLockGuard(File);
|
||||||
|
|
|
@ -606,7 +606,7 @@ pub struct DeviceLockGuard(std::fs::File);
|
||||||
// Uses systemd escape_unit to compute a file name from `device_path`, the try
|
// Uses systemd escape_unit to compute a file name from `device_path`, the try
|
||||||
// to lock `/var/lock/<name>`.
|
// to lock `/var/lock/<name>`.
|
||||||
fn open_device_lock(device_path: &str) -> Result<std::fs::File, Error> {
|
fn open_device_lock(device_path: &str) -> Result<std::fs::File, Error> {
|
||||||
let lock_name = proxmox_systemd::escape_unit(device_path, true);
|
let lock_name = proxmox::tools::systemd::escape_unit(device_path, true);
|
||||||
|
|
||||||
let mut path = std::path::PathBuf::from(crate::tape::DRIVE_LOCK_DIR);
|
let mut path = std::path::PathBuf::from(crate::tape::DRIVE_LOCK_DIR);
|
||||||
path.push(lock_name);
|
path.push(lock_name);
|
||||||
|
|
Loading…
Reference in New Issue