Assert - don't stop playbook, only report findings

hi I want to check some pre-requisites on a couple of remote machines upon which I (if conditions are not met) I’ll create a ticket for the Linux department of my organisation (for them to fix those, which I am not able to do myself due to privilege restrictions).

There is one part using assert

- name: Get Group Data
  ansible.builtin.getent:
    database: "group"
    key: "pgsqlroot"
    split: ","

- name: Validate that current User is member of group
  assert:
    that: ansible_user_id in item.value
    fail_msg: "User {{ ansible_user_id }} is not member of the group {{ item.value }}"
    quiet: yes
  with_dict: "{{ ansible_facts.getent_group }}"

this stops execition once hitting the first failure which prevents me from getting the required information for all remotes. I assert maybe just the wrong module for only collecting information, or did I miss an option that prevents the playbook from stopping if condition is not met with ansible-doc assert?


@gwmngilfen: you removed the tag feeback-wanted from this post. Is there any explanation on how to use which tag, anywhere? Or would you mind to comment on why it was not the right fit for this Topic?

1 Like

Happy to! And apologies if that felt harsh, it wasn’t intended as criticism.

So my feeling is that every topic in Get Help wants “feedback” in the sense that all the topics here are people getting stuck and wanting an answer to their problem. So while a “feedback-wanted” tag isn’t wrong exactly, it’s not helpful here, because we’d have to tag every post with it.

The intention with that tag was to flag wider discussion topics in the Project Discussions or Forum Guide & Feedback categories where decisions need to be made, so that people can search for those. I will go add a description to the tag page to that effect, and I think I can restrict it from being used here too.

Hope that clarifies things!

Edit: done! You’ll see it on the right-side of Topics tagged feedback-wanted now (may need a hard-refresh)

3 Likes

no worries, Neither did I perceive that as harsh nor do I mind critisism or harshness in any forum, mailing list, etc. … It’s part of the game/fun if you ask me :-).

3 Likes

Off the top of my head, have you tried ignore_errors on the assert task?

6 Likes

Came to say the same thing.

This should work just update as follows:

- name: Validate that current User is member of group
  assert:
    that: ansible_user_id in item.value
    fail_msg: "User {{ ansible_user_id }} is not member of the group {{ item.value }}"
    quiet: true
  with_dict: "{{ ansible_facts.getent_group }}"
  ignore_errors: true
3 Likes

In addition to the suggestion from @bahmanm and @bmccafferty you could also try fail. I think this wouldn’t fail everything, just the current (remote) host.

Not sure if this helps, just an idea.

1 Like

Also if you want to only report findings it might be a debug instead where it prints a message if something is true or with an inline if/else. As with anything ansible 10 ways to achieve the same result.

3 Likes

I am going against the grain here… I would avoid ignore_errors: true and only use that as a last resort…

Any reporting tool looking for failures (e.g. Automation controller, AWX, ARA, etc), or even just your Ansible terminal output and the color schema (you will see failed, and the color red go by) and finally even your Play Recap will show failures. Is that the desired outcome? Show failures but don’t act on them? (nice Reddit thread here: Reddit - Dive into anything)

I would suggest in most cases of changing what a failure means of using failed_when.

However going back to your original requirements…

hi I want to check some pre-requisites on a couple of remote machines upon which I (if conditions are not met) I’ll create a ticket for the Linux department of my organisation (for them to fix those, which I am not able to do myself due to privilege restrictions).

What about something like this->

- name: Get Group Data
  ansible.builtin.getent:
    database: "group"
    key: "pgsqlroot"
    split: ","

- name: Validate that current User is member of group
  include_tasks: validate_user_groups.yml
  loop: "{{ ansible_facts.getent_group }}"

the 2nd file:

# validate_user_groups.yml
---
- name: validate that users is member of group or open ticket
  block:
    - name: Validate that current User is member of group
      assert:
        that: ansible_user_id in item.value
        fail_msg: "User {{ ansible_user_id }} is not member of the group {{ item.value }}"
        quiet: yes
  rescue:
    - name: Open ticket with Linux department
      choose.your.module:
        dosomething: true

The reason I use two files is you can’t use a loop with block unless you do it this way.

The rescue task(s) will only run when there is a failure under the block, and if the rescue task(s) pass, there will be no failures. You can have it open a ticket automatically, or just post a message to slack about which users… (whatever you want…). Not sure how your organization handles tickets… but it could be as simple as appending a csv file with all the users to an email that you can forward to your Linux group… (doesn’t have to be super fancy).

For more information on handling errors with blocks, check out the docs here: Blocks — Ansible Documentation

4 Likes

Don’t use assert either use debug or just use an action (mail, get_url, etc) that will trigger the API/other system to react as you wish.

4 Likes

Hi @dulhaver! It looks like the post might be solved - could you check to see if the response by @IPvSean worked for you?

If so, it would be super helpful if you could click the :heavy_check_mark: on their post to accept the solution - it helps users find solutions (solved topics have a higher search priority), recognises the input of the people who help you, helps our volunteers find new issues to answer, and keeps the forum nice and tidy. It’s just a nice way to give back, and only takes a moment :slight_smile:

Thanks!
(this is template reply, do feel free to reply if I’ve misunderstood the situation!)

I am geting this error:

TASK [include 'valiadate_user_groups.yml'] ************************************************************************************************************************************************************************
fatal: [dvzsn-rd5400.ref.eakte.rz-dvz.cn-mv.de]: FAILED! => {"msg": "Invalid data passed to 'loop', it requires a list, got this instead: {'pgsqlroot:x:20104:': []}. Hint: If you passed a list/dict of just one element, try adding wantlist=True to your lookup invocation or use q/query instead of lookup."}

would not know where or how to add the suggest adding wantlist=True to overcoome this though. Any idea?

also I’d want to extend this similar as below.

- name: Get Group Data
  ansible.builtin.getent:
    database: "group"
    key: "{{ item }}"
    split: ","
  loop:
    - pgsqlroot
    - pgsqldba

and am wondering whether there is more trouble to expect due to that (and a more complex data structure maybe)

1 Like

Suggest… making sure you get pgsqlroot or pgsqldba working before you start the next task. You need (and I forgot to put) a register keyword on the original getent task.

for example, something like this:

- name: Get Group Data
  ansible.builtin.getent:
    database: "group"
    key: "pgsqlroot"
    split: ","
  register: group_data

Would suggest doing a debug task on the group_data var to “see” what the data model looks like it is returning. My guess, based on the error, is that you are getting a dictionary, versus a list

Here is an example debug… (From memory so I might make a syntax error…)

- name: debug the var
  debug:
    var: group_data

… realizing half way through this post… why I didn’t have a register last time… it is a module I have not used a ton… and has this disclaimer in the docs:

Facts returned by this module are added/updated in the hostvars host facts and can be referenced by name just like any other host fact. They do not need to be registered in order to use them.

although the register might be easier? b/c you just set it to a key you know…

I need to see the data structure, but in general you can convert a dictionary to a list in Ansible a variety of ways… for example:

some_dict:
  key1: value1
  key2: value2
  key3: value3

the playbook:

- name: Convert dictionary to list
  ansible.builtin.debug:
    msg: "{{ some_dict | dict2items }}"

the output

[
  {"key": "key1", "value": "value1"},
  {"key": "key2", "value": "value2"},
  {"key": "key3", "value": "value3"}
]
2 Likes

Sorry. It took a while coming back to this. I am stuck at this stage now:

playbook

---
- name: check preqequisites for postgres
  hosts: "{{ targets | default('postgres') }}"
  vars:
    - member_of_groups:
        - pgsqlroot
        - pgsqldba
        - jbossadm
        - jbossroot

  tasks:
    - name: Get Group Data
      ansible.builtin.getent:
        database: "group"
        key: "{{ item }}"
        split: ","
        fail_key: false
      loop: "{{ member_of_groups }}"
      register: pg_groups

    - name: "include 'valiadate_user_groups.yml'"
      include_tasks: validate_user_groups.yml
      loop: "{{ member_of_groups }}"

validate_user_groups.yml

---
- name: debug user_groups
  debug:
    var: member_of_groups

- name: validate that user is member of group or open ticket
  block:
    - name: Validate that current User is member of group
      assert:
        that: ansible_user_id in member_of_groups
        fail_msg: "User {{ ansible_user_id }} is not member of the group {{ member_of_groups }}"
  rescue:
    - name: Open ticket with Linux department
      debug:
        msg: "{{ ansible_user_id }} is not member of {{ member_of_groups }}"

I end up with 4 times the message

TASK [debug 'member_of_groups'] **************************************************************************************************************************************************
task path: /home/gwagner/repos/automation_postgres/playbooks/validate_user_groups.yml:3
ok: [dvzsn-rd5234.vdz.portal.cn-mv.de] => {
    "member_of_groups": [
        "pgsqlroot",
        "pgsqldba",
        "jbossadm",
        "jbossroot"
    ]
}

TASK [Validate that current User is member of group] *****************************************************************************************************************************
task path: /home/gwagner/repos/automation_postgres/playbooks/validate_user_groups.yml:9
fatal: [dvzsn-rd5234.vdz.portal.cn-mv.de]: FAILED! => {
    "assertion": "ansible_user_id in member_of_groups",
    "changed": false,
    "evaluated_to": false,
    "msg": "User gwagner is not member of the group ['pgsqlroot', 'pgsqldba', 'jbossadm', 'jbossroot']"
}

TASK [Open ticket with Linux department] *****************************************************************************************************************************************
task path: /home/gwagner/repos/automation_postgres/playbooks/validate_user_groups.yml:17
ok: [dvzsn-rd5234.vdz.portal.cn-mv.de] => {
    "msg": "gwagner is not member of ['pgsqlroot', 'pgsqldba', 'jbossadm', 'jbossroot']"

so at least that seems to proove I am going through the tasks file 4 times (one per group). I am actually member of 2 of those groups. so I should get a message Open ticket with Linux department twice.

It seems the problem was to check for each list item of member_of_groups individually whether ansible_user_id matches. So I guess I am not all to far away from my goal.

The suggestions above involve looping through the results of ansible.builtin.getent but you are looping through member_of_groups?

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.