How can i run ansible command if certain file chan

2019-04-07 19:03发布

问题:

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

回答1:

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


回答2:

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


回答3:

I use this pretty short workaround for git repository.

  - name: get requirements changes since last pull
    shell: "cd {{ project_root }}; git log --name-status --oneline origin/master
           {{ git_result.before }}..{{ git_result.after }} | grep requirements.txt"
    register: pip_check
    failed_when: false

  - name: update pip requirements
    pip: requirements={{ project_root }}/requirements.txt
         virtualenv=~/.virtualenvs/www/
    when: pip_check.stdout_lines

It's not universal and not cross-platform recipe, but works well for many situations.