snapshot: teach virsh about new undefine flags

Similar to 'undefine --managed-save' (commit 83e849c1), we must
assume that the old API is unsafe; however, we cannot emulate
metadata-only deletion on older servers.  Additionally, we have
the wrinkle that while virDomainUndefineFlags and managed save
cleanup were introduced in 0.9.4, it wasn't until 0.9.5 that
snapshots block undefine of a domain.  Do the best we can given
the server we are talking to.

* tools/virsh.c (cmdUndefine): Add --snapshots-metadata flag.
* tools/virsh.pod (undefine, destroy, shutdown): Document effect
of snapshots.
This commit is contained in:
Eric Blake 2011-08-11 20:24:19 -06:00
parent 282fe1f08c
commit e88872e9a9
2 changed files with 145 additions and 50 deletions

View File

@ -1434,6 +1434,8 @@ static const vshCmdInfo info_undefine[] = {
static const vshCmdOptDef opts_undefine[] = {
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name or uuid")},
{"managed-save", VSH_OT_BOOL, 0, N_("remove domain managed state file")},
{"snapshots-metadata", VSH_OT_BOOL, 0,
N_("remove all domain snapshot metadata, if inactive")},
{NULL, 0, 0, NULL}
};
@ -1441,18 +1443,31 @@ static bool
cmdUndefine(vshControl *ctl, const vshCmd *cmd)
{
virDomainPtr dom;
bool ret = true;
bool ret = false;
const char *name = NULL;
/* Flags to attempt. */
unsigned int flags = 0;
int managed_save = vshCommandOptBool(cmd, "managed-save");
/* User-requested actions. */
bool managed_save = vshCommandOptBool(cmd, "managed-save");
bool snapshots_metadata = vshCommandOptBool(cmd, "snapshots-metadata");
/* Positive if these items exist. */
int has_managed_save = 0;
int has_snapshots_metadata = 0;
int has_snapshots = 0;
/* True if undefine will not strand data, even on older servers. */
bool managed_save_safe = false;
bool snapshots_safe = false;
int rc = -1;
int running;
if (managed_save)
if (managed_save) {
flags |= VIR_DOMAIN_UNDEFINE_MANAGED_SAVE;
if (!managed_save)
flags = -1;
managed_save_safe = true;
}
if (snapshots_metadata) {
flags |= VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA;
snapshots_safe = true;
}
if (!vshConnectionUsability(ctl, ctl->conn))
return false;
@ -1460,61 +1475,120 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
return false;
has_managed_save = virDomainHasManagedSaveImage(dom, 0);
if (has_managed_save < 0) {
if (last_error->code != VIR_ERR_NO_SUPPORT) {
virshReportError(ctl);
virDomainFree(dom);
return false;
} else {
virFreeError(last_error);
last_error = NULL;
}
/* Do some flag manipulation. The goal here is to disable bits
* from flags to reduce the likelihood of a server rejecting
* unknown flag bits, as well as to track conditions which are
* safe by default for the given hypervisor and server version. */
running = virDomainIsActive(dom);
if (running < 0) {
virshReportError(ctl);
goto cleanup;
}
if (flags == -1) {
if (has_managed_save == 1) {
vshError(ctl,
_("Refusing to undefine while domain managed save "
"image exists"));
virDomainFree(dom);
return false;
}
rc = virDomainUndefine(dom);
} else {
rc = virDomainUndefineFlags(dom, flags);
/* It might fail when virDomainUndefineFlags is not
* supported on older libvirt, try to undefine the
* domain with combo virDomainManagedSaveRemove and
* virDomainUndefine.
*/
if (rc < 0) {
if (!running) {
/* Undefine with snapshots only fails for inactive domains,
* and managed save only exists on inactive domains; if
* running, then we don't want to remove anything. */
has_managed_save = virDomainHasManagedSaveImage(dom, 0);
if (has_managed_save < 0) {
if (last_error->code != VIR_ERR_NO_SUPPORT) {
virshReportError(ctl);
goto end;
} else {
goto cleanup;
}
virFreeError(last_error);
last_error = NULL;
has_managed_save = 0;
}
has_snapshots = virDomainSnapshotNum(dom, 0);
if (has_snapshots < 0) {
if (last_error->code != VIR_ERR_NO_SUPPORT) {
virshReportError(ctl);
goto cleanup;
}
virFreeError(last_error);
last_error = NULL;
has_snapshots = 0;
}
if (has_snapshots) {
has_snapshots_metadata
= virDomainSnapshotNum(dom, VIR_DOMAIN_SNAPSHOT_LIST_METADATA);
if (has_snapshots_metadata < 0) {
/* The server did not know the new flag, assume that all
snapshots have metadata. */
virFreeError(last_error);
last_error = NULL;
has_snapshots_metadata = has_snapshots;
} else {
/* The server knew the new flag, all aspects of
* undefineFlags are safe. */
managed_save_safe = snapshots_safe = true;
}
}
}
if (!has_managed_save) {
flags &= ~VIR_DOMAIN_UNDEFINE_MANAGED_SAVE;
managed_save_safe = true;
}
if (has_snapshots == 0) {
snapshots_safe = true;
}
if (has_snapshots_metadata == 0) {
flags &= ~VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA;
snapshots_safe = true;
}
if ((has_managed_save == 1) &&
virDomainManagedSaveRemove(dom, 0) < 0)
goto end;
/* Generally we want to try the new API first. However, while
* virDomainUndefineFlags was introduced at the same time as
* VIR_DOMAIN_UNDEFINE_MANAGED_SAVE in 0.9.4, the
* VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA flag was not present
* until 0.9.5; skip to piecewise emulation if we couldn't prove
* above that the new API is safe. */
if (managed_save_safe && snapshots_safe) {
rc = virDomainUndefineFlags(dom, flags);
if (rc == 0 || (last_error->code != VIR_ERR_NO_SUPPORT &&
last_error->code != VIR_ERR_INVALID_ARG))
goto out;
virFreeError(last_error);
last_error = NULL;
}
rc = virDomainUndefine(dom);
/* The new API is unsupported or unsafe; fall back to doing things
* piecewise. */
if (has_managed_save) {
if (!managed_save) {
vshError(ctl, "%s",
_("Refusing to undefine while domain managed save "
"image exists"));
goto cleanup;
}
if (virDomainManagedSaveRemove(dom, 0) < 0) {
virshReportError(ctl);
goto cleanup;
}
}
end:
if (rc == 0) {
vshPrint(ctl, _("Domain %s has been undefined\n"), name);
} else {
vshError(ctl, _("Failed to undefine domain %s"), name);
ret = false;
/* No way to emulate deletion of just snapshot metadata
* without support for the newer flags. Oh well. */
if (has_snapshots_metadata) {
vshError(ctl,
snapshots_metadata ?
_("Unable to remove metadata of %d snapshots") :
_("Refusing to undefine while %d snapshots exist"),
has_snapshots_metadata);
goto cleanup;
}
rc = virDomainUndefine(dom);
out:
if (rc == 0) {
vshPrint(ctl, _("Domain %s has been undefined\n"), name);
ret = true;
} else {
vshError(ctl, _("Failed to undefine domain %s"), name);
}
cleanup:
virDomainFree(dom);
return ret;
}

View File

@ -496,6 +496,11 @@ the B<shutdown> command instead. However, this does not delete any
storage volumes used by the guest, and if the domain is persistent, it
can be restarted later.
If I<domain-id> is transient, then the metadata of any snapshots will
be lost once the guest stops running, but the snapshot contents still
exist, and a new domain with the same name and UUID can restore the
snapshot metadata with B<snapshot-create>.
=item B<domblkstat> I<domain> I<block-device>
Get device block stats for a running domain.
@ -998,6 +1003,11 @@ services must be shutdown in the domain.
The exact behavior of a domain when it shuts down is set by the
I<on_shutdown> parameter in the domain's XML definition.
If I<domain-id> is transient, then the metadata of any snapshots will
be lost once the guest stops running, but the snapshot contents still
exist, and a new domain with the same name and UUID can restore the
snapshot metadata with B<snapshot-create>.
=item B<start> I<domain-name> [I<--console>] [I<--paused>] [I<--autodestroy>]
[I<--bypass-cache>] [I<--force-boot>]
@ -1029,16 +1039,22 @@ hypervisor.
Output the device used for the TTY console of the domain. If the information
is not available the processes will provide an exit code of 1.
=item B<undefine> I<domain-id> [I<--managed-save>]
=item B<undefine> I<domain-id> [I<--managed-save>] [I<--snapshots-metadata]
Undefine a domain. If the domain is running, this converts it to a
transient domain, without stopping it. If the domain is inactive,
the domain configuration is removed.
The I<--managed-save> flag guarantees that any managed save image(see
The I<--managed-save> flag guarantees that any managed save image (see
the B<managedsave> command) is also cleaned up. Without the flag, attempts
to undefine a domain with a managed save image will fail.
The I<--snapshots-metadata> flag guarantees that any snapshots (see the
B<snapshot-list> command) are also cleaned up when undefining an inactive
domain. Without the flag, attempts to undefine an inactive domain with
snapshot metadata will fail. If the domain is active, this flag is
ignored.
NOTE: For an inactive domain, the domain name or UUID must be used as the
I<domain-id>.
@ -1711,6 +1727,11 @@ treat the snapshot as current, and cannot revert to the snapshot
unless I<--redefine> is later used to teach libvirt about the
metadata again).
Existence of snapshot metadata will prevent attempts to B<undefine>
a persistent domain. However, for transient domains, snapshot
metadata is silently lost when the domain quits running (whether
by command such as B<destroy> or by internal guest action).
=item B<snapshot-create-as> I<domain> {[I<--print-xml>] | [I<--no-metadata>]}
[I<name>] [I<description>]