Unfortunately Hyper-V does not enforce any uniqueness constraints on snapshot names (called ElementName in Hyper-V). So it's possible for multiple snapshots of the same domain to have identical ElementNames. Since libvirt uses the domain and snapshot name as a unique key to reference a snapshot, we can't use the hyperv ElementName as the snapshot name in libvirt.
So instead I've decided to use the InstanceId of the snapshot as the snapshot name and use the ElementName as the snapshot description. This results in a worse user experience (since the snapshot names end up being something like "Microsoft:$(UUID)"), but guarantees that we will be able to uniquely reference every snapshot. Signed-off-by: Jonathon Jongsma <[email protected]> --- src/hyperv/hyperv_driver.c | 53 ++++++++++++++++++++++++++++++++++++++ src/hyperv/hyperv_wmi.h | 3 +++ 2 files changed, 56 insertions(+) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 906f6e5d19..44b671b45e 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -4077,6 +4077,58 @@ hypervDomainGetBlockInfo(virDomainPtr domain, } +static Msvm_VirtualSystemSettingData* +hypervDomainLookupSnapshotSD(virDomainPtr domain, const char *snapshot) +{ + hypervPrivate *priv = domain->conn->privateData; + g_autoptr(Msvm_VirtualSystemSettingData) vssd = NULL; + char domain_uuid_string[VIR_UUID_STRING_BUFLEN]; + g_auto(virBuffer) query = VIR_BUFFER_INITIALIZER; + + virUUIDFormat(domain->uuid, domain_uuid_string); + + /* Hyper-V does not enforce unique snapshot names per domain, so we don't + * use the Hyper-V snapshot's ElementName field as the libvirt snapshot name. + * Instead we use the unique InstanceID as the name, even though it is not as + * user-friendly */ + virBufferEscapeSQL(&query, + MSVM_VIRTUALSYSTEMSETTINGDATA_WQL_SELECT + "WHERE InstanceID='%s'", + snapshot); + virBufferEscapeSQL(&query, "AND VirtualSystemIdentifier='%s'", domain_uuid_string); + virBufferAddLit(&query, "AND VirtualSystemType='" + MSVM_VIRTUALSYSTEMSETTINGDATA_VIRTUALTYPE_SNAPSHOT "'"); + + if (hypervGetWmiClass(Msvm_VirtualSystemSettingData, &vssd) < 0) + return NULL; + + if (!vssd) { + virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, + _("no domain snapshot with matching name '%1$s'"), snapshot); + return NULL; + } + + return g_steal_pointer(&vssd); +} + + +static virDomainSnapshotPtr +hypervDomainSnapshotLookupByName(virDomainPtr domain, + const char *name, + unsigned int flags) +{ + g_autoptr(Msvm_VirtualSystemSettingData) vssd = NULL; + + virCheckFlags(0, NULL); + + vssd = hypervDomainLookupSnapshotSD(domain, name); + if (vssd == NULL) + return NULL; + + return virGetDomainSnapshot(domain, name); +} + + static virHypervisorDriver hypervHypervisorDriver = { .name = "Hyper-V", .connectOpen = hypervConnectOpen, /* 0.9.5 */ @@ -4143,6 +4195,7 @@ static virHypervisorDriver hypervHypervisorDriver = { .connectIsAlive = hypervConnectIsAlive, /* 0.9.8 */ .domainInterfaceAddresses = hypervDomainInterfaceAddresses, /* 12.1.0 */ .domainGetBlockInfo = hypervDomainGetBlockInfo, /* 12.1.0 */ + .domainSnapshotLookupByName = hypervDomainSnapshotLookupByName, /* 12.2.0 */ }; diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h index 65b1211b89..d577dbcecb 100644 --- a/src/hyperv/hyperv_wmi.h +++ b/src/hyperv/hyperv_wmi.h @@ -38,6 +38,9 @@ #define MSVM_IMAGEMANAGEMENTSERVICE_SELECTOR \ "CreationClassName=Msvm_ImageManagementService" +#define MSVM_VIRTUALSYSTEMSETTINGDATA_VIRTUALTYPE_SNAPSHOT \ + "Microsoft:Hyper-V:Snapshot:Realized" + int hypervVerifyResponse(WsManClient *client, WsXmlDocH response, const char *detail); -- 2.53.0
