Selfnet Blog

Jul 02, 2017

Ceph storage upgrade post mortem

Unser Servernetz besteht hauptsächlich aus virtuellen Maschinen auf VM-Hosts, deren Daten in einem Storage-Cluster (SAN) verteilt liegen. Die Maschinen sind aus Redundanzgründen aufgeteilt auf verschiedene Standorte in Vahingen und Stadtmitte. Wichtige Dienste (z.B. DHCP, DNS) sind auch redundant auf mehreren VM-Hosts verteilt.

Wir haben vorgestern (nach dem AOA) und gestern auf unserem Storage-Cluster ein Update der Ceph Version von "Hammer" auf "Jewel" durchgeführt. Gleichzeitig haben die Admins von unseren VM-Hosts diese auf ein aktuelles Debian geupdated.

Damit es nicht zu Ausfällen kommt, haben wir auf einem unserer 3 VM-Hosts (den in der Stadt) alle wichtigen VMs am laufen gehalten.

Das Update vom Ceph-Cluster lief anfänglich gut, bis auf eine kurze Downtime. Das Cluster hat Lese- und Schreibzugriffe blockiert, weil kurzzeitig zu wenige Teile vom Cluster online waren. Aber dann waren auch alle Clusterknoten auf der neusten LTS Version.

Das "Upgrade" der VM-Hosts wurde zu einer Neuinstallation, damit alles mal wieder sauber und gleichmäßig aufgesetzt ist. Daher hat das länger als geplant gedauert. Besonders kamen hier unerwartete Inkompatibilitäten zwischen Betriebssystem, verwendeter Virtualisierungssoftware und Storage zu Tage, welche den Prozess weiter verzögerten.

Die wichtigsten VMs (auf dem KVM-Host in der Stadt) konnten dann leider unerwarteterweise nicht mehr mit der neuen Ceph Version reden und damit waren auch DHCP/DNS-Dienste nicht mehr verfügbar. Das war Freitagbend gegen viel-zu-spät Uhr und das war auch der Zeitpunkt als die ersten Mails von euch eintrudelten :)

Um den Netzbetrieb schnellst möglich wieder herzustellen wurde ein manuelles Upgrade des Linuxes auf dem VM-Host in der Stadt durchgeführt (das dauert leider auch etwas...). Nach dem Upgrade waren die Ceph Versionen wieder kompatibel und die wichtigsten Server konnten wieder gestartet werden. Damit hatten alle (ok fast alle) Nutzer wieder Internetzugriff.

Die Ausfälle haben also lediglich unsere Server betroffen. Unser (Kabel-)Netzwerk ist super stabil und redundant aufgebaut. Die Ausfälle des Internetzugangs rühren daher, dass man ohne DHCP-Server keine IP-Adresse bekommt und ohne DNS-Server keine Domains in IP-Adressen auflösen kann.

Zusätzlich erschwerend kam hinzu, dass es aktuell ungelöste Probleme im Netzwerk zwischen der Serverfarm in der Stadtmitte und den Wohnheimen Pfaffenhof 2 und Bauhäusle gibt. Dieses Problem sorgt zum Beispiel dafür, dass der zweite DHCP-Server in der Stadt seine Antworten nicht an eure Computer in den betroffenen Wohnheimen schicken kann, die Pakete gehen unterwegs verloren oder kommen so kaputt an, dass sie verworfen werden. Daher kamen die meisten eurer E-Mails auch aus den besagten Wohnheimen.

Wenn du es geschafft hast bis hier zu lesen: Komm doch demnächst nach dem Support mal bei uns vorbei und lass dir alles zeigen. Wir sind auf der Suche nach neuen und motivierten Mitgliedern. Du lernst hier spannende Dinge und hast die Möglichkeit mit neuer cooler Hardware zu spielen.

Feb 09, 2015

Plastikonf, dumping the flash

The last time, I analyzed the the hardware and figured out where the firmware is stored. So let's dump it. The datasheet tells us, that the flash IC has an SPI interface. Now we need something that adapts SPI to a more common interface like preferably USB. There are several devices to to this:

  • Use some microcontroller and write firmware for it that reads the SPI flash and dumps its contents via UART/USB. Downside: have to write code for microcontroller, hard to debug
  • Bus Pirate already supports SPI flashes. Unfortunately, Selfnet doesn't have one.
  • FTDI also makes USB to SPI converters besides USB to UART. I didn't have one at hand either, but I've had existing code for using certain FTDI bridges as USB - SPI converts.

So I purchased the FT2232H Mini Module and built an adapter to connect the SPI flash to it.

Picture of FT2232H Setup

The FT2232H contains a so called MPSSE (Multi-Protocol Synchronous Serial Engine) to do SPI. Side note: FTDI claims that the MPSSE also supports I²C, but since the FT2232H doesn't have open-drain outputs and has some glitching issues, it's really painful to implement. Since my existing code was developed on Windows™, it used the proprietary FTD2XX driver. After some fiddling, I got ftd2xx to work on python 3. Sorry, libftdi people :(

Implementing the protocol used by the SPI flash was rather straightforward since its datasheet is available. One particular nice aspect of the protocol is that you can read an arbitrary amount of data after sending the start address. So I hacked an IPython notebook to dump the flash. Magically, it worked the first time, therefore I didn't bother to clean it up to make it publishable.

That's inside the romdump:

$ binwalk romdump

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
94976         0x17300         U-Boot version string, "U-Boot 1.1.3 (Dec  4 2013 - 08:55:41)"
131584        0x20200         LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 3515396 bytes
1441792       0x160000        Squashfs filesystem, little endian, version 4.0, compression:lzma (non-standard type definition), size: 5051300 bytes,  627 inodes, blocksize: 131072 bytes, created: Fri Jun 20 05:19:24 2014
8126480       0x7C0010        XML document, version: "1.0"

In the next post, we'll dig into the romdump.

Feb 08, 2015

Graphing interface errors with M R T G

If you ever want to graph interface errors with MRTG you'll find a few posts on mrtg related mailing lists, however none of them seemed to work with our installation of MRTG. There is no native support in MRTG but you can specify a template for interfaces via the experimental --if-template flag. The following code is based on an example by Tobias Oetiker, I have merely added support for multiple OIDs via a for loop. The code is ugly, but it works.

There is one kink to be aware of though: Since there is not always an evenly matched set of ifIN/ifOUT OIDs I've decided to graph all OIDs on their own. This is achieved by setting

1
Options[$target]: noo

for each OID and by that making sure that MRTG doesn't render 'outgoing' data.

To configure the template you have to fill the 3 arrays special_oid_name, special_oid and special_oid_desc according to your needs, I have included some example OIDs below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Author: Tobias Oetiker <tobi@oetiker.ch>  
# Date: 2006-09-06  
# Purpose: Add an Error graph for each Traffic Graph  
# 02/07/2015: add juniper interface errors / Hannes Rist  
# i am soooo sorry for this  
# see http://www.oidview.com/mibs/2636/JUNIPER-IF-MIB.html  
my @special_oid_name = ('ifJnxInFrameErrors', 'ifJnxInQDrops','ifJnxInRunts');
my @special_oid = ('1.3.6.1.4.1.2636.3.3.1.1.10','1.3.6.1.4.1.2636.3.3.1.1.11','1.3.6.1.4.1.2636.3.3.1.1.12');
my @special_oid_desc = ('Framing Errors: The number of input packets which were misaligned.','Drops: The number of packets dropped by the input queue ofthe I/O Manager ASIC.','Runts: Frames received that are smaller than the runt threshold.');
#$target_lines = $default_target_lines."\n";
for (my $i = 0; $i < @special_oid_name; $i++) {
 my $el = $default_target_lines;
 $el =~ s/^(Target\S+:\s+).+/${1}$special_oid[$i]$if_ref&$special_oid[$i]$if_ref:$router_connect/m; # Error Target
 $el =~ s/^([^\s\]]+)/${1}.$special_oid_name[$i]/gm; # Filename for error log and graphs
 $el =~ s|</h1>| - $special_oid_name[$i]</h1><span style="color: white; background-color: black;">$special_oid_desc[$i]</span><br />|i;
 $el =~ s|^(Title\[.+)|$1 - $special_oid_name[$i]|mi;
 $el =~ s/Traffic/$special_oid_name[$i]/;
 $el =~ s/^(MaxBytes)(\S+)\s+\d+/$1$2 10000/m;  # more than 10'000 errors a second are BIG trouble anyway
 $el .= <<LEGEND;
YLegend$2 $special_oid_name[$i] per Minute
ShortLegend$2 e/min
Legend1$2 $special_oid_name[$i] per Minute
Legend3$2 Maximal 5 Minute $special_oid_name[$i]
LegendI$2 &nbsp;$special_oid_name[$i]:
Options$2 perminute,noo
LEGEND

  if (oid_pick($router_connect,$v3opt,"$special_oid[$i].$if_index")){
        $target_lines .= $el;
  }
  $target_lines =~ s{<tr>\s+<td>(.+?)</td>\s+<td>(.+?)</td>\s*</tr>}{<tr><td>$1</td>\t<td>$2</td></tr>}g;

}

If you want to use it the template has to be passed as an argument to cfgmaker like so (Line 13):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
/usr/bin/cfgmaker \
    --global 'workdir: /var/www/mrtg-rrd' \
    --global 'Forks: 5' \
    --global 'LogFormat: rrdtool' \
    --global 'Options[_]: bits' \
    --global 'WithPeak[_]: ymw' \
    --no-down \
    --show-op-down \
    --ifref=name \
    --ifdesc=alias \
    --enable-ipv6 \
    --if-filter="$default && !($if_type ~~ [1, 53, 131])" \
    --if-template=if_errors.tmpl \
    public@$device:::::2 \
    >> $device_err.cfg

After that running MRTG with $device_err.cfg will create graphs like this one:

Picture of RRDTOOL Graph

I hope this article is of some help and spares you of many hours searching the web.

← Previous Next → Page 9 of 11