Files
harmony/opnsense-api/examples/list_packages.rs
Jean-Gabriel Gill-Couture da90dc55ad
Some checks failed
Run Check Script / check (pull_request) Failing after 19s
chore: cargo fmt across workspace
2026-03-25 23:20:57 -04:00

167 lines
5.2 KiB
Rust

//! Example: list all OPNsense packages (installed and available).
//!
//! ```text
//! cargo run --example list_packages
//! ```
//!
//! Calls `GET /api/core/firmware/info` which returns package listings
//! from OPNsense's firmware API.
use std::env;
use opnsense_api::client::OpnsenseClient;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct FirmwareInfoResponse {
pub product: ProductInfo,
#[serde(default)]
pub package: Vec<PackageInfo>,
#[serde(default)]
pub plugin: Vec<PackageInfo>,
}
#[derive(Debug, Deserialize)]
pub struct ProductInfo {
pub product_name: String,
pub product_version: String,
pub product_arch: String,
#[serde(default)]
pub product_check: Option<serde_json::Value>,
}
#[derive(Debug, Deserialize)]
pub struct PackageInfo {
pub name: String,
pub version: String,
#[serde(default)]
pub comment: String,
#[serde(default)]
pub flatsize: String,
#[serde(default)]
pub locked: String,
#[serde(default)]
pub automatic: String,
#[serde(default)]
pub license: String,
#[serde(default)]
pub repository: String,
#[serde(default)]
pub origin: String,
#[serde(default)]
pub provided: String,
#[serde(default)]
pub installed: String,
#[serde(default)]
pub configured: String,
#[serde(default)]
pub tier: String,
}
#[tokio::main]
async fn main() {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
let base_url =
env::var("OPNSENSE_BASE_URL").unwrap_or_else(|_| "https://192.168.1.1/api".to_string());
let client = match (
env::var("OPNSENSE_API_KEY").ok(),
env::var("OPNSENSE_API_SECRET").ok(),
) {
(Some(key), Some(secret)) => OpnsenseClient::builder()
.base_url(&base_url)
.auth_from_key_secret(&key, &secret)
.skip_tls_verify()
.build()
.expect("failed to build HTTP client"),
_ => {
eprintln!("ERROR: OPNSENSE_API_KEY and OPNSENSE_API_SECRET must be set.");
eprintln!(" export OPNSENSE_API_KEY=your_key");
eprintln!(" export OPNSENSE_API_SECRET=your_secret");
eprintln!(" export OPNSENSE_BASE_URL=https://your-firewall/api");
std::process::exit(1);
}
};
log::info!("Fetching /api/core/firmware/info ...");
let response: FirmwareInfoResponse = client
.get_typed("core", "firmware", "info")
.await
.expect("API call failed");
println!();
println!("╔═══════════════════════════════════════════════════════════╗");
println!("║ OPNsense Package Information ║");
println!("╚═══════════════════════════════════════════════════════════╝");
println!();
println!(
" {} {} ({})",
response.product.product_name,
response.product.product_version,
response.product.product_arch
);
println!();
let installed: Vec<_> = response
.plugin
.iter()
.filter(|p| p.installed == "1")
.collect();
let available: Vec<_> = response
.plugin
.iter()
.filter(|p| p.installed != "1" && p.provided == "1")
.collect();
println!(
" Installed plugins: {} (showing first 30)",
installed.len()
);
println!(" ─────────────────────────────────────────────────────────");
for pkg in installed.iter().take(30) {
println!(" {:40} {}", pkg.name, pkg.version);
}
if installed.len() > 30 {
println!(" ... and {} more", installed.len() - 30);
}
println!();
println!(
" Available plugins: {} (showing first 20)",
available.len()
);
println!(" ─────────────────────────────────────────────────────────");
for pkg in available.iter().take(20) {
println!(" {:40} {}", pkg.name, pkg.version);
}
if available.len() > 20 {
println!(" ... and {} more", available.len() - 20);
}
println!();
let os_packages: Vec<_> = response
.package
.iter()
.filter(|p| p.name.starts_with("os-"))
.collect();
println!(
" System packages (os-*): {} (showing first 20)",
os_packages.len()
);
println!(" ─────────────────────────────────────────────────────────");
for pkg in os_packages.iter().take(20) {
let installed = if pkg.installed == "1" {
" [installed]"
} else {
""
};
println!(" {:40} {}{}", pkg.name, pkg.version, installed);
}
if os_packages.len() > 20 {
println!(" ... and {} more", os_packages.len() - 20);
}
}