Archiv des Autors: Jörg Kastning

mysql_upgrade – prüft und aktualisiert MySQL-Tabellen

Vergangenes Wochenende hat KOFREZO unseren Server von Ubuntu Trusty Tahr auf die aktuelle LTS-Version Xenial Xerus aktualisiert. Einhergehend mit dem Release-Upgrade wurde MySQL auf Version 5.7 aktualisiert.

Beim ersten Versuch, ein Backup meiner Datenbank mit mysqldump zu erzeugen, wurde ich überraschend mit folgender Fehlermeldung konfrontiert:


mysqldump: Couldn't execute 'SHOW VARIABLES LIKE 'gtid\_mode'': Native table 'performance_schema'.'session_variables' has the wrong structure (1682)

In der Folge wurde kein Backup erstellt.

Die Lösung für dieses Problem fand ich nach kurzer Internetrecherche im Werkzeug mysql_upgrade. Dieses Programm untersucht alle Datenbanken und Tabellen auf Kompatibilität mit der aktuell installierten Version des MySQL-Servers. Dabei werden die entsprechenden Datenbanken und Tabellen falls nötig automatisch aktualisiert. Die Manpage (MYSQL_UPGRADE(1)) empfiehlt die Ausführung des Programms nach jedem Upgrade von MySQL.

Achtung: Das im Folgenden gezeigte Kommando hat mein Problem zwar gelöst, jedoch erfolgt die Ausführung auf eigene Gefahr. Ich selbst habe das Kommando das erste Mal verwendet und bin alles andere als ein Experte dafür. Dieser Post dient mir vor allem zur Erinnerung, wie ich das aktuelle Problem lösen konnte.

Das aktuelle Problem wurde wie folgt gelöst:

  1. Sicherstellen, dass MySQL läuft mit sudo systemctl status mysql.service
  2. Ausführung von mysql_upgrade -u root --skip-sys-schema
  3. Neustart von MySQL mit sudo systemctl restart mysql.service

Fertig. Hoffentlich erinnere ich mich beim nächsten MySQL-Update an diesen Beitrag.

Import von iCal-Dateien in einen ownCloud-Kalender

Dieses Tutorial zeigt, wie Kalender bzw. Termine aus einer iCalendar-Datei (Abk. iCal; Dateiendung: .ics, .ifb, .iCal, .iFBf) in einen ownCloud-Kalender importiert werden können. Zur Erstellung des Tutorials habe ich das Vortragsprogramm der Chemnitzer Linux Tage 2017 genommen, welches als ICS-Datei bereitgestellt wurde. Die verwendete Datei ist am Ende des Tutorials angehängt, so dass man diese für eigene Tests nutzen kann.

In diesem Tutorial wird vorausgesetzt, dass man mit der Verwendung von ownCloud im allgemeinen vertraut ist. Die Installation und Konfiguration von ownCloud sind ausdrücklich nicht Bestandteil dieses Tutorials.

Erstellung eines neuen ownCloud-Kalenders

Die zu importierenden Termine sollen in einen separaten Kalender importiert werden, um sie bei Bedarf einfach ein- und ausblenden zu können. Dazu wird im ersten Schritt ein neuer ownCloud-Kalender erstellt.

ceate-calendar

Erstellung eines neuen Kalenders

choose_name-and-color

Name und Farbe des neuen Kalenders auswählen

ICS-Datei hochladen und Importieren

Die zu importierende ICS-Datei wird im Bereich „Dateien“ hochgeladen. Anschließend klickt man auf den Dateinamen, um den Import-Dialog zu öffnen.

open-iics-file-in-oc

Die Datei wird mit einem Links-Klick zum Import geöffnet

import-ics-to-oc

Kalender auswählen und Import starten

In dem Dialgofenster kann der Kalender ausgewählt werden, in den die Termine aus der ICS-Datei importiert werden sollen. Bei Bedarf kann an dieser Stelle auch ein neuer Kalender angelegt werden, wenn dies nicht bereits geschehen ist. Mit einem Klick auf „Importieren“ wird der Import gestartet.

Import abgeschlossen

Ist der Import abgeschlossen, kann das Dialogfenster geschlossen werden. Das Ergebnis des Imports kann in der Kalenderansicht überprüft werden. Und nun freue ich mich, morgen alle Vorträge im Blick zu haben.

Programm der Chemnitzer Linux Tage 2017

Interessante Links und Dateien

Protokoll zum Ausfall eines Webdienstes nach der fehlgeschlagenen Erneuerung eines Let’s Encrypt Zertifikats

In diesem Beitrag werden die Ursache und der Verlauf der Störung protokolliert, welche die vorübergehende Nichterreichbarkeit einer Seafile1-Installation zur Folge hatte, welche ich für den Freifunk Lippe2 betreibe.

Beschreibung der Umgebung

Die Seafile-Installation wird ausführlich in „Installation von Seafile auf einem Ubuntu/Debian Server“ beschrieben. Die aktuelle Installation wurde wie dort erwähnt zusätzlich mit HSTS (TLS-Kochbuch, Abschnitt 2.7) und HPKP (TLS-Kochbuch, Abschnitt 2.8) gesichert. Das benötigte TLS-Zertifikat stammt von Let’s Encrypt (Abschnitt 3.4.1, TLS-Kochbuch).

Zur automatisierten Verlängerung wird das Skript smartrenew.sh verwendet, welches in Abschnitt 5.4 im TLS-Kochbuch beschrieben wird.

Eingang der Störungsmeldung

Die Störungsmeldung ging am 04.02.2017 per E-Mail. Die Meldung wies auf einen Fehler bei der Erneuerung des Zertifikats durch Let’s Encrypt hin:


arsing account key...
Parsing CSR...
Registering account...
Already registered!
Verifying seafile.example.com...
Traceback (most recent call last):
  File "acme-tiny-by-frezbo/acme_tiny.py", line 200, in 
    main(sys.argv[1:])
  File "acme-tiny-by-frezbo/acme_tiny.py", line 196, in main
    signed_crt = get_crt(args.account_key, args.csr, args.acme_dir, verifychallenge=args.verifychallenge, log=LOGGER, CA=args.ca)
  File "acme-tiny-by-frezbo/acme_tiny.py", line 150, in get_crt
    domain, challenge_status))
ValueError: seafile.example.com challenge did not pass: {u'status': u'invalid', u'validationRecord': [{u'url': u'http://seafile.example.com/.well-known/acme-challenge/ag0bYKs4XzfkYlzRPYLC1cFtv-ypEIQCEVfYulPlMGk', u'hostname': u'seafile.example.com', u'addressUsed': u'IPv4-Adresse', u'port': u'80', u'addressesResolved': [u'IPv4-Adresse', u'IPv6-Adresse']}, {u'url': u'https://seafile.example.com/.well-known/acme-challenge/ag0bYKs4XzfkYlzRPYLC1cFtv-ypEIQCEVfYulPlMGk', u'hostname': u'seafile.example.com', u'addressUsed': u'IPv4-Adresse', u'port': u'443', u'addressesResolved': [u'IPv4-Adresse', u'IPv6-Adresse']}], u'keyAuthorization': u'ag0bYKs4XzfkYlzRPYLC1cFtv-ypEIQCEVfYulPlMGk.pW0Gip0L_WLx7XEnmH_3ZArt9Vi4TbokaUuSXsc1dm4', u'uri': u'https://acme-v01.api.letsencrypt.org/acme/challenge/u5hporNk0I5YunYlQQeJPKdRyd-9BKGMWjBhm_7Za9E/578797992', u'token': u'ag0bYKs4XzfkYlzRPYLC1cFtv-ypEIQCEVfYulPlMGk', u'error': {u'status': 403, u'type': u'urn:acme:error:
 unauthorized', u'detail': u'Invalid response from http://seafile.example.com/.well-known/acme-challenge/ag0bYKs4XzfkYlzRPYLC1cFtv-ypEIQCEVfYulPlMGk: "\r\n404 Not Found\r\n\r\n404 Not Found\r\n"'}, u'type': u'http-01'}
 * Reloading nginx configuration nginx
   ...fail!

Der Fehlermeldung ist zu entnehmen, dass die ACME-Challenge nicht verifiziert werden konnte, da der Server auf die Anfrage mit der Meldung „404 Not Found“ antwortete. Dieser Fehler konnte durch Aufruf der URL mit dem Programm wget bestätigt werden.

Ergebnis der Systemanalyse

Die Analyse der NGINX-Konfiguration ergab, dass der von Let’s Encrypt signierte öffentliche Schlüssel des Zertifikats nicht zum dazugehörenden privaten Schlüssel passte. Dies hatte zur Folge, dass sich die Webseite im Browser, der HSTS und HPKP unterstützt, nicht mehr aufgerufen werden konnte. Denn durch HSTS wird auch ein Aufruf der Seite über HTTP automatisch auf HTTPS umgeleitet. Hier wird nun durch HPKP ebenfalls festgestellt, dass der gepinnte Key nicht mit dem vom Webserver ausgelieferten übereinstimmte und der Browser verweigerte den Aufruf der Webseite.

Die Ursache hierfür lag in der fehlenden Fehlerbehandlung im folgenden Skript:


python acme-tiny-by-frezbo/acme_tiny.py --no-verify --account-key /var/www/seafile.example.com/ssl/account.key --csr /var/www/seafile.example.com/ssl/seafile.example.com.csr --acme-dir /var/www/seafile.example.com/public/.well-known/acme-challenge/ > /var/www/seafile.example.com/ssl/seafile.example.com.crt

cat /var/www/seafile.example.com/ssl/seafile.example.com.crt /var/www/seafile.example.com/ssl/lets-encrypt-x3-cross-signed.pem > /var/www/seafile.example.com/ssl/seafile.example.com_chained.crt

sudo service nginx reload

Zuerst versucht das Skript, das Zertifikat zu erneuern und in die Datei seafile.example.com.crt zu schreiben. Schlägt dieser Vorgang fehl, wird durch den zweiten Teil des Skripts trotzdem aus der korrupten Datei und dem Intermediate-Zertifikat die Zertifikatskette erstellt und in der Datei seafile.example.com_chained.crt gespeichert.

In diesem Fall trat bei der Erneuerung des Zertifikats ein Fehler auf. Es wurde jedoch trotzdem eine Datei namens seafile.example.com.crt mit einer Größe von 0 Byte erstellt. Daher fehlte das Zertifikat auch in der daraufhin erstellten Zertifikatskette. Dies hatte zur Folge, dass durch HPKP der Webbrowser den Zugriff auf die Domain verweigerte und die Anwendung nicht mehr erreichbar war.

Eine Überprüfung der Datensicherung ergab leider, dass das Verzeichnis mit den Zertifikatsdateien nicht Bestandteil des Backups war. Somit war die schnelle Wiederherstellung der Zertifikatskette nicht möglich.

Störungsbeseitigung

Um die Störung zu beseitigen, wurde zuerst die bestehende vHost-Konfiguration für die Seafile-Instanz deaktiviert. Anschließend wurde ein neuer vHost eingerichtet, der ausschließlich via HTTP das Verzeichnis ausliefert, welches die ACME-Challenge beinhaltet:


server {
        listen       80;
        server_name  seafile.example.com;

        root /var/www/seafile.example.com/public/;
        location / {
        index index.html index.htm index.php;
        }
}

Nun wurde das Skript zur Erneuerung des Let’s Encrypt Zertifikats erneut gestartet. Das Skript lief diesmal fehlerfrei durch und es wurde wieder eine vollständige Zertifikatskette erstellt und in der vorgesehenen Datei gespeichert.

Daher konnte die temporäre vHost-Konfiguration nun wieder deaktiviert und die ursprüngliche Konfiguration wieder aktiviert werden.

Maßnahmen zur Risikominimierung

Nachdem mich die Störung natürlich zur ungünstigsten Zeit (welche Zeit ist für eine Störung schon günstig?) erwischt hat, habe ich mir Gedanken gemacht, wie sich das Risiko minimieren lässt, dass mich der gleiche Ärger in Zukunft nochmal ereilt.

Datensicherung anpassen

Zuerst habe ich meine Datensicherung angepasst und das Verzeichnis, welches die Zertifikatsdateien enthält, mit ins Backup aufgenommen. Selbstverständlich ist das Backup nur die halbe Miete. Ob sich dieses erfolgreich wiederherstellen lässt, muss natürlich auch getestet werden.

Fehler bei der Skript-Ausführung abfangen

Wie weiter oben bereits beschrieben, begann die ganze Problematik damit, dass das Skript zur Zertifikatserneuerung weiterarbeitete, obwohl bereits bei der Erneuerung des Zertifikats ein Fehler aufgetreten war.

Zukünftig soll das Skript abbrechen, wenn bei der Verarbeitung ein Fehler auftritt. Dazu wurde es wie folgt erweitert:


function check() {
  if [ $1 -gt 0 ]; then
    echo "Uuups, hier ist was schiefgegangen"
    echo "exit $1"
    exit 1
  fi
}

python acme-tiny-by-frezbo/acme_tiny.py --no-verify --account-key /var/www/seafile.example.com/ssl/account.key --csr /var/www/seafile.example.com/ssl/seafile.example.com.csr --acme-dir /var/www/seafile.example.com/public/.well-known/acme-challenge/ > /var/www/seafile.example.com/ssl/seafile.example.com.crt

check $?

cat /var/www/seafile.example.com/ssl/seafile.example.com.crt /var/www/seafile.example.com/ssl/lets-encrypt-x3-cross-signed.pem > /var/www/seafile.example.com/ssl/seafile.example.com_chained.crt

check $?

sudo service nginx reload

Schlägt die Erneuerung des Zertifikats fehl, gibt das Kommando einen Exit-Status größer Null zurück. Dies wird von der check-Funktion erkannt und das Skript abgebrochen. Dadurch bleiben die alte Datei mit der Zertifikatskette erhalten und der Dienst bleibt verfügbar, bis das Problem mit der Zertifikatserneuerung behoben werden kann.

NGINX verweigert Neustart – [emerg]: bind() to 0.0.0.0:80 failed (98: Address already in use)

In diesem Artikel möchte ich einige Informationen zur NGINX-Fehlermeldung „[emerg]: bind() to 0.0.0.0:80 failed (98: Address already in use)“ wiedergeben.

Als ich heute Morgen die E-Mail-Reports meiner Server durchgesehen habe, fiel mir die Meldung ins Auge, dass auf einem meiner Server die NGINX-Konfiguration nicht erneut eingelesen werden konnte. Auch der Versuch eines manuellen Neustarts wurde mit folgender Meldung quittiert:

# sudo service nginx restart
* Restarting nginx nginx [fail]

Konfiguration überprüfen

Die obige Meldung gibt noch keinerlei Hinweise auf die Ursache des Fehlers. Mit dem folgenden Kommando lässt sich die Konfiguration des NGINX überprüfen und der Fehler etwas eingrenzen:

# sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: [emerg] listen() to 0.0.0.0:80, backlog 511 failed (98: Address already in use)
nginx: configuration file /etc/nginx/nginx.conf test failed

Die Fehlermeldung sagt aus, dass der NGINX-Prozess nicht erneut an den Port 80 gebunden werden kann, da dieser bereits verwendet wird. Für mich noch immer etwas verwirrend, da NGINX ja noch läuft und selbstverständlich auf Port 80 lauscht. Weshalb dadurch plötzlich kein Neustart mehr möglich ist, erschließt sich mir noch nicht.

Eine Lösung

Bei der Internetrecherche nach einer Lösung, bin ich auf einen englischsprachigen Troubleshootingguide gestoßen, welcher empfiehlt, alle Prozesse, die auf Port 80 lauschen, mit dem folgenden Kommando zu beenden:

sudo fuser -k 80/tcp

Anschließend konnte ich den NGINX wie gewohnt neu starten (restart) oder die Konfiguration neu einlesen (reload). Das Problem scheint damit erstmal behoben zu sein.

WordPress fordert zum Update Verbindungsinformationen (FTP-Zugangsdaten) an

Wie im letzten Beitrag geschildert, ist dieser Blog auf einen anderen Server umgezogen.

Aktuell teste ich noch alle Funktionen und versuche, die gefundenen Fehler zu bereinigen. An dieser Stelle möchte ich mich auch schon einmal bei all denen bedanken, die mich auf Fehler aufmerksam gemacht haben.

Heute wurde ich im Backend auf das WordPress-Update 4.7.1 aufmerksam, welches ich umgehend installieren wollte. Dabei forderte mich WordPress unerwartet auf, FTP-Zugangsdaten einzugeben, um das Update durchführen zu können.

Diese Meldung irritierte mich etwas, da ich diese Informationen auf dem alten Server nicht benötigte. Auf dem aktuellen Server läuft noch ein weiterer WordPress-Blog, welcher ebenfalls ohne Angabe dieser Verbindungsinformationen aktualisiert werden konnte.

Nach kurzer Internetrecherche fand ich die Lösung für mein Problem in dem Artikel WordPress Berechtigungen korrekt setzen (Problem mit FTP-Serverdaten Aufforderungen beheben) von Ansas Meyer. Ich habe wie dort beschrieben die Berechtigungen überprüft. Diese waren jedoch bereits korrekt gesetzt. Anschließend habe ich der Datei wp-config.php folgende Zeile hinzugefügt:

define('FS_METHOD', 'direct');

Anschließend konnte das Update wie gewohnt über das Backend eingespielt werden.

Die Ursache, die für die plötzliche Anforderung der Verbindungsinformationen verantwortlich ist, kenne ich leider immer noch nicht. Jedoch bin ich froh, dass ich dank des Artikels von Ansas die Folgen behandeln konnte.

Jörg Kastning

26. Dezember 2016

Mein WordPress-Blog „My-IT-Brain“ ist bis auf Weiteres auf einen neuen Server umgezogen.

Die Migration verlief nahezu reibungslos. Es mussten lediglich ein paar Plugins entfernt werden, die auf dem neuen Server ihre Arbeit verweigerten.

Falls ihr beim Besuch meiner Seite auf Fehler stoßt bzw. Dinge entdeckt die nicht (mehr) funktionieren, freue ich mich, wenn ihr diese über das Kontaktformular meldet.

Frohe Weihnachten
Der Webmaster

Kurztipp: nginx_modsite

In diesem Post möchte ich ganz kurz das Skript nginx_modsite vorstellen.

Dieses ermöglicht die einfache De-/Aktivierung von Nginx-Konfigurationsdateien in den Standard-Verzeichnissen /etc/nginx/sites-available und /etc/nginx/sites-enabled.

Das Skript wurde ursprünglich 2010 von Michael Lustfield erstellt. Es ist u.a. in meinem GitHub-Repository1 zu finden.

Zur einfachen Verwendung kopiert man das Skript in das Verzeichnis /usr/local/sbin. Ruft man es mit den Argumenten -h bzw. --help auf, erhält man eine Übersicht der verfügbaren Optionen:

sudo nginx_modsite -h
Usage: nginx_modsite [options]
Options:
<-e|--enable> Enable site
<-d|--disable> Disable site
<-l|--list> List sites
<-h|--help> Display help

If is left out a selection of options will be presented.
It is assumed you are using the default sites-enabled and
sites-disabled located at /etc/nginx.

Somit müssen die Links in /etc/nginx/sites-enabled nicht mehr per Hand erstellt werden. Alles in allem ein sehr schönes Skript, welches ich nicht mehr missen möchte.

Ankündigung von Wartungsarbeiten im Zeitraum 24.12.-30.12.2016

Liebe Leserinnen und Leser,

zwischen den Feiertagen werde ich die Migration dieses Blogs vorbereiten. Denn My-It-Brain wird vom aktuellen Webspace bei einem deutschen Webhosting-Provider auf einen gemieteten Root-Server umziehen.

Während der Migration kann es vorübergehend zu Störungen in der Erreichbarkeit kommen. Ich bitte diese zu entschuldigen.

Der Zeitraum ist bewusst so lang gewählt, da auch ich zwischen den Feiertagen mit meiner Familie feiern werde und die Migration nur „nebenbei“ voran treibe.

Ich wünsche euch allen eine schöne Weihnachtszeit und einen guten Rutsch ins Jahr 2017.

Ansible – Was ich am Ad-hoc-Modus schätze

Schon seit einiger Zeit hilft mir Ansible1 fast täglich dabei, meine Arbeit leichter zu gestalten. Heute möchte ich euch ganz kurz erzählen, was ich am Ad-hoc-Modus schätze.

Der Ad-hoc-Modus bietet die Möglichkeit, einfache Kommandos parallel auf einer Gruppe von Nodes ausführen zu lassen, ohne zuvor ein Playbook erstellen zu müssen. Ein Ad-hoc-Befehl besitzt z.B. den folgenden Aufbau:

ansible [-m module_name] [-a args] [options]

Ein einfaches Beispiel aus der Ansible-Dokumentation2 soll die Anwendung verdeutlichen:

# ansible all -m ping -i staging --limit=e-stage
host01.example.com | SUCCESS => {
"changed": false,
"ping": "pong"
}
host02.example.com | SUCCESS => {
"changed": false,
"ping": "pong"
}
host03.example.com | SUCCESS => {
"changed": false,
"ping": "pong"
}

Das Schlüsselwort all gibt an, dass das Kommando auf allen Nodes ausgeführt werden soll, welche in der Inventar-Datei enthalten sind. Mit -m ping wird das zu verwendende Ansible-Modul spezifiziert. Da das verwendete Modul keine weiteren Argumente besitzt, findet -a in diesem Beispiel keine Anwendung. Mit der Option -i kann die zu verwendende Inventar-Datei angegeben werden. Lässt man diese Option weg, wird die Standard-Inventar-Datei /etc/ansible/hosts verwendet. Mit der Option --limit=e-stage wird die Ausführung noch weiter eingeschränkt. So wird in diesem Fall das Modul ping nur auf den Nodes der Gruppe e-stage ausgeführt. Das in diesem Beispiel verwendete Inventar besitzt den folgenden Aufbau:

[e-stage]
host01.example.com
host02.example.com
host03.example.com
host06.example.com
host07.example.com

[i-stage]
host04.example.com

[p-stage]
host05.example.com

Verknüpfung mit weiteren Kommandos

Selbstverständlich lassen sich Ansible-Ad-hoc-Kommandos auf der Kommandozeile auch weiter verknüpfen. Dies soll an zwei kleinen Beispielen verdeutlicht werden.

Status eines Dienstes prüfen

In diesem ersten Beispiel soll der Status des Dienstes chronyd überprüft werden, ohne den aktuellen Status zu ändern. Dabei soll das Kommando systemctl status chronyd.service via Ansible parallel auf den Nodes ausgeführt werden.

Zuvor habe ich mir auf einem Node angesehen, wie die Ansible-Ausgabe in Abhängigkeit vom Dienststatus aussieht (Ausgabe gekürzt):

# Der Dienst auf dem Node ist gestartet
root@ansible-control-machine>ansible all -m command -a'/usr/bin/systemctl status chronyd.service' -i staging -l host01.example.com
host01.example.com | SUCCESS | rc=0 >>
* chronyd.service - NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2016-12-15 14:52:02 CET; 19h ago

# Der Dienst auf dem Node ist gestoppt
root@ansible-control-machine>ansible all -m command -a’/usr/bin/systemctl status chronyd.service‘ -i staging -l host01.example.com
host01.example.com | FAILED | rc=3 >>
* chronyd.service – NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
Active: inactive (dead) since Fri 2016-12-16 10:04:34 CET; 4s ago

# Das Paket, welches den Dienst enthaelt ist nicht installiert
root@ansible-control-machine>ansible all -m command -a’/usr/bin/systemctl status chronyd.service‘ -i staging -l host01.example.com
host01.example.com | FAILED | rc=4 >>
Unit chronyd.service could not be found.

Anhand der Ausgaben ist zu erkennen, dass Ansible den Task als „| SUCCESS |“ markiert, wenn der Dienst läuft und als „| FAILED |“, wenn der Dienst gestoppt bzw. gar nicht installiert ist. Durch Verknüpfung des Kommandos mit grep kann man sich nun schnell einen Überblick über den Dienststatus auf seinen Rechnern verschaffen:

root@ansible-control-machine> ansible all -m command -a'/usr/bin/systemctl status chronyd.service' -i staging --limit=e-stage | grep '| SUCCESS |\|| FAILED |'
host01.example.com | SUCCESS | rc=0 >>
host02.example.com | SUCCESS | rc=0 >>
host03.example.com | FAILED | rc=3 >>
host06.example.com | SUCCESS | rc=0 >>
host07.example.com | SUCCESS | rc=0 >>

Anhand der Ausgabe ist leicht zu erkennen, dass der Dienst chronyd auf host03 nicht läuft. Anhand des Return-Codes rc=3 lässt sich weiterhin erkennen, dass das notwendige Paket offensichtlich installiert ist, der Dienst jedoch nicht gestartet wurde. Dies kann nun jedoch schnell durch folgenden Befehl korrigiert werden (Ausgabe gekürzt):

root@ansible-control-machine>ansible host03.example.com -m systemd -a'name=chronyd state=started' -i staging
host03.example.com | SUCCESS => {
"changed": true,
"name": "chronyd",
"state": "started",
"status": {...}
}

Eine erneute Ausführung des ersten Kommandos bestätigt, dass der Dienst nun auch auf dem Node host03 ausgeführt wird.

root@ansible-control-machine> ansible all -m command -a'/usr/bin/systemctl status chronyd.service' -i staging --limit=e-stage | grep '| SUCCESS |\|| FAILED |'
host01.example.com | SUCCESS | rc=0 >>
host02.example.com | SUCCESS | rc=0 >>
host03.example.com | SUCCESS | rc=0 >>
host06.example.com | SUCCESS | rc=0 >>
host07.example.com | SUCCESS | rc=0 >>

Paketversion überprüfen

In diesem Beispiel möchte ich die installierte Version des Pakets tzdata abfragen. Dies geschieht auf einem einzelnen Host mit dem Kommando rpm -qi :

# rpm -qi tzdata
Name : tzdata
Version : 2016i
Release : 1.el7
Architecture: noarch
Install Date: Wed Nov 9 08:47:03 2016
Group : System Environment/Base
Size : 1783642
License : Public Domain
Signature : RSA/SHA256, Fri Nov 4 17:21:59 2016, Key ID 199e2f91fd431d51
Source RPM : tzdata-2016i-1.el7.src.rpm
Build Date : Thu Nov 3 12:46:39 2016
Build Host : ppc-045.build.eng.bos.redhat.com
Relocations : (not relocatable)
Packager : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>
Vendor : Red Hat, Inc.
URL : https://www.iana.org/time-zones
Summary : Timezone data
Description :
This package contains data files with rules for various timezones around
the world.

Mich interessiert lediglich die zweite Zeile, welche die Version des Pakets enthält. Die frage ich nun wie folgt ab:

root@ansible-control-machine> ansible all -m command -a'/usr/bin/rpm -qi tzdata' -i staging --limit=e-stage | grep 'SUCCESS\|Version'
host01.example.com | SUCCESS | rc=0 >>
Version : 2016f
host02.example.com | SUCCESS | rc=0 >>
Version : 2016g
host03.example.com | SUCCESS | rc=0 >>
Version : 2016i
host06.example.com | SUCCESS | rc=0 >>
Version : 2016i
host07.example.com | SUCCESS | rc=0 >>
Version : 2016i

Ohne Ansible hätte ich diese Aufgaben entweder mit Iteration in einem kurzen Shell-Skript lösen müssen, oder zuerst ein Kochbuch, Manifest, etc. schreiben, welches dann anschließend ausgeführt werden kann. So wurde mir hingegen einiges an Zeit gespart, die ich für andere Dinge verwenden konnte.

Quellen und weiterführende Links

RHEL/CentOS: Ändert sich beim Update eines Pakets der Inode der Dateien?

Heute fragte mich ein Kollege, ob sich der Inode ändert, wenn eine Datei wie z.B. /usr/bin/firefox bei einem Update aktualisiert wird.

Die Antwort lautet: Ja, der Inode ändert sich.

[user@rhel-72-dev ~]$ diff -u inode_4_update.txt inode_after_update.txt 
--- inode_4_update.txt	2016-12-02 21:20:17.231097211 +0100
+++ inode_after_update.txt	2016-12-02 21:22:10.987883736 +0100
@@ -1 +1 @@
-267718 8.0K -rwxr-xr-x. 1 root root 6.8K Nov  8 11:18 /usr/bin/firefox
+264866 8.0K -rwxr-xr-x. 1 root root 6.8K Nov 30 09:41 /usr/bin/firefox