centos:ansible:playbooks1

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
centos:ansible:playbooks1 [28.06.2020 14:10. ] – [07: Mit Hilfe von Ansible einen Offloader auf Basis eines Raspberry 4B bauen] djangocentos:ansible:playbooks1 [14.09.2022 14:50. ] (aktuell) – gelöscht django
Zeile 1: Zeile 1:
-====== Ansible - Playbookbeispiele ====== 
-{{:centos:ansible:ansible_logo.png?nolink&125|Bild: Ansible Logo}} \\ \\ 
- 
-Nachdem wir uns bereits eingehend mit den **[[centos:ansible:start#grundlagen|Grundlagen]]** und auch schon das benötigte Programmpaket auf unserer Admin-Workstation zur Orchestrierung **[[centos:ansible:start#installation|installiert haben]]**, werden wir uns nun ein paar Beispile ansehen, wie man sich das Leben mit Ansible-Playbooks leichter gestalten kann. 
- 
-===== Playbook - Beispiele ===== 
-In den beiden Kapiteln **[[centos:ansible:start#playbooks|Playbooks]]** und **[[centos:ansible:start#yaml_-_was_ist_das|YAML - was ist das?]]** hatten wir uns schon eingehend mit den Hintergrundinformationen zu diesen beiden Themenblöcken beschäftigt, so dass wir uns nun direkt mit unserem ersten Playbook beschäftigen können. 
- 
- 
-==== 01: Benutzer anlegen ==== 
-Bei unserem ersten Playbook-Beispiel wollen wir mit Hilfe von Ansible einen Benutzer auf unserem Zielsystem automatisiert anlegen. 
-Bevor wir unser erstes Script schreiben, wechseln wir in unser zuvor angelegtes Zielverzeichnis: 
-   $ cd ~/ansible 
- 
-=== Script anlegen === 
-Hier legen wir nun unser erstes Script ab. 
-   $ vim 01_create-user.yml 
- 
-<file bash 01_create-user.yml>--- 
-- hosts: centos8 
-  become: true 
-  vars: 
-    sudoers: ansible 
-    createguid: '1010' 
-    createuser: 'ruben' 
-    createusername: 'Ruben Nausch' 
-    createpassword: 'M31nP4p4157d3r4113r83573!' 
- 
-  tasks: 
-    - name: Make sure we have a group '{{ createuser }}' for our new admin-user '{{ createuser }}' 
-      group: 
-        name: '{{ createuser }}' 
-        gid: '{{ createguid }}' 
-        state: present 
- 
-    - name: Add the user '{{ createuser }}' with a specific uid and a primary group of '{{ createuser }}' 
-      user: 
-        name: '{{ createuser }}' 
-        comment: '{{ createusername }}' 
-        uid: '{{ createguid }}' 
-        group: '{{ createuser }}' 
-        state: present 
- 
-    - name: Initial password generation for user '{{ createuser }}' 
-      shell: usermod -p $(echo '{{ createpassword }}' | openssl passwd -1 -stdin) {{ createuser }} 
-...</file> 
- 
-=== Script Beschreibung === 
-Die einzelnen Zeilen haben dabei folgende Funktionen und Aufgaben. 
-Zeile: 
-  * Zeile **1**: **''%%---%%''** : Start-Ziele einer jeden YAML-Datei 
-  * Zeile **2**: **''- hosts: centos8''** : Das Script soll auf allen Systemen, die in unserer **[[#remote_user-anpassung_via_inventory_hostsyml|Inventory]]**-Datei die Eigenschaft **//CentOS 8//** zugewiesen bekommen haben. 
-  * Zeile **3**: **''become: true''** : Wir benötigen eine **[[#mit_abfrage_eines_passwortes|Rechteerweiterung]]** zu **root**-Rechten, damit wir einen neuen Nutzer auf dem Zielsystem anlegen können. 
-  * Zeile **4**: **''vars:''** Wir möchten unser Script so gestalten, dass dies später für ggf. weiter Nutzer möglichst einfach zu verwenden ist. Daher verwenden wir hier Variablen. 
-  * Zeile **5**: **''sudoers: ansible''** Nutzer auf dem Zielsystem, der für die Administrationsaufgaben benutzt werden soll. 
-  * Zeile **6**: **''createguid: '1010'''** Variable die der **UID** bzw. der **GID** unseres Nutzers 'ruben' zugewiesen werden soll. 
-  * Zeile **7**: **''createuser: 'ruben'''** Variable mit dem Nutzernamen 'ruben' 
-  * Zeile **8**: **''createusername: 'Ruben Nausch'''** Variable mit dem vollen Namen des Benutzers 'ruben' 
-  * Zeile **9**: **''createpassword: 'M31nP4p4157d3r4113r8357'''** Variable mit dem initialen Klartextpasswortes der Benutzers 'ruben' 
-  * Zeile **10**: 
-  * Zeile **11**: **''tasks''** Schlüsselwort mit den nachfolgenden Aufgaben, die mit dem Playbook dann abgearbeitet werden sollen. 
-  * Zeile **12**: **''name''**: Beschreibender Text(//Make sure we have a group 'ruben' for our new admin-user 'ruben'//), der später beim Aufruf von **''ansible-playbooks''** ausgegeben werden soll. 
-  * Zeile **13 - 16**: **''group:''** Ansible Module **[[https://docs.ansible.com/ansible/latest/modules/group_module.html|group]]** welches zum Anlegen, verändern und auch Löschen von Gruppen herangezogen werden kann.  
-  * Zeile **17**: 
-  * Zeile **18**: **''name''**: Beschreibender Text(//Add the user 'ruben' with a specific uid and a primary group of 'ruben'//), der später beim Aufruf von **''ansible-playbooks''** ausgegeben werden soll. 
-  * Zeile **19 - 24**: **''user:''** Ansible Module **[[https://docs.ansible.com/ansible/latest/modules/user_module.html|user]]** welches zum Anlegen, verändern und auch Löschen von Benutzern herangezogen werden kann.  
-  * Zeile **25**: 
-  * Zeile **26**: **''name''**: Beschreibender Text(//Initial password generation for user 'ruben'//), der später beim Aufruf von **''ansible-playbooks''** ausgegeben werden soll. 
-  * Zeile **27**: **''shell:''** Ansible Module **[[https://docs.ansible.com/ansible/latest/modules/shell_module.html|shell]]** welches zum Ausführen von Shell-Befehlen auf dem Zielsystem verwendet werden kann. Hiermit setzen wir das Passwort unseres gerade angelegten Users 'ruben'. 
-  * Zeile **28**: **''%%...%%''** Endekennzeichen der YML-Datei 
- 
- 
-=== Script ausführen === 
-Nun wollen wir unser ersten Playbook ausführen, um auf dem Zielhost den gewünschten Benutzer anzulegen; hierzu rufen wir unser Script wie folgt auf: 
-   $ ansible-playbook -v 01_create-user.yml --limit=demo 
- 
-<WRAP center round tip 80%> 
-Da wir den User erst einmal nur auf dem Host **demo** anlegen wollen, \\ schränken wir beim Aufruf des Playbooks die Ausführung mit dem Parameter **''limit=''** entsprechend ein. 
-</WRAP> 
- 
- 
-<html><pre class="code"> 
-<font style="color: rgb(43, 100, 164)">Using /etc/ansible/ansible.cfg as config file</font> 
-<font style="color: rgb(0, 0, 0)">BECOME password:  
- 
-PLAY [centos8] **************************************************************************************************************************************** 
- 
-TASK [Gathering Facts] ****************************************************************************************************************************************</font> 
-<font style="color: rgb(25, 100, 5)">ok: [www8.dmz.nausch.org]</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [Make sure we have a group 'ruben' for our new admin-user 'ruben'] ****************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">changed: [www8.dmz.nausch.org] => {"changed": true, "gid": 1010, "name": "ruben", "state": "present", "system": false}</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [Add the user 'ruben' with a specific uid and a primary group of 'ruben'] *********************************************************</font> 
-<font style="color: rgb(196, 160, 0)">changed: [www8.dmz.nausch.org] => {"changed": true, "comment": "Ruben Nausch", "create_home": true, "group": 1010, "home": "/home/ruben", "name": "ruben", "shell": "/bin/bash", "state": "present", "stderr": "Creating mailbox file: File exists\n", "stderr_lines": ["Creating mailbox file: File exists"], "system": false, "uid": 1010}</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [Initial password generation for user 'ruben'] ************************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">changed: [www8.dmz.nausch.org] => {"changed": true, "cmd": "usermod -p $(echo 'M31nP4p4157d3r4113r83573!' | openssl passwd -1 -stdin) ruben", "delta": "0:00:00.375778", "end": "2020-01-04 20:00:16.435753", "rc": 0, "start": "2020-01-04 20:00:16.059975", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}</font></br> 
-<font style="color: rgb(0, 0, 0)">PLAY RECAP ***************************************************************************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">www8.dmz.nausch.org        </font><font style="color: rgb(0, 0, 0)">: </font><font style="color: rgb(25, 100, 5)">ok=4    </font><font style="color: rgb(196, 160, 0)">changed=3    </font><font style="color: rgb(0, 0, 0)">unreachable=0    failed=0    skipped=0    rescued=0    ignored=0</font><br></pre> 
-</html> 
- 
-=== Script Ablaufbeschreibung === 
-Bei jedem Ansible-Playbook werden beim Ausführen zu aller erst die sog. Facts durch Ansible gesammelt.  
- 
-Anschließend werden die einzelnen Tasks (Aufgaben) der Reihe nach abgearbeitet. In der Zeile nach **TASK** wird dann die Beschreibung ausgegeben, die wir im YAML-Script nach dem Schlüsselwort **''name:''** angegeben hatten. 
- 
-Bei der Ausgabe werden Stati mit einer entsprechneden Farbe hinterlegt: 
-  * <html><b><font style="color: rgb(25, 100, 5)">grün</font></b></html> : Werden lediglich von Ansible Daten erhoben, oder wenn Aufgaben keine Änderungen nach sich ziehen, werden die entsprechenden Zeilen mit der Farbe <html><b><font style="color: rgb(25, 100, 5)">grün</font></b></html> dargestellt. 
-  * <html><b><font style="color: rgb(196, 160, 0)">ockergelb</font></b></html> : Werden Änderungen durch das Script verursacht erfolgt die Anzeige in der Farbe <html><b><font style="color: rgb(196, 160, 0)">ockergelb</font></b></html> angezeigt. 
-  * <html><b><font style="color: rgb(99, 0, 0)">rot</font></b></html> : Fehler werden in der Farbe <html><b><font style="color: rgb(99, 0, 0)">rot</font></b></html> dargestellt. 
- 
-Eine Zusammenfasssung für jeden Host wir am ende unter dem Kennzeichen **PLAY RECAP** nochmals zusammengefasst. 
- 
-=== Protokollierung === 
-Auf dem Zielhost werden die Aktivitäten des Ansible-Playbooks entsprechend protokolliert. 
-   # less /var/log/secure 
- 
-<code>Jan  4 19:59:51 vml000090 sshd[11916]: Postponed publickey for ansible from 10.0.0.27 port 50940 ssh2 [preauth] 
-Jan  4 19:59:51 vml000090 sshd[11916]: Accepted publickey for ansible from 10.0.0.27 port 50940 ssh2: ED25519 SHA256:jTZQUDbCqZaV648fKVBfx3L4+tBMWL+z+iUCBY3kKMQ 
-Jan  4 19:59:51 vml000090 systemd[11920]: pam_unix(systemd-user:session): session opened for user ansible by (uid=0) 
-Jan  4 19:59:51 vml000090 sshd[11916]: pam_unix(sshd:session): session opened for user ansible by (uid=0) 
-Jan  4 19:59:58 vml000090 sudo[12053]: ansible : TTY=pts/1 ; PWD=/home/ansible ; USER=root ; COMMAND=/bin/sh -c echo BECOME-SUCCESS-lxiprplnioypvfmjjylwxvdjapibaahs ; /usr/libexec/platform-python /home/ansible/.ansible/tmp/ansible-tmp-1578164696.339052-252470145168513/AnsiballZ_setup.py 
-Jan  4 19:59:58 vml000090 sudo[12053]: pam_systemd(sudo:session): Cannot create session: Already running in a session or user slice 
-Jan  4 19:59:58 vml000090 sudo[12053]: pam_unix(sudo:session): session opened for user root by ansible(uid=0) 
-Jan  4 20:00:06 vml000090 sudo[12053]: pam_unix(sudo:session): session closed for user root 
-Jan  4 20:00:12 vml000090 sudo[12213]: ansible : TTY=pts/1 ; PWD=/home/ansible ; USER=root ; COMMAND=/bin/sh -c echo BECOME-SUCCESS-dkoativjxmvilrtomekhdjnqzyyyuqqr ; /usr/libexec/platform-python /home/ansible/.ansible/tmp/ansible-tmp-1578164713.323935-211226042197181/AnsiballZ_group.py 
-Jan  4 20:00:12 vml000090 sudo[12213]: pam_systemd(sudo:session): Cannot create session: Already running in a session or user slice 
-Jan  4 20:00:12 vml000090 sudo[12213]: pam_unix(sudo:session): session opened for user root by ansible(uid=0) 
-Jan  4 20:00:12 vml000090 groupadd[12222]: group added to /etc/group: name=ruben, GID=1010 
-Jan  4 20:00:12 vml000090 groupadd[12222]: group added to /etc/gshadow: name=ruben 
-Jan  4 20:00:12 vml000090 groupadd[12222]: new group: name=ruben, GID=1010 
-Jan  4 20:00:12 vml000090 sudo[12213]: pam_unix(sudo:session): session closed for user root 
-Jan  4 20:00:14 vml000090 sudo[12330]: ansible : TTY=pts/1 ; PWD=/home/ansible ; USER=root ; COMMAND=/bin/sh -c echo BECOME-SUCCESS-qrempbbpxxpgsigefdvnuctemlnerdpu ; /usr/libexec/platform-python /home/ansible/.ansible/tmp/ansible-tmp-1578164719.7395723-99484507541654/AnsiballZ_user.py 
-Jan  4 20:00:14 vml000090 sudo[12330]: pam_systemd(sudo:session): Cannot create session: Already running in a session or user slice 
-Jan  4 20:00:14 vml000090 sudo[12330]: pam_unix(sudo:session): session opened for user root by ansible(uid=0) 
-Jan  4 20:00:14 vml000090 useradd[12339]: new user: name=ruben, UID=1010, GID=1010, home=/home/ruben, shell=/bin/bash 
-Jan  4 20:00:14 vml000090 sudo[12330]: pam_unix(sudo:session): session closed for user root 
-Jan  4 20:00:15 vml000090 sudo[12448]: ansible : TTY=pts/1 ; PWD=/home/ansible ; USER=root ; COMMAND=/bin/sh -c echo BECOME-SUCCESS-guzlsexqnsjzxvmqkxlzyfmeywwkmtxf ; /usr/libexec/platform-python /home/ansible/.ansible/tmp/ansible-tmp-1578164721.6724513-118758141371611/AnsiballZ_command.py 
-Jan  4 20:00:15 vml000090 sudo[12448]: pam_systemd(sudo:session): Cannot create session: Already running in a session or user slice 
-Jan  4 20:00:15 vml000090 sudo[12448]: pam_unix(sudo:session): session opened for user root by ansible(uid=0) 
-Jan  4 20:00:16 vml000090 usermod[12455]: change user 'ruben' password 
-Jan  4 20:00:16 vml000090 sudo[12448]: pam_unix(sudo:session): session closed for user root</code> 
- 
-==== 02: sudoers anpassen ==== 
-Bei unserem zweiten Beispiel wollen wir lediglich dafür sorgen, dass die Nutzer der Gruppe **''wheel''** beim Ausführen von Befehlen, die **root**-Berechtigungen erfordern, ihr Passwort eingeben müssen. Hierzu werden wir im Verzeichnis **''/etc/sudoers.d/''** eine Datei mit dem Namen **''10_passwd_sudo_wheel''** ablegen, die nachfolgenden Inhalt aufweist. 
-<code># Allows people in group wheel to run all command 
-%wheel ALL=(ALL) ALL</code> 
- 
-=== Script anlegen === 
-Hier legen wir nun unser erstes Script ab. 
-   $ vim 02_passwd_sudo_wheel.yml 
- 
-<file bash 02_passwd_sudo_wheel.yml>--- 
-- hosts: centos8 
-  become: true 
-  vars: 
-    sudoers: ansible 
- 
-  tasks: 
-    - name: All users from groub 'wheel' are allowed sudo users 
-      copy: 
-        content: "# Allows people in group wheel to run all command\n%wheel    ALL=(ALL)       ALL\n" 
-        dest: /etc/sudoers.d/10_passwd_sudo_wheel 
-        owner: root 
-        group: root 
-        mode: "0440" 
-        validate: visudo -cf %s 
-...</file> 
- 
-=== Script Beschreibung === 
-Die einzelnen Zeilen/Blöcke haben dabei folgende Funktionen und Aufgaben. 
-Zeile: 
-  * Zeile **1 - 5**: Der bereits bekannte Block aus dem **[[#script_beschreibung|ersten Beispiel]]**, der Aussagen trifft, wo das Script laufen soll, unter welchen User-Rechten das passiern soll etc. pp.. 
-  * https://docs.ansible.com/ansible/latest/modules/copy_module.html 
-  * Zeile **6**: 
-  * Zeile **7**: **''tasks''** Schlüsselwort mit den nachfolgenden Aufgaben, die mit dem Playbook dann abgearbeitet werden sollen. 
-  * Zeile **8**: **''name''**: Beschreibender Text (//All users from groub 'wheel' are allowed sudo users//), der später beim Aufruf von **''ansible-playbooks''** ausgegeben werden soll. 
-  * Zeile **9 - 15**: **''copy:''** Ansible Module **[[https://docs.ansible.com/ansible/latest/modules/copy_module.html|copy]]** welches zum Kopieren, verändern und auch Löschen von Dateien herangezogen werden kann.  
-  * Zeile **16**: **''%%...%%''** Endekennzeichen der YML-Datei 
-=== Script ausführen === 
-Nun wollen wir unser ersten Playbook ausführen, um auf dem Zielhost eine Datei mit dem gewünschten Inhalt ablegen; hierzu rufen wir unser Script wie folgt auf: 
-   $ ansible-playbook -v 02_passwd_sudo_wheel.yml 
- 
-<html><pre class="code"> 
-<font style="color: rgb(43, 100, 164)">Using /etc/ansible/ansible.cfg as config file</font> 
-<font style="color: rgb(0, 0, 0)">BECOME password:  
- 
-PLAY [centos8] **************************************************************************************************************************************** 
- 
-TASK [Gathering Facts] ****************************************************************************************************************************************</font> 
-<font style="color: rgb(25, 100, 5)">ok: [www8.dmz.nausch.org]</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [All users from groub 'wheel' are allowed sudo users] *****************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">changed: [www8.dmz.nausch.org] => {"changed": true, "checksum": "b51f017f799aca0d0aef9fa29b7da87006ea5c29", "dest": "/etc/sudoers.d/10_passwd_sudo_wheel", "gid": 0, "group": "root", "md5sum": "a7c4cc84eb0dbbf844d2a8d4fbe64164", "mode": "0440", "owner": "root", "secontext": "system_u:object_r:etc_t:s0", "size": 80, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1578174240.9800038-82649856412743/source", "state": "file", "uid": 0}</font><br> 
-<font style="color: rgb(0, 0, 0)">PLAY RECAP ***************************************************************************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">www8.dmz.nausch.org        </font><font style="color: rgb(0, 0, 0)">: </font><font style="color: rgb(25, 100, 5)">ok=2    </font><font style="color: rgb(196, 160, 0)">changed=1    </font><font style="color: rgb(0, 0, 0)">unreachable=0    failed=0    skipped=0    rescued=0    ignored=0</font><br></pre> 
-</html> 
- 
-=== Ergebnis === 
-Auf dem Zielhost findet sich nun unsere gewünschte Datei mit dem zugehörigen Inhalt.  
-   # cat /etc/sudoers.d/10_passwd_sudo_wheel 
- 
-<file bash /etc/sudoers.d/10_passwd_sudo_wheel># Allows people in group wheel to run all command 
-%wheel    ALL=(ALL)       ALL</file> 
- 
- 
-==== 03: mehrere Benutzer anlegen und SSH-Schlüssel kopieren ==== 
-Beim drittem Playbook-Beispiel wollen wir mit Hilfe von Ansible nicht nur ein Admin-Konto sondern gleich mehrere anlegen. Dabei kopieren wir dann auch noch gleich die zugehörigen öffentlichen SSH-Schlüssel an Ort und Stelle. Zu guter Letzt stellen wir noch sicher dass der Eintrag **''%wheel    ALL=(ALL)       ALL''** gesetzt ist, hierzu binden wird das YAML-Playbook von [[#sudoers_anpassen|Beispiel 02]] ein. 
- 
-Bevor wir unser erstes Script schreiben, wechseln wir in unser zuvor angelegtes Zielverzeichnis: 
-   $ cd ~/ansible 
- 
-=== Script anlegen === 
-Nun legen wir nun unser erstes Script ab. 
-   $ vim 03_create-admins.yml 
- 
-<file bash 03_create-admins.yml>--- 
-- hosts: centos8 
-  become: true 
-  vars: 
-    sudoers: ansible 
- 
-  tasks: 
-    - name: add several users to the system 
-      user: 
-        name: "{{ item.name }}" 
-        comment: "{{ item.fullname }}" 
-        uid: "{{ item.uid }}" 
-        groups: "{{ item.groups }}" 
-        state: present 
-      with_items: 
-         - { name: bofh, fullname: "Bastard Operator from Hell", uid: 1020, groups: "wheel, users" } 
-         - { name: ruben, fullname: "Ruben Nausch", uid: 1010, groups: wheel } 
-         - { name: ansible, fullname: "Ansible Systemuser", uid: 2003, groups: wheel } 
- 
-    - name: Initial password generation for each user 
-      shell: usermod -p $(echo '{{ item.secret }}' | openssl passwd -1 -stdin) {{ item.name }} 
-      with_items: 
-         - { name: bofh, secret: "/ImTAxBwi++W2Y26195+Q72GbH73i/zQyaq12wsx" } 
-         - { name: ruben, secret: "lop5YtypT+E6qhOjpZEoAlnyiLH7HlIF1k212qyo" } 
-         - { name: ansible, secret: "X4z3AEx6WZ2+DDzvuzjx0mBERQ-o03f12qwPOSyx" } 
- 
-    - name: Set authorized keys for each user 
-      authorized_key: 
-        user: "{{ item.name }}" 
-        state: present 
-        key: "{{ lookup('file', '/home/django/ansible/authkeys/{{ item.name }}.pub') }}" 
-      with_items: 
-         - {name: bofh } 
-         - {name: ruben } 
-         - {name: ansible } 
- 
-    - include_tasks: 02_passwd_sudo_wheel.yml 
-... 
-</file> 
- 
-=== Script Beschreibung === 
-Das Script ist soweit selbsterklärend, werden doch der Reihe nach vier Tasks abgearbeitet: 
-  * **Task 1** : Drei Userkonten anlegen - die betreffenden Daten für unsere User holen wir uns dabei aus einer Liste (array) 
-  * **Task 2** : Setzen der initialen Passwörter je Userkonto 
-  * **Task 3** : Kopieren der jeweiligen öffentlichen SSH-Schlüssel der User. In diesem Konfigurationsbeispiel liegen diese im Verzeichnis **''/home/django/ansible/authkeys/''**. <code> $ ~/ansible/authkeys/ </code><code>insgesamt 12 
--rw-r--r--. 1 django django 100  4. Jan 22:12 ansible.pub 
--rw-r--r--. 1 django django 108  4. Jan 22:13 bofh.pub 
--rw-r--r--. 1 django django  98  4. Jan 22:16 ruben.pub</code> 
-  * **Task 4** : Das Anpassen der **sudoers**-Eigenschaften haben wir in diesem Konfigurationsbeispiel in eine separate YAML-Datei ausgelagert. Hierzu nutzen wir das YAML-Modul **[[https://docs.ansible.com/ansible/latest/modules/include_module.html|include]]**. Das entsprechende Include-Verzeichnis legen wir gleich mal an. <code> $ mkdir ~/ansible/includes</code> Hier legen wir uns eine YAML-Datei an, die **__nur__** den entsprechenden **''task''** beinhaltet. <code> $ vim  includes/sudoers.yml</code> <file bash includes/sudoers.yml>--- 
-    - name: All users from groub 'wheel' are allowed sudo users 
-      copy: 
-        content: "# Allows people in group wheel to run all command\n%wheel    ALL=(ALL)       ALL\n" 
-        dest: /etc/sudoers.d/10_passwd_sudo_wheel 
-        owner: root 
-        group: root 
-        mode: "0440" 
-        validate: visudo -cf %s 
-</file> 
- 
- 
-=== Script ausführen === 
-Nun wollen wir unser Playbook ausführen, um auf dem Zielhost den gewünschten Benutzer anzulegen; hierzu rufen wir unser Script wie folgt auf: 
-   $ ansible-playbook -v 03_create-admins.yml03_create-admins.yml 
- 
-<html><pre class="code"> 
-<font style="color: rgb(43, 100, 164)">Using /etc/ansible/ansible.cfg as config file</font> 
-<font style="color: rgb(0, 0, 0)">BECOME password:  
- 
-PLAY [centos8] **************************************************************************************************************************************** 
- 
-TASK [Gathering Facts] ****************************************************************************************************************************************</font> 
-<font style="color: rgb(25, 100, 5)">ok: [www8.dmz.nausch.org]</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [add several users to the system] *************************************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">changed: [www8.dmz.nausch.org] => (item={'name': 'bofh', 'fullname': 'Bastard Operator from Hell', 'uid': 1020, 'groups': 'wheel, users'}) => {"ansible_loop_var": "item", "changed": true, "comment": "Bastard Operator from Hell", "create_home": true, "group": 1020, "groups": "wheel, users", "home": "/home/bofh", "item": {"fullname": "Bastard Operator from Hell", "groups": "wheel, users", "name": "bofh", "uid": 1020}, "name": "bofh", "shell": "/bin/bash", "state": "present", "system": false, "uid": 1020} 
-changed: [www8.dmz.nausch.org] => (item={'name': 'ruben', 'fullname': 'Ruben Nausch', 'uid': 1010, 'groups': 'wheel'}) => {"ansible_loop_var": "item", "changed": true, "comment": "Ruben Nausch", "create_home": true, "group": 1010, "groups": "wheel", "home": "/home/ruben", "item": {"fullname": "Ruben Nausch", "groups": "wheel", "name": "ruben", "uid": 1010}, "name": "ruben", "shell": "/bin/bash", "state": "present", "system": false, "uid": 1010}</font> 
-<font style="color: rgb(25, 100, 5)">ok: [www8.dmz.nausch.org] => (item={'name': 'ansible', 'fullname': 'Ansible Systemuser', 'uid': 500, 'groups': 'wheel'}) => {"ansible_loop_var": "item", "append": false, "changed": false, "comment": "Ansible Systemuser", "group": 500, "groups": "wheel", "home": "/home/ansible", "item": {"fullname": "Ansible Systemuser", "groups": "wheel", "name": "ansible", "uid": 500}, "move_home": false, "name": "ansible", "shell": "/bin/bash", "state": "present", "uid": 500}</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [Initial password generation for each user] ***************************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">changed: [www8.dmz.nausch.org] => (item={'name': 'bofh', 'secret': '/ImTAxBwi++W2Y26195+Q72GbH73i/zQyaq12wsx'}) => {"ansible_loop_var": "item", "changed": true, "cmd": "usermod -p $(echo '/ImTAxBwi++W2Y26195+Q72GbH73i/zQyaq12wsx' | openssl passwd -1 -stdin) bofh", "delta": "0:00:00.389066", "end": "2020-01-05 17:04:51.991293", "item": {"name": "bofh", "secret": "/ImTAxBwi++W2Y26195+Q72GbH73i/zQyaq12wsx"}, "rc": 0, "start": "2020-01-05 17:04:51.602227", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []} 
-changed: [www8.dmz.nausch.org] => (item={'name': 'ruben', 'secret': 'lop5YtypT+E6qhOjpZEoAlnyiLH7HlIF1k212qyo'}) => {"ansible_loop_var": "item", "changed": true, "cmd": "usermod -p $(echo 'lop5YtypT+E6qhOjpZEoAlnyiLH7HlIF1k212qyo' | openssl passwd -1 -stdin) ruben", "delta": "0:00:00.382204", "end": "2020-01-05 17:04:53.167841", "item": {"name": "ruben", "secret": "lop5YtypT+E6qhOjpZEoAlnyiLH7HlIF1k212qyo"}, "rc": 0, "start": "2020-01-05 17:04:52.785637", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []} 
-changed: [www8.dmz.nausch.org] => (item={'name': 'ansible', 'secret': 'X4z3AEx6WZ2+DDzvuzjx0mBERQ-o03f12qwPOSyx'}) => {"ansible_loop_var": "item", "changed": true, "cmd": "usermod -p $(echo 'P1r473np4r731' | openssl passwd -1 -stdin) ansible", "delta": "0:00:00.386751", "end": "2020-01-05 17:04:54.313829", "item": {"name": "ansible", "secret": "X4z3AEx6WZ2+DDzvuzjx0mBERQ-o03f12qwPOSyx"}, "rc": 0, "start": "2020-01-05 17:04:53.927078", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [Set authorized keys for each user] ***********************************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">hanged: [www8.dmz.nausch.org] => (item={'name': 'bofh'}) => {"ansible_loop_var": "item", "changed": true, "comment": null, "exclusive": false, "follow": false, "item": {"name": "bofh"}, "key": "ssh-ed25519 AAAAC3NzaC2lZDI1NTE5AAAAILxi47aZOS3tfvNFxVVqkJAfSKXjpvemB3kRZEQ5q/kf Bastard Operator from Hell", "key_options": null, "keyfile": "/home/bofh/.ssh/authorized_keys", "manage_dir": true, "path": null, "state": "present", "user": "bofh", "validate_certs": true} 
-changed: [www8.dmz.nausch.org] => (item={'name': 'ruben'}) => {"ansible_loop_var": "item", "changed": true, "comment": null, "exclusive": false, "follow": false, "item": {"name": "ruben"}, "key": "ssh-ed25519 AAAAC3TzaC2lZ60DI1NTE5AAILxi47aZOS3tfvNFxq16293SKXjp4tsB3kRZffQ5q/kf ruben@nausch.org", "key_options": null, "keyfile": "/home/ruben/.ssh/authorized_keys", "manage_dir": true, "path": null, "state": "present", "user": "ruben", "validate_certs": true}</font> 
-<font style="color: rgb(25, 100, 5)">ok: [www8.dmz.nausch.org] => (item={'name': 'ansible'}) => {"ansible_loop_var": "item", "changed": false, "comment": null, "exclusive": false, "follow": false, "item": {"name": "ansible"}, "key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILti47aZOSetfvNFxVVqkJAfSKXjyvemB3kRZEQ5q/kf Ansible Systemuser", "key_options": null, "keyfile": "/home/ansible/.ssh/authorized_keys", "manage_dir": true, "path": null, "state": "present", "user": "ansible", "validate_certs": true}</font></br> 
-<font style="color: rgb(0, 0, 0)">TASK [All users from groub 'wheel' are allowed sudo users] *****************************************************************************</font> 
-<font style="color: rgb(4, 138, 145)">included: /home/django/ansible/includes/sudoers.yml for www8.dmz.nausch.org</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [All users from groub 'wheel' are allowed sudo users] *****************************************************************************</font> 
-<font style="color: rgb(25, 100, 5)">ok: [www8.dmz.nausch.org] => {"changed": false, "checksum": "b51f017f799aca0d0aef9fa29b7da87006ea5c29", "dest": "/etc/sudoers.d/10_passwd_sudo_wheel", "gid": 0, "group": "root", "mode": "0440", "owner": "root", "path": "/etc/sudoers.d/10_passwd_sudo_wheel", "secontext": "system_u:object_r:etc_t:s0", "size": 80, "state": "file", "uid": 0}</font></br> 
-<font style="color: rgb(0, 0, 0)">PLAY RECAP ***************************************************************************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">www8.dmz.nausch.org        </font><font style="color: rgb(0, 0, 0)">: </font><font style="color: rgb(25, 100, 5)">ok=6    </font><font style="color: rgb(196, 160, 0)">changed=3    </font><font style="color: rgb(0, 0, 0)">unreachable=0    failed=0    skipped=0    rescued=0    ignored=0</font><br></pre> 
-</html> 
- 
-=== Ergebnis === 
-Auf dem Zielhost findet sich nun unsere gewünschte Datei mit dem zugehörigen Inhalt.  
-   # cat /etc/sudoers.d/10_passwd_sudo_wheel 
- 
-<file bash /etc/sudoers.d/10_passwd_sudo_wheel># Allows people in group wheel to run all command 
-%wheel    ALL=(ALL)       ALL</file> 
- 
-Auch unsere drei Nutzer-/Admin-Konten sind angelet und deren öffentlicher SSH-Schlüssel in diue Datei **''.ssh/authorized_keys''** im jeweiligen Homeverzeichnis der User kopiert. 
-<code>/home/ 
-├── ansible 
-│   ├── .bash_logout 
-│   ├── .bash_profile 
-│   ├── .bashrc 
-│   ├── .ssh 
-│   │   └── authorized_keys 
-├── bofh 
-│   ├── .bash_logout 
-│   ├── .bash_profile 
-│   ├── .bashrc 
-│   └── .ssh 
-│       └── authorized_keys 
-└── ruben 
-    ├── .bash_logout 
-    ├── .bash_profile 
-    ├── .bashrc 
-    └── .ssh 
-        └── authorized_keys</code> 
- 
-==== 04: Bedingtes Kopieren ==== 
-Im vierten Beispiel wollen wir die Konfigurationsdatei **''mailserver.guru.repo''** für das Repository mailserver.guru auf alle unsere definierten CentOS-Hosts kopieren. Dabei müssen wir natürlich beachten, dass sich die Datei zwischen den Versionen **CentOS 7** und **CentOS 8** unterscheiden, wenn auch nur geringfügig! 
- 
-=== Script anlegen === 
-Das Script legen wir wie auch schon bei den anderen Beispielen zuvor im Verzeichnis **''~/ansible''** an 
-   $ vim 04_repro.yml 
- 
-<file bash 04_repro.yml>--- 
-- hosts: all 
-  become: true 
-  vars: 
-    sudoers: ansible 
- 
-  tasks: 
-    - name: Place repo-file mailserver.guru for CentOS 8 right in place 
-      copy: 
-        src: /home/django/ansible/files/CentOS8/mailserver.guru.repo  
-        dest: /etc/yum.repos.d/ 
-      when: 
-        - ansible_facts['distribution'] == "CentOS" 
-        - ansible_facts['distribution_major_version'] == "8" 
- 
-    - name: Place repo-file mailserver.guru for CentOS 7 right in place  
-      copy: 
-        src: files/CentOS7/mailserver.guru.repo  
-        dest: /etc/yum.repos.d/ 
-      when: 
-        - ansible_facts['distribution'] == "CentOS" 
-        - ansible_facts['distribution_major_version'] == "7" 
-... 
-</file> 
- 
-Im Arbeitsverzeichnis für unsere Ansible hatten wir **[[#verzeichnis-struktur|zu Beginn]]** bereits ein Verzeichnis für lokale (Konfigurationsdateien) angelegt. Zur besseren Unterscheidung legen wir uns dort noch zwei Verzeichnisse an, in denen wir die Releaseversionsabhängigen Dateien vorhalten werden. 
-   $ mkdir ~/ansible/files/CentOS7 
-   $ mkdir ~/ansible/files/CentOS8 
- 
-\\ 
-Die **CentOS 7** spezifische Repo-Datei **''mailserver.guru.repo''** speichern wir nun im Verzeichnis **''~/ansible/files/CentOS7''**. 
-   $ vim ~/ansible/files/CentOS7/mailserver.guru.repo 
- 
-<file bash ~/ansible/files/CentOS7/mailserver.guru.repo># Repository mailserver.guru 
-[mailserver.guru-os] 
-name=Extra (Mailserver-)Packages for Enterprise Linux 7 - $basearch 
-baseurl=http://repo.mailserver.guru/7/os/$basearch 
-priority=5 
-enabled=1 
-gpgcheck=1 
-gpgkey=file:///etc/pki/rpm-gpg/MAILSERVER.GURU-RPM-GPG-KEY-CentOS-7 
- 
- 
-[mailserver.guru-testing] 
-name=Testing (Mailserver-)Packages for Enterprise Linux 7 - $basearch 
-baseurl=http://repo.mailserver.guru/7/testing/$basearch/ 
-#priority=5 
-enabled=0 
-gpgcheck=1 
-gpgkey=file:///etc/pki/rpm-gpg/MAILSERVER.GURU-RPM-GPG-KEY-CentOS-7</file> 
- 
-Die **CentOS 8** spezifische Repo-Datei **''mailserver.guru.repo''** speichern wir entsprechend im Verzeichnis **''~/ansible/files/CentOS8''** ab. 
-   $ vim ~/ansible/files/CentOS8/mailserver.guru.repo 
- 
-<file bash ~/ansible/files/CentOS8/mailserver.guru.repo># Repository mailserver.guru 
-[mailserver.guru-os] 
-name=Extra (Mailserver-)Packages for Enterprise Linux 8 - $basearch 
-baseurl=http://repo.mailserver.guru/8/os/$basearch 
-priority=5 
-enabled=1 
-gpgcheck=1 
-gpgkey=file:///etc/pki/rpm-gpg/MAILSERVER.GURU-RPM-GPG-KEY-CentOS-8 
- 
- 
-[mailserver.guru-testing] 
-name=Testing (Mailserver-)Packages for Enterprise Linux 8 - $basearch 
-baseurl=http://repo.mailserver.guru/8/testing/$basearch/ 
-#priority=5 
-enabled=0 
-gpgcheck=1 
-gpgkey=file:///etc/pki/rpm-gpg/MAILSERVER.GURU-RPM-GPG-KEY-CentOS-8</file> 
- 
-=== Script Beschreibung === 
-Unser Playbook, welches alle Hosts anspricht besteht im Wesentlichen aus zwei Tasks/Aufgaben. Abhängig von den beiden Ansible Facts **''distribution''** und **''distribution_major_version''** wird die Repository-Konfigurations-Datei **''mailserver.guru.repo''** auf den entsprechenden Zielhost kopiert.   
- 
-Zum Kopieren wird dann das Ansible Modul **[[https://docs.ansible.com/ansible/latest/modules/copy_module.html|copy]]** verwendet. Da wir das RPM-Paket **[[centos:ansible:start#dokumentation_rpm|ansible-doc]]** installiert hatten, könne wir auch auf der Konsole direkt Informationen zu dem Modul beziehen. Allgemeine Infos zu dem Modul erhalten wir mit folgendem Befehl: 
-   $ ansible-doc copy 
- 
-<code>> COPY    (/usr/lib/python2.7/site-packages/ansible/modules/files/copy.py) 
- 
-        The `copy' module copies a file from the local or remote machine to a location on the remote 
-        machine. Use the [fetch] module to copy files from remote locations to the local box. If you need 
-        variable interpolation in copied files, use the [template] module. For Windows targets, use the 
-        [win_copy] module instead. 
- 
-  * note: This module has a corresponding action plugin. 
- 
-OPTIONS (= is mandatory): 
- 
-- attributes 
-        Attributes the file or directory should have. To get supported flags look at the man page for 
-        `chattr' on the target system. This string should contain the attributes in the same order as the 
-        one displayed by `lsattr'. 
-        (Aliases: attr)[Default: None] 
-        version_added: 2.3 
- 
-- backup 
-        Create a backup file including the timestamp information so you can get the original file back if 
-        you somehow clobbered it incorrectly. 
-        [Default: no] 
-        type: bool 
-        version_added: 0.7 
- 
-- content 
-        When used instead of `src', sets the contents of a file directly to the specified value. For 
-        anything advanced or with formatting also look at the template module. 
-        [Default: (null)] 
-        version_added: 1.1 
- 
-- decrypt 
-        This option controls the autodecryption of source files using vault. 
-        [Default: Yes] 
-        type: bool 
-        version_added: 2.4 
- 
-= dest 
-        Remote absolute path where the file should be copied to. If `src' is a directory, this must be a 
-        directory too. If `dest' is a nonexistent path and if either `dest' ends with "/" or `src' is a 
-        directory, `dest' is created. If `src' and `dest' are files, the parent directory of `dest' isn't 
-        created: the task fails if it doesn't already exist. 
- 
- 
-- directory_mode 
-        When doing a recursive copy set the mode for the directories. If this is not set we will use the 
-        system defaults. The mode is only set on directories which are newly created, and will not affect 
-        those that already existed. 
-        [Default: (null)] 
-        version_added: 1.5 
- 
-- follow 
-        This flag indicates that filesystem links in the destination, if they exist, should be followed. 
-        [Default: no] 
-        type: bool 
-        version_added: 1.8 
- 
-- force 
-        the default is `yes', which will replace the remote file when contents are different than the 
-        source. If `no', the file will only be transferred if the destination does not exist. 
-        (Aliases: thirsty)[Default: yes] 
-        type: bool 
-        version_added: 1.1 
- 
-- group 
-        Name of the group that should own the file/directory, as would be fed to `chown'. 
-        [Default: None] 
- 
-- local_follow 
-        This flag indicates that filesystem links in the source tree, if they exist, should be followed. 
-        [Default: yes] 
-        type: bool 
-        version_added: 2.4 
- 
-- mode 
-        Mode the file or directory should be. For those used to `/usr/bin/chmod' remember that modes are 
-        actually octal numbers (like 0644). Leaving off the leading zero will likely have unexpected 
-        results. As of version 1.8, the mode may be specified as a symbolic mode (for example, `u+rwx' or 
-        `u=rw,g=r,o=r'). 
-        [Default: None] 
- 
-- owner 
-        Name of the user that should own the file/directory, as would be fed to `chown'. 
-        [Default: None] 
- 
-- remote_src 
-        If `no', it will search for `src' at originating/master machine. 
-        If `yes' it will go to the remote/target machine for the `src'. Default is `no'. 
-        Currently `remote_src' does not support recursive copying. 
-        [Default: no] 
-        type: bool 
-        version_added: 2.0 
- 
-- selevel 
-        Level part of the SELinux file context. This is the MLS/MCS attribute, sometimes known as the 
-        `range'. `_default' feature works as for `seuser'. 
-        [Default: s0] 
- 
-- serole 
-        Role part of SELinux file context, `_default' feature works as for `seuser'. 
-        [Default: None] 
- 
-- setype 
-        Type part of SELinux file context, `_default' feature works as for `seuser'. 
-        [Default: None] 
- 
-- seuser 
-        User part of SELinux file context. Will default to system policy, if applicable. If set to 
-        `_default', it will use the `user' portion of the policy if available. 
-        [Default: None] 
- 
-- src 
-        Local path to a file to copy to the remote server; can be absolute or relative. If path is a 
-        directory, it is copied recursively. In this case, if path ends with "/", only inside contents of 
-        that directory are copied to destination. Otherwise, if it does not end with "/", the directory 
-        itself with all contents is copied. This behavior is similar to Rsync. 
-        [Default: (null)] 
- 
-- unsafe_writes 
-        Normally this module uses atomic operations to prevent data corruption or inconsistent reads from 
-        the target files, sometimes systems are configured or just broken in ways that prevent this. One 
-        example are docker mounted files, they cannot be updated atomically and can only be done in an 
-        unsafe manner. 
-        This boolean option allows ansible to fall back to unsafe methods of updating files for those 
-        cases in which you do not have any other choice. Be aware that this is subject to race conditions 
-        and can lead to data corruption. 
-        [Default: False] 
-        type: bool 
-        version_added: 2.2 
- 
-- validate 
-        The validation command to run before copying into place. The path to the file to validate is 
-        passed in via '%s' which must be present as in the example below. The command is passed securely 
-        so shell features like expansion and pipes won't work. 
-        [Default: None] 
- 
- 
-NOTES: 
-      * The [copy] module recursively copy facility does not scale to lots (>hundreds) of files. 
-        For alternative, see [synchronize] module, which is a wrapper around `rsync'. 
-      * For Windows targets, use the [win_copy] module instead. 
- 
-AUTHOR: Ansible Core Team, Michael DeHaan 
-EXTENDS_DOCUMENTATION_FRAGMENT: files, validate, decrypt 
-        METADATA: 
-          status: 
-          - stableinterface 
-          supported_by: core 
-         
- 
-EXAMPLES: 
-# Example from Ansible Playbooks 
-- copy: 
-    src: /srv/myfiles/foo.conf 
-    dest: /etc/foo.conf 
-    owner: foo 
-    group: foo 
-    mode: 0644 
- 
-# The same example as above, but using a symbolic mode equivalent to 0644 
-- copy: 
-    src: /srv/myfiles/foo.conf 
-    dest: /etc/foo.conf 
-    owner: foo 
-    group: foo 
-    mode: u=rw,g=r,o=r 
- 
-# Another symbolic mode example, adding some permissions and removing others 
-- copy: 
-    src: /srv/myfiles/foo.conf 
-    dest: /etc/foo.conf 
-    owner: foo 
-    group: foo 
-    mode: u+rw,g-wx,o-rwx 
- 
-# Copy a new "ntp.conf file into place, backing up the original if it differs from the copied version 
-- copy: 
-    src: /mine/ntp.conf 
-    dest: /etc/ntp.conf 
-    owner: root 
-    group: root 
-    mode: 0644 
-    backup: yes 
- 
-# Copy a new "sudoers" file into place, after passing validation with visudo 
-- copy: 
-    src: /mine/sudoers 
-    dest: /etc/sudoers 
-    validate: /usr/sbin/visudo -cf %s 
- 
-# Copy a "sudoers" file on the remote machine for editing 
-- copy: 
-    src: /etc/sudoers 
-    dest: /etc/sudoers.edit 
-    remote_src: yes 
-    validate: /usr/sbin/visudo -cf %s 
- 
-# Create a CSV file from your complete inventory using an inline template 
-- hosts: all 
-  tasks: 
-  - copy: 
-      content: | 
-        HOSTNAME;IPADDRESS;FQDN;OSNAME;OSVERSION;PROCESSOR;ARCHITECTURE;MEMORY; 
-        {% for host in hostvars %} 
-        {%   set vars = hostvars[host|string] %} 
-        {{ vars.ansible_hostname }};{{ vars.remote_host }};{{ vars.ansible_fqdn }};{{ vars.ansible_distribution }};{{ vars.ansible_d 
-        {% endfor %} 
-      dest: /some/path/systems.csv 
-      backup: yes 
-    run_once: yes 
-    delegate_to: localhost 
- 
-RETURN VALUES: 
- 
- 
-dest: 
-    description: destination file/path 
-    returned: success 
-    type: string 
-    sample: /path/to/file.txt 
-src: 
-    description: source file used for the copy on the target machine 
-    returned: changed 
-    type: string 
-    sample: /home/httpd/.ansible/tmp/ansible-tmp-1423796390.97-147729857856000/source 
-md5sum: 
-    description: md5 checksum of the file after running copy 
-    returned: when supported 
-    type: string 
-    sample: 2a5aeecc61dc98c4d780b14b330e3282 
-checksum: 
-    description: sha1 checksum of the file after running copy 
-    returned: success 
-    type: string 
-    sample: 6e642bb8dd5c2e027bf21dd923337cbb4214f827 
-backup_file: 
-    description: name of backup file created 
-    returned: changed and if backup=yes 
-    type: string 
-    sample: /path/to/file.txt.2015-02-12@22:09~ 
-gid: 
-    description: group id of the file, after execution 
-    returned: success 
-    type: int 
-    sample: 100 
-group: 
-    description: group of the file, after execution 
-    returned: success 
-    type: string 
-    sample: httpd 
-owner: 
-    description: owner of the file, after execution 
-    returned: success 
-    type: string 
-    sample: httpd 
-uid: 
-    description: owner id of the file, after execution 
-    returned: success 
-    type: int 
-    sample: 100 
-mode: 
-    description: permissions of the target, after execution 
-    returned: success 
-    type: string 
-    sample: 0644 
-size: 
-    description: size of the target, after execution 
-    returned: success 
-    type: int 
-    sample: 1220 
-state: 
-    description: state of the target, after execution 
-    returned: success 
-    type: string 
-    sample: file 
- 
-</code> 
-Wollen wir direkt ein **snippet** für unser Playbook zum Kopieren haben, geben wir bei dem Befehl **''ansible-doc copy''** noch die Option **''-s''** an. 
-   $ ansible-doc copy -s 
-<code>- name: Copies files to remote locations 
-  copy: 
-      attributes:            # Attributes the file or directory should have. To get supported flags look at the man page for 
-                               `chattr' on the target system. This string should contain the 
-                               attributes in the same order as the one displayed by `lsattr'. 
-      backup:                # Create a backup file including the timestamp information so you can get the original file back if 
-                               you somehow clobbered it incorrectly. 
-      content:               # When used instead of `src', sets the contents of a file directly to the specified value. For 
-                               anything advanced or with formatting also look at the template 
-                               module. 
-      decrypt:               # This option controls the autodecryption of source files using vault. 
-      dest:                  # (required) Remote absolute path where the file should be copied to. If `src' is a directory, this 
-                               must be a directory too. If `dest' is a nonexistent path and if 
-                               either `dest' ends with "/" or `src' is a directory, `dest' is 
-                               created. If `src' and `dest' are files, the parent directory of 
-                               `dest' isn't created: the task fails if it doesn't already exist. 
-      directory_mode:        # When doing a recursive copy set the mode for the directories. If this is not set we will use the 
-                               system defaults. The mode is only set on directories which are newly 
-                               created, and will not affect those that already existed. 
-      follow:                # This flag indicates that filesystem links in the destination, if they exist, should be followed. 
-      force:                 # the default is `yes', which will replace the remote file when contents are different than the 
-                               source. If `no', the file will only be transferred if the destination 
-                               does not exist. 
-      group:                 # Name of the group that should own the file/directory, as would be fed to `chown'. 
-      local_follow:          # This flag indicates that filesystem links in the source tree, if they exist, should be followed. 
-      mode:                  # Mode the file or directory should be. For those used to `/usr/bin/chmod' remember that modes are 
-                               actually octal numbers (like 0644). Leaving off the leading zero will 
-                               likely have unexpected results. As of version 1.8, the mode may be 
-                               specified as a symbolic mode (for example, `u+rwx' or 
-                               `u=rw,g=r,o=r'). 
-      owner:                 # Name of the user that should own the file/directory, as would be fed to `chown'. 
-      remote_src:            # If `no', it will search for `src' at originating/master machine. If `yes' it will go to the 
-                               remote/target machine for the `src'. Default is `no'. Currently 
-                               `remote_src' does not support recursive copying. 
-      selevel:               # Level part of the SELinux file context. This is the MLS/MCS attribute, sometimes known as the 
-                               `range'. `_default' feature works as for `seuser'. 
-      serole:                # Role part of SELinux file context, `_default' feature works as for `seuser'. 
-      setype:                # Type part of SELinux file context, `_default' feature works as for `seuser'. 
-      seuser:                # User part of SELinux file context. Will default to system policy, if applicable. If set to 
-                               `_default', it will use the `user' portion of the policy if 
-                               available. 
-      src:                   # Local path to a file to copy to the remote server; can be absolute or relative. If path is a 
-                               directory, it is copied recursively. In this case, if path ends with 
-                               "/", only inside contents of that directory are copied to 
-                               destination. Otherwise, if it does not end with "/", the directory 
-                               itself with all contents is copied. This behavior is similar to 
-                               Rsync. 
-      unsafe_writes:         # Normally this module uses atomic operations to prevent data corruption or inconsistent reads from 
-                               the target files, sometimes systems are configured or just broken in 
-                               ways that prevent this. One example are docker mounted files, they 
-                               cannot be updated atomically and can only be done in an unsafe 
-                               manner. This boolean option allows ansible to fall back to unsafe 
-                               methods of updating files for those cases in which you do not have 
-                               any other choice. Be aware that this is subject to race conditions 
-                               and can lead to data corruption. 
-      validate:              # The validation command to run before copying into place. The path to the file to validate is passed 
-                               in via '%s' which must be present as in the example below. The 
-                               command is passed securely so shell features like expansion and pipes 
-                               won't work. 
-</code> 
- 
-=== Script ausführen === 
-Zum Kopieren der unterschiedlichen Dateien rufen wir nun unser Playbook wie folgt auf: 
-   $ ansible-playbook -v 04_repro.yml  
- 
-<html><pre class="code"> 
-<font style="color: rgb(43, 100, 164)">Using /etc/ansible/ansible.cfg as config file</font> 
-<font style="color: rgb(0, 0, 0)">BECOME password:  
- 
-PLAY [all] ***************************************************************************************************************************** 
- 
-TASK [Gathering Facts] *****************************************************************************************************************</font> 
-<font style="color: rgb(25, 100, 5)">ok: [www7.dmz.nausch.org] 
-ok: [www8.dmz.nausch.org]</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [Place repo-file mailserver.guru for CentOS 8 right in place] *********************************************************************</font> 
-<font style="color: rgb(4, 138, 145)">skipping: [www7.dmz.nausch.org] => {"changed": false, "skip_reason": "Conditional result was False"}</font> 
-<font style="color: rgb(196, 160, 0)">changed: [www8.dmz.nausch.org] => {"changed": true, "checksum": "e9ab494c29df71d4e869c5b0bf68caf865ef74c9", "dest": "/etc/yum.repos.d/mailserver.guru.repo", "gid": 0, "group": "root", "md5sum": "f21be9d7340e512c004747204b54a2b5", "mode": "0644", "owner": "root", "secontext": "system_u:object_r:system_conf_t:s0", "size": 614, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1578253275.4362092-25566445227282/source", "state": "file", "uid": 0}</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [Place repo-file mailserver.guru for CentOS 7 right in place] *********************************************************************</font> 
-<font style="color: rgb(4, 138, 145)">skipping: [www8.dmz.nausch.org] => {"changed": false, "skip_reason": "Conditional result was False"}</font> 
-<font style="color: rgb(196, 160, 0)">changed: [www7.dmz.nausch.org] => {"changed": true, "checksum": "0fac1360785f0e02e074b4cc4f785e181f6620b9", "dest": "/etc/yum.repos.d/mailserver.guru.repo", "gid": 0, "group": "root", "md5sum": "90d8ca6369ff514b3c3dc3ddfac4ebdb", "mode": "0644", "owner": "root", "secontext": "system_u:object_r:system_conf_t:s0", "size": 614, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1578253277.3541374-16074731401428/source", "state": "file", "uid": 0}</font><br> 
-<font style="color: rgb(0, 0, 0)">PLAY RECAP ***************************************************************************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">www7.dmz.nausch.org        </font><font style="color: rgb(0, 0, 0)">: </font><font style="color: rgb(25, 100, 5)">ok=2    </font><font style="color: rgb(196, 160, 0)">changed=1    </font><font style="color: rgb(0, 0, 0)">unreachable=0    failed=0    <font style="color: rgb(4, 138, 145)">skipped=1</font><font style="color: rgb(0, 0, 0)">    rescued=0    ignored=0</font> 
-<font style="color: rgb(196, 160, 0)">www8.dmz.nausch.org        </font><font style="color: rgb(0, 0, 0)">: </font><font style="color: rgb(25, 100, 5)">ok=2    </font><font style="color: rgb(196, 160, 0)">changed=1    </font><font style="color: rgb(0, 0, 0)">unreachable=0    failed=0    <font style="color: rgb(4, 138, 145)">skipped=1</font><font style="color: rgb(0, 0, 0)">    rescued=0    ignored=0</font><br></pre> 
-</html> 
- 
-\\ 
-Die <html><b><font style="color: rgb(4, 138, 145)">blau</font></b></html> markierten Zeilen bzw. in der Zusammenfassung genannten <html><b><font style="color: rgb(4, 138, 145)">skipped=1</font></b></html> brauchen uns nicht beunruhigen. \\ 
-Die Ursache hierzu ist einfach erklärt: Da wir die Prüfung auf die CentOS-Version **7** und **8** auf beiden Hosts ausführen, führt natürlich immer nur zu einem Treffer, der jeweils "falsche" wird einfach übersprungen. 
- 
-=== Ergebnis === 
-Auf dem Zielhost findet sich nun unsere gewünschte Datei mit dem zugehörigen Inhalt an Ort und Stelle.  
-   # ll /etc/yum.repos.d/mailserver.guru.repo 
- 
-<code>-rw-r--r--. 1 root root 614 Jan  5 20:41 /etc/yum.repos.d/mailserver.guru.repo</code> 
- 
-==== 05: NTP-Daemon chrony installieren und konfigurieren ==== 
-In folgendem Beispiel Nummer fünf wollen wir auf unseren **CentOS 8**-Hosts den NTP-Deamon **[[https://chrony.tuxfamily.org/|chrony]]** installieren und auch entsprechend als Client konfigurieren. 
- 
-=== Script anlegen === 
-Das Script legen wir wie auch schon bei den anderen Beispielen zuvor im Verzeichnis **''~/ansible''** an 
-   $ vim 05_chrony.yml 
- 
-<file bash 05_chrony.yml>--- 
-- hosts: centos8 
-  become: true 
-  vars: 
-    sudoers: ansible 
-    config_file: /etc/chrony.conf 
-    # chronyd client config-options 
-    chrony_pool: "server time.dmz.nausch.org iburst" 
-    chrony_stratumweight: "stratumweight 0" 
-    chrony_makestep: "makestep 10 3" 
- 
-  tasks: 
-    - name: Install chrony ntp Deamon 
-      dnf:  
-      #https://docs.ansible.com/ansible/latest/modules/dnf_module.html 
-        name: chrony 
-        state: latest 
- 
-    - name: Check if /etc/chrony.orig does exists 
-      stat: 
-      #https://docs.ansible.com/ansible/latest/modules/stat_module.html 
-        path: /etc/chrony.conf.orig 
-      register: stat_result 
- 
-    - name: Make a copy of /etc/chrony.conf as /etc/chrony.conf.orig   
-      copy: 
-      #https://docs.ansible.com/ansible/latest/modules/copy_module.html 
-        remote_src: yes 
-        src: /etc/chrony.conf 
-        dest: /etc/chrony.conf.orig 
-      when: stat_result.stat.exists == False 
- 
-    - name: Copy template config-file in place 
-      template: 
-      #https://docs.ansible.com/ansible/latest/modules/template_module.html         
-        src: templates/CentOS8/chrony-client.conf.j2  
-        dest: "{{ config_file }}" 
- 
-    - name: Make sure Chrony is started up 
-      service:  
-      #https://docs.ansible.com/ansible/latest/modules/service_module.html 
-        name: chronyd  
-        state: started  
-        enabled: yes 
-... 
-</file> 
- 
-Die Konfigurationsdatei unseres chrony-Daemon werden wir im Arbeitsbereich unserer ansible-Umgebung auf dem Admin-Rechner/-Server in einem eigenen Verzeichnis vorhalten. Diese Verzeichnis erstellen wir uns nun noch. 
-   $ mkdir -p ~/ansible/templates/CentOS8/ 
- 
-Ansible nutzt die **[[https://jinja.palletsprojects.com/en/2.10.x/templates/|Jinja2 Template Engine]]** zum abgleich der verwendeten Variablen in einem Playbook. Wir werden also unsere Konfigurationsdatei entsprechend präparieren und dort ablegen. Als Datei-Extension verwenden wir hier **''.j2''**, um dies optisch abzutrennen. Wir könnten auch andere Datei-Extension verwenden, da Ansible selbst nur den Inhalt bzw. die Formatierung der Variablen interprätiert. 
- 
- 
-   $ vim ~/ansible/templates/CentOS8/chrony-client.conf.j2 
- 
-<file bash ~/ansible/templates/CentOS8/chrony-client.conf.j2># Use public servers from the pool.ntp.org project. 
-# Please consider joining the pool (http://www.pool.ntp.org/join.html). 
-{{ chrony_pool }} 
- 
-# Ignore stratum in source selection 
-{{ chrony_stratumweight }} 
- 
-# Record the rate at which the system clock gains/losses time. 
-driftfile /var/lib/chrony/drift 
- 
-# Allow the system clock to be stepped in the first three updates 
-# if its offset is larger than 1 second. 
-makestep 1.0 3 
- 
-# Enable kernel synchronization of the real-time clock (RTC). 
-rtcsync 
- 
-# In first three updates step the system clock instead of slew 
-# if the adjustment is larger than 10 seconds. 
-{{ chrony_makestep }} 
- 
-# Enable hardware timestamping on all interfaces that support it. 
-#hwtimestamp * 
- 
-# Increase the minimum number of selectable sources required to adjust 
-# the system clock. 
-#minsources 2 
- 
-# Allow NTP client access from local network. 
-#allow 192.168.0.0/16 
- 
-# Serve time even if not synchronized to a time source. 
-#local stratum 10 
- 
-# Specify file containing keys for NTP authentication. 
-keyfile /etc/chrony.keys 
- 
-# Get TAI-UTC offset and leap seconds from the system tz database. 
-leapsectz right/UTC 
- 
-# Specify directory for log files. 
-logdir /var/log/chrony 
- 
-# Select which information is logged. 
-#log measurements statistics tracking 
- 
-</file> 
- 
-Die drei Konfigurationsoptionen, die wir für unsere chrony-client Konfiguration später setzen und ggf. verändern wollen haben wir hier mit einer Variable belegt: 
-  * **''%%{{%% chrony_pool %%}}%%''** : Server von dem bzw. denen wir später die Zeit beziehen wollen. 
-  * **''%%{{%% chrony_stratumweight %%}}%%''** : Ignorieren der **stratum** Bewertung, da wir hier nur einen Zielhost zur Zeit befragen 
-  * **''%%{{%% chrony_makestep %%}}%%''** : Definition wie bei den ersten Aktualisierungsschritten zu verfahren ist. 
- 
-=== Script Beschreibung === 
-Im Playbook greifen wir auf folgende Ansible-Module zurück: 
-  * **[[https://docs.ansible.com/ansible/latest/modules/dnf_module.html|dnf]]** zum Installieren des Paketes 
-  * **[[https://docs.ansible.com/ansible/latest/modules/stat_module.html|stat]]** und **[[https://docs.ansible.com/ansible/latest/modules/copy_module.html|copy]]** zum Sichern der originalen Konfigurationsdatei. 
-  * **[[https://docs.ansible.com/ansible/latest/modules/template_module.html|template]]** zur Konfiguration unseres Daemon 
-  * **[[https://docs.ansible.com/ansible/latest/modules/service_module.html|service]]** zum (automatischen) Starten (beim Systemstart des Hosts)). 
- 
-In unserem Playbook werden am Anfang den entsprechenden Variablen ihre werte zugewiesen. Im Anschluss daran werden fünft **''tasks''** definiert: 
-  - Aufgabe: Installation des chrony NTP-Daemon 
-  - Aufgabe: Überprüfen ob von der Konfigurationsdatei, die das RPM-Paket mitbrachte schon eine Sicherungskopie erstellt wurde. 
-  - Aufgabe: Sofern bei der Prüfung in Aufgabe **2** noch keine Sicherungskopie erstellt wurde, wird eine Sicherungsopie erstellt. 
-  - Aufgabe: Konfigurieren unseres chrony-Daemon 
-  - Aufgabe: Starten des chrony-Daemon und aktivieren des automatischen Starts beim Starten des Hosts 
- 
-=== Script ausführen === 
-Zum Kopieren der unterschiedlichen Dateien rufen wir nun unser Playbook wie folgt auf: 
-   $ ansible-playbook -v 05_chrony.yml  
- 
-<html><pre class="code"> 
-<font style="color: rgb(43, 100, 164)">Using /etc/ansible/ansible.cfg as config file</font> 
-<font style="color: rgb(0, 0, 0)">BECOME password:  
- 
-PLAY [centos8] ************************************************************************************************************************* 
- 
-TASK [Gathering Facts] *****************************************************************************************************************</font> 
-<font style="color: rgb(25, 100, 5)">ok: [www7.dmz.nausch.org] 
-ok: [www8.dmz.nausch.org]</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [Install chrony ntp Deamon] *******************************************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">changed: [www8.dmz.nausch.org] => {"changed": true, "msg": "", "rc": 0, "results": ["Installed: chrony", "Installed: chrony-3.3-3.el8.x86_64"]}</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [Check if /etc/chrony.orig does exists] *******************************************************************************************</font> 
-<font style="color: rgb(25, 100, 5)">ok: [www8.dmz.nausch.org] => {"changed": false, "stat": {"exists": false}}</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [Make a copy of /etc/chrony.conf as /etc/chrony.conf.orig] ************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">changed: [www8.dmz.nausch.org] => {"changed": true, "checksum": "89175e7c294dedf12bd473a952014e2cefd5766d", "dest": "/etc/chrony.conf.orig", "gid": 0, "group": "root", "md5sum": "97078948a9e2c1b99ab3e38d26a3311d", "mode": "0644", "owner": "root", "secontext": "system_u:object_r:etc_t:s0", "size": 1085, "src": "/etc/chrony.conf", "state": "file", "uid": 0}</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [Copy template config-file in place] **********************************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">changed: [www8.dmz.nausch.org] => {"changed": true, "checksum": "37539ecdd11393937e5596894db41a02c6121c5f", "dest": "/etc/chrony.conf", "gid": 0, "group": "root", "md5sum": "adde7eeb1766f7f83bd3fba6cc30ec23", "mode": "0644", "owner": "root", "secontext": "system_u:object_r:etc_t:s0", "size": 1265, "src": "/home/ansible/.ansible/tmp/ansible-tmp-1578323551.4891849-132640554634531/source", "state": "file", "uid": 0}</font><br> 
-<font style="color: rgb(0, 0, 0)">TASK [Make sure Chrony is started up] **************************************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">changed: [www8.dmz.nausch.org] => {"changed": true, "enabled": true, "name": "chronyd", "state": "started", "status": {"ActiveEnterTimestampMonotonic": "0", "ActiveExitTimestampMonotonic": "0", "ActiveState": "inactive", "After": "sysinit.target system.slice -.mount systemd-tmpfiles-setup.service sntp.service ntpdate.service tmp.mount systemd-journald.socket ntpd.service basic.target", "AllowIsolate": "no", "AmbientCapabilities": "", "AssertResult": "no", "AssertTimestampMonotonic": "0", "Before": "multi-user.target shutdown.target", "BlockIOAccounting": "no", "BlockIOWeight": "[not set]", "CPUAccounting": "no", "CPUQuotaPerSecUSec": "infinity", "CPUSchedulingPolicy": "0", "CPUSchedulingPriority": "0", "CPUSchedulingResetOnFork": "no", "CPUShares": "[not set]", "CPUUsageNSec": "[not set]", "CPUWeight": "[not set]", "CacheDirectoryMode": "0755", "CanIsolate": "no", "CanReload": "no", "CanStart": "yes", "CanStop": "yes", "CapabilityBoundingSet": "cap_chown cap_dac_override cap_dac_read_search cap_fowner cap_fsetid cap_kill cap_setgid cap_setuid cap_setpcap cap_linux_immutable cap_net_bind_service cap_net_broadcast cap_net_admin cap_net_raw cap_ipc_lock cap_ipc_owner cap_sys_module cap_sys_rawio cap_sys_chroot cap_sys_ptrace cap_sys_pacct cap_sys_admin cap_sys_boot cap_sys_nice cap_sys_resource cap_sys_time cap_sys_tty_config cap_mknod cap_lease cap_audit_write cap_audit_control cap_setfcap cap_mac_override cap_mac_admin cap_syslog cap_wake_alarm cap_block_suspend", "CollectMode": "inactive", "ConditionResult": "no", "ConditionTimestampMonotonic": "0", "ConfigurationDirectoryMode": "0755", "Conflicts": "systemd-timesyncd.service shutdown.target ntpd.service", "ControlPID": "0", "DefaultDependencies": "yes", "Delegate": "no", "Description": "NTP client/server", "DevicePolicy": "auto", "Documentation": "man:chronyd(8) man:chrony.conf(5)", "DynamicUser": "no", "EnvironmentFiles": "/etc/sysconfig/chronyd (ignore_errors=yes)", "ExecMainCode": "0", "ExecMainExitTimestampMonotonic": "0", "ExecMainPID": "0", "ExecMainStartTimestampMonotonic": "0", "ExecMainStatus": "0", "ExecStart": "{ path=/usr/sbin/chronyd ; argv[]=/usr/sbin/chronyd $OPTIONS ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }", "ExecStartPost": "{ path=/usr/libexec/chrony-helper ; argv[]=/usr/libexec/chrony-helper update-daemon ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }", "FailureAction": "none", "FileDescriptorStoreMax": "0", "FragmentPath": "/usr/lib/systemd/system/chronyd.service", "GID": "[not set]", "GuessMainPID": "yes", "IOAccounting": "no", "IOSchedulingClass": "0", "IOSchedulingPriority": "0", "IOWeight": "[not set]", "IPAccounting": "no", "IPEgressBytes": "18446744073709551615", "IPEgressPackets": "18446744073709551615", "IPIngressBytes": "18446744073709551615", "IPIngressPackets": "18446744073709551615", "Id": "chronyd.service", "IgnoreOnIsolate": "no", "IgnoreSIGPIPE": "yes", "InactiveEnterTimestampMonotonic": "0", "InactiveExitTimestampMonotonic": "0", "JobRunningTimeoutUSec": "infinity", "JobTimeoutAction": "none", "JobTimeoutUSec": "infinity", "KeyringMode": "private", "KillMode": "control-group", "KillSignal": "15", "LimitAS": "infinity", "LimitASSoft": "infinity", "LimitCORE": "infinity", "LimitCORESoft": "infinity", "LimitCPU": "infinity", "LimitCPUSoft": "infinity", "LimitDATA": "infinity", "LimitDATASoft": "infinity", "LimitFSIZE": "infinity", "LimitFSIZESoft": "infinity", "LimitLOCKS": "infinity", "LimitLOCKSSoft": "infinity", "LimitMEMLOCK": "16777216", "LimitMEMLOCKSoft": "16777216", "LimitMSGQUEUE": "819200", "LimitMSGQUEUESoft": "819200", "LimitNICE": "0", "LimitNICESoft": "0", "LimitNOFILE": "4096", "LimitNOFILESoft": "1024", "LimitNPROC": "31132", "LimitNPROCSoft": "31132", "LimitRSS": "infinity", "LimitRSSSoft": "infinity", "LimitRTPRIO": "0", "LimitRTPRIOSoft": "0", "LimitRTTIME": "infinity", "LimitRTTIMESoft": "infinity", "LimitSIGPENDING": "31132", "LimitSIGPENDINGSoft": "31132", "LimitSTACK": "infinity", "LimitSTACKSoft": "8388608", "LoadState": "loaded", "LockPersonality": "no", "LogLevelMax": "-1", "LogsDirectoryMode": "0755", "MainPID": "0", "MemoryAccounting": "yes", "MemoryCurrent": "[not set]", "MemoryDenyWriteExecute": "no", "MemoryHigh": "infinity", "MemoryLimit": "infinity", "MemoryLow": "0", "MemoryMax": "infinity", "MemorySwapMax": "infinity", "MountAPIVFS": "no", "MountFlags": "", "NFileDescriptorStore": "0", "NRestarts": "0", "Names": "chronyd.service", "NeedDaemonReload": "no", "Nice": "0", "NoNewPrivileges": "no", "NonBlocking": "no", "NotifyAccess": "none", "OOMScoreAdjust": "0", "OnFailureJobMode": "replace", "PIDFile": "/var/run/chrony/chronyd.pid", "PermissionsStartOnly": "no", "Perpetual": "no", "PrivateDevices": "no", "PrivateMounts": "no", "PrivateNetwork": "no", "PrivateTmp": "yes", "PrivateUsers": "no", "ProtectControlGroups": "no", "ProtectHome": "yes", "ProtectKernelModules": "no", "ProtectKernelTunables": "no", "ProtectSystem": "full", "RefuseManualStart": "no", "RefuseManualStop": "no", "RemainAfterExit": "no", "RemoveIPC": "no", "Requires": "sysinit.target -.mount system.slice", "RequiresMountsFor": "/var/tmp", "Restart": "no", "RestartUSec": "100ms", "RestrictNamespaces": "no", "RestrictRealtime": "no", "Result": "success", "RootDirectoryStartOnly": "no", "RuntimeDirectoryMode": "0755", "RuntimeDirectoryPreserve": "no", "RuntimeMaxUSec": "infinity", "SameProcessGroup": "no", "SecureBits": "0", "SendSIGHUP": "no", "SendSIGKILL": "yes", "Slice": "system.slice", "StandardError": "inherit", "StandardInput": "null", "StandardInputData": "", "StandardOutput": "journal", "StartLimitAction": "none", "StartLimitBurst": "5", "StartLimitIntervalUSec": "10s", "StartupBlockIOWeight": "[not set]", "StartupCPUShares": "[not set]", "StartupCPUWeight": "[not set]", "StartupIOWeight": "[not set]", "StateChangeTimestampMonotonic": "0", "StateDirectoryMode": "0755", "StatusErrno": "0", "StopWhenUnneeded": "no", "SubState": "dead", "SuccessAction": "none", "SyslogFacility": "3", "SyslogLevel": "6", "SyslogLevelPrefix": "yes", "SyslogPriority": "30", "SystemCallErrorNumber": "0", "TTYReset": "no", "TTYVHangup": "no", "TTYVTDisallocate": "no", "TasksAccounting": "yes", "TasksCurrent": "[not set]", "TasksMax": "26213", "TimeoutStartUSec": "1min 30s", "TimeoutStopUSec": "1min 30s", "TimerSlackNSec": "50000", "Transient": "no", "Type": "forking", "UID": "[not set]", "UMask": "0022", "UnitFilePreset": "enabled", "UnitFileState": "enabled", "UtmpMode": "init", "WantedBy": "multi-user.target", "WatchdogTimestampMonotonic": "0", "WatchdogUSec": "0"}}</font><br> 
-<font style="color: rgb(0, 0, 0)">PLAY RECAP ***************************************************************************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">www8.dmz.nausch.org        </font><font style="color: rgb(0, 0, 0)">: </font><font style="color: rgb(25, 100, 5)">ok=6    </font><font style="color: rgb(196, 160, 0)">changed=0    </font><font style="color: rgb(0, 0, 0)">unreachable=0    failed=0    skipped=0    rescued=0    ignored=0</font><br></pre> 
-</html> 
- 
-=== Ergebnis === 
-Auf dem Zielhost finden wir nun die Sicherungskopie der originalen chrony.conf aus dem RPM-Paket. 
-   # ll /etc/chrony.conf* 
-<code>-rw-r--r--. 1 root root 1265 Jan  6 16:12 /etc/chrony.conf 
--rw-r--r--. 1 root root 1085 Apr  4  2018 /etc/chrony.conf.orig</code> 
- 
-Der Dienst **chrony.conf** wurde entsprechend gestartet und läuft: 
-   # systemctl status chronyd.service 
- 
-<html><pre class="code"> 
-<font style="color: rgb(0, 255, 0)"><b>● </b></font><font style="color: rgb(0, 0, 0)">chronyd.service - NTP client/server 
-   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled) 
-   Active: <font style="color: rgb(0, 255, 0)"><b>active (running) </b></font><font style="color: rgb(0, 0, 0)">since Mon 2020-01-06 16:12:34 CET; 47s ago 
-     Docs: man:chronyd(8) 
-           man:chrony.conf(5) 
-  Process: 10697 ExecStartPost=/usr/libexec/chrony-helper update-daemon (code=exited, status=0/SUCCESS) 
-  Process: 10693 ExecStart=/usr/sbin/chronyd $OPTIONS (code=exited, status=0/SUCCESS) 
- Main PID: 10695 (chronyd) 
-    Tasks: 1 (limit: 26213) 
-   Memory: 1.1M 
-   CGroup: /system.slice/chronyd.service 
-           └─10695 /usr/sbin/chronyd 
- 
-Jan 06 16:12:34 vml000090.dmz.nausch.org systemd[1]: Starting NTP client/server... 
-Jan 06 16:12:34 vml000090.dmz.nausch.org chronyd[10695]: chronyd version 3.3 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +SECHASH +IPV6 +DEBUG) 
-Jan 06 16:12:34 vml000090.dmz.nausch.org chronyd[10695]: Initial frequency 10.454 ppm 
-Jan 06 16:12:34 vml000090.dmz.nausch.org chronyd[10695]: Using right/UTC timezone to obtain leap second data</font> 
-</pre></html> 
- 
-Beim Starten des Servers/Hosts wird der **chronyd**-Daemon auch automatisch gestartet. Dies können wir wie folgt überprüfen: 
-   # systemctl is-enabled chronyd.service 
- 
-  enabled 
- 
-==== 06: Ansible und Zielhosts ohne Python ==== 
-In diesem Konfigurationsbeispiel befassen wir uns nun mit einer Besonderheit in Sachen Zielhosts. Nicht immer hat man auf einem Zielsystem **[[https://python.org|Python]]** zur Verfügung, wie z.B. bei **[[https://freifunk.net/|Freifunk]]**-Hardware, die auf **[[https://gluon.readthedocs.io/en/v2019.1.x/|gluon]]** und **[[https://openwrt.org/|OpenWrt]]** basieren. Aber auch hier gibt es eine Lösungsmöglichkeit, in dem man für diesen speziellen Fall auf das Modul **[[https://docs.ansible.com/ansible/latest/modules/dnf_module.html|raw]]** zurückgreift. 
- 
-=== Script anlegen === 
-Auch dieses Beispiel-Script speichern wir im Verzeichnis **''~/ansible''** ab. 
-   $ vim 06_change_contact.yml 
- 
-<file bash 06_change_contact.yml>--- 
-- hosts: ffmuc_gluon 
-  gather_facts: False 
- 
-  tasks: 
-    - name: "Update new contact-address on own ffmuc-nodes" 
-      #https://docs.ansible.com/ansible/latest/modules/raw_module.html 
-      raw: uci set gluon-node-info.@owner[0].contact=' Django [BOfH] django@nausch.org | chat -> @django' ; uci commit 
-... 
-</file> 
- 
-=== Script Beschreibung === 
-Dieses Playbook besteht nur aus einer Aufgabe, nämlich dem Ändern der Kontakt-Adresse unserer Freifunk-WLAN-Knoten, die allesamt auf **Gluon/OpenWRT** basieren. Daher macht es auch keinen Sinn, dass Ansible versuchen wird, die **Facts** der Zielhosts zu ermitteln, da dort **Python** nicht zur Verfügung steht, welches für die Ermittlung der systemdaten benötigt wird. 
- 
-Wir deaktivieren also mit **''gather_facts: False''** diese Funktion zu Beginn. 
- 
-Zum Ausführen der Kommandos auf den Freifunk-Knoten verwenden wird das Ansible Modul **[[https://docs.ansible.com/ansible/latest/modules/raw_module.html|raw]]**. Zum Ändern der **[[https://ffmuc.net/wiki/doku.php?id=knb:ssh#kontaktdaten|Kontaktdaten]]** benutzen wir die beiden Befehle: 
-  uci set gluon-node-info.@owner[0].contact='Django [BOfH] django@nausch.org | chat -> @django' 
-  uci commit 
- 
-=== Script ausführen === 
-Nun wollen wir unser ersten Playbook ausführen, um auf den Freifunk-Knoten die Kontaktdaten zu aktualisieren; hierzu rufen wir unser Script wie folgt auf: 
-   $ ansible-playbook -v 06_change_contact.yml 
- 
-<html><pre class="code"> 
-<font style="color: rgb(43, 100, 164)">Using /etc/ansible/ansible.cfg as config file</font> 
-<font style="color: rgb(0, 0, 0)">BECOME password:  
- 
-PLAY [ffmuc_gluon] ********************************************************************************************************************* 
- 
-<font style="color: rgb(0, 0, 0)">TASK [Update new contact-address on own ffmuc-nodes] ***********************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">changed: [ff_pliening_gbw_ug] => {"changed": true, "rc": 0, "stderr": "Shared connection to 2001:608:a01:102:32b5:c2ff:fe56:62b1 closed.\r\n", "stderr_lines": ["Shared connection to 2001:608:a01:102:32b5:c2ff:fe56:62b1 closed."], "stdout": "", "stdout_lines": []} 
-changed: [ff_pliening_gbw_egod] => {"changed": true, "rc": 0, "stderr": "Shared connection to 2001:608:a01:102:1ae8:29ff:fea9:22ed closed.\r\n", "stderr_lines": ["Shared connection to 2001:608:a01:102:1ae8:29ff:fea9:22ed closed."], "stdout": "", "stdout_lines": []} 
-changed: [ff_pliening_gbw_ogod] => {"changed": true, "rc": 0, "stderr": "Shared connection to 2001:608:a01:102:1ae8:29ff:fec0:aaae closed.\r\n", "stderr_lines": ["Shared connection to 2001:608:a01:102:1ae8:29ff:fec0:aaae closed."], "stdout": "", "stdout_lines": []} 
-changed: [ff_pliening_gbw_dgod] => {"changed": true, "rc": 0, "stderr": "Shared connection to 2001:608:a01:102:1ae8:29ff:fec6:c8eb closed.\r\n", "stderr_lines": ["Shared connection to 2001:608:a01:102:1ae8:29ff:fec6:c8eb closed."], "stdout": "", "stdout_lines": []} 
-changed: [ff_pliening_gbw_cpod] => {"changed": true, "rc": 0, "stderr": "Shared connection to 2001:608:a01:102:1ae8:29ff:fec6:c8dd closed.\r\n", "stderr_lines": ["Shared connection to 2001:608:a01:102:1ae8:29ff:fec6:c8dd closed."], "stdout": "", "stdout_lines": []} 
-changed: [ff_pliening_gbw_kvm_ol] => {"changed": true, "rc": 0, "stderr": "Shared connection to 2001:608:a01:102:5054:ff:fe9e:b358 closed.\r\n", "stderr_lines": ["Shared connection to 2001:608:a01:102:5054:ff:fe9e:b358 closed."], "stdout": "", "stdout_lines": []}</font><br> 
-<font style="color: rgb(0, 0, 0)">PLAY RECAP *****************************************************************************************************************************</font> 
-<font style="color: rgb(196, 160, 0)">ff_pliening_gbw_cpod       </font><font style="color: rgb(0, 0, 0)">: </font><font style="color: rgb(25, 100, 5)">ok=1    </font><font style="color: rgb(196, 160, 0)">changed=1    </font><font style="color: rgb(0, 0, 0)">unreachable=0    failed=0    skipped=0    rescued=0    ignored=0</font> 
-<font style="color: rgb(196, 160, 0)">ff_pliening_gbw_dgod       </font><font style="color: rgb(0, 0, 0)">: </font><font style="color: rgb(25, 100, 5)">ok=1    </font><font style="color: rgb(196, 160, 0)">changed=1    </font><font style="color: rgb(0, 0, 0)">unreachable=0    failed=0    skipped=0    rescued=0    ignored=0</font> 
-<font style="color: rgb(196, 160, 0)">ff_pliening_gbw_egod       </font><font style="color: rgb(0, 0, 0)">: </font><font style="color: rgb(25, 100, 5)">ok=1    </font><font style="color: rgb(196, 160, 0)">changed=1    </font><font style="color: rgb(0, 0, 0)">unreachable=0    failed=0    skipped=0    rescued=0    ignored=0</font> 
-<font style="color: rgb(196, 160, 0)">ff_pliening_gbw_kvm_ol     </font><font style="color: rgb(0, 0, 0)">: </font><font style="color: rgb(25, 100, 5)">ok=1    </font><font style="color: rgb(196, 160, 0)">changed=1    </font><font style="color: rgb(0, 0, 0)">unreachable=0    failed=0    skipped=0    rescued=0    ignored=0</font> 
-<font style="color: rgb(196, 160, 0)">ff_pliening_gbw_ogod       </font><font style="color: rgb(0, 0, 0)">: </font><font style="color: rgb(25, 100, 5)">ok=1    </font><font style="color: rgb(196, 160, 0)">changed=1    </font><font style="color: rgb(0, 0, 0)">unreachable=0    failed=0    skipped=0    rescued=0    ignored=0</font> 
-<font style="color: rgb(196, 160, 0)">ff_pliening_gbw_ug         </font><font style="color: rgb(0, 0, 0)">: </font><font style="color: rgb(25, 100, 5)">ok=1    </font><font style="color: rgb(196, 160, 0)">changed=1    </font><font style="color: rgb(0, 0, 0)">unreachable=0    failed=0    skipped=0    rescued=0    ignored=0</font> 
-<br></pre> 
-</html> 
- 
-=== Ergebnis === 
-Alle unsere eigenen definierten Freifunk Knoten haben nun auf der **[[https://map.ffmuc.net/#!/de/map/18e829a922ed|Freifunk München Karte]]** unseren aktualisierte Kontaktdaten. 
- 
-==== 07: Mit Hilfe von Ansible einen Offloader auf Basis eines Raspberry 4B bauen ==== 
-In diesem **[[centos:ansible:ffmuc-rpb4-ol|Konfigurationsbeispiel]]** wollen wir möglichst einfach und schnell einen Offloader für **[[https://ffmuc.net|Freifunk München]] auf Basis eines **[[https://www.raspberrypi.org/products/raspberry-pi-4-model-b/|Raspberry 4B]] befassen. Dabei gehen wir auf unterschiedliche Konfigurations-Optionen ein und wollen dennoch die Einstiegshürden für den ungeübteren Ansible und Linux-User möglichst tief ansetzen.  
- 
-Die detaillierte Beschreibung hierzu ist im Kapitel **[[centos:ansible:ffmuc-rpb4-ol|Bau eines Freifunk-Offloaders auf Basis eines Raspberry 4B]]** zu finden. 
-====== Links ====== 
-  * **[[centos:ansible:first|zurück zum Kapitel "Erste Schritte Rund um Ansible"]] <= ** 
-  * **=> [[centos:ansible:detail|weiter zum Kapitel "Ansible - Erweiterte Konfigurationsbeispiele]]** 
-  * ** [[centos:ansible:start|Zurück zur "Ansible"-Übersicht]]** 
-  * **[[wiki:start|Zurück zu >>Projekte und Themenkapitel<<]]** 
-  * **[[http://dokuwiki.nausch.org/doku.php/|Zurück zur Startseite]]** 
- 
  
  • centos/ansible/playbooks1.1593353451.txt.gz
  • Zuletzt geändert: 28.06.2020 14:10.
  • von django