diff --git a/src/api2/config/remote.rs b/src/api2/config/remote.rs index ffbba1d2..f053ef36 100644 --- a/src/api2/config/remote.rs +++ b/src/api2/config/remote.rs @@ -1,11 +1,13 @@ -use anyhow::{bail, Error}; +use anyhow::{bail, format_err, Error}; use serde_json::Value; use ::serde::{Deserialize, Serialize}; use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission}; +use proxmox::http_err; use proxmox::tools::fs::open_file_locked; use crate::api2::types::*; +use crate::client::{HttpClient, HttpClientOptions}; use crate::config::cached_user_info::CachedUserInfo; use crate::config::remote; use crate::config::acl::{PRIV_REMOTE_AUDIT, PRIV_REMOTE_MODIFY}; @@ -301,10 +303,83 @@ pub fn delete_remote(name: String, digest: Option) -> Result<(), Error> Ok(()) } +/// Helper to get client for remote.cfg entry +pub async fn remote_client(remote: remote::Remote) -> Result { + let options = HttpClientOptions::new() + .password(Some(remote.password.clone())) + .fingerprint(remote.fingerprint.clone()); + + let client = HttpClient::new( + &remote.host, + remote.port.unwrap_or(8007), + &remote.userid, + options)?; + let _auth_info = client.login() // make sure we can auth + .await + .map_err(|err| format_err!("remote connection to '{}' failed - {}", remote.host, err))?; + + Ok(client) +} + + +#[api( + input: { + properties: { + name: { + schema: REMOTE_ID_SCHEMA, + }, + }, + }, + access: { + permission: &Permission::Privilege(&["remote", "{name}"], PRIV_REMOTE_AUDIT, false), + }, + returns: { + description: "List the accessible datastores.", + type: Array, + items: { + description: "Datastore name and description.", + type: DataStoreListItem, + }, + }, +)] +/// List datastores of a remote.cfg entry +pub async fn scan_remote_datastores(name: String) -> Result, Error> { + let (remote_config, _digest) = remote::config()?; + let remote: remote::Remote = remote_config.lookup("remote", &name)?; + + let map_remote_err = |api_err| { + http_err!(INTERNAL_SERVER_ERROR, + "failed to scan remote '{}' - {}", + &name, + api_err) + }; + + let client = remote_client(remote) + .await + .map_err(map_remote_err)?; + let api_res = client + .get("api2/json/admin/datastore", None) + .await + .map_err(map_remote_err)?; + let parse_res = match api_res.get("data") { + Some(data) => serde_json::from_value::>(data.to_owned()), + None => bail!("remote {} did not return any datastore list data", &name), + }; + + match parse_res { + Ok(parsed) => Ok(parsed), + Err(_) => bail!("Failed to parse remote scan api result."), + } +} + +const SCAN_ROUTER: Router = Router::new() + .get(&API_METHOD_SCAN_REMOTE_DATASTORES); + const ITEM_ROUTER: Router = Router::new() .get(&API_METHOD_READ_REMOTE) .put(&API_METHOD_UPDATE_REMOTE) - .delete(&API_METHOD_DELETE_REMOTE); + .delete(&API_METHOD_DELETE_REMOTE) + .subdirs(&[("scan", &SCAN_ROUTER)]); pub const ROUTER: Router = Router::new() .get(&API_METHOD_LIST_REMOTES) diff --git a/src/api2/pull.rs b/src/api2/pull.rs index d9e9d31d..87015c72 100644 --- a/src/api2/pull.rs +++ b/src/api2/pull.rs @@ -9,7 +9,7 @@ use proxmox::api::{ApiMethod, Router, RpcEnvironment, Permission}; use crate::server::{WorkerTask, jobstate::Job}; use crate::backup::DataStore; -use crate::client::{HttpClient, HttpClientOptions, BackupRepository, pull::pull_store}; +use crate::client::{HttpClient, BackupRepository, pull::pull_store}; use crate::api2::types::*; use crate::config::{ remote, @@ -50,17 +50,9 @@ pub async fn get_pull_parameters( let (remote_config, _digest) = remote::config()?; let remote: remote::Remote = remote_config.lookup("remote", remote)?; - let options = HttpClientOptions::new() - .password(Some(remote.password.clone())) - .fingerprint(remote.fingerprint.clone()); - let src_repo = BackupRepository::new(Some(remote.userid.clone()), Some(remote.host.clone()), remote.port, remote_store.to_string()); - let client = HttpClient::new(&src_repo.host(), src_repo.port(), &src_repo.auth_id(), options)?; - let _auth_info = client.login() // make sure we can auth - .await - .map_err(|err| format_err!("remote connection to '{}' failed - {}", remote.host, err))?; - + let client = crate::api2::config::remote::remote_client(remote).await?; Ok((client, src_repo, tgt_store)) } diff --git a/src/bin/proxmox-backup-manager.rs b/src/bin/proxmox-backup-manager.rs index 7499446b..e52c2f76 100644 --- a/src/bin/proxmox-backup-manager.rs +++ b/src/bin/proxmox-backup-manager.rs @@ -413,29 +413,13 @@ pub fn complete_remote_datastore_name(_arg: &str, param: &HashMap