Emit an event whenever a secret value changes
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
daemon/remote.c | 29 ++++++++++++++++++++
include/libvirt/libvirt-secret.h | 1 +
src/conf/secret_event.c | 59 ++++++++++++++++++++++++++++++++++++++++
src/conf/secret_event.h | 4 +++
src/libvirt_private.syms | 1 +
src/remote/remote_driver.c | 30 ++++++++++++++++++++
src/remote/remote_protocol.x | 13 ++++++++-
src/secret/secret_driver.c | 6 ++++
tools/virsh-secret.c | 35 ++++++++++++++++++++++++
9 files changed, 177 insertions(+), 1 deletion(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index 3a7ee9e..f2b9b9a 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -1528,8 +1528,37 @@ remoteRelaySecretEventLifecycle(virConnectPtr conn,
return 0;
}
+static int
+remoteRelaySecretEventValueChanged(virConnectPtr conn,
+ virSecretPtr secret,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_secret_event_value_changed_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelaySecretEventCheckACL(callback->client, conn, secret))
+ return -1;
+
+ VIR_DEBUG("Relaying node secret value changed callback %d",
+ callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_secret(&data.secret, secret);
+ data.callbackID = callback->callbackID;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_SECRET_EVENT_VALUE_CHANGED,
+ (xdrproc_t)xdr_remote_secret_event_value_changed_msg,
+ &data);
+
+ return 0;
+}
+
static virConnectSecretEventGenericCallback secretEventCallbacks[] = {
VIR_SECRET_EVENT_CALLBACK(remoteRelaySecretEventLifecycle),
+ VIR_SECRET_EVENT_CALLBACK(remoteRelaySecretEventValueChanged),
};
verify(ARRAY_CARDINALITY(secretEventCallbacks) == VIR_SECRET_EVENT_ID_LAST);
diff --git a/include/libvirt/libvirt-secret.h b/include/libvirt/libvirt-secret.h
index 1bbbf3f..5df0b8f 100644
--- a/include/libvirt/libvirt-secret.h
+++ b/include/libvirt/libvirt-secret.h
@@ -127,6 +127,7 @@ int virSecretFree (virSecretPtr
secret);
*/
typedef enum {
VIR_SECRET_EVENT_ID_LIFECYCLE = 0, /* virConnectSecretEventLifecycleCallback */
+ VIR_SECRET_EVENT_ID_VALUE_CHANGED = 1, /* virConnectSecretEventGenericCallback */
# ifdef VIR_ENUM_SENTINELS
VIR_SECRET_EVENT_ID_LAST
diff --git a/src/conf/secret_event.c b/src/conf/secret_event.c
index 9d578f0..c130909 100644
--- a/src/conf/secret_event.c
+++ b/src/conf/secret_event.c
@@ -48,10 +48,19 @@ struct _virSecretEventLifecycle {
typedef struct _virSecretEventLifecycle virSecretEventLifecycle;
typedef virSecretEventLifecycle *virSecretEventLifecyclePtr;
+struct _virSecretEventValueChanged {
+ virSecretEvent parent;
+ bool dummy;
+};
+typedef struct _virSecretEventValueChanged virSecretEventValueChanged;
+typedef virSecretEventValueChanged *virSecretEventValueChangedPtr;
+
static virClassPtr virSecretEventClass;
static virClassPtr virSecretEventLifecycleClass;
+static virClassPtr virSecretEventValueChangedClass;
static void virSecretEventDispose(void *obj);
static void virSecretEventLifecycleDispose(void *obj);
+static void virSecretEventValueChangedDispose(void *obj);
static int
virSecretEventsOnceInit(void)
@@ -68,6 +77,12 @@ virSecretEventsOnceInit(void)
sizeof(virSecretEventLifecycle),
virSecretEventLifecycleDispose)))
return -1;
+ if (!(virSecretEventValueChangedClass =
+ virClassNew(virSecretEventClass,
+ "virSecretEventValueChanged",
+ sizeof(virSecretEventValueChanged),
+ virSecretEventValueChangedDispose)))
+ return -1;
return 0;
}
@@ -90,6 +105,14 @@ virSecretEventLifecycleDispose(void *obj)
static void
+virSecretEventValueChangedDispose(void *obj)
+{
+ virSecretEventValueChangedPtr event = obj;
+ VIR_DEBUG("obj=%p", event);
+}
+
+
+static void
virSecretEventDispatchDefaultFunc(virConnectPtr conn,
virObjectEventPtr event,
virConnectObjectEventGenericCallback cb,
@@ -116,6 +139,13 @@ virSecretEventDispatchDefaultFunc(virConnectPtr conn,
goto cleanup;
}
+ case VIR_SECRET_EVENT_ID_VALUE_CHANGED:
+ {
+ ((virConnectSecretEventGenericCallback)cb)(conn, secret,
+ cbopaque);
+ goto cleanup;
+ }
+
case VIR_SECRET_EVENT_ID_LAST:
break;
}
@@ -250,3 +280,32 @@ virSecretEventLifecycleNew(const unsigned char *uuid,
return (virObjectEventPtr)event;
}
+
+
+/**
+ * virSecretEventValueChangedNew:
+ * @uuid: UUID of the secret object the event describes
+ *
+ * Create a new secret lifecycle event.
+ */
+virObjectEventPtr
+virSecretEventValueChangedNew(const unsigned char *uuid,
+ int usage_type,
+ const char *usage_id)
+{
+ virSecretEventValueChangedPtr event;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ if (virSecretEventsInitialize() < 0)
+ return NULL;
+
+ virUUIDFormat(uuid, uuidstr);
+ VIR_DEBUG("Event %s %d %s", uuidstr, usage_type, usage_id);
+ if (!(event = virObjectEventNew(virSecretEventValueChangedClass,
+ virSecretEventDispatchDefaultFunc,
+ VIR_SECRET_EVENT_ID_VALUE_CHANGED,
+ usage_type, usage_id, uuid, uuidstr)))
+ return NULL;
+
+ return (virObjectEventPtr)event;
+}
diff --git a/src/conf/secret_event.h b/src/conf/secret_event.h
index 4649d94..5fd52f3 100644
--- a/src/conf/secret_event.h
+++ b/src/conf/secret_event.h
@@ -57,5 +57,9 @@ virSecretEventLifecycleNew(const unsigned char *uuid,
const char *usage_id,
int type,
int detail);
+virObjectEventPtr
+virSecretEventValueChangedNew(const unsigned char *uuid,
+ int usage_type,
+ const char *usage_id);
#endif
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 2c78ed6..3d98780 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -842,6 +842,7 @@ virSecretUsageTypeToString;
# conf/secret_event.h
virSecretEventLifecycleNew;
virSecretEventStateRegisterID;
+virSecretEventValueChangedNew;
# conf/snapshot_conf.h
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index e689316..59d74a2 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -391,6 +391,11 @@ remoteSecretBuildEventLifecycle(virNetClientProgramPtr prog
ATTRIBUTE_UNUSED,
void *evdata, void *opaque);
static void
+remoteSecretBuildEventValueChanged(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque);
+
+static void
remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque);
@@ -593,6 +598,10 @@ static virNetClientProgramEvent remoteEvents[] = {
remoteSecretBuildEventLifecycle,
sizeof(remote_secret_event_lifecycle_msg),
(xdrproc_t)xdr_remote_secret_event_lifecycle_msg },
+ { REMOTE_PROC_SECRET_EVENT_VALUE_CHANGED,
+ remoteSecretBuildEventValueChanged,
+ sizeof(remote_secret_event_value_changed_msg),
+ (xdrproc_t)xdr_remote_secret_event_value_changed_msg },
};
static void
@@ -5517,6 +5526,27 @@ remoteSecretBuildEventLifecycle(virNetClientProgramPtr prog
ATTRIBUTE_UNUSED,
}
static void
+remoteSecretBuildEventValueChanged(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_secret_event_value_changed_msg *msg = evdata;
+ virSecretPtr secret;
+ virObjectEventPtr event = NULL;
+
+ secret = get_nonnull_secret(conn, msg->secret);
+ if (!secret)
+ return;
+
+ event = virSecretEventValueChangedNew(secret->uuid, secret->usageType,
secret->usageID);
+ virObjectUnref(secret);
+
+ remoteEventQueue(priv, event, msg->callbackID);
+}
+
+static void
remoteDomainBuildQemuMonitorEvent(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque)
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index ce4c4ef..6445685 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3381,6 +3381,11 @@ struct remote_secret_event_lifecycle_msg {
int detail;
};
+struct remote_secret_event_value_changed_msg {
+ int callbackID;
+ remote_nonnull_secret secret;
+};
+
/*----- Protocol. -----*/
/* Define the program number, protocol version and procedure numbers here. */
@@ -6007,6 +6012,12 @@ enum remote_procedure {
* @generate: both
* @acl: none
*/
- REMOTE_PROC_SECRET_EVENT_LIFECYCLE = 382
+ REMOTE_PROC_SECRET_EVENT_LIFECYCLE = 382,
+
+ /**
+ * @generate: both
+ * @acl: none
+ */
+ REMOTE_PROC_SECRET_EVENT_VALUE_CHANGED = 383
};
diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c
index 0e3d97e..2a371b6 100644
--- a/src/secret/secret_driver.c
+++ b/src/secret/secret_driver.c
@@ -327,6 +327,7 @@ secretSetValue(virSecretPtr obj,
int ret = -1;
virSecretObjPtr secret;
virSecretDefPtr def;
+ virObjectEventPtr event = NULL;
virCheckFlags(0, -1);
@@ -343,10 +344,15 @@ secretSetValue(virSecretPtr obj,
if (virSecretObjSetValue(secret, value, value_size) < 0)
goto cleanup;
+ event = virSecretEventValueChangedNew(def->uuid,
+ def->usage_type,
+ def->usage_id);
ret = 0;
cleanup:
virSecretObjEndAPI(&secret);
+ if (event)
+ virObjectEventStateQueue(driver->secretEventState, event);
return ret;
}
diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c
index f7197f4..cd788b6 100644
--- a/tools/virsh-secret.c
+++ b/tools/virsh-secret.c
@@ -614,9 +614,44 @@ vshEventLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
vshEventDone(data->ctl);
}
+static void
+vshEventGenericPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virSecretPtr secret,
+ void *opaque)
+{
+ virshSecretEventData *data = opaque;
+ char uuid[VIR_UUID_STRING_BUFLEN];
+
+ if (!data->loop && data->count)
+ return;
+
+ virSecretGetUUIDString(secret, uuid);
+
+ if (data->timestamp) {
+ char timestamp[VIR_TIME_STRING_BUFLEN];
+
+ if (virTimeStringNowRaw(timestamp) < 0)
+ timestamp[0] = '\0';
+
+ vshPrint(data->ctl, _("%s: event '%s' for secret %s\n"),
+ timestamp,
+ data->cb->name,
+ uuid);
+ } else {
+ vshPrint(data->ctl, _("event '%s' for secret %s\n"),
+ data->cb->name,
+ uuid);
+ }
+
+ data->count++;
+ if (!data->loop)
+ vshEventDone(data->ctl);
+}
+
static vshEventCallback vshEventCallbacks[] = {
{ "lifecycle",
VIR_SECRET_EVENT_CALLBACK(vshEventLifecyclePrint), },
+ { "value-changed", vshEventGenericPrint, },
};
static const vshCmdInfo info_secret_event[] = {
--
2.9.3