Archive for the ‘Perl’ Category

h1

RSPerl in Ubuntu installieren

16. März 2010

Zusammenfassung

RSPerl erlaubt die Interaktion zwischen Perl und R. Mich hätte vor allem interessiert, R-Funktionen von Perl aus zu verwenden. Das geht irgendwie, dann aber doch auch nicht so super – kurz: Ich verwende es zur zur Zeit nicht, sondern erzeuge mit print FH eine Datei (ein R-Skript), dass ich dann direkt in R ausführe. Trotzdem im folgenden die Vorgangsweise …

Die Schritte

Die in Ubuntu Desktop 9.10 vorhandene R-Installation ist als shared-library kompiliert. Das ist schon einmal gut. Dann braucht man aber noch eine lib installieren:

$ sudo apt-get install libperl-dev

Ab dann lässt sich RSPerl wie dolumentiert installieren:

$ R CMD INSTALL  --configure-args='--with-in-perl' Desktop/RSPerl

(Voraussgesetzt man hat das tar zuvor auf dem Desktop ausgepackt).

http://www.omegahat.org/RSPerl/RFromPerl.html

Das heisst aber noch nicht, dass man R von Perl aus damit erreicht …

Nacharbeiten

$ ./hello_R.pl

Can’t load ‚/home/ubuntu/R/i486-pc-linux-gnu-library/2.9/RSPerl/perl/i486-linux-gnu-thread-multi/auto/R/R.so‘ for module R: libPerlConverter.so: cannot open shared object file: No such file or directory at /usr/lib/perl/5.10/DynaLoader.pm line 196.

at ./hello_R.pl line 7

Compilation failed in require at ./hello_R.pl line 7.

BEGIN failed–compilation aborted at ./hello_R.pl line 7.

Das lässt sich dann mit Umgebungsvariablen unterbinden:

$ export PERL_MODULES="`perl -s modules.pl -modules | sed s/modperl//`"

http://tolstoy.newcastle.edu.au/R/help/03b/7997.html

Letztendlich sollten diese mit export gesetzt sein:

PERL5LIB="/home/ubuntu/R/i486-pc-linux-gnu-library/2.9/RSPerl/perl"
PERL_MODULES="Gtk2 Locale::gettext Gnome2 Cairo LibAppArmor HTML::Parser Sub::Name Glib Compress::Bzip2 Pango UUID Net::DBus Term::ReadKey XML::Parser::Expat Text::CharWidth Text::Iconv IO PerlIO::scalar PerlIO::encoding PerlIO::via SDBM_File Data::Dumper Opcode Fcntl DB_File I18N::Langinfo POSIX IPC::SysV Sys::Syslog Sys::Hostname re Cwd GDBM_File threads ODBM_File attrs Compress::Raw::Zlib Time::HiRes Time::Piece Filter::Util::Call Hash::Util Math::BigInt::FastCalc MIME::Base64 NDBM_File Encode Digest::SHA Digest::MD5 Devel::PPPort Devel::DProf Devel::Peek List::Util File::Glob Storable Socket Unicode::Normalize Text::Soundex "
LD_LIBRARY_PATH="/home/ubuntu/R/i486-pc-linux-gnu-library/2.9/RSPerl/libs:/usr/lib/R/lib"

Doch auch mit diesen Tipps mag R sich nicht von Perl aus aufrufen lassen. Ich denke man muss da andere Wege beschreiten. Zum Beispiel R-Scripts über das system-Komando aufrufen …

$ R -f hello.r --slave; open Rplots.pdf

Unschön, aber es geht.

Wie es dann doch noch lief …

Ok, wenn man den Code der Module patched (da sind grauslige pod-Fehler drin) und auf die Verwendung des eigentlich empfohlenen use RReferences verzichtet, kann man R von Perl aus aufrufen. Sehr vertrauenserweckend ist das aber nicht – schade.

Hier noch das hello_R.pl:

#!/usr/bin/perl -w
use strict;
use warnings;
use lib '/home/ubuntu/R/i486-pc-linux-gnu-library/2.9/RSPerl/perl/i486-linux-gnu-thread-multi';
use R;
#use RReferences;
&R::initR('--silent');
my $x = R::sum((1,2,3));
print $x . "\n";
Advertisements
h1

Perl-Skript in Windows EXE umwandeln

4. März 2010

Voraussetzung ist eine Windows-Maschine – kann auch virtuell sein. Bei ist das ein XP gewesen.

Download und Installation von Strawberry Perl http://strawberryperl.com/, Datei http://strawberry-perl.googlecode.com/files/strawberry-perl-5.10.1.1.msi

In Start->Programme die CPAN-Shell öffnen

cpan> install Bundle::libwin32
cpan> install PAR::Packer

Tipp: Hier gab es einen Bug und einer der Tests meldet dass PAR::Filter::PodStrip nicht gefunden werden kann. Der Workaround dazu ist hier:

http://www.nntp.perl.org/group/perl.par/2009/12/msg4278.html

und besteht im Wesentlichen darin, ein Verzeichnis anzulegen und ein pm dorthin zu kopieren.)

Auf der Commandline geht's dann weiter:
c:>pp -o hello.exe hello.pl

Das war’s – es seit denn, in hello.pl sind irgendwelche nicht-Standard Module in use … doch das wäre dann eine andere Geschichte.

h1

Foldings für pod und HERE-Documents in TextMate

23. Juni 2009

Um die mitunter längeren HERE-Dokumente sowie die Dokumentationen zwischen =pod und =cut in TextMate einklappen zu können, muss man dessen Voreinstellungen ein wenig ergänzen:

Im Bundle-Editor die Language-Grammar für Perl öffnen und die Regex für foldingStartMarker und foldingStopMarker ergänzen:

foldingStartMarker = '(/\*|(\{|\[|\()\s*$|=pod|<<\s+"\s*END_HERE")';
foldingStopMarker = '(\*/|^\s*(\}|\]|\)|=cut|\s*END_HERE))';

Damit die Foldmarker dann auch zu sehen sind, muss man sich an die folgenden Konventionen halten:

1. POD-Abschnitte immer mit =pod einleitenund =cut beenden (letzteres wird von Perl ohnedies verlangt).

2. Here-Dkumente immer mit END_HERE terminieren.

Und falls man die Rechtschreibkontrolle auch in den PODs haben will, lese man bei der glücklichen Giraffe nach

http://happygiraffe.net/blog/2006/06/22/spellchecking-pod-with-textmate/

(Allerdings stimmt der Scopeselektor dort nicht, dieser lautet richtig comment.block.documentation.perl )

h1

Debugging Nagios Plugins

9. Juni 2009

Heute war Debugging-Tag für die NetApp-Plugins für Nagios. Am meisten Probleme bereitete mir mein Ehrgeiz sie im ePN (Embedded Perlinterpreter for Nagios) laufen zu lassen. Bei einer Kundeninstallation wurden die Performancedaten nicht mehr verarbeitet, wenn das Script im ePN läuft – ein Fehler den ich bisher nicht nachvollziehen konnte, ich tippe hier auf eine fehlenden Kennzeichnung  (#nagios: -epn) im performance-Parser. Aber wer weiss …

Der andere Fehler waren einige Scripts, die sich im Nagios mit „Service check did not exit properly“ meldeten, während sie auf der Commandline problemlos liefen. Zunächst einmal drehte ich das Debugging im Nagios auf, indem ich in der nagios.cfg diese Werte setzte:

debug_level=16
debug_verbosity=1
debug_file=/usr/local/nagios/var/nagios.debug

Somit bekam ich dan schon alle Infos frei Haus geliefert, um die Fehler einzugrenzen. Z.B.
Embedded Perl failed to compile /usr/local/nagios/libexec/check_netapp_hardware.pl, compile error **ePN failed to compile /usr/local/nagios/libexec/check_netapp_hardware.pl: „Variable „$object“ will not stay shared at (eval 3969) line 240,“ at /usr/local/nagios/bin/p1.pl line 248.
– skipping plugin

Bei der Nachsicht in dem Plugin entdeckte ich, dass in einer Subroutine auf die mit my im Hauptprogramm definierte Variable (eben jene $object) zugegriffen wurde, was nicht 100%-ig sauber ist. Nach einer Änderung auf local our $object; lief das Plugin durch, bis zum nächsten Fehler, der dann sinngemäß gleich zu beheben war.

Anschliessend bekam ich dann noch die Meldung Check of service ‚CPU-Utilization‘ on host ’simbig‘ could not be performed due to a fork() error: ‚Cannot allocate memory‘! bzw. etwas ähnliches mit „too many open files“ was sich aber durch einen Neustart von Nagios beheben ließ.

Interessant auch, dass es schon ein Reihe von Wrapper-Scripts für Plugins gibt; die Folgenden habe ich gefunden aber sie für diese Debugging-Session dann gar nicht benötigt:

http://www.nagios.org/faqs/viewfaq.php?faq_id=379

http://www.waggy.at/nagios/capture_plugin.htm

h1

Nagios-Plugins für NetApp: Usage und Beispiele online

20. Februar 2009

Ich habe heute die Seite mit den Nagios-Plugins für NetApp-Filer wesentlich erweitert und übsichtlicher gestaltet. Die Daten dazu werden per Perlscript drirekt aus dem git gezogen und sind somit leicht und präzise aktulell zu halten.

Um die Beispiele und Usage unabhängig vom Browser und der Fenstergröße auf einen Blick erfassbar zu machen, war es wichtig, dass keine unerwünschten Zeilenumbrüche gemacht werden. Dabei hat sich das via regex eingesetzte <nobr>-Attribut als sehr hilfreich erwiesen. Die subroutine lautet:

sub nobr {
    # hält die Bereiche der Parameter (-H host, --help, ...) zusammen
    s/\[?\-+\w+[\ = \]]\S*/<nobr>$&<\/nobr>/g;
}

Link http://ingo.lantschner.name/NetappNagiosPlugins.html

h1

Mehrsprachige Perlscripte

30. Juni 2008

Ein Perlscript, wie z.B. ein Plugin für Nagios zu schreiben, das in mehreren Sprachen seine Meldungen ausgibt, ist an sich einfach. Nur die Doku dazu ist eher mager und zu allererst steht man vor dem Problem, welches Modul man denn dafür am besten nehmen soll. Ich entschied mich dann für Locale::TextDomain – eine high-level Schnittstelle zu anderen Modulen.

Folgend ein kleines Beispiel:

#!/usr/bin/perl -w
use strict;
use warnings;
use lib "/opt/local/lib/perl5/site_perl/5.8.8";  # plattformspezifische Zeile
use Locale::TextDomain "en"; #  "./LocaleXData";
## einfaches Beispiel
my $translated = __"Hallo Welt!";
print "$translated\n";
## Anhängen eines Zeilenumbruchs (der zu übersetzende String muss in Klammern!)
print __("Mir geht's gut.") . "\n";
# Schön ist, dass man auch Umlaute verwenden kann -
# bei der Erstellung der po-Datei mit xgettext
# --out-format=UTF-8 angeben!
print __("Täglicher Unsinn mit scharfem ß.") . "\n";
## Variablen können auch übersetzt werden
my $msg = "Hallo Welt!";
print __$msg;
print "\n";
my $world = "Welt!";
print __"Hallo $world";
print "\n";

Dieses Script gibt folgende Ausgabe aus, wenn man ein paar Vorbereitungen getroffen hat:

$ export LANG=de_AT
$ ./world2.pl
Hallo Welt!
Mir geht's gut.
Täglicher Unsinn mit scharfem ß.
Hallo Welt!
Hallo Welt!

So und nun schalten wir auf English um:

$ export LANG=en_US
$ ./world2.pl
Hello World!
Mir geht's gut.
Daily nonsens with non-ASCII
Hello World!
Hello World!

Es wurden also die Texte „Hallo Welt!“ und „Täglicher Unsinn …“ übersetzt – letzterer etwas eigenwillig. Für „Mir geht’s gut.“ gabe s keine vor bereitet Übersetzung – daher wurde der deutsche Originaltext ausgegeben.

Die nötigen Vorarbeiten für dieses kleine „Wunder“ waren der Reihe nach:

  1. Installation von Locale::Textdomain mit cpan
  2. Anlegen eines Unterverzeichnisses LocaleData im Arbeitsverzeichnis des Scripts. Heisst das Verzeichnis anders, oder liegt es nicht in einem der @INC-Pfade muss es dediziert angegeben werden:
  3. use Locale::TextDomain "en",  "./mylocales";
  4. Export der zu übersetzenden Strings mit xgettext in ein po-File
  5. Übersetzeung dieser Strings (mit einem Editor) – der Text „Mir geht’s gut“ wurde dabei ausgelassen.
  6. Umwandlung des po in ein mo-File (binär) mittels msgfmt. Dieses ist exakt mit diesem Namen und Pfad LocaleData/<locale_name>/LC_MESSAGES/<localename>.mo abzulegen. Der locale-Name kommt also sowohl im Verzeichnis unterhalb von LocaleData als auch im Namen der Datei vor! Es kann allerdings auch en für en_US usw. verwendet werden.
  7. Im Script dann das Locale referenzieren. (Will man mehrere refrerenzieren, muss man das mit einer if-Abfrage machen.)

ABER: So ganz komplett ist die Sache nicht, denn vor allem die Mischung aus Fixtext und Variablen kann man man so nicht sauber übersetzen. Wie das nun geht sieht man am besten in diesem Beispiel:

#!/usr/bin/perl -w

use strict;
use warnings;

use lib "/opt/local/lib/perl5/site_perl/5.8.8";  # plattformspezifische Zeile
use Locale::TextDomain "en"; #  "./LocaleXData";

## einfaches Beispiel

my $translated = __"Hallo Welt!";
print "$translated\n";

## Anhängen eines Zeilenumbruchs (der zu übersetzende String muss in Klammern!)

print __("Mir geht's gut.") . "\n";

# Schön ist, dass man auch Umlaute verwenden kann - 
# bei der Erstellung der po-Datei mit xgettext 
# --out-format=UTF-8 angeben!
print __("Täglicher Unsinn mit scharfem ß.") . "\n";

## Variablen können auch übersetzt werden

my $msg = "Hallo Welt!";
print __$msg;
print "\n";

# Schwieriger wird es bei Variablen, die gemeinsam mit Fixtext ausgegeben
# werden sollen. Das folgende Beispiel funktioniert mehr oder weniger zufällig,
# und nur hier, da "Hallo Welt!" oben schon übersetzt wurde. Aber xgettext 
# würde sich dagegen sträuben ("world2.pl:37: ungültige Interpolation einer 
# Variablen bei »$«") 
my $world = "Welt!";
#print __"Hallo $world";  # muss für parsing mit xgettext auskomentiert werden
						  # danach könnte man es wieder aktivieren - Perl käme damit zurecht
						  # aber Lösung ist das natürlich keine ...
print "\n";

# Richtig ist die Mischung von Fixtext und Variablen so:
print __x ("Hallo {person}!\n",
	person => "Franz");

Dieses Script kann man nun so parsen:

$ xgettext world3.pl --from-code=UTF-8 --keyword=__ --keyword=__x

Und bekommt dann ein po-file, das man so übersetzt:

#: world3.pl:12
msgid "Hallo Welt!"
msgstr "Hello World!"

#: world3.pl:18
msgid "Mir geht's gut."
msgstr "I am fine."

#: world3.pl:23
msgid "Täglicher Unsinn mit scharfem ß."
msgstr "Daily nonsens with non-ASCII."

#: world3.pl:44
#, perl-brace-format
msgid "Hallo {person}!\n"
msgstr "Hello {person}!\n"

Und es dann ganz einfach in ein mo umwandelt und dieses wie oben schon beschrieben ablegt.

Und Die Ausgabe schaut dann so aus:

$ ./world3.pl 
Hallo Welt!
Mir geht's gut.
Täglicher Unsinn mit scharfem ß.
Hallo Welt!

Hallo Franz!

$ export LANG=en_US

$ ./world3.pl 
Hello World!
I am fine.
Daily nonsens with non-ASCII.
Hello World!

Hello Franz!
h1

Net::SSH::Perl und known_hosts

21. April 2008

Bei der Verwendung des Perl Moduls Net::SSH-Perl tritt folgendes Problem auf:

Eine Verbindung zu einem Host mit SSH1 erzeugt die folgende Meldung:

Argument "ssh-rsa" isn't numeric in numeric eq (==) at modules/Net/SSH/Perl/Key/RSA1.pm line 103, <FH> line 23.

Nach längerem Suchen entdeckte ich, dass das Modul Hosts.PM die Methode equal aus dem Modul RSA1.pm verwenden. Dabei wird folgende Ausgabe erzeugt, wenn man das Modul RSA1 kurzfristig umschreibt wie folgt:

sub equal {
my($keyA, $keyB) = @_;
print "$keyA->{rsa}
$keyB->{rsa}
bitsA: $keyA->{rsa}{bits}
bitsB: $keyB->{rsa}{bits}
keyA: $keyA->{rsa}{n}
keyB: $keyB->{rsa}{n}
$keyA->{rsa}{e}
$keyB->{rsa}{e}\n";
$keyA->{rsa} && $keyB->{rsa} &&
$keyA->{rsa}{bits} == $keyB->{rsa}{bits} &&
$keyA->{rsa}{n} == $keyB->{rsa}{n} &&
$keyA->{rsa}{e} == $keyB->{rsa}{e};
}

Ausgabe:

Use of uninitialized value in concatenation (.) or string at modules/Net/SSH/Perl/Key/RSA1.pm line 95, <FH> line 23.
HASH(0x96fe78)
HASH(0x9659e4)
bitsA: 768
bitsB: ssh-rsa
keyA: 1295114094267464959040618524315923090715719842401896780056623074041026914313434353851674959103867550024637278939333976156853100989243816594892986096194402545568572126024189142175098585647756961269395154835682416927930811763277092609
keyB:
35
AAAAB3NzaC1yc2EAAAABIwAAAGEAoDtFmzlg44nJ6JdBs218W3xUmR1TXvTpQYLnAn6djlQPj2d6+Ev0nPObZ0cucvyRqanlkcT4XI6CmKozv4+7v5X3NxLMxA82llPqBQJFUJx+pHJYkOiKiP1cAtI0wXu1
Argument "ssh-rsa" isn't numeric in numeric eq (==) at modules/Net/SSH/Perl/Key/RSA1.pm line 103, <FH> line 23.
HASH(0x96fe78)
HASH(0x952f74)
bitsA: 768
bitsB: 768
keyA: 1295114094267464959040618524315923090715719842401896780056623074041026914313434353851674959103867550024637278939333976156853100989243816594892986096194402545568572126024189142175098585647756961269395154835682416927930811763277092609
keyB: 1295114094267464959040618524315923090715719842401896780056623074041026914313434353851674959103867550024637278939333976156853100989243816594892986096194402545568572126024189142175098585647756961269395154835682416927930811763277092609
35
35

Weitere Recherchen ergaben, dass hier die Datei .ssh/known_hosts gelesen wurde, und diese erlaubt laut man sshd zwei verschiedene Formate:

Examples
closenet,…,130.233.208.41 1024 37 159…93 closenet.hut.fi
cvs.openbsd.org,199.185.137.3 ssh-rsa AAAA1234…..=

Net::SSH::Perl kommt aber mit zweiterem nicht zurecht!

Workarund: In meinem konkreten Fall möchte ich den Hostcheck komplett deaktivieren, um das Perl-Skript von der SSH-Konfig des Hosts vollkommen unabhängig zu machen. Das erreiche mit einem einzigen # an der richtigen Stelle des SSH1.pm:

    $ssh->{session}{id} = $session_id;
# disabled von Ingo: $ssh->check_host_key($keys{host});
my $session_key = join '', map chr rand(255), 1..32;

Die Security-Implications sind hoffentlich klar: Es findet keine Überprüfung mehr statt, ob der kontaktierte Host nicht in irgend einer Form gespooft ist. Die Verbindung wird ohne Warnung und Prüfung aufgebaut und das Passwort übertragen! Nameresolution und Routing tragen somit die gesamte Verantwortung für die Vertraulichkeit des Passwortes. (Bei automatisierten Scripts in einer an sich gesicherten Umgebung erscheint mir das vertretbar)

http://rt.cpan.org/Public/Bug/Display.html?id=25175