
Repost of http://www.redhat.com/archives/libvir-list/2010-February/msg00177.html The virsh output is now scaled to show KB/MB as needed, instead of always bytes. The public API gained extra status 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 */ VIR_DOMAIN_JOB_CANCELLED = 6, /* Job was aborted, but isn't cleaned up */ to allow to more easily detecting end of a job, once we allow for truely async usage

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 */ + 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; +}; + +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); -- 1.6.6

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 ?
+ 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
+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 -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

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 :|

The internal glue layer for the new pubic API * src/driver.h: Define internal driver API contract * src/libvirt.c, src/libvirt_public.syms: Wire up public API to internal driver API * src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_driver.c, src/phyp/phyp_driver.c, src/qemu/qemu_driver.c, src/remote/remote_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c, src/xen/xen_driver.c: Stub new entry point --- src/driver.h | 5 ++++ src/esx/esx_driver.c | 1 + src/libvirt.c | 48 +++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + src/lxc/lxc_driver.c | 1 + src/opennebula/one_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 1 + src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/xen/xen_driver.c | 1 + 14 files changed, 65 insertions(+), 0 deletions(-) diff --git a/src/driver.h b/src/driver.h index fe21ea3..8c5d97d 100644 --- a/src/driver.h +++ b/src/driver.h @@ -373,6 +373,10 @@ typedef char * unsigned int ncpus, unsigned int flags); +typedef int + (*virDrvDomainGetJobInfo)(virDomainPtr domain, + virDomainJobInfoPtr info); + /** * _virDriver: * @@ -464,6 +468,7 @@ struct _virDriver { virDrvDomainIsPersistent domainIsPersistent; virDrvCPUCompare cpuCompare; virDrvCPUBaseline cpuBaseline; + virDrvDomainGetJobInfo domainGetJobInfo; }; typedef int diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index e125a09..226a6a0 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -3404,6 +3404,7 @@ static virDriver esxDriver = { esxDomainIsPersistent, /* domainIsPersistent */ NULL, /* cpuCompare */ NULL, /* cpuBaseline */ + NULL, /* domainGetJobInfo */ }; diff --git a/src/libvirt.c b/src/libvirt.c index 0e5f4a2..46e1221 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -11147,3 +11147,51 @@ error: virDispatchError(conn); return NULL; } + + +/** + * virDomainGetJobInfo: + * @domain: a domain object + * @info: pointer to a virDomainJobInfo structure allocated by the user + * + * Extract information about progress of a background job on a domain. + * Will return an error if the domain is not active. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainGetJobInfo(virDomainPtr domain, virDomainJobInfoPtr info) +{ + virConnectPtr conn; + DEBUG("domain=%p, info=%p", domain, info); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return (-1); + } + if (info == NULL) { + virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + memset(info, 0, sizeof(virDomainJobInfo)); + + conn = domain->conn; + + if (conn->driver->domainGetJobInfo) { + int ret; + ret = conn->driver->domainGetJobInfo (domain, info); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 152aae4..6997b7b 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -354,6 +354,7 @@ LIBVIRT_0.7.7 { virDomainAttachDeviceFlags; virDomainDetachDeviceFlags; virConnectBaselineCPU; + virDomainGetJobInfo; } LIBVIRT_0.7.5; # .... define new API here using predicted next version number .... diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index f7e9c7d..2613bd5 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2451,6 +2451,7 @@ static virDriver lxcDriver = { lxcDomainIsPersistent, NULL, /* cpuCompare */ NULL, /* cpuBaseline */ + NULL, /* domainGetJobInfo */ }; static virStateDriver lxcStateDriver = { diff --git a/src/opennebula/one_driver.c b/src/opennebula/one_driver.c index 57825d5..5ffc5eb 100644 --- a/src/opennebula/one_driver.c +++ b/src/opennebula/one_driver.c @@ -786,6 +786,7 @@ static virDriver oneDriver = { NULL, /* domainIsPersistent */ NULL, /* cpuCompare */ NULL, /* cpuBaseline */ + NULL, /* domainGetJobInfo */ }; static virStateDriver oneStateDriver = { diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 68d0398..071407f 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1538,6 +1538,7 @@ static virDriver openvzDriver = { openvzDomainIsPersistent, NULL, /* cpuCompare */ NULL, /* cpuBaseline */ + NULL, /* domainGetJobInfo */ }; int openvzRegister(void) { diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 1e8ed30..3dbf16a 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -1654,6 +1654,7 @@ virDriver phypDriver = { NULL, /* domainIsPersistent */ NULL, /* cpuCompare */ NULL, /* cpuBaseline */ + NULL, /* domainGetJobInfo */ }; int diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8766ca2..a6dc4f9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -8746,6 +8746,7 @@ static virDriver qemuDriver = { qemuDomainIsPersistent, qemuCPUCompare, /* cpuCompare */ qemuCPUBaseline, /* cpuBaseline */ + NULL, /* domainGetJobInfo */ }; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 13534ce..81016fc 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -9012,6 +9012,7 @@ static virDriver remote_driver = { remoteDomainIsPersistent, /* domainIsPersistent */ remoteCPUCompare, /* cpuCompare */ remoteCPUBaseline, /* cpuBaseline */ + NULL, /* domainGetJobInfo */ }; static virNetworkDriver network_driver = { diff --git a/src/test/test_driver.c b/src/test/test_driver.c index e4720ef..e0c4f89 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5243,6 +5243,7 @@ static virDriver testDriver = { testDomainIsPersistent, /* domainIsPersistent */ NULL, /* cpuCompare */ NULL, /* cpuBaseline */ + NULL, /* domainGetJobInfo */ }; static virNetworkDriver testNetworkDriver = { diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 10268db..e2be5b3 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -1920,6 +1920,7 @@ static virDriver umlDriver = { umlDomainIsPersistent, NULL, /* cpuCompare */ NULL, /* cpuBaseline */ + NULL, /* domainGetJobInfo */ }; diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 8a9af52..b81f4d7 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -7063,6 +7063,7 @@ virDriver NAME(Driver) = { vboxDomainIsPersistent, NULL, /* cpuCompare */ NULL, /* cpuBaseline */ + NULL, /* domainGetJobInfo */ }; virNetworkDriver NAME(NetworkDriver) = { diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 700682c..3e796d3 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -1904,6 +1904,7 @@ static virDriver xenUnifiedDriver = { xenUnifiedDomainisPersistent, NULL, /* cpuCompare */ NULL, /* cpuBaseline */ + NULL, /* domainGetJobInfo */ }; /** -- 1.6.6

On Thu, Feb 18, 2010 at 03:56:08PM +0000, Daniel P. Berrange wrote:
The internal glue layer for the new pubic API
* src/driver.h: Define internal driver API contract * src/libvirt.c, src/libvirt_public.syms: Wire up public API to internal driver API * src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_driver.c, src/phyp/phyp_driver.c, src/qemu/qemu_driver.c, src/remote/remote_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c, src/xen/xen_driver.c: Stub new entry point --- src/driver.h | 5 ++++ src/esx/esx_driver.c | 1 + src/libvirt.c | 48 +++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + src/lxc/lxc_driver.c | 1 + src/opennebula/one_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 1 + src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/xen/xen_driver.c | 1 + 14 files changed, 65 insertions(+), 0 deletions(-)
diff --git a/src/driver.h b/src/driver.h index fe21ea3..8c5d97d 100644 --- a/src/driver.h +++ b/src/driver.h @@ -373,6 +373,10 @@ typedef char * unsigned int ncpus, unsigned int flags);
+typedef int + (*virDrvDomainGetJobInfo)(virDomainPtr domain, + virDomainJobInfoPtr info); + /** * _virDriver: * @@ -464,6 +468,7 @@ struct _virDriver { virDrvDomainIsPersistent domainIsPersistent; virDrvCPUCompare cpuCompare; virDrvCPUBaseline cpuBaseline; + virDrvDomainGetJobInfo domainGetJobInfo; };
typedef int diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index e125a09..226a6a0 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -3404,6 +3404,7 @@ static virDriver esxDriver = { esxDomainIsPersistent, /* domainIsPersistent */ NULL, /* cpuCompare */ NULL, /* cpuBaseline */ + NULL, /* domainGetJobInfo */ };
diff --git a/src/libvirt.c b/src/libvirt.c index 0e5f4a2..46e1221 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -11147,3 +11147,51 @@ error: virDispatchError(conn); return NULL; } + + +/** + * virDomainGetJobInfo: + * @domain: a domain object + * @info: pointer to a virDomainJobInfo structure allocated by the user + * + * Extract information about progress of a background job on a domain. + * Will return an error if the domain is not active. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainGetJobInfo(virDomainPtr domain, virDomainJobInfoPtr info) +{ + virConnectPtr conn; + DEBUG("domain=%p, info=%p", domain, info); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return (-1); + } + if (info == NULL) { + virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + memset(info, 0, sizeof(virDomainJobInfo)); + + conn = domain->conn; + + if (conn->driver->domainGetJobInfo) { + int ret; + ret = conn->driver->domainGetJobInfo (domain, info); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 152aae4..6997b7b 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -354,6 +354,7 @@ LIBVIRT_0.7.7 { virDomainAttachDeviceFlags; virDomainDetachDeviceFlags; virConnectBaselineCPU; + virDomainGetJobInfo; } LIBVIRT_0.7.5;
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

* src/remote/remote_protocol.x: Define wire protocol format for virDomainGetJobInfo API * src/remote/remote_driver.c, daemon/remote.c: Implement client and server marshalling code for virDomainGetJobInfo() * daemon/remote_dispatch_args.h, daemon/remote_dispatch_prototypes.h daemon/remote_dispatch_ret.h, daemon/remote_dispatch_table.h, src/remote/remote_protocol.c, src/remote/remote_protocol.h: Rebuild files from src/remote/remote_protocol.x --- daemon/remote.c | 44 +++++++++++++++++++++++++++++++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 ++++++ daemon/remote_dispatch_ret.h | 1 + daemon/remote_dispatch_table.h | 5 ++++ src/remote/remote_driver.c | 42 ++++++++++++++++++++++++++++++++- src/remote/remote_protocol.c | 40 +++++++++++++++++++++++++++++++ src/remote/remote_protocol.h | 26 ++++++++++++++++++++ src/remote/remote_protocol.x | 27 ++++++++++++++++++++- 9 files changed, 192 insertions(+), 2 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index eacc6f9..67d663e 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5386,6 +5386,50 @@ remoteDispatchCpuBaseline(struct qemud_server *server ATTRIBUTE_UNUSED, } ret->cpu = cpu; + + return 0; +} + + +static int +remoteDispatchDomainGetJobInfo (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, + remote_message_header *hdr ATTRIBUTE_UNUSED, + remote_error *rerr, + remote_domain_get_job_info_args *args, + remote_domain_get_job_info_ret *ret) +{ + virDomainPtr dom; + virDomainJobInfo info; + + dom = get_nonnull_domain (conn, args->dom); + if (dom == NULL) { + remoteDispatchConnError(rerr, conn); + return -1; + } + + if (virDomainGetJobInfo (dom, &info) == -1) { + virDomainFree(dom); + remoteDispatchConnError(rerr, conn); + return -1; + } + + ret->type = info.type; + ret->timeElapsed = info.timeElapsed; + ret->timeRemaining = info.timeRemaining; + ret->dataTotal = info.dataTotal; + ret->dataProcessed = info.dataProcessed; + ret->dataRemaining = info.dataRemaining; + ret->memTotal = info.memTotal; + ret->memProcessed = info.memProcessed; + ret->memRemaining = info.memRemaining; + ret->fileTotal = info.fileTotal; + ret->fileProcessed = info.fileProcessed; + ret->fileRemaining = info.fileRemaining; + + virDomainFree(dom); + return 0; } diff --git a/daemon/remote_dispatch_args.h b/daemon/remote_dispatch_args.h index 86a881e..3a40542 100644 --- a/daemon/remote_dispatch_args.h +++ b/daemon/remote_dispatch_args.h @@ -138,3 +138,4 @@ remote_domain_attach_device_flags_args val_remote_domain_attach_device_flags_args; remote_domain_detach_device_flags_args val_remote_domain_detach_device_flags_args; remote_cpu_baseline_args val_remote_cpu_baseline_args; + remote_domain_get_job_info_args val_remote_domain_get_job_info_args; diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h index be67f9a..4b8992e 100644 --- a/daemon/remote_dispatch_prototypes.h +++ b/daemon/remote_dispatch_prototypes.h @@ -194,6 +194,14 @@ static int remoteDispatchDomainGetInfo( remote_error *err, remote_domain_get_info_args *args, remote_domain_get_info_ret *ret); +static int remoteDispatchDomainGetJobInfo( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *err, + remote_domain_get_job_info_args *args, + remote_domain_get_job_info_ret *ret); static int remoteDispatchDomainGetMaxMemory( struct qemud_server *server, struct qemud_client *client, diff --git a/daemon/remote_dispatch_ret.h b/daemon/remote_dispatch_ret.h index 5c6a78f..aa74480 100644 --- a/daemon/remote_dispatch_ret.h +++ b/daemon/remote_dispatch_ret.h @@ -118,3 +118,4 @@ remote_cpu_compare_ret val_remote_cpu_compare_ret; remote_domain_memory_stats_ret val_remote_domain_memory_stats_ret; remote_cpu_baseline_ret val_remote_cpu_baseline_ret; + remote_domain_get_job_info_ret val_remote_domain_get_job_info_ret; diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h index 428057a..a1b34d4 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -817,3 +817,8 @@ .args_filter = (xdrproc_t) xdr_remote_cpu_baseline_args, .ret_filter = (xdrproc_t) xdr_remote_cpu_baseline_ret, }, +{ /* DomainGetJobInfo => 163 */ + .fn = (dispatch_fn) remoteDispatchDomainGetJobInfo, + .args_filter = (xdrproc_t) xdr_remote_domain_get_job_info_args, + .ret_filter = (xdrproc_t) xdr_remote_domain_get_job_info_ret, +}, diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 81016fc..82a6990 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -7621,6 +7621,46 @@ done: return cpu; } + +static int +remoteDomainGetJobInfo (virDomainPtr domain, virDomainJobInfoPtr info) +{ + int rv = -1; + remote_domain_get_job_info_args args; + remote_domain_get_job_info_ret ret; + struct private_data *priv = domain->conn->privateData; + + remoteDriverLock(priv); + + make_nonnull_domain (&args.dom, domain); + + memset (&ret, 0, sizeof ret); + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_JOB_INFO, + (xdrproc_t) xdr_remote_domain_get_job_info_args, (char *) &args, + (xdrproc_t) xdr_remote_domain_get_job_info_ret, (char *) &ret) == -1) + goto done; + + info->type = ret.type; + info->timeElapsed = ret.timeElapsed; + info->timeRemaining = ret.timeRemaining; + info->dataTotal = ret.dataTotal; + info->dataProcessed = ret.dataProcessed; + info->dataRemaining = ret.dataRemaining; + info->memTotal = ret.memTotal; + info->memProcessed = ret.memProcessed; + info->memRemaining = ret.memRemaining; + info->fileTotal = ret.fileTotal; + info->fileProcessed = ret.fileProcessed; + info->fileRemaining = ret.fileRemaining; + + rv = 0; + +done: + remoteDriverUnlock(priv); + return rv; +} + + /*----------------------------------------------------------------------*/ @@ -9012,7 +9052,7 @@ static virDriver remote_driver = { remoteDomainIsPersistent, /* domainIsPersistent */ remoteCPUCompare, /* cpuCompare */ remoteCPUBaseline, /* cpuBaseline */ - NULL, /* domainGetJobInfo */ + remoteDomainGetJobInfo, /* domainGetJobInfo */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 164eca5..a1f33cc 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -2960,6 +2960,46 @@ xdr_remote_cpu_baseline_ret (XDR *xdrs, remote_cpu_baseline_ret *objp) } bool_t +xdr_remote_domain_get_job_info_args (XDR *xdrs, remote_domain_get_job_info_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_domain_get_job_info_ret (XDR *xdrs, remote_domain_get_job_info_ret *objp) +{ + + if (!xdr_int (xdrs, &objp->type)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->timeElapsed)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->timeRemaining)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->dataTotal)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->dataProcessed)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->dataRemaining)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->memTotal)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->memProcessed)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->memRemaining)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->fileTotal)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->fileProcessed)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->fileRemaining)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_procedure (XDR *xdrs, remote_procedure *objp) { diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index 0344077..be2df93 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -1678,6 +1678,27 @@ struct remote_cpu_baseline_ret { remote_nonnull_string cpu; }; typedef struct remote_cpu_baseline_ret remote_cpu_baseline_ret; + +struct remote_domain_get_job_info_args { + remote_nonnull_domain dom; +}; +typedef struct remote_domain_get_job_info_args remote_domain_get_job_info_args; + +struct remote_domain_get_job_info_ret { + int type; + uint64_t timeElapsed; + uint64_t timeRemaining; + uint64_t dataTotal; + uint64_t dataProcessed; + uint64_t dataRemaining; + uint64_t memTotal; + uint64_t memProcessed; + uint64_t memRemaining; + uint64_t fileTotal; + uint64_t fileProcessed; + uint64_t fileRemaining; +}; +typedef struct remote_domain_get_job_info_ret remote_domain_get_job_info_ret; #define REMOTE_PROGRAM 0x20008086 #define REMOTE_PROTOCOL_VERSION 1 @@ -1844,6 +1865,7 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_ATTACH_DEVICE_FLAGS = 160, REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161, REMOTE_PROC_CPU_BASELINE = 162, + REMOTE_PROC_DOMAIN_GET_JOB_INFO = 163, }; typedef enum remote_procedure remote_procedure; @@ -2150,6 +2172,8 @@ extern bool_t xdr_remote_cpu_compare_args (XDR *, remote_cpu_compare_args*); extern bool_t xdr_remote_cpu_compare_ret (XDR *, remote_cpu_compare_ret*); extern bool_t xdr_remote_cpu_baseline_args (XDR *, remote_cpu_baseline_args*); extern bool_t xdr_remote_cpu_baseline_ret (XDR *, remote_cpu_baseline_ret*); +extern bool_t xdr_remote_domain_get_job_info_args (XDR *, remote_domain_get_job_info_args*); +extern bool_t xdr_remote_domain_get_job_info_ret (XDR *, remote_domain_get_job_info_ret*); extern bool_t xdr_remote_procedure (XDR *, remote_procedure*); extern bool_t xdr_remote_message_type (XDR *, remote_message_type*); extern bool_t xdr_remote_message_status (XDR *, remote_message_status*); @@ -2430,6 +2454,8 @@ extern bool_t xdr_remote_cpu_compare_args (); extern bool_t xdr_remote_cpu_compare_ret (); extern bool_t xdr_remote_cpu_baseline_args (); extern bool_t xdr_remote_cpu_baseline_ret (); +extern bool_t xdr_remote_domain_get_job_info_args (); +extern bool_t xdr_remote_domain_get_job_info_ret (); extern bool_t xdr_remote_procedure (); extern bool_t xdr_remote_message_type (); extern bool_t xdr_remote_message_status (); diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 432359d..e54c739 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1488,6 +1488,30 @@ struct remote_cpu_baseline_ret { }; +struct remote_domain_get_job_info_args { + remote_nonnull_domain dom; +}; + +struct remote_domain_get_job_info_ret { + int type; + + unsigned hyper timeElapsed; + unsigned hyper timeRemaining; + + unsigned hyper dataTotal; + unsigned hyper dataProcessed; + unsigned hyper dataRemaining; + + unsigned hyper memTotal; + unsigned hyper memProcessed; + unsigned hyper memRemaining; + + unsigned hyper fileTotal; + unsigned hyper fileProcessed; + unsigned hyper fileRemaining; +}; + + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -1672,7 +1696,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_ATTACH_DEVICE_FLAGS = 160, REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161, - REMOTE_PROC_CPU_BASELINE = 162 + REMOTE_PROC_CPU_BASELINE = 162, + REMOTE_PROC_DOMAIN_GET_JOB_INFO = 163 /* * Notice how the entries are grouped in sets of 10 ? -- 1.6.6

On Thu, Feb 18, 2010 at 03:56:09PM +0000, Daniel P. Berrange wrote:
* src/remote/remote_protocol.x: Define wire protocol format for virDomainGetJobInfo API * src/remote/remote_driver.c, daemon/remote.c: Implement client and server marshalling code for virDomainGetJobInfo() * daemon/remote_dispatch_args.h, daemon/remote_dispatch_prototypes.h daemon/remote_dispatch_ret.h, daemon/remote_dispatch_table.h, src/remote/remote_protocol.c, src/remote/remote_protocol.h: Rebuild files from src/remote/remote_protocol.x --- daemon/remote.c | 44 +++++++++++++++++++++++++++++++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 ++++++ daemon/remote_dispatch_ret.h | 1 + daemon/remote_dispatch_table.h | 5 ++++ src/remote/remote_driver.c | 42 ++++++++++++++++++++++++++++++++- src/remote/remote_protocol.c | 40 +++++++++++++++++++++++++++++++ src/remote/remote_protocol.h | 26 ++++++++++++++++++++ src/remote/remote_protocol.x | 27 ++++++++++++++++++++- 9 files changed, 192 insertions(+), 2 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c index eacc6f9..67d663e 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5386,6 +5386,50 @@ remoteDispatchCpuBaseline(struct qemud_server *server ATTRIBUTE_UNUSED, }
ret->cpu = cpu; + + return 0; +} + + +static int +remoteDispatchDomainGetJobInfo (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, + remote_message_header *hdr ATTRIBUTE_UNUSED, + remote_error *rerr, + remote_domain_get_job_info_args *args, + remote_domain_get_job_info_ret *ret) +{ + virDomainPtr dom; + virDomainJobInfo info; + + dom = get_nonnull_domain (conn, args->dom); + if (dom == NULL) { + remoteDispatchConnError(rerr, conn); + return -1; + } + + if (virDomainGetJobInfo (dom, &info) == -1) { + virDomainFree(dom); + remoteDispatchConnError(rerr, conn); + return -1; + } + + ret->type = info.type; + ret->timeElapsed = info.timeElapsed; + ret->timeRemaining = info.timeRemaining; + ret->dataTotal = info.dataTotal; + ret->dataProcessed = info.dataProcessed; + ret->dataRemaining = info.dataRemaining; + ret->memTotal = info.memTotal; + ret->memProcessed = info.memProcessed; + ret->memRemaining = info.memRemaining; + ret->fileTotal = info.fileTotal; + ret->fileProcessed = info.fileProcessed; + ret->fileRemaining = info.fileRemaining; + + virDomainFree(dom); + return 0; }
Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Introduce support for virDomainGetJobInfo in the QEMU driver. This allows for monitoring of any API that uses the 'info migrate' monitor command. ie virDomainMigrate, virDomainSave and virDomainCoreDump Unfortunately QEMU does not provide a way to monitor incoming migration so we can't wire up virDomainRestore yet. The virsh tool gets a new command 'domjobinfo' to query status * src/qemu/qemu_driver.c: Record virDomainJobInfo and start time in qemuDomainObjPrivatePtr objects. Add generic shared handler for calling 'info migrate' with all migration based APIs. * src/qemu/qemu_monitor_text.c: Fix parsing of 'info migration' reply * tools/virsh.c: add new 'domjobinfo' command to query progress --- src/qemu/qemu_driver.c | 208 +++++++++++++++++++++++++++++++++++------- src/qemu/qemu_monitor_text.c | 7 +- tools/virsh.c | 129 ++++++++++++++++++++++---- 3 files changed, 288 insertions(+), 56 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a6dc4f9..b245eb2 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -87,6 +87,8 @@ struct _qemuDomainObjPrivate { int jobActive; /* Non-zero if a job is active. Only 1 job is allowed at any time * A job includes *all* monitor commands, even those just querying * information, not merely actions */ + virDomainJobInfo jobInfo; + unsigned long long jobStart; qemuMonitorPtr mon; virDomainChrDefPtr monConfig; @@ -329,6 +331,8 @@ static int qemuDomainObjBeginJob(virDomainObjPtr obj) } } priv->jobActive = 1; + priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); return 0; } @@ -373,6 +377,8 @@ static int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver, } } priv->jobActive = 1; + priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); virDomainObjUnlock(obj); qemuDriverLock(driver); @@ -395,6 +401,8 @@ static int ATTRIBUTE_RETURN_CHECK qemuDomainObjEndJob(virDomainObjPtr obj) qemuDomainObjPrivatePtr priv = obj->privateData; priv->jobActive = 0; + priv->jobStart = 0; + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); virCondSignal(&priv->jobCond); return virDomainObjUnref(obj); @@ -3919,6 +3927,96 @@ cleanup: } +static int +qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr vm) +{ + int ret = -1; + int status; + unsigned long long memProcessed; + unsigned long long memRemaining; + unsigned long long memTotal; + qemuDomainObjPrivatePtr priv = vm->privateData; + + priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED; + + while (priv->jobInfo.type == VIR_DOMAIN_JOB_UNBOUNDED) { + /* Poll every 1/2 second for progress & to allow cancellation */ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 500 * 1000ull }; + struct timeval now; + int rc; + + qemuDomainObjEnterMonitorWithDriver(driver, vm); + rc = qemuMonitorGetMigrationStatus(priv->mon, + &status, + &memProcessed, + &memRemaining, + &memTotal); + qemuDomainObjExitMonitorWithDriver(driver, vm); + + if (rc < 0) { + priv->jobInfo.type = VIR_DOMAIN_JOB_FAILED; + goto cleanup; + } + + if (gettimeofday(&now, NULL) < 0) { + priv->jobInfo.type = VIR_DOMAIN_JOB_FAILED; + virReportSystemError(errno, "%s", + _("cannot get time of day")); + goto cleanup; + } + priv->jobInfo.timeElapsed = + ((now.tv_sec * 1000ull) + (now.tv_usec / 1000)) - + priv->jobStart; + + switch (status) { + case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE: + priv->jobInfo.type = VIR_DOMAIN_JOB_NONE; + qemuReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("Migration is not active")); + break; + + case QEMU_MONITOR_MIGRATION_STATUS_ACTIVE: + priv->jobInfo.dataTotal = memTotal; + priv->jobInfo.dataRemaining = memRemaining; + priv->jobInfo.dataProcessed = memProcessed; + + priv->jobInfo.memTotal = memTotal; + priv->jobInfo.memRemaining = memRemaining; + priv->jobInfo.memProcessed = memProcessed; + break; + + case QEMU_MONITOR_MIGRATION_STATUS_COMPLETED: + priv->jobInfo.type = VIR_DOMAIN_JOB_COMPLETED; + ret = 0; + break; + + case QEMU_MONITOR_MIGRATION_STATUS_ERROR: + priv->jobInfo.type = VIR_DOMAIN_JOB_FAILED; + qemuReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("Migration unexpectedly failed")); + break; + + case QEMU_MONITOR_MIGRATION_STATUS_CANCELLED: + priv->jobInfo.type = VIR_DOMAIN_JOB_CANCELLED; + qemuReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("Migration was cancelled by client")); + break; + } + + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + + nanosleep(&ts, NULL); + + qemuDriverLock(driver); + virDomainObjLock(vm); + } + +cleanup: + return ret; +} + + #define QEMUD_SAVE_MAGIC "LibvirtQemudSave" #define QEMUD_SAVE_VERSION 2 @@ -3967,6 +4065,7 @@ static int qemudDomainSave(virDomainPtr dom, int ret = -1; int rc; virDomainEventPtr event = NULL; + qemuDomainObjPrivatePtr priv; memset(&header, 0, sizeof(header)); memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)); @@ -3995,6 +4094,7 @@ static int qemudDomainSave(virDomainPtr dom, _("no domain with matching uuid '%s'"), uuidstr); goto cleanup; } + priv = vm->privateData; if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) goto cleanup; @@ -4005,9 +4105,11 @@ static int qemudDomainSave(virDomainPtr dom, goto endjob; } + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); + priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED; + /* Pause */ if (vm->state == VIR_DOMAIN_RUNNING) { - qemuDomainObjPrivatePtr priv = vm->privateData; header.was_running = 1; qemuDomainObjEnterMonitorWithDriver(driver, vm); if (qemuMonitorStopCPUs(priv->mon) < 0) { @@ -4061,26 +4163,29 @@ static int qemudDomainSave(virDomainPtr dom, if (header.compressed == QEMUD_SAVE_FORMAT_RAW) { const char *args[] = { "cat", NULL }; - qemuDomainObjPrivatePtr priv = vm->privateData; qemuDomainObjEnterMonitorWithDriver(driver, vm); - rc = qemuMonitorMigrateToCommand(priv->mon, 0, args, path); + rc = qemuMonitorMigrateToCommand(priv->mon, 1, args, path); qemuDomainObjExitMonitorWithDriver(driver, vm); } else { const char *prog = qemudSaveCompressionTypeToString(header.compressed); - qemuDomainObjPrivatePtr priv = vm->privateData; const char *args[] = { prog, "-c", NULL }; qemuDomainObjEnterMonitorWithDriver(driver, vm); - rc = qemuMonitorMigrateToCommand(priv->mon, 0, args, path); + rc = qemuMonitorMigrateToCommand(priv->mon, 1, args, path); qemuDomainObjExitMonitorWithDriver(driver, vm); } if (rc < 0) goto endjob; + rc = qemuDomainWaitForMigrationComplete(driver, vm); + + if (rc < 0) + goto endjob; + if (driver->securityDriver && driver->securityDriver->domainRestoreSavedStateLabel && driver->securityDriver->domainRestoreSavedStateLabel(vm, path) == -1) @@ -4103,7 +4208,7 @@ static int qemudDomainSave(virDomainPtr dom, endjob: if (vm && qemuDomainObjEndJob(vm) == 0) - vm = NULL; + vm = NULL; cleanup: if (fd != -1) @@ -4132,6 +4237,7 @@ static int qemudDomainCoreDump(virDomainPtr dom, "cat", NULL, }; + qemuDomainObjPrivatePtr priv; qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -4144,6 +4250,7 @@ static int qemudDomainCoreDump(virDomainPtr dom, _("no domain with matching uuid '%s'"), uuidstr); goto cleanup; } + priv = vm->privateData; if (qemuDomainObjBeginJob(vm) < 0) goto cleanup; @@ -4177,8 +4284,6 @@ static int qemudDomainCoreDump(virDomainPtr dom, independent of whether the stop command is issued. */ resume = (vm->state == VIR_DOMAIN_RUNNING); - qemuDomainObjPrivatePtr priv = vm->privateData; - /* Pause domain for non-live dump */ if (!(flags & VIR_DUMP_LIVE) && vm->state == VIR_DOMAIN_RUNNING) { qemuDomainObjEnterMonitor(vm); @@ -4191,9 +4296,18 @@ static int qemudDomainCoreDump(virDomainPtr dom, } qemuDomainObjEnterMonitor(vm); - ret = qemuMonitorMigrateToCommand(priv->mon, 0, args, path); + ret = qemuMonitorMigrateToCommand(priv->mon, 1, args, path); qemuDomainObjExitMonitor(vm); - paused |= (ret == 0); + + if (ret < 0) + goto endjob; + + ret = qemuDomainWaitForMigrationComplete(driver, vm); + + if (ret < 0) + goto endjob; + + paused = 1; if (driver->securityDriver && driver->securityDriver->domainRestoreSavedStateLabel && @@ -7888,8 +8002,6 @@ static int doNativeMigrate(struct qemud_driver *driver, { int ret = -1; xmlURIPtr uribits = NULL; - int status; - unsigned long long transferred, remaining, total; qemuDomainObjPrivatePtr priv = vm->privateData; /* Issue the migrate command. */ @@ -7918,29 +8030,14 @@ static int doNativeMigrate(struct qemud_driver *driver, goto cleanup; } - if (qemuMonitorMigrateToHost(priv->mon, 0, uribits->server, uribits->port) < 0) { - qemuDomainObjExitMonitorWithDriver(driver, vm); - goto cleanup; - } - - /* it is also possible that the migrate didn't fail initially, but - * rather failed later on. Check the output of "info migrate" - */ - if (qemuMonitorGetMigrationStatus(priv->mon, - &status, - &transferred, - &remaining, - &total) < 0) { + if (qemuMonitorMigrateToHost(priv->mon, 1, uribits->server, uribits->port) < 0) { qemuDomainObjExitMonitorWithDriver(driver, vm); goto cleanup; } qemuDomainObjExitMonitorWithDriver(driver, vm); - if (status != QEMU_MONITOR_MIGRATION_STATUS_COMPLETED) { - qemuReportError(VIR_ERR_OPERATION_FAILED, - "%s", _("migrate did not successfully complete")); + if (qemuDomainWaitForMigrationComplete(driver, vm) < 0) goto cleanup; - } ret = 0; @@ -8291,6 +8388,7 @@ qemudDomainMigratePerform (virDomainPtr dom, virDomainEventPtr event = NULL; int ret = -1; int paused = 0; + qemuDomainObjPrivatePtr priv; qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -8301,6 +8399,7 @@ qemudDomainMigratePerform (virDomainPtr dom, _("no domain with matching uuid '%s'"), uuidstr); goto cleanup; } + priv = vm->privateData; if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) goto cleanup; @@ -8311,8 +8410,10 @@ qemudDomainMigratePerform (virDomainPtr dom, goto endjob; } + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); + priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED; + if (!(flags & VIR_MIGRATE_LIVE) && vm->state == VIR_DOMAIN_RUNNING) { - qemuDomainObjPrivatePtr priv = vm->privateData; /* Pause domain for non-live migration */ qemuDomainObjEnterMonitorWithDriver(driver, vm); if (qemuMonitorStopCPUs(priv->mon) < 0) { @@ -8357,7 +8458,6 @@ qemudDomainMigratePerform (virDomainPtr dom, endjob: if (paused) { - qemuDomainObjPrivatePtr priv = vm->privateData; /* we got here through some sort of failure; start the domain again */ qemuDomainObjEnterMonitorWithDriver(driver, vm); if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) { @@ -8654,6 +8754,7 @@ qemuCPUCompare(virConnectPtr conn, return ret; } + static char * qemuCPUBaseline(virConnectPtr conn ATTRIBUTE_UNUSED, const char **xmlCPUs, @@ -8667,6 +8768,49 @@ qemuCPUBaseline(virConnectPtr conn ATTRIBUTE_UNUSED, return cpu; } + +static int qemuDomainGetJobInfo(virDomainPtr dom, + virDomainJobInfoPtr info) { + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + qemuDomainObjPrivatePtr priv; + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + qemuDriverUnlock(driver); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + priv = vm->privateData; + + if (virDomainObjIsActive(vm)) { + if (priv->jobActive) { + memcpy(info, &priv->jobInfo, sizeof(*info)); + } else { + memset(info, 0, sizeof(*info)); + info->type = VIR_DOMAIN_JOB_NONE; + } + } else { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + + static virDriver qemuDriver = { VIR_DRV_QEMU, "QEMU", @@ -8746,7 +8890,7 @@ static virDriver qemuDriver = { qemuDomainIsPersistent, qemuCPUCompare, /* cpuCompare */ qemuCPUBaseline, /* cpuBaseline */ - NULL, /* domainGetJobInfo */ + qemuDomainGetJobInfo, /* domainGetJobInfo */ }; diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 62ffcc6..3f27e49 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1004,18 +1004,19 @@ int qemuMonitorTextGetMigrationStatus(qemuMonitorPtr mon, goto done; tmp += strlen(MIGRATION_TRANSFER_PREFIX); - if (virStrToLong_ull(tmp, NULL, 10, transferred) < 0) { + if (virStrToLong_ull(tmp, &end, 10, transferred) < 0 || !end) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("cannot parse migration data transferred statistic %s"), tmp); goto cleanup; } *transferred *= 1024; + tmp = end; if (!(tmp = strstr(tmp, MIGRATION_REMAINING_PREFIX))) goto done; tmp += strlen(MIGRATION_REMAINING_PREFIX); - if (virStrToLong_ull(tmp, NULL, 10, remaining) < 0) { + if (virStrToLong_ull(tmp, &end, 10, remaining) < 0 || !end) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("cannot parse migration data remaining statistic %s"), tmp); goto cleanup; @@ -1026,7 +1027,7 @@ int qemuMonitorTextGetMigrationStatus(qemuMonitorPtr mon, goto done; tmp += strlen(MIGRATION_TOTAL_PREFIX); - if (virStrToLong_ull(tmp, NULL, 10, total) < 0) { + if (virStrToLong_ull(tmp, &end, 10, total) < 0 || !end) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("cannot parse migration data total statistic %s"), tmp); goto cleanup; diff --git a/tools/virsh.c b/tools/virsh.c index e1d1300..0bf03df 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -327,6 +327,28 @@ static int namesorter(const void *a, const void *b) { return strcasecmp(*sa, *sb); } +static double +prettyCapacity(unsigned long long val, + const char **unit) { + if (val < 1024) { + *unit = ""; + return (double)val; + } else if (val < (1024.0l * 1024.0l)) { + *unit = "KB"; + return (((double)val / 1024.0l)); + } else if (val < (1024.0l * 1024.0l * 1024.0l)) { + *unit = "MB"; + return ((double)val / (1024.0l * 1024.0l)); + } else if (val < (1024.0l * 1024.0l * 1024.0l * 1024.0l)) { + *unit = "GB"; + return ((double)val / (1024.0l * 1024.0l * 1024.0l)); + } else { + *unit = "TB"; + return ((double)val / (1024.0l * 1024.0l * 1024.0l * 1024.0l)); + } +} + + static virErrorPtr last_error; /* @@ -1792,6 +1814,91 @@ cmdDominfo(vshControl *ctl, const vshCmd *cmd) } /* + * "domjobinfo" command + */ +static const vshCmdInfo info_domjobinfo[] = { + {"help", gettext_noop("domain job information")}, + {"desc", gettext_noop("Returns information about jobs running on a domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domjobinfo[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + + +static int +cmdDomjobinfo(vshControl *ctl, const vshCmd *cmd) +{ + virDomainJobInfo info; + virDomainPtr dom; + int ret = TRUE, autostart; + unsigned int id; + char *str, uuid[VIR_UUID_STRING_BUFLEN]; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return FALSE; + + if (virDomainGetJobInfo(dom, &info) == 0) { + const char *unit; + double val; + + vshPrint(ctl, "%-17s ", _("Job type:")); + switch (info.type) { + case VIR_DOMAIN_JOB_BOUNDED: + vshPrint(ctl, "%-12s\n", _("Bounded")); + break; + + case VIR_DOMAIN_JOB_UNBOUNDED: + vshPrint(ctl, "%-12s\n", _("Unbounded")); + break; + + case VIR_DOMAIN_JOB_NONE: + default: + vshPrint(ctl, "%-12s\n", _("None")); + goto cleanup; + } + + vshPrint(ctl, "%-17s %-12llu ms\n", _("Time elapsed:"), info.timeElapsed); + if (info.type == VIR_DOMAIN_JOB_BOUNDED) + vshPrint(ctl, "%-17s %-12llu ms\n", _("Time remaining:"), info.timeRemaining); + if (info.dataTotal || info.dataRemaining || info.dataProcessed) { + val = prettyCapacity(info.dataProcessed, &unit); + vshPrint(ctl, "%-17s %-0.3ld %s\n", _("Data processed:"), val, unit); + val = prettyCapacity(info.dataRemaining, &unit); + vshPrint(ctl, "%-17s %-0.3ld %s\n", _("Data remaining:"), val, unit); + val = prettyCapacity(info.dataTotal, &unit); + vshPrint(ctl, "%-17s %-0.3ld %s\n", _("Data total:"), val, unit); + } + if (info.memTotal || info.memRemaining || info.memProcessed) { + val = prettyCapacity(info.memProcessed, &unit); + vshPrint(ctl, "%-17s %-0.3ld %s\n", _("Memory processed:"), val, unit); + val = prettyCapacity(info.memRemaining, &unit); + vshPrint(ctl, "%-17s %-0.3ld %s\n", _("Memory remaining:"), val, unit); + val = prettyCapacity(info.memTotal, &unit); + vshPrint(ctl, "%-17s %-0.3ld %s\n", _("Memory total:"), val, unit); + } + if (info.fileTotal || info.fileRemaining || info.fileProcessed) { + val = prettyCapacity(info.fileProcessed, &unit); + vshPrint(ctl, "%-17s %-0.3ld %s\n", _("File processed:"), val, unit); + val = prettyCapacity(info.fileRemaining, &unit); + vshPrint(ctl, "%-17s %-0.3ld %s\n", _("File remaining:"), val, unit); + val = prettyCapacity(info.fileTotal, &unit); + vshPrint(ctl, "%-17s %-0.3ld %s\n", _("File total:"), val, unit); + } + } else { + ret = FALSE; + } +cleanup: + virDomainFree(dom); + return ret; +} + +/* * "freecell" command */ static const vshCmdInfo info_freecell[] = { @@ -4453,27 +4560,6 @@ cmdPoolDiscoverSources(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED) } -static double -prettyCapacity(unsigned long long val, - const char **unit) { - if (val < 1024) { - *unit = ""; - return (double)val; - } else if (val < (1024.0l * 1024.0l)) { - *unit = "KB"; - return (((double)val / 1024.0l)); - } else if (val < (1024.0l * 1024.0l * 1024.0l)) { - *unit = "MB"; - return ((double)val / (1024.0l * 1024.0l)); - } else if (val < (1024.0l * 1024.0l * 1024.0l * 1024.0l)) { - *unit = "GB"; - return ((double)val / (1024.0l * 1024.0l * 1024.0l)); - } else { - *unit = "TB"; - return ((double)val / (1024.0l * 1024.0l * 1024.0l * 1024.0l)); - } -} - /* * "pool-info" command */ @@ -7526,6 +7612,7 @@ static const vshCmdDef commands[] = { {"domid", cmdDomid, opts_domid, info_domid}, {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid}, {"dominfo", cmdDominfo, opts_dominfo, info_dominfo}, + {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo}, {"domname", cmdDomname, opts_domname, info_domname}, {"domstate", cmdDomstate, opts_domstate, info_domstate}, {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat}, -- 1.6.6

On Thu, Feb 18, 2010 at 03:56:10PM +0000, Daniel P. Berrange wrote:
Introduce support for virDomainGetJobInfo in the QEMU driver. This allows for monitoring of any API that uses the 'info migrate' monitor command. ie virDomainMigrate, virDomainSave and virDomainCoreDump
Unfortunately QEMU does not provide a way to monitor incoming migration so we can't wire up virDomainRestore yet.
The virsh tool gets a new command 'domjobinfo' to query status
* src/qemu/qemu_driver.c: Record virDomainJobInfo and start time in qemuDomainObjPrivatePtr objects. Add generic shared handler for calling 'info migrate' with all migration based APIs. * src/qemu/qemu_monitor_text.c: Fix parsing of 'info migration' reply * tools/virsh.c: add new 'domjobinfo' command to query progress --- src/qemu/qemu_driver.c | 208 +++++++++++++++++++++++++++++++++++------- src/qemu/qemu_monitor_text.c | 7 +- tools/virsh.c | 129 ++++++++++++++++++++++---- 3 files changed, 288 insertions(+), 56 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a6dc4f9..b245eb2 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -87,6 +87,8 @@ struct _qemuDomainObjPrivate { int jobActive; /* Non-zero if a job is active. Only 1 job is allowed at any time * A job includes *all* monitor commands, even those just querying * information, not merely actions */ + virDomainJobInfo jobInfo; + unsigned long long jobStart;
qemuMonitorPtr mon; virDomainChrDefPtr monConfig; @@ -329,6 +331,8 @@ static int qemuDomainObjBeginJob(virDomainObjPtr obj) } } priv->jobActive = 1; + priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
return 0; } @@ -373,6 +377,8 @@ static int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver, } } priv->jobActive = 1; + priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
Hum, I though the time was measured in second in the job strcture, why keep a millisecond timestamp here ? Maybe seconds are too coarse in the API anyway
virDomainObjUnlock(obj); qemuDriverLock(driver); @@ -395,6 +401,8 @@ static int ATTRIBUTE_RETURN_CHECK qemuDomainObjEndJob(virDomainObjPtr obj) qemuDomainObjPrivatePtr priv = obj->privateData;
priv->jobActive = 0; + priv->jobStart = 0; + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); virCondSignal(&priv->jobCond);
return virDomainObjUnref(obj); @@ -3919,6 +3927,96 @@ cleanup: }
+static int +qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr vm) +{ + int ret = -1; + int status; + unsigned long long memProcessed; + unsigned long long memRemaining; + unsigned long long memTotal; + qemuDomainObjPrivatePtr priv = vm->privateData; + + priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED; + + while (priv->jobInfo.type == VIR_DOMAIN_JOB_UNBOUNDED) { + /* Poll every 1/2 second for progress & to allow cancellation */
that's way larger than an human perception window so from an UI perspective the user will percieve the time between the request and when it takes effect, probably not a big deal but could be refined in the future.
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 500 * 1000ull }; + struct timeval now; + int rc; + + qemuDomainObjEnterMonitorWithDriver(driver, vm);
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Fri, Feb 26, 2010 at 06:51:05PM +0100, Daniel Veillard wrote:
On Thu, Feb 18, 2010 at 03:56:10PM +0000, Daniel P. Berrange wrote:
Introduce support for virDomainGetJobInfo in the QEMU driver. This allows for monitoring of any API that uses the 'info migrate' monitor command. ie virDomainMigrate, virDomainSave and virDomainCoreDump
Unfortunately QEMU does not provide a way to monitor incoming migration so we can't wire up virDomainRestore yet.
The virsh tool gets a new command 'domjobinfo' to query status
* src/qemu/qemu_driver.c: Record virDomainJobInfo and start time in qemuDomainObjPrivatePtr objects. Add generic shared handler for calling 'info migrate' with all migration based APIs. * src/qemu/qemu_monitor_text.c: Fix parsing of 'info migration' reply * tools/virsh.c: add new 'domjobinfo' command to query progress --- src/qemu/qemu_driver.c | 208 +++++++++++++++++++++++++++++++++++------- src/qemu/qemu_monitor_text.c | 7 +- tools/virsh.c | 129 ++++++++++++++++++++++---- 3 files changed, 288 insertions(+), 56 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a6dc4f9..b245eb2 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -87,6 +87,8 @@ struct _qemuDomainObjPrivate { int jobActive; /* Non-zero if a job is active. Only 1 job is allowed at any time * A job includes *all* monitor commands, even those just querying * information, not merely actions */ + virDomainJobInfo jobInfo; + unsigned long long jobStart;
qemuMonitorPtr mon; virDomainChrDefPtr monConfig; @@ -329,6 +331,8 @@ static int qemuDomainObjBeginJob(virDomainObjPtr obj) } } priv->jobActive = 1; + priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
return 0; } @@ -373,6 +377,8 @@ static int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver, } } priv->jobActive = 1; + priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
Hum, I though the time was measured in second in the job strcture, why keep a millisecond timestamp here ? Maybe seconds are too coarse in the API anyway
Yeah, the public API comment was wrong - we were passing milliseconds out to the client app, and virsh is processing it as milliseconds.
virDomainObjUnlock(obj); qemuDriverLock(driver); @@ -395,6 +401,8 @@ static int ATTRIBUTE_RETURN_CHECK qemuDomainObjEndJob(virDomainObjPtr obj) qemuDomainObjPrivatePtr priv = obj->privateData;
priv->jobActive = 0; + priv->jobStart = 0; + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); virCondSignal(&priv->jobCond);
return virDomainObjUnref(obj); @@ -3919,6 +3927,96 @@ cleanup: }
+static int +qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr vm) +{ + int ret = -1; + int status; + unsigned long long memProcessed; + unsigned long long memRemaining; + unsigned long long memTotal; + qemuDomainObjPrivatePtr priv = vm->privateData; + + priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED; + + while (priv->jobInfo.type == VIR_DOMAIN_JOB_UNBOUNDED) { + /* Poll every 1/2 second for progress & to allow cancellation */
that's way larger than an human perception window so from an UI perspective the user will percieve the time between the request and when it takes effect, probably not a big deal but could be refined in the future.
Migration still starts immediately, we merely have a 1/2 second delay for detecting its completion. We need to improve this regardless though since migraiton is supposed to be seemless !
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 500 * 1000ull }; + struct timeval now; + int rc; + + qemuDomainObjEnterMonitorWithDriver(driver, vm);
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 :|

On Mon, Mar 01, 2010 at 01:02:32PM +0000, Daniel P. Berrange wrote:
On Fri, Feb 26, 2010 at 06:51:05PM +0100, Daniel Veillard wrote:
On Thu, Feb 18, 2010 at 03:56:10PM +0000, Daniel P. Berrange wrote:
Introduce support for virDomainGetJobInfo in the QEMU driver. This allows for monitoring of any API that uses the 'info migrate' monitor command. ie virDomainMigrate, virDomainSave and virDomainCoreDump
Unfortunately QEMU does not provide a way to monitor incoming migration so we can't wire up virDomainRestore yet.
The virsh tool gets a new command 'domjobinfo' to query status
* src/qemu/qemu_driver.c: Record virDomainJobInfo and start time in qemuDomainObjPrivatePtr objects. Add generic shared handler for calling 'info migrate' with all migration based APIs. * src/qemu/qemu_monitor_text.c: Fix parsing of 'info migration' reply * tools/virsh.c: add new 'domjobinfo' command to query progress --- src/qemu/qemu_driver.c | 208 +++++++++++++++++++++++++++++++++++------- src/qemu/qemu_monitor_text.c | 7 +- tools/virsh.c | 129 ++++++++++++++++++++++---- 3 files changed, 288 insertions(+), 56 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a6dc4f9..b245eb2 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -87,6 +87,8 @@ struct _qemuDomainObjPrivate { int jobActive; /* Non-zero if a job is active. Only 1 job is allowed at any time * A job includes *all* monitor commands, even those just querying * information, not merely actions */ + virDomainJobInfo jobInfo; + unsigned long long jobStart;
qemuMonitorPtr mon; virDomainChrDefPtr monConfig; @@ -329,6 +331,8 @@ static int qemuDomainObjBeginJob(virDomainObjPtr obj) } } priv->jobActive = 1; + priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
return 0; } @@ -373,6 +377,8 @@ static int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver, } } priv->jobActive = 1; + priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
Hum, I though the time was measured in second in the job strcture, why keep a millisecond timestamp here ? Maybe seconds are too coarse in the API anyway
Yeah, the public API comment was wrong - we were passing milliseconds out to the client app, and virsh is processing it as milliseconds.
Ah okay :-) so fix for 1/9 accordingly, and well after all my comment about units in the API was kind of right ... Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

The new virDomainAbortJob() method provides a way for a second thread to abort an ongoing job run by another thread. This extends to any API with which the virDomainGetJobInfo() API is intended to work. Cancellation is not guarenteed, rather best effort on part of the hypervisor and not required to be implmented. * include/libvirt/libvirt.h.in: Define virDomainAbortJob() --- include/libvirt/libvirt.h.in | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 51c0844..25f10c8 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1834,6 +1834,7 @@ struct _virDomainJobInfo { int virDomainGetJobInfo(virDomainPtr dom, virDomainJobInfoPtr info); +int virDomainAbortJob(virDomainPtr dom); #ifdef __cplusplus -- 1.6.6

On Thu, Feb 18, 2010 at 03:56:11PM +0000, Daniel P. Berrange wrote:
The new virDomainAbortJob() method provides a way for a second thread to abort an ongoing job run by another thread. This extends to any API with which the virDomainGetJobInfo() API is intended to work. Cancellation is not guarenteed, rather best effort on part of the hypervisor and not required to be implmented.
* include/libvirt/libvirt.h.in: Define virDomainAbortJob() --- include/libvirt/libvirt.h.in | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 51c0844..25f10c8 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1834,6 +1834,7 @@ struct _virDomainJobInfo {
int virDomainGetJobInfo(virDomainPtr dom, virDomainJobInfoPtr info); +int virDomainAbortJob(virDomainPtr dom);
I would feel a bit better if we could add a flags there for future extensions, like POSIX kill() ended up with many different semantics we may have to refine at some point. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

This provides the internal glue for the driver API * src/driver.h: Internal API contract * src/libvirt.c, src/libvirt_public.syms: Connect public API to driver API * src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_driver.c, src/phyp/phyp_driver.c, src/qemu/qemu_driver.c, src/remote/remote_driver.c, src/test/test_driver.c src/uml/uml_driver.c, src/vbox/vbox_tmpl.c, src/xen/xen_driver.c: Stub out entry points --- src/driver.h | 4 +++ src/esx/esx_driver.c | 1 + src/libvirt.c | 47 +++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + src/lxc/lxc_driver.c | 1 + src/opennebula/one_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 1 + src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/xen/xen_driver.c | 1 + 14 files changed, 63 insertions(+), 0 deletions(-) diff --git a/src/driver.h b/src/driver.h index 8c5d97d..7b7dfea 100644 --- a/src/driver.h +++ b/src/driver.h @@ -377,6 +377,9 @@ typedef int (*virDrvDomainGetJobInfo)(virDomainPtr domain, virDomainJobInfoPtr info); +typedef int + (*virDrvDomainAbortJob)(virDomainPtr domain); + /** * _virDriver: * @@ -469,6 +472,7 @@ struct _virDriver { virDrvCPUCompare cpuCompare; virDrvCPUBaseline cpuBaseline; virDrvDomainGetJobInfo domainGetJobInfo; + virDrvDomainAbortJob domainAbortJob; }; typedef int diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 226a6a0..fc2e68c 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -3405,6 +3405,7 @@ static virDriver esxDriver = { NULL, /* cpuCompare */ NULL, /* cpuBaseline */ NULL, /* domainGetJobInfo */ + NULL, /* domainAbortJob */ }; diff --git a/src/libvirt.c b/src/libvirt.c index 46e1221..20bf3a9 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -11195,3 +11195,50 @@ error: virDispatchError(domain->conn); return -1; } + + +/** + * virDomainAbortJob: + * @domain: a domain object + * + * Requests that the current background job be aborted at the + * soonest opportunity. This will block until the job has + * either completed, or aborted. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainAbortJob(virDomainPtr domain) +{ + virConnectPtr conn; + + DEBUG("domain=%p", domain); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return (-1); + } + + conn = domain->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + if (conn->driver->domainAbortJob) { + int ret; + ret = conn->driver->domainAbortJob(domain); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 6997b7b..64e7505 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -355,6 +355,7 @@ LIBVIRT_0.7.7 { virDomainDetachDeviceFlags; virConnectBaselineCPU; virDomainGetJobInfo; + virDomainAbortJob; } LIBVIRT_0.7.5; # .... define new API here using predicted next version number .... diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 2613bd5..35c8659 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2452,6 +2452,7 @@ static virDriver lxcDriver = { NULL, /* cpuCompare */ NULL, /* cpuBaseline */ NULL, /* domainGetJobInfo */ + NULL, /* domainAbortJob */ }; static virStateDriver lxcStateDriver = { diff --git a/src/opennebula/one_driver.c b/src/opennebula/one_driver.c index 5ffc5eb..9fc0ada 100644 --- a/src/opennebula/one_driver.c +++ b/src/opennebula/one_driver.c @@ -787,6 +787,7 @@ static virDriver oneDriver = { NULL, /* cpuCompare */ NULL, /* cpuBaseline */ NULL, /* domainGetJobInfo */ + NULL, /* domainAbortJob */ }; static virStateDriver oneStateDriver = { diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 071407f..dcf4999 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1539,6 +1539,7 @@ static virDriver openvzDriver = { NULL, /* cpuCompare */ NULL, /* cpuBaseline */ NULL, /* domainGetJobInfo */ + NULL, /* domainAbortJob */ }; int openvzRegister(void) { diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 3dbf16a..8ed8f54 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -1655,6 +1655,7 @@ virDriver phypDriver = { NULL, /* cpuCompare */ NULL, /* cpuBaseline */ NULL, /* domainGetJobInfo */ + NULL, /* domainAbortJob */ }; int diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b245eb2..7641fd7 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -8891,6 +8891,7 @@ static virDriver qemuDriver = { qemuCPUCompare, /* cpuCompare */ qemuCPUBaseline, /* cpuBaseline */ qemuDomainGetJobInfo, /* domainGetJobInfo */ + NULL, /* domainFinishJob */ }; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 82a6990..82a82f4 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -9053,6 +9053,7 @@ static virDriver remote_driver = { remoteCPUCompare, /* cpuCompare */ remoteCPUBaseline, /* cpuBaseline */ remoteDomainGetJobInfo, /* domainGetJobInfo */ + NULL, /* domainFinishJob */ }; static virNetworkDriver network_driver = { diff --git a/src/test/test_driver.c b/src/test/test_driver.c index e0c4f89..5807288 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5244,6 +5244,7 @@ static virDriver testDriver = { NULL, /* cpuCompare */ NULL, /* cpuBaseline */ NULL, /* domainGetJobInfo */ + NULL, /* domainAbortJob */ }; static virNetworkDriver testNetworkDriver = { diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index e2be5b3..bbea429 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -1921,6 +1921,7 @@ static virDriver umlDriver = { NULL, /* cpuCompare */ NULL, /* cpuBaseline */ NULL, /* domainGetJobInfo */ + NULL, /* domainAbortJob */ }; diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index b81f4d7..41e5d3a 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -7064,6 +7064,7 @@ virDriver NAME(Driver) = { NULL, /* cpuCompare */ NULL, /* cpuBaseline */ NULL, /* domainGetJobInfo */ + NULL, /* domainAbortJob */ }; virNetworkDriver NAME(NetworkDriver) = { diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 3e796d3..0eb3927 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -1905,6 +1905,7 @@ static virDriver xenUnifiedDriver = { NULL, /* cpuCompare */ NULL, /* cpuBaseline */ NULL, /* domainGetJobInfo */ + NULL, /* domainAbortJob */ }; /** -- 1.6.6

On Thu, Feb 18, 2010 at 03:56:12PM +0000, Daniel P. Berrange wrote:
This provides the internal glue for the driver API
* src/driver.h: Internal API contract * src/libvirt.c, src/libvirt_public.syms: Connect public API to driver API * src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_driver.c, src/phyp/phyp_driver.c, src/qemu/qemu_driver.c, src/remote/remote_driver.c, src/test/test_driver.c src/uml/uml_driver.c, src/vbox/vbox_tmpl.c, src/xen/xen_driver.c: Stub out entry points --- src/driver.h | 4 +++ src/esx/esx_driver.c | 1 + src/libvirt.c | 47 +++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + src/lxc/lxc_driver.c | 1 + src/opennebula/one_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 1 + src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/xen/xen_driver.c | 1 + 14 files changed, 63 insertions(+), 0 deletions(-)
diff --git a/src/driver.h b/src/driver.h index 8c5d97d..7b7dfea 100644 --- a/src/driver.h +++ b/src/driver.h @@ -377,6 +377,9 @@ typedef int (*virDrvDomainGetJobInfo)(virDomainPtr domain, virDomainJobInfoPtr info);
+typedef int + (*virDrvDomainAbortJob)(virDomainPtr domain); + /** * _virDriver: * @@ -469,6 +472,7 @@ struct _virDriver { virDrvCPUCompare cpuCompare; virDrvCPUBaseline cpuBaseline; virDrvDomainGetJobInfo domainGetJobInfo; + virDrvDomainAbortJob domainAbortJob; };
typedef int diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 226a6a0..fc2e68c 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -3405,6 +3405,7 @@ static virDriver esxDriver = { NULL, /* cpuCompare */ NULL, /* cpuBaseline */ NULL, /* domainGetJobInfo */ + NULL, /* domainAbortJob */ };
diff --git a/src/libvirt.c b/src/libvirt.c index 46e1221..20bf3a9 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -11195,3 +11195,50 @@ error: virDispatchError(domain->conn); return -1; } + + +/** + * virDomainAbortJob: + * @domain: a domain object + * + * Requests that the current background job be aborted at the + * soonest opportunity. This will block until the job has + * either completed, or aborted. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainAbortJob(virDomainPtr domain) +{ + virConnectPtr conn; + + DEBUG("domain=%p", domain); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return (-1); + } + + conn = domain->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + if (conn->driver->domainAbortJob) { + int ret; + ret = conn->driver->domainAbortJob(domain); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 6997b7b..64e7505 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -355,6 +355,7 @@ LIBVIRT_0.7.7 { virDomainDetachDeviceFlags; virConnectBaselineCPU; virDomainGetJobInfo; + virDomainAbortJob; } LIBVIRT_0.7.5;
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

This defines the wire protocol for the new API * src/remote/remote_protocol.x: Wire protocol definition * src/remote/remote_driver.c,daemon/remote.c: Client and server side implementation * daemon/remote_dispatch_args.h, daemon/remote_dispatch_prototypes.h, daemon/remote_dispatch_table.h, src/remote/remote_protocol.c, src/remote/remote_protocol.h: Re-generate from remote_protocol.x --- daemon/remote.c | 29 +++++++++++++++++++++++++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 ++++++++ daemon/remote_dispatch_table.h | 5 +++++ src/remote/remote_driver.c | 26 +++++++++++++++++++++++++- src/remote/remote_protocol.c | 9 +++++++++ src/remote/remote_protocol.h | 8 ++++++++ src/remote/remote_protocol.x | 8 +++++++- 8 files changed, 92 insertions(+), 2 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 67d663e..d4713b2 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5434,6 +5434,35 @@ remoteDispatchDomainGetJobInfo (struct qemud_server *server ATTRIBUTE_UNUSED, } +static int +remoteDispatchDomainAbortJob (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, + remote_message_header *hdr ATTRIBUTE_UNUSED, + remote_error *rerr, + remote_domain_abort_job_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virDomainPtr dom; + + dom = get_nonnull_domain (conn, args->dom); + if (dom == NULL) { + remoteDispatchConnError(rerr, conn); + return -1; + } + + if (virDomainAbortJob (dom) == -1) { + virDomainFree(dom); + remoteDispatchConnError(rerr, conn); + return -1; + } + + virDomainFree(dom); + + return 0; +} + + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/daemon/remote_dispatch_args.h b/daemon/remote_dispatch_args.h index 3a40542..f97155b 100644 --- a/daemon/remote_dispatch_args.h +++ b/daemon/remote_dispatch_args.h @@ -139,3 +139,4 @@ remote_domain_detach_device_flags_args val_remote_domain_detach_device_flags_args; remote_cpu_baseline_args val_remote_cpu_baseline_args; remote_domain_get_job_info_args val_remote_domain_get_job_info_args; + remote_domain_abort_job_args val_remote_domain_abort_job_args; diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h index 4b8992e..b81c8c3 100644 --- a/daemon/remote_dispatch_prototypes.h +++ b/daemon/remote_dispatch_prototypes.h @@ -66,6 +66,14 @@ static int remoteDispatchCpuCompare( remote_error *err, remote_cpu_compare_args *args, remote_cpu_compare_ret *ret); +static int remoteDispatchDomainAbortJob( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *err, + remote_domain_abort_job_args *args, + void *ret); static int remoteDispatchDomainAttachDevice( struct qemud_server *server, struct qemud_client *client, diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h index a1b34d4..5ad6bff 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -822,3 +822,8 @@ .args_filter = (xdrproc_t) xdr_remote_domain_get_job_info_args, .ret_filter = (xdrproc_t) xdr_remote_domain_get_job_info_ret, }, +{ /* DomainAbortJob => 164 */ + .fn = (dispatch_fn) remoteDispatchDomainAbortJob, + .args_filter = (xdrproc_t) xdr_remote_domain_abort_job_args, + .ret_filter = (xdrproc_t) xdr_void, +}, diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 82a82f4..a12f964 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -7661,6 +7661,30 @@ done: } +static int +remoteDomainAbortJob (virDomainPtr domain) +{ + int rv = -1; + remote_domain_abort_job_args args; + struct private_data *priv = domain->conn->privateData; + + remoteDriverLock(priv); + + make_nonnull_domain (&args.dom, domain); + + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_ABORT_JOB, + (xdrproc_t) xdr_remote_domain_abort_job_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + goto done; + + rv = 0; + +done: + remoteDriverUnlock(priv); + return rv; +} + + /*----------------------------------------------------------------------*/ @@ -9053,7 +9077,7 @@ static virDriver remote_driver = { remoteCPUCompare, /* cpuCompare */ remoteCPUBaseline, /* cpuBaseline */ remoteDomainGetJobInfo, /* domainGetJobInfo */ - NULL, /* domainFinishJob */ + remoteDomainAbortJob, /* domainFinishJob */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index a1f33cc..701acab 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -3000,6 +3000,15 @@ xdr_remote_domain_get_job_info_ret (XDR *xdrs, remote_domain_get_job_info_ret *o } bool_t +xdr_remote_domain_abort_job_args (XDR *xdrs, remote_domain_abort_job_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_procedure (XDR *xdrs, remote_procedure *objp) { diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index be2df93..e06d73f 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -1699,6 +1699,11 @@ struct remote_domain_get_job_info_ret { uint64_t fileRemaining; }; typedef struct remote_domain_get_job_info_ret remote_domain_get_job_info_ret; + +struct remote_domain_abort_job_args { + remote_nonnull_domain dom; +}; +typedef struct remote_domain_abort_job_args remote_domain_abort_job_args; #define REMOTE_PROGRAM 0x20008086 #define REMOTE_PROTOCOL_VERSION 1 @@ -1866,6 +1871,7 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161, REMOTE_PROC_CPU_BASELINE = 162, REMOTE_PROC_DOMAIN_GET_JOB_INFO = 163, + REMOTE_PROC_DOMAIN_ABORT_JOB = 164, }; typedef enum remote_procedure remote_procedure; @@ -2174,6 +2180,7 @@ extern bool_t xdr_remote_cpu_baseline_args (XDR *, remote_cpu_baseline_args*); extern bool_t xdr_remote_cpu_baseline_ret (XDR *, remote_cpu_baseline_ret*); extern bool_t xdr_remote_domain_get_job_info_args (XDR *, remote_domain_get_job_info_args*); extern bool_t xdr_remote_domain_get_job_info_ret (XDR *, remote_domain_get_job_info_ret*); +extern bool_t xdr_remote_domain_abort_job_args (XDR *, remote_domain_abort_job_args*); extern bool_t xdr_remote_procedure (XDR *, remote_procedure*); extern bool_t xdr_remote_message_type (XDR *, remote_message_type*); extern bool_t xdr_remote_message_status (XDR *, remote_message_status*); @@ -2456,6 +2463,7 @@ extern bool_t xdr_remote_cpu_baseline_args (); extern bool_t xdr_remote_cpu_baseline_ret (); extern bool_t xdr_remote_domain_get_job_info_args (); extern bool_t xdr_remote_domain_get_job_info_ret (); +extern bool_t xdr_remote_domain_abort_job_args (); extern bool_t xdr_remote_procedure (); extern bool_t xdr_remote_message_type (); extern bool_t xdr_remote_message_status (); diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index e54c739..5e33da5 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1512,6 +1512,11 @@ struct remote_domain_get_job_info_ret { }; +struct remote_domain_abort_job_args { + remote_nonnull_domain dom; +}; + + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -1697,7 +1702,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161, REMOTE_PROC_CPU_BASELINE = 162, - REMOTE_PROC_DOMAIN_GET_JOB_INFO = 163 + REMOTE_PROC_DOMAIN_GET_JOB_INFO = 163, + REMOTE_PROC_DOMAIN_ABORT_JOB = 164 /* * Notice how the entries are grouped in sets of 10 ? -- 1.6.6

On Thu, Feb 18, 2010 at 03:56:13PM +0000, Daniel P. Berrange wrote:
This defines the wire protocol for the new API
* src/remote/remote_protocol.x: Wire protocol definition * src/remote/remote_driver.c,daemon/remote.c: Client and server side implementation * daemon/remote_dispatch_args.h, daemon/remote_dispatch_prototypes.h, daemon/remote_dispatch_table.h, src/remote/remote_protocol.c, src/remote/remote_protocol.h: Re-generate from remote_protocol.x --- daemon/remote.c | 29 +++++++++++++++++++++++++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 ++++++++ daemon/remote_dispatch_table.h | 5 +++++ src/remote/remote_driver.c | 26 +++++++++++++++++++++++++- src/remote/remote_protocol.c | 9 +++++++++ src/remote/remote_protocol.h | 8 ++++++++ src/remote/remote_protocol.x | 8 +++++++- 8 files changed, 92 insertions(+), 2 deletions(-)
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

This supports cancellation of jobs for the QEMU driver against the virDomainMigrate, virDomainSave and virDomainCoreDump APIs. It is not yet supported for the virDomainRestore API, although it is desirable. * src/qemu/qemu_driver.c: Issue 'migrate_cancel' command if virDomainAbortJob is issued during a migration operation * tools/virsh.c: Add a domjobabort command --- src/qemu/qemu_driver.c | 66 +++++++++++++++++++++++++++++++++++++++++++++--- tools/virsh.c | 37 +++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 7641fd7..5e787ce 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -84,9 +84,10 @@ typedef struct _qemuDomainObjPrivate qemuDomainObjPrivate; typedef qemuDomainObjPrivate *qemuDomainObjPrivatePtr; struct _qemuDomainObjPrivate { virCond jobCond; /* Use in conjunction with main virDomainObjPtr lock */ - int jobActive; /* Non-zero if a job is active. Only 1 job is allowed at any time - * A job includes *all* monitor commands, even those just querying - * information, not merely actions */ + unsigned int jobActive : 1; /* Non-zero if a job is active. Only 1 job is allowed at any time + * A job includes *all* monitor commands, even those just querying + * information, not merely actions */ + unsigned int jobCancel : 1; /* Non-zero if a cancel request from client has arrived */ virDomainJobInfo jobInfo; unsigned long long jobStart; @@ -331,6 +332,7 @@ static int qemuDomainObjBeginJob(virDomainObjPtr obj) } } priv->jobActive = 1; + priv->jobCancel = 0; priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); @@ -377,6 +379,7 @@ static int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver, } } priv->jobActive = 1; + priv->jobCancel = 0; priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); @@ -401,6 +404,7 @@ static int ATTRIBUTE_RETURN_CHECK qemuDomainObjEndJob(virDomainObjPtr obj) qemuDomainObjPrivatePtr priv = obj->privateData; priv->jobActive = 0; + priv->jobCancel = 0; priv->jobStart = 0; memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); virCondSignal(&priv->jobCond); @@ -3945,6 +3949,17 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr struct timeval now; int rc; + if (priv->jobCancel) { + priv->jobCancel = 0; + VIR_DEBUG0("Cancelling migration at client request"); + qemuDomainObjEnterMonitorWithDriver(driver, vm); + rc = qemuMonitorMigrateCancel(priv->mon); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (rc < 0) { + VIR_WARN0("Unable to cancel migration"); + } + } + qemuDomainObjEnterMonitorWithDriver(driver, vm); rc = qemuMonitorGetMigrationStatus(priv->mon, &status, @@ -8811,6 +8826,49 @@ cleanup: } +static int qemuDomainAbortJob(virDomainPtr dom) { + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + qemuDomainObjPrivatePtr priv; + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + qemuDriverUnlock(driver); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + priv = vm->privateData; + + if (virDomainObjIsActive(vm)) { + if (priv->jobActive) { + VIR_DEBUG("Requesting cancellation of job on vm %s", vm->def->name); + priv->jobCancel = 1; + } else { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("no job is active on the domain")); + goto cleanup; + } + } else { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + + static virDriver qemuDriver = { VIR_DRV_QEMU, "QEMU", @@ -8891,7 +8949,7 @@ static virDriver qemuDriver = { qemuCPUCompare, /* cpuCompare */ qemuCPUBaseline, /* cpuBaseline */ qemuDomainGetJobInfo, /* domainGetJobInfo */ - NULL, /* domainFinishJob */ + qemuDomainAbortJob, /* domainAbortJob */ }; diff --git a/tools/virsh.c b/tools/virsh.c index 0bf03df..cea92fd 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -1899,6 +1899,42 @@ cleanup: } /* + * "domjobabort" command + */ +static const vshCmdInfo info_domjobabort[] = { + {"help", gettext_noop("abort active domain job")}, + {"desc", gettext_noop("Aborts the currently running domain job")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domjobabort[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdDomjobabort(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int ret = TRUE; + unsigned int id; + char *str, uuid[VIR_UUID_STRING_BUFLEN]; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return FALSE; + + if (virDomainAbortJob(dom) < 0) + ret = FALSE; + +cleanup: + virDomainFree(dom); + return ret; +} + +/* * "freecell" command */ static const vshCmdInfo info_freecell[] = { @@ -7613,6 +7649,7 @@ static const vshCmdDef commands[] = { {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid}, {"dominfo", cmdDominfo, opts_dominfo, info_dominfo}, {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo}, + {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort}, {"domname", cmdDomname, opts_domname, info_domname}, {"domstate", cmdDomstate, opts_domstate, info_domstate}, {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat}, -- 1.6.6

On Thu, Feb 18, 2010 at 03:56:14PM +0000, Daniel P. Berrange wrote:
This supports cancellation of jobs for the QEMU driver against the virDomainMigrate, virDomainSave and virDomainCoreDump APIs. It is not yet supported for the virDomainRestore API, although it is desirable.
* src/qemu/qemu_driver.c: Issue 'migrate_cancel' command if virDomainAbortJob is issued during a migration operation * tools/virsh.c: Add a domjobabort command [...] - int jobActive; /* Non-zero if a job is active. Only 1 job is allowed at any time - * A job includes *all* monitor commands, even those just querying - * information, not merely actions */ + unsigned int jobActive : 1; /* Non-zero if a job is active. Only 1 job is allowed at any time
ah a cleanup too
+ * A job includes *all* monitor commands, even those just querying + * information, not merely actions */ + unsigned int jobCancel : 1; /* Non-zero if a cancel request from client has arrived */ virDomainJobInfo jobInfo; unsigned long long jobStart;
@@ -331,6 +332,7 @@ static int qemuDomainObjBeginJob(virDomainObjPtr obj) } } priv->jobActive = 1; + priv->jobCancel = 0; priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
@@ -377,6 +379,7 @@ static int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver, } } priv->jobActive = 1; + priv->jobCancel = 0; priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
@@ -401,6 +404,7 @@ static int ATTRIBUTE_RETURN_CHECK qemuDomainObjEndJob(virDomainObjPtr obj) qemuDomainObjPrivatePtr priv = obj->privateData;
priv->jobActive = 0; + priv->jobCancel = 0; priv->jobStart = 0; memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); virCondSignal(&priv->jobCond); @@ -3945,6 +3949,17 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr struct timeval now; int rc;
+ if (priv->jobCancel) { + priv->jobCancel = 0; + VIR_DEBUG0("Cancelling migration at client request"); + qemuDomainObjEnterMonitorWithDriver(driver, vm); + rc = qemuMonitorMigrateCancel(priv->mon); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (rc < 0) { + VIR_WARN0("Unable to cancel migration"); + } + } + qemuDomainObjEnterMonitorWithDriver(driver, vm); rc = qemuMonitorGetMigrationStatus(priv->mon, &status, @@ -8811,6 +8826,49 @@ cleanup: }
+static int qemuDomainAbortJob(virDomainPtr dom) { + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + qemuDomainObjPrivatePtr priv; + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + qemuDriverUnlock(driver); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + priv = vm->privateData; + + if (virDomainObjIsActive(vm)) { + if (priv->jobActive) { + VIR_DEBUG("Requesting cancellation of job on vm %s", vm->def->name); + priv->jobCancel = 1; + } else { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("no job is active on the domain")); + goto cleanup; + } + } else { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + + static virDriver qemuDriver = { VIR_DRV_QEMU, "QEMU", @@ -8891,7 +8949,7 @@ static virDriver qemuDriver = { qemuCPUCompare, /* cpuCompare */ qemuCPUBaseline, /* cpuBaseline */ qemuDomainGetJobInfo, /* domainGetJobInfo */ - NULL, /* domainFinishJob */ + qemuDomainAbortJob, /* domainAbortJob */ };
diff --git a/tools/virsh.c b/tools/virsh.c index 0bf03df..cea92fd 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -1899,6 +1899,42 @@ cleanup: }
/* + * "domjobabort" command + */ +static const vshCmdInfo info_domjobabort[] = { + {"help", gettext_noop("abort active domain job")}, + {"desc", gettext_noop("Aborts the currently running domain job")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domjobabort[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdDomjobabort(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int ret = TRUE; + unsigned int id; + char *str, uuid[VIR_UUID_STRING_BUFLEN]; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return FALSE; + + if (virDomainAbortJob(dom) < 0) + ret = FALSE; + +cleanup: + virDomainFree(dom); + return ret; +} + +/* * "freecell" command */ static const vshCmdInfo info_freecell[] = { @@ -7613,6 +7649,7 @@ static const vshCmdDef commands[] = { {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid}, {"dominfo", cmdDominfo, opts_dominfo, info_dominfo}, {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo}, + {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort}, {"domname", cmdDomname, opts_domname, info_domname}, {"domstate", cmdDomstate, opts_domstate, info_domstate}, {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat},
ACK, but virsh.pod need to be extended with the new entry points, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

When a VM save attempt failed, the VM would be left in a paused state. It is neccessary to resume CPU execution upon failure if it was running originally * src/qemu/qemu_driver.c: Resume CPUs upon save failure --- src/qemu/qemu_driver.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 5e787ce..0a39745 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4221,6 +4221,16 @@ static int qemudDomainSave(virDomainPtr dom, } endjob: + if (ret != 0 && header.was_running) { + qemuDomainObjEnterMonitorWithDriver(driver, vm); + rc = qemuMonitorStartCPUs(priv->mon, dom->conn); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (rc < 0) + VIR_WARN0("Unable to resume guest CPUs after save failure"); + else + vm->state = VIR_DOMAIN_RUNNING; + } + if (vm && qemuDomainObjEndJob(vm) == 0) vm = NULL; -- 1.6.6

On Thu, Feb 18, 2010 at 03:56:15PM +0000, Daniel P. Berrange wrote:
When a VM save attempt failed, the VM would be left in a paused state. It is neccessary to resume CPU execution upon failure if it was running originally
* src/qemu/qemu_driver.c: Resume CPUs upon save failure --- src/qemu/qemu_driver.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 5e787ce..0a39745 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4221,6 +4221,16 @@ static int qemudDomainSave(virDomainPtr dom, }
endjob: + if (ret != 0 && header.was_running) { + qemuDomainObjEnterMonitorWithDriver(driver, vm); + rc = qemuMonitorStartCPUs(priv->mon, dom->conn); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (rc < 0) + VIR_WARN0("Unable to resume guest CPUs after save failure"); + else + vm->state = VIR_DOMAIN_RUNNING; + } + if (vm && qemuDomainObjEndJob(vm) == 0) vm = NULL;
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/
participants (2)
-
Daniel P. Berrange
-
Daniel Veillard