1

I am trying to get the "count" value from the dictionary

"{ \"_id\" : ObjectId(\"5d3a1643c43c898d01a3c740\"), \"count\" : 2 }"

present at the last element of the ansible stdout_lines.

TASK [version_update : debug] ******************************************************************************************************************************************
ok: [192.168.27.125] => {
    "count_info.stdout": "MongoDB shell version v4.0.6\nconnecting to: mongodb://127.0.0.1:27017/configure-db?gssapiServiceName=mongodb\nImplicit session: session { \"id\" : UUID(\"4bfad3ba-981f-47de-86f9-a1fadbe28e12\") }\nMongoDB server version: 4.0.6\n{ \"_id\" : ObjectId(\"5d3a1643c43c898d01a3c740\"), \"count\" : 2 }"
}

TASK [version_update : debug] ******************************************************************************************************************************************
ok: [192.168.27.125] => {
    "count_info.stdout_lines": [
        "MongoDB shell version v4.0.6",
        "connecting to: mongodb://127.0.0.1:27017/configure-db?gssapiServiceName=mongodb",
        "Implicit session: session { \"id\" : UUID(\"4bfad3ba-981f-47de-86f9-a1fadbe28e12\") }",
        "MongoDB server version: 4.0.6",
        "{ \"_id\" : ObjectId(\"5d3a1643c43c898d01a3c740\"), \"count\" : 2 }"
    ]
}

I tried the following two ways but not successful.

- debug:
    msg: "{{ (count_info.stdout_lines[-1] | from_json).count }}"

- name: count value
  debug:
    msg: "{{ count_info.stdout_lines[-1] | json_query('count') }}"

Error log:

TASK [version_update : debug] ******************************************************************************************************************************************
fatal: [192.168.27.125]: FAILED! => {"msg": "the field 'args' has an invalid value ({u'msg': u'{{ (count_info.stdout_lines[-1] | from_json).count }}'}), and could not be converted to an dict.The error was: No JSON object could be decoded\n\nThe error appears to have been in '/home/admin/playbook-3/roles/version_update/tasks/version_update.yml': line 73, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- debug:\n  ^ here\n"}
        to retry, use: --limit @/home/admin/playbook-3/version_update.retry

TASK [version_update : count value] ************************************************************************************************************************************
ok: [192.168.27.125] => {
    "msg": ""
}
Bhavani Prasad
  • 1,079
  • 1
  • 9
  • 26

2 Answers2

3

Your last line in the output is not a pure json string (probably bson from your MongoDB output). The error you get is actually coming from the filter itself not getting a correct input and failing.

You will have to translate that to pure json before you can use the from_json filter. The offending data is the ObjectId(\"5d3a1643c43c898d01a3c740\") that cannot be deserialized by the filter. This should be changed in the task/command you use to register your variable. You can have a look at this interesting question on the subject with many answers that will probably give you some clues.

Once this is done, accessing your data becomes easy as you had already figured out. Here is an example with a modified sample data (the way I think you should finally get it) just to confirm your where on the right track.

- name: Get count in json serialized string
  hosts: localhost
  gather_facts: false

  vars:
    "count_info":
      "stdout_lines": [
        "MongoDB shell version v4.0.6",
        "connecting to: mongodb://127.0.0.1:27017/configure-db?gssapiServiceName=mongodb",
        "Implicit session: session { \"id\" : UUID(\"4bfad3ba-981f-47de-86f9-a1fadbe28e12\") }",
        "MongoDB server version: 4.0.6",
        "{ \"_id\" : \"someDeserializedId\", \"count\" : 2 }"
      ]

  tasks:
    - name: Get count
      debug:
        msg: "{{ (count_info.stdout_lines[-1] | from_json).count }}"

And the result

PLAY [Get count in json serialized string] ********************************************************************************************************************************************************************************

TASK [Get count] **********************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "2"
}
Zeitounator
  • 38,476
  • 7
  • 53
  • 66
0

although the element has the structure of a dictionary, its in fact a string, which i couldnt filter it with to_json or to_nice_json to convert it to a dictionary.

using the below sequence of tasks will get the value you want to pick up, unfortunately i didnt find a way to do it in one task. the logic is as follows:

  1. get the last element from the list, and split the string into key-value substrings, separated by the ,.

  2. parse this list and find the element that contains the keyword count (you can enhance it here if you think the count may appear in other lines too). then with regex, get the numerical value out of it.

PB:

---
- hosts: localhost
  gather_facts: false
  vars:
    final_count_value: -1
    count_info:
      stdout_lines:
      - MongoDB shell version v4.0.6
      - 'connecting to: mongodb://127.0.0.1:27017/configure-db?gssapiServiceName=mongodb'
      - 'Implicit session: session { "id" : UUID("4bfad3ba-981f-47de-86f9-a1fadbe28e12")
        }'
      - 'MongoDB server version: 4.0.6'
      - '{ "_id" : ObjectId("5d3a1643c43c898d01a3c740"), "count" : 2 }'

  tasks:
    - name: prepare list var
      set_fact:
        temp_list: "{{ (count_info.stdout_lines | last).split(', ') | list }}"

    - name: find count
      set_fact: 
        final_count_value: "{{ item | regex_replace('\"count\" : ', '') | regex_replace(' }', '') }}"
      when: item is search('count')
      with_items:
      - "{{ temp_list }}"

    - name: print result
      debug:
        var: final_count_value

output:

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

TASK [prepare list var] ************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [find count] ******************************************************************************************************************************************************************************************************
skipping: [localhost] => (item={ "_id" : ObjectId("5d3a1643c43c898d01a3c740")) 
ok: [localhost] => (item="count" : 2 })

TASK [print result] ****************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "final_count_value": "2"
}

UPDATE

to subtract 1 from the result, you should use:

- name: find count and subtract 1
  set_fact: 
    final_count_value: "{{ item | regex_replace('\"count\" : ', '') | regex_replace(' }', '') | int - 1 }}"
  when: item is search('count')
  with_items:
  - "{{ temp_list }}"

hope it helps!.

ilias-sp
  • 6,135
  • 4
  • 28
  • 41