Ansible, git and Rails

I think I wrote the following playbook a few months ago, when I was halfway through watching the 2 hour introduction (now replaced with this):

---
- name: automatic deploy new version
  hosts: ruby-production
  user: root
  sudo: yes
  tasks:

  - name: stop monit
    command: service monit stop

  - name: checkout correct version
    sudo_user: projectuser
    command: chdir=/workspace/project git checkout release-1.0

  - name: grab latest sources for that release
    sudo_user: projectuser
    command: chdir=/workspace/project git pull origin release-1.0

  - name: run db:migrate
    sudo_user: projectuser
    sudo: no
    script: migrate.sh

  - name: restart apache
    command: service httpd restart

  - name: start monit
    command: service monit start

What the above playbook does is simple:

– Stop monit to avoid any automatic restarts when you’re half way through updating stuff that it monitors.

– It makes sure that you grab the latest updates from the correct branch

– It runs a script on all servers that takes care of any bundle install and db:migrate stuff.

– It restarts apache. Yes, a touch tmp/restart.txt should do the trick but sometimes it does not.

– It restarts monit.

There is plenty of room for improvement here, for example using the git module instead of running an explicit command and even making use of roles as the project expands and becomes more demanding and of course get rid of the script in favor of a more ansible specific play.

So why post it now? Basically at the request of @nanobeep and as a means of self-pressure to improve the playbook. Maybe I should promise this to someone?

So there, nothing complex or elaborate. BTW, here is a similar way to do this with git and Capistrano that I bumped into.

Having monit complement ansible

Here is a weird thing:

When running /etc/init.d/milter-greylist restart via ansible (either direct or via a playbook) it hangs. I had no time to debug this, so I reverted to the next best workaround since the machine was already running monit:

Have ansible distribute greylist.conf and then have monit restart the process. So here is a simple playbook:

- hosts: greylist
  user: root
  tasks:
  - name: copy local milter-greylist configuration to hosts
    action: copy src=/usr/local/etc/greylist.conf dest=/etc/milter-greylist/greylist.conf

and here is how monit finishes the task:

check file greylist.conf with path /etc/milter-greylist/greylist.conf
 if changed checksum then exec "/etc/init.d/milter-greylist restart"

Of course this is just a simple case of having the two cooperate. But once you get the hang of it, more elaborate schemes where ansible and monit can cooperate will pop out.

ansible and yum check-update

When calling yum check-update from an ansible playbook, your play may fail because check-update returns non-zero exit status for two reasons:

check-update […] returns exit value of 100 if there are packages available for an update. Also returns a list of the packages to be updated in list format. Returns 0 if no packages are available for update. Returns 1 if an error occurred.

One quick and dirty way to bypass this is to use ignore_errors: yes in your task, but this will ignore both the case of pending updates and any other kind of error and your play will continue regardless. To avoid this one can modify the play sightly to check for the exit status:

  - name: yum check-update
    shell: 'yum check-update || test $? -eq 100'

The single quotes in the shell command above do matter.