Ich schrieb vor einiger Zeit über die Visualisierung und Analyse von Abhängigkeiten in Linux-Distributionen, die auf Debian aufbauen. Damals habe ich noch behauptet, dass andere Distributionen, die zum Beispiel auf yum als Paketmanagement-Lösung setzen nur schwer in dieser Art und Weise analysierbar sind. Ich habe weiter recherchiert und nun auch dafür eine Lösung gefunden.
Ich habe, nachdem ich herausgefunden hatte, wie diese Informationen mitelsa yum zu erlangen sind zwei Skripte geschrieben - eines davon erzeugt eine Graphen-Definition für graphviz ähnlich zum damaligen Vorgehen:
!/bin/bash
ssh 192.168.10.69 'rpm -qa --qf "%{NAME}\n"' >nodes.txt
cat >graph.gviz <<EOF
# Attributes in here apply to the graph itself.
pad="1"
outputorder=edgesfirst
bgcolor=transparent
# layout= specifies a layout engine:
# circo — for circular layout of graphs
# dot — for drawing directed graphs (the default)
# fdp — for drawing undirected graphs
# neato — for drawing undirected graphs
# osage — for drawing large undirected graphs
# twopi — for radial layouts of graphs
#layout=neato
#layout=dot
#layout=twopi
# Default node attributes
node [
shape = circle
style="filled,bold"
color=black
fillcolor="#F2F2F2"
fontname=Inter
]
# Uncomment this to hide labels
#node [ label="" ]
# Uncomment this to arrange nodes in a grid
#layout=osage edge [style=invis]
EOF
while IFS="" read -r p || [ -n "$p" ]
do
printf '"%s"\n' "$p" >>graph.gviz
done < nodes.txt
while IFS="" read -r p || [ -n "$p" ]
do
dependent=$(ssh -n 192.168.10.69 "yum repoquery --installed --whatrequires \"$p\" --qf \"%{NAME}\n\"")
if [ -n "$dependent" ] ; then
while IFS= read -r i
do
if [ -n "$i" ] ; then
echo "dep $p $i"
printf '"%s" -> "%s"\n' "$p" "$i" >>graph.gviz
fi
done <<< "$dependent"
fi
done < nodes.txt
Die zweite (da die Visualisierung mit den enthaltenen 312 Paketen mittels Graphviz sehr unübersichtlich ist) Variante erzeugt den Graphen im Format GEFX, das man zum Beispiel mittels gephi visualisieren kann:
#!/bin/bash
ssh 192.168.10.69 'rpm -qa --qf "%{NAME}\n"' >nodes.txt
cat >graph.gexf <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<gexf xmlns="http://gexf.net/1.2" version="1.2">
<meta lastmodifieddate="2009-03-20">
<creator>Gexf.net</creator>
<description>A hello world! file</description>
</meta>
<graph mode="static" defaultedgetype="directed">
<nodes>
EOF
while IFS="" read -r p || [ -n "$p" ]
do
printf ' <node id="%s" label="%s"/>\n' "$p" "$p" >>graph.gexf
done < nodes.txt
cat >>graph.gexf <<EOF
</nodes>
<edges>
EOF
while IFS="" read -r p || [ -n "$p" ]
do
dependent=$(ssh -n 192.168.10.69 "yum repoquery --installed --whatrequires \"$p\" --qf \"%{NAME}\n\"")
if [ -n "$dependent" ] ; then
while IFS= read -r i
do
if [ -n "$i" ] ; then
echo "dep $p $i"
printf ' <edge id="%s_%s" source="%s" target="%s"/>\n' "$p" "$i" "$p" "$i" >>graph.gexf
fi
done <<< "$dependent"
fi
done < nodes.txt
cat >>graph.gexf <<EOF
</edges>
</graph>
</gexf>
EOF
In gephi ist es möglich, die Knoten und Kanten eines Graphen sehr flexibel zu filtern - so würde etwa folgender Code als Filter dafür sorgen, lediglich Pakete anzuzeigen, die direkte Abhängigkeiten von python3 sind oder die von python3 abhängen:
/**
* Filtering function.
*
* @param {string} id ID of the item
* @param {Object.<string, number | string | boolean | undefined | null>} attributes Attributes of the item
* @param {FullGraph} full graph (data and rendering attributes + topology) dataset
* @return {boolean} TRUE if the item should be kept in the graph, FALSE to filter it
*/
function edgeFilter(id, attributes, graph) {
// Your code goes here
return id.endsWith('_python3')||id.startsWith('python3_');
}
Nachdem ich so weit gekommen war, wollte ich noch einen Schritt weiter gehen: Mit den gezeigten Filtern kann man nur direkte Abhänggikeiten behandeln. Möchte man aber zum Beispiel alle Pakete herausfinden, die direkte oder transiente Abhängigkeiten eines Pakets darstellen, kommt man mit diesen Filtern nicht zum gewünschten Ergebnis. In dem früheren Artikel habe ich aber bereits über Visualisierungsbibliotheken berichtet, die es erlauben, sehr flexibel und dynamisch mit Graphen zu arbeiten... Daher überlegte ich mir, dass ich die GEFX-Dateien in ein Java-Programm einlesen wollen würde, um dann mit ein wenig Code zur Analyse der Graphen sehr mächtige und flexible Filter und Abfragen zu realisieren un deren Ergebnisse in ansprechender Form zu visualisieren.
Als ersten Schritt dahin überlegte ich mir, ein XSLT-Stylesheet zu entwerfen, mit dem ich das GEFX-Format on-the-fly über den XMLDecoder in Java-Objekte deserialisieren könnte.
Ich nahm zunächst also dieses Problem in Angriff - allerdings nur mit dem absolut notwendigen Minimum. Würde man das vollständige Featureset des Formats GEFX umsetzen, müsste das Template noch deutlich umgangreicher ausfallen. Aber die Minimallösung funktionierte für meinen Proof-of-Concept sehr gut:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:gefx="http://gexf.net/1.2">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:element name="java">
<xsl:attribute name="version">17.0.2"</xsl:attribute>
<xsl:attribute name="class">java.beans.XMLDecoder</xsl:attribute>
<xsl:element name="object">
<xsl:attribute name="class">de.elbosso.algorithms.graph.Graph</xsl:attribute>
<xsl:element name="object">
<xsl:attribute name="class">java.util.LinkedList</xsl:attribute>
<xsl:for-each select="gefx:gexf/gefx:graph/gefx:nodes/gefx:node">
<xsl:element name="void">
<xsl:attribute name="method">add</xsl:attribute>
<xsl:element name="object">
<xsl:attribute name="class">de.elbosso.algorithms.graph.Vertex</xsl:attribute>
<xsl:attribute name="id"><xsl:value-of select="./@id"/></xsl:attribute>
<xsl:element name="string"><xsl:value-of select="@label"/></xsl:element>
<xsl:element name="null"/>
<xsl:element name="object">
<xsl:attribute name="class">de.elbosso.util.lang.collections.TypeSafeHashMap</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
<xsl:element name="object">
<xsl:attribute name="class">java.util.HashSet</xsl:attribute>
<xsl:for-each select="gefx:gexf/gefx:graph/gefx:edges/gefx:edge">
<xsl:element name="void">
<xsl:attribute name="method">add</xsl:attribute>
<xsl:element name="object">
<xsl:attribute name="class">de.elbosso.algorithms.graph.Edge</xsl:attribute>
<xsl:element name="object">
<xsl:attribute name="idref"><xsl:value-of select="./@source"/></xsl:attribute>
</xsl:element>
<xsl:element name="object">
<xsl:attribute name="idref"><xsl:value-of select="./@target"/></xsl:attribute>
</xsl:element>
<xsl:element name="null"/>
<xsl:element name="void">
<xsl:attribute name="property">directed</xsl:attribute>
<xsl:element name="boolean">true</xsl:element>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Damit konnte ich nahtlos die Beschreibung des Dependency-Graphen in meine Domain-Objekte zur Arbeit mit Graphen umwandeln und darauf dann Visualisierungen vornehmen wie die folgende:
Visualisierung transienter Abhängigkeiten des Pakets curl in Alma Linux (dargestellt werden pakete, die curl als direkte oder transiente Abhängigkeit benötigen)
Auch die implementierten Algorithmen lassen sich so auf die Dependencies anwenden - die Suche nach Paketen, die keine outgoing Connections haben und damit keine Abhängigkeiten anderer Pakete darstellen ergab folgendes Ergebnis:
on the edge (50):
[Vertex{id=almalinux-repos },
Vertex{id=glibc-minimal-langpack },
Vertex{id=rpm-plugin-audit },
Vertex{id=hostname },
Vertex{id=binutils },
Vertex{id=initscripts-service },
Vertex{id=logrotate },
Vertex{id=kpartx },
Vertex{id=selinux-policy-targeted },
Vertex{id=tpm2-tools },
Vertex{id=samba-common-libs },
Vertex{id=python3-gobject-base-noarch },
Vertex{id=kdump-utils },
Vertex{id=xfsprogs },
Vertex{id=NetworkManager-tui },
Vertex{id=sg3_utils },
Vertex{id=iproute-tc },
Vertex{id=kernel-tools },
Vertex{id=irqbalance },
Vertex{id=dnf-plugins-core },
Vertex{id=yum },
Vertex{id=firewalld },
Vertex{id=crypto-policies-scripts },
Vertex{id=python3-libselinux },
Vertex{id=sssd-kcm },
Vertex{id=kernel },
Vertex{id=grub2-pc },
Vertex{id=dracut-config-rescue },
Vertex{id=rsyslog },
Vertex{id=audit},
Vertex{id=lvm2 },
Vertex{id=openssh-clients },
Vertex{id=openssh-server },
Vertex{id=chrony },
Vertex{id=microcode_ctl },
Vertex{id=parted },
Vertex{id=man-db },
Vertex{id=e2fsprogs },
Vertex{id=sudo },
Vertex{id=initscripts-rename-device },
Vertex{id=rpm-plugin-selinux },
Vertex{id=prefixdevname },
Vertex{id=vim-minimal },
Vertex{id=lshw },
Vertex{id=libsysfs },
Vertex{id=lsscsi },
Vertex{id=ncurses },
Vertex{id=iwlwifi-dvm-firmware },
Vertex{id=iwlwifi-mvm-firmware },
Vertex{id=rootfiles }]
Styles für GeoJSON in EBMap4D
22.08.2021
Ich habe bereits darüber berichtet, dass EBMap4D jetzt über die Möglichkeit verfügt, beliebige GeoJSON-Layer darzustellen. Nun ist die Anwendung um die Möglichkeit erweitert worden, in diesen GeoJSON-Daten enthaltene Stilinformationen für die Darstellung zu nutzen.
WeiterlesenAI und ML Android Basteln C und C++ Chaos Datenbanken Docker dWb+ ESP Wifi Garten Geo Go GUI Hardware Java Jupyter JupyterBinder Komponenten Links Linux Markdown Markup Music Numerik OpenSource PKI-X.509-CA Präsentationen Python QBrowser Rants Raspi Revisited Security Software-Test sQLshell TeleGrafana Verschiedenes Video Virtualisierung Windows Upcoming...
Ich habe inzwischen 35 Jahre Softwareentwicklung auf dem Buckel - viele davon für Geld...
WeiterlesenHier meine Highlights der DefCon 34 in Las Vegas
WeiterlesenIch habe neulich darüber geschrieben, dass ich mit in meinem Homelab von Gitlab verabschieden möchte und nach Alternativen gesucht habe. Bei meiner Suche stieß ich auf verteilte Issue Tracker, die die vertraute Integration von PlantUML nicht bieten. Daher suchte ich nach einem Weg, auch dieses Feature in solchen Lösungen zu integrieren.
WeiterlesenManche nennen es Blog, manche Web-Seite - ich schreibe hier hin und wieder über meine Erlebnisse, Rückschläge und Erleuchtungen bei meinen Hobbies.
Wer daran teilhaben und eventuell sogar davon profitieren möchte, muss damit leben, daß ich hin und wieder kleine Ausflüge in Bereiche mache, die nichts mit IT, Administration oder Softwareentwicklung zu tun haben.
Ich wünsche allen Lesern viel Spaß und hin und wieder einen kleinen AHA!-Effekt...
PS: Meine öffentlichen Codeberg-Repositories findet man hier.