Dienstag, 7. Oktober 2014

Ubuntu 12.04: Probleme bei der Nutzung von check_vmware_api.pl / check_vmware_esx

Wenn es um die Überwachung von ESX-Servern geht, haben sich zwei Plugins bei mir bewährt.

Auf die Installation des Plugins gehe ich jetzt nicht weiter ein, sondern mehr auf meine Fallstricke/Optimierungen

1. Nutzung der Umgebungsvariablen http_proxy / https_proxy


Falls die Umgebungsvariablen http(s)_proxy gesetzt sind, wird der Abruf der Daten über den Proxyserver erfolgen (falls keine Ausnahmen deklariert wurden), umgehen kann man dieses, indem man die Skripte um folgende Zeilen erweitert:

Erweiterung der Plugins um folgende Zeilen (z.B. auf Höhe der Variablen-Deklaration)

  # reset proxy
  $ENV{http_proxy} = "";
  $ENV{https_proxy} = "";

Streng genommen würde https_proxy reichen, da die Requests über SSL erfolgen.

2. Timeouts beim Abruf mit Ubuntu 12.04



Da scheinbar das vSphere SDK nicht mit den aktuellen libwww-perl Modulen zurecht kommen, muss eine ältere Version installiert werden:


cpan[1]> i /libwww-perl/
Going to read '/root/.cpan/Metadata'
  Database was generated on Mon, 06 Oct 2014 13:17:02 GMT
Distribution    GAAS/libwww-perl-5.837.tar.gz
Distribution    MSCHILLI/libwww-perl-6.08.tar.gz
Author          LWWWP ("The libwww-perl mailing list" <libwww@perl.org>)
3 items found

cpan[2]> install GAAS/libwww-perl-5.837.tar.gz

Anschließend klappt der Abruf der Daten.

3. Ablegen der Session Files in ein TMPFS


Um die Performance zu steigern empfiehlt es sich eine RAM-Disk als Plugin Cache anzulegen, dazu erstellt man folgenden Eintrag in der /etc/fstab

# nagios plugins
tmpfs           /var/cache/nagios_plugin     tmpfs   nodev,nosuid,noexec,nodiratime,size=512M        0 0

Der Parameter "size" muss natürlich angepasst werden, möglich sind dort die Kombinationen 
  • % - z.B. 10% des zur Verfügung stehenden RAMs
  • k,m,g - Angabe in Kilobyte,Megabyte oder Gigabyte

Achtung: wenn die RAM-Disk zu groß angelegt wird, kann es zu Problemen mit dem System kommen, daher vorher mit "free -m" überprüfen.

Anschließend wird der mount point erstellt und die Zugriffsrechte für den Nagios/Icinga User gesetzt:

$ mkdir /var/cache/nagios_plugin
$ chown nagios:nagios $_

Kleine Randnotiz: innerhalb der bash enthält die Variable "$_" das letzte Argument des zuletzt ausgeführten Befehls.

Nun soll die RAM-Disk gemountet werden:
$ mount /var/cache/nagios_plugn

Im Plugin muss nun noch die Variable plugin_cache angepasst werden:
$ sed -i 's/plugin_cache=.*/plugin_cache="\/var\/cache\/nagios_plugin\/";/g' /usr/lib/nagios/plugins/check_vmware_esx

Dabei muss noch der Pfad des Plugins entsprechend angepasst werden.

Donnerstag, 28. August 2014

Nagios: NetApp Plugin check_netapp_sdk.pl

Written in Perl, using NetApp Manageability SDK


Functions
  • check-volume
  • check-lun
  • check-snapmirror
  • check-aggr
  • check-cluster
  • check-shelf
  • check-license

Dependencies:
- NetApp 7-Mode
- Nagios::Plugins (Perl)
- NetApp Manageability SDK (Perl)
- At line 24 adjust your lib path:
use lib "/usr/lib/perl5/site_perl/5.8.8/NetApp";
- Warning/Critical defaults to 85/95%


check-volume [-n VOLUME_NAME] - List volumes use -n to specify volume
-> size in percent (-w/-c)
check-lun [-n LUN_NAME] - List LUNs, use -n to specify lun
-> size in percent (-w/-c)
-> misalignment results to warning
-> offline state and is mapped results to critical
check-snapmirror [-n SNAPMIRROR_NAME] - List snapmirrors, use -n to specify snapmirror
-> lag_time in seconds (-w/-c)
-> transfer error -> CRITICAL
check-aggr [-n AGGREGATE_NAME] - List aggregates, use -n to specify lun
-> size in percent (-w/-c)
-> mount state: warning on creating, mounting, unmounting, quiescing; ok on online consistent quiesced; critical for the rest!
-> mirror state: warning on 'CP count check in progress'; ok on mirrored, unmirrored; critical for the rest!
-> raid state: warning on resyncing, copying, growing, reconstruct; ok on normal, mirrored; critical for the rest
-> inconsistency results on critical
check-cluster - checks for cluster state
-> warning/critical on other state than connected
-> warning on inactive hwassist (if available)
-> interconnect state
check-shelf
-> critical on failed power-supply
-> critical on failed voltage sensor
-> critical on failed temp sensor
-> temperature (values provided by netapp, is needed due to different sensor locations)
-> shelf state : warning on informational, non_critical; ok on normal; critical for the rest!
check-license - checks license
-> expiry date (excludes demo, auto_enabled and non expiry lics)

Sample Output:


$ check_netapp_sdk.pl -H snapmirror1 -U $USER1$ -P $USER2$ -S -C check-snapmirror -w 43200 -c 86400
CRITICAL - 1 failed snapmirror found: C->netapp1->snapmirror1: nfs_ds2_snapmirror: Lag-time: 10.2 days Error: - | netapp1_snapmirror1_nfs_ds2_snapmirror_xfer_size=36609B;; netapp1_snapmirror1_nfs_ds2_snapmirror_lag_time=885023s;43200;86400

$ check_netapp_sdk.pl -H netapp1 -U $USER1$ -P $USER2$ -S -C check-cluster
OK - Cluster is fine! Partner netapp2 is connected

$ check_netapp_sdk.pl -H netapp1 -U $USER1$ -P $USER2$ -S -C check-lun -n /vol/lun_1_vol/lun_1
WARNING - 1 suspicious luns found: W->lun_1: 85.66% | lun_1_size_used=44911216B;44564480;47185920;;52428800 lun_1_size_pct=85.66%;85;9

$ check_netapp_sdk.pl -H netapp1 -U $USER1$ -P $USER2$ -S -C check-volume -n lun_1_vol
WARNING - 1 suspicious volumes found: W->lun_1_vol: 88.56% | lun_1_vol_size_used=52653680B;50537015;53509781;;59455312 lun_1_vol_size_pct=88.56%;85;9

$ check_netapp_sdk.pl -H netapp1 -U $USER1$ -P $USER2$ -S -C check-aggr
OK - 0 suspicious aggregate found | aggr_unmirrored_size_used=3161408134.68B;3274284218;3466889172;;3852099080 aggr_unmirrored_size_pct=82.07%;85;90 aggr0_size_used=10676546580.44B;11114697879;11768503637;;13076115152 aggr0_size_pct=81.65%;85;90

$ check_netapp_sdk.pl -H netapp1 -U $USER1$ -P $USER2$ -S -C check-license
OK - 0/48 expired licenses found

$ check_netapp_sdk.pl -H netapp1 -U $USER1$ -P $USER2$ -S -C check-version
OK - System-Name: netapp1 System-ID: 123456789 Model: FAS3240 Serial: 123456789 Version: NetApp Release 8.1.2P4 7-Mode: Fri Apr 26 19:57:25 PDT 2013
 
 
 

Mittwoch, 20. August 2014

Nachtrag für Ubuntu 14.04 Trusty zu Active-Directory User-Login für Ubuntu/Debian Servern

Nachdem ich gestern das erste System von 12.04 auf 14.04 gehoben habe, musste ich feststellen, dass der AD-Login (wie hier beschrieben: http://oskibbe.blogspot.de/2014/07/linux-active-directory-user-login-fur.html) nicht mehr funktionierte.


Der Server war weiterhin in der Domäne und die Winbind Tools wbinfo -u / wbinfo -g lieferten weiterhin die korrekten User/Gruppen zurück.

Im Auth-Log fand ich allerdings einen Eintrag:

Aug 18 16:07:38 host login[1738]: pam_listfile(login:auth): Refused user oliver.skibbe for service login
Aug 18 16:07:40 host login[1738]: pam_unix(login:auth): check pass; user unknown
Aug 18 16:07:40 host login[1738]: pam_unix(login:auth): authentication failure; logname=LOGIN uid=0 euid=0 tty=/dev/tty1 ruser= rhost=
Aug 18 16:07:40 host login[1738]: pam_winbind(login:auth): getting password (0x00000388)
Aug 18 16:07:40 host login[1738]: pam_winbind(login:auth): pam_get_item returned a password
Aug 18 16:07:42 host login[1738]: FAILED LOGIN (1) on '/dev/tty1' FOR 'UNKNOWN', Authentication failure

Ausgehend von diesem Eintrag und der Info, dass die User weiterhin abrufbar waren, konnte ich das Problem auf nsswitch eingrenzen und zwar gibt es seit Ubuntu 14.04 Trusty für diesen Part zwei zusätzliche Pakete Namens: libnss-winbind und libpam-winbind benötigt werden:

ii  libnss-winbind:amd64                2:4.1.6+dfsg-1ubuntu2.14.04.3 amd64        Samba nameservice integration plugins
ii  libpam-winbind:amd64                2:4.1.6+dfsg-1ubuntu2.14.04.3       amd64        Windows domain authentication integration plugin


Nach der Installation dieses Paketes funktionierte dann der AD-Login sofort wieder, schade das Winbind keine explizite Abhängigkeit für dieses Paket hat.

Freitag, 1. August 2014

My github for monitoring plugins

Instead of using a local subversion, i moved my selfwritten monitoring plugins to github.

It's accessible through this link: https://github.com/riskersen/Monitoring


Feel free to contribute :-)

Dienstag, 29. Juli 2014

Nagios crashing while using scheduled downtimes, log rotation and MK-Livestatus

So, this is my first post in English so please don't expect too much ;-)


There is a problem in nagios 3.4.x - 3.5.x while using NEB mk_livestatus (https://mathias-kettner.de/checkmk_livestatus.html), setting log_rotation_method and using scheduled downtimes.

This bug leads to a crashing nagios process at the time where a logrotate should be done.

I noticed this after updating nagios core from 3.3.x to 3.4.4 and also in 3.5.1.

There is a patch available at http://tracker.nagios.org/view.php?id=455 (Bug ID 455)

--- nagios-3.5.0/include/downtime.h     2013-02-10 00:55:47.000000000 +0100
+++ /tmp/downtime.h     2013-04-04 17:05:14.000000000 +0200
@@ -39,24 +39,26 @@
        char *service_description;
        time_t entry_time;
        time_t start_time;
-       time_t flex_downtime_start;             /* Time the flexible downtime started */
        time_t end_time;
        int fixed;
        unsigned long triggered_by;
        unsigned long duration;
        unsigned long downtime_id;
-       int is_in_effect;
-       int     start_notification_sent;
        char *author;
        char *comment;
 #ifdef NSCORE
        unsigned long comment_id;
+#endif
+       int is_in_effect;
+#ifdef NSCORE
        int start_flex_downtime;
        int incremented_pending_downtime;
 //     int start_event;
 //     int stop_event;
 #endif
        struct scheduled_downtime_struct *next;
+       time_t flex_downtime_start;             /* Time the flexible downtime started */
+       int     start_notification_sent;
        } scheduled_downtime;

This patch also works with 3.5.1 and should be applicable to 3.4.x.

On my next post i'll talk about creating rpms for nagios (which is very easy if you know how to)


Freitag, 18. Juli 2014

Linux: Active-Directory User-Login für Ubuntu/Debian Servern

Warum muss eigentlich für jedes Linux-System immer ein Passwort aus einem Passwort-Manager geholt werden, nur um eben einen Dienst neuzustarten oder die Logs zu durchforsten, wenn wir doch ein funktionierendes Active Directory im Einsatz haben?

Was muss also her: AD-Login für die Linux-Maschinen (Ubuntu/Debian)!
Da wir aber, wie auf den Windows Servern, nicht jedem den Zugriff und sudo (Kommandos als root ausführen!) erlauben wollen, müssen wir die Zugriffe einschränken, welches ich in diesem kurzen Tutorial ebenfalls tun werde.

Im Wesentlichen brauchen wir dafür die folgenden Pakete:
apt-get install winbind samba krb5-user libpam-krb5

Winbind übernimmt hier als Komponente von Samba im Zusammenspiel mit PAM & Kerberos die Hauptarbeit.

Kerberos

Als erstes werden die Kerberos Konfigurationen erledigt, dazu erstellen wir die /etc/krb5.conf in folgender Weise:

[libdefaults]
  default_realm = DOMAIN.TLD
  allow_weak_crypto = yes
  # passend zum AD:
  default_tkt_enctypes = arcfour-hmac-md5 des-cbc-crc des-cbc-md5
  default_tgs_enctypes = arcfour-hmac-md5 des-cbc-crc des-cbc-md5

[domain_realm]
  .domain.tld = DOMAIN.TLD

# wir nutzen nicht den PRÄ-2000 Namen!
[realms]
  DOMAIN.TLD = {
   kdc = dc1.fqdn
   kdc = dc2.fqdn
   admin_server = dc1.fqdn
  }
 
# wir nutzen nicht den PRÄ-2000 Namen, daher umschreiben, falls nötig
[appdefaults]
  pam = {
   mappings = DOMAIN_2000\\(.*) $1@DOMAIN.TLD
   forwardable = true
   validate = true
  }

  # Vorbereitung für Apache Kerberos Authentifizierung!
  httpd = {
   mappings = DOMAIN_2000\\(.*) $1@DOMAIN.TLD
   reverse_mappings = (.*)@DOMAIN\.TLD DOMAIN_2000\$1
  }

Zu ändern sind hier nur die Domänen-Namen, also der 2000er Name und die "moderne" Variante, sowie die Domänen-Controller, idealerweise als fqdn.

Jetzt testen wir den ersten Login mit einem AD-Admin und erzeugen ein Kerberos-Ticket mit
 kinit AD-Admin@DOMAIN.TLD

Und lassen uns das erzeugte Ticket anzeigen:
klist

Der Kerberos Part ist damit abgeschlossen.

Samba

Auch hier müssen wir die Konfiguration in /etc/samba/smb.conf ändern:
[global]
    security = ads
    realm = domain.tld
    workgroup = DOMAIN
    idmap uid = 70000-100000
    idmap gid = 70000-100000
    winbind enum users = yes
    winbind enum groups = yes
    winbind use default domain = yes
    winbind refresh tickets = yes
    template homedir = /home/%U
    template shell = /bin/bash
    client use spnego = yes
    client ntlmv2 auth = yes
    encrypt passwords = true
    restrict anonymous = 2
    domain master = no
    local master = no
    preferred master = no
    os level = 0
    socket address = 127.0.0.1
    load printers = no
    printing = bsd
    printcap name = /dev/null
    disable spoolss = yes

[domain-share]
 path = /foo/bar
 comment = Foo-Bar
 browseable = no
 read only = no
 force user = root
 force group = "DOMAIN+ad-group"
 force create mode = 0666
 force directory mode = 2777
 force directory security mode = 0777
 valid users = @"DOMAIN+ad-group"

Der "domain-share" ist nur ein Beispiel, wie man Samba-Freigaben mit AD Berechtigungen anlegen kann.
Wenn dieser genutzt werden soll, sollte die socket address auf die entsprechende IP-Adresse gesetzt werden oder einfach auskommentiert werden.
Um den Overhead zu reduzieren habe ich dem Samba hier verboten Master zu werden, sowie Druckfunktionen anzubieten.

Die Konfiguration des Samba ist abgeschlossen, wir müssen nun die smb und winbind (Wichtig!) Dienste neustarten
/etc/init.d/smbd restart && /etc/init.d/winbind restart

Fehlt nun noch der AD-Join:
net ads join -U AD-Admin

Ob der AD-Join wirklich erfolgreich war, können wir mit dem Tool wbinfo gut ermitteln:
wbinfo -u | wc -l

wbinfo -u liefert alle User aus dem AD zurück und mit wc -l zählen wir das Ergebnis.
Alternativ geht auch wbinfo -g (Gruppen).
Achtung: es kann eine gewisse Zeit dauern bis wbinfo korrekte Ergebnisse anzeigt!

Damit wir die gefundenen User auch als User im System und damit auch für die Anmeldung nutzen können, müssen wir am "internen" DNS ebenfalls etwas ändern und zwar in der /etc/nsswitch.conf:
Im Wesentlichen ergänzen wir die Zeilen user und group, so dass diese dann folgendermaßen aussehen:
passwd:         compat winbind
group:          compat winbind

Anschließend können wir noch einmal die Dienste neustarten:
/etc/init.d/smbd restart && /etc/init.d/winbind restart

Und einen erneuten Test durchführen, dieses Mal rufen wir die virtuelle passwd inkl. Domänen-User ab:
getent passwd

Hier sollten nun alle Domänen-User im normalen Passwd Format auftauchen:
username:*:71776:70000:Surname, givenName:/home/username:/bin/bash

Die Domänen-User können wir gut an den IDs über 70000 erkennen.

Damit haben wir die Samba Konfiguration abgeschlossen.

PAM

Dem Plugable Authentication Mechanism, kurz PAM, muss nun noch die Nutzung von Winbind beigebracht werden, dazu wird die Datei /etc/pam.d/common-account um folgende Zeile erweitert:
account [success=1 new_authtok_reqd=done default=ignore] pam_winbind.so 

Weiterhin müssen wir Datei /etc/pam.d/common-auth erweitern, so dass sie wie folgt aussieht:
## restricted access
auth required pam_listfile.so onerr=fail item=group sense=allow file=/etc/login.group.allowed

auth [success=2 default=ignore] pam_unix.so nullok_secure
auth [success=1 default=ignore] pam_winbind.so krb5_auth krb5_ccache_type=FILE cached_login try_first_pass
# here's the fallback if no module succeeds
auth requisite   pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth required   pam_permit.so

Wir erinnern uns, wir wollen den Zugriff für bestimmte Nutzer Gruppen einschränken, dazu nutzen wir das PAM-Modul pam_listfile.so und tragen dort zeilen-basiert unsere erlaubten Gruppen (ohne Prefix!) ein.

Damit wir auf jedem System auch ein entsprechendes Home Verzeichnis bekommen, benötigen wir das Modul pam_mkhomedir.so, welches wir in die Datei /etc/pam.d/common-session einfügen:
session required   pam_mkhomedir.so umask=0022 skel=/etc/skel

Abschluss

Damit wir die Änderungen testen können, machen wir einen SSH auf uns selbst:
ssh ad-user@hostname

Wenn das erfolgreich ist, fügen wir noch Samba und Winbind zum Autostart hinzu:
update-rc.d smb defaults && update-rc.d winbind defaults

Das wars!

Nachtrag: RHEL/CentOS/Oracle Linux

Das ganze funktioniert natürlich auch unter RHEL basierten Systen, dafür nutzt man die Pakete:
nscd pam_krb5 samba-common samba

Und ergänzt die Datei /etc/pam.d/system-auth-ac um folgende Zeilen:
auth        sufficient    pam_winbind.so use_first_pass
account     [default=bad success=ok user_unknown=ignore] pam_winbind.so
session     optional      pam_winbind.so mkhomedir

Ansonsten variieren natürlich die Befehle etwas.


Bei Fragen bitte einfach melden.



Donnerstag, 17. Juli 2014

ORA-15303: Probleme beim Erstellen der Voting files für ein Oracle RAC auf RHEL-basierten Linuxen mit iSCSI Luns und ASM

Es gibt leider einen nervigen Bug(?) bei der Verwendung von Oracle ASM (http://docs.oracle.com/cd/B28359_01/server.111/b31107/asmcon.htm) im Zusammenspiel mit iSCSI LUNs, der Bug äußert sich bei der Installation einer Grid Infrastructure für Oracle RAC (http://docs.oracle.com/cd/B28359_01/rac.111/b28254/admcon.htm).

Man wird nach der X-basierten Installation der Grid Infrastructure gebeten das root.sh Script auszuführen ($ORACLE_HOME/root.sh), dabei kommt es zu einem Fehler, welcher in folgendem Log gefunden werden kann: (eigentlich könnte die Variable imho auch $GRID_HOME genannt werden, aber seis drum):

$ORACLE_HOME/cfgtoollogs/crsconfig/rootcrs_oraracqs1.log

2013-10-15 15:29:12: Creating voting files
2013-10-15 15:29:12: Creating voting files in ASM diskgroup OCR_VOTING
2013-10-15 15:29:12: Executing crsctl replace votedisk '+OCR_VOTING'
2013-10-15 15:29:12: Executing /u01/app/11.2.0.3/grid/bin/crsctl replace votedisk '+OCR_VOTING'
2013-10-15 15:29:12: Executing cmd: /u01/app/11.2.0.3/grid/bin/crsctl replace votedisk '+OCR_VOTING'
2013-10-15 15:29:13: Command output:
>  Failed to create voting files on disk group OCR_VOTING.
>  Change to configuration failed, but was successfully rolled back.
>  CRS-4000: Command Replace failed, or completed with errors.
>End Command output

Diese Ausgabe hilft erstmal nicht wirklich weiter, also schauen wir im ASM Log nach:

Auf dem 1. Knoten:
/u01/app/grid/diag/asm/+asm/+ASM1/trace/alert_+ASM1.log

Dort können wir folgende Ausgabe sehen:
NOTE: Voting File refresh pending for group 1/0x4b5bc0ec (OCR_VOTING)
NOTE: Attempting voting file creation in diskgroup OCR_VOTING
ERROR: Could not create voting files. It spans across 161 AUs (max supported is 64 AUs)
ERROR: Voting file allocation failed for group OCR_VOTING
Errors in file /u01/app/grid/diag/asm/+asm/+ASM1/trace/+ASM1_ora_1511.trc:
ORA-15303: Voting files could not be created in diskgroup OCR_VOTING due to small Allocation Unit size
NOTE: Attempting voting file refresh on diskgroup OCR_VOTING

Das hilft uns schon mal etwas weiter, also überprüfen wir die Disks auf ihre Blocksize (hier sdc)

[root@orarac1 queue]# pwd
/sys/block/sdc/queue
[root@orarac1 queue]# grep "" *block_size
logical_block_size:512
physical_block_size:4096

Was sehen wir hier? Das SAN präsentiert uns unterschiedliche Werte für die Block Size, um dieses Problem zu beheben müssen wir in der Konfiguration der ASM (/etc/sysconfig/oracleasm) den folgenden Wert von false auf true setzen

# ORACLEASM_USE_LOGICAL_BLOCK_SIZE: 'true' means use the logical block size
# reported by the underlying disk instead of the physical. The default
# is 'false'
ORACLEASM_USE_LOGICAL_BLOCK_SIZE=true

Alternativ kann das auch mittels Konfigurations-Tool gesetzt werden:
/usr/sbin/oracleasm configure -b

Anschließend muss die Konfiguration aktiviert werden:
service oracleasm restart

Wenn wir nun das root.sh Skript erneut ausführen, funktioniert die Erstellung der Voting Files auf unserer ASM Diskgroup.


Für weitere Informationen empfiehlt sich das Studium des Oracle MetaLinks DOC-ID: 1526096.1


Dienstag, 1. Juli 2014

Wie funktioniert eigentlich der Linux IO-Stack oder wie kommen wir Performance Problemen auf die Schliche

Bei Performance Problemen ist es immer nett zu wissen, an welchen Stellen man suchen sollte.


Dazu bin ich im Thomas-Krenn Wiki auf eine nette Grafik zum Thema IO-Stack unter Linux gestoßen:

Linux I/O Stack Diagram

Schön und gut, wir wissen nun wie der IO-Stack arbeitet, aber wie kommen wir nun tatsächlich unserem Performance-Problem auf die Schliche? Dazu gucken wir uns das Diagramm von Brendan Gregg - Linux Performance Analysis & Tools an.

Dieses Diagramm zeigt recht anschaulich mit welchen Tools man welchen Problem auf den Grund gehen kann:



Links:

Donnerstag, 19. Juni 2014

Monitoring: Sophos SafeGuard Enterprise

Was ist Sophos SafeGuard Enterprise?

Sophos SafeGuard Enterprise ist eine Software-Lösung für Endpoint-Security, mit der man im wesentlichen eine managed Verschlüsselungslösung für Clients aufbauen kann.

Wesentliche Komponenten sind:
  • Zertifizierte Verschlüsselungstechnologien (FIPS, Common Criteria)
  • Hohe Verschlüsselungsstärke (AES 256 Bit)
  • Festplattenverschlüsselung
  • Verschlüsselung von Wechselmedien
  • Verschlüsselter Datenaustausch, ohne dass der Empfänger selber das Produkt installiert haben muss
  • Verschlüsselung für CloudStorage (Dropbox und co) mit Zugriffsmöglichkeiten auf mobile devices
  • Verschlüsselung für Netzwerk-Freigaben
  • Unterstützung von BitLocker, FileVault etc
  • Token-basierte Authentifizierung
  • OU-basierte Zuweisung von Richtlinien
  • Client-Unterstützung: Windows  XP - 8.1, MAC OSX 10.5 - 10.9
  • Datenbank-Unterstützung: SQL Server 2005 - 2012 SP1 (jeweils auch Express)
  • Management-Server: Windows Server 2003 - 2012 R2
  • Management-Konsole: Windows Server 2003 - 2012 R2, XP - 8.1
Die Installation des Clients kann bequem mittels einer Software-Verteilung erfolgen, die Kommunikation mit dem Server erfolgt dann bidirektional (z.B. Richtlinien abrufen, Zustand hochladen), über HTTP optional mit SSL-Verschlüsselung.




Die Überwachung von Sophos SafeGuard Enterprise gestaltet sich als relativ einfach, da Sophos bereits eine Web-Schnittstelle für die wichtigsten Komponenten bereitstellt:
  • WebService (wie bereits oben beschrieben, eine sehr kritische Komponente)
  • DBAuth: Zugriff auf die Datenbank
Da der Abruf der Informationen aus Sicherheitsgründen nur über Localhost gestattet ist und der Server/Management Center nur auf einem Windows Server installiert werden kann, konnte ich, ohne Interpreter-Installation auf dem Server, leider keine meiner bevorzugten Sprachen nutzen.
Daher habe ich das Plugin VBS geschrieben und bin dabei auf einen unschönen Bug in der Web-Schnittstelle gestoßen.

Die Informationen der Schnittstelle werden als XML abgerufen, allerdings werden die spitzen Klammern als HTML Steuerzeichen ausgegeben und können somit nicht direkt verarbeitet werden:

Falsches XML:
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">&lt;Dataroot&gt;&lt;WebService&gt;OK&lt;/WebService&gt;
&lt;DBAuth&gt;OK&lt;/DBAuth&gt;
&lt;Info&gt;
&lt;Database&gt;SafeGuard&lt;/Database&gt;
   &lt;Server&gt;SGE1\SQLEXPRESS&lt;/Server&gt;
   &lt;Version&gt;11.00.3000&lt;/Version&gt;
   &lt;Name&gt;DBFactorySql on process: w3wp
Process ID: 33264&lt;/Name&gt;
   &lt;Owner&gt;[dbo]&lt;/Owner&gt;
   &lt;ConnectionInfo&gt;SQL Server credentials are used for authentication.&lt;/ConnectionInfo&gt;
&lt;/Info&gt;
&lt;/Dataroot&gt;</string>

Valides XML:
<?xml version="1.0"?>
<string xmlns="http://tempuri.org/"><Dataroot><WebService>OK</WebService>
<DBAuth>OK</DBAuth>
<Info>
<Database>SafeGuard</Database>
   <Server>SGE1\SQLEXPRESS</Server>
   <Version>11.00.3000</Version>
   <Name>DBFactorySql on process: w3wp
 Process ID: 49588</Name>
   <Owner>[dbo]</Owner>
   <ConnectionInfo>SQL Server credentials are used for authentication.</ConnectionInfo>
</Info>
</Dataroot></string>


Durch diesen Bug musste ich im Plugin ein Tempfile erstellen (%windir%/temp) und in diesem, das XML gerade biegen.

Dabei kommt dann folgendes raus:
' Author: Oliver Skibbe
' Date: 2014-06-18
' Required Variables
Const PROGNAME = "check_sge"
Const VERSION = "1.0.0"

' Nagios helper functions
nsclientDir = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName)
Include nsclientDir & "\lib\NagiosPlugins.vbs"

' Create the NagiosPlugin object
Set np = New NagiosPlugin
Set WshShell = WScript.CreateObject("WScript.Shell")
Set xmlDoc = CreateObject("Msxml2.DOMDocument")
Set objFSO = CreateObject("Scripting.FileSystemObject") 

' fetch xml, per default "CheckConnection" is only available via localhost
Set oXMLHTTP = CreateObject("Msxml2.ServerXMLHTTP.3.0")
oXMLHTTP.SetOption 2, oXMLHTTP.GetOption(2) - SXH_SERVER_CERT_IGNORE_ALL_SERVER_ERRORS
oXMLHTTP.Open "POST", "https://localhost/SGNSRV/Trans.asmx/CheckConnection", False
oXMLHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
oXMLHTTP.Send ""

' Ugly, but we have to build a Tempfile, cause SafeGuard Enterprise does not provide a valid xml file
' Sophos Support: might be fixed in 6.20
' temporary file, 
strWinDir = WshShell.ExpandEnvironmentStrings("%WinDir%")
TEMPFILE = strWinDir & "\Temp\nagios_sge.xml"

' load fetched xml file
Set myFile = objFSO.CreateTextFile(TEMPFILE, True)
bodyStr = oXMLHTTP.responseXML.xml
' this is the magic, replace broken html stuff with real ">" & "<"
bodyXML = Replace(bodyStr, "<", "<")
bodyXML = Replace(bodyXML, ">", ">")
' save file
myFile.write(bodyXML)

' Website is responding and returns OK
If oXMLHTTP.Status = 200 Then 
 ' Parse XML
 xmlDoc.load(TEMPFILE)
 
 If isObject(xmlDoc) Then
  ' prepare output
  For Each x In xmlDoc.documentElement.selectNodes("//string/Dataroot")
   WebService = x.selectSingleNode("WebService").Text
   DBAuth = x.selectSingleNode("DBAuth").Text
   Info = "Database: " & x.selectSingleNode("Info/Database").Text
   Info = Info & vbcrlf & "DBServer: " & x.selectSingleNode("Info/Server").Text
   Info = Info & vbcrlf & "DBVersion: " & x.selectSingleNode("Info/Version").Text
   Info = Info & vbcrlf & "DBOwner: " & x.selectSingleNode("Info/Owner").Text
   Info = Info & vbcrlf & "DBConnectionInfo: " & x.selectSingleNode("Info/ConnectionInfo").Text
  Next
  
  If WebService = "OK" And DBAuth = "OK" Then
   return_code = OK
   return_msg = "Everything's fine!"
  Else
   return_code = CRITICAL
   return_msg = "Something happened!"
  End If ' end if webserver and dbauth
  ' prepare return msg
  return_msg = return_msg & " WebService: " & WebService & " DBAuth: " & DBAuth & vbcrlf & Info    
 Else
  ' XML not loaded
  return_code = CRITICAL
  return_msg = "XML could not be read"
 End If ' end if xml load
Else 
' Webservice reporting something other than 200 (OK)
 MsgBox("Error: " & oXMLHTTP.Status)
 return_code = CRITICAL
 return_msg = "Webservice answered something strange, http status: " & oXMLHTTP.Status
End If ' end if Webservice status 200 (OK)

' exit
np.nagios_exit return_msg, return_code

' helper for including nagios lib
Sub Include( cNameScript )
    Set oFS = CreateObject("Scripting.FileSystemObject")  
    Set oFile = oFS.OpenTextFile( cNameScript )
    ExecuteGlobal oFile.ReadAll()
    oFile.Close
End Sub
' EOF

Das Plugin wird kritisch, wenn entweder:
  • DBAuth und/oder WebService nicht "OK" sind
  • HTTP Status != 200
  • Fehler bei der XML Verarbeitung aufgetreten sind

Download: Nagios Exchange


Bei Fragen bitte einfach melden.

Mittwoch, 11. Juni 2014

Nützliche Dinge rund um die Bash und den Prompt

Da wir Admins generell faul sind, suchen wir Wege um unsere Arbeit effizienter zu gestalten.

Unter Linux gibt es da mit der Bash einige schöne Möglichkeiten, von denen ich einige mal vorstellen möchte:

(Alle Beispiele gehören in die $HOME/.bash_alias, damit sie auch beim Login aktiv sind)

Farbige Manpages (kann natürlich auch in die /etc/environments eingetragen werden)

export LESS_TERMCAP_mb=$'\E[01;31m'
export LESS_TERMCAP_md=$'\E[01;31m'
export LESS_TERMCAP_me=$'\E[0m'
export LESS_TERMCAP_se=$'\E[0m'
export LESS_TERMCAP_so=$'\E[01;44;33m'
export LESS_TERMCAP_ue=$'\E[0m'
export LESS_TERMCAP_us=$'\E[01;32m'

Textdateien

alias t="tail -f -n200" # t /var/log/apache2/error.log -> tail wird im fortlaufenden Modus gestartet
alias nocomment='grep -Ev '\''^(#|$)'\''' # nocomment /etc/apache2/apache2.conf -> Ausgabe der Zieldatei, allerdings ohne Kommentare
alias lvim="vim -c \"normal '0\"" # erneut die zuletzt geöffnete Datei im vim öffnen

 

 Nützliche "Tools"

alias mkdir="mkdir -pv" # erstellung von rekursiven Ordnern und Anzeige der zuerstellenden Ordner
alias lsmount="mount|column -t" # formatierte Ausgabe von mount
alias path='echo -e ${PATH//:/\\n}' # formatierte Ausgabe des Path

# System
alias meminfo='free -m -l -t' # erweiterte RAM Ausgabe
alias psmem='ps auxf | sort -nr -k 4' # sortierte Ausgabe aller Prozesse nach RAM Auslastung
alias pscpu='ps auxf | sort -nr -k 3' # sortierte Ausgabe aller Prozesse nach CPU Auslastung
alias j="jobs -l" # Ausgabe der aktiven Jobs (Strg+Z, fg)
alias h="history" # Kurzform für Ausgabe der History

# Datum
alias nowtime='date +"%T"' # formatierte Ausgabe der Uhrzeit
alias nowdate='date +"%d-%m-%Y"' # formatierte Ausgabe des Datums

# Netzwerk
alias ports='netstat -tulanp' # Anzeige aller offenen Ports

# Web
alias header='curl -I' # Abruf des Headers von Argument Webseite 
alias headerc='curl -I --compress' # same, allerdings mit Komprimierung
alias apache2test='/usr/sbin/apachectl -t && /usr/sbin/apachectl -t -D DUMP_VHOSTS' # Apache2 Configtest 

function cdl(){ cd "$@"; ls -al;} # Bei der Nutzung von cdl, anstelle von cd, wird nun der Inhalt des Zielordners angezeigt

## Zeigt die aktuelle Verzeichnisstruktur an, sehr huebsch
function tree(){
        pwd
        ls -R | grep ":$" | \
        sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/ /' -e 's/-/|/'
}

# Für die Apt Nutzer unter uns
alias upd="apt-get update" # refresh der sourcen
alias del="apt-get remove " # Entfernen (kein purge!) von Paketen
alias get="apt-get install " # Installation von Paketen
alias upg="apt-get upgrade" # Aktualisierung des Systems 
alias searchpkg="apt-cache search " # Paketsuche
alias update="apt-get update && apt-get upgrade" # Refresh der Sourcen und Aktualisierung der Pakete kombiniert



Wenn man diese Funktionen / Aliases und Variablen in der .bash_alias verankert hat, erspart man sich eine Menge Zeit und kann diese Zeit in die Weiterentwicklung der System-Landschaft stecken.

Tipp: Natürlich gibt es da noch mehr Möglichkeiten,  einfach mal sich selber über die Schulter schauen und überlegen ob man sein Nutzverhalten nicht mit eigenen Aliases/Funktionen noch optimieren kann


Bei Fragen bitte einfach kurz melden :-)

Donnerstag, 3. April 2014

Netzwerk-Debugging mit und unter Linux

Nachdem der letzte Blog-Eintrag schon etwas her ist, möchte ich dieses Mal etwas über (einfaches) Netzwerk-Debugging mit und unter Linux schreiben.

Die typischen Kommandos ping, netstat lasse ich dabei mal außen vor, sondern gehe auf "etwas" speziellere Kommandos bzw. Alternativen ein.

Prüfung auf aktive Hosts/Erreichbarkeit

Ich nutze dafür fping:
Vorteile: Ip-Ranges (Range oder CIDR Notation!), Statistiken und parallele Verarbeitung!
Nachteile: muss meist nachinstalliert werden

1. Single Host
$ fping -s 172.16.1.91

172.16.1.91 is alive

       1 targets
       1 alive
       0 unreachable
       0 unknown addresses

       0 timeouts (waiting for response)
       1 ICMP Echos sent
       1 ICMP Echo Replies received
       0 other ICMP received

 0.98 ms (min round trip time)
 0.98 ms (avg round trip time)
 0.98 ms (max round trip time)
        0.011 sec (elapsed real time)


2. mit IP-Range und Statisktik
$ fping -s -g 172.16.1.90 172.16.1.100 -r 1
172.16.1.91 is alive
172.16.1.92 is alive
172.16.1.93 is alive
172.16.1.94 is alive
172.16.1.95 is alive
172.16.1.97 is alive
172.16.1.90 is unreachable
172.16.1.96 is unreachable
172.16.1.98 is unreachable
172.16.1.99 is unreachable
172.16.1.100 is unreachable
 
      11 targets
       6 alive
       5 unreachable
       0 unknown addresses
 
      10 timeouts (waiting for response)
      16 ICMP Echos sent
       6 ICMP Echo Replies received
       0 other ICMP received
 
 0.38 ms (min round trip time)
 0.75 ms (avg round trip time)
 1.45 ms (max round trip time)
        2.808 sec (elapsed real time)

Verbindungen/Sessions anzeigen

Die meisten werden wahrscheinlich netstat nutzen, ich nehme dafür "ss".
"ss" ist schneller und bietet mehr Möglichkeiten in den Abfragen.


Alle Verbindungen anzeigen
$ ss -a | less
 
State      Recv-Q Send-Q      Local Address:Port          Peer Address:Port
LISTEN     0      0                       *:6080                     *:*
LISTEN     0      0             172.16.0.250:5667                     *:*
LISTEN     0      0                       *:5668                     *:*
LISTEN     0      0                       *:11301                    *:*
LISTEN     0      0               127.0.0.1:smux                     *:*
LISTEN     0      0                       *:mysql                    *:*
LISTEN     0      0                       *:sunrpc                   *:*
LISTEN     0      0                       *:http                     *:*
LISTEN     0      0                       *:ssh                      *:*
LISTEN     0      0                       *:smtp                     *:*
LISTEN     0      0                       *:iscsi                    *:*
TIME-WAIT  0      0             172.16.0.250:http           172.16.0.1:14653
TIME-WAIT  0      0             172.16.0.250:http           172.16.0.14:58166
TIME-WAIT  0      0             172.16.0.250:http           172.16.0.14:58167
TIME-WAIT  0      0             172.16.0.250:http           172.16.0.14:58164
TIME-WAIT  0      0             172.16.0.250:http           172.16.0.1:14654
TIME-WAIT  0      0             172.16.0.250:http           172.16.0.14:58165
<snip>

Lauschende Ports

Alle offenen Ports auflisten
$ ss -l | less
 
State      Recv-Q Send-Q      Local Address:Port          Peer Address:Port
LISTEN     0      50              127.0.0.1:netbios-ssn              *:*
LISTEN     0      128                     *:59532                    *:*
LISTEN     0      128                    :::sunrpc                  :::*
LISTEN     0      128                     *:sunrpc                   *:*
LISTEN     0      128                     *:http                     *:*
LISTEN     0      128                    :::38386                   :::*
LISTEN     0      128                    :::ssh                     :::*
LISTEN     0      128                     *:ssh                      *:*
LISTEN     0      128             127.0.0.1:6010                     *:*
LISTEN     0      128                   ::1:6010                    :::*
LISTEN     0      50              127.0.0.1:microsoft-ds             *:*
LISTEN     0      50              127.0.0.1:mysql                    *:*
Nur TCP auflisten
$ ss -lt | less
 
State      Recv-Q Send-Q      Local Address:Port          Peer Address:Port
LISTEN     0      50              127.0.0.1:netbios-ssn              *:*
LISTEN     0      128                     *:59532                    *:*
LISTEN     0      128                    :::sunrpc                  :::*
LISTEN     0      128                     *:sunrpc                   *:*
LISTEN     0      128                     *:http                     *:*
LISTEN     0      128                    :::38386                   :::*
LISTEN     0      128                    :::ssh                     :::*
LISTEN     0      128                     *:ssh                      *:*
LISTEN     0      128             127.0.0.1:6010                     *:*
LISTEN     0      128                   ::1:6010                    :::*
LISTEN     0      50              127.0.0.1:microsoft-ds             *:*
LISTEN     0      50              127.0.0.1:mysql                    *:*
Nur UDP auflisten
$ ss -lu | less
 
State      Recv-Q Send-Q      Local Address:Port          Peer Address:Port
UNCONN     0      0                       *:bootpc                   *:*
UNCONN     0      0                       *:sunrpc                   *:*
UNCONN     0      0              172.16.0.75:ntp                      *:*
UNCONN     0      0               127.0.0.1:ntp                      *:*
UNCONN     0      0                       *:ntp                      *:*
UNCONN     0      0            172.16.255.255:netbios-ns               *:*
UNCONN     0      0              172.16.0.75:netbios-ns               *:*
UNCONN     0      0                       *:netbios-ns               *:*
UNCONN     0      0            172.16.255.255:netbios-dgm              *:*
UNCONN     0      0              172.16.0.75:netbios-dgm              *:*
UNCONN     0      0                       *:netbios-dgm              *:*
UNCONN     0      0                       *:37222                    *:*
UNCONN     0      0               127.0.0.1:746                      *:*
UNCONN     0      0                       *:858                      *:*
UNCONN     0      0                      :::sunrpc                  :::*
UNCONN     0      0                     ::1:ntp                     :::*
UNCONN     0      0        fe80::250:56ff:feb2:6063:ntp             :::*
UNCONN     0      0                      :::ntp                     :::*
UNCONN     0      0                      :::858                     :::*
UNCONN     0      0                      :::38139                   :::*
Prozess-IDs zu den jeweiligen Diensten mit anzeigen
ss -lp

Anzeige mit Filterung

Die Filter können im iproute(2)-doc nachgeschlagen werden.

Nach Port:
Alle SSH Verbindungen:
$ ss -t src :22
 
State      Recv-Q Send-Q      Local Address:Port          Peer Address:Port
ESTAB      0      0              172.16.0.75:ssh           172.16.0.12:62708
Alle HTTP oder HTTPS Verbindungen
$ ss -t '( src :80 or src: 443 )'
 
State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port
ESTAB      0      0               172.16.0.250:80             172.16.0.239:59538
Nach Adresse in CIDR Notation, nur TCP (-t!)
$ ss -t  dst 172.16.0.0/24
oder single Host:
$ ss -t dst 172.16.0.123
oder mit Host und Port
$ ss -t dst 172.16.0.123:80
Aktive (state established) TCP-Sessions
$ ss -t state established | less
 
Recv-Q Send-Q           Local Address:Port               Peer Address:Port
0      0                   172.16.0.75:58739                 172.16.0.2:microsoft-ds
0      0                   172.16.0.75:51709                 172.16.0.3:microsoft-ds
0      0                   172.16.0.75:39253                 172.16.0.3:1025
0      0                   172.16.0.75:ssh                 172.16.0.123:62708
Mögliche weitere States:
  • established
  • syn-sent
  • syn-recv
  • fin-wait-1
  • fin-wait-2
  • time-wait
  • closed
  • close-wait
  • last-ack
  • closing
  • all - Alle..
  • connected - Alle verbundenen Sessions
  • synchronized - Alle verbundenen Sessions, ohne syn-sent
  • bucket - minisockets, z.B. time-wait und syn-recv.
  • big - „Normale“ sockets

Statistiken

$ ss -s
 
Total: 364 (kernel 449)
TCP:   1272 (estab 19, closed 1240, orphaned 1, synrecv 0, timewait 1238/0), ports 825
 
Transport Total     IP        IPv6
*         449       -         -
RAW       0         0         0
UDP       11        11        0
TCP       32        32        0
INET      43        43        0
FRAG      0         0         0

Verbindungen mitschneiden

Bei Netzwerk/Verständnis-Problemen können Verbindungen mitgeschnitten werden, dazu wird TCPdump genutzt. Die geschriebene Datei kann dann mit WireShark verarbeitet/gelesen werden.
Format:
$ tcpdump -n -i $INTERFACE -s$MAXIMALEPAKETGRÖßE -w $AUSGABEDATEI $FILTER
 
-s = maximale Paketgröße, 0 => 65535 Bytes (empfehlenswert)
-n = keine DNS Auflösung
-i = Interface
-w = Ausgabedatei

Filter

Alles was einen bestimmten Host betrifft (IP oder DNS-Name)
$ tcpdump -ni lanbond0 -w ~/http_mitschnitt.pcap -s0 host 172.16.0.5
Alles was HTTP betrifft, ohne SSH Verbindungen
$ tcpdump -ni lanbond0 -w ~/http_mitschnitt.pcap -s0  port not ssh and port http

Beispiel

Welche Daten werden bei einem Request mittels HTTP und Host 172.16.0.5 übertragen:
$ tcpdump -ni lanbond0 -w ~/http_mitschnitt.pcap -s0 host 172.16.0.5 and port http

Montag, 6. Januar 2014

How-To: Backup/Snapshots mehrerer Oracle Datenbanken mittels NetApp

Um Oracle Datenbanken zu sichern gibt es mehrere Wege:

Alle Technologien haben jeweils Ihre Vor- und Nachteile, auf diese möchte ich jetzt nicht eingehen, dieses Thema behandle ich in einem weiteren Blogpost in naher Zukunft.

Heute möchte ich mich auf die Sicherung mehrerer Oracle Datenbanken mittels Snapshottechnologie beziehen, welche als LUNs via ASM angebunden sind.

Beim manuellen Weg würde man die Datenbank in den Backup Modus (z.B. via sqlplus als sysdba) versetzen ("ALTER DATABASE BEGIN BACKUP"), einen Log-Switch durchführen ("ALTER SYSTEM ARCHIVE LOG CURRENT"), sich dann auf die NetApp mittels SSH aufschalten und den Snapshot anlegen lassen ("snap create VOLUME_NAME SNAPSHOT_NAME").

Dieses Verfahren mag bei einer Datenbank noch gut funktionieren, allerdings kommt man schnell in Zeitnot oder könnte einige Schritte vergessen, daher bietet es sich die Automatisierung an.

Ein weiterer Effekt, den man betrachten muss, sind mehrere, unterschiedliche Datenbanken, welche voneinander abhängig sind, d.h. die den gleichen Stand haben müssen, dort sollte man dann zwingend automatisieren.

Dieses habe ich im Rahmen eines Projekts gemacht und möchte hier das Perl-Skript kurz präsentieren, vielleicht hilft es noch anderen Leuten.

Vorab, das Perl-Skript bietet sicher noch den einen oder anderen Optimierungsspielraum, allerdings geht es im Projektgeschäft primär um das Erfüllen der Anforderungen, das "schön" machen ist dann ein nice-to-have, falls noch Zeit über ist.

Folgende Prerequisistes benötigt das Skript, welches auf dem Oracle Host ausgeführt werden soll:
  • Anpassung der Konfigurationsvariablen in den Zeilen: 9, 22, 72, 232
  • DBD::Oracle (z.B. via CPAN, Paketmanager, Oracle Instant Client oder eine volle Oracle Datenbank [das Skript ist auf diesen Fall konfiguriert, siehe Zeile "use lib xxx"])
  • DBI
  • Net::SSH::Expect (via CPAN)
  • Key-based SSH-Login auf der NetApp mit möglichst wenigen Rechten (wie z.B. hier beschrieben: http://cmdcmplt.wordpress.com/category/ssh-snapshot-filer-netapp-passwordless-roles/ Achtung: bei neueren OnTap Versionen wird als zusätzliches Recht: ssh-login benötigt: useradmin role modify snaps -a login-ssh,cli-snap*)
  • Volume-Name auf der NetApp: Diskgroup-name  + Zusatz "_vol" z.B. DATA_DB1_vol

#!/usr/bin/perl -w
# Author: Oliver Skibbe oliskibbe (at) gmail.com
# Date: 2014-01-06
# Purpose: Backup multiple Oracle ASM Databases with NetApp and snapshotting
#
#
use strict;

use lib "/u01/app/oracle/11.2.0.3/perl/lib/site_perl/5.10.0/x86_64-linux-thread-multi";

use DBI;
use Net::SSH::Expect;

# debug stuff
my $debug = 0;
my $self = undef;

# config stuff
my $auto_snaps = 5;

# databases to backup 
my %sidhash = (
    "DB1" => 
       {
       "data" => "DATA_DB1",
       "archive" => "ARCHIVE_DB1",
       "password" => 'PASSWORD'
       },
    "DB2" => 
       {
       "data" => "DATA_DB2",
       "archive" => "ARCHIVE_DB2", 
       "password" => 'PASSWORD' 
       },
    "DB3" => {
       "data" => "DATA_DB3",        
       "archive" => "ARCHIVE_DB3", 
       "password" => 'PASSWORD'
       },
); # end sidhash

### oracle connect stuff
# db handler
my $dbh = undef;
my $sth = undef;
# connect options
## ora session mode 2: sysdba
my $connecthash = { RaiseError => 0, RowCacheSize => 16, AutoCommit => 0, PrintError => 0,
              ora_session_mode => 0x0002 };
my $dsn = undef;
# user & pass
my $username = "sys";

# helper arrays
my @data_arr;
my @archive_arr;
my @row;

# backup sqls
my $b_begin_backup_sql = "alter database begin backup";
my $b_end_backup_sql = "alter database end backup";
my $b_archive_log_sql = "alter system archive log current";
my $b_control_file_trace_sql = "alter database backup controlfile to trace as '/backup/controlfiles/controlfile_PLACEHOLDER.sql' reuse";
my $b_control_file_sql = "alter database backup controlfile to '/backup/controlfiles/controlfile_PLACEHOLDER.ctl' reuse";

##################################################
#  SSH Stuff         #
##################################################

# prepare ssh object
my $ssh = Net::SSH::Expect->new (
    host => "NETAPP_HOST",
    user => 'SNAPSHOT_USER',
    raw_pty => 1
);

# just a little dumper
sub dump {
 my $message = shift || "";
 printf "%s \n", Data::Dumper::Dumper($message);
}

# begin backup, switch archive log, controlfiles
sub begin_backup { 
 foreach my $sid ( keys %sidhash ) {

  print "START: ", $sid, "\n" if $debug;
  # connect to each database
  $dsn = sprintf "DBI:Oracle:%s", $sid;
  $dbh = DBI->connect(
   $dsn, 
   $username,
   $sidhash{$sid}{'password'},
   $connecthash) || die( "begin_backup: " . $DBI::errstr . "\n" );
  
  # reuse sql for all SIDs
  (my $sid_b_control_file_trace_sql = $b_control_file_trace_sql) =~ s/PLACEHOLDER/$sid/;
  (my $sid_b_control_file_sql = $b_control_file_sql) =~ s/PLACEHOLDER/$sid/;
  
  # begin backup
  $dbh->do($b_begin_backup_sql);
  # log switch
  $dbh->do($b_archive_log_sql);
  # controlfile trace sql
  $dbh->do($sid_b_control_file_trace_sql);
  # control file
  $dbh->do($sid_b_control_file_sql);
  
  # db disconnect
  $dbh->disconnect if defined($dbh);  
 }
}

sub manage_snapshots {
 my $diskgroup = shift;
 my $snapshot = $ssh->exec(sprintf "snap list %s", $diskgroup);
 my $snapshot_name = undef;
 
 # if return value includes "no snapshot exists", create first snapshot
 if ( $snapshot =~ /No snapshots exist/ ) {
  $snapshot_name = "AUTO_${diskgroup}_1";
  print "No auto shapshot for ", $diskgroup, " found, lets create ", $snapshot_name, "\n" if $debug;
 } else {
  # get all elements of interest
  my @snapshots = $snapshot =~ /AUTO_${diskgroup}_\d+/g;
  my $snapshot_count = @snapshots;
  
  if ( $snapshot_count >= $auto_snaps ) {
   # delete oldest snapshot
   my $snapshot_delete = $ssh->exec(sprintf "snap delete %s %s", $diskgroup, $snapshots[-1]);
   # new snapshot name
   $snapshot_name = $snapshots[-1];
  } elsif ( $snapshot_count == 0 ) {
   $snapshot_name = "AUTO_${diskgroup}_1";
  } else {
   my @list;   
   foreach my $snapshot ( @snapshots ) {
    push(@list,substr($snapshot,-1));
   }
   @list = sort(@list);
   print "List: ", @list, "\n\n" if $debug;
   
   my $lo = 0;
   my $hi = $auto_snaps;
   
   my $idx = 0;
   for (my $cnt=$lo;$cnt<=$hi;$cnt++) {
    if ($cnt == $list[$idx]) {
     $idx++;
    } else {
     # free index will be used for name
     $snapshot_name = sprintf "AUTO_%s_%s", $diskgroup, $cnt;
    }
   }
  }  
 }
 print "Snapshot: ", $snapshot_name, " for diskgroup ", $diskgroup, " will be created\n";
 # create snapshot
 my $create_snapshot = $ssh->exec(sprintf "snap create %s %s", $diskgroup, $snapshot_name);
}

sub end_backup {
 my $dbh = undef;
 foreach my $sid ( keys %sidhash ) {
  print "END: ", $sid, "\n" if $debug;
  # connect to each database
  $dsn = sprintf "DBI:Oracle:%s", $sid;
  $dbh = DBI->connect(
   $dsn, 
   $username,
   $sidhash{$sid}{'password'},
   $connecthash) || die( "end_backup: " . $DBI::errstr . "\n" );
  $dbh->{TraceLevel} = 0;
  # end backup
  $dbh->do($b_end_backup_sql);
  
  # disconnect
  $dbh->disconnect if defined($dbh);
 }
}

# base sql to get groups and generate volume names, assumption: volume name is asm diskgroup name + _vol e.g. DATA_VISITOUR_1_vol
my $diskgroup_sql = 'SELECT
    d.GROUP_NUMBER, 
    g.NAME AS groupname, 
    d.NAME, 
    LOWER (d.NAME)||\'_vol\' AS volume 
   FROM 
    v$asm_diskgroup g, 
    v$asm_disk d 
   WHERE 
    d.GROUP_NUMBER = g.GROUP_NUMBER 
    AND g.NAME IN (?,?,?)';

#####################################
# Begin Backup      #
#####################################

begin_backup();

# prepare arrays for sql statement
foreach my $sid ( keys %sidhash ) {
 push(@data_arr, $sidhash{$sid}{'data'});
 push(@archive_arr, $sidhash{$sid}{'archive'});
}

# now start the ssh process
$ssh->run_ssh() or die "SSH process couldn't start: $!";
#
#$ssh->timeout(10); 
sleep(3);
# you should be logged on now. Test if you received the remote prompt:
my $counter = 0;
while ($counter <= 10) {
 if ($ssh->read_all(10) =~ />\s*\z/) {
  # break out if login prompt
  last;
 } else {
  $ssh->run_ssh();
 }
 $counter++;
}

# disable terminal translations and echo on the SSH server executing on the server the stty command:
$ssh->exec("stty raw -echo");

##################################################
# Get Diskgroups          #
##################################################
$dbh = DBI->connect(
 'DBI:Oracle:DB1', 
 $username,
 $sidhash{'DB1'}{'password'},
 $connecthash) || die( "get_diskgroup: " . $DBI::errstr . "\n" );

# parse and prepare query
$sth = $dbh->prepare($diskgroup_sql);

##############################
# DATA SNAPSHOTS    #
##############################
# execute query for data diskgroups
$sth->execute(@data_arr);

# create snapshots for each data volume on atlas-2
while (my @row = $sth->fetchrow_array()) {
 # create, delete snapshots
 manage_snapshots($row[3]);
}

# executes end backup sql
end_backup();

##############################
# ARCHIVE SNAPSHOTS   #
##############################
# log switch
$dbh->do($b_archive_log_sql);

# execute query for archive diskgroups
$sth->execute(@archive_arr);

# create snapshots for each archive volume on atlas-2
while (my @row = $sth->fetchrow_array()) {
 # create, delete snapshots
 manage_snapshots($row[3]);
}

END {
 # closes the ssh connection
 $ssh->close() if defined($ssh);
 # closes db handler
    $dbh->disconnect if defined($dbh);
}
# EOF


Folgende Schritte führt das Skript aus:
  • Über einen Hash (Zeile: 22) werden 1-n Datenbanken in den Backup-Modus versetzt, ein Log-Switch wird durchgeführt, ein Trace Controlfile und das Plain SQL Controlfile werden exportiert.
  • SSH Login (Zugangsdaten Zeile 72,73) zur NetApp
  • Hole alle Diskgroups, aus den konfigurierten Datenbanken (Quell-DB-Name ist dort hardcodiert, siehe Zeilen 232 und 234)
  • Starte für jede DATA Diskgroup (es wird angenommen, dass die NetApp Volumes im Format: DISKGROUP_vol benamt wurden) die Snapshoterstellung (Format: VOLNAME_1-X (siehe dazu Zeile 19, maximale Anzahl von Snapshots), der älteste Snapshot wird jeweils vorher gelöscht, wenn die maximale, konfigurierte Anzahl erreicht wurde
  • Beende Backup-Modus
  • Weiterer Log-Switch
  • Snapshoterstellung für die Archive Log Volumes im gleichen Format wie bei den Data Diskgroups
  • Ende..

Kleiner Hinweis: In der Schleifenlogik für die Erstellung  der Snapshotnamen gibt es noch einen kleinen Bug, bei der Generierung des Namens für den zweiten Snapshot, hat aber keine Einschränken auf den Produktiveinsatz.

Und hier natürlich noch der Download-Link: https://dl.dropboxusercontent.com/u/9482545/smo_backup.pl


Bei Fragen bitte wie immer melden.