Update eMMC provisioning documentation and deployment scripts: clarify one-command deploy process, enhance deployment layout details, and improve SSH setup instructions for LXC containers. Add functionality to dynamically find LXC by hostname and streamline backup directory configuration.
This commit is contained in:
@@ -1,11 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
# Deploy CM4 eMMC provisioning to a Proxmox host (creates LXC 201, installs scripts on host and in LXC).
|
||||
# Deploy CM4 eMMC provisioning to a Proxmox host: host scripts, udev, systemd units,
|
||||
# LXC container (dashboard), usbboot (rpiboot), and PiShrink. Uses hostname "cm4-provisioning"
|
||||
# to find the container on redeploy; creates with next available ID if not found.
|
||||
#
|
||||
# With host internet: installs usbboot and PiShrink so USB flash/backup and dashboard
|
||||
# Shrink/Compress work. The only manual step left is to add a golden image for Deploy.
|
||||
#
|
||||
# Usage: ./deploy-to-proxmox.sh [proxmox_host]
|
||||
# Example: ./deploy-to-proxmox.sh root@10.130.60.224
|
||||
# Optional: DEPLOY_ROOTFS_STORAGE=local-lvm (or local-zfs, etc.) — storage for LXC rootfs
|
||||
# Optional: CM4_BACKUPS_HOST_PATH=/mnt/storage/cm4-backups — host dir for backup images; bind-mounted into LXC so images are stored on the host
|
||||
# Requires: ssh key access to root@<host>
|
||||
# Logging: set DEPLOY_LOG=1 to also write to deploy-YYYYMMDD-HHMMSS.log in the script dir.
|
||||
# Example: ./deploy-to-proxmox.sh root@10.20.30.152
|
||||
#
|
||||
# Optional env:
|
||||
# DEPLOY_ROOTFS_STORAGE=local-lvm — LXC rootfs storage (default: local-lvm)
|
||||
# CM4_BACKUPS_HOST_PATH=/path — host dir for backups; bind-mounted into LXC
|
||||
# DEPLOY_LXC_ROOT_PASSWORD=secret — set root password in LXC and enable SSH
|
||||
# DEPLOY_LXC_SSH_KEY=/path/to/pub — copy this key to LXC root (default: ~/.ssh/id_ed25519.pub or id_rsa.pub)
|
||||
# DEPLOY_LOG=1 — also log to deploy-YYYYMMDD-HHMMSS.log
|
||||
#
|
||||
# Requires: ssh key access to root@<host>. For full install (usbboot, PiShrink), host needs internet.
|
||||
|
||||
set -e
|
||||
PROXMOX="${1:-root@10.130.60.224}"
|
||||
@@ -21,24 +32,56 @@ fi
|
||||
|
||||
log() { echo "[$(date -Iseconds)] $*"; }
|
||||
|
||||
log "Deploying to $PROXMOX ..."
|
||||
# Use a clean staging dir (remove if present so we never write into a symlink or bad state)
|
||||
log "[1/4] Cleaning remote staging dir ..."
|
||||
ssh "$PROXMOX" "rm -rf /tmp/emmc-provisioning-deploy"
|
||||
log "[2/4] Rsync repo to $PROXMOX ..."
|
||||
rsync -a "$REPO_DIR/" "$PROXMOX:/tmp/emmc-provisioning-deploy/" --exclude='.git' --exclude='scripts/deploy-to-proxmox.sh'
|
||||
log "[3/4] Running remote install (host + LXC) ..."
|
||||
# Optional: gather SSH key and LXC root password for setup inside deploy
|
||||
DEPLOY_SSH_KEY_B64=""
|
||||
DEPLOY_LXC_PWD_B64=""
|
||||
if [[ -n "${DEPLOY_LXC_ROOT_PASSWORD:-}" ]]; then
|
||||
DEPLOY_LXC_PWD_B64=$(echo -n "$DEPLOY_LXC_ROOT_PASSWORD" | base64 -w 0 2>/dev/null || base64 2>/dev/null | tr -d '\n')
|
||||
fi
|
||||
KEY_FILE="${DEPLOY_LXC_SSH_KEY:-}"
|
||||
if [[ -z "$KEY_FILE" ]]; then
|
||||
for f in ~/.ssh/id_ed25519.pub ~/.ssh/id_rsa.pub; do
|
||||
[[ -f "$f" ]] && { KEY_FILE="$f"; break; }
|
||||
done
|
||||
fi
|
||||
if [[ -n "$KEY_FILE" && -f "$KEY_FILE" ]]; then
|
||||
DEPLOY_SSH_KEY_B64=$(base64 -w 0 < "$KEY_FILE" 2>/dev/null || base64 < "$KEY_FILE" 2>/dev/null | tr -d '\n')
|
||||
log "Will copy SSH key to LXC: $KEY_FILE"
|
||||
fi
|
||||
[[ -n "$DEPLOY_LXC_ROOT_PASSWORD" ]] && log "Will set LXC root password (DEPLOY_LXC_ROOT_PASSWORD)."
|
||||
|
||||
ssh "$PROXMOX" "ROOTFS_STORAGE='$ROOTFS_STORAGE' CM4_BACKUPS_HOST_PATH='${CM4_BACKUPS_HOST_PATH:-}'" bash -s << 'REMOTE'
|
||||
log "Deploying to $PROXMOX ..."
|
||||
log "[1/5] Cleaning remote staging dir ..."
|
||||
ssh "$PROXMOX" "rm -rf /tmp/emmc-provisioning-deploy"
|
||||
log "[2/5] Rsync repo to $PROXMOX ..."
|
||||
rsync -a "$REPO_DIR/" "$PROXMOX:/tmp/emmc-provisioning-deploy/" --exclude='.git' --exclude='scripts/deploy-to-proxmox.sh' --exclude='scripts/deploy-*.log'
|
||||
log "[3/5] Running remote install (host + LXC) ..."
|
||||
|
||||
# Pass optional LXC SSH vars (base64) so remote can set password and add key
|
||||
ssh "$PROXMOX" "ROOTFS_STORAGE='$ROOTFS_STORAGE' CM4_BACKUPS_HOST_PATH='${CM4_BACKUPS_HOST_PATH:-}' DEPLOY_SSH_KEY_B64='${DEPLOY_SSH_KEY_B64:-}' DEPLOY_LXC_PWD_B64='${DEPLOY_LXC_PWD_B64:-}'" bash -s << 'REMOTE'
|
||||
set -e
|
||||
DEPLOY=/tmp/emmc-provisioning-deploy
|
||||
ROOTFS_STORAGE="${ROOTFS_STORAGE:-local-lvm}"
|
||||
BACKUPS_HOST_PATH="${CM4_BACKUPS_HOST_PATH:-}"
|
||||
LXC_HOSTNAME="cm4-provisioning"
|
||||
log() { echo "[$(date -Iseconds)] $*"; }
|
||||
|
||||
# Ensure LXC 201 exists (create if not)
|
||||
if ! pct status 201 &>/dev/null; then
|
||||
# Use Debian 12 template: prefer one in cache, else download latest
|
||||
# --- Find existing LXC by hostname or use next available ID ---
|
||||
CTID=""
|
||||
for id in $(pct list 2>/dev/null | awk 'NR>1 {print $1}'); do
|
||||
h=$(pct config "$id" 2>/dev/null | sed -n 's/^hostname: *//p')
|
||||
if [[ "$h" == "$LXC_HOSTNAME" ]]; then
|
||||
CTID="$id"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ -n "$CTID" ]]; then
|
||||
log "Found existing LXC $CTID (hostname: $LXC_HOSTNAME)."
|
||||
else
|
||||
MAX_ID=$(pct list 2>/dev/null | awk 'NR>1 {print $1}' | sort -n | tail -1)
|
||||
[[ -z "$MAX_ID" ]] && MAX_ID=0
|
||||
CTID=$((MAX_ID + 1))
|
||||
log "Creating LXC $CTID ($LXC_HOSTNAME) (rootfs on ${ROOTFS_STORAGE})..."
|
||||
VZTMPL_DIR=/var/lib/vz/template/cache
|
||||
DEBIAN12_TMPL=$(ls "$VZTMPL_DIR"/debian-12-standard_*.tar.zst 2>/dev/null | head -1)
|
||||
if [[ -z "$DEBIAN12_TMPL" ]]; then
|
||||
@@ -46,30 +89,28 @@ if ! pct status 201 &>/dev/null; then
|
||||
pveam download local debian-12-standard_12.12-1_amd64.tar.zst || pveam download local debian-12-standard_12.7-1_amd64.tar.zst
|
||||
DEBIAN12_TMPL=$(ls "$VZTMPL_DIR"/debian-12-standard_*.tar.zst 2>/dev/null | head -1)
|
||||
fi
|
||||
[[ -z "$DEBIAN12_TMPL" ]] && { log "Error: no Debian 12 template found"; exit 1; }
|
||||
TMPL_NAME=$(basename "$DEBIAN12_TMPL")
|
||||
log "Creating LXC 201 (cm4-provisioning) (rootfs on ${ROOTFS_STORAGE}, template ${TMPL_NAME})..."
|
||||
pct create 201 "local:vztmpl/${TMPL_NAME}" \
|
||||
--hostname cm4-provisioning --memory 1024 --swap 0 --cores 1 \
|
||||
pct create "$CTID" "local:vztmpl/${TMPL_NAME}" \
|
||||
--hostname "$LXC_HOSTNAME" --memory 1024 --swap 0 --cores 1 \
|
||||
--rootfs "${ROOTFS_STORAGE}:8" --net0 name=eth0,bridge=vmbr0,ip=dhcp \
|
||||
--unprivileged 0 --features nesting=1 -tag cm4-provisioning
|
||||
mkdir -p /var/lib/cm4-provisioning
|
||||
pct set 201 -mp0 /var/lib/cm4-provisioning,mp=/var/lib/cm4-provisioning
|
||||
log "LXC 201 created and mount configured."
|
||||
else
|
||||
log "LXC 201 already exists."
|
||||
pct set "$CTID" -mp0 /var/lib/cm4-provisioning,mp=/var/lib/cm4-provisioning
|
||||
log "LXC $CTID created and mount configured."
|
||||
fi
|
||||
|
||||
# Optional: bind-mount a host directory for backup images (so they are stored on the host, not LXC rootfs)
|
||||
# Optional: bind-mount host directory for backup images
|
||||
if [[ -n "$BACKUPS_HOST_PATH" ]]; then
|
||||
mkdir -p "$BACKUPS_HOST_PATH"
|
||||
pct stop 201 2>/dev/null || true
|
||||
pct set 201 -mp1 "$BACKUPS_HOST_PATH",mp=/var/lib/cm4-provisioning/backups
|
||||
pct start 201 2>/dev/null || true
|
||||
log "Backups mount: host $BACKUPS_HOST_PATH -> LXC /var/lib/cm4-provisioning/backups"
|
||||
pct stop "$CTID" 2>/dev/null || true
|
||||
pct set "$CTID" -mp1 "$BACKUPS_HOST_PATH",mp=/var/lib/cm4-provisioning/backups
|
||||
pct start "$CTID" 2>/dev/null || true
|
||||
log "Backups mount: host $BACKUPS_HOST_PATH -> LXC $CTID /var/lib/cm4-provisioning/backups"
|
||||
fi
|
||||
|
||||
# Host: install scripts and udev (from host/)
|
||||
log "Host: installing scripts and udev ..."
|
||||
# --- Host: scripts, systemd, udev ---
|
||||
log "Host: installing scripts and systemd units ..."
|
||||
mkdir -p /opt/cm4-provisioning /etc/cm4-provisioning
|
||||
cp "$DEPLOY/host/flash-emmc-on-connect.sh" /opt/cm4-provisioning/
|
||||
chmod +x /opt/cm4-provisioning/flash-emmc-on-connect.sh
|
||||
@@ -77,6 +118,7 @@ cp "$DEPLOY/host/build-cloudinit-image.sh" /opt/cm4-provisioning/
|
||||
chmod +x /opt/cm4-provisioning/build-cloudinit-image.sh
|
||||
cp "$DEPLOY/host/run-shrink-on-host.sh" /opt/cm4-provisioning/
|
||||
chmod +x /opt/cm4-provisioning/run-shrink-on-host.sh
|
||||
cp "$DEPLOY/scripts/fix-gadget-bootcode-on-host.sh" /opt/cm4-provisioning/ 2>/dev/null && chmod +x /opt/cm4-provisioning/fix-gadget-bootcode-on-host.sh || true
|
||||
cp "$DEPLOY/host/cm4-flash-trigger.sh" /usr/local/bin/
|
||||
chmod +x /usr/local/bin/cm4-flash-trigger.sh
|
||||
cp "$DEPLOY/host/cm4-flash.service" /etc/systemd/system/
|
||||
@@ -89,7 +131,8 @@ systemctl enable --now cm4-build-cloudinit.path 2>/dev/null || true
|
||||
systemctl enable --now cm4-shrink.path 2>/dev/null || true
|
||||
cp "$DEPLOY/host/89-cm4-boot-mode-permissions.rules" /etc/udev/rules.d/ 2>/dev/null || true
|
||||
cp "$DEPLOY/host/90-cm4-boot-mode.rules" /etc/udev/rules.d/
|
||||
udevadm control --reload-rules
|
||||
udevadm control --reload-rules 2>/dev/null || true
|
||||
|
||||
log "Host: env and dirs ..."
|
||||
cat > /opt/cm4-provisioning/env << 'ENV'
|
||||
GOLDEN_IMAGE=/var/lib/cm4-provisioning/golden.img
|
||||
@@ -101,44 +144,86 @@ touch /etc/cm4-provisioning/enabled
|
||||
mkdir -p /var/lib/cm4-provisioning/backups
|
||||
[[ -n "$BACKUPS_HOST_PATH" ]] && mkdir -p "$BACKUPS_HOST_PATH"
|
||||
|
||||
# Start LXC if stopped
|
||||
log "Starting LXC 201 if stopped ..."
|
||||
pct start 201 2>/dev/null || true
|
||||
# --- Host: install usbboot (rpiboot) so USB flash/backup works ---
|
||||
log "Host: installing usbboot (rpiboot)..."
|
||||
if bash "$DEPLOY/scripts/install-usbboot-on-host.sh" 2>&1; then
|
||||
log "Host: usbboot installed at /opt/usbboot/rpiboot"
|
||||
else
|
||||
log "Warning: usbboot install failed (e.g. no internet). USB flash/backup will not work until you run: bash /tmp/emmc-provisioning-deploy/scripts/install-usbboot-on-host.sh"
|
||||
fi
|
||||
|
||||
# LXC: install scripts (from host/)
|
||||
# --- Host: install PiShrink so dashboard Shrink/Compress work ---
|
||||
log "Host: installing PiShrink..."
|
||||
if bash "$DEPLOY/scripts/install-pishrink-on-host.sh" 2>&1; then
|
||||
log "Host: PiShrink installed"
|
||||
grep -q "SHRINK_BACKUP" /opt/cm4-provisioning/env || echo "SHRINK_BACKUP=1" >> /opt/cm4-provisioning/env
|
||||
grep -q "PISHRINK_COMPRESS" /opt/cm4-provisioning/env || echo "PISHRINK_COMPRESS=xz" >> /opt/cm4-provisioning/env
|
||||
else
|
||||
log "Warning: PiShrink install failed (e.g. no internet). Dashboard Shrink/Compress will report 'PiShrink not installed' until you run: bash /tmp/emmc-provisioning-deploy/scripts/install-pishrink-on-host.sh"
|
||||
fi
|
||||
|
||||
# --- Start LXC if stopped ---
|
||||
log "Starting LXC $CTID if stopped ..."
|
||||
pct start "$CTID" 2>/dev/null || true
|
||||
|
||||
# --- LXC: flash scripts (for reference; actual flash runs on host) ---
|
||||
log "LXC: installing flash scripts ..."
|
||||
pct exec 201 -- mkdir -p /opt/cm4-provisioning /etc/cm4-provisioning
|
||||
pct push 201 "$DEPLOY/host/flash-emmc-on-connect.sh" /opt/cm4-provisioning/flash-emmc-on-connect.sh
|
||||
pct exec 201 -- chmod +x /opt/cm4-provisioning/flash-emmc-on-connect.sh
|
||||
pct push 201 "$DEPLOY/host/cm4-flash-trigger.sh" /usr/local/bin/cm4-flash-trigger.sh
|
||||
pct exec 201 -- chmod +x /usr/local/bin/cm4-flash-trigger.sh
|
||||
pct exec 201 -- bash -c 'echo -e "GOLDEN_IMAGE=/var/lib/cm4-provisioning/golden.img\nRPIBOOT_DIR=/opt/usbboot\nEMMC_SIZE_BYTES=8589934592" > /opt/cm4-provisioning/env'
|
||||
pct exec "$CTID" -- mkdir -p /opt/cm4-provisioning /etc/cm4-provisioning
|
||||
pct push "$CTID" "$DEPLOY/host/flash-emmc-on-connect.sh" /opt/cm4-provisioning/flash-emmc-on-connect.sh
|
||||
pct exec "$CTID" -- chmod +x /opt/cm4-provisioning/flash-emmc-on-connect.sh
|
||||
pct push "$CTID" "$DEPLOY/host/cm4-flash-trigger.sh" /usr/local/bin/cm4-flash-trigger.sh
|
||||
pct exec "$CTID" -- chmod +x /usr/local/bin/cm4-flash-trigger.sh
|
||||
pct exec "$CTID" -- bash -c 'echo -e "GOLDEN_IMAGE=/var/lib/cm4-provisioning/golden.img\nRPIBOOT_DIR=/opt/usbboot\nEMMC_SIZE_BYTES=8589934592" > /opt/cm4-provisioning/env'
|
||||
|
||||
# LXC: install dashboard
|
||||
# --- LXC: dashboard (all files) ---
|
||||
log "LXC: installing dashboard ..."
|
||||
pct exec 201 -- mkdir -p /opt/cm4-provisioning/dashboard/templates
|
||||
pct push 201 "$DEPLOY/dashboard/app.py" /opt/cm4-provisioning/dashboard/app.py
|
||||
pct push 201 "$DEPLOY/dashboard/templates/index.html" /opt/cm4-provisioning/dashboard/templates/index.html
|
||||
pct push 201 "$DEPLOY/dashboard/cm4-dashboard.service" /opt/cm4-provisioning/dashboard/cm4-dashboard.service
|
||||
pct exec "$CTID" -- mkdir -p /opt/cm4-provisioning/dashboard/templates
|
||||
pct push "$CTID" "$DEPLOY/dashboard/app.py" /opt/cm4-provisioning/dashboard/app.py
|
||||
pct push "$CTID" "$DEPLOY/dashboard/templates/index.html" /opt/cm4-provisioning/dashboard/templates/index.html
|
||||
pct push "$CTID" "$DEPLOY/dashboard/cm4-dashboard.service" /opt/cm4-provisioning/dashboard/cm4-dashboard.service
|
||||
|
||||
# LXC: install Flask and enable dashboard service
|
||||
log "LXC: installing python3-flask and enabling cm4-dashboard service ..."
|
||||
pct exec 201 -- bash -c 'apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq python3-flask'
|
||||
pct exec 201 -- cp /opt/cm4-provisioning/dashboard/cm4-dashboard.service /etc/systemd/system/
|
||||
pct exec 201 -- systemctl daemon-reload
|
||||
pct exec 201 -- systemctl enable --now cm4-dashboard
|
||||
# --- LXC: Flask and systemd ---
|
||||
log "LXC: installing python3-flask and enabling cm4-dashboard ..."
|
||||
pct exec "$CTID" -- bash -c 'apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq python3-flask'
|
||||
pct exec "$CTID" -- cp /opt/cm4-provisioning/dashboard/cm4-dashboard.service /etc/systemd/system/
|
||||
pct exec "$CTID" -- systemctl daemon-reload
|
||||
pct exec "$CTID" -- systemctl enable --now cm4-dashboard
|
||||
log "LXC: cm4-dashboard enabled and started."
|
||||
|
||||
log "Deploy done (remote)."
|
||||
echo "Next: Install usbboot on host when online: ssh <host> 'bash /tmp/emmc-provisioning-deploy/scripts/install-usbboot-on-host.sh'"
|
||||
# --- LXC: optional SSH (root password + SSH key from deploy env) ---
|
||||
if [[ -n "${DEPLOY_SSH_KEY_B64:-}" ]] || [[ -n "${DEPLOY_LXC_PWD_B64:-}" ]]; then
|
||||
log "LXC: configuring SSH (root login, password, authorized_keys)..."
|
||||
pct exec "$CTID" -- bash -c 'apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openssh-server 2>/dev/null; systemctl enable ssh 2>/dev/null; systemctl start ssh 2>/dev/null' || true
|
||||
pct exec "$CTID" -- bash -c 'sed -i "s/^#*PermitRootLogin.*/PermitRootLogin yes/" /etc/ssh/sshd_config 2>/dev/null; grep -q "^PermitRootLogin" /etc/ssh/sshd_config || echo "PermitRootLogin yes" >> /etc/ssh/sshd_config; systemctl restart ssh 2>/dev/null || systemctl restart sshd 2>/dev/null' || true
|
||||
if [[ -n "${DEPLOY_LXC_PWD_B64:-}" ]]; then
|
||||
PWD_RAW=$(echo "$DEPLOY_LXC_PWD_B64" | base64 -d 2>/dev/null)
|
||||
echo "root:$PWD_RAW" | pct exec "$CTID" -- chpasswd 2>/dev/null && log "LXC: root password set." || true
|
||||
fi
|
||||
if [[ -n "${DEPLOY_SSH_KEY_B64:-}" ]]; then
|
||||
echo "$DEPLOY_SSH_KEY_B64" | base64 -d 2>/dev/null | pct exec "$CTID" -- bash -c "mkdir -p /root/.ssh; chmod 700 /root/.ssh; cat >> /root/.ssh/authorized_keys; chmod 600 /root/.ssh/authorized_keys" 2>/dev/null && log "LXC: SSH key added to /root/.ssh/authorized_keys." || true
|
||||
fi
|
||||
LXC_IP=$(pct exec "$CTID" -- hostname -I 2>/dev/null | awk '{print $1}')
|
||||
[[ -n "$LXC_IP" ]] && echo "LXC SSH: ssh root@$LXC_IP"
|
||||
fi
|
||||
|
||||
log "Deploy done (remote). LXC ID: $CTID"
|
||||
REMOTE
|
||||
|
||||
log "[4/4] Deploy finished."
|
||||
log "[5/5] Deploy finished."
|
||||
echo ""
|
||||
echo "Done. Put golden.img in /var/lib/cm4-provisioning/ on the host (or scp to LXC 201 at /var/lib/cm4-provisioning/)."
|
||||
[[ -n "${CM4_BACKUPS_HOST_PATH:-}" ]] && echo "Backup images are stored on the host at: $CM4_BACKUPS_HOST_PATH (bind-mounted into LXC at /var/lib/cm4-provisioning/backups)."
|
||||
echo "When the host has internet, run on the host: bash /tmp/emmc-provisioning-deploy/scripts/install-usbboot-on-host.sh"
|
||||
echo "Dashboard: install flask in LXC 201 and enable cm4-dashboard.service (see docs/PROXMOX-LXC-DEPLOYMENT.md)."
|
||||
echo "=== Deploy complete ==="
|
||||
echo "Host and LXC are fully set up: usbboot (rpiboot), PiShrink, dashboard, systemd, udev."
|
||||
echo ""
|
||||
echo "--- Only remaining step (manual) ---"
|
||||
echo " Add a golden image for Deploy (writing image to device):"
|
||||
echo " • Dashboard: open http://<LXC-IP>:5000 → Build cloud-init image → then Set as golden"
|
||||
echo " • Or copy your image: scp your-image.img $PROXMOX:/var/lib/cm4-provisioning/golden.img"
|
||||
echo " Backup (read from device) works without golden.img."
|
||||
echo ""
|
||||
echo "--- You have ---"
|
||||
echo " - Dashboard: http://<LXC-IP>:5000 (LXC IP: from Proxmox UI, or on host: pct exec <CTID> -- hostname -I)"
|
||||
[[ -n "${DEPLOY_LXC_ROOT_PASSWORD:-}" || -n "${DEPLOY_SSH_KEY_B64:-}" ]] && echo " - LXC SSH: ssh root@<LXC-IP> (password and/or key were set)"
|
||||
[[ -n "${CM4_BACKUPS_HOST_PATH:-}" ]] && echo " - Backups on host: $CM4_BACKUPS_HOST_PATH"
|
||||
if [[ -n "$LOG_FILE" ]]; then
|
||||
echo "Log written to: $LOG_FILE"
|
||||
echo " - Log: $LOG_FILE"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user