Seit ein paar Monaten setzen wir auf unseren Server Borg-Backup für die inkrementellen Backups ein. Gerade am Anfang war dies etwas schwierig zu überwachen, da man alle Backup-Server und alle Repositories einzelnd mit borg stats
oder borg list
überprüfen musste.
Nun kam mir der Gedanke, die Ausgabe von borg stats
in unsere Munin-Graphen einfließen zu lassen. Da unsere Server mit Ansible bespielt werden, verteile ich zwei Skripte mittels Ansible in das Munin-Plugin-Verzeichnis. Hier ein Auszug aus dem Ansible-Task:
- name: 'Munin-Skripte anlegen' template: dest: /etc/munin/plugins/borg_backup_chunks_{{ item.value.pool | regex_replace('/', '_') }}_{{ item.value.host}} mode: 0755 owner: root src: munin_chunks.py with_dict: '{{ borg_host_repositories }}' notify: restart munin-node - name: 'Munin-Skripte anlegen' template: dest: /etc/munin/plugins/borg_backup_sizes_{{ item.value.pool | regex_replace('/', '_') }}_{{ item.value.host}} mode: 0755 owner: root src: munin_sizes.py with_dict: '{{ borg_host_repositories }}' notify: restart munin-node - name: 'Munin Zugriff auf Stats gewähren' file: path: "{{ item.value.pool }}/{{ item.value.host }}_stats.json" owner: borg-backup group: borg-backup mode: 0644 state: touch access_time: preserve modification_time: preserve with_dict: '{{ borg_host_repositories }}'
Es folgt die Datei für Chunks. Diese muss dann entsprechend in dem Template-Verzeichnis des Ansible-Tasks liegen:
#!/usr/bin/env python import sys import json if len(sys.argv) > 1 and sys.argv[1] == 'config': print("graph_title Borg Backup Chunks {{ item.value.pool }}/{{ item.value.host}}") print("graph_args --base 1000 -l 0") print("graph_category backup") #print("graph_vlabel files\n") print("total_chunks.label total_chunks") print("total_chunks.draw AREA") print("total_unique_chunks.label total_unique_chunks") print("total_unique_chunks.draw AREA") sys.exit(0) with open('{{ item.value.pool }}/{{ item.value.host }}_stats.json', 'r') as myfile: data=myfile.read() obj = json.loads(data) print("total_chunks.value " + str(obj['cache']['stats']['total_chunks'])) print("total_unique_chunks.value " + str(obj['cache']['stats']['total_unique_chunks']))
Das gleiche gilt für die folgende Datei, die nur andere Werte (Dateigröße) und somit eine Basis von 1024 hat:
#!/usr/bin/env python import sys import json if len(sys.argv) > 1 and sys.argv[1] == 'config': print("graph_title Borg Backup Sizes {{ item.value.pool }}/{{ item.value.host}}") print("graph_args --base 1024 -l 0") print("graph_category backup") #print("graph_vlabel files\n") print("total_csize.label total_csize") print("total_csize.draw AREA") print("total_size.label total_size") print("total_size.draw AREA") print("unique_csize.label unique_csize") print("unique_csize.draw AREA") print("unique_size.label unique_size") print("unique_size.draw AREA") sys.exit(0) with open('{{ item.value.pool }}/{{ item.value.host }}_stats.json', 'r') as myfile: data=myfile.read() obj = json.loads(data) print("total_csize.value " + str(obj['cache']['stats']['total_csize'])) print("total_size.value " + str(obj['cache']['stats']['total_size'])) print("unique_csize.value " + str(obj['cache']['stats']['unique_csize'])) print("unique_size.value " + str(obj['cache']['stats']['unique_size']))
Wenn man sich den Python-Code ansieht, entdeckt man, dass eine JSON-Datei erwartet wird. Diese lasse ich im Cronjob nach dem Löschen der überflüssigen Backups (borg prune
) erstellen:
/usr/local/bin/borg info --json {{ repo.pool }}/{{ repo.host }} > {{ repo.pool }}/{{ repo.host }}_stats.json
Nach einem Neustart der Munin-Nodes werden auch diese Daten ausgewertet und erzeugen alle 5 Minuten neue Graphen. Da ich meinen Cronjob zum Erzeugen der JSON-Stats-Datei nur Nachts ausführe, erhalten ich nur dort eine Änderung. Für das einfache Überwachen der Größe eines Repositories reicht dies aus. Für die generelle Überwachung der Backups nutzen wir zusätzlich Icinga2.