Ich wollte nur [...] und dann ist das Universum explodiert.

Projects
Books
Archive
About









    Permalink
  1. Explain | Shell-Kommandos visualisiert erklären

    Neulich bin ich über das github Profil von Peter Hofmann gestolpert. Darin befand sich ein Projekt, welches ich sehr interessant fand.

    Explain versucht Shell Kommandos zu erklären und zu visualisieren. Gerade für Blogs oder andere Dokumentationen finde ich das mehr als sinnvoll. Es erstellt aus einem simpel gestricktem Markdown File eine ASCII-Art ähnliche Erläuterung des Kommandos. Beispielsweise:

    $ ./explain.py command.markdown
    find . -iname '*.png' -exec echo '<br><img src="{}">' \; > gallery.html
    \__/ | \___________/  \________/ \___________________/ |  \___________/
      |  |       |             |               |           |        |
      |  |       |             |               |           |        \- Ausgeben nach
      |  |       |             |               |           |           gallery.html
      |  |       |             |               |           |
      |  |       |             |               |           \- find Syntax Ende.
      |  |       |             |               |
      |  |       |             |               \- mit folgendem Inhalt aus.
      |  |       |             |
      |  |       |             \- und führe echo
      |  |       |
      |  |       \- alle Dateien die mit .png enden
      |  |
      |  \- im aktuellen Verzeichnis
      |
      \- Finde (via find)

    (PlainText: http://zwetschge.org/paste/015)

    Die Syntax des Files das zur Deklaration der Ausgabe dient:

    find . -iname '*.png' -exec echo '<br><img src="{}">' \; > gallery.html
    ---- ! -------------  ---------- --------------------- ! -------------
    
    Finde (via find)
    
    im aktuellen Verzeichnis
    
    alle Dateien die mit .png enden
    
    und führe echo
    
    mit folgendem Inhalt aus.
    
    find Syntax Ende.
    
    Ausgeben nach gallery.html

    Die Trennzeichen  sind via Parameter austauschbar und auch ansonsten tut das kleine Python Script seinen Job hervorragend. Sollte demnächst mal wieder ein Kommando erläutert werden müssen, werde ich definitiv darauf zurückgreifen. Weitere Beispiele auch unter:

    [1] http://www.uninformativ.de/?section=news&ndo=single&newsid=118
    [2] http://github.com/vain/explain


  2. Permalink
  3. Gitosis | Zweischneidigkeit des Auth-Verfahrens

    Ein Nachtrag und zugleich ein ganz besonders unschöner Zustand kam mir gestern unter die Finger. Gitosis benutzt bekanntermaßen SSH-Public-Keys zum authentifizieren der User, die in Git-Repositories arbeiten dürfen. Dieser Austausch zwischen Reporitory und Arbeitskopie passiert ebenfalls über SSH-Port 22. Die Benutzer, die sich dort anmelden, dürfen allerdings keinen direkten SSH-Zugriff bekommen. Soweit die Theorie.

    Wenn man seinen Public-Key also Gitosis zur automatischen Authentifizierung vorwirft, wird man in das System der Git-Benutzer eingespeißt.

    cp id_rsa.pub ~/gitosis/keydir/user@host.pub
    git add keydir/*
    git commit -a -m "user hinzugefügt"
    git push

    Bei erneuter Anmeldung an das System passiert folgendes:

    $ ssh user@gitserver.domain.com
    PTY allocation request failed on channel 0
    ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment.
    Connection to git closed.

    Ich darf mich also nicht mehr einloggen. Bin ich normaler Benutzer, der wirklich nur mit git arbeiten darf, ist das auch gut so. Denn so wird die Sicherheit des Systems gewahrt. Bin ich allerdings Administrator des git-Remote-Servers sieht das anders aus. Ich habe ab diesem Zeitpunkt keine Möglichkeit mehr mein System (auf gewohntem Wege) zu pflegen.

    Die Verbose-Ausgabe von ssh lässt darauf schließen was passiert:

    $ ssh -v user@gitserver.domain.com
    debug1: Authentications that can continue: publickey,password
    debug1: Next authentication method: publickey
    debug1: Trying private key: /home/user/.ssh/identity
    debug1: Offering public key: /home/user/.ssh/id_rsa
    debug1: Remote: Forced command: gitosis-serve user@host
    debug1: Remote: Port forwarding disabled.
    debug1: Remote: X11 forwarding disabled.
    debug1: Remote: Agent forwarding disabled.
    debug1: Remote: Pty allocation disabled.
    debug1: Server accepts key: pkalg ssh-rsa blen 277
    debug1: read PEM private key done: type RSA
    debug1: Remote: Forced command: gitosis-serve user@host
    debug1: Remote: Port forwarding disabled.
    debug1: Remote: X11 forwarding disabled.
    debug1: Remote: Agent forwarding disabled.
    debug1: Remote: Pty allocation disabled.
    debug1: Authentication succeeded (publickey).
    PTY allocation request failed on channel 0
    ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment.
    debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
    debug1: client_input_channel_req: channel 0 rtype eow@openssh.com reply 0
    debug1: channel 0: free: client-session, nchannels 1
    Connection to git closed.

    Die Authentifizierung mit meinen Public-Key klappt zwar, aber ich werde in eine gitosis-serve ssh-session gezwungen und damit bleibt mir der ssh-zugang ins System verwehrt. Nicht mit dieser Situation rechnend, starrte ich völlig perplex auf mein Terminal und die Reverse-Engeneering-Abteilung in meinem Kopf ratterte vor sich hin. Was passiert da und warum passiert das? Und vor allem: Wie komme ich jetzt wieder auf den Server?

    Solve it!

    1. Public-Key Auth deaktivieren
    Ohne PubKey Auth, wird der ssh-daemon nicht erkennen, das er mir eine git-serve session geben müsste. Dem lokalen ssh-client beizubringen sich nicht mit dem Public-Key am entfernten System anzumelden, wäre also eine Lösung (aber keine Schöne). Folgende Konfiguration führt dazu.
    $ vi ~/.ssh/config
    Host git
    HostName gitserver.domain.com
    User root
    pubkeyauthentication no

    2. Different User
    Die Alternative zu dieser dauerhaften Veränderung ist (wenn vorhanden) einen anderen Benutzer zu verwenden um sich ins System einzuloggen und erst anschließend zu root zu werden.

    3. gitosis-serve zurechtstutzen
    Nachdem der Zugriff auf das System  wiederhergestellt ist, gehts zum Bugfix (gitosis-serve). gitosis muss diesen Umstand in irgendeiner ssh-config erzwingen. Ich verstehe nicht ganz warum, aber gitosis schrieb mir diese Änderungen in /root/.ssh/authorized_keys.

    command="gitosis-serve user@host",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AABBB3NzaC1yc2EAAAABIwAAAQEAyjwZCinCmB4oJJZ4RuiSqrQmiYE8+C+JKpTmiPkdfojUbiB9gm3BOhsYAdu99vP7yDOaIqg9e2dk/4HGm+P8obUR7lVrinMf5NvoRkOa8EfGdPJRz4ABOGRDte454bwestyWlvLhnKyWd+a9lU07siDJg5b1NbitIXkXa76V+lGMrqkixaDC6meZQEjZlxnVMpgzC5wyEQy2cVwUnX+Swiw68gsHsMYKBNsiVgNQ7nY8fa5lhV13E6L2aYAIorVpudS1bTiQfvfXCpVtJkJVSNPP6RzUtuSSErhsqOn1o2QtVjWhH5J/Y0D1b4eeEAgmdhq7554kQupJ9LgRww== user@host

    Dieser Eintrag ist für das Verhalten verantwortlich. Auskommentieren oder entfernen aller Parameter bis ssh-rsa fixt das Problem . Happy Committing.


  4. Permalink
  5. Git | Dateien wiederherstellen

    Versehentlich gelöschte Dateien recovern. Schön wenn einem dann klar wird, warum man ein VCS benutzt. In der Annahme das wahrscheinlich mehr als genug (genug == >3) Blogs oder HowTo’s diese Thematik bereits behandeln, erstelle ich trotzdem kurz einen Post, wie sich Dateien mit Git zurückholen lassen.

    Datei ging gerade eben verloren
    aus aktuellem HEAD wiederherstellen:
    $ git checkout HEAD -- verloren.txt

    Datei hat vor gewisser Zeit einmal existiert
    Aus vorher gegangenem Commit, Branch oder Tag. Feststellen, wo das File noch existiert haben könnte:
    $ git log --oneline
    5aadc10 formatierte Ausgabe
    88e22fb Aufräumaktion
    746f92c bugfix #1234
    ee8a1da initial commit

    Vorletzter Commit 88e22fb betitelt mit “Aufräumaktion” lässt stark darauf schließen, dass hier etwas verloren gegangen sein könnte. Checkout lässt sich eigentlich mit so ziemlich allem füttern, was ein Object ist und anhand eines SHA1 Hashwertes identifizieren lässt. Gewählt wird der Commit vor der Aufräumaktion.

    git checkout 746f92c -- verloren.txt

    Nachdem die Datei nun wieder im aktuellen Working-Directory liegt:

    via git-add hinzufügen
    git add verloren.txt

    und Commit absetzen.
    git commit -a -m "Ich werde ab jetzt besser aufpassen"


  6. Permalink
  7. Git | Dotfiles des Home-Dirs verwalten

    Permanent an verschiedenen Workstations zu sitzen hat Nachteile. Heimrechner(Xubuntu), Arbeits-PC(Xubuntu), Macbook und im blödsten Fall noch (private) Server. An all diesen Maschinen entwickelt man Vorlieben, bestimmte Software zu bedienen, entsprechend anzupassen oder zu konfigurieren. Es müssen nicht mal elementare Sachen sein. Selbst nicht vorhandene triviale Kleinigkeiten wie zum Beispiel Anpassungen der .dircolors oder .bashrc bzw. .bash_aliases sind manchmal extrem nervig.

    “Warum funktioniert mein Alias hier eigent…..ah. Falscher Host :/ “

    Das brauche ich hier warscheinlich niemandem weiter erläutern ;)

    Grundsätzlich bemühte ich mich einen kleinen Satz ausgewählter .dotfiles meiner Home-Verzeichnisse auf neue Systeme zu kopieren bzw zu aktualiseren. Aber bei einer Änderung >4 Hosts neu umkopieren? Oder Änderungen sogar per Hand separat ausführen? Jedenfalls entwickelt mit der Zeit jeder, der auf diese Problemstellung trifft, seinen eigenen Weg alle Dotfiles synchron zu halten. Hier ist nun der (seit neuestem) Meinige.

    Ich benutze ein Git-Repository. In diesem Repo befinden sich alle Dotfiles die ich im alltäglichen Gebrauch benötige. Das sieht ungefähr so aus:

    dotfiles/
    |-- .bashrc
    |-- coming-home.bash
    |-- .csshrc
    |-- .dircolors
    |-- .dmrc
    |-- .git/
    |-- .gitconfig
    `-- .vimrc

    (Aus Gründen der Lesbarkeit gekürzt)

    Alle Änderungen, die für die Configs anstehen, kann ich nun hier tätigen. Füge neue Aliase hinzu, ändere meine Editor einstellungen für Vim oder ähnliches. Für die automatische Einrichtung habe ich “coming-home.bash” geschrieben. Das Script filtert automatisch alle Verzeichnisse(., .., .git) und Files (z.B. das Script selbst) die nicht ins $HOME-Verzeichnis gehören und kopiert alles was übrig bleibt in das Home-Dir des aktuellen Benutzers.

    #!/bin/bash
    # get dotfiles
    dotfiles=$(ls -la | grep -v ^d | awk '{print $8}'| grep -v ^coming-home.bash$ )
    mode=${1:-normal}
    
    for x in $dotfiles; do
        # fishing errors
        if [ ! -e $x ] ; then echo "error reading files" ; exit 1 ; fi
        # keep old .bashrc
        if [ $x = ".bashrc" ]; then
            if [ ! -e $HOME/.bashrc_old ]; then
                cp $HOME/.bashrc $HOME/.bashrc_old
            fi
        fi
        # forced hook
        if [ $mode = "--hook" ]; then echo "hook: copying $x" ; /bin/cp -r $x $HOME/ ; fi
        # standard run
        if [ $mode != "--hook" ]; then /bin/cp -i $x $HOME/ ; fi
    done

    Git bietet weiterhin noch schöne Möglichkeiten, Operationen bei Änderungen automatisch ausführen zu lassen. Hooks. Ein post-commit-Hook führt das Skript jetzt nach jeder eingespeicherten Änderung automatisch aus.

    .git/hooks/post-commit:

    #!/bin/bash
    $GIT_DIR/../coming-home.bash --hook

    Anwendungsbeispiel:

    $ git commit -a -m "added aliases and changed colors in vimrc"
    hook: copying .bashrc
    hook: copying .csshrc
    hook: copying .dircolors
    hook: copying .dmrc
    hook: copying .gitconfig
    hook: copying .vimrc

    So kann ich jetzt Änderungen der Dotfiles im Git-Repo durchführen und habe diese gleich darauf im Home-Verzeichnis. Dieses Repo existiert (über einen Git-Server verwaltet) auf jedem meiner Hosts. Um im Fallbeispiel zu bleiben: Gehe ich morgen in die Arbeit, aktualisiere ich das (auch dort vorhandene) Repo und führe coming-home.bash aus.

    By the Way: An dieser Stelle habe ich auch über Automatisierung nachgedacht. Git-Hooks gibt es für die verschiedensten Situationen:

    Pre-Commit (vor speichern einer Änderung)
    Post-Update (Nach dem pushen auf den Server)
    usw.

    Für eine Situation darf es diese Automatisierung aber nicht geben. Nämlich nach dem post-clone (unmittelbar nach dem Herunterladen eines Repos). Automatische Skripte die nach dem Herunterladen ausgeführt werden könnten große Schäden anrichten, wenn man so drüber nachdenkt.


  8. Permalink
  9. Bash | NerdTool Config for MacOSX

    GeekTool und NerdTool für MacOSX sind schöne Programme, welche Ausgaben von Bash-Scripten auf den Desktop ausgeben und ständig aktualiseren. Kein Geheimnis und nichts Neues.
    Das Netz ist voll von schönen Spielereien für diese Tools. Hier mein Setup. (Benutze Nerdtool, Script ist aber unabhängig von der Software)

    Bash-Script: http://gist.github.com/525385

    ESC=$(printf "\e")
    echo "$ESC[34;47mDATE$ESC[0m"
    date
    echo ""
    echo "$ESC[34;47mUPTIME$ESC[0m"
    uptime
    echo ""
    echo "$ESC[34;47mSTATUS$ESC[0m"
    top -l1 -u -o cpu -S | head -n 12
    echo ""
    echo "$ESC[34;47mEstablished$ESC[0m"
    lsof -i -n | grep -i established | awk '{print $1" "$8" "$9 }' | head -n 18
    echo ""
    echo "$ESC[34;47mListen$ESC[0m"
    lsof -i -n | grep -i listen | awk '{print $1" "$8" "$9 }' | head -n 18 

    Besonderheit hierbei: Der Escape-Character muss so _zwingend_ wie beschrieben eingesetzt werden. Normale Ausgabe wird nicht entsprechend wahrgenommen. Er ist nötig um die Farbtöne innerhalb des Scripts zu managen ;)


  10. Permalink
  11. Gitosis | Debugging, Undokumentiertes und Konfiguration

    Aktuell setze ich mich mit Gitosis auseinander. Ja, auseinander setzen ist gut ausgedrückt. Dieses widerspenstige, (standardmäßig) wenig gesprächige und nur oberflächlich dokumentierte Stück Software sträubt sich vehement gegen den tieferen Einsatz und komplexeren Ordnerhierarchien.

    Also im Klartext: Ich finde Gitosis super. Der Ansatz ist gut. Definierbare Rechte und Gruppenorganisation für Git-Repositories. Im Web findet man unzählige How-To’s die eine Standardinstallation wirklich gut und übersichtlich dokumentieren bzw. dazu anleiten. Speziellere Anpassungen und kleinere Grauzonen hingegen leider gar nicht.

    Um den Überblick über kleinere Mängel zu behalten und auch zu dokumentieren:

    (1) post-update – Hook-Problematik

    Die Funktionsweise von Gitosis ist eigentlich denkbar simpel. Konfigurationsdatei syntaxgerecht anpassen und innerhalb des admin-repos committen+pushen. Ist die neue Config gepusht und der Benutzer bzw. das neue Repo nicht ansprechbar, verbringt man lange Zeit damit, Configs und Pubkeys (siehe 2) zu kontrollieren und erneut zu initialisieren. An dieser Stelle begegnet einem schon das erste Problem, welches Kenntnis über die Funktionsweise von Gitosis voraussetzt und hervorragend schlecht dokumentiert ist.
    ERROR:gitosis.serve.main:Repository read access denied fatal: The remote end hung up unexpectedly
    Nach dem das Master-Repo die gepushte Version von Gitosis erhält, führt es einen sogenannten Hook aus. Dieser Hook ist ein Skript (bzw. ein Symlink dazu) welches die neue Konfiguration der Authentifizierungsstelle von Gitosis einließt. Der erste Fehler der (wirklich häufig) passiert ist, dass dieses Skript schlicht weg einfach nicht ausführbar ist. Das lässt sich natürlich sehr einfach durch

    chmod 755 /home/git/repositories/gitosis-admin.git/hooks/post-update

    lösen. Aber der knackende Punkt stellt (wie ich finde) die fehlende Meldung dieses Fehlers dar. Gitosis teilt einem einfach nicht mit, dass der Hook fehlschlug und die getätigten Änderungen komplett für die Katz waren.

    (2) Pub-Key-Format

    Ein weiteres undefiniertes Loch der Konfiguration ist das Format, in dem der PublicKeys im conf-File angegeben werden muss.

    Abgelegte Keys in gitosis-admin.git/keydir/ müssen mit .pub enden. Sonst werden diese nicht als Keys erkannt. Das ist das kleinere Übel. Die, für mich etwas unklare, Dokumentation darüber findet sich in den verschiedensten Varianten. Wie soll der PublicKey in der gitosis.conf hinterlegt werden?

    “Wer wird Millionär”-mäßig kann ich jetzt nach dem Trial-and-Error-Verfahren auflösen. Die endlosen Variationen von Filenamen und Config-Aufruf, die ich testen musste, damit ich mich anmelden durfte, haben sich also gelohnt.

    ( ) Name des Key-Files user@host.pub ( ) Im File hinterlegtes Suffix user@host
    (X) FQDN user@host.domain.com ( ) Nur User zB. jdoe wie dokumentiert

    (3) Gitosis, sprich mit mir.

    Ein weniger behütetes Geheimnis, ist die Gesprächigkeit von Gitosis. Im Konfigurationsfile lässt sich das LogLevel deklarieren.
    [gitosis]
    loglevel = DEBUG
    gitweb = no
    git-daemon = no

    Siehe da, Informationen!

    DEBUG:gitosis.serve.main:Got command "git-receive-pack 'repo1'"
    DEBUG:gitosis.access.haveAccess:Access check for 'user@domain.com' as 'writable' on 'repo1'...
    DEBUG:gitosis.group.getMembership:found 'user@domain.com' in 'domain.com'
    DEBUG:gitosis.access.haveAccess:Access ok for 'user@domain.com' as 'writable' on 'repo1'
    DEBUG:gitosis.access.haveAccess:Using prefix 'repositories' for 'repo1'
    Initialized empty Git repository in /home/git/repositories/repo1.git/
    DEBUG:gitosis.gitdaemon:Global default is 'deny'
    DEBUG:gitosis.gitdaemon:Walking '.', seeing ['repo1', 'repo2', 'repo3', 'gitosis-admin.git']
    DEBUG:gitosis.gitdaemon:Deny 'gitosis-admin'
    DEBUG:gitosis.gitdaemon:Walking 'repo1', seeing ['justatest.git']
    DEBUG:gitosis.gitdaemon:Deny 'repo1/justatest'
    DEBUG:gitosis.serve.main:Serving git-receive-pack 'repositories/repo1.git'

    Diese Infos werden nun zu fast jeder Gelegenheit ausgegeben. Pushen lokal, Authentifizieren per Remote usw. Für weitere Administration mit Gitosis unabdingbar.

    (4) Subdirectories handhaben

    Angenommen ich habe oder möchte eine Ordnerstruktur meiner Projekte die nicht alle in repositories/ liegen. Dieser kleine total untriviale Umstand, lässt sich einfach nirgends nachlesen. Um das Ganze zu verdeutlichen, habe ich kurz eine kleine Umgebung angelegt und mit tree -L 2 ausgegeben:

    `-- repositories
        |-- subdir1
        |   |-- repo1.git
        |   |-- repo2.git
        |   `-- repo3.git
        |-- subdir2
        |   `-- test.git
        `-- subdir3

    Angelege und initalisierte Repos werden zwar in der DEBUG-Ausgabe von Gitosis wargenommen (siehe 3.), aber einfach übergangen. Stattdessen wird ein neues Repo in repositories/ angelegt. Zumindest, wenn man der Konfiguration folgt, wie sie in 95% der Fällen im Netz zu finden ist. Als Faustregel für Unterordner gilt also: Zwingend jeden(!) Pfad mit Angabe des Subdirs angeben.
    Remote add:
    git remote add origin git@gitserver.org:subdir1/repo2.git
    gitosis.conf:
    [group subrepo]
    members = user@host.com
    writable = subdir1/repo2.git

    Es klingt logisch. Aber ohne Dokumentation, ist es hart herauszubekommen.

    Letztlich möchte ich kurz noch erwähnen, dass dieser Post keinerlei Vorwurf, Flame oder Sh!t-Storm gegen Gitosis darstellen soll. Gitosis ist ein wunderbarer Ansatz einer Benutzerverwaltung für Git-Remotes. Allerdings abenteuerlich bei nicht alltäglicher Nutzung. In diesem Sinne. Happy committing.