Seite wählen

NETWAYS Blog

Variablen mergen mit Ansible

 

Ansible kann Variable standardmäßig nicht mergen (miteinander vereinen, ineinander übergeben), sondern nur an verschiedenen Stellen überschreiben. Dies ist  bei manchen Anwendungsfällen unpraktisch, unübersichtlich und fehleranfällig wie z. B. beim ausrollen von SSH-Keys, Usern oder Firewall-Regeln. Angenommen wir wollen sowohl allgemeine SSH-Keys auf alle Server ausrollen, als auch extra Schlüssel zu bestimmten Servern zuordnen. In diesem Fall können wir unter group_vars/all  die allgemeinen Keys in einem Array oder in einem Dictonary definieren und unter group_vars/group_name oder host_vars/hostname die vorherigen Keys plus die Extras eintragen. Eine andere Möglichkeit wäre, dass wir die SSH-Keys (allgemeine und spezifische) in unterschiedlichen Variablen packen, die jeweils mit einem Task behandelt werden können. Die oben erwähnte Möglichkeiten machen besonders bei großen Umgebungen kein Spaß und ergibt am Ende entweder unübersichtliche Variablen-Definition oder statische Rollen.

In diesem Zuge wäre hiera im Kombination mit dem hiera lookup plugin eine gute Lösung. hiera ist ein hierarchisch durchsuchbarer key => value Store. In diesem Blogpost werde ich anhand eines Beispiels demonstrieren, wie hiera mit Ansible eingesetzt werden kann. Dieses Beispiel befasst die Verteilung der Konfigurationen für Gruppen, Benutzers und SSH-Keys auf zwei Server.  Bei allen Linux-Distrubtionen gibt es in unserem Fall keine Unterschiede. Alle Schritte erfolgen auf dem Ansible Controller.  Ich fange mal mit der hiera Installation an.

# yum install ruby -y
# gem install hiera

Unter /etc/hiera.yaml liegt die hiera-Konfiguration.

:backends:
- yaml
:hierarchy:
- "%{groups}"
- "%{hosts}"
- common

:yaml:
:datadir: /etc/hieradata

:merge_behavior: deeper

Unter hierarchy definieren wir die Stufen aufsteigend/absteigend, bei denen hiera nach einem Schlüssel suchen soll. hiera fängt mit groups an zu suchen und endet mit common. common trifft immer zu und gilt in unserem Fall für alle Server. groups und hosts sind Facts, die wir später dem Ansible playbook übergeben wollen. Der Pfad zu suchenden Daten bzw. Schlüsseln kann man beliebig ändern. Außerdem kann man bei :merge_behavior: eine der drei folgenden Optionen einstellen: native, deep, deeper. Um die Unterschiede zu erfahren, könnt ihr das hier nachlesen.

In der Ansible-Inentory stehen zwei Hosts jweils unter einer Gruppe.

[webserver]
web1.shared
web2.shared
web3.shared

[monitoring]
icinga-master1.shared

Unter /etc/hieradata/common.yaml liegen die SSH-Keys, die auf alle Server ausgerollt werden müssen, da common.yaml als unser Default für alle Hosts gilt, wie schon vorher erwähnt wurde.

---
ssh_users:
  - name: 'sergio'
    comment: 'sergio@example.com'
    key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDjuyGPTdo17ATAu69v2Bqui/f38e1uqOLvObiMw+uS9+Raxy5sO12pagVJeN9BTQaL09Sp9Dw+ozozg67WXfgTo+yoC5wy5a3d3Ihl4XJ/68SFUmEO2qo8Zg3914teL+FQMw5BE52LyqJjjBulGQ+jloGaldqxBfvjrmGMnz3mafCLtix+/UO1W+51gkea925XAOQ+KR1u1WFbEM3E6TfAoMv5Ev41e3jIcS+O+dnBqiZLsSIF3h72ni4eGr6h6x51itoFGQhN1jRcK9J5QfJG4O8OciReUCU5gETLi8RgFuBlQqDztZT1jGPbpkH2/swt3WGBUGOv+GizQg8iK9F"
    authorize_to: 'root'
    state: present

  - name: 'david'
    key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDRsAZ3DKxisCchDBd1dqtM9kPEgq+8MXbkClYVAoAlidx6qLz8Z6zBeSZ8ob+ae0dEegoN31mXv9ITaFhIdgIUxP0s54Mb4kgc9FE4njNRlb7xkTwsU3C6G7JUN9pJ64ucEqLI2iJ1JLI+zh0u5sWZS0tMoyEy73ZaAE6O32XyywIw5X+Uw7ISwqeeFsnWc4faKoWVgjt/s1MsuEOGsD1ocUxVPG7PKMEy8LQtQ7WL+RybV/TYH56hxBMi5H4BfC61Wm6Fn7pck5pCMzZOwstYikHoTWhJ16UYoJ6MubddoAOq/JyTimC/559U3lYgdHBXGJyCyW2xcGF7blmh0U97"
    authorize_to: 'root'
    state: absent

Unter /etc/hieradata/monitoring.yaml steht extra Konfiguration für die Hosts, die der monitoring-Gruppe zugeordnet sind.

user_groups:
  - name: 'nagios'
    state: 'present'

users:
  - name: 'icinga'
    shell: '/bin/bash'
    groups: 'nagios'
    append: yes
    state: 'present'

ssh_users:
  - name: 'alex'
    comment: 'sergio@example.com'
    key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCu5vAfoePg8Z5Tc3uOfua+RvxpA/WyDNKtHJze/pogssAtA+RZ6wdmvwuBGVFILgVKrpHItsUWZwWwsrNF0rjXV4MsPZzS8TbUNISoV7sETOk6pM1vg8ldy5XEszCokFsHmYLfovlqaICneKwiZ4SfQo21WjgzNXeVSND/1W5BZNAptobH6HC9oASRgeidwbDjDEux8//zvjjcIQlj9HXGmsKT5/r2+LR5Wo8rRkhdC+sbDJcDfN9OFg2Wo+PmwX6ArMfZ3oqh4xEGS3hN4Yo8lAVK8APPKNojtKv53qnFNTkfNrHRw9MbiXpPiYMFmKtGZztc9vPNKB6kBF1DFL/'
    authorize_to: 'icinga'
    state: present

Die Konfigurationen unter /etc/hieradata/web1.shared.yaml werden nur dem web1.shared angeordnet.

---
user_groups:
  - name: 'web-group'
    state: 'present'

  - name: 'admins'
    state: 'present'

users:
  - name: 'web-user'
    shell: '/bin/bash'
    groups: 'web-group, admins'
    append: yes
    state: 'present'

ssh_users:
  - name: 'mueller'
    comment: 'web-user@example.com'
    key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCg6fvX0UIN22fPHHbSxPZQCyeqa8j2AEeqF7TlX3TSkJ17Q7Rz3g4B1RG8L+WfI+eb11bmESPTQ5Pym27qmNvfYl6dJynSdrRihnNj4Id1fKEzoW6J835rtRmaKD0V7KJ1JJvip0m24oIlFJIYSfShWSrOuvUgP3TpYUsU3KA2AQhoNtXWhgUM+wwFfCF3qZ4AX5zhQFy+bdqyYudmW99DasuZjaCq3djoMh9Ocm9lRPdDTpGS/Yb1yAqKU7rizrwlS3EmNcbQddRd2ZXFQnustfSX+ejo7PcEpimAPpcC2jbbS38pFbYdIvdm7BXsRMpsOXEuEZLrrbZMsPpEQ8FJ'
    authorize_to: 'web-user'
    state: present

Unser playbook kann so aussehen.

---
- hosts: all
  remote_user: root
  become: true
  tasks:
    - name: Set facts
      set_fact:
        ssh_users: "{{ lookup('hiera', 'ssh_users --array hosts={{ inventory_hostname }}  groups={{ item }} --format yaml')|from_yaml }}"
        user_groups: "{{ lookup('hiera', 'user_groups --array hosts={{ inventory_hostname }}  groups={{ item }} --format yaml')|from_yaml }}"
        users: "{{ lookup('hiera', 'users --array hosts={{ inventory_hostname }}  groups={{ item }} --format yaml')|from_yaml }}"
      loop: "{{ group_names }}"
 
    - name: Create groups
      group:
        name: "{{ item.name }}"
        state: "{{ item.state }}"
      loop: "{{ user_groups | default ([]) }}"
  - name: Create users
      user:
        name: "{{ item.name }}"
        shell: "{{ item.shell | default (omit) }}"
        state: "{{ item.state }}"
        append: "{{ item.append }}"
      loop: "{{ users | default ([]) }}"

    - name: Set ssh-keys
      authorized_key:
        user: "{{ item.authorize_to }}"
        state: "{{ item.state }}"
        key: "{{ item.key }}"
      loop: "{{ ssh_users | default ([]) }}"

Das lookup-Plugin nutzt hiera um auf Daten bzw. Schlüssel zugreifen zu können. Wir geben die zu suchenden Schlüssel mit, z. B. ssh-users. Wir übermitteln auch die Facts die hiera erwartet, nämlich hosts und groups. Man kann anstatt “inventory_hostname” “ansible_hostname” oder “ansible_fqdn” verwenden. Allerdings muss man die Datein unter /etc/hieradata entsprechend benennen. Groupe-Fact geben wir durch einen Loop über den Ansible-Fact group_names an die hiera weiter, in dem alle Gruppen der Inventory aufgelistet sind. Die Rückgabe ist in unserem Fall ein array, man kann auch einen hash auswählen. Die standardmäßige Format bei hiera is ruby, allerdings stellen wir das auf yaml um, damit Ansible die Format verarbeiten kann.

# ansible-playbook hiera-playbook.yml -i inventory

PLAY [all] ****************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************************************************************************
ok: [web1.shared]
ok: [icinga-master1.shared]

TASK [Set facts] **********************************************************************************************************************************************************************************************************************
ok: [icinga-master1.shared] => (item=monitoring)
ok: [web1.shared] => (item=webserver)

TASK [Create groups] ******************************************************************************************************************************************************************************************************************
ok: [icinga-master1.shared] => (item={u'state': u'present', u'name': u'nagios'})
ok: [web1.shared] => (item={u'state': u'present', u'name': u'web-group'})
ok: [web1.shared] => (item={u'state': u'present', u'name': u'admins'})

TASK [Create users] *******************************************************************************************************************************************************************************************************************
ok: [web1.shared] => (item={u'groups': u'web-group, admins', u'state': u'present', u'shell': u'/bin/bash', u'name': u'web-user', u'append': True})
ok: [icinga-master1.shared] => (item={u'groups': u'nagios', u'state': u'present', u'shell': u'/bin/bash', u'name': u'icinga', u'append': True})

TASK [Set ssh-keys] *******************************************************************************************************************************************************************************************************************
ok: [icinga-master1.shared] => (item={u'comment': u'sergio@example.com', u'state': u'present', u'authorize_to': u'icinga', u'name': u'alex', u'key': u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCu5vAfoePg8Z5Tc3uOfua+RvxpA/WyDNKtHJze/pogssAtA+RZ6wdmvwuBGVFILgVKrpHItsUWZwWwsrNF0rjXV4MsPZzS8TbUNISoV7sETOk6pM1vg8ldy5XEszCokFsHmYLfovlqaICneKwiZ4SfQo21WjgzNXeVSND/1W5BZNAptobH6HC9oASRgeidwbDjDEux8//zvjjcIQlj9HXGmsKT5/r2+LR5Wo8rRkhdC+sbDJcDfN9OFg2Wo+PmwX6ArMfZ3oqh4xEGS3hN4Yo8lAVK8APPKNojtKv53qnFNTkfNrHRw9MbiXpPiYMFmKtGZztc9vPNKB6kBF1DFL/'})
ok: [web1.shared] => (item={u'comment': u'web-user@example.com', u'state': u'present', u'authorize_to': u'web-user', u'name': u'mueller', u'key': u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCg6fvX0UIN22fPHHbSxPZQCyeqa8j2AEeqF7TlX3TSkJ17Q7Rz3g4B1RG8L+WfI+eb11bmESPTQ5Pym27qmNvfYl6dJynSdrRihnNj4Id1fKEzoW6J835rtRmaKD0V7KJ1JJvip0m24oIlFJIYSfShWSrOuvUgP3TpYUsU3KA2AQhoNtXWhgUM+wwFfCF3qZ4AX5zhQFy+bdqyYudmW99DasuZjaCq3djoMh9Ocm9lRPdDTpGS/Yb1yAqKU7rizrwlS3EmNcbQddRd2ZXFQnustfSX+ejo7PcEpimAPpcC2jbbS38pFbYdIvdm7BXsRMpsOXEuEZLrrbZMsPpEQ8FJ'})
ok: [web1.shared] => (item={u'comment': u'sergio@example.com', u'state': u'present', u'authorize_to': u'root', u'name': u'sergio', u'key': u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDjuyGPTdo17ATAu69v2Bqui/f38e1uqOLvObiMw+uS9+Raxy5sO12pagVJeN9BTQaL09Sp9Dw+ozozg67WXfgTo+yoC5wy5a3d3Ihl4XJ/68SFUmEO2qo8Zg3914teL+FQMw5BE52LyqJjjBulGQ+jloGaldqxBfvjrmGMnz3mafCLtix+/UO1W+51gkea925XAOQ+KR1u1WFbEM3E6TfAoMv5Ev41e3jIcS+O+dnBqiZLsSIF3h72ni4eGr6h6x51itoFGQhN1jRcK9J5QfJG4O8OciReUCU5gETLi8RgFuBlQqDztZT1jGPbpkH2/swt3WGBUGOv+GizQg8iK9F'})
ok: [icinga-master1.shared] => (item={u'comment': u'sergio@example.com', u'state': u'present', u'authorize_to': u'root', u'name': u'sergio', u'key': u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDjuyGPTdo17ATAu69v2Bqui/f38e1uqOLvObiMw+uS9+Raxy5sO12pagVJeN9BTQaL09Sp9Dw+ozozg67WXfgTo+yoC5wy5a3d3Ihl4XJ/68SFUmEO2qo8Zg3914teL+FQMw5BE52LyqJjjBulGQ+jloGaldqxBfvjrmGMnz3mafCLtix+/UO1W+51gkea925XAOQ+KR1u1WFbEM3E6TfAoMv5Ev41e3jIcS+O+dnBqiZLsSIF3h72ni4eGr6h6x51itoFGQhN1jRcK9J5QfJG4O8OciReUCU5gETLi8RgFuBlQqDztZT1jGPbpkH2/swt3WGBUGOv+GizQg8iK9F'})
ok: [icinga-master1.shared] => (item={u'state': u'absent', u'authorize_to': u'root', u'name': u'david', u'key': u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDRsAZ3DKxisCchDBd1dqtM9kPEgq+8MXbkClYVAoAlidx6qLz8Z6zBeSZ8ob+ae0dEegoN31mXv9ITaFhIdgIUxP0s54Mb4kgc9FE4njNRlb7xkTwsU3C6G7JUN9pJ64ucEqLI2iJ1JLI+zh0u5sWZS0tMoyEy73ZaAE6O32XyywIw5X+Uw7ISwqeeFsnWc4faKoWVgjt/s1MsuEOGsD1ocUxVPG7PKMEy8LQtQ7WL+RybV/TYH56hxBMi5H4BfC61Wm6Fn7pck5pCMzZOwstYikHoTWhJ16UYoJ6MubddoAOq/JyTimC/559U3lYgdHBXGJyCyW2xcGF7blmh0U97'})
ok: [web1.shared] => (item={u'state': u'absent', u'authorize_to': u'root', u'name': u'david', u'key': u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDRsAZ3DKxisCchDBd1dqtM9kPEgq+8MXbkClYVAoAlidx6qLz8Z6zBeSZ8ob+ae0dEegoN31mXv9ITaFhIdgIUxP0s54Mb4kgc9FE4njNRlb7xkTwsU3C6G7JUN9pJ64ucEqLI2iJ1JLI+zh0u5sWZS0tMoyEy73ZaAE6O32XyywIw5X+Uw7ISwqeeFsnWc4faKoWVgjt/s1MsuEOGsD1ocUxVPG7PKMEy8LQtQ7WL+RybV/TYH56hxBMi5H4BfC61Wm6Fn7pck5pCMzZOwstYikHoTWhJ16UYoJ6MubddoAOq/JyTimC/559U3lYgdHBXGJyCyW2xcGF7blmh0U97'})

PLAY RECAP ****************************************************************************************************************************************************************************************************************************
icinga-master1.shared      : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
web1.shared                : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

 

Wenn Du mehr über Ansible lernen und Dein wissen vertiefen willst, wäre eine Teilnahme an einer Ansible Schulung nicht verkehrt.

 

Afeef Ghannam
Afeef Ghannam
Support Engineer

Afeef hat seine Ausbildung Als Fachinformatiker in Richtung Systemintegration im Juli 2020 bei NETWAYS absolviert, seitdem unterstützt er die Kollegen im Support und bei der Betriebsunterstützung. Nach der Arbeit macht er gerne Sport, trifft Freunde oder mag es Filme zu schauen.

Ansible – AWX|Tower State handling on Workflows

The Ansible Tower or its upstream AWX provides an easy to use GUI to handle Ansible tasks and schedules. Playbooks are configured as templates and as the name suggests, they can be modified to the needs, extended by variables, a survey or tags.

Furthermore those templates can be logically grouped, connected and visualised in Workflows.

The downside to those Workflows, all playbooks affected by this are executed separately and can’t access each others variables. On first glance we maybe only spot that we can define variables for the whole workflow but those are not changeable throughout the flow.

But there is a solution, which is the module set_stats. This module allows to save or accumulate variables and make them available for other playbooks within the workflow.

As an example we could use the monitoring environment when setting downtimes.

workflow

As a downtime is created before a maintenance and should be gone when the maintenance is done. This creates a dependency on the first task, which can be solved as we save the result of the first tasks with the set_stats module.


      - name: schedule downtimes
        icinga2_downtimes:
          state: "{{ downtime_icinga_state | default('present') }}"
          host: ***
          author: "{{ icinga2_downtimes_author | default('ansible_downtime') }}"
          comment: "{{ icinga2_downtimes_comment | default('Downtime scheduled by Ansible') }}"
          duration: "{{ icinga2_downtimes_duration | default(omit) }}"
        register: content
 
      - set_stats:
          data:
            downtime: "{{ content }}"

The content of the data will be now available to all playbooks included by the workflow. The variable is also shown as artefacts in the GUI.

artefacts

Keep in mind that the variable will be part of the extra variables for all other playbooks. As covered in the variable precedence it will overwrite any other variable named the same.

With this module you can reorganise your playbooks and connect them in workflows. This allows you to have a more flexible automation than before.

Check out our Blog for more awesome posts and if you need help with Ansible send us a message or sign up for one of our trainings!

Thilo Wening
Thilo Wening
Consultant

Thilo hat bei NETWAYS mit der Ausbildung zum Fachinformatiker, Schwerpunkt Systemadministration begonnen und unterstützt nun nach erfolgreich bestandener Prüfung tatkräftig die Kollegen im Consulting. In seiner Freizeit ist er athletisch in der Senkrechten unterwegs und stählt seine Muskeln beim Bouldern. Als richtiger Profi macht er das natürlich am liebsten in der Natur und geht nur noch in Ausnahmefällen in die Kletterhalle.

Ansible – Loop over multiple tasks

ansible logo

The last time I wrote about Ansible and the possibility to use blocks to group multiple tasks. Which you can read here. Sadly this feature does not work with loop, so there is no clean way to loop over multiple tasks in a play without writing the same loop statement at tasks over and over.

But when we come across the need of tasks which depend on each other, for example, we execute a script with a certain parameter and its result is necessary for the upcoming tasks.

Let’s go through a common example, creating a site consists of a few steps. Creating the directory, creating the vhost and then enabling the site.


- name: "create {{ site }} directory"
  file:
    ensure: directory
    dest: "/var/www/{{ site }}"
    
- name: "create {{ site }}"
  template:
    src: vhost.j2
    dest: "/etc/apache2/sites-available/{{ site }}"
  register: vhost

- name: "enable {{ site }}"
  command: /usr/sbin/a2ensite "{{ site }}"
  register: result
  when: vhost.changed
  changed_when: "'Enabling site' in result.stdout"
  notify: apache_reload

We could use a loop for each tasks and afterwards find the right result for the next task to depend on. But the styleguide will warn you if you try to use Jinja2 syntax in when statements.

So the best solution to this is to use include_tasks, which can include a file with tasks. This task is allowed to have a loop directive and so we can include it multiple times.
Lets see how this would apply to our scenario:


- set_fact:
    sites:
      - default
      - icingaweb2

- name: create vhosts
  include_tasks: create-vhosts.yml
  loop: "{{ sites }}"
  loop_control:
    loop_var: site


In the Result we can see clearly that all tasks are applied for each element in the sites variable.


TASK [set_fact] *********************************************
ok: [localhost]

TASK [create vhosts] ****************************************
included: /Users/twening/Documents/netways/ansible_test20/create-vhosts.yml for localhost => (item=default)
included: /Users/twening/Documents/netways/ansible_test20/create-vhosts.yml for localhost => (item=icingaweb2)

TASK [create default directory] *****************************
ok: [localhost]

TASK [create default] ***************************************
ok: [localhost]

TASK [enable default] ***************************************
ok: [localhost]

TASK [create icingaweb2 directory] **************************
ok: [localhost]

TASK [create icingaweb2] ************************************
ok: [localhost]

TASK [enable icingaweb2] ************************************
ok: [localhost]

PLAY RECAP **************************************************
localhost                  : ok=10   changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0


Check out our Blog for more awesome posts and if you need help with Ansible send us a message or sign up for one of our trainings!

Thilo Wening
Thilo Wening
Consultant

Thilo hat bei NETWAYS mit der Ausbildung zum Fachinformatiker, Schwerpunkt Systemadministration begonnen und unterstützt nun nach erfolgreich bestandener Prüfung tatkräftig die Kollegen im Consulting. In seiner Freizeit ist er athletisch in der Senkrechten unterwegs und stählt seine Muskeln beim Bouldern. Als richtiger Profi macht er das natürlich am liebsten in der Natur und geht nur noch in Ausnahmefällen in die Kletterhalle.

Ansible Host-Gruppen: Wer gehört zu wem?

Immer wieder kommt es vor, dass ich in größeren Ansible-Umgebungen arbeite. Diese enthalten eine Vielzahl von verschiedenen Gruppen im Inventory, die sich auch mal aus anderen Host-Gruppen zusammen setzen. Da ist es nicht immer leicht den Überblick zu behalten.
Da kommt es schon mal vor, prüfen zu wollen oder zu müssen ob alle Gruppen richtig aufgebaut sind oder korrekt interpretiert werden.
Nach ein wenig Recherche war auch schnell mit einem einfachen Ein-Zeiler eine Lösung gefunden, um sich anzeigen zu lassen in welcher Gruppe die einzelnen Server einsortiert sind oder wie sich die Gruppe im Ansible-Inventory zusammen setzt

ansible -i <inventory> localhost -m debug -a 'var=groups'

Dabei lässt sich entweder das Inventory-Verzeichnis oder eine konkrete Inventory-Hostdatei angeben.
Und weil es mit einem Beispiel immer besser ist:

ansible -i hosts localhost -m debug -a 'var=groups'
localhost | SUCCESS => {
    "groups": {
        "all": [
            "maja42310",
            "maja42444",
            "willy1334",
            "willy24242",
            "koenigin_blau"
        ],
        "drohnen": [
            "willy1334",
            "willy24242"
        ],
        "honigbienen": [
            "maja42310",
            "maja42444"
        ],
        "honigbienenvolk": [
            "maja42310",
            "maja42444",           
            "willy1334",
            "willy24242",
            "koenigin_blau"
        ],
        "koenigin": [
            "koenigin_blau"
        ],
        "ungrouped": []
    }
}

Da ich mir das nun mehr als ein mal nicht merken konnte, dachte ich mir ich schreib das mal hier auf. Vielleicht hilft es ja dem ein oder anderen und ich kann es mir jetzt besser merken:)

Wenn Ihr noch mehr über Ansible erfahren wollt, dann besucht doch einfach eines unserer Trainings bei Netways Events. Sollte es schon etwas konkreter sein und Ihr benötigt gezielt Hilfe, fragt doch gerne unsere Kollegen vom Sales Team ob Ihr nicht Unterstützung von Netways Professional Service bekommt.

Daniel Neuberger
Daniel Neuberger
Senior Consultant

Nach seiner Ausbildung zum Fachinformatiker für Systemintegration und Tätigkeit als Systemadministrator kam er 2012 zum Consulting. Nach nun mehr als 4 Jahren Linux und Open Source Backup Consulting zieht es ihn in die Welt des Monitorings und System Management. Seit April 2017 verstärkt er das NETWAYS Professional Services Team im Consulting rund um die Themen Elastic, Icinga und Bareos. Wenn er gerade mal nicht um anderen zu Helfen durch die Welt tingelt geht er seiner...

Ansible – Use Blocks and Rescue Errors

Ansible is a widely used and powerful open-source configuration and deployment management tool. It can be used for simple repetitive daily tasks or complex application deployments, therefore Ansible is able to cover mostly any situation.

Since version 2.0.0 Ansible introduced the usage of blocks, they provide the possibility to group or rescue failed tasks.
On blocks we can assign most directives which are available for any other task at block level, only loops aren’t available.

- name: Update Systems
  hosts: all
  tasks:
    - name: execute this block only for rhel family hosts
      block:
        - name: install epel repository
          yum:
            name: epel-release
            state: present

        - name: install updates
          yum:
            name: '*'
            state: latest
            exclude: kernel*

      when: ansible_os_family == 'RedHat'
      become: true

When we try to deploy applications, sometimes we need to test connections or if requirements are met. When those tasks fail caused by the negative test result, the playbook by default fails and therefore stops.
To force Ansible to execute all other tasks, we could use the directive ignore_failed: true and checking the return value for any other depending task.

With blocks this is easily solved, by using rescue to catch the error and force a particular tasks to run.
The always will make sure that the listed tasks get executed.


- name: rescue my errors
  hosts: localhost
  tasks:
    - name: Try to reach host
      block:
        - name: "[Try reach DNS] Check Connection over DNS"
          command: ping client01.demo.local -c 2
          register: output
      rescue:
        - name: "[Rescue failed DNS] Check Connection over IP"
          command: ping 192.168.33.1 -c 2
          register: output
      always:
        - debug:
            var: output

To handle more than one rescue statement, the block can be simply used in the rescue section, like in the following example.


  - name: Try to execute skript
    block:
      - name: Check Connection over DNS
        command: ping nclient01.demo.local -c 2
        register: output
    rescue:
      - name: "this will fail"
        block:
          - name: it will be false
            command: /bin/false
            register: output
        rescue:
          - name: "this works"
            command: ping 192.168.33.1 -c 2
            register: output

Try to reduce ignored tasks in failed state with rescue blocks, this reduces the confusion of users when inspecting the output.
As second advice try to reduce code duplication by grouping tasks with similar directives.

Check out our Blog for more awesome posts and if you need help with Ansible send us a message or sign up for one of our trainings!

Thilo Wening
Thilo Wening
Consultant

Thilo hat bei NETWAYS mit der Ausbildung zum Fachinformatiker, Schwerpunkt Systemadministration begonnen und unterstützt nun nach erfolgreich bestandener Prüfung tatkräftig die Kollegen im Consulting. In seiner Freizeit ist er athletisch in der Senkrechten unterwegs und stählt seine Muskeln beim Bouldern. Als richtiger Profi macht er das natürlich am liebsten in der Natur und geht nur noch in Ausnahmefällen in die Kletterhalle.

Veranstaltungen

Di 18

Icinga 2 Fundamentals Training | Online

Mai 18 @ 09:00 - Mai 21 @ 17:00
Jun 15

stackconf online

Juni 15 - Juni 17
Jun 22

Ansible Fundamentals Training | Online

Juni 22 @ 09:00 - Juni 24 @ 17:00
Jun 22

Kubernetes Quick Start | Online

Juni 22 @ 09:00 - 17:00
Jun 25

Ansible AWX (Tower) Training | Online

Juni 25 @ 09:00 - 17:00