0

I have an ansible playbook which is made up of two plays as shown below:

  • First play validates everything on the localbox where I am running my ansible before invoking Play2. If my validation fails in Play1 then I don't want to start Play2 at all.
  • Second play will only start if Play1 validation is successful and this play creates a directory on remoter server if it is not there and then copies process.tar.gz file in a particular directory on all remote servers.

Below is my playbook:

---
- name: Play 1
  hosts: 127.0.0.1
  tasks:
      - name: check whether we have all the necessary files
        shell: "ls files/ | wc -l"
        retries: 10
        delay: 10
        register: number_of_files
        until: "number_of_files.stdout == '10'"

      - name: Total number of files
        debug: msg="Total files {{ number_of_files.stdout }}"

      - name: check whether all the files are generated within a minute difference
        shell: "find files/ -mmin -1 -type f -print | wc -l"
        register: file_time
        failed_when: "file_time.stdout != '10'"

      - name: Total number of files
        debug: msg="Total files {{ file_time }}"

      - name: check whether success file was generated
        shell: "ls files/SUCCESS | wc -l"
        register: success_file
        failed_when: "success_file.stdout != '1'"

      - name: Success file
        debug: msg="{{ success_file }}"

      - name: compress all the files in tar.gz
        shell: "rm process.tar.gz; tar -czvf process.tar.gz -C files . --exclude='SUCCESS'"

- name: Play 2
  hosts: ALL_HOSTS
  serial: "{{ serial }}"
  tasks:
      - name: creates directory
        file: path=/data/taks/files/ state=directory

      - name: copy and untar process.tar.gz file
        unarchive: src=process.tar.gz dest=/data/taks/files/

      - name: sleep for few seconds
        pause: seconds=20

I wanted to see if there is any better way to write my above ansible? Since I recently started working with ansible so not sure I am following all the best practices.. I am running ansible version ansible 2.4.3.0. Also I always get a warning from ansible on this task:

- name: compress all the files in tar.gz
  shell: "rm process.tar.gz; tar -czvf process.tar.gz -C files . --exclude='SUCCESS'"

Here is the warning:

[WARNING]: Consider using file module with state=absent rather than running rm
[WARNING]: Consider using unarchive module rather than running tar

Update:

Below is my path where my ansible playbook is sitting and from this directory only, I execute my PLAYBOOK1. And files directory contains all the files including SUCCESS which I need to compress into tar.gz.

jenkins@machineA:~/jobs/processdata/workspace$ ls -lrth
total 145M
drwxr-xr-x 2 jenkins jenkins 4.0K Feb 19 17:36 files
-rw-r--r-- 1 jenkins root    1.6K Feb 19 19:32 PLAYBOOK1.yml
-rw-r--r-- 1 jenkins root    1.6K Feb 19 19:32 PLAYBOOK2.yml

Here is the error I am getting after I execute PLAYBOOK1 with your changes:

TASK [Check all files] **********************************************************************************************************************************************************************
fatal: [127.0.0.1]: FAILED! => {"changed": false, "examined": 0, "failed_when_result": true, "files": [], "matched": 0, "msg": "/files was skipped as it does not seem to be a valid directory or it cannot be accessed\n"}
user1950349
  • 223
  • 1
  • 3
  • 10
  • 3
    You should use the archive and unarchve modules instead of running tar yourself, and the file module rather than running rm yourself. – Michael Hampton Feb 14 '18 at 02:18

1 Answers1

3

See my coments marked with #

Playbook1

- hosts: YOURHOST1
  remote_user: "YOURUSER"
  become: True

  tasks:

  #Instead using shell, use find module... It will check if there are 10 files created before 1 minute in folder, otherwise playbook fails
  - name: Check all files
    find: paths=/var/lib/jenkins/jobs/processdata/workspace/files
          file_type=file
          age=-1m
          age_stamp=mtime
    register: files
    failed_when: files.matched < 10

  - name: Number of files
    debug: msg="Total files {{ files.matched }}"

  #Check for SUCCESS file, I didn't add an action to delete SUCCESS file... Hope you have any other script to do it
  - name: Check Success File
    find: paths=/var/lib/jenkins/jobs/processdata/workspace/files
          file_type=file
          patterns=SUCCESS
    register: success_file
    failed_when: success_file.matched < 1

  - name: Success file
    debug: msg='Success file is {{ success_file.files.0.path }}'

  - name: Remove previous tarFile
    file: path=/tmp/process.tar.gz
          state=absent

  #I've found a way to make it work
  - name: compress all the files in tar.gz
    archive: path="{{ files_to_archive }}"
             dest=/tmp/test.tar.gz
             format=gz
    vars:
        files_to_archive: "{{ files.files | map(attribute='path') | list }}"

- include: PLAYBOOK2.yml 

Playbook2 If one of the previous actions fails, Ansible stops and won't run any other action.

- hosts: YOURHOST2
  remote_user: "YOURUSER"
  become: True

  tasks:

  - name: creates directory
    file: path=/data/taks/files/
          state=directory

  - name: Copy tar file
    copy: src=/tmp/test.tar.gz
          dest=/tmp/process.tar.gz
          owner=root
          group=root
          mode=0744

  - name: copy and untar process.tar.gz file
    unarchive: src=/tmp/process.tar.gz
               dest=/data/taks/files/

  - name: Remove SUCCESS File
    file: path=/data/taks/files/SUCCESS
          state=absent

#I don't know why you'll need this:
  - name: sleep for few seconds
    pause: seconds=20

Please consider that one of the features of ansible is idempotency, you should write your scripts to run and continue from previous actions (if they have failed in a previous launch). Neither yours nor mine scripts are idempotent, because you need to find files newer than a minute before, hence during next launch (if something fails) your script discards files older than a minute.

Same happens with SUCCESS file, if you have a platform/script that is continue deleting it, is possible that Ansible script fails when running.

Alvaro Niño
  • 359
  • 2
  • 6
  • Thanks for your detailed explanation. In my case, my first playbook does validation on `localhost` where I am running my ansible playbook and second play then runs if my first play is successful on all remote servers in `ALL_HOSTS` file. So in your suggestion I don't see you are using `127.0.0.1` localhost anywhere? So will all the validation from Playbook1 in your example run on remote servers or will it run on localhost where I am running my ansible? – user1950349 Feb 15 '18 at 18:33
  • Also I have a `files` directory where my ansible playbook is sitting so it should `files` instead of `/files` I think. And after making that change as well, I am getting error with first task. – user1950349 Feb 15 '18 at 19:25
  • I'm gonna edit it for you, as reference use two playbooks and call the first one with your command... `files` folder is for roles that has files you'll need for your roll as static information, you cannot use them for file creation during the playbook. I'd recommend to use `/tmp` dir – Alvaro Niño Feb 16 '18 at 10:00
  • ok got it on `/tmp` dir.. I have few questions. In the task `compress all the files in tar.gz`, Is there any way to exclude `SUCCESS` file while making `test.tar.gz`? Also what is `- include: file-probe2.yml ` means at the bottom of playbook1? – user1950349 Feb 17 '18 at 04:08
  • Hi, I don't know if you can exclude `SUCCESS` file, although I've added a last task to delete this file in HOST2. And no `- include: PLAYBOOK2.yml ` must be at the end of playbook 1, you should call playbook2 once playbook1 has ended... I've changed `- include: file-probe2.yml` to `- include: PLAYBOOK2.yml` in order to have good name references (Playbook1 and Playbook2)... Please give answer as valid. – Alvaro Niño Feb 19 '18 at 08:57
  • yeah I will accept the answer very soon. So now when I started running the playbook1, it is giving me error on first task which is `Check all files`. Error I am getting is this `fatal: [127.0.0.1]: FAILED! => {"changed": false, "examined": 0, "failed_when_result": true, "files": [], "matched": 0, "msg": "/files was skipped as it does not seem to be a valid directory or it cannot be accessed\n"}`. I have updated the question to clarify on this. – user1950349 Feb 20 '18 at 02:36
  • Playbook is prepared to have `file` directory in `/files` not in `~/jobs/processdata/workspace/files`... I've made your requested playbook, I won't help you anymore unlesss you give answer as valid. – Alvaro Niño Feb 20 '18 at 08:44
  • I have accepted the answer now can you help me with that files directory issue? – user1950349 Feb 20 '18 at 16:23
  • Thanks, I cannot change it because I don't know your home dir location (you have shared it as `~/jobs/processdata/workspace/files`), you should share complete path... Although, you only need to change two lines in playbook1, lines are here `- name: Check all files find: paths=YOURFILES PATH` and `- name: Check Success File find: paths=YOURFILES PATH` – Alvaro Niño Feb 20 '18 at 16:56
  • This is my full path `/var/lib/jenkins/jobs/processdata/workspace/files`. After I add this path, I get different error. Do you see any issue with that task? – user1950349 Feb 20 '18 at 17:04
  • I've updated answer with your path, although if you don't share error log I'm not able to track it – Alvaro Niño Feb 20 '18 at 17:08
  • hey I have another question [here](https://serverfault.com/questions/898332/retry-ansible-remote-task-that-copies-the-file-if-there-is-any-failure) on ansible. Wanted to see if you can help me out? – user1950349 Feb 22 '18 at 17:34