[libvirt] [PATCH 1/9] Introduce public API for domain async job handling

Daniel P. Berrange berrange at redhat.com
Mon Mar 1 13:04:53 UTC 2010


On Fri, Feb 26, 2010 at 06:40:10PM +0100, Daniel Veillard wrote:
> On Thu, Feb 18, 2010 at 03:56:07PM +0000, Daniel P. Berrange wrote:
> > Introduce a new public API that provides a way to get progress
> > info on currently running jobs on a virDomainpPtr. APIs that
> > are initially within scope of this idea are
> > 
> >  virDomainMigrate
> >  virDomainMigrateToURI
> >  virDomainSave
> >  virDomainRestore
> >  virDomainCoreDump
> > 
> > These all take a potentially long time and benefit from monitoring.
> > The virDomainJobInfo struct allows for various pieces of information
> > to be reported
> > 
> >  - Percentage completion
> >  - Time
> >  - Overall data
> >  - Guest memory data
> >  - Guest disk/file data
> > 
> > * include/libvirt/libvirt.h.in: Add virDomainGetJobInfo
> > * python/generator.py, python/libvirt-override-api.xml,
> >   python/libvirt-override.c: Override for virDomainGetJobInfo API
> > * python/typewrappers.c, python/typewrappers.h: Introduce wrapper
> >   for unsigned long long type
> > ---
> >  include/libvirt/libvirt.h.in    |   49 +++++++++++++++++++++++++++++++++++++++
> >  python/generator.py             |    1 +
> >  python/libvirt-override-api.xml |    5 ++++
> >  python/libvirt-override.c       |   36 ++++++++++++++++++++++++++++
> >  python/typewrappers.c           |    8 ++++++
> >  python/typewrappers.h           |    1 +
> >  6 files changed, 100 insertions(+), 0 deletions(-)
> > 
> > diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
> > index 260505e..51c0844 100644
> > --- a/include/libvirt/libvirt.h.in
> > +++ b/include/libvirt/libvirt.h.in
> > @@ -1787,6 +1787,55 @@ char *virConnectBaselineCPU(virConnectPtr conn,
> >                              unsigned int ncpus,
> >                              unsigned int flags);
> >  
> > +typedef enum {
> > +    VIR_DOMAIN_JOB_NONE      = 0, /* No job is active */
> > +    VIR_DOMAIN_JOB_BOUNDED   = 1, /* Job with a finite completion time */
> > +    VIR_DOMAIN_JOB_UNBOUNDED = 2, /* Job without a finite completion time */
> > +    VIR_DOMAIN_JOB_COMPLETED = 3, /* Job has finished, but isn't cleaned up */
> > +    VIR_DOMAIN_JOB_FAILED    = 4, /* Job hit error, but isn't cleaned up */
> 
> 
>   5 disapeared ?

Opps, bad counting !

> 
> > +    VIR_DOMAIN_JOB_CANCELLED = 6, /* Job was aborted, but isn't cleaned up */
> > +} virDomainJobType;
> > +
> > +typedef struct _virDomainJobInfo virDomainJobInfo;
> > +typedef virDomainJobInfo *virDomainJobInfoPtr;
> > +struct _virDomainJobInfo {
> > +    /* One of virDomainJobType */
> > +    int type;
> > +
> > +    /* Time is measured in seconds */
> > +    unsigned long long timeElapsed;    /* Always set */
> > +    unsigned long long timeRemaining;  /* Only for VIR_DOMAIN_JOB_BOUNDED */
> > +
> > +    /* Data is measured in bytes unless otherwise specified
> > +     * and is measuring the job as a whole
> > +     *
> > +     * For VIR_DOMAIN_JOB_UNBOUNDED, dataTotal may be less
> > +     * than the final sum of dataProcessed + dataRemaining
> > +     * in the event that the hypervisor has to repeat some
> > +     * data eg due to dirtied pages during migration
> > +     *
> > +     * For VIR_DOMAIN_JOB_BOUNDED, dataTotal shall always
> > +     * equal sum of dataProcessed + dataRemaining
> > +     */
> > +    unsigned long long dataTotal;
> > +    unsigned long long dataProcessed;
> > +    unsigned long long dataRemaining;
> > +
> > +    /* As above, but only tracking guest memory progress */
> > +    unsigned long long memTotal;
> > +    unsigned long long memProcessed;
> > +    unsigned long long memRemaining;
> > +
> > +    /* As above, but only tracking guest disk file progress */
> > +    unsigned long long fileTotal;
> > +    unsigned long long fileProcessed;
> > +    unsigned long long fileRemaining;
> > +};
> 
>   I wonder if we should not somehow provide an unit for the items being
> measured. Maybe we don't want bytes in the future

The idea here is that the 'mem' and 'file' fields are always in bytes.
The 'data' field units are defined by the type of job being executed,
though effectively they're always bytes too.

> 
> > +int virDomainGetJobInfo(virDomainPtr dom,
> > +                        virDomainJobInfoPtr info);
> > +
> > +
> >  #ifdef __cplusplus
> >  }
> >  #endif
> > diff --git a/python/generator.py b/python/generator.py
> > index 24eaf50..f7625fd 100755
> > --- a/python/generator.py
> > +++ b/python/generator.py
> > @@ -271,6 +271,7 @@ skip_impl = (
> >      'virConnGetLastError',
> >      'virGetLastError',
> >      'virDomainGetInfo',
> > +    'virDomainGetJobInfo',
> >      'virNodeGetInfo',
> >      'virDomainGetUUID',
> >      'virDomainGetUUIDString',
> > diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml
> > index 76a6fd5..1260c0c 100644
> > --- a/python/libvirt-override-api.xml
> > +++ b/python/libvirt-override-api.xml
> > @@ -48,6 +48,11 @@
> >        <return type='int *' info='the list of information or None in case of error'/>
> >        <arg name='domain' type='virDomainPtr' info='a domain object'/>
> >      </function>
> > +    <function name='virDomainGetJobInfo' file='python'>
> > +      <info>Extract information about an active job being processed for a domain.</info>
> > +      <return type='int *' info='the list of information or None in case of error'/>
> > +      <arg name='domain' type='virDomainPtr' info='a domain object'/>
> > +    </function>
> >      <function name='virNodeGetInfo' file='python'>
> >        <info>Extract hardware information about the Node.</info>
> >        <return type='int *' info='the list of information or None in case of error'/>
> > diff --git a/python/libvirt-override.c b/python/libvirt-override.c
> > index 2447ad7..e27bce6 100644
> > --- a/python/libvirt-override.c
> > +++ b/python/libvirt-override.c
> > @@ -2072,6 +2072,41 @@ libvirt_virConnectBaselineCPU(PyObject *self ATTRIBUTE_UNUSED,
> >  }
> >  
> >  
> > +static PyObject *
> > +libvirt_virDomainGetJobInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
> > +    PyObject *py_retval;
> > +    int c_retval;
> > +    virDomainPtr domain;
> > +    PyObject *pyobj_domain;
> > +    virDomainJobInfo info;
> > +
> > +    if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetJobInfo", &pyobj_domain))
> > +        return(NULL);
> > +    domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
> > +
> > +    LIBVIRT_BEGIN_ALLOW_THREADS;
> > +    c_retval = virDomainGetJobInfo(domain, &info);
> > +    LIBVIRT_END_ALLOW_THREADS;
> > +    if (c_retval < 0)
> > +        return VIR_PY_NONE;
> > +    py_retval = PyList_New(12);
> > +    PyList_SetItem(py_retval, 0, libvirt_intWrap((int) info.type));
> > +    PyList_SetItem(py_retval, 1, libvirt_ulonglongWrap(info.timeElapsed));
> > +    PyList_SetItem(py_retval, 2, libvirt_ulonglongWrap(info.timeRemaining));
> > +    PyList_SetItem(py_retval, 3, libvirt_ulonglongWrap(info.dataTotal));
> > +    PyList_SetItem(py_retval, 4, libvirt_ulonglongWrap(info.dataProcessed));
> > +    PyList_SetItem(py_retval, 5, libvirt_ulonglongWrap(info.dataRemaining));
> > +    PyList_SetItem(py_retval, 6, libvirt_ulonglongWrap(info.memTotal));
> > +    PyList_SetItem(py_retval, 7, libvirt_ulonglongWrap(info.memProcessed));
> > +    PyList_SetItem(py_retval, 8, libvirt_ulonglongWrap(info.memRemaining));
> > +    PyList_SetItem(py_retval, 9, libvirt_ulonglongWrap(info.fileTotal));
> > +    PyList_SetItem(py_retval, 10, libvirt_ulonglongWrap(info.fileProcessed));
> > +    PyList_SetItem(py_retval, 11, libvirt_ulonglongWrap(info.fileRemaining));
> > +
> > +    return(py_retval);
> > +}
> > +
> > +
> >  /*******************************************
> >   * Helper functions to avoid importing modules
> >   * for every callback
> > @@ -2788,6 +2823,7 @@ static PyMethodDef libvirtMethods[] = {
> >      {(char *) "virConnectListInterfaces", libvirt_virConnectListInterfaces, METH_VARARGS, NULL},
> >      {(char *) "virConnectListDefinedInterfaces", libvirt_virConnectListDefinedInterfaces, METH_VARARGS, NULL},
> >      {(char *) "virConnectBaselineCPU", libvirt_virConnectBaselineCPU, METH_VARARGS, NULL},
> > +    {(char *) "virDomainGetJobInfo", libvirt_virDomainGetJobInfo, METH_VARARGS, NULL},
> >      {NULL, NULL, 0, NULL}
> >  };
> >  
> > diff --git a/python/typewrappers.c b/python/typewrappers.c
> > index 9ba99de..b33822c 100644
> > --- a/python/typewrappers.c
> > +++ b/python/typewrappers.c
> > @@ -49,6 +49,14 @@ libvirt_longlongWrap(long long val)
> >  }
> >  
> >  PyObject *
> > +libvirt_ulonglongWrap(unsigned long long val)
> > +{
> > +    PyObject *ret;
> > +    ret = PyLong_FromUnsignedLongLong(val);
> > +    return (ret);
> > +}
> > +
> > +PyObject *
> >  libvirt_charPtrWrap(char *str)
> >  {
> >      PyObject *ret;
> > diff --git a/python/typewrappers.h b/python/typewrappers.h
> > index 61f7249..dadcdd4 100644
> > --- a/python/typewrappers.h
> > +++ b/python/typewrappers.h
> > @@ -138,6 +138,7 @@ PyObject * libvirt_intWrap(int val);
> >  PyObject * libvirt_longWrap(long val);
> >  PyObject * libvirt_ulongWrap(unsigned long val);
> >  PyObject * libvirt_longlongWrap(long long val);
> > +PyObject * libvirt_ulonglongWrap(unsigned long long val);
> >  PyObject * libvirt_charPtrWrap(char *str);
> >  PyObject * libvirt_constcharPtrWrap(const char *str);
> >  PyObject * libvirt_charPtrConstWrap(const char *str);
> 
>   The unit is more a question, I don't see an use right now, but
> it sounds like it can make the API more flexible if we want to use
> it for "something else"
> 
>   Basically looks fine ACK,

Daniel
-- 
|: Red Hat, Engineering, London    -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org        -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list