[libvirt] [dbus PATCH 00/10] Impement some APIs for network Interface

Katerina Koukiou (10): Implement BridgeName property for Network interface. Implement Autostart property for Network Interface Implement UUID property for Network interface. Implement NetworkLookupByUUID method for network interface. Rename virtDBusEventsRegisterEvent to virtDBusDomainEventsRegisterEvent Rename callback_ids variable to domain_callback_ids Register Network Lifecycle Events Implement Destroy method for Network Interface. Implement Undefine method for Network Interface Implement Create method for Network Interface data/org.libvirt.Connect.xml | 12 ++++ data/org.libvirt.Network.xml | 24 ++++++++ src/connect.c | 50 +++++++++++++++-- src/connect.h | 3 +- src/events.c | 112 ++++++++++++++++++++++++++++--------- src/network.c | 128 +++++++++++++++++++++++++++++++++++++++++++ test/test_connect.py | 1 + test/test_network.py | 43 +++++++++++++++ 8 files changed, 342 insertions(+), 31 deletions(-) -- 2.15.0

Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Network.xml | 4 ++++ src/network.c | 23 +++++++++++++++++++++++ test/test_network.py | 1 + 3 files changed, 28 insertions(+) diff --git a/data/org.libvirt.Network.xml b/data/org.libvirt.Network.xml index 1215ac3..83a6b9e 100644 --- a/data/org.libvirt.Network.xml +++ b/data/org.libvirt.Network.xml @@ -3,6 +3,10 @@ <node name="/org/libvirt/network"> <interface name="org.libvirt.Network"> + <property name="BridgeName" type="s" access="read"> + <annotation name="org.gtk.GDBus.DocString" + value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkGetBridgeName"/> + </property> <property name="Name" type="s" access="read"> <annotation name="org.gtk.GDBus.DocString" value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkGetName"/> diff --git a/src/network.c b/src/network.c index 56cbb41..fab017c 100644 --- a/src/network.c +++ b/src/network.c @@ -24,6 +24,28 @@ virtDBusNetworkGetVirNetwork(virtDBusConnect *connect, return network; } +static void +virtDBusNetworkGetBridgeName(const gchar *objectPath, + gpointer userData, + GVariant **value, + GError **error) +{ + virtDBusConnect *connect = userData; + g_autoptr(virNetwork) network = NULL; + const gchar *bridge; + + network = virtDBusNetworkGetVirNetwork(connect, objectPath, error); + if (!network) + return; + + bridge = virNetworkGetBridgeName(network); + + if (!bridge) + return virtDBusUtilSetLastVirtError(error); + + *value = g_variant_new("s", bridge); +} + static void virtDBusNetworkGetName(const gchar *objectPath, gpointer userData, @@ -46,6 +68,7 @@ virtDBusNetworkGetName(const gchar *objectPath, } static virtDBusGDBusPropertyTable virtDBusNetworkPropertyTable[] = { + { "BridgeName", virtDBusNetworkGetBridgeName, NULL }, { "Name", virtDBusNetworkGetName, NULL }, { 0 } }; diff --git a/test/test_network.py b/test/test_network.py index 97ab0aa..9f15c2e 100755 --- a/test/test_network.py +++ b/test/test_network.py @@ -12,6 +12,7 @@ class TestNetwork(libvirttest.BaseTestClass): """ _, obj = self.test_network() props = obj.GetAll('org.libvirt.Network', dbus_interface=dbus.PROPERTIES_IFACE) + assert isinstance(props['BridgeName'], dbus.String) assert isinstance(props['Name'], dbus.String) -- 2.15.0

On Thu, Apr 05, 2018 at 03:29:25PM +0200, Katerina Koukiou wrote:
Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Network.xml | 4 ++++ src/network.c | 23 +++++++++++++++++++++++ test/test_network.py | 1 + 3 files changed, 28 insertions(+)
diff --git a/data/org.libvirt.Network.xml b/data/org.libvirt.Network.xml index 1215ac3..83a6b9e 100644 --- a/data/org.libvirt.Network.xml +++ b/data/org.libvirt.Network.xml @@ -3,6 +3,10 @@
<node name="/org/libvirt/network"> <interface name="org.libvirt.Network"> + <property name="BridgeName" type="s" access="read"> + <annotation name="org.gtk.GDBus.DocString" + value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkGetBridgeName"/> + </property> <property name="Name" type="s" access="read"> <annotation name="org.gtk.GDBus.DocString" value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkGetName"/> diff --git a/src/network.c b/src/network.c index 56cbb41..fab017c 100644 --- a/src/network.c +++ b/src/network.c @@ -24,6 +24,28 @@ virtDBusNetworkGetVirNetwork(virtDBusConnect *connect, return network; }
+static void +virtDBusNetworkGetBridgeName(const gchar *objectPath, + gpointer userData, + GVariant **value, + GError **error) +{ + virtDBusConnect *connect = userData; + g_autoptr(virNetwork) network = NULL; + const gchar *bridge;
This needs to be g_autofree gchar *bridge = NULL; virtDBusNetworkGetVirNetwork returns a string that needs to be freed.
+ + network = virtDBusNetworkGetVirNetwork(connect, objectPath, error); + if (!network) + return; + + bridge = virNetworkGetBridgeName(network); + + if (!bridge) + return virtDBusUtilSetLastVirtError(error); + + *value = g_variant_new("s", bridge); +}
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>

On Thu, 2018-04-05 at 15:44 +0200, Pavel Hrdina wrote:
On Thu, Apr 05, 2018 at 03:29:25PM +0200, Katerina Koukiou wrote:
Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Network.xml | 4 ++++ src/network.c | 23 +++++++++++++++++++++++ test/test_network.py | 1 + 3 files changed, 28 insertions(+)
diff --git a/data/org.libvirt.Network.xml b/data/org.libvirt.Network.xml index 1215ac3..83a6b9e 100644 --- a/data/org.libvirt.Network.xml +++ b/data/org.libvirt.Network.xml @@ -3,6 +3,10 @@
<node name="/org/libvirt/network"> <interface name="org.libvirt.Network"> + <property name="BridgeName" type="s" access="read"> + <annotation name="org.gtk.GDBus.DocString" + value="See https://libvirt.org/html/libvirt-libvirt-networ k.html#virNetworkGetBridgeName"/>; + </property> <property name="Name" type="s" access="read"> <annotation name="org.gtk.GDBus.DocString" value="See https://libvirt.org/html/libvirt-libvirt-networ k.html#virNetworkGetName"/>; diff --git a/src/network.c b/src/network.c index 56cbb41..fab017c 100644 --- a/src/network.c +++ b/src/network.c @@ -24,6 +24,28 @@ virtDBusNetworkGetVirNetwork(virtDBusConnect *connect, return network; }
+static void +virtDBusNetworkGetBridgeName(const gchar *objectPath, + gpointer userData, + GVariant **value, + GError **error) +{ + virtDBusConnect *connect = userData; + g_autoptr(virNetwork) network = NULL; + const gchar *bridge;
This needs to be g_autofree gchar *bridge = NULL;
virtDBusNetworkGetVirNetwork returns a string that needs to be freed.
You mean virNetworkGetBridgeName. Nice catch, thanks.
+ + network = virtDBusNetworkGetVirNetwork(connect, objectPath, error); + if (!network) + return; + + bridge = virNetworkGetBridgeName(network); + + if (!bridge) + return virtDBusUtilSetLastVirtError(error); + + *value = g_variant_new("s", bridge); +}
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>

Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Network.xml | 4 ++++ src/network.c | 21 +++++++++++++++++++++ test/test_network.py | 1 + 3 files changed, 26 insertions(+) diff --git a/data/org.libvirt.Network.xml b/data/org.libvirt.Network.xml index 83a6b9e..30b352a 100644 --- a/data/org.libvirt.Network.xml +++ b/data/org.libvirt.Network.xml @@ -3,6 +3,10 @@ <node name="/org/libvirt/network"> <interface name="org.libvirt.Network"> + <property name="Autostart" type="b" access="read"> + <annotation name="org.gtk.GDBus.DocString" + value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkGetAutostart"/> + </property> <property name="BridgeName" type="s" access="read"> <annotation name="org.gtk.GDBus.DocString" value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkGetBridgeName"/> diff --git a/src/network.c b/src/network.c index fab017c..5e48fa7 100644 --- a/src/network.c +++ b/src/network.c @@ -24,6 +24,26 @@ virtDBusNetworkGetVirNetwork(virtDBusConnect *connect, return network; } +static void +virtDBusNetworkGetAutostart(const gchar *objectPath, + gpointer userData, + GVariant **value, + GError **error) +{ + virtDBusConnect *connect = userData; + g_autoptr(virNetwork) network = NULL; + gint autostart = 0; + + network = virtDBusNetworkGetVirNetwork(connect, objectPath, error); + if (!network) + return; + + if (virNetworkGetAutostart(network, &autostart) < 0) + return virtDBusUtilSetLastVirtError(error); + + *value = g_variant_new("b", !!autostart); +} + static void virtDBusNetworkGetBridgeName(const gchar *objectPath, gpointer userData, @@ -68,6 +88,7 @@ virtDBusNetworkGetName(const gchar *objectPath, } static virtDBusGDBusPropertyTable virtDBusNetworkPropertyTable[] = { + { "Autostart", virtDBusNetworkGetAutostart, NULL }, { "BridgeName", virtDBusNetworkGetBridgeName, NULL }, { "Name", virtDBusNetworkGetName, NULL }, { 0 } diff --git a/test/test_network.py b/test/test_network.py index 9f15c2e..1842944 100755 --- a/test/test_network.py +++ b/test/test_network.py @@ -12,6 +12,7 @@ class TestNetwork(libvirttest.BaseTestClass): """ _, obj = self.test_network() props = obj.GetAll('org.libvirt.Network', dbus_interface=dbus.PROPERTIES_IFACE) + assert isinstance(props['Autostart'], dbus.Boolean) assert isinstance(props['BridgeName'], dbus.String) assert isinstance(props['Name'], dbus.String) -- 2.15.0

On Thu, Apr 05, 2018 at 03:29:26PM +0200, Katerina Koukiou wrote:
Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Network.xml | 4 ++++ src/network.c | 21 +++++++++++++++++++++ test/test_network.py | 1 + 3 files changed, 26 insertions(+)
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>

Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Network.xml | 4 ++++ src/network.c | 21 +++++++++++++++++++++ test/test_network.py | 1 + 3 files changed, 26 insertions(+) diff --git a/data/org.libvirt.Network.xml b/data/org.libvirt.Network.xml index 30b352a..d144c5d 100644 --- a/data/org.libvirt.Network.xml +++ b/data/org.libvirt.Network.xml @@ -15,5 +15,9 @@ <annotation name="org.gtk.GDBus.DocString" value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkGetName"/> </property> + <property name="UUID" type="s" access="read"> + <annotation name="org.gtk.GDBus.DocString" + value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkGetUUIDString"/> + </property> </interface> </node> diff --git a/src/network.c b/src/network.c index 5e48fa7..90c2d9c 100644 --- a/src/network.c +++ b/src/network.c @@ -87,10 +87,31 @@ virtDBusNetworkGetName(const gchar *objectPath, *value = g_variant_new("s", name); } +static void +virtDBusNetworkGetUUID(const gchar *objectPath, + gpointer userData, + GVariant **value, + GError **error) +{ + virtDBusConnect *connect = userData; + g_autoptr(virNetwork) network = NULL; + gchar uuid[VIR_UUID_STRING_BUFLEN] = ""; + + network = virtDBusNetworkGetVirNetwork(connect, objectPath, error); + if (!network) + return; + + if (virNetworkGetUUIDString(network, uuid) < 0) + return virtDBusUtilSetLastVirtError(error); + + *value = g_variant_new("s", uuid); +} + static virtDBusGDBusPropertyTable virtDBusNetworkPropertyTable[] = { { "Autostart", virtDBusNetworkGetAutostart, NULL }, { "BridgeName", virtDBusNetworkGetBridgeName, NULL }, { "Name", virtDBusNetworkGetName, NULL }, + { "UUID", virtDBusNetworkGetUUID, NULL }, { 0 } }; diff --git a/test/test_network.py b/test/test_network.py index 1842944..e753f7f 100755 --- a/test/test_network.py +++ b/test/test_network.py @@ -15,6 +15,7 @@ class TestNetwork(libvirttest.BaseTestClass): assert isinstance(props['Autostart'], dbus.Boolean) assert isinstance(props['BridgeName'], dbus.String) assert isinstance(props['Name'], dbus.String) + assert isinstance(props['UUID'], dbus.String) if __name__ == '__main__': -- 2.15.0

On Thu, Apr 05, 2018 at 03:29:27PM +0200, Katerina Koukiou wrote:
Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Network.xml | 4 ++++ src/network.c | 21 +++++++++++++++++++++ test/test_network.py | 1 + 3 files changed, 26 insertions(+)
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>

Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Connect.xml | 6 ++++++ src/connect.c | 29 +++++++++++++++++++++++++++++ test/test_connect.py | 1 + 3 files changed, 36 insertions(+) diff --git a/data/org.libvirt.Connect.xml b/data/org.libvirt.Connect.xml index 043ee32..d15c2f6 100644 --- a/data/org.libvirt.Connect.xml +++ b/data/org.libvirt.Connect.xml @@ -56,6 +56,12 @@ <arg name="name" type="s" direction="in"/> <arg name="network" type="o" direction="out"/> </method> + <method name="NetworkLookupByUUID"> + <annotation name="org.gtk.GDBus.DocString" + value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkLookupByUUID"/> + <arg name="uuid" type="s" direction="in"/> + <arg name="network" type="o" direction="out"/> + </method> <signal name="DomainEvent"> <annotation name="org.gtk.GDBus.DocString" value="See https://libvirt.org/html/libvirt-libvirt-domain.html#virConnectDomainEventCallback"/> diff --git a/src/connect.c b/src/connect.c index d036753..f22f682 100644 --- a/src/connect.c +++ b/src/connect.c @@ -348,6 +348,34 @@ virtDBusNetworkLookupByName(GVariant *inArgs, *outArgs = g_variant_new("(o)", path); } +static void +virtDBusNetworkLookupByUUID(GVariant *inArgs, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath G_GNUC_UNUSED, + gpointer userData, + GVariant **outArgs, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect = userData; + g_autoptr(virNetwork) network = NULL; + g_autofree gchar *path = NULL; + const gchar *uuidstr; + + g_variant_get(inArgs, "(s)", &uuidstr); + + if (!virtDBusConnectOpen(connect, error)) + return; + + network = virNetworkLookupByUUIDString(connect->connection, uuidstr); + if (!network) + return virtDBusUtilSetLastVirtError(error); + + path = virtDBusUtilBusPathForVirNetwork(network, connect->networkPath); + + *outArgs = g_variant_new("(o)", path); +} + static virtDBusGDBusPropertyTable virtDBusConnectPropertyTable[] = { { "Version", virtDBusConnectGetVersion, NULL }, { 0 } @@ -362,6 +390,7 @@ static virtDBusGDBusMethodTable virtDBusConnectMethodTable[] = { { "DomainLookupByUUID", virtDBusDomainLookupByUUID }, { "ListNetworks", virtDBusConnectListNetworks }, { "NetworkLookupByName", virtDBusNetworkLookupByName }, + { "NetworkLookupByUUID", virtDBusNetworkLookupByUUID }, { 0 } }; diff --git a/test/test_connect.py b/test/test_connect.py index 440a496..5bddd2f 100755 --- a/test/test_connect.py +++ b/test/test_connect.py @@ -88,6 +88,7 @@ class TestConnect(libvirttest.BaseTestClass): @pytest.mark.parametrize("lookup_method_name,lookup_item", [ ("NetworkLookupByName", 'Name'), + ("NetworkLookupByUUID", 'UUID'), ]) def test_connect_network_lookup_by_property(self, lookup_method_name, lookup_item): """Parameterized test for all NetworkLookupBy* API calls of Connect interface -- 2.15.0

On Thu, Apr 05, 2018 at 03:29:28PM +0200, Katerina Koukiou wrote:
Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Connect.xml | 6 ++++++ src/connect.c | 29 +++++++++++++++++++++++++++++ test/test_connect.py | 1 + 3 files changed, 36 insertions(+)
diff --git a/data/org.libvirt.Connect.xml b/data/org.libvirt.Connect.xml index 043ee32..d15c2f6 100644 --- a/data/org.libvirt.Connect.xml +++ b/data/org.libvirt.Connect.xml @@ -56,6 +56,12 @@ <arg name="name" type="s" direction="in"/> <arg name="network" type="o" direction="out"/> </method> + <method name="NetworkLookupByUUID"> + <annotation name="org.gtk.GDBus.DocString" + value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkLookupByUUID"/>
This should mention virNetworkLookupByUUIDString.
+ <arg name="uuid" type="s" direction="in"/> + <arg name="network" type="o" direction="out"/> + </method> <signal name="DomainEvent"> <annotation name="org.gtk.GDBus.DocString" value="See https://libvirt.org/html/libvirt-libvirt-domain.html#virConnectDomainEventCallback"/> diff --git a/src/connect.c b/src/connect.c index d036753..f22f682 100644 --- a/src/connect.c +++ b/src/connect.c @@ -348,6 +348,34 @@ virtDBusNetworkLookupByName(GVariant *inArgs, *outArgs = g_variant_new("(o)", path); }
+static void +virtDBusNetworkLookupByUUID(GVariant *inArgs, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath G_GNUC_UNUSED, + gpointer userData, + GVariant **outArgs, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect = userData; + g_autoptr(virNetwork) network = NULL; + g_autofree gchar *path = NULL; + const gchar *uuidstr; + + g_variant_get(inArgs, "(s)", &uuidstr);
In order to use const gchar you need to use "(&s)" as the format string. The "&" indicates that the string is not copied to the variable but you get only a pointer.
+ + if (!virtDBusConnectOpen(connect, error)) + return; + + network = virNetworkLookupByUUIDString(connect->connection, uuidstr); + if (!network) + return virtDBusUtilSetLastVirtError(error); + + path = virtDBusUtilBusPathForVirNetwork(network, connect->networkPath); + + *outArgs = g_variant_new("(o)", path); +}
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>

This function was specific to Domain Lifecycle Events. Rename it now, so that we can keep consistent naming when introducing Events for other entities. Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- src/events.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/events.c b/src/events.c index eb85a3a..c6896d4 100644 --- a/src/events.c +++ b/src/events.c @@ -171,9 +171,9 @@ virtDBusEventsDomainDiskChange(virConnectPtr connection G_GNUC_UNUSED, } static void -virtDBusEventsRegisterEvent(virtDBusConnect *connect, - gint id, - virConnectDomainEventGenericCallback callback) +virtDBusDomainEventsRegisterEvent(virtDBusConnect *connect, + gint id, + virConnectDomainEventGenericCallback callback) { g_assert(connect->callback_ids[id] == -1); @@ -188,24 +188,24 @@ virtDBusEventsRegisterEvent(virtDBusConnect *connect, void virtDBusEventsRegister(virtDBusConnect *connect) { - virtDBusEventsRegisterEvent(connect, - VIR_DOMAIN_EVENT_ID_LIFECYCLE, - VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainLifecycle)); + virtDBusDomainEventsRegisterEvent(connect, + VIR_DOMAIN_EVENT_ID_LIFECYCLE, + VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainLifecycle)); - virtDBusEventsRegisterEvent(connect, - VIR_DOMAIN_EVENT_ID_DEVICE_ADDED, - VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainDeviceAdded)); + virtDBusDomainEventsRegisterEvent(connect, + VIR_DOMAIN_EVENT_ID_DEVICE_ADDED, + VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainDeviceAdded)); - virtDBusEventsRegisterEvent(connect, - VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED, - VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainDeviceRemoved)); + virtDBusDomainEventsRegisterEvent(connect, + VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED, + VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainDeviceRemoved)); - virtDBusEventsRegisterEvent(connect, - VIR_DOMAIN_EVENT_ID_DISK_CHANGE, - VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainDiskChange)); + virtDBusDomainEventsRegisterEvent(connect, + VIR_DOMAIN_EVENT_ID_DISK_CHANGE, + VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainDiskChange)); - virtDBusEventsRegisterEvent(connect, - VIR_DOMAIN_EVENT_ID_TRAY_CHANGE, - VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainTrayChange)); + virtDBusDomainEventsRegisterEvent(connect, + VIR_DOMAIN_EVENT_ID_TRAY_CHANGE, + VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainTrayChange)); } -- 2.15.0

On Thu, Apr 05, 2018 at 03:29:29PM +0200, Katerina Koukiou wrote:
This function was specific to Domain Lifecycle Events. Rename it now, so that we can keep consistent naming when introducing Events for other entities.
Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- src/events.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/src/events.c b/src/events.c index eb85a3a..c6896d4 100644 --- a/src/events.c +++ b/src/events.c @@ -171,9 +171,9 @@ virtDBusEventsDomainDiskChange(virConnectPtr connection G_GNUC_UNUSED, }
static void -virtDBusEventsRegisterEvent(virtDBusConnect *connect, - gint id, - virConnectDomainEventGenericCallback callback) +virtDBusDomainEventsRegisterEvent(virtDBusConnect *connect,
The name should be virtDBusEventsRegisterDomainEvent. virtDBusEvents is prefix for this file.
+ gint id, + virConnectDomainEventGenericCallback callback) { g_assert(connect->callback_ids[id] == -1);
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>

The callback_ids var is domain specific. Renaming it now, so as to keep consistent naming when introducing events for other entities. Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- src/connect.c | 8 ++++---- src/connect.h | 2 +- src/events.c | 16 ++++++++-------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/connect.c b/src/connect.c index f22f682..90172e3 100644 --- a/src/connect.c +++ b/src/connect.c @@ -40,12 +40,12 @@ virtDBusConnectClose(virtDBusConnect *connect, { for (gint i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i += 1) { - if (connect->callback_ids[i] >= 0) { + if (connect->domain_callback_ids[i] >= 0) { if (deregisterEvents) { virConnectDomainEventDeregisterAny(connect->connection, - connect->callback_ids[i]); + connect->domain_callback_ids[i]); } - connect->callback_ids[i] = -1; + connect->domain_callback_ids[i] = -1; } } @@ -429,7 +429,7 @@ virtDBusConnectNew(virtDBusConnect **connectp, g_mutex_init(&connect->lock); for (gint i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i += 1) - connect->callback_ids[i] = -1; + connect->domain_callback_ids[i] = -1; connect->bus = bus; connect->uri = uri; diff --git a/src/connect.h b/src/connect.h index 7ed84b8..e69898c 100644 --- a/src/connect.h +++ b/src/connect.h @@ -17,7 +17,7 @@ struct virtDBusConnect { virConnectPtr connection; GMutex lock; - gint callback_ids[VIR_DOMAIN_EVENT_ID_LAST]; + gint domain_callback_ids[VIR_DOMAIN_EVENT_ID_LAST]; }; typedef struct virtDBusConnect virtDBusConnect; diff --git a/src/events.c b/src/events.c index c6896d4..5fa61f5 100644 --- a/src/events.c +++ b/src/events.c @@ -175,14 +175,14 @@ virtDBusDomainEventsRegisterEvent(virtDBusConnect *connect, gint id, virConnectDomainEventGenericCallback callback) { - g_assert(connect->callback_ids[id] == -1); - - connect->callback_ids[id] = virConnectDomainEventRegisterAny(connect->connection, - NULL, - id, - VIR_DOMAIN_EVENT_CALLBACK(callback), - connect, - NULL); + g_assert(connect->domain_callback_ids[id] == -1); + + connect->domain_callback_ids[id] = virConnectDomainEventRegisterAny(connect->connection, + NULL, + id, + VIR_DOMAIN_EVENT_CALLBACK(callback), + connect, + NULL); } void -- 2.15.0

On Thu, Apr 05, 2018 at 03:29:30PM +0200, Katerina Koukiou wrote:
The callback_ids var is domain specific. Renaming it now, so as to keep consistent naming when introducing events for other entities.
Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- src/connect.c | 8 ++++---- src/connect.h | 2 +- src/events.c | 16 ++++++++-------- 3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/src/connect.c b/src/connect.c index f22f682..90172e3 100644 --- a/src/connect.c +++ b/src/connect.c @@ -40,12 +40,12 @@ virtDBusConnectClose(virtDBusConnect *connect, {
for (gint i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i += 1) { - if (connect->callback_ids[i] >= 0) { + if (connect->domain_callback_ids[i] >= 0) {
Since we are renaming it I would suggest to use camleCase, domainCallbackIds, to make the name consistent with the rest of libvirt-dbus code. Reviewed-by: Pavel Hrdina <phrdina@redhat.com>

Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Connect.xml | 6 +++++ src/connect.c | 13 ++++++++++ src/connect.h | 1 + src/events.c | 60 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) diff --git a/data/org.libvirt.Connect.xml b/data/org.libvirt.Connect.xml index d15c2f6..b11dbfb 100644 --- a/data/org.libvirt.Connect.xml +++ b/data/org.libvirt.Connect.xml @@ -68,5 +68,11 @@ <arg name="domain" type="o"/> <arg name="event" type="s"/> </signal> + <signal name="NetworkEvent"> + <annotation name="org.gtk.GDBus.DocString" + value="See https://libvirt.org/html/libvirt-libvirt-network.html#virConnectNetworkEventCallback"/> + <arg name="network" type="o"/> + <arg name="event" type="s"/> + </signal> </interface> </node> diff --git a/src/connect.c b/src/connect.c index 90172e3..a9006a2 100644 --- a/src/connect.c +++ b/src/connect.c @@ -49,6 +49,16 @@ virtDBusConnectClose(virtDBusConnect *connect, } } + for (gint i = 0; i < VIR_NETWORK_EVENT_ID_LAST; i += 1) { + if (connect->network_callback_ids[i] >= 0) { + if (deregisterEvents) { + virConnectNetworkEventDeregisterAny(connect->connection, + connect->network_callback_ids[i]); + } + connect->network_callback_ids[i] = -1; + } + } + virConnectClose(connect->connection); connect->connection = NULL; } @@ -431,6 +441,9 @@ virtDBusConnectNew(virtDBusConnect **connectp, for (gint i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i += 1) connect->domain_callback_ids[i] = -1; + for (gint i = 0; i < VIR_NETWORK_EVENT_ID_LAST; i += 1) + connect->network_callback_ids[i] = -1; + connect->bus = bus; connect->uri = uri; connect->connectPath = connectPath; diff --git a/src/connect.h b/src/connect.h index e69898c..e8c757f 100644 --- a/src/connect.h +++ b/src/connect.h @@ -18,6 +18,7 @@ struct virtDBusConnect { GMutex lock; gint domain_callback_ids[VIR_DOMAIN_EVENT_ID_LAST]; + gint network_callback_ids[VIR_NETWORK_EVENT_ID_LAST]; }; typedef struct virtDBusConnect virtDBusConnect; diff --git a/src/events.c b/src/events.c index 5fa61f5..b4d22a6 100644 --- a/src/events.c +++ b/src/events.c @@ -170,6 +170,48 @@ virtDBusEventsDomainDiskChange(virConnectPtr connection G_GNUC_UNUSED, return 0; } +VIRT_DBUS_ENUM_DECL(virtDBusEventsNetworkEvent) +VIRT_DBUS_ENUM_IMPL(virtDBusEventsNetworkEvent, + VIR_NETWORK_EVENT_LAST, + "Defined", + "Undefined", + "Started", + "Stopped") + +static const gchar * +virtDBusEventsNetworkEventToString(gint event) +{ + const gchar *str = virtDBusEventsNetworkEventTypeToString(event); + return str ? str : "unknown"; +} + +static gint +virtDBusEventsNetworkLifecycle(virConnectPtr connection G_GNUC_UNUSED, + virNetworkPtr network, + gint event, + gint detail G_GNUC_UNUSED, + gpointer opaque) +{ + virtDBusConnect *connect = opaque; + g_autofree gchar *path = NULL; + const gchar *eventStr = virtDBusEventsNetworkEventToString(event); + + if (!eventStr) + return 0; + + path = virtDBusUtilBusPathForVirNetwork(network, connect->networkPath); + + g_dbus_connection_emit_signal(connect->bus, + NULL, + connect->connectPath, + VIRT_DBUS_CONNECT_INTERFACE, + "NetworkEvent", + g_variant_new("(os)", path, eventStr), + NULL); + + return 0; +} + static void virtDBusDomainEventsRegisterEvent(virtDBusConnect *connect, gint id, @@ -185,6 +227,21 @@ virtDBusDomainEventsRegisterEvent(virtDBusConnect *connect, NULL); } +static void +virtDBusNetworkEventsRegisterEvent(virtDBusConnect *connect, + gint id, + virConnectNetworkEventGenericCallback callback) +{ + g_assert(connect->network_callback_ids[id] == -1); + + connect->network_callback_ids[id] = virConnectNetworkEventRegisterAny(connect->connection, + NULL, + id, + VIR_NETWORK_EVENT_CALLBACK(callback), + connect, + NULL); +} + void virtDBusEventsRegister(virtDBusConnect *connect) { @@ -208,4 +265,7 @@ virtDBusEventsRegister(virtDBusConnect *connect) VIR_DOMAIN_EVENT_ID_TRAY_CHANGE, VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainTrayChange)); + virtDBusNetworkEventsRegisterEvent(connect, + VIR_NETWORK_EVENT_ID_LIFECYCLE, + VIR_NETWORK_EVENT_CALLBACK(virtDBusEventsNetworkLifecycle)); } -- 2.15.0

On Thu, Apr 05, 2018 at 03:29:31PM +0200, Katerina Koukiou wrote:
Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Connect.xml | 6 +++++ src/connect.c | 13 ++++++++++ src/connect.h | 1 + src/events.c | 60 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+)
diff --git a/data/org.libvirt.Connect.xml b/data/org.libvirt.Connect.xml index d15c2f6..b11dbfb 100644 --- a/data/org.libvirt.Connect.xml +++ b/data/org.libvirt.Connect.xml @@ -68,5 +68,11 @@ <arg name="domain" type="o"/> <arg name="event" type="s"/> </signal> + <signal name="NetworkEvent"> + <annotation name="org.gtk.GDBus.DocString" + value="See https://libvirt.org/html/libvirt-libvirt-network.html#virConnectNetworkEventCallback"/>
This should point to virConnectNetworkEventLifecycleCallback.
+ <arg name="network" type="o"/> + <arg name="event" type="s"/> + </signal> </interface> </node> diff --git a/src/connect.c b/src/connect.c index 90172e3..a9006a2 100644 --- a/src/connect.c +++ b/src/connect.c @@ -49,6 +49,16 @@ virtDBusConnectClose(virtDBusConnect *connect, } }
+ for (gint i = 0; i < VIR_NETWORK_EVENT_ID_LAST; i += 1) { + if (connect->network_callback_ids[i] >= 0) { + if (deregisterEvents) { + virConnectNetworkEventDeregisterAny(connect->connection, + connect->network_callback_ids[i]); + } + connect->network_callback_ids[i] = -1; + } + } + virConnectClose(connect->connection); connect->connection = NULL; } @@ -431,6 +441,9 @@ virtDBusConnectNew(virtDBusConnect **connectp, for (gint i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i += 1) connect->domain_callback_ids[i] = -1;
+ for (gint i = 0; i < VIR_NETWORK_EVENT_ID_LAST; i += 1) + connect->network_callback_ids[i] = -1; + connect->bus = bus; connect->uri = uri; connect->connectPath = connectPath; diff --git a/src/connect.h b/src/connect.h index e69898c..e8c757f 100644 --- a/src/connect.h +++ b/src/connect.h @@ -18,6 +18,7 @@ struct virtDBusConnect { GMutex lock;
gint domain_callback_ids[VIR_DOMAIN_EVENT_ID_LAST]; + gint network_callback_ids[VIR_NETWORK_EVENT_ID_LAST];
Same as for domain, networkCallbackIds.
}; typedef struct virtDBusConnect virtDBusConnect;
diff --git a/src/events.c b/src/events.c index 5fa61f5..b4d22a6 100644 --- a/src/events.c +++ b/src/events.c @@ -170,6 +170,48 @@ virtDBusEventsDomainDiskChange(virConnectPtr connection G_GNUC_UNUSED, return 0; }
+VIRT_DBUS_ENUM_DECL(virtDBusEventsNetworkEvent) +VIRT_DBUS_ENUM_IMPL(virtDBusEventsNetworkEvent, + VIR_NETWORK_EVENT_LAST, + "Defined", + "Undefined", + "Started", + "Stopped") + +static const gchar * +virtDBusEventsNetworkEventToString(gint event) +{ + const gchar *str = virtDBusEventsNetworkEventTypeToString(event); + return str ? str : "unknown"; +}
I missed this while reviewing the domain event changes, but this function is no longer needed because we check the return value for NULL in order to not emit any signal if we cannot translate it into string. Whit this function it will never happen because it returns "unknown" in that case. So we can remove it.
+ +static gint +virtDBusEventsNetworkLifecycle(virConnectPtr connection G_GNUC_UNUSED, + virNetworkPtr network, + gint event, + gint detail G_GNUC_UNUSED, + gpointer opaque) +{ + virtDBusConnect *connect = opaque; + g_autofree gchar *path = NULL; + const gchar *eventStr = virtDBusEventsNetworkEventToString(event);
Here we can use virtDBusEventsNetworkEventTypeToString directly. Reviewed-by: Pavel Hrdina <phrdina@redhat.com>

Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Network.xml | 4 ++++ src/network.c | 21 +++++++++++++++++++++ test/test_network.py | 13 +++++++++++++ 3 files changed, 38 insertions(+) diff --git a/data/org.libvirt.Network.xml b/data/org.libvirt.Network.xml index d144c5d..c143f08 100644 --- a/data/org.libvirt.Network.xml +++ b/data/org.libvirt.Network.xml @@ -19,5 +19,9 @@ <annotation name="org.gtk.GDBus.DocString" value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkGetUUIDString"/> </property> + <method name="Destroy"> + <annotation name="org.gtk.GDBus.DocString" + value="See https://libvirt.org/html/libvirt-libvirt-network.html#virDomainDestroy"/> + </method> </interface> </node> diff --git a/src/network.c b/src/network.c index 90c2d9c..d46e327 100644 --- a/src/network.c +++ b/src/network.c @@ -107,6 +107,26 @@ virtDBusNetworkGetUUID(const gchar *objectPath, *value = g_variant_new("s", uuid); } +static void +virtDBusNetworkDestroy(GVariant *inArgs G_GNUC_UNUSED, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath, + gpointer userData, + GVariant **outArgs G_GNUC_UNUSED, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect = userData; + g_autoptr(virNetwork) network = NULL; + + network = virtDBusNetworkGetVirNetwork(connect, objectPath, error); + if (!network) + return; + + if (virNetworkDestroy(network) < 0) + virtDBusUtilSetLastVirtError(error); +} + static virtDBusGDBusPropertyTable virtDBusNetworkPropertyTable[] = { { "Autostart", virtDBusNetworkGetAutostart, NULL }, { "BridgeName", virtDBusNetworkGetBridgeName, NULL }, @@ -116,6 +136,7 @@ static virtDBusGDBusPropertyTable virtDBusNetworkPropertyTable[] = { }; static virtDBusGDBusMethodTable virtDBusNetworkMethodTable[] = { + { "Destroy", virtDBusNetworkDestroy }, { 0 } }; diff --git a/test/test_network.py b/test/test_network.py index e753f7f..825b52f 100755 --- a/test/test_network.py +++ b/test/test_network.py @@ -17,6 +17,19 @@ class TestNetwork(libvirttest.BaseTestClass): assert isinstance(props['Name'], dbus.String) assert isinstance(props['UUID'], dbus.String) + def test_network_destroy(self): + def network_stopped(path, _event): + assert isinstance(path, dbus.ObjectPath) + self.loop.quit() + + self.connect.connect_to_signal('NetworkEvent', network_stopped, arg1='Stopped') + + _, test_network = self.test_network() + interface_obj = dbus.Interface(test_network, 'org.libvirt.Network') + interface_obj.Destroy() + + self.main_loop() + if __name__ == '__main__': libvirttest.run() -- 2.15.0

On Thu, Apr 05, 2018 at 03:29:32PM +0200, Katerina Koukiou wrote:
Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Network.xml | 4 ++++ src/network.c | 21 +++++++++++++++++++++ test/test_network.py | 13 +++++++++++++ 3 files changed, 38 insertions(+)
diff --git a/data/org.libvirt.Network.xml b/data/org.libvirt.Network.xml index d144c5d..c143f08 100644 --- a/data/org.libvirt.Network.xml +++ b/data/org.libvirt.Network.xml @@ -19,5 +19,9 @@ <annotation name="org.gtk.GDBus.DocString" value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkGetUUIDString"/> </property> + <method name="Destroy"> + <annotation name="org.gtk.GDBus.DocString" + value="See https://libvirt.org/html/libvirt-libvirt-network.html#virDomainDestroy"/>
virNetworkDestroy I guess that's a copy&paste error :).
+ </method> </interface>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>

Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Network.xml | 4 ++++ src/network.c | 21 +++++++++++++++++++++ test/test_network.py | 13 +++++++++++++ 3 files changed, 38 insertions(+) diff --git a/data/org.libvirt.Network.xml b/data/org.libvirt.Network.xml index c143f08..8a8eef7 100644 --- a/data/org.libvirt.Network.xml +++ b/data/org.libvirt.Network.xml @@ -23,5 +23,9 @@ <annotation name="org.gtk.GDBus.DocString" value="See https://libvirt.org/html/libvirt-libvirt-network.html#virDomainDestroy"/> </method> + <method name="Undefine"> + <annotation name="org.gtk.GDBus.DocString" + value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkUndefine"/> + </method> </interface> </node> diff --git a/src/network.c b/src/network.c index d46e327..c911880 100644 --- a/src/network.c +++ b/src/network.c @@ -127,6 +127,26 @@ virtDBusNetworkDestroy(GVariant *inArgs G_GNUC_UNUSED, virtDBusUtilSetLastVirtError(error); } +static void +virtDBusNetworkUndefine(GVariant *inArgs G_GNUC_UNUSED, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath, + gpointer userData, + GVariant **outArgs G_GNUC_UNUSED, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect = userData; + g_autoptr(virNetwork) network = NULL; + + network = virtDBusNetworkGetVirNetwork(connect, objectPath, error); + if (!network) + return; + + if (virNetworkUndefine(network) < 0) + virtDBusUtilSetLastVirtError(error); +} + static virtDBusGDBusPropertyTable virtDBusNetworkPropertyTable[] = { { "Autostart", virtDBusNetworkGetAutostart, NULL }, { "BridgeName", virtDBusNetworkGetBridgeName, NULL }, @@ -137,6 +157,7 @@ static virtDBusGDBusPropertyTable virtDBusNetworkPropertyTable[] = { static virtDBusGDBusMethodTable virtDBusNetworkMethodTable[] = { { "Destroy", virtDBusNetworkDestroy }, + { "Undefine", virtDBusNetworkUndefine }, { 0 } }; diff --git a/test/test_network.py b/test/test_network.py index 825b52f..f61e73d 100755 --- a/test/test_network.py +++ b/test/test_network.py @@ -30,6 +30,19 @@ class TestNetwork(libvirttest.BaseTestClass): self.main_loop() + def test_network_undefine(self): + def domain_undefined(path, _event): + assert isinstance(path, dbus.ObjectPath) + self.loop.quit() + + self.connect.connect_to_signal('NetworkEvent', domain_undefined, arg1='Undefined') + + _,test_network = self.test_network() + interface_obj = dbus.Interface(test_network, 'org.libvirt.Network') + interface_obj.Destroy() + interface_obj.Undefine() + + self.main_loop() if __name__ == '__main__': libvirttest.run() -- 2.15.0

On Thu, Apr 05, 2018 at 03:29:33PM +0200, Katerina Koukiou wrote:
Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Network.xml | 4 ++++ src/network.c | 21 +++++++++++++++++++++ test/test_network.py | 13 +++++++++++++ 3 files changed, 38 insertions(+)
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>

Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Network.xml | 4 ++++ src/network.c | 21 +++++++++++++++++++++ test/test_network.py | 14 ++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/data/org.libvirt.Network.xml b/data/org.libvirt.Network.xml index 8a8eef7..0505e7a 100644 --- a/data/org.libvirt.Network.xml +++ b/data/org.libvirt.Network.xml @@ -19,6 +19,10 @@ <annotation name="org.gtk.GDBus.DocString" value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkGetUUIDString"/> </property> + <method name="Create"> + <annotation name="org.gtk.GDBus.DocString" + value="See https://libvirt.org/html/libvirt-libvirt-network.html#virNetworkCreate"/> + </method> <method name="Destroy"> <annotation name="org.gtk.GDBus.DocString" value="See https://libvirt.org/html/libvirt-libvirt-network.html#virDomainDestroy"/> diff --git a/src/network.c b/src/network.c index c911880..1d749e4 100644 --- a/src/network.c +++ b/src/network.c @@ -107,6 +107,26 @@ virtDBusNetworkGetUUID(const gchar *objectPath, *value = g_variant_new("s", uuid); } +static void +virtDBusNetworkCreate(GVariant *inArgs G_GNUC_UNUSED, + GUnixFDList *inFDs G_GNUC_UNUSED, + const gchar *objectPath, + gpointer userData, + GVariant **outArgs G_GNUC_UNUSED, + GUnixFDList **outFDs G_GNUC_UNUSED, + GError **error) +{ + virtDBusConnect *connect = userData; + g_autoptr(virNetwork) network = NULL; + + network = virtDBusNetworkGetVirNetwork(connect, objectPath, error); + if (!network) + return; + + if (virNetworkCreate(network) < 0) + virtDBusUtilSetLastVirtError(error); +} + static void virtDBusNetworkDestroy(GVariant *inArgs G_GNUC_UNUSED, GUnixFDList *inFDs G_GNUC_UNUSED, @@ -156,6 +176,7 @@ static virtDBusGDBusPropertyTable virtDBusNetworkPropertyTable[] = { }; static virtDBusGDBusMethodTable virtDBusNetworkMethodTable[] = { + { "Create", virtDBusNetworkCreate }, { "Destroy", virtDBusNetworkDestroy }, { "Undefine", virtDBusNetworkUndefine }, { 0 } diff --git a/test/test_network.py b/test/test_network.py index f61e73d..17d4555 100755 --- a/test/test_network.py +++ b/test/test_network.py @@ -17,6 +17,20 @@ class TestNetwork(libvirttest.BaseTestClass): assert isinstance(props['Name'], dbus.String) assert isinstance(props['UUID'], dbus.String) + def test_network_create(self): + def domain_started(path, _event): + assert isinstance(path, dbus.ObjectPath) + self.loop.quit() + + self.connect.connect_to_signal('NetworkEvent', domain_started, arg1='Started') + + _,test_network = self.test_network() + interface_obj = dbus.Interface(test_network, 'org.libvirt.Network') + interface_obj.Destroy() + interface_obj.Create() + + self.main_loop() + def test_network_destroy(self): def network_stopped(path, _event): assert isinstance(path, dbus.ObjectPath) -- 2.15.0

On Thu, Apr 05, 2018 at 03:29:34PM +0200, Katerina Koukiou wrote:
Signed-off-by: Katerina Koukiou <kkoukiou@redhat.com> --- data/org.libvirt.Network.xml | 4 ++++ src/network.c | 21 +++++++++++++++++++++ test/test_network.py | 14 ++++++++++++++ 3 files changed, 39 insertions(+)
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
participants (2)
-
Katerina Koukiou
-
Pavel Hrdina