From 1a07c2efb34357f164c353ce86e8384282fd3089 Mon Sep 17 00:00:00 2001 From: Erik Skultety Date: Fri, 14 Aug 2015 09:17:01 +0200 Subject: [PATCH] admin: Introduce adminDaemonConnectListServers API 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 Signed-off-by: Martin Kletzander --- 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 | 81 ++++++++++++++++++++++++++++++++- 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, 396 insertions(+), 4 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 9edaf5f696..2dbe81bf03 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 fa6caf337e..0c1ddc0709 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 0000000000..7521e822c2 --- /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 + * . + * + * Authors: Erik Skultety + * Martin Kletzander + */ + +#include + +#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) < 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 0000000000..2a5aa16335 --- /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 + * . + * + * Authors: Erik Skultety + * Martin Kletzander + */ + +#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 b3425102a0..e9ec394102 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 171d2b1e15..ff207cbb03 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 549fdf36fb..089ce57c74 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; + 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 7b40ea16e1..e634fa79e8 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 95ea4e436b..8f2633ae7c 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 6e6da81b3f..36674441b1 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 ff0ef2e332..ffaf4f32a3 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 33b1db45a3..52ff2dc1b4 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 9210de4c2e..298fbf4ab0 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 968708b94f..9a3404f544 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__ */