While you can chain the virsh output up to a later 'xmllint' or 'xpath' command, integrating it into virsh avoids needs for installing extra binaries which we've often found to be missing on production installs of libvirt. It also gives better response if the initial virsh command hits an error, as you don't get an aborted pipeline. $ virsh pool-dumpxml --xpath //permissions default <permissions> <mode>0711</mode> <owner>1000</owner> <group>1000</group> <label>unconfined_u:object_r:svirt_home_t:s0</label> </permissions> If multiple nodes match, they are emitted individually: $ virsh dumpxml --xpath '//devices/*/address[@type="pci"]' --wrap demo <address type="pci" domain="0x0000" bus="0x05" slot="0x00" function="0x0"/> <address type="pci" domain="0x0000" bus="0x03" slot="0x00" function="0x0"/> ...snip... <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x0" multifunction="on"/> <address type="pci" domain="0x0000" bus="0x07" slot="0x00" function="0x0"/> but if intending to post-process the output further, the results can be wrapped in a parent node $ virsh dumpxml --xpath '//devices/*/address[@type="pci"]' --wrap demo <nodes> <address type="pci" domain="0x0000" bus="0x05" slot="0x00" function="0x0"/> <address type="pci" domain="0x0000" bus="0x03" slot="0x00" function="0x0"/> ...snip... <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x0" multifunction="on"/> <address type="pci" domain="0x0000" bus="0x07" slot="0x00" function="0x0"/> </nodes> Fixes https://gitlab.com/libvirt/libvirt/-/issues/244 Signed-off-by: Daniel P. Berrangé <berrange@xxxxxxxxxx> --- docs/manpages/virsh.rst | 138 ++++++++++++++++++++++++++++++++++----- tools/virsh-backup.c | 17 ++++- tools/virsh-checkpoint.c | 17 ++++- tools/virsh-domain.c | 55 +++++++++++++--- tools/virsh-interface.c | 22 +++++-- tools/virsh-network.c | 47 +++++++++---- tools/virsh-nodedev.c | 17 ++++- tools/virsh-nwfilter.c | 51 ++++++++++----- tools/virsh-pool.c | 27 +++++--- tools/virsh-secret.c | 18 ++++- tools/virsh-snapshot.c | 17 ++++- tools/virsh-volume.c | 28 +++++--- 12 files changed, 370 insertions(+), 84 deletions(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index 580245adb1..4701791b04 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -1959,10 +1959,16 @@ backup-dumpxml :: - backup-dumpxml domain + backup-dumpxml [--xpath EXPRESSION] [--wrap] domain Output XML describing the current backup job. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. domiflist --------- @@ -2652,7 +2658,8 @@ dumpxml :: - dumpxml domain [--inactive] [--security-info] [--update-cpu] [--migratable] + dumpxml [--inactive] [--security-info] [--update-cpu] [--migratable] + [--xpath EXPRESSION] [--wrap] domain Output the domain information as an XML dump to stdout, this format can be used by the ``create`` command. Additional options affecting the XML dump may be @@ -2665,6 +2672,13 @@ migrations, i.e., compatible with older libvirt releases and possibly amended with internal run-time options. This option may automatically enable other options (*--update-cpu*, *--security-info*, ...) as necessary. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + edit ---- @@ -3090,12 +3104,19 @@ managedsave-dumpxml :: - managedsave-dumpxml domain [--security-info] + managedsave-dumpxml [--security-info] [--xpath EXPRESSION] [--wrap] domain Extract the domain XML that was in effect at the time the saved state file *file* was created with the ``managedsave`` command. Using *--security-info* will also include security sensitive information. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + managedsave-edit ---------------- @@ -3890,12 +3911,19 @@ save-image-dumpxml :: - save-image-dumpxml file [--security-info] + save-image-dumpxml [--security-info] [--xpath EXPRESSION] [--wrap] file Extract the domain XML that was in effect at the time the saved state file *file* was created with the ``save`` command. Using *--security-info* will also include security sensitive information. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + save-image-edit --------------- @@ -5244,7 +5272,7 @@ nodedev-dumpxml :: - nodedev-dumpxml device + nodedev-dumpxml [--xpath EXPRESSION] [--wrap] device Dump a <device> XML representation for the given node device, including such information as the device name, which bus owns the device, the @@ -5253,6 +5281,13 @@ libvirt (such as whether device reset is supported). *device* can be either device name or wwn pair in "wwnn,wwpn" format (only works for HBA). +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + nodedev-info ------------ @@ -5433,13 +5468,20 @@ net-dumpxml :: - net-dumpxml network [--inactive] + net-dumpxml [--inactive] [--xpath EXPRESSION] [--wrap] network Output the virtual network information as an XML dump to stdout. If *--inactive* is specified, then physical functions are not expanded into their associated virtual functions. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + net-edit -------- @@ -5695,10 +5737,17 @@ net-port-dumpxml :: - net-port-dumpxml network port + net-port-dumpxml [--xpath EXPRESSION] [--wrap] network port Output the network port information as an XML dump to stdout. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + net-port-delete --------------- @@ -5782,12 +5831,19 @@ iface-dumpxml :: - iface-dumpxml interface [--inactive] + iface-dumpxml [--inactive] [--xpath EXPRESSION] [--wrap] interface Output the host interface information as an XML dump to stdout. If *--inactive* is specified, then the output reflects the persistent state of the interface that will be used the next time it is started. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + iface-edit ---------- @@ -6258,12 +6314,19 @@ pool-dumpxml :: - pool-dumpxml [--inactive] pool-or-uuid + pool-dumpxml [--inactive] [--xpath EXPRESSION] [--wrap] pool-or-uuid Returns the XML information about the *pool* object. *--inactive* tells virsh to dump pool configuration that will be used on next start of the pool as opposed to the current pool configuration. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + pool-edit --------- @@ -6750,7 +6813,8 @@ vol-dumpxml :: - vol-dumpxml vol-name-or-key-or-path [--pool pool-or-uuid] + vol-dumpxml [--pool pool-or-uuid] [--xpath EXPRESSION] [--wrap] + vol-name-or-key-or-path Output the volume information as an XML dump to stdout. @@ -6762,6 +6826,13 @@ is in. If the volume name is provided instead of the key or path, then providing the pool is necessary to find the volume to be uploaded into; otherwise, the first volume found by the key or path will be used. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + vol-info -------- @@ -6949,10 +7020,17 @@ secret-dumpxml :: - secret-dumpxml secret + secret-dumpxml [--xpath EXPRESSION] [--wrap] secret Output properties of *secret* (specified by its UUID) as an XML dump to stdout. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + secret-event ------------ @@ -7370,12 +7448,20 @@ snapshot-dumpxml :: - snapshot-dumpxml domain snapshot [--security-info] + snapshot-dumpxml [--security-info] [--xpath EXPRESSION] [--wrap] + domain snapshot Output the snapshot XML for the domain's snapshot named *snapshot*. Using *--security-info* will also include security sensitive information. Use ``snapshot-current`` to easily access the XML of the current snapshot. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + snapshot-parent --------------- @@ -7655,7 +7741,8 @@ checkpoint-dumpxml :: - checkpoint-dumpxml domain checkpoint [--security-info] [--no-domain] [--size] + checkpoint-dumpxml [--security-info] [--no-domain] [--size] + [--xpath EXPRESSION] [--wrap] domain checkpoint Output the checkpoint XML for the domain's checkpoint named *checkpoint*. Using @@ -7671,6 +7758,13 @@ space). Note that some hypervisors may require that *domain* is running when Using *--no-domain* will omit the <domain> element from the output for a more compact view. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + checkpoint-parent ----------------- @@ -7773,10 +7867,17 @@ nwfilter-dumpxml :: - nwfilter-dumpxml nwfilter-name + nwfilter-dumpxml [--xpath EXPRESSION] [--wrap] nwfilter-name Output the network filter XML. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + nwfilter-edit ------------- @@ -7876,11 +7977,18 @@ nwfilter-binding-dumpxml :: - nwfilter-binding-dumpxml port-name + nwfilter-binding-dumpxml [--xpath EXPRESSION] [--wrap] port-name Output the network filter binding XML for the network device called ``port-name``. +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + HYPERVISOR-SPECIFIC COMMANDS ============================ diff --git a/tools/virsh-backup.c b/tools/virsh-backup.c index 7bac1923a6..db122abc09 100644 --- a/tools/virsh-backup.c +++ b/tools/virsh-backup.c @@ -115,6 +115,15 @@ static const vshCmdInfo info_backup_dumpxml[] = { static const vshCmdOptDef opts_backup_dumpxml[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -124,15 +133,19 @@ cmdBackupDumpXML(vshControl *ctl, { g_autoptr(virshDomain) dom = NULL; g_autofree char *xml = NULL; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) return false; + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) + return false; + if (!(xml = virDomainBackupGetXMLDesc(dom, 0))) return false; - vshPrint(ctl, "%s", xml); - return true; + return virshDumpXML(ctl, xml, "domain-backup", xpath, wrap); } diff --git a/tools/virsh-checkpoint.c b/tools/virsh-checkpoint.c index 8ad37ece69..59f9b08e37 100644 --- a/tools/virsh-checkpoint.c +++ b/tools/virsh-checkpoint.c @@ -854,6 +854,15 @@ static const vshCmdOptDef opts_checkpoint_dumpxml[] = { .type = VSH_OT_BOOL, .help = N_("include backup size estimate in XML dump") }, + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -866,6 +875,8 @@ cmdCheckpointDumpXML(vshControl *ctl, g_autoptr(virshDomainCheckpoint) checkpoint = NULL; g_autofree char *xml = NULL; unsigned int flags = 0; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; if (vshCommandOptBool(cmd, "security-info")) flags |= VIR_DOMAIN_CHECKPOINT_XML_SECURE; @@ -877,6 +888,9 @@ cmdCheckpointDumpXML(vshControl *ctl, if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) return false; + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) + return false; + if (virshLookupCheckpoint(ctl, cmd, "checkpointname", dom, &checkpoint, &name) < 0) return false; @@ -884,8 +898,7 @@ cmdCheckpointDumpXML(vshControl *ctl, if (!(xml = virDomainCheckpointGetXMLDesc(checkpoint, flags))) return false; - vshPrint(ctl, "%s", xml); - return true; + return virshDumpXML(ctl, xml, "domain-checkpoint", xpath, wrap); } diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 06ed6ba9cf..1c9703563a 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -4528,6 +4528,15 @@ static const vshCmdOptDef opts_save_image_dumpxml[] = { .type = VSH_OT_BOOL, .help = N_("include security sensitive information in XML dump") }, + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -4538,6 +4547,8 @@ cmdSaveImageDumpxml(vshControl *ctl, const vshCmd *cmd) unsigned int flags = 0; g_autofree char *xml = NULL; virshControl *priv = ctl->privData; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; if (vshCommandOptBool(cmd, "security-info")) flags |= VIR_DOMAIN_XML_SECURE; @@ -4545,12 +4556,14 @@ cmdSaveImageDumpxml(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptStringReq(ctl, cmd, "file", &file) < 0) return false; + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) + return false; + xml = virDomainSaveImageGetXMLDesc(priv->conn, file, flags); if (!xml) return false; - vshPrint(ctl, "%s", xml); - return true; + return virshDumpXML(ctl, xml, "domain-save-image", xpath, wrap); } /* @@ -4947,6 +4960,15 @@ static const vshCmdOptDef opts_managed_save_dumpxml[] = { .type = VSH_OT_BOOL, .help = N_("include security sensitive information in XML dump") }, + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -4956,6 +4978,8 @@ cmdManagedSaveDumpxml(vshControl *ctl, const vshCmd *cmd) g_autoptr(virshDomain) dom = NULL; unsigned int flags = 0; g_autofree char *xml = NULL; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; if (vshCommandOptBool(cmd, "security-info")) flags |= VIR_DOMAIN_XML_SECURE; @@ -4963,11 +4987,13 @@ cmdManagedSaveDumpxml(vshControl *ctl, const vshCmd *cmd) if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) return false; + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) + return false; + if (!(xml = virDomainManagedSaveGetXMLDesc(dom, flags))) return false; - vshPrint(ctl, "%s", xml); - return true; + return virshDumpXML(ctl, xml, "domain-save-image", xpath, wrap); } /* @@ -10434,6 +10460,15 @@ static const vshCmdOptDef opts_dumpxml[] = { .type = VSH_OT_BOOL, .help = N_("provide XML suitable for migrations") }, + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -10441,12 +10476,14 @@ static bool cmdDumpXML(vshControl *ctl, const vshCmd *cmd) { g_autoptr(virshDomain) dom = NULL; - g_autofree char *dump = NULL; + g_autofree char *xml = NULL; unsigned int flags = 0; bool inactive = vshCommandOptBool(cmd, "inactive"); bool secure = vshCommandOptBool(cmd, "security-info"); bool update = vshCommandOptBool(cmd, "update-cpu"); bool migratable = vshCommandOptBool(cmd, "migratable"); + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; if (inactive) flags |= VIR_DOMAIN_XML_INACTIVE; @@ -10460,11 +10497,13 @@ cmdDumpXML(vshControl *ctl, const vshCmd *cmd) if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) return false; - if (!(dump = virDomainGetXMLDesc(dom, flags))) + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) return false; - vshPrint(ctl, "%s", dump); - return true; + if (!(xml = virDomainGetXMLDesc(dom, flags))) + return false; + + return virshDumpXML(ctl, xml, "domain", xpath, wrap); } /* diff --git a/tools/virsh-interface.c b/tools/virsh-interface.c index 55d3532c55..b29ffc9bef 100644 --- a/tools/virsh-interface.c +++ b/tools/virsh-interface.c @@ -470,6 +470,16 @@ static const vshCmdOptDef opts_interface_dumpxml[] = { .type = VSH_OT_BOOL, .help = N_("show inactive defined XML") }, + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, + {.name = NULL} }; @@ -477,7 +487,9 @@ static bool cmdInterfaceDumpXML(vshControl *ctl, const vshCmd *cmd) { g_autoptr(virshInterface) iface = NULL; - g_autofree char *dump = NULL; + g_autofree char *xml = NULL; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; unsigned int flags = 0; if (vshCommandOptBool(cmd, "inactive")) @@ -486,11 +498,13 @@ cmdInterfaceDumpXML(vshControl *ctl, const vshCmd *cmd) if (!(iface = virshCommandOptInterface(ctl, cmd, NULL))) return false; - if (!(dump = virInterfaceGetXMLDesc(iface, flags))) + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) return false; - vshPrint(ctl, "%s", dump); - return true; + if (!(xml = virInterfaceGetXMLDesc(iface, flags))) + return false; + + return virshDumpXML(ctl, xml, "interface", xpath, wrap); } /* diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 97a160f772..99ced6ccc6 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -349,6 +349,15 @@ static const vshCmdOptDef opts_network_dumpxml[] = { .type = VSH_OT_BOOL, .help = N_("show inactive defined XML") }, + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -356,8 +365,10 @@ static bool cmdNetworkDumpXML(vshControl *ctl, const vshCmd *cmd) { g_autoptr(virshNetwork) network = NULL; - g_autofree char *dump = NULL; + g_autofree char *xml = NULL; unsigned int flags = 0; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; if (!(network = virshCommandOptNetwork(ctl, cmd, NULL))) return false; @@ -365,12 +376,13 @@ cmdNetworkDumpXML(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptBool(cmd, "inactive")) flags |= VIR_NETWORK_XML_INACTIVE; - if (!(dump = virNetworkGetXMLDesc(network, flags))) { + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) return false; - } - vshPrint(ctl, "%s", dump); - return true; + if (!(xml = virNetworkGetXMLDesc(network, flags))) + return false; + + return virshDumpXML(ctl, xml, "network", xpath, wrap); } /* @@ -1542,6 +1554,15 @@ static const vshCmdInfo info_network_port_dumpxml[] = { static const vshCmdOptDef opts_network_port_dumpxml[] = { VIRSH_COMMON_OPT_NETWORK_FULL(VIR_CONNECT_LIST_NETWORKS_ACTIVE), VIRSH_COMMON_OPT_NETWORK_PORT(0), + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -1551,8 +1572,10 @@ cmdNetworkPortDumpXML(vshControl *ctl, const vshCmd *cmd) g_autoptr(virshNetwork) network = NULL; virNetworkPortPtr port = NULL; bool ret = true; - g_autofree char *dump = NULL; + g_autofree char *xml = NULL; unsigned int flags = 0; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; if (!(network = virshCommandOptNetwork(ctl, cmd, NULL))) goto cleanup; @@ -1560,13 +1583,13 @@ cmdNetworkPortDumpXML(vshControl *ctl, const vshCmd *cmd) if (!(port = virshCommandOptNetworkPort(ctl, cmd, network, NULL))) goto cleanup; - dump = virNetworkPortGetXMLDesc(port, flags); + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) + return false; - if (dump != NULL) { - vshPrint(ctl, "%s", dump); - } else { - ret = false; - } + if (!(xml = virNetworkPortGetXMLDesc(port, flags))) + goto cleanup; + + ret = virshDumpXML(ctl, xml, "network-port", xpath, wrap); cleanup: if (port) diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index 90066249af..72516c89c3 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -566,6 +566,15 @@ static const vshCmdOptDef opts_node_device_dumpxml[] = { .help = N_("device name or wwn pair in 'wwnn,wwpn' format"), .completer = virshNodeDeviceNameCompleter, }, + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -575,10 +584,15 @@ cmdNodeDeviceDumpXML(vshControl *ctl, const vshCmd *cmd) g_autoptr(virshNodeDevice) device = NULL; g_autofree char *xml = NULL; const char *device_value = NULL; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0) return false; + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) + return false; + device = vshFindNodeDevice(ctl, device_value); if (!device) @@ -587,8 +601,7 @@ cmdNodeDeviceDumpXML(vshControl *ctl, const vshCmd *cmd) if (!(xml = virNodeDeviceGetXMLDesc(device, 0))) return false; - vshPrint(ctl, "%s\n", xml); - return true; + return virshDumpXML(ctl, xml, "node-device", xpath, wrap); } /* diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c index 5a9e57e3f5..ff7f6f4026 100644 --- a/tools/virsh-nwfilter.c +++ b/tools/virsh-nwfilter.c @@ -186,6 +186,15 @@ static const vshCmdOptDef opts_nwfilter_dumpxml[] = { .help = N_("network filter name or uuid"), .completer = virshNWFilterNameCompleter, }, + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -193,20 +202,20 @@ static bool cmdNWFilterDumpXML(vshControl *ctl, const vshCmd *cmd) { g_autoptr(virshNWFilter) nwfilter = NULL; - bool ret = true; - g_autofree char *dump = NULL; + g_autofree char *xml = NULL; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; if (!(nwfilter = virshCommandOptNWFilter(ctl, cmd, NULL))) return false; - dump = virNWFilterGetXMLDesc(nwfilter, 0); - if (dump != NULL) { - vshPrint(ctl, "%s", dump); - } else { - ret = false; - } + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) + return false; - return ret; + if (!(xml = virNWFilterGetXMLDesc(nwfilter, 0))) + return false; + + return virshDumpXML(ctl, xml, "nwfilter", xpath, wrap); } static int @@ -599,6 +608,15 @@ static const vshCmdOptDef opts_nwfilter_binding_dumpxml[] = { .help = N_("network filter binding portdev"), .completer = virshNWFilterBindingNameCompleter, }, + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -607,18 +625,19 @@ cmdNWFilterBindingDumpXML(vshControl *ctl, const vshCmd *cmd) { virNWFilterBindingPtr binding; bool ret = true; - g_autofree char *dump = NULL; + g_autofree char *xml = NULL; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; if (!(binding = virshCommandOptNWFilterBinding(ctl, cmd, NULL))) return false; - dump = virNWFilterBindingGetXMLDesc(binding, 0); - if (dump != NULL) { - vshPrint(ctl, "%s", dump); - } else { - ret = false; - } + if (!(xml = virNWFilterBindingGetXMLDesc(binding, 0))) + goto cleanup; + ret = virshDumpXML(ctl, xml, "nwfilter-binding", xpath, wrap); + + cleanup: virNWFilterBindingFree(binding); return ret; } diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c index 7e7a8d511f..4fb6875a98 100644 --- a/tools/virsh-pool.c +++ b/tools/virsh-pool.c @@ -776,6 +776,15 @@ static const vshCmdOptDef opts_pool_dumpxml[] = { .type = VSH_OT_BOOL, .help = N_("show inactive defined XML") }, + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -783,10 +792,11 @@ static bool cmdPoolDumpXML(vshControl *ctl, const vshCmd *cmd) { g_autoptr(virshStoragePool) pool = NULL; - bool ret = true; bool inactive = vshCommandOptBool(cmd, "inactive"); unsigned int flags = 0; - g_autofree char *dump = NULL; + g_autofree char *xml = NULL; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; if (inactive) flags |= VIR_STORAGE_XML_INACTIVE; @@ -794,14 +804,13 @@ cmdPoolDumpXML(vshControl *ctl, const vshCmd *cmd) if (!(pool = virshCommandOptPool(ctl, cmd, "pool", NULL))) return false; - dump = virStoragePoolGetXMLDesc(pool, flags); - if (dump != NULL) { - vshPrint(ctl, "%s", dump); - } else { - ret = false; - } + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) + return false; - return ret; + if (!(xml = virStoragePoolGetXMLDesc(pool, flags))) + return false; + + return virshDumpXML(ctl, xml, "pool", xpath, wrap); } static int diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c index 842647cb17..79fa3faf5a 100644 --- a/tools/virsh-secret.c +++ b/tools/virsh-secret.c @@ -138,6 +138,15 @@ static const vshCmdOptDef opts_secret_dumpxml[] = { .help = N_("secret UUID"), .completer = virshSecretUUIDCompleter, }, + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -147,16 +156,21 @@ cmdSecretDumpXML(vshControl *ctl, const vshCmd *cmd) virSecretPtr secret; bool ret = false; g_autofree char *xml = NULL; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; secret = virshCommandOptSecret(ctl, cmd, NULL); if (secret == NULL) return false; + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) + return false; + xml = virSecretGetXMLDesc(secret, 0); if (xml == NULL) goto cleanup; - vshPrint(ctl, "%s", xml); - ret = true; + + ret = virshDumpXML(ctl, xml, "secret", xpath, wrap); cleanup: virshSecretFree(secret); diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c index 7cd76f39e2..73854d2486 100644 --- a/tools/virsh-snapshot.c +++ b/tools/virsh-snapshot.c @@ -1608,6 +1608,15 @@ static const vshCmdOptDef opts_snapshot_dumpxml[] = { .type = VSH_OT_BOOL, .help = N_("include security sensitive information in XML dump") }, + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -1619,6 +1628,8 @@ cmdSnapshotDumpXML(vshControl *ctl, const vshCmd *cmd) g_autoptr(virshDomainSnapshot) snapshot = NULL; g_autofree char *xml = NULL; unsigned int flags = 0; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; if (vshCommandOptBool(cmd, "security-info")) flags |= VIR_DOMAIN_XML_SECURE; @@ -1632,11 +1643,13 @@ cmdSnapshotDumpXML(vshControl *ctl, const vshCmd *cmd) if (!(snapshot = virDomainSnapshotLookupByName(dom, name, 0))) return false; + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) + return false; + if (!(xml = virDomainSnapshotGetXMLDesc(snapshot, flags))) return false; - vshPrint(ctl, "%s", xml); - return true; + return virshDumpXML(ctl, xml, "domain-snapshot", xpath, wrap); } /* diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c index 503acda874..bf72d8135f 100644 --- a/tools/virsh-volume.c +++ b/tools/virsh-volume.c @@ -1159,6 +1159,15 @@ static const vshCmdInfo info_vol_dumpxml[] = { static const vshCmdOptDef opts_vol_dumpxml[] = { VIRSH_COMMON_OPT_VOL_FULL, VIRSH_COMMON_OPT_POOL_OPTIONAL, + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = virshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, {.name = NULL} }; @@ -1166,21 +1175,20 @@ static bool cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd) { g_autoptr(virshStorageVol) vol = NULL; - bool ret = true; - char *dump; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; + g_autofree char *xml = NULL; if (!(vol = virshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) return false; - dump = virStorageVolGetXMLDesc(vol, 0); - if (dump != NULL) { - vshPrint(ctl, "%s", dump); - VIR_FREE(dump); - } else { - ret = false; - } + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) + return false; - return ret; + if (!(xml = virStorageVolGetXMLDesc(vol, 0))) + return false; + + return virshDumpXML(ctl, xml, "volume", xpath, wrap); } static int -- 2.36.1