Archiv des Autors: Jörg Kastning

Linux: Wann ist ein Neustart erforderlich?

Es ist allgemein bekannt, dass ein Neustart erforderlich ist, um einen neu installierten oder aktualisierten Kernel zu laden. Doch gibt es auch noch weitere Pakete, welche den Neustart eines Hosts erforderlich machen. Dieser Artikel beschreibt Methoden für CentOS, RHEL, Oracle Linux, Debian und Ubuntu, mit denen geprüft werden kann, ob ein Neustart erforderlich ist oder nicht.

Prüfung unter CentOS, RHEL, Oracle Linux

Unter den genannten Distributionen existiert das Programm needs-restarting, welches durch das Paket yum-utils bereitgestellt wird. Dieses kann genutzt werden, um Prozesse anzuzeigen, die aktualisiert wurden:

# needs-restarting
477 : /usr/bin/VGAuthService -s

Die Ausgabe gibt die Prozess-ID und den Namen des Prozesses zurück. Möchte man prüfen, ob ein Neustart des gesamten Systems erforderlich ist, so nutzt man die Option -r:

# needs-restarting -r
Core libraries or services have been updated:
  kernel -> 3.10.0-693.1.1.el7

Reboot is required to ensure that your system benefits from these updates.

More information:
https://access.redhat.com/solutions/27943

Obige Ausgabe deutet darauf hin, dass ein Neustart erforderlich ist, da ein neuer Kernel installiert wurde. Auf einem neugestarteten System sieht die Ausgabe wie folgt aus:

$ sudo needs-restarting -r
No core libraries or services have been updated.
Reboot is probably not necessary

Prüfung unter Debian und Ubuntu

Um festzustellen, ob ein Neustart erforderlich ist oder nicht, kann man prüfen, ob die Datei /var/run/reboot-required existiert. Existiert die Datei, ist es angeraten, einen Neustart des Systems durchzuführen. Ist die Datei hingegen nicht vorhanden, ist höchstwahrscheinlich auch kein Neustart erforderlich.

Quellen und weiterführende Links

Geschwindigkeit von PowerLAN mit iperf messen

PowerLAN, auch bekannt als dLAN oder Powerline, bezeichnet eine Technologie, zum Aufbau eines lokalen Netzwerks, unter Nutzung vorhandener Stromleitungen.

Adapter verschiedener Hersteller versprechen dabei eine Übertragungsgeschwindigkeit von bis zu 2000 Mbit/s. Doch ob diese Geschwindigkeit im eigenen Haushalt auch nur annähernd erreicht wird hängt von vielen Faktoren ab. Darunter fallen z.B. Alter und Zustand der Hausverkabelung, aber auch angeschlossene elektrische Geräte können die Übertragungsgeschwindigkeit negativ beeinflussen.

Um die Geschwindigkeit des PowerLAN zu messen bietet sich das Programm iperf an, welches unter allen gängigen Linux-Distributionen zur Verfügung steht.

Test der Messmittel

Bevor man mit der Messung beginnt und viel Mist misst, sollte man noch ein paar Dinge beachten.

Um mit iperf die Geschwindigkeit des Netzwerks zu messen, kommen in meinem kleinen Versuchsaufbau zwei Notebooks mit Ubuntu 16.04 LTS und Gigabit-Netzwerkkarte zum Einsatz. Denn selbstverständlich haben auch die Geschwindigkeit der verwendeten Netzwerkkarten und selbst der Netzwerkkabel einen Einfluss auf das Messergebnis. Verwendet man Netzwerkkarten mit einer Geschwindigkeit von 100 Mbit/s oder ist schon ein paar Mal mit dem Bürostuhl über das Netzwerkkabel gerollt, darf man sich nicht wundern, wenn man nicht mal annähernd an die versprochene Geschwindigkeit herankommt. Aber auch andere Programme, die evtl. zur gleichen Zeit ausgeführt werden und das Netzwerk nutzen, können die Messergebnisse beeinträchtigen. Es gilt diese Störfaktoren möglichst auszuschließen.

Die beiden Notebooks verbinde ich zuerst über einen Gbit-Switch miteinander. Dazu verwende ich die neuen LAN-Kabel, welche den PowerLAN-Adaptern beiliegen. Dank IPv6 ist keine weitere Konfiguration der Schnittstellen erforderlich. Es können direkt die link-local Adressen genutzt werden, um miteinander zu kommunizieren. Nun wird auf einem der beiden Notebooks iperf (iperf -s) im Servermodus gestartet, womit es auf eingehende Verbindungen wartet.

Auf dem anderen Notebook wird iperf im Client-Modus gestartet (iperf -c hostname), welches sich dann zum Server verbindet und mit der Messeung beginnt. Das Ergebnis einer solchen Messung ist der folgenden Ausgabe zu entnehmen:

------------------------------------------------------------
Client connecting to fe80::%eth0, TCP port 5001
TCP window size: 85.0 KByte (default)
------------------------------------------------------------
[  3] local fe80:: port 47748 connected with fe80:: port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-10.0 sec  1.07 GBytes   915 Mbits/sec

Bei ca. 10 Wiederholungen dieses Tests lag die Geschwindigkeit stets zwischen 910 Mbits/s und 936 Mbits/s. Für einen kleinen SoHo-Switch ein hervorragendes Ergebnis. Nun bin ich natürlich gespannt, ob die PowerLAN-Adapter die angepriesene Geschwindigkeit ebenfalls liefern können.

Messung der PowerLAN-Verbindung

Die PowerLAN-Adapter wurden direkt in Wandsteckdosen eingesetzt. Die integrierten Steckdosen sollen von weiteren Endgeräten verursachte Störungen auf der Leitung herausfiltern und so die bestmögliche Leistung garantieren.

In meinem Versuchsaufbau befand sich ein Adapter im Erdgeschoss, während der andere im darüberliegenden Raum im 1. OG angeschlossen wurde. Beide Adapter haben sich innerhalb kurzer Zeit gefunden und zu einem Paar verbinden lassen.

Anschließend wurde die Übertragungsgeschwindigkeit mit iperf gemessen. Die Messung wurde mehrfach wiederholt, um Ausreißer erkennen zu können. Das Ergebnis war leider sehr enttäuschend. Die durchschnittliche Übertragungsrate lag bei 31 Mbit/s. Ausreißer gab es ledigich nach unten, wo bei einigen Tests nur 7 Mbit/s übertragen wurden.

In der Folge habe ich noch weitere Messungen an anderen Steckdosen im Haus durchgeführt, kam aber nicht über eine maximale Übertragungsrate von 36 Mbit/s hinaus. Hinzu kommt die Beobachtung, dass die getesteten Adapter während einer Messung wiederholt die Verbindung zueinander verloren und Messungen wiederholt werden mussten.

Leider bestätigten sich damit Ergebnisse aus früheren Tests, so dass kein sinnvoller Einsatz dieser Technik in unserem Haus möglich scheint.

Fazit

PowerLAN verspricht die schnelle und einfache Vernetzung von netzwerkfähigen Geräten über das Stromnetz in der eigenen Wohnung bzw. im eigenen Haus. Die versprochenen Übertragungsraten von teilweise mehr als 1 Gbit/s werden dabei jedoch nicht in jedem Fall erreicht. Häufig liegen diese sogar deutlich unter den angegebenen Maximalwerten. Daher ist ein Test der Übertragungsgeschwindigkeit in jedem Fall empfehlenswert.

Bevor man jedoch mit der Messung beginnt, sollte man die eingesetzten Messmittel auf ihre Tauglichkeit und Leistungsfähigkeit hin überprüfen. Denn sonst gilt wieder: „Wer viel misst, misst viel Mist.“

Was sind die maximalen und minimalen Werte für UID und GID in den verschiedenen Linux-Distributionen?

In verschiedenen Kreisen kam wiederholt die Frage auf, aus welchem Bereich unter Linux die Werte für UID und GID stammen. Diese Frage möchte ich in diesem Beitrag beantworten.

Der maximal mögliche Wert, den eine UID oder GID annehmen kann, wird vom Typ der Variablen bestimmt, in der dieser Wert gespeichert wird. Bei den im Folgenden betrachteten Distributionen besitzen diese Integer-Variablen eine Größe von 32 Bit. Der maximal mögliche Wert für UID bzw. GID liegt in diesen Distributionen also bei 4.294.967.295. Wie die Größe dieser Variablen ermittelt werden kann, wird in der Red Hat Wissensdatenbank beschrieben.

Darüber hinaus definieren die Distributionen in der Datei /etc/login.defs einen Bereich, aus dem eine automatische Vergabe bei der Verwendung der Kommandos useradd bzw. groupadd erfolgt.

Min- und Maximal-Werte für UID und GID

Min/Max-WerteUbuntu 16.04 LTSRHEL/CentOS 7SLES 12 SP1
UID_MIN100010001000
UID_MAX600006000060000
SYS_UID_MIN100201100
SYS_UID_MAX999999499
GID_MIN100010001000
GID_MAX600006000060000
SYS_GID_MIN100201100
SYS_GID_MAX999999499
Voreingestellte Minima und Maxima für UID und GID verschiedener Distributionen

UID und GID gelten für „normale“ Benutzer, während SYS_UID und SYS_GID die Grenzen für Systembenutzer angeben.

Quellen und weiterführende Links

Wer keine Online-Anfragen wünscht, sollte das Kontaktformular schließen

Seien Sie gegrüßt. Bieten Sie auf ihrer Webseite im Bereich Kontakt auch ein Kontaktformular an? Zur allgemeinen Kontaktaufnahme oder evtl. auch zur Online-Terminvereinbarung? Versprechen Sie ihren Besuchern evtl. sogar, auf eingehende Anfragen zu reagieren?

Wenn einer dieser Punkte auf Sie zutrifft und Sie ihren Besuchern tatsächlich auf eingehende Nachrichten bzw. Terminanfragen antworten, dann haben Sie vielen Dank dafür. Sie müssen von hier ab nicht weiterlesen.

Sie wissen gar nicht, ob Sie so ein Kontaktformular auf Ihrer Webseite haben? Dann schauen Sie vielleicht mal nach, ob es dort nicht doch eines gibt. Und wenn Sie sowieso nicht vorhaben, auf Nachrichten, die Sie auf diesem Weg erreichen, zu antworten, habe ich eine Bitte. Schalten Sie das Kontaktformular ab. Bieten Sie diesen Kommunikationsweg nicht mehr an. Sie ersparen sich selbst unerwünschte Nachrichten und allen anderen Besuchern Zeit und Frust.

Warum das so ist, möchte ich Ihnen gerne erklären. Wie viele andere heute lebende Menschen gehöre ich zur Generation Y. Das bedeutet unter anderem, dass ich sehr gerne online kommuniziere, einkaufe, Medien konsumiere usw. Manche behaupten sogar, dass ich per E-Mail schneller reagiere, als bei entgangenen Anrufen zurückzurufen. Für mich hat dies einige ganz entscheidende Vorteile. Ich kann Sie kontaktieren, wann es mir passt. Dann wann ich Zeit habe.

So könnte ich z.B. einen Zahnarzttermin vereinbaren, ohne minutenlang in der Warteschleife der Praxis zu hängen. Ich könnte einfach und zeitsparend bei mehreren Fachärzten anfragen, ob sie überhaupt noch Patienten nehmen und wann ich einen Termin bekommen kann. Gleiches gilt für Handwerker, denen ich den zu vergebenen Auftrag schildern und ein Angebot anfordern könnte. Oder den Kabelnetzbetreiber, den ich um Auskunft zu bestehenden Vertragsoptionen bitten könnte.

Leider bleibt es allzu oft beim Konjunktiv. Denn oftmals sind diese Kontaktmöglichkeiten nichts weiter als schwarze Löcher. Selbst auf wiederholte Anfragen erhalte ich keine Antwort.

Also bleibt wie so oft doch wieder nur der Griff zum Telefon. Fragt man bei der Gelegenheit nach, warum man auf elektronische Anfragen keine Antwort erhält, reichen die Aussagen von „Ihre Nachricht ist nicht angekommen, dass kommt schon mal vor“ bis hin zu „Wir haben so viel zu tun, da können wir nicht auch noch auf jede Nachricht antworten.“

Und ob Sie es glauben oder nicht, ich habe Verständnis dafür. Nicht jeder gehört zur Generation Y und kann einen Computer bedienen und das Internet nutzen. Ich bin mir bewusst, dass es viele Menschen schaudert, wenn sie an den täglichen Kampf mit ihrem E-Mail-Programm denken. Und ich habe vollstes Verständnis dafür, dass jeder irgendwann Feierabend hat und dann nicht noch 1337 E-Mails beantworten möchte. In diesen Fällen wiederhole ich meine Bitte von oben:

Dann lassen Sie doch endlich die Kontaktformulare von Ihrer Webseite entfernen!

Ganz ehrlich, Sie brauchen sie nicht. Ihre Webseite wird auch ohne Kontaktformular funktionieren. Besucher erkennen sofort, dass Sie auf diesem Wege nicht erreichbar sind und verschwenden nicht ihre Zeit mit der Formulierung einer ausführlichen Anfrage.

Und wenn Sie schon dabei sind, prüfen Sie doch gleich, ob die veröffentlichten Öffnungszeiten noch korrekt sind. Dann stehe ich zukünftig nicht mehr vor verschlossenen Türen (an denen übrigens auch die falschen Öffnungszeiten stehen).

Wer viel misst, misst viel Mist

Im Falle dieses Artikels bezieht sich der Titel auf das Messen von Temperatur und relativer Luftfeuchtigkeit mit einem DHT22-Sensor (AM2302).

Im Rahmen eines kleinen Wochenend-Projekts möchte ich mit Hilfe des genannten Sensors, der Open-Source-Plattform NodeMCU V3 und einem Raspberry Pi eine Raumklimaüberwachung für unsere Wohnung basteln. Der NodeMCU V3 mit aufgesetztem ESP8266 scheint dazu gut geeignet, da er dank integriertem WLAN die aufgezeichneten Messdaten direkt an eine zentrale Instanz übertragen kann. An dieser Stelle beschreibe ich, wie ich dabei vorgegangen bin, welche Komponenten zum Einsatz kamen, wie der Prototyp funktioniert, welche Erkenntnisse ich dabei gewonnen habe und was ich damit in Zukunft anzustellen gedenke.

Vorwort zum Prototyp

Für meine Bastelei verwende ich am liebsten den DHT22-Sensor. Dieser ist günstig und liefert eine hinreichende Genauigkeit. Mir ist jedoch in der Vergangenheit aufgefallen, dass einzelne Exemplare in ihren Messwerten teils deutlich nach oben oder unten ausreißen.

Um nun herauszufinden, ob sich in der jüngsten Charge wieder ein paar Ausreißer befinden, habe ich mich für einen demokratischen Ansatz entschieden. Dabei schließe ich mehrere Sensoren an den gleichen Mikrocontroller an und messe mit ihnen am gleichen Ort. Theoretisch dürfen die Messwerte nur in dem angegebenen Toleranzbereich von maximal +/- 5% RH und +/- 0,5 °C abweichen. Mit der parallelen Anordnung von vier Sensoren kann ich erkennen, ob einer aus der Reihe tanzt.

Vorbereitung der Plattform

Als Firmware für den ESP8266 habe ich ESPEasy ausgewählt. Das Projekt verfügt über ein gut strukturiertes Wiki, welches in englischer Sprache erklärt, wie man die Firmware auf den ESP8266 installiert.

Aufbau des Prototyps

Für den Aufbau habe ich zwei kĺeine Steckbretter und ein NodeMCU V3 verwendet. Der Aufbau wird im folgenden Bild dargestellt. Da dies mein erster Versuch war, einen Aufbau zu modellieren, bitte ich um etwas Nachsicht.

dht22-on-esp8266

Aufbau des Prototypen

Es wurden Pull-Up-Widerstände mit einem Widerstand von 10k Ohm verwendet und an die GPIO-PINs 12, 13, 14 und 16 angeschlossen.

Eine Übersicht über alle zur Verfügung stehenden PINs bietet das folgende Bild:

PIN-Belegung des NodeMCU

Wurde die Schaltung wie im obigen Bild aufgebaut, verbindet man sich mit der Weboberfläche des ESPEasy und konfiguriert diesen entsprechend. Eine ausführliche Dokumentation zum Webinterface findet man unter der URL https://www.letscontrolit.com/wiki/index.php/ESP_Easy_web_interface.

In meinem Aufbau erscheinen die Sensoren nach erfolgreicher Konfiguration wie folgt unter „Devices“ im Webinterface.

Devices im Webinterface des ESPEasy

Die meisten Schritte sind intuitiv zu bearbeiten. Lediglich zur Konfiguration des Template-Strings, welcher zur Übertragung der Messwerte an einen Webserver verwendet wird, habe ich etwas länger gebraucht. Ich verwende dazu folgenden Publish-Template-String, welcher unter Tools -> Advanced -> Publish Template eingetragen wird.

import.php?name=%sysname%&task=%tskname%&valuename=%valname%&value=%value%

Das folgende Listing zeigt, wie die HTTP-GET-Anfragen beim Webserver ankommen:

192.168.x.x 192.168.x.x - [07/Jun/2017:20:44:05 +0200] "GET /import.php?name=esp8266%5fdht22%5f2&task=DHT22%2d1&valuename=Temperature&value=22.00 HTTP/1.1" 200 411 "-" "-"
192.168.x.x 192.168.x.x - [07/Jun/2017:20:44:06 +0200] "GET /import.php?name=esp8266%5fdht22%5f2&task=DHT22%2d1&valuename=Humidity&value=43.60 HTTP/1.1" 200 411 "-" "-"
192.168.x.x 192.168.x.x - [07/Jun/2017:20:44:07 +0200] "GET /import.php?name=esp8266%5fdht22%5f2&task=DHT22%2d2&valuename=Temperature&value=22.00 HTTP/1.1" 200 411 "-" "-"
192.168.x.x 192.168.x.x - [07/Jun/2017:20:44:08 +0200] "GET /import.php?name=esp8266%5fdht22%5f2&task=DHT22%2d2&valuename=Humidity&value=44.30 HTTP/1.1" 200 411 "-" "-"
192.168.x.x 192.168.x.x - [07/Jun/2017:20:44:09 +0200] "GET /import.php?name=esp8266%5fdht22%5f2&task=DHT22%2d3&valuename=Temperature&value=22.10 HTTP/1.1" 200 411 "-" "-"
192.168.x.x 192.168.x.x - [07/Jun/2017:20:44:10 +0200] "GET /import.php?name=esp8266%5fdht22%5f2&task=DHT22%2d3&valuename=Humidity&value=55.20 HTTP/1.1" 200 411 "-" "-"
192.168.x.x 192.168.x.x - [07/Jun/2017:20:44:11 +0200] "GET /import.php?name=esp8266%5fdht22%5f2&task=DHT22%2d4&valuename=Temperature&value=22.00 HTTP/1.1" 200 411 "-" "-"
192.168.x.x 192.168.x.x - [07/Jun/2017:20:44:12 +0200] "GET /import.php?name=esp8266%5fdht22%5f2&task=DHT22%2d4&valuename=Humidity&value=44.30 HTTP/1.1" 200 411 "-" "-"

Der Aufbau des Prototyps ist damit im Wesentlichen abgeschlossen.

Erstellung der import.php

In meinem Heimnetzwerk befindet sich bereits ein Raspberry Pi, auf welchem ein kleiner Webserver (lighttpd) läuft. Für diesen erstelle ich ein kleines Import-Skript, welches die Messdaten einsammelt und in eine Datei schreibt.

Für die Erstellung der Datei „import.php“ nehme ich an, dass die Ergebnisse der vier Sensoren stets in der gleichen Reihenfolge übermittelt werden. Da jeweils Temperatur und Luftfeuchtigkeit gemessen werden, überträgt der ESP8266 acht Werte pro Messintervall. Diese sollten mit einem Zeitstempel in eine Zeile einer CSV-Datei geschrieben werden. Dafür kommt aktuell das folgende Skript zum Einsatz:

switch ($_GET[„task“]) {
case „DHT22-1“:
if ($_GET[„valuename“] == ‚Temperature‘) {
$data = date(‚Y-m-d‘). „T“ . date(‚H:i:s‘, time()) . „,“ . $_GET[„value“] . „,“;
} else {
$data = $_GET[„value“] . „,“;
}
break;
case „DHT22-2“:
if ($_GET[„valuename“] == ‚Temperature‘) {
$data = $_GET[„value“] . „,“;
} else {
$data = $_GET[„value“] . „,“;
}
break;
case „DHT22-3“:
if ($_GET[„valuename“] == ‚Temperature‘) {
$data = $_GET[„value“] . „,“;
} else {
$data = $_GET[„value“] . „,“;
}
break;
case „DHT22-4“:
if ($_GET[„valuename“] == ‚Temperature‘) {
$data = $_GET[„value“] . „,“;
} else {
$data = $_GET[„value“] . „\n“;
}
break;
}

print($data);
file_put_contents(‚/var/www/dht22data.csv‘, $data, FILE_APPEND);

 

Erste Erkenntnisse

Im aktuellen Aufbau werden die Messwerte alle 5 Minuten an den Webserver übertragen. Die empfangenen Daten habe ich mit LibreOffice Calc geöffnet und etwas aufbereitet:

Erste Messergebnisse (aufbereitet)

Die Messwerte wurden auf ganze Zahlen gerundet. Es lässt sich erkennen, dass tatsächlich ein Sensor aus der Reihe tanzt. Der DHT22-3 weicht bei der Luftfeuchtigkeit um 9-11 Prozentpunkte nach oben ab. Das ist erstmal nicht weiter schlimm, jedoch gut zu wissen. Ich werde die nächste Zeit beobachten, wie sich diese Abweichung bei wechselnden Temperaturen entwickelt.

Entweder passe ich die gemessenen Werte an, indem ich in der Weboberfläche einen festen Faktor zu den gemessenen Werten hinzurechne bzw. abziehe oder ich sondere den Sensor aus, sollte die Abweichung zu stark schwanken.

Ausblick

Die nächsten Tage werde ich den Prototyp in seiner aktuellen Konfiguration weiterlaufen lassen. Anschließend beschaffe ich mir ein paar kleine Gehäuse, um jeweils einen Sensor mit einem Controller zusammen einzusetzen und in der Wohnung aufzustellen. So weiß ich in Zukunft schon vorher, ob es sich lohnt, die Wohnung zu betreten oder ich lieber gleich in den Garten gehe.

Darüber hinaus habe ich noch eine Handvoll weiterer DHT22-Sensoren. Diese werde ich ebenfalls auf einem Steckbrett anordnen und sie an einen Raspberry Pi anschließen. Ich werde bei diesen das gleiche Verfahren anwenden, um Ausreißer erkennen zu können.

RHEL 7: Wie stelle ich sicher, dass nur Pakete aus unterstützten Quellen installiert sind?

In diesem Artikel dokumentiere ich (vor allem für mich selbst), wie man ein System in einen Zustand versetzen kann, in dem ausschließlich RPM-Pakete aus Repositories (Repos) installiert sind, für die man kommerziellen Support erhält.

Dazu gehe ich kurz auf den Hintergrund der Aufgabenstellung ein, bevor ich anschließend eine mögliche Lösung beschreibe.

Die Hintergrundgeschichte

Für meine ersten Gehversuche mit Red Hat Enterprise Linux habe ich mich unter der URL „https://developers.redhat.com/“ für eine Developer Subscription registriert. Diese gestattet die unbeschränkte Nutzung zu Forschungs- und Entwicklungszwecken.

Mit der Developer Subscription erhält man Zugriff auf eine ganze Reihe von Repos, aus denen man Software installieren kann. Etliche Pakete wie z.B. sed, less, etc. sind dabei in mehreren Quellen verfügbar.

Nach einer gewissen Evaluierungszeit sollte das System produktiv genutzt werden. Da eine produktive Nutzung in der Developer Subscription ausgeschlossen ist, wurde eine RHEL Standard Subscription für das System beschafft. Diese wurde dem System über den „Subscription Manager“ hinzugefügt. Die Developer Subscription wurde im Gegenzug entfernt.

Um zu überprüfen, ob auf dem System Pakete aus anderen Repos als „rhel-7-server-rpms“ installiert waren, wurde folgendes Kommando genutzt:

# yum list installed | grep -v "rhel-7-server-rpms\|anaconda"
Loaded plugins: product-id, search-disabled-repos, subscription-manager
Installed Packages
NetworkManager-config-server.x86_64
Red_Hat_Enterprise_Linux-Release_Notes-7-en-US.noarch
libdnet.x86_64 1.12-13.1.el7 @rhel-7-server-eus-rpms
libicu.x86_64 50.1.2-15.el7 @rhel-7-server-eus-rpms
libmspack.x86_64 0.5-0.4.alpha.el7 @rhel-7-server-eus-rpms
net-tools.x86_64 2.0-0.17.20131004git.el7 @rhel-7-server-eus-rpms
sed.x86_64 4.2.2-5.el7.sjis.1 @rhel-sjis-for-rhel-7-server-eus-rpms

# yum repolist enabled
Loaded plugins: product-id, search-disabled-repos, subscription-manager
repo id repo name status
rhel-7-server-rpms/7Server/x86_64 Red Hat Enterprise Linux 7 Server (RPMs) 14,280
repolist: 14,280

Der Ausgabe ist zu entnehmen, dass fünf Pakete aus Quellen stammen, die auf dem System nicht mehr verfügbar sind. Diesen Zustand galt es zu ändern.

Die Lösung

Für die ersten vier Pakete bestand die Lösung darin, diese einfach neuzuinstallieren:

yum reinstall libdnet libicu libmspack net-tools

Bei sed stellte sich dieser Ansatz als problematisch heraus, da der Versuch das Paket neuzuinstallieren mit folgender Meldung quittiert wurde:

# yum reinstall sed
Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager
rhel-7-server-optional-rpms | 3.5 kB 00:00:00
rhel-7-server-rpms | 3.5 kB 00:00:00
rhel-server-rhscl-7-rpms | 3.5 kB 00:00:00
Installed package sed-4.2.2-5.el7.sjis.1.x86_64 (from rhel-sjis-for-rhel-7-server-eus-rpms) not available.
Error: Nothing to do

Der zweite Ansatz, das Paket erst zu entfernen und dann erneut zu installieren, scheiterte an der Überprüfung der Paket-Abhängigkeiten (Auszug der Ausgabe):

# yum remove sed
[...]
--> Finished Dependency Resolution
Error: Trying to remove "systemd", which is protected
Error: Trying to remove "yum", which is protected

Die Lösung gelang mit dem dritten Versuch. Hierbei wurde ein Downgrade auf die Paket-Version aus dem Repo „rhel-7-server-rpms“ durchgeführt:

# yum downgrade sed-4.2.2-5.el7.x86_64
Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager
Resolving Dependencies
--> Running transaction check
---> Package sed.x86_64 0:4.2.2-5.el7 will be a downgrade
---> Package sed.x86_64 0:4.2.2-5.el7.sjis.1 will be erased
--> Finished Dependency Resolution

Dependencies Resolved

===============================================================================================================================================================
Package Arch Version Repository Size
===============================================================================================================================================================
Downgrading:
sed x86_64 4.2.2-5.el7 rhel-7-server-rpms 231 k

Transaction Summary
===============================================================================================================================================================
Downgrade 1 Package

Total download size: 231 k
Is this ok [y/d/N]: y
Downloading packages:
sed-4.2.2-5.el7.x86_64.rpm | 231 kB 00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : sed-4.2.2-5.el7.x86_64 1/2
Cleanup : sed-4.2.2-5.el7.sjis.1.x86_64 2/2
Verifying : sed-4.2.2-5.el7.x86_64 1/2
Verifying : sed-4.2.2-5.el7.sjis.1.x86_64 2/2

Removed:
sed.x86_64 0:4.2.2-5.el7.sjis.1

Installed:
sed.x86_64 0:4.2.2-5.el7

Complete!
# yum list installed | grep sed
sed.x86_64 4.2.2-5.el7 @rhel-7-server-rpms

Am Ende des Listings ist zu sehen, dass sed nun aus dem Repo „rhel-7-server-rpms“ installiert wurde. Damit stammen nun alle Pakete wieder aus Quellen, die von einer Subscription mit Support abgedeckt.

Bei zukünftigen Installationen mit einer Developer Subscription werde ich jedoch von Anfang an darauf achten, dass nur die Repos verwendet werden, die auch in der RHEL Standard Subscription enthalten sind.

Verweise

vSphere PowerCLI: Snapshots nach Namen suchen und löschen

In diesem Beitrag möchte ich kurz dokumentieren, wie vSphere Snapshots mit Hilfe der PowerCLI nach Namen gesucht und gelöscht werden können.

Anwendungsfall

Beruflich betreue ich mehrere vSphere-Cluster mit einigen hundert virtuellen Maschinen (VMs). Um diese VMs zu sichern, kommt eine Image-Backup-Software zum Einsatz. Diese erstellt zum Zeitpunkt der Sicherung von jeder VM einen Snapshot, sichert die zur VM gehörenden Dateien und löscht den Snapshot anschließend wieder.

Läuft es mal nicht so gut und das Backup wird unterbrochen oder schlägt fehl, werden diese Snapshots nicht immer von allen VMs entfernt. Diese liegengebliebenen Snapshots von Hand suchen und löschen zu müssen, macht keinen Spaß. Zum Glück lässt sich diese Aufgabe automatisieren.

Alle Snapshots mit einem bestimmten Namen löschen

Mit der folgenden Befehlszeile wird der verbundene vCenter Server angewiesen, alle Snapshots, die dem spezifizierten Namensmuster entsprechen, zu löschen:

Get-VM | Get-Snapshot | Where {$_.Name -like "SNAPSHOTNAME*"} | Remove-Snapshot -Confirm:$false

Es wird dabei immer ein Snapshots nach dem anderen gelöscht. Dies kann durch Angabe des Parameters RunAsync beschleunigt werden. Es ist jedoch zu beachten, dass durch die Parallelisierung eine hohe I/O-Last im Storage erzeugt wird. Damit besteht das Risiko, den gesamten Cluster lahmzulegen.

Möchte man statt des Namens des Snapshots dessen Beschreibung verwenden, ist dies mit folgendem Befehl ebenfalls möglich:

get-vm | get-snapshot | where {$_.Description -match "Snapshot generated for backup"}| Remove-Snapshot -Confirm:$false

Quellen und weiterführende Links

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 Seafile[1. Seafile – Wikipedia]-Installation zur Folge hatte, welche ich für den Freifunk Lippe[2. Webpräsenz Freifunk Lippe] 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.