[PATCH] Added attach-disk parameters for network disk support

Ryan Gahagan rgahagan at cs.utexas.edu
Wed Nov 11 23:00:51 UTC 2020


Related issue: https://gitlab.com/libvirt/libvirt/-/issues/16
Added in support for the following parameters in attach-disk:
--source-name
--source-protocol
--source-host-name
--source-host-socket
--source-host-transport

Allowed for multiple hosts to be added to a single source.
Multiple hosts can be defined by providing multiple instances of
--source-host-name, followed by optional transport and socket
parameters.
Using a single host does not require a host name.

Added documentation to virsh.rst specifying usage.

Signed-off-by: Ryan Gahagan <rgahagan at cs.utexas.edu>
---
 docs/manpages/virsh.rst |  24 +++++++-
 tools/virsh-domain.c    | 125 +++++++++++++++++++++++++++++++++++++---
 2 files changed, 138 insertions(+), 11 deletions(-)

diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index bfd26e3120..60e5f5ebe4 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -4500,9 +4500,11 @@ attach-disk
       [--current]] | [--persistent]] [--targetbus bus]
       [--driver driver] [--subdriver subdriver] [--iothread iothread]
       [--cache cache] [--io io] [--type type] [--alias alias]
-      [--mode mode] [--sourcetype sourcetype] [--serial serial]
-      [--wwn wwn] [--rawio] [--address address] [--multifunction]
-      [--print-xml]
+      [--mode mode] [--sourcetype sourcetype] [--source-name name]
+      [--source-protocol protocol] [--source-host-name hostname:port]
+      [--source-host-transport transport] [--source-host-socket socket]
+      [--serial serial] [--wwn wwn] [--rawio] [--address address]
+      [--multifunction] [--print-xml]
 
 Attach a new disk device to the domain.
 *source* is path for the files and devices. *target* controls the bus or
@@ -4541,6 +4543,22 @@ ccw:cssid.ssid.devno. Virtio-ccw devices must have their cssid set to 0xfe.
 *multifunction* indicates specified pci address is a multifunction pci device
 address.
 
+If *--source-protocol* or *--source-name* is specified, then the parameters
+will be inserted into the XML that is generated for the source.
+If any of *--source-host-name*, *--source-host-transport*, or
+*--source-host-socket* are specified, then a ``<host>`` tag
+will be generated under the ``<source>`` tag containing whichever
+parameters were provided. If needed, the user can provide multiple hosts
+by providing each host with a *--source-host-name*. Each host will
+receive the host parameters which come between it and the next instance
+of *--source-host-name* or between it and the end of the command.
+If a user tries to provide multiple of the same host parameter
+for any single host, only the first one will be generated as
+part of the XML output.
+
+--source-host-name me --source-host-transport t1 --source-host-transport t2 --source-host-transport t3 --soure-host-name you
+<host transport='t1' transport='t2' transport='t3'>
+
 If *--print-xml* is specified, then the XML of the disk that would be attached
 is printed instead.
 
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 12b35c037d..609189e398 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -224,6 +224,26 @@ static const vshCmdOptDef opts_attach_disk[] = {
      .flags = VSH_OFLAG_REQ | VSH_OFLAG_EMPTY_OK,
      .help = N_("source of disk device")
     },
+    {.name = "source-protocol",
+     .type = VSH_OT_STRING,
+     .help = N_("protocol used by disk device source")
+    },
+    {.name = "source-name",
+     .type = VSH_OT_STRING,
+     .help = N_("name of disk device source")
+    },
+    {.name = "source-host-name",
+     .type = VSH_OT_STRING,
+     .help = N_("host name for source of disk device")
+    },
+    {.name = "source-host-transport",
+     .type = VSH_OT_STRING,
+     .help = N_("host transport for source of disk device")
+    },
+    {.name = "source-host-socket",
+     .type = VSH_OT_STRING,
+     .help = N_("host socket for source of disk device")
+    },
     {.name = "target",
      .type = VSH_OT_DATA,
      .flags = VSH_OFLAG_REQ,
@@ -558,15 +578,68 @@ static int str2DiskAddress(const char *str, struct DiskAddress *diskAddr)
     return -1;
 }
 
+static void attachDiskHostGen(virBufferPtr buf, const vshCmd *cmd)
+{
+    // Can be multiple hosts so we have to scan
+    // the cmd options to find all the host params
+    // <source tag in XML not yet closed
+    vshCmdOpt *candidate = cmd->opts;
+    char *host_name = NULL, *host_port = NULL;
+    int close_tag = 0, seen_socket = 0, seen_transport = 0;
+
+    while (candidate) {
+        // Iterate candidates to find each host-name
+        if (STREQ(candidate->def->name, "source-host-name")) {
+            // After the first host-name, we need to terminate
+            // the <host ... tag
+            // It's left open so socket and transport can be added later
+
+            // Only include the first example of socket or transport per host
+            // When a socket or transport is seen, these are set to true
+            // until the next name is encountered.
+            seen_socket = 0;
+            seen_transport = 0;
+
+            if (close_tag)
+                virBufferAddLit(buf, "/>\n");
+            else
+                close_tag = 1;
+
+            host_name = candidate->data;
+            host_port = strchr(host_name, ':');
+
+            if (!host_port) {
+                // If port isn't provided, only print name
+                virBufferAsprintf(buf, "<host name='%s'", host_name);
+            } else {
+                // If port is provided, manipulate strings and print both
+                host_name[(int)(host_port - host_name)] = '\0';
+                virBufferAsprintf(buf, "<host name='%s' port='%s'", host_name, host_port + 1);
+            }
+        } else if (!seen_socket && STREQ(candidate->def->name, "source-host-socket")) {
+            seen_socket = 1;
+            virBufferAsprintf(buf, " socket='%s'", candidate->data);
+        } else if (!seen_transport && STREQ(candidate->def->name, "source-host-transport")) {
+            seen_transport = 1;
+            virBufferAsprintf(buf, " transport='%s'", candidate->data);
+        }
+
+        candidate = candidate->next;
+    }
+    // Close final <host tag
+    virBufferAddLit(buf, "/>\n");
+}
+
 static bool
 cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
 {
     virDomainPtr dom = NULL;
-    const char *source = NULL, *target = NULL, *driver = NULL,
-                *subdriver = NULL, *type = NULL, *mode = NULL,
-                *iothread = NULL, *cache = NULL, *io = NULL,
-                *serial = NULL, *straddr = NULL, *wwn = NULL,
-                *targetbus = NULL, *alias = NULL;
+    const char *source = NULL, *source_name = NULL, *source_protocol = NULL,
+                *target = NULL, *driver = NULL, *subdriver = NULL, *type = NULL,
+                *mode = NULL, *iothread = NULL, *cache = NULL,
+                *io = NULL, *serial = NULL, *straddr = NULL,
+                *wwn = NULL, *targetbus = NULL, *alias = NULL,
+                *host_transport = NULL, *host_name = NULL, *host_socket = NULL;
     struct DiskAddress diskAddr;
     bool isFile = false, functionReturn = false;
     int ret;
@@ -591,6 +664,8 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
         flags |= VIR_DOMAIN_AFFECT_LIVE;
 
     if (vshCommandOptStringReq(ctl, cmd, "source", &source) < 0 ||
+        vshCommandOptStringReq(ctl, cmd, "source-name", &source_name) < 0 ||
+        vshCommandOptStringReq(ctl, cmd, "source-protocol", &source_protocol) < 0 ||
         vshCommandOptStringReq(ctl, cmd, "target", &target) < 0 ||
         vshCommandOptStringReq(ctl, cmd, "driver", &driver) < 0 ||
         vshCommandOptStringReq(ctl, cmd, "subdriver", &subdriver) < 0 ||
@@ -604,7 +679,10 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
         vshCommandOptStringReq(ctl, cmd, "address", &straddr) < 0 ||
         vshCommandOptStringReq(ctl, cmd, "targetbus", &targetbus) < 0 ||
         vshCommandOptStringReq(ctl, cmd, "alias", &alias) < 0 ||
-        vshCommandOptStringReq(ctl, cmd, "sourcetype", &stype) < 0)
+        vshCommandOptStringReq(ctl, cmd, "sourcetype", &stype) < 0 ||
+        vshCommandOptStringReq(ctl, cmd, "source-host-name", (const char **) &host_name) < 0 ||
+        vshCommandOptStringReq(ctl, cmd, "source-host-transport", &host_transport) < 0 ||
+        vshCommandOptStringReq(ctl, cmd, "source-host-socket", &host_socket) < 0)
         goto cleanup;
 
     if (!stype) {
@@ -659,9 +737,40 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
         virBufferAddLit(&buf, "/>\n");
     }
 
-    if (source)
-        virBufferAsprintf(&buf, "<source %s='%s'/>\n",
+    if (source || source_protocol || source_name ||
+        host_name || host_transport || host_socket) {
+        virBufferAddLit(&buf, "<source");
+
+        if (source)
+            virBufferAsprintf(&buf, " %s='%s'",
                           isFile ? "file" : "dev", source);
+        if (source_protocol)
+            virBufferAsprintf(&buf, " protocol='%s'", source_protocol);
+        if (source_name)
+            virBufferAsprintf(&buf, " name='%s'", source_name);
+
+        if (!(host_name || host_transport || host_socket)) {
+            // Close source if no host is provided
+            virBufferAddLit(&buf, "/>\n");
+        } else if (!host_name) {
+            // If no host name is provided but there is a host,
+            // we have a single host with params
+            virBufferAddLit(&buf, ">\n<host");
+
+            if (host_transport)
+                virBufferAsprintf(&buf, " transport='%s'", host_transport);
+            if (host_socket)
+                virBufferAsprintf(&buf, " socket='%s'", host_socket);
+
+            virBufferAddLit(&buf, "/>\n</source>\n");
+        } else {
+            // May have multiple hosts, use helper method
+            virBufferAddLit(&buf, ">\n");
+            attachDiskHostGen(&buf, cmd);
+            virBufferAddLit(&buf, "</source>\n");
+        }
+    }
+
     virBufferAsprintf(&buf, "<target dev='%s'", target);
     if (targetbus)
         virBufferAsprintf(&buf, " bus='%s'", targetbus);
-- 
2.29.0




More information about the libvir-list mailing list