From nobody Thu Mar 28 22:42:38 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1570707920; cv=none; d=zoho.com; s=zohoarc; b=lDRI1cA1EvD4xaaiVbwJHzMn4x2ZxXf/rrPJHDBLb/L0mRgB62xe+n/xh1Mi+TbL9stQcXJ9zQG35a6yAG1K8IcL1cyMhuYrozYYq7XSRufm/A4LF1Aihr/6tol3Jyuc2lpz8gH3lytZlDiOX5ZNfwp4He9CNjOQtYt1iUo7bXo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1570707920; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=KCNYsls+D1ZZ8zLc2MK1kD5kysrXmO0IivBZbJ+rZn8=; b=RzBGlEDy9RO027ntQ8BCIZC0jaPGsbeZAWkoyCPB2D8GMF0huf+qFPTaqIpdoA4du/zQnAPXSa41m2V/C1DyYRQ8gCr/v/BtbIjhw3EHSKeiJOAqkos6PCT9X4WjkkACMr3hR84HhVcZHrvNUceYAY5SzxXCYrsn0TVLDBIgyKM= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1570707920903319.48824098706655; Thu, 10 Oct 2019 04:45:20 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C7267306731D; Thu, 10 Oct 2019 11:45:18 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id CD544600C4; Thu, 10 Oct 2019 11:45:16 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id CA814180B536; Thu, 10 Oct 2019 11:45:14 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id x9ABhLUo012879 for ; Thu, 10 Oct 2019 07:43:21 -0400 Received: by smtp.corp.redhat.com (Postfix) id 904155D6B7; Thu, 10 Oct 2019 11:43:21 +0000 (UTC) Received: from localhost.localdomain.com (unknown [10.43.2.98]) by smtp.corp.redhat.com (Postfix) with ESMTPS id C07305D6B2; Thu, 10 Oct 2019 11:43:18 +0000 (UTC) From: Simon Kobyda To: libvir-list@redhat.com Date: Thu, 10 Oct 2019 13:43:09 +0200 Message-Id: <20191010114310.749-2-skobyda@redhat.com> In-Reply-To: <20191010114310.749-1-skobyda@redhat.com> References: <20191010114310.749-1-skobyda@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-loop: libvir-list@redhat.com Cc: Simon Kobyda Subject: [libvirt] [libvirt-dbus] [PATCH 1/2] Introduce Domain Snapshot Interface X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.48]); Thu, 10 Oct 2019 11:45:19 +0000 (UTC) Content-Type: text/plain; charset="utf-8" Signed-off-by: Simon Kobyda --- data/org.libvirt.DomainSnapshot.xml | 7 +++ src/connect.c | 6 +++ src/connect.h | 1 + src/domainsnapshot.c | 79 +++++++++++++++++++++++++++++ src/domainsnapshot.h | 9 ++++ src/meson.build | 1 + src/util.c | 49 ++++++++++++++++++ src/util.h | 16 ++++++ 8 files changed, 168 insertions(+) create mode 100644 data/org.libvirt.DomainSnapshot.xml create mode 100644 src/domainsnapshot.c create mode 100644 src/domainsnapshot.h diff --git a/data/org.libvirt.DomainSnapshot.xml b/data/org.libvirt.DomainS= napshot.xml new file mode 100644 index 0000000..80f61c6 --- /dev/null +++ b/data/org.libvirt.DomainSnapshot.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/src/connect.c b/src/connect.c index f8f76a2..b40b0ba 100644 --- a/src/connect.c +++ b/src/connect.c @@ -1,5 +1,6 @@ #include "connect.h" #include "domain.h" +#include "domainsnapshot.h" #include "events.h" #include "interface.h" #include "network.h" @@ -2002,6 +2003,7 @@ virtDBusConnectFree(virtDBusConnect *connect) virtDBusConnectClose(connect, TRUE); =20 g_free(connect->domainPath); + g_free(connect->domainSnapshotPath); g_free(connect->interfacePath); g_free(connect->networkPath); g_free(connect->nodeDevPath); @@ -2062,6 +2064,10 @@ virtDBusConnectNew(virtDBusConnect **connectp, if (error && *error) return; =20 + virtDBusDomainSnapshotRegister(connect, error); + if (error && *error) + return; + virtDBusInterfaceRegister(connect, error); if (error && *error) return; diff --git a/src/connect.h b/src/connect.h index 829bd57..74c89cf 100644 --- a/src/connect.h +++ b/src/connect.h @@ -13,6 +13,7 @@ struct virtDBusConnect { const gchar *uri; const gchar *connectPath; gchar *domainPath; + gchar *domainSnapshotPath; gchar *interfacePath; gchar *networkPath; gchar *nodeDevPath; diff --git a/src/domainsnapshot.c b/src/domainsnapshot.c new file mode 100644 index 0000000..590cbef --- /dev/null +++ b/src/domainsnapshot.c @@ -0,0 +1,79 @@ +#include "domainsnapshot.h" +#include "util.h" + +#include + +static virtDBusGDBusPropertyTable virtDBusDomainSnapshotPropertyTable[] = =3D { + { 0 } +}; + +static virtDBusGDBusMethodTable virtDBusDomainSnapshotMethodTable[] =3D { + { 0 } +}; + +static gchar ** +virtDBusDomainSnapshotEnumerate(gpointer userData) +{ + virtDBusConnect *connect =3D userData; + g_autoptr(virDomainPtr) domains =3D NULL; + gint numDoms =3D 0; + GPtrArray *list =3D NULL; + + if (!virtDBusConnectOpen(connect, NULL)) + return NULL; + + numDoms =3D virConnectListAllDomains(connect->connection, &domains, 0); + if (numDoms <=3D 0) + return NULL; + + list =3D g_ptr_array_new(); + + for (gint i =3D 0; i < numDoms; i++) { + g_autoptr(virDomainSnapshotPtr) domainSnapshots =3D NULL; + gint numSnaps; + + numSnaps =3D virDomainListAllSnapshots(domains[i], &domainSnapshot= s, 0); + if (numSnaps <=3D 0) + continue; + + for (gint j =3D 0; j < numSnaps; j++) { + gchar *snapPath =3D virtDBusUtilBusPathForVirDomainSnapshot(do= mains[i], + doma= inSnapshots[j], + conn= ect->domainSnapshotPath); + g_ptr_array_add(list, snapPath); + } + } + + gchar **ret =3D g_new0(gchar *, numDoms + 1); + + for (gint i =3D 0; i < numDoms; i++) { + ret[i] =3D virtDBusUtilBusPathForVirDomain(domains[i], + connect->domainPath); + } + + return ret; +} + +static GDBusInterfaceInfo *interfaceInfo =3D NULL; + +void +virtDBusDomainSnapshotRegister(virtDBusConnect *connect, + GError **error) +{ + connect->domainSnapshotPath =3D g_strdup_printf("%s/snapshot", connect= ->connectPath); + + if (!interfaceInfo) { + interfaceInfo =3D virtDBusGDBusLoadIntrospectData(VIRT_DBUS_DOMAIN= _SNAPSHOT_INTERFACE, + error); + if (!interfaceInfo) + return; + } + + virtDBusGDBusRegisterSubtree(connect->bus, + connect->domainSnapshotPath, + interfaceInfo, + virtDBusDomainSnapshotEnumerate, + virtDBusDomainSnapshotMethodTable, + virtDBusDomainSnapshotPropertyTable, + connect); +} diff --git a/src/domainsnapshot.h b/src/domainsnapshot.h new file mode 100644 index 0000000..7d8a938 --- /dev/null +++ b/src/domainsnapshot.h @@ -0,0 +1,9 @@ +#pragma once + +#include "connect.h" + +#define VIRT_DBUS_DOMAIN_SNAPSHOT_INTERFACE "org.libvirt.DomainSnapshot" + +void +virtDBusDomainSnapshotRegister(virtDBusConnect *connect, + GError **error); diff --git a/src/meson.build b/src/meson.build index de96596..1839c79 100644 --- a/src/meson.build +++ b/src/meson.build @@ -16,6 +16,7 @@ exe_libvirt_dbus =3D executable( [ 'connect.c', 'domain.c', + 'domainsnapshot.c', 'events.c', 'gdbus.c', 'interface.c', diff --git a/src/util.c b/src/util.c index 103bb29..daf3c2a 100644 --- a/src/util.c +++ b/src/util.c @@ -279,6 +279,55 @@ virtDBusUtilVirDomainListFree(virDomainPtr *domains) g_free(domains); } =20 +virDomainSnapshotPtr +virtDBusUtilVirDomainSnapshotFromBusPath(virConnectPtr connection, + const gchar *path, + const gchar *domainSnapshotPath) +{ + g_autofree gchar *uuidStr =3D NULL; + g_autofree gchar *snapshotName =3D NULL; + g_autoptr(virDomain) domain =3D NULL; + gsize prefixLen =3D strlen(domainSnapshotPath) + 1; + gchar** strings =3D g_strsplit(path + prefixLen, "_", 2); + + uuidStr =3D virtDBusUtilDecodeStr(strings[0]); + snapshotName =3D virtDBusUtilDecodeStr(strings[1]); + + domain =3D virDomainLookupByUUIDString(connection, uuidStr); + + return virDomainSnapshotLookupByName(domain, snapshotName, 0); +} + +gchar * +virtDBusUtilBusPathForVirDomainSnapshot(virDomainPtr domain, + virDomainSnapshotPtr domainSnapsho= t, + const gchar *domainSnapshotPath) +{ + const gchar *snapshotName =3D NULL; + gchar uuidStr[VIR_UUID_STRING_BUFLEN] =3D ""; + g_autofree const gchar *encodedDomainNameStr =3D NULL; + g_autofree const gchar *encodedSnapshotNameStr =3D NULL; + + if (virDomainGetUUIDString(domain, uuidStr) < 0) + return virtDBusUtilSetLastVirtError(error); + + snapshotName =3D virDomainSnapshotGetName(domainSnapshot); + encodedDomainNameStr =3D virtDBusUtilEncodeStr(uuidStr); + encodedSnapshotNameStr =3D virtDBusUtilEncodeStr(snapshotName); + + return g_strdup_printf("%s/%s_%s", domainSnapshotPath, + encodedDomainNameStr, encodedSnapshotNameStr); +} + +void +virtDBusUtilVirDomainSnapshotListFree(virDomainSnapshotPtr* domainSnapshot= s) +{ + for (gint i =3D 0; domainSnapshots[i] !=3D NULL; i++) + virDomainSnapshotFree(domainSnapshots[i]); + + g_free(domainSnapshots); +} + virInterfacePtr virtDBusUtilVirInterfaceFromBusPath(virConnectPtr connection, const gchar *path, diff --git a/src/util.h b/src/util.h index b05c2fc..c0b314d 100644 --- a/src/util.h +++ b/src/util.h @@ -65,6 +65,22 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainPtr, virtDBusUtil= VirDomainListFree); =20 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainStatsRecordPtr, virDomainStatsRecor= dListFree); =20 +virDomainSnapshotPtr +virtDBusUtilVirDomainSnapshotFromBusPath(virConnectPtr connection, + const gchar *path, + const gchar *domainSnapshotPath); + +gchar * +virtDBusUtilBusPathForVirDomainSnapshot(virDomainPtr domain, + virDomainSnapshotPtr domainSnapsho= t, + const gchar *domainSnapshotPath); + +void +virtDBusUtilVirDomainSnapshotListFree(virDomainSnapshotPtr* domainSnapshot= s); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainSnapshot, virDomainSnapshotFree); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainSnapshotPtr, virtDBusUtilVirDomainS= napshotListFree); + virInterfacePtr virtDBusUtilVirInterfaceFromBusPath(virConnectPtr connection, const gchar *path, --=20 2.21.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Thu Mar 28 22:42:38 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1570707927; cv=none; d=zoho.com; s=zohoarc; b=WmoGTxOCDg9KodbD4tiZEVKdjlPtgGgHn8LHxFFpSnMmtjWf1p7gyXDehpN47dNfqJstM1dppcMhM053eHDY56ToNQkh1DGGUWNyK3rfabPv8x0t10tbwUJPXHejeeMDahPXloIMGGMddaNn+buNiNzSeWxDeS6GIq0/ZygdgpU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1570707927; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=ImAS+XqYx/tnIdBzCYNY1mAkDszKYljKt/UEotpjAOs=; b=TfeJ3vTo+XPNYjDVMBiG3SaOMkpi+vEcPnpF85vQ6fBDJHPGdhZ1BZ8NXDKQelrAEx2wT+pIBxxv6gF4Fxl0DfG1J4ySTZ+t0jYhqKDPcEOAqtozroSVn8ZSlhEYkc2TT4SEdh4ByRfuh9jYWu+AxEV8o77DFZttOABRXUoGuzY= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1570707927153362.11922119437884; Thu, 10 Oct 2019 04:45:27 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 938C8315C031; Thu, 10 Oct 2019 11:45:25 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 6D6BF60920; Thu, 10 Oct 2019 11:45:25 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 28D60180B536; Thu, 10 Oct 2019 11:45:25 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id x9ABhOeF012890 for ; Thu, 10 Oct 2019 07:43:24 -0400 Received: by smtp.corp.redhat.com (Postfix) id 6868A5D6C8; Thu, 10 Oct 2019 11:43:24 +0000 (UTC) Received: from localhost.localdomain.com (unknown [10.43.2.98]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 72FDB5D6B7; Thu, 10 Oct 2019 11:43:21 +0000 (UTC) From: Simon Kobyda To: libvir-list@redhat.com Date: Thu, 10 Oct 2019 13:43:10 +0200 Message-Id: <20191010114310.749-3-skobyda@redhat.com> In-Reply-To: <20191010114310.749-1-skobyda@redhat.com> References: <20191010114310.749-1-skobyda@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-loop: libvir-list@redhat.com Cc: Simon Kobyda Subject: [libvirt] [libvirt-dbus] [PATCH 2/2] Implement snapshots APIs X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.41]); Thu, 10 Oct 2019 11:45:26 +0000 (UTC) Content-Type: text/plain; charset="utf-8" Signed-off-by: Simon Kobyda --- data/org.libvirt.Domain.xml | 26 ++++ data/org.libvirt.DomainSnapshot.xml | 34 +++++ src/domain.c | 158 +++++++++++++++++++++ src/domainsnapshot.c | 205 +++++++++++++++++++++++++++- tests/libvirttest.py | 14 ++ tests/meson.build | 1 + tests/test_domain.py | 8 ++ tests/test_snapshot.py | 43 ++++++ tests/xmldata.py | 6 + 9 files changed, 494 insertions(+), 1 deletion(-) create mode 100755 tests/test_snapshot.py diff --git a/data/org.libvirt.Domain.xml b/data/org.libvirt.Domain.xml index b4ed495..f03faf8 100644 --- a/data/org.libvirt.Domain.xml +++ b/data/org.libvirt.Domain.xml @@ -350,6 +350,12 @@ + + + + + @@ -589,6 +595,26 @@ value=3D"See https://libvirt.org/html/libvirt-libvirt-domain.html#= virDomainShutdownFlags"/> + + + + + + + + + + + + + + + + + diff --git a/data/org.libvirt.DomainSnapshot.xml b/data/org.libvirt.DomainS= napshot.xml index 80f61c6..463654f 100644 --- a/data/org.libvirt.DomainSnapshot.xml +++ b/data/org.libvirt.DomainSnapshot.xml @@ -3,5 +3,39 @@ =20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/domain.c b/src/domain.c index 10fa8de..3fc5bab 100644 --- a/src/domain.c +++ b/src/domain.c @@ -1857,6 +1857,50 @@ virtDBusDomainInjectNMI(GVariant *inArgs, virtDBusUtilSetLastVirtError(error); } =20 +static void +virtDBusDomainListDomainSnapshots(GVariant *inArgs, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath, + gpointer userData, + GVariant **outArgs G_GNUC_UNUSED, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect =3D userData; + g_autoptr(virDomain) domain =3D NULL; + g_autoptr(virDomainSnapshotPtr) domainSnapshots =3D NULL; + guint flags; + GVariantBuilder builder; + GVariant *gdomainSnapshots; + + g_variant_get(inArgs, "(u)", &flags); + + domain =3D virtDBusDomainGetVirDomain(connect, objectPath, + error); + if (!domain) + return; + + if (!virtDBusConnectOpen(connect, error)) + return; + + if (virDomainListAllSnapshots(domain, &domainSnapshots, flags) < 0) + return virtDBusUtilSetLastVirtError(error); + + g_variant_builder_init(&builder, G_VARIANT_TYPE("ao")); + + for (gint i =3D 0; domainSnapshots[i]; i++) { + g_autofree gchar *path =3D NULL; + path =3D virtDBusUtilBusPathForVirDomainSnapshot(domain, + domainSnapshots[i], + connect->domainSnap= shotPath); + + g_variant_builder_add(&builder, "o", path); + } + + gdomainSnapshots =3D g_variant_builder_end(&builder); + *outArgs =3D g_variant_new_tuple(&gdomainSnapshots, 1); +} + static void virtDBusDomainInterfaceAddresses(GVariant *inArgs, GUnixFDList *inFDs G_GNUC_UNUSED, @@ -2966,6 +3010,116 @@ virtDBusDomainShutdown(GVariant *inArgs, virtDBusUtilSetLastVirtError(error); } =20 +static void +virtDBusDomainSnapshotCurrent(GVariant *inArgs, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath, + gpointer userData, + GVariant **outArgs G_GNUC_UNUSED, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect =3D userData; + g_autofree gchar *path =3D NULL; + g_autoptr(virDomain) domain =3D NULL; + g_autoptr(virDomainSnapshot) snapshot =3D NULL; + guint flags; + + g_variant_get(inArgs, "(u)", &flags); + + domain =3D virtDBusDomainGetVirDomain(connect, objectPath, + error); + if (!domain) + return; + + if (!virtDBusConnectOpen(connect, error)) + return; + + snapshot =3D virDomainSnapshotCurrent(domain, flags); + if (!snapshot) + return virtDBusUtilSetLastVirtError(error); + + path =3D virtDBusUtilBusPathForVirDomainSnapshot(domain, + snapshot, + connect->domainSnapshot= Path); + + *outArgs =3D g_variant_new("(o)", path); +} + +static void +virtDBusDomainSnapshotCreateXML(GVariant *inArgs, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath, + gpointer userData, + GVariant **outArgs G_GNUC_UNUSED, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect =3D userData; + g_autofree gchar *path =3D NULL; + g_autoptr(virDomain) domain =3D NULL; + g_autoptr(virDomainSnapshot) snapshot =3D NULL; + guint flags; + const gchar *xml; + + g_variant_get(inArgs, "(su)", &xml, &flags); + + domain =3D virtDBusDomainGetVirDomain(connect, objectPath, + error); + if (!domain) + return; + + if (!virtDBusConnectOpen(connect, error)) + return; + + snapshot =3D virDomainSnapshotCreateXML(domain, xml, flags); + if (!snapshot) + return virtDBusUtilSetLastVirtError(error); + + path =3D virtDBusUtilBusPathForVirDomainSnapshot(domain, + snapshot, + connect->domainSnapshot= Path); + + *outArgs =3D g_variant_new("(o)", path); +} + +static void +virtDBusDomainSnapshotLookupByName(GVariant *inArgs, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath, + gpointer userData, + GVariant **outArgs G_GNUC_UNUSED, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect =3D userData; + g_autofree gchar *path =3D NULL; + g_autoptr(virDomain) domain =3D NULL; + g_autoptr(virDomainSnapshot) snapshot =3D NULL; + guint flags; + const gchar *name; + + g_variant_get(inArgs, "(su)", &name, &flags); + + domain =3D virtDBusDomainGetVirDomain(connect, objectPath, + error); + if (!domain) + return; + + if (!virtDBusConnectOpen(connect, error)) + return; + + snapshot =3D virDomainSnapshotLookupByName(domain, name, flags); + if (!snapshot) + return virtDBusUtilSetLastVirtError(error); + + path =3D virtDBusUtilBusPathForVirDomainSnapshot(domain, + snapshot, + connect->domainSnapshot= Path); + + *outArgs =3D g_variant_new("(o)", path); +} + static void virtDBusDomainSuspend(GVariant *inArgs G_GNUC_UNUSED, GUnixFDList *inFDs G_GNUC_UNUSED, @@ -3095,6 +3249,7 @@ static virtDBusGDBusMethodTable virtDBusDomainMethodT= able[] =3D { { "HasManagedSaveImage", virtDBusDomainHasManagedSaveImage }, { "InjectNMI", virtDBusDomainInjectNMI }, { "InterfaceAddresses", virtDBusDomainInterfaceAddresses }, + { "ListDomainSnapshots", virtDBusDomainListDomainSnapshots }, { "ManagedSave", virtDBusDomainManagedSave }, { "ManagedSaveRemove", virtDBusDomainManagedSaveRemove }, { "MemoryPeek", virtDBusDomainMemoryPeek }, @@ -3132,6 +3287,9 @@ static virtDBusGDBusMethodTable virtDBusDomainMethodT= able[] =3D { { "SetSchedulerParameters", virtDBusDomainSetSchedulerParameters }, { "SetTime", virtDBusDomainSetTime }, { "SetUserPassword", virtDBusDomainSetUserPassword }, + { "SnapshotCurrent", virtDBusDomainSnapshotCurrent }, + { "SnapshotCreateXML", virtDBusDomainSnapshotCreateXML }, + { "SnapshotLookupByName", virtDBusDomainSnapshotLookupByName }, { "Shutdown", virtDBusDomainShutdown }, { "Suspend", virtDBusDomainSuspend }, { "Undefine", virtDBusDomainUndefine }, diff --git a/src/domainsnapshot.c b/src/domainsnapshot.c index 590cbef..3f5f5a3 100644 --- a/src/domainsnapshot.c +++ b/src/domainsnapshot.c @@ -1,14 +1,217 @@ #include "domainsnapshot.h" +#include "domain.h" #include "util.h" =20 #include =20 +static void +virtDBusDomainSnapshotDelete(GVariant *inArgs, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath, + gpointer userData, + GVariant **outArgs G_GNUC_UNUSED, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect =3D userData; + g_autoptr(virDomainSnapshot) domainSnapshot =3D NULL; + guint flags; + + g_variant_get(inArgs, "(u)", &flags); + + domainSnapshot =3D virtDBusUtilVirDomainSnapshotFromBusPath(connect->c= onnection, + objectPath, + connect->dom= ainSnapshotPath); + if (!domainSnapshot) + return; + + if (virDomainSnapshotDelete(domainSnapshot, flags) < 0) + return virtDBusUtilSetLastVirtError(error); +} + +static void +virtDBusDomainSnapshotGetParent(GVariant *inArgs, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath, + gpointer userData, + GVariant **outArgs G_GNUC_UNUSED, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect =3D userData; + g_autoptr(virDomainSnapshot) domainSnapshot =3D NULL; + g_autoptr(virDomainSnapshot) parent =3D NULL; + guint flags; + g_autofree gchar *domainName =3D NULL; + g_autoptr(virDomain) domain =3D NULL; + gsize prefixLen =3D strlen(connect->domainSnapshotPath) + 1; + gchar** strings =3D g_strsplit(objectPath + prefixLen, "_", 2); + g_autofree gchar *parentPath =3D NULL; + + g_variant_get(inArgs, "(u)", &flags); + + domainSnapshot =3D virtDBusUtilVirDomainSnapshotFromBusPath(connect->c= onnection, + objectPath, + connect->dom= ainSnapshotPath); + if (!domainSnapshot) + return; + + parent =3D virDomainSnapshotGetParent(domainSnapshot, flags); + if (!parent) + return virtDBusUtilSetLastVirtError(error); + + domainName =3D virtDBusUtilDecodeStr(strings[0]); + domain =3D virDomainLookupByName(connect->connection, domainName); + parentPath =3D virtDBusUtilBusPathForVirDomainSnapshot(domain, + parent, + connect->domainSn= apshotPath); + + *outArgs =3D g_variant_new("(o)", parentPath); +} + +static void +virtDBusDomainSnapshotGetXMLDesc(GVariant *inArgs, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath, + gpointer userData, + GVariant **outArgs G_GNUC_UNUSED, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect =3D userData; + g_autoptr(virDomainSnapshot) domainSnapshot =3D NULL; + guint flags; + g_autofree gchar *xml =3D NULL; + + g_variant_get(inArgs, "(u)", &flags); + + domainSnapshot =3D virtDBusUtilVirDomainSnapshotFromBusPath(connect->c= onnection, + objectPath, + connect->dom= ainSnapshotPath); + if (!domainSnapshot) + return; + + xml =3D virDomainSnapshotGetXMLDesc(domainSnapshot, flags); + if (!xml) + return virtDBusUtilSetLastVirtError(error); + + *outArgs =3D g_variant_new("(s)", xml); +} + +static void +virtDBusDomainSnapshotIsCurrent(GVariant *inArgs, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath, + gpointer userData, + GVariant **outArgs G_GNUC_UNUSED, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect =3D userData; + g_autoptr(virDomainSnapshot) domainSnapshot =3D NULL; + guint flags; + gint isCurrent; + + g_variant_get(inArgs, "(u)", &flags); + + domainSnapshot =3D virtDBusUtilVirDomainSnapshotFromBusPath(connect->c= onnection, + objectPath, + connect->dom= ainSnapshotPath); + if (!domainSnapshot) + return; + + isCurrent =3D virDomainSnapshotIsCurrent(domainSnapshot, flags); + if (isCurrent < 0) + return virtDBusUtilSetLastVirtError(error); + + *outArgs =3D g_variant_new("(b)", !!isCurrent); +} + +static void +virtDBusDomainSnapshotListAllChildren(GVariant *inArgs, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath, + gpointer userData, + GVariant **outArgs G_GNUC_UNUSED, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect =3D userData; + g_autoptr(virDomainSnapshot) domainSnapshot =3D NULL; + g_autoptr(virDomainSnapshotPtr) snaps =3D NULL; + guint flags; + GVariantBuilder builder; + GVariant *gdomainSnapshots; + g_autofree gchar *domainName =3D NULL; + g_autoptr(virDomain) domain =3D NULL; + gsize prefixLen =3D strlen(connect->domainSnapshotPath) + 1; + gchar** strings =3D g_strsplit(objectPath + prefixLen, "_", 2); + + g_variant_get(inArgs, "(u)", &flags); + + domainSnapshot =3D virtDBusUtilVirDomainSnapshotFromBusPath(connect->c= onnection, + objectPath, + connect->dom= ainSnapshotPath); + if (!domainSnapshot) + return; + + if (virDomainSnapshotListAllChildren(domainSnapshot, &snaps, flags) < = 0) + return virtDBusUtilSetLastVirtError(error); + + g_variant_builder_init(&builder, G_VARIANT_TYPE("ao")); + + domainName =3D virtDBusUtilDecodeStr(strings[0]); + domain =3D virDomainLookupByName(connect->connection, domainName); + for (gint i =3D 0; snaps[i]; i++) { + g_autofree gchar *path =3D NULL; + path =3D virtDBusUtilBusPathForVirDomainSnapshot(domain, + snaps[i], + connect->domainSnap= shotPath); + + g_variant_builder_add(&builder, "o", path); + } + + gdomainSnapshots =3D g_variant_builder_end(&builder); + *outArgs =3D g_variant_new_tuple(&gdomainSnapshots, 1); +} + +static void +virtDBusDomainSnapshotRevert(GVariant *inArgs, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath, + gpointer userData, + GVariant **outArgs G_GNUC_UNUSED, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect =3D userData; + g_autoptr(virDomainSnapshot) domainSnapshot =3D NULL; + guint flags; + + g_variant_get(inArgs, "(u)", &flags); + + domainSnapshot =3D virtDBusUtilVirDomainSnapshotFromBusPath(connect->c= onnection, + objectPath, + connect->dom= ainSnapshotPath); + if (!domainSnapshot) + return; + + if (virDomainRevertToSnapshot(domainSnapshot, flags) < 0) + return virtDBusUtilSetLastVirtError(error); +} + static virtDBusGDBusPropertyTable virtDBusDomainSnapshotPropertyTable[] = =3D { { 0 } }; =20 static virtDBusGDBusMethodTable virtDBusDomainSnapshotMethodTable[] =3D { - { 0 } + { "Delete", virtDBusDomainSnapshotDelete }, + { "GetParent", virtDBusDomainSnapshotGetParent }, + { "GetXMLDesc", virtDBusDomainSnapshotGetXMLDesc }, + /* Needs to be method since it takes 'flags' parameter */ + { "IsCurrent", virtDBusDomainSnapshotIsCurrent }, + { "ListChildren", virtDBusDomainSnapshotListAllChildren }, + { "Revert", virtDBusDomainSnapshotRevert }, }; =20 static gchar ** diff --git a/tests/libvirttest.py b/tests/libvirttest.py index a442196..8462fc3 100644 --- a/tests/libvirttest.py +++ b/tests/libvirttest.py @@ -112,6 +112,20 @@ class BaseTestClass(): """ return self.node_device_create() =20 + @pytest.fixture + def snapshot_create(self): + """ Fixture to create simple snapshot the test driver + + This fixture should be used in the setup of every test manipulating + with snaphots. + """ + _, test_domain =3D self.get_test_domain() + interface_obj =3D dbus.Interface(test_domain, 'org.libvirt.Domain') + path =3D interface_obj.SnapshotCreateXML(xmldata.minimal_snapshot_= xml, 0) + obj =3D self.bus.get_object('org.libvirt', path) + interface_obj =3D dbus.Interface(obj, 'org.libvirt.DomainSnapshot') + return interface_obj + @pytest.fixture def storage_volume_create(self): """ Fixture to create dummy storage volume on the test driver diff --git a/tests/meson.build b/tests/meson.build index b6d4bd5..0ad5cdb 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -22,6 +22,7 @@ test('test_util', test_exec, suite: 'unit') python_tests =3D [ 'test_connect.py', 'test_domain.py', + 'test_snapshot.py', 'test_interface.py', 'test_network.py', 'test_nodedev.py', diff --git a/tests/test_domain.py b/tests/test_domain.py index b5879b4..fdb5aa4 100755 --- a/tests/test_domain.py +++ b/tests/test_domain.py @@ -2,6 +2,7 @@ =20 import dbus import libvirttest +import xmldata =20 DBUS_EXCEPTION_MISSING_FUNCTION =3D 'this function is not supported by the= connection driver' =20 @@ -160,6 +161,13 @@ class TestDomain(libvirttest.BaseTestClass): pinInfo =3D domain.GetVcpuPinInfo(0) assert pinInfo =3D=3D pinInfo_expected =20 + def test_snapshot(self): + obj, domain =3D self.get_test_domain() + domain.SnapshotCreateXML(xmldata.minimal_snapshot_xml, 0) + assert isinstance(domain.SnapshotCurrent(0), dbus.ObjectPath) + assert isinstance(domain.SnapshotLookupByName("my_snapshot", 0), d= bus.ObjectPath) + assert isinstance(domain.ListDomainSnapshots(0), dbus.Array) =20 if __name__ =3D=3D '__main__': libvirttest.run() + diff --git a/tests/test_snapshot.py b/tests/test_snapshot.py new file mode 100755 index 0000000..e9cc5b9 --- /dev/null +++ b/tests/test_snapshot.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +import dbus +import libvirttest +import pytest + +EXCEPTION_NO_PARENT =3D 'does not have a parent' + +@pytest.mark.usefixtures("snapshot_create") +class TestSnapshot(libvirttest.BaseTestClass): + """ Tests for methods and properties of the Snapshot snapshot + """ + + def test_snapshot_delete(self, snapshot_create): + snapshot_obj =3D snapshot_create + snapshot_obj.Delete(0) + + def test_snapshot_get_parent(self, snapshot_create): + snapshot_obj =3D snapshot_create + try: + snapshot_obj.GetParent(0) + except dbus.exceptions.DBusException as e: + if not any(EXCEPTION_NO_PARENT in arg for arg in e.args): + raise e + + def test_snapshot_get_xml(self, snapshot_create): + snapshot_obj =3D snapshot_create + assert isinstance(snapshot_obj.GetXMLDesc(0), dbus.String) + + def test_snapshot_get_is_current(self, snapshot_create): + snapshot_obj =3D snapshot_create + assert isinstance(snapshot_obj.IsCurrent(0), dbus.Boolean) + + def test_snapshot_list_children(self, snapshot_create): + snapshot_obj =3D snapshot_create + assert isinstance(snapshot_obj.ListChildren(0), dbus.Array) + + def test_snapshot_revert(self, snapshot_create): + snapshot_obj =3D snapshot_create + snapshot_obj.Revert(0) + +if __name__ =3D=3D '__main__': + libvirttest.run() diff --git a/tests/xmldata.py b/tests/xmldata.py index 8075052..0146ccf 100644 --- a/tests/xmldata.py +++ b/tests/xmldata.py @@ -54,6 +54,12 @@ minimal_node_device_xml =3D ''' ''' =20 +minimal_snapshot_xml =3D ''' + + my_snapshot + +''' + minimal_storage_pool_xml =3D ''' foo --=20 2.21.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list