--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/relpipe-data/examples-in-xmltable-libvirt.xml Thu Jul 25 22:16:12 2019 +0200
@@ -0,0 +1,139 @@
+<stránka
+ xmlns="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/strana"
+ xmlns:m="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/makro">
+
+ <nadpis>Reading Libvirt XML files using XMLTable</nadpis>
+ <perex>converting arbitrary XML into one or more relations</perex>
+ <m:pořadí-příkladu>02700</m:pořadí-příkladu>
+
+ <text xmlns="http://www.w3.org/1999/xhtml">
+
+ <p>
+ <a href="https://libvirt.org/">Libvirt</a> is a popular API/tool for managing virtual machines (KVM/Qemu, LXC etc.) and stores its configuration in XML files.
+ Thanks to the tool <code>relpipe-in-xmltable</code> we can get aggregated overview of our virtual machines.
+ This tool does similar job like the <a href="https://www.postgresql.org/docs/current/functions-xml.html">xmltable</a> function known from SQL.
+ It uses the <a href="https://www.w3.org/TR/xpath/all/">XPath</a> language for selecting parts of the input XML – one XPath expression points to record nodes
+ and one or more XPath expressions point to attribute nodes/values relatively to particular record node.
+ Our tool is able to produce one or more relations from a single XML input.
+ The input is parsed at once and converted to DOM in memory i.e. no streaming – thus processing of huge XML files requires appropriate amounts of RAM, on the other hand:
+ our expression can access whole XML document and pick values not only from currently processed record node.
+ </p>
+
+
+ <p>These XML config files contain lot of information describing given virtual machine:</p>
+
+
+ <m:pre jazyk="xml"><![CDATA[<?xml version="1.0" encoding="utf8"?>
+<domain type="kvm">
+ <name>relpipe-1</name>
+ <uuid>36d1e8b2-97e9-40cb-9fc2-306ebf989282</uuid>
+ <memory unit="KiB">1048576</memory>
+ <currentMemory unit="KiB">1048576</currentMemory>
+ <vcpu placement="static">2</vcpu>
+ <os>
+ <type arch="x86_64" machine="pc-i440fx-bionic">hvm</type>
+ <boot dev="hd"/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <vmport state="off"/>
+ </features>
+ <cpu mode="custom" match="exact" check="partial">
+ <model fallback="allow">Opteron_G5</model>
+ </cpu>
+ <clock offset="utc">
+ <timer name="rtc" tickpolicy="catchup"/>
+ <timer name="pit" tickpolicy="delay"/>
+ <timer name="hpet" present="no"/>
+ </clock>
+ …
+ <devices>
+ <emulator>/usr/bin/kvm-spice</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='qcow2'/>
+ <source file='/mnt/kvm-image/relpipe-1.qcow2'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+ </disk>
+ <disk type='file' device='cdrom'>
+ <driver name='qemu' type='raw'/>
+ <target dev='hda' bus='ide'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+ </disk>
+ …
+ <interface type='bridge'>
+ <mac address='52:54:e9:f2:f6:bb'/>
+ <source bridge='br0'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+ </interface>
+ …
+ </devices>
+</domain>]]></m:pre>
+
+
+ <p>If we are interested only in certain parts, we can pick them using a command like this one:</p>
+
+ <m:pre jazyk="bash"><![CDATA[cat /etc/libvirt/qemu/relpipe-1.xml \
+ | relpipe-in-xmltable \
+ --relation "machine" \
+ --records "/domain" \
+ --attribute "uuid" string "uuid" \
+ --attribute "name" string "name" \
+ --attribute "memory_size" integer "memory" \
+ --attribute "memory_unit" string "memory/@unit" \
+ --attribute "cpu_count" integer "vcpu" \
+ --relation "storage" \
+ --records "/domain/devices/disk" \
+ --attribute "machine" string "/domain/uuid" \
+ --attribute "type" string "@device" \
+ --attribute "format" string "driver/@type" \
+ --attribute "source" string "source/@file" \
+ --attribute "target_dev" string "target/@dev" \
+ --attribute "target_type" string "target/@bus" \
+ --relation "network_interface" \
+ --records "/domain/devices/interface" \
+ --attribute "machine" string "/domain/uuid" \
+ --attribute "mac" string "mac/@address" \
+ | relpipe-out-tabular]]></m:pre>
+
+
+ <p>And get three relations:</p>
+
+ <pre><![CDATA[machine:
+ ╭──────────────────────────────────────┬───────────────┬───────────────────────┬──────────────────────┬─────────────────────╮
+ │ uuid (string) │ name (string) │ memory_size (integer) │ memory_unit (string) │ cpu_count (integer) │
+ ├──────────────────────────────────────┼───────────────┼───────────────────────┼──────────────────────┼─────────────────────┤
+ │ 36d1e8b2-97e9-40cb-9fc2-306ebf989282 │ relpipe-1 │ 1048576 │ KiB │ 2 │
+ ╰──────────────────────────────────────┴───────────────┴───────────────────────┴──────────────────────┴─────────────────────╯
+Record count: 1
+
+storage:
+ ╭──────────────────────────────────────┬───────────────┬─────────────────┬─────────────────────────────────┬─────────────────────┬──────────────────────╮
+ │ machine (string) │ type (string) │ format (string) │ source (string) │ target_dev (string) │ target_type (string) │
+ ├──────────────────────────────────────┼───────────────┼─────────────────┼─────────────────────────────────┼─────────────────────┼──────────────────────┤
+ │ 36d1e8b2-97e9-40cb-9fc2-306ebf989282 │ disk │ qcow2 │ /mnt/kvm-image/relpipe-1.qcow2 │ vda │ virtio │
+ │ 36d1e8b2-97e9-40cb-9fc2-306ebf989282 │ cdrom │ raw │ │ hda │ ide │
+ ╰──────────────────────────────────────┴───────────────┴─────────────────┴─────────────────────────────────┴─────────────────────┴──────────────────────╯
+Record count: 2
+
+network_interface:
+ ╭──────────────────────────────────────┬───────────────────╮
+ │ machine (string) │ mac (string) │
+ ├──────────────────────────────────────┼───────────────────┤
+ │ 36d1e8b2-97e9-40cb-9fc2-306ebf989282 │ 52:54:e9:f2:f6:bb │
+ ╰──────────────────────────────────────┴───────────────────╯
+Record count: 1]]></pre>
+
+ <p>
+ Each record contain ID of the machine, thus if we collect data from several VMs,
+ we can JOIN relevant records together, do some aggregations or statistics.
+ If we are sure that the <code>name</code> field is unique, we can use it as a key instead of the UUID.
+ </p>
+
+
+ </text>
+
+</stránka>