Score:0

Ansible: grep crontab files based on usernames extracted from /etc/passwd

eg flag

I'm looking to extract a list of users from /etc/passwd and then grep their crontab files for disabled (commented: ^#) jobs.

The high level steps would be:

  1. Grab an array of usernames from /etc/passwd ("my_users")
  2. Run grep against the files named in step 1 (/var/spool/cron/{{my_users}})
  3. Use 'Debug' to print out the results.

I'd appreciate any suggestions, here's what I have so far:

  - name: ANSIBLE PLAYBOOK - disabled cronjob check
  hosts: "{{ variable_host | default('testvm') }}"
  remote_user: admin
  gather_facts: no
  become: yes

  tasks:    
  - getent:
      database: passwd
  - name: set_fact
    debugger: on_failed
    ansible.builtin.set_fact:
      my_users: "{{ getent_passwd|dict2items|json_query('[?contains(value,`/bin/bash`)].key') }}"
      cacheable: yes

  - name: set_fact_2
    ansible.builtin.set_fact:
      array_length: "{{ my_users|length }}"
  - debug:
      msg: "Debugging 2: {{ my_users|length }}"

  - name: Get disabled cron jobs
    debugger: always
    loop: "{{ my_users }}"
    ansible.builtin.lineinfile:
      path: "/var/spool/cron/{{ my_users }}"
      regexp: "^#"

Here's the output in question, which isn't quite what I expected:

TASK [Get disabled cron jobs]*********************************************************************************************************************************************************************************** failed: [testvm] (item=n2disk) => {"ansible_loop_var": "item", "changed": false, "item": "n2disk", "msg": "line is required with state=present"} failed: [testvm] (item=cento) => {"ansible_loop_var": "item", "changed": false, "item": "cento", "msg": "line is required with state=present"} failed: [testvm] (item=admin) => {"ansible_loop_var": "item", "changed": false, "item": "admin", "msg": "line is required with state=present"} failed: [testvm] (item=nprobe) => {"ansible_loop_var": "item", "changed": false, "item": "nprobe", "msg": "line is required with state=present"} failed: [testvm] (item=root) => {"ansible_loop_var": "item", "changed": false, "item": "root", "msg": "line is required with state=present"} failed: [testvm] (item=backup) => {"ansible_loop_var": "item", "changed": false, "item": "backup", "msg": "line is required with state=present"}

in flag
lineinfile is not meant to be used to only check if a line exists. It is meant to make sure that a line exists. [This answer](https://stackoverflow.com/a/54525651/212107) uses the check mode to reach your goal.
br flag
How are you going to recognize commented jobs from other comments?
Score:1
br flag

As a hint see below how to create a dictionary comprising all crontab info

  1. Declare the variables
  cron_tabs_path: /var/cron/tabs
  cron_users: "{{ cron_user.files|map(attribute='path')|
                                  map('basename')|list }}"
  cron_tabs: "{{ cron_tab.results|map(attribute='stdout')|
                                  map('community.general.jc', 'crontab')|list }}"
  cron_tabs_dict_all: "{{ dict(ansible_play_hosts|
                               zip(ansible_play_hosts|
                                   map('extract', hostvars, ['cron_tabs_dict']))) }}"
  1. Find all crontab files (cron_users)
    - find:
        paths: "{{ cron_tabs_path }}"
      register: cron_user
  1. Read all crontabs
    - command: "crontab -u {{ item }} -l"
      register: cron_tab
      loop: "{{ cron_users }}"
  1. Create a dictionary of users and their crontabs
    - set_fact:
        cron_tabs_dict: "{{ dict(cron_users|zip(cron_tabs)) }}"

For example, given the crontabs on remote hosts test_11 and test_13

shell> ssh admin@test_11 sudo crontab -u admin -l
#Ansible: test_1
5 12 * * * echo test 1
#Ansible: test_5
5 14 * * * echo test 5
#Ansible: test_4
5 13 * * * echo test 4
shell> ssh admin@test_11 sudo crontab -u alice -l
#Ansible: test_2
5 13 * * * echo test 2
shell> ssh admin@test_11 sudo crontab -u bob -l
#Ansible: test_3
5 14 * * * echo test 3
shell> ssh admin@test_13 sudo crontab -u admin -l
#Ansible: test_1
5 12 * * * echo test 1
#Ansible: test_4
5 13 * * * echo test 4
#Ansible: test_5
5 14 * * * echo test 5

The playbook

shell> cat pb.yml
- hosts: test_11,test_13

  vars:

    cron_tabs_path: /var/cron/tabs
    cron_tabs: "{{ cron_tab.results|map(attribute='stdout')|
                                    map('community.general.jc', 'crontab')|list }}"
    cron_users: "{{ cron_user.files|map(attribute='path')|
                                    map('basename')|list }}"
    cron_tabs_dict_all: "{{ dict(ansible_play_hosts|
                                 zip(ansible_play_hosts|
                                     map('extract', hostvars, ['cron_tabs_dict']))) }}"

  tasks:

    - find:
        paths: "{{ cron_tabs_path }}"
      register: cron_user
    - debug:
        var: cron_users

    - command: "crontab -u {{ item }} -l"
      register: cron_tab
      loop: "{{ cron_users }}"
    - debug:
        var: cron_tabs

    - set_fact:
        cron_tabs_dict: "{{ dict(cron_users|zip(cron_tabs)) }}"
    - debug:
        var: cron_tabs_dict|to_yaml

    - debug:
        var: cron_tabs_dict_all|to_yaml
      run_once: true

gives

  cron_tabs_dict_all:
    test_11:
      admin:
        schedule:
        - command: echo test 1
          day_of_month: ['*']
          day_of_week: ['*']
          hour: ['12']
          minute: ['5']
          month: ['*']
        - command: echo test 5
          day_of_month: ['*']
          day_of_week: ['*']
          hour: ['14']
          minute: ['5']
          month: ['*']
        - command: echo test 4
          day_of_month: ['*']
          day_of_week: ['*']
          hour: ['13']
          minute: ['5']
          month: ['*']
        variables: []
      alice:
        schedule:
        - command: echo test 2
          day_of_month: ['*']
          day_of_week: ['*']
          hour: ['13']
          minute: ['5']
          month: ['*']
        variables: []
      bob:
        schedule:
        - command: echo test 3
          day_of_month: ['*']
          day_of_week: ['*']
          hour: ['14']
          minute: ['5']
          month: ['*']
        variables: []
    test_13:
      admin:
        schedule:
        - command: echo test 1
          day_of_month: ['*']
          day_of_week: ['*']
          hour: ['12']
          minute: ['5']
          month: ['*']
        - command: echo test 4
          day_of_month: ['*']
          day_of_week: ['*']
          hour: ['13']
          minute: ['5']
          month: ['*']
        - command: echo test 5
          day_of_month: ['*']
          day_of_week: ['*']
          hour: ['14']
          minute: ['5']
          month: ['*']
        variables: []

Use getent to read /etc/passwd

    - getent:
        database: passwd
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.