[Cialug] JSON Question

Todd Walton tdwalton at gmail.com
Fri Oct 4 18:39:54 UTC 2019


I have a test JSON file that closely resembles the format of a for-real
JSON stream I get out of Ansible. It does something aggravating: it returns
a set of host data in a JSON object that doesn't include a unique
identifier for the host. Instead, it uses a key:value pair with the key
being the hostname and the value being a JSON object with all the
attributes of the host. Here's my test file, check it out:

todd $ jq '.' test-data.json
{
  "tasks": [
    {
      "hosts": {
        "hostone.example.com": {
          "_ansible_no_log": false,
          "_ansible_parsed": true,
          "action": "command",
          "changed": true,
          "failed": false,
          "msg": "non-zero return code",
          "stderr": "",
          "stderr_lines": [],
          "stdout": "",
          "stdout_lines": []
        },
        "hosttwo.example.com": {
          "_ansible_no_log": false,
          "_ansible_parsed": true,
          "action": "command",
          "changed": true,
          "failed": true,
          "msg": "non-zero return code",
          "stderr": "",
          "stderr_lines": [],
          "stdout": "",
          "stdout_lines": []
        }
      }
    }
  ]
}

jq has a feature whereby if you append '.[]' to an object it will return
just the values of the object. So in this case:

todd $ jq '.tasks[].hosts[]' test-data.json
{
  "_ansible_no_log": false,
  "_ansible_parsed": true,
  "action": "command",
  "changed": true,
  "failed": false,
  "msg": "non-zero return code",
  "stderr": "",
  "stderr_lines": [],
  "stdout": "",
  "stdout_lines": []
}
{
  "_ansible_no_log": false,
  "_ansible_parsed": true,
  "action": "command",
  "changed": true,
  "failed": true,
  "msg": "non-zero return code",
  "stderr": "",
  "stderr_lines": [],
  "stdout": "",
  "stdout_lines": []
}

I get the set of attributes for each host, but not the key names, i.e. not
the hostnames. But let's say I want to return the value of "failed" for
each host, associating each hostname with its value for "failed". So,
something like this:

{
  "hostone.example.com": false
  "hosttwo.example.com": true
}

or

{
  "hostone.example.com": {
    "failed": false
  },
  "hosttwo.example.com": {
    "failed": true
  }
}

How do I do that? How do I grab that hostname and use it in the later
expression? I've tried various things, including piping .tasks[] to a
custom object with the path I would take to each, but I'm not sure how to
get just one hostname at a time and query just that one, etc. Any
suggestions?

--
Todd


More information about the Cialug mailing list