mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-22 04:25:18 +00:00
snapshot: better virsh handling of missing current, parent
Previously, virsh 'snapshot-parent' and 'snapshot-current' were completely silent in the case where the code conclusively proved there was no parent or current snapshot, but differed in exit status; this silence caused some confusion on whether the commands worked. Furthermore, commit d1be48f introduced a regression where snapshot-parent would leak output about an unknown function, but only on the first attempt, when talking to an older server that lacks virDomainSnapshotGetParent. This changes things to consistenly report an error message and exit with status 1 when no snapshot exists, and to avoid leaking unknown function warnings when using fallbacks. * tools/virsh.c (vshGetSnapshotParent): Alter signature, to distinguish between real error and missing parent. Don't pollute last_error on success. (cmdSnapshotParent): Adjust caller. Always output message on failure. (cmdSnapshotList): Adjust caller. (cmdSnapshotCurrent): Always output message on failure.
This commit is contained in:
parent
ae37001d78
commit
64703c03fc
@ -12946,6 +12946,7 @@ cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd)
|
|||||||
char *xml = NULL;
|
char *xml = NULL;
|
||||||
const char *snapshotname = NULL;
|
const char *snapshotname = NULL;
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
|
const char *domname;
|
||||||
|
|
||||||
if (vshCommandOptBool(cmd, "security-info"))
|
if (vshCommandOptBool(cmd, "security-info"))
|
||||||
flags |= VIR_DOMAIN_XML_SECURE;
|
flags |= VIR_DOMAIN_XML_SECURE;
|
||||||
@ -12953,7 +12954,7 @@ cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd)
|
|||||||
if (!vshConnectionUsability(ctl, ctl->conn))
|
if (!vshConnectionUsability(ctl, ctl->conn))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
dom = vshCommandOptDomain(ctl, cmd, NULL);
|
dom = vshCommandOptDomain(ctl, cmd, &domname);
|
||||||
if (dom == NULL)
|
if (dom == NULL)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -12987,9 +12988,12 @@ cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
current = virDomainHasCurrentSnapshot(dom, 0);
|
current = virDomainHasCurrentSnapshot(dom, 0);
|
||||||
if (current < 0)
|
if (current < 0) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
else if (current) {
|
} else if (!current) {
|
||||||
|
vshError(ctl, _("domain '%s' has no current snapshot"), domname);
|
||||||
|
goto cleanup;
|
||||||
|
} else {
|
||||||
const char *name = NULL;
|
const char *name = NULL;
|
||||||
|
|
||||||
if (!(snapshot = virDomainSnapshotCurrent(dom, 0)))
|
if (!(snapshot = virDomainSnapshotCurrent(dom, 0)))
|
||||||
@ -13011,6 +13015,8 @@ cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd)
|
|||||||
ret = true;
|
ret = true;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
if (!ret)
|
||||||
|
virshReportError(ctl);
|
||||||
VIR_FREE(xml);
|
VIR_FREE(xml);
|
||||||
if (snapshot)
|
if (snapshot)
|
||||||
virDomainSnapshotFree(snapshot);
|
virDomainSnapshotFree(snapshot);
|
||||||
@ -13021,26 +13027,33 @@ cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Helper function to get the name of a snapshot's parent. Caller
|
/* Helper function to get the name of a snapshot's parent. Caller
|
||||||
* must free the result. */
|
* must free the result. Returns 0 on success (including when it was
|
||||||
static char *
|
* proven no parent exists), and -1 on failure with error reported
|
||||||
vshGetSnapshotParent(vshControl *ctl, virDomainSnapshotPtr snapshot)
|
* (such as no snapshot support or domain deleted in meantime). */
|
||||||
|
static int
|
||||||
|
vshGetSnapshotParent(vshControl *ctl, virDomainSnapshotPtr snapshot,
|
||||||
|
char **parent_name)
|
||||||
{
|
{
|
||||||
virDomainSnapshotPtr parent = NULL;
|
virDomainSnapshotPtr parent = NULL;
|
||||||
char *xml = NULL;
|
char *xml = NULL;
|
||||||
xmlDocPtr xmldoc = NULL;
|
xmlDocPtr xmldoc = NULL;
|
||||||
xmlXPathContextPtr ctxt = NULL;
|
xmlXPathContextPtr ctxt = NULL;
|
||||||
char *parent_name = NULL;
|
int ret = -1;
|
||||||
|
|
||||||
|
*parent_name = NULL;
|
||||||
|
|
||||||
/* Try new API, since it is faster. */
|
/* Try new API, since it is faster. */
|
||||||
if (!ctl->useSnapshotGetXML) {
|
if (!ctl->useSnapshotGetXML) {
|
||||||
parent = virDomainSnapshotGetParent(snapshot, 0);
|
parent = virDomainSnapshotGetParent(snapshot, 0);
|
||||||
if (parent) {
|
if (parent) {
|
||||||
/* API works, and virDomainSnapshotGetName will succeed */
|
/* API works, and virDomainSnapshotGetName will succeed */
|
||||||
parent_name = vshStrdup(ctl, virDomainSnapshotGetName(parent));
|
*parent_name = vshStrdup(ctl, virDomainSnapshotGetName(parent));
|
||||||
|
ret = 0;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (last_error->code == VIR_ERR_NO_DOMAIN_SNAPSHOT) {
|
if (last_error->code == VIR_ERR_NO_DOMAIN_SNAPSHOT) {
|
||||||
/* API works, and we found a root with no parent */
|
/* API works, and we found a root with no parent */
|
||||||
|
ret = 0;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
/* API didn't work, fall back to XML scraping. */
|
/* API didn't work, fall back to XML scraping. */
|
||||||
@ -13055,15 +13068,23 @@ vshGetSnapshotParent(vshControl *ctl, virDomainSnapshotPtr snapshot)
|
|||||||
if (!xmldoc)
|
if (!xmldoc)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
parent_name = virXPathString("string(/domainsnapshot/parent/name)", ctxt);
|
*parent_name = virXPathString("string(/domainsnapshot/parent/name)", ctxt);
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
if (ret < 0) {
|
||||||
|
virshReportError(ctl);
|
||||||
|
vshError(ctl, "%s", _("unable to determine if snapshot has parent"));
|
||||||
|
} else {
|
||||||
|
virFreeError(last_error);
|
||||||
|
last_error = NULL;
|
||||||
|
}
|
||||||
if (parent)
|
if (parent)
|
||||||
virDomainSnapshotFree(parent);
|
virDomainSnapshotFree(parent);
|
||||||
xmlXPathFreeContext(ctxt);
|
xmlXPathFreeContext(ctxt);
|
||||||
xmlFreeDoc(xmldoc);
|
xmlFreeDoc(xmldoc);
|
||||||
VIR_FREE(xml);
|
VIR_FREE(xml);
|
||||||
return parent_name;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -13188,13 +13209,13 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
|
|||||||
if (snapshot)
|
if (snapshot)
|
||||||
virDomainSnapshotFree(snapshot);
|
virDomainSnapshotFree(snapshot);
|
||||||
snapshot = virDomainSnapshotLookupByName(dom, names[i], 0);
|
snapshot = virDomainSnapshotLookupByName(dom, names[i], 0);
|
||||||
if (!snapshot) {
|
if (!snapshot ||
|
||||||
|
vshGetSnapshotParent(ctl, snapshot, &parents[i]) < 0) {
|
||||||
while (--i >= 0)
|
while (--i >= 0)
|
||||||
VIR_FREE(parents[i]);
|
VIR_FREE(parents[i]);
|
||||||
VIR_FREE(parents);
|
VIR_FREE(parents);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
parents[i] = vshGetSnapshotParent(ctl, snapshot);
|
|
||||||
}
|
}
|
||||||
for (i = 0 ; i < actual ; i++) {
|
for (i = 0 ; i < actual ; i++) {
|
||||||
memset(indentBuf, '\0', sizeof indentBuf);
|
memset(indentBuf, '\0', sizeof indentBuf);
|
||||||
@ -13390,9 +13411,12 @@ cmdSnapshotParent(vshControl *ctl, const vshCmd *cmd)
|
|||||||
if (snapshot == NULL)
|
if (snapshot == NULL)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
parent = vshGetSnapshotParent(ctl, snapshot);
|
if (vshGetSnapshotParent(ctl, snapshot, &parent) < 0)
|
||||||
if (!parent)
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
if (!parent) {
|
||||||
|
vshError(ctl, _("snapshot '%s' has no parent"), name);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
vshPrint(ctl, "%s", parent);
|
vshPrint(ctl, "%s", parent);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user