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

Reply via email to