use pxar::accessor::{MaybeReady, ReadAt, ReadAtOperation};
use proxmox_backup::tools;
+use proxmox_backup::api2::access::user::UserWithTokens;
use proxmox_backup::api2::types::*;
use proxmox_backup::api2::version;
use proxmox_backup::client::*;
use proxmox_backup::pxar::catalog::*;
-use proxmox_backup::config::user::complete_user_name;
use proxmox_backup::backup::{
archive_type,
decrypt_key,
result
}
-fn connect(server: &str, port: u16, userid: &Userid) -> Result<HttpClient, Error> {
+fn connect(repo: &BackupRepository) -> Result<HttpClient, Error> {
+ connect_do(repo.host(), repo.port(), repo.auth_id())
+ .map_err(|err| format_err!("error building client for repository {} - {}", repo, err))
+}
+fn connect_do(server: &str, port: u16, auth_id: &Authid) -> Result<HttpClient, Error> {
let fingerprint = std::env::var(ENV_VAR_PBS_FINGERPRINT).ok();
use std::env::VarError::*;
.fingerprint_cache(true)
.ticket_cache(true);
- HttpClient::new(server, port, userid, options)
+ HttpClient::new(server, port, auth_id, options)
}
async fn view_task_result(
let repo = extract_repository_from_value(¶m)?;
- let client = connect(repo.host(), repo.port(), repo.user())?;
+ let client = connect(&repo)?;
let path = format!("api2/json/admin/datastore/{}/groups", repo.store());
description: "Backup group.",
},
"new-owner": {
- type: Userid,
+ type: Authid,
},
}
}
let repo = extract_repository_from_value(¶m)?;
- let mut client = connect(repo.host(), repo.port(), repo.user())?;
+ let mut client = connect(&repo)?;
param.as_object_mut().unwrap().remove("repository");
let output_format = get_output_format(¶m);
- let client = connect(repo.host(), repo.port(), repo.user())?;
+ let client = connect(&repo)?;
let group: Option<BackupGroup> = if let Some(path) = param["group"].as_str() {
Some(path.parse()?)
let path = tools::required_string_param(¶m, "snapshot")?;
let snapshot: BackupDir = path.parse()?;
- let mut client = connect(repo.host(), repo.port(), repo.user())?;
+ let mut client = connect(&repo)?;
let path = format!("api2/json/admin/datastore/{}/snapshots", repo.store());
let repo = extract_repository_from_value(¶m)?;
- let client = connect(repo.host(), repo.port(), repo.user())?;
+ let client = connect(&repo)?;
client.login().await?;
record_repository(&repo);
let repo = extract_repository_from_value(¶m);
if let Ok(repo) = repo {
- let client = connect(repo.host(), repo.port(), repo.user())?;
+ let client = connect(&repo)?;
match client.get("api2/json/version", None).await {
Ok(mut result) => version_info["server"] = result["data"].take(),
let output_format = get_output_format(¶m);
- let client = connect(repo.host(), repo.port(), repo.user())?;
+ let client = connect(&repo)?;
let path = format!("api2/json/admin/datastore/{}/files", repo.store());
let output_format = get_output_format(¶m);
- let mut client = connect(repo.host(), repo.port(), repo.user())?;
+ let mut client = connect(&repo)?;
let path = format!("api2/json/admin/datastore/{}/gc", repo.store());
let keydata = match (keyfile, key_fd) {
(None, None) => None,
(Some(_), Some(_)) => bail!("--keyfile and --keyfd are mutually exclusive"),
- (Some(keyfile), None) => Some(file_get_contents(keyfile)?),
+ (Some(keyfile), None) => {
+ println!("Using encryption key file: {}", keyfile);
+ Some(file_get_contents(keyfile)?)
+ },
(None, Some(fd)) => {
let input = unsafe { std::fs::File::from_raw_fd(fd) };
let mut data = Vec::new();
.map_err(|err| {
format_err!("error reading encryption key from fd {}: {}", fd, err)
})?;
+ println!("Using encryption key from file descriptor");
Some(data)
}
};
Ok(match (keydata, crypt_mode) {
// no parameters:
(None, None) => match key::read_optional_default_encryption_key()? {
- Some(key) => (Some(key), CryptMode::Encrypt),
+ Some(key) => {
+ println!("Encrypting with default encryption key!");
+ (Some(key), CryptMode::Encrypt)
+ },
None => (None, CryptMode::None),
},
// just --crypt-mode other than none
(None, Some(crypt_mode)) => match key::read_optional_default_encryption_key()? {
None => bail!("--crypt-mode without --keyfile and no default key file available"),
- Some(key) => (Some(key), crypt_mode),
+ Some(key) => {
+ println!("Encrypting with default encryption key!");
+ (Some(key), crypt_mode)
+ },
}
// just --keyfile
description: "Path to file.",
}
},
+ "all-file-systems": {
+ type: Boolean,
+ description: "Include all mounted subdirectories.",
+ optional: true,
+ },
keyfile: {
schema: KEYFILE_SCHEMA,
optional: true,
let backup_time = backup_time_opt.unwrap_or_else(|| epoch_i64());
- let client = connect(repo.host(), repo.port(), repo.user())?;
+ let client = connect(&repo)?;
record_repository(&repo);
println!("Starting backup: {}/{}/{}", backup_type, backup_id, BackupDir::backup_time_to_string(backup_time)?);
let (crypt_config, rsa_encrypted_key) = match keydata {
None => (None, None),
Some(key) => {
- let (key, created) = decrypt_key(&key, &key::get_encryption_key_password)?;
+ let (key, created, _fingerprint) = decrypt_key(&key, &key::get_encryption_key_password)?;
let crypt_config = CryptConfig::new(key)?;
let archive_name = tools::required_string_param(¶m, "archive-name")?;
- let client = connect(repo.host(), repo.port(), repo.user())?;
+ let client = connect(&repo)?;
record_repository(&repo);
let crypt_config = match keydata {
None => None,
Some(key) => {
- let (key, _) = decrypt_key(&key, &key::get_encryption_key_password)?;
+ let (key, _, _) = decrypt_key(&key, &key::get_encryption_key_password)?;
Some(Arc::new(CryptConfig::new(key)?))
}
};
let snapshot = tools::required_string_param(¶m, "snapshot")?;
let snapshot: BackupDir = snapshot.parse()?;
- let mut client = connect(repo.host(), repo.port(), repo.user())?;
+ let mut client = connect(&repo)?;
let (keydata, crypt_mode) = keyfile_parameters(¶m)?;
let crypt_config = match keydata {
None => None,
Some(key) => {
- let (key, _created) = decrypt_key(&key, &key::get_encryption_key_password)?;
+ let (key, _created, _) = decrypt_key(&key, &key::get_encryption_key_password)?;
let crypt_config = CryptConfig::new(key)?;
Some(Arc::new(crypt_config))
}
async fn prune_async(mut param: Value) -> Result<Value, Error> {
let repo = extract_repository_from_value(¶m)?;
- let mut client = connect(repo.host(), repo.port(), repo.user())?;
+ let mut client = connect(&repo)?;
let path = format!("api2/json/admin/datastore/{}/prune", repo.store());
let output_format = get_output_format(¶m);
- let client = connect(repo.host(), repo.port(), repo.user())?;
+ let client = connect(&repo)?;
let path = format!("api2/json/admin/datastore/{}/status", repo.store());
let mut result = client.get(&path, None).await?;
- let mut data = result["data"]["storage"].take();
+ let mut data = result["data"].take();
record_repository(&repo);
.fingerprint_cache(true)
.ticket_cache(true);
- let client = match HttpClient::new(repo.host(), repo.port(), repo.user(), options) {
+ let client = match HttpClient::new(repo.host(), repo.port(), repo.auth_id(), options) {
Ok(v) => v,
_ => return Value::Null,
};
result
}
+fn complete_auth_id(_arg: &str, param: &HashMap<String, String>) -> Vec<String> {
+ proxmox_backup::tools::runtime::main(async { complete_auth_id_do(param).await })
+}
+
+async fn complete_auth_id_do(param: &HashMap<String, String>) -> Vec<String> {
+
+ let mut result = vec![];
+
+ let repo = match extract_repository_from_map(param) {
+ Some(v) => v,
+ _ => return result,
+ };
+
+ let data = try_get(&repo, "api2/json/access/users?include_tokens=true").await;
+
+ if let Ok(parsed) = serde_json::from_value::<Vec<UserWithTokens>>(data) {
+ for user in parsed {
+ result.push(user.userid.to_string());
+ for token in user.tokens {
+ result.push(token.tokenid.to_string());
+ }
+ }
+ };
+
+ result
+}
+
use proxmox_backup::client::RemoteChunkReader;
/// This is a workaround until we have cleaned up the chunk/reader/... infrastructure for better
/// async use!
let change_owner_cmd_def = CliCommand::new(&API_METHOD_CHANGE_BACKUP_OWNER)
.arg_param(&["group", "new-owner"])
.completion_cb("group", complete_backup_group)
- .completion_cb("new-owner", complete_user_name)
+ .completion_cb("new-owner", complete_auth_id)
.completion_cb("repository", complete_repository);
let cmd_def = CliCommandMap::new()