Quote of the week
Mann, ist die VNC-Verbindung langsam. Alles Scheiße außer Putty!
- R.B. am Donnerstag
Mann, ist die VNC-Verbindung langsam. Alles Scheiße außer Putty!
- R.B. am Donnerstag
Eine schöne und einfache Methode, um mit Python Verzeichnisse und/oder Dateien zu kopieren habe ich bei stackoverflow gefunden:
import shutil, errno def copyanything(src, dst): try: shutil.copytree(src, dst) except OSError as exc: # python >2.5 if exc.errno == errno.ENOTDIR: shutil.copy(src, dst) else: raise
Das ist hilfreich, wenn vor dem Kopieren nicht bekannt ist was genau kopiert wird. Im ersten Kommentar zu dieser Antwort wird vorgeschlagen mit
os.path.isdir(src)
einfach vorher zu prüfen, ob es sich um ein Verzeichnis handelt, aber die obige Lösung ist der pythonic way dieses Problem zu lösen.
Das Update von meiner Radiant Seiten mit der Version 0.8.1 (gem) zu 0.9.1 (gem) war unkompliziert. Das Backup-Skript anwerfen, das die Seiten und die zugehörigen Datenbanken sichert und dann mit
gem update radiant
die neuste Version des gems holen. Dann für jede Seite
cd <meine_seite>
rake radiant:update
RAILS_ENV=production rake db:migrate
durchführen und schon schnuckelt alles wieder.
Radiant ist ein meiner Meinung nach sehr schönes CMS (=Content Management System), weil es von Haus aus erst einmal sehr wenige Einstellungsmöglichkeiten gibt und man recht schnell loslegen kann. Andererseits sollte man zumindest in etwa wissen was man tut und mindestens Grundkenntnisse in (x)html und css haben. Dann hat man aber wie gesagt ein schönes CMS, in das man prima seine xhtml/css-Templates packen kann.
Leider ist die Dokumentation von Radiant nicht wirklich ausführlich und nicht immer hilfreich. Vor allem bei den ersten Schritten hat sie mir kaum weiter geholfen. Auch sonst habe ich nicht viel gefunden. Die wichtigsten Links sind hier und hier gesammelt. Deshalb will ich hier einmal zusammenfassen, wie ich mir das Arbeiten mit Radiant etwas leichter gemacht habe.
Ruby und die Rubygems hatte ich sowieso schon installiert, also konnte ich direkt mit
sudo gem install radiant
Radiant installieren. Ein neues Projekt kann man dann einfach mit
radiant mein_projekt -d sqlite3
anlegen. Sqlite3 als Datenbank reicht für ein Testprojekt aus. Die nächsten Schritte bekommt man direkt angezeit.
cd mein_projekt
rake production db:bootstrap
Die erste Frage mit y beantworten und dann Daten für den Administrator eingeben. Für das DB-Template wählt man 1 - Empty aus. Die drei anderen DB-Templates sind Beispielseiten, die zeigen, was man mit Radiant machen kann. Deshalb habe ich mir ein Verzeichnis radiant_demos angelegt und dort die Schritte von oben für alle drei Templates wiederholt. Die drei Seiten sind prima, um zu sehen wie die grundlegenden Schritte in Radiant aussehen sollen und dienen also sowohl als Spickzettel als auch als gutes Beispiel.
Um nicht immer den Server stoppen und neu starten zu müssen, um zwischen den Seiten hin und her zu schalten starte ich sie auf verschiedenen Ports:
mein_projekt/script/server -e production
radiant_demos/roaster/script/server -e production -p 3001
radiant_demos/simple_blog/script/server -e production -p 3002
radiant_demos/styled_blog/script/server -e production -p 3003
So kann ich im Browser unter http://localhost:3000 bis http://localhost:3003 meine vier Seiten finden.
Wenn das letzte Backup schon deutlich zu alt kommt für den entsprechenden Server die ideale Zeit zum kaputt gehen. Vorzugsweise durch einen Plattencrash oder ähnlichen Spaß, so dass sich das Linux des Servers nur noch im Recovery Modus starten lässt. Services hochfahren oder das längst fällige Backup anzustarten sind keine Optionen mehr. Was tun?
Ganz pauschal und einfach lässt sich das natürlich nicht beantworten. Alles wird man z.B. bei einem Plattencrash nicht wieder bekommen, aber vielleicht genug, um den Server wieder aufsetzen zu können. Dafür gibt es natürlich viele Möglichkeiten. dd_rescue zum Beispiel. Hier gibt es eine Anleitung für Debian basierte Systeme.
Eine etwas simplere (und vielleicht auch naivere) Herangehensweise die oft auch zum Ziel führt versuche ich hier kurz zu beschreiben. Es wird sicher nicht alles wiederhergestellt werden können, ich übernehme keine Garantie dafür, dass überhaupt etwas wiederhergestellt wird. Aber ich denke, dass es je nach Situation einen Versuch wert sein kann.
Auch im Rescue System lassen sich die beschädigten Platten evtl. noch mounten. Wenn das klappt versucht man erstmal selektiv alle wichtigen Dateien zu sichern. Natürlich nicht einfach mit einem cp in ein anderes Verzeichnis auf der kaputten Platte, sondern am besten per rsync und ssh auf einen anderen Rechner:
rsync -av /mnt/pfad user@meinNeuerServer:/sicherungspfad
Damit lassen sich z.B. die Dateien aus /var/www/meineSeite oder /var/www/meinBlog sichern (für den rsync Aufruf dem Pfad natürlich ein /mnt voranstellen). Mit etwas Glück bekommt man so den Teil seiner Seite, der nicht in einer Datenbank liegt schnell wieder. Evtl. einfach die Dateien aus dem neusten Update drüber bügeln und dieser Teil der Seite ist schnell wieder hergestellt. Ohne die Daten aus der Datenbank ist das natürlich aber noch nicht viel Wert, sondern erspart höchstens etwas Arbeit, denn drupal oder einen WordPress Blog hat man auch von Hand schnell wieder aufgesetzt.
Also, wie bekomme ich die Daten aus meiner MySQL Datenbank wieder, wenn ich mysql nicht mehr starten kann? Eine Antwort habe ich u.a. hier gefunden. Die Dateien einer MySQL Datenbank liegen im Verzeichnis /var/lib/mysql/<db_name>. Wenn auf dem neuen Server schon mysql installiert ist, kann man direkt wieder ein rsync Kommando absetzen:
rsync -av /mnt/var/lib/mysql/<db_name> user@meinServer:/var/lib/mysql/
Mit etwas Glück wird vieles oder alles kopiert. Kaputte Sektoren auf der Platte bedeuten ja nicht unweigerlich, dass die gesamte Platte nicht mehr gelesen werden kann.
Auf dem neuen Server müssen noch ein paar kleine Schritte getan werden, bevor man testen kann, ob es wirklich funktioniert hat:
1. Die Besitzer der Datenbank Dateien anpassen:
chown -R mysql:mysql /var/lib/mysql/<dbname>
2. Mit der Datenbank verbinden und die Tabellen einzeln checken und ggf. reparieren und den alten Datenbank Benutzer wieder anlegen:
mysql -u user -p
USE <db_name>; SHOW TABLES;
Für jede Tabelle in der Liste check table ausführen:
CHECK TABLE <tabellenname>;
Hiervon bekommt man entweder OK oder please run repair table `<tabellenname>` als Antwort. Im zweiten Fall führt man das auch aus:
repair TABLE `<tabellenname>`;
Am Schluss noch den alten Benutzer wieder anlegen, bevor man den Browser auf den neuen Server loslässt und schaut, ob die Seite wieder läuft:
GRANT ALL privileges ON <tabellenname>.* TO 'benutzer'@'localhost' IDENTIFIED BY 'tollesPasswort' WITH GRANT OPTION;
Mit etwas Glück funktioniert die Seite danach wieder wie gewohnt auf dem neuen Server. Wenn das alles nichts geholfen hat bleibt der Versuch mit dd_rescue oder eben man packt das letzte (wenn auch evtl. alte) Backup auf den neuen Server und kann zumindest für einige der Inhalte den google Cache bemühen.
Eine tolle Sache habe ich gefunden, während ich eigentlich etwas ganz anderes gesucht habe. Mit rvm lassen sich verschiedene Ruby Versionen und für jede Version unterschiedliche Gemsets verwalten und das einfach und unkompliziert. Die Installation ist einfach und schnell gemacht.
Wenn man sich eigentlich nicht viel macht und nur ein paar einfache Kommandos wissen möchte, um zwischen seinen Gemsets und Ruby-Versionen zu wechseln kann man sich entweder durch die Doku auf der rvm Seite lesen oder sich diesen Artikel bei stackoverflow anschauen, der eine prima Übersicht zum schnellen und unkomplizierten Einstieg bietet. rvm kann noch mehr als das dort Beschriebene, aber schon alleine das fand ich so toll, dass ich erst viel später auf den Rest gestoßen bin.
Sollte es notwendig sein mich damit ausführlicher zu beschäftigen, werde ich natürlich davon berichten. Bis jetzt war es für mich genug für Spree, Radiant und ein paar andere Sachen, die ich ausprobiert habe ein eigenes Gemset zu haben und die empfohlene Ruby Version verwenden zu können. Und das mit nicht mehr als zwei kleinen Kommandos.
Wäre toll, wenn es sowas auch für andere Sprachen gäbe, z.B. um Python und Django in verschiedenen Versionen zur Verfügung zu haben ohne zu viel zu basteln. Mal sehen, was es da gibt…
Eigentlich wollte ich mir nur schnell ein Perl-Skript schreiben, das mir auf einem Linux Rechner mehrere Skripte startet und zwar jedes in seinem eigenen Screen. Das Perl-Skript war auch nicht das Problem, mit screen hatte ich da schon mehr zu kämpfen.
Aber ich war erfolgreich, hier kurz meine Erkenntnisse und Ergebnisse. Der Einfachheit halber verwendet ich den Befehl top, da man bei top sehr gut die Aktivität sieht und es sich nicht sofort wieder beendet. Meine Tests mit ls waren genau deshalb wenig hilfreich. Zuerst habe ich die man-page überfolgen und ein wenig im Netz gesucht und dann eine Weile zumprobiert. Die erste Idee, alles in einem einzigen Aufruf zu machen hat mich nach einigen missglückten Versuchen hierhin gebracht:
screen -d -m -S test top
test ist hier der Name meines Screens und top wie gesagt der Befehl, den ich ausführen möchte. Das klappt soweit ganz gut, mit screen -r test kann ich mich mit dem screen verbinden und sehe das laufende top. Der Nachteil dabei ist, dass sich der screen wieder beendet, wenn ich top mit q beende. Das mag in vielen Fällen nicht schlimm sein, ich wollte den screen aber hinterher behalten, da ich ja eigentlich mehr machen wollte als nur top. Also der nächste Versuch, dieses Mal in zwei Schritten:
screen -d -m -S test screen -S test -X stuff top
Was mache ich hier? Der erste Befehl erstellt einen screen mit Namen test an den ich mich mit screen -r test verbinden könnte. Das war einfach, im zweiten Befehl steckt etwas mehr drin und es muss auch noch etwas mehr dazu.
screen -S test -X stuff top versucht top an den screen test zu schicken und auszuführen. stuff übernimmt sozusagen das Einfügen des Befehls. Das funktioniert allerdings nur, wenn ich mich vorher schon von Hand mit dem screen verbunden habe, also verbinden, detachen und dann das zweite Kommando ausführen. Wenn ich mich jetzt wieder an den screen attache, sehe ich top im Prompt stehen und könnte es mit Return starten.
Also habe ich zwei Probleme:
Die Lösung dafür sieht folgendermaßen aus:
screen -S test -X -p0 stuff "top $(echo -ne '\r')"
Problem 1 löse ich mit -p0, das sagt dem screen Kommando, dass ich meinen Befehl an das Window 0 im screen schicken will. Problem 2 löst der etwas kryptisch aussehende Ausdruck am Ende, der im Prinzip ein Return an den Befehl anhängt, dass er auch gleich ausgeführt wird. Wenn ich jetzt in den screen reinschaue sehe ich ein laufendes top. Problem gelöst, damit läuft mein Perl-Skript ganz prima, einfach nur die Kommandos zusammenbasteln und jedes an seinen eigenen Screen senden.
Hallo mal wieder, ist ja schon eine Weile her, dass sich hier was sichtbares getan hat.
Ein paar Notizen zur Verwendung von Perls XML:LibXML möchte ich hier mal veröffentlichen, damit sie mir nicht mehr verloren gehen. Schon etwas älter, aber trotzdem nützlich ist die LibXML Quick Reference Card von Andrew Ford.
Und hier noch ein paar Code-Schnipsel mit kurzen Erklärungen dazu.
Zuerst ein Test, ob alles richtig eingerichtet ist:
use XML::LibXML; my $parser = XML::LibXML->new(); my $xmlfile = "./test.xml"; my $dom = $parser->parse_file( $xmlfile ); print $dom->toString();
Das sollte wieder das eingelesene xml-File ausgeben. Damit lässt sich schnell testen, ob alles richtig geladen wird und richtig eingelesen ist.
Ein Ausschnitt aus dem xml-File hilft vielleicht zu verstehen, wonach ich hier suche.
<Component name="Server"> <InstType name="install"> <Command name="win32"> $INSTPATH\install.exe </Command> <Command name="linux"> $INSTPATH/install </Command> </InstType> <InstType name="update"> <Command name="linux"> $INSTPATH/update </Command> <Command name="win32"> $INSTPATH\update.exe </Command> </InstType> </Component>
Für verschiedene Komponenten sind je nach Installationstyp Kommandos im xml-File hinterlegt. Jetzt möchte ich in meinem Perl-Skript mit Hilfe von LibXML das Ganze parsen:
use XML::LibXML; my $parser = XML::LibXML->new(); my $xmlfile = "./components.xml"; my $dom = $parser->parse_file( $xmlfile ); @cmd_list = (); my $xpath = '/scenarios/scenario[@name='."'".$SCENARIO."'".']/installation'; foreach my $scen_node ( $scen_dom->findnodes( $xpath ) ){ my $cfg_xpath = '/Component[@name='."'".$scen_node->findvalue( './component' )."'".']/InstType[@name='."'".$scen_node->findvalue( './type' )."'".']/Command[@name='."'".$os."'".']'; foreach my $cmd ( $cfg_dom->findnodes( $cfg_xpath ) ){ push( @cmd_list, { 'type' => $scen_node->findvalue( './type' ), 'component' => $scen_node->findvalue( './component' ), 'cmd' => $cmd->textContent() } ); } }
Um das foreach bin ich nicht rumgekommen, selbst wenn ich weiß, dass ich immer nur einen Treffer habe. Man bekommt eben ein Ergebnis vom Typ Nodelist und nicht vom Typ Node.
Ein xml-File gegen ein dtd-File validieren. Gefunden habe ich das hier, vielen Dank dafür.
sub validate_xml_file{ my $xml_file = shift; my $dtd_file = ( $xml_file =~ /(.+)\.xml/ ) ? "$1.dtd" : undef;; my $val = 0; if ( -e $dtd_file ) { my $dtd = XML::LibXML::Dtd->new( "", $dtd_file ); my $xml = XML::LibXML->new; $xml->keep_blanks(0); my $tree = $xml->parse_file( $xml_file ); $val = $tree->validate( $dtd ); } return( $val ); }
Noch ein paar Links zu Seiten, die ich mal kurz überflogen habe und die so aussahen, als sollte ich das mal genauer lesen:
Über Hilfe wie man das alles evtl. etwas eleganter machen kann und Links zu verständlichen Tutorials oder Beispielen würde ich mich freuen.
Wie verhindere ich das anmelden von Spam-Benutzern und sonstigen Benutzern, die durch automatische Skripte angemeldet werden?
Habe in letzter Zeit mal ein paar Plugins getestet, die mir das erleichtern sollten, allerdings ohne großen Erfolg. Jetzt habe ich erstmal die Benutzeranmeldung deaktiviert, alle dahingehenden Plugins auch und die Benutzerliste geleert, um mich erstmal richtig in das Thema einzulesen und nicht einfach weiter zu probieren. Sollte ich wider erwarten jemanden rausgeworfen haben, der sich hier von Hand angemeldet hat, tut es mir leid. Bald werde ich wieder die Anmeldung aktivieren und dann auch wieder ein paar Artikel schreiben, damit es sich auch lohnt, sich hier anzumelden.
Ansonsten wünsche ich allen einen guten Start ins Jahr 2011 und bis bald.
/home/git/repositories/ ein Verzeichnis, bspw. neuesprojekt, anlegendummy.txt anlegengit initgit add *git commit -a -m "initial"git-clone --bare neuesprojekt neuesprojekt.gitchown -R git:git neuesprojekt*git clone git@meinserver.net:repositories/neuesprojektgit add *<*code> und git commit -a -m "beschreibung"git pushEin Server ist natürlich bei git nicht zwingend notwendig, ist ja verteiltes System, aber ich wollte trotzdem einen haben. Das ist wahrscheinlich nicht vollständig und funktioniert unter Umständen nur auf meinem Server, bei dem ich inzwischen vergessen habe, was da alles konfiguriert und installiert wurde. git sollte aber sowohl auf dem Server als auch lokal vorhanden sein, das ist schonmal ein guter Anfang.
Ich werde versuchen das bei Gelegenheit mal etwas ausführlicher zu beschreiben. Spätestens, wenn ein neuer Linux-Server aufgesetzt werden muss.
Ein paar Links, die ich noch ungelesen in meinen Bookmarks hatte und nicht verlieren wollte:
Aber da gibt’s sicherlich noch viel mehr…