hardware_report 0.1.7

Hardware inventory reports for observability and cluster acceptance testing
Documentation
use crate::ServerInfo;
use reqwest;
use serde::Serialize;
use std::collections::HashMap;
use std::error::Error;

#[derive(Debug)]
pub enum PostMethod {
    HTTPS,
    Disabled,
}

#[derive(Serialize)]
pub struct PostPayload {
    pub labels: HashMap<String, String>,
    pub system_id: String,
    pub result: ServerInfo,
}

fn resolve_system_id(data: &ServerInfo, system_identifier: Option<&str>) -> String {
    system_identifier
        .map(str::trim)
        .filter(|s| !s.is_empty())
        .map(String::from)
        .unwrap_or_else(|| data.summary.system_info.uuid.clone())
}

pub async fn post_data(
    data: ServerInfo,
    labels: HashMap<String, String>,
    system_identifier: Option<&str>,
    endpoint: &str,
    auth_token: Option<&str>,
    write_payload_to: Option<&str>,
    skip_tls_verify: bool,
) -> Result<(), Box<dyn Error>> {
    let system_id = resolve_system_id(&data, system_identifier);
    let payload = PostPayload {
        labels,
        system_id,
        result: data,
    };

    // Write payload to file if path is provided
    if let Some(path) = write_payload_to {
        match std::fs::write(path, serde_json::to_string_pretty(&payload)?) {
            Ok(_) => println!("Successfully saved payload to {path}"),
            Err(e) => eprintln!("Failed to write payload to {path}: {e}"),
        }
    }

    // Validate endpoint when posting is enabled
    if endpoint.trim().is_empty() {
        return Err("Endpoint URL is required when --post is enabled".into());
    }

    // Create a client with optional TLS verification
    let client = reqwest::Client::builder()
        .danger_accept_invalid_certs(skip_tls_verify)
        .build()?;
    let mut request = client.post(endpoint).json(&payload);

    if let Some(token) = auth_token {
        request = request.header("Authorization", format!("Bearer {token}"));
    }

    let response = request.send().await?;

    if !response.status().is_success() {
        let status = response.status();
        return Err(format!("HTTP request failed: {status}").into());
    }
    Ok(())
}