From: "Fabian Grünbichler" <f.gruenbichler@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup 3/4] api: refactor remote client and add remote scan
Date: Wed, 4 Nov 2020 14:10:25 +0100 [thread overview]
Message-ID: <20201104131026.4017010-3-f.gruenbichler@proxmox.com> (raw)
In-Reply-To: <20201104131026.4017010-1-f.gruenbichler@proxmox.com>
to allow on-demand scanning of remote datastores accessible for the
configured remote user.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
Notes:
not 100% sure about PRIV_REMOTE_AUDIT vs PRIV_REMOTE_READ.. the latter is required to use a datastore for syncing/pull purposes
src/api2/config/remote.rs | 66 ++++++++++++++++++++++++++++++-
src/api2/pull.rs | 12 +-----
src/bin/proxmox-backup-manager.rs | 26 +++---------
3 files changed, 71 insertions(+), 33 deletions(-)
diff --git a/src/api2/config/remote.rs b/src/api2/config/remote.rs
index ffbba1d2..b415f63d 100644
--- a/src/api2/config/remote.rs
+++ b/src/api2/config/remote.rs
@@ -1,4 +1,4 @@
-use anyhow::{bail, Error};
+use anyhow::{bail, format_err, Error};
use serde_json::Value;
use ::serde::{Deserialize, Serialize};
@@ -6,6 +6,7 @@ use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
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 +302,71 @@ pub fn delete_remote(name: String, digest: Option<String>) -> Result<(), Error>
Ok(())
}
+/// Helper to get client for remote.cfg entry
+pub async fn remote_client(remote: remote::Remote) -> Result<HttpClient, Error> {
+ 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<Vec<DataStoreListItem>, Error> {
+ let (remote_config, _digest) = remote::config()?;
+ let remote: remote::Remote = remote_config.lookup("remote", &name)?;
+
+ let client = remote_client(remote).await?;
+ let api_res = client.get("api2/json/admin/datastore", None).await?;
+ let parse_res = match api_res.get("data") {
+ Some(data) => serde_json::from_value::<Vec<DataStoreListItem>>(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<String, String
let _ = proxmox::try_block!({
let remote = param.get("remote").ok_or_else(|| format_err!("no remote"))?;
- let (remote_config, _digest) = config::remote::config()?;
- let remote: config::remote::Remote = remote_config.lookup("remote", &remote)?;
+ let data = crate::tools::runtime::block_on(async move {
+ crate::api2::config::remote::scan_remote_datastores(remote.clone()).await
+ })?;
- 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 result = crate::tools::runtime::block_on(client.get("api2/json/admin/datastore", None))?;
-
- if let Some(data) = result["data"].as_array() {
- for item in data {
- if let Some(store) = item["store"].as_str() {
- list.push(store.to_owned());
- }
- }
+ for item in data {
+ list.push(item.store);
}
Ok(())
--
2.20.1
next prev parent reply other threads:[~2020-11-04 13:11 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-04 13:10 [pbs-devel] [PATCH proxmox-backup 1/4] www: don't default to hourly sync job schedule Fabian Grünbichler
2020-11-04 13:10 ` [pbs-devel] [PATCH proxmox-backup 2/4] types: extract DataStoreListItem Fabian Grünbichler
2020-11-04 13:10 ` Fabian Grünbichler [this message]
2020-11-04 16:57 ` [pbs-devel] [PATCH proxmox-backup 3/4] api: refactor remote client and add remote scan Thomas Lamprecht
2020-11-05 7:42 ` Fabian Grünbichler
2020-11-05 9:03 ` Thomas Lamprecht
2020-11-04 17:12 ` Thomas Lamprecht
2020-11-05 7:43 ` Fabian Grünbichler
2020-11-05 8:58 ` Thomas Lamprecht
2020-11-04 13:10 ` [pbs-devel] [PATCH proxmox-backup 4/4] www: add remote store selector Fabian Grünbichler
2020-11-04 13:42 ` [pbs-devel] [PATCH proxmox-backup 1/4] www: don't default to hourly sync job schedule Thomas Lamprecht
[not found] ` <dce0d21f-20dc-5443-bbb0-6b6f5be73e43@proxmox.com>
[not found] ` <1604497203.f21gwhaa55.astroid@nora.none>
2020-11-04 17:03 ` Thomas Lamprecht
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201104131026.4017010-3-f.gruenbichler@proxmox.com \
--to=f.gruenbichler@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.