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/tests/virsh-output-commands b/tests/virsh-output-commands index 43f87bee0f..d8e73fc1ac 100755 --- a/tests/virsh-output-commands +++ b/tests/virsh-output-commands @@ -78,3 +78,17 @@ attach_disk --target sda --sourcetype file --type disk --address ccw:12.34.56 attach_disk --target vda --sourcetype file --type disk --address test:12.34.56 attach_disk --target vda --sourcetype file --type disk --address test:12:34:56 attach_disk --target vda --sourcetype file --type disk --address test:12.34.56 + +./virsh attach-disk --print-xml --domain testdom $@ --source "" --source-protocol AAA +./virsh attach-disk --print-xml --domain testdom $@ --source "" --source-protocol AAA +attach_disk --target hda --source-protocol AAA --sourcetype file +attach_disk --target hda --sourcetype network +attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-name hostname +attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-name hostname:port +attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-name hostname: +attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-name :port +attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-name : +attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-name hostname:port --source-host-transport trnsp +attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-transport trnsp +attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-transport trnsp --source-host-socket /nonexistent/socket +attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-socket /nonexistent/socket diff --git a/tests/virsh-output.out b/tests/virsh-output.out index 6af7600a9c..d8ef641c2a 100644 --- a/tests/virsh-output.out +++ b/tests/virsh-output.out @@ -405,4 +405,92 @@ error: Invalid address. + ./virsh attach-disk --print-xml --domain testdom --target vda --sourcetype file --type disk --address test:12.34.56 --source /nonexistent/file error: Invalid address. ++ ./virsh attach-disk --print-xml --domain testdom --source '' --source-protocol AAA +error: command 'attach-disk' requires option ++ ./virsh attach-disk --print-xml --domain testdom --source '' --source-protocol AAA +error: command 'attach-disk' requires option ++ attach_disk --target hda --source-protocol AAA --sourcetype file ++ ./virsh attach-disk --print-xml --domain testdom --target hda --source-protocol AAA --sourcetype file --source /nonexistent/file +error: --source-protocol option requires --sourcetype network + ++ attach_disk --target hda --sourcetype network ++ ./virsh attach-disk --print-xml --domain testdom --target hda --sourcetype network --source /nonexistent/file +error: --source-protocol option requires --sourcetype network + ++ attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-name hostname ++ ./virsh attach-disk --print-xml --domain testdom --target hda --sourcetype network --source-protocol TEST --source-host-name hostname --source /nonexistent/file + + + + + + + ++ attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-name hostname:port ++ ./virsh attach-disk --print-xml --domain testdom --target hda --sourcetype network --source-protocol TEST --source-host-name hostname:port --source /nonexistent/file + + + + + + + ++ attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-name hostname: ++ ./virsh attach-disk --print-xml --domain testdom --target hda --sourcetype network --source-protocol TEST --source-host-name hostname: --source /nonexistent/file + + + + + + + ++ attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-name :port ++ ./virsh attach-disk --print-xml --domain testdom --target hda --sourcetype network --source-protocol TEST --source-host-name :port --source /nonexistent/file + + + + + + + ++ attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-name : ++ ./virsh attach-disk --print-xml --domain testdom --target hda --sourcetype network --source-protocol TEST --source-host-name : --source /nonexistent/file + + + + + + + ++ attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-name hostname:port --source-host-transport trnsp ++ ./virsh attach-disk --print-xml --domain testdom --target hda --sourcetype network --source-protocol TEST --source-host-name hostname:port --source-host-transport trnsp --source /nonexistent/file + + + + + + + ++ attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-transport trnsp ++ ./virsh attach-disk --print-xml --domain testdom --target hda --sourcetype network --source-protocol TEST --source-host-transport trnsp --source /nonexistent/file + + + + + + + ++ attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-transport trnsp --source-host-socket /nonexistent/socket ++ ./virsh attach-disk --print-xml --domain testdom --target hda --sourcetype network --source-protocol TEST --source-host-transport trnsp --source-host-socket /nonexistent/socket --source /nonexistent/file + + + + + + + ++ attach_disk --target hda --sourcetype network --source-protocol TEST --source-host-socket /nonexistent/socket ++ ./virsh attach-disk --print-xml --domain testdom --target hda --sourcetype network --source-protocol TEST --source-host-socket /nonexistent/socket --source /nonexistent/file +error: Option --source-host-transport is required by option --source-host-socket + end diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index b0e1c6e6f7..7203403b31 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -394,7 +394,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, @@ -440,7 +440,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, @@ -470,6 +470,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, @@ -523,6 +539,7 @@ enum virshAttachDiskSourceType { VIRSH_ATTACH_DISK_SOURCE_TYPE_NONE, VIRSH_ATTACH_DISK_SOURCE_TYPE_FILE, VIRSH_ATTACH_DISK_SOURCE_TYPE_BLOCK, + VIRSH_ATTACH_DISK_SOURCE_TYPE_NETWORK, VIRSH_ATTACH_DISK_SOURCE_TYPE_LAST }; @@ -532,7 +549,8 @@ VIR_ENUM_IMPL(virshAttachDiskSource, VIRSH_ATTACH_DISK_SOURCE_TYPE_LAST, "", "file", - "block"); + "block", + "network"); static bool @@ -553,6 +571,10 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd) const char *wwn = NULL; const char *targetbus = NULL; const char *alias = NULL; + const char *source_protocol = NULL; + const char *host_name = NULL; + const char *host_transport = NULL; + const char *host_socket = NULL; int ret; unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT; const char *stype = NULL; @@ -562,6 +584,8 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd) g_auto(virBuffer) diskChildBuf = VIR_BUFFER_INIT_CHILD(&buf); g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER; g_auto(virBuffer) sourceAttrBuf = VIR_BUFFER_INITIALIZER; + g_auto(virBuffer) sourceChildBuf = VIR_BUFFER_INIT_CHILD(&diskChildBuf); + g_auto(virBuffer) hostAttrBuf = VIR_BUFFER_INITIALIZER; g_autofree char *xml = NULL; struct stat st; bool current = vshCommandOptBool(cmd, "current"); @@ -575,6 +599,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) @@ -594,7 +625,11 @@ 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) return false; if (stype && @@ -604,17 +639,24 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd) } if (type == VIRSH_ATTACH_DISK_SOURCE_TYPE_NONE) { - if (STRNEQ_NULLABLE(driver, "file") && - STRNEQ_NULLABLE(driver, "tap") && - source && - stat(source, &st) == 0 && - S_ISBLK(st.st_mode)) { + if (source_protocol) { + type = VIRSH_ATTACH_DISK_SOURCE_TYPE_NETWORK; + } else if (STRNEQ_NULLABLE(driver, "file") && + STRNEQ_NULLABLE(driver, "tap") && + source && + stat(source, &st) == 0 && + S_ISBLK(st.st_mode)) { type = VIRSH_ATTACH_DISK_SOURCE_TYPE_BLOCK; } else { type = VIRSH_ATTACH_DISK_SOURCE_TYPE_FILE; } } + if ((type == VIRSH_ATTACH_DISK_SOURCE_TYPE_NETWORK) != !!source_protocol) { + vshError(ctl, _("--source-protocol option requires --sourcetype network")); + return false; + } + if (mode) { if (STRNEQ(mode, "readonly") && STRNEQ(mode, "shareable")) { vshError(ctl, _("No support for %s in command 'attach-disk'"), @@ -648,11 +690,33 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd) virBufferEscapeString(&sourceAttrBuf, " dev='%s'", source); break; + case VIRSH_ATTACH_DISK_SOURCE_TYPE_NETWORK: + virBufferEscapeString(&sourceAttrBuf, " protocol='%s'", source_protocol); + virBufferEscapeString(&sourceAttrBuf, " name='%s'", source); + + virBufferEscapeString(&hostAttrBuf, " transport='%s'", host_transport); + virBufferEscapeString(&hostAttrBuf, " socket='%s'", host_socket); + + if (host_name) { + g_autofree char *host_name_copy = g_strdup(host_name); + char *host_port = strchr(host_name_copy, ':'); + + if (host_port) { + *host_port = '\0'; + host_port++; + } + + virBufferEscapeString(&hostAttrBuf, " name='%s'", host_name_copy); + virBufferEscapeString(&hostAttrBuf, " port='%s'", host_port); + } + virXMLFormatElement(&sourceChildBuf, "host", &hostAttrBuf, NULL); + break; + case VIRSH_ATTACH_DISK_SOURCE_TYPE_NONE: case VIRSH_ATTACH_DISK_SOURCE_TYPE_LAST: break; } - virXMLFormatElement(&diskChildBuf, "source", &sourceAttrBuf, NULL); + virXMLFormatElement(&diskChildBuf, "source", &sourceAttrBuf, &sourceChildBuf); virBufferAsprintf(&diskChildBuf, "