[libvirt] [PATCH v4 6/7] admin: Introduce adminDaemonConnectListServers API

Erik Skultety eskultet at redhat.com
Fri Feb 12 10:08:07 UTC 2016


This API is merely a convenience API, i.e. when managing clients connected to
daemon's servers, we should know (convenience) which server the specific client
is connected to. This implies a client-side representation of a server along
with a basic API to let the administrating client know what servers are actually
available on the daemon.

Signed-off-by: Erik Skultety <eskultet at redhat.com>
Signed-off-by: Martin Kletzander <mkletzan at redhat.com>
---
 daemon/Makefile.am              |  2 +-
 daemon/admin.c                  | 55 ++++++++++++++++++++++++++++
 daemon/admin_server.c           | 73 +++++++++++++++++++++++++++++++++++++
 daemon/admin_server.h           | 34 ++++++++++++++++++
 include/libvirt/libvirt-admin.h |  8 ++++-
 po/POTFILES.in                  |  1 +
 src/admin/admin_protocol.x      | 18 +++++++++-
 src/admin/admin_remote.c        | 71 ++++++++++++++++++++++++++++++++++++
 src/admin_protocol-structs      | 12 +++++++
 src/libvirt-admin.c             | 79 +++++++++++++++++++++++++++++++++++++++++
 src/libvirt_admin_private.syms  |  2 ++
 src/libvirt_admin_public.syms   |  3 ++
 src/rpc/virnetdaemon.c          | 39 ++++++++++++++++++++
 src/rpc/virnetdaemon.h          |  1 +
 14 files changed, 395 insertions(+), 3 deletions(-)
 create mode 100644 daemon/admin_server.c
 create mode 100644 daemon/admin_server.h

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 9edaf5f..2dbe81b 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -128,7 +128,7 @@ libvirtd_conf_la_LIBADD = $(LIBXML_LIBS)
 
 noinst_LTLIBRARIES += libvirtd_admin.la
 libvirtd_admin_la_SOURCES = \
-		admin.c admin.h
+		admin.c admin.h admin_server.c admin_server.h
 
 libvirtd_admin_la_CFLAGS = \
 		$(AM_CFLAGS)		\
diff --git a/daemon/admin.c b/daemon/admin.c
index fa6caf3..0c1ddc0 100644
--- a/daemon/admin.c
+++ b/daemon/admin.c
@@ -28,6 +28,7 @@
 
 #include "admin_protocol.h"
 #include "admin.h"
+#include "admin_server.h"
 #include "datatypes.h"
 #include "viralloc.h"
 #include "virerror.h"
@@ -77,6 +78,15 @@ remoteAdmClientInitHook(virNetServerClientPtr client ATTRIBUTE_UNUSED,
     return priv;
 }
 
+/* Helpers */
+
+static void
+make_nonnull_server(admin_nonnull_server *srv_dst,
+                    virAdmServerPtr srv_src)
+{
+    ignore_value(VIR_STRDUP_QUIET(srv_dst->name, srv_src->name));
+}
+
 /* Functions */
 static int
 adminDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED,
@@ -123,4 +133,49 @@ adminConnectGetLibVersion(virNetDaemonPtr dmn ATTRIBUTE_UNUSED,
     return 0;
 }
 
+static int
+adminDispatchConnectListServers(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                virNetServerClientPtr client,
+                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
+                                virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+                                admin_connect_list_servers_args *args,
+                                admin_connect_list_servers_ret *ret)
+{
+    virAdmServerPtr *servers = NULL;
+    int nservers = 0;
+    int rv = -1;
+    size_t i;
+    struct daemonAdmClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
+
+    if ((nservers =
+            adminDaemonListServers(priv->dmn,
+                                   args->need_results ? &servers : NULL,
+                                   args->flags)) < 0)
+        goto cleanup;
+
+    if (servers && nservers) {
+        if (VIR_ALLOC_N(ret->servers.servers_val, nservers) < 0)
+            goto cleanup;
+
+        ret->servers.servers_len = nservers;
+        for (i = 0; i < nservers; i++)
+            make_nonnull_server(ret->servers.servers_val + i, servers[i]);
+    } else {
+        ret->servers.servers_len = 0;
+        ret->servers.servers_val = NULL;
+    }
+
+    ret->ret = nservers;
+    rv = 0;
+
+ cleanup:
+    if (rv < 0)
+        virNetMessageSaveError(rerr);
+    if (servers && nservers > 0)
+        for (i = 0; i < nservers; i++)
+            virObjectUnref(servers[i]);
+    VIR_FREE(servers);
+    return rv;
+}
 #include "admin_dispatch.h"
diff --git a/daemon/admin_server.c b/daemon/admin_server.c
new file mode 100644
index 0000000..a054421
--- /dev/null
+++ b/daemon/admin_server.c
@@ -0,0 +1,73 @@
+/*
+ * admin_server.c: admin methods to manage daemons and clients
+ *
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Erik Skultety <eskultet at redhat.com>
+ *          Martin Kletzander <mkletzan at redhat.com>
+ */
+
+#include <config.h>
+
+#include "admin_server.h"
+#include "datatypes.h"
+#include "viralloc.h"
+#include "virerror.h"
+#include "virlog.h"
+#include "virnetdaemon.h"
+#include "virnetserver.h"
+#include "virstring.h"
+
+#define VIR_FROM_THIS VIR_FROM_ADMIN
+
+VIR_LOG_INIT("daemon.admin_server");
+
+int
+adminDaemonListServers(virNetDaemonPtr dmn,
+                       virAdmServerPtr **servers,
+                       unsigned int flags)
+{
+    int ret = -1;
+    const char **srv_names = NULL;
+    virAdmServerPtr *srvs = NULL;
+    size_t i;
+    ssize_t nsrvs = 0;
+
+    virCheckFlags(0, -1);
+
+    if ((nsrvs = virNetDaemonGetServerNames(dmn, &srv_names)) < 0)
+        goto cleanup;
+
+    if (servers) {
+        if (VIR_ALLOC_N(srvs, nsrvs + 1) < 0)
+            goto cleanup;
+
+        for (i = 0; i < nsrvs; i++) {
+            if (!(srvs[i] = virAdmGetServer(NULL, srv_names[i])))
+                goto cleanup;
+        }
+
+        *servers = srvs;
+        srvs = NULL;
+    }
+
+    ret = nsrvs;
+
+ cleanup:
+    virObjectListFree(srvs);
+    return ret;
+}
diff --git a/daemon/admin_server.h b/daemon/admin_server.h
new file mode 100644
index 0000000..2a5aa16
--- /dev/null
+++ b/daemon/admin_server.h
@@ -0,0 +1,34 @@
+/*
+ * admin_server.h: admin methods to manage daemons and clients
+ *
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Erik Skultety <eskultet at redhat.com>
+ *          Martin Kletzander <mkletzan at redhat.com>
+ */
+
+#ifndef __LIBVIRTD_ADMIN_SERVER_H__
+# define __LIBVIRTD_ADMIN_SERVER_H__
+
+# include "rpc/virnetdaemon.h"
+
+int
+adminDaemonListServers(virNetDaemonPtr dmn,
+                       virAdmServerPtr **servers,
+                       unsigned int flags);
+
+#endif /* __LIBVIRTD_ADMIN_SERVER_H__ */
diff --git a/include/libvirt/libvirt-admin.h b/include/libvirt/libvirt-admin.h
index b342510..e9ec394 100644
--- a/include/libvirt/libvirt-admin.h
+++ b/include/libvirt/libvirt-admin.h
@@ -70,9 +70,13 @@ typedef virAdmServer *virAdmServerPtr;
 
 virAdmConnectPtr virAdmConnectOpen(const char *name, unsigned int flags);
 int virAdmConnectClose(virAdmConnectPtr conn);
-
 int virAdmConnectRef(virAdmConnectPtr conn);
 int virAdmConnectIsAlive(virAdmConnectPtr conn);
+int virAdmServerFree(virAdmServerPtr srv);
+
+int virAdmConnectListServers(virAdmConnectPtr dmn,
+                             virAdmServerPtr **servers,
+                             unsigned int flags);
 
 int virAdmGetVersion(unsigned long long *libVer);
 
@@ -100,6 +104,8 @@ int virAdmConnectRegisterCloseCallback(virAdmConnectPtr conn,
 int virAdmConnectUnregisterCloseCallback(virAdmConnectPtr conn,
                                          virAdmConnectCloseFunc cb);
 
+const char *virAdmServerGetName(virAdmServerPtr srv);
+
 # ifdef __cplusplus
 }
 # endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5fd6402..8f87a33 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -10,6 +10,7 @@ gnulib/lib/gai_strerror.c
 gnulib/lib/regcomp.c
 src/access/viraccessdriverpolkit.c
 src/access/viraccessmanager.c
+src/admin/admin_remote.c
 src/bhyve/bhyve_command.c
 src/bhyve/bhyve_device.c
 src/bhyve/bhyve_driver.c
diff --git a/src/admin/admin_protocol.x b/src/admin/admin_protocol.x
index 549fdf3..089ce57 100644
--- a/src/admin/admin_protocol.x
+++ b/src/admin/admin_protocol.x
@@ -55,6 +55,16 @@ struct admin_connect_get_lib_version_ret {
     unsigned hyper libVer;
 };
 
+struct admin_connect_list_servers_args {
+    unsigned int need_results;
+    unsigned int flags;
+};
+
+struct admin_connect_list_servers_ret {
+    admin_nonnull_server servers<ADMIN_SERVER_LIST_MAX>;
+    unsigned int ret;
+};
+
 /* Define the program number, protocol version and procedure numbers here. */
 const ADMIN_PROGRAM = 0x06900690;
 const ADMIN_PROTOCOL_VERSION = 1;
@@ -90,5 +100,11 @@ enum admin_procedure {
     /**
      * @generate: both
      */
-    ADMIN_PROC_CONNECT_GET_LIB_VERSION = 3
+    ADMIN_PROC_CONNECT_GET_LIB_VERSION = 3,
+
+    /**
+      * @generate: none
+      * @priority: high
+      */
+    ADMIN_PROC_CONNECT_LIST_SERVERS = 4
 };
diff --git a/src/admin/admin_remote.c b/src/admin/admin_remote.c
index 7b40ea1..e634fa7 100644
--- a/src/admin/admin_remote.c
+++ b/src/admin/admin_remote.c
@@ -47,6 +47,14 @@ remoteAdminPrivDispose(void *opaque)
 }
 
 
+/* Helpers */
+static virAdmServerPtr
+get_nonnull_server(virAdmConnectPtr conn, admin_nonnull_server server)
+{
+    return virAdmGetServer(conn, server.name);
+}
+
+
 static int
 callFull(virAdmConnectPtr conn ATTRIBUTE_UNUSED,
          remoteAdminPrivPtr priv,
@@ -214,3 +222,66 @@ remoteAdminPrivNew(const char *sock_path)
     virObjectUnref(priv);
     return NULL;
 }
+
+static int
+remoteAdminConnectListServers(virAdmConnectPtr conn,
+                              virAdmServerPtr **servers,
+                              unsigned int flags)
+{
+    int rv = -1;
+    size_t i;
+    virAdmServerPtr *tmp_srvs = NULL;
+    remoteAdminPrivPtr priv = conn->privateData;
+    admin_connect_list_servers_args args;
+    admin_connect_list_servers_ret ret;
+
+    args.need_results = !!servers;
+    args.flags = flags;
+
+    memset(&ret, 0, sizeof(ret));
+    virObjectLock(priv);
+
+    if (call(conn,
+             0,
+             ADMIN_PROC_CONNECT_LIST_SERVERS,
+             (xdrproc_t) xdr_admin_connect_list_servers_args,
+             (char *) &args,
+             (xdrproc_t) xdr_admin_connect_list_servers_ret,
+             (char *) &ret) == -1)
+        goto done;
+
+    if (ret.servers.servers_len > ADMIN_SERVER_LIST_MAX) {
+        virReportError(VIR_ERR_RPC,
+                       _("Too many servers '%d' for limit '%d'"),
+                       ret.servers.servers_len, ADMIN_SERVER_LIST_MAX);
+        goto cleanup;
+    }
+
+    if (servers) {
+        if (VIR_ALLOC_N(tmp_srvs, ret.servers.servers_len + 1) < 0)
+            goto cleanup;
+
+        for (i = 0; i < ret.servers.servers_len; i++) {
+            tmp_srvs[i] = get_nonnull_server(conn, ret.servers.servers_val[i]);
+            if (!tmp_srvs[i])
+                goto cleanup;
+        }
+        *servers = tmp_srvs;
+        tmp_srvs = NULL;
+    }
+
+    rv = ret.ret;
+
+ cleanup:
+    if (tmp_srvs) {
+        for (i = 0; i < ret.servers.servers_len; i++)
+            virObjectUnref(tmp_srvs[i]);
+        VIR_FREE(tmp_srvs);
+    }
+
+    xdr_free((xdrproc_t) xdr_admin_connect_list_servers_ret, (char *) &ret);
+
+ done:
+    virObjectUnlock(priv);
+    return rv;
+}
diff --git a/src/admin_protocol-structs b/src/admin_protocol-structs
index 95ea4e4..8f2633a 100644
--- a/src/admin_protocol-structs
+++ b/src/admin_protocol-structs
@@ -8,8 +8,20 @@ struct admin_connect_open_args {
 struct admin_connect_get_lib_version_ret {
         uint64_t                   libVer;
 };
+struct admin_connect_list_servers_args {
+        u_int                      need_results;
+        u_int                      flags;
+};
+struct admin_connect_list_servers_ret {
+        struct {
+                u_int              servers_len;
+                admin_nonnull_server * servers_val;
+        } servers;
+        u_int                      ret;
+};
 enum admin_procedure {
         ADMIN_PROC_CONNECT_OPEN = 1,
         ADMIN_PROC_CONNECT_CLOSE = 2,
         ADMIN_PROC_CONNECT_GET_LIB_VERSION = 3,
+        ADMIN_PROC_CONNECT_LIST_SERVERS = 4,
 };
diff --git a/src/libvirt-admin.c b/src/libvirt-admin.c
index 6e6da81..3667444 100644
--- a/src/libvirt-admin.c
+++ b/src/libvirt-admin.c
@@ -549,7 +549,86 @@ int virAdmConnectGetLibVersion(virAdmConnectPtr conn,
         goto error;
 
     return 0;
+ error:
+    virDispatchError(NULL);
+    return -1;
+}
+
+/**
+ * virAdmServerGetName:
+ * @srv: a server object
+ *
+ *  Get the public name for specified server
+ *
+ * Returns a pointer to the name or NULL. The string doesn't need to be
+ * deallocated since its lifetime will be the same as the server object.
+ */
+const char *
+virAdmServerGetName(virAdmServerPtr srv)
+{
+    VIR_DEBUG("server=%p", srv);
+
+    virResetLastError();
+    virCheckAdmServerReturn(srv, NULL);
+
+    return srv->name;
+}
+
+/**
+ * virAdmServerFree:
+ * @srv: server object
+ *
+ * Release the server object. The running instance is kept alive.
+ * The data structure is freed and should not be used thereafter.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int virAdmServerFree(virAdmServerPtr srv)
+{
+    VIR_DEBUG("server=%p", srv);
 
+    virResetLastError();
+    virCheckAdmServerReturn(srv, -1);
+
+    virObjectUnref(srv);
+    return 0;
+}
+
+/**
+ * virAdmConnectListServers:
+ * @conn: daemon connection reference
+ * @servers: Pointer to a list to store an array containing objects or NULL
+ *           if the list is not required (number of servers only)
+ * @flags: bitwise-OR of virAdmConnectListServersFlags
+ *
+ * Collect list of all servers provided by daemon the client is connected to.
+ *
+ * Returns the number of servers available on daemon side or -1 in case of a
+ * failure, setting @servers to NULL. There is a guaranteed extra element set
+ * to NULL in the @servers list returned to make the iteration easier, excluding
+ * this extra element from the final count.
+ * Caller is responsible to call virAdmServerFree() on each list element,
+ * followed by freeing @servers.
+ */
+int
+virAdmConnectListServers(virAdmConnectPtr conn,
+                         virAdmServerPtr **servers,
+                         unsigned int flags)
+{
+    int ret = -1;
+
+    VIR_DEBUG("conn=%p, servers=%p, flags=%x", conn, servers, flags);
+
+    virResetLastError();
+
+    if (servers)
+        *servers = NULL;
+
+    virCheckAdmConnectReturn(conn, -1);
+    if ((ret = remoteAdminConnectListServers(conn, servers, flags)) < 0)
+        goto error;
+
+    return ret;
  error:
     virDispatchError(NULL);
     return -1;
diff --git a/src/libvirt_admin_private.syms b/src/libvirt_admin_private.syms
index 31f1f8d..ae6b9dd 100644
--- a/src/libvirt_admin_private.syms
+++ b/src/libvirt_admin_private.syms
@@ -7,6 +7,8 @@
 
 # admin/admin_protocol.x
 xdr_admin_connect_get_lib_version_ret;
+xdr_admin_connect_list_servers_args;
+xdr_admin_connect_list_servers_ret;
 xdr_admin_connect_open_args;
 
 # datatypes.h
diff --git a/src/libvirt_admin_public.syms b/src/libvirt_admin_public.syms
index 33b1db4..52ff2dc 100644
--- a/src/libvirt_admin_public.syms
+++ b/src/libvirt_admin_public.syms
@@ -21,4 +21,7 @@ LIBVIRT_ADMIN_1.3.0 {
         virAdmConnectGetLibVersion;
         virAdmConnectRegisterCloseCallback;
         virAdmConnectUnregisterCloseCallback;
+        virAdmConnectListServers;
+        virAdmServerGetName;
+        virAdmServerFree;
 };
diff --git a/src/rpc/virnetdaemon.c b/src/rpc/virnetdaemon.c
index 9210de4..298fbf4 100644
--- a/src/rpc/virnetdaemon.c
+++ b/src/rpc/virnetdaemon.c
@@ -190,6 +190,45 @@ virNetDaemonGetServer(virNetDaemonPtr dmn,
     return srv;
 }
 
+
+/*
+ * Returns number of names allocated in *servers, on error sets
+ * *servers to NULL and returns -1.  List of *servers must be free()d,
+ * but not the items in it (similarly to virHashGetItems).
+ */
+ssize_t
+virNetDaemonGetServerNames(virNetDaemonPtr dmn,
+                           const char ***servers)
+{
+    virHashKeyValuePairPtr items = NULL;
+    size_t nservers = 0;
+    ssize_t ret = -1;
+    size_t i;
+
+    *servers = NULL;
+
+    virObjectLock(dmn);
+
+    items = virHashGetItems(dmn->servers, NULL);
+    if (!items)
+        goto cleanup;
+
+    for (i = 0; items[i].key; i++) {
+        if (VIR_APPEND_ELEMENT(*servers, nservers, items[i].key) < 0)
+            goto cleanup;
+    }
+
+    ret = nservers;
+
+ cleanup:
+    if (ret < 0)
+        VIR_FREE(*servers);
+    VIR_FREE(items);
+    virObjectUnlock(dmn);
+    return ret;
+}
+
+
 virNetServerPtr
 virNetDaemonAddServerPostExec(virNetDaemonPtr dmn,
                               const char *serverName,
diff --git a/src/rpc/virnetdaemon.h b/src/rpc/virnetdaemon.h
index 968708b..9a3404f 100644
--- a/src/rpc/virnetdaemon.h
+++ b/src/rpc/virnetdaemon.h
@@ -83,5 +83,6 @@ bool virNetDaemonHasClients(virNetDaemonPtr dmn);
 
 virNetServerPtr virNetDaemonGetServer(virNetDaemonPtr dmn,
                                       const char *serverName);
+ssize_t virNetDaemonGetServerNames(virNetDaemonPtr dmn, const char ***servers);
 
 #endif /* __VIR_NET_DAEMON_H__ */
-- 
2.4.3




More information about the libvir-list mailing list