This adds a metadata-field `$fetchinfo` containing a single key `version` (for now) to the POST payload json, indicating which schema version (and thus structure) this document uses.
The version field follows the format "<major>.<minor>" and applies semantic versioning meaning for both the major and minor number. A patch version is left out here, as it doesn't make much sense in this context. Works in the same manner as the post-hook does it [0]. Useful to have it for this too, as we might change/expand this structure too in the future. In the resulting JSON, this will look like this: { "$fetchinfo": { "version": "1.0" }, "product": .., .. } [0] https://lore.proxmox.com/pve-devel/20241112145405.929194-1-c.he...@proxmox.com/ Signed-off-by: Christoph Heiss <c.he...@proxmox.com> --- proxmox-auto-installer/src/sysinfo.rs | 5 -- proxmox-fetch-answer/Cargo.toml | 2 + .../src/fetch_plugins/http.rs | 65 ++++++++++++++++++- 3 files changed, 66 insertions(+), 6 deletions(-) diff --git a/proxmox-auto-installer/src/sysinfo.rs b/proxmox-auto-installer/src/sysinfo.rs index 0a6aaf2..a45ae59 100644 --- a/proxmox-auto-installer/src/sysinfo.rs +++ b/proxmox-auto-installer/src/sysinfo.rs @@ -41,11 +41,6 @@ impl SysInfo { let info = Self::get()?; Ok(serde_json::to_string_pretty(&info)?) } - - pub fn as_json() -> Result<String> { - let info = Self::get()?; - Ok(serde_json::to_string(&info)?) - } } #[derive(Debug, Serialize)] diff --git a/proxmox-fetch-answer/Cargo.toml b/proxmox-fetch-answer/Cargo.toml index 50f3da3..23bd094 100644 --- a/proxmox-fetch-answer/Cargo.toml +++ b/proxmox-fetch-answer/Cargo.toml @@ -15,4 +15,6 @@ anyhow.workspace = true log.workspace = true proxmox-auto-installer.workspace = true proxmox-installer-common = { workspace = true, features = ["http"] } +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true toml.workspace = true diff --git a/proxmox-fetch-answer/src/fetch_plugins/http.rs b/proxmox-fetch-answer/src/fetch_plugins/http.rs index 4317430..fb9ffc8 100644 --- a/proxmox-fetch-answer/src/fetch_plugins/http.rs +++ b/proxmox-fetch-answer/src/fetch_plugins/http.rs @@ -1,5 +1,6 @@ use anyhow::{bail, Result}; use log::info; +use serde::Serialize; use std::{ fs::{self, read_to_string}, process::Command, @@ -28,6 +29,67 @@ static DHCP_URL_OPTION: &str = "proxmox-auto-installer-manifest-url"; static DHCP_CERT_FP_OPTION: &str = "proxmox-auto-installer-cert-fingerprint"; static DHCP_LEASE_FILE: &str = "/var/lib/dhcp/dhclient.leases"; +/// Metadata of the HTTP POST payload, such as schema version of the document. +#[derive(Serialize)] +#[serde(rename_all = "kebab-case")] +struct HttpFetchInfoMeta { + /// major.minor version describing the schema version of this document, in a semanticy-version + /// way. + /// + /// major: Incremented for incompatible/breaking API changes, e.g. removing an existing + /// field. + /// minor: Incremented when adding functionality in a backwards-compatible matter, e.g. + /// adding a new field. + version: String, +} + +impl HttpFetchInfoMeta { + const SCHEMA_VERSION: &str = "1.0"; +} + +impl Default for HttpFetchInfoMeta { + fn default() -> Self { + Self { + version: Self::SCHEMA_VERSION.to_owned(), + } + } +} + +/// All data sent as request payload with the answerfile fetch POST request. +/// +/// NOTE: The format is versioned through `fetch_meta.version` (`$fetchinfo.version` in the +/// resulting JSON), ensure you update it when this struct or any of its members gets modified. +#[derive(Serialize)] +#[serde(rename_all = "kebab-case")] +struct HttpFetchPayload { + /// Metadata for the answerfile fetch payload + // This field is prefixed by `$` on purpose, to indicate that it is document metadata and not + // part of the actual content itself. (E.g. JSON Schema uses a similar naming scheme) + #[serde(rename = "$fetchinfo")] + fetch_meta: HttpFetchInfoMeta, + /// Information about the running system, flattened into this structure directly. + #[serde(flatten)] + sysinfo: SysInfo, +} + +impl HttpFetchPayload { + /// Retrieves the required information from the system and constructs the + /// full payload including meta data. + fn get() -> Result<Self> { + Ok(Self { + fetch_meta: HttpFetchInfoMeta::default(), + sysinfo: SysInfo::get()?, + }) + } + + /// Retrieves the required information from the system and constructs the + /// full payload including meta data, serialized as JSON. + pub fn as_json() -> Result<String> { + let info = Self::get()?; + Ok(serde_json::to_string(&info)?) + } +} + pub struct FetchFromHTTP; impl FetchFromHTTP { @@ -65,7 +127,8 @@ impl FetchFromHTTP { } info!("Gathering system information."); - let payload = SysInfo::as_json()?; + let payload = HttpFetchPayload::as_json()?; + info!("Sending POST request to '{answer_url}'."); let answer = proxmox_installer_common::http::post(&answer_url, fingerprint.as_deref(), payload)?; -- 2.47.0 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel