2024-11-07 04:41:49 +00:00
|
|
|
use std::time::Duration;
|
|
|
|
use proxmox_api::nodes::node::lxc::vmid::migrate;
|
|
|
|
use proxmox_api::nodes::node::tasks::upid;
|
|
|
|
use sea_orm::{ActiveModelTrait, EntityTrait, IntoActiveModel, Set};
|
|
|
|
use tokio::time::sleep;
|
|
|
|
use crate::api::entity::nodes;
|
|
|
|
use crate::api::entity::nodes::P5xError;
|
|
|
|
use crate::api::services::Services;
|
|
|
|
|
2025-02-23 17:42:48 +00:00
|
|
|
|
|
|
|
/** Migrate an LXC container from its current PVE node to the given PVE node. */
|
2024-11-07 04:41:49 +00:00
|
|
|
pub async fn migrate_node(
|
|
|
|
svc: &Services<'_>,
|
|
|
|
node: nodes::Model,
|
|
|
|
to_host: &str,
|
|
|
|
) -> Result<nodes::Model, P5xError> {
|
|
|
|
// Ask the PVE API to start migrating the node
|
|
|
|
let params = migrate::PostParams::new(to_host.to_string());
|
|
|
|
let upid = svc.pve_node(&node.pve_host)
|
|
|
|
.map_err(P5xError::ServiceError)?
|
|
|
|
.lxc()
|
|
|
|
.vmid(node.vm_id())
|
|
|
|
.migrate()
|
|
|
|
.post(params)
|
|
|
|
.map_err(P5xError::PveError)?;
|
|
|
|
|
|
|
|
// Wait for the UPID to finish
|
|
|
|
wait_upid(svc, &node.pve_host, &upid).await?;
|
|
|
|
|
|
|
|
// Persist the node
|
|
|
|
let mut node = node.into_active_model();
|
|
|
|
node.pve_host = Set(to_host.to_string());
|
|
|
|
let node = node.save(svc.db).await.map_err(P5xError::DbErr)?;
|
|
|
|
|
|
|
|
nodes::Entity::find_by_id(node.id.unwrap())
|
|
|
|
.one(svc.db)
|
|
|
|
.await
|
|
|
|
.map_err(P5xError::DbErr)?
|
|
|
|
.ok_or(P5xError::BadPostcondition("Could not look up node after persisting"))
|
|
|
|
}
|
|
|
|
|
2025-02-23 17:42:48 +00:00
|
|
|
|
|
|
|
/** Wait for a PVE task to complete using its UPID */
|
2024-11-07 04:41:49 +00:00
|
|
|
pub async fn wait_upid(svc: &Services<'_>, node: &str, upid: &str) -> Result<(), P5xError> {
|
|
|
|
info!("Waiting for UPID {upid} on node {node}");
|
|
|
|
let pve = svc.pve_node(node)
|
|
|
|
.map_err(P5xError::ServiceError)?;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let status = pve.tasks()
|
|
|
|
.upid(upid)
|
|
|
|
.status()
|
|
|
|
.get()
|
|
|
|
.map_err(P5xError::PveError)?;
|
|
|
|
|
|
|
|
if status.status == upid::status::Status::Running {
|
|
|
|
sleep(Duration::from_secs(1)).await;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(s) = status.exitstatus {
|
|
|
|
if s == "OK" {
|
|
|
|
info!("UPID {upid} on node {node} finished");
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
error!("UPID {upid} on node {node} failed");
|
|
|
|
return Err(P5xError::UpidFailed(node.to_string(), upid.to_string()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|