From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id D78331FF348 for ; Wed, 17 Apr 2024 14:32:54 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 9AF075C8C; Wed, 17 Apr 2024 14:31:47 +0200 (CEST) From: Aaron Lauterer To: pve-devel@lists.proxmox.com Date: Wed, 17 Apr 2024 14:31:06 +0200 Message-Id: <20240417123108.212720-35-a.lauterer@proxmox.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240417123108.212720-1-a.lauterer@proxmox.com> References: <20240417123108.212720-1-a.lauterer@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.096 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment PROLO_LEO2 0.1 Meta Catches all Leo drug variations so far SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [PATCH installer v6 34/36] fetch-answer: use ISO specified configurations X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox VE development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" This patch switches the behavior to use the settings that can be specified in the ISO. This means, that it is possible to control how the answer file should be fetched: * auto - as usually, go through the options until one works (partition, http) * included - the answer file is included in the ISO * partition - only check for an answer file in a partition called 'proxmoxinst' in lower or uppercase * http - only fetch the answer file via an HTTP POST request. Additionally it is possible to specify the HTTP URL directly in the ISO. Placing the SSL fingerprint on a partition is not possible anymore. If one wants to provide it right away (besides DHCP or DNS), it must be incluced in the ISO itself. This reduced the need for another USB flash drive. Signed-off-by: Aaron Lauterer --- proxmox-fetch-answer/Cargo.toml | 1 + .../src/fetch_plugins/http.rs | 65 +++++++------------ proxmox-fetch-answer/src/main.rs | 64 ++++++++++++++---- 3 files changed, 77 insertions(+), 53 deletions(-) diff --git a/proxmox-fetch-answer/Cargo.toml b/proxmox-fetch-answer/Cargo.toml index fbcca46..797c185 100644 --- a/proxmox-fetch-answer/Cargo.toml +++ b/proxmox-fetch-answer/Cargo.toml @@ -17,6 +17,7 @@ log = "0.4.20" ureq = { version = "2.6", features = [ "native-certs", "native-tls" ] } rustls = { version = "0.20", features = [ "dangerous_configuration" ] } rustls-native-certs = "0.6" +toml = "0.7" native-tls = "0.2" sha2 = "0.10" hex = "0.4" diff --git a/proxmox-fetch-answer/src/fetch_plugins/http.rs b/proxmox-fetch-answer/src/fetch_plugins/http.rs index 5772c42..4093131 100644 --- a/proxmox-fetch-answer/src/fetch_plugins/http.rs +++ b/proxmox-fetch-answer/src/fetch_plugins/http.rs @@ -2,16 +2,12 @@ use anyhow::{bail, Error, Result}; use log::info; use std::{ fs::{self, read_to_string}, - path::Path, process::Command, }; use crate::fetch_plugins::utils::post; -use proxmox_auto_installer::sysinfo; +use proxmox_auto_installer::{sysinfo, utils::AutoInstSettings}; -use super::utils; - -static CERT_FINGERPRINT_FILE: &str = "cert_fingerprint.txt"; static ANSWER_SUBDOMAIN: &str = "proxmoxinst"; static ANSWER_SUBDOMAIN_FP: &str = "proxmoxinst-fp"; @@ -37,30 +33,33 @@ pub struct FetchFromHTTP; impl FetchFromHTTP { /// Will try to fetch the answer.toml by sending a HTTP POST request. The URL can be configured - /// either via DHCP or DNS. - /// DHCP options are checked first. The SSL certificate need to be either trusted by the root - /// certs or a SHA256 fingerprint needs to be provided. The SHA256 SSL fingerprint can either - /// be placed in a `cert_fingerprint.txt` file in the `proxmoxinst` partition, as DHCP option, - /// or as DNS TXT record. If provided, the `cert_fingerprint.txt` file has preference. - pub fn get_answer() -> Result { - info!("Checking for certificate fingerprint in file."); - let mut fingerprint: Option = match Self::get_cert_fingerprint_from_file() { - Ok(fp) => Some(fp), - Err(err) => { - info!("{err}"); - None + /// either via DHCP or DNS or preconfigured in the ISO. + /// If the URL is not defined in the ISO, it will first check DHCP options. The SSL certificate + /// needs to be either trusted by the root certs or a SHA256 fingerprint needs to be provided. + /// The SHA256 SSL fingerprint can either be defined in the ISO, as DHCP option, or as DNS TXT + /// record. If provided, the fingerprint provided in the ISO has preference. + pub fn get_answer(settings: &AutoInstSettings) -> Result { + let mut fingerprint: Option = match settings.cert_fingerprint.clone() { + Some(fp) => { + info!("SSL fingerprint provided through ISO."); + Some(fp) } + None => None, }; let answer_url: String; - - (answer_url, fingerprint) = match Self::fetch_dhcp(fingerprint.clone()) { - Ok((url, fp)) => (url, fp), - Err(err) => { - info!("{err}"); - Self::fetch_dns(fingerprint.clone())? - } - }; + if let Some(url) = settings.http_url.clone() { + info!("URL specified in ISO"); + answer_url = url; + } else { + (answer_url, fingerprint) = match Self::fetch_dhcp(fingerprint.clone()) { + Ok((url, fp)) => (url, fp), + Err(err) => { + info!("{err}"); + Self::fetch_dns(fingerprint.clone())? + } + }; + } if fingerprint.is_some() { let fp = fingerprint.clone(); @@ -74,22 +73,6 @@ impl FetchFromHTTP { Ok(answer) } - /// Reads certificate fingerprint from file - pub fn get_cert_fingerprint_from_file() -> Result { - let mount_path = utils::mount_proxmoxinst_part()?; - let cert_path = Path::new(mount_path.as_str()).join(CERT_FINGERPRINT_FILE); - match cert_path.try_exists() { - Ok(true) => { - info!("Found certifacte fingerprint file."); - Ok(fs::read_to_string(cert_path)?.trim().into()) - } - _ => Err(Error::msg(format!( - "could not find cert fingerprint file expected at: {}", - cert_path.display() - ))), - } - } - /// Fetches search domain from resolv.conf file fn get_search_domain() -> Result { info!("Retrieving default search domain."); diff --git a/proxmox-fetch-answer/src/main.rs b/proxmox-fetch-answer/src/main.rs index 8c762e9..fe5d599 100644 --- a/proxmox-fetch-answer/src/main.rs +++ b/proxmox-fetch-answer/src/main.rs @@ -1,13 +1,15 @@ use anyhow::{anyhow, Error, Result}; use fetch_plugins::{http::FetchFromHTTP, partition::FetchFromPartition}; use log::{error, info, LevelFilter}; -use proxmox_auto_installer::log::AutoInstLogger; +use proxmox_auto_installer::{log::AutoInstLogger, utils::{AutoInstModes, AutoInstSettings}}; +use std::{fs, path::PathBuf}; use std::io::Write; use std::process::{Command, ExitCode, Stdio}; mod fetch_plugins; static LOGGER: AutoInstLogger = AutoInstLogger; +static AUTOINST_MODE_FILE: &str = "/cdrom/autoinst-mode.toml"; pub fn init_log() -> Result<()> { AutoInstLogger::init("/tmp/fetch_answer.log")?; @@ -16,16 +18,40 @@ pub fn init_log() -> Result<()> { .map_err(|err| anyhow!(err)) } -fn fetch_answer() -> Result { - match FetchFromPartition::get_answer() { - Ok(answer) => return Ok(answer), - Err(err) => info!("Fetching answer file from partition failed: {err}"), - } - match FetchFromHTTP::get_answer() { - Ok(answer) => return Ok(answer), - Err(err) => info!("Fetching answer file via HTTP failed: {err}"), - } +fn fetch_answer(install_settings: &AutoInstSettings) -> Result { + info!("Fetching answer file in mode {:?}:", &install_settings.mode); + match install_settings.mode { + AutoInstModes::Auto => { + match FetchFromPartition::get_answer() { + Ok(answer) => return Ok(answer), + Err(err) => info!("Fetching answer file from partition failed: {err}"), + } + match FetchFromHTTP::get_answer(install_settings) { + Ok(answer) => return Ok(answer), + Err(err) => info!("Fetching answer file via HTTP failed: {err}"), + } + }, + AutoInstModes::Included => { + let answer_path = PathBuf::from("/cdrom/answer.toml"); + match fetch_plugins::utils::get_answer_file(&answer_path) { + Ok(answer) => return Ok(answer), + Err(err) => info!("Fetching answer file from ISO failed: {err}"), + } + }, + AutoInstModes::Partition => { + match FetchFromPartition::get_answer() { + Ok(answer) => return Ok(answer), + Err(err) => info!("Fetching answer file from partition failed: {err}"), + } + }, + AutoInstModes::Http => { + match FetchFromHTTP::get_answer(install_settings) { + Ok(answer) => return Ok(answer), + Err(err) => info!("Fetching answer file via HTTP failed: {err}"), + } + }, + } Err(Error::msg("Could not find any answer file!")) } @@ -34,8 +60,22 @@ fn main() -> ExitCode { panic!("could not initialize logging: {err}"); } - info!("Fetching answer file"); - let answer = match fetch_answer() { + let raw_install_settings = match fs::read_to_string(AUTOINST_MODE_FILE) { + Ok(f) => f, + Err(err) => { + error!("Could not find needed file '{AUTOINST_MODE_FILE}' in live environment: {err}"); + return ExitCode::FAILURE; + }, + }; + let install_settings: AutoInstSettings = match toml::from_str(raw_install_settings.as_str()) { + Ok(content) => content, + Err(err) => { + error!("Failed to parse '{AUTOINST_MODE_FILE}': {err}"); + return ExitCode::FAILURE; + }, + }; + + let answer = match fetch_answer(&install_settings) { Ok(answer) => answer, Err(err) => { error!("Aborting: {}", err); -- 2.39.2 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel