This command can be used to view/modify the `<title>` and
`<description>` fields of the Network filter object.

Signed-off-by: K Shiva Kiran <shiva...@riseup.net>
---
 docs/manpages/virsh.rst |  40 ++++++++
 tools/virsh-nwfilter.c  | 209 ++++++++++++++++++++++++++++++++++++++++
 tools/virsh-util.c      |  25 +++++
 tools/virsh-util.h      |   9 ++
 4 files changed, 283 insertions(+)

diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index 4ae3bb4d93..3c7cbf1e11 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -8134,6 +8134,46 @@ The editor used can be supplied by the ``$VISUAL`` or 
``$EDITOR`` environment
 variables, and defaults to ``vi``.
 
 
+nwfilter-desc
+-------------
+
+**Syntax:**
+
+::
+
+   nwfilter-desc [--nwfilter] nwfilter-name
+      [--title] [--edit] [--remove]
+      [--new-desc new-value]
+
+Show or modify description and title of a network filter.
+
+These values are user fields that allow storing arbitrary textual data to
+allow easy identification of network filters.
+Title should be short, although it's not enforced.
+(See also ``nwfilter-metadata`` that works with XML based network filter 
metadata.)
+
+- *--title*
+
+  Specifies to operate on the title field instead of description.
+
+- *--edit*
+
+  Opens an editor with the current title or description.
+  Modifications to the contents will be saved back.
+  Alternatively, the new contents can be provided via the *--new-desc* option.
+
+- *--remove*
+
+  Removes the title or description field.
+
+- *--new-desc*
+
+  Stores the provided title/description string.
+
+If neither of *--edit* or *--new-desc* are specified, the title or description
+is displayed instead of being modified.
+
+
 NWFILTER BINDING COMMANDS
 =========================
 
diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c
index 92b2b7b3bc..615d126def 100644
--- a/tools/virsh-nwfilter.c
+++ b/tools/virsh-nwfilter.c
@@ -26,6 +26,7 @@
 #include "viralloc.h"
 #include "virfile.h"
 #include "vsh-table.h"
+#include "virxml.h"
 
 virNWFilterPtr
 virshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd,
@@ -345,6 +346,53 @@ virshNWFilterListCollect(vshControl *ctl,
     return list;
 }
 
+/* extract description or title from nwfilter xml */
+static char *
+virshGetNWFilterDescription(vshControl *ctl, virNWFilterPtr nwfilter,
+                            bool title, unsigned int flags,
+                            unsigned int queryflags)
+{
+    char *desc = NULL;
+    g_autoptr(xmlDoc) doc = NULL;
+    g_autoptr(xmlXPathContext) ctxt = NULL;
+    int type;
+
+    if (title)
+        type = VIR_NWFILTER_METADATA_TITLE;
+    else
+        type = VIR_NWFILTER_METADATA_DESCRIPTION;
+
+    if ((desc = virNWFilterGetMetadata(nwfilter, type, NULL, flags))) {
+        return desc;
+    } else {
+        int errCode = virGetLastErrorCode();
+
+        if (errCode == VIR_ERR_NO_NWFILTER_METADATA) {
+            desc = g_strdup("");
+            vshResetLibvirtError();
+            return desc;
+        }
+
+        if (errCode != VIR_ERR_NO_SUPPORT)
+            return desc;
+    }
+
+    /* fall back to xml */
+    if (virshNWFilterGetXMLFromNWFilter(ctl, nwfilter, queryflags, &doc, 
&ctxt) < 0)
+        return NULL;
+
+    if (title)
+        desc = virXPathString("string(./title[1])", ctxt);
+    else
+        desc = virXPathString("string(./description[1])", ctxt);
+
+    if (!desc)
+        desc = g_strdup("");
+
+    return desc;
+}
+
+
 /*
  * "nwfilter-list" command
  */
@@ -768,6 +816,161 @@ cmdNWFilterBindingList(vshControl *ctl, const vshCmd *cmd 
G_GNUC_UNUSED)
 }
 
 
+/*
+ * "nwfilter-desc" command
+ */
+static const vshCmdInfo info_nwfilter_desc[] = {
+    {.name = "help",
+     .data = N_("show or set network filter's description or title")
+    },
+    {.name = "desc",
+     .data = N_("Allows setting or modifying the description or title of a 
network filter.")
+    },
+    {.name = NULL}
+};
+
+static const vshCmdOptDef opts_nwfilter_desc[] = {
+    {.name = "nwfilter",
+     .type = VSH_OT_DATA,
+     .flags = VSH_OFLAG_REQ,
+     .help = N_("network filter name or uuid"),
+     .completer = virshNWFilterNameCompleter,
+    },
+    {.name = "title",
+     .type = VSH_OT_BOOL,
+     .help = N_("modify/get the title instead of description")
+    },
+    {.name = "edit",
+     .type = VSH_OT_BOOL,
+     .help = N_("open an editor to modify the description")
+    },
+    {.name = "remove",
+     .type = VSH_OT_BOOL,
+     .help = N_("remove the element")
+    },
+    {.name = "new-desc",
+     .type = VSH_OT_ARGV,
+     .help = N_("message")
+    },
+    {.name = NULL}
+};
+
+static bool
+cmdNWFilterDesc(vshControl *ctl, const vshCmd *cmd)
+{
+    g_autoptr(virshNWFilter) nwfilter = NULL;
+    bool title = vshCommandOptBool(cmd, "title");
+    bool edit = vshCommandOptBool(cmd, "edit");
+    bool remove = vshCommandOptBool(cmd, "remove");
+    int type;
+    g_autofree char *descArg = NULL;
+    const vshCmdOpt *opt = NULL;
+    g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+    unsigned int flags = 0;
+    unsigned int queryflags = 0;
+
+    VSH_EXCLUSIVE_OPTIONS("remove", "edit");
+
+    if (!(nwfilter = virshCommandOptNWFilter(ctl, cmd, NULL)))
+        return false;
+
+    if (title)
+        type = VIR_NWFILTER_METADATA_TITLE;
+    else
+        type = VIR_NWFILTER_METADATA_DESCRIPTION;
+
+
+    while ((opt = vshCommandOptArgv(ctl, cmd, opt)))
+        virBufferAsprintf(&buf, "%s ", opt->data);
+
+    virBufferTrim(&buf, " ");
+
+    descArg = virBufferContentAndReset(&buf);
+
+    if (remove) {
+
+        if (descArg) {
+            vshPrintExtra(ctl, "unexpected data: \'%s\'", descArg);
+            return false;
+        }
+
+        if (virNWFilterSetMetadata(nwfilter, type, "", NULL, NULL, flags) < 0)
+            goto error;
+
+        vshPrintExtra(ctl, "%s removed successfully", title ? "Title" : 
"Description");
+
+    } else if (edit || descArg) {
+
+        g_autofree char *descNWFilter = NULL;
+        g_autofree char *descNew = NULL;
+
+        if (!(descNWFilter = virshGetNWFilterDescription(ctl, nwfilter,
+                                                         title, flags, 
queryflags)))
+            return false;
+
+        if (!descArg)
+            descArg = g_strdup(descNWFilter);
+
+        if (edit) {
+            g_autoptr(vshTempFile) tmp = NULL;
+            g_autofree char *desc_edited = NULL;
+            char *tmpstr;
+
+            /* Create and open a temporary file. */
+            if (!(tmp = vshEditWriteToTempFile(ctl, descArg)))
+                return false;
+
+            /* Start the editor. */
+            if (vshEditFile(ctl, tmp) == -1)
+                return false;
+
+            /* Read back the edited file. */
+            if (!(desc_edited = vshEditReadBackFile(ctl, tmp)))
+                return false;
+
+            /* strip a possible newline at the end */
+            if (title &&
+                (tmpstr = strrchr(desc_edited, '\n')) &&
+                *(tmpstr+1) == '\0')
+                *tmpstr = '\0';
+
+            /* Check whether XML has changed */
+            if (STREQ(descNWFilter, desc_edited)) {
+                vshPrintExtra(ctl, "Network filter %s has not changed", title 
? "title" : "description");
+                return true;
+            }
+
+            descNew = g_steal_pointer(&desc_edited);
+
+        } else {
+            descNew = g_steal_pointer(&descArg);
+        }
+
+        if (virNWFilterSetMetadata(nwfilter, type, descNew, NULL, NULL, flags) 
< 0)
+            goto error;
+
+        vshPrintExtra(ctl, "Network filter %s updated successfully", title ? 
"title" : "description");
+
+    } else {
+        g_autofree char *desc = virshGetNWFilterDescription(ctl, nwfilter, 
title, flags, queryflags);
+        if (!desc)
+            return false;
+
+        if (strlen(desc) > 0) {
+            vshPrint(ctl, "%s", desc);
+        } else {
+            vshPrintExtra(ctl, _("No %1$s for network filter: %2$s"), title ? 
"title" : "description", virNWFilterGetName(nwfilter));
+        }
+    }
+
+    return true;
+
+    error:
+        vshError(ctl, "Failed to set %s for network filter", title ? "title" : 
"description");
+        return false;
+}
+
+
 const vshCmdDef nwfilterCmds[] = {
     {.name = "nwfilter-define",
      .handler = cmdNWFilterDefine,
@@ -823,5 +1026,11 @@ const vshCmdDef nwfilterCmds[] = {
      .info = info_nwfilter_binding_list,
      .flags = 0
     },
+    {.name = "nwfilter-desc",
+     .handler = cmdNWFilterDesc,
+     .opts = opts_nwfilter_desc,
+     .info = info_nwfilter_desc,
+     .flags = 0
+    },
     {.name = NULL}
 };
diff --git a/tools/virsh-util.c b/tools/virsh-util.c
index fb6327613a..c3af770c29 100644
--- a/tools/virsh-util.c
+++ b/tools/virsh-util.c
@@ -423,6 +423,31 @@ virshNetworkGetXMLFromNet(vshControl *ctl,
 }
 
 
+int
+virshNWFilterGetXMLFromNWFilter(vshControl *ctl,
+                                virNWFilterPtr nwfilter,
+                                unsigned int flags,
+                                xmlDocPtr *xml,
+                                xmlXPathContextPtr *ctxt)
+{
+    g_autofree char *desc = NULL;
+
+    if (!(desc = virNWFilterGetXMLDesc(nwfilter, flags))) {
+        vshError(ctl, _("Failed to get nwfilter description xml"));
+        return -1;
+    }
+
+    *xml = virXMLParseStringCtxt(desc, _("(nwfilter_definition)"), ctxt);
+
+    if (!(*xml)) {
+        vshError(ctl, _("Failed to parse nwfilter description xml"));
+        return -1;
+    }
+
+    return 0;
+}
+
+
 int
 virshDomainGetXML(vshControl *ctl,
                   const vshCmd *cmd,
diff --git a/tools/virsh-util.h b/tools/virsh-util.h
index 2386847072..4cad3d7eb9 100644
--- a/tools/virsh-util.h
+++ b/tools/virsh-util.h
@@ -152,6 +152,15 @@ virshNetworkGetXMLFromNet(vshControl *ctl,
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4)
     ATTRIBUTE_NONNULL(5) G_GNUC_WARN_UNUSED_RESULT;
 
+int
+virshNWFilterGetXMLFromNWFilter(vshControl *ctl,
+                                virNWFilterPtr nwfilter,
+                                unsigned int flags,
+                                xmlDocPtr *xml,
+                                xmlXPathContextPtr *ctxt)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4)
+    ATTRIBUTE_NONNULL(5) G_GNUC_WARN_UNUSED_RESULT;
+
 int
 virshDomainGetXML(vshControl *ctl,
                   const vshCmd *cmd,
-- 
2.42.0

Reply via email to