chore: refactor pxe templates to jinja templates rendered by askama
Some checks failed
Run Check Script / check (pull_request) Failing after 36s
Some checks failed
Run Check Script / check (pull_request) Failing after 36s
This commit is contained in:
parent
94ddf027dd
commit
57c3b01e66
52
Cargo.lock
generated
52
Cargo.lock
generated
@ -362,6 +362,48 @@ version = "1.7.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "askama"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
|
||||||
|
dependencies = [
|
||||||
|
"askama_derive",
|
||||||
|
"itoa",
|
||||||
|
"percent-encoding",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "askama_derive"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
|
||||||
|
dependencies = [
|
||||||
|
"askama_parser",
|
||||||
|
"basic-toml",
|
||||||
|
"memchr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustc-hash",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "askama_parser"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "assert_cmd"
|
name = "assert_cmd"
|
||||||
version = "2.0.17"
|
version = "2.0.17"
|
||||||
@ -485,6 +527,15 @@ version = "1.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
|
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "basic-toml"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bcrypt-pbkdf"
|
name = "bcrypt-pbkdf"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
@ -1659,6 +1710,7 @@ dependencies = [
|
|||||||
name = "example-pxe"
|
name = "example-pxe"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"askama",
|
||||||
"cidr",
|
"cidr",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"harmony",
|
"harmony",
|
||||||
|
@ -16,3 +16,4 @@ harmony_macros = { path = "../../harmony_macros" }
|
|||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
env_logger = { workspace = true }
|
env_logger = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
|
askama = "0.14.0"
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
mod topology;
|
mod topology;
|
||||||
|
|
||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
|
use askama::Template;
|
||||||
use harmony::{
|
use harmony::{
|
||||||
data::{FileContent, FilePath},
|
data::{FileContent, FilePath},
|
||||||
modules::{dhcp::DhcpScore, http::StaticFilesHttpScore, tftp::TftpScore},
|
modules::{dhcp::DhcpScore, http::StaticFilesHttpScore, tftp::TftpScore},
|
||||||
@ -13,7 +16,7 @@ use crate::topology::{get_inventory, get_topology};
|
|||||||
async fn main() {
|
async fn main() {
|
||||||
let inventory = get_inventory();
|
let inventory = get_inventory();
|
||||||
let topology = get_topology().await;
|
let topology = get_topology().await;
|
||||||
let gateway_ip = topology.router.get_gateway();
|
let gateway_ip = &topology.router.get_gateway();
|
||||||
|
|
||||||
let kickstart_filename = "inventory.kickstart";
|
let kickstart_filename = "inventory.kickstart";
|
||||||
let cluster_pubkey_filename = "cluster_ssh_key.pub";
|
let cluster_pubkey_filename = "cluster_ssh_key.pub";
|
||||||
@ -33,160 +36,30 @@ async fn main() {
|
|||||||
files_to_serve: Url::LocalFolder("./data/pxe/okd/tftpboot/".to_string()),
|
files_to_serve: Url::LocalFolder("./data/pxe/okd/tftpboot/".to_string()),
|
||||||
}),
|
}),
|
||||||
Box::new(StaticFilesHttpScore {
|
Box::new(StaticFilesHttpScore {
|
||||||
folder_to_serve: Some(Url::LocalFolder("./data/pxe/okd/http_files/".to_string())),
|
// TODO The current russh based copy is way too slow, check for a lib update or use scp
|
||||||
|
// when available
|
||||||
|
//
|
||||||
|
// For now just run :
|
||||||
|
// scp -r data/pxe/okd/http_files/* root@192.168.1.1:/usr/local/http/
|
||||||
|
//
|
||||||
|
folder_to_serve: None,
|
||||||
|
// folder_to_serve: Some(Url::LocalFolder("./data/pxe/okd/http_files/".to_string())),
|
||||||
files: vec![
|
files: vec![
|
||||||
FileContent {
|
FileContent {
|
||||||
path: FilePath::Relative("boot.ipxe".to_string()),
|
path: FilePath::Relative("boot.ipxe".to_string()),
|
||||||
content: format!(
|
content: BootIpxeTpl { gateway_ip }.to_string(),
|
||||||
"#!ipxe
|
|
||||||
|
|
||||||
set base-url http://{gateway_ip}:8080
|
|
||||||
set hostfile ${{base-url}}/byMAC/01-${{mac:hexhyp}}.ipxe
|
|
||||||
|
|
||||||
chain ${{hostfile}} || chain ${{base-url}}/default.ipxe"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
FileContent {
|
FileContent {
|
||||||
path: FilePath::Relative(kickstart_filename.to_string()),
|
path: FilePath::Relative(kickstart_filename.to_string()),
|
||||||
content: format!(
|
content: InventoryKickstartTpl {
|
||||||
r#"# =================================================================
|
gateway_ip,
|
||||||
# Harmony Discovery Agent - Kickstart File (inventory.kickstart)
|
harmony_inventory_agent,
|
||||||
# =================================================================
|
cluster_pubkey_filename,
|
||||||
#
|
}.to_string(),
|
||||||
# This Kickstart file configures the CentOS Stream 9 live environment.
|
|
||||||
# It does NOT install to disk. It sets up SSH for remote access
|
|
||||||
# and downloads and runs the harmony-inventory-agent.
|
|
||||||
#
|
|
||||||
|
|
||||||
# --- System Configuration
|
|
||||||
lang en_US.UTF-8
|
|
||||||
keyboard --xlayouts='us'
|
|
||||||
timezone America/New_York --isUtc
|
|
||||||
|
|
||||||
# --- Network Configuration
|
|
||||||
# Ensure the network is activated using DHCP.
|
|
||||||
network --bootproto=dhcp --device=link --activate
|
|
||||||
|
|
||||||
# --- Security Configuration
|
|
||||||
# Disable the firewall for this isolated provisioning network.
|
|
||||||
firewall --disabled
|
|
||||||
# Disable SELinux for simplicity in the live environment.
|
|
||||||
selinux --disabled
|
|
||||||
# Disable password-based root login for security.
|
|
||||||
rootpw --lock
|
|
||||||
|
|
||||||
# --- Service Configuration
|
|
||||||
# Ensure the SSH daemon is enabled.
|
|
||||||
services --enabled="sshd"
|
|
||||||
|
|
||||||
# We are running a live environment, so no disk partitioning.
|
|
||||||
# The 'liveimg' command would be used here if booting from a squashfs,
|
|
||||||
# but since we are booting from kernel/initrd, we just use the %post.
|
|
||||||
|
|
||||||
# Do not run the graphical initial setup wizard.
|
|
||||||
firstboot --disable
|
|
||||||
|
|
||||||
# --- Post-Boot Scripting
|
|
||||||
# This section runs after the live environment has booted into RAM.
|
|
||||||
%post --log=/root/ks-post.log
|
|
||||||
|
|
||||||
echo "Harmony Kickstart: Post-boot script started."
|
|
||||||
|
|
||||||
# 1. Configure SSH Access
|
|
||||||
# Create the .ssh directory and set correct permissions.
|
|
||||||
echo " - Setting up SSH authorized_keys..."
|
|
||||||
mkdir -p /root/.ssh
|
|
||||||
chmod 700 /root/.ssh
|
|
||||||
|
|
||||||
# Download the public key and place it in authorized_keys.
|
|
||||||
curl -sSL "http://{gateway_ip}:8080/{cluster_pubkey_filename}" -o /root/.ssh/authorized_keys
|
|
||||||
chmod 600 /root/.ssh/authorized_keys
|
|
||||||
|
|
||||||
# SELinux context is handled by 'selinux --disabled' above,
|
|
||||||
# but if SELinux were enabled, this would be essential:
|
|
||||||
# restorecon -R /root/.ssh
|
|
||||||
|
|
||||||
# 2. Download the Harmony Inventory Agent
|
|
||||||
echo " - Downloading harmony-inventory-agent..."
|
|
||||||
curl -sSL "http://{gateway_ip}:8080/{harmony_inventory_agent}" -o /usr/local/bin/harmony-inventory-agent
|
|
||||||
chmod +x /usr/local/bin/harmony-inventory-agent
|
|
||||||
|
|
||||||
# 3. Create a systemd service to run the agent persistently
|
|
||||||
echo " - Creating systemd service for the agent..."
|
|
||||||
cat > /etc/systemd/system/harmony-agent.service << EOF
|
|
||||||
[Unit]
|
|
||||||
Description=Harmony Inventory Agent
|
|
||||||
After=network-online.target
|
|
||||||
Wants=network-online.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
ExecStart=/usr/local/bin/harmony-inventory-agent
|
|
||||||
Restart=always
|
|
||||||
RestartSec=5
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# 4. Enable and start the service
|
|
||||||
echo " - Enabling and starting harmony-agent.service..."
|
|
||||||
systemctl daemon-reload
|
|
||||||
systemctl enable --now harmony-agent.service
|
|
||||||
|
|
||||||
echo "Harmony Kickstart: Post-boot script finished. The inventory agent is running."
|
|
||||||
|
|
||||||
curl localhost:8080/inventory | tee -a /tmp/harmony_inventory.json
|
|
||||||
|
|
||||||
%end
|
|
||||||
|
|
||||||
# Do not automatically reboot or poweroff.
|
|
||||||
# The machine should remain running for inventory scraping."#
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
FileContent {
|
FileContent {
|
||||||
path: FilePath::Relative("default.ipxe".to_string()),
|
path: FilePath::Relative("fallback.ipxe".to_string()),
|
||||||
content: format!(
|
content: FallbackIpxeTpl { gateway_ip, kickstart_filename}.to_string(),
|
||||||
r#"#!ipxe
|
|
||||||
|
|
||||||
# =================================================================
|
|
||||||
# Harmony Discovery Agent - Default Boot Script (default.ipxe)
|
|
||||||
# =================================================================
|
|
||||||
#
|
|
||||||
# This script boots the CentOS Stream live environment for the
|
|
||||||
# purpose of hardware inventory. It loads the kernel and initramfs
|
|
||||||
# directly and passes a Kickstart URL for full automation.
|
|
||||||
#
|
|
||||||
|
|
||||||
# --- Configuration
|
|
||||||
# Set the base URL for where the CentOS kernel/initrd are hosted.
|
|
||||||
set os_base_url http://{gateway_ip}:8080/os/centos-stream-9
|
|
||||||
# Set the URL for the Kickstart file.
|
|
||||||
set ks_url http://{gateway_ip}:8080/{kickstart_filename}
|
|
||||||
|
|
||||||
# --- Boot Process
|
|
||||||
echo "Harmony: Starting automated node discovery..."
|
|
||||||
echo "Fetching kernel from ${{os_base_url}}/vmlinuz..."
|
|
||||||
kernel ${{os_base_url}}/vmlinuz
|
|
||||||
|
|
||||||
echo "Fetching initramfs from ${{os_base_url}}/initrd.img..."
|
|
||||||
initrd ${{os_base_url}}/initrd.img
|
|
||||||
|
|
||||||
echo "Configuring kernel boot arguments..."
|
|
||||||
# Kernel Arguments Explained:
|
|
||||||
# - initrd=initrd.img: Specifies the initial ramdisk to use.
|
|
||||||
# - inst.stage2: Points to the OS source. For a live boot, the base URL is sufficient.
|
|
||||||
# - inst.ks: CRITICAL: Points to our Kickstart file for automation.
|
|
||||||
# - ip=dhcp: Ensures the live environment configures its network.
|
|
||||||
# - console=...: Provides boot output on both serial and graphical consoles for debugging.
|
|
||||||
imgargs vmlinuz initrd=initrd.img inst.stage2=${{os_base_url}} inst.ks=${{ks_url}} ip=dhcp console=ttyS0,115200 console=tty1
|
|
||||||
|
|
||||||
echo "Booting into CentOS Stream 9 live environment..."
|
|
||||||
boot || goto failed
|
|
||||||
|
|
||||||
:failed
|
|
||||||
echo "Boot failed. Dropping to iPXE shell."
|
|
||||||
shell"#
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
@ -196,3 +69,24 @@ shell"#
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "boot.ipxe.j2")]
|
||||||
|
struct BootIpxeTpl<'a> {
|
||||||
|
gateway_ip: &'a IpAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "fallback.ipxe.j2")]
|
||||||
|
struct FallbackIpxeTpl<'a> {
|
||||||
|
gateway_ip: &'a IpAddr,
|
||||||
|
kickstart_filename: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "inventory.kickstart.j2")]
|
||||||
|
struct InventoryKickstartTpl<'a> {
|
||||||
|
gateway_ip: &'a IpAddr,
|
||||||
|
cluster_pubkey_filename: &'a str,
|
||||||
|
harmony_inventory_agent: &'a str,
|
||||||
|
}
|
||||||
|
6
examples/okd_pxe/templates/boot.ipxe.j2
Normal file
6
examples/okd_pxe/templates/boot.ipxe.j2
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#!ipxe
|
||||||
|
|
||||||
|
set base-url http://{{ gateway_ip }}:8080
|
||||||
|
set hostfile ${base-url}/byMAC/01-${mac:hexhyp}.ipxe
|
||||||
|
|
||||||
|
chain ${hostfile} || chain ${base-url}/fallback.ipxe
|
40
examples/okd_pxe/templates/fallback.ipxe.j2
Normal file
40
examples/okd_pxe/templates/fallback.ipxe.j2
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#!ipxe
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# Harmony Discovery Agent - Default Boot Script (default.ipxe)
|
||||||
|
# =================================================================
|
||||||
|
#
|
||||||
|
# This script boots the CentOS Stream live environment for the
|
||||||
|
# purpose of hardware inventory. It loads the kernel and initramfs
|
||||||
|
# directly and passes a Kickstart URL for full automation.
|
||||||
|
#
|
||||||
|
|
||||||
|
# --- Configuration
|
||||||
|
# Set the base URL for where the CentOS kernel/initrd are hosted.
|
||||||
|
set os_base_url http://{{gateway_ip}}:8080/os/centos-stream-9
|
||||||
|
# Set the URL for the Kickstart file.
|
||||||
|
set ks_url http://{{ gateway_ip }}:8080/{{ kickstart_filename }}
|
||||||
|
|
||||||
|
# --- Boot Process
|
||||||
|
echo "Harmony: Starting automated node discovery..."
|
||||||
|
echo "Fetching kernel from ${os_base_url}/vmlinuz..."
|
||||||
|
kernel ${os_base_url}/vmlinuz
|
||||||
|
|
||||||
|
echo "Fetching initramfs from ${os_base_url}/initrd.img..."
|
||||||
|
initrd ${os_base_url}/initrd.img
|
||||||
|
|
||||||
|
echo "Configuring kernel boot arguments..."
|
||||||
|
# Kernel Arguments Explained:
|
||||||
|
# - initrd=initrd.img: Specifies the initial ramdisk to use.
|
||||||
|
# - inst.stage2: Points to the OS source. For a live boot, the base URL is sufficient.
|
||||||
|
# - inst.ks: CRITICAL: Points to our Kickstart file for automation.
|
||||||
|
# - ip=dhcp: Ensures the live environment configures its network.
|
||||||
|
# - console=...: Provides boot output on both serial and graphical consoles for debugging.
|
||||||
|
imgargs vmlinuz initrd=initrd.img inst.stage2=${os_base_url} inst.ks=${ks_url} ip=dhcp console=ttyS0,115200 console=tty1
|
||||||
|
|
||||||
|
echo "Booting into CentOS Stream 9 live environment..."
|
||||||
|
boot || goto failed
|
||||||
|
|
||||||
|
:failed
|
||||||
|
echo "Boot failed. Dropping to iPXE shell."
|
||||||
|
shell
|
92
examples/okd_pxe/templates/inventory.kickstart.j2
Normal file
92
examples/okd_pxe/templates/inventory.kickstart.j2
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# =================================================================
|
||||||
|
# Harmony Discovery Agent - Kickstart File (inventory.kickstart)
|
||||||
|
# =================================================================
|
||||||
|
#
|
||||||
|
# This Kickstart file configures the CentOS Stream 9 live environment.
|
||||||
|
# It does NOT install to disk. It sets up SSH for remote access
|
||||||
|
# and downloads and runs the harmony-inventory-agent.
|
||||||
|
#
|
||||||
|
|
||||||
|
# --- System Configuration
|
||||||
|
lang en_US.UTF-8
|
||||||
|
keyboard --xlayouts='us'
|
||||||
|
timezone America/New_York --isUtc
|
||||||
|
|
||||||
|
# --- Network Configuration
|
||||||
|
# Ensure the network is activated using DHCP.
|
||||||
|
network --bootproto=dhcp --device=link --activate
|
||||||
|
|
||||||
|
# --- Security Configuration
|
||||||
|
# Disable the firewall for this isolated provisioning network.
|
||||||
|
firewall --disabled
|
||||||
|
# Disable SELinux for simplicity in the live environment.
|
||||||
|
selinux --disabled
|
||||||
|
# Disable password-based root login for security.
|
||||||
|
rootpw --lock
|
||||||
|
|
||||||
|
# --- Service Configuration
|
||||||
|
# Ensure the SSH daemon is enabled.
|
||||||
|
services --enabled="sshd"
|
||||||
|
|
||||||
|
# We are running a live environment, so no disk partitioning.
|
||||||
|
# The 'liveimg' command would be used here if booting from a squashfs,
|
||||||
|
# but since we are booting from kernel/initrd, we just use the %post.
|
||||||
|
|
||||||
|
# Do not run the graphical initial setup wizard.
|
||||||
|
firstboot --disable
|
||||||
|
|
||||||
|
# --- Post-Boot Scripting
|
||||||
|
# This section runs after the live environment has booted into RAM.
|
||||||
|
%post --log=/root/ks-post.log
|
||||||
|
|
||||||
|
echo "Harmony Kickstart: Post-boot script started."
|
||||||
|
|
||||||
|
# 1. Configure SSH Access
|
||||||
|
# Create the .ssh directory and set correct permissions.
|
||||||
|
echo " - Setting up SSH authorized_keys..."
|
||||||
|
mkdir -p /root/.ssh
|
||||||
|
chmod 700 /root/.ssh
|
||||||
|
|
||||||
|
# Download the public key and place it in authorized_keys.
|
||||||
|
curl -sSL "http://{{ gateway_ip }}:8080/{{ cluster_pubkey_filename }}" -o /root/.ssh/authorized_keys
|
||||||
|
chmod 600 /root/.ssh/authorized_keys
|
||||||
|
|
||||||
|
# SELinux context is handled by 'selinux --disabled' above,
|
||||||
|
# but if SELinux were enabled, this would be essential:
|
||||||
|
# restorecon -R /root/.ssh
|
||||||
|
|
||||||
|
# 2. Download the Harmony Inventory Agent
|
||||||
|
echo " - Downloading harmony-inventory-agent..."
|
||||||
|
curl -sSL "http://{{ gateway_ip }}:8080/{{ harmony_inventory_agent }}" -o /usr/local/bin/harmony-inventory-agent
|
||||||
|
chmod +x /usr/local/bin/harmony-inventory-agent
|
||||||
|
|
||||||
|
# 3. Create a systemd service to run the agent persistently
|
||||||
|
echo " - Creating systemd service for the agent..."
|
||||||
|
cat > /etc/systemd/system/harmony-agent.service << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Harmony Inventory Agent
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/local/bin/harmony-inventory-agent
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 4. Enable and start the service
|
||||||
|
echo " - Enabling and starting harmony-agent.service..."
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now harmony-agent.service
|
||||||
|
|
||||||
|
echo "Harmony Kickstart: Post-boot script finished. The inventory agent is running."
|
||||||
|
|
||||||
|
curl localhost:8080/inventory | tee -a /tmp/harmony_inventory.json
|
||||||
|
|
||||||
|
%end
|
||||||
|
|
||||||
|
# Do not automatically reboot or poweroff.
|
||||||
|
# The machine should remain running for inventory scraping.
|
Loading…
Reference in New Issue
Block a user