Dienstag, 31. Mai 2016

GIT Server einrichten

Im vergangen Post habe ich beschrieben, wie der Umstieg von svn zu git erfolgen kann. Ich hatte bis dahin meine Projekte in einem svn Repository gepflegt, wobei einer meiner Raspberry Pis als SVN Server fungierte. In diesem Post beschreibe ich, wie ein git Server am Beispiel des Raspberry Pis eingerichtet wird.

Dafür gibt es eine grundsätzliche Vorgehensweise, auf die ich zunächst in einem "vereinfachten" Beispiel eingehen werde. Später werde ich noch eine ausführlichere Einrichtung (mit eigenen user für den Server) beschreiben.

1. einfache Konfiguration

Zunächst muss auf dem Target git installiert werden, für die Funktion als Server reich das Paket git-core.

# server
sudo apt-get install git-core

Für das einfache Beispiel arbeiten wir unter dem standard User, am Beispiel des Raspberry Pis also dem User pi. Wie man für den Server einen eigenen User anlegt und konfiguriet, beschreibe ich im Kapitel 2.

Wir wechseln also in das Home Verzeichnis und legen uns einen Stammordner für alle Repositories und darin einen Ordner für das Projekt an. Standardmäßig sollten git Projektordner immer mit *.git benannt werden, da der Pfad auch in der späteren URL verwendet wird.

# server
cd ~
mkdir git_repositories
mkdir projectname.git

Anschließend wird in das Projektverzeichnis gewechslt und ein leeres git Repositorie angelegt.

# server
cd projectname.git
git init --bare
>>Initialisierte leeres Git-Repository in /home/pi/projectname.git/

Damit ist die Server Konfiguration schon abgeschlossen und wir wechseln auf den Entwicklungsrechner.

Wenn man bereits ein vorhandes git Repositorie hat, wechselt man in dieses und fügt den neuen Server als remote hinzu. Falls man noch kein Repositorie hat, legt man dieses zunächst an. Anschließend wird der Stand auf den neuen Server gepushed. Als Beispiel verwende ich die IP meines Servers, diese muss natürlich angepasst werden.

# client
cd projectname
git remote add pi pi@192.168.1.123:/home/pi/projectname.git
git push pi master

# push all tags and branches to server
git push --all pi

Ob die Konfiguration auf dem Entwicklungsrechner korrekt ist, kann man z.b. mittels git remote -v testen. Damit wird sowohl die push als auch die fetch URL des Servers ausgegebe.

# client
$git remote -v
pi  pi@192.168.1.123:/home/pi/projectname.git (fetch)
pi  pi@192.168.1.123:/home/pi/projectname.git (push)

Abschließend kann mit folgendem Kommando das Repositorie vom neuen Server gecloned werden.

git clone pi@192.168.1.123:/home/pi/projectname.git

2. erweiterte Konfiguration

to do

Freitag, 13. Mai 2016

SVN zu Git Migration

Bis jetzt habe ich meine Projekte in einem svn Repository gepflegt. In letzter Zeit habe ich mich aber vermehrt mit git als Mittel zur Sourcecodeverwaltung beschäftigt. Daher entwickelte sich bei mir das Interesse, meine bestehenden Projekte von svn zu git zu migirieren. Eine sehr gute Dokumentation über git bietet folgende Seite git-scm.com

An dieser Stelle beschreibe ich, wie ein svn Projekt in ein git Projekt importiert werden kann. Dazu werde ich nur die einzelnen Schritte festhalten. Eine detailierte Dokumentation kann dem Kapitel 9.2 Git and Other Systems - Migrating to Git der obigen Seite entnommen werden.

Für die Migration von svn zu git wird das Paket "git-svn" benötigt. Falls dieses noch nicht vorhanden ist, kann dieses wie folgt installiert werden.

sudo apt-get update && sudo apt-get install git-svn

Jetzt kann mittels dem Befehl git svn clone "svn-url" ein svn Repository in ein git Repository umgewandelt werden. Dazu folgende Randbedingungen:

  1. Dieser Befehl klappt nur, wenn das svn Repository aus den "standard" Verzeichnissen trunk, branches und tags besteht. Wenn davon abgewichen wird, können diese mittels der Parameter -T, -b und -t angepasst werden.
  2. Weiterhin empfielt sich der Parameter --no-metadata. Damit sehen die commit Nachrichten besser aus, da die git-svn-id nicht eingetragen wird.
  3. Evtl. ist es notwendig ein Mapping der Autoren vorzunehmen. Dazu kann der Parameter --authors-file=users.txt verwendet werden. In der users.txt sind dann alle Autoren im format svn-user = git-user aufzuführen.

Für mein Beispiel Projekt ergab sich daraus folgender Befehl:

git svn clone http://192.168.2.112:8002/svn/repo/callist -T trunk -b branch -t tags --no-metadata

Durch diesen Schritt wurde aber nur der svn trunk in den git master branch überführt. Evtl. svn tags und branches bestehen noch als unschöne remote branches.

Um die Tags des SVN Repositories in git tags umzuwandeln, müssen deren Referenzen aus dem remote kopiert werden.

cp -Rf .git/refs/remotes/tags/* .git/refs/tags/

Anschließend können diese gelöscht werden.

rm -Rf .git/refs/remotes/tags

Diesen Schritt kann man mit dem Befehl git tag kontrollieren. Damit sollten nun alle Tags des svn Repositories auch im git Repository aufgelistet werden.

Um die Referenzen der Branches zu übernehmen, werden auch diese kopiert und anschließend aus dem remote gelöscht.

cp -Rf .git/refs/remotes/* .git/refs/heads/
rm -Rf .git/refs/remotes

Um die übernommen Branches zu kontrollieren, können diese mittels git branch -av aufgelistet werden. Dabei wird auffallen, dass auch für den svn trunk ein Branch angelegt wurde. Da sich dieser mit dem master Branch doppelt, kann er gelöscht werden.

git branch -d trunk

Damit ist die Migration von svn zu git abgeschlossen.

Wenn man möchte kann das so erzeugte lokale Repository noch auf einem Server gepusht werden. Dazu muss dieser als remote hinzugefügt werden und alle branches und tags gepusht werden.

git remote add orogin user@server_ip:repo_name.git
git push origin --all
git push origin --tags

Python logging modul Beispiel

Bei Python ist auch ein recht umfangreiches Logging Modul enthalten. Hier möchte ich ein einfaches Beispiel aufführen, wie dieses verwendet werden kann. Die sehr ausführliche Dokumentation zum Thema Python und Logging kann unter folgender SeitePython Logging How to nachgelesen werden.

Das Logging Modul ist sehr mächtig und bietet eine vielzahl von Konfigurationsmöglichkeiten. Ich beschränke mich hier nur auf ein grundlegendes Beispiel. Um das Logging Modul zu verwenden, muss dieses Eingebunden werden und eine initiale Konfiguration angelegt werden.

import logging
# Festlegung des Lognames, z.b. Name der Applikation
logger = logging.getLogger('example_logger')
# Festlegung des Loglevels
logger.setLevel(logging.DEBUG)

Zwei der am häufigsten verwendeten Logging Ausgaben sind das Loggen auf die Konsole und in ein Logfile. Für diese Umsetzung muss ein entsprechender Logging Handler erzeugt und hinzugefügt werden.

# Für das Loggen auf die Konsole wird ein StreamHandler benötigt
ch = logging.StreamHandler()
# Für das Loggen in eine Datei wird wiederum ein FileHandler benötigt
fh = logging.FileHandler("example.log")

Wie bei der initialen Konfiguration bereits angegeben, unterstützt das Logging Modul verschiedene Logging Level. Diese haben hinsichtlich ihres Schweregrads folgende, aufsteigende Abstufung. - DEBUG - INFO - WARNING - ERROR - CRITICAL

Das Logging Modul bietet die Möglichkeit für jeden Logging Handler ein separates Level festzulegen. Dadurch erfolgt eine Filterung der Logs, bezüglich ihrer Ausgabe, bezogen auf das Logging Medium

# Auf der Konsole werden nur Logs mit Level INFO oder höher ausgegeben
ch.setLevel(logging.INFO)
# In das Logfile werden auch die Debug Logs geschrieben
fh.setLevel(logging.DEBUG)

Neben dem Loglevel kann auch das Logformat festgelegt werden. Für dieses Beispiel ist jeder Logeintrag wie folgt aufgebaut: "Zeitpunkt [Loglevel] Logname: Lognachricht"

formatter = logging.Formatter('%(asctime)s [%(levelname)s]: %(name)s: %(message)s')
# Die Formatierung muss noch den Handlern zugewiesen werden
ch.setFormatter(formatter)
fh.setFormatter(formatter)

Im letzten Schritt müssen die konfigurierten Logging Handler noch dem Logger hinzugefügt werden. Anschließend kann über den Loger in die Datei und auf die Konsole geloggt werden.

# add both handler to logger
logger.addHandler(ch)
logger.addHandler(fh)
#start logging, only in the logfile
logger.debug("start")

Hier noch einige Beispiele mit der zugehörigen Ausgabe:

#this will be printed on the console and to the logfile
self.logger.critical("This is a critical message")
#this will be printed on the console and to the logfile
self.logger.error("This is an error message")
#this will be printed on the console and to the logfile
self.logger.warning("This is a warning message")
#this will be printed on the console and to the logfile
self.logger.info("This is an info message")
#this will be printed only on the console
self.logger.debug("This is a debug message")
$cat example.log
2016-05-13 20:26:52,497 [DEBUG]: example_logger: start
2016-05-13 20:26:52,497 [CRITICAL]: example_logger: This is a fatal message
2016-05-13 20:26:52,497 [ERROR]: example_logger: This is an error message
2016-05-13 20:26:52,498 [WARNING]: example_logger: This is a warning message
2016-05-13 20:26:52,498 [INFO]: example_logger: This is an info message
2016-05-13 20:26:52,498 [DEBUG]: example_logger: This is a debug message

Den Code zu diesem Beispiel gibt es in meinem github Repository.

Donnerstag, 5. Mai 2016

raspberry pi als host für mehrere webseiten

Motivation

In meinem letzten Post Zusammenspiel von lighttpd und pelican habe ich beschrieben, wie eine eigene Webseite (am Beispiel meines Blogs) mit Hilfe von lighttpd vom Raspberry Pi gehostet werden kann. Wenn man sich einmal diese Mühe gemacht hat, will man evtl. auch weitere Seiten im lokalen Netz verfügbar haben. Dafür ist es aber nicht notwendig für jede Seite ein eigens Board einzurichten. Mit lighttpd kann man mehrere Seiten von einem Host zur Verfügung stellen.

Installation

Für die grundlegene Installation von lighttpd verweise ich an dieser Stelle auf meinen Post: Zusammenspiel von lighttpd und pelican

Konfiguration

Damit mit lighttpd mehrere Seiten gehosted werden können, gibt es verschiedene Möglichkeiten. Wenn man danach sucht, findet man am häufigsten das Modul mod_simple_vhost. Diese Konfiguration beruht aber auf der Grundlage, das der Server über eine Domäne (z.B. example.org) oder eine Subdomäne (mail.example.org) erreichbar ist. Dies ist für meinen Zweck zu viel Aufwand, da hierfür ein Nameserver für das eigene LAN aufgesetzt werden muss. Mir reicht es, wenn ich den Server via IP (z.b. 192.168.1.123) ansprechen kann.

Eine weitaus einfacher Möglicheit bietet daher das Modul mod_alias. Mit diesem kann für ein url-subset (z.b. /example) ein eigenes Dokumenten Root Verzeichnis hinterlegt werden. Hier mein Beispiel:

<IP>  => Zeigt auf meinem Blog, mit root-dir /var/www/html/blog
<IP>/one   => Zeigt auf eine zweite Seite, mit root-dir /var/www/html/one/pages
<IP>/two   => Zeigt auf eine dritte Seite, mit root-dir /var/www/html/two/pages

Im ersten Schritt müssen die root-Verzeichnisse angelegt werden.

mkdir /var/www/html/blog
mkdir /var/www/html/one/pages
mkdir /var/www/html/two/pages

Jetzt wird für jede Seite eine index.html (oder der entsprechende Inhalt) angelegt.

echo "Blog" >/var/www/html/blog/index.html
echo "one" >/var/www/html/one/index.html
echo "two" >/var/www/html/two/index.html

Anschließend kann die Konfiguration von lighttpd vorgenommen werden. Begonnen wird mit der Aktivierung des Moduls mod_alias. Hierfür muss das Modul in die Liste der aktvierten Servermodule eingetragen werden. Dazu muss die lighttpd.conf wie folgt bearbietet werden.

$sudo  vi /etc/lighttpd/lighttpd.conf 
...
# "mod_alias" unter server.modules eintragen
server.modules = (
        "mod_access",
        "mod_alias",
        "mod_compress",
        "mod_redirect",
        "mod_status",
)
...

Die weitere Konfiguration kann auch in dieser Datei erfolgen. Zuerst muss man sich dafür entscheiden, welche Seite bei einfacher Eingabe der IP als Default angezeigt werden soll. Ich habe mich für meinen Blog entschieden. Dafür muss folgende Zeile eingetragen/angepasst werden.

server.document-root        = "/var/www/html/blog"

Für die beiden weiteren Seiten, müssen die folgenden Zeilen ergänzt werden. Diese leiten bei Eingabe des IP/url-subset an das entsprechende Root Verzeichnis der Seite.

alias.url = ( "/one" => "/var/www/html/one/pages" )
alias.url += ( "/two" => "/var/www/html/two/pages" )

Abschließend wird die Datei gespeichert und mit folgenden Kommando die Syntax geprüft.

$lighttpd -t -f /etc/lighttpd/lighttpd.conf
Syntax OK

Ist alls OK, kann lighttpd neugestartet werden, damit die neue Konfiguration aktiv wird.

sudo service lighttpd restart

Jetzt kann man im Browser die drei Seiten durch Eingabe der IP und dem url-subset aufrufen.

<IP>     => blog Seite als default
<IP>\one => Seite one
<IP>\two => Seite two