diff --git a/.gitignore b/.gitignore
index ed78c4e..7b6ade0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
.idea
k
*.sqlite
+.env
diff --git a/Cargo.lock b/Cargo.lock
index 4e137dd..1c27f8c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -188,12 +188,6 @@ dependencies = [
"bytemuck",
]
-[[package]]
-name = "atomic-waker"
-version = "1.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
-
[[package]]
name = "autocfg"
version = "1.4.0"
@@ -675,6 +669,12 @@ dependencies = [
"subtle",
]
+[[package]]
+name = "dotenv"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
+
[[package]]
name = "dotenvy"
version = "0.15.7"
@@ -1023,25 +1023,6 @@ dependencies = [
"tracing",
]
-[[package]]
-name = "h2"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205"
-dependencies = [
- "atomic-waker",
- "bytes",
- "fnv",
- "futures-core",
- "futures-sink",
- "http 1.1.0",
- "indexmap",
- "slab",
- "tokio",
- "tokio-util",
- "tracing",
-]
-
[[package]]
name = "handlebars"
version = "5.1.2"
@@ -1180,29 +1161,6 @@ dependencies = [
"pin-project-lite",
]
-[[package]]
-name = "http-body"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
-dependencies = [
- "bytes",
- "http 1.1.0",
-]
-
-[[package]]
-name = "http-body-util"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
-dependencies = [
- "bytes",
- "futures-util",
- "http 1.1.0",
- "http-body 1.0.1",
- "pin-project-lite",
-]
-
[[package]]
name = "httparse"
version = "1.9.5"
@@ -1231,9 +1189,9 @@ dependencies = [
"futures-channel",
"futures-core",
"futures-util",
- "h2 0.3.26",
+ "h2",
"http 0.2.12",
- "http-body 0.4.6",
+ "http-body",
"httparse",
"httpdate",
"itoa",
@@ -1245,78 +1203,6 @@ dependencies = [
"want",
]
-[[package]]
-name = "hyper"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-util",
- "h2 0.4.6",
- "http 1.1.0",
- "http-body 1.0.1",
- "httparse",
- "itoa",
- "pin-project-lite",
- "smallvec",
- "tokio",
- "want",
-]
-
-[[package]]
-name = "hyper-rustls"
-version = "0.27.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
-dependencies = [
- "futures-util",
- "http 1.1.0",
- "hyper 1.5.0",
- "hyper-util",
- "rustls",
- "rustls-pki-types",
- "tokio",
- "tokio-rustls",
- "tower-service",
-]
-
-[[package]]
-name = "hyper-tls"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
-dependencies = [
- "bytes",
- "http-body-util",
- "hyper 1.5.0",
- "hyper-util",
- "native-tls",
- "tokio",
- "tokio-native-tls",
- "tower-service",
-]
-
-[[package]]
-name = "hyper-util"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-util",
- "http 1.1.0",
- "http-body 1.0.1",
- "hyper 1.5.0",
- "pin-project-lite",
- "socket2",
- "tokio",
- "tower-service",
- "tracing",
-]
-
[[package]]
name = "iana-time-zone"
version = "0.1.61"
@@ -1413,12 +1299,6 @@ dependencies = [
"cfg-if",
]
-[[package]]
-name = "ipnet"
-version = "2.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
-
[[package]]
name = "is-terminal"
version = "0.4.13"
@@ -1917,11 +1797,11 @@ name = "p5x"
version = "0.1.0"
dependencies = [
"async-trait",
+ "dotenv",
"env_logger",
"futures",
"log",
"proxmox-api",
- "reqwest",
"rocket",
"rocket_dyn_templates",
"sea-orm",
@@ -1929,7 +1809,6 @@ dependencies = [
"sea-orm-rocket",
"serde",
"serde_json",
- "serde_urlencoded",
"ssh2",
"tokio",
"ureq",
@@ -2392,49 +2271,6 @@ dependencies = [
"bytecheck",
]
-[[package]]
-name = "reqwest"
-version = "0.12.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f"
-dependencies = [
- "base64",
- "bytes",
- "encoding_rs",
- "futures-core",
- "futures-util",
- "h2 0.4.6",
- "http 1.1.0",
- "http-body 1.0.1",
- "http-body-util",
- "hyper 1.5.0",
- "hyper-rustls",
- "hyper-tls",
- "hyper-util",
- "ipnet",
- "js-sys",
- "log",
- "mime",
- "native-tls",
- "once_cell",
- "percent-encoding",
- "pin-project-lite",
- "rustls-pemfile",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "sync_wrapper",
- "system-configuration",
- "tokio",
- "tokio-native-tls",
- "tower-service",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "windows-registry",
-]
-
[[package]]
name = "ring"
version = "0.17.8"
@@ -2557,7 +2393,7 @@ dependencies = [
"either",
"futures",
"http 0.2.12",
- "hyper 0.14.31",
+ "hyper",
"indexmap",
"log",
"memchr",
@@ -2644,15 +2480,6 @@ dependencies = [
"zeroize",
]
-[[package]]
-name = "rustls-pemfile"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
-dependencies = [
- "rustls-pki-types",
-]
-
[[package]]
name = "rustls-pki-types"
version = "1.10.0"
@@ -3405,36 +3232,6 @@ dependencies = [
"syn 2.0.86",
]
-[[package]]
-name = "sync_wrapper"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
-dependencies = [
- "futures-core",
-]
-
-[[package]]
-name = "system-configuration"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
-dependencies = [
- "bitflags 2.6.0",
- "core-foundation",
- "system-configuration-sys",
-]
-
-[[package]]
-name = "system-configuration-sys"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
[[package]]
name = "tap"
version = "1.0.1"
@@ -3558,27 +3355,6 @@ dependencies = [
"syn 2.0.86",
]
-[[package]]
-name = "tokio-native-tls"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
-dependencies = [
- "native-tls",
- "tokio",
-]
-
-[[package]]
-name = "tokio-rustls"
-version = "0.26.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
-dependencies = [
- "rustls",
- "rustls-pki-types",
- "tokio",
-]
-
[[package]]
name = "tokio-stream"
version = "0.1.16"
@@ -3906,18 +3682,6 @@ dependencies = [
"wasm-bindgen-shared",
]
-[[package]]
-name = "wasm-bindgen-futures"
-version = "0.4.45"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
-dependencies = [
- "cfg-if",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
-]
-
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.95"
@@ -3947,16 +3711,6 @@ version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
-[[package]]
-name = "web-sys"
-version = "0.3.72"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
[[package]]
name = "webpki-roots"
version = "0.26.6"
@@ -4025,36 +3779,6 @@ dependencies = [
"windows-targets 0.52.6",
]
-[[package]]
-name = "windows-registry"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
-dependencies = [
- "windows-result",
- "windows-strings",
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-result"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-strings"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
-dependencies = [
- "windows-result",
- "windows-targets 0.52.6",
-]
-
[[package]]
name = "windows-sys"
version = "0.48.0"
diff --git a/Cargo.toml b/Cargo.toml
index 7218000..324820a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,9 +16,8 @@ rocket_dyn_templates = { version = "0.2.0", features = ["handlebars"] }
sea-orm-migration = "1.1.0"
uuid = { version = "1.11.0", features = ["v4", "fast-rng"] }
ssh2 = "0.9.4"
-reqwest = "0.12.9"
futures = { version = "0.3.31", features = ["executor"] }
serde_json = "1.0.132"
-serde_urlencoded = "0.7.1"
proxmox-api = { git = "https://github.com/glmdev/p5x-proxmox-api", version = "0.1.2-pre", features = ["ureq-client"] }
ureq = "2.10.1"
+dotenv = "0.15.0"
diff --git a/Rocket.toml b/Rocket.toml
index 09a93a6..ebc2bef 100644
--- a/Rocket.toml
+++ b/Rocket.toml
@@ -1,5 +1,10 @@
[default]
template_dir = "resources/views"
+address = "0.0.0.0"
+port = 3450
+
+[default.p5x]
+pvemaster = ""
[default.databases.p5x_api]
url = "sqlite://p5x_api.sqlite?mode=rwc"
diff --git a/package.sh b/package.sh
new file mode 100755
index 0000000..af111b0
--- /dev/null
+++ b/package.sh
@@ -0,0 +1,18 @@
+#!/bin/bash -e
+
+P_NAME="p5x-$(arch)"
+
+cargo build --release
+mkdir "$P_NAME"
+cd "$P_NAME"
+
+cp -r ../resources .
+cp -r ../Rocket.toml .
+cp -r ../start.sh .
+cp -r ../target/release/p5x .
+
+cd ..
+zip -r "$P_NAME.zip" "$P_NAME"
+rm -rf "$P_NAME"
+
+
diff --git a/resources/views/settings.html.hbs b/resources/views/settings.html.hbs
deleted file mode 100644
index ed546b5..0000000
--- a/resources/views/settings.html.hbs
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
- Settings | P5x
-
-
- Configure P5x
- Current config version: {{#if settings.id}}v{{settings.id}}{{^}}v0{{/if}}
-
-
-
diff --git a/src/api/cluster/carrier.rs b/src/api/cluster/carrier.rs
index b298b1e..d74a3cd 100644
--- a/src/api/cluster/carrier.rs
+++ b/src/api/cluster/carrier.rs
@@ -3,14 +3,16 @@ use uuid::Uuid;
use proxmox_api::nodes::node::lxc;
use proxmox_api::nodes::node::lxc::vmid;
use proxmox_api::types::VmId;
-use sea_orm::{ActiveModelTrait, EntityTrait, Set, TryIntoModel};
+use sea_orm::*;
use crate::api::cluster::node::wait_upid;
use crate::api::entity::locks::lock_vmid;
-use crate::api::entity::nodes;
+use crate::api::entity::{locks, nodes};
use crate::api::entity::nodes::P5xError;
use crate::api::services::{ssh_run_trimmed, Services};
use crate::api::services::SshError;
+
+/** Create an empty Proxmox LXC container that can be used to shuttle a volume between PVE nodes. */
pub async fn provision_carrier(
svc: &Services<'_>,
from_node: &nodes::Model,
@@ -32,8 +34,7 @@ pub async fn provision_carrier(
// Build the new container params
let hostname = format!("carrier-{}", Uuid::new_v4().to_string());
- let storage = svc.setting_req(|s| &s.pve_storage_pool)
- .map_err(P5xError::ServiceError)?;
+ let storage = &svc.config.pve_storage_pool;
let mut params = lxc::PostParams::new("local:vztmpl/p5x-empty.tar.xz".to_string(), vm_id);
params.cores = Some(1);
@@ -41,7 +42,7 @@ pub async fn provision_carrier(
params.hostname = Some(hostname.to_string());
params.memory = Some(16); // in MB, min 16
params.start = Some(false);
- params.storage = Some(storage);
+ params.storage = Some(storage.to_string());
params.tags = Some("p5x".to_string());
// Ask the PVE API to start creating the carrier node based on our empty template
@@ -68,9 +69,23 @@ pub async fn provision_carrier(
.await
.map_err(P5xError::DbErr)?;
- node.try_into_model().map_err(P5xError::DbErr)
+ let node = node.try_into_model().map_err(P5xError::DbErr)?;
+
+ // Create a lock instance for the new node
+ locks::ActiveModel {
+ lock_type: Set("nodes".to_string()),
+ lock_resource: Set(node.id.to_string()),
+ ..Default::default()
+ }
+ .save(svc.db)
+ .await
+ .map_err(P5xError::DbErr)?;
+
+ Ok(node)
}
+
+/** Make sure the tarball LXC template for the carrier container exists on the given node. */
pub async fn ensure_carrier_template(
svc: &Services<'_>,
node: &nodes::Model,
@@ -100,6 +115,8 @@ pub async fn ensure_carrier_template(
Ok(())
}
+
+/** Destroy the given carrier LXC container. */
pub async fn terminate_carrier(
svc: &Services<'_>,
carrier: nodes::Model,
@@ -122,5 +139,12 @@ pub async fn terminate_carrier(
.await
.map_err(P5xError::DbErr)?;
+ locks::Entity::delete_many()
+ .filter(locks::Column::LockType.eq("nodes"))
+ .filter(locks::Column::LockResource.eq(carrier.id.to_string()))
+ .exec(svc.db)
+ .await
+ .map_err(P5xError::DbErr)?;
+
Ok(())
}
diff --git a/src/api/cluster/node.rs b/src/api/cluster/node.rs
index 92c94eb..6a40640 100644
--- a/src/api/cluster/node.rs
+++ b/src/api/cluster/node.rs
@@ -7,6 +7,8 @@ use crate::api::entity::nodes;
use crate::api::entity::nodes::P5xError;
use crate::api::services::Services;
+
+/** Migrate an LXC container from its current PVE node to the given PVE node. */
pub async fn migrate_node(
svc: &Services<'_>,
node: nodes::Model,
@@ -37,6 +39,8 @@ pub async fn migrate_node(
.ok_or(P5xError::BadPostcondition("Could not look up node after persisting"))
}
+
+/** Wait for a PVE task to complete using its UPID */
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)
diff --git a/src/api/cluster/volume.rs b/src/api/cluster/volume.rs
index 9677fe3..c9362d9 100644
--- a/src/api/cluster/volume.rs
+++ b/src/api/cluster/volume.rs
@@ -5,16 +5,20 @@ use proxmox_api::nodes::node::lxc::vmid::config::PutParams;
use proxmox_api::nodes::node::lxc::vmid::move_volume;
use proxmox_api::types::VmId;
use proxmox_api::UreqError;
+use proxmox_api::UreqError::Ureq;
use sea_orm::*;
use sea_orm::ActiveValue::Set;
use serde::{Deserialize, Serialize};
use tokio::time::sleep;
+use ureq::Error::Status;
use crate::api::cluster::carrier::{provision_carrier, terminate_carrier};
use crate::api::cluster::node::migrate_node;
use crate::api::entity::nodes::{lock_first_available, P5xError};
use crate::api::entity::{nodes, volumes};
use crate::api::services::{ssh_run_trimmed, Services};
+
+/** Parameters required from an API call to manage a volume. */
#[derive(Serialize, Deserialize, FromForm)]
pub struct VolumeParams {
pub id: Option,
@@ -25,6 +29,7 @@ pub struct VolumeParams {
}
impl VolumeParams {
+ /** Look up a volume by name and get its params. */
pub async fn resolve(svc: &Services<'_>, name: &str) -> Result