Home > Mobile >  Registering output to complex variable and placing conditionals on sub-components
Registering output to complex variable and placing conditionals on sub-components

Time:12-12

I'm getting a bit lost with next variable types and am hoping for some direction in a specific task please:

The Goal: Based on a list of username:publickey values. I'd like to:

  • ensure the user exists on the target system
  • if the user does exist then: - ensure the "/home/$user/.ssh/authorized_keys" file exists with the correct permissions through the path.

The Scene:

I have a variable:

ssh_vars:
  auth_keys:
    bob: "bobs_public_key_string"
    anne: "annes_public_key_string"
    anon: "anons_public_key_string

I need to iterate over this variable and for each auth_keys item call a tasklist:

- name: loop through the auth_keys and call ssh_dirs.yml for each
  ansible.builtin.include_tasks: "ssh_dirs.yaml"
  loop: "{{ ssh_vars.auth_keys }}"

However, I only really want to do this when the auth_key(key) is a user which already exists on the host.

I have been playing with getent, within "ssh_dirs.yaml":

- name: "Ensure the user exists on the target system"
  ansible.builtin.getent:
    database: passwd
    key: "{{ item.name }}"
    fail_key: false
  register: userlookup

which creates what i think is a list of dictionaries:

ok: [ans-client.local] => {
    "userlookup": {
        "changed": false,
        "msg": "All items completed",
        "results": [
            {
                "ansible_facts": {
                    "getent_passwd": {
                        "bob": [
                            "x",
                            "1003",
                            "1003",
                            "",
                            "/home/bob",
                            "/usr/bin/bash"
                        ]
                    }
                },
                "ansible_loop_var": "item",
                "changed": false,
                "failed": false,
                "invocation": {
                    "module_args": {
                        "database": "passwd",
                        "fail_key": false,
                        "key": "bob",
                        "service": null,
                        "split": null
                    }
                },
                "item": {
                    "key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDvIZuaBhAIGShw21rkvgqyvNePunbVs6OtOBhYJOY2P anne@ans-server",
                    "name": "bob"
                }
            },
            {
                "ansible_facts": {
                    "getent_passwd": {
                        "anne": [
                            "x",
                            "1000",
                            "1000",
                            "anne",
                            "/home/anne",
                            "/bin/bash"
                        ]
                    }
                },
                "ansible_loop_var": "item",
                "changed": false,
                "failed": false,
                "invocation": {
                    "module_args": {
                        "database": "passwd",
                        "fail_key": false,
                        "key": "anne",
                        "service": null,
                        "split": null
                    }
                },
                "item": {
                    "key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKr/76O3hLJlcyZuy7EJxf7sC1z9BSHMuxGsFGBibJY3 anne@ans-server",
                    "name": "anne"
                }
            },
            {
                "ansible_facts": {
                    "getent_passwd": {
                        "anon": null
                    }
                },
                "ansible_loop_var": "item",
                "changed": false,
                "failed": false,
                "invocation": {
                    "module_args": {
                        "database": "passwd",
                        "fail_key": false,
                        "key": "anon",
                        "service": null,
                        "split": null
                    }
                },
                "item": {
                    "key": "SOMEKEY",
                    "name": "anon"
                },
                "msg": "One or more supplied key could not be found in the database."
            }
        ],
        "skipped": false
    }
}

But I can't figure out how to isolate this list to ensure the include_tasks: is not called if the user doesn't exist.

- name: loop through the auth_keys and call ssh_dirs.yml for each
  ansible.builtin.include_tasks: "ssh_dirs.yaml"
  loop: "{{ ssh_vars.auth_keys }}"
  when: userlookup.results.???????

How can I figure out how to reference this nested variable, and how best to isolate a non-missing user?

Something like userlookup.results.msg is not defined might work but it's very loose - is there something better I'm missing?

CodePudding user response:

See registering variables with loop

The global idea is

  • loop over you var to get the existing/unavailable users
  • loop over the results of that previous task for you next one. The original loop variable is available in the item key of each result and you can filter as you like.

For your particular case, in a nutshell (untested):

- name: Ensure the user exists on the target system
  ansible.builtin.getent:
    database: passwd
    key: "{{ item.name }}"
  register: userlookup
  ignore_errors: true
  loop: "{{ ssh_vars.auth_keys }}"

- name: Call ssh_dirs.yml for each existing users
  ansible.builtin.include_tasks: ssh_dirs.yaml
  loop: "{{ userlookup.results | select('success') }}"
  loop_control:
    loop_var: user_checked
  vars:
    userloop: "{{ user_checked.item }}"

CodePudding user response:

I think I've solved it, although maybe there's a better thing to look for in the getent response than just the msg?

The logic and variable reference which works:

- name: "Ensure the user exists on the target system"
  ansible.builtin.getent:
    database: passwd
    key: "{{ item.name }}"
    fail_key: false
  register: userlookup
  loop: "{{ ssh_vars.auth_keys }}"

- name: Build a list of usernames which don't exist on the remote host (missing_users)
  ansible.builtin.set_fact:
    missing_users: "{{ missing_users | default([])   [usercheck.item.name | string] }}"
  loop: "{{ userlookup.results }}"
  loop_control:
    loop_var: usercheck
  when: usercheck.msg is defined

- name: loop through the users and ensure the necessary user folders and files are there
  ansible.builtin.include_tasks: "ssh_dirs.yaml"
  loop: "{{ ssh_vars.auth_keys }}"
  loop_control:
    loop_var: userloop
  when: userloop.name not in missing_users

Although this is still checking the msg: output mindlessly so only a partial solution

  • Related