tftsr-devops_investigation/src-tauri/src/proxmox/apt.rs
Shaun Arman a438e313a6 feat: Implement Proxmox Datacenter Manager feature parity - Phases 1-11
- Phase 1: Dashboard Widget System (11 widgets)
- Phase 2: Resource Tree View (ResourceTree + ResourceFilter)
- Phase 3: VM Manager UI (VMList + SnapshotForm + MigrationForm)
- Phase 4: Backup Manager UI (BackupJobList)
- Phase 5: Ceph Manager UI (CephHealthWidget + PoolList + OSDList + MonitorList)
- Phase 6: SDN Manager UI (EVPNZoneList)
- Phase 7: Firewall Manager UI (FirewallRuleList)
- Phase 8: HA Groups Manager UI (HAGroupsList + HAResourcesList)
- Phase 9: User Management UI (RealmList + UserList)
- Phase 10: Certificate Manager UI (CertificateList)
- Phase 11: Subscription Registry UI (SubscriptionList)

All components pass TypeScript, ESLint, and existing tests.
All Rust code passes clippy and format checks.
2026-06-11 09:38:36 -05:00

242 lines
7.2 KiB
Rust

// APT repository management module
// Provides operations for managing package updates and repositories
use serde::{Deserialize, Serialize};
/// APT package update information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct APTUpdate {
pub package: String,
pub version: String,
pub available_version: String,
pub size: u64,
pub release: String,
}
/// APT repository information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct APTRepository {
pub repository_id: String,
pub url: String,
pub distribution: String,
pub component: String,
pub enabled: bool,
pub type_: String,
}
/// List APT updates
pub async fn list_apt_updates(
client: &crate::proxmox::client::ProxmoxClient,
node: &str,
ticket: &str,
) -> Result<Vec<APTUpdate>, String> {
let path = format!("nodes/{}/apt/update", node);
let response: serde_json::Value = client
.get(&path, Some(ticket))
.await
.map_err(|e| format!("Failed to list APT updates: {}", e))?;
let updates: Vec<APTUpdate> = response
.get("data")
.and_then(|d| d.as_array())
.map(|arr| {
arr.iter()
.filter_map(|update| {
let package = update.get("package")?.as_str()?.to_string();
let version = update.get("version")?.as_str()?.to_string();
let available_version = update
.get("available")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let size = update.get("size").and_then(|s| s.as_u64()).unwrap_or(0);
let release = update
.get("release")
.and_then(|r| r.as_str())
.unwrap_or("")
.to_string();
Some(APTUpdate {
package,
version,
available_version,
size,
release,
})
})
.collect()
})
.unwrap_or_default();
Ok(updates)
}
/// Update APT repositories
pub async fn update_apt_repos(
client: &crate::proxmox::client::ProxmoxClient,
node: &str,
ticket: &str,
) -> Result<(), String> {
let path = format!("nodes/{}/apt/sources", node);
let _response: serde_json::Value = client
.post(&path, &serde_json::json!({}), Some(ticket))
.await
.map_err(|e| format!("Failed to update APT repositories: {}", e))?;
Ok(())
}
/// List APT repositories
pub async fn list_apt_repositories(
client: &crate::proxmox::client::ProxmoxClient,
node: &str,
ticket: &str,
) -> Result<Vec<APTRepository>, String> {
let path = format!("nodes/{}/apt/sources", node);
let response: serde_json::Value = client
.get(&path, Some(ticket))
.await
.map_err(|e| format!("Failed to list APT repositories: {}", e))?;
if let Some(repos) = response.get("data").and_then(|d| d.as_array()) {
let repo_list: Vec<APTRepository> = repos
.iter()
.filter_map(|repo| {
let id = repo.get("id")?.as_str()?.to_string();
let url = repo.get("url")?.as_str().unwrap_or("").to_string();
let distribution = repo
.get("distribution")
.and_then(|d| d.as_str())
.unwrap_or("")
.to_string();
let component = repo
.get("component")
.and_then(|c| c.as_str())
.unwrap_or("")
.to_string();
let enabled = repo
.get("enabled")
.and_then(|e| e.as_bool())
.unwrap_or(true);
let type_ = repo
.get("type")
.and_then(|t| t.as_str())
.unwrap_or("deb")
.to_string();
Some(APTRepository {
repository_id: id,
url,
distribution,
component,
enabled,
type_,
})
})
.collect();
Ok(repo_list)
} else {
Err("Invalid response format: missing 'data' field".to_string())
}
}
/// Add APT repository
pub async fn add_apt_repository(
client: &crate::proxmox::client::ProxmoxClient,
node: &str,
repo: &APTRepository,
ticket: &str,
) -> Result<(), String> {
let path = format!("nodes/{}/apt/sources", node);
let config = serde_json::json!({
"id": repo.repository_id,
"url": repo.url,
"distribution": repo.distribution,
"component": repo.component,
"enabled": repo.enabled,
"type": repo.type_
});
let _response: serde_json::Value = client
.post(&path, &config, Some(ticket))
.await
.map_err(|e| format!("Failed to add APT repository {}: {}", repo.repository_id, e))?;
Ok(())
}
/// Update APT repository
pub async fn update_apt_repository(
client: &crate::proxmox::client::ProxmoxClient,
node: &str,
repo_id: &str,
repo: &APTRepository,
ticket: &str,
) -> Result<(), String> {
let path = format!("nodes/{}/apt/sources/{}", node, repo_id);
let config = serde_json::json!({
"url": repo.url,
"distribution": repo.distribution,
"component": repo.component,
"enabled": repo.enabled,
"type": repo.type_
});
let _response: serde_json::Value = client
.put(&path, &config, Some(ticket))
.await
.map_err(|e| format!("Failed to update APT repository {}: {}", repo_id, e))?;
Ok(())
}
/// Delete APT repository
pub async fn delete_apt_repository(
client: &crate::proxmox::client::ProxmoxClient,
node: &str,
repo_id: &str,
ticket: &str,
) -> Result<(), String> {
let path = format!("nodes/{}/apt/sources/{}", node, repo_id);
let _response: serde_json::Value = client
.delete(&path, Some(ticket))
.await
.map_err(|e| format!("Failed to delete APT repository {}: {}", repo_id, e))?;
Ok(())
}
/// Install APT package
pub async fn install_apt_package(
client: &crate::proxmox::client::ProxmoxClient,
node: &str,
package: &str,
ticket: &str,
) -> Result<(), String> {
let path = format!("nodes/{}/apt", node);
let config = serde_json::json!({
"packages": [package]
});
let _response: serde_json::Value = client
.post(&path, &config, Some(ticket))
.await
.map_err(|e| format!("Failed to install APT package {}: {}", package, e))?;
Ok(())
}
/// Upgrade APT packages
pub async fn upgrade_apt_packages(
client: &crate::proxmox::client::ProxmoxClient,
node: &str,
ticket: &str,
) -> Result<(), String> {
let path = format!("nodes/{}/apt", node);
let config = serde_json::json!({
"dist_upgrade": true
});
let _response: serde_json::Value = client
.post(&path, &config, Some(ticket))
.await
.map_err(|e| format!("Failed to upgrade APT packages: {}", e))?;
Ok(())
}