Two few small things inline
On 2024-07-18 15:49, Christoph Heiss wrote:
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.he...@proxmox.com>
---
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()
Signed-off-by: Christoph Heiss <c.he...@proxmox.com>
---
Cargo.toml | 1 +
Makefile | 8 +-
debian/install | 1 +
proxmox-auto-installer/src/answer.rs | 16 +-
.../src/bin/proxmox-auto-installer.rs | 13 +-
proxmox-auto-installer/src/udevinfo.rs | 8 +-
.../src/fetch_plugins/http.rs | 2 +-
proxmox-installer-common/src/http.rs | 6 +-
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 ++++++++++++++++++
13 files changed, 843 insertions(+), 23 deletions(-)
create mode 100644 proxmox-post-hook/Cargo.toml
create mode 100644 proxmox-post-hook/src/main.rs
[…]
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.he...@proxmox.com>",
+ "Proxmox Support Team <supp...@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..d3e5b5c
--- /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,
+}
+
+/// A single disk configured as boot disk.
Is this comment valid this way? AFAIU there was a dedicated struct for
boot disks in the previous version, but now this struct is for all
disks, optionally marking it as boot disk.
+#[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 ..");
The three dots at the end can most likely be either 3 (or UTF-8 3-dots)
or just one?
+
+ let config: InstallConfig =
+
serde_json::from_reader(BufReader::new(File::open("/tmp/low-level-config.json")?))?;
+
[…]
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel