Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can i run ansible command if certain file changed

I am using ansible to deploy my django App

using

- name: Upgrade the virtualenv.
  pip: requirements={{project_root}}/www/requirements.txt virtualenv={{project_root}}/www/virtualenv

But i only want to run that if requirements.txt changed since last run

like image 327
user1994660 Avatar asked Mar 14 '14 03:03

user1994660


People also ask

How do I run a specific part of my playbook in Ansible?

The easiest way to run only one task in Ansible Playbook is using the tags statement parameter of the “ansible-playbook” command. The default behavior is to execute all the tags in your Playbook with --tags all .

Why does Ansible say changed?

When a module think that it's action changed something (e.g. a state of a subject before module execution and a state after are different), it need to report 'changed' to Ansible.

What happens when one playbook fails a task?

If a task notifies a handler but another task fails later in the play, by default the handler does not run on that host, which may leave the host in an unexpected state. For example, a task could update a configuration file and notify a handler to restart some service.

How do you execute a failed playbook again?

You can achieve similar effect by just using the --step flag e.g: ansible-playbook playbook. yml --step . The step asks you on before executing each task and you could choose (N)o/(y)es/(c)ontinue . With this approach you selectively execute tasks when needed and also continue from point where it failed, after fixes.


2 Answers

We need to determine if any of the requirement files have changed. The steps are as follows:

  1. Touch the temp requirement files. (If they didn't exist, the md5 will be different for the new blank file)
  2. Calculate the md5 hash of the previous requirement files
  3. Caclulate the md5 hash of the current requirement files (the ones just pulled down from GIT)
  4. Iterate through the results of these stat commands in-step, comparing the md5 hash, register the output of the comparison
  5. Only if ANY of the results in #4 changed will we install the pip packages
  6. Copy the current requirement files to the tmp location.

Here's my playbook, {{virtualenv.requirements}} is a list of requirement files, eg: ['/work/project/requirements.txt', '/work/project/requirements-prod.txt']:

- name: Assures temp requirements directory exists
  file: path="/tmp{{ virtualenv.path }}" state=directory
  sudo: yes
  when: install_pip_packages

- name: Assures temp requirements files exists
  file: path="/tmp{{ item }}" state=touch
  sudo: yes
  with_items: virtualenv.requirements_files
  when: install_pip_packages

- name: Calculate md5 of temp requirements
  stat: path="/tmp{{ item }}"
  with_items: virtualenv.requirements_files
  register: temp_requirements_stat
  when: install_pip_packages

- name: Calculate md5 of current requirements
  stat: path="{{ item }}"
  with_items: virtualenv.requirements_files
  register: current_requirements_stat
  when: install_pip_packages

- name: Check requirement files for changes
  command: test {{ temp_requirements_stat.results[item.0].stat.md5 }} = {{ current_requirements_stat.results[item.0].stat.md5 }}
  changed_when: "requirements_check.rc != 0"
  failed_when: requirements_check.stderr
  with_indexed_items: virtualenv.requirements_files
  register: requirements_check
  when: install_pip_packages

- name: Install packages required by the Django app inside virtualenv
  pip: virtualenv={{ virtualenv.path }} extra_args='-U' requirements="{{ virtualenv.requirements_files | join(' -r ') }}"
  when: install_pip_packages and requirements_check.changed

- name: Copy requirements to /tmp
  command: cp "{{ item }}" "/tmp{{ item }}"
  sudo: yes
  with_items: virtualenv.requirements_files
  when: install_pip_packages
like image 148
burroughs06 Avatar answered Oct 06 '22 11:10

burroughs06


Here are two options:

  • put your requirements.txt under Ansible control and use 'copy' or 'template' module, then invoke 'pip' module with 'notify:' statement

  • second way is more complex:

    • retrieve md5 sum of requirements.txt on each Ansible run and compare it with saved md5 somewhere on the server ('stat' module could be used)
    • retrieve pre-saved md5 sum of requirements.txt
    • if current md5 is not equal to presaved, then invoke pip task ('when:' statement)
    • save new md5 somewhere on the server for next Ansible run
like image 38
ghloogh Avatar answered Oct 06 '22 10:10

ghloogh