From 728ad0e82b283f682586f48903856866e20bd4a1 Mon Sep 17 00:00:00 2001 From: Simon Kobyda Date: Thu, 12 Jul 2018 16:07:59 +0200 Subject: [PATCH] New virsh feature: domif-setlink --domain --interface --state completer After you go through command mentioned above, completer finds what state the device is currently in, and suggests an opposite state. Signed-off-by: Simon Kobyda Signed-off-by: Michal Privoznik --- tools/virsh-completer.c | 73 +++++++++++++++++++++++++++++++++++++++++ tools/virsh-completer.h | 4 +++ tools/virsh-domain.c | 1 + 3 files changed, 78 insertions(+) diff --git a/tools/virsh-completer.c b/tools/virsh-completer.c index be59ea2e82..44ddada538 100644 --- a/tools/virsh-completer.c +++ b/tools/virsh-completer.c @@ -32,6 +32,7 @@ #include "internal.h" #include "virutil.h" #include "viralloc.h" +#include "virmacaddr.h" #include "virstring.h" #include "virxml.h" @@ -777,6 +778,78 @@ virshPoolEventNameCompleter(vshControl *ctl ATTRIBUTE_UNUSED, } +char ** +virshDomainInterfaceStateCompleter(vshControl *ctl, + const vshCmd *cmd, + unsigned int flags) +{ + virshControlPtr priv = ctl->privData; + const char *iface = NULL; + char **ret = NULL; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + virMacAddr macaddr; + char macstr[VIR_MAC_STRING_BUFLEN] = ""; + int ninterfaces; + xmlNodePtr *interfaces = NULL; + char *xpath = NULL; + char *state = NULL; + + virCheckFlags(0, NULL); + + if (!priv->conn || virConnectIsAlive(priv->conn) <= 0) + return NULL; + + if (virshDomainGetXML(ctl, cmd, flags, &xml, &ctxt) < 0) + goto cleanup; + + if (vshCommandOptStringReq(ctl, cmd, "interface", &iface) < 0) + goto cleanup; + + /* normalize the mac addr */ + if (virMacAddrParse(iface, &macaddr) == 0) + virMacAddrFormat(&macaddr, macstr); + + if (virAsprintf(&xpath, "/domain/devices/interface[(mac/@address = '%s') or " + " (target/@dev = '%s')]", + macstr, iface) < 0) + goto cleanup; + + if ((ninterfaces = virXPathNodeSet(xpath, ctxt, &interfaces)) < 0) + goto cleanup; + + if (ninterfaces != 1) + goto cleanup; + + ctxt->node = interfaces[0]; + + if (VIR_ALLOC_N(ret, 2) < 0) + goto error; + + if ((state = virXPathString("string(./link/@state)", ctxt)) && + STREQ(state, "down")) { + if (VIR_STRDUP(ret[0], "up") < 0) + goto error; + } else { + if (VIR_STRDUP(ret[0], "down") < 0) + goto error; + } + + cleanup: + VIR_FREE(state); + VIR_FREE(xpath); + VIR_FREE(interfaces); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + return ret; + + error: + virStringListFree(ret); + ret = NULL; + goto cleanup; +} + + char ** virshNodedevEventNameCompleter(vshControl *ctl ATTRIBUTE_UNUSED, const vshCmd *cmd ATTRIBUTE_UNUSED, diff --git a/tools/virsh-completer.h b/tools/virsh-completer.h index 1c14bb2a54..b4fd2a86c6 100644 --- a/tools/virsh-completer.h +++ b/tools/virsh-completer.h @@ -94,6 +94,10 @@ char ** virshPoolEventNameCompleter(vshControl *ctl, const vshCmd *cmd, unsigned int flags); +char ** virshDomainInterfaceStateCompleter(vshControl *ctl, + const vshCmd *cmd, + unsigned int flags); + char ** virshNodedevEventNameCompleter(vshControl *ctl, const vshCmd *cmd, unsigned int flags); diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 3959b5475b..8adec1d9b1 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -3064,6 +3064,7 @@ static const vshCmdOptDef opts_domif_setlink[] = { {.name = "state", .type = VSH_OT_DATA, .flags = VSH_OFLAG_REQ, + .completer = virshDomainInterfaceStateCompleter, .help = N_("new state of the device") }, {.name = "persistent",