move acl to pbs_config workspaces, pbs_api_types cleanups
This commit is contained in:
parent
1cb08a0a05
commit
8cc3760e74
|
@ -0,0 +1,284 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde::de::{value, IntoDeserializer};
|
||||||
|
|
||||||
|
use proxmox::api::api;
|
||||||
|
use proxmox::api::schema::{
|
||||||
|
ApiStringFormat, BooleanSchema, EnumEntry, Schema, StringSchema,
|
||||||
|
};
|
||||||
|
use proxmox::{constnamedbitmap, const_regex};
|
||||||
|
|
||||||
|
const_regex! {
|
||||||
|
pub ACL_PATH_REGEX = concat!(r"^(?:/|", r"(?:/", PROXMOX_SAFE_ID_REGEX_STR!(), ")+", r")$");
|
||||||
|
}
|
||||||
|
|
||||||
|
// define Privilege bitfield
|
||||||
|
|
||||||
|
constnamedbitmap! {
|
||||||
|
/// Contains a list of privilege name to privilege value mappings.
|
||||||
|
///
|
||||||
|
/// The names are used when displaying/persisting privileges anywhere, the values are used to
|
||||||
|
/// allow easy matching of privileges as bitflags.
|
||||||
|
PRIVILEGES: u64 => {
|
||||||
|
/// Sys.Audit allows knowing about the system and its status
|
||||||
|
PRIV_SYS_AUDIT("Sys.Audit");
|
||||||
|
/// Sys.Modify allows modifying system-level configuration
|
||||||
|
PRIV_SYS_MODIFY("Sys.Modify");
|
||||||
|
/// Sys.Modify allows to poweroff/reboot/.. the system
|
||||||
|
PRIV_SYS_POWER_MANAGEMENT("Sys.PowerManagement");
|
||||||
|
|
||||||
|
/// Datastore.Audit allows knowing about a datastore,
|
||||||
|
/// including reading the configuration entry and listing its contents
|
||||||
|
PRIV_DATASTORE_AUDIT("Datastore.Audit");
|
||||||
|
/// Datastore.Allocate allows creating or deleting datastores
|
||||||
|
PRIV_DATASTORE_ALLOCATE("Datastore.Allocate");
|
||||||
|
/// Datastore.Modify allows modifying a datastore and its contents
|
||||||
|
PRIV_DATASTORE_MODIFY("Datastore.Modify");
|
||||||
|
/// Datastore.Read allows reading arbitrary backup contents
|
||||||
|
PRIV_DATASTORE_READ("Datastore.Read");
|
||||||
|
/// Allows verifying a datastore
|
||||||
|
PRIV_DATASTORE_VERIFY("Datastore.Verify");
|
||||||
|
|
||||||
|
/// Datastore.Backup allows Datastore.Read|Verify and creating new snapshots,
|
||||||
|
/// but also requires backup ownership
|
||||||
|
PRIV_DATASTORE_BACKUP("Datastore.Backup");
|
||||||
|
/// Datastore.Prune allows deleting snapshots,
|
||||||
|
/// but also requires backup ownership
|
||||||
|
PRIV_DATASTORE_PRUNE("Datastore.Prune");
|
||||||
|
|
||||||
|
/// Permissions.Modify allows modifying ACLs
|
||||||
|
PRIV_PERMISSIONS_MODIFY("Permissions.Modify");
|
||||||
|
|
||||||
|
/// Remote.Audit allows reading remote.cfg and sync.cfg entries
|
||||||
|
PRIV_REMOTE_AUDIT("Remote.Audit");
|
||||||
|
/// Remote.Modify allows modifying remote.cfg
|
||||||
|
PRIV_REMOTE_MODIFY("Remote.Modify");
|
||||||
|
/// Remote.Read allows reading data from a configured `Remote`
|
||||||
|
PRIV_REMOTE_READ("Remote.Read");
|
||||||
|
|
||||||
|
/// Sys.Console allows access to the system's console
|
||||||
|
PRIV_SYS_CONSOLE("Sys.Console");
|
||||||
|
|
||||||
|
/// Tape.Audit allows reading tape backup configuration and status
|
||||||
|
PRIV_TAPE_AUDIT("Tape.Audit");
|
||||||
|
/// Tape.Modify allows modifying tape backup configuration
|
||||||
|
PRIV_TAPE_MODIFY("Tape.Modify");
|
||||||
|
/// Tape.Write allows writing tape media
|
||||||
|
PRIV_TAPE_WRITE("Tape.Write");
|
||||||
|
/// Tape.Read allows reading tape backup configuration and media contents
|
||||||
|
PRIV_TAPE_READ("Tape.Read");
|
||||||
|
|
||||||
|
/// Realm.Allocate allows viewing, creating, modifying and deleting realms
|
||||||
|
PRIV_REALM_ALLOCATE("Realm.Allocate");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Admin always has all privileges. It can do everything except a few actions
|
||||||
|
/// which are limited to the 'root@pam` superuser
|
||||||
|
pub const ROLE_ADMIN: u64 = std::u64::MAX;
|
||||||
|
|
||||||
|
/// NoAccess can be used to remove privileges from specific (sub-)paths
|
||||||
|
pub const ROLE_NO_ACCESS: u64 = 0;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
/// Audit can view configuration and status information, but not modify it.
|
||||||
|
pub const ROLE_AUDIT: u64 = 0
|
||||||
|
| PRIV_SYS_AUDIT
|
||||||
|
| PRIV_DATASTORE_AUDIT;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
/// Datastore.Admin can do anything on the datastore.
|
||||||
|
pub const ROLE_DATASTORE_ADMIN: u64 = 0
|
||||||
|
| PRIV_DATASTORE_AUDIT
|
||||||
|
| PRIV_DATASTORE_MODIFY
|
||||||
|
| PRIV_DATASTORE_READ
|
||||||
|
| PRIV_DATASTORE_VERIFY
|
||||||
|
| PRIV_DATASTORE_BACKUP
|
||||||
|
| PRIV_DATASTORE_PRUNE;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
/// Datastore.Reader can read/verify datastore content and do restore
|
||||||
|
pub const ROLE_DATASTORE_READER: u64 = 0
|
||||||
|
| PRIV_DATASTORE_AUDIT
|
||||||
|
| PRIV_DATASTORE_VERIFY
|
||||||
|
| PRIV_DATASTORE_READ;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
/// Datastore.Backup can do backup and restore, but no prune.
|
||||||
|
pub const ROLE_DATASTORE_BACKUP: u64 = 0
|
||||||
|
| PRIV_DATASTORE_BACKUP;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
/// Datastore.PowerUser can do backup, restore, and prune.
|
||||||
|
pub const ROLE_DATASTORE_POWERUSER: u64 = 0
|
||||||
|
| PRIV_DATASTORE_PRUNE
|
||||||
|
| PRIV_DATASTORE_BACKUP;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
/// Datastore.Audit can audit the datastore.
|
||||||
|
pub const ROLE_DATASTORE_AUDIT: u64 = 0
|
||||||
|
| PRIV_DATASTORE_AUDIT;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
/// Remote.Audit can audit the remote
|
||||||
|
pub const ROLE_REMOTE_AUDIT: u64 = 0
|
||||||
|
| PRIV_REMOTE_AUDIT;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
/// Remote.Admin can do anything on the remote.
|
||||||
|
pub const ROLE_REMOTE_ADMIN: u64 = 0
|
||||||
|
| PRIV_REMOTE_AUDIT
|
||||||
|
| PRIV_REMOTE_MODIFY
|
||||||
|
| PRIV_REMOTE_READ;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
/// Remote.SyncOperator can do read and prune on the remote.
|
||||||
|
pub const ROLE_REMOTE_SYNC_OPERATOR: u64 = 0
|
||||||
|
| PRIV_REMOTE_AUDIT
|
||||||
|
| PRIV_REMOTE_READ;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
/// Tape.Audit can audit the tape backup configuration and media content
|
||||||
|
pub const ROLE_TAPE_AUDIT: u64 = 0
|
||||||
|
| PRIV_TAPE_AUDIT;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
/// Tape.Admin can do anything on the tape backup
|
||||||
|
pub const ROLE_TAPE_ADMIN: u64 = 0
|
||||||
|
| PRIV_TAPE_AUDIT
|
||||||
|
| PRIV_TAPE_MODIFY
|
||||||
|
| PRIV_TAPE_READ
|
||||||
|
| PRIV_TAPE_WRITE;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
/// Tape.Operator can do tape backup and restore (but no configuration changes)
|
||||||
|
pub const ROLE_TAPE_OPERATOR: u64 = 0
|
||||||
|
| PRIV_TAPE_AUDIT
|
||||||
|
| PRIV_TAPE_READ
|
||||||
|
| PRIV_TAPE_WRITE;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
/// Tape.Reader can do read and inspect tape content
|
||||||
|
pub const ROLE_TAPE_READER: u64 = 0
|
||||||
|
| PRIV_TAPE_AUDIT
|
||||||
|
| PRIV_TAPE_READ;
|
||||||
|
|
||||||
|
/// NoAccess can be used to remove privileges from specific (sub-)paths
|
||||||
|
pub const ROLE_NAME_NO_ACCESS: &str = "NoAccess";
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
type_text: "<role>",
|
||||||
|
)]
|
||||||
|
#[repr(u64)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
/// Enum representing roles via their [PRIVILEGES] combination.
|
||||||
|
///
|
||||||
|
/// Since privileges are implemented as bitflags, each unique combination of privileges maps to a
|
||||||
|
/// single, unique `u64` value that is used in this enum definition.
|
||||||
|
pub enum Role {
|
||||||
|
/// Administrator
|
||||||
|
Admin = ROLE_ADMIN,
|
||||||
|
/// Auditor
|
||||||
|
Audit = ROLE_AUDIT,
|
||||||
|
/// Disable Access
|
||||||
|
NoAccess = ROLE_NO_ACCESS,
|
||||||
|
/// Datastore Administrator
|
||||||
|
DatastoreAdmin = ROLE_DATASTORE_ADMIN,
|
||||||
|
/// Datastore Reader (inspect datastore content and do restores)
|
||||||
|
DatastoreReader = ROLE_DATASTORE_READER,
|
||||||
|
/// Datastore Backup (backup and restore owned backups)
|
||||||
|
DatastoreBackup = ROLE_DATASTORE_BACKUP,
|
||||||
|
/// Datastore PowerUser (backup, restore and prune owned backup)
|
||||||
|
DatastorePowerUser = ROLE_DATASTORE_POWERUSER,
|
||||||
|
/// Datastore Auditor
|
||||||
|
DatastoreAudit = ROLE_DATASTORE_AUDIT,
|
||||||
|
/// Remote Auditor
|
||||||
|
RemoteAudit = ROLE_REMOTE_AUDIT,
|
||||||
|
/// Remote Administrator
|
||||||
|
RemoteAdmin = ROLE_REMOTE_ADMIN,
|
||||||
|
/// Syncronisation Opertator
|
||||||
|
RemoteSyncOperator = ROLE_REMOTE_SYNC_OPERATOR,
|
||||||
|
/// Tape Auditor
|
||||||
|
TapeAudit = ROLE_TAPE_AUDIT,
|
||||||
|
/// Tape Administrator
|
||||||
|
TapeAdmin = ROLE_TAPE_ADMIN,
|
||||||
|
/// Tape Operator
|
||||||
|
TapeOperator = ROLE_TAPE_OPERATOR,
|
||||||
|
/// Tape Reader
|
||||||
|
TapeReader = ROLE_TAPE_READER,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl FromStr for Role {
|
||||||
|
type Err = value::Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Self::deserialize(s.into_deserializer())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ACL_PATH_FORMAT: ApiStringFormat =
|
||||||
|
ApiStringFormat::Pattern(&ACL_PATH_REGEX);
|
||||||
|
|
||||||
|
pub const ACL_PATH_SCHEMA: Schema = StringSchema::new(
|
||||||
|
"Access control path.")
|
||||||
|
.format(&ACL_PATH_FORMAT)
|
||||||
|
.min_length(1)
|
||||||
|
.max_length(128)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const ACL_PROPAGATE_SCHEMA: Schema = BooleanSchema::new(
|
||||||
|
"Allow to propagate (inherit) permissions.")
|
||||||
|
.default(true)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const ACL_UGID_TYPE_SCHEMA: Schema = StringSchema::new(
|
||||||
|
"Type of 'ugid' property.")
|
||||||
|
.format(&ApiStringFormat::Enum(&[
|
||||||
|
EnumEntry::new("user", "User"),
|
||||||
|
EnumEntry::new("group", "Group")]))
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
properties: {
|
||||||
|
propagate: {
|
||||||
|
schema: ACL_PROPAGATE_SCHEMA,
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
schema: ACL_PATH_SCHEMA,
|
||||||
|
},
|
||||||
|
ugid_type: {
|
||||||
|
schema: ACL_UGID_TYPE_SCHEMA,
|
||||||
|
},
|
||||||
|
ugid: {
|
||||||
|
type: String,
|
||||||
|
description: "User or Group ID.",
|
||||||
|
},
|
||||||
|
roleid: {
|
||||||
|
type: Role,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
/// ACL list entry.
|
||||||
|
pub struct AclListItem {
|
||||||
|
pub path: String,
|
||||||
|
pub ugid: String,
|
||||||
|
pub ugid_type: String,
|
||||||
|
pub propagate: bool,
|
||||||
|
pub roleid: String,
|
||||||
|
}
|
|
@ -0,0 +1,363 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use proxmox::api::api;
|
||||||
|
use proxmox::api::schema::{
|
||||||
|
ApiStringFormat, ApiType, ArraySchema, EnumEntry, IntegerSchema, ReturnType, Schema,
|
||||||
|
StringSchema,
|
||||||
|
};
|
||||||
|
|
||||||
|
use proxmox::const_regex;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
PROXMOX_SAFE_ID_FORMAT, SHA256_HEX_REGEX, SINGLE_LINE_COMMENT_SCHEMA, CryptMode, UPID,
|
||||||
|
Fingerprint, Authid,
|
||||||
|
};
|
||||||
|
|
||||||
|
const_regex!{
|
||||||
|
pub BACKUP_TYPE_REGEX = concat!(r"^(", BACKUP_TYPE_RE!(), r")$");
|
||||||
|
|
||||||
|
pub BACKUP_ID_REGEX = concat!(r"^", BACKUP_ID_RE!(), r"$");
|
||||||
|
|
||||||
|
pub BACKUP_DATE_REGEX = concat!(r"^", BACKUP_TIME_RE!() ,r"$");
|
||||||
|
|
||||||
|
pub GROUP_PATH_REGEX = concat!(r"^(", BACKUP_TYPE_RE!(), ")/(", BACKUP_ID_RE!(), r")$");
|
||||||
|
|
||||||
|
pub BACKUP_FILE_REGEX = r"^.*\.([fd]idx|blob)$";
|
||||||
|
|
||||||
|
pub SNAPSHOT_PATH_REGEX = concat!(r"^", SNAPSHOT_PATH_REGEX_STR!(), r"$");
|
||||||
|
|
||||||
|
pub DATASTORE_MAP_REGEX = concat!(r"(:?", PROXMOX_SAFE_ID_REGEX_STR!(), r"=)?", PROXMOX_SAFE_ID_REGEX_STR!());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const CHUNK_DIGEST_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SHA256_HEX_REGEX);
|
||||||
|
|
||||||
|
pub const BACKUP_ARCHIVE_NAME_SCHEMA: Schema = StringSchema::new("Backup archive name.")
|
||||||
|
.format(&PROXMOX_SAFE_ID_FORMAT)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const BACKUP_ID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&BACKUP_ID_REGEX);
|
||||||
|
|
||||||
|
pub const BACKUP_ID_SCHEMA: Schema = StringSchema::new("Backup ID.")
|
||||||
|
.format(&BACKUP_ID_FORMAT)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const BACKUP_TYPE_SCHEMA: Schema = StringSchema::new("Backup type.")
|
||||||
|
.format(&ApiStringFormat::Enum(&[
|
||||||
|
EnumEntry::new("vm", "Virtual Machine Backup"),
|
||||||
|
EnumEntry::new("ct", "Container Backup"),
|
||||||
|
EnumEntry::new("host", "Host Backup"),
|
||||||
|
]))
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const BACKUP_TIME_SCHEMA: Schema = IntegerSchema::new("Backup time (Unix epoch.)")
|
||||||
|
.minimum(1_547_797_308)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const DATASTORE_SCHEMA: Schema = StringSchema::new("Datastore name.")
|
||||||
|
.format(&PROXMOX_SAFE_ID_FORMAT)
|
||||||
|
.min_length(3)
|
||||||
|
.max_length(32)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const CHUNK_DIGEST_SCHEMA: Schema = StringSchema::new("Chunk digest (SHA256).")
|
||||||
|
.format(&CHUNK_DIGEST_FORMAT)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const DATASTORE_MAP_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&DATASTORE_MAP_REGEX);
|
||||||
|
|
||||||
|
pub const DATASTORE_MAP_SCHEMA: Schema = StringSchema::new("Datastore mapping.")
|
||||||
|
.format(&DATASTORE_MAP_FORMAT)
|
||||||
|
.min_length(3)
|
||||||
|
.max_length(65)
|
||||||
|
.type_text("(<source>=)?<target>")
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const DATASTORE_MAP_ARRAY_SCHEMA: Schema = ArraySchema::new(
|
||||||
|
"Datastore mapping list.", &DATASTORE_MAP_SCHEMA)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const DATASTORE_MAP_LIST_SCHEMA: Schema = StringSchema::new(
|
||||||
|
"A list of Datastore mappings (or single datastore), comma separated. \
|
||||||
|
For example 'a=b,e' maps the source datastore 'a' to target 'b and \
|
||||||
|
all other sources to the default 'e'. If no default is given, only the \
|
||||||
|
specified sources are mapped.")
|
||||||
|
.format(&ApiStringFormat::PropertyString(&DATASTORE_MAP_ARRAY_SCHEMA))
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
properties: {
|
||||||
|
store: {
|
||||||
|
schema: DATASTORE_SCHEMA,
|
||||||
|
},
|
||||||
|
comment: {
|
||||||
|
optional: true,
|
||||||
|
schema: SINGLE_LINE_COMMENT_SCHEMA,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
/// Basic information about a datastore.
|
||||||
|
pub struct DataStoreListItem {
|
||||||
|
pub store: String,
|
||||||
|
pub comment: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
properties: {
|
||||||
|
"filename": {
|
||||||
|
schema: BACKUP_ARCHIVE_NAME_SCHEMA,
|
||||||
|
},
|
||||||
|
"crypt-mode": {
|
||||||
|
type: CryptMode,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
/// Basic information about archive files inside a backup snapshot.
|
||||||
|
pub struct BackupContent {
|
||||||
|
pub filename: String,
|
||||||
|
/// Info if file is encrypted, signed, or neither.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub crypt_mode: Option<CryptMode>,
|
||||||
|
/// Archive size (from backup manifest).
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub size: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[api()]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
/// Result of a verify operation.
|
||||||
|
pub enum VerifyState {
|
||||||
|
/// Verification was successful
|
||||||
|
Ok,
|
||||||
|
/// Verification reported one or more errors
|
||||||
|
Failed,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
properties: {
|
||||||
|
upid: {
|
||||||
|
type: UPID,
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
type: VerifyState,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
/// Task properties.
|
||||||
|
pub struct SnapshotVerifyState {
|
||||||
|
/// UPID of the verify task
|
||||||
|
pub upid: UPID,
|
||||||
|
/// State of the verification. Enum.
|
||||||
|
pub state: VerifyState,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
properties: {
|
||||||
|
"backup-type": {
|
||||||
|
schema: BACKUP_TYPE_SCHEMA,
|
||||||
|
},
|
||||||
|
"backup-id": {
|
||||||
|
schema: BACKUP_ID_SCHEMA,
|
||||||
|
},
|
||||||
|
"backup-time": {
|
||||||
|
schema: BACKUP_TIME_SCHEMA,
|
||||||
|
},
|
||||||
|
comment: {
|
||||||
|
schema: SINGLE_LINE_COMMENT_SCHEMA,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
verification: {
|
||||||
|
type: SnapshotVerifyState,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
fingerprint: {
|
||||||
|
type: String,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
files: {
|
||||||
|
items: {
|
||||||
|
schema: BACKUP_ARCHIVE_NAME_SCHEMA
|
||||||
|
},
|
||||||
|
},
|
||||||
|
owner: {
|
||||||
|
type: Authid,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
/// Basic information about backup snapshot.
|
||||||
|
pub struct SnapshotListItem {
|
||||||
|
pub backup_type: String, // enum
|
||||||
|
pub backup_id: String,
|
||||||
|
pub backup_time: i64,
|
||||||
|
/// The first line from manifest "notes"
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub comment: Option<String>,
|
||||||
|
/// The result of the last run verify task
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub verification: Option<SnapshotVerifyState>,
|
||||||
|
/// Fingerprint of encryption key
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub fingerprint: Option<Fingerprint>,
|
||||||
|
/// List of contained archive files.
|
||||||
|
pub files: Vec<BackupContent>,
|
||||||
|
/// Overall snapshot size (sum of all archive sizes).
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub size: Option<u64>,
|
||||||
|
/// The owner of the snapshots group
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub owner: Option<Authid>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
properties: {
|
||||||
|
"backup-type": {
|
||||||
|
schema: BACKUP_TYPE_SCHEMA,
|
||||||
|
},
|
||||||
|
"backup-id": {
|
||||||
|
schema: BACKUP_ID_SCHEMA,
|
||||||
|
},
|
||||||
|
"last-backup": {
|
||||||
|
schema: BACKUP_TIME_SCHEMA,
|
||||||
|
},
|
||||||
|
"backup-count": {
|
||||||
|
type: Integer,
|
||||||
|
},
|
||||||
|
files: {
|
||||||
|
items: {
|
||||||
|
schema: BACKUP_ARCHIVE_NAME_SCHEMA
|
||||||
|
},
|
||||||
|
},
|
||||||
|
owner: {
|
||||||
|
type: Authid,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
/// Basic information about a backup group.
|
||||||
|
pub struct GroupListItem {
|
||||||
|
pub backup_type: String, // enum
|
||||||
|
pub backup_id: String,
|
||||||
|
pub last_backup: i64,
|
||||||
|
/// Number of contained snapshots
|
||||||
|
pub backup_count: u64,
|
||||||
|
/// List of contained archive files.
|
||||||
|
pub files: Vec<String>,
|
||||||
|
/// The owner of group
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub owner: Option<Authid>,
|
||||||
|
/// The first line from group "notes"
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub comment: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
properties: {
|
||||||
|
"backup-type": {
|
||||||
|
schema: BACKUP_TYPE_SCHEMA,
|
||||||
|
},
|
||||||
|
"backup-id": {
|
||||||
|
schema: BACKUP_ID_SCHEMA,
|
||||||
|
},
|
||||||
|
"backup-time": {
|
||||||
|
schema: BACKUP_TIME_SCHEMA,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
/// Prune result.
|
||||||
|
pub struct PruneListItem {
|
||||||
|
pub backup_type: String, // enum
|
||||||
|
pub backup_id: String,
|
||||||
|
pub backup_time: i64,
|
||||||
|
/// Keep snapshot
|
||||||
|
pub keep: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
properties: {
|
||||||
|
ct: {
|
||||||
|
type: TypeCounts,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
host: {
|
||||||
|
type: TypeCounts,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
vm: {
|
||||||
|
type: TypeCounts,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
other: {
|
||||||
|
type: TypeCounts,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
#[derive(Serialize, Deserialize, Default)]
|
||||||
|
/// Counts of groups/snapshots per BackupType.
|
||||||
|
pub struct Counts {
|
||||||
|
/// The counts for CT backups
|
||||||
|
pub ct: Option<TypeCounts>,
|
||||||
|
/// The counts for Host backups
|
||||||
|
pub host: Option<TypeCounts>,
|
||||||
|
/// The counts for VM backups
|
||||||
|
pub vm: Option<TypeCounts>,
|
||||||
|
/// The counts for other backup types
|
||||||
|
pub other: Option<TypeCounts>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[api()]
|
||||||
|
#[derive(Serialize, Deserialize, Default)]
|
||||||
|
/// Backup Type group/snapshot counts.
|
||||||
|
pub struct TypeCounts {
|
||||||
|
/// The number of groups of the type.
|
||||||
|
pub groups: u64,
|
||||||
|
/// The number of snapshots of the type.
|
||||||
|
pub snapshots: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub const ADMIN_DATASTORE_LIST_SNAPSHOTS_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
|
optional: false,
|
||||||
|
schema: &ArraySchema::new(
|
||||||
|
"Returns the list of snapshots.",
|
||||||
|
&SnapshotListItem::API_SCHEMA,
|
||||||
|
).schema(),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ADMIN_DATASTORE_LIST_SNAPSHOT_FILES_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
|
optional: false,
|
||||||
|
schema: &ArraySchema::new(
|
||||||
|
"Returns the list of archive files inside a backup snapshots.",
|
||||||
|
&BackupContent::API_SCHEMA,
|
||||||
|
).schema(),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ADMIN_DATASTORE_LIST_GROUPS_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
|
optional: false,
|
||||||
|
schema: &ArraySchema::new(
|
||||||
|
"Returns the list of backup groups.",
|
||||||
|
&GroupListItem::API_SCHEMA,
|
||||||
|
).schema(),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ADMIN_DATASTORE_PRUNE_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
|
optional: false,
|
||||||
|
schema: &ArraySchema::new(
|
||||||
|
"Returns the list of snapshots and a flag indicating if there are kept or removed.",
|
||||||
|
&PruneListItem::API_SCHEMA,
|
||||||
|
).schema(),
|
||||||
|
};
|
|
@ -1,10 +1,11 @@
|
||||||
//! Basic API types used by most of the PBS code.
|
//! Basic API types used by most of the PBS code.
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use anyhow::bail;
|
||||||
|
|
||||||
use proxmox::api::api;
|
use proxmox::api::api;
|
||||||
use proxmox::api::schema::{
|
use proxmox::api::schema::{
|
||||||
ApiStringFormat, ApiType, ArraySchema, EnumEntry, IntegerSchema, ReturnType, Schema,
|
ApiStringFormat, ApiType, ArraySchema, IntegerSchema, ReturnType, Schema,
|
||||||
StringSchema,
|
StringSchema,
|
||||||
};
|
};
|
||||||
use proxmox::const_regex;
|
use proxmox::const_regex;
|
||||||
|
@ -34,6 +35,12 @@ macro_rules! SNAPSHOT_PATH_REGEX_STR {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod acl;
|
||||||
|
pub use acl::*;
|
||||||
|
|
||||||
|
mod datastore;
|
||||||
|
pub use datastore::*;
|
||||||
|
|
||||||
mod jobs;
|
mod jobs;
|
||||||
pub use jobs::*;
|
pub use jobs::*;
|
||||||
|
|
||||||
|
@ -73,6 +80,10 @@ pub use remote::*;
|
||||||
mod tape;
|
mod tape;
|
||||||
pub use tape::*;
|
pub use tape::*;
|
||||||
|
|
||||||
|
mod zfs;
|
||||||
|
pub use zfs::*;
|
||||||
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod local_macros {
|
mod local_macros {
|
||||||
|
@ -104,17 +115,7 @@ const_regex! {
|
||||||
|
|
||||||
pub UUID_REGEX = r"^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$";
|
pub UUID_REGEX = r"^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$";
|
||||||
|
|
||||||
pub BACKUP_TYPE_REGEX = concat!(r"^(", BACKUP_TYPE_RE!(), r")$");
|
pub SYSTEMD_DATETIME_REGEX = r"^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$"; // fixme: define in common_regex ?
|
||||||
|
|
||||||
pub BACKUP_ID_REGEX = concat!(r"^", BACKUP_ID_RE!(), r"$");
|
|
||||||
|
|
||||||
pub BACKUP_DATE_REGEX = concat!(r"^", BACKUP_TIME_RE!() ,r"$");
|
|
||||||
|
|
||||||
pub GROUP_PATH_REGEX = concat!(r"^(", BACKUP_TYPE_RE!(), ")/(", BACKUP_ID_RE!(), r")$");
|
|
||||||
|
|
||||||
pub BACKUP_FILE_REGEX = r"^.*\.([fd]idx|blob)$";
|
|
||||||
|
|
||||||
pub SNAPSHOT_PATH_REGEX = concat!(r"^", SNAPSHOT_PATH_REGEX_STR!(), r"$");
|
|
||||||
|
|
||||||
pub FINGERPRINT_SHA256_REGEX = r"^(?:[0-9a-fA-F][0-9a-fA-F])(?::[0-9a-fA-F][0-9a-fA-F]){31}$";
|
pub FINGERPRINT_SHA256_REGEX = r"^(?:[0-9a-fA-F][0-9a-fA-F])(?::[0-9a-fA-F][0-9a-fA-F]){31}$";
|
||||||
|
|
||||||
|
@ -138,6 +139,7 @@ const_regex! {
|
||||||
);
|
);
|
||||||
|
|
||||||
pub BLOCKDEVICE_NAME_REGEX = r"^(:?(:?h|s|x?v)d[a-z]+)|(:?nvme\d+n\d+)$";
|
pub BLOCKDEVICE_NAME_REGEX = r"^(:?(:?h|s|x?v)d[a-z]+)|(:?nvme\d+n\d+)$";
|
||||||
|
pub SUBSCRIPTION_KEY_REGEX = concat!(r"^pbs(?:[cbsp])-[0-9a-f]{10}$");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const IP_V4_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&IP_V4_REGEX);
|
pub const IP_V4_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&IP_V4_REGEX);
|
||||||
|
@ -146,6 +148,38 @@ pub const IP_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&IP_REGEX);
|
||||||
pub const CIDR_V4_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_V4_REGEX);
|
pub const CIDR_V4_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_V4_REGEX);
|
||||||
pub const CIDR_V6_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_V6_REGEX);
|
pub const CIDR_V6_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_V6_REGEX);
|
||||||
pub const CIDR_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_REGEX);
|
pub const CIDR_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_REGEX);
|
||||||
|
pub const PVE_CONFIG_DIGEST_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SHA256_HEX_REGEX);
|
||||||
|
pub const PASSWORD_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&PASSWORD_REGEX);
|
||||||
|
pub const UUID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&UUID_REGEX);
|
||||||
|
pub const BLOCKDEVICE_NAME_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&BLOCKDEVICE_NAME_REGEX);
|
||||||
|
pub const SUBSCRIPTION_KEY_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SUBSCRIPTION_KEY_REGEX);
|
||||||
|
pub const SYSTEMD_DATETIME_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SYSTEMD_DATETIME_REGEX);
|
||||||
|
pub const HOSTNAME_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&HOSTNAME_REGEX);
|
||||||
|
|
||||||
|
pub const DNS_ALIAS_FORMAT: ApiStringFormat =
|
||||||
|
ApiStringFormat::Pattern(&DNS_ALIAS_REGEX);
|
||||||
|
|
||||||
|
pub const SEARCH_DOMAIN_SCHEMA: Schema =
|
||||||
|
StringSchema::new("Search domain for host-name lookup.").schema();
|
||||||
|
|
||||||
|
pub const FIRST_DNS_SERVER_SCHEMA: Schema =
|
||||||
|
StringSchema::new("First name server IP address.")
|
||||||
|
.format(&IP_FORMAT)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const SECOND_DNS_SERVER_SCHEMA: Schema =
|
||||||
|
StringSchema::new("Second name server IP address.")
|
||||||
|
.format(&IP_FORMAT)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const THIRD_DNS_SERVER_SCHEMA: Schema =
|
||||||
|
StringSchema::new("Third name server IP address.")
|
||||||
|
.format(&IP_FORMAT)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const HOSTNAME_SCHEMA: Schema = StringSchema::new("Hostname (as defined in RFC1123).")
|
||||||
|
.format(&HOSTNAME_FORMAT)
|
||||||
|
.schema();
|
||||||
|
|
||||||
pub const DNS_NAME_FORMAT: ApiStringFormat =
|
pub const DNS_NAME_FORMAT: ApiStringFormat =
|
||||||
ApiStringFormat::Pattern(&DNS_NAME_REGEX);
|
ApiStringFormat::Pattern(&DNS_NAME_REGEX);
|
||||||
|
@ -157,24 +191,48 @@ pub const DNS_NAME_OR_IP_SCHEMA: Schema = StringSchema::new("DNS name or IP addr
|
||||||
.format(&DNS_NAME_OR_IP_FORMAT)
|
.format(&DNS_NAME_OR_IP_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const BACKUP_ID_SCHEMA: Schema = StringSchema::new("Backup ID.")
|
pub const NODE_SCHEMA: Schema = StringSchema::new("Node name (or 'localhost')")
|
||||||
.format(&BACKUP_ID_FORMAT)
|
.format(&ApiStringFormat::VerifyFn(|node| {
|
||||||
.schema();
|
if node == "localhost" || node == proxmox::tools::nodename() {
|
||||||
pub const BACKUP_TYPE_SCHEMA: Schema = StringSchema::new("Backup type.")
|
Ok(())
|
||||||
.format(&ApiStringFormat::Enum(&[
|
} else {
|
||||||
EnumEntry::new("vm", "Virtual Machine Backup"),
|
bail!("no such node '{}'", node);
|
||||||
EnumEntry::new("ct", "Container Backup"),
|
}
|
||||||
EnumEntry::new("host", "Host Backup"),
|
}))
|
||||||
]))
|
|
||||||
.schema();
|
|
||||||
pub const BACKUP_TIME_SCHEMA: Schema = IntegerSchema::new("Backup time (Unix epoch.)")
|
|
||||||
.minimum(1_547_797_308)
|
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const DATASTORE_SCHEMA: Schema = StringSchema::new("Datastore name.")
|
pub const TIME_ZONE_SCHEMA: Schema = StringSchema::new(
|
||||||
.format(&PROXMOX_SAFE_ID_FORMAT)
|
"Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.")
|
||||||
|
.format(&SINGLE_LINE_COMMENT_FORMAT)
|
||||||
|
.min_length(2)
|
||||||
|
.max_length(64)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const BLOCKDEVICE_NAME_SCHEMA: Schema = StringSchema::new("Block device name (/sys/block/<name>).")
|
||||||
|
.format(&BLOCKDEVICE_NAME_FORMAT)
|
||||||
.min_length(3)
|
.min_length(3)
|
||||||
.max_length(32)
|
.max_length(64)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const DISK_ARRAY_SCHEMA: Schema = ArraySchema::new(
|
||||||
|
"Disk name list.", &BLOCKDEVICE_NAME_SCHEMA)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const DISK_LIST_SCHEMA: Schema = StringSchema::new(
|
||||||
|
"A list of disk names, comma separated.")
|
||||||
|
.format(&ApiStringFormat::PropertyString(&DISK_ARRAY_SCHEMA))
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const PASSWORD_SCHEMA: Schema = StringSchema::new("Password.")
|
||||||
|
.format(&PASSWORD_FORMAT)
|
||||||
|
.min_length(1)
|
||||||
|
.max_length(1024)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.")
|
||||||
|
.format(&PASSWORD_FORMAT)
|
||||||
|
.min_length(5)
|
||||||
|
.max_length(64)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const REALM_ID_SCHEMA: Schema = StringSchema::new("Realm name.")
|
pub const REALM_ID_SCHEMA: Schema = StringSchema::new("Realm name.")
|
||||||
|
@ -229,6 +287,16 @@ pub const SINGLE_LINE_COMMENT_SCHEMA: Schema = StringSchema::new("Comment (singl
|
||||||
.format(&SINGLE_LINE_COMMENT_FORMAT)
|
.format(&SINGLE_LINE_COMMENT_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
pub const SUBSCRIPTION_KEY_SCHEMA: Schema = StringSchema::new("Proxmox Backup Server subscription key.")
|
||||||
|
.format(&SUBSCRIPTION_KEY_FORMAT)
|
||||||
|
.min_length(15)
|
||||||
|
.max_length(16)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const SERVICE_ID_SCHEMA: Schema = StringSchema::new("Service ID.")
|
||||||
|
.max_length(256)
|
||||||
|
.schema();
|
||||||
|
|
||||||
pub const PROXMOX_CONFIG_DIGEST_SCHEMA: Schema = StringSchema::new(
|
pub const PROXMOX_CONFIG_DIGEST_SCHEMA: Schema = StringSchema::new(
|
||||||
"Prevent changes if current configuration file has different \
|
"Prevent changes if current configuration file has different \
|
||||||
SHA256 digest. This can be used to prevent concurrent \
|
SHA256 digest. This can be used to prevent concurrent \
|
||||||
|
@ -237,8 +305,6 @@ pub const PROXMOX_CONFIG_DIGEST_SCHEMA: Schema = StringSchema::new(
|
||||||
.format(&PVE_CONFIG_DIGEST_FORMAT)
|
.format(&PVE_CONFIG_DIGEST_FORMAT)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
pub const BACKUP_ID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&BACKUP_ID_REGEX);
|
|
||||||
|
|
||||||
/// API schema format definition for repository URLs
|
/// API schema format definition for repository URLs
|
||||||
pub const BACKUP_REPO_URL: ApiStringFormat = ApiStringFormat::Pattern(&BACKUP_REPO_URL_REGEX);
|
pub const BACKUP_REPO_URL: ApiStringFormat = ApiStringFormat::Pattern(&BACKUP_REPO_URL_REGEX);
|
||||||
|
|
||||||
|
@ -295,219 +361,8 @@ impl Default for GarbageCollectionStatus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const PVE_CONFIG_DIGEST_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SHA256_HEX_REGEX);
|
|
||||||
pub const CHUNK_DIGEST_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SHA256_HEX_REGEX);
|
|
||||||
|
|
||||||
pub const PASSWORD_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&PASSWORD_REGEX);
|
|
||||||
|
|
||||||
pub const UUID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&UUID_REGEX);
|
|
||||||
|
|
||||||
pub const BACKUP_ARCHIVE_NAME_SCHEMA: Schema = StringSchema::new("Backup archive name.")
|
|
||||||
.format(&PROXMOX_SAFE_ID_FORMAT)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
// Complex type definitions
|
// Complex type definitions
|
||||||
|
|
||||||
#[api(
|
|
||||||
properties: {
|
|
||||||
"filename": {
|
|
||||||
schema: BACKUP_ARCHIVE_NAME_SCHEMA,
|
|
||||||
},
|
|
||||||
"crypt-mode": {
|
|
||||||
type: CryptMode,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
/// Basic information about archive files inside a backup snapshot.
|
|
||||||
pub struct BackupContent {
|
|
||||||
pub filename: String,
|
|
||||||
/// Info if file is encrypted, signed, or neither.
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub crypt_mode: Option<CryptMode>,
|
|
||||||
/// Archive size (from backup manifest).
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub size: Option<u64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api()]
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "lowercase")]
|
|
||||||
/// Result of a verify operation.
|
|
||||||
pub enum VerifyState {
|
|
||||||
/// Verification was successful
|
|
||||||
Ok,
|
|
||||||
/// Verification reported one or more errors
|
|
||||||
Failed,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api(
|
|
||||||
properties: {
|
|
||||||
upid: {
|
|
||||||
type: UPID,
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
type: VerifyState,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
/// Task properties.
|
|
||||||
pub struct SnapshotVerifyState {
|
|
||||||
/// UPID of the verify task
|
|
||||||
pub upid: UPID,
|
|
||||||
/// State of the verification. Enum.
|
|
||||||
pub state: VerifyState,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api(
|
|
||||||
properties: {
|
|
||||||
"backup-type": {
|
|
||||||
schema: BACKUP_TYPE_SCHEMA,
|
|
||||||
},
|
|
||||||
"backup-id": {
|
|
||||||
schema: BACKUP_ID_SCHEMA,
|
|
||||||
},
|
|
||||||
"backup-time": {
|
|
||||||
schema: BACKUP_TIME_SCHEMA,
|
|
||||||
},
|
|
||||||
comment: {
|
|
||||||
schema: SINGLE_LINE_COMMENT_SCHEMA,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
verification: {
|
|
||||||
type: SnapshotVerifyState,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
fingerprint: {
|
|
||||||
type: String,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
files: {
|
|
||||||
items: {
|
|
||||||
schema: BACKUP_ARCHIVE_NAME_SCHEMA
|
|
||||||
},
|
|
||||||
},
|
|
||||||
owner: {
|
|
||||||
type: Authid,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
/// Basic information about backup snapshot.
|
|
||||||
pub struct SnapshotListItem {
|
|
||||||
pub backup_type: String, // enum
|
|
||||||
pub backup_id: String,
|
|
||||||
pub backup_time: i64,
|
|
||||||
/// The first line from manifest "notes"
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub comment: Option<String>,
|
|
||||||
/// The result of the last run verify task
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub verification: Option<SnapshotVerifyState>,
|
|
||||||
/// Fingerprint of encryption key
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub fingerprint: Option<Fingerprint>,
|
|
||||||
/// List of contained archive files.
|
|
||||||
pub files: Vec<BackupContent>,
|
|
||||||
/// Overall snapshot size (sum of all archive sizes).
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub size: Option<u64>,
|
|
||||||
/// The owner of the snapshots group
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub owner: Option<Authid>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api(
|
|
||||||
properties: {
|
|
||||||
"backup-type": {
|
|
||||||
schema: BACKUP_TYPE_SCHEMA,
|
|
||||||
},
|
|
||||||
"backup-id": {
|
|
||||||
schema: BACKUP_ID_SCHEMA,
|
|
||||||
},
|
|
||||||
"last-backup": {
|
|
||||||
schema: BACKUP_TIME_SCHEMA,
|
|
||||||
},
|
|
||||||
"backup-count": {
|
|
||||||
type: Integer,
|
|
||||||
},
|
|
||||||
files: {
|
|
||||||
items: {
|
|
||||||
schema: BACKUP_ARCHIVE_NAME_SCHEMA
|
|
||||||
},
|
|
||||||
},
|
|
||||||
owner: {
|
|
||||||
type: Authid,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
/// Basic information about a backup group.
|
|
||||||
pub struct GroupListItem {
|
|
||||||
pub backup_type: String, // enum
|
|
||||||
pub backup_id: String,
|
|
||||||
pub last_backup: i64,
|
|
||||||
/// Number of contained snapshots
|
|
||||||
pub backup_count: u64,
|
|
||||||
/// List of contained archive files.
|
|
||||||
pub files: Vec<String>,
|
|
||||||
/// The owner of group
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub owner: Option<Authid>,
|
|
||||||
/// The first line from group "notes"
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub comment: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api(
|
|
||||||
properties: {
|
|
||||||
store: {
|
|
||||||
schema: DATASTORE_SCHEMA,
|
|
||||||
},
|
|
||||||
comment: {
|
|
||||||
optional: true,
|
|
||||||
schema: SINGLE_LINE_COMMENT_SCHEMA,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
/// Basic information about a datastore.
|
|
||||||
pub struct DataStoreListItem {
|
|
||||||
pub store: String,
|
|
||||||
pub comment: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api(
|
|
||||||
properties: {
|
|
||||||
"backup-type": {
|
|
||||||
schema: BACKUP_TYPE_SCHEMA,
|
|
||||||
},
|
|
||||||
"backup-id": {
|
|
||||||
schema: BACKUP_ID_SCHEMA,
|
|
||||||
},
|
|
||||||
"backup-time": {
|
|
||||||
schema: BACKUP_TIME_SCHEMA,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
/// Prune result.
|
|
||||||
pub struct PruneListItem {
|
|
||||||
pub backup_type: String, // enum
|
|
||||||
pub backup_id: String,
|
|
||||||
pub backup_time: i64,
|
|
||||||
/// Keep snapshot
|
|
||||||
pub keep: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api()]
|
#[api()]
|
||||||
#[derive(Default, Serialize, Deserialize)]
|
#[derive(Default, Serialize, Deserialize)]
|
||||||
|
@ -521,49 +376,6 @@ pub struct StorageStatus {
|
||||||
pub avail: u64,
|
pub avail: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api()]
|
|
||||||
#[derive(Serialize, Deserialize, Default)]
|
|
||||||
/// Backup Type group/snapshot counts.
|
|
||||||
pub struct TypeCounts {
|
|
||||||
/// The number of groups of the type.
|
|
||||||
pub groups: u64,
|
|
||||||
/// The number of snapshots of the type.
|
|
||||||
pub snapshots: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api(
|
|
||||||
properties: {
|
|
||||||
ct: {
|
|
||||||
type: TypeCounts,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
host: {
|
|
||||||
type: TypeCounts,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
vm: {
|
|
||||||
type: TypeCounts,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
other: {
|
|
||||||
type: TypeCounts,
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)]
|
|
||||||
#[derive(Serialize, Deserialize, Default)]
|
|
||||||
/// Counts of groups/snapshots per BackupType.
|
|
||||||
pub struct Counts {
|
|
||||||
/// The counts for CT backups
|
|
||||||
pub ct: Option<TypeCounts>,
|
|
||||||
/// The counts for Host backups
|
|
||||||
pub host: Option<TypeCounts>,
|
|
||||||
/// The counts for VM backups
|
|
||||||
pub vm: Option<TypeCounts>,
|
|
||||||
/// The counts for other backup types
|
|
||||||
pub other: Option<TypeCounts>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const PASSWORD_HINT_SCHEMA: Schema = StringSchema::new("Password hint.")
|
pub const PASSWORD_HINT_SCHEMA: Schema = StringSchema::new("Password hint.")
|
||||||
.format(&SINGLE_LINE_COMMENT_FORMAT)
|
.format(&SINGLE_LINE_COMMENT_FORMAT)
|
||||||
.min_length(1)
|
.min_length(1)
|
||||||
|
@ -634,37 +446,6 @@ pub struct TaskListItem {
|
||||||
pub status: Option<String>,
|
pub status: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ADMIN_DATASTORE_LIST_SNAPSHOTS_RETURN_TYPE: ReturnType = ReturnType {
|
|
||||||
optional: false,
|
|
||||||
schema: &ArraySchema::new(
|
|
||||||
"Returns the list of snapshots.",
|
|
||||||
&SnapshotListItem::API_SCHEMA,
|
|
||||||
).schema(),
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ADMIN_DATASTORE_LIST_SNAPSHOT_FILES_RETURN_TYPE: ReturnType = ReturnType {
|
|
||||||
optional: false,
|
|
||||||
schema: &ArraySchema::new(
|
|
||||||
"Returns the list of archive files inside a backup snapshots.",
|
|
||||||
&BackupContent::API_SCHEMA,
|
|
||||||
).schema(),
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ADMIN_DATASTORE_LIST_GROUPS_RETURN_TYPE: ReturnType = ReturnType {
|
|
||||||
optional: false,
|
|
||||||
schema: &ArraySchema::new(
|
|
||||||
"Returns the list of backup groups.",
|
|
||||||
&GroupListItem::API_SCHEMA,
|
|
||||||
).schema(),
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ADMIN_DATASTORE_PRUNE_RETURN_TYPE: ReturnType = ReturnType {
|
|
||||||
optional: false,
|
|
||||||
schema: &ArraySchema::new(
|
|
||||||
"Returns the list of snapshots and a flag indicating if there are kept or removed.",
|
|
||||||
&PruneListItem::API_SCHEMA,
|
|
||||||
).schema(),
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const NODE_TASKS_LIST_TASKS_RETURN_TYPE: ReturnType = ReturnType {
|
pub const NODE_TASKS_LIST_TASKS_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
optional: false,
|
optional: false,
|
||||||
|
@ -703,3 +484,42 @@ pub struct APTUpdateInfo {
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if="Option::is_none")]
|
||||||
pub extra_info: Option<String>,
|
pub extra_info: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[api()]
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "UPPERCASE")]
|
||||||
|
pub enum RRDMode {
|
||||||
|
/// Maximum
|
||||||
|
Max,
|
||||||
|
/// Average
|
||||||
|
Average,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[api()]
|
||||||
|
#[repr(u64)]
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum RRDTimeFrameResolution {
|
||||||
|
/// 1 min => last 70 minutes
|
||||||
|
Hour = 60,
|
||||||
|
/// 30 min => last 35 hours
|
||||||
|
Day = 60*30,
|
||||||
|
/// 3 hours => about 8 days
|
||||||
|
Week = 60*180,
|
||||||
|
/// 12 hours => last 35 days
|
||||||
|
Month = 60*720,
|
||||||
|
/// 1 week => last 490 days
|
||||||
|
Year = 60*10080,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[api()]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
/// Node Power command type.
|
||||||
|
pub enum NodePowerCommand {
|
||||||
|
/// Restart the server
|
||||||
|
Reboot,
|
||||||
|
/// Shutdown the server
|
||||||
|
Shutdown,
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use proxmox::api::{api, schema::*};
|
||||||
|
|
||||||
|
use proxmox::const_regex;
|
||||||
|
|
||||||
|
const_regex! {
|
||||||
|
pub ZPOOL_NAME_REGEX = r"^[a-zA-Z][a-z0-9A-Z\-_.:]+$";
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ZFS_ASHIFT_SCHEMA: Schema = IntegerSchema::new(
|
||||||
|
"Pool sector size exponent.")
|
||||||
|
.minimum(9)
|
||||||
|
.maximum(16)
|
||||||
|
.default(12)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
pub const ZPOOL_NAME_SCHEMA: Schema = StringSchema::new("ZFS Pool Name")
|
||||||
|
.format(&ApiStringFormat::Pattern(&ZPOOL_NAME_REGEX))
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
#[api(default: "On")]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
/// The ZFS compression algorithm to use.
|
||||||
|
pub enum ZfsCompressionType {
|
||||||
|
/// Gnu Zip
|
||||||
|
Gzip,
|
||||||
|
/// LZ4
|
||||||
|
Lz4,
|
||||||
|
/// LZJB
|
||||||
|
Lzjb,
|
||||||
|
/// ZLE
|
||||||
|
Zle,
|
||||||
|
/// ZStd
|
||||||
|
ZStd,
|
||||||
|
/// Enable compression using the default algorithm.
|
||||||
|
On,
|
||||||
|
/// Disable compression.
|
||||||
|
Off,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[api()]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
/// The ZFS RAID level to use.
|
||||||
|
pub enum ZfsRaidLevel {
|
||||||
|
/// Single Disk
|
||||||
|
Single,
|
||||||
|
/// Mirror
|
||||||
|
Mirror,
|
||||||
|
/// Raid10
|
||||||
|
Raid10,
|
||||||
|
/// RaidZ
|
||||||
|
RaidZ,
|
||||||
|
/// RaidZ2
|
||||||
|
RaidZ2,
|
||||||
|
/// RaidZ3
|
||||||
|
RaidZ3,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[api()]
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all="kebab-case")]
|
||||||
|
/// zpool list item
|
||||||
|
pub struct ZpoolListItem {
|
||||||
|
/// zpool name
|
||||||
|
pub name: String,
|
||||||
|
/// Health
|
||||||
|
pub health: String,
|
||||||
|
/// Total size
|
||||||
|
pub size: u64,
|
||||||
|
/// Used size
|
||||||
|
pub alloc: u64,
|
||||||
|
/// Free space
|
||||||
|
pub free: u64,
|
||||||
|
/// ZFS fragnentation level
|
||||||
|
pub frag: u64,
|
||||||
|
/// ZFS deduplication ratio
|
||||||
|
pub dedup: f64,
|
||||||
|
}
|
|
@ -8,230 +8,11 @@ use anyhow::{bail, Error};
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
use ::serde::{Deserialize, Serialize};
|
use proxmox::api::schema::{Schema, StringSchema, ApiStringFormat, ApiType};
|
||||||
use serde::de::{value, IntoDeserializer};
|
|
||||||
|
|
||||||
use proxmox::api::{api, schema::*};
|
use pbs_api_types::{Authid, Userid, Role, ROLE_NAME_NO_ACCESS};
|
||||||
use proxmox::constnamedbitmap;
|
|
||||||
|
|
||||||
use crate::api2::types::{Authid, Userid};
|
use crate::{open_backup_lockfile, replace_backup_config, BackupLockGuard};
|
||||||
|
|
||||||
// define Privilege bitfield
|
|
||||||
|
|
||||||
constnamedbitmap! {
|
|
||||||
/// Contains a list of privilege name to privilege value mappings.
|
|
||||||
///
|
|
||||||
/// The names are used when displaying/persisting privileges anywhere, the values are used to
|
|
||||||
/// allow easy matching of privileges as bitflags.
|
|
||||||
PRIVILEGES: u64 => {
|
|
||||||
/// Sys.Audit allows knowing about the system and its status
|
|
||||||
PRIV_SYS_AUDIT("Sys.Audit");
|
|
||||||
/// Sys.Modify allows modifying system-level configuration
|
|
||||||
PRIV_SYS_MODIFY("Sys.Modify");
|
|
||||||
/// Sys.Modify allows to poweroff/reboot/.. the system
|
|
||||||
PRIV_SYS_POWER_MANAGEMENT("Sys.PowerManagement");
|
|
||||||
|
|
||||||
/// Datastore.Audit allows knowing about a datastore,
|
|
||||||
/// including reading the configuration entry and listing its contents
|
|
||||||
PRIV_DATASTORE_AUDIT("Datastore.Audit");
|
|
||||||
/// Datastore.Allocate allows creating or deleting datastores
|
|
||||||
PRIV_DATASTORE_ALLOCATE("Datastore.Allocate");
|
|
||||||
/// Datastore.Modify allows modifying a datastore and its contents
|
|
||||||
PRIV_DATASTORE_MODIFY("Datastore.Modify");
|
|
||||||
/// Datastore.Read allows reading arbitrary backup contents
|
|
||||||
PRIV_DATASTORE_READ("Datastore.Read");
|
|
||||||
/// Allows verifying a datastore
|
|
||||||
PRIV_DATASTORE_VERIFY("Datastore.Verify");
|
|
||||||
|
|
||||||
/// Datastore.Backup allows Datastore.Read|Verify and creating new snapshots,
|
|
||||||
/// but also requires backup ownership
|
|
||||||
PRIV_DATASTORE_BACKUP("Datastore.Backup");
|
|
||||||
/// Datastore.Prune allows deleting snapshots,
|
|
||||||
/// but also requires backup ownership
|
|
||||||
PRIV_DATASTORE_PRUNE("Datastore.Prune");
|
|
||||||
|
|
||||||
/// Permissions.Modify allows modifying ACLs
|
|
||||||
PRIV_PERMISSIONS_MODIFY("Permissions.Modify");
|
|
||||||
|
|
||||||
/// Remote.Audit allows reading remote.cfg and sync.cfg entries
|
|
||||||
PRIV_REMOTE_AUDIT("Remote.Audit");
|
|
||||||
/// Remote.Modify allows modifying remote.cfg
|
|
||||||
PRIV_REMOTE_MODIFY("Remote.Modify");
|
|
||||||
/// Remote.Read allows reading data from a configured `Remote`
|
|
||||||
PRIV_REMOTE_READ("Remote.Read");
|
|
||||||
|
|
||||||
/// Sys.Console allows access to the system's console
|
|
||||||
PRIV_SYS_CONSOLE("Sys.Console");
|
|
||||||
|
|
||||||
/// Tape.Audit allows reading tape backup configuration and status
|
|
||||||
PRIV_TAPE_AUDIT("Tape.Audit");
|
|
||||||
/// Tape.Modify allows modifying tape backup configuration
|
|
||||||
PRIV_TAPE_MODIFY("Tape.Modify");
|
|
||||||
/// Tape.Write allows writing tape media
|
|
||||||
PRIV_TAPE_WRITE("Tape.Write");
|
|
||||||
/// Tape.Read allows reading tape backup configuration and media contents
|
|
||||||
PRIV_TAPE_READ("Tape.Read");
|
|
||||||
|
|
||||||
/// Realm.Allocate allows viewing, creating, modifying and deleting realms
|
|
||||||
PRIV_REALM_ALLOCATE("Realm.Allocate");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Admin always has all privileges. It can do everything except a few actions
|
|
||||||
/// which are limited to the 'root@pam` superuser
|
|
||||||
pub const ROLE_ADMIN: u64 = std::u64::MAX;
|
|
||||||
|
|
||||||
/// NoAccess can be used to remove privileges from specific (sub-)paths
|
|
||||||
pub const ROLE_NO_ACCESS: u64 = 0;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::identity_op)]
|
|
||||||
/// Audit can view configuration and status information, but not modify it.
|
|
||||||
pub const ROLE_AUDIT: u64 = 0
|
|
||||||
| PRIV_SYS_AUDIT
|
|
||||||
| PRIV_DATASTORE_AUDIT;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::identity_op)]
|
|
||||||
/// Datastore.Admin can do anything on the datastore.
|
|
||||||
pub const ROLE_DATASTORE_ADMIN: u64 = 0
|
|
||||||
| PRIV_DATASTORE_AUDIT
|
|
||||||
| PRIV_DATASTORE_MODIFY
|
|
||||||
| PRIV_DATASTORE_READ
|
|
||||||
| PRIV_DATASTORE_VERIFY
|
|
||||||
| PRIV_DATASTORE_BACKUP
|
|
||||||
| PRIV_DATASTORE_PRUNE;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::identity_op)]
|
|
||||||
/// Datastore.Reader can read/verify datastore content and do restore
|
|
||||||
pub const ROLE_DATASTORE_READER: u64 = 0
|
|
||||||
| PRIV_DATASTORE_AUDIT
|
|
||||||
| PRIV_DATASTORE_VERIFY
|
|
||||||
| PRIV_DATASTORE_READ;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::identity_op)]
|
|
||||||
/// Datastore.Backup can do backup and restore, but no prune.
|
|
||||||
pub const ROLE_DATASTORE_BACKUP: u64 = 0
|
|
||||||
| PRIV_DATASTORE_BACKUP;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::identity_op)]
|
|
||||||
/// Datastore.PowerUser can do backup, restore, and prune.
|
|
||||||
pub const ROLE_DATASTORE_POWERUSER: u64 = 0
|
|
||||||
| PRIV_DATASTORE_PRUNE
|
|
||||||
| PRIV_DATASTORE_BACKUP;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::identity_op)]
|
|
||||||
/// Datastore.Audit can audit the datastore.
|
|
||||||
pub const ROLE_DATASTORE_AUDIT: u64 = 0
|
|
||||||
| PRIV_DATASTORE_AUDIT;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::identity_op)]
|
|
||||||
/// Remote.Audit can audit the remote
|
|
||||||
pub const ROLE_REMOTE_AUDIT: u64 = 0
|
|
||||||
| PRIV_REMOTE_AUDIT;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::identity_op)]
|
|
||||||
/// Remote.Admin can do anything on the remote.
|
|
||||||
pub const ROLE_REMOTE_ADMIN: u64 = 0
|
|
||||||
| PRIV_REMOTE_AUDIT
|
|
||||||
| PRIV_REMOTE_MODIFY
|
|
||||||
| PRIV_REMOTE_READ;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::identity_op)]
|
|
||||||
/// Remote.SyncOperator can do read and prune on the remote.
|
|
||||||
pub const ROLE_REMOTE_SYNC_OPERATOR: u64 = 0
|
|
||||||
| PRIV_REMOTE_AUDIT
|
|
||||||
| PRIV_REMOTE_READ;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::identity_op)]
|
|
||||||
/// Tape.Audit can audit the tape backup configuration and media content
|
|
||||||
pub const ROLE_TAPE_AUDIT: u64 = 0
|
|
||||||
| PRIV_TAPE_AUDIT;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::identity_op)]
|
|
||||||
/// Tape.Admin can do anything on the tape backup
|
|
||||||
pub const ROLE_TAPE_ADMIN: u64 = 0
|
|
||||||
| PRIV_TAPE_AUDIT
|
|
||||||
| PRIV_TAPE_MODIFY
|
|
||||||
| PRIV_TAPE_READ
|
|
||||||
| PRIV_TAPE_WRITE;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::identity_op)]
|
|
||||||
/// Tape.Operator can do tape backup and restore (but no configuration changes)
|
|
||||||
pub const ROLE_TAPE_OPERATOR: u64 = 0
|
|
||||||
| PRIV_TAPE_AUDIT
|
|
||||||
| PRIV_TAPE_READ
|
|
||||||
| PRIV_TAPE_WRITE;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::identity_op)]
|
|
||||||
/// Tape.Reader can do read and inspect tape content
|
|
||||||
pub const ROLE_TAPE_READER: u64 = 0
|
|
||||||
| PRIV_TAPE_AUDIT
|
|
||||||
| PRIV_TAPE_READ;
|
|
||||||
|
|
||||||
/// NoAccess can be used to remove privileges from specific (sub-)paths
|
|
||||||
pub const ROLE_NAME_NO_ACCESS: &str = "NoAccess";
|
|
||||||
|
|
||||||
#[api(
|
|
||||||
type_text: "<role>",
|
|
||||||
)]
|
|
||||||
#[repr(u64)]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
/// Enum representing roles via their [PRIVILEGES] combination.
|
|
||||||
///
|
|
||||||
/// Since privileges are implemented as bitflags, each unique combination of privileges maps to a
|
|
||||||
/// single, unique `u64` value that is used in this enum definition.
|
|
||||||
pub enum Role {
|
|
||||||
/// Administrator
|
|
||||||
Admin = ROLE_ADMIN,
|
|
||||||
/// Auditor
|
|
||||||
Audit = ROLE_AUDIT,
|
|
||||||
/// Disable Access
|
|
||||||
NoAccess = ROLE_NO_ACCESS,
|
|
||||||
/// Datastore Administrator
|
|
||||||
DatastoreAdmin = ROLE_DATASTORE_ADMIN,
|
|
||||||
/// Datastore Reader (inspect datastore content and do restores)
|
|
||||||
DatastoreReader = ROLE_DATASTORE_READER,
|
|
||||||
/// Datastore Backup (backup and restore owned backups)
|
|
||||||
DatastoreBackup = ROLE_DATASTORE_BACKUP,
|
|
||||||
/// Datastore PowerUser (backup, restore and prune owned backup)
|
|
||||||
DatastorePowerUser = ROLE_DATASTORE_POWERUSER,
|
|
||||||
/// Datastore Auditor
|
|
||||||
DatastoreAudit = ROLE_DATASTORE_AUDIT,
|
|
||||||
/// Remote Auditor
|
|
||||||
RemoteAudit = ROLE_REMOTE_AUDIT,
|
|
||||||
/// Remote Administrator
|
|
||||||
RemoteAdmin = ROLE_REMOTE_ADMIN,
|
|
||||||
/// Syncronisation Opertator
|
|
||||||
RemoteSyncOperator = ROLE_REMOTE_SYNC_OPERATOR,
|
|
||||||
/// Tape Auditor
|
|
||||||
TapeAudit = ROLE_TAPE_AUDIT,
|
|
||||||
/// Tape Administrator
|
|
||||||
TapeAdmin = ROLE_TAPE_ADMIN,
|
|
||||||
/// Tape Operator
|
|
||||||
TapeOperator = ROLE_TAPE_OPERATOR,
|
|
||||||
/// Tape Reader
|
|
||||||
TapeReader = ROLE_TAPE_READER,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Role {
|
|
||||||
type Err = value::Error;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
Self::deserialize(s.into_deserializer())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Map of pre-defined [Roles](Role) to their associated [privileges](PRIVILEGES) combination and
|
/// Map of pre-defined [Roles](Role) to their associated [privileges](PRIVILEGES) combination and
|
||||||
|
@ -253,7 +34,7 @@ lazy_static! {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn split_acl_path(path: &str) -> Vec<&str> {
|
pub fn split_acl_path(path: &str) -> Vec<&str> {
|
||||||
let items = path.split('/');
|
let items = path.split('/');
|
||||||
|
|
||||||
let mut components = vec![];
|
let mut components = vec![];
|
||||||
|
@ -791,8 +572,8 @@ impl AclTree {
|
||||||
Ok((tree, digest))
|
Ok((tree, digest))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
/// This is used for testing
|
||||||
pub(crate) fn from_raw(raw: &str) -> Result<Self, Error> {
|
pub fn from_raw(raw: &str) -> Result<Self, Error> {
|
||||||
let mut tree = Self::new();
|
let mut tree = Self::new();
|
||||||
for (linenr, line) in raw.lines().enumerate() {
|
for (linenr, line) in raw.lines().enumerate() {
|
||||||
let line = line.trim();
|
let line = line.trim();
|
||||||
|
@ -845,6 +626,11 @@ pub const ACL_CFG_FILENAME: &str = "/etc/proxmox-backup/acl.cfg";
|
||||||
/// Path used to lock the [AclTree] when modifying.
|
/// Path used to lock the [AclTree] when modifying.
|
||||||
pub const ACL_CFG_LOCKFILE: &str = "/etc/proxmox-backup/.acl.lck";
|
pub const ACL_CFG_LOCKFILE: &str = "/etc/proxmox-backup/.acl.lck";
|
||||||
|
|
||||||
|
/// Get exclusive lock
|
||||||
|
pub fn lock_config() -> Result<BackupLockGuard, Error> {
|
||||||
|
open_backup_lockfile(ACL_CFG_LOCKFILE, None, true)
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads the [AclTree] from the [default path](ACL_CFG_FILENAME).
|
/// Reads the [AclTree] from the [default path](ACL_CFG_FILENAME).
|
||||||
pub fn config() -> Result<(AclTree, [u8; 32]), Error> {
|
pub fn config() -> Result<(AclTree, [u8; 32]), Error> {
|
||||||
let path = PathBuf::from(ACL_CFG_FILENAME);
|
let path = PathBuf::from(ACL_CFG_FILENAME);
|
||||||
|
@ -911,7 +697,7 @@ pub fn save_config(acl: &AclTree) -> Result<(), Error> {
|
||||||
|
|
||||||
acl.write_config(&mut raw)?;
|
acl.write_config(&mut raw)?;
|
||||||
|
|
||||||
pbs_config::replace_backup_config(ACL_CFG_FILENAME, &raw)
|
replace_backup_config(ACL_CFG_FILENAME, &raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -919,7 +705,7 @@ mod test {
|
||||||
use super::AclTree;
|
use super::AclTree;
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
|
|
||||||
use crate::api2::types::Authid;
|
use pbs_api_types::Authid;
|
||||||
|
|
||||||
fn check_roles(tree: &AclTree, auth_id: &Authid, path: &str, expected_roles: &str) {
|
fn check_roles(tree: &AclTree, auth_id: &Authid, path: &str, expected_roles: &str) {
|
||||||
let path_vec = super::split_acl_path(path);
|
let path_vec = super::split_acl_path(path);
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod acl;
|
||||||
pub mod domains;
|
pub mod domains;
|
||||||
pub mod drive;
|
pub mod drive;
|
||||||
pub mod key_config;
|
pub mod key_config;
|
||||||
|
|
|
@ -4,14 +4,18 @@ use anyhow::{bail, Error};
|
||||||
|
|
||||||
use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
||||||
|
|
||||||
use crate::api2::types::*;
|
use pbs_api_types::{
|
||||||
use crate::config::acl;
|
Authid, AclListItem, Role,
|
||||||
use crate::config::acl::{Role, PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY};
|
ACL_PATH_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA, PROXMOX_GROUP_ID_SCHEMA,
|
||||||
|
ACL_PROPAGATE_SCHEMA, PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY,
|
||||||
|
};
|
||||||
|
|
||||||
|
use pbs_config::acl::AclTreeNode;
|
||||||
|
|
||||||
use crate::config::cached_user_info::CachedUserInfo;
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
use pbs_config::open_backup_lockfile;
|
|
||||||
|
|
||||||
fn extract_acl_node_data(
|
fn extract_acl_node_data(
|
||||||
node: &acl::AclTreeNode,
|
node: &AclTreeNode,
|
||||||
path: &str,
|
path: &str,
|
||||||
list: &mut Vec<AclListItem>,
|
list: &mut Vec<AclListItem>,
|
||||||
exact: bool,
|
exact: bool,
|
||||||
|
@ -110,7 +114,7 @@ pub fn read_acl(
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let (mut tree, digest) = acl::config()?;
|
let (mut tree, digest) = pbs_config::acl::config()?;
|
||||||
|
|
||||||
let mut list: Vec<AclListItem> = Vec::new();
|
let mut list: Vec<AclListItem> = Vec::new();
|
||||||
if let Some(path) = &path {
|
if let Some(path) = &path {
|
||||||
|
@ -200,9 +204,9 @@ pub fn update_acl(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let _lock = open_backup_lockfile(acl::ACL_CFG_LOCKFILE, None, true)?;
|
let _lock = pbs_config::acl::lock_config()?;
|
||||||
|
|
||||||
let (mut tree, expected_digest) = acl::config()?;
|
let (mut tree, expected_digest) = pbs_config::acl::config()?;
|
||||||
|
|
||||||
if let Some(ref digest) = digest {
|
if let Some(ref digest) = digest {
|
||||||
let digest = proxmox::tools::hex_to_digest(digest)?;
|
let digest = proxmox::tools::hex_to_digest(digest)?;
|
||||||
|
@ -228,7 +232,7 @@ pub fn update_acl(
|
||||||
}
|
}
|
||||||
|
|
||||||
if !delete { // Note: we allow to delete entries with invalid path
|
if !delete { // Note: we allow to delete entries with invalid path
|
||||||
acl::check_acl_path(&path)?;
|
pbs_config::acl::check_acl_path(&path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(auth_id) = auth_id {
|
if let Some(auth_id) = auth_id {
|
||||||
|
@ -245,7 +249,7 @@ pub fn update_acl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
acl::save_config(&tree)?;
|
pbs_config::acl::save_config(&tree)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,17 @@ use proxmox::api::{api, Permission, RpcEnvironment};
|
||||||
use proxmox::{http_err, list_subdirs_api_method};
|
use proxmox::{http_err, list_subdirs_api_method};
|
||||||
use proxmox::{identity, sortable};
|
use proxmox::{identity, sortable};
|
||||||
|
|
||||||
|
use pbs_api_types::{
|
||||||
|
Userid, Authid, PASSWORD_SCHEMA, ACL_PATH_SCHEMA,
|
||||||
|
PRIVILEGES, PRIV_PERMISSIONS_MODIFY, PRIV_SYS_AUDIT,
|
||||||
|
};
|
||||||
use pbs_tools::auth::private_auth_key;
|
use pbs_tools::auth::private_auth_key;
|
||||||
use pbs_tools::ticket::{self, Empty, Ticket};
|
use pbs_tools::ticket::{self, Empty, Ticket};
|
||||||
|
use pbs_config::acl::AclTreeNode;
|
||||||
|
|
||||||
use crate::api2::types::*;
|
|
||||||
use crate::auth_helpers::*;
|
use crate::auth_helpers::*;
|
||||||
use crate::server::ticket::ApiTicket;
|
use crate::server::ticket::ApiTicket;
|
||||||
|
|
||||||
use crate::config::acl as acl_config;
|
|
||||||
use crate::config::acl::{PRIVILEGES, PRIV_PERMISSIONS_MODIFY, PRIV_SYS_AUDIT};
|
|
||||||
use crate::config::cached_user_info::CachedUserInfo;
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
use crate::config::tfa::TfaChallenge;
|
use crate::config::tfa::TfaChallenge;
|
||||||
|
|
||||||
|
@ -355,7 +357,7 @@ pub fn list_permissions(
|
||||||
|
|
||||||
fn populate_acl_paths(
|
fn populate_acl_paths(
|
||||||
mut paths: HashSet<String>,
|
mut paths: HashSet<String>,
|
||||||
node: acl_config::AclTreeNode,
|
node: AclTreeNode,
|
||||||
path: &str,
|
path: &str,
|
||||||
) -> HashSet<String> {
|
) -> HashSet<String> {
|
||||||
for (sub_path, child_node) in node.children {
|
for (sub_path, child_node) in node.children {
|
||||||
|
@ -375,7 +377,7 @@ pub fn list_permissions(
|
||||||
None => {
|
None => {
|
||||||
let mut paths = HashSet::new();
|
let mut paths = HashSet::new();
|
||||||
|
|
||||||
let (acl_tree, _) = acl_config::config()?;
|
let (acl_tree, _) = pbs_config::acl::config()?;
|
||||||
paths = populate_acl_paths(paths, acl_tree.root, "");
|
paths = populate_acl_paths(paths, acl_tree.root, "");
|
||||||
|
|
||||||
// default paths, returned even if no ACL exists
|
// default paths, returned even if no ACL exists
|
||||||
|
@ -392,7 +394,7 @@ pub fn list_permissions(
|
||||||
let map = paths.into_iter().fold(
|
let map = paths.into_iter().fold(
|
||||||
HashMap::new(),
|
HashMap::new(),
|
||||||
|mut map: HashMap<String, HashMap<String, bool>>, path: String| {
|
|mut map: HashMap<String, HashMap<String, bool>>, path: String| {
|
||||||
let split_path = acl_config::split_acl_path(path.as_str());
|
let split_path = pbs_config::acl::split_acl_path(path.as_str());
|
||||||
let (privs, propagated_privs) = user_info.lookup_privs_details(&auth_id, &split_path);
|
let (privs, propagated_privs) = user_info.lookup_privs_details(&auth_id, &split_path);
|
||||||
|
|
||||||
match privs {
|
match privs {
|
||||||
|
|
|
@ -7,8 +7,8 @@ use serde_json::{json, Value};
|
||||||
use proxmox::api::{api, Permission};
|
use proxmox::api::{api, Permission};
|
||||||
use proxmox::api::router::Router;
|
use proxmox::api::router::Router;
|
||||||
|
|
||||||
use crate::api2::types::*;
|
use pbs_api_types::{Role, SINGLE_LINE_COMMENT_SCHEMA, PRIVILEGES};
|
||||||
use crate::config::acl::{Role, ROLE_NAMES, PRIVILEGES};
|
use pbs_config::acl::ROLE_NAMES;
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
returns: {
|
returns: {
|
||||||
|
|
|
@ -7,8 +7,8 @@ use proxmox::api::{api, Permission, Router, RpcEnvironment};
|
||||||
use proxmox::tools::tfa::totp::Totp;
|
use proxmox::tools::tfa::totp::Totp;
|
||||||
use proxmox::{http_bail, http_err};
|
use proxmox::{http_bail, http_err};
|
||||||
|
|
||||||
use crate::api2::types::{Authid, Userid, PASSWORD_SCHEMA};
|
use pbs_api_types::{Authid, Userid, PASSWORD_SCHEMA, PRIV_PERMISSIONS_MODIFY, PRIV_SYS_AUDIT};
|
||||||
use crate::config::acl::{PRIV_PERMISSIONS_MODIFY, PRIV_SYS_AUDIT};
|
|
||||||
use crate::config::cached_user_info::CachedUserInfo;
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
use crate::config::tfa::{TfaInfo, TfaUserData};
|
use crate::config::tfa::{TfaInfo, TfaUserData};
|
||||||
|
|
||||||
|
|
|
@ -11,14 +11,13 @@ use proxmox::api::schema::{Schema, StringSchema};
|
||||||
|
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
PASSWORD_FORMAT, PROXMOX_CONFIG_DIGEST_SCHEMA, SINGLE_LINE_COMMENT_SCHEMA, Authid,
|
PASSWORD_FORMAT, PROXMOX_CONFIG_DIGEST_SCHEMA, SINGLE_LINE_COMMENT_SCHEMA, Authid,
|
||||||
Tokenname, UserWithTokens, Userid,
|
Tokenname, UserWithTokens, Userid, PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY,
|
||||||
};
|
};
|
||||||
use pbs_config::token_shadow;
|
use pbs_config::token_shadow;
|
||||||
|
use pbs_config::open_backup_lockfile;
|
||||||
|
|
||||||
use crate::config::user;
|
use crate::config::user;
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY};
|
|
||||||
use crate::config::cached_user_info::CachedUserInfo;
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
use pbs_config::open_backup_lockfile;
|
|
||||||
|
|
||||||
pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.")
|
pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.")
|
||||||
.format(&PASSWORD_FORMAT)
|
.format(&PASSWORD_FORMAT)
|
||||||
|
|
|
@ -30,6 +30,10 @@ use pbs_api_types::{
|
||||||
Authid, BackupContent, Counts, CryptMode, DataStoreListItem, GarbageCollectionStatus,
|
Authid, BackupContent, Counts, CryptMode, DataStoreListItem, GarbageCollectionStatus,
|
||||||
GroupListItem, SnapshotListItem, SnapshotVerifyState, BACKUP_ARCHIVE_NAME_SCHEMA,
|
GroupListItem, SnapshotListItem, SnapshotVerifyState, BACKUP_ARCHIVE_NAME_SCHEMA,
|
||||||
BACKUP_ID_SCHEMA, BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA,
|
BACKUP_ID_SCHEMA, BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA,
|
||||||
|
IGNORE_VERIFIED_BACKUPS_SCHEMA, UPID_SCHEMA, VERIFICATION_OUTDATED_AFTER_SCHEMA,
|
||||||
|
PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_READ, PRIV_DATASTORE_PRUNE,
|
||||||
|
PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_VERIFY,
|
||||||
|
|
||||||
};
|
};
|
||||||
use pbs_client::pxar::create_zip;
|
use pbs_client::pxar::create_zip;
|
||||||
use pbs_datastore::{BackupDir, BackupGroup, StoreProgress, CATALOG_NAME};
|
use pbs_datastore::{BackupDir, BackupGroup, StoreProgress, CATALOG_NAME};
|
||||||
|
@ -47,10 +51,7 @@ use pbs_tools::blocking::WrappedReaderStream;
|
||||||
use pbs_tools::stream::{AsyncReaderStream, AsyncChannelWriter};
|
use pbs_tools::stream::{AsyncReaderStream, AsyncChannelWriter};
|
||||||
use pbs_tools::json::{required_integer_param, required_string_param};
|
use pbs_tools::json::{required_integer_param, required_string_param};
|
||||||
|
|
||||||
use crate::api2::types::{
|
use crate::api2::types::{DataStoreStatus, RRDMode, RRDTimeFrameResolution};
|
||||||
DataStoreStatus, RRDMode, RRDTimeFrameResolution, IGNORE_VERIFIED_BACKUPS_SCHEMA, UPID_SCHEMA,
|
|
||||||
VERIFICATION_OUTDATED_AFTER_SCHEMA
|
|
||||||
};
|
|
||||||
use crate::api2::node::rrd::create_value_from_rrd;
|
use crate::api2::node::rrd::create_value_from_rrd;
|
||||||
use crate::backup::{
|
use crate::backup::{
|
||||||
check_backup_owner, verify_all_backups, verify_backup_group, verify_backup_dir, verify_filter,
|
check_backup_owner, verify_all_backups, verify_backup_group, verify_backup_dir, verify_filter,
|
||||||
|
@ -61,14 +62,6 @@ use crate::config::cached_user_info::CachedUserInfo;
|
||||||
|
|
||||||
use crate::server::{jobstate::Job, WorkerTask};
|
use crate::server::{jobstate::Job, WorkerTask};
|
||||||
|
|
||||||
use crate::config::acl::{
|
|
||||||
PRIV_DATASTORE_AUDIT,
|
|
||||||
PRIV_DATASTORE_MODIFY,
|
|
||||||
PRIV_DATASTORE_READ,
|
|
||||||
PRIV_DATASTORE_PRUNE,
|
|
||||||
PRIV_DATASTORE_BACKUP,
|
|
||||||
PRIV_DATASTORE_VERIFY,
|
|
||||||
};
|
|
||||||
|
|
||||||
const GROUP_NOTES_FILE_NAME: &str = "notes";
|
const GROUP_NOTES_FILE_NAME: &str = "notes";
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,10 @@ use proxmox::api::router::SubdirMap;
|
||||||
use proxmox::{list_subdirs_api_method, sortable};
|
use proxmox::{list_subdirs_api_method, sortable};
|
||||||
use proxmox::api::{api, ApiMethod, Permission, Router, RpcEnvironment};
|
use proxmox::api::{api, ApiMethod, Permission, Router, RpcEnvironment};
|
||||||
|
|
||||||
use pbs_api_types::{VerificationJobConfig, VerificationJobStatus, JOB_ID_SCHEMA, Authid};
|
use pbs_api_types::{
|
||||||
|
VerificationJobConfig, VerificationJobStatus, JOB_ID_SCHEMA, Authid,
|
||||||
|
PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_VERIFY,
|
||||||
|
};
|
||||||
use pbs_config::verify;
|
use pbs_config::verify;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -22,16 +25,9 @@ use crate::{
|
||||||
compute_schedule_status,
|
compute_schedule_status,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
config::{
|
config::cached_user_info::CachedUserInfo,
|
||||||
acl::{
|
|
||||||
PRIV_DATASTORE_AUDIT,
|
|
||||||
PRIV_DATASTORE_VERIFY,
|
|
||||||
},
|
|
||||||
cached_user_info::CachedUserInfo,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
input: {
|
input: {
|
||||||
properties: {
|
properties: {
|
||||||
|
|
|
@ -12,6 +12,11 @@ use proxmox::api::{ApiResponseFuture, ApiHandler, ApiMethod, Router, RpcEnvironm
|
||||||
use proxmox::api::router::SubdirMap;
|
use proxmox::api::router::SubdirMap;
|
||||||
use proxmox::api::schema::*;
|
use proxmox::api::schema::*;
|
||||||
|
|
||||||
|
use pbs_api_types::{
|
||||||
|
Authid, VerifyState, SnapshotVerifyState,
|
||||||
|
BACKUP_ID_SCHEMA, BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA,
|
||||||
|
CHUNK_DIGEST_SCHEMA, PRIV_DATASTORE_BACKUP,
|
||||||
|
};
|
||||||
use pbs_tools::fs::lock_dir_noblock_shared;
|
use pbs_tools::fs::lock_dir_noblock_shared;
|
||||||
use pbs_tools::json::{required_array_param, required_integer_param, required_string_param};
|
use pbs_tools::json::{required_array_param, required_integer_param, required_string_param};
|
||||||
use pbs_datastore::PROXMOX_BACKUP_PROTOCOL_ID_V1;
|
use pbs_datastore::PROXMOX_BACKUP_PROTOCOL_ID_V1;
|
||||||
|
@ -21,8 +26,6 @@ use pbs_datastore::manifest::{archive_type, ArchiveType};
|
||||||
|
|
||||||
use crate::server::{WorkerTask, H2Service};
|
use crate::server::{WorkerTask, H2Service};
|
||||||
use crate::backup::DataStore;
|
use crate::backup::DataStore;
|
||||||
use crate::api2::types::*;
|
|
||||||
use crate::config::acl::PRIV_DATASTORE_BACKUP;
|
|
||||||
use crate::config::cached_user_info::CachedUserInfo;
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
|
|
||||||
mod environment;
|
mod environment;
|
||||||
|
|
|
@ -6,9 +6,10 @@ use ::serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox::api::{api, Permission, Router, RpcEnvironment};
|
use proxmox::api::{api, Permission, Router, RpcEnvironment};
|
||||||
|
|
||||||
|
use pbs_api_types::{
|
||||||
|
PROXMOX_CONFIG_DIGEST_SCHEMA, REALM_ID_SCHEMA, PRIV_SYS_AUDIT, PRIV_REALM_ALLOCATE,
|
||||||
|
};
|
||||||
use pbs_config::domains::{self, OpenIdRealmConfig, OpenIdRealmConfigUpdater};
|
use pbs_config::domains::{self, OpenIdRealmConfig, OpenIdRealmConfigUpdater};
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_REALM_ALLOCATE};
|
|
||||||
use crate::api2::types::*;
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
input: {
|
input: {
|
||||||
|
|
|
@ -16,9 +16,10 @@ use proxmox::list_subdirs_api_method;
|
||||||
use proxmox_acme_rs::account::AccountData as AcmeAccountData;
|
use proxmox_acme_rs::account::AccountData as AcmeAccountData;
|
||||||
use proxmox_acme_rs::Account;
|
use proxmox_acme_rs::Account;
|
||||||
|
|
||||||
|
use pbs_api_types::{Authid, PRIV_SYS_MODIFY};
|
||||||
|
|
||||||
use crate::acme::AcmeClient;
|
use crate::acme::AcmeClient;
|
||||||
use crate::api2::types::{AcmeAccountName, AcmeChallengeSchema, Authid, KnownAcmeDirectory};
|
use crate::api2::types::{AcmeAccountName, AcmeChallengeSchema, KnownAcmeDirectory};
|
||||||
use crate::config::acl::PRIV_SYS_MODIFY;
|
|
||||||
use crate::config::acme::plugin::{
|
use crate::config::acme::plugin::{
|
||||||
self, DnsPlugin, DnsPluginCore, DnsPluginCoreUpdater, PLUGIN_ID_SCHEMA,
|
self, DnsPlugin, DnsPluginCore, DnsPluginCoreUpdater, PLUGIN_ID_SCHEMA,
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,23 +11,13 @@ use proxmox::api::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
Authid,
|
Authid, ScsiTapeChanger, ScsiTapeChangerUpdater, LtoTapeDrive,
|
||||||
PROXMOX_CONFIG_DIGEST_SCHEMA,
|
PROXMOX_CONFIG_DIGEST_SCHEMA, CHANGER_NAME_SCHEMA, SLOT_ARRAY_SCHEMA,
|
||||||
CHANGER_NAME_SCHEMA,
|
PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY,
|
||||||
SLOT_ARRAY_SCHEMA,
|
|
||||||
ScsiTapeChanger,
|
|
||||||
ScsiTapeChangerUpdater,
|
|
||||||
LtoTapeDrive,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config::cached_user_info::CachedUserInfo,
|
||||||
cached_user_info::CachedUserInfo,
|
|
||||||
acl::{
|
|
||||||
PRIV_TAPE_AUDIT,
|
|
||||||
PRIV_TAPE_MODIFY,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tape::{
|
tape::{
|
||||||
linux_tape_changer_list,
|
linux_tape_changer_list,
|
||||||
check_drive_path,
|
check_drive_path,
|
||||||
|
|
|
@ -11,6 +11,11 @@ use proxmox::api::schema::{ApiType, parse_property_string};
|
||||||
use pbs_datastore::chunk_store::ChunkStore;
|
use pbs_datastore::chunk_store::ChunkStore;
|
||||||
use pbs_datastore::task::TaskState;
|
use pbs_datastore::task::TaskState;
|
||||||
use pbs_config::BackupLockGuard;
|
use pbs_config::BackupLockGuard;
|
||||||
|
use pbs_api_types::{
|
||||||
|
Authid, DatastoreNotify,
|
||||||
|
DATASTORE_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA,
|
||||||
|
PRIV_DATASTORE_ALLOCATE, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_MODIFY,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::api2::config::sync::delete_sync_job;
|
use crate::api2::config::sync::delete_sync_job;
|
||||||
use crate::api2::config::verify::delete_verification_job;
|
use crate::api2::config::verify::delete_verification_job;
|
||||||
|
@ -19,10 +24,8 @@ use crate::api2::admin::{
|
||||||
sync::list_sync_jobs,
|
sync::list_sync_jobs,
|
||||||
verify::list_verification_jobs,
|
verify::list_verification_jobs,
|
||||||
};
|
};
|
||||||
use crate::api2::types::*;
|
|
||||||
use crate::config::cached_user_info::CachedUserInfo;
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
use crate::config::datastore::{self, DataStoreConfig, DataStoreConfigUpdater};
|
use crate::config::datastore::{self, DataStoreConfig, DataStoreConfigUpdater};
|
||||||
use crate::config::acl::{PRIV_DATASTORE_ALLOCATE, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_MODIFY};
|
|
||||||
use crate::server::{jobstate, WorkerTask};
|
use crate::server::{jobstate, WorkerTask};
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
|
|
|
@ -5,22 +5,12 @@ use serde_json::Value;
|
||||||
use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
||||||
|
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
Authid,
|
Authid, LtoTapeDrive, LtoTapeDriveUpdater, ScsiTapeChanger,
|
||||||
PROXMOX_CONFIG_DIGEST_SCHEMA,
|
PROXMOX_CONFIG_DIGEST_SCHEMA, DRIVE_NAME_SCHEMA, PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY,
|
||||||
DRIVE_NAME_SCHEMA,
|
|
||||||
LtoTapeDrive,
|
|
||||||
LtoTapeDriveUpdater,
|
|
||||||
ScsiTapeChanger,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config::cached_user_info::CachedUserInfo,
|
||||||
cached_user_info::CachedUserInfo,
|
|
||||||
acl::{
|
|
||||||
PRIV_TAPE_AUDIT,
|
|
||||||
PRIV_TAPE_MODIFY,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tape::{
|
tape::{
|
||||||
lto_tape_device_list,
|
lto_tape_device_list,
|
||||||
check_drive_path,
|
check_drive_path,
|
||||||
|
|
|
@ -11,21 +11,11 @@ use proxmox::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
Authid,
|
Authid, MediaPoolConfig, MediaPoolConfigUpdater, MEDIA_POOL_NAME_SCHEMA,
|
||||||
MEDIA_POOL_NAME_SCHEMA,
|
PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY,
|
||||||
MediaPoolConfig,
|
|
||||||
MediaPoolConfigUpdater,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
config::{
|
|
||||||
cached_user_info::CachedUserInfo,
|
|
||||||
acl::{
|
|
||||||
PRIV_TAPE_AUDIT,
|
|
||||||
PRIV_TAPE_MODIFY,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
protected: true,
|
protected: true,
|
||||||
|
|
|
@ -9,11 +9,11 @@ use pbs_client::{HttpClient, HttpClientOptions};
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
REMOTE_ID_SCHEMA, REMOTE_PASSWORD_SCHEMA, Remote, RemoteConfig, RemoteConfigUpdater,
|
REMOTE_ID_SCHEMA, REMOTE_PASSWORD_SCHEMA, Remote, RemoteConfig, RemoteConfigUpdater,
|
||||||
Authid, PROXMOX_CONFIG_DIGEST_SCHEMA, DataStoreListItem, SyncJobConfig,
|
Authid, PROXMOX_CONFIG_DIGEST_SCHEMA, DataStoreListItem, SyncJobConfig,
|
||||||
|
PRIV_REMOTE_AUDIT, PRIV_REMOTE_MODIFY,
|
||||||
};
|
};
|
||||||
use pbs_config::sync;
|
use pbs_config::sync;
|
||||||
|
|
||||||
use crate::config::cached_user_info::CachedUserInfo;
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
use crate::config::acl::{PRIV_REMOTE_AUDIT, PRIV_REMOTE_MODIFY};
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
input: {
|
input: {
|
||||||
|
|
|
@ -6,18 +6,11 @@ use proxmox::api::{api, Permission, Router, RpcEnvironment};
|
||||||
|
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
Authid, SyncJobConfig, SyncJobConfigUpdater, JOB_ID_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA,
|
Authid, SyncJobConfig, SyncJobConfigUpdater, JOB_ID_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA,
|
||||||
|
PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_PRUNE,
|
||||||
|
PRIV_REMOTE_AUDIT, PRIV_REMOTE_READ,
|
||||||
};
|
};
|
||||||
use pbs_config::sync;
|
use pbs_config::sync;
|
||||||
|
|
||||||
use crate::config::acl::{
|
|
||||||
PRIV_DATASTORE_AUDIT,
|
|
||||||
PRIV_DATASTORE_BACKUP,
|
|
||||||
PRIV_DATASTORE_MODIFY,
|
|
||||||
PRIV_DATASTORE_PRUNE,
|
|
||||||
PRIV_REMOTE_AUDIT,
|
|
||||||
PRIV_REMOTE_READ,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::config::cached_user_info::CachedUserInfo;
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
|
|
||||||
pub fn check_sync_job_read_access(
|
pub fn check_sync_job_read_access(
|
||||||
|
@ -371,7 +364,7 @@ user: read@pbs
|
||||||
user: write@pbs
|
user: write@pbs
|
||||||
|
|
||||||
"###).expect("test user.cfg is not parsable");
|
"###).expect("test user.cfg is not parsable");
|
||||||
let acl_tree = crate::config::acl::AclTree::from_raw(r###"
|
let acl_tree = pbs_config::acl::AclTree::from_raw(r###"
|
||||||
acl:1:/datastore/localstore1:read@pbs,write@pbs:DatastoreAudit
|
acl:1:/datastore/localstore1:read@pbs,write@pbs:DatastoreAudit
|
||||||
acl:1:/datastore/localstore1:write@pbs:DatastoreBackup
|
acl:1:/datastore/localstore1:write@pbs:DatastoreBackup
|
||||||
acl:1:/datastore/localstore2:write@pbs:DatastorePowerUser
|
acl:1:/datastore/localstore2:write@pbs:DatastorePowerUser
|
||||||
|
|
|
@ -7,17 +7,10 @@ use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
Authid, TapeBackupJobConfig, TapeBackupJobConfigUpdater,
|
Authid, TapeBackupJobConfig, TapeBackupJobConfigUpdater,
|
||||||
JOB_ID_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA,
|
JOB_ID_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA,
|
||||||
|
PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
config::{
|
|
||||||
cached_user_info::CachedUserInfo,
|
|
||||||
acl::{
|
|
||||||
PRIV_TAPE_AUDIT,
|
|
||||||
PRIV_TAPE_MODIFY,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
input: {
|
input: {
|
||||||
|
|
|
@ -15,6 +15,7 @@ use pbs_api_types::{
|
||||||
Fingerprint, KeyInfo, Kdf,
|
Fingerprint, KeyInfo, Kdf,
|
||||||
TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
|
TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
|
||||||
PROXMOX_CONFIG_DIGEST_SCHEMA, PASSWORD_HINT_SCHEMA,
|
PROXMOX_CONFIG_DIGEST_SCHEMA, PASSWORD_HINT_SCHEMA,
|
||||||
|
PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY,
|
||||||
};
|
};
|
||||||
|
|
||||||
use pbs_config::key_config::KeyConfig;
|
use pbs_config::key_config::KeyConfig;
|
||||||
|
@ -28,15 +29,6 @@ use pbs_config::tape_encryption_keys::{
|
||||||
insert_key,
|
insert_key,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
|
||||||
config::{
|
|
||||||
acl::{
|
|
||||||
PRIV_TAPE_AUDIT,
|
|
||||||
PRIV_TAPE_MODIFY,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
input: {
|
input: {
|
||||||
properties: {},
|
properties: {},
|
||||||
|
|
|
@ -6,15 +6,10 @@ use proxmox::api::{api, Permission, Router, RpcEnvironment};
|
||||||
|
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
Authid, VerificationJobConfig, VerificationJobConfigUpdater, JOB_ID_SCHEMA,
|
Authid, VerificationJobConfig, VerificationJobConfigUpdater, JOB_ID_SCHEMA,
|
||||||
PROXMOX_CONFIG_DIGEST_SCHEMA,
|
PROXMOX_CONFIG_DIGEST_SCHEMA, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_VERIFY,
|
||||||
};
|
};
|
||||||
use pbs_config::verify;
|
use pbs_config::verify;
|
||||||
|
|
||||||
use crate::config::acl::{
|
|
||||||
PRIV_DATASTORE_AUDIT,
|
|
||||||
PRIV_DATASTORE_VERIFY,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::config::cached_user_info::CachedUserInfo;
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
|
|
|
@ -13,6 +13,11 @@ use proxmox_apt::repositories::{
|
||||||
};
|
};
|
||||||
use proxmox_http::ProxyConfig;
|
use proxmox_http::ProxyConfig;
|
||||||
|
|
||||||
|
use pbs_api_types::{
|
||||||
|
Authid, APTUpdateInfo, NODE_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA, UPID_SCHEMA,
|
||||||
|
PRIV_SYS_AUDIT, PRIV_SYS_MODIFY,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::config::node;
|
use crate::config::node;
|
||||||
use crate::server::WorkerTask;
|
use crate::server::WorkerTask;
|
||||||
use crate::tools::{
|
use crate::tools::{
|
||||||
|
@ -20,8 +25,6 @@ use crate::tools::{
|
||||||
pbs_simple_http,
|
pbs_simple_http,
|
||||||
subscription,
|
subscription,
|
||||||
};
|
};
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
|
||||||
use crate::api2::types::{Authid, APTUpdateInfo, NODE_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA, UPID_SCHEMA};
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
input: {
|
input: {
|
||||||
|
|
|
@ -11,14 +11,12 @@ use proxmox::api::router::SubdirMap;
|
||||||
use proxmox::api::{api, Permission, Router, RpcEnvironment};
|
use proxmox::api::{api, Permission, Router, RpcEnvironment};
|
||||||
use proxmox::list_subdirs_api_method;
|
use proxmox::list_subdirs_api_method;
|
||||||
|
|
||||||
|
use pbs_api_types::{Authid, NODE_SCHEMA, PRIV_SYS_MODIFY};
|
||||||
use pbs_buildcfg::configdir;
|
use pbs_buildcfg::configdir;
|
||||||
use pbs_tools::cert;
|
use pbs_tools::cert;
|
||||||
|
|
||||||
use crate::acme::AcmeClient;
|
use crate::acme::AcmeClient;
|
||||||
use crate::api2::types::Authid;
|
|
||||||
use crate::api2::types::NODE_SCHEMA;
|
|
||||||
use crate::api2::types::AcmeDomain;
|
use crate::api2::types::AcmeDomain;
|
||||||
use crate::config::acl::PRIV_SYS_MODIFY;
|
|
||||||
use crate::config::node::NodeConfig;
|
use crate::config::node::NodeConfig;
|
||||||
use crate::server::WorkerTask;
|
use crate::server::WorkerTask;
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@ use ::serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox::api::{api, Permission, Router, RpcEnvironment};
|
use proxmox::api::{api, Permission, Router, RpcEnvironment};
|
||||||
|
|
||||||
use crate::api2::types::NODE_SCHEMA;
|
use pbs_api_types::{NODE_SCHEMA, PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
||||||
|
|
||||||
use crate::api2::node::apt::update_apt_proxy_config;
|
use crate::api2::node::apt::update_apt_proxy_config;
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
|
||||||
use crate::config::node::{NodeConfig, NodeConfigUpdater};
|
use crate::config::node::{NodeConfig, NodeConfigUpdater};
|
||||||
|
|
||||||
pub const ROUTER: Router = Router::new()
|
pub const ROUTER: Router = Router::new()
|
||||||
|
|
|
@ -6,7 +6,11 @@ use proxmox::api::{api, Permission, RpcEnvironment, RpcEnvironmentType};
|
||||||
use proxmox::api::section_config::SectionConfigData;
|
use proxmox::api::section_config::SectionConfigData;
|
||||||
use proxmox::api::router::Router;
|
use proxmox::api::router::Router;
|
||||||
|
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
use pbs_api_types::{
|
||||||
|
Authid, NODE_SCHEMA, BLOCKDEVICE_NAME_SCHEMA, DATASTORE_SCHEMA, UPID_SCHEMA,
|
||||||
|
PRIV_SYS_AUDIT, PRIV_SYS_MODIFY,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::tools::disks::{
|
use crate::tools::disks::{
|
||||||
DiskManage, FileSystemType, DiskUsageType,
|
DiskManage, FileSystemType, DiskUsageType,
|
||||||
create_file_system, create_single_linux_partition, get_fs_uuid, get_disk_usage_info,
|
create_file_system, create_single_linux_partition, get_fs_uuid, get_disk_usage_info,
|
||||||
|
@ -15,7 +19,6 @@ use crate::tools::systemd::{self, types::*};
|
||||||
|
|
||||||
use crate::server::WorkerTask;
|
use crate::server::WorkerTask;
|
||||||
|
|
||||||
use crate::api2::types::*;
|
|
||||||
use crate::config::datastore::{self, DataStoreConfig};
|
use crate::config::datastore::{self, DataStoreConfig};
|
||||||
use pbs_config::open_backup_lockfile;
|
use pbs_config::open_backup_lockfile;
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,17 @@ use proxmox::api::router::{Router, SubdirMap};
|
||||||
use proxmox::{sortable, identity};
|
use proxmox::{sortable, identity};
|
||||||
use proxmox::{list_subdirs_api_method};
|
use proxmox::{list_subdirs_api_method};
|
||||||
|
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
use pbs_api_types::{
|
||||||
|
Authid, UPID_SCHEMA, NODE_SCHEMA, BLOCKDEVICE_NAME_SCHEMA,
|
||||||
|
PRIV_SYS_AUDIT, PRIV_SYS_MODIFY,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::tools::disks::{
|
use crate::tools::disks::{
|
||||||
DiskUsageInfo, DiskUsageType, DiskManage, SmartData,
|
DiskUsageInfo, DiskUsageType, DiskManage, SmartData,
|
||||||
get_disks, get_smart_data, get_disk_usage_info, inititialize_gpt_disk,
|
get_disks, get_smart_data, get_disk_usage_info, inititialize_gpt_disk,
|
||||||
};
|
};
|
||||||
use crate::server::WorkerTask;
|
use crate::server::WorkerTask;
|
||||||
|
|
||||||
use crate::api2::types::{Authid, UPID_SCHEMA, NODE_SCHEMA, BLOCKDEVICE_NAME_SCHEMA};
|
|
||||||
|
|
||||||
pub mod directory;
|
pub mod directory;
|
||||||
pub mod zfs;
|
pub mod zfs;
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
use anyhow::{bail, Error};
|
use anyhow::{bail, Error};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use proxmox::api::{
|
use proxmox::api::{
|
||||||
api, Permission, RpcEnvironment, RpcEnvironmentType,
|
api, Permission, RpcEnvironment, RpcEnvironmentType,
|
||||||
schema::{
|
schema::parse_property_string,
|
||||||
Schema,
|
|
||||||
StringSchema,
|
|
||||||
ArraySchema,
|
|
||||||
IntegerSchema,
|
|
||||||
ApiStringFormat,
|
|
||||||
parse_property_string,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use proxmox::api::router::Router;
|
use proxmox::api::router::Router;
|
||||||
|
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
use pbs_api_types::{
|
||||||
|
Authid, ZpoolListItem, ZfsRaidLevel, ZfsCompressionType,
|
||||||
|
NODE_SCHEMA, ZPOOL_NAME_SCHEMA, DATASTORE_SCHEMA, DISK_ARRAY_SCHEMA,
|
||||||
|
DISK_LIST_SCHEMA, ZFS_ASHIFT_SCHEMA, UPID_SCHEMA,
|
||||||
|
PRIV_SYS_AUDIT, PRIV_SYS_MODIFY,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::tools::disks::{
|
use crate::tools::disks::{
|
||||||
zpool_list, zpool_status, parse_zpool_status_config_tree, vdev_list_to_tree,
|
zpool_list, zpool_status, parse_zpool_status_config_tree, vdev_list_to_tree,
|
||||||
DiskUsageType,
|
DiskUsageType,
|
||||||
|
@ -24,92 +22,6 @@ use crate::config::datastore::{self, DataStoreConfig};
|
||||||
|
|
||||||
use crate::server::WorkerTask;
|
use crate::server::WorkerTask;
|
||||||
|
|
||||||
use crate::api2::types::*;
|
|
||||||
|
|
||||||
pub const DISK_ARRAY_SCHEMA: Schema = ArraySchema::new(
|
|
||||||
"Disk name list.", &BLOCKDEVICE_NAME_SCHEMA)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const DISK_LIST_SCHEMA: Schema = StringSchema::new(
|
|
||||||
"A list of disk names, comma separated.")
|
|
||||||
.format(&ApiStringFormat::PropertyString(&DISK_ARRAY_SCHEMA))
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const ZFS_ASHIFT_SCHEMA: Schema = IntegerSchema::new(
|
|
||||||
"Pool sector size exponent.")
|
|
||||||
.minimum(9)
|
|
||||||
.maximum(16)
|
|
||||||
.default(12)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const ZPOOL_NAME_SCHEMA: Schema =StringSchema::new("ZFS Pool Name")
|
|
||||||
.format(&ApiStringFormat::Pattern(&ZPOOL_NAME_REGEX))
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
#[api(
|
|
||||||
default: "On",
|
|
||||||
)]
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "lowercase")]
|
|
||||||
/// The ZFS compression algorithm to use.
|
|
||||||
pub enum ZfsCompressionType {
|
|
||||||
/// Gnu Zip
|
|
||||||
Gzip,
|
|
||||||
/// LZ4
|
|
||||||
Lz4,
|
|
||||||
/// LZJB
|
|
||||||
Lzjb,
|
|
||||||
/// ZLE
|
|
||||||
Zle,
|
|
||||||
/// ZStd
|
|
||||||
ZStd,
|
|
||||||
/// Enable compression using the default algorithm.
|
|
||||||
On,
|
|
||||||
/// Disable compression.
|
|
||||||
Off,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api()]
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "lowercase")]
|
|
||||||
/// The ZFS RAID level to use.
|
|
||||||
pub enum ZfsRaidLevel {
|
|
||||||
/// Single Disk
|
|
||||||
Single,
|
|
||||||
/// Mirror
|
|
||||||
Mirror,
|
|
||||||
/// Raid10
|
|
||||||
Raid10,
|
|
||||||
/// RaidZ
|
|
||||||
RaidZ,
|
|
||||||
/// RaidZ2
|
|
||||||
RaidZ2,
|
|
||||||
/// RaidZ3
|
|
||||||
RaidZ3,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[api()]
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all="kebab-case")]
|
|
||||||
/// zpool list item
|
|
||||||
pub struct ZpoolListItem {
|
|
||||||
/// zpool name
|
|
||||||
pub name: String,
|
|
||||||
/// Health
|
|
||||||
pub health: String,
|
|
||||||
/// Total size
|
|
||||||
pub size: u64,
|
|
||||||
/// Used size
|
|
||||||
pub alloc: u64,
|
|
||||||
/// Free space
|
|
||||||
pub free: u64,
|
|
||||||
/// ZFS fragnentation level
|
|
||||||
pub frag: u64,
|
|
||||||
/// ZFS deduplication ratio
|
|
||||||
pub dedup: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
protected: true,
|
protected: true,
|
||||||
|
|
|
@ -11,8 +11,11 @@ use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
|
||||||
use proxmox::tools::fs::{file_get_contents, replace_file, CreateOptions};
|
use proxmox::tools::fs::{file_get_contents, replace_file, CreateOptions};
|
||||||
use proxmox::{IPRE, IPV4RE, IPV6RE, IPV4OCTET, IPV6H16, IPV6LS32};
|
use proxmox::{IPRE, IPV4RE, IPV6RE, IPV4OCTET, IPV6H16, IPV6LS32};
|
||||||
|
|
||||||
use crate::api2::types::*;
|
use pbs_api_types::{
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
PROXMOX_CONFIG_DIGEST_SCHEMA, FIRST_DNS_SERVER_SCHEMA, SECOND_DNS_SERVER_SCHEMA,
|
||||||
|
THIRD_DNS_SERVER_SCHEMA, NODE_SCHEMA, SEARCH_DOMAIN_SCHEMA,
|
||||||
|
PRIV_SYS_AUDIT, PRIV_SYS_MODIFY,
|
||||||
|
};
|
||||||
|
|
||||||
static RESOLV_CONF_FN: &str = "/etc/resolv.conf";
|
static RESOLV_CONF_FN: &str = "/etc/resolv.conf";
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,7 @@ use std::io::{BufRead,BufReader};
|
||||||
|
|
||||||
use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
|
use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
|
||||||
|
|
||||||
use crate::api2::types::*;
|
use pbs_api_types::{NODE_SCHEMA, PRIV_SYS_AUDIT};
|
||||||
use crate::config::acl::PRIV_SYS_AUDIT;
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
protected: true,
|
protected: true,
|
||||||
|
|
|
@ -20,11 +20,10 @@ use proxmox::list_subdirs_api_method;
|
||||||
use proxmox_http::websocket::WebSocket;
|
use proxmox_http::websocket::WebSocket;
|
||||||
use proxmox::{identity, sortable};
|
use proxmox::{identity, sortable};
|
||||||
|
|
||||||
|
use pbs_api_types::{Authid, NODE_SCHEMA, PRIV_SYS_CONSOLE};
|
||||||
use pbs_tools::auth::private_auth_key;
|
use pbs_tools::auth::private_auth_key;
|
||||||
use pbs_tools::ticket::{self, Empty, Ticket};
|
use pbs_tools::ticket::{self, Empty, Ticket};
|
||||||
|
|
||||||
use crate::api2::types::*;
|
|
||||||
use crate::config::acl::PRIV_SYS_CONSOLE;
|
|
||||||
use crate::server::WorkerTask;
|
use crate::server::WorkerTask;
|
||||||
use crate::tools;
|
use crate::tools;
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,11 @@ use pbs_api_types::{
|
||||||
Authid, Interface, NetworkInterfaceType, LinuxBondMode, NetworkConfigMethod, BondXmitHashPolicy,
|
Authid, Interface, NetworkInterfaceType, LinuxBondMode, NetworkConfigMethod, BondXmitHashPolicy,
|
||||||
NETWORK_INTERFACE_ARRAY_SCHEMA, NETWORK_INTERFACE_LIST_SCHEMA, NETWORK_INTERFACE_NAME_SCHEMA,
|
NETWORK_INTERFACE_ARRAY_SCHEMA, NETWORK_INTERFACE_LIST_SCHEMA, NETWORK_INTERFACE_NAME_SCHEMA,
|
||||||
CIDR_V4_SCHEMA, CIDR_V6_SCHEMA, IP_V4_SCHEMA, IP_V6_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA,
|
CIDR_V4_SCHEMA, CIDR_V6_SCHEMA, IP_V4_SCHEMA, IP_V6_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA,
|
||||||
|
NODE_SCHEMA, PRIV_SYS_AUDIT, PRIV_SYS_MODIFY,
|
||||||
};
|
};
|
||||||
use pbs_config::network::{self, NetworkConfig};
|
use pbs_config::network::{self, NetworkConfig};
|
||||||
|
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
|
||||||
use crate::server::{WorkerTask};
|
use crate::server::{WorkerTask};
|
||||||
use crate::api2::types::NODE_SCHEMA;
|
|
||||||
|
|
||||||
fn split_interface_list(list: &str) -> Result<Vec<String>, Error> {
|
fn split_interface_list(list: &str) -> Result<Vec<String>, Error> {
|
||||||
let value = parse_property_string(&list, &NETWORK_INTERFACE_ARRAY_SCHEMA)?;
|
let value = parse_property_string(&list, &NETWORK_INTERFACE_ARRAY_SCHEMA)?;
|
||||||
|
|
|
@ -2,8 +2,8 @@ use anyhow::Error;
|
||||||
use proxmox::api::{api, ApiMethod, Permission, Router, RpcEnvironment};
|
use proxmox::api::{api, ApiMethod, Permission, Router, RpcEnvironment};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use crate::api2::types::*;
|
use pbs_api_types::{NODE_SCHEMA, PRIV_SYS_AUDIT};
|
||||||
use crate::config::acl::PRIV_SYS_AUDIT;
|
|
||||||
use crate::server::generate_report;
|
use crate::server::generate_report;
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
|
|
|
@ -3,8 +3,8 @@ use serde_json::{Value, json};
|
||||||
|
|
||||||
use proxmox::api::{api, Permission, Router};
|
use proxmox::api::{api, Permission, Router};
|
||||||
|
|
||||||
use crate::api2::types::*;
|
use pbs_api_types::{RRDMode, RRDTimeFrameResolution, NODE_SCHEMA, PRIV_SYS_AUDIT};
|
||||||
use crate::config::acl::PRIV_SYS_AUDIT;
|
|
||||||
use crate::rrd::{extract_cached_data, RRD_DATA_ENTRIES};
|
use crate::rrd::{extract_cached_data, RRD_DATA_ENTRIES};
|
||||||
|
|
||||||
pub fn create_value_from_rrd(
|
pub fn create_value_from_rrd(
|
||||||
|
|
|
@ -6,10 +6,9 @@ use serde_json::{json, Value};
|
||||||
use proxmox::{sortable, identity, list_subdirs_api_method};
|
use proxmox::{sortable, identity, list_subdirs_api_method};
|
||||||
use proxmox::api::{api, Router, Permission, RpcEnvironment};
|
use proxmox::api::{api, Router, Permission, RpcEnvironment};
|
||||||
use proxmox::api::router::SubdirMap;
|
use proxmox::api::router::SubdirMap;
|
||||||
use proxmox::api::schema::*;
|
|
||||||
|
|
||||||
use crate::api2::types::*;
|
use pbs_api_types::{Authid, NODE_SCHEMA, SERVICE_ID_SCHEMA, PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
|
||||||
use crate::server::WorkerTask;
|
use crate::server::WorkerTask;
|
||||||
|
|
||||||
static SERVICE_NAME_LIST: [&str; 7] = [
|
static SERVICE_NAME_LIST: [&str; 7] = [
|
||||||
|
@ -346,11 +345,6 @@ fn reload_service(
|
||||||
run_service_command(&service, "reload", auth_id)
|
run_service_command(&service, "reload", auth_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const SERVICE_ID_SCHEMA: Schema = StringSchema::new("Service ID.")
|
|
||||||
.max_length(256)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
#[sortable]
|
#[sortable]
|
||||||
const SERVICE_SUBDIRS: SubdirMap = &sorted!([
|
const SERVICE_SUBDIRS: SubdirMap = &sorted!([
|
||||||
(
|
(
|
||||||
|
|
|
@ -9,9 +9,11 @@ use proxmox::sys::linux::procfs;
|
||||||
use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
|
use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
|
||||||
|
|
||||||
use pbs_tools::cert::CertInfo;
|
use pbs_tools::cert::CertInfo;
|
||||||
|
use pbs_api_types::{NODE_SCHEMA, NodePowerCommand, PRIV_SYS_AUDIT, PRIV_SYS_POWER_MANAGEMENT};
|
||||||
|
|
||||||
use crate::api2::types::*;
|
use crate::api2::types::{
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_POWER_MANAGEMENT};
|
NodeCpuInformation, NodeStatus, NodeMemoryCounters, NodeSwapCounters, NodeInformation,
|
||||||
|
};
|
||||||
|
|
||||||
impl std::convert::From<procfs::ProcFsCPUInfo> for NodeCpuInformation {
|
impl std::convert::From<procfs::ProcFsCPUInfo> for NodeCpuInformation {
|
||||||
fn from(info: procfs::ProcFsCPUInfo) -> Self {
|
fn from(info: procfs::ProcFsCPUInfo) -> Self {
|
||||||
|
|
|
@ -3,11 +3,14 @@ use serde_json::Value;
|
||||||
|
|
||||||
use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
||||||
|
|
||||||
|
use pbs_api_types::{
|
||||||
|
NODE_SCHEMA, SUBSCRIPTION_KEY_SCHEMA, Authid,
|
||||||
|
PRIV_SYS_AUDIT,PRIV_SYS_MODIFY,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::tools;
|
use crate::tools;
|
||||||
use crate::tools::subscription::{self, SubscriptionStatus, SubscriptionInfo};
|
use crate::tools::subscription::{self, SubscriptionStatus, SubscriptionInfo};
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT,PRIV_SYS_MODIFY};
|
|
||||||
use crate::config::cached_user_info::CachedUserInfo;
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
use crate::api2::types::{NODE_SCHEMA, SUBSCRIPTION_KEY_SCHEMA, Authid};
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
input: {
|
input: {
|
||||||
|
|
|
@ -5,8 +5,7 @@ use serde_json::{json, Value};
|
||||||
|
|
||||||
use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
|
use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
|
||||||
|
|
||||||
use crate::api2::types::*;
|
use pbs_api_types::{NODE_SCHEMA, SYSTEMD_DATETIME_FORMAT, PRIV_SYS_AUDIT};
|
||||||
use crate::config::acl::PRIV_SYS_AUDIT;
|
|
||||||
|
|
||||||
fn dump_journal(
|
fn dump_journal(
|
||||||
start: Option<u64>,
|
start: Option<u64>,
|
||||||
|
|
|
@ -8,16 +8,16 @@ use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
||||||
use proxmox::api::router::SubdirMap;
|
use proxmox::api::router::SubdirMap;
|
||||||
use proxmox::{identity, list_subdirs_api_method, sortable};
|
use proxmox::{identity, list_subdirs_api_method, sortable};
|
||||||
|
|
||||||
use crate::api2::types::*;
|
use pbs_api_types::{
|
||||||
use crate::api2::pull::check_pull_privs;
|
Userid, Authid, Tokenname, TaskListItem,
|
||||||
|
NODE_SCHEMA, UPID_SCHEMA, VERIFICATION_JOB_WORKER_ID_REGEX,
|
||||||
use crate::server::{self, UPID, UPIDExt, TaskState, TaskListInfoIterator};
|
SYNC_JOB_WORKER_ID_REGEX, DATASTORE_SCHEMA,
|
||||||
use crate::config::acl::{
|
PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_VERIFY, PRIV_SYS_AUDIT, PRIV_SYS_MODIFY,
|
||||||
PRIV_DATASTORE_MODIFY,
|
|
||||||
PRIV_DATASTORE_VERIFY,
|
|
||||||
PRIV_SYS_AUDIT,
|
|
||||||
PRIV_SYS_MODIFY,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::api2::types::TaskStateType;
|
||||||
|
use crate::api2::pull::check_pull_privs;
|
||||||
|
use crate::server::{self, UPID, UPIDExt, TaskState, TaskListInfoIterator};
|
||||||
use crate::config::cached_user_info::CachedUserInfo;
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
|
|
||||||
// matches respective job execution privileges
|
// matches respective job execution privileges
|
||||||
|
|
|
@ -4,8 +4,7 @@ use serde_json::{json, Value};
|
||||||
use proxmox::api::{api, Router, Permission};
|
use proxmox::api::{api, Router, Permission};
|
||||||
use proxmox::tools::fs::{file_read_firstline, replace_file, CreateOptions};
|
use proxmox::tools::fs::{file_read_firstline, replace_file, CreateOptions};
|
||||||
|
|
||||||
use crate::config::acl::PRIV_SYS_MODIFY;
|
use pbs_api_types::{NODE_SCHEMA, TIME_ZONE_SCHEMA, PRIV_SYS_MODIFY};
|
||||||
use crate::api2::types::*;
|
|
||||||
|
|
||||||
fn read_etc_localtime() -> Result<String, Error> {
|
fn read_etc_localtime() -> Result<String, Error> {
|
||||||
// use /etc/timezone
|
// use /etc/timezone
|
||||||
|
|
|
@ -9,18 +9,14 @@ use proxmox::api::{ApiMethod, Router, RpcEnvironment, Permission};
|
||||||
|
|
||||||
use pbs_client::{HttpClient, BackupRepository};
|
use pbs_client::{HttpClient, BackupRepository};
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
Remote, DATASTORE_SCHEMA, REMOTE_ID_SCHEMA, Authid,
|
Remote, Authid, SyncJobConfig,
|
||||||
|
DATASTORE_SCHEMA, REMOTE_ID_SCHEMA, REMOVE_VANISHED_BACKUPS_SCHEMA,
|
||||||
|
PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_PRUNE, PRIV_REMOTE_READ,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::server::{WorkerTask, jobstate::Job, pull::pull_store};
|
use crate::server::{WorkerTask, jobstate::Job, pull::pull_store};
|
||||||
use crate::backup::DataStore;
|
use crate::backup::DataStore;
|
||||||
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
use pbs_api_types::{SyncJobConfig, REMOVE_VANISHED_BACKUPS_SCHEMA};
|
|
||||||
|
|
||||||
use crate::config::{
|
|
||||||
acl::{PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_PRUNE, PRIV_REMOTE_READ},
|
|
||||||
cached_user_info::CachedUserInfo,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn check_pull_privs(
|
pub fn check_pull_privs(
|
||||||
auth_id: &Authid,
|
auth_id: &Authid,
|
||||||
|
|
|
@ -27,6 +27,10 @@ use proxmox::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use pbs_api_types::{
|
||||||
|
Authid, DATASTORE_SCHEMA, BACKUP_TYPE_SCHEMA, BACKUP_TIME_SCHEMA, BACKUP_ID_SCHEMA,
|
||||||
|
CHUNK_DIGEST_SCHEMA, PRIV_DATASTORE_READ, PRIV_DATASTORE_BACKUP,
|
||||||
|
};
|
||||||
use pbs_tools::fs::lock_dir_noblock_shared;
|
use pbs_tools::fs::lock_dir_noblock_shared;
|
||||||
use pbs_tools::json::{required_integer_param, required_string_param};
|
use pbs_tools::json::{required_integer_param, required_string_param};
|
||||||
use pbs_datastore::PROXMOX_BACKUP_READER_PROTOCOL_ID_V1;
|
use pbs_datastore::PROXMOX_BACKUP_READER_PROTOCOL_ID_V1;
|
||||||
|
@ -35,29 +39,13 @@ use pbs_datastore::index::IndexFile;
|
||||||
use pbs_datastore::manifest::{archive_type, ArchiveType};
|
use pbs_datastore::manifest::{archive_type, ArchiveType};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
api2::{
|
api2::helpers,
|
||||||
helpers,
|
|
||||||
types::{
|
|
||||||
DATASTORE_SCHEMA,
|
|
||||||
BACKUP_TYPE_SCHEMA,
|
|
||||||
BACKUP_TIME_SCHEMA,
|
|
||||||
BACKUP_ID_SCHEMA,
|
|
||||||
CHUNK_DIGEST_SCHEMA,
|
|
||||||
Authid,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
backup::DataStore,
|
backup::DataStore,
|
||||||
server::{
|
server::{
|
||||||
WorkerTask,
|
WorkerTask,
|
||||||
H2Service,
|
H2Service,
|
||||||
},
|
},
|
||||||
config::{
|
config::cached_user_info::CachedUserInfo,
|
||||||
acl::{
|
|
||||||
PRIV_DATASTORE_READ,
|
|
||||||
PRIV_DATASTORE_BACKUP,
|
|
||||||
},
|
|
||||||
cached_user_info::CachedUserInfo,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod environment;
|
mod environment;
|
||||||
|
|
|
@ -14,21 +14,15 @@ use proxmox::api::{
|
||||||
SubdirMap,
|
SubdirMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::api2::types::{
|
use pbs_api_types::{
|
||||||
DATASTORE_SCHEMA,
|
DATASTORE_SCHEMA, RRDMode, RRDTimeFrameResolution, Authid,
|
||||||
RRDMode,
|
PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP,
|
||||||
RRDTimeFrameResolution,
|
|
||||||
Authid,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::backup::DataStore;
|
use crate::backup::DataStore;
|
||||||
use crate::config::datastore;
|
use crate::config::datastore;
|
||||||
use crate::tools::statistics::{linear_regression};
|
use crate::tools::statistics::{linear_regression};
|
||||||
use crate::config::cached_user_info::CachedUserInfo;
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
use crate::config::acl::{
|
|
||||||
PRIV_DATASTORE_AUDIT,
|
|
||||||
PRIV_DATASTORE_BACKUP,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
returns: {
|
returns: {
|
||||||
|
|
|
@ -17,7 +17,7 @@ use proxmox::{
|
||||||
|
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
Authid, Userid, TapeBackupJobConfig, TapeBackupJobSetup, TapeBackupJobStatus, MediaPoolConfig,
|
Authid, Userid, TapeBackupJobConfig, TapeBackupJobSetup, TapeBackupJobStatus, MediaPoolConfig,
|
||||||
UPID_SCHEMA, JOB_ID_SCHEMA,
|
UPID_SCHEMA, JOB_ID_SCHEMA, PRIV_DATASTORE_READ, PRIV_TAPE_AUDIT, PRIV_TAPE_WRITE,
|
||||||
};
|
};
|
||||||
|
|
||||||
use pbs_datastore::{task_log, task_warn, StoreProgress};
|
use pbs_datastore::{task_log, task_warn, StoreProgress};
|
||||||
|
@ -25,14 +25,7 @@ use pbs_datastore::backup_info::{BackupDir, BackupInfo};
|
||||||
use pbs_datastore::task::TaskState;
|
use pbs_datastore::task::TaskState;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config::cached_user_info::CachedUserInfo,
|
||||||
cached_user_info::CachedUserInfo,
|
|
||||||
acl::{
|
|
||||||
PRIV_DATASTORE_READ,
|
|
||||||
PRIV_TAPE_AUDIT,
|
|
||||||
PRIV_TAPE_WRITE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
server::{
|
server::{
|
||||||
lookup_user_email,
|
lookup_user_email,
|
||||||
TapeBackupJobSummary,
|
TapeBackupJobSummary,
|
||||||
|
|
|
@ -7,23 +7,13 @@ use serde_json::Value;
|
||||||
use proxmox::api::{api, Router, SubdirMap, RpcEnvironment, Permission};
|
use proxmox::api::{api, Router, SubdirMap, RpcEnvironment, Permission};
|
||||||
use proxmox::list_subdirs_api_method;
|
use proxmox::list_subdirs_api_method;
|
||||||
|
|
||||||
|
use pbs_api_types::{
|
||||||
|
Authid, ChangerListEntry, LtoTapeDrive, MtxEntryKind, MtxStatusEntry, ScsiTapeChanger,
|
||||||
|
CHANGER_NAME_SCHEMA, PRIV_TAPE_AUDIT, PRIV_TAPE_READ,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config::cached_user_info::CachedUserInfo,
|
||||||
cached_user_info::CachedUserInfo,
|
|
||||||
acl::{
|
|
||||||
PRIV_TAPE_AUDIT,
|
|
||||||
PRIV_TAPE_READ,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
api2::types::{
|
|
||||||
Authid,
|
|
||||||
CHANGER_NAME_SCHEMA,
|
|
||||||
ChangerListEntry,
|
|
||||||
LtoTapeDrive,
|
|
||||||
MtxEntryKind,
|
|
||||||
MtxStatusEntry,
|
|
||||||
ScsiTapeChanger,
|
|
||||||
},
|
|
||||||
tape::{
|
tape::{
|
||||||
TAPE_STATUS_DIR,
|
TAPE_STATUS_DIR,
|
||||||
Inventory,
|
Inventory,
|
||||||
|
|
|
@ -22,37 +22,20 @@ use proxmox::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use pbs_api_types::{
|
||||||
|
UPID_SCHEMA, CHANGER_NAME_SCHEMA, DRIVE_NAME_SCHEMA, MEDIA_LABEL_SCHEMA, MEDIA_POOL_NAME_SCHEMA,
|
||||||
|
Authid, DriveListEntry, LtoTapeDrive, MediaIdFlat, LabelUuidMap, MamAttribute,
|
||||||
|
LtoDriveAndMediaStatus, Lp17VolumeStatistics,
|
||||||
|
};
|
||||||
|
|
||||||
use pbs_datastore::task_log;
|
use pbs_datastore::task_log;
|
||||||
|
use pbs_api_types::{PRIV_TAPE_AUDIT, PRIV_TAPE_READ, PRIV_TAPE_WRITE};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config::cached_user_info::CachedUserInfo,
|
||||||
cached_user_info::CachedUserInfo,
|
api2::tape::restore::{
|
||||||
acl::{
|
fast_catalog_restore,
|
||||||
PRIV_TAPE_AUDIT,
|
restore_media,
|
||||||
PRIV_TAPE_READ,
|
|
||||||
PRIV_TAPE_WRITE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
api2::{
|
|
||||||
types::{
|
|
||||||
UPID_SCHEMA,
|
|
||||||
CHANGER_NAME_SCHEMA,
|
|
||||||
DRIVE_NAME_SCHEMA,
|
|
||||||
MEDIA_LABEL_SCHEMA,
|
|
||||||
MEDIA_POOL_NAME_SCHEMA,
|
|
||||||
Authid,
|
|
||||||
DriveListEntry,
|
|
||||||
LtoTapeDrive,
|
|
||||||
MediaIdFlat,
|
|
||||||
LabelUuidMap,
|
|
||||||
MamAttribute,
|
|
||||||
LtoDriveAndMediaStatus,
|
|
||||||
Lp17VolumeStatistics,
|
|
||||||
},
|
|
||||||
tape::restore::{
|
|
||||||
fast_catalog_restore,
|
|
||||||
restore_media,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
server::WorkerTask,
|
server::WorkerTask,
|
||||||
tape::{
|
tape::{
|
||||||
|
|
|
@ -14,15 +14,11 @@ use pbs_api_types::{
|
||||||
MEDIA_POOL_NAME_SCHEMA, MEDIA_LABEL_SCHEMA, MEDIA_UUID_SCHEMA, CHANGER_NAME_SCHEMA,
|
MEDIA_POOL_NAME_SCHEMA, MEDIA_LABEL_SCHEMA, MEDIA_UUID_SCHEMA, CHANGER_NAME_SCHEMA,
|
||||||
VAULT_NAME_SCHEMA, Authid, MediaPoolConfig, MediaListEntry, MediaSetListEntry,
|
VAULT_NAME_SCHEMA, Authid, MediaPoolConfig, MediaListEntry, MediaSetListEntry,
|
||||||
MediaStatus, MediaContentEntry, MediaContentListFilter,
|
MediaStatus, MediaContentEntry, MediaContentListFilter,
|
||||||
|
PRIV_TAPE_AUDIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config::cached_user_info::CachedUserInfo,
|
||||||
cached_user_info::CachedUserInfo,
|
|
||||||
acl::{
|
|
||||||
PRIV_TAPE_AUDIT,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tape::{
|
tape::{
|
||||||
TAPE_STATUS_DIR,
|
TAPE_STATUS_DIR,
|
||||||
Inventory,
|
Inventory,
|
||||||
|
|
|
@ -28,7 +28,12 @@ use proxmox::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use pbs_api_types::CryptMode;
|
use pbs_api_types::{
|
||||||
|
Authid, Userid, CryptMode,
|
||||||
|
DATASTORE_MAP_ARRAY_SCHEMA, DATASTORE_MAP_LIST_SCHEMA, DRIVE_NAME_SCHEMA,
|
||||||
|
UPID_SCHEMA, TAPE_RESTORE_SNAPSHOT_SCHEMA,
|
||||||
|
PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_MODIFY, PRIV_TAPE_READ,
|
||||||
|
};
|
||||||
use pbs_datastore::{task_log, task_warn, DataBlob};
|
use pbs_datastore::{task_log, task_warn, DataBlob};
|
||||||
use pbs_datastore::backup_info::BackupDir;
|
use pbs_datastore::backup_info::BackupDir;
|
||||||
use pbs_datastore::dynamic_index::DynamicIndexReader;
|
use pbs_datastore::dynamic_index::DynamicIndexReader;
|
||||||
|
@ -39,23 +44,7 @@ use pbs_datastore::task::TaskState;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
tools::ParallelHandler,
|
tools::ParallelHandler,
|
||||||
api2::types::{
|
config::cached_user_info::CachedUserInfo,
|
||||||
DATASTORE_MAP_ARRAY_SCHEMA,
|
|
||||||
DATASTORE_MAP_LIST_SCHEMA,
|
|
||||||
DRIVE_NAME_SCHEMA,
|
|
||||||
UPID_SCHEMA,
|
|
||||||
Authid,
|
|
||||||
Userid,
|
|
||||||
TAPE_RESTORE_SNAPSHOT_SCHEMA,
|
|
||||||
},
|
|
||||||
config::{
|
|
||||||
cached_user_info::CachedUserInfo,
|
|
||||||
acl::{
|
|
||||||
PRIV_DATASTORE_BACKUP,
|
|
||||||
PRIV_DATASTORE_MODIFY,
|
|
||||||
PRIV_TAPE_READ,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
backup::DataStore,
|
backup::DataStore,
|
||||||
server::{
|
server::{
|
||||||
lookup_user_email,
|
lookup_user_email,
|
||||||
|
|
|
@ -4,9 +4,6 @@ use anyhow::bail;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox::api::{api, schema::*};
|
use proxmox::api::{api, schema::*};
|
||||||
use proxmox::const_regex;
|
|
||||||
|
|
||||||
use crate::config::acl::Role;
|
|
||||||
|
|
||||||
mod acme;
|
mod acme;
|
||||||
pub use acme::*;
|
pub use acme::*;
|
||||||
|
@ -24,177 +21,6 @@ pub const FILENAME_FORMAT: ApiStringFormat = ApiStringFormat::VerifyFn(|name| {
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
const_regex!{
|
|
||||||
pub SYSTEMD_DATETIME_REGEX = r"^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$"; // fixme: define in common_regex ?
|
|
||||||
|
|
||||||
pub ACL_PATH_REGEX = concat!(r"^(?:/|", r"(?:/", PROXMOX_SAFE_ID_REGEX_STR!(), ")+", r")$");
|
|
||||||
|
|
||||||
pub SUBSCRIPTION_KEY_REGEX = concat!(r"^pbs(?:[cbsp])-[0-9a-f]{10}$");
|
|
||||||
|
|
||||||
pub ZPOOL_NAME_REGEX = r"^[a-zA-Z][a-z0-9A-Z\-_.:]+$";
|
|
||||||
|
|
||||||
pub DATASTORE_MAP_REGEX = concat!(r"(:?", PROXMOX_SAFE_ID_REGEX_STR!(), r"=)?", PROXMOX_SAFE_ID_REGEX_STR!());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const SYSTEMD_DATETIME_FORMAT: ApiStringFormat =
|
|
||||||
ApiStringFormat::Pattern(&SYSTEMD_DATETIME_REGEX);
|
|
||||||
|
|
||||||
pub const HOSTNAME_FORMAT: ApiStringFormat =
|
|
||||||
ApiStringFormat::Pattern(&HOSTNAME_REGEX);
|
|
||||||
|
|
||||||
pub const DNS_ALIAS_FORMAT: ApiStringFormat =
|
|
||||||
ApiStringFormat::Pattern(&DNS_ALIAS_REGEX);
|
|
||||||
|
|
||||||
pub const ACL_PATH_FORMAT: ApiStringFormat =
|
|
||||||
ApiStringFormat::Pattern(&ACL_PATH_REGEX);
|
|
||||||
|
|
||||||
|
|
||||||
pub const SUBSCRIPTION_KEY_FORMAT: ApiStringFormat =
|
|
||||||
ApiStringFormat::Pattern(&SUBSCRIPTION_KEY_REGEX);
|
|
||||||
|
|
||||||
pub const BLOCKDEVICE_NAME_FORMAT: ApiStringFormat =
|
|
||||||
ApiStringFormat::Pattern(&BLOCKDEVICE_NAME_REGEX);
|
|
||||||
|
|
||||||
pub const DATASTORE_MAP_FORMAT: ApiStringFormat =
|
|
||||||
ApiStringFormat::Pattern(&DATASTORE_MAP_REGEX);
|
|
||||||
|
|
||||||
pub const PASSWORD_SCHEMA: Schema = StringSchema::new("Password.")
|
|
||||||
.format(&PASSWORD_FORMAT)
|
|
||||||
.min_length(1)
|
|
||||||
.max_length(1024)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.")
|
|
||||||
.format(&PASSWORD_FORMAT)
|
|
||||||
.min_length(5)
|
|
||||||
.max_length(64)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const CHUNK_DIGEST_SCHEMA: Schema = StringSchema::new("Chunk digest (SHA256).")
|
|
||||||
.format(&CHUNK_DIGEST_FORMAT)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const NODE_SCHEMA: Schema = StringSchema::new("Node name (or 'localhost')")
|
|
||||||
.format(&ApiStringFormat::VerifyFn(|node| {
|
|
||||||
if node == "localhost" || node == proxmox::tools::nodename() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
bail!("no such node '{}'", node);
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const SEARCH_DOMAIN_SCHEMA: Schema =
|
|
||||||
StringSchema::new("Search domain for host-name lookup.").schema();
|
|
||||||
|
|
||||||
pub const FIRST_DNS_SERVER_SCHEMA: Schema =
|
|
||||||
StringSchema::new("First name server IP address.")
|
|
||||||
.format(&IP_FORMAT)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const SECOND_DNS_SERVER_SCHEMA: Schema =
|
|
||||||
StringSchema::new("Second name server IP address.")
|
|
||||||
.format(&IP_FORMAT)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const THIRD_DNS_SERVER_SCHEMA: Schema =
|
|
||||||
StringSchema::new("Third name server IP address.")
|
|
||||||
.format(&IP_FORMAT)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
|
|
||||||
pub const TIME_ZONE_SCHEMA: Schema = StringSchema::new(
|
|
||||||
"Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.")
|
|
||||||
.format(&SINGLE_LINE_COMMENT_FORMAT)
|
|
||||||
.min_length(2)
|
|
||||||
.max_length(64)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const ACL_PATH_SCHEMA: Schema = StringSchema::new(
|
|
||||||
"Access control path.")
|
|
||||||
.format(&ACL_PATH_FORMAT)
|
|
||||||
.min_length(1)
|
|
||||||
.max_length(128)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const ACL_PROPAGATE_SCHEMA: Schema = BooleanSchema::new(
|
|
||||||
"Allow to propagate (inherit) permissions.")
|
|
||||||
.default(true)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const ACL_UGID_TYPE_SCHEMA: Schema = StringSchema::new(
|
|
||||||
"Type of 'ugid' property.")
|
|
||||||
.format(&ApiStringFormat::Enum(&[
|
|
||||||
EnumEntry::new("user", "User"),
|
|
||||||
EnumEntry::new("group", "Group")]))
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
#[api(
|
|
||||||
properties: {
|
|
||||||
propagate: {
|
|
||||||
schema: ACL_PROPAGATE_SCHEMA,
|
|
||||||
},
|
|
||||||
path: {
|
|
||||||
schema: ACL_PATH_SCHEMA,
|
|
||||||
},
|
|
||||||
ugid_type: {
|
|
||||||
schema: ACL_UGID_TYPE_SCHEMA,
|
|
||||||
},
|
|
||||||
ugid: {
|
|
||||||
type: String,
|
|
||||||
description: "User or Group ID.",
|
|
||||||
},
|
|
||||||
roleid: {
|
|
||||||
type: Role,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
/// ACL list entry.
|
|
||||||
pub struct AclListItem {
|
|
||||||
pub path: String,
|
|
||||||
pub ugid: String,
|
|
||||||
pub ugid_type: String,
|
|
||||||
pub propagate: bool,
|
|
||||||
pub roleid: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const DATASTORE_MAP_SCHEMA: Schema = StringSchema::new("Datastore mapping.")
|
|
||||||
.format(&DATASTORE_MAP_FORMAT)
|
|
||||||
.min_length(3)
|
|
||||||
.max_length(65)
|
|
||||||
.type_text("(<source>=)?<target>")
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const DATASTORE_MAP_ARRAY_SCHEMA: Schema = ArraySchema::new(
|
|
||||||
"Datastore mapping list.", &DATASTORE_MAP_SCHEMA)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const DATASTORE_MAP_LIST_SCHEMA: Schema = StringSchema::new(
|
|
||||||
"A list of Datastore mappings (or single datastore), comma separated. \
|
|
||||||
For example 'a=b,e' maps the source datastore 'a' to target 'b and \
|
|
||||||
all other sources to the default 'e'. If no default is given, only the \
|
|
||||||
specified sources are mapped.")
|
|
||||||
.format(&ApiStringFormat::PropertyString(&DATASTORE_MAP_ARRAY_SCHEMA))
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
|
|
||||||
pub const HOSTNAME_SCHEMA: Schema = StringSchema::new("Hostname (as defined in RFC1123).")
|
|
||||||
.format(&HOSTNAME_FORMAT)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const SUBSCRIPTION_KEY_SCHEMA: Schema = StringSchema::new("Proxmox Backup Server subscription key.")
|
|
||||||
.format(&SUBSCRIPTION_KEY_FORMAT)
|
|
||||||
.min_length(15)
|
|
||||||
.max_length(16)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
pub const BLOCKDEVICE_NAME_SCHEMA: Schema = StringSchema::new("Block device name (/sys/block/<name>).")
|
|
||||||
.format(&BLOCKDEVICE_NAME_FORMAT)
|
|
||||||
.min_length(3)
|
|
||||||
.max_length(64)
|
|
||||||
.schema();
|
|
||||||
|
|
||||||
// Complex type definitions
|
// Complex type definitions
|
||||||
|
|
||||||
|
@ -242,17 +68,6 @@ pub enum TaskStateType {
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api()]
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "lowercase")]
|
|
||||||
/// Node Power command type.
|
|
||||||
pub enum NodePowerCommand {
|
|
||||||
/// Restart the server
|
|
||||||
Reboot,
|
|
||||||
/// Shutdown the server
|
|
||||||
Shutdown,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regression tests
|
// Regression tests
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -340,34 +155,6 @@ fn test_proxmox_user_id_schema() -> Result<(), anyhow::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api()]
|
|
||||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "UPPERCASE")]
|
|
||||||
pub enum RRDMode {
|
|
||||||
/// Maximum
|
|
||||||
Max,
|
|
||||||
/// Average
|
|
||||||
Average,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[api()]
|
|
||||||
#[repr(u64)]
|
|
||||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "lowercase")]
|
|
||||||
pub enum RRDTimeFrameResolution {
|
|
||||||
/// 1 min => last 70 minutes
|
|
||||||
Hour = 60,
|
|
||||||
/// 30 min => last 35 hours
|
|
||||||
Day = 60*30,
|
|
||||||
/// 3 hours => about 8 days
|
|
||||||
Week = 60*180,
|
|
||||||
/// 12 hours => last 35 days
|
|
||||||
Month = 60*720,
|
|
||||||
/// 1 week => last 490 days
|
|
||||||
Year = 60*10080,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api]
|
#[api]
|
||||||
#[derive(Serialize, Deserialize, Default)]
|
#[derive(Serialize, Deserialize, Default)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
|
|
@ -25,13 +25,9 @@ use proxmox::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use proxmox_backup::{
|
use pbs_api_types::PRIVILEGES;
|
||||||
api2,
|
|
||||||
config::{
|
use proxmox_backup::{api2, config};
|
||||||
self,
|
|
||||||
acl::PRIVILEGES,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
fn get_args() -> (String, Vec<String>) {
|
fn get_args() -> (String, Vec<String>) {
|
||||||
|
|
||||||
|
@ -62,7 +58,7 @@ fn main() -> Result<(), Error> {
|
||||||
"sync.cfg" => dump_section_config(&pbs_config::sync::CONFIG),
|
"sync.cfg" => dump_section_config(&pbs_config::sync::CONFIG),
|
||||||
"verification.cfg" => dump_section_config(&pbs_config::verify::CONFIG),
|
"verification.cfg" => dump_section_config(&pbs_config::verify::CONFIG),
|
||||||
"media-pool.cfg" => dump_section_config(&pbs_config::media_pool::CONFIG),
|
"media-pool.cfg" => dump_section_config(&pbs_config::media_pool::CONFIG),
|
||||||
"config::acl::Role" => dump_enum_properties(&config::acl::Role::API_SCHEMA)?,
|
"config::acl::Role" => dump_enum_properties(&pbs_api_types::Role::API_SCHEMA)?,
|
||||||
_ => bail!("docgen: got unknown type"),
|
_ => bail!("docgen: got unknown type"),
|
||||||
};
|
};
|
||||||
println!("{}", text);
|
println!("{}", text);
|
||||||
|
|
|
@ -3,20 +3,17 @@ use serde_json::Value;
|
||||||
|
|
||||||
use proxmox::api::{api, cli::*, RpcEnvironment, ApiHandler};
|
use proxmox::api::{api, cli::*, RpcEnvironment, ApiHandler};
|
||||||
|
|
||||||
|
use pbs_api_types::{
|
||||||
|
DISK_LIST_SCHEMA, ZFS_ASHIFT_SCHEMA, ZfsRaidLevel, ZfsCompressionType,
|
||||||
|
BLOCKDEVICE_NAME_SCHEMA, DATASTORE_SCHEMA,
|
||||||
|
};
|
||||||
use proxmox_backup::tools::disks::{
|
use proxmox_backup::tools::disks::{
|
||||||
FileSystemType,
|
FileSystemType,
|
||||||
SmartAttribute,
|
SmartAttribute,
|
||||||
complete_disk_name,
|
complete_disk_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
use proxmox_backup::api2::node::disks::{
|
use proxmox_backup::api2;
|
||||||
zfs::DISK_LIST_SCHEMA,
|
|
||||||
zfs::ZFS_ASHIFT_SCHEMA,
|
|
||||||
zfs::ZfsRaidLevel,
|
|
||||||
zfs::ZfsCompressionType,
|
|
||||||
};
|
|
||||||
|
|
||||||
use proxmox_backup::api2::{self, types::* };
|
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
input: {
|
input: {
|
||||||
|
|
|
@ -9,9 +9,10 @@ use lazy_static::lazy_static;
|
||||||
use proxmox::api::UserInformation;
|
use proxmox::api::UserInformation;
|
||||||
use proxmox::tools::time::epoch_i64;
|
use proxmox::tools::time::epoch_i64;
|
||||||
|
|
||||||
use super::acl::{AclTree, ROLE_NAMES, ROLE_ADMIN};
|
use pbs_api_types::{Authid, Userid, ROLE_ADMIN};
|
||||||
|
use pbs_config::acl::{AclTree, ROLE_NAMES};
|
||||||
|
|
||||||
use super::user::{ApiToken, User};
|
use super::user::{ApiToken, User};
|
||||||
use crate::api2::types::{Authid, Userid};
|
|
||||||
use crate::tools::Memcom;
|
use crate::tools::Memcom;
|
||||||
|
|
||||||
/// Cache User/Group/Token/Acl configuration data for fast permission tests
|
/// Cache User/Group/Token/Acl configuration data for fast permission tests
|
||||||
|
@ -54,7 +55,7 @@ impl CachedUserInfo {
|
||||||
|
|
||||||
let config = Arc::new(CachedUserInfo {
|
let config = Arc::new(CachedUserInfo {
|
||||||
user_cfg: super::user::cached_config()?,
|
user_cfg: super::user::cached_config()?,
|
||||||
acl_tree: super::acl::cached_config()?,
|
acl_tree: pbs_config::acl::cached_config()?,
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut cache = CACHED_CONFIG.write().unwrap();
|
let mut cache = CACHED_CONFIG.write().unwrap();
|
||||||
|
|
|
@ -14,7 +14,6 @@ use proxmox::try_block;
|
||||||
|
|
||||||
use pbs_buildcfg::{self, configdir};
|
use pbs_buildcfg::{self, configdir};
|
||||||
|
|
||||||
pub mod acl;
|
|
||||||
pub mod acme;
|
pub mod acme;
|
||||||
pub mod cached_user_info;
|
pub mod cached_user_info;
|
||||||
pub mod datastore;
|
pub mod datastore;
|
||||||
|
|
|
@ -5,10 +5,9 @@ use anyhow::Error;
|
||||||
use pbs_datastore::{task_log, task_warn};
|
use pbs_datastore::{task_log, task_warn};
|
||||||
use pbs_datastore::backup_info::BackupInfo;
|
use pbs_datastore::backup_info::BackupInfo;
|
||||||
use pbs_datastore::prune::{compute_prune_info, PruneOptions};
|
use pbs_datastore::prune::{compute_prune_info, PruneOptions};
|
||||||
|
use pbs_api_types::{Authid, PRIV_DATASTORE_MODIFY};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
api2::types::*,
|
|
||||||
config::acl::PRIV_DATASTORE_MODIFY,
|
|
||||||
config::cached_user_info::CachedUserInfo,
|
config::cached_user_info::CachedUserInfo,
|
||||||
backup::DataStore,
|
backup::DataStore,
|
||||||
server::jobstate::Job,
|
server::jobstate::Job,
|
||||||
|
|
|
@ -88,7 +88,7 @@ fn verify_access_permissions(permission: &Permission) -> Result<(), Error> {
|
||||||
}
|
}
|
||||||
Permission::Privilege(path_comp, ..)=> {
|
Permission::Privilege(path_comp, ..)=> {
|
||||||
let path = format!("/{}", path_comp.join("/"));
|
let path = format!("/{}", path_comp.join("/"));
|
||||||
proxmox_backup::config::acl::check_acl_path(&path)?;
|
pbs_config::acl::check_acl_path(&path)?;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue