rpc: virnetserverclient: Introduce new attribute conn_time to client

Besides ID, libvirt should provide several parameters to help the user
distinguish two clients from each other. One of them is the connection
timestamp. This patch also adds a testcase for proper JSON formatting of the
new attribute too (proper formatting of older clients that did not support
this attribute yet is included in the existing tests) - in order to
testGenerateJSON to work, a mock of time_t time(time_t *timer) needed to be
created.

Signed-off-by: Erik Skultety <eskultet@redhat.com>
This commit is contained in:
Erik Skultety 2016-04-12 19:21:43 +02:00
parent 5841d64d25
commit a32135b3b1
7 changed files with 228 additions and 4 deletions

View File

@ -85,6 +85,13 @@ struct _virNetServerClient
virIdentityPtr identity;
/* Connection timestamp, i.e. when a client connected to the daemon (UTC).
* For old clients restored by post-exec-restart, which did not have this
* attribute, value of 0 (epoch time) is used to indicate we have no
* information about their connection time.
*/
time_t conn_time;
/* Count of messages in the 'tx' queue,
* and the server worker pool queue
* ie RPC calls in progress. Does not count
@ -355,7 +362,8 @@ virNetServerClientNewInternal(unsigned long long id,
virNetTLSContextPtr tls,
#endif
bool readonly,
size_t nrequests_max)
size_t nrequests_max,
time_t timestamp)
{
virNetServerClientPtr client;
@ -373,6 +381,7 @@ virNetServerClientNewInternal(unsigned long long id,
client->tlsCtxt = virObjectRef(tls);
#endif
client->nrequests_max = nrequests_max;
client->conn_time = timestamp;
client->sockTimer = virEventAddTimeout(-1, virNetServerClientSockTimerFunc,
client, NULL);
@ -413,6 +422,7 @@ virNetServerClientPtr virNetServerClientNew(unsigned long long id,
void *privOpaque)
{
virNetServerClientPtr client;
time_t now;
VIR_DEBUG("sock=%p auth=%d tls=%p", sock, auth,
#ifdef WITH_GNUTLS
@ -422,11 +432,17 @@ virNetServerClientPtr virNetServerClientNew(unsigned long long id,
#endif
);
if ((now = time(NULL)) == (time_t) - 1) {
virReportSystemError(errno, "%s", _("failed to get current time"));
return NULL;
}
if (!(client = virNetServerClientNewInternal(id, sock, auth,
#ifdef WITH_GNUTLS
tls,
#endif
readonly, nrequests_max)))
readonly, nrequests_max,
now)))
return NULL;
if (privNew) {
@ -456,6 +472,7 @@ virNetServerClientPtr virNetServerClientNewPostExecRestart(virJSONValuePtr objec
bool readonly;
unsigned int nrequests_max;
unsigned long long id;
time_t timestamp;
if (virJSONValueObjectGetNumberInt(object, "auth", &auth) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@ -492,6 +509,18 @@ virNetServerClientPtr virNetServerClientNewPostExecRestart(virJSONValuePtr objec
}
}
if (!virJSONValueObjectHasKey(object, "conn_time")) {
timestamp = 0;
} else {
if (virJSONValueObjectGetNumberLong(object, "conn_time",
(long long *) &timestamp) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Malformed conn_time field in JSON "
"state document"));
return NULL;
}
}
if (!(sock = virNetSocketNewPostExecRestart(child))) {
virObjectUnref(sock);
return NULL;
@ -504,7 +533,8 @@ virNetServerClientPtr virNetServerClientNewPostExecRestart(virJSONValuePtr objec
NULL,
#endif
readonly,
nrequests_max))) {
nrequests_max,
timestamp))) {
virObjectUnref(sock);
return NULL;
}
@ -552,6 +582,11 @@ virJSONValuePtr virNetServerClientPreExecRestart(virNetServerClientPtr client)
if (virJSONValueObjectAppendNumberUint(object, "nrequests_max", client->nrequests_max) < 0)
goto error;
if (client->conn_time &&
virJSONValueObjectAppendNumberLong(object, "conn_time",
client->conn_time) < 0)
goto error;
if (!(child = virNetSocketPreExecRestart(client->sock)))
goto error;
@ -610,6 +645,11 @@ unsigned long long virNetServerClientGetID(virNetServerClientPtr client)
return client->id;
}
long long virNetServerClientGetTimestamp(virNetServerClientPtr client)
{
return client->conn_time;
}
#ifdef WITH_GNUTLS
bool virNetServerClientHasTLSSession(virNetServerClientPtr client)
{

View File

@ -82,6 +82,7 @@ int virNetServerClientGetAuth(virNetServerClientPtr client);
void virNetServerClientSetAuth(virNetServerClientPtr client, int auth);
bool virNetServerClientGetReadonly(virNetServerClientPtr client);
unsigned long long virNetServerClientGetID(virNetServerClientPtr client);
long long virNetServerClientGetTimestamp(virNetServerClientPtr client);
# ifdef WITH_GNUTLS
bool virNetServerClientHasTLSSession(virNetServerClientPtr client);

View File

@ -408,6 +408,7 @@ EXTRA_DIST += $(test_scripts)
test_libraries = libshunload.la \
virportallocatormock.la \
virnetdaemonmock.la \
virnetserverclientmock.la \
vircgroupmock.la \
virpcimock.la \
@ -927,6 +928,12 @@ virnetdaemontest_SOURCES = \
virnetdaemontest_CFLAGS = $(XDR_CFLAGS) $(AM_CFLAGS)
virnetdaemontest_LDADD = $(LDADDS)
virnetdaemonmock_la_SOURCES = \
virnetdaemonmock.c
virnetdaemonmock_la_CFLAGS = $(AM_CFLAGS)
virnetdaemonmock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
virnetdaemonmock_la_LIBADD = $(MOCKLIBS_LIBS)
virnetserverclienttest_SOURCES = \
virnetserverclienttest.c \
testutils.h testutils.c

View File

@ -0,0 +1,70 @@
{
"servers": {
"testServer0": {
"min_workers": 10,
"max_workers": 50,
"priority_workers": 5,
"max_clients": 100,
"max_anonymous_clients": 10,
"keepaliveInterval": 120,
"keepaliveCount": 5,
"next_client_id": 3,
"services": [
{
"auth": 0,
"readonly": true,
"nrequests_client_max": 2,
"socks": [
{
"fd": 100,
"errfd": -1,
"pid": 0,
"isClient": false
}
]
},
{
"auth": 2,
"readonly": false,
"nrequests_client_max": 5,
"socks": [
{
"fd": 101,
"errfd": -1,
"pid": 0,
"isClient": false
}
]
}
],
"clients": [
{
"id": 1,
"auth": 1,
"readonly": true,
"nrequests_max": 15,
"conn_time": 1234567890,
"sock": {
"fd": 102,
"errfd": -1,
"pid": -1,
"isClient": true
}
},
{
"id": 2,
"auth": 2,
"readonly": true,
"nrequests_max": 66,
"conn_time": 1234567890,
"sock": {
"fd": 103,
"errfd": -1,
"pid": -1,
"isClient": true
}
}
]
}
}
}

View File

@ -0,0 +1,70 @@
{
"servers": {
"testServer0": {
"min_workers": 10,
"max_workers": 50,
"priority_workers": 5,
"max_clients": 100,
"max_anonymous_clients": 10,
"keepaliveInterval": 120,
"keepaliveCount": 5,
"next_client_id": 3,
"services": [
{
"auth": 0,
"readonly": true,
"nrequests_client_max": 2,
"socks": [
{
"fd": 100,
"errfd": -1,
"pid": 0,
"isClient": false
}
]
},
{
"auth": 2,
"readonly": false,
"nrequests_client_max": 5,
"socks": [
{
"fd": 101,
"errfd": -1,
"pid": 0,
"isClient": false
}
]
}
],
"clients": [
{
"id": 1,
"auth": 1,
"readonly": true,
"nrequests_max": 15,
"conn_time": 1234567890,
"sock": {
"fd": 102,
"errfd": -1,
"pid": -1,
"isClient": true
}
},
{
"id": 2,
"auth": 2,
"readonly": true,
"nrequests_max": 66,
"conn_time": 1234567890,
"sock": {
"fd": 103,
"errfd": -1,
"pid": -1,
"isClient": true
}
}
]
}
}
}

34
tests/virnetdaemonmock.c Normal file
View File

@ -0,0 +1,34 @@
/*
* 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/>.
*
* Author: Erik Skultety <eskultet@redhat.com>
*/
#include <config.h>
#include "internal.h"
#include <time.h>
#define VIR_FROM_THIS VIR_FROM_NONE
time_t time(time_t *t)
{
const time_t ret = 1234567890;
if (t)
*t = ret;
return ret;
}

View File

@ -339,15 +339,17 @@ mymain(void)
EXEC_RESTART_TEST("admin-server-names", 2);
EXEC_RESTART_TEST("no-keepalive-required", 2);
EXEC_RESTART_TEST("client-ids", 1);
EXEC_RESTART_TEST("client-timestamp", 1);
EXEC_RESTART_TEST_FAIL("anon-clients", 2);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/virnetdaemonmock.so")
#else
static int
mymain(void)
{
return EXIT_AM_SKIP;
}
#endif
VIRT_TEST_MAIN(mymain);
#endif