Define two new virsh commands: one to control disk streaming and one to print the status of active disk streams. * tools/virsh.c: implement the new commands Signed-off-by: Adam Litke <agl@xxxxxxxxxx> --- tools/virsh.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 157 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index ab83976..17957ac 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -229,6 +229,8 @@ static char *vshCommandOptString(const vshCmd *cmd, const char *name, int *found); static long long vshCommandOptLongLong(const vshCmd *cmd, const char *name, int *found); +static unsigned long long vshCommandOptULL(const vshCmd *cmd, const char *name, + int *found); static int vshCommandOptBool(const vshCmd *cmd, const char *name); static char *vshCommandOptArgv(const vshCmd *cmd, int count); @@ -3490,6 +3492,141 @@ done: } /* + * "domstreamdisk" command + */ +static const vshCmdInfo info_domstreamdisk[] = { + {"help", gettext_noop("Stream data to a disk")}, + {"desc", gettext_noop("Stream data to a disk connected to a running domain")}, + { NULL, NULL }, +}; + +static const vshCmdOptDef opts_domstreamdisk[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")}, + {"start", VSH_OT_BOOL, VSH_OFLAG_NONE, N_("Start streaming a disk") }, + {"stop", VSH_OT_BOOL, VSH_OFLAG_NONE, N_("Stop streaming a disk") }, + {"incremental", VSH_OT_BOOL, VSH_OFLAG_NONE, N_("Perform an incremental stream") }, + {"path", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")}, + {"offset", VSH_OT_DATA, VSH_OFLAG_NONE, N_("Device offset for incremental stream")}, + { NULL, 0, 0, NULL }, +}; + +static int +cmdDomStreamDisk(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + char *name; + const char *path; + int found; + unsigned long long offset, next; + unsigned int flags, start, stop, incr; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return FALSE; + + flags = start = stop = incr = 0; + if (vshCommandOptBool(cmd, "start")) { + start = 1; + flags = VIR_STREAM_DISK_START; + } + if (vshCommandOptBool(cmd, "stop")) { + stop = 1; + flags = VIR_STREAM_DISK_STOP; + } + if (vshCommandOptBool(cmd, "incremental")) { + incr = 1; + flags = VIR_STREAM_DISK_ONE; + } + if (start + stop + incr != 1) { + vshError(ctl, _("Exactly one mode: --start, --stop, --incremental, " + "is required")); + return FALSE; + } + + if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) + return FALSE; + + path = vshCommandOptString(cmd, "path", NULL); + + if (flags == VIR_STREAM_DISK_ONE) { + offset = vshCommandOptULL(cmd, "offset", &found); + if (!found) { + vshError(ctl, _("An offset is required for incremental streaming")); + virDomainFree(dom); + return FALSE; + } + } else { + offset = 0; + } + + next = virDomainStreamDisk(dom, path, offset, flags); + if (next == (unsigned long long) -1) { + vshError(ctl, _("Stream operation failed for the device" + "'%s' connected to the domain '%s'"), path, name); + virDomainFree(dom); + return FALSE; + } + + if (flags == VIR_STREAM_DISK_START) + vshPrint (ctl, "Stream successfully started\n"); + else if (flags == VIR_STREAM_DISK_STOP) + vshPrint (ctl, "Stream successfully stopped\n"); + else + vshPrint (ctl, "Strem successful. Continue at offset %llu\n", next); + + virDomainFree(dom); + return TRUE; +} + +/* + * "domstreamdiskinfo" command + */ +static const vshCmdInfo info_domstreamdiskinfo[] = { + {"help", gettext_noop("Get disk streaming status for a domain")}, + {"desc", gettext_noop("Get disk streaming status for a running domain")}, + { NULL, NULL }, +}; + +static const vshCmdOptDef opts_domstreamdiskinfo[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")}, + { NULL, 0, 0, NULL }, +}; + +static int +cmdDomStreamDiskInfo(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + char *name; + struct _virStreamDiskState streams[VIR_STREAM_DISK_MAX_STREAMS]; + int nr_streams, i; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) + return FALSE; + + nr_streams = virDomainStreamDiskInfo(dom, streams, + VIR_STREAM_DISK_MAX_STREAMS, 0); + if (nr_streams < 0) { + vshError(ctl, _("Failed to get disk stream information for domain %s"), + name); + virDomainFree(dom); + return FALSE; + } + + vshPrint (ctl, "%-30s %-10s %-10s\n", _("Device"), _("Offset"), + _("Size")); + vshPrint (ctl, "----------------------------------------------------\n"); + for (i = 0; i < nr_streams; i++) { + vshPrint (ctl, "%-30s %-10llu %-10llu\n", streams[i].path, + streams[i].offset, streams[i].size); + } + + virDomainFree(dom); + return TRUE; +} + +/* * "net-autostart" command */ static const vshCmdInfo info_network_autostart[] = { @@ -9854,6 +9991,8 @@ static const vshCmdDef commands[] = { {"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus}, {"migrate", cmdMigrate, opts_migrate, info_migrate}, {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime}, + {"domstreamdisk", cmdDomStreamDisk, opts_domstreamdisk, info_domstreamdisk}, + {"domstreamdiskinfo", cmdDomStreamDiskInfo, opts_domstreamdiskinfo, info_domstreamdiskinfo}, {"net-autostart", cmdNetworkAutostart, opts_network_autostart, info_network_autostart}, {"net-create", cmdNetworkCreate, opts_network_create, info_network_create}, @@ -10288,6 +10427,24 @@ vshCommandOptLongLong(const vshCmd *cmd, const char *name, int *found) } /* + * Returns option as unsigned long long + */ +static unsigned long long +vshCommandOptULL(const vshCmd *cmd, const char *name, int *found) +{ + vshCmdOpt *arg = vshCommandOpt(cmd, name); + int num_found = FALSE; + unsigned long long res = 0; + char *end_p = NULL; + + if ((arg != NULL) && (arg->data != NULL)) + num_found = !virStrToLong_ull(arg->data, &end_p, 10, &res); + if (found) + *found = num_found; + return res; +} + +/* * Returns TRUE/FALSE if the option exists */ static int -- 1.7.3.2.164.g6f10c -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list