tftsr-devops_investigation/src-tauri/src/proxmox/storage.rs

121 lines
3.5 KiB
Rust
Raw Normal View History

// Storage management module
// Provides operations for managing Proxmox storage
use serde::{Deserialize, Serialize};
/// Storage information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StorageInfo {
pub storage: String,
pub node: String,
pub type_: String,
pub content: String,
pub size: u64,
pub used: u64,
pub available: u64,
pub status: String,
}
/// List all storages
pub async fn list_storages(
_client: &crate::proxmox::client::ProxmoxClient,
_node: &str,
_ticket: &str,
) -> Result<Vec<StorageInfo>, String> {
Err("Not implemented yet".to_string())
}
/// Get storage status
pub async fn get_storage_status(
_client: &crate::proxmox::client::ProxmoxClient,
_node: &str,
_storage: &str,
_ticket: &str,
) -> Result<StorageInfo, String> {
Err("Not implemented yet".to_string())
}
/// List ISO images available in a storage (client-side filtered from storage content)
pub async fn list_storage_content_iso(
client: &crate::proxmox::client::ProxmoxClient,
node: &str,
storage: &str,
ticket: &str,
) -> Result<Vec<serde_json::Value>, String> {
let path = format!("nodes/{}/storage/{}/content", node, storage);
let response: serde_json::Value = client
.get(&path, Some(ticket))
.await
.map_err(|e| format!("Failed to list storage content for {}/{}: {}", node, storage, e))?;
response
.as_array()
.map(|arr| {
arr.iter()
.filter(|item| {
item.get("content")
.and_then(|c| c.as_str())
.map(|c| c == "iso")
.unwrap_or(false)
})
.cloned()
.collect::<Vec<_>>()
})
.ok_or_else(|| "Invalid response format from storage content".to_string())
}
/// Upload an ISO file to a Proxmox storage pool.
/// Returns the task UPID string that can be polled for completion.
pub async fn upload_iso(
client: &crate::proxmox::client::ProxmoxClient,
node: &str,
storage: &str,
filename: &str,
file_bytes: Vec<u8>,
ticket: &str,
) -> Result<String, String> {
let path = format!("nodes/{}/storage/{}/upload", node, storage);
let file_part = reqwest::multipart::Part::bytes(file_bytes)
.file_name(filename.to_string())
.mime_str("application/octet-stream")
.map_err(|e| format!("Failed to build multipart part: {}", e))?;
let form = reqwest::multipart::Form::new()
.text("content", "iso")
.text("filename", filename.to_string())
.part("file", file_part);
let task_id: String = client
.post_multipart(&path, form, Some(ticket))
.await
.map_err(|e| format!("Failed to upload ISO to {}/{}: {}", node, storage, e))?;
Ok(task_id)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_storage_info_serialization() {
let storage = StorageInfo {
storage: "local".to_string(),
node: "pve-node-1".to_string(),
type_: "dir".to_string(),
content: "images,backup,iso".to_string(),
size: 1000000000000,
used: 300000000000,
available: 700000000000,
status: "available".to_string(),
};
let json = serde_json::to_string(&storage).unwrap();
let deserialized: StorageInfo = serde_json::from_str(&json).unwrap();
assert_eq!(storage.storage, deserialized.storage);
assert_eq!(storage.status, "available");
}
}