Conditional Include Question

Hello,

I’m running in to an issue with conditional includes. I’m trying to create an automatic rollback procedure for one of my playbooks which attempts to deploy new versions of our company software. I’m using includes to abstract the common roll back tasks to separate YAML files in a directory called “rollback”. I’ve included a small sample of the playbook below which includes “rollback/exit.yml” when the result of the previous task failed. What seems to happen is that ansible includes the tasks from the rollback/exit.yml file and applies the “when: result|failed” condition to every task in the included yaml file. This produces the desired result but does print out a bunch of “skipped” messages as shown below. Is there a way to tell ansible to only include the tasks if the previous task failed or to not show the skipped tasks? Is there a better way to accomplish what I’m trying to do?

I’m using a version of the command below to run the playbook (filename of playbook changed):

ansible-playbook playbooks/company_app.yml -i playbooks/hosts --tags "testing"

playbooks/company_app.yml

`

  • hosts: all
    vars:
    RPM_NAME: ‘company_app_pacakge_name’
    remote_user: ansible
    sudo: yes
    #accelerate: true
    tasks:
  • name: Installing new RPM
    yum: “name={{ RPM_NAME }} state=present”
    ignore_errors: true

tags:

  • testing
    register: result
  • include: rollback/exit.yml
    when: result|failed
    <>
    `

playbooks/rollback/exit.yml
`

Includes with conditionals are implemented by including all the steps and applying the conditional to each included task.

You will get skipped messages.

Often a better solution is using the group_by module to create a dynamic group, and then applying that config to just the hosts that match.

This almost always produces cleaner output and is used often to apply different configs based on OS.

http://docs.ansible.com/group_by_module.html

Thanks for the reply Michael.

I came across the group_by module when Googling around but I didn’t understand how to use it until I started typing this reply. Below is an edited version of my previously posted playbook snippet. The only question I have is how should I skip the task “Stopping nginx” if “Installing new RPM” fails? Should I add “when: result|success” to all of my tasks so that later tasks will not be applied if one fails? Once one task fails, no other deployment tasks should be attempted and the rollback playlists should be called.

`

I’m not sure why you are ignoring failures on the install RPM step. That seems not good.

And ignoring errors on the service part, also not good!

What’s the reason for all of this?

We’re trying to avoid Ansible exiting when there’s an error, leaving the node in a half-deployed state. We want Ansible to attempt a rollback if the deployment of new software fails. That is, if any of the tasks fail, we want Ansible to stop executing the existing play and run some recover playbook instead.

I’m not sure if we are going down the right track with the current playbook. We’re definitely open to other suggestions of how to accomplish our goal.

"We’re trying to avoid Ansible exiting when there’s an error, leaving the node in a half-deployed state. "

Hmm.

Not sure of your production environment, but seems something about the package is very wrong if upgrades sometimes fail that I would want to get sorted out. Package installs should be meant to be reliable.

Consider moving your database schema upgrade invocation outside of the package?

As for leaving nodes in broken states, this is a good case for a rolling update with load balancers.

I don’t know your infrastructure enough to say if that’s possible, but ansible is designed to stop on a failure on purpose – which would leave failed nodes out of rotation.

You could also consider a seperate rollback playbook to use if you so decided to apply it, keeping it from maybe applying it self unexpectedly.