Home > Software design >  Ansible get a subset of items from a list
Ansible get a subset of items from a list

Time:08-25

I have a list of output from an MQ command that shows the status of a channel, the stdout_lines of my registered variable is;

'stdout_lines': [u'CHANNEL(SVRCONN.CHL) CHLTYPE(SVRCONN) CONNAME(1.2.3.4) STATUS(RUNNING) SUBSTATE(RECEIVE)']}

This out worked OK for what I was intending on doing as I need to display the output of the CHANNEL and STATUS only and could find the values using a combinations of .split(')')[1].split('(')[1] and split(')')[4].split('(')[1] to get values SVRCONN.CHL and RUNNING

I have also been using this task for CLUSTER channel but found it was failing, the reason for this was that there is was an extra field,

'stdout_lines': [u'CHANNEL(CLUSTER_CHL) CHLTYPE(CLUSRCVR) CONNAME(2.3.4.5) RQMNAME(CLUS00) STATUS(RUNNING) SUBSTATE(RECEIVE)']}

now i could do a check to see if RQMNAME is in the output and then use a different split, but is there a way that this can be done using a string to find the location in output of STATUS?

CodePudding user response:

The best way is to convert it to real structured data, and you can then access any value that you need. The following is a somewhat hacky way to achieve that, but works:

- hosts: localhost
  tasks:
    - debug:
        msg: "{{ cooked.CHANNEL }} / {{ cooked.STATUS }}"
      vars:
        cooked: "{{ dict(item | split | map('regex_replace', '\\((. )\\)$', ' \\1') | map('split')) }}"
      loop:
        - 'CHANNEL(SVRCONN.CHL) CHLTYPE(SVRCONN) CONNAME(1.2.3.4) STATUS(RUNNING) SUBSTATE(RECEIVE)'
        - 'CHANNEL(CLUSTER_CHL) CHLTYPE(CLUSRCVR) CONNAME(2.3.4.5) RQMNAME(CLUS00) STATUS(RUNNING) SUBSTATE(RECEIVE)'

To parse this into a dictionary we split on whitespace, convert each key(value) into key value, split on whitespace again to separate keys from values, then pass that into dict().

PLAY [localhost] ****************************************************************

TASK [debug] ********************************************************************
ok: [localhost] => (item=CHANNEL(SVRCONN.CHL) CHLTYPE(SVRCONN) CONNAME(1.2.3.4) STATUS(RUNNING) SUBSTATE(RECEIVE)) => {
    "msg": "SVRCONN.CHL / RUNNING"
}
ok: [localhost] => (item=CHANNEL(CLUSTER_CHL) CHLTYPE(CLUSRCVR) CONNAME(2.3.4.5) RQMNAME(CLUS00) STATUS(RUNNING) SUBSTATE(RECEIVE)) => {
    "msg": "CLUSTER_CHL / RUNNING"
}

CodePudding user response:

Given the list

lines:
  - CHANNEL(SVRCONN.CHL) CHLTYPE(SVRCONN) CONNAME(1.2.3.4) STATUS(RUNNING) SUBSTATE(RECEIVE)
  - CHANNEL(CLUSTER_CHL) CHLTYPE(CLUSRCVR) CONNAME(2.3.4.5) RQMNAME(CLUS00) STATUS(RUNNING) SUBSTATE(RECEIVE)

You can create the list of dictionaries without iteration. For example,

cooked: "{{ lines|map('split')|
                  map('map', 'regex_replace', '\\((. )\\)$', ' \\1')|
                  map('map', 'split')|
                  map('community.general.dict')|
                  list }}"

gives

cooked:
  - CHANNEL: SVRCONN.CHL
    CHLTYPE: SVRCONN
    CONNAME: 1.2.3.4
    STATUS: RUNNING
    SUBSTATE: RECEIVE
  - CHANNEL: CLUSTER_CHL
    CHLTYPE: CLUSRCVR
    CONNAME: 2.3.4.5
    RQMNAME: CLUS00
    STATUS: RUNNING
    SUBSTATE: RECEIVE

Example of a complete playbook for testing

- hosts: localhost

  vars:

    lines:
      - 'CHANNEL(SVRCONN.CHL) CHLTYPE(SVRCONN) CONNAME(1.2.3.4) STATUS(RUNNING) SUBSTATE(RECEIVE)'
      - 'CHANNEL(CLUSTER_CHL) CHLTYPE(CLUSRCVR) CONNAME(2.3.4.5) RQMNAME(CLUS00) STATUS(RUNNING) SUBSTATE(RECEIVE)'

    cooked: "{{ lines|map('split')|
                      map('map', 'regex_replace', '\\((. )\\)$', ' \\1')|
                      map('map', 'split')|
                      map('community.general.dict')|
                      list }}"

  tasks:

    - debug:
        var: cooked
    - debug:
        msg: "{{ item.CHANNEL }} / {{ item.STATUS }}"
      loop: "{{ cooked }}"
  • Related