proxmox-api 0.2.0

Rust bindings for the Proxmox VE HTTP API
Documentation
use clap::Parser;
use proxmox_api::{ReqwestClient, client::Client};

#[derive(Debug, Parser)]
pub struct Cli {
    #[clap(env = "PROXMOX_HOST")]
    host: String,

    /// <user>@<realm>
    #[clap(env = "PROXMOX_USER")]
    user: String,

    /// The password to use.
    #[clap(long, env = "PROXMOX_PASSWORD")]
    password: Option<String>,

    /// The API token to use.
    #[clap(long, env = "PROXMOX_API_TOKEN")]
    token: Option<String>,

    /// The API token ID. Required if `token` is set.
    #[clap(long, env = "PROXMOX_API_TOKEN_ID")]
    token_id: Option<String>,
}

impl Cli {
    pub async fn client(&self) -> std::io::Result<impl Client + std::fmt::Debug> {
        fn err<T: std::fmt::Display>(t: T) -> std::io::Error {
            std::io::Error::other(format!("{t}"))
        }

        fn err_dbg<T: std::fmt::Debug>(t: T) -> std::io::Error {
            std::io::Error::other(format!("Error while creating client: {t:?}"))
        }

        let (user, realm) = self
            .user
            .split_once('@')
            .expect("User must be provided as <user>@<realm>");

        if let Some(token) = &self.token {
            let token_id = self.token_id.as_ref().ok_or(err("API token requires ID"))?;

            Ok(ReqwestClient::new(&self.host, user, realm, None).with_api_token(token_id, token))
        } else {
            let password = self
                .password
                .as_ref()
                .expect("Password or token is required.");

            ReqwestClient::new(&self.host, user, realm, None)
                .with_login(password)
                .await
                .map_err(err_dbg)
        }
    }
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    pretty_env_logger::init();

    let cli = Cli::parse();

    log::debug!("CLI args: {cli:?}");

    let client = cli.client().await?;

    #[cfg(feature = "nodes")]
    nodes(&client).await;

    #[cfg(feature = "pools")]
    pools(&client).await;

    Ok(())
}

#[cfg(feature = "nodes")]
async fn nodes(client: &impl Client) {
    use proxmox_api::{nodes::NodesClient, types::VmId, types::bounded_integer::BoundedInteger};

    let nodes_client = NodesClient::new(client);

    println!(
        "VM config: {:#?}",
        nodes_client
            .node("proxmox")
            .qemu()
            .vmid(VmId::new(118).unwrap())
            .config()
            .get(Default::default())
            .await
    );
}

#[cfg(feature = "pools")]
async fn pools(client: &impl Client) {
    use proxmox_api::pools::{GetParams, PoolsClient};

    let pools_client = PoolsClient::new(client);

    for v in pools_client.get(Default::default()).await.unwrap() {
        let pool = pools_client
            .get(GetParams {
                poolid: Some(v.poolid.clone()),
                ..Default::default()
            })
            .await
            .unwrap();

        println!("Pool info for {}: {:?}", v.poolid, pool[0]);
    }
}