Datenbank-Inhalte versionieren (betrifft auch: ipfw)

PMc

Well-Known Member
Hi,
ich hab da ein kleines Problem... wer Lust hat sich mit mir den Kopf zu zerbrechen, gute Ideen sind hochwillkommen. (Vielleicht fehlt mir auch nur der richtige Ansatz zum suchen?)

Und zwar geht es darum, dass in einer Datenbank (postgres) bestimmte Informationen gespeichert sind, und ich hätte gern eine Information darüber, wann darin was geändert wurde, und die entsprechenden diffs - so ähnlich wie man das mit GIT oder SVN in einem Dateienbaum realisieren kann.

Gefunden hab ich dazu dieses hier: https://stackoverflow.com/questions/6365710/database-content-versioning
Aber das ist für mein Interesse recht nährwertlos. Klar kann man in Postgres die redologs arichivieren und damit prinzipiell jede Veränderung nachvollziehen, aber diese Daten kann man nicht filtern und nicht sinnvoll lesen.
Ausserdem brauche ich das nicht für die ganze postgres Installation, sondern nur für eine bestimmte Datenbank und darin selektiv für einzelne Objektbäume.

Hintergrund:
Ich hab eine "gewachsene" ipfw Konfiguration, die über die Jahre recht lang geworden ist, so dass ich sie gar nicht mehr anrühren wollte. Wer schon mit ipfw gearbeitet hat, wird wissen dass das etwas verwickelt wird, wenn man NAT und stateful rules und jails und source-based routing drin hat - man braucht dann bedingte Verzweigungen und subroutines oder dergleichen, und das ganze ist keine Freude mehr zu modifizieren.

Als hab ich mir gesagt, es müsste doch möglich sein, nur die Netzwerk-Topologie und die benötigten Flows aufzulisten, und die sich daraus ergebenden Rules dann automatisch zu erzeugen. Hab einen kurzen Blick auf FirewallBuilder geworfen, fand das aber nicht ganz überzeugend, zumal es ipfw nur am rande mit zu unterstützen scheint. Hab also selber was geschrieben.

Das liegt nun in der Datenbank, und zum Bedienen ist ein Ruby-on-Rails obendrauf, und es ist eigentlich jetzt ein echter Genuß, da was zusammenzuklicken.
Nur eben: der Output (die eigentlichen Rules) ist jetzt sozusagen "kompiliert" - das ist zwar logisch richtig und funktioniert, aber man kanns nicht mehr vernünftig lesen. Und im daily.log sieht es auch nur noch so aus:

Code:
+01420       8        320 unreach filter-prohib log ip from any to any
+01730      90      20526 unreach filter-prohib log ip from any to any
+03440     726     148982 unreach filter-prohib log ip from any to any
+05270       8        336 unreach filter-prohib log ip from any to any
+05500     482      25709 unreach filter-prohib log ip from any to any
+07680      12        976 unreach filter-prohib log ip from any to any
+10090     262      25082 unreach filter-prohib log ip from any to any
+10690       3       1560 unreach filter-prohib log ip from any to any

Um das zu verstehen, und um Änderungen nachzuvollziehen, muss man jetzt sozusagen die "source" lesen. Die aber ist eine Tabellenhierariche in der Datenbank - da kann man keine Kommentare reinschreiben oder Zeilen auskommentieren oder ein SVN draufsetzen.

Und da fehlt mir grad die zündende Idee wie man das weiter angehen könnte. Wobei die Lösung an sich echt Spass macht, also ich denke schon dass der Ansatz richtig ist.
 
Richtig gute Ideen hab ich auch nicht. Du könntest die entsprechende DB auf einen eignenen Tablespace legen der auf einem Snapshotbaren FS liegt (z.b. ZFS). Mit einem Script überprüfst du nur ob sich da was geändert hat und machst dann einen Snapshot. Theoretisch müsstest du auch immer die WAL Files mitsichern, da dir PG nur so Konsistenz garantiert, ob das praktischa uch so sein muss kommt wohl drauf an.

Dann hättest du zumindest halbwegs Platzeffizient die Änderungen versioniert, zum Ansehen könntest du mit Clones und einer eigenen DBMS Instanz arbeiten. Ein übersichtliche Darstellung ist das aber sicher nicht, von Diffs ganz zu schweigen.

Da du die Software ja selbst geschrieben hast, wäre es nicht einfacher dort das Logging unterzubringen? Für die einzelnen Objektbäume müsstest du ja nur je eine weitere Tabelle erstellen in die du Stumpf die Änderungen zusätzlich schreibst.
 
Richtig gute Ideen hab ich auch nicht. Du könntest die entsprechende DB auf einen eignenen Tablespace legen der auf einem Snapshotbaren FS liegt (z.b. ZFS). Mit einem Script überprüfst du nur ob sich da was geändert hat und machst dann einen Snapshot. Theoretisch müsstest du auch immer die WAL Files mitsichern, da dir PG nur so Konsistenz garantiert, ob das praktischa uch so sein muss kommt wohl drauf an.

Doch, das gibt Ärger. Ist schon gelegentlich auf der PG Liste diskutiert worden, Tenor: geht nicht.
Das einfachere ist dann, die täglichen DB-Dumps (die von periodic daily sowieso erzeugt werden) aufzuheben - das ganze ist ja nicht groß.

Da du die Software ja selbst geschrieben hast, wäre es nicht einfacher dort das Logging unterzubringen? Für die einzelnen Objektbäume müsstest du ja nur je eine weitere Tabelle erstellen in die du Stumpf die Änderungen zusätzlich schreibst.

Auf sowas wirds hinauslaufen wenn sich nix fertiges anbietet. Das Problem ist aber eigentlich ein generisches, und da deucht es mich wunder ;) wenns da keine existierende Lösung gibt. (Ideal wär eine, die die Revision Control mit in die Web-Oberfläche einbinden läßt.)
Soweit ich mich erinnere, gab es auch im Rails mal ein Tool, das sich "acts_as_versioned" nennt. Hat sich aber seit Jahren niemand mehr dafür interessiert. Muss da auch nochmal weitersuchen...
 
Klingt wie das typische "Ich hab mich in meiner Komplexität verrannt und brauche jetzt eine magische Handvoll noch mehr Komplexität, um noch irgendwas damit machen zu können".

Ich empfehle den Schritt zurück und den Blick aus der Distanz auf das Nötigste.

Wenn ein paar Firewallregeln dermaßen ausufern, ist entweder die Firewall viel zu komplex und macht zu viele Dinge auf einmal oder die Firewall-Software ist richtig kacke. Vielleicht sollte Address Translation, Source Routing und Filterung auf mehrere Kisten aufgeteilt werden.

Ich habe kein Problem, mir für 30+ VLANs die PF-Regeln zu schreiben. Source routing und NAT machen bei mir aber Router mit wenigen Regeln, die keine Policy abbilden müssen.
 
Ich empfehle den Schritt zurück und den Blick aus der Distanz auf das Nötigste.

Aha.

Wenn ein paar Firewallregeln dermaßen ausufern, ist entweder die Firewall viel zu komplex und macht zu viele Dinge auf einmal

Natürlich macht die viele Dinge. (Ich brauche mehrere NAT. Und Traffic-Shaping natürlich auch.)

Vielleicht sollte Address Translation, Source Routing und Filterung auf mehrere Kisten aufgeteilt werden.

Ah, das ist also "das nötigste". <staun> Wer bezahlt die? Und wo soll ich die hinstellen?

(Vielleicht sollte man das eher beim Hauptstadtflughafen beherzigen.)
 
Schau dir mal OrpheusDB an, ggf ist es das, was du suchst?

Wie hast Du das denn gefunden? Das liest sich schon genau nach dem woran ich dachte.
Gibt da aber nur eine 1.0 und wird offenbar nicht aktiv dran entwickelt.

Ich hab gestern noch was anderes gefunden: https://evilmartians.com/chronicles/introducing-logidze
(die anderen beiden tools von denen der redet muss ich mir erst noch anschauen)

Das macht einfach eine zusätzliche Spalte in die Tabellen, und jeder Record schreibt in dieses zusätzliche Feld seine eigene Versionsgeschichte, mit timestamps. Geht offenbar automatisch mit trigger; d.h. an der Anwendung muss man gar nix ändern.
 
In FreeBSD 12 sind ein Haufen IPFW Features endlich ausgereift, die komplizierte Regelsätze einfacher und wartbarer machen. Damit solltest du die gröbsten Probleme z.B. in-kernel NAT vs. state tracking gut lösen können. Insbesondere die Entkoppelung von Stateful Regeln in State erzeugen und State anwenden. Damit kannst du endlich States auf beiden seiten des NATs haben ohne wahnsinnig zu werden. Mit Flow Tables kannst du komplizierte Filter in einer Table ausdrücken z.B. Skipto/Call zu tablearg mit Destination IP und Port als Lookup key.
 
In FreeBSD 12 sind ein Haufen IPFW Features endlich ausgereift, die komplizierte Regelsätze einfacher und wartbarer machen. Damit solltest du die gröbsten Probleme z.B. in-kernel NAT vs. state tracking gut lösen können.

Sagen wir mal so: sie sind signifikant verbessert. Soo viel hat sich nicht geändert, wobei das mit den stateful rules recht hübsch ist. Wenn ich heute anfangen würde ein Design zu machen, würde ich das nutzen.
So wie ich das verstehe, kann man jetzt mit defer-action + record-state eine rule machen, die bei einem check-state etwas anderes macht als das was mit dem ursprünglichen Eröffnungspaket gemacht wurde.
Das andere Problem ist aber, dass ein check-state eine implizite Verzweigung darstellt: wenn keine dynamic rule gefunden wird, gehts mit der nächsten Rule hinter dem check-state weiter. Wenn aber eine dynamic rule gefunden wird, dann wird deren originaler Body ausgeführt und die Ausführung springt in die Zeile, in der der keep-state war, geht also nicht hinter dem check-state weiter.

Aber mir ist die Sache schon vorher auf die Füße gefallen, nämlich letztes Jahr, als hier VoIP aufgetaucht ist, woraufhin ich mir den Asterisk ein bischen angeschaut hab, und dann festgestellt, dass früher oder später der -bekanntermaßen krude- SIP Traffic mit in die Rules hineinmuss. Und da hab ich beschlossen, dass das Problem gleich ordentlich gelöst werden muss.

Insbesondere die Entkoppelung von Stateful Regeln in State erzeugen und State anwenden. Damit kannst du endlich States auf beiden seiten des NATs haben ohne wahnsinnig zu werden.

Das kann ich jetzt auch mit 11.2. Und vor allem: ich kann unbegrenzt viele NATs haben. Dazu unbegrenzt viele Forwards, Queues, Pipes, usw.
Und ich kann sie live umschalten, ohne dass dynamische Rules und Sessions runterfallen. Das geht natürlich mit Tables auch - aber die muss man dazu halt auch erstmal scheiben, und Zeilennummern zählen, usw. Ich mochte keine Zeilennnummern mehr zählen; ich mach das jetzt mit klicki-bunti. Hab ja auch irgendwann mal aufgehört Assembler zu coden.
 
Wie hast Du das denn gefunden? Das liest sich schon genau nach dem woran ich dachte.

Da hatte ich selber schon mal vor einer Weile recherchiert, aber wg Veränderung im Job das dann nicht weiter verfolgt/gebraucht... bzw war mein (sehr - ähem - rustikaler) Ansatz, die neuen Daten (besser: wirklich die Änderungsstatements, SELECTS, JOINS usw... ) erstmal ganz simpel in ein git Repo zu 'pasten', dann in die DB (quasiparallel) - das fliegt einem aber sogleich um die Ohren, spätestens beim ersten Backup-Replay in der DB, wenn git und DB nicht mehr zusammenpassen, bzw irgendwo ne Fliege draufhustet...
wie gesagt: habs (gottseidank) dann nicht mehr benötigt....
 
Zurück
Oben