From 8cc3760e747294d643ab858611f7b2d6eb07ab0a Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Thu, 9 Sep 2021 10:32:44 +0200 Subject: [PATCH] move acl to pbs_config workspaces, pbs_api_types cleanups --- pbs-api-types/src/acl.rs | 284 +++++++++++++++ pbs-api-types/src/datastore.rs | 363 +++++++++++++++++++ pbs-api-types/src/lib.rs | 446 +++++++----------------- pbs-api-types/src/zfs.rs | 81 +++++ {src/config => pbs-config/src}/acl.rs | 240 +------------ pbs-config/src/lib.rs | 1 + src/api2/access/acl.rs | 24 +- src/api2/access/mod.rs | 14 +- src/api2/access/role.rs | 4 +- src/api2/access/tfa.rs | 4 +- src/api2/access/user.rs | 5 +- src/api2/admin/datastore.rs | 17 +- src/api2/admin/verify.rs | 14 +- src/api2/backup/mod.rs | 7 +- src/api2/config/access/openid.rs | 5 +- src/api2/config/acme.rs | 5 +- src/api2/config/changer.rs | 18 +- src/api2/config/datastore.rs | 7 +- src/api2/config/drive.rs | 16 +- src/api2/config/media_pool.rs | 16 +- src/api2/config/remote.rs | 2 +- src/api2/config/sync.rs | 13 +- src/api2/config/tape_backup_job.rs | 11 +- src/api2/config/tape_encryption_keys.rs | 10 +- src/api2/config/verify.rs | 7 +- src/api2/node/apt.rs | 7 +- src/api2/node/certificates.rs | 4 +- src/api2/node/config.rs | 4 +- src/api2/node/disks/directory.rs | 7 +- src/api2/node/disks/mod.rs | 8 +- src/api2/node/disks/zfs.rs | 104 +----- src/api2/node/dns.rs | 7 +- src/api2/node/journal.rs | 3 +- src/api2/node/mod.rs | 3 +- src/api2/node/network.rs | 3 +- src/api2/node/report.rs | 4 +- src/api2/node/rrd.rs | 4 +- src/api2/node/services.rs | 10 +- src/api2/node/status.rs | 6 +- src/api2/node/subscription.rs | 7 +- src/api2/node/syslog.rs | 3 +- src/api2/node/tasks.rs | 16 +- src/api2/node/time.rs | 3 +- src/api2/pull.rs | 12 +- src/api2/reader/mod.rs | 24 +- src/api2/status.rs | 12 +- src/api2/tape/backup.rs | 11 +- src/api2/tape/changer.rs | 22 +- src/api2/tape/drive.rs | 39 +-- src/api2/tape/media.rs | 8 +- src/api2/tape/restore.rs | 25 +- src/api2/types/mod.rs | 213 ----------- src/bin/docgen.rs | 12 +- src/bin/proxmox_backup_manager/disk.rs | 13 +- src/config/cached_user_info.rs | 7 +- src/config/mod.rs | 1 - src/server/prune_job.rs | 3 +- tests/verify-api.rs | 2 +- 58 files changed, 1062 insertions(+), 1159 deletions(-) create mode 100644 pbs-api-types/src/acl.rs create mode 100644 pbs-api-types/src/datastore.rs create mode 100644 pbs-api-types/src/zfs.rs rename {src/config => pbs-config/src}/acl.rs (77%) diff --git a/pbs-api-types/src/acl.rs b/pbs-api-types/src/acl.rs new file mode 100644 index 00000000..140ff58e --- /dev/null +++ b/pbs-api-types/src/acl.rs @@ -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: "", +)] +#[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::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, +} diff --git a/pbs-api-types/src/datastore.rs b/pbs-api-types/src/datastore.rs new file mode 100644 index 00000000..e20771ba --- /dev/null +++ b/pbs-api-types/src/datastore.rs @@ -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("(=)?") + .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, +} + +#[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, + /// Archive size (from backup manifest). + #[serde(skip_serializing_if = "Option::is_none")] + pub size: Option, +} + +#[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, + /// The result of the last run verify task + #[serde(skip_serializing_if = "Option::is_none")] + pub verification: Option, + /// Fingerprint of encryption key + #[serde(skip_serializing_if = "Option::is_none")] + pub fingerprint: Option, + /// List of contained archive files. + pub files: Vec, + /// Overall snapshot size (sum of all archive sizes). + #[serde(skip_serializing_if = "Option::is_none")] + pub size: Option, + /// The owner of the snapshots group + #[serde(skip_serializing_if = "Option::is_none")] + pub owner: Option, +} + +#[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, + /// The owner of group + #[serde(skip_serializing_if = "Option::is_none")] + pub owner: Option, + /// The first line from group "notes" + #[serde(skip_serializing_if = "Option::is_none")] + pub comment: Option, +} + +#[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, + /// The counts for Host backups + pub host: Option, + /// The counts for VM backups + pub vm: Option, + /// The counts for other backup types + pub other: Option, +} + +#[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(), +}; diff --git a/pbs-api-types/src/lib.rs b/pbs-api-types/src/lib.rs index 62ded91d..59bb6f6e 100644 --- a/pbs-api-types/src/lib.rs +++ b/pbs-api-types/src/lib.rs @@ -1,10 +1,11 @@ //! Basic API types used by most of the PBS code. use serde::{Deserialize, Serialize}; +use anyhow::bail; use proxmox::api::api; use proxmox::api::schema::{ - ApiStringFormat, ApiType, ArraySchema, EnumEntry, IntegerSchema, ReturnType, Schema, + ApiStringFormat, ApiType, ArraySchema, IntegerSchema, ReturnType, Schema, StringSchema, }; 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; pub use jobs::*; @@ -73,6 +80,10 @@ pub use remote::*; mod tape; pub use tape::*; +mod zfs; +pub use zfs::*; + + #[rustfmt::skip] #[macro_use] 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 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 SYSTEMD_DATETIME_REGEX = r"^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$"; // fixme: define in common_regex ? 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 SUBSCRIPTION_KEY_REGEX = concat!(r"^pbs(?:[cbsp])-[0-9a-f]{10}$"); } 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_V6_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_V6_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 = 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) .schema(); -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"), - ])) +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 BACKUP_TIME_SCHEMA: Schema = IntegerSchema::new("Backup time (Unix epoch.)") - .minimum(1_547_797_308) + +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 DATASTORE_SCHEMA: Schema = StringSchema::new("Datastore name.") - .format(&PROXMOX_SAFE_ID_FORMAT) +pub const BLOCKDEVICE_NAME_SCHEMA: Schema = StringSchema::new("Block device name (/sys/block/).") + .format(&BLOCKDEVICE_NAME_FORMAT) .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(); 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) .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( "Prevent changes if current configuration file has different \ 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) .schema(); -pub const BACKUP_ID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&BACKUP_ID_REGEX); - /// API schema format definition for repository URLs 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 -#[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, - /// Archive size (from backup manifest). - #[serde(skip_serializing_if = "Option::is_none")] - pub size: Option, -} - -#[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, - /// The result of the last run verify task - #[serde(skip_serializing_if = "Option::is_none")] - pub verification: Option, - /// Fingerprint of encryption key - #[serde(skip_serializing_if = "Option::is_none")] - pub fingerprint: Option, - /// List of contained archive files. - pub files: Vec, - /// Overall snapshot size (sum of all archive sizes). - #[serde(skip_serializing_if = "Option::is_none")] - pub size: Option, - /// The owner of the snapshots group - #[serde(skip_serializing_if = "Option::is_none")] - pub owner: Option, -} - -#[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, - /// The owner of group - #[serde(skip_serializing_if = "Option::is_none")] - pub owner: Option, - /// The first line from group "notes" - #[serde(skip_serializing_if = "Option::is_none")] - pub comment: Option, -} - -#[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, -} - -#[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()] #[derive(Default, Serialize, Deserialize)] @@ -521,49 +376,6 @@ pub struct StorageStatus { 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, - /// The counts for Host backups - pub host: Option, - /// The counts for VM backups - pub vm: Option, - /// The counts for other backup types - pub other: Option, -} - pub const PASSWORD_HINT_SCHEMA: Schema = StringSchema::new("Password hint.") .format(&SINGLE_LINE_COMMENT_FORMAT) .min_length(1) @@ -634,37 +446,6 @@ pub struct TaskListItem { pub status: Option, } -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 { optional: false, @@ -703,3 +484,42 @@ pub struct APTUpdateInfo { #[serde(skip_serializing_if="Option::is_none")] pub extra_info: Option, } + +#[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, +} diff --git a/pbs-api-types/src/zfs.rs b/pbs-api-types/src/zfs.rs new file mode 100644 index 00000000..517ca914 --- /dev/null +++ b/pbs-api-types/src/zfs.rs @@ -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, +} diff --git a/src/config/acl.rs b/pbs-config/src/acl.rs similarity index 77% rename from src/config/acl.rs rename to pbs-config/src/acl.rs index 1716b5c3..57e88cbc 100644 --- a/src/config/acl.rs +++ b/pbs-config/src/acl.rs @@ -8,230 +8,11 @@ use anyhow::{bail, Error}; use lazy_static::lazy_static; -use ::serde::{Deserialize, Serialize}; -use serde::de::{value, IntoDeserializer}; +use proxmox::api::schema::{Schema, StringSchema, ApiStringFormat, ApiType}; -use proxmox::api::{api, schema::*}; -use proxmox::constnamedbitmap; +use pbs_api_types::{Authid, Userid, Role, ROLE_NAME_NO_ACCESS}; -use crate::api2::types::{Authid, Userid}; - -// 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: "", -)] -#[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::deserialize(s.into_deserializer()) - } -} +use crate::{open_backup_lockfile, replace_backup_config, BackupLockGuard}; lazy_static! { /// 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 mut components = vec![]; @@ -791,8 +572,8 @@ impl AclTree { Ok((tree, digest)) } - #[cfg(test)] - pub(crate) fn from_raw(raw: &str) -> Result { + /// This is used for testing + pub fn from_raw(raw: &str) -> Result { let mut tree = Self::new(); for (linenr, line) in raw.lines().enumerate() { 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. pub const ACL_CFG_LOCKFILE: &str = "/etc/proxmox-backup/.acl.lck"; +/// Get exclusive lock +pub fn lock_config() -> Result { + open_backup_lockfile(ACL_CFG_LOCKFILE, None, true) +} + /// Reads the [AclTree] from the [default path](ACL_CFG_FILENAME). pub fn config() -> Result<(AclTree, [u8; 32]), Error> { let path = PathBuf::from(ACL_CFG_FILENAME); @@ -911,7 +697,7 @@ pub fn save_config(acl: &AclTree) -> Result<(), Error> { acl.write_config(&mut raw)?; - pbs_config::replace_backup_config(ACL_CFG_FILENAME, &raw) + replace_backup_config(ACL_CFG_FILENAME, &raw) } #[cfg(test)] @@ -919,7 +705,7 @@ mod test { use super::AclTree; 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) { let path_vec = super::split_acl_path(path); diff --git a/pbs-config/src/lib.rs b/pbs-config/src/lib.rs index 48ceb73d..a5a50aff 100644 --- a/pbs-config/src/lib.rs +++ b/pbs-config/src/lib.rs @@ -1,3 +1,4 @@ +pub mod acl; pub mod domains; pub mod drive; pub mod key_config; diff --git a/src/api2/access/acl.rs b/src/api2/access/acl.rs index 296d29a3..4dec3660 100644 --- a/src/api2/access/acl.rs +++ b/src/api2/access/acl.rs @@ -4,14 +4,18 @@ use anyhow::{bail, Error}; use proxmox::api::{api, Router, RpcEnvironment, Permission}; -use crate::api2::types::*; -use crate::config::acl; -use crate::config::acl::{Role, PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY}; +use pbs_api_types::{ + Authid, AclListItem, Role, + 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 pbs_config::open_backup_lockfile; fn extract_acl_node_data( - node: &acl::AclTreeNode, + node: &AclTreeNode, path: &str, list: &mut Vec, exact: bool, @@ -110,7 +114,7 @@ pub fn read_acl( None }; - let (mut tree, digest) = acl::config()?; + let (mut tree, digest) = pbs_config::acl::config()?; let mut list: Vec = Vec::new(); 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 { 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 - acl::check_acl_path(&path)?; + pbs_config::acl::check_acl_path(&path)?; } 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(()) } diff --git a/src/api2/access/mod.rs b/src/api2/access/mod.rs index 32dfe9de..f504d763 100644 --- a/src/api2/access/mod.rs +++ b/src/api2/access/mod.rs @@ -11,15 +11,17 @@ use proxmox::api::{api, Permission, RpcEnvironment}; use proxmox::{http_err, list_subdirs_api_method}; 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::ticket::{self, Empty, Ticket}; +use pbs_config::acl::AclTreeNode; -use crate::api2::types::*; use crate::auth_helpers::*; 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::tfa::TfaChallenge; @@ -355,7 +357,7 @@ pub fn list_permissions( fn populate_acl_paths( mut paths: HashSet, - node: acl_config::AclTreeNode, + node: AclTreeNode, path: &str, ) -> HashSet { for (sub_path, child_node) in node.children { @@ -375,7 +377,7 @@ pub fn list_permissions( None => { 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, ""); // default paths, returned even if no ACL exists @@ -392,7 +394,7 @@ pub fn list_permissions( let map = paths.into_iter().fold( HashMap::new(), |mut map: HashMap>, 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); match privs { diff --git a/src/api2/access/role.rs b/src/api2/access/role.rs index be2054b5..af48734e 100644 --- a/src/api2/access/role.rs +++ b/src/api2/access/role.rs @@ -7,8 +7,8 @@ use serde_json::{json, Value}; use proxmox::api::{api, Permission}; use proxmox::api::router::Router; -use crate::api2::types::*; -use crate::config::acl::{Role, ROLE_NAMES, PRIVILEGES}; +use pbs_api_types::{Role, SINGLE_LINE_COMMENT_SCHEMA, PRIVILEGES}; +use pbs_config::acl::ROLE_NAMES; #[api( returns: { diff --git a/src/api2/access/tfa.rs b/src/api2/access/tfa.rs index d75b7f95..3f46f769 100644 --- a/src/api2/access/tfa.rs +++ b/src/api2/access/tfa.rs @@ -7,8 +7,8 @@ use proxmox::api::{api, Permission, Router, RpcEnvironment}; use proxmox::tools::tfa::totp::Totp; use proxmox::{http_bail, http_err}; -use crate::api2::types::{Authid, Userid, PASSWORD_SCHEMA}; -use crate::config::acl::{PRIV_PERMISSIONS_MODIFY, PRIV_SYS_AUDIT}; +use pbs_api_types::{Authid, Userid, PASSWORD_SCHEMA, PRIV_PERMISSIONS_MODIFY, PRIV_SYS_AUDIT}; + use crate::config::cached_user_info::CachedUserInfo; use crate::config::tfa::{TfaInfo, TfaUserData}; diff --git a/src/api2/access/user.rs b/src/api2/access/user.rs index 6d5aa0ee..2d26cdcc 100644 --- a/src/api2/access/user.rs +++ b/src/api2/access/user.rs @@ -11,14 +11,13 @@ use proxmox::api::schema::{Schema, StringSchema}; use pbs_api_types::{ 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::open_backup_lockfile; use crate::config::user; -use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY}; use crate::config::cached_user_info::CachedUserInfo; -use pbs_config::open_backup_lockfile; pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.") .format(&PASSWORD_FORMAT) diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs index 5470de73..0863d000 100644 --- a/src/api2/admin/datastore.rs +++ b/src/api2/admin/datastore.rs @@ -30,6 +30,10 @@ use pbs_api_types::{ Authid, BackupContent, Counts, CryptMode, DataStoreListItem, GarbageCollectionStatus, GroupListItem, SnapshotListItem, SnapshotVerifyState, BACKUP_ARCHIVE_NAME_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_datastore::{BackupDir, BackupGroup, StoreProgress, CATALOG_NAME}; @@ -47,10 +51,7 @@ use pbs_tools::blocking::WrappedReaderStream; use pbs_tools::stream::{AsyncReaderStream, AsyncChannelWriter}; use pbs_tools::json::{required_integer_param, required_string_param}; -use crate::api2::types::{ - DataStoreStatus, RRDMode, RRDTimeFrameResolution, IGNORE_VERIFIED_BACKUPS_SCHEMA, UPID_SCHEMA, - VERIFICATION_OUTDATED_AFTER_SCHEMA -}; +use crate::api2::types::{DataStoreStatus, RRDMode, RRDTimeFrameResolution}; use crate::api2::node::rrd::create_value_from_rrd; use crate::backup::{ 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::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"; diff --git a/src/api2/admin/verify.rs b/src/api2/admin/verify.rs index a01208a2..cc30f258 100644 --- a/src/api2/admin/verify.rs +++ b/src/api2/admin/verify.rs @@ -7,7 +7,10 @@ use proxmox::api::router::SubdirMap; use proxmox::{list_subdirs_api_method, sortable}; 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 crate::{ @@ -22,16 +25,9 @@ use crate::{ compute_schedule_status, }, }, - config::{ - acl::{ - PRIV_DATASTORE_AUDIT, - PRIV_DATASTORE_VERIFY, - }, - cached_user_info::CachedUserInfo, - }, + config::cached_user_info::CachedUserInfo, }; - #[api( input: { properties: { diff --git a/src/api2/backup/mod.rs b/src/api2/backup/mod.rs index 19ca1226..76e0e28a 100644 --- a/src/api2/backup/mod.rs +++ b/src/api2/backup/mod.rs @@ -12,6 +12,11 @@ use proxmox::api::{ApiResponseFuture, ApiHandler, ApiMethod, Router, RpcEnvironm use proxmox::api::router::SubdirMap; 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::json::{required_array_param, required_integer_param, required_string_param}; 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::backup::DataStore; -use crate::api2::types::*; -use crate::config::acl::PRIV_DATASTORE_BACKUP; use crate::config::cached_user_info::CachedUserInfo; mod environment; diff --git a/src/api2/config/access/openid.rs b/src/api2/config/access/openid.rs index 0dcebd1a..3dfa8de4 100644 --- a/src/api2/config/access/openid.rs +++ b/src/api2/config/access/openid.rs @@ -6,9 +6,10 @@ use ::serde::{Deserialize, Serialize}; 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 crate::config::acl::{PRIV_SYS_AUDIT, PRIV_REALM_ALLOCATE}; -use crate::api2::types::*; #[api( input: { diff --git a/src/api2/config/acme.rs b/src/api2/config/acme.rs index 5d8c4481..6aad953e 100644 --- a/src/api2/config/acme.rs +++ b/src/api2/config/acme.rs @@ -16,9 +16,10 @@ use proxmox::list_subdirs_api_method; use proxmox_acme_rs::account::AccountData as AcmeAccountData; use proxmox_acme_rs::Account; +use pbs_api_types::{Authid, PRIV_SYS_MODIFY}; + use crate::acme::AcmeClient; -use crate::api2::types::{AcmeAccountName, AcmeChallengeSchema, Authid, KnownAcmeDirectory}; -use crate::config::acl::PRIV_SYS_MODIFY; +use crate::api2::types::{AcmeAccountName, AcmeChallengeSchema, KnownAcmeDirectory}; use crate::config::acme::plugin::{ self, DnsPlugin, DnsPluginCore, DnsPluginCoreUpdater, PLUGIN_ID_SCHEMA, }; diff --git a/src/api2/config/changer.rs b/src/api2/config/changer.rs index 486313f2..720fc6bd 100644 --- a/src/api2/config/changer.rs +++ b/src/api2/config/changer.rs @@ -11,23 +11,13 @@ use proxmox::api::{ }; use pbs_api_types::{ - Authid, - PROXMOX_CONFIG_DIGEST_SCHEMA, - CHANGER_NAME_SCHEMA, - SLOT_ARRAY_SCHEMA, - ScsiTapeChanger, - ScsiTapeChangerUpdater, - LtoTapeDrive, + Authid, ScsiTapeChanger, ScsiTapeChangerUpdater, LtoTapeDrive, + PROXMOX_CONFIG_DIGEST_SCHEMA, CHANGER_NAME_SCHEMA, SLOT_ARRAY_SCHEMA, + PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY, }; use crate::{ - config::{ - cached_user_info::CachedUserInfo, - acl::{ - PRIV_TAPE_AUDIT, - PRIV_TAPE_MODIFY, - }, - }, + config::cached_user_info::CachedUserInfo, tape::{ linux_tape_changer_list, check_drive_path, diff --git a/src/api2/config/datastore.rs b/src/api2/config/datastore.rs index 0dbb7fec..9b127115 100644 --- a/src/api2/config/datastore.rs +++ b/src/api2/config/datastore.rs @@ -11,6 +11,11 @@ use proxmox::api::schema::{ApiType, parse_property_string}; use pbs_datastore::chunk_store::ChunkStore; use pbs_datastore::task::TaskState; 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::verify::delete_verification_job; @@ -19,10 +24,8 @@ use crate::api2::admin::{ sync::list_sync_jobs, verify::list_verification_jobs, }; -use crate::api2::types::*; use crate::config::cached_user_info::CachedUserInfo; 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}; #[api( diff --git a/src/api2/config/drive.rs b/src/api2/config/drive.rs index b92d8103..74ce3cbb 100644 --- a/src/api2/config/drive.rs +++ b/src/api2/config/drive.rs @@ -5,22 +5,12 @@ use serde_json::Value; use proxmox::api::{api, Router, RpcEnvironment, Permission}; use pbs_api_types::{ - Authid, - PROXMOX_CONFIG_DIGEST_SCHEMA, - DRIVE_NAME_SCHEMA, - LtoTapeDrive, - LtoTapeDriveUpdater, - ScsiTapeChanger, + Authid, LtoTapeDrive, LtoTapeDriveUpdater, ScsiTapeChanger, + PROXMOX_CONFIG_DIGEST_SCHEMA, DRIVE_NAME_SCHEMA, PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY, }; use crate::{ - config::{ - cached_user_info::CachedUserInfo, - acl::{ - PRIV_TAPE_AUDIT, - PRIV_TAPE_MODIFY, - }, - }, + config::cached_user_info::CachedUserInfo, tape::{ lto_tape_device_list, check_drive_path, diff --git a/src/api2/config/media_pool.rs b/src/api2/config/media_pool.rs index 3e583a29..56f86498 100644 --- a/src/api2/config/media_pool.rs +++ b/src/api2/config/media_pool.rs @@ -11,21 +11,11 @@ use proxmox::{ }; use pbs_api_types::{ - Authid, - MEDIA_POOL_NAME_SCHEMA, - MediaPoolConfig, - MediaPoolConfigUpdater, + Authid, MediaPoolConfig, MediaPoolConfigUpdater, MEDIA_POOL_NAME_SCHEMA, + PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY, }; -use crate::{ - config::{ - cached_user_info::CachedUserInfo, - acl::{ - PRIV_TAPE_AUDIT, - PRIV_TAPE_MODIFY, - }, - }, -}; +use crate::config::cached_user_info::CachedUserInfo; #[api( protected: true, diff --git a/src/api2/config/remote.rs b/src/api2/config/remote.rs index df91c4c8..4daca23c 100644 --- a/src/api2/config/remote.rs +++ b/src/api2/config/remote.rs @@ -9,11 +9,11 @@ use pbs_client::{HttpClient, HttpClientOptions}; use pbs_api_types::{ REMOTE_ID_SCHEMA, REMOTE_PASSWORD_SCHEMA, Remote, RemoteConfig, RemoteConfigUpdater, Authid, PROXMOX_CONFIG_DIGEST_SCHEMA, DataStoreListItem, SyncJobConfig, + PRIV_REMOTE_AUDIT, PRIV_REMOTE_MODIFY, }; use pbs_config::sync; use crate::config::cached_user_info::CachedUserInfo; -use crate::config::acl::{PRIV_REMOTE_AUDIT, PRIV_REMOTE_MODIFY}; #[api( input: { diff --git a/src/api2/config/sync.rs b/src/api2/config/sync.rs index 6d92dfc0..bb2152fa 100644 --- a/src/api2/config/sync.rs +++ b/src/api2/config/sync.rs @@ -6,18 +6,11 @@ use proxmox::api::{api, Permission, Router, RpcEnvironment}; use pbs_api_types::{ 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 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; pub fn check_sync_job_read_access( @@ -371,7 +364,7 @@ user: read@pbs user: write@pbs "###).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:write@pbs:DatastoreBackup acl:1:/datastore/localstore2:write@pbs:DatastorePowerUser diff --git a/src/api2/config/tape_backup_job.rs b/src/api2/config/tape_backup_job.rs index 2eabed79..b0c41bf6 100644 --- a/src/api2/config/tape_backup_job.rs +++ b/src/api2/config/tape_backup_job.rs @@ -7,17 +7,10 @@ use proxmox::api::{api, Router, RpcEnvironment, Permission}; use pbs_api_types::{ Authid, TapeBackupJobConfig, TapeBackupJobConfigUpdater, JOB_ID_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA, + PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY, }; -use crate::{ - config::{ - cached_user_info::CachedUserInfo, - acl::{ - PRIV_TAPE_AUDIT, - PRIV_TAPE_MODIFY, - }, - }, -}; +use crate::config::cached_user_info::CachedUserInfo; #[api( input: { diff --git a/src/api2/config/tape_encryption_keys.rs b/src/api2/config/tape_encryption_keys.rs index d20302a5..ba66b6f6 100644 --- a/src/api2/config/tape_encryption_keys.rs +++ b/src/api2/config/tape_encryption_keys.rs @@ -15,6 +15,7 @@ use pbs_api_types::{ Fingerprint, KeyInfo, Kdf, TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA, PASSWORD_HINT_SCHEMA, + PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY, }; use pbs_config::key_config::KeyConfig; @@ -28,15 +29,6 @@ use pbs_config::tape_encryption_keys::{ insert_key, }; -use crate::{ - config::{ - acl::{ - PRIV_TAPE_AUDIT, - PRIV_TAPE_MODIFY, - }, - }, -}; - #[api( input: { properties: {}, diff --git a/src/api2/config/verify.rs b/src/api2/config/verify.rs index d631c73a..7c8946d4 100644 --- a/src/api2/config/verify.rs +++ b/src/api2/config/verify.rs @@ -6,15 +6,10 @@ use proxmox::api::{api, Permission, Router, RpcEnvironment}; use pbs_api_types::{ 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 crate::config::acl::{ - PRIV_DATASTORE_AUDIT, - PRIV_DATASTORE_VERIFY, -}; - use crate::config::cached_user_info::CachedUserInfo; #[api( diff --git a/src/api2/node/apt.rs b/src/api2/node/apt.rs index c01da81f..8f4bc691 100644 --- a/src/api2/node/apt.rs +++ b/src/api2/node/apt.rs @@ -13,6 +13,11 @@ use proxmox_apt::repositories::{ }; 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::server::WorkerTask; use crate::tools::{ @@ -20,8 +25,6 @@ use crate::tools::{ pbs_simple_http, 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( input: { diff --git a/src/api2/node/certificates.rs b/src/api2/node/certificates.rs index b249b22d..82fa028d 100644 --- a/src/api2/node/certificates.rs +++ b/src/api2/node/certificates.rs @@ -11,14 +11,12 @@ use proxmox::api::router::SubdirMap; use proxmox::api::{api, Permission, Router, RpcEnvironment}; use proxmox::list_subdirs_api_method; +use pbs_api_types::{Authid, NODE_SCHEMA, PRIV_SYS_MODIFY}; use pbs_buildcfg::configdir; use pbs_tools::cert; use crate::acme::AcmeClient; -use crate::api2::types::Authid; -use crate::api2::types::NODE_SCHEMA; use crate::api2::types::AcmeDomain; -use crate::config::acl::PRIV_SYS_MODIFY; use crate::config::node::NodeConfig; use crate::server::WorkerTask; diff --git a/src/api2/node/config.rs b/src/api2/node/config.rs index f6133d99..88ec3955 100644 --- a/src/api2/node/config.rs +++ b/src/api2/node/config.rs @@ -3,9 +3,9 @@ use ::serde::{Deserialize, Serialize}; 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::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY}; use crate::config::node::{NodeConfig, NodeConfigUpdater}; pub const ROUTER: Router = Router::new() diff --git a/src/api2/node/disks/directory.rs b/src/api2/node/disks/directory.rs index d415023b..0cb6f4e2 100644 --- a/src/api2/node/disks/directory.rs +++ b/src/api2/node/disks/directory.rs @@ -6,7 +6,11 @@ use proxmox::api::{api, Permission, RpcEnvironment, RpcEnvironmentType}; use proxmox::api::section_config::SectionConfigData; 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::{ DiskManage, FileSystemType, DiskUsageType, 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::api2::types::*; use crate::config::datastore::{self, DataStoreConfig}; use pbs_config::open_backup_lockfile; diff --git a/src/api2/node/disks/mod.rs b/src/api2/node/disks/mod.rs index e0c3d39c..67f8f63a 100644 --- a/src/api2/node/disks/mod.rs +++ b/src/api2/node/disks/mod.rs @@ -6,15 +6,17 @@ use proxmox::api::router::{Router, SubdirMap}; use proxmox::{sortable, identity}; 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::{ DiskUsageInfo, DiskUsageType, DiskManage, SmartData, get_disks, get_smart_data, get_disk_usage_info, inititialize_gpt_disk, }; use crate::server::WorkerTask; -use crate::api2::types::{Authid, UPID_SCHEMA, NODE_SCHEMA, BLOCKDEVICE_NAME_SCHEMA}; - pub mod directory; pub mod zfs; diff --git a/src/api2/node/disks/zfs.rs b/src/api2/node/disks/zfs.rs index 1e539ca1..bff01c81 100644 --- a/src/api2/node/disks/zfs.rs +++ b/src/api2/node/disks/zfs.rs @@ -1,21 +1,19 @@ use anyhow::{bail, Error}; use serde_json::{json, Value}; -use serde::{Deserialize, Serialize}; use proxmox::api::{ api, Permission, RpcEnvironment, RpcEnvironmentType, - schema::{ - Schema, - StringSchema, - ArraySchema, - IntegerSchema, - ApiStringFormat, - parse_property_string, - }, + schema::parse_property_string, }; 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::{ zpool_list, zpool_status, parse_zpool_status_config_tree, vdev_list_to_tree, DiskUsageType, @@ -24,92 +22,6 @@ use crate::config::datastore::{self, DataStoreConfig}; 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( protected: true, diff --git a/src/api2/node/dns.rs b/src/api2/node/dns.rs index e3dd614d..ff5b5f14 100644 --- a/src/api2/node/dns.rs +++ b/src/api2/node/dns.rs @@ -11,8 +11,11 @@ use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission}; use proxmox::tools::fs::{file_get_contents, replace_file, CreateOptions}; use proxmox::{IPRE, IPV4RE, IPV6RE, IPV4OCTET, IPV6H16, IPV6LS32}; -use crate::api2::types::*; -use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY}; +use pbs_api_types::{ + 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"; diff --git a/src/api2/node/journal.rs b/src/api2/node/journal.rs index c5a41bda..aa708a82 100644 --- a/src/api2/node/journal.rs +++ b/src/api2/node/journal.rs @@ -6,8 +6,7 @@ use std::io::{BufRead,BufReader}; use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission}; -use crate::api2::types::*; -use crate::config::acl::PRIV_SYS_AUDIT; +use pbs_api_types::{NODE_SCHEMA, PRIV_SYS_AUDIT}; #[api( protected: true, diff --git a/src/api2/node/mod.rs b/src/api2/node/mod.rs index 88485991..f1a17934 100644 --- a/src/api2/node/mod.rs +++ b/src/api2/node/mod.rs @@ -20,11 +20,10 @@ use proxmox::list_subdirs_api_method; use proxmox_http::websocket::WebSocket; use proxmox::{identity, sortable}; +use pbs_api_types::{Authid, NODE_SCHEMA, PRIV_SYS_CONSOLE}; use pbs_tools::auth::private_auth_key; use pbs_tools::ticket::{self, Empty, Ticket}; -use crate::api2::types::*; -use crate::config::acl::PRIV_SYS_CONSOLE; use crate::server::WorkerTask; use crate::tools; diff --git a/src/api2/node/network.rs b/src/api2/node/network.rs index 33f8d40c..351fd11c 100644 --- a/src/api2/node/network.rs +++ b/src/api2/node/network.rs @@ -9,12 +9,11 @@ use pbs_api_types::{ Authid, Interface, NetworkInterfaceType, LinuxBondMode, NetworkConfigMethod, BondXmitHashPolicy, 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, + NODE_SCHEMA, PRIV_SYS_AUDIT, PRIV_SYS_MODIFY, }; use pbs_config::network::{self, NetworkConfig}; -use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY}; use crate::server::{WorkerTask}; -use crate::api2::types::NODE_SCHEMA; fn split_interface_list(list: &str) -> Result, Error> { let value = parse_property_string(&list, &NETWORK_INTERFACE_ARRAY_SCHEMA)?; diff --git a/src/api2/node/report.rs b/src/api2/node/report.rs index b58427d7..54d87dc4 100644 --- a/src/api2/node/report.rs +++ b/src/api2/node/report.rs @@ -2,8 +2,8 @@ use anyhow::Error; use proxmox::api::{api, ApiMethod, Permission, Router, RpcEnvironment}; use serde_json::{json, Value}; -use crate::api2::types::*; -use crate::config::acl::PRIV_SYS_AUDIT; +use pbs_api_types::{NODE_SCHEMA, PRIV_SYS_AUDIT}; + use crate::server::generate_report; #[api( diff --git a/src/api2/node/rrd.rs b/src/api2/node/rrd.rs index 692a84a1..f689232d 100644 --- a/src/api2/node/rrd.rs +++ b/src/api2/node/rrd.rs @@ -3,8 +3,8 @@ use serde_json::{Value, json}; use proxmox::api::{api, Permission, Router}; -use crate::api2::types::*; -use crate::config::acl::PRIV_SYS_AUDIT; +use pbs_api_types::{RRDMode, RRDTimeFrameResolution, NODE_SCHEMA, PRIV_SYS_AUDIT}; + use crate::rrd::{extract_cached_data, RRD_DATA_ENTRIES}; pub fn create_value_from_rrd( diff --git a/src/api2/node/services.rs b/src/api2/node/services.rs index 40520208..25edd1b6 100644 --- a/src/api2/node/services.rs +++ b/src/api2/node/services.rs @@ -6,10 +6,9 @@ use serde_json::{json, Value}; use proxmox::{sortable, identity, list_subdirs_api_method}; use proxmox::api::{api, Router, Permission, RpcEnvironment}; use proxmox::api::router::SubdirMap; -use proxmox::api::schema::*; -use crate::api2::types::*; -use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY}; +use pbs_api_types::{Authid, NODE_SCHEMA, SERVICE_ID_SCHEMA, PRIV_SYS_AUDIT, PRIV_SYS_MODIFY}; + use crate::server::WorkerTask; static SERVICE_NAME_LIST: [&str; 7] = [ @@ -346,11 +345,6 @@ fn reload_service( run_service_command(&service, "reload", auth_id) } - -const SERVICE_ID_SCHEMA: Schema = StringSchema::new("Service ID.") - .max_length(256) - .schema(); - #[sortable] const SERVICE_SUBDIRS: SubdirMap = &sorted!([ ( diff --git a/src/api2/node/status.rs b/src/api2/node/status.rs index 12f6dc71..07d641aa 100644 --- a/src/api2/node/status.rs +++ b/src/api2/node/status.rs @@ -9,9 +9,11 @@ use proxmox::sys::linux::procfs; use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission}; 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::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_POWER_MANAGEMENT}; +use crate::api2::types::{ + NodeCpuInformation, NodeStatus, NodeMemoryCounters, NodeSwapCounters, NodeInformation, +}; impl std::convert::From for NodeCpuInformation { fn from(info: procfs::ProcFsCPUInfo) -> Self { diff --git a/src/api2/node/subscription.rs b/src/api2/node/subscription.rs index 0fa4f963..58e80e53 100644 --- a/src/api2/node/subscription.rs +++ b/src/api2/node/subscription.rs @@ -3,11 +3,14 @@ use serde_json::Value; 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::subscription::{self, SubscriptionStatus, SubscriptionInfo}; -use crate::config::acl::{PRIV_SYS_AUDIT,PRIV_SYS_MODIFY}; use crate::config::cached_user_info::CachedUserInfo; -use crate::api2::types::{NODE_SCHEMA, SUBSCRIPTION_KEY_SCHEMA, Authid}; #[api( input: { diff --git a/src/api2/node/syslog.rs b/src/api2/node/syslog.rs index 56662805..4c956f09 100644 --- a/src/api2/node/syslog.rs +++ b/src/api2/node/syslog.rs @@ -5,8 +5,7 @@ use serde_json::{json, Value}; use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission}; -use crate::api2::types::*; -use crate::config::acl::PRIV_SYS_AUDIT; +use pbs_api_types::{NODE_SCHEMA, SYSTEMD_DATETIME_FORMAT, PRIV_SYS_AUDIT}; fn dump_journal( start: Option, diff --git a/src/api2/node/tasks.rs b/src/api2/node/tasks.rs index 89665c68..29a0ee14 100644 --- a/src/api2/node/tasks.rs +++ b/src/api2/node/tasks.rs @@ -8,16 +8,16 @@ use proxmox::api::{api, Router, RpcEnvironment, Permission}; use proxmox::api::router::SubdirMap; use proxmox::{identity, list_subdirs_api_method, sortable}; -use crate::api2::types::*; -use crate::api2::pull::check_pull_privs; +use pbs_api_types::{ + Userid, Authid, Tokenname, TaskListItem, + NODE_SCHEMA, UPID_SCHEMA, VERIFICATION_JOB_WORKER_ID_REGEX, + SYNC_JOB_WORKER_ID_REGEX, DATASTORE_SCHEMA, + 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::acl::{ - PRIV_DATASTORE_MODIFY, - PRIV_DATASTORE_VERIFY, - PRIV_SYS_AUDIT, - PRIV_SYS_MODIFY, -}; use crate::config::cached_user_info::CachedUserInfo; // matches respective job execution privileges diff --git a/src/api2/node/time.rs b/src/api2/node/time.rs index 3c8e6abd..bf82c25a 100644 --- a/src/api2/node/time.rs +++ b/src/api2/node/time.rs @@ -4,8 +4,7 @@ use serde_json::{json, Value}; use proxmox::api::{api, Router, Permission}; use proxmox::tools::fs::{file_read_firstline, replace_file, CreateOptions}; -use crate::config::acl::PRIV_SYS_MODIFY; -use crate::api2::types::*; +use pbs_api_types::{NODE_SCHEMA, TIME_ZONE_SCHEMA, PRIV_SYS_MODIFY}; fn read_etc_localtime() -> Result { // use /etc/timezone diff --git a/src/api2/pull.rs b/src/api2/pull.rs index 95030e3b..a24f7983 100644 --- a/src/api2/pull.rs +++ b/src/api2/pull.rs @@ -9,18 +9,14 @@ use proxmox::api::{ApiMethod, Router, RpcEnvironment, Permission}; use pbs_client::{HttpClient, BackupRepository}; 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::backup::DataStore; - -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, -}; +use crate::config::cached_user_info::CachedUserInfo; pub fn check_pull_privs( auth_id: &Authid, diff --git a/src/api2/reader/mod.rs b/src/api2/reader/mod.rs index 461d06d9..692eee8f 100644 --- a/src/api2/reader/mod.rs +++ b/src/api2/reader/mod.rs @@ -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::json::{required_integer_param, required_string_param}; 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 crate::{ - api2::{ - helpers, - types::{ - DATASTORE_SCHEMA, - BACKUP_TYPE_SCHEMA, - BACKUP_TIME_SCHEMA, - BACKUP_ID_SCHEMA, - CHUNK_DIGEST_SCHEMA, - Authid, - }, - }, + api2::helpers, backup::DataStore, server::{ WorkerTask, H2Service, }, - config::{ - acl::{ - PRIV_DATASTORE_READ, - PRIV_DATASTORE_BACKUP, - }, - cached_user_info::CachedUserInfo, - }, + config::cached_user_info::CachedUserInfo, }; mod environment; diff --git a/src/api2/status.rs b/src/api2/status.rs index 3aff91e7..7250c616 100644 --- a/src/api2/status.rs +++ b/src/api2/status.rs @@ -14,21 +14,15 @@ use proxmox::api::{ SubdirMap, }; -use crate::api2::types::{ - DATASTORE_SCHEMA, - RRDMode, - RRDTimeFrameResolution, - Authid, +use pbs_api_types::{ + DATASTORE_SCHEMA, RRDMode, RRDTimeFrameResolution, Authid, + PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP, }; use crate::backup::DataStore; use crate::config::datastore; use crate::tools::statistics::{linear_regression}; use crate::config::cached_user_info::CachedUserInfo; -use crate::config::acl::{ - PRIV_DATASTORE_AUDIT, - PRIV_DATASTORE_BACKUP, -}; #[api( returns: { diff --git a/src/api2/tape/backup.rs b/src/api2/tape/backup.rs index 29329280..2369d69c 100644 --- a/src/api2/tape/backup.rs +++ b/src/api2/tape/backup.rs @@ -17,7 +17,7 @@ use proxmox::{ use pbs_api_types::{ 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}; @@ -25,14 +25,7 @@ use pbs_datastore::backup_info::{BackupDir, BackupInfo}; use pbs_datastore::task::TaskState; use crate::{ - config::{ - cached_user_info::CachedUserInfo, - acl::{ - PRIV_DATASTORE_READ, - PRIV_TAPE_AUDIT, - PRIV_TAPE_WRITE, - }, - }, + config::cached_user_info::CachedUserInfo, server::{ lookup_user_email, TapeBackupJobSummary, diff --git a/src/api2/tape/changer.rs b/src/api2/tape/changer.rs index f73945ca..ee2c70d7 100644 --- a/src/api2/tape/changer.rs +++ b/src/api2/tape/changer.rs @@ -7,23 +7,13 @@ use serde_json::Value; use proxmox::api::{api, Router, SubdirMap, RpcEnvironment, Permission}; 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::{ - config::{ - cached_user_info::CachedUserInfo, - acl::{ - PRIV_TAPE_AUDIT, - PRIV_TAPE_READ, - }, - }, - api2::types::{ - Authid, - CHANGER_NAME_SCHEMA, - ChangerListEntry, - LtoTapeDrive, - MtxEntryKind, - MtxStatusEntry, - ScsiTapeChanger, - }, + config::cached_user_info::CachedUserInfo, tape::{ TAPE_STATUS_DIR, Inventory, diff --git a/src/api2/tape/drive.rs b/src/api2/tape/drive.rs index 5878ca44..263210ee 100644 --- a/src/api2/tape/drive.rs +++ b/src/api2/tape/drive.rs @@ -22,37 +22,20 @@ use proxmox::{ }, }; +use pbs_api_types::{ + UPID_SCHEMA, CHANGER_NAME_SCHEMA, DRIVE_NAME_SCHEMA, MEDIA_LABEL_SCHEMA, MEDIA_POOL_NAME_SCHEMA, + Authid, DriveListEntry, LtoTapeDrive, MediaIdFlat, LabelUuidMap, MamAttribute, + LtoDriveAndMediaStatus, Lp17VolumeStatistics, +}; + use pbs_datastore::task_log; +use pbs_api_types::{PRIV_TAPE_AUDIT, PRIV_TAPE_READ, PRIV_TAPE_WRITE}; use crate::{ - config::{ - cached_user_info::CachedUserInfo, - 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, - restore_media, - }, + config::cached_user_info::CachedUserInfo, + api2::tape::restore::{ + fast_catalog_restore, + restore_media, }, server::WorkerTask, tape::{ diff --git a/src/api2/tape/media.rs b/src/api2/tape/media.rs index 15514d52..d669d720 100644 --- a/src/api2/tape/media.rs +++ b/src/api2/tape/media.rs @@ -14,15 +14,11 @@ use pbs_api_types::{ MEDIA_POOL_NAME_SCHEMA, MEDIA_LABEL_SCHEMA, MEDIA_UUID_SCHEMA, CHANGER_NAME_SCHEMA, VAULT_NAME_SCHEMA, Authid, MediaPoolConfig, MediaListEntry, MediaSetListEntry, MediaStatus, MediaContentEntry, MediaContentListFilter, + PRIV_TAPE_AUDIT, }; use crate::{ - config::{ - cached_user_info::CachedUserInfo, - acl::{ - PRIV_TAPE_AUDIT, - }, - }, + config::cached_user_info::CachedUserInfo, tape::{ TAPE_STATUS_DIR, Inventory, diff --git a/src/api2/tape/restore.rs b/src/api2/tape/restore.rs index 8aa00c0e..1147c3d4 100644 --- a/src/api2/tape/restore.rs +++ b/src/api2/tape/restore.rs @@ -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::backup_info::BackupDir; use pbs_datastore::dynamic_index::DynamicIndexReader; @@ -39,23 +44,7 @@ use pbs_datastore::task::TaskState; use crate::{ tools::ParallelHandler, - api2::types::{ - 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, - }, - }, + config::cached_user_info::CachedUserInfo, backup::DataStore, server::{ lookup_user_email, diff --git a/src/api2/types/mod.rs b/src/api2/types/mod.rs index bd40cd7e..21f1816f 100644 --- a/src/api2/types/mod.rs +++ b/src/api2/types/mod.rs @@ -4,9 +4,6 @@ use anyhow::bail; use serde::{Deserialize, Serialize}; use proxmox::api::{api, schema::*}; -use proxmox::const_regex; - -use crate::config::acl::Role; mod acme; pub use acme::*; @@ -24,177 +21,6 @@ pub const FILENAME_FORMAT: ApiStringFormat = ApiStringFormat::VerifyFn(|name| { 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("(=)?") - .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/).") - .format(&BLOCKDEVICE_NAME_FORMAT) - .min_length(3) - .max_length(64) - .schema(); // Complex type definitions @@ -242,17 +68,6 @@ pub enum TaskStateType { 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 #[test] @@ -340,34 +155,6 @@ fn test_proxmox_user_id_schema() -> Result<(), anyhow::Error> { 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] #[derive(Serialize, Deserialize, Default)] #[serde(rename_all = "kebab-case")] diff --git a/src/bin/docgen.rs b/src/bin/docgen.rs index 6eb92a42..b54e4185 100644 --- a/src/bin/docgen.rs +++ b/src/bin/docgen.rs @@ -25,13 +25,9 @@ use proxmox::{ }, }; -use proxmox_backup::{ - api2, - config::{ - self, - acl::PRIVILEGES, - }, -}; +use pbs_api_types::PRIVILEGES; + +use proxmox_backup::{api2, config}; fn get_args() -> (String, Vec) { @@ -62,7 +58,7 @@ fn main() -> Result<(), Error> { "sync.cfg" => dump_section_config(&pbs_config::sync::CONFIG), "verification.cfg" => dump_section_config(&pbs_config::verify::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"), }; println!("{}", text); diff --git a/src/bin/proxmox_backup_manager/disk.rs b/src/bin/proxmox_backup_manager/disk.rs index 164f8831..668c6f16 100644 --- a/src/bin/proxmox_backup_manager/disk.rs +++ b/src/bin/proxmox_backup_manager/disk.rs @@ -3,20 +3,17 @@ use serde_json::Value; 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::{ FileSystemType, SmartAttribute, complete_disk_name, }; -use proxmox_backup::api2::node::disks::{ - zfs::DISK_LIST_SCHEMA, - zfs::ZFS_ASHIFT_SCHEMA, - zfs::ZfsRaidLevel, - zfs::ZfsCompressionType, -}; - -use proxmox_backup::api2::{self, types::* }; +use proxmox_backup::api2; #[api( input: { diff --git a/src/config/cached_user_info.rs b/src/config/cached_user_info.rs index a4c4604f..1ec480a0 100644 --- a/src/config/cached_user_info.rs +++ b/src/config/cached_user_info.rs @@ -9,9 +9,10 @@ use lazy_static::lazy_static; use proxmox::api::UserInformation; 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 crate::api2::types::{Authid, Userid}; use crate::tools::Memcom; /// Cache User/Group/Token/Acl configuration data for fast permission tests @@ -54,7 +55,7 @@ impl CachedUserInfo { let config = Arc::new(CachedUserInfo { 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(); diff --git a/src/config/mod.rs b/src/config/mod.rs index 7b3d3add..cfb114cc 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -14,7 +14,6 @@ use proxmox::try_block; use pbs_buildcfg::{self, configdir}; -pub mod acl; pub mod acme; pub mod cached_user_info; pub mod datastore; diff --git a/src/server/prune_job.rs b/src/server/prune_job.rs index 2ea8b713..1c0d4cc0 100644 --- a/src/server/prune_job.rs +++ b/src/server/prune_job.rs @@ -5,10 +5,9 @@ use anyhow::Error; use pbs_datastore::{task_log, task_warn}; use pbs_datastore::backup_info::BackupInfo; use pbs_datastore::prune::{compute_prune_info, PruneOptions}; +use pbs_api_types::{Authid, PRIV_DATASTORE_MODIFY}; use crate::{ - api2::types::*, - config::acl::PRIV_DATASTORE_MODIFY, config::cached_user_info::CachedUserInfo, backup::DataStore, server::jobstate::Job, diff --git a/tests/verify-api.rs b/tests/verify-api.rs index e4b8ebec..2d282e03 100644 --- a/tests/verify-api.rs +++ b/tests/verify-api.rs @@ -88,7 +88,7 @@ fn verify_access_permissions(permission: &Permission) -> Result<(), Error> { } Permission::Privilege(path_comp, ..)=> { let path = format!("/{}", path_comp.join("/")); - proxmox_backup::config::acl::check_acl_path(&path)?; + pbs_config::acl::check_acl_path(&path)?; } _ => {} } -- 2.39.2