move acl to pbs_config workspaces, pbs_api_types cleanups

This commit is contained in:
Dietmar Maurer 2021-09-09 10:32:44 +02:00
parent 1cb08a0a05
commit 8cc3760e74
58 changed files with 1064 additions and 1161 deletions

284
pbs-api-types/src/acl.rs Normal file
View File

@ -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,
}

View File

@ -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(),
};

View File

@ -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,
}

81
pbs-api-types/src/zfs.rs Normal file
View File

@ -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,
}

View File

@ -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);

View File

@ -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;

View File

@ -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(())
} }

View File

@ -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 {

View File

@ -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: {

View File

@ -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};

View File

@ -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)

View File

@ -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";

View File

@ -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: {

View File

@ -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;

View File

@ -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: {

View File

@ -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,
}; };

View File

@ -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,

View File

@ -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(

View File

@ -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,

View File

@ -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,

View File

@ -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: {

View File

@ -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

View File

@ -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: {

View File

@ -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: {},

View File

@ -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(

View File

@ -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: {

View File

@ -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;

View File

@ -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()

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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";

View File

@ -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,

View File

@ -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;

View File

@ -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)?;

View File

@ -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(

View File

@ -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(

View File

@ -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!([
( (

View File

@ -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 {

View File

@ -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: {

View File

@ -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>,

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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: {

View File

@ -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,

View File

@ -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,

View File

@ -22,38 +22,21 @@ 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::{
PRIV_TAPE_AUDIT,
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, fast_catalog_restore,
restore_media, restore_media,
}, },
},
server::WorkerTask, server::WorkerTask,
tape::{ tape::{
TAPE_STATUS_DIR, TAPE_STATUS_DIR,

View File

@ -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,

View File

@ -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,

View File

@ -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")]

View File

@ -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);

View File

@ -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: {

View File

@ -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();

View File

@ -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;

View File

@ -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,

View File

@ -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)?;
} }
_ => {} _ => {}
} }