blancco: fix silent prefs fallback, suspend trap, display blank + add View
End-to-end fixes for Blancco Drive Eraser PXE flow uncovered by chasing
"reports never reach SMB share" across two air-gapped sites:
playbook/blancco-init.sh:
* Drop silent || true on wget of preferences.xml + config.xml. Fail
loud with shell-drop if download or marker grep fails. Background:
airootfs /opt/scripts/validate_preferences.sh restores
/albus/preferences.save (factory defaults, empty network_share) if
xmllint fails. wget failure made every report silently land nowhere.
* Clobber /albus/preferences.save with the same served file so even if
the validator fallback fires, the SMB target survives.
* Bind-mount /dev/null over /sys/power/{state,disk,mem_sleep,autosleep}
before switch_root. Albus's license-retry path writes /sys/power/state
directly (bypassing systemd targets); this is the last-line block.
* /dev/null symlinks for sleep/suspend/hibernate systemd targets in the
airootfs overlay + logind drop-in with IdleAction/Handle*=ignore.
Three independent layers because cmdline systemd.mask alone is bypassed
by direct /sys/power/state writes.
* xinitrc.d/00-no-screen-blank.sh runs xset s off -dpms + setterm
-blank 0 -powerdown 0 so the Blancco GUI doesn't blank during long
erasures.
* Removed the 20-failsafeDriver.conf "modesetting" pin. modesetting
needs DRM/KMS which we disable on kernel cmdline; "vesa" also failed
on NVIDIA. With the pin gone Xorg auto-picks fbdev which uses the
kernel framebuffer from vga=normal - works across Intel, AMD, and
older NVIDIA without nouveau.
playbook/pxe_server_setup.yml:
* dnsmasq.conf: explicit empty-value dhcp-option=3 + dhcp-option=6.
Without them, dnsmasq defaults to sending its own IP as router AND
DNS. Commenting the configured-value lines did NOT disable the push
(root cause of "wired keeps picking up 10.9.100.1 as gateway").
* Split the Blancco config.img extraction and preferences.xml deploy
into separate tasks. The previous shell-with-creates: gate caused
playbook re-runs to skip the prefs deploy entirely after first run.
* Added a validation task that runs python3 xml parse + grep on the
deployed preferences.xml to fail the playbook at deploy time if the
SMB markers are missing.
* Added Environment=TZ=America/New_York to the pxe-webapp systemd
service so report mtimes and audit log render in Eastern time even
if the Python process is started before timedatectl converges.
webapp:
* services/blancco_report.py: parse Blancco's XML report format
(recursive <entries name="..."> walker) into a friendly dict.
* templates/report_view.html: Bootstrap "Drive Erasure Certificate"
layout - hero summary, customer + system cards, per-drive cards with
step-by-step erasure timeline, document signing footer with
integrity hash detail.
* /reports/view/<filename> route + View button on the reports list
(XML reports only; PDFs still download).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -33,7 +33,7 @@ from lxml import etree
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
import config
|
||||
from services import deploy, fs, images, system, unattend, wim
|
||||
from services import blancco_report, deploy, fs, images, system, unattend, wim
|
||||
from services.audit import audit
|
||||
from services.csrf import init_csrf
|
||||
|
||||
@@ -390,6 +390,24 @@ def blancco_download_report(filename):
|
||||
return send_file(fpath, as_attachment=True)
|
||||
|
||||
|
||||
@app.route("/reports/view/<filename>")
|
||||
def blancco_view_report(filename):
|
||||
filename = secure_filename(filename)
|
||||
fpath = os.path.join(config.BLANCCO_REPORTS, filename)
|
||||
if not os.path.isfile(fpath):
|
||||
flash(f"Report not found: {filename}", "danger")
|
||||
return redirect(url_for("blancco_reports"))
|
||||
if not filename.lower().endswith(".xml"):
|
||||
flash("Formatted view supports XML reports only.", "warning")
|
||||
return redirect(url_for("blancco_reports"))
|
||||
try:
|
||||
data = blancco_report.parse(fpath)
|
||||
except Exception as ex:
|
||||
flash(f"Failed to parse {filename}: {ex}", "danger")
|
||||
return redirect(url_for("blancco_reports"))
|
||||
return render_template("report_view.html", filename=filename, data=data)
|
||||
|
||||
|
||||
@app.route("/reports/delete/<filename>", methods=["POST"])
|
||||
def blancco_delete_report(filename):
|
||||
filename = secure_filename(filename)
|
||||
|
||||
Reference in New Issue
Block a user