Why does this Ansible task report a failure

ansibleshell

I am trying to configure an Ansible task that will check for the existence of a specific cert within the Java cacerts keystore file, and if it does not exist, install it.

- name: copy cert to home
    copy:
      src: my_cert_file.crt
      dest: /home/ec2-user/my_cert_file.crt
      owner: root
      group: root
      mode: 0644

- name: check for domain SSL cert 
  shell: /usr/java/latest/bin/keytool -keystore /usr/java/latest/jre/lib/security/cacerts -storepass changeit -alias trusted_cert -list
  register: trusted_cert



- name: install SSL cert into cacerts
  shell: /usr/java/latest/bin/keytool -import -keystore /usr/java/latest/jre/lib/security/cacerts -storepass changeit -file /home/ec2-user/my_cert_file.crt -noprompt -alias trusted_cert
  when: trusted_cert.stdout.find('trustedCertEntry') == 1

The above command, /usr/java/latest/bin/keytool -keystore /usr/java/latest/jre/lib/security/cacerts -storepass changeit -alias trusted_cert -list, returns the following when the cert doesn't exist:

keytool error: java.lang.Exception: Alias <trusted_cert> does not exist

This causes the task to return FAILED!, and causes the remaining tasks for the host to be skipped. When this task fails, however, I'd like the next step to install the cert. It already works correctly the other way — when the task succeeds, it does not attempt to install the cert, and it skips the install task.

I don't know enough about Ansible to say this definitively, but my assumption here is that when Java keytool is run and encounters the exception, it exits with status 1. Ansible sees the command exit status 1 and interprets this as a failure, and then reports the task as failed. The documentation on Ansible's error handling is good but it doesn't really talk about what's going on under the hood. So, is my assumption correct about how Ansible interprets the exit code 1, and I just need to ignore_errors: yes while registering the output of name: check for domain SSL cert?

I just want to clarify, I know how to solve the problem — my question isn't how to fix my Ansible tasks and make them work, but is to understand why my task is failing.

Best Answer

Anything non-zero exit status for the command is counted as a failure.

You can ignore all errors on the task:

ignore_errors: yes

or it's likely you could use failed_when to set conditions (I haven't tested this exact condition set, but you get the idea...) that ensure it fails if an unexpected failure is encountered, but continues if this expected one is seen:

failed_when: 
  - "'does not exist' not in trusted_cert.stderr"
  - "trusted_cert.rc != 0"