Related issue: https://gitlab.com/libvirt/libvirt/-/issues/16 Added in support for the following parameters in attach-disk: --source-protocol --source-host-name --source-host-socket --source-host-transport Added documentation to virsh.rst specifying usage. Signed-off-by: Ryan Gahagan <rgahagan@xxxxxxxxxxxxx> --- docs/manpages/virsh.rst | 31 ++++++--- tools/virsh-domain.c | 135 +++++++++++++++++++++++++++++++++++----- 2 files changed, 145 insertions(+), 21 deletions(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index 1ae6d1a0d4..36c868a3e6 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -4538,14 +4538,18 @@ 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-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 -device under which the disk is exposed to the guest OS. It indicates the -"logical" device name; the optional *targetbus* attribute specifies the type +*source* is path for the files and devices unless *--source-protocol* +is specified, in which case *source* is the name of a network disk. +*target* controls the bus or device under which the disk is exposed +to the guest OS. It indicates the "logical" device name; +the optional *targetbus* attribute specifies the type of disk device to emulate; possible values are driver specific, with typical values being *ide*, *scsi*, *virtio*, *xen*, *usb*, *sata*, or *sd*, if omitted, the bus type is inferred from the style of the device name (e.g. a @@ -4563,7 +4567,7 @@ within the existing virtual cdrom or floppy device; consider using ``update-device`` for this usage instead. *alias* can set user supplied alias. *mode* can specify the two specific mode *readonly* or *shareable*. -*sourcetype* can indicate the type of source (block|file) +*sourcetype* can indicate the type of source (block|file|network) *cache* can be one of "default", "none", "writethrough", "writeback", "directsync" or "unsafe". *io* controls specific policies on I/O; QEMU guests support "threads", @@ -4579,6 +4583,19 @@ 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. +There is also support for using a network disk. As specified, the user can +provide a *--source-protocol* in which case the *source* parameter will +be interpreted as the source name. *--source-protocol* must be provided +if the user intends to provide a network disk or host information. +Host information can be provided using the tags +*--source-host-name*, *--source-host-transport*, and *--source-host-socket*, +which respectively denote the name of the host, the host's transport method, +and the socket that the host uses. *--source-host-socket* and +*--source-host-name* cannot both be provided, and the user must provide a +*--source-host-transport* if they want to provide a *--source-host-socket*. +The *--source-host-name* parameter supports host:port syntax +if the user wants to provide a port as well. + 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 c999458d72..1303676c33 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -222,7 +222,7 @@ static const vshCmdOptDef opts_attach_disk[] = { {.name = "source", .type = VSH_OT_DATA, .flags = VSH_OFLAG_REQ | VSH_OFLAG_EMPTY_OK, - .help = N_("source of disk device") + .help = N_("source of disk device or name of network disk") }, {.name = "target", .type = VSH_OT_DATA, @@ -268,7 +268,7 @@ static const vshCmdOptDef opts_attach_disk[] = { }, {.name = "sourcetype", .type = VSH_OT_STRING, - .help = N_("type of source (block|file)") + .help = N_("type of source (block|file|network)") }, {.name = "serial", .type = VSH_OT_STRING, @@ -298,6 +298,22 @@ static const vshCmdOptDef opts_attach_disk[] = { .type = VSH_OT_BOOL, .help = N_("print XML document rather than attach the disk") }, + {.name = "source-protocol", + .type = VSH_OT_STRING, + .help = N_("protocol used by 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") + }, VIRSH_COMMON_OPT_DOMAIN_PERSISTENT, VIRSH_COMMON_OPT_DOMAIN_CONFIG, VIRSH_COMMON_OPT_DOMAIN_LIVE, @@ -558,6 +574,13 @@ static int str2DiskAddress(const char *str, struct DiskAddress *diskAddr) return -1; } +typedef enum { + VIRSH_SOURCE_TYPE_FILE, + VIRSH_SOURCE_TYPE_BLOCK, + VIRSH_SOURCE_TYPE_NETWORK, + VIRSH_SOURCE_TYPE_UNKNOWN, +} virshAttachDiskSourceType; + static bool cmdAttachDisk(vshControl *ctl, const vshCmd *cmd) { @@ -567,8 +590,14 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd) *iothread = NULL, *cache = NULL, *io = NULL, *serial = NULL, *straddr = NULL, *wwn = NULL, *targetbus = NULL, *alias = NULL; + const char *source_protocol = NULL; + const char *host_name = NULL; + const char *host_transport = NULL; + const char *host_socket = NULL; + char *host_port = NULL; struct DiskAddress diskAddr; - bool isFile = false, functionReturn = false; + virshAttachDiskSourceType disk_type = VIRSH_SOURCE_TYPE_UNKNOWN; + bool functionReturn = false; int ret; unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT; const char *stype = NULL; @@ -585,6 +614,13 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd) VSH_EXCLUSIVE_OPTIONS_VAR(current, live); VSH_EXCLUSIVE_OPTIONS_VAR(current, config); + VSH_REQUIRE_OPTION("source-host-name", "source-protocol"); + VSH_REQUIRE_OPTION("source-host-transport", "source-protocol"); + VSH_REQUIRE_OPTION("source-host-socket", "source-protocol"); + VSH_REQUIRE_OPTION("source-host-socket", "source-host-transport"); + + VSH_EXCLUSIVE_OPTIONS("source-host-name", "source-host-socket"); + if (config || persistent) flags |= VIR_DOMAIN_AFFECT_CONFIG; if (live) @@ -604,23 +640,45 @@ 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-protocol", &source_protocol) < 0 || + vshCommandOptStringReq(ctl, cmd, "source-host-name", &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) { if (driver && (STREQ(driver, "file") || STREQ(driver, "tap"))) { - isFile = true; + disk_type = VIRSH_SOURCE_TYPE_FILE; } else { - if (source && !stat(source, &st)) - isFile = S_ISREG(st.st_mode) ? true : false; + if (source && !stat(source, &st)) { + if (S_ISREG(st.st_mode)) + disk_type = VIRSH_SOURCE_TYPE_FILE; + else + disk_type = VIRSH_SOURCE_TYPE_BLOCK; + } } } else if (STREQ(stype, "file")) { - isFile = true; - } else if (STRNEQ(stype, "block")) { + disk_type = VIRSH_SOURCE_TYPE_FILE; + } else if (STREQ(stype, "block")) { + disk_type = VIRSH_SOURCE_TYPE_BLOCK; + } else if (STREQ(stype, "network")) { + /* The user must provide a protocol for a network disk */ + if (!source_protocol) { + vshError(ctl, _("A source-protocol must be provided for a network disk")); + goto cleanup; + } + } else { vshError(ctl, _("Unknown source type: '%s'"), stype); goto cleanup; } + /* If a protocol is provided, the disk is assumed to be a network disk. + * This overwrites other disk types, such as an explicit + * 'sourcetype=file' or comparable parameter. */ + if (source_protocol) + disk_type = VIRSH_SOURCE_TYPE_NETWORK; + if (mode) { if (STRNEQ(mode, "readonly") && STRNEQ(mode, "shareable")) { vshError(ctl, _("No support for %s in command 'attach-disk'"), @@ -633,8 +691,13 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd) goto cleanup; /* Make XML of disk */ - virBufferAsprintf(&buf, "<disk type='%s'", - isFile ? "file" : "block"); + if (disk_type == VIRSH_SOURCE_TYPE_FILE) + virBufferAddLit(&buf, "<disk type='file'"); + else if (disk_type == VIRSH_SOURCE_TYPE_BLOCK) + virBufferAddLit(&buf, "<disk type='block'"); + else if (disk_type == VIRSH_SOURCE_TYPE_NETWORK) + virBufferAddLit(&buf, "<disk type='network'"); + if (type) virBufferAsprintf(&buf, " device='%s'", type); if (vshCommandOptBool(cmd, "rawio")) @@ -659,9 +722,53 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd) virBufferAddLit(&buf, "/>\n"); } - if (source) - virBufferAsprintf(&buf, "<source %s='%s'/>\n", - isFile ? "file" : "dev", source); + if (source || source_protocol) { + virBufferAddLit(&buf, "<source"); + if (source_protocol) { + /* Using a network disk; source is --source-name */ + virBufferAsprintf(&buf, " protocol='%s'", source_protocol); + if (source) + virBufferAsprintf(&buf, " name='%s'", source); + + if (host_name || host_socket || host_transport) { + /* Host information provided, add a <host> tag */ + virBufferAddLit(&buf, ">\n"); + virBufferAdjustIndent(&buf, 2); + virBufferAddLit(&buf, "<host"); + + if (host_name) { + /* Logic for host:port syntax */ + g_autofree char *host_name_copy = g_strdup(host_name); + host_port = strchr(host_name_copy, ':'); + + if (host_port) { + *host_port = '\0'; + virBufferAsprintf(&buf, + " name='%s' port='%s'", + host_name_copy, host_port + 1); + } else { + virBufferAsprintf(&buf, " name='%s'", host_name); + } + } + + if (host_transport) + virBufferAsprintf(&buf, " transport='%s'", host_transport); + if (host_socket) + virBufferAsprintf(&buf, " socket='%s'", host_socket); + virBufferAddLit(&buf, "/>\n"); + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</source>\n"); + } + } else { + /* Using a local disk; source is file or dev */ + if (disk_type == VIRSH_SOURCE_TYPE_FILE) + virBufferAsprintf(&buf, " file='%s'", source); + else + virBufferAsprintf(&buf, " dev='%s'", source); + virBufferAddLit(&buf, "/>\n"); + } + } + virBufferAsprintf(&buf, "<target dev='%s'", target); if (targetbus) virBufferAsprintf(&buf, " bus='%s'", targetbus); -- 2.29.0