From b2465e53d506d7d8ba49a92a76bc661012c5355d Mon Sep 17 00:00:00 2001 From: Doug Holt Date: Wed, 15 Jul 2026 10:02:50 -0600 Subject: [PATCH] fix: make memory fact locale-safe and integer-valued MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The memory custom fact computed total_mb with awk's default print, which emits a float (e.g. 60760.1) whose decimal separator follows LC_NUMERIC. On comma-decimal locales the fact rendered as { "total_mb": 60760,1 } — invalid JSON — so Ansible fell back to providing the fact as a raw string and slurm.conf templating failed with an opaque AnsibleUnsafeText attribute error on total_mb. Use printf "%d" so the value is always an integer with no locale- dependent formatting (RealMemory expects an integer anyway), and harden the slurm.conf template to parse a string fact so a malformed fact fails clearly rather than with an attribute error. Fixes #1321 --- roles/facts/files/memory.fact | 5 ++++- roles/slurm/templates/etc/slurm/slurm.conf | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/roles/facts/files/memory.fact b/roles/facts/files/memory.fact index ced76c126..dad229622 100644 --- a/roles/facts/files/memory.fact +++ b/roles/facts/files/memory.fact @@ -1,2 +1,5 @@ #!/bin/bash -echo "{ \"total_mb\": $(free -m | grep Mem: | awk '{print $2*0.95}') }" \ No newline at end of file +# printf "%d" keeps the value an integer regardless of locale: the default +# awk print emits a float whose decimal separator follows LC_NUMERIC, which +# on comma-decimal locales produces invalid JSON and breaks the local fact. +echo "{ \"total_mb\": $(free -m | awk '/^Mem:/ {printf "%d", $2*0.95}') }" diff --git a/roles/slurm/templates/etc/slurm/slurm.conf b/roles/slurm/templates/etc/slurm/slurm.conf index 73015cd96..91d946007 100644 --- a/roles/slurm/templates/etc/slurm/slurm.conf +++ b/roles/slurm/templates/etc/slurm/slurm.conf @@ -133,6 +133,10 @@ GresTypes=gpu {% endif %} {% for node_name in groups['slurm-node'] %} {% set memory = hostvars[node_name]["ansible_local"]["memory"] -%} +{# If the custom fact failed JSON parsing Ansible hands us a string; + parse it here so a bad fact fails loudly instead of with an opaque + attribute error on total_mb. -#} +{% if memory is string %}{% set memory = memory | from_json -%}{% endif -%} {% set cpu_topology = hostvars[node_name]["ansible_local"]["topology"]["cpu_topology"] -%} {% set gpu_topology = hostvars[node_name]["ansible_local"]["topology"]["gpu_topology"] -%} NodeName={{ node_name }}{{ " " -}}