use proxmox 0.1.25, use new EnumEntry feature

This commit is contained in:
Dietmar Maurer 2020-04-29 13:01:24 +02:00
parent acb428cdec
commit bc0d03885c
8 changed files with 79 additions and 114 deletions

View File

@ -34,7 +34,7 @@ pam = "0.7"
pam-sys = "0.5"
percent-encoding = "2.1"
pin-utils = "0.1.0-alpha"
proxmox = { version = "0.1.24", features = [ "sortable-macro", "api-macro" ] }
proxmox = { version = "0.1.25", features = [ "sortable-macro", "api-macro" ] }
#proxmox = { git = "ssh://gitolite3@proxdev.maurer-it.com/rust/proxmox", version = "0.1.2", features = [ "sortable-macro", "api-macro" ] }
#proxmox = { path = "../proxmox/proxmox", features = [ "sortable-macro", "api-macro" ] }
regex = "1.2"

View File

@ -5,7 +5,7 @@ use proxmox::api::{api, Router, RpcEnvironment, Permission};
use crate::api2::types::*;
use crate::config::acl;
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
use crate::config::acl::{Role, PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
#[api(
properties: {
@ -23,7 +23,7 @@ use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
description: "User or Group ID.",
},
roleid: {
schema: ACL_ROLE_SCHEMA,
type: Role,
}
}
)]
@ -118,7 +118,7 @@ pub fn read_acl(
schema: ACL_PATH_SCHEMA,
},
role: {
schema: ACL_ROLE_SCHEMA,
type: Role,
},
propagate: {
optional: true,

View File

@ -6,7 +6,7 @@ use proxmox::api::{api, Permission};
use proxmox::api::router::Router;
use crate::api2::types::*;
use crate::config::acl::ROLE_NAMES;
use crate::config::acl::{Role, ROLE_NAMES};
#[api(
returns: {
@ -17,7 +17,7 @@ use crate::config::acl::ROLE_NAMES;
description: "User name with description.",
properties: {
role: {
schema: ACL_ROLE_SCHEMA,
type: Role,
},
comment: {
schema: SINGLE_LINE_COMMENT_SCHEMA,

View File

@ -31,15 +31,9 @@ pub const API_METHOD_UPGRADE_BACKUP: ApiMethod = ApiMethod::new(
concat!("Upgraded to backup protocol ('", PROXMOX_BACKUP_READER_PROTOCOL_ID_V1!(), "')."),
&sorted!([
("store", false, &DATASTORE_SCHEMA),
("backup-type", false, &StringSchema::new("Backup type.")
.format(&ApiStringFormat::Enum(&["vm", "ct", "host"]))
.schema()
),
("backup-id", false, &StringSchema::new("Backup ID.").schema()),
("backup-time", false, &IntegerSchema::new("Backup time (Unix epoch.)")
.minimum(1_547_797_308)
.schema()
),
("backup-type", false, &BACKUP_TYPE_SCHEMA),
("backup-id", false, &BACKUP_ID_SCHEMA),
("backup-time", false, &BACKUP_TIME_SCHEMA),
("debug", true, &BooleanSchema::new("Enable verbose debug logging.").schema()),
]),
)

View File

@ -248,24 +248,9 @@ pub const ACL_PROPAGATE_SCHEMA: Schema = BooleanSchema::new(
pub const ACL_UGID_TYPE_SCHEMA: Schema = StringSchema::new(
"Type of 'ugid' property.")
.format(&ApiStringFormat::Enum(&["user", "group"]))
.schema();
pub const ACL_ROLE_SCHEMA: Schema = StringSchema::new(
"Role.")
.format(&ApiStringFormat::Enum(&[
"Admin",
"Audit",
"Datastore.Admin",
"Datastore.Reader",
"Datastore.Audit",
"Datastore.Backup",
"Datastore.PowerUser",
"Remote.Admin",
"Remote.Audit",
"Remote.SyncOperator",
"NoAccess",
]))
EnumEntry::new("user", "User"),
EnumEntry::new("group", "Group")]))
.schema();
pub const BACKUP_ARCHIVE_NAME_SCHEMA: Schema =
@ -275,7 +260,10 @@ pub const BACKUP_ARCHIVE_NAME_SCHEMA: Schema =
pub const BACKUP_TYPE_SCHEMA: Schema =
StringSchema::new("Backup type.")
.format(&ApiStringFormat::Enum(&["vm", "ct", "host"]))
.format(&ApiStringFormat::Enum(&[
EnumEntry::new("vm", "Virtual Machine Backup"),
EnumEntry::new("ct", "Container Backup"),
EnumEntry::new("host", "Host Backup")]))
.schema();
pub const BACKUP_ID_SCHEMA: Schema =

View File

@ -1852,7 +1852,9 @@ fn key_mgmt_cli() -> CliCommandMap {
const KDF_SCHEMA: Schema =
StringSchema::new("Key derivation function. Choose 'none' to store the key unecrypted.")
.format(&ApiStringFormat::Enum(&["scrypt", "none"]))
.format(&ApiStringFormat::Enum(&[
EnumEntry::new("scrypt", "SCrypt"),
EnumEntry::new("none", "Do not encrypt the key")]))
.default("scrypt")
.schema();

View File

@ -2,12 +2,17 @@ use std::io::Write;
use std::collections::{HashMap, HashSet, BTreeMap, BTreeSet};
use std::path::{PathBuf, Path};
use std::sync::{Arc, RwLock};
use std::str::FromStr;
use anyhow::{bail, Error};
use lazy_static::lazy_static;
use ::serde::{Deserialize, Serialize};
use serde::de::{value, IntoDeserializer};
use proxmox::tools::{fs::replace_file, fs::CreateOptions};
use proxmox::api::{api, schema::*};
// define Privilege bitfield
@ -83,56 +88,56 @@ PRIV_REMOTE_PRUNE;
pub const ROLE_NAME_NO_ACCESS: &str ="NoAccess";
#[api()]
#[repr(u64)]
#[derive(Serialize, Deserialize)]
/// Role
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,
}
impl FromStr for Role {
type Err = value::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::deserialize(s.into_deserializer())
}
}
lazy_static! {
pub static ref ROLE_NAMES: HashMap<&'static str, (u64, &'static str)> = {
let mut map = HashMap::new();
map.insert("Admin", (
ROLE_ADMIN,
"Administrator",
));
map.insert("Audit", (
ROLE_AUDIT,
"Auditor",
));
map.insert(ROLE_NAME_NO_ACCESS, (
ROLE_NO_ACCESS,
"Disable access",
));
let list = match Role::API_SCHEMA {
Schema::String(StringSchema { format: Some(ApiStringFormat::Enum(list)), .. }) => list,
_ => unreachable!(),
};
map.insert("Datastore.Admin", (
ROLE_DATASTORE_ADMIN,
"Datastore Administrator",
));
map.insert("Datastore.Reader", (
ROLE_DATASTORE_READER,
"Datastore Reader (inspect datastore content and do restores)",
));
map.insert("Datastore.Backup", (
ROLE_DATASTORE_BACKUP,
"Datastore Backup (backup and restore owned backups)",
));
map.insert("Datastore.PowerUser", (
ROLE_DATASTORE_POWERUSER,
"Datastore PowerUser (backup, restore and prune owned backup)",
));
map.insert("Datastore.Audit", (
ROLE_DATASTORE_AUDIT,
"Datastore Auditor",
));
map.insert("Remote.Audit", (
ROLE_REMOTE_AUDIT,
"Remote Auditor",
));
map.insert("Remote.Admin", (
ROLE_REMOTE_ADMIN,
"Remote Administrator",
));
map.insert("Remote.SyncOperator", (
ROLE_REMOTE_SYNC_OPERATOR,
"Syncronisation Opertator",
));
for entry in list.iter() {
let privs: u64 = Role::from_str(entry.value).unwrap() as u64;
map.insert(entry.value, (privs, entry.description));
}
map
};
@ -615,15 +620,15 @@ mod test {
let tree = AclTree::from_raw(r###"
acl:0:/store/store2:user1:Admin
acl:0:/store/store2:user2:Admin
acl:0:/store/store2:user1:Datastore.Backup
acl:0:/store/store2:user2:Datastore.Backup
acl:0:/store/store2:user1:DatastoreBackup
acl:0:/store/store2:user2:DatastoreBackup
"###)?;
let mut raw: Vec<u8> = Vec::new();
tree.write_config(&mut raw)?;
let raw = std::str::from_utf8(&raw)?;
assert_eq!(raw, "acl:0:/store/store2:user1,user2:Admin,Datastore.Backup\n");
assert_eq!(raw, "acl:0:/store/store2:user1,user2:Admin,DatastoreBackup\n");
Ok(())
}
@ -633,18 +638,18 @@ acl:0:/store/store2:user2:Datastore.Backup
let tree = AclTree::from_raw(r###"
acl:1:/storage:user1@pbs:Admin
acl:1:/storage/store1:user1@pbs:Datastore.Backup
acl:1:/storage/store2:user2@pbs:Datastore.Backup
acl:1:/storage/store1:user1@pbs:DatastoreBackup
acl:1:/storage/store2:user2@pbs:DatastoreBackup
"###)?;
check_roles(&tree, "user1@pbs", "/", "");
check_roles(&tree, "user1@pbs", "/storage", "Admin");
check_roles(&tree, "user1@pbs", "/storage/store1", "Datastore.Backup");
check_roles(&tree, "user1@pbs", "/storage/store1", "DatastoreBackup");
check_roles(&tree, "user1@pbs", "/storage/store2", "Admin");
check_roles(&tree, "user2@pbs", "/", "");
check_roles(&tree, "user2@pbs", "/storage", "");
check_roles(&tree, "user2@pbs", "/storage/store1", "");
check_roles(&tree, "user2@pbs", "/storage/store2", "Datastore.Backup");
check_roles(&tree, "user2@pbs", "/storage/store2", "DatastoreBackup");
Ok(())
}
@ -655,22 +660,22 @@ acl:1:/storage/store2:user2@pbs:Datastore.Backup
let tree = AclTree::from_raw(r###"
acl:1:/:user1@pbs:Admin
acl:1:/storage:user1@pbs:NoAccess
acl:1:/storage/store1:user1@pbs:Datastore.Backup
acl:1:/storage/store1:user1@pbs:DatastoreBackup
"###)?;
check_roles(&tree, "user1@pbs", "/", "Admin");
check_roles(&tree, "user1@pbs", "/storage", "NoAccess");
check_roles(&tree, "user1@pbs", "/storage/store1", "Datastore.Backup");
check_roles(&tree, "user1@pbs", "/storage/store1", "DatastoreBackup");
check_roles(&tree, "user1@pbs", "/storage/store2", "NoAccess");
check_roles(&tree, "user1@pbs", "/system", "Admin");
let tree = AclTree::from_raw(r###"
acl:1:/:user1@pbs:Admin
acl:0:/storage:user1@pbs:NoAccess
acl:1:/storage/store1:user1@pbs:Datastore.Backup
acl:1:/storage/store1:user1@pbs:DatastoreBackup
"###)?;
check_roles(&tree, "user1@pbs", "/", "Admin");
check_roles(&tree, "user1@pbs", "/storage", "NoAccess");
check_roles(&tree, "user1@pbs", "/storage/store1", "Datastore.Backup");
check_roles(&tree, "user1@pbs", "/storage/store1", "DatastoreBackup");
check_roles(&tree, "user1@pbs", "/storage/store2", "Admin");
check_roles(&tree, "user1@pbs", "/system", "Admin");

View File

@ -142,27 +142,3 @@ fn verify_root_api() -> Result<(), Error> {
Ok(())
}
#[test]
fn verify_acl_role_schema() -> Result<(), Error> {
let list = match api2::types::ACL_ROLE_SCHEMA {
Schema::String(StringSchema { format: Some(ApiStringFormat::Enum(list)), .. }) => list,
_ => unreachable!(),
};
let map = &proxmox_backup::config::acl::ROLE_NAMES;
for item in *list {
if !map.contains_key(item) {
bail!("found role '{}' without description/mapping", item);
}
}
for role in map.keys() {
if !list.contains(role) {
bail!("role '{}' missing in ACL_ROLE_SCHEMA enum", role);
}
}
Ok(())
}