Gauge Hartwell
← all write-ups

correctly reported, misread

Skipped, Not Broken: What "12 of 15 Hosts Skipped" Actually Meant

TL;DR: An Ansible task built to generate DNS rewrites for every host in inventory reported most of the fleet as "skipped." The task wasn't malfunctioning — it was correctly detecting that most hosts had no meaningful hostname to build a record from in the first place, because they were defined in inventory.ini as bare IP addresses rather than named aliases.

The symptom

A task meant to add a DNS rewrite for every lab host, driven by hostvars[item].ansible_host, produced output like this across most of the fleet:

skipping: [10.0.1.130] => (item=10.0.2.1.hartwelg.com -> skipped)
skipping: [10.0.1.130] => (item=10.0.1.10.hartwelg.com -> skipped)
...
skipping: [10.0.1.130] => (item=k3s-master.hartwelg.com -> 10.0.1.20)

Twelve entries showed a nonsense domain — an IP address with .hartwelg.com stapled onto it — and no resolved answer. Three showed a real hostname and a real resolved IP.

Diagnosis

The task's own when: hostvars[item].ansible_host is defined condition was doing exactly its job: for the twelve failing entries, item was itself already a bare IP string ("10.0.2.1"), because that's literally how those hosts were written in inventory.ini — no separate name, no ansible_host= assignment. Building {{ item }}.hartwelg.com from that input produces a domain that's just an IP address with a suffix, and since no ansible_host fact exists separately for those entries, the condition correctly evaluated false and skipped them.

The three working entries — k3s-master, k3s-worker, thinclient — had already been defined with a real alias and a separate ansible_host= value, the only format the task was actually built to handle.

Root cause

The automation assumed every host in inventory had both a friendly name and a separate IP, because that happened to be true for the three hosts used to build and test it. It was true for 3 of roughly 15. The rest of the fleet had never been given that structure at all — this wasn't a bug in the DNS rewrite task, it was a gap in what the inventory itself provided for it to work with.

Fix

Converted the remaining bare-IP entries in inventory.ini to the same name ansible_host=IP format already working for the three good examples:

[gitlab]
gitlab ansible_host=10.0.1.10

[vault]
vault ansible_host=10.0.1.80

Before renaming anything, checked for existing references to each host by its current bare-IP identity as an actual Ansible target — hosts:, delegate_to:, hostvars[...], a habitual --limit — since those would break the moment the inventory name changed, distinct from places the same IP was used as plain configuration data (a curl target, a sonar.host.url value), which are unrelated strings and unaffected by renaming Ansible's own notion of the host:

grep -rn "10\.0\.1\.10" --include="*.yml" .

Each renamed host was tested individually with --check --diff before trusting the rename across the whole fleet at once.

What this demonstrates

"12 of 15 skipped" read, at a glance, like a bug report. It was actually the task correctly reporting that most of its inputs didn't contain what it needed — a distinction that mattered, because the fix wasn't in the task's logic at all, it was in the data being fed to it. Reading exactly what the skip condition was actually checking, rather than assuming the automation was broken, turned this from "why isn't this working" into a much narrower, more accurate question: "why do most of these hosts have no name to work with." That's also the kind of gap that tends to be invisible until something downstream actually tries to use the missing structure — the inventory had worked fine for every other purpose in this build right up until a task needed a real hostname to build something from.