[libvirt] [PATCH v2 REBASE] lib: provide error message in new blockjob event

Nikolay Shirokovskiy nshirokovskiy at virtuozzo.com
Thu May 3 09:27:57 UTC 2018


ping

On 19.04.2018 17:18, Nikolay Shirokovskiy wrote:
> If block job is completed with error qemu additionally
> provides error message. This patch introduces new event
> VIR_DOMAIN_EVENT_ID_BLOCK_JOB_ERROR to pass error message to client.
> 
> This error message has no semantics and should not be interpreted.
> API and RPC layer also have reserved 'code' field to pass semantics
> loaded error code value in the future.
> 
> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy at virtuozzo.com>
> 
> ---
> 
> Diff from v1 [1]:
>   - replace block job event version 3 with block job error event
>   - add code field to API/RPC to pass error code in the future
> 
> Peter, I decided not to use enum/union as this looks like to much effort to extend
> code generation for this simple case. Using typed params looks unsuitable too.
> 
> [1] https://www.redhat.com/archives/libvir-list/2017-October/msg01369.html
> 
>  examples/object-events/event-test.c | 20 ++++++++
>  include/libvirt/libvirt-domain.h    | 25 ++++++++++
>  src/conf/domain_event.c             | 92 +++++++++++++++++++++++++++++++++++++
>  src/conf/domain_event.h             | 13 ++++++
>  src/libvirt_private.syms            |  2 +
>  src/qemu/qemu_blockjob.c            | 10 +++-
>  src/qemu/qemu_blockjob.h            |  3 +-
>  src/qemu/qemu_domain.c              |  4 +-
>  src/qemu/qemu_domain.h              |  1 +
>  src/qemu/qemu_driver.c              |  9 ++--
>  src/qemu/qemu_process.c             |  1 +
>  src/remote/remote_daemon_dispatch.c | 48 +++++++++++++++++++
>  src/remote/remote_driver.c          | 34 ++++++++++++++
>  src/remote/remote_protocol.x        | 17 ++++++-
>  src/remote_protocol-structs         |  9 ++++
>  tools/virsh-domain.c                | 24 ++++++++++
>  16 files changed, 304 insertions(+), 8 deletions(-)
> 
> diff --git a/examples/object-events/event-test.c b/examples/object-events/event-test.c
> index 8499e0b..23d5a3f 100644
> --- a/examples/object-events/event-test.c
> +++ b/examples/object-events/event-test.c
> @@ -936,6 +936,25 @@ myDomainEventBlockJobCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
>  
>  
>  static int
> +myDomainEventBlockJobErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
> +                                   virDomainPtr dom,
> +                                   const char *dev,
> +                                   int type,
> +                                   unsigned int code,
> +                                   const char *message,
> +                                   void *opaque)
> +{
> +    const char *eventName = opaque;
> +
> +    printf("%s EVENT: Domain %s(%d) block job error callback '%s' disk '%s', "
> +           "type '%s' code '%u' message '%s'",
> +           __func__, virDomainGetName(dom), virDomainGetID(dom), eventName,
> +           dev, blockJobTypeToStr(type), code, NULLSTR(message));
> +    return 0;
> +}
> +
> +
> +static int
>  myDomainEventBlockThresholdCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
>                                      virDomainPtr dom,
>                                      const char *dev,
> @@ -1082,6 +1101,7 @@ struct domainEventData domainEvents[] = {
>      DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED, myDomainEventDeviceRemovalFailedCallback),
>      DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_METADATA_CHANGE, myDomainEventMetadataChangeCallback),
>      DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD, myDomainEventBlockThresholdCallback),
> +    DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_JOB_ERROR, myDomainEventBlockJobErrorCallback),
>  };
>  
>  struct storagePoolEventData {
> diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
> index 12fd340..ee55ab9 100644
> --- a/include/libvirt/libvirt-domain.h
> +++ b/include/libvirt/libvirt-domain.h
> @@ -4370,6 +4370,30 @@ typedef void (*virConnectDomainEventBlockThresholdCallback)(virConnectPtr conn,
>                                                              unsigned long long excess,
>                                                              void *opaque);
>  
> +
> +/**
> + * virConnectDomainEventBlockJobErrorCallback:
> + * @conn: connection object
> + * @dom: domain on which the event occurred
> + * @dev: name associated with the affected disk or storage backing chain
> + *       element
> + * @type: type of block job (virDomainBlockJobType)
> + * @code: always 0, reserved for future use
> + * @message: error message with no semantics, can be NULL
> + * @opaque: application specified data
> + *
> + * The callback occurs when block job is completed with error and provides
> + * error message in @message.
> + *
> + */
> +typedef void (*virConnectDomainEventBlockJobErrorCallback)(virConnectPtr conn,
> +                                                           virDomainPtr dom,
> +                                                           const char *dev,
> +                                                           int type,
> +                                                           unsigned int code,
> +                                                           const char *message,
> +                                                           void *opaque);
> +
>  /**
>   * VIR_DOMAIN_EVENT_CALLBACK:
>   *
> @@ -4412,6 +4436,7 @@ typedef enum {
>      VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED = 22, /* virConnectDomainEventDeviceRemovalFailedCallback */
>      VIR_DOMAIN_EVENT_ID_METADATA_CHANGE = 23, /* virConnectDomainEventMetadataChangeCallback */
>      VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD = 24, /* virConnectDomainEventBlockThresholdCallback */
> +    VIR_DOMAIN_EVENT_ID_BLOCK_JOB_ERROR = 25, /* virConnectDomainEventBlockJobErrorCallback */
>  
>  # ifdef VIR_ENUM_SENTINELS
>      VIR_DOMAIN_EVENT_ID_LAST
> diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
> index 9752070..54f4cf4 100644
> --- a/src/conf/domain_event.c
> +++ b/src/conf/domain_event.c
> @@ -47,6 +47,7 @@ static virClassPtr virDomainEventWatchdogClass;
>  static virClassPtr virDomainEventIOErrorClass;
>  static virClassPtr virDomainEventGraphicsClass;
>  static virClassPtr virDomainEventBlockJobClass;
> +static virClassPtr virDomainEventBlockJobErrorClass;
>  static virClassPtr virDomainEventDiskChangeClass;
>  static virClassPtr virDomainEventTrayChangeClass;
>  static virClassPtr virDomainEventBalloonChangeClass;
> @@ -69,6 +70,7 @@ static void virDomainEventWatchdogDispose(void *obj);
>  static void virDomainEventIOErrorDispose(void *obj);
>  static void virDomainEventGraphicsDispose(void *obj);
>  static void virDomainEventBlockJobDispose(void *obj);
> +static void virDomainEventBlockJobErrorDispose(void *obj);
>  static void virDomainEventDiskChangeDispose(void *obj);
>  static void virDomainEventTrayChangeDispose(void *obj);
>  static void virDomainEventBalloonChangeDispose(void *obj);
> @@ -151,6 +153,17 @@ struct _virDomainEventBlockJob {
>  typedef struct _virDomainEventBlockJob virDomainEventBlockJob;
>  typedef virDomainEventBlockJob *virDomainEventBlockJobPtr;
>  
> +struct _virDomainEventBlockJobError {
> +    virDomainEvent parent;
> +
> +    char *dev;
> +    int type;
> +    unsigned int code;
> +    char *message;
> +};
> +typedef struct _virDomainEventBlockJobError virDomainEventBlockJobError;
> +typedef virDomainEventBlockJobError *virDomainEventBlockJobErrorPtr;
> +
>  struct _virDomainEventGraphics {
>      virDomainEvent parent;
>  
> @@ -309,6 +322,8 @@ virDomainEventsOnceInit(void)
>          return -1;
>      if (!VIR_CLASS_NEW(virDomainEventBlockJob, virDomainEventClass))
>          return -1;
> +    if (!VIR_CLASS_NEW(virDomainEventBlockJobError, virDomainEventClass))
> +        return -1;
>      if (!VIR_CLASS_NEW(virDomainEventDiskChange, virDomainEventClass))
>          return -1;
>      if (!VIR_CLASS_NEW(virDomainEventTrayChange, virDomainEventClass))
> @@ -420,6 +435,16 @@ virDomainEventBlockJobDispose(void *obj)
>  }
>  
>  static void
> +virDomainEventBlockJobErrorDispose(void *obj)
> +{
> +    virDomainEventBlockJobErrorPtr event = obj;
> +    VIR_DEBUG("obj=%p", event);
> +
> +    VIR_FREE(event->dev);
> +    VIR_FREE(event->message);
> +}
> +
> +static void
>  virDomainEventDiskChangeDispose(void *obj)
>  {
>      virDomainEventDiskChangePtr event = obj;
> @@ -977,6 +1002,59 @@ virDomainEventBlockJob2NewFromDom(virDomainPtr dom,
>                                       dst, type, status);
>  }
>  
> +static virObjectEventPtr
> +virDomainEventBlockJobErrorNew(int id,
> +                               const char *name,
> +                               unsigned char *uuid,
> +                               const char *dev,
> +                               int type,
> +                               unsigned int code,
> +                               const char *message)
> +{
> +    virDomainEventBlockJobErrorPtr ev;
> +
> +    if (virDomainEventsInitialize() < 0)
> +        return NULL;
> +
> +    if (!(ev = virDomainEventNew(virDomainEventBlockJobErrorClass,
> +                                 VIR_DOMAIN_EVENT_ID_BLOCK_JOB_ERROR,
> +                                 id, name, uuid)))
> +        return NULL;
> +
> +    if (VIR_STRDUP(ev->dev, dev) < 0) {
> +        virObjectUnref(ev);
> +        return NULL;
> +    }
> +    ignore_value(VIR_STRDUP_QUIET(ev->message, message));
> +    ev->type = type;
> +    ev->code = code;
> +
> +    return (virObjectEventPtr)ev;
> +}
> +
> +virObjectEventPtr
> +virDomainEventBlockJobErrorNewFromObj(virDomainObjPtr obj,
> +                                      const char *dev,
> +                                      int type,
> +                                      unsigned int code,
> +                                      const char *message)
> +{
> +    return virDomainEventBlockJobErrorNew(obj->def->id, obj->def->name,
> +                                          obj->def->uuid, dev, type, code,
> +                                          message);
> +}
> +
> +virObjectEventPtr
> +virDomainEventBlockJobErrorNewFromDom(virDomainPtr dom,
> +                                      const char *dev,
> +                                      int type,
> +                                      unsigned int code,
> +                                      const char *message)
> +{
> +    return virDomainEventBlockJobErrorNew(dom->id, dom->name, dom->uuid,
> +                                          dev, type, code, message);
> +}
> +
>  virObjectEventPtr
>  virDomainEventControlErrorNewFromDom(virDomainPtr dom)
>  {
> @@ -1787,6 +1865,20 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
>              goto cleanup;
>          }
>  
> +    case VIR_DOMAIN_EVENT_ID_BLOCK_JOB_ERROR:
> +        {
> +            virDomainEventBlockJobErrorPtr blockJobErrorEvent;
> +
> +            blockJobErrorEvent = (virDomainEventBlockJobErrorPtr)event;
> +            ((virConnectDomainEventBlockJobErrorCallback)cb)(conn, dom,
> +                                                             blockJobErrorEvent->dev,
> +                                                             blockJobErrorEvent->type,
> +                                                             blockJobErrorEvent->code,
> +                                                             blockJobErrorEvent->message,
> +                                                             cbopaque);
> +            goto cleanup;
> +        }
> +
>      case VIR_DOMAIN_EVENT_ID_DISK_CHANGE:
>          {
>              virDomainEventDiskChangePtr diskChangeEvent;
> diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
> index 3992a29..456026c 100644
> --- a/src/conf/domain_event.h
> +++ b/src/conf/domain_event.h
> @@ -138,6 +138,19 @@ virDomainEventBlockJob2NewFromDom(virDomainPtr dom,
>                                    int status);
>  
>  virObjectEventPtr
> +virDomainEventBlockJobErrorNewFromObj(virDomainObjPtr obj,
> +                                      const char *dev,
> +                                      int type,
> +                                      unsigned int code,
> +                                      const char *message);
> +virObjectEventPtr
> +virDomainEventBlockJobErrorNewFromDom(virDomainPtr dom,
> +                                      const char *dev,
> +                                      int type,
> +                                      unsigned int code,
> +                                      const char *message);
> +
> +virObjectEventPtr
>  virDomainEventDiskChangeNewFromObj(virDomainObjPtr obj,
>                                     const char *oldSrcPath,
>                                     const char *newSrcPath,
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index b31f599..303f28c 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -589,6 +589,8 @@ virDomainEventBalloonChangeNewFromDom;
>  virDomainEventBalloonChangeNewFromObj;
>  virDomainEventBlockJob2NewFromDom;
>  virDomainEventBlockJob2NewFromObj;
> +virDomainEventBlockJobErrorNewFromDom;
> +virDomainEventBlockJobErrorNewFromObj;
>  virDomainEventBlockJobNewFromDom;
>  virDomainEventBlockJobNewFromObj;
>  virDomainEventBlockThresholdNewFromDom;
> diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
> index 617e4ee..4df4ed6 100644
> --- a/src/qemu/qemu_blockjob.c
> +++ b/src/qemu/qemu_blockjob.c
> @@ -70,7 +70,8 @@ qemuBlockJobUpdate(virQEMUDriverPtr driver,
>      if (status != -1) {
>          qemuBlockJobEventProcess(driver, vm, disk, asyncJob,
>                                   diskPriv->blockJobType,
> -                                 diskPriv->blockJobStatus);
> +                                 diskPriv->blockJobStatus,
> +                                 diskPriv->blockJobError);
>          diskPriv->blockJobStatus = -1;
>          if (error)
>              VIR_STEAL_PTR(*error, diskPriv->blockJobError);
> @@ -100,10 +101,12 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
>                           virDomainDiskDefPtr disk,
>                           qemuDomainAsyncJob asyncJob,
>                           int type,
> -                         int status)
> +                         int status,
> +                         const char *error)
>  {
>      virObjectEventPtr event = NULL;
>      virObjectEventPtr event2 = NULL;
> +    virObjectEventPtr errorEvent = NULL;
>      const char *path;
>      virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
>      virDomainDiskDefPtr persistDisk = NULL;
> @@ -123,6 +126,8 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
>      path = virDomainDiskGetSource(disk);
>      event = virDomainEventBlockJobNewFromObj(vm, path, type, status);
>      event2 = virDomainEventBlockJob2NewFromObj(vm, disk->dst, type, status);
> +    if (error)
> +        errorEvent = virDomainEventBlockJobErrorNewFromObj(vm, disk->dst, type, 0, error);
>  
>      /* If we completed a block pull or commit, then update the XML
>       * to match.  */
> @@ -213,6 +218,7 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
>  
>      qemuDomainEventQueue(driver, event);
>      qemuDomainEventQueue(driver, event2);
> +    qemuDomainEventQueue(driver, errorEvent);
>  
>      virObjectUnref(cfg);
>  }
> diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
> index e71d691..18bcaaa 100644
> --- a/src/qemu/qemu_blockjob.h
> +++ b/src/qemu/qemu_blockjob.h
> @@ -36,7 +36,8 @@ void qemuBlockJobEventProcess(virQEMUDriverPtr driver,
>                                virDomainDiskDefPtr disk,
>                                qemuDomainAsyncJob asyncJob,
>                                int type,
> -                              int status);
> +                              int status,
> +                              const char *error);
>  
>  void qemuBlockJobSyncBegin(virDomainDiskDefPtr disk);
>  void qemuBlockJobSyncEnd(virQEMUDriverPtr driver,
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index e2a8450..883652d 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -11951,12 +11951,14 @@ qemuProcessEventFree(struct qemuProcessEvent *event)
>      case QEMU_PROCESS_EVENT_GUESTPANIC:
>          qemuMonitorEventPanicInfoFree(event->data);
>          break;
> +    case QEMU_PROCESS_EVENT_MONITOR_EOF:
> +        VIR_FREE(event->error);
> +        ATTRIBUTE_FALLTHROUGH;
>      case QEMU_PROCESS_EVENT_WATCHDOG:
>      case QEMU_PROCESS_EVENT_DEVICE_DELETED:
>      case QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED:
>      case QEMU_PROCESS_EVENT_SERIAL_CHANGED:
>      case QEMU_PROCESS_EVENT_BLOCK_JOB:
> -    case QEMU_PROCESS_EVENT_MONITOR_EOF:
>          VIR_FREE(event->data);
>          break;
>      case QEMU_PROCESS_EVENT_LAST:
> diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
> index 2c27dfb..f3b262f 100644
> --- a/src/qemu/qemu_domain.h
> +++ b/src/qemu/qemu_domain.h
> @@ -456,6 +456,7 @@ struct qemuProcessEvent {
>      int action;
>      int status;
>      void *data;
> +    char *error;
>  };
>  
>  void qemuProcessEventFree(struct qemuProcessEvent *event);
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 5673d9f..cefbe52 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -4748,7 +4748,8 @@ processBlockJobEvent(virQEMUDriverPtr driver,
>                       virDomainObjPtr vm,
>                       const char *diskAlias,
>                       int type,
> -                     int status)
> +                     int status,
> +                     char *error)
>  {
>      virDomainDiskDefPtr disk;
>  
> @@ -4761,7 +4762,8 @@ processBlockJobEvent(virQEMUDriverPtr driver,
>      }
>  
>      if ((disk = qemuProcessFindDomainDiskByAlias(vm, diskAlias)))
> -        qemuBlockJobEventProcess(driver, vm, disk, QEMU_ASYNC_JOB_NONE, type, status);
> +        qemuBlockJobEventProcess(driver, vm, disk, QEMU_ASYNC_JOB_NONE,
> +                                 type, status, error);
>  
>   endjob:
>      qemuDomainObjEndJob(driver, vm);
> @@ -4846,7 +4848,8 @@ static void qemuProcessEventHandler(void *data, void *opaque)
>          processBlockJobEvent(driver, vm,
>                               processEvent->data,
>                               processEvent->action,
> -                             processEvent->status);
> +                             processEvent->status,
> +                             processEvent->error);
>          break;
>      case QEMU_PROCESS_EVENT_MONITOR_EOF:
>          processMonitorEOFEvent(driver, vm);
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 6a5262a..12b156f 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -1026,6 +1026,7 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
>          processEvent->vm = virObjectRef(vm);
>          processEvent->action = type;
>          processEvent->status = status;
> +        ignore_value(VIR_STRDUP_QUIET(processEvent->error, error));
>  
>          if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) {
>              ignore_value(virObjectUnref(vm));
> diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c
> index a8a5932..07c9dbb 100644
> --- a/src/remote/remote_daemon_dispatch.c
> +++ b/src/remote/remote_daemon_dispatch.c
> @@ -1342,6 +1342,53 @@ remoteRelayDomainEventBlockThreshold(virConnectPtr conn,
>  }
>  
>  
> +static int
> +remoteRelayDomainEventBlockJobError(virConnectPtr conn,
> +                                    virDomainPtr dom,
> +                                    const char *dev,
> +                                    int type,
> +                                    unsigned int code,
> +                                    const char *message,
> +                                    void *opaque)
> +{
> +    daemonClientEventCallbackPtr callback = opaque;
> +    remote_domain_event_block_job_error_msg msg;
> +
> +    if (callback->callbackID < 0 ||
> +        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
> +        return -1;
> +
> +    VIR_DEBUG("Relaying domain block job error event %s %d %s %i %u %s, callback %d",
> +              dom->name, dom->id, dev, type, code, NULLSTR(message),
> +              callback->callbackID);
> +
> +    memset(&msg, 0, sizeof(msg));
> +    msg.callbackID = callback->callbackID;
> +    if (VIR_STRDUP(msg.dev, dev) < 0)
> +        return -1;
> +    if (message) {
> +        if (VIR_ALLOC(msg.message) < 0 ||
> +            VIR_STRDUP(*(msg.message), message) < 0)
> +            goto error;
> +    }
> +    msg.type = type;
> +    msg.code = code;
> +    make_nonnull_domain(&msg.dom, dom);
> +
> +    remoteDispatchObjectEventSend(callback->client, remoteProgram,
> +                                  REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_ERROR,
> +                                  (xdrproc_t)xdr_remote_domain_event_block_job_error_msg,
> +                                  &msg);
> +    return 0;
> +
> + error:
> +    VIR_FREE(msg.dev);
> +    VIR_FREE(msg.message);
> +
> +    return -1;
> +}
> +
> +
>  static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
>      VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
>      VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
> @@ -1368,6 +1415,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
>      VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemovalFailed),
>      VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMetadataChange),
>      VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockThreshold),
> +    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJobError),
>  };
>  
>  verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
> diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
> index d3b588c..0d30bf3 100644
> --- a/src/remote/remote_driver.c
> +++ b/src/remote/remote_driver.c
> @@ -405,6 +405,11 @@ remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_U
>                                           virNetClientPtr client ATTRIBUTE_UNUSED,
>                                           void *evdata, void *opaque);
>  
> +static void
> +remoteDomainBuildEventBlockJobError(virNetClientProgramPtr prog,
> +                                    virNetClientPtr client,
> +                                    void *evdata, void *opaque);
> +
>  static virNetClientProgramEvent remoteEvents[] = {
>      { REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE,
>        remoteDomainBuildEventLifecycle,
> @@ -611,6 +616,10 @@ static virNetClientProgramEvent remoteEvents[] = {
>        remoteDomainBuildEventBlockThreshold,
>        sizeof(remote_domain_event_block_threshold_msg),
>        (xdrproc_t)xdr_remote_domain_event_block_threshold_msg },
> +    { REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_ERROR,
> +      remoteDomainBuildEventBlockJobError,
> +      sizeof(remote_domain_event_block_job_error_msg),
> +      (xdrproc_t)xdr_remote_domain_event_block_job_error_msg },
>  };
>  
>  static void
> @@ -5533,6 +5542,31 @@ remoteDomainBuildEventBlockThreshold(virNetClientProgramPtr prog ATTRIBUTE_UNUSE
>  }
>  
>  
> +static void
> +remoteDomainBuildEventBlockJobError(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
> +                                    virNetClientPtr client ATTRIBUTE_UNUSED,
> +                                    void *evdata, void *opaque)
> +{
> +    virConnectPtr conn = opaque;
> +    remote_domain_event_block_job_error_msg *msg = evdata;
> +    struct private_data *priv = conn->privateData;
> +    virDomainPtr dom;
> +    virObjectEventPtr event = NULL;
> +
> +    dom = get_nonnull_domain(conn, msg->dom);
> +    if (!dom)
> +        return;
> +
> +    event = virDomainEventBlockJobErrorNewFromDom(dom, msg->dev, msg->type,
> +                                                  msg->code,
> +                                                  msg->message ? *msg->message : NULL);
> +
> +    virObjectUnref(dom);
> +
> +    remoteEventQueue(priv, event, msg->callbackID);
> +}
> +
> +
>  static int
>  remoteStreamSend(virStreamPtr st,
>                   const char *data,
> diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
> index 296a087..051a773 100644
> --- a/src/remote/remote_protocol.x
> +++ b/src/remote/remote_protocol.x
> @@ -3103,6 +3103,15 @@ struct remote_domain_event_block_job_2_msg {
>      int status;
>  };
>  
> +struct remote_domain_event_block_job_error_msg {
> +    int callbackID;
> +    remote_nonnull_domain dom;
> +    remote_nonnull_string dev;
> +    int type;
> +    int code;
> +    remote_string message;
> +};
> +
>  struct remote_domain_event_block_threshold_msg {
>      int callbackID;
>      remote_nonnull_domain dom;
> @@ -6135,5 +6144,11 @@ enum remote_procedure {
>       * @priority: high
>       * @acl: storage_pool:getattr
>       */
> -    REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH = 391
> +    REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH = 391,
> +
> +    /**
> +     * @generate: none
> +     * @acl: none
> +     */
> +    REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_ERROR = 392
>  };
> diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
> index fe163db..567f307 100644
> --- a/src/remote_protocol-structs
> +++ b/src/remote_protocol-structs
> @@ -2541,6 +2541,14 @@ struct remote_domain_event_block_job_2_msg {
>          int                        type;
>          int                        status;
>  };
> +struct remote_domain_event_block_job_error_msg {
> +        int                        callbackID;
> +        remote_nonnull_domain      dom;
> +        remote_nonnull_string      dev;
> +        int                        type;
> +        int                        code;
> +        remote_string              message;
> +};
>  struct remote_domain_event_block_threshold_msg {
>          int                        callbackID;
>          remote_nonnull_domain      dom;
> @@ -3269,4 +3277,5 @@ enum remote_procedure {
>          REMOTE_PROC_DOMAIN_MANAGED_SAVE_DEFINE_XML = 389,
>          REMOTE_PROC_DOMAIN_SET_LIFECYCLE_ACTION = 390,
>          REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH = 391,
> +        REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_ERROR = 392,
>  };
> diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
> index 2b775fc..40d3c82 100644
> --- a/tools/virsh-domain.c
> +++ b/tools/virsh-domain.c
> @@ -13286,6 +13286,28 @@ virshEventBlockThresholdPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
>  }
>  
>  
> +static void
> +virshEventBlockJobErrorPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
> +                             virDomainPtr dom,
> +                             const char *dev,
> +                             int type,
> +                             unsigned int code ATTRIBUTE_UNUSED,
> +                             const char *message,
> +                             void *opaque)
> +{
> +    virBuffer buf = VIR_BUFFER_INITIALIZER;
> +
> +    virBufferAsprintf(&buf, _("event '%s' for domain %s: %s for %s, "
> +                              "error: %s\n"),
> +                      ((virshDomEventData *) opaque)->cb->name,
> +                      virDomainGetName(dom),
> +                      virshDomainBlockJobToString(type),
> +                      dev,
> +                      NULLSTR(message));
> +    virshEventPrint(opaque, &buf);
> +}
> +
> +
>  static vshEventCallback vshEventCallbacks[] = {
>      { "lifecycle",
>        VIR_DOMAIN_EVENT_CALLBACK(virshEventLifecyclePrint), },
> @@ -13335,6 +13357,8 @@ static vshEventCallback vshEventCallbacks[] = {
>        VIR_DOMAIN_EVENT_CALLBACK(virshEventMetadataChangePrint), },
>      { "block-threshold",
>        VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockThresholdPrint), },
> +    { "block-job-error",
> +      VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockJobErrorPrint), },
>  };
>  verify(VIR_DOMAIN_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks));
>  
> 




More information about the libvir-list mailing list