Search code examples
cronansibleansible-2.xmailto

Ansbile way of having multiple MAILTO environment varialbes in crontab


I have to create crontab in Ansible in such a way that the rendered crontab should have multiple MAILTO which is based on following cron task. For instance, the final crontab may look like below

[email protected]
#Ansible: TEST 1
0 * * * * ls -ahl > /dev/null

[email protected]
#Ansible: TEST 2
1 * * * * ls -ahl > /dev/null

MAILTO being an environment variable , it gets overridden if I specify it multiple times sample of playbook using env.

- cron:
    env: true
    name: MAILTO
    job: [email protected]
    state: "present"
    insertbefore: "TEST 1"
- cron:
    name: "TEST 1"
    job: "ls -ahl > /dev/null"
    state: "present"
    minute: "0"
    hours: "5,2"
- cron:
    env: true
    name: MAILTO
    job: [email protected]
    state: "present"
    insertbefore: "TEST 2"
- cron:
    name: "TEST 2"
    job: "ls -ahl > /dev/null"
    state: "present"
    minute: "1"
    hours: "4,2"

but no luck and I have also tried using cronvar

- cronvar:
    name: MAILTO
    value: [email protected]
    state: "present"
    insertbefore: "TEST 1"
- cron:
    name: "TEST 1"
    job: "ls -ahl > /dev/null"
    state: "present"
    minute: "0"
    hours: "5,2"
- cronvar:
    name: MAILTO
    value: [email protected]
    state: "present"
    insertbefore: "TEST 2"
- cron:
    name: "TEST 2"
    job: "ls -ahl > /dev/null"
    state: "present"
    minute: "1"
    hours: "4,2"

again no luck

Could someone point out a way to achieve this?


Solution

  • Because cronvar is meant to add variable to the files, which are uniques and since I am not totally sure from that comment that having multiple MAILTO is something possible on all the implementation of crontab, so it is likely that it is not going to be supported by Ansible, I guess your best bet is to resort to a plain old lineinfile.

    The not-so-nice part of this, of course, is that you have to make an host, play or task variable holding the path to the crontab file.
    I looked through the documentation quickly, but it seems like there is no fact giving the actual crontab of a user, and since it seems it is part of the cron module code itself, I am not sure there will be a nice way to find it out from Ansible itself.

    The part identifying where the line should be added, on the other hand seems future proof, as it is clearly documented as an expected behaviour:

    When crontab jobs are managed: the module includes one line with the description of the crontab entry "#Ansible: <name>" corresponding to the “name” passed to the module, which is used by future ansible/module calls to find/check the state. The “name” parameter should be unique, and changing the “name” value will result in a new cron task being created (or a different one being removed).

    From documentation: https://docs.ansible.com/ansible/2.9/modules/cron_module.html

    With all this, given the playbook:

    - hosts: all
      gather_facts: no
      vars:
        cron_file: /etc/crontabs/root
      
      tasks:
        - cron:
            name: "TEST 1"
            job: "ls -ahl > /dev/null"
            state: "present"
            minute: "0"
            hour: "5,2"
          register: cron
    
        - lineinfile:
            path: "{{ cron_file }}"
            insertbefore: '#Ansible: TEST 1'
            line: '[email protected]'
    
        - cron:
            name: "TEST 2"
            job: "ls -ahl > /dev/null"
            state: "present"
            minute: "1"
            hour: "4,2"
        
        - lineinfile:
            path: "{{ cron_file }}"
            insertbefore: '#Ansible: TEST 2'
            line: '[email protected]'
    

    This yields the recap:

    PLAY [all] *********************************************************************************************************
    
    TASK [cron] ********************************************************************************************************
    changed: [localhost]
    
    TASK [lineinfile] **************************************************************************************************
    changed: [localhost]
    
    TASK [cron] ********************************************************************************************************
    changed: [localhost]
    
    TASK [lineinfile] **************************************************************************************************
    changed: [localhost]
    
    PLAY RECAP *********************************************************************************************************
    localhost                  : ok=4    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    

    And in the /etc/crontabs/root of the Alpine used to test:

    [email protected]
    #Ansible: TEST 1
    0 5,2 * * * ls -ahl > /dev/null
    [email protected]
    #Ansible: TEST 2
    1 4,2 * * * ls -ahl > /dev/null
    

    Last but not least, rerunning the exact same playbook show the idempotency is respected:

    PLAY [all] *********************************************************************************************************
    
    TASK [cron] ********************************************************************************************************
    ok: [localhost]
    
    TASK [lineinfile] **************************************************************************************************
    ok: [localhost]
    
    TASK [cron] ********************************************************************************************************
    ok: [localhost]
    
    TASK [lineinfile] **************************************************************************************************
    ok: [localhost]
    
    PLAY RECAP *********************************************************************************************************
    localhost                  : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0