Dimitar Mihaylov
Dimitar Mihaylov

Reputation: 75

How can I configure Ansible playbook to ignore certain error codes?

I have a task to configure the following Ansible playbook to ignore error code 422 (which should happen when it looks for a volume that is detached from the server).
Furthermore, I currently see that this situation can also display error code 400, so, I may also have to exclude this.

    # ---
#   # This script will print the received parameters only
 - hosts: localhost
   connection: local

#   # Required parameters
#   # for testing locally
   vars:
     server_id: xxx
     backup_properties:
       name: xxx
       retention_period: x
       volume_ids:
       - xxx

   gather_facts: no

   tasks:

    # Get moss_url variable
    - include_tasks: ../vault_get_moss_environment.yml   

    # Request the backup from the endpoint
    - name: Call MOS Windows Service Endpoint
      uri:
        url: "{{ moss_url }}/v1/service-instances/{{ server_id }}/backups"
        method: POST
        return_content: yes
        status_code: 202
        headers:
            Content-Type: "application/json"
            Authorization: "Bearer {{ getToken.json.access_token }}"
        body_format: json
        body: {
              "name": "{{ backup_properties.name | default('Backup Before Update') }}",
              "volumeIds": "{{ backup_properties.volume_ids | default(omit) }}",
              "retentionPeriod": "{{ backup_properties.retention_period | default(14) }}" 
        }
      register: trigger_backup_response 
      no_log: false
      ignore_errors: yes
    
    - fail:
       msg: "Error code: {% if trigger_backup_response.msg %}{{ trigger_backup_response.msg }}{% else %}{{ trigger_backup_response }}{% endif %}"
      when: trigger_backup_response.failed | default(false) and trigger_backup_response.json.status != "NOT_FOUND" # .failed is defined only when it fails

    - name: Delete server's backup schedules if server is not found in Openstack
      include_tasks: ../MOSS/call_moss_delete_backup_schedules.yml
      vars:
        id: "{{ server_id }}"
      when: trigger_backup_response.status == 404 and trigger_backup_response.json.status == "NOT_FOUND"

    - name: Get the id from the content
      debug: 
        msg: "Started backup job with id: {{ trigger_backup_response.json.id }} for server with id: {{ server_id }}"
      when: trigger_backup_response.status == 202

    - name: Set backup_job_id as a fact 
      set_fact: 
        backup_job_id="{{ trigger_backup_response.json.id }}"
      when: trigger_backup_response.status == 202
    
    ###### Please do not delete this debug as it is used by MOSS #####
    - debug:
        msg: "backup_job_id={{ backup_job_id }}"
      when: trigger_backup_response.status == 202

I am aware that I probably have to use ignore_erros in some context, but, am not able to locate any way to exclude errors specifically by their code.

So, overall the question is how can I make this playbook ignore specifically errors 422 and 400 without sending any alerts or performing any actions?

Upvotes: 2

Views: 5418

Answers (2)

Dimitar Mihaylov
Dimitar Mihaylov

Reputation: 75

So two things turned out to be the issue here:

  1. I had forgotten initally to refresh my project in AWS.
  2. The failed_when had to be used before no_log: false and ignore_errors: yes (the no_log part probably didn't matter too much, but the ignore_errors mechanism was apparently taking effect as it was before the condition of when not to fail).

Currently, the working code looks like this:

# ---
#   # This script will print the received parameters only
# - hosts: localhost
#   connection: local

#   # Required parameters
#   # for testing locally
#   vars:
#     server_id: xxx
#     backup_properties:
#       name: xxx
#       retention_period: x
#       volume_ids:
#       - xxx

#   # gather_facts: no

#   tasks:

    # Get moss_url variable
    - include_tasks: ../vault_get_moss_environment.yml   

    # Request the backup from the endpoint
    - name: Call MOS Windows Service Endpoint
      uri:
        url: "{{ moss_url }}/v1/service-instances/{{ server_id }}/backups"
        method: POST
        return_content: yes
        status_code: 202
        headers:
            Content-Type: "application/json"
            Authorization: "Bearer {{ getToken.json.access_token }}"
        body_format: json
        body: {
              "name": "{{ backup_properties.name | default('Backup Before Update') }}",
              "volumeIds": "{{ backup_properties.volume_ids | default(omit) }}",
              "retentionPeriod": "{{ backup_properties.retention_period | default(14) }}" 
        }
      register: trigger_backup_response
      failed_when: trigger_backup_response.status not in [202, 422] 
      no_log: false
      ignore_errors: yes
    
    - fail:
       msg: "Error code: {% if trigger_backup_response.msg %}{{ trigger_backup_response.msg }}{% else %}{{ trigger_backup_response }}{% endif %}"
      when: trigger_backup_response.failed | default(false) and trigger_backup_response.json.status != "NOT_FOUND" # .failed is defined only when it fails

    - name: Delete server's backup schedules if server is not found in Openstack
      include_tasks: ../MOSS/call_moss_delete_backup_schedules.yml
      vars:
        id: "{{ server_id }}"
      when: trigger_backup_response.status == 404 and trigger_backup_response.json.status == "NOT_FOUND"

    - name: Get the id from the content
      debug: 
        msg: "Started backup job with id: {{ trigger_backup_response.json.id }} for server with id: {{ server_id }}"
      when: trigger_backup_response.status == 202

    - name: Set backup_job_id as a fact 
      set_fact: 
        backup_job_id="{{ trigger_backup_response.json.id }}"
      when: trigger_backup_response.status == 202
    
    ###### Please do not delete this debug as it is used by MOSS #####
    - debug:
        msg: "backup_job_id={{ backup_job_id }}"
      when: trigger_backup_response.status == 202

With that said, the previous answer was completely valid, just needed some modifications in this specific case. So thanks a lot for the assistance! =)

Upvotes: 0

β.εηοιτ.βε
β.εηοιτ.βε

Reputation: 39355

You can use a better mechanism than ignore_errors in this case, it is failed_when.
With it, you can fine grain the failure of a task to exactly what you want.

In your case it would be something like:

- name: Call MOS Windows Service Endpoint
  uri:
    url: https://example.org/api
  ## reduced the uri for brevity
  register: trigger_backup_response
  failed_when: trigger_backup_response.status not in [202, 400, 422]

This will cause the codes 202, 400 and 422 to have a successful task, all other status code would, then, fail.

Next to this, in order to handle the tasks based on the return of that API call, you can either use a block:

- block:
    - debug:
        msg: First task upon receiving a return form the API

    - debug:
        msg: Second task upon receiving a return form the API

    - debug:
        msg: Third task upon receiving a return form the API

  when: trigger_backup_response.status == 202

Or, stop the execution totally, with the help of the meta module.
The task here under will stop the play, on an host basis, if the the return code of the API is either 400 or 422.

- meta: end_host
  when: trigger_backup_response.status in [400, 422]

So, having a scenario like:

- name: Call API
  uri:
    url: https://example.org/api
  register: trigger_backup_response
  failed_when: trigger_backup_response.status not in [202, 400, 422]

- name: End play for hosts with detached volumes
  meta: end_host
  when: trigger_backup_response.status in [400, 422]

## From now on, it is safe to assume
## we are only dealing with API answer status being 202
- name: Display volume IDs
  debug:
    var: backup_properties.volume_ids

Upvotes: 4

Related Questions