* [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism
@ 2024-11-11 13:14 Christoph Heiss
2024-11-11 13:14 ` [pve-devel] [PATCH installer v4 01/12] debian: strip unused library dependencies Christoph Heiss
` (12 more replies)
0 siblings, 13 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-11 13:14 UTC (permalink / raw)
To: pve-devel
This implements a mechanism for post-installation "notifications" via a
POST request [0] when using the auto-installer.
It's implemented as a separate, small utility to facilitate separation
of concerns and make the information gathering easier by having it
isolated in one place.
Patches #1 through #5 are simply clean-ups, refactors, etc. that were
done along the way and can be applied independently.
Most interesting here will be patch #16, which adds the actual
implementation of the post-hook. (Bind-)mounting the installed host
system is done using the existing `proxmox-chroot` utility, and the HTTP
POST functionality can fortunately be re-used 1:1 from
`proxmox-fetch-answer`.
I've also included an example of how the JSON body (pretty-printed and
reduced some things for readability) of such a post-installation request
would look like below, for reference.
Where applicable (and sensible), I have tried to align the format as
much as possible with 1) the format as used in the `fetch-answer` POST
request and 2) PVE's /nodes/<host>/status API endpoint.
Feedback on the post-hook information schema is of course also very much
appreciated!
It should be noted that some information like DMI is generally very
depended on the motherboard/firmware, on what information is actually
available and filled-in. So the contents are expected to vary wildly
between machines and may also be empty, as in the example below from a
VM.
Tested this with both PVE and PBS ISOs, with BIOS, UEFI w/ and w/o
SecureBoot. PMG did not (yet) have a auto-installation-capable release.
The only really product-specific code is the version detection in
`proxmox-post-hook`, which already handles all three products, so it
should work OOTB too.
[0] https://bugzilla.proxmox.com/show_bug.cgi?id=5536
History
=======
v3: https://lore.proxmox.com/pve-devel/20240821094023.667806-1-c.heiss@proxmox.com/
v2: https://lists.proxmox.com/pipermail/pve-devel/2024-July/064764.html
v1: https://lists.proxmox.com/pipermail/pve-devel/2024-July/064580.html
Notable changes v3 -> v4:
* rebased on latest master
* dropped already applied patches
* use script from proxmox-backup for stripping unneeded dependencies
instead of open-coding
Notable changes v2 -> v3:
* dropped patch #11 "auto-installer: tests: replace manual panic!()
with assert_eq!()"
* split out some preparatory changes into separate patches, based on
Aaron's feedback
* fixed bug in run env serialization w.r.t. secureboot state
Notable changes v1 -> v2:
* dropped already applied patches & rebased on master
* new fields; now includes ISO version, SecureBoot state, CPU and DMI
info
* product information was split into separate fields & expanded
* boot mode information was split into separate fields
* product version is now retrieved from the package using dpkg-query
directly
* kernel version was split into separate fields
* all disks and NICs are now included, a field indicates whether they
are boot disk or management interface, respectively
* some new cleanup/refactoring patches as noted on v1
(thanks Stefan for the in-depth review!)
Post notification example json
==============================
{
"debian-version": "12.5",
"product": {
"fullname": "Proxmox VE",
"short": "pve",
"version": "8.2.2"
},
"iso": {
"release": "8.2",
"isorelease": "1"
},
"kernel-version": {
"sysname": "Linux",
"release": "6.8.4-2-pve",
"version": "#1 SMP PREEMPT_DYNAMIC PMX 6.8.4-2 (2024-04-10T17:36Z)",
"machine": "x86_64"
},
"boot-info": {
"mode": "efi",
"secureboot": true
},
"cpu-info": {
"cores": 4,
"cpus": 4,
"flags": "fpu vme [..]",
"hvm": true,
"model": "AMD Ryzen 7 3700X 8-Core Processor",
"sockets": 1
},
"dmi": {
"system": {
"serial": "",
"sku": "",
"uuid": "b2fd1aa2-dc6e-4d8f-ad67-6dcc31984938",
"name": "Standard PC (Q35 + ICH9, 2009)"
},
"baseboard": {},
"chassis": {
"asset_tag": "",
"serial": ""
}
},
"filesystem": "ext4",
"fqdn": "host.domain",
"machine-id": "b8737afea804482697ffe04db69c73d1",
"disks": [
{
"size": 8589934592,
"is-bootdisk": true,
"udev-properties": {
"DEVNAME": "/dev/vda",
[..]
}
},
{
"size": 8589934592,
"udev-properties": {
"DEVNAME": "/dev/vdb",
[..]
}
}
],
"network-interfaces": [
{
"mac": "de:ad:ff:c2:63:5e",
"address": "10.0.0.27/24",
"is-management": true,
"udev-properties": {
"INTERFACE": "enp6s18",
[..]
}
},
{
"mac": "de:ad:ff:1c:c9:01",
"udev-properties": {
"INTERFACE": "enp6s19",
[..]
}
}
],
"ssh-public-host-keys": {
"ecdsa": "ecdsa-sha2-nistp256 [..] root@host.domain",
"ed25519": "ssh-ed25519 [..] root@host.domain",
"rsa": "ssh-rsa [..] root@host.domain"
}
}
Diffstat
========
Christoph Heiss (12):
debian: strip unused library dependencies
fetch-answer: move http-related code to gated module in
installer-common
tree-wide: convert some more crates to use workspace dependencies
auto-install-assistant: replace `PathBuf` parameters with
`AsRef<Path>`
auto-installer: tests: simplify empty disks check
auto-installer: tests: replace `PathBuf` parameters with `AsRef<Path>`
auto-installer: move `SystemDMI` struct to common crate
auto-installer: answer: factor out answer file reading into function
auto-installer: udevinfo: introduce type alias for udev properties
fix #5536: auto-installer: answer: add `posthook` section
fix #5536: post-hook: add utility for sending notifications after
auto-install
unconfigured.sh: run proxmox-post-hook after successful auto-install
Cargo.toml | 9 +
Makefile | 8 +-
debian/control | 1 +
debian/install | 1 +
debian/rules | 9 +
.../scripts/elf-strip-unused-dependencies.sh | 20 +
proxmox-auto-install-assistant/Cargo.toml | 13 +-
proxmox-auto-install-assistant/src/main.rs | 23 +-
proxmox-auto-installer/Cargo.toml | 14 +-
proxmox-auto-installer/src/answer.rs | 27 +-
.../src/bin/proxmox-auto-installer.rs | 13 +-
proxmox-auto-installer/src/sysinfo.rs | 51 +-
proxmox-auto-installer/src/udevinfo.rs | 8 +-
proxmox-auto-installer/tests/parse-answer.rs | 13 +-
proxmox-chroot/Cargo.toml | 7 +-
proxmox-fetch-answer/Cargo.toml | 15 +-
.../src/fetch_plugins/http.rs | 100 +--
proxmox-installer-common/Cargo.toml | 26 +-
proxmox-installer-common/src/http.rs | 94 +++
proxmox-installer-common/src/lib.rs | 4 +
proxmox-installer-common/src/options.rs | 5 +
proxmox-installer-common/src/setup.rs | 2 +-
proxmox-installer-common/src/sysinfo.rs | 52 ++
proxmox-installer-common/src/utils.rs | 2 +
proxmox-post-hook/Cargo.toml | 18 +
proxmox-post-hook/src/main.rs | 784 ++++++++++++++++++
proxmox-tui-installer/Cargo.toml | 8 +-
unconfigured.sh | 5 +-
28 files changed, 1115 insertions(+), 217 deletions(-)
create mode 100755 debian/scripts/elf-strip-unused-dependencies.sh
create mode 100644 proxmox-installer-common/src/http.rs
create mode 100644 proxmox-installer-common/src/sysinfo.rs
create mode 100644 proxmox-post-hook/Cargo.toml
create mode 100644 proxmox-post-hook/src/main.rs
--
2.45.1
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [pve-devel] [PATCH installer v4 01/12] debian: strip unused library dependencies
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
@ 2024-11-11 13:14 ` Christoph Heiss
2024-11-11 13:14 ` [pve-devel] [PATCH installer v4 02/12] fetch-answer: move http-related code to gated module in installer-common Christoph Heiss
` (11 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-11 13:14 UTC (permalink / raw)
To: pve-devel
Rust links in some dynamic libraries even if only used by a disabled
feature gate.
This will be needed due to moving http-related code into the
proxmox-installer-common crate and thus pulling it in at more places.
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v3 -> v4:
* use/copy script from proxmox-backup
Changes v2 -> v3:
* no changes
Changes v1 -> v2:
* print libraries being stripped from each binary
debian/control | 1 +
debian/rules | 9 +++++++++
.../scripts/elf-strip-unused-dependencies.sh | 20 +++++++++++++++++++
3 files changed, 30 insertions(+)
create mode 100755 debian/scripts/elf-strip-unused-dependencies.sh
diff --git a/debian/control b/debian/control
index 04b0c6e..ff00cc2 100644
--- a/debian/control
+++ b/debian/control
@@ -26,6 +26,7 @@ Build-Depends: cargo:native,
librust-toml-0.8-dev,
librust-ureq-2.10-dev,
libtest-mockmodule-perl,
+ patchelf,
perl,
rustc:native,
shellcheck,
diff --git a/debian/rules b/debian/rules
index 1c03065..8a3f879 100755
--- a/debian/rules
+++ b/debian/rules
@@ -10,3 +10,12 @@ export BUILD_MODE=release
override_dh_missing:
dh_missing --fail-missing
+
+override_dh_strip:
+ dh_strip
+ for exe in $$(find \
+ debian/proxmox-installer \
+ debian/proxmox-auto-install-assistant \
+ -executable -type f); do \
+ debian/scripts/elf-strip-unused-dependencies.sh "$$exe" || true; \
+ done
diff --git a/debian/scripts/elf-strip-unused-dependencies.sh b/debian/scripts/elf-strip-unused-dependencies.sh
new file mode 100755
index 0000000..9f89c09
--- /dev/null
+++ b/debian/scripts/elf-strip-unused-dependencies.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+binary=$1
+
+exec 3< <(ldd -u "$binary" | grep -oP '[^/:]+$')
+
+patchargs=""
+dropped=""
+while read -r dep; do
+ dropped="$dep $dropped"
+ patchargs="--remove-needed $dep $patchargs"
+done <&3
+exec 3<&-
+
+if [[ $dropped == "" ]]; then
+ exit 0
+fi
+
+echo -e "patchelf '$binary' - removing unused dependencies:\n $dropped"
+patchelf $patchargs $binary
--
2.47.0
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [pve-devel] [PATCH installer v4 02/12] fetch-answer: move http-related code to gated module in installer-common
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
2024-11-11 13:14 ` [pve-devel] [PATCH installer v4 01/12] debian: strip unused library dependencies Christoph Heiss
@ 2024-11-11 13:14 ` Christoph Heiss
2024-11-11 13:14 ` [pve-devel] [PATCH installer v4 03/12] tree-wide: convert some more crates to use workspace dependencies Christoph Heiss
` (10 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-11 13:14 UTC (permalink / raw)
To: pve-devel
This enable reusage of this code in other crates. Needed esp. by the
upcoming post-installation notification hook functionality.
No functional changes overall.
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v2 -> v3:
* rebased on latest master
Changes v2 -> v3:
* no changes
Changes v1 -> v2:
* no changes
Cargo.toml | 4 +
proxmox-fetch-answer/Cargo.toml | 15 +--
.../src/fetch_plugins/http.rs | 100 +-----------------
proxmox-installer-common/Cargo.toml | 18 ++++
proxmox-installer-common/src/http.rs | 94 ++++++++++++++++
proxmox-installer-common/src/lib.rs | 3 +
6 files changed, 125 insertions(+), 109 deletions(-)
create mode 100644 proxmox-installer-common/src/http.rs
diff --git a/Cargo.toml b/Cargo.toml
index ec1deaf..e20db33 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,3 +11,7 @@ members = [
[workspace.dependencies]
anyhow = "1.0"
+log = "0.4.20"
+toml = "0.8"
+proxmox-auto-installer.path = "./proxmox-auto-installer"
+proxmox-installer-common.path = "./proxmox-installer-common"
diff --git a/proxmox-fetch-answer/Cargo.toml b/proxmox-fetch-answer/Cargo.toml
index 9149176..50f3da3 100644
--- a/proxmox-fetch-answer/Cargo.toml
+++ b/proxmox-fetch-answer/Cargo.toml
@@ -10,16 +10,9 @@ license = "AGPL-3"
exclude = [ "build", "debian" ]
homepage = "https://www.proxmox.com"
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
[dependencies]
anyhow.workspace = true
-hex = "0.4"
-log = "0.4.20"
-native-tls = "0.2"
-proxmox-auto-installer = { path = "../proxmox-auto-installer" }
-rustls = { version = "0.21", features = [ "dangerous_configuration" ] }
-rustls-native-certs = "0.6"
-sha2 = "0.10"
-toml = "0.8"
-ureq = { version = "2.6", features = [ "native-certs", "native-tls" ] }
+log.workspace = true
+proxmox-auto-installer.workspace = true
+proxmox-installer-common = { workspace = true, features = ["http"] }
+toml.workspace = true
diff --git a/proxmox-fetch-answer/src/fetch_plugins/http.rs b/proxmox-fetch-answer/src/fetch_plugins/http.rs
index 5e10f6a..4317430 100644
--- a/proxmox-fetch-answer/src/fetch_plugins/http.rs
+++ b/proxmox-fetch-answer/src/fetch_plugins/http.rs
@@ -67,7 +67,8 @@ impl FetchFromHTTP {
info!("Gathering system information.");
let payload = SysInfo::as_json()?;
info!("Sending POST request to '{answer_url}'.");
- let answer = http_post::call(&answer_url, fingerprint.as_deref(), payload)?;
+ let answer =
+ proxmox_installer_common::http::post(&answer_url, fingerprint.as_deref(), payload)?;
Ok(answer)
}
@@ -179,100 +180,3 @@ impl FetchFromHTTP {
value.map(|value| String::from(&value[1..value.len() - 2]))
}
}
-
-mod http_post {
- use anyhow::Result;
- use rustls::ClientConfig;
- use sha2::{Digest, Sha256};
- use std::sync::Arc;
- use ureq::{Agent, AgentBuilder};
-
- /// Issues a POST request with the payload (JSON). Optionally a SHA256 fingerprint can be used to
- /// check the cert against it, instead of the regular cert validation.
- /// To gather the sha256 fingerprint you can use the following command:
- /// ```no_compile
- /// openssl s_client -connect <host>:443 < /dev/null 2>/dev/null | openssl x509 -fingerprint -sha256 -noout -in /dev/stdin
- /// ```
- ///
- /// # Arguments
- /// * `url` - URL to call
- /// * `fingerprint` - SHA256 cert fingerprint if certificate pinning should be used. Optional.
- /// * `payload` - The payload to send to the server. Expected to be a JSON formatted string.
- pub fn call(url: &str, fingerprint: Option<&str>, payload: String) -> Result<String> {
- let answer;
-
- if let Some(fingerprint) = fingerprint {
- let tls_config = ClientConfig::builder()
- .with_safe_defaults()
- .with_custom_certificate_verifier(VerifyCertFingerprint::new(fingerprint)?)
- .with_no_client_auth();
-
- let agent: Agent = AgentBuilder::new().tls_config(Arc::new(tls_config)).build();
-
- answer = agent
- .post(url)
- .set("Content-type", "application/json; charset=utf-8")
- .send_string(&payload)?
- .into_string()?;
- } else {
- let mut roots = rustls::RootCertStore::empty();
- for cert in rustls_native_certs::load_native_certs()? {
- roots.add(&rustls::Certificate(cert.0)).unwrap();
- }
-
- let tls_config = rustls::ClientConfig::builder()
- .with_safe_defaults()
- .with_root_certificates(roots)
- .with_no_client_auth();
-
- let agent = AgentBuilder::new()
- .tls_connector(Arc::new(native_tls::TlsConnector::new()?))
- .tls_config(Arc::new(tls_config))
- .build();
- answer = agent
- .post(url)
- .set("Content-type", "application/json; charset=utf-8")
- .timeout(std::time::Duration::from_secs(60))
- .send_string(&payload)?
- .into_string()?;
- }
- Ok(answer)
- }
-
- struct VerifyCertFingerprint {
- cert_fingerprint: Vec<u8>,
- }
-
- impl VerifyCertFingerprint {
- fn new<S: AsRef<str>>(cert_fingerprint: S) -> Result<std::sync::Arc<Self>> {
- let cert_fingerprint = cert_fingerprint.as_ref();
- let sanitized = cert_fingerprint.replace(':', "");
- let decoded = hex::decode(sanitized)?;
- Ok(std::sync::Arc::new(Self {
- cert_fingerprint: decoded,
- }))
- }
- }
-
- impl rustls::client::ServerCertVerifier for VerifyCertFingerprint {
- fn verify_server_cert(
- &self,
- end_entity: &rustls::Certificate,
- _intermediates: &[rustls::Certificate],
- _server_name: &rustls::ServerName,
- _scts: &mut dyn Iterator<Item = &[u8]>,
- _ocsp_response: &[u8],
- _now: std::time::SystemTime,
- ) -> Result<rustls::client::ServerCertVerified, rustls::Error> {
- let mut hasher = Sha256::new();
- hasher.update(end_entity);
- let result = hasher.finalize();
-
- if result.as_slice() == self.cert_fingerprint {
- Ok(rustls::client::ServerCertVerified::assertion())
- } else {
- Err(rustls::Error::General("Fingerprint did not match!".into()))
- }
- }
- }
-}
diff --git a/proxmox-installer-common/Cargo.toml b/proxmox-installer-common/Cargo.toml
index fa99c57..007e6f4 100644
--- a/proxmox-installer-common/Cargo.toml
+++ b/proxmox-installer-common/Cargo.toml
@@ -13,3 +13,21 @@ regex = "1.7"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_plain = "1.0"
+
+# `http` feature
+hex = { version = "0.4", optional = true }
+native-tls = { version = "0.2", optional = true }
+rustls = { version = "0.21", features = [ "dangerous_configuration" ], optional = true }
+rustls-native-certs = { version = "0.6", optional = true }
+sha2 = { version = "0.10", optional = true }
+ureq = { version = "2.6", features = [ "native-certs", "native-tls" ], optional = true }
+
+[features]
+http = [
+ "dep:hex",
+ "dep:native-tls",
+ "dep:rustls",
+ "dep:rustls-native-certs",
+ "dep:sha2",
+ "dep:ureq"
+]
diff --git a/proxmox-installer-common/src/http.rs b/proxmox-installer-common/src/http.rs
new file mode 100644
index 0000000..b754ed8
--- /dev/null
+++ b/proxmox-installer-common/src/http.rs
@@ -0,0 +1,94 @@
+use anyhow::Result;
+use rustls::ClientConfig;
+use sha2::{Digest, Sha256};
+use std::sync::Arc;
+use ureq::{Agent, AgentBuilder};
+
+/// Issues a POST request with the payload (JSON). Optionally a SHA256 fingerprint can be used to
+/// check the cert against it, instead of the regular cert validation.
+/// To gather the sha256 fingerprint you can use the following command:
+/// ```no_compile
+/// openssl s_client -connect <host>:443 < /dev/null 2>/dev/null | openssl x509 -fingerprint -sha256 -noout -in /dev/stdin
+/// ```
+///
+/// # Arguments
+/// * `url` - URL to call
+/// * `fingerprint` - SHA256 cert fingerprint if certificate pinning should be used. Optional.
+/// * `payload` - The payload to send to the server. Expected to be a JSON formatted string.
+pub fn post(url: &str, fingerprint: Option<&str>, payload: String) -> Result<String> {
+ let answer;
+
+ if let Some(fingerprint) = fingerprint {
+ let tls_config = ClientConfig::builder()
+ .with_safe_defaults()
+ .with_custom_certificate_verifier(VerifyCertFingerprint::new(fingerprint)?)
+ .with_no_client_auth();
+
+ let agent: Agent = AgentBuilder::new().tls_config(Arc::new(tls_config)).build();
+
+ answer = agent
+ .post(url)
+ .set("Content-Type", "application/json; charset=utf-8")
+ .send_string(&payload)?
+ .into_string()?;
+ } else {
+ let mut roots = rustls::RootCertStore::empty();
+ for cert in rustls_native_certs::load_native_certs()? {
+ roots.add(&rustls::Certificate(cert.0)).unwrap();
+ }
+
+ let tls_config = rustls::ClientConfig::builder()
+ .with_safe_defaults()
+ .with_root_certificates(roots)
+ .with_no_client_auth();
+
+ let agent = AgentBuilder::new()
+ .tls_connector(Arc::new(native_tls::TlsConnector::new()?))
+ .tls_config(Arc::new(tls_config))
+ .build();
+ answer = agent
+ .post(url)
+ .set("Content-Type", "application/json; charset=utf-8")
+ .timeout(std::time::Duration::from_secs(60))
+ .send_string(&payload)?
+ .into_string()?;
+ }
+ Ok(answer)
+}
+
+struct VerifyCertFingerprint {
+ cert_fingerprint: Vec<u8>,
+}
+
+impl VerifyCertFingerprint {
+ fn new<S: AsRef<str>>(cert_fingerprint: S) -> Result<std::sync::Arc<Self>> {
+ let cert_fingerprint = cert_fingerprint.as_ref();
+ let sanitized = cert_fingerprint.replace(':', "");
+ let decoded = hex::decode(sanitized)?;
+ Ok(std::sync::Arc::new(Self {
+ cert_fingerprint: decoded,
+ }))
+ }
+}
+
+impl rustls::client::ServerCertVerifier for VerifyCertFingerprint {
+ fn verify_server_cert(
+ &self,
+ end_entity: &rustls::Certificate,
+ _intermediates: &[rustls::Certificate],
+ _server_name: &rustls::ServerName,
+ _scts: &mut dyn Iterator<Item = &[u8]>,
+ _ocsp_response: &[u8],
+ _now: std::time::SystemTime,
+ ) -> Result<rustls::client::ServerCertVerified, rustls::Error> {
+ let mut hasher = Sha256::new();
+ hasher.update(end_entity);
+ let result = hasher.finalize();
+
+ if result.as_slice() == self.cert_fingerprint {
+ Ok(rustls::client::ServerCertVerified::assertion())
+ } else {
+ Err(rustls::Error::General("Fingerprint did not match!".into()))
+ }
+ }
+}
diff --git a/proxmox-installer-common/src/lib.rs b/proxmox-installer-common/src/lib.rs
index 028b43c..85fc399 100644
--- a/proxmox-installer-common/src/lib.rs
+++ b/proxmox-installer-common/src/lib.rs
@@ -3,6 +3,9 @@ pub mod options;
pub mod setup;
pub mod utils;
+#[cfg(feature = "http")]
+pub mod http;
+
pub const RUNTIME_DIR: &str = "/run/proxmox-installer";
/// Default placeholder value for the administrator email address.
--
2.47.0
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [pve-devel] [PATCH installer v4 03/12] tree-wide: convert some more crates to use workspace dependencies
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
2024-11-11 13:14 ` [pve-devel] [PATCH installer v4 01/12] debian: strip unused library dependencies Christoph Heiss
2024-11-11 13:14 ` [pve-devel] [PATCH installer v4 02/12] fetch-answer: move http-related code to gated module in installer-common Christoph Heiss
@ 2024-11-11 13:14 ` Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 04/12] auto-install-assistant: replace `PathBuf` parameters with `AsRef<Path>` Christoph Heiss
` (9 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-11 13:14 UTC (permalink / raw)
To: pve-devel
No functional changes.
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v3 -> v4:
* no changes
Changes v2 -> v3:
* no changes
Changes v1 -> v2:
* no changes
Cargo.toml | 4 ++++
proxmox-auto-install-assistant/Cargo.toml | 13 +++++++------
proxmox-auto-installer/Cargo.toml | 14 +++++++-------
proxmox-chroot/Cargo.toml | 7 ++++---
proxmox-installer-common/Cargo.toml | 8 ++++----
proxmox-tui-installer/Cargo.toml | 8 +++++---
6 files changed, 31 insertions(+), 23 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index e20db33..a27df88 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,6 +12,10 @@ members = [
[workspace.dependencies]
anyhow = "1.0"
log = "0.4.20"
+regex = "1.7"
+serde = "1.0"
+serde_json = "1.0"
+serde_plain = "1.0"
toml = "0.8"
proxmox-auto-installer.path = "./proxmox-auto-installer"
proxmox-installer-common.path = "./proxmox-installer-common"
diff --git a/proxmox-auto-install-assistant/Cargo.toml b/proxmox-auto-install-assistant/Cargo.toml
index ab70d39..c4486f8 100644
--- a/proxmox-auto-install-assistant/Cargo.toml
+++ b/proxmox-auto-install-assistant/Cargo.toml
@@ -12,11 +12,12 @@ homepage = "https://www.proxmox.com"
[dependencies]
anyhow.workspace = true
+log.workspace = true
+proxmox-auto-installer.workspace = true
+serde = { workspace = true, features = ["derive"] }
+serde_json.workspace = true
+toml.workspace = true
+regex.workspace = true
+
clap = { version = "4.0", features = ["derive"] }
glob = "0.3"
-log = "0.4.20"
-proxmox-auto-installer = { path = "../proxmox-auto-installer" }
-regex = "1.7"
-serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
-toml = "0.8"
diff --git a/proxmox-auto-installer/Cargo.toml b/proxmox-auto-installer/Cargo.toml
index 0353d6a..21ed538 100644
--- a/proxmox-auto-installer/Cargo.toml
+++ b/proxmox-auto-installer/Cargo.toml
@@ -12,12 +12,12 @@ homepage = "https://www.proxmox.com"
[dependencies]
anyhow.workspace = true
+log.workspace = true
+proxmox-installer-common.workspace = true
+serde = { workspace = true, features = ["derive"] }
+serde_json.workspace = true
+serde_plain.workspace = true
+toml.workspace = true
+
clap = { version = "4.0", features = ["derive"] }
glob = "0.3"
-log = "0.4.20"
-proxmox-installer-common = { path = "../proxmox-installer-common" }
-regex = "1.7"
-serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
-serde_plain = "1.0"
-toml = "0.8"
diff --git a/proxmox-chroot/Cargo.toml b/proxmox-chroot/Cargo.toml
index 6247baa..4a27bf7 100644
--- a/proxmox-chroot/Cargo.toml
+++ b/proxmox-chroot/Cargo.toml
@@ -9,8 +9,9 @@ homepage = "https://www.proxmox.com"
[dependencies]
anyhow.workspace = true
+proxmox-installer-common.workspace = true
+serde_json.workspace = true
+regex.workspace = true
+
clap = { version = "4.0", features = ["derive"] }
nix = "0.26.1"
-proxmox-installer-common = { path = "../proxmox-installer-common" }
-regex = "1.7"
-serde_json = "1.0"
diff --git a/proxmox-installer-common/Cargo.toml b/proxmox-installer-common/Cargo.toml
index 007e6f4..ef7a614 100644
--- a/proxmox-installer-common/Cargo.toml
+++ b/proxmox-installer-common/Cargo.toml
@@ -9,10 +9,10 @@ homepage = "https://www.proxmox.com"
[dependencies]
anyhow.workspace = true
-regex = "1.7"
-serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
-serde_plain = "1.0"
+regex.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+serde_plain.workspace = true
# `http` feature
hex = { version = "0.4", optional = true }
diff --git a/proxmox-tui-installer/Cargo.toml b/proxmox-tui-installer/Cargo.toml
index 618904c..c7a0e30 100644
--- a/proxmox-tui-installer/Cargo.toml
+++ b/proxmox-tui-installer/Cargo.toml
@@ -8,7 +8,9 @@ exclude = [ "build", "debian" ]
homepage = "https://www.proxmox.com"
[dependencies]
+proxmox-installer-common.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+regex.workspace = true
+
cursive = { version = "0.21", default-features = false, features = ["crossterm-backend"] }
-serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
-proxmox-installer-common = { path = "../proxmox-installer-common" }
--
2.47.0
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [pve-devel] [PATCH installer v4 04/12] auto-install-assistant: replace `PathBuf` parameters with `AsRef<Path>`
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
` (2 preceding siblings ...)
2024-11-11 13:14 ` [pve-devel] [PATCH installer v4 03/12] tree-wide: convert some more crates to use workspace dependencies Christoph Heiss
@ 2024-11-11 13:15 ` Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 05/12] auto-installer: tests: simplify empty disks check Christoph Heiss
` (8 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-11 13:15 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v3 -> v4:
* no changes
Changes v2 -> v3:
* no changes
Changes v1 -> v2:
* new patch, suggestion by Stefan
proxmox-auto-install-assistant/src/main.rs | 23 +++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/proxmox-auto-install-assistant/src/main.rs b/proxmox-auto-install-assistant/src/main.rs
index 7b8d3ba..746ad84 100644
--- a/proxmox-auto-install-assistant/src/main.rs
+++ b/proxmox-auto-install-assistant/src/main.rs
@@ -5,7 +5,7 @@ use regex::Regex;
use serde::Serialize;
use std::{
collections::BTreeMap,
- fs,
+ fmt, fs,
io::{self, Read},
path::{Path, PathBuf},
process::{Command, Stdio},
@@ -387,7 +387,12 @@ fn final_iso_location(args: &CommandPrepareISO) -> PathBuf {
target.to_path_buf()
}
-fn inject_file_to_iso(iso: &PathBuf, file: &PathBuf, location: &str, uuid: &String) -> Result<()> {
+fn inject_file_to_iso(
+ iso: impl AsRef<Path> + fmt::Debug,
+ file: &PathBuf,
+ location: &str,
+ uuid: &String,
+) -> Result<()> {
let result = Command::new("xorriso")
.arg("-boot_image")
.arg("any")
@@ -396,7 +401,7 @@ fn inject_file_to_iso(iso: &PathBuf, file: &PathBuf, location: &str, uuid: &Stri
.arg("uuid")
.arg(uuid)
.arg("-dev")
- .arg(iso)
+ .arg(iso.as_ref())
.arg("-map")
.arg(file)
.arg(location)
@@ -410,10 +415,10 @@ fn inject_file_to_iso(iso: &PathBuf, file: &PathBuf, location: &str, uuid: &Stri
Ok(())
}
-fn get_iso_uuid(iso: &PathBuf) -> Result<String> {
+fn get_iso_uuid(iso: impl AsRef<Path>) -> Result<String> {
let result = Command::new("xorriso")
.arg("-dev")
- .arg(iso)
+ .arg(iso.as_ref())
.arg("-report_system_area")
.arg("cmd")
.output()?;
@@ -540,11 +545,11 @@ fn get_nics() -> Result<BTreeMap<String, BTreeMap<String, String>>> {
Ok(nics)
}
-fn get_udev_properties(path: &PathBuf) -> Result<String> {
+fn get_udev_properties(path: impl AsRef<Path> + fmt::Debug) -> Result<String> {
let udev_output = Command::new("udevadm")
.arg("info")
.arg("--path")
- .arg(path)
+ .arg(path.as_ref())
.arg("--query")
.arg("all")
.output()?;
@@ -554,8 +559,8 @@ fn get_udev_properties(path: &PathBuf) -> Result<String> {
Ok(String::from_utf8(udev_output.stdout)?)
}
-fn parse_answer(path: &PathBuf) -> Result<Answer> {
- let mut file = match fs::File::open(path) {
+fn parse_answer(path: impl AsRef<Path> + fmt::Debug) -> Result<Answer> {
+ let mut file = match fs::File::open(&path) {
Ok(file) => file,
Err(err) => bail!("Opening answer file {path:?} failed: {err}"),
};
--
2.47.0
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [pve-devel] [PATCH installer v4 05/12] auto-installer: tests: simplify empty disks check
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
` (3 preceding siblings ...)
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 04/12] auto-install-assistant: replace `PathBuf` parameters with `AsRef<Path>` Christoph Heiss
@ 2024-11-11 13:15 ` Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 06/12] auto-installer: tests: replace `PathBuf` parameters with `AsRef<Path>` Christoph Heiss
` (7 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-11 13:15 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v3 -> v4:
* no changes
Changes v2 -> v3:
* no changes
Changes v1 -> v2:
* new patch, suggestion by Stefan
proxmox-auto-installer/tests/parse-answer.rs | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/proxmox-auto-installer/tests/parse-answer.rs b/proxmox-auto-installer/tests/parse-answer.rs
index 450915a..72bddaa 100644
--- a/proxmox-auto-installer/tests/parse-answer.rs
+++ b/proxmox-auto-installer/tests/parse-answer.rs
@@ -40,9 +40,7 @@ pub fn setup_test_basic(path: &Path) -> (SetupInfo, LocaleInfo, RuntimeInfo, Ude
};
runtime_info.disks.sort();
- if runtime_info.disks.is_empty() {
- panic!("disk list is empty!");
- }
+ assert!(!runtime_info.disks.is_empty(), "disk list cannot be empty");
(installer_info, locale_info, runtime_info, udev_info)
}
--
2.47.0
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [pve-devel] [PATCH installer v4 06/12] auto-installer: tests: replace `PathBuf` parameters with `AsRef<Path>`
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
` (4 preceding siblings ...)
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 05/12] auto-installer: tests: simplify empty disks check Christoph Heiss
@ 2024-11-11 13:15 ` Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 07/12] auto-installer: move `SystemDMI` struct to common crate Christoph Heiss
` (6 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-11 13:15 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v3 -> v4:
* no changes
Changes v2 -> v3:
* no changes
Changes v1 -> v2:
* new patch, suggestion by Stefan
proxmox-auto-installer/tests/parse-answer.rs | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/proxmox-auto-installer/tests/parse-answer.rs b/proxmox-auto-installer/tests/parse-answer.rs
index 72bddaa..0e5d6e7 100644
--- a/proxmox-auto-installer/tests/parse-answer.rs
+++ b/proxmox-auto-installer/tests/parse-answer.rs
@@ -18,7 +18,7 @@ fn get_test_resource_path() -> Result<PathBuf, String> {
.join("tests/resources"))
}
-fn get_answer(path: PathBuf) -> Result<Answer, String> {
+fn get_answer(path: impl AsRef<Path>) -> Result<Answer, String> {
let answer_raw = std::fs::read_to_string(path).unwrap();
let answer: answer::Answer = toml::from_str(&answer_raw)
.map_err(|err| format!("error parsing answer.toml: {err}"))
@@ -27,11 +27,12 @@ fn get_answer(path: PathBuf) -> Result<Answer, String> {
Ok(answer)
}
-pub fn setup_test_basic(path: &Path) -> (SetupInfo, LocaleInfo, RuntimeInfo, UdevInfo) {
- let (installer_info, locale_info, mut runtime_info) = load_installer_setup_files(path).unwrap();
+pub fn setup_test_basic(path: impl AsRef<Path>) -> (SetupInfo, LocaleInfo, RuntimeInfo, UdevInfo) {
+ let (installer_info, locale_info, mut runtime_info) =
+ load_installer_setup_files(&path).unwrap();
let udev_info: UdevInfo = {
- let mut path = path.to_path_buf();
+ let mut path = path.as_ref().to_path_buf();
path.push("run-env-udev.json");
read_json(&path)
--
2.47.0
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [pve-devel] [PATCH installer v4 07/12] auto-installer: move `SystemDMI` struct to common crate
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
` (5 preceding siblings ...)
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 06/12] auto-installer: tests: replace `PathBuf` parameters with `AsRef<Path>` Christoph Heiss
@ 2024-11-11 13:15 ` Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 08/12] auto-installer: answer: factor out answer file reading into function Christoph Heiss
` (5 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-11 13:15 UTC (permalink / raw)
To: pve-devel
This functionality will be reused by the post-hook, which sends this
data as part of its information set.
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v3 -> v4:
* no changes
Changes v2 -> v3:
* no changes
Changes v1 -> v2:
* new patch
proxmox-auto-installer/src/sysinfo.rs | 51 +-----------------------
proxmox-installer-common/src/lib.rs | 1 +
proxmox-installer-common/src/sysinfo.rs | 52 +++++++++++++++++++++++++
3 files changed, 55 insertions(+), 49 deletions(-)
create mode 100644 proxmox-installer-common/src/sysinfo.rs
diff --git a/proxmox-auto-installer/src/sysinfo.rs b/proxmox-auto-installer/src/sysinfo.rs
index 112e898..0a6aaf2 100644
--- a/proxmox-auto-installer/src/sysinfo.rs
+++ b/proxmox-auto-installer/src/sysinfo.rs
@@ -1,15 +1,14 @@
use anyhow::{bail, Result};
use proxmox_installer_common::{
setup::{IsoInfo, ProductConfig, SetupInfo},
+ sysinfo::SystemDMI,
RUNTIME_DIR,
};
use serde::Serialize;
-use std::{collections::HashMap, fs, io, path::PathBuf};
+use std::{fs, io, path::PathBuf};
use crate::utils::get_nic_list;
-const DMI_PATH: &str = "/sys/devices/virtual/dmi/id";
-
#[derive(Debug, Serialize)]
pub struct SysInfo {
product: ProductConfig,
@@ -70,49 +69,3 @@ impl NetdevWithMac {
Ok(result)
}
}
-
-#[derive(Debug, Serialize)]
-struct SystemDMI {
- system: HashMap<String, String>,
- baseboard: HashMap<String, String>,
- chassis: HashMap<String, String>,
-}
-
-impl SystemDMI {
- pub(crate) fn get() -> Result<Self> {
- let system_files = [
- "product_serial",
- "product_sku",
- "product_uuid",
- "product_name",
- ];
- let baseboard_files = ["board_asset_tag", "board_serial", "board_name"];
- let chassis_files = ["chassis_serial", "chassis_sku", "chassis_asset_tag"];
-
- Ok(Self {
- system: Self::get_dmi_infos(&system_files)?,
- baseboard: Self::get_dmi_infos(&baseboard_files)?,
- chassis: Self::get_dmi_infos(&chassis_files)?,
- })
- }
-
- fn get_dmi_infos(files: &[&str]) -> Result<HashMap<String, String>> {
- let mut res: HashMap<String, String> = HashMap::new();
-
- for file in files {
- let path = format!("{DMI_PATH}/{file}");
- let content = match fs::read_to_string(&path) {
- Err(ref err) if err.kind() == std::io::ErrorKind::NotFound => continue,
- Err(ref err) if err.kind() == std::io::ErrorKind::PermissionDenied => {
- bail!("Could not read data. Are you running as root or with sudo?")
- }
- Err(err) => bail!("Error: '{err}' on '{path}'"),
- Ok(content) => content.trim().into(),
- };
- let key = file.splitn(2, '_').last().unwrap();
- res.insert(key.into(), content);
- }
-
- Ok(res)
- }
-}
diff --git a/proxmox-installer-common/src/lib.rs b/proxmox-installer-common/src/lib.rs
index 85fc399..10b5940 100644
--- a/proxmox-installer-common/src/lib.rs
+++ b/proxmox-installer-common/src/lib.rs
@@ -1,6 +1,7 @@
pub mod disk_checks;
pub mod options;
pub mod setup;
+pub mod sysinfo;
pub mod utils;
#[cfg(feature = "http")]
diff --git a/proxmox-installer-common/src/sysinfo.rs b/proxmox-installer-common/src/sysinfo.rs
new file mode 100644
index 0000000..9746cb2
--- /dev/null
+++ b/proxmox-installer-common/src/sysinfo.rs
@@ -0,0 +1,52 @@
+use std::{collections::HashMap, fs};
+
+use anyhow::{bail, Result};
+use serde::Serialize;
+
+const DMI_PATH: &str = "/sys/devices/virtual/dmi/id";
+
+#[derive(Debug, Serialize)]
+pub struct SystemDMI {
+ system: HashMap<String, String>,
+ baseboard: HashMap<String, String>,
+ chassis: HashMap<String, String>,
+}
+
+impl SystemDMI {
+ pub fn get() -> Result<Self> {
+ let system_files = [
+ "product_serial",
+ "product_sku",
+ "product_uuid",
+ "product_name",
+ ];
+ let baseboard_files = ["board_asset_tag", "board_serial", "board_name"];
+ let chassis_files = ["chassis_serial", "chassis_sku", "chassis_asset_tag"];
+
+ Ok(Self {
+ system: Self::get_dmi_infos(&system_files)?,
+ baseboard: Self::get_dmi_infos(&baseboard_files)?,
+ chassis: Self::get_dmi_infos(&chassis_files)?,
+ })
+ }
+
+ fn get_dmi_infos(files: &[&str]) -> Result<HashMap<String, String>> {
+ let mut res: HashMap<String, String> = HashMap::new();
+
+ for file in files {
+ let path = format!("{DMI_PATH}/{file}");
+ let content = match fs::read_to_string(&path) {
+ Err(ref err) if err.kind() == std::io::ErrorKind::NotFound => continue,
+ Err(ref err) if err.kind() == std::io::ErrorKind::PermissionDenied => {
+ bail!("Could not read data. Are you running as root or with sudo?")
+ }
+ Err(err) => bail!("Error: '{err}' on '{path}'"),
+ Ok(content) => content.trim().into(),
+ };
+ let key = file.splitn(2, '_').last().unwrap();
+ res.insert(key.into(), content);
+ }
+
+ Ok(res)
+ }
+}
--
2.47.0
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [pve-devel] [PATCH installer v4 08/12] auto-installer: answer: factor out answer file reading into function
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
` (6 preceding siblings ...)
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 07/12] auto-installer: move `SystemDMI` struct to common crate Christoph Heiss
@ 2024-11-11 13:15 ` Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 09/12] auto-installer: udevinfo: introduce type alias for udev properties Christoph Heiss
` (4 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-11 13:15 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v3 -> v4:
* no changes
Changes v2 -> v3:
* new patch, split out from later patch
proxmox-auto-installer/src/answer.rs | 16 +++++++++++++++-
.../src/bin/proxmox-auto-installer.rs | 11 +----------
2 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/proxmox-auto-installer/src/answer.rs b/proxmox-auto-installer/src/answer.rs
index fd0ed0d..8a4f9ef 100644
--- a/proxmox-auto-installer/src/answer.rs
+++ b/proxmox-auto-installer/src/answer.rs
@@ -1,3 +1,4 @@
+use anyhow::{format_err, Result};
use clap::ValueEnum;
use proxmox_installer_common::{
options::{
@@ -7,7 +8,7 @@ use proxmox_installer_common::{
utils::{CidrAddress, Fqdn},
};
use serde::{Deserialize, Serialize};
-use std::{collections::BTreeMap, net::IpAddr};
+use std::{collections::BTreeMap, io::BufRead, net::IpAddr};
// BTreeMap is used to store filters as the order of the filters will be stable, compared to
// storing them in a HashMap
@@ -21,6 +22,19 @@ pub struct Answer {
pub disks: Disks,
}
+impl Answer {
+ pub fn try_from_reader(reader: impl BufRead) -> Result<Self> {
+ let mut buffer = String::new();
+ let lines = reader.lines();
+ for line in lines {
+ buffer.push_str(&line.unwrap());
+ buffer.push('\n');
+ }
+
+ toml::from_str(&buffer).map_err(|err| format_err!("Failed parsing answer file: {err}"))
+ }
+}
+
#[derive(Clone, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Global {
diff --git a/proxmox-auto-installer/src/bin/proxmox-auto-installer.rs b/proxmox-auto-installer/src/bin/proxmox-auto-installer.rs
index f2197a8..1da6e79 100644
--- a/proxmox-auto-installer/src/bin/proxmox-auto-installer.rs
+++ b/proxmox-auto-installer/src/bin/proxmox-auto-installer.rs
@@ -42,16 +42,7 @@ fn auto_installer_setup(in_test_mode: bool) -> Result<(Answer, UdevInfo)> {
.map_err(|err| format_err!("Failed to retrieve udev info details: {err}"))?
};
- let mut buffer = String::new();
- let lines = std::io::stdin().lock().lines();
- for line in lines {
- buffer.push_str(&line.unwrap());
- buffer.push('\n');
- }
-
- let answer: Answer =
- toml::from_str(&buffer).map_err(|err| format_err!("Failed parsing answer file: {err}"))?;
-
+ let answer = Answer::try_from_reader(std::io::stdin().lock())?;
Ok((answer, udev_info))
}
--
2.47.0
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [pve-devel] [PATCH installer v4 09/12] auto-installer: udevinfo: introduce type alias for udev properties
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
` (7 preceding siblings ...)
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 08/12] auto-installer: answer: factor out answer file reading into function Christoph Heiss
@ 2024-11-11 13:15 ` Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 10/12] fix #5536: auto-installer: answer: add `posthook` section Christoph Heiss
` (3 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-11 13:15 UTC (permalink / raw)
To: pve-devel
Makes handling & passing them around a bit more convenient. Will be used
in the upcoming proxmox-post-hook utility.
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v3 -> v4:
* no changes
Changes v2 -> v3:
* new patch, split out from later patch
proxmox-auto-installer/src/udevinfo.rs | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/proxmox-auto-installer/src/udevinfo.rs b/proxmox-auto-installer/src/udevinfo.rs
index a6b61b5..677f3f6 100644
--- a/proxmox-auto-installer/src/udevinfo.rs
+++ b/proxmox-auto-installer/src/udevinfo.rs
@@ -1,9 +1,11 @@
use serde::Deserialize;
use std::collections::BTreeMap;
+/// Uses a BTreeMap to have the keys sorted
+pub type UdevProperties = BTreeMap<String, String>;
+
#[derive(Clone, Deserialize, Debug)]
pub struct UdevInfo {
- // use BTreeMap to have keys sorted
- pub disks: BTreeMap<String, BTreeMap<String, String>>,
- pub nics: BTreeMap<String, BTreeMap<String, String>>,
+ pub disks: BTreeMap<String, UdevProperties>,
+ pub nics: BTreeMap<String, UdevProperties>,
}
--
2.47.0
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [pve-devel] [PATCH installer v4 10/12] fix #5536: auto-installer: answer: add `posthook` section
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
` (8 preceding siblings ...)
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 09/12] auto-installer: udevinfo: introduce type alias for udev properties Christoph Heiss
@ 2024-11-11 13:15 ` Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 11/12] fix #5536: post-hook: add utility for sending notifications after auto-install Christoph Heiss
` (2 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-11 13:15 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v3 -> v4:
* no changes
Changes v2 -> v3:
* no changes
Changes v1 -> v2:
* no changes
proxmox-auto-installer/src/answer.rs | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/proxmox-auto-installer/src/answer.rs b/proxmox-auto-installer/src/answer.rs
index 8a4f9ef..c23f1f3 100644
--- a/proxmox-auto-installer/src/answer.rs
+++ b/proxmox-auto-installer/src/answer.rs
@@ -20,6 +20,8 @@ pub struct Answer {
pub network: Network,
#[serde(rename = "disk-setup")]
pub disks: Disks,
+ #[serde(default)]
+ pub posthook: Option<PostNotificationHookInfo>,
}
impl Answer {
@@ -51,6 +53,15 @@ pub struct Global {
pub root_ssh_keys: Vec<String>,
}
+#[derive(Clone, Deserialize, Debug)]
+#[serde(deny_unknown_fields)]
+pub struct PostNotificationHookInfo {
+ /// URL to send a POST request to
+ pub url: String,
+ /// SHA256 cert fingerprint if certificate pinning should be used.
+ pub cert_fingerprint: Option<String>,
+}
+
#[derive(Clone, Deserialize, Debug, Default, PartialEq)]
#[serde(deny_unknown_fields)]
enum NetworkConfigMode {
--
2.47.0
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [pve-devel] [PATCH installer v4 11/12] fix #5536: post-hook: add utility for sending notifications after auto-install
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
` (9 preceding siblings ...)
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 10/12] fix #5536: auto-installer: answer: add `posthook` section Christoph Heiss
@ 2024-11-11 13:15 ` Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 12/12] unconfigured.sh: run proxmox-post-hook after successful auto-install Christoph Heiss
2024-11-11 17:41 ` [pve-devel] applied: [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Thomas Lamprecht
12 siblings, 0 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-11 13:15 UTC (permalink / raw)
To: pve-devel
This utility can be called with the low-level install config after a
successful installation to send a notification via a HTTP POST request,
if the user has configured an endpoint for that in the answer file.
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v3 -> v4:
* no changes
Changes v2 -> v3:
* split out two prepratory changes into separate changes
* fix outdated doc-comment for `struct DiskInfo`
* align continuation dots with rest of messages
Changes v1 -> v2:
* squash implementation and unit tests into one patch
* simplify udev property retrieving by introducing proper helpers on
`UdevInfo` itself
* rename Answer::from_reader() -> Answer::try_from_reader to better
reflect it returns a Result<>
* improved error message in some places
* added new fields; now includes ISO version, SecureBoot state, CPU
and DMI info
* product information was split into separate fields
* boot mode information was split into separate fields
* product version is now retrieved from the package using dpkg-query
directly
* kernel version was split into separate fields, retrieving version
string from the image directly
* all disks and NICs are now included, a field indicates whether they
are boot disk or management interface, respectively
* move with_chroot() invocation out of PostHookInfo::gather()
Cargo.toml | 1 +
Makefile | 8 +-
debian/install | 1 +
.../src/bin/proxmox-auto-installer.rs | 2 -
proxmox-installer-common/src/options.rs | 5 +
proxmox-installer-common/src/setup.rs | 2 +-
proxmox-installer-common/src/utils.rs | 2 +
proxmox-post-hook/Cargo.toml | 18 +
proxmox-post-hook/src/main.rs | 784 ++++++++++++++++++
9 files changed, 818 insertions(+), 5 deletions(-)
create mode 100644 proxmox-post-hook/Cargo.toml
create mode 100644 proxmox-post-hook/src/main.rs
diff --git a/Cargo.toml b/Cargo.toml
index a27df88..8385d58 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,7 @@ members = [
"proxmox-fetch-answer",
"proxmox-installer-common",
"proxmox-tui-installer",
+ "proxmox-post-hook",
]
[workspace.dependencies]
diff --git a/Makefile b/Makefile
index d80fc63..d85347f 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,8 @@ USR_BIN := \
proxmox-tui-installer\
proxmox-fetch-answer\
proxmox-auto-install-assistant \
- proxmox-auto-installer
+ proxmox-auto-installer \
+ proxmox-post-hook
COMPILED_BINS := \
$(addprefix $(CARGO_COMPILEDIR)/,$(USR_BIN))
@@ -59,6 +60,7 @@ $(BUILDDIR):
proxmox-chroot \
proxmox-tui-installer/ \
proxmox-installer-common/ \
+ proxmox-post-hook \
test/ \
$(SHELL_SCRIPTS) \
$@.tmp
@@ -132,7 +134,9 @@ cargo-build:
--package proxmox-auto-installer --bin proxmox-auto-installer \
--package proxmox-fetch-answer --bin proxmox-fetch-answer \
--package proxmox-auto-install-assistant --bin proxmox-auto-install-assistant \
- --package proxmox-chroot --bin proxmox-chroot $(CARGO_BUILD_ARGS)
+ --package proxmox-chroot --bin proxmox-chroot \
+ --package proxmox-post-hook --bin proxmox-post-hook \
+ $(CARGO_BUILD_ARGS)
%-banner.png: %-banner.svg
rsvg-convert -o $@ $<
diff --git a/debian/install b/debian/install
index bb91da7..b64c8ec 100644
--- a/debian/install
+++ b/debian/install
@@ -15,4 +15,5 @@ usr/bin/proxmox-chroot
usr/bin/proxmox-fetch-answer
usr/bin/proxmox-low-level-installer
usr/bin/proxmox-tui-installer
+usr/bin/proxmox-post-hook
var
diff --git a/proxmox-auto-installer/src/bin/proxmox-auto-installer.rs b/proxmox-auto-installer/src/bin/proxmox-auto-installer.rs
index 1da6e79..ea45c29 100644
--- a/proxmox-auto-installer/src/bin/proxmox-auto-installer.rs
+++ b/proxmox-auto-installer/src/bin/proxmox-auto-installer.rs
@@ -82,8 +82,6 @@ fn main() -> ExitCode {
}
}
- // TODO: (optionally) do a HTTP post with basic system info, like host SSH public key(s) here
-
ExitCode::SUCCESS
}
diff --git a/proxmox-installer-common/src/options.rs b/proxmox-installer-common/src/options.rs
index de5d578..8b6c281 100644
--- a/proxmox-installer-common/src/options.rs
+++ b/proxmox-installer-common/src/options.rs
@@ -49,6 +49,11 @@ impl FsType {
pub fn is_btrfs(&self) -> bool {
matches!(self, FsType::Btrfs(_))
}
+
+ /// Returns true if the filesystem is used on top of LVM, e.g. ext4 or XFS.
+ pub fn is_lvm(&self) -> bool {
+ matches!(self, FsType::Ext4 | FsType::Xfs)
+ }
}
impl fmt::Display for FsType {
diff --git a/proxmox-installer-common/src/setup.rs b/proxmox-installer-common/src/setup.rs
index d203e78..cd1e8b4 100644
--- a/proxmox-installer-common/src/setup.rs
+++ b/proxmox-installer-common/src/setup.rs
@@ -363,7 +363,7 @@ pub struct RuntimeInfo {
pub secure_boot: Option<bool>,
}
-#[derive(Copy, Clone, Eq, Deserialize, PartialEq)]
+#[derive(Copy, Clone, Eq, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum BootType {
Bios,
diff --git a/proxmox-installer-common/src/utils.rs b/proxmox-installer-common/src/utils.rs
index 57b1753..2579c80 100644
--- a/proxmox-installer-common/src/utils.rs
+++ b/proxmox-installer-common/src/utils.rs
@@ -114,6 +114,8 @@ impl<'de> Deserialize<'de> for CidrAddress {
}
}
+serde_plain::derive_serialize_from_display!(CidrAddress);
+
fn mask_limit(addr: &IpAddr) -> usize {
if addr.is_ipv4() {
32
diff --git a/proxmox-post-hook/Cargo.toml b/proxmox-post-hook/Cargo.toml
new file mode 100644
index 0000000..3acea6c
--- /dev/null
+++ b/proxmox-post-hook/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "proxmox-post-hook"
+version = "0.1.0"
+edition = "2021"
+authors = [
+ "Christoph Heiss <c.heiss@proxmox.com>",
+ "Proxmox Support Team <support@proxmox.com>",
+]
+license = "AGPL-3"
+exclude = [ "build", "debian" ]
+homepage = "https://www.proxmox.com"
+
+[dependencies]
+anyhow.workspace = true
+proxmox-auto-installer.workspace = true
+proxmox-installer-common = { workspace = true, features = ["http"] }
+serde.workspace = true
+serde_json.workspace = true
diff --git a/proxmox-post-hook/src/main.rs b/proxmox-post-hook/src/main.rs
new file mode 100644
index 0000000..8558da2
--- /dev/null
+++ b/proxmox-post-hook/src/main.rs
@@ -0,0 +1,784 @@
+//! Post installation hook for the Proxmox installer, mainly for combination
+//! with the auto-installer.
+//!
+//! If a `[posthook]` section is specified in the given answer file, it will
+//! send a HTTP POST request to that URL, with an optional certificate fingerprint
+//! for usage with (self-signed) TLS certificates.
+//! In the body of the request, information about the newly installed system is sent.
+//!
+//! Relies on `proxmox-chroot` as an external dependency to (bind-)mount the
+//! previously installed system.
+
+use std::{
+ collections::HashSet,
+ ffi::CStr,
+ fs::{self, File},
+ io::BufReader,
+ os::unix::fs::FileExt,
+ path::PathBuf,
+ process::{Command, ExitCode},
+};
+
+use anyhow::{anyhow, bail, Context, Result};
+use proxmox_auto_installer::{
+ answer::{Answer, PostNotificationHookInfo},
+ udevinfo::{UdevInfo, UdevProperties},
+};
+use proxmox_installer_common::{
+ options::{Disk, FsType},
+ setup::{
+ load_installer_setup_files, BootType, InstallConfig, IsoInfo, ProxmoxProduct, RuntimeInfo,
+ SetupInfo,
+ },
+ sysinfo::SystemDMI,
+ utils::CidrAddress,
+};
+use serde::Serialize;
+
+/// Information about the system boot status.
+#[derive(Serialize)]
+struct BootInfo {
+ /// Whether the system is booted using UEFI or legacy BIOS.
+ mode: BootType,
+ /// Whether SecureBoot is enabled for the installation.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ secureboot: Option<bool>,
+}
+
+/// Holds all the public keys for the different algorithms available.
+#[derive(Serialize)]
+struct SshPublicHostKeys {
+ // ECDSA-based public host key
+ ecdsa: String,
+ // ED25519-based public host key
+ ed25519: String,
+ // RSA-based public host key
+ rsa: String,
+}
+
+/// Holds information about a single disk in the system.
+#[derive(Serialize)]
+#[serde(rename_all = "kebab-case")]
+struct DiskInfo {
+ /// Size in bytes
+ size: usize,
+ /// Set to true if the disk is used for booting.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ is_bootdisk: Option<bool>,
+ /// Properties about the device as given by udev.
+ udev_properties: UdevProperties,
+}
+
+/// Holds information about the management network interface.
+#[derive(Serialize)]
+#[serde(rename_all = "kebab-case")]
+struct NetworkInterfaceInfo {
+ /// MAC address of the interface
+ mac: String,
+ /// (Designated) IP address of the interface
+ #[serde(skip_serializing_if = "Option::is_none")]
+ address: Option<CidrAddress>,
+ /// Set to true if the interface is the chosen management interface during
+ /// installation.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ is_management: Option<bool>,
+ /// Properties about the device as given by udev.
+ udev_properties: UdevProperties,
+}
+
+/// Information about the installed product itself.
+#[derive(Serialize)]
+#[serde(rename_all = "kebab-case")]
+struct ProductInfo {
+ /// Full name of the product
+ fullname: String,
+ /// Product abbreviation
+ short: ProxmoxProduct,
+ /// Version of the installed product
+ version: String,
+}
+
+/// The current kernel version.
+/// Aligns with the format as used by the /nodes/<node>/status API of each product.
+#[derive(Serialize)]
+struct KernelVersionInformation {
+ /// The systemname/nodename
+ pub sysname: String,
+ /// The kernel release number
+ pub release: String,
+ /// The kernel version
+ pub version: String,
+ /// The machine architecture
+ pub machine: String,
+}
+
+/// Information about the CPU(s) installed in the system
+#[derive(Serialize)]
+struct CpuInfo {
+ /// Number of physical CPU cores.
+ cores: usize,
+ /// Number of logical CPU cores aka. threads.
+ cpus: usize,
+ /// CPU feature flag set as a space-delimited list.
+ flags: String,
+ /// Whether hardware-accelerated virtualization is supported.
+ hvm: bool,
+ /// Reported model of the CPU(s)
+ model: String,
+ /// Number of physical CPU sockets
+ sockets: usize,
+}
+
+/// All data sent as request payload with the post-hook POST request.
+#[derive(Serialize)]
+#[serde(rename_all = "kebab-case")]
+struct PostHookInfo {
+ /// major.minor version of Debian as installed, retrieved from /etc/debian_version
+ debian_version: String,
+ /// PVE/PMG/PBS version as reported by `pveversion`, `pmgversion` or
+ /// `proxmox-backup-manager version`, respectively.
+ product: ProductInfo,
+ /// Release information for the ISO used for the installation.
+ iso: IsoInfo,
+ /// Installed kernel version
+ kernel_version: KernelVersionInformation,
+ /// Describes the boot mode of the machine and the SecureBoot status.
+ boot_info: BootInfo,
+ /// Information about the installed CPU(s)
+ cpu_info: CpuInfo,
+ /// DMI information about the system
+ dmi: SystemDMI,
+ /// Filesystem used for boot disk(s)
+ filesystem: FsType,
+ /// Fully qualified domain name of the installed system
+ fqdn: String,
+ /// Unique systemd-id128 identifier of the installed system (128-bit, 16 bytes)
+ machine_id: String,
+ /// All disks detected on the system.
+ disks: Vec<DiskInfo>,
+ /// All network interfaces detected on the system.
+ network_interfaces: Vec<NetworkInterfaceInfo>,
+ /// Public parts of SSH host keys of the installed system
+ ssh_public_host_keys: SshPublicHostKeys,
+}
+
+/// Defines the size of a gibibyte in bytes.
+const SIZE_GIB: usize = 1024 * 1024 * 1024;
+
+impl PostHookInfo {
+ /// Gathers all needed information about the newly installed system for sending
+ /// it to a specified server.
+ ///
+ /// # Arguments
+ ///
+ /// * `target_path` - Path to where the chroot environment root is mounted
+ /// * `answer` - Answer file as provided by the user
+ fn gather(target_path: &str, answer: &Answer) -> Result<Self> {
+ println!("Gathering installed system data ...");
+
+ let config: InstallConfig =
+ serde_json::from_reader(BufReader::new(File::open("/tmp/low-level-config.json")?))?;
+
+ let (setup_info, _, run_env) =
+ load_installer_setup_files(proxmox_installer_common::RUNTIME_DIR)
+ .map_err(|err| anyhow!("Failed to load setup files: {err}"))?;
+
+ let udev: UdevInfo = {
+ let path =
+ PathBuf::from(proxmox_installer_common::RUNTIME_DIR).join("run-env-udev.json");
+ serde_json::from_reader(BufReader::new(File::open(path)?))?
+ };
+
+ // Opens a file, specified by an absolute path _inside_ the chroot
+ // from the target.
+ let open_file = |path: &str| {
+ File::open(format!("{}/{}", target_path, path))
+ .with_context(|| format!("failed to open '{path}'"))
+ };
+
+ // Reads a file, specified by an absolute path _inside_ the chroot
+ // from the target.
+ let read_file = |path: &str| {
+ fs::read_to_string(format!("{}/{}", target_path, path))
+ .map(|s| s.trim().to_owned())
+ .with_context(|| format!("failed to read '{path}'"))
+ };
+
+ // Runs a command inside the target chroot.
+ let run_cmd = |cmd: &[&str]| {
+ Command::new("chroot")
+ .arg(target_path)
+ .args(cmd)
+ .output()
+ .with_context(|| format!("failed to run '{cmd:?}'"))
+ .and_then(|r| Ok(String::from_utf8(r.stdout)?))
+ };
+
+ Ok(Self {
+ debian_version: read_file("/etc/debian_version")?,
+ product: Self::gather_product_info(&setup_info, &run_cmd)?,
+ iso: setup_info.iso_info.clone(),
+ kernel_version: Self::gather_kernel_version(&run_cmd, &open_file)?,
+ boot_info: BootInfo {
+ mode: run_env.boot_type,
+ secureboot: run_env.secure_boot,
+ },
+ cpu_info: Self::gather_cpu_info(&run_env)?,
+ dmi: SystemDMI::get()?,
+ filesystem: answer.disks.fs_type,
+ fqdn: answer.global.fqdn.to_string(),
+ machine_id: read_file("/etc/machine-id")?,
+ disks: Self::gather_disks(&config, &run_env, &udev)?,
+ network_interfaces: Self::gather_nic(&config, &run_env, &udev)?,
+ ssh_public_host_keys: SshPublicHostKeys {
+ ecdsa: read_file("/etc/ssh/ssh_host_ecdsa_key.pub")?,
+ ed25519: read_file("/etc/ssh/ssh_host_ed25519_key.pub")?,
+ rsa: read_file("/etc/ssh/ssh_host_rsa_key.pub")?,
+ },
+ })
+ }
+
+ /// Retrieves all needed information about the boot disks that were selected during
+ /// installation, most notable the udev properties.
+ ///
+ /// # Arguments
+ ///
+ /// * `config` - Low-level installation configuration
+ /// * `run_env` - Runtime envirornment information gathered by the installer at the start
+ /// * `udev` - udev information for all system devices
+ fn gather_disks(
+ config: &InstallConfig,
+ run_env: &RuntimeInfo,
+ udev: &UdevInfo,
+ ) -> Result<Vec<DiskInfo>> {
+ let get_udev_properties = |disk: &Disk| {
+ udev.disks
+ .get(&disk.index)
+ .with_context(|| {
+ format!("could not find udev information for disk '{}'", disk.path)
+ })
+ .cloned()
+ };
+
+ let disks = if config.filesys.is_lvm() {
+ // If the filesystem is LVM, there is only boot disk. The path (aka. /dev/..)
+ // can be found in `config.target_hd`.
+ run_env
+ .disks
+ .iter()
+ .flat_map(|disk| {
+ let is_bootdisk = config
+ .target_hd
+ .as_ref()
+ .and_then(|hd| (*hd == disk.path).then_some(true));
+
+ anyhow::Ok(DiskInfo {
+ size: (config.hdsize * (SIZE_GIB as f64)) as usize,
+ is_bootdisk,
+ udev_properties: get_udev_properties(disk)?,
+ })
+ })
+ .collect()
+ } else {
+ // If the filesystem is not LVM-based (thus Btrfs or ZFS), `config.disk_selection`
+ // contains a list of indices identifiying the boot disks, as given by udev.
+ let selected_disks_indices: Vec<&String> = config.disk_selection.values().collect();
+
+ run_env
+ .disks
+ .iter()
+ .flat_map(|disk| {
+ let is_bootdisk = selected_disks_indices
+ .contains(&&disk.index)
+ .then_some(true);
+
+ anyhow::Ok(DiskInfo {
+ size: (config.hdsize * (SIZE_GIB as f64)) as usize,
+ is_bootdisk,
+ udev_properties: get_udev_properties(disk)?,
+ })
+ })
+ .collect()
+ };
+
+ Ok(disks)
+ }
+
+ /// Retrieves all needed information about the management network interface that was selected
+ /// during installation, most notable the udev properties.
+ ///
+ /// # Arguments
+ ///
+ /// * `config` - Low-level installation configuration
+ /// * `run_env` - Runtime envirornment information gathered by the installer at the start
+ /// * `udev` - udev information for all system devices
+ fn gather_nic(
+ config: &InstallConfig,
+ run_env: &RuntimeInfo,
+ udev: &UdevInfo,
+ ) -> Result<Vec<NetworkInterfaceInfo>> {
+ Ok(run_env
+ .network
+ .interfaces
+ .values()
+ .flat_map(|nic| {
+ let udev_properties = udev
+ .nics
+ .get(&nic.name)
+ .with_context(|| {
+ format!("could not find udev information for NIC '{}'", nic.name)
+ })?
+ .clone();
+
+ if config.mngmt_nic == nic.name {
+ // Use the actual IP address from the low-level install config, as the runtime info
+ // contains the original IP address from DHCP.
+ anyhow::Ok(NetworkInterfaceInfo {
+ mac: nic.mac.clone(),
+ address: Some(config.cidr.clone()),
+ is_management: Some(true),
+ udev_properties,
+ })
+ } else {
+ anyhow::Ok(NetworkInterfaceInfo {
+ mac: nic.mac.clone(),
+ address: None,
+ is_management: None,
+ udev_properties,
+ })
+ }
+ })
+ .collect())
+ }
+
+ /// Retrieves the version of the installed product from the chroot.
+ ///
+ /// # Arguments
+ ///
+ /// * `setup_info` - Filled-out struct with information about the product
+ /// * `run_cmd` - Callback to run a command inside the target chroot.
+ fn gather_product_info(
+ setup_info: &SetupInfo,
+ run_cmd: &dyn Fn(&[&str]) -> Result<String>,
+ ) -> Result<ProductInfo> {
+ let package = match setup_info.config.product {
+ ProxmoxProduct::PVE => "pve-manager",
+ ProxmoxProduct::PMG => "pmg-api",
+ ProxmoxProduct::PBS => "proxmox-backup-server",
+ };
+
+ let version = run_cmd(&[
+ "dpkg-query",
+ "--showformat",
+ "${Version}",
+ "--show",
+ package,
+ ])
+ .with_context(|| format!("failed to retrieve version of {package}"))?;
+
+ Ok(ProductInfo {
+ fullname: setup_info.config.fullname.clone(),
+ short: setup_info.config.product,
+ version,
+ })
+ }
+
+ /// Extracts the version string from the *installed* kernel image.
+ ///
+ /// First, it determines the exact path to the kernel image (aka. `/boot/vmlinuz-<version>`)
+ /// by looking at the installed kernel package, then reads the string directly from the image
+ /// from the well-defined kernel header. See also [0] for details.
+ ///
+ /// [0] https://www.kernel.org/doc/html/latest/arch/x86/boot.html
+ ///
+ /// # Arguments
+ ///
+ /// * `run_cmd` - Callback to run a command inside the target chroot.
+ /// * `open_file` - Callback to open a file inside the target chroot.
+ #[cfg(target_arch = "x86_64")]
+ fn gather_kernel_version(
+ run_cmd: &dyn Fn(&[&str]) -> Result<String>,
+ open_file: &dyn Fn(&str) -> Result<File>,
+ ) -> Result<KernelVersionInformation> {
+ let file = open_file(&Self::find_kernel_image_path(run_cmd)?)?;
+
+ // Read the 2-byte `kernel_version` field at offset 0x20e [0] from the file ..
+ // https://www.kernel.org/doc/html/latest/arch/x86/boot.html#the-real-mode-kernel-header
+ let mut buffer = [0u8; 2];
+ file.read_exact_at(&mut buffer, 0x20e)
+ .context("could not read kernel_version offset from image")?;
+
+ // .. which gives us the offset of the kernel version string inside the image, minus 0x200.
+ // https://www.kernel.org/doc/html/latest/arch/x86/boot.html#details-of-header-fields
+ let offset = u16::from_le_bytes(buffer) + 0x200;
+
+ // The string is usually somewhere around 80-100 bytes long, so 256 bytes is more than
+ // enough to cover all cases.
+ let mut buffer = [0u8; 256];
+ file.read_exact_at(&mut buffer, offset.into())
+ .context("could not read kernel version string from image")?;
+
+ // Now just consume the buffer until the NUL byte
+ let kernel_version = CStr::from_bytes_until_nul(&buffer)
+ .context("did not find a NUL-terminator in kernel version string")?
+ .to_str()
+ .context("could not convert kernel version string")?;
+
+ // The version string looks like:
+ // 6.8.4-2-pve (build@proxmox) #1 SMP PREEMPT_DYNAMIC PMX 6.8.4-2 (2024-04-10T17:36Z) x86_64 GNU/Linux
+ //
+ // Thus split it into three parts, as we are interested in the release version
+ // and everything starting at the build number
+ let parts: Vec<&str> = kernel_version.splitn(3, ' ').collect();
+
+ if parts.len() != 3 {
+ bail!("failed to split kernel version string");
+ }
+
+ Ok(KernelVersionInformation {
+ machine: std::env::consts::ARCH.to_owned(),
+ sysname: "Linux".to_owned(),
+ release: parts
+ .first()
+ .context("kernel release not found")?
+ .to_string(),
+ version: parts
+ .get(2)
+ .context("kernel version not found")?
+ .to_string(),
+ })
+ }
+
+ /// Retrieves the absolute path to the kernel image (aka. `/boot/vmlinuz-<version>`)
+ /// inside the chroot by looking at the file list installed by the kernel package.
+ ///
+ /// # Arguments
+ ///
+ /// * `run_cmd` - Callback to run a command inside the target chroot.
+ fn find_kernel_image_path(run_cmd: &dyn Fn(&[&str]) -> Result<String>) -> Result<String> {
+ let pkg_name = Self::find_kernel_package_name(run_cmd)?;
+
+ let all_files = run_cmd(&["dpkg-query", "--listfiles", &pkg_name])?;
+ for file in all_files.lines() {
+ if file.starts_with("/boot/vmlinuz-") {
+ return Ok(file.to_owned());
+ }
+ }
+
+ bail!("failed to find installed kernel image path")
+ }
+
+ /// Retrieves the full name of the kernel package installed inside the chroot.
+ ///
+ /// # Arguments
+ ///
+ /// * `run_cmd` - Callback to run a command inside the target chroot.
+ fn find_kernel_package_name(run_cmd: &dyn Fn(&[&str]) -> Result<String>) -> Result<String> {
+ let dpkg_arch = run_cmd(&["dpkg", "--print-architecture"])?
+ .trim()
+ .to_owned();
+
+ let kernel_pkgs = run_cmd(&[
+ "dpkg-query",
+ "--showformat",
+ "${db:Status-Abbrev}|${Architecture}|${Package}\\n",
+ "--show",
+ "proxmox-kernel-[0-9]*",
+ ])?;
+
+ // The output to parse looks like this:
+ // ii |all|proxmox-kernel-6.8
+ // un ||proxmox-kernel-6.8.8-2-pve
+ // ii |amd64|proxmox-kernel-6.8.8-2-pve-signed
+ for pkg in kernel_pkgs.lines() {
+ let parts = pkg.split('|').collect::<Vec<&str>>();
+
+ if let [status, arch, name] = parts[..] {
+ if status.trim() == "ii" && arch.trim() == dpkg_arch {
+ return Ok(name.trim().to_owned());
+ }
+ }
+ }
+
+ bail!("failed to find installed kernel package")
+ }
+
+ /// Retrieves some basic information about the CPU in the running system,
+ /// reading them from /proc/cpuinfo.
+ ///
+ /// # Arguments
+ ///
+ /// * `run_env` - Runtime envirornment information gathered by the installer at the start
+ fn gather_cpu_info(run_env: &RuntimeInfo) -> Result<CpuInfo> {
+ let mut result = CpuInfo {
+ cores: 0,
+ cpus: 0,
+ flags: String::new(),
+ hvm: run_env.hvm_supported,
+ model: String::new(),
+ sockets: 0,
+ };
+ let mut sockets = HashSet::new();
+ let mut cores = HashSet::new();
+
+ // Does not matter if we read the file from inside the chroot or directly on the host.
+ let cpuinfo = fs::read_to_string("/proc/cpuinfo")?;
+ for line in cpuinfo.lines() {
+ match line.split_once(':') {
+ Some((key, _)) if key.trim() == "processor" => {
+ result.cpus += 1;
+ }
+ Some((key, value)) if key.trim() == "core id" => {
+ cores.insert(value);
+ }
+ Some((key, value)) if key.trim() == "physical id" => {
+ sockets.insert(value);
+ }
+ Some((key, value)) if key.trim() == "flags" => {
+ value.trim().clone_into(&mut result.flags);
+ }
+ Some((key, value)) if key.trim() == "model name" => {
+ value.trim().clone_into(&mut result.model);
+ }
+ _ => {}
+ }
+ }
+
+ result.cores = cores.len();
+ result.sockets = sockets.len();
+
+ Ok(result)
+ }
+}
+
+/// Runs the specified callback with the mounted chroot, passing along the
+/// absolute path to where / is mounted.
+/// The callback is *not* run inside the chroot itself, that is left to the caller.
+///
+/// # Arguments
+///
+/// * `callback` - Callback to call with the absolute path where the chroot environment root is
+/// mounted.
+fn with_chroot<R, F: FnOnce(&str) -> Result<R>>(callback: F) -> Result<R> {
+ let ec = Command::new("proxmox-chroot")
+ .arg("prepare")
+ .status()
+ .context("failed to run proxmox-chroot")?;
+
+ if !ec.success() {
+ bail!("failed to create chroot for installed system");
+ }
+
+ // See also proxmox-chroot/src/main.rs w.r.t to the path, which is hard-coded there
+ let result = callback("/target");
+
+ let ec = Command::new("proxmox-chroot").arg("cleanup").status();
+ // We do not want to necessarily fail here, as the install environment is about
+ // to be teared down completely anyway.
+ if ec.is_err() || !ec.map(|ec| ec.success()).unwrap_or(false) {
+ eprintln!("failed to clean up chroot for installed system");
+ }
+
+ result
+}
+
+/// Reads the answer file from stdin, checks for a configured post-hook URL (+ optional certificate
+/// fingerprint for HTTPS). If configured, retrieves all relevant information about the installed
+/// system and sends them to the given endpoint.
+fn do_main() -> Result<()> {
+ let answer = Answer::try_from_reader(std::io::stdin().lock())?;
+
+ if let Some(PostNotificationHookInfo {
+ url,
+ cert_fingerprint,
+ }) = &answer.posthook
+ {
+ println!("Found posthook; sending POST request to '{url}'.");
+
+ let info = with_chroot(|target_path| PostHookInfo::gather(target_path, &answer))?;
+
+ proxmox_installer_common::http::post(
+ url,
+ cert_fingerprint.as_deref(),
+ serde_json::to_string(&info)?,
+ )?;
+ } else {
+ println!("No posthook found; skipping");
+ }
+
+ Ok(())
+}
+
+fn main() -> ExitCode {
+ match do_main() {
+ Ok(()) => ExitCode::SUCCESS,
+ Err(err) => {
+ eprintln!("\nError occurred during posthook:");
+ eprintln!("{err:#}");
+ ExitCode::FAILURE
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::PostHookInfo;
+
+ #[test]
+ fn finds_correct_kernel_package_name() {
+ let mocked_run_cmd = |cmd: &[&str]| {
+ if cmd[0] == "dpkg" {
+ assert_eq!(cmd, &["dpkg", "--print-architecture"]);
+ Ok("amd64\n".to_owned())
+ } else {
+ assert_eq!(
+ cmd,
+ &[
+ "dpkg-query",
+ "--showformat",
+ "${db:Status-Abbrev}|${Architecture}|${Package}\\n",
+ "--show",
+ "proxmox-kernel-[0-9]*",
+ ]
+ );
+ Ok(r#"ii |all|proxmox-kernel-6.8
+un ||proxmox-kernel-6.8.8-2-pve
+ii |amd64|proxmox-kernel-6.8.8-2-pve-signed
+ "#
+ .to_owned())
+ }
+ };
+
+ assert_eq!(
+ PostHookInfo::find_kernel_package_name(&mocked_run_cmd).unwrap(),
+ "proxmox-kernel-6.8.8-2-pve-signed"
+ );
+ }
+
+ #[test]
+ fn find_kernel_package_name_fails_on_wrong_architecture() {
+ let mocked_run_cmd = |cmd: &[&str]| {
+ if cmd[0] == "dpkg" {
+ assert_eq!(cmd, &["dpkg", "--print-architecture"]);
+ Ok("arm64\n".to_owned())
+ } else {
+ assert_eq!(
+ cmd,
+ &[
+ "dpkg-query",
+ "--showformat",
+ "${db:Status-Abbrev}|${Architecture}|${Package}\\n",
+ "--show",
+ "proxmox-kernel-[0-9]*",
+ ]
+ );
+ Ok(r#"ii |all|proxmox-kernel-6.8
+un ||proxmox-kernel-6.8.8-2-pve
+ii |amd64|proxmox-kernel-6.8.8-2-pve-signed
+ "#
+ .to_owned())
+ }
+ };
+
+ assert_eq!(
+ PostHookInfo::find_kernel_package_name(&mocked_run_cmd)
+ .unwrap_err()
+ .to_string(),
+ "failed to find installed kernel package"
+ );
+ }
+
+ #[test]
+ fn find_kernel_package_name_fails_on_missing_package() {
+ let mocked_run_cmd = |cmd: &[&str]| {
+ if cmd[0] == "dpkg" {
+ assert_eq!(cmd, &["dpkg", "--print-architecture"]);
+ Ok("amd64\n".to_owned())
+ } else {
+ assert_eq!(
+ cmd,
+ &[
+ "dpkg-query",
+ "--showformat",
+ "${db:Status-Abbrev}|${Architecture}|${Package}\\n",
+ "--show",
+ "proxmox-kernel-[0-9]*",
+ ]
+ );
+ Ok(r#"ii |all|proxmox-kernel-6.8
+un ||proxmox-kernel-6.8.8-2-pve
+ "#
+ .to_owned())
+ }
+ };
+
+ assert_eq!(
+ PostHookInfo::find_kernel_package_name(&mocked_run_cmd)
+ .unwrap_err()
+ .to_string(),
+ "failed to find installed kernel package"
+ );
+ }
+
+ #[test]
+ fn finds_correct_absolute_kernel_image_path() {
+ let mocked_run_cmd = |cmd: &[&str]| {
+ if cmd[0] == "dpkg" {
+ assert_eq!(cmd, &["dpkg", "--print-architecture"]);
+ Ok("amd64\n".to_owned())
+ } else if cmd[0..=1] == ["dpkg-query", "--showformat"] {
+ assert_eq!(
+ cmd,
+ &[
+ "dpkg-query",
+ "--showformat",
+ "${db:Status-Abbrev}|${Architecture}|${Package}\\n",
+ "--show",
+ "proxmox-kernel-[0-9]*",
+ ]
+ );
+ Ok(r#"ii |all|proxmox-kernel-6.8
+un ||proxmox-kernel-6.8.8-2-pve
+ii |amd64|proxmox-kernel-6.8.8-2-pve-signed
+ "#
+ .to_owned())
+ } else {
+ assert_eq!(
+ cmd,
+ [
+ "dpkg-query",
+ "--listfiles",
+ "proxmox-kernel-6.8.8-2-pve-signed"
+ ]
+ );
+ Ok(r#"
+/.
+/boot
+/boot/System.map-6.8.8-2-pve
+/boot/config-6.8.8-2-pve
+/boot/vmlinuz-6.8.8-2-pve
+/lib
+/lib/modules
+/lib/modules/6.8.8-2-pve
+/lib/modules/6.8.8-2-pve/kernel
+/lib/modules/6.8.8-2-pve/kernel/arch
+/lib/modules/6.8.8-2-pve/kernel/arch/x86
+/lib/modules/6.8.8-2-pve/kernel/arch/x86/crypto
+/lib/modules/6.8.8-2-pve/kernel/arch/x86/crypto/aegis128-aesni.ko
+/lib/modules/6.8.8-2-pve/kernel/arch/x86/crypto/aesni-intel.ko
+/lib/modules/6.8.8-2-pve/kernel/arch/x86/crypto/aria-aesni-avx-x86_64.ko
+/lib/modules/6.8.8-2-pve/kernel/arch/x86/crypto/aria-aesni-avx2-x86_64.ko
+/lib/modules/6.8.8-2-pve/kernel/arch/x86/crypto/aria-gfni-avx512-x86_64.ko
+/lib/modules/6.8.8-2-pve/kernel/arch/x86/crypto/blowfish-x86_64.ko
+/lib/modules/6.8.8-2-pve/kernel/arch/x86/crypto/camellia-aesni-avx-x86_64.ko
+ "#
+ .to_owned())
+ }
+ };
+
+ assert_eq!(
+ PostHookInfo::find_kernel_image_path(&mocked_run_cmd).unwrap(),
+ "/boot/vmlinuz-6.8.8-2-pve"
+ );
+ }
+}
--
2.47.0
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [pve-devel] [PATCH installer v4 12/12] unconfigured.sh: run proxmox-post-hook after successful auto-install
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
` (10 preceding siblings ...)
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 11/12] fix #5536: post-hook: add utility for sending notifications after auto-install Christoph Heiss
@ 2024-11-11 13:15 ` Christoph Heiss
2024-11-11 17:41 ` [pve-devel] applied: [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Thomas Lamprecht
12 siblings, 0 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-11 13:15 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v3 -> v4:
* dropped whitespace-only change
Changes v2 -> v3:
* no changes
Changes v1 -> v2:
* no changes
unconfigured.sh | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/unconfigured.sh b/unconfigured.sh
index b1c980a..208ed77 100755
--- a/unconfigured.sh
+++ b/unconfigured.sh
@@ -253,7 +253,10 @@ elif [ $start_auto_installer -ne 0 ]; then
debugsh || true
fi
echo "Starting automatic installation"
- /usr/bin/proxmox-auto-installer </run/automatic-installer-answers
+
+ if /usr/bin/proxmox-auto-installer </run/automatic-installer-answers; then
+ /usr/bin/proxmox-post-hook </run/automatic-installer-answers
+ fi
else
echo "Starting the installer GUI - see tty2 (CTRL+ALT+F2) for any errors..."
xinit -- -dpi "$DPI" -s 0 >/dev/tty2 2>&1
--
2.47.0
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [pve-devel] applied: [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
` (11 preceding siblings ...)
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 12/12] unconfigured.sh: run proxmox-post-hook after successful auto-install Christoph Heiss
@ 2024-11-11 17:41 ` Thomas Lamprecht
2024-11-12 10:33 ` Christoph Heiss
12 siblings, 1 reply; 15+ messages in thread
From: Thomas Lamprecht @ 2024-11-11 17:41 UTC (permalink / raw)
To: Proxmox VE development discussion, Christoph Heiss
Am 11.11.24 um 14:14 schrieb Christoph Heiss:
> This implements a mechanism for post-installation "notifications" via a
> POST request [0] when using the auto-installer.
>
> It's implemented as a separate, small utility to facilitate separation
> of concerns and make the information gathering easier by having it
> isolated in one place.
>
> Patches #1 through #5 are simply clean-ups, refactors, etc. that were
> done along the way and can be applied independently.
>
> Most interesting here will be patch #16, which adds the actual
> implementation of the post-hook. (Bind-)mounting the installed host
> system is done using the existing `proxmox-chroot` utility, and the HTTP
> POST functionality can fortunately be re-used 1:1 from
> `proxmox-fetch-answer`.
>
> I've also included an example of how the JSON body (pretty-printed and
> reduced some things for readability) of such a post-installation request
> would look like below, for reference.
> Where applicable (and sensible), I have tried to align the format as
> much as possible with 1) the format as used in the `fetch-answer` POST
> request and 2) PVE's /nodes/<host>/status API endpoint.
>
> Feedback on the post-hook information schema is of course also very much
> appreciated!
What about adding an X.Y format version? So that we can expand this nicely or
even rework completely. Here the semantic meaning of the two tuples would
be
X: major version, increased if existing keys vanish or get renamed or
restructured, i.e. a breaking change.
Y: minor version, increased if new information gets added.
A patch level does not make much sense here IMO, so I left that out.
This way consumers could decide if they can cope with the current format
version and e.g. take different actions or what not.
One naturally can use the product version for deriving the format version,
but in the long run that needs more client side handling and mapping than
a separate format version.
>
> It should be noted that some information like DMI is generally very
> depended on the motherboard/firmware, on what information is actually
> available and filled-in. So the contents are expected to vary wildly
> between machines and may also be empty, as in the example below from a
> VM.
Can we also dump the schema so that this can be added to the docs, or
at least (linked to) in the wiki of the automated installer?
Also, I figure you already planned to document this in the wiki for the
next ISO release? Just asking to be sure it won't be overlooked.
>
> Diffstat
> ========
>
> Christoph Heiss (12):
> debian: strip unused library dependencies
> fetch-answer: move http-related code to gated module in
> installer-common
> tree-wide: convert some more crates to use workspace dependencies
> auto-install-assistant: replace `PathBuf` parameters with
> `AsRef<Path>`
^- this one would have done well with some short commit message body,
even if obvious it will never hurt to state the intention of the commit.
> auto-installer: tests: simplify empty disks check
> auto-installer: tests: replace `PathBuf` parameters with `AsRef<Path>`
^- same here w.r.t. the lack of a short commit message body
> auto-installer: move `SystemDMI` struct to common crate
> auto-installer: answer: factor out answer file reading into function
> auto-installer: udevinfo: introduce type alias for udev properties
> fix #5536: auto-installer: answer: add `posthook` section
> fix #5536: post-hook: add utility for sending notifications after
> auto-install
^- above two might have been better off squashed, but I can get how you
wanted to separate them, so I kept them as is.
> unconfigured.sh: run proxmox-post-hook after successful auto-install
applied series, thanks!
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [pve-devel] applied: [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism
2024-11-11 17:41 ` [pve-devel] applied: [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Thomas Lamprecht
@ 2024-11-12 10:33 ` Christoph Heiss
0 siblings, 0 replies; 15+ messages in thread
From: Christoph Heiss @ 2024-11-12 10:33 UTC (permalink / raw)
To: Thomas Lamprecht; +Cc: Proxmox VE development discussion
On Mon, Nov 11, 2024 at 06:41:15PM +0100, Thomas Lamprecht wrote:
> Am 11.11.24 um 14:14 schrieb Christoph Heiss:
> > This implements a mechanism for post-installation "notifications" via a
> > POST request [0] when using the auto-installer.
> > [..]
> > Feedback on the post-hook information schema is of course also very much
> > appreciated!
>
> What about adding an X.Y format version? So that we can expand this nicely or
> even rework completely.
> [..]
> One naturally can use the product version for deriving the format version,
> but in the long run that needs more client side handling and mapping than
> a separate format version.
Sure, makes sense! The document format will surely change/get
expanded in the future, so definitely good to have something like this
from the get-go.
I'll send a patch asap, fairly trivial to implement for now anyway.
>
> >
> > It should be noted that some information like DMI is generally very
> > depended on the motherboard/firmware, on what information is actually
> > available and filled-in. So the contents are expected to vary wildly
> > between machines and may also be empty, as in the example below from a
> > VM.
>
> Can we also dump the schema so that this can be added to the docs, or
> at least (linked to) in the wiki of the automated installer?
Of course! Glancing over it, the schema for the JSON that
`proxmox-fetch-answer` is also not explicitly documented - so I'll that
one too.
>
> Also, I figure you already planned to document this in the wiki for the
> next ISO release? Just asking to be sure it won't be overlooked.
Yes! Just waited for this to get applied, i.e. having a finalized
format.
>
> >
> > Diffstat
> > ========
> >
> > Christoph Heiss (12):
> > debian: strip unused library dependencies
> > fetch-answer: move http-related code to gated module in
> > installer-common
> > tree-wide: convert some more crates to use workspace dependencies
> > auto-install-assistant: replace `PathBuf` parameters with
> > `AsRef<Path>`
>
> ^- this one would have done well with some short commit message body,
> even if obvious it will never hurt to state the intention of the commit.
Ack!
>
> > auto-installer: tests: simplify empty disks check
> > auto-installer: tests: replace `PathBuf` parameters with `AsRef<Path>`
>
> ^- same here w.r.t. the lack of a short commit message body
>
> > auto-installer: move `SystemDMI` struct to common crate
> > auto-installer: answer: factor out answer file reading into function
> > auto-installer: udevinfo: introduce type alias for udev properties
> > fix #5536: auto-installer: answer: add `posthook` section
> > fix #5536: post-hook: add utility for sending notifications after
> > auto-install
>
> ^- above two might have been better off squashed, but I can get how you
> wanted to separate them, so I kept them as is.
Thanks! Since the second patch, adding the `proxmox-post-hook` tool, was
pretty big already, I'd tried to split off things not immediately
relevant to it. (In a sense that the tool is considered "standalone")
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2024-11-12 10:33 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-11-11 13:14 [pve-devel] [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Christoph Heiss
2024-11-11 13:14 ` [pve-devel] [PATCH installer v4 01/12] debian: strip unused library dependencies Christoph Heiss
2024-11-11 13:14 ` [pve-devel] [PATCH installer v4 02/12] fetch-answer: move http-related code to gated module in installer-common Christoph Heiss
2024-11-11 13:14 ` [pve-devel] [PATCH installer v4 03/12] tree-wide: convert some more crates to use workspace dependencies Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 04/12] auto-install-assistant: replace `PathBuf` parameters with `AsRef<Path>` Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 05/12] auto-installer: tests: simplify empty disks check Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 06/12] auto-installer: tests: replace `PathBuf` parameters with `AsRef<Path>` Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 07/12] auto-installer: move `SystemDMI` struct to common crate Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 08/12] auto-installer: answer: factor out answer file reading into function Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 09/12] auto-installer: udevinfo: introduce type alias for udev properties Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 10/12] fix #5536: auto-installer: answer: add `posthook` section Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 11/12] fix #5536: post-hook: add utility for sending notifications after auto-install Christoph Heiss
2024-11-11 13:15 ` [pve-devel] [PATCH installer v4 12/12] unconfigured.sh: run proxmox-post-hook after successful auto-install Christoph Heiss
2024-11-11 17:41 ` [pve-devel] applied: [PATCH installer v4 00/12] fix #5536: implement post-(auto-)installation notification mechanism Thomas Lamprecht
2024-11-12 10:33 ` Christoph Heiss
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox