Fontawesome Upgrade von Version 5 auf Version 6

Dienstag, 23. Mai, 2023

Um Fontawesome von Version 5 auf 6 zu aktualisieren, gibt es einen Upgrade-Guide [1].

Aber das ist viel zu kompliziert :-)

nachdem ich einige Web-projekte umgestellt habe (das Intranet unseres Instituts, IML Appmonitor, ahCrawler, Pimped Apache Status) kann ich meinen Ansatz präsentieren:

  1. Man entferne das eingebundene CSS File von Fontawesome 5 und ersetze es durch das der Version 6, z.B.:
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
  2. Die meisten Icons sollten nach wie vor da sein. Aber wir aktualisieren einmal die Schreibweise der CSS Klassen für die Version 6.
  3. im Projektordner Suchen und Ersetzen “fas fa” –> “fa-solid fa”
  4. im Projektordner Suchen und Ersetzen “far fa” –> “fa-regular fa”

Damit sind 98% erledigt. Nun sollte man die Webseite nochmal genau anschauen. Es kann sein, dass es noch das ein oder andere Prefix umzustellen gilt (z.B. für Brands). Oder aber es gibt auch einige (wenige) Icons, die nun anders heissen - wenngleich sich diese vielleicht nur schwer finden lassen - für diese muss man in [2] die neue Schreibweise ermitteln.

Viel Glück bei der Umstellung!

Weiterführende Links:

  1. Fontawesome.com: Upgrade (en)
  2. Fontawesome.com: frei verwendbare Icons durchsuchen (en)

Pimped Apache Status - PHP 8.2 kompatibel

Montag, 22. Mai, 2023

Der Pimped Apachestatus ist ein Webtool, dass die etwas schwer verdauliche Apache Serverstatus Page aufbereitet. Es gibt verschiedene Ansichten, sortier- und filterbare Tabellen und Graphen. Das ganze funktioniert nicht nur für einen einzelnen Server, sondern auch für mehrere Webhosts, z.B loadbalante Webeiten.

2023-05-22-pimped-apache-status.png

Am Wochenende gab es ein Update, in dem einige Vendor-Bibliotheken aktualisiert wurden.

Da die als kompatibel bestätigte Version 8.0 alsbald ausläuft, wurde es mit neueren PHP Versionen getestet. Es ist nunmehr PHP 8.2 kompatibel.

Zum Aktualisieren meldet sich der Updater. Bei Installationen mit git bitte git pull verwenden.

Weiterführende Links:

Timeshift und Prozentrechnung

Sonntag, 2. April, 2023

Timeshift speichert Snapshots eines Linux-Systems. Es kann sich u.a. als Hook in den Paketmanager einklinken und vor jedem Update einen Snapshot anlegen, um im Falle eines Nicht-Funktionierens zurückzurollen.

  • Wenn die Snapshots auch auf der Systemdisk abgelegt werden, wird das Grub-Menü um die Auswahl der letzten Snapshots erweitert.
  • Falls nicht, wird ein Rsync zum Sichern des Snapshots bemüht. Wenn man sein Linux booten kann (also notfalls von USB Stick), kann man Timeshift auch so einen anderen Stand wiederherstellen lassen.

Einen kleinen Schönheitsfehler gibt es aber. Im CLI Modus gibt Timeshift eine Fortschrittsinfo aus. Dumm nur, wenn es bei 100% gar nicht fertig ist.

2023-04-02-timeshift.png

Naja, ich kann darüber hinwegsehen. Wenn der Moment kommt, wo man mal ein Backup braucht, ist man froh um jeden verfügbaren Zwischenstand von so vielen Informationen wie möglich.

Ich fahre auf meinen Linux-PCs mit einer Kombination von Timeshift und Restic (IML Backup). Aber man will ja selbst keinen interaktiven Aufwand und sich nicht darum kümmern. Aber ich weiss, dass ich mich auf das Funktionieren beider Varianten in deren Kombination mit Snapshots und Datei-Backups verlassen kann.

Weiterführende Links

Theme “A touch of glass” aktualisiert

Mittwoch, 29. März, 2023

Ich habe einmal für den Blog Flatpress ein Theme bereitgestellt.

Die schlechte Nachricht: Nach Update auf die aktuelle Flatpress-Version ging leider nicht mehr viel.
Die gute: es war einfach zu beheben.

2023-03-29_atog.png

Weiterführende Links

Ansible git: detected dubious ownership in repository

Mittwoch, 8. Februar, 2023

Wir lassen diverse Applikationen mit Ansible von einem Git-Repository installieren. Etwa so:

- name: 'install - Clone repo {{ repo_url }}'
  ansible.builtin.git:
    repo: '{{ repo_url }}'
    dest: '{{ install_dir }}'

Dummerweise kommt dann noch ein Verschenken der Berechtigungen hinterher.

Seit Kurzem - mit einer neueren Git Version - häufen sich Abbrüche beim Git pull

detected dubious ownership in repository

Und auch die Lösung wird in der Fehlermeldung mitgegeben:

git config --global --add safe.directory [Verzeichnis]

Ja denn … packen wir doch einen Schnipsel hierfür dazu:

# set install dir as safedir ...
- name: "FIX - add installdir {{ install_dir }} as safedir"
  ansible.builtin.shell: |
    git config --global --get-all safe.directory \
      | grep "{{ install_dir }}" \
      || git config --global --add safe.directory "{{ install_dir }}"

Wenn es ein paar mehr Server sind, sollte man sich das in in eine Rolle verpacken, um es etwas abstrakter zu halten.

Zum Reparieren packt man es zur einmaligen Ausführung des Playbooks VOR das ansible.builtin.git … aber dann gehört es dahinter.

Der Shell-Aufruf präft, ob der Pfad bereits aufgenommen ist - nur wenn nicht, wird er hinzugefügt. Ansonsten würde ein mehrfaches “add” zu zigfachen Duplikaten desselben Pfades führen.

Fehlermuster im Streamripper

Dienstag, 3. Januar, 2023

Ich schrieb vor nicht allzu langer Zeit einen Blogeintrag, um in Streamripper2 die Aufnahme-Funktion besser zu nutzen.
Diese muss man konfigurieren - also schlusendlich einen Kommandozeilenaufruf hinterlegen. Klassischerweise wird für Radiostreams das Tool Streamripper konfiguriert - und um eine optische Ausgabe zu haben, setzte man einen Konsolenaufruf davor. Ich fand das sehr bescheiden - sehr oft war bei egenen Versuchen war das Konsolenfenster gleich wieder zu und damit auch eine etwaige Fehlermeldung weg. Das ist doch nur unbefriedigend.

So fing alles an. Ich kann zum Glück etwas Shellprogrammierung.
Es sollte zunächst ein kleiner Wrapper sein, der anzeigt, welches Kommando mit welchen Parametern aufgerufen wird - und im Falle eines Abbruchs mich auch den Fehlertext lesen lässt.

streamtuner2-record-helper.jpg

Aber das wurde schnell etwas mehr, weil ich mit den ersten Versionen des Wrapperskripts nun auch die verschiedenen Fehlerkonstellationen von Streamripper sehen konnte. Mit Hilfe von Curl wurden die Http Response Header angezeigt, was weitere Dinge aufzeigt. So ergaben sich diese Fehlermuster:

Problem: Fehler 404 oder 410.
Lösung: keine - der Stream existiert nicht mehr.

Problem: Fehler 50x
Lösung: Ein Streamingserver arbeitet derzeit nicht oder reagiert nicht schnell genug (Timeout). Lösen kann ich das nicht, aber eine Meldung ausgeben, damit man weiss, dass es wohl ein nur temporäres Problem gibt und man es später wieder versuchen kann.

Problem: die URL ist kein abspielbarer Stream, sondern eine Playlist.
Lösung: Die Playlist wird ausgelesen und die erste Streaming-URL daraus extrahiert. Anm.: Es gibt durchaus auch Playlisten-Typen, die Streamripper versteht.

Problem: Streamipper wird mit einem 403 abgewiesen.
Lösung: Manche Streamingserver verweigern den Zugriff je nach Useragent und unterbinden den Abruf durch den Streamripper. Aber im Kommandozeilenaufruf des Streamrippers kann man den Useragent umschalten.

Problem: Streamriupper meldet -28 [SR_ERROR_INVALID_METADATA]
Lösung: Keine - das ist ein Fehler im Streamripper selbst: er fordert Daten mit Http1.1 an, versteht aber selbst nur Http 1.0 und kommt dann mit der Antwort des Streamingservers nicht klar. Neben dem kurzen kryptischen Fehlercode wird dann ein ergänzender Hinweis eingeblendet. Es gibt einen nicht offiziellen Patch, mit dem man Streamripper neu complilieren kann - da die letzte Streamripperversion 2008 erschien, wird es wohl nicht mehr offiziell gefixt.

Weil es im Streamripper noch Plugins auf MODarchive und Jamendo gibt: ich habe noch Downloads mit Curl ergänzt:

  • für Trackerfiles von MODarchive hinzugefügt (die Benamung der Zieldatei hole ich aus dem Http Response Header aus dem Attachment Filenamen)
  • für jamendo MP3s (die Benamung der Zieldati erfolgt nach Aufruf von ffprobe - welches zu ffmpeg gehört - und wird aus Titel, Künstler und Jahr zusammengesetzt)

Im Dezember erschien die Version 1.1 - diese prüft die benötigten Tools und hat eine Erweiterung in der Cleanup-Funktionalität erfahren.

Die kleinen Heilungsfunktionen und verwertbare Meldungen für ein Debugging im Fehlerfalls sind doch immer hilfreich. Das scheint auch anderen zu gefallen. Mario Salzer verlinkte den Wrapper auf fossil.include-once.org - ich setze hiermit einen Link auch gern zu ihm zurück.

weiterführende Links:

  1. Axels Blog: Streamtuner2 - Aufnahmen/ Downloads
  2. Github: mein ST2 record helper (en)
  3. Docs: mein ST2 record helper (en)
  4. sourceforge - Streamtuner2 Diskussion “ST2 does not record” (en)
  5. fossil.include-once.org: Hilfe zu Streamtuner2 (en)
  6. Streamtuner2 (en)
  7. Streamripper (en)

Bash: starte für zig Server pro Tag etwas auf nur einzelnen Systemen

Dienstag, 22. November, 2022

Ich habe da eine unbekannt lang laufende Aufgabe: ich möchte vom Backup-Tool Restic das Backup-Repository auf Version 2 migrieren. OK, eigentlich ist die Aufgabe ja egal. Alle 100+ Systeme kommen damit nicht in der Nacht durch.

Ich möchte …

  • dass pro Nacht nur einige Systeme eine lang laufende Aufgabe wahrnehmen
  • nach N Tagen soll sichergestellt sein, dass auch alle Systeme den Job 1x gemacht haben.

Mir kam der Modulus in den Sinn. [Weiterlesen…]

Streamtuner2 - Aufnahmen/ Downloads

Montag, 7. November, 2022

Ich habe auf meinem Linux PC Streamtuner2 installiert. Das ist ein Browser von (Radio)Streaming Diensten mit deren Kategorien an Musikrichtungen. Was beim Druck auf [Play] zur Wiedergabe oder [Record] zur Aufnahme passieren soll, lässt sich konfigurieren.

Die Wiedergabe - es ist VLC vorkonfiguriert - funktioniert wunderbar. Das reicht wohl Vielen.

Zur Aufnahmefunktion … huh, da wird es langsam kompliziert. Vorkonfiguriert war das Öffnen eines Terminals. Das nimmt naturgemäss ja noch nichts auf. Das Standardwerkzeug unter Linux ist der Streamripper. Den muss man erst einmal konfigurieren.

Das habe ich gemacht. Einige Radiostreams wieden mir angezeigt, dass sie mitgeschnitten würden. Falls nicht, blitzte - wenn überhaupt - für Sekundenbruchteile ein Fenster hoch. Was nicht geht, warum es nicht geht - das zu analysieren, ist bei dieser Verfahrensweise aussichstlos. Was für ein Frust! Und all die Jahre, die Streamtuner und Streamripper existieren, gab es keine tatsächlich schlaue Lösung in der Doku?

Aber: hey, ich kann ja die Record Taste nach Audio-Typ in der Konfiguration belegen, wie ich will! Dann schreiben wir doch ein Skript, auf dass man sehen kann, was da passiert - und wenn nicht, wieso denn nicht.

Schritt 1

Gesagt - getan: ein Skript zeigt die übergebene URL an und was der Streamripper tut - oder aber bei Abbruch allenfalls an Fehlermeldung zurückwirft. Das Skript ist dann nicht einfach fertig - sondern wartet noch eine vordefinierte Zeit. Das war schön und ein Segen, das endlich einmal tatsächlich sehen zu können, an welcher Stelle und bei welchem Typ Url oder MIME Type er die Segel streicht.

Schritt 2

Manche Muster erkennt man: Streamripper kann bei bestimmten Playlist-URLs diese nicht parsen - er braucht dann hier eine Direkt-URL eines Streams, die man aber aus der Playlist ziehen könnte.

Oder es gibt Plugins, die einen Download eines Files anbieten - also gar keine Radiostreams sind, z.B Jamendo und MODarchive. Und beide benötigen unterschiedliche Handhabungsweisen, was bei einem Download zur Benamung der Zieldatei passieren muss.

Oh, es wird ja kompliziert - gut, wenn man noch nen Tick besser skripten kann.

Schritt 3

Wir bauen mal mehr Logik ein. Und Debugging Ausgabe, wie den Http Response Header.

Mein Downloader-Skript bekommt also eine URL. Es muss feststellen, ob es eine Datei oder eine Streaming URL ist. Dazu prüfen wir mal die URL, ob sie Weiterleitungen besitzt. Das letzte “Location:” im Http-Header bei aktiviertem Follow-Redirects ist meine finale URL zum Analysieren.

Jene Url ist entweder ein Stream oder eine Datei. Wenn es eine Datei ist, dann könnte es entweder eine Playlist sein, aus der man eine Streaming URL beziehen muss - oder eine Datei zum Download.

Seine Streaming Url oder ggf. aus der Playlist extrahierte Streaming URL wird an den Streamripper übergeben.
Ein Download File wird hingegen mit Curl heruntergeladen und je nach Typ wird eine Zieldatei geschrieben.

Ich glaube, mit einer solchen Ausgabeform kann man mit der Aufnahmefunktion und etwaigen bereits etwas mehr anfangen:

st2_record_helper.png

UPDTAES:
2022-11-14 - the helper script reached version 1.0 now.

weiterführende Links:

  1. Gihub: axelhahn st2_record_helper
  2. Streamtuner 2 internet radio directory browser
  3. Streamripper record streams as mp3 to your hard drive
  4. Mitteilung auf Fosstodon

Neues Feature beim IML-Backup: Hooks

Donnerstag, 13. Oktober, 2022

Nachdem vor 2 Wochen das Prune und Verify separat ausführbar und konfigurierbar wurden, gibt es nun ein weiteres Feature: Hooks.

Das Backup läuft wie folgt ab

  • Initialisierung
  • Start der Backups der lokalen Datenbanken (z.B. Mysql, Sqlite)
  • Backup der definierten lokalen Verzeichnisse
  • Prune (Ausdünnen und Löschen alter Backup-Daten)
  • Verify

Die Hooks dienen zum Starten von eigenen Skripten … vor dem Start des Backups und danach sowie auch an mehreren Punkten während des Backups.

Es gibt initial diese Verzeichnisse, die du Skripte ablegen kannst, um sie zu definierten Zeitpunkten zu starten:

> tree -d hooks/
hooks/
|-- 10-before-backup
|   `-- always
|-- 12-before-db-service
|   `-- always
|-- 14-before-db-dump (UNUSED)
|   `-- always
|-- 16-after-db-dump (UNUSED)
|   |-- always
|   |-- on-error
|   `-- on-ok
|-- 18-after-db-service
|   |-- always
|   |-- on-error
|   `-- on-ok
|-- 20-before-transfer
|   `-- always
|-- 22-before-folder-transfer
|   `-- always
|-- 24-after-folder-transfer
|   |-- always
|   |-- on-error
|   `-- on-ok
|-- 26-after-prune
|   |-- always
|   |-- on-error
|   `-- on-ok
|-- 28-after-verify
|   |-- always
|   |-- on-error
|   `-- on-ok
`-- 30-post-backup
    |-- always
    |-- on-error
    `-- on-ok

34 directories

Als am ehesten einleuchtende Beispiele:

  • Vor dem Start des Backups kann man Sachen lokal synchronisieren, die ebenfalls ins Backup einfliessen sollen.
  • Nach dem Backup kann man beispielsweise Notifikationen ins Monitoring oder per E-mail auslösen.

Bei “nach einer Aktion” zu startenden Hooks kann man jeweils getrennte Sets von Skripten starten, sobald eine Aktion OK war … oder aber fehlerhaft … oder aber auch immer (unabhängig vom Status).

Und wie ist es implementiert? Schauen wir mal auf die Bash-Interna.

Es gibt zu den definierten Zeitpunkten im Skript einen Aufruf einer Hook-Funktion - mit dem Hook-Verzeichnis als Namen als Parameter 1 und für “nach einer Aktion” zu startende Hooks den Exitcode als optionalen 2. Parameter. Als willkürliches Beispiel:

_j_runHooks "24-after-folder-transfer" "$myrc"

Die Hookfunktion ruft bei Exitcode 0 die Skripte im “on-ok” Untrverzeichnis - und bei Exitcode > 0 jene vom “on-error”. Anschliessend (oder bei Aufruf ohne einen Exitcode) werden vom jeweiligen Hook die Skripte im Unterverzeichnis “always” verarbeitet.
Die Ausführung der Skripte erfolgt in alphabetischer Reihenfolge - mit der Benamung kann man also die Abfolge der Abarbeitung mehrerer Skripte beeinflussen.

Die Hookfunktion sieht so aus (genaugenommen erschreckend einfach):

...
# ------------------------------------------------------------
# execute hook skripts in a given directory in alphabetic order
# param  string   name of hook directory
# param  string   optional: integer of existcode or "" for non-on-result hook
# ------------------------------------------------------------
function _j_runHooks(){
  local _hookbase="$1"
  local _exitcode="$2"
  local _hookdir="$( dirname $0 )/hooks/$_hookbase"

  if [ -z "$_exitcode" ]; then
    _hookdir="$_hookdir/always"
  elif [ "$_exitcode" = "0" ]; then
    _hookdir="$_hookdir/on-ok"
  else
    _hookdir="$_hookdir/on-error"
  fi
  for hookscript in $( ls -1a "$_hookdir" | grep -v "^." | sort )
  do
    if [ -x "$_hookdir/$hookscript" ]; then
      h3 "HOOK: start $_hookdir/$hookscript ..."
      $_hookdir/$hookscript
    else
      h3 "HOOK: SKIP $_hookdir/$hookscript (not executable) ..."
    fi
  done

  # if an exitcode was given as param then run hooks without exitcode 
  # (in subdir "always")
  if [ -n "$_exitcode" ]; then
    _j_runHooks "$_hookbase"
  fi

  echo
}
...

weiterführende Links:

  1. IML OS Docs - IML Backup: Hooks (en)
  2. IML OS Docs - IML Backup: Startseite (en)

Neue grep Version warnt “warning: stray before white space”

Montag, 10. Oktober, 2022

Ich spiele immer fleissig Updates ein.
Plötzlich überraschen mich meine Shellskripte mit der Ausgabe

grep: warning: stray  before white space

Die Ursache ist schnell gefunden … eine neue Grep Version 3.8 ist aufgespielt worden, die sich offensichtlich anders verhält.

> grep --version
grep (GNU grep) 3.8
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Mike Haertel and others; see
<https://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>.

Ich hielt es bisher immer so: Sonderzeichen MUSS man im Regex maskieren … und beliebige normale Zeichen KANN man immer mit Backslash maskieren und es schadet auch nicht. Letzteres ist nun offensichtlich anders.

> echo "   OK" | grep "\ \ "
grep: warning: stray  before white space
grep: warning: stray  before white space
   OK

Zur Abschaltung der Warnung entferne ich im Regex den einem Space vorangestellte Backslash:

> echo "   OK" | grep "  "
   OK

Yep.
Soweit so gut … alles gut … dachte ich.

Es kamen in anderen Skripten aber auch Meldungen der Art

grep: warning: stray  before -

Also die Suche nach einem Minus muss nun auch nicht mehr mit Backslash maskiert werden? Einmal schnell testen:

> echo "------" | grep "\-\-\-"
grep: warning: stray  before -
grep: warning: stray  before -
------

Backslash weggenommen, hagelt ebenfalls eine Fehlermeldung:

> echo "------" | grep "---"
grep: unrecognized option '---'
Usage: grep [OPTION]... PATTERNS [FILE]...
Try 'grep --help' for more information.

Leider nein.
Die Lösung hier: Nun braucht es als Option ein Doppel-Minus. Und im Regex darf man das Minus nicht maskieren. Also so:

> echo "------" | grep -- "---"
------

Ich fürchte, die neue grep Version wird mich noch in anderen Skripten ärgern.