Skip to content

Python nur für mich...

Sehnsüchtig warte ich auf das nächste Debian Release. Eigentlich ist Testing schon für die meisten Anwendungen stabil genug. Aber es warten noch ca 200 Bugs, die als Releasekritisch eingestuft sind. Somit ist noch ein bischen Zeit, indem ich die Wartezeit von Squeeze zu Wheezy überbrücken muss. In diesem Falle bin ich kürzlich über das Python Modul fabric gestolpert. Echt interessant und es verlangte nach Tests. Allerdings ist die in Squeeze enthaltene Version doch recht betagt...

Also mal schauen, ob ich nicht neuere Python Versionen und Module installiert bekomme, ohne dabei alles in die Systempfade installieren zu müssen. Python bietet dort interessante Möglichkeiten. Mit dem Programm pip lassen sich module bequem nachinstallieren. Aber auch dort ist die Squeeze Version so alt, dass es noch nicht die Möglichkeit gibt die Module in das Homeverzeichnis eines einzelnen Users zu installieren. pip selbst gibt an ein Replacement für easy_install aus den Setuptools zu sein. Und easy_install ist in der bei Squeeze mitgelieferten Version in der Lage ins User-Verzeichnis zu installieren. Viola. Installationspfad gefunden...

Als erstes installiert man eine aktuelle Version von pip. Wird easy_install mit der Option --user aufgerufen, erfolgt die Installation in das Verzeichnis $HOME/.local des aktuellen Users.

easy_install --user pip

Ist die Installation erfolgreich durchgelaufen, befindet sich im Verzeichnis $HOME/.local/bin ein Executeable namens pip in der neuen Version.

Ist pip installiert, gibt es nur noch eines zu tun. Der Pfad für die Suche nach den Binarys sollte angepasst werden:

PATH=$HOME/.local/bin:$PATH
export PATH


Den Schnipsel packt man am besten in die .bash_profile, damit es nach dem nächsten Login auch noch gültig ist. Einen Funktionstest kann man in der Shell ganz einfach mit which python durchführen. Es muss python in $HOME/.local/bin/ angezeigt werden.

Damit ist das erste Zwischenziel erreicht und ich kann mit
pip install fabric
die aktuelle Version von fabric installieren.

Kür


Zusätzlich wird jetzt noch das Python Packet virtualenv installiert. Virtualenv ermöglicht es einen python-Interpreter mit allen Abhängigkeiten in ein extra Verzeichnis zu installieren. Die Dateien aus /usr/ und Co werden bei dieser Version nicht angefasst. Es ist also auch möglich eine neue Version eines Moduls sauber zu installieren, ohne die OS-gelieferte Version zu deinstallieren oder zu überschreiben.

easy_install --user virtualenv

virtualenv ~/mypython

Virtualenv erwartet als Parameter den Pfad zur neuen Python-Umgebung. Beim Aufruf wird der Python-Interpreter und einige Basis-Programme und Librarys von Python in das angegebene Verzeichnis übertragen.

Möchte ich diese Installation anstatt jener in $HOME/.local/ nutzen, muss ich entsprechend der o.g. Anleitung die PATH-Umgebungsvariable anpassen.

noch ein kleiner Tip...


Ein Python-Script beginnt so wie viele andere Scripte unter Unix auch mit der Angabe des Interpreters. Meistens steht dort #!/usr/bin/python in der ersten Zeile und das Script wird mit dem angegebenen Interpreter ausgeführt.

Trägt man statt dessen in den Scripten

#!/usr/bin/env python

ein, sucht das Programm env nach einem Interpreter mit dem Namen python in den Verzeichnissen, die in $PATH angegeben sind. Welcher Interpreter verwendet wird, hängt jetzt also von der Reihenfolge der Verzeichnisse in $PATH ab. Dies funktioniert nach gleichem Prinzip im Übrigen auch mit perl, php...

Happy coding.

Die Sache mit dem Kernelupdate

Schon seit vielen Jahren baue ich nur noch Linux-Kernels selber, wenn es wegen Treibern o.ä. gar nicht anders geht. Ansonsten bleibt immer der Kernel aus der Distribution drauf. Das sichert auch ein anständiges Update mit dem Packetmanager des Systems.

Wie immer werfe ich mein Update also mit aptitude safe-upgrade an und lasse den Kernel mit updaten. Geht immer Problemfrei. Aber heute hatte ich mal wieder so einen Mist-die-Installation-ist-schon-älter-Effekt. Das ist beim Debian absolut nichts schlimmes. Aber zu erkennen ist es daran, dass ich der /boot-Partiton nur 100MB gegönnt habe. Das hat früher immer ausgereicht. Aber neue Kernels werden auch immer größer. Und so kam es, dass beim Update die Initramdisk für den 3.2er Kernel keinen Platz mehr fang.


update-initramfs: Generating /boot/initrd.img-3.2.0-4-686-pae

gzip: stdout: No space left on device
cpio: Fehler beim Schreiben: Datenübergabe unterbrochen (broken pipe)
E: mkinitramfs failure cpio 1 gzip 1
update-initramfs: failed for /boot/initrd.img-3.2.0-4-686-pae with 1.
dpkg: Fehler beim Bearbeiten von initramfs-tools (--configure):
Unterprozess installiertes post-installation-Skript gab den Fehlerwert 1 zurück
Fehler traten auf beim Bearbeiten von:
initramfs-tools


Ein df -h zeigte auch gleich an, dass die Partition voll ist. Hätte ich so rebootet wäre das System nicht mehr hochgekommen. Was bei einem Webserver ohne Zugriff auf eine lokale Konsole fatal ist.

Gelöst bekommt man das Problem ganz einfach. Einmal ein dpkg -l linux-image-* abschicken und ich kann sehen, welche Kernels noch alle Installiert sind. Mit der Ausgabe rollt man das Problem jetzt von hinten auf und deinstalliert die alten Kernels einfach in aufsteigender Versionsnummer bis nur noch die notwendigen Kernels vorhanden sind. Das sieht dann so aus: aptitude remove linux-image-2.6-686 linux-image-2.6.32-5-686 linux-image-3.0.0-1-686-pae linux-image-3.1.0-1-686-pae.

Beim Deinstallieren des Kernels werden auch die Init-Ramdisks, die beim installieren eines Kernels erstellt werden, wieder mit entfernt. Ich hab also danach wieder genug Platz frei.

Das schöne daran ist, dass der Debian-Packetmanager auch gleich mitbekommt, dass der aktuelle Kernel nicht vollständig installiert ist. Nachdem die alten Kernels deinstalliert sind, baut der also automatisch die fehlende Initramdisk nach und das System ist wieder bootfähig.

Der Ablauf ist absolut nichts schwieriges. Aber er taucht bei mir so selten auf, dass ich nicht vor einem Update auf die Größe der /boot Partition schaue. Also dachte ich mir, ich präg mir das jetzt mal durch Bloggen ein...

@hilfe

Es gibt so Tage, an denen will man direkt nach dem ersten Kontakt mit Windows gleich wieder Feierabend machen. Ich hab mich ja bereits an vieles Gewöhnt, seit dem ich wieder so viel Fenstern muss, aber die Implementierung, die mir eben unter gekommen ist, verlangt nach einem lauten Aufschrei.

Linux-Admins wird es bekannt vorkommen. Auch unter Windows gibt es den Befehl at zum einrichten von Tasks. Im Gegensatz zur Linux Version kann man dort aber auch mit dem Parameter /EVERY wiederkehrende Tasks mit anlegen. Als Werte können dann entweder die Tage im Monat als Zahl angegeben werden oder die Wochentage mit einem Kürzel. Also z.B. "m" für Monday. Aufpassen muss man nur beim Thursday. Denn der Beginnt mit dem selben Buchstaben wie der Tuesday. Also verwendet man für den Thursday halt th. Alles logisch. Vor allem, wenn man sich die Hilfe anschaut.

Auf meinem Testsystem führt also folgender Aufruf zum gewünschten Ergebnis und führt jeden Montag (m=monday) einen Reboot aus...

at localhost 08:00 /EVERY:m "c:Scriptssystem_reboot.cmd"


Also alles Verifiziert. Reboot klappt. Ab damit auf meine Produktionskiste. Pustekuchen. Nichts geht. Befehl wird abgelehnt. Nochmal nachschauen. Vertippt? Nein. Moment. Produktionskiste hat jemand in Deutsch installiert. Mir schwant böses. Bei meiner Vermutung fange ich schonmal mit einem leichten Kopfschüttelt an. Das kann doch nicht wirklich stimmen. Oder?

Also kurz die Hilfe über "Hilfe und Support" im Startmenü aufgerufen und Peng:


Fehlermeldung beim Öffnen der Hilfe

Wie bitte? Willste mir vera...? Ja. Will er. :-(


Aber was soll's. Also Reverse Engeneering. Befehl kurz abgewandelt und ein "/EVERY:mo" draus gemacht und zack. Funktioniert.

Die Knalltüten haben allen ernstes die Aufrufparameter Sprachabhängig gemacht. Ich kann wohl froh sein, dass der Parameter noch EVERY und nicht WIEDERHOLUNG heisst. Liebe Leuts in Redmond. Wie soll sowas denn in gemischten Umgebungen zum Scripten taugen???

Nach so einem kompetenten Hilfefenster und dem hochgradig durchdachten Befehlsaufruf so direkt aufeinander brauch ich jetzt erstmal ein Käffchen...

Das leidige mit Konfigdateien für PHP und Zugangsdaten für die DB

Immer wieder stolpere ich auf Servern oder in diversen Sourcode-Versionsverwaltungen wie git oder svn über hart eincodierte Zugangsdaten zu Datenbankservern oder sogar zu FTP-Servern. Auch in meinen ersten Projekten hat es sowas gegeben. Aber da hab ich noch keine Versionsverwaltung benutzt. Im Laufe der Jahre mit PHP-Projekten habe ich mir eine Aufteilung der Konfigdateien angewöhnt, die meinen Sicherheitsanforderungen stand hält und gleichzeitig die Passwörter aus irgendwelchen Repositorys raushält. Dies möchte ich hier mal als Anregung für die diversen Frischling-Programierer oder als Denkanstoß für einige alte Hasen vorstellen.

Der Grundgedanke dabei ist folgender. Ich benötige immer wieder Konfigurationseinstellungen, die sich je nach Projekt unterscheiden. Aber es gibt auch immer wieder Files, die ich in jedem Projekt verwende und die auch bei jedem Script eingebunden werden.

Als erstes gibt es da die global.php. Dieser File befindet sich im Web-Hauptverzeichnis des Projekts. Die Datei enthält Definitionen von Konstanten und Includes von PHP-Files, die immer benötigt werden.


<?php
// global.php
define('WEB_ROOT',dirname(__FILE__));

require_once(WEB_ROOT . '/lib/class.DieIchImmerBrauche.php');
require_once(WEB_ROOT . '/lib/class.Database.php');
require_once(WEB_ROOT . '/config.php');
?>


Als erstes definiere ich WEB_ROOT. Damit haben alle anderen Scripte unabhängig davon in welchem Verzeichnis sie sich befinden eine Konstante mit dem Root-Verzeichnis des Projekts. Da __FILE__ sich immer auf das Script "global.php" bezieht, kommt auch der richtige Pfad dabei raus, wenn ich die global.php z.B. aus einem Unterverzeichnis als "../../global.php" includieren muss. Wie zu sehen ist, kann ich diese Datei getrost in ein neues Projekt kopieren, ohne etwas zu ändern.

In der untersten Zeile sieht man den nächsten Step. Es wird eine Datei config.php eingebunden. In jedem Projekt benötige ich Einstellungen, die es in einem anderen nicht gibt. Dies könnte z.B. der Pfad zu einem Datenverzeichnis sein.


<?php
// config.php

$MYSQL_HOST = "127.0.0.1";
$MYSQL_USER = "demo";
$MYSQL_PASS = "demo";
$MYSQL_NAME = "demo";

$DATA_DIR = WEB_ROOT . '/../data/';

$DEFAULT_IMAGE_WIDTH = 170;

if( is_file(WEB_ROOT . '/.htconfig.php') ) {
include_once(WEB_ROOT . '/.htconfig.php');
}

define('CONFIG_OK',1)
?>



In der Datei config.php habe ich ALLE Konfigurationseinstellungen für mein Projekt hinterlegt, die ich benötige. Aber wichtig dabei ist, das es sich dabei um DEFAULT-Einstellungen handelt. Vor allem die DB-Zugangsdaten sind dort ganz deutlich nur ein Beispiel, welches aber funktionieren würde wenn man sich auf so unsichere Zugangsdaten einlassen würde. Mit DATA_DIR definiere ich z.B. eine Defaultkonfig für ein Datenverzeichnis ausserhalb des Projektverzeichnisses. Einige Files will man nunmal nicht im DOCUMENT_ROOT des Webservers liegen haben. Mit DEFAULT_IMAGE_WIDTH ist auch noch ein Beispiel enthalten, welches ich benötige, um Vorschaubilder zu skallieren. Dadurch, dass hier alle notwendigen Konfigvariablen initalisiert werden, hab ich später keinen Ärger mit Fehlermeldungen, weil irgend ein Wert nicht gesetzt ist.

Die Magie der Datei ist die if-Anweisung. Es wird gecheckt, ob sich eine Datei namens .htconfig.php im WEB_ROOT befinden. Wenn dies der Fall ist, wird sie importiert. Der Dateiname ist ganz bewust gewählt. Dateien mit einem "." am Anfang sind unter Linux versteckte Dateien. Aber am wichtigsten ist mir dabei, dass in einem Apache-Webserver per Default Dateien, die mit ".ht" anfangen, nicht ausgeliefert werden. Dies ist ein Schutzmechanismuss, der auch die ".htaccess" Dateien vor dem Download schützt. PHP und Apache haben bei einem unvorsichtigen Admin oder auch unter bestimmten Fehlerbildern leider die Angewohnheit die Scriptdateien ungeparst auszuliefern. Ist der Webserver also nicht sauber konfiguriert, würde ein Angreifer die Zugangsdaten im Klartext sehen. Dies Problem stellt sich nicht, wenn man die Zugangsdaten in der ".htconfig.php" versteckt.


<?php
// .htconfig.php

$MYSQL_USER = "appuser";
$MYSQL_PASS = "realpassword";
$MYSQL_NAME = "appdb";
?>


In der ".htconfig.php" können nun alle Variablen aus der "config.php" mit den richtigen Werten überschrieben werden. Werte, die ich nicht benötige, können einfach übersprungen werden.

Um den Bogen zu git und Subversion wieder zu schliessen, sei jetzt noch erwähnt, dass die Datei ".htconfig.php" nicht mit in die Versionsverwaltung übertragen werden. Bei git steht sie dazu einfach in der Datei ".gitignore" und bei Subversion in der ".svnignore".

Als Goodie kommt dabei auch noch heraus, dass ich eine neue Softwareversion jederzeit im Webverzeichnis entpacken kann. Da in diesen Archiven die ".htconfig.php" auch nicht enthalten ist, wird auch meine Konfig nicht überschrieben.

So. Und wer bis hierhin aufgepasst hat, wird sich jetzt evtl. noch über die Konstante CONFIG_OK wundern. Dies ist ein weiterer Sicherheitsmechanismuss für die Scripte. Habe ich in einer PHP-Datei nur eine Klasse definiert, stört es mich nicht wenn diese Datei von einem Browser aufgerufen wird. Aber es gibt auch Dateien, die nicht ohne bestimmte Vorraussetzungen aufgerufen werden dürfen. Diese schützte ich einfach direkt am dateianfang wie folgt...


<?php
// eine Datei die nicht vom Browser aufgerufen werden soll...

if( ! defined('CONFIG_OK') ) {
die('Du kommst hier nicht rein!');
}

[...]
?>

Der neue Trend: Barfuss laufen

Meinen letzten Sommerurlaub anno 2011 habe ich 300km mit Barfussschuhen absolviert. Auch beim Sport trage ich immer häufiger Barfussschuhwerk. In den letzten Wochen tauchen die Barfussschuhe immer häufiger in den Onlinemedien auf. Deswegen hier mal ein Link zu einem Artikel mit ein paar Hinweisen zum Barfusslaufen...

Der neue Trend: Barfuss laufen

cronjob