Home > Blockchain >  How to concisely extract or merge hash values in Ansible playbook
How to concisely extract or merge hash values in Ansible playbook

Time:02-25

To simplify printing shell output in many simple situations, I'd like a quick Ansible Playbook snippet to show just the stdout_lines and stderr_lines — but still keeping them distinct.

- name: demo output streams
  shell: "echo hi stdout; echo ho stderr 1>&2; false; true"
  register: tout

- debug:
    var: tout

gives this:

TASK [debug] **************************************************************
ok: [remote] => {
    "tout": {
        "changed": true,
        "cmd": "echo hi stdout; echo ho stderr 1>&2; false; true",
        "delta": "0:00:00.011020",
        "end": "2022-02-24 16:19:25.812732",
        "failed": false,
        "msg": "",
        "rc": 0,
        "start": "2022-02-24 16:19:25.801712",
        "stderr": "ho stderr",
        "stderr_lines": [
            "ho stderr"
        ],
        "stdout": "hi stdout",
        "stdout_lines": [
            "hi stdout"
        ]
    }
}

What I want is something more concise like this, or perhaps split, but still referenced by a single debug task in the Playbook. (Integrated into the shell task itself would be even more ideal, but I guess that's off the table.)

TASK [debug] **************************************************************
ok: [remote] => {
    "tout": {
        "stderr_lines": [
            "ho stderr"
        ],
        "stdout_lines": [
            "hi stdout"
        ]
    }
}

The false and true fluff just indicates that I simply want to see the command outputs, without Ansible-worrying about success or failure.

Of course I could use multiple debug's, but that output becomes cumbersome when there are many of these quick-info tasks.

CodePudding user response:

you could do something like this:

- name: demo output streams
  shell: "echo hi stdout; echo ho stderr 1>&2; false; true"
  register: tout

- debug:
    var: result
  vars: 
    result: "{{ {'tout': [{'stdout_lines': tout.stdout_lines}, {'stderr_lines': tout.stderr_lines}]} }}"

or using

- debug:
    var: result
  vars: 
    result: "{{ {'tout': { 'stdout_lines': tout.stdout_lines, 'stderr_lines': tout.stderr_lines} } }}"

if you want something easy to read, create a custom plugin: (here onlystd)

#!/usr/bin/python
class FilterModule(object):
    def filters(self):
        return {
            'onlystd': self.onlystd
        }
 
    def onlystd(self, out, name = ''):
        result= { 'stdout_lines': out['stdout_lines'], 'stderr_lines': out['stderr_lines'] }
        if name != '':
            result= { name: result }
        
        return result

playbook to use it

- name: "make this working"
  hosts: localhost
  vars:

  tasks:
    - name: demo output streams
      shell: "echo hi stdout; echo ho stderr 1>&2; false; true"
      register: tout

    - debug:
        var: tout | onlystd('tout') #if you want a name

    - debug:
        var: tout | onlystd   #without name

results:

ok: [localhost] => {
    "tout | onlystd('tout')": {
        "tout": {
            "stderr_lines": [
                "ho stderr"
            ],
            "stdout_lines": [
                "hi stdout"
            ]
        }
    }
}

ok: [localhost] => {
    "tout | onlystd": {
        "stderr_lines": [
            "ho stderr"
        ],
        "stdout_lines": [
            "hi stdout"
        ]
    }
}

CodePudding user response:

Use selectattr to filter the keys given by the result of the filter dict2items on your dictionary. Then swap it back to a dictionary with items2dict.

Given:

- name: demo output streams
  shell: "echo hi stdout; echo ho stderr 1>&2; false; true"
  register: tout

- debug:
    var: tout | dict2items | selectattr('key', 'in', _keys_filter) | items2dict
  vars:
    _keys_filter:
      - stdout_lines
      - stderr_lines

This would yield:

TASK [demo output streams] ***************************************************
changed: [localhost]

TASK [debug] *****************************************************************
ok: [localhost] => 
  tout | dict2items | selectattr('key', 'in', _keys_filter) | items2dict:
    stderr_lines:
    - ho stderr
    stdout_lines:
    - hi stdout
  • Related