mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
Merge
This commit is contained in:
commit
8250e0c500
284 files changed
+8817
-8898
No files matched your search
+237
-137
@@ -42,7 +42,7 @@ static PyObject *pyxc_domain_dumpcore(PyObject *self,
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom;
|
||||
uint32_t dom;
|
||||
char *corefile;
|
||||
|
||||
static char *kwd_list[] = { "dom", "corefile", NULL };
|
||||
@@ -77,29 +77,73 @@ static PyObject *pyxc_domain_create(PyObject *self,
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom = 0;
|
||||
int ret;
|
||||
u32 ssidref = 0x0;
|
||||
uint32_t dom = 0;
|
||||
int ret, i;
|
||||
uint32_t ssidref = 0;
|
||||
PyObject *pyhandle = NULL;
|
||||
xen_domain_handle_t handle = {
|
||||
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
|
||||
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef };
|
||||
|
||||
static char *kwd_list[] = { "dom", "ssidref", NULL };
|
||||
static char *kwd_list[] = { "dom", "ssidref", "handle", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list,
|
||||
&dom, &ssidref))
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iiO", kwd_list,
|
||||
&dom, &ssidref, &pyhandle))
|
||||
return NULL;
|
||||
|
||||
if ( (ret = xc_domain_create(xc->xc_handle, ssidref, &dom)) < 0 )
|
||||
if ( pyhandle != NULL )
|
||||
{
|
||||
if ( !PyList_Check(pyhandle) ||
|
||||
(PyList_Size(pyhandle) != sizeof(xen_domain_handle_t)) )
|
||||
{
|
||||
out_exception:
|
||||
errno = EINVAL;
|
||||
PyErr_SetFromErrno(xc_error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( i = 0; i < sizeof(xen_domain_handle_t); i++ )
|
||||
{
|
||||
PyObject *p = PyList_GetItem(pyhandle, i);
|
||||
if ( !PyInt_Check(p) )
|
||||
goto out_exception;
|
||||
handle[i] = (uint8_t)PyInt_AsLong(p);
|
||||
}
|
||||
}
|
||||
|
||||
if ( (ret = xc_domain_create(xc->xc_handle, ssidref, handle, &dom)) < 0 )
|
||||
return PyErr_SetFromErrno(xc_error);
|
||||
|
||||
return PyInt_FromLong(dom);
|
||||
}
|
||||
|
||||
static PyObject *pyxc_domain_max_vcpus(PyObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
uint32_t dom, max;
|
||||
|
||||
static char *kwd_list[] = { "dom", "max", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list, &dom, &max) )
|
||||
return NULL;
|
||||
|
||||
if ( xc_domain_max_vcpus(xc->xc_handle, dom, max) != 0 )
|
||||
return PyErr_SetFromErrno(xc_error);
|
||||
|
||||
Py_INCREF(zero);
|
||||
return zero;
|
||||
}
|
||||
|
||||
static PyObject *pyxc_domain_pause(PyObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom;
|
||||
uint32_t dom;
|
||||
|
||||
static char *kwd_list[] = { "dom", NULL };
|
||||
|
||||
@@ -119,7 +163,7 @@ static PyObject *pyxc_domain_unpause(PyObject *self,
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom;
|
||||
uint32_t dom;
|
||||
|
||||
static char *kwd_list[] = { "dom", NULL };
|
||||
|
||||
@@ -139,7 +183,7 @@ static PyObject *pyxc_domain_destroy(PyObject *self,
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom;
|
||||
uint32_t dom;
|
||||
|
||||
static char *kwd_list[] = { "dom", NULL };
|
||||
|
||||
@@ -159,17 +203,25 @@ static PyObject *pyxc_domain_pincpu(PyObject *self,
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom;
|
||||
int vcpu = 0;
|
||||
cpumap_t cpumap = 0xFFFFFFFF;
|
||||
uint32_t dom;
|
||||
int vcpu = 0, i;
|
||||
cpumap_t cpumap = ~0ULL;
|
||||
PyObject *cpulist = NULL;
|
||||
|
||||
static char *kwd_list[] = { "dom", "vcpu", "cpumap", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|ii", kwd_list,
|
||||
&dom, &vcpu, &cpumap) )
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|iO", kwd_list,
|
||||
&dom, &vcpu, &cpulist) )
|
||||
return NULL;
|
||||
|
||||
if ( xc_domain_pincpu(xc->xc_handle, dom, vcpu, &cpumap) != 0 )
|
||||
if ( (cpulist != NULL) && PyList_Check(cpulist) )
|
||||
{
|
||||
cpumap = 0ULL;
|
||||
for ( i = 0; i < PyList_Size(cpulist); i++ )
|
||||
cpumap |= (cpumap_t)1 << PyInt_AsLong(PyList_GetItem(cpulist, i));
|
||||
}
|
||||
|
||||
if ( xc_domain_pincpu(xc->xc_handle, dom, vcpu, cpumap) != 0 )
|
||||
return PyErr_SetFromErrno(xc_error);
|
||||
|
||||
Py_INCREF(zero);
|
||||
@@ -182,7 +234,7 @@ static PyObject *pyxc_domain_setcpuweight(PyObject *self,
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom;
|
||||
uint32_t dom;
|
||||
float cpuweight = 1;
|
||||
|
||||
static char *kwd_list[] = { "dom", "cpuweight", NULL };
|
||||
@@ -198,14 +250,55 @@ static PyObject *pyxc_domain_setcpuweight(PyObject *self,
|
||||
return zero;
|
||||
}
|
||||
|
||||
static PyObject *pyxc_domain_sethandle(PyObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
int i;
|
||||
uint32_t dom;
|
||||
PyObject *pyhandle;
|
||||
xen_domain_handle_t handle;
|
||||
|
||||
static char *kwd_list[] = { "dom", "handle", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iO", kwd_list,
|
||||
&dom, &pyhandle) )
|
||||
return NULL;
|
||||
|
||||
if ( !PyList_Check(pyhandle) ||
|
||||
(PyList_Size(pyhandle) != sizeof(xen_domain_handle_t)) )
|
||||
{
|
||||
out_exception:
|
||||
errno = EINVAL;
|
||||
PyErr_SetFromErrno(xc_error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( i = 0; i < sizeof(xen_domain_handle_t); i++ )
|
||||
{
|
||||
PyObject *p = PyList_GetItem(pyhandle, i);
|
||||
if ( !PyInt_Check(p) )
|
||||
goto out_exception;
|
||||
handle[i] = (uint8_t)PyInt_AsLong(p);
|
||||
}
|
||||
|
||||
if ( xc_domain_sethandle(xc->xc_handle, dom, handle) < 0 )
|
||||
return PyErr_SetFromErrno(xc_error);
|
||||
|
||||
Py_INCREF(zero);
|
||||
return zero;
|
||||
}
|
||||
|
||||
static PyObject *pyxc_domain_getinfo(PyObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
PyObject *list, *vcpu_list, *cpumap_list, *info_dict;
|
||||
PyObject *list, *info_dict;
|
||||
|
||||
u32 first_dom = 0;
|
||||
uint32_t first_dom = 0;
|
||||
int max_doms = 1024, nr_doms, i, j;
|
||||
xc_dominfo_t *info;
|
||||
|
||||
@@ -229,19 +322,14 @@ static PyObject *pyxc_domain_getinfo(PyObject *self,
|
||||
list = PyList_New(nr_doms);
|
||||
for ( i = 0 ; i < nr_doms; i++ )
|
||||
{
|
||||
vcpu_list = PyList_New(MAX_VIRT_CPUS);
|
||||
cpumap_list = PyList_New(MAX_VIRT_CPUS);
|
||||
for ( j = 0; j < MAX_VIRT_CPUS; j++ ) {
|
||||
PyList_SetItem( vcpu_list, j,
|
||||
Py_BuildValue("i", info[i].vcpu_to_cpu[j]));
|
||||
PyList_SetItem( cpumap_list, j,
|
||||
Py_BuildValue("i", info[i].cpumap[j]));
|
||||
}
|
||||
|
||||
info_dict = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i"
|
||||
PyObject *pyhandle = PyList_New(sizeof(xen_domain_handle_t));
|
||||
for ( j = 0; j < sizeof(xen_domain_handle_t); j++ )
|
||||
PyList_SetItem(pyhandle, j, PyInt_FromLong(info[i].handle[j]));
|
||||
info_dict = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i"
|
||||
",s:l,s:L,s:l,s:i,s:i}",
|
||||
"dom", info[i].domid,
|
||||
"vcpus", info[i].vcpus,
|
||||
"online_vcpus", info[i].nr_online_vcpus,
|
||||
"max_vcpu_id", info[i].max_vcpu_id,
|
||||
"dying", info[i].dying,
|
||||
"crashed", info[i].crashed,
|
||||
"shutdown", info[i].shutdown,
|
||||
@@ -253,10 +341,8 @@ static PyObject *pyxc_domain_getinfo(PyObject *self,
|
||||
"maxmem_kb", info[i].max_memkb,
|
||||
"ssidref", info[i].ssidref,
|
||||
"shutdown_reason", info[i].shutdown_reason);
|
||||
PyDict_SetItemString( info_dict, "vcpu_to_cpu", vcpu_list );
|
||||
PyDict_SetItemString( info_dict, "cpumap", cpumap_list );
|
||||
PyList_SetItem( list, i, info_dict);
|
||||
|
||||
PyDict_SetItemString(info_dict, "handle", pyhandle);
|
||||
PyList_SetItem(list, i, info_dict);
|
||||
}
|
||||
|
||||
free(info);
|
||||
@@ -264,15 +350,57 @@ static PyObject *pyxc_domain_getinfo(PyObject *self,
|
||||
return list;
|
||||
}
|
||||
|
||||
static PyObject *pyxc_vcpu_getinfo(PyObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
PyObject *info_dict, *cpulist;
|
||||
|
||||
uint32_t dom, vcpu = 0;
|
||||
xc_vcpuinfo_t info;
|
||||
int rc, i;
|
||||
cpumap_t cpumap;
|
||||
|
||||
static char *kwd_list[] = { "dom", "vcpu", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
|
||||
&dom, &vcpu) )
|
||||
return NULL;
|
||||
|
||||
rc = xc_domain_get_vcpu_info(xc->xc_handle, dom, vcpu, &info);
|
||||
if ( rc < 0 )
|
||||
return PyErr_SetFromErrno(xc_error);
|
||||
|
||||
info_dict = Py_BuildValue("{s:i,s:i,s:i,s:L,s:i}",
|
||||
"online", info.online,
|
||||
"blocked", info.blocked,
|
||||
"running", info.running,
|
||||
"cpu_time", info.cpu_time,
|
||||
"cpu", info.cpu);
|
||||
|
||||
cpumap = info.cpumap;
|
||||
cpulist = PyList_New(0);
|
||||
for ( i = 0; cpumap != 0; i++ )
|
||||
{
|
||||
if ( cpumap & 1 )
|
||||
PyList_Append(cpulist, PyInt_FromLong(i));
|
||||
cpumap >>= 1;
|
||||
}
|
||||
PyDict_SetItemString(info_dict, "cpumap", cpulist);
|
||||
|
||||
return info_dict;
|
||||
}
|
||||
|
||||
static PyObject *pyxc_linux_build(PyObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom;
|
||||
uint32_t dom;
|
||||
char *image, *ramdisk = NULL, *cmdline = "";
|
||||
int flags = 0, vcpus = 1;
|
||||
int flags = 0;
|
||||
int store_evtchn, console_evtchn;
|
||||
unsigned long store_mfn = 0;
|
||||
unsigned long console_mfn = 0;
|
||||
@@ -280,19 +408,17 @@ static PyObject *pyxc_linux_build(PyObject *self,
|
||||
static char *kwd_list[] = { "dom", "store_evtchn",
|
||||
"console_evtchn", "image",
|
||||
/* optional */
|
||||
"ramdisk", "cmdline", "flags",
|
||||
"vcpus", NULL };
|
||||
"ramdisk", "cmdline", "flags", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiis|ssii", kwd_list,
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiis|ssi", kwd_list,
|
||||
&dom, &store_evtchn,
|
||||
&console_evtchn, &image,
|
||||
/* optional */
|
||||
&ramdisk, &cmdline, &flags,
|
||||
&vcpus) )
|
||||
&ramdisk, &cmdline, &flags) )
|
||||
return NULL;
|
||||
|
||||
if ( xc_linux_build(xc->xc_handle, dom, image,
|
||||
ramdisk, cmdline, flags, vcpus,
|
||||
ramdisk, cmdline, flags,
|
||||
store_evtchn, &store_mfn,
|
||||
console_evtchn, &console_mfn) != 0 )
|
||||
return PyErr_SetFromErrno(xc_error);
|
||||
@@ -303,28 +429,28 @@ static PyObject *pyxc_linux_build(PyObject *self,
|
||||
}
|
||||
|
||||
static PyObject *pyxc_vmx_build(PyObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom;
|
||||
uint32_t dom;
|
||||
char *image;
|
||||
int control_evtchn, store_evtchn;
|
||||
int flags = 0, vcpus = 1;
|
||||
int control_evtchn, store_evtchn;
|
||||
int vcpus = 1;
|
||||
int memsize;
|
||||
unsigned long store_mfn = 0;
|
||||
|
||||
static char *kwd_list[] = { "dom", "control_evtchn", "store_evtchn",
|
||||
"memsize", "image", "flags", "vcpus", NULL };
|
||||
"memsize", "image", "vcpus", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiisii", kwd_list,
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiisi", kwd_list,
|
||||
&dom, &control_evtchn, &store_evtchn,
|
||||
&memsize, &image, &flags, &vcpus) )
|
||||
&memsize, &image, &vcpus) )
|
||||
return NULL;
|
||||
|
||||
if ( xc_vmx_build(xc->xc_handle, dom, memsize, image, control_evtchn,
|
||||
flags, vcpus, store_evtchn, &store_mfn) != 0 )
|
||||
vcpus, store_evtchn, &store_mfn) != 0 )
|
||||
return PyErr_SetFromErrno(xc_error);
|
||||
|
||||
return Py_BuildValue("{s:i}", "store_mfn", store_mfn);
|
||||
@@ -373,10 +499,10 @@ static PyObject *pyxc_bvtsched_domain_set(PyObject *self,
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom;
|
||||
u32 mcuadv;
|
||||
uint32_t dom;
|
||||
uint32_t mcuadv;
|
||||
int warpback;
|
||||
s32 warpvalue;
|
||||
int32_t warpvalue;
|
||||
long long warpl;
|
||||
long long warpu;
|
||||
|
||||
@@ -401,10 +527,10 @@ static PyObject *pyxc_bvtsched_domain_get(PyObject *self,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
u32 dom;
|
||||
u32 mcuadv;
|
||||
uint32_t dom;
|
||||
uint32_t mcuadv;
|
||||
int warpback;
|
||||
s32 warpvalue;
|
||||
int32_t warpvalue;
|
||||
long long warpl;
|
||||
long long warpu;
|
||||
|
||||
@@ -432,7 +558,7 @@ static PyObject *pyxc_evtchn_alloc_unbound(PyObject *self,
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom, remote_dom;
|
||||
uint32_t dom, remote_dom;
|
||||
int port;
|
||||
|
||||
static char *kwd_list[] = { "dom", "remote_dom", NULL };
|
||||
@@ -454,7 +580,7 @@ static PyObject *pyxc_evtchn_status(PyObject *self,
|
||||
XcObject *xc = (XcObject *)self;
|
||||
PyObject *dict;
|
||||
|
||||
u32 dom = DOMID_SELF;
|
||||
uint32_t dom = DOMID_SELF;
|
||||
int port, ret;
|
||||
xc_evtchn_status_t status;
|
||||
|
||||
@@ -507,7 +633,7 @@ static PyObject *pyxc_physdev_pci_access_modify(PyObject *self,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
u32 dom;
|
||||
uint32_t dom;
|
||||
int bus, dev, func, enable, ret;
|
||||
|
||||
static char *kwd_list[] = { "dom", "bus", "dev", "func", "enable", NULL };
|
||||
@@ -631,13 +757,13 @@ static PyObject *pyxc_xeninfo(PyObject *self,
|
||||
|
||||
|
||||
static PyObject *pyxc_sedf_domain_set(PyObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
u32 domid;
|
||||
u64 period, slice, latency;
|
||||
u16 extratime, weight;
|
||||
uint32_t domid;
|
||||
uint64_t period, slice, latency;
|
||||
uint16_t extratime, weight;
|
||||
static char *kwd_list[] = { "dom", "period", "slice",
|
||||
"latency", "extratime", "weight",NULL };
|
||||
|
||||
@@ -654,13 +780,13 @@ static PyObject *pyxc_sedf_domain_set(PyObject *self,
|
||||
}
|
||||
|
||||
static PyObject *pyxc_sedf_domain_get(PyObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
u32 domid;
|
||||
u64 period, slice,latency;
|
||||
u16 weight, extratime;
|
||||
uint32_t domid;
|
||||
uint64_t period, slice,latency;
|
||||
uint16_t weight, extratime;
|
||||
|
||||
static char *kwd_list[] = { "dom", NULL };
|
||||
|
||||
@@ -671,34 +797,13 @@ static PyObject *pyxc_sedf_domain_get(PyObject *self,
|
||||
&slice,&latency,&extratime,&weight) )
|
||||
return PyErr_SetFromErrno(xc_error);
|
||||
|
||||
return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i}",
|
||||
return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i,s:i}",
|
||||
"domain", domid,
|
||||
"period", period,
|
||||
"slice", slice,
|
||||
"latency", latency,
|
||||
"extratime", extratime);
|
||||
}
|
||||
|
||||
static PyObject *pyxc_shadow_control(PyObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom;
|
||||
int op=0;
|
||||
|
||||
static char *kwd_list[] = { "dom", "op", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
|
||||
&dom, &op) )
|
||||
return NULL;
|
||||
|
||||
if ( xc_shadow_control(xc->xc_handle, dom, op, NULL, 0, NULL) < 0 )
|
||||
return PyErr_SetFromErrno(xc_error);
|
||||
|
||||
Py_INCREF(zero);
|
||||
return zero;
|
||||
"extratime", extratime,
|
||||
"weight", weight);
|
||||
}
|
||||
|
||||
static PyObject *pyxc_domain_setmaxmem(PyObject *self,
|
||||
@@ -707,7 +812,7 @@ static PyObject *pyxc_domain_setmaxmem(PyObject *self,
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom;
|
||||
uint32_t dom;
|
||||
unsigned int maxmem_kb;
|
||||
|
||||
static char *kwd_list[] = { "dom", "maxmem_kb", NULL };
|
||||
@@ -729,7 +834,7 @@ static PyObject *pyxc_domain_memory_increase_reservation(PyObject *self,
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom;
|
||||
uint32_t dom;
|
||||
unsigned long mem_kb;
|
||||
unsigned int extent_order = 0 , address_bits = 0;
|
||||
unsigned long nr_extents;
|
||||
@@ -752,23 +857,6 @@ static PyObject *pyxc_domain_memory_increase_reservation(PyObject *self,
|
||||
return zero;
|
||||
}
|
||||
|
||||
static PyObject *pyxc_init_store(PyObject *self, PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
int remote_port;
|
||||
|
||||
static char *kwd_list[] = { "remote_port", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list,
|
||||
&remote_port) )
|
||||
return NULL;
|
||||
|
||||
return PyInt_FromLong(xc_init_store(xc->xc_handle, remote_port));
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef pyxc_methods[] = {
|
||||
{ "handle",
|
||||
(PyCFunction)pyxc_handle,
|
||||
@@ -783,6 +871,14 @@ static PyMethodDef pyxc_methods[] = {
|
||||
" dom [int, 0]: Domain identifier to use (allocated if zero).\n"
|
||||
"Returns: [int] new domain identifier; -1 on error.\n" },
|
||||
|
||||
{ "domain_max_vcpus",
|
||||
(PyCFunction)pyxc_domain_max_vcpus,
|
||||
METH_VARARGS | METH_KEYWORDS, "\n"
|
||||
"Set the maximum number of VCPUs a domain may create.\n"
|
||||
" dom [int, 0]: Domain identifier to use.\n"
|
||||
" max [int, 0]: New maximum number of VCPUs in domain.\n"
|
||||
"Returns: [int] 0 on success; -1 on error.\n" },
|
||||
|
||||
{ "domain_dumpcore",
|
||||
(PyCFunction)pyxc_domain_dumpcore,
|
||||
METH_VARARGS | METH_KEYWORDS, "\n"
|
||||
@@ -818,7 +914,7 @@ static PyMethodDef pyxc_methods[] = {
|
||||
"Pin a VCPU to a specified set CPUs.\n"
|
||||
" dom [int]: Identifier of domain to which VCPU belongs.\n"
|
||||
" vcpu [int, 0]: VCPU being pinned.\n"
|
||||
" cpumap [int, -1]: Bitmap of usable CPUs.\n\n"
|
||||
" cpumap [list, []]: list of usable CPUs.\n\n"
|
||||
"Returns: [int] 0 on success; -1 on error.\n" },
|
||||
|
||||
{ "domain_setcpuweight",
|
||||
@@ -829,6 +925,14 @@ static PyMethodDef pyxc_methods[] = {
|
||||
" cpuweight [float, 1]: VCPU being pinned.\n"
|
||||
"Returns: [int] 0 on success; -1 on error.\n" },
|
||||
|
||||
{ "domain_sethandle",
|
||||
(PyCFunction)pyxc_domain_sethandle,
|
||||
METH_VARARGS | METH_KEYWORDS, "\n"
|
||||
"Set domain's opaque handle.\n"
|
||||
" dom [int]: Identifier of domain.\n"
|
||||
" handle [list of 16 ints]: New opaque handle.\n"
|
||||
"Returns: [int] 0 on success; -1 on error.\n" },
|
||||
|
||||
{ "domain_getinfo",
|
||||
(PyCFunction)pyxc_domain_getinfo,
|
||||
METH_VARARGS | METH_KEYWORDS, "\n"
|
||||
@@ -852,8 +956,21 @@ static PyMethodDef pyxc_methods[] = {
|
||||
" maxmem_kb [int]: Maximum memory limit, in kilobytes\n"
|
||||
" cpu_time [long]: CPU time consumed, in nanoseconds\n"
|
||||
" shutdown_reason [int]: Numeric code from guest OS, explaining "
|
||||
"reason why it shut itself down.\n"
|
||||
" vcpu_to_cpu [[int]]: List that maps VCPUS to CPUS\n" },
|
||||
"reason why it shut itself down.\n" },
|
||||
|
||||
{ "vcpu_getinfo",
|
||||
(PyCFunction)pyxc_vcpu_getinfo,
|
||||
METH_VARARGS | METH_KEYWORDS, "\n"
|
||||
"Get information regarding a VCPU.\n"
|
||||
" dom [int]: Domain to retrieve info about.\n"
|
||||
" vcpu [int, 0]: VCPU to retrieve info about.\n\n"
|
||||
"Returns: [dict]\n"
|
||||
" online [int]: Bool - Is this VCPU currently online?\n"
|
||||
" blocked [int]: Bool - Is this VCPU blocked waiting for an event?\n"
|
||||
" running [int]: Bool - Is this VCPU currently running on a CPU?\n"
|
||||
" cpu_time [long]: CPU time consumed, in nanoseconds\n"
|
||||
" cpumap [int]: Bitmap of CPUs this VCPU can run on\n"
|
||||
" cpu [int]: CPU that this VCPU is currently bound to\n" },
|
||||
|
||||
{ "linux_build",
|
||||
(PyCFunction)pyxc_linux_build,
|
||||
@@ -869,12 +986,10 @@ static PyMethodDef pyxc_methods[] = {
|
||||
{ "vmx_build",
|
||||
(PyCFunction)pyxc_vmx_build,
|
||||
METH_VARARGS | METH_KEYWORDS, "\n"
|
||||
"Build a new Linux guest OS.\n"
|
||||
"Build a new VMX guest OS.\n"
|
||||
" dom [int]: Identifier of domain to build into.\n"
|
||||
" image [str]: Name of kernel image file. May be gzipped.\n"
|
||||
" memmap [str]: Memory map.\n\n"
|
||||
" ramdisk [str, n/a]: Name of ramdisk file, if any.\n"
|
||||
" cmdline [str, n/a]: Kernel parameters, if any.\n\n"
|
||||
" image [str]: Name of VMX loader image file.\n"
|
||||
" vcpus [int, 1]: Number of Virtual CPUS in domain.\n\n"
|
||||
"Returns: [int] 0 on success; -1 on error.\n" },
|
||||
|
||||
{ "bvtsched_global_set",
|
||||
@@ -995,14 +1110,6 @@ static PyMethodDef pyxc_methods[] = {
|
||||
"Returns [dict]: information about Xen"
|
||||
" [None]: on failure.\n" },
|
||||
|
||||
{ "shadow_control",
|
||||
(PyCFunction)pyxc_shadow_control,
|
||||
METH_VARARGS | METH_KEYWORDS, "\n"
|
||||
"Set parameter for shadow pagetable interface\n"
|
||||
" dom [int]: Identifier of domain.\n"
|
||||
" op [int, 0]: operation\n\n"
|
||||
"Returns: [int] 0 on success; -1 on error.\n" },
|
||||
|
||||
{ "domain_setmaxmem",
|
||||
(PyCFunction)pyxc_domain_setmaxmem,
|
||||
METH_VARARGS | METH_KEYWORDS, "\n"
|
||||
@@ -1019,13 +1126,6 @@ static PyMethodDef pyxc_methods[] = {
|
||||
" mem_kb [long]: .\n"
|
||||
"Returns: [int] 0 on success; -1 on error.\n" },
|
||||
|
||||
{ "init_store",
|
||||
(PyCFunction)pyxc_init_store,
|
||||
METH_VARARGS | METH_KEYWORDS, "\n"
|
||||
"Initialize the store event channel and return the store page mfn.\n"
|
||||
" remote_port [int]: store event channel port number.\n"
|
||||
"Returns: [int] mfn on success; <0 on error.\n" },
|
||||
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <xenctrl.h>
|
||||
#include "xs.h"
|
||||
|
||||
/** @file
|
||||
@@ -512,6 +513,7 @@ static PyObject *xspy_read_watch(PyObject *self, PyObject *args,
|
||||
goto exit;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
|
||||
goto exit;
|
||||
again:
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_read_watch(xh, &num);
|
||||
Py_END_ALLOW_THREADS
|
||||
@@ -528,8 +530,13 @@ static PyObject *xspy_read_watch(PyObject *self, PyObject *args,
|
||||
break;
|
||||
}
|
||||
if (i == PyList_Size(xsh->watches)) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "invalid token");
|
||||
goto exit;
|
||||
/* We do not have a registered watch for the one that has just fired.
|
||||
Ignore this -- a watch that has been recently deregistered can still
|
||||
have watches in transit. This is a blocking method, so go back to
|
||||
read again.
|
||||
*/
|
||||
free(xsval);
|
||||
goto again;
|
||||
}
|
||||
/* Create tuple (path, token). */
|
||||
val = Py_BuildValue("(sO)", xsval[XS_WATCH_PATH], token);
|
||||
@@ -679,7 +686,6 @@ static PyObject *xspy_transaction_end(PyObject *self, PyObject *args,
|
||||
" dom [int] : domain id\n" \
|
||||
" page [long] : address of domain's xenstore page\n" \
|
||||
" port [int] : port the domain is using for xenstore\n" \
|
||||
" path [string]: path to the domain's data in xenstore\n" \
|
||||
"\n" \
|
||||
"Returns None on success.\n" \
|
||||
"Raises RuntimeError on error.\n" \
|
||||
@@ -688,12 +694,11 @@ static PyObject *xspy_transaction_end(PyObject *self, PyObject *args,
|
||||
static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static char *kwd_spec[] = { "dom", "page", "port", "path", NULL };
|
||||
static char *arg_spec = "iiis|";
|
||||
static char *kwd_spec[] = { "dom", "page", "port", NULL };
|
||||
static char *arg_spec = "iii";
|
||||
domid_t dom = 0;
|
||||
unsigned long page = 0;
|
||||
unsigned int port = 0;
|
||||
char *path = NULL;
|
||||
|
||||
struct xs_handle *xh = xshandle(self);
|
||||
PyObject *val = NULL;
|
||||
@@ -702,10 +707,10 @@ static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args,
|
||||
if (!xh)
|
||||
goto exit;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
|
||||
&dom, &page, &port, &path))
|
||||
&dom, &page, &port))
|
||||
goto exit;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_introduce_domain(xh, dom, page, port, path);
|
||||
xsval = xs_introduce_domain(xh, dom, page, port);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (!xsval) {
|
||||
PyErr_SetFromErrno(PyExc_RuntimeError);
|
||||
@@ -790,11 +795,10 @@ static PyObject *xspy_close(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
}
|
||||
|
||||
#define xspy_get_domain_path_doc "\n" \
|
||||
"Return store path of domain.\n" \
|
||||
"Return store path of domain, whether or not the domain exists.\n" \
|
||||
" domid [int]: domain id\n" \
|
||||
"\n" \
|
||||
"Returns: [string] domain store path.\n" \
|
||||
" None if domid doesn't exist.\n" \
|
||||
"Raises RuntimeError on error.\n" \
|
||||
"\n"
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
LIB_BIN_32 = "/usr/lib/xen/bin"
|
||||
LIB_BIN_64 = "/usr/lib64/xen/bin"
|
||||
|
||||
## The architectures on which the LIB_BIN_64 directory is used. This
|
||||
# deliberately excludes ia64.
|
||||
LIB_64_ARCHS = [ 'x86_64', 'ppc64', 's390x', 'sparc64']
|
||||
|
||||
|
||||
import os
|
||||
import os.path
|
||||
@@ -38,7 +42,7 @@ def pathTo(exe):
|
||||
|
||||
def path():
|
||||
machine = os.uname()[4]
|
||||
if machine.find('64') != -1 and os.path.exists(LIB_BIN_64):
|
||||
if machine in LIB_64_ARCHS and os.path.exists(LIB_BIN_64):
|
||||
return LIB_BIN_64
|
||||
else:
|
||||
return LIB_BIN_32
|
||||
@@ -0,0 +1,150 @@
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2.1 of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Copyright (c) 2005 XenSource Ltd
|
||||
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
from xen.xend import sxp
|
||||
|
||||
from xen.xend.XendClient import server
|
||||
from xen.xend.XendError import XendError
|
||||
from xen.xend.xenstore.xstransact import xstransact
|
||||
|
||||
import xen.xend.XendProtocol
|
||||
|
||||
|
||||
domain = None
|
||||
domid = None
|
||||
deviceClass = None
|
||||
device = None
|
||||
frontendPath = None
|
||||
backendPath = None
|
||||
|
||||
|
||||
def diagnose(dom):
|
||||
global domain
|
||||
global domid
|
||||
global dompath
|
||||
|
||||
try:
|
||||
domain = server.xend_domain(dom)
|
||||
state = sxp.child_value(domain, 'state')
|
||||
domid = int(sxp.child_value(domain, 'domid'))
|
||||
name = sxp.child_value(domain, 'name')
|
||||
dompath = '/local/domain/%d' % domid
|
||||
|
||||
print "Domain ID is %d." % domid
|
||||
print "Domain name is %s." % name
|
||||
|
||||
if not state:
|
||||
raise XendError("Cannot find state")
|
||||
|
||||
if state.find('c') != -1:
|
||||
print "Domain has crashed."
|
||||
|
||||
diagnose_console()
|
||||
|
||||
diagnose_devices()
|
||||
except xen.xend.XendProtocol.XendError, exn:
|
||||
print exn
|
||||
|
||||
|
||||
def diagnose_console():
|
||||
port = xstransact.Read(dompath + '/console/port')
|
||||
ringref = xstransact.Read(dompath + '/console/ring-ref')
|
||||
tty = xstransact.Read(dompath + '/console/tty')
|
||||
|
||||
if not port:
|
||||
print "Console port is missing; Xend has failed."
|
||||
if not ringref:
|
||||
print "Console ring-ref is missing; Xend has failed."
|
||||
if not tty:
|
||||
print "Console tty is missing; Xenconsoled has failed."
|
||||
|
||||
|
||||
def diagnose_devices():
|
||||
global deviceClass
|
||||
global device
|
||||
global frontendPath
|
||||
global backendPath
|
||||
|
||||
device_path = dompath + '/device'
|
||||
|
||||
device_classes = xstransact.List(device_path)
|
||||
|
||||
print "Found %d device classes in use." % len(device_classes)
|
||||
|
||||
for dc in device_classes:
|
||||
deviceClass = dc
|
||||
device_class_path = device_path + '/' + deviceClass
|
||||
|
||||
devices = xstransact.List(device_class_path)
|
||||
|
||||
print "Found %d %s devices." % (len(devices), deviceClass)
|
||||
|
||||
for d in devices:
|
||||
device = d
|
||||
|
||||
print "Found device %s, %s." % (deviceClass, device)
|
||||
|
||||
frontendPath = device_class_path + '/' + device
|
||||
backendPath = xstransact.Read(frontendPath, 'backend')
|
||||
|
||||
if not backendPath:
|
||||
print ("Cannot find backend path for device %s, %s." %
|
||||
(deviceClass, device))
|
||||
else:
|
||||
backend_error = xstransact.Read(
|
||||
backendPath.replace('backend/', 'error/backend/'),
|
||||
'error')
|
||||
|
||||
if backend_error:
|
||||
diagnose_device_error(backend_error)
|
||||
|
||||
|
||||
def diagnose_device_error(err):
|
||||
if re.search("2 reading .*/ring-ref and event-channel", err):
|
||||
print ("Backend is stuck waiting for frontend for device %s, %s." %
|
||||
(deviceClass, device))
|
||||
diagnose_stuck_frontend()
|
||||
else:
|
||||
print ("Device %s, %s shows error %s." %
|
||||
(deviceClass, device, err))
|
||||
|
||||
|
||||
def diagnose_stuck_frontend():
|
||||
if deviceClass == "vbd":
|
||||
phy = xstransact.Read(backendPath, 'physical-device')
|
||||
|
||||
if phy:
|
||||
print ("Device %s, %s hotplugging has completed successfully." %
|
||||
(deviceClass, device))
|
||||
else:
|
||||
print ("Device %s, %s hotplugging failed." %
|
||||
(deviceClass, device))
|
||||
|
||||
|
||||
def main(argv = None):
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
|
||||
diagnose(argv[1])
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1,39 +0,0 @@
|
||||
# Copyright (C) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
|
||||
|
||||
# os.system() replacement which outputs through the logger
|
||||
|
||||
import popen2
|
||||
import select
|
||||
import string
|
||||
|
||||
from xen.xend.XendLogging import log
|
||||
|
||||
def runscript(cmd):
|
||||
# split after first space, then grab last component of path
|
||||
cmdname = "[%s] " % cmd.split()[0].split('/')[-1]
|
||||
# run command and grab stdin, stdout and stderr
|
||||
cout, cin, cerr = popen2.popen3(cmd)
|
||||
# close stdin to get command to terminate if it waits for input
|
||||
cin.close()
|
||||
# wait for output and process
|
||||
p = select.poll()
|
||||
p.register(cout)
|
||||
p.register(cerr)
|
||||
stdout = ""
|
||||
while True:
|
||||
r = p.poll()
|
||||
for (fd, event) in r:
|
||||
if event == select.POLLHUP:
|
||||
cout.close()
|
||||
cerr.close()
|
||||
return stdout
|
||||
if fd == cout.fileno():
|
||||
stdout = stdout + cout.readline()
|
||||
if fd == cerr.fileno():
|
||||
l = cerr.readline()
|
||||
if l[0] == '-':
|
||||
log.debug(cmdname + l[1:].rstrip())
|
||||
elif l[0] == '*':
|
||||
log.info(cmdname + l[1:].rstrip())
|
||||
else:
|
||||
log.error(cmdname + l.rstrip())
|
||||
@@ -86,7 +86,7 @@ class SrvBase(resource.Resource):
|
||||
except Exception, exn:
|
||||
log.exception("Request %s failed.", op)
|
||||
if req.useSxp():
|
||||
return ['xend.err', "Exception: " + str(exn)]
|
||||
return ['xend.err', str(exn)]
|
||||
else:
|
||||
return "<p>%s</p>" % str(exn)
|
||||
|
||||
|
||||
@@ -19,87 +19,17 @@
|
||||
"""Xend interface to networking control scripts.
|
||||
"""
|
||||
import os
|
||||
import os.path
|
||||
import xen.util.process
|
||||
|
||||
from xen.xend import XendRoot
|
||||
xroot = XendRoot.instance()
|
||||
import XendRoot
|
||||
|
||||
"""Where network control scripts live."""
|
||||
SCRIPT_DIR = xroot.network_script_dir
|
||||
|
||||
def network(op, script=None, bridge=None, antispoof=None):
|
||||
def network(op):
|
||||
"""Call a network control script.
|
||||
Xend calls this with op 'start' when it starts.
|
||||
|
||||
@param op: operation (start, stop, status)
|
||||
@param script: network script name
|
||||
@param bridge: xen bridge
|
||||
@param antispoof: whether to enable IP antispoofing rules
|
||||
@param op: operation (start, stop)
|
||||
"""
|
||||
if op not in ['start', 'stop', 'status']:
|
||||
raise ValueError('Invalid operation:' + op)
|
||||
if script is None:
|
||||
script = xroot.get_network_script()
|
||||
if bridge is None:
|
||||
bridge = xroot.get_vif_bridge()
|
||||
if antispoof is None:
|
||||
antispoof = xroot.get_vif_antispoof()
|
||||
script = os.path.join(SCRIPT_DIR, script)
|
||||
args = [op]
|
||||
args.append("bridge='%s'" % bridge)
|
||||
if antispoof:
|
||||
args.append("antispoof=yes")
|
||||
else:
|
||||
args.append("antispoof=no")
|
||||
args = ' '.join(args)
|
||||
ret = xen.util.process.runscript(script + ' ' + args)
|
||||
if len(ret):
|
||||
return ret.splitlines()[0]
|
||||
|
||||
def set_vif_name(vif_old, vif_new):
|
||||
if vif_old == vif_new:
|
||||
vif = vif_new
|
||||
return vif
|
||||
if os.system("ip link show %s" % vif_old) == 0:
|
||||
os.system("ip link set %s down" % vif_old)
|
||||
os.system("ip link set %s name %s" % (vif_old, vif_new))
|
||||
os.system("ip link set %s up" % vif_new)
|
||||
if os.system("ip link show %s" % vif_new) == 0:
|
||||
vif = vif_new
|
||||
else:
|
||||
vif = vif_old
|
||||
return vif
|
||||
|
||||
def vifctl(op, vif=None, script=None, domain=None, mac=None, bridge=None, ipaddr=None):
|
||||
"""Call a vif control script.
|
||||
Xend calls this when bringing vifs up or down.
|
||||
|
||||
@param op: vif operation (up, down)
|
||||
@param vif: vif name
|
||||
@param script: name of control script
|
||||
@param domain: name of domain the vif is on
|
||||
@param mac: vif MAC address
|
||||
@param bridge: bridge to add the vif to
|
||||
@param ipaddr: list of ipaddrs the vif may use
|
||||
"""
|
||||
if op not in ['up', 'down']:
|
||||
raise ValueError('Invalid operation:' + op)
|
||||
if script is None:
|
||||
script = xroot.get_vif_script()
|
||||
if bridge is None:
|
||||
bridge = xroot.get_vif_bridge()
|
||||
script = os.path.join(SCRIPT_DIR, script)
|
||||
args = [op]
|
||||
args.append("vif='%s'" % vif)
|
||||
args.append("domain='%s'" % domain)
|
||||
args.append("mac='%s'" % mac)
|
||||
if bridge:
|
||||
args.append("bridge='%s'" % bridge)
|
||||
if ipaddr:
|
||||
ips = ' '.join(ipaddr)
|
||||
args.append("ip='%s'" % ips)
|
||||
args = ' '.join(args)
|
||||
ret = xen.util.process.runscript(script + ' ' + args)
|
||||
if len(ret):
|
||||
return ret.splitlines()[0]
|
||||
if op not in ['start', 'stop']:
|
||||
raise ValueError('Invalid operation: ' + op)
|
||||
script = XendRoot.instance().get_network_script()
|
||||
if script:
|
||||
os.spawnl(os.P_WAIT, script, script, op)
|
||||
@@ -118,9 +118,11 @@ def restore(xd, fd):
|
||||
|
||||
dominfo = xd.restore_(vmconfig)
|
||||
|
||||
assert dominfo.store_channel
|
||||
assert dominfo.console_channel
|
||||
assert dominfo.getDomainPath()
|
||||
store_port = dominfo.getStorePort()
|
||||
console_port = dominfo.getConsolePort()
|
||||
|
||||
assert store_port
|
||||
assert console_port
|
||||
|
||||
try:
|
||||
l = read_exact(fd, sizeof_unsigned_long,
|
||||
@@ -130,34 +132,21 @@ def restore(xd, fd):
|
||||
raise XendError(
|
||||
"not a valid guest state file: pfn count out of range")
|
||||
|
||||
store_evtchn = dominfo.store_channel
|
||||
console_evtchn = dominfo.console_channel
|
||||
|
||||
cmd = [xen.util.auxbin.pathTo(XC_RESTORE), str(xc.handle()), str(fd),
|
||||
str(dominfo.getDomid()), str(nr_pfns),
|
||||
str(store_evtchn), str(console_evtchn)]
|
||||
cmd = map(str, [xen.util.auxbin.pathTo(XC_RESTORE),
|
||||
xc.handle(), fd, dominfo.getDomid(), nr_pfns,
|
||||
store_port, console_port])
|
||||
log.debug("[xc_restore]: %s", string.join(cmd))
|
||||
|
||||
def restoreInputHandler(line, _):
|
||||
m = re.match(r"^(store-mfn) (\d+)$", line)
|
||||
if m:
|
||||
store_mfn = int(m.group(2))
|
||||
dominfo.setStoreRef(store_mfn)
|
||||
log.debug("IntroduceDomain %d %d %d %s",
|
||||
dominfo.getDomid(),
|
||||
store_mfn,
|
||||
dominfo.store_channel,
|
||||
dominfo.getDomainPath())
|
||||
IntroduceDomain(dominfo.getDomid(),
|
||||
store_mfn,
|
||||
dominfo.store_channel,
|
||||
dominfo.getDomainPath())
|
||||
else:
|
||||
m = re.match(r"^(console-mfn) (\d+)$", line)
|
||||
if m:
|
||||
dominfo.setConsoleRef(int(m.group(2)))
|
||||
handler = RestoreInputHandler()
|
||||
|
||||
forkHelper(cmd, fd, restoreInputHandler, True)
|
||||
forkHelper(cmd, fd, handler.handler, True)
|
||||
|
||||
if handler.store_mfn is None or handler.console_mfn is None:
|
||||
raise XendError('Could not read store/console MFN')
|
||||
|
||||
dominfo.unpause()
|
||||
|
||||
dominfo.completeRestore(handler.store_mfn, handler.console_mfn)
|
||||
|
||||
return dominfo
|
||||
except:
|
||||
@@ -165,12 +154,29 @@ def restore(xd, fd):
|
||||
raise
|
||||
|
||||
|
||||
class RestoreInputHandler:
|
||||
def __init__(self):
|
||||
self.store_mfn = None
|
||||
self.console_mfn = None
|
||||
|
||||
|
||||
def handler(self, line, _):
|
||||
m = re.match(r"^(store-mfn) (\d+)$", line)
|
||||
if m:
|
||||
self.store_mfn = int(m.group(2))
|
||||
else:
|
||||
m = re.match(r"^(console-mfn) (\d+)$", line)
|
||||
if m:
|
||||
self.console_mfn = int(m.group(2))
|
||||
|
||||
|
||||
def forkHelper(cmd, fd, inputHandler, closeToChild):
|
||||
child = xPopen3(cmd, True, -1, [fd, xc.handle()])
|
||||
|
||||
if closeToChild:
|
||||
child.tochild.close()
|
||||
|
||||
lasterr = "error unknown"
|
||||
try:
|
||||
fds = [child.fromchild.fileno(),
|
||||
child.childerr.fileno()]
|
||||
|
||||
@@ -199,6 +199,9 @@ class Xend:
|
||||
def xend_list_domains(self):
|
||||
return self.xendGet(self.domainurl(), {'detail': '1'})
|
||||
|
||||
def xend_domain_vcpuinfo(self, dom):
|
||||
return self.xendGet(self.domainurl(dom), {'op': 'vcpuinfo'})
|
||||
|
||||
def xend_domain_create(self, conf):
|
||||
return self.xendPost(self.domainurl(),
|
||||
{'op' : 'create',
|
||||
@@ -255,7 +258,7 @@ class Xend:
|
||||
return self.xendPost(self.domainurl(id),
|
||||
{'op' : 'pincpu',
|
||||
'vcpu' : vcpu,
|
||||
'cpumap' : cpumap })
|
||||
'cpumap' : str(cpumap) })
|
||||
|
||||
def xend_domain_cpu_bvt_set(self, id, mcuadv, warpback, warpvalue, warpl, warpu):
|
||||
return self.xendPost(self.domainurl(id),
|
||||
@@ -266,6 +269,10 @@ class Xend:
|
||||
'warpl' : warpl,
|
||||
'warpu' : warpu })
|
||||
|
||||
def xend_domain_cpu_sedf_get(self, id):
|
||||
return self.xendPost(self.domainurl(id),
|
||||
{'op' : 'cpu_sedf_get'})
|
||||
|
||||
def xend_domain_cpu_sedf_set(self, id, period, slice, latency, extratime, weight):
|
||||
return self.xendPost(self.domainurl(id),
|
||||
{'op' : 'cpu_sedf_set',
|
||||
@@ -286,11 +293,10 @@ class Xend:
|
||||
'target' : mem_target })
|
||||
return val
|
||||
|
||||
def xend_domain_vcpu_hotplug(self, id, vcpu, state):
|
||||
return self.xendPost(self.domainurl(id),
|
||||
{'op' : 'vcpu_hotplug',
|
||||
'vcpu' : vcpu,
|
||||
'state' : state })
|
||||
def xend_domain_set_vcpus(self, dom, vcpus):
|
||||
return self.xendPost(self.domainurl(dom),
|
||||
{'op' : 'set_vcpus',
|
||||
'vcpus' : vcpus })
|
||||
|
||||
def xend_domain_vif_limit(self, id, vif, credit, period):
|
||||
return self.xendPost(self.domainurl(id),
|
||||
|
||||
@@ -21,8 +21,10 @@
|
||||
Nothing here is persistent (across reboots).
|
||||
Needs to be persistent for one uptime.
|
||||
"""
|
||||
import os
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
|
||||
import xen.lowlevel.xc
|
||||
@@ -57,13 +59,16 @@ class XendDomain:
|
||||
# So we stuff the XendDomain instance (self) into xroot's components.
|
||||
xroot.add_component("xen.xend.XendDomain", self)
|
||||
self.domains = {}
|
||||
self.domains_lock = threading.Condition()
|
||||
self.domains_lock = threading.RLock()
|
||||
self.watchReleaseDomain()
|
||||
|
||||
self.domains_lock.acquire()
|
||||
try:
|
||||
self.refresh(True)
|
||||
self._add_domain(
|
||||
XendDomainInfo.recreate(self.xen_domains()[PRIV_DOMAIN],
|
||||
True))
|
||||
self.dom0_setup()
|
||||
self.refresh(True)
|
||||
finally:
|
||||
self.domains_lock.release()
|
||||
|
||||
@@ -129,7 +134,14 @@ class XendDomain:
|
||||
def dom0_setup(self):
|
||||
"""Expects to be protected by the domains_lock."""
|
||||
dom0 = self.domains[PRIV_DOMAIN]
|
||||
dom0.dom0_enforce_vcpus()
|
||||
|
||||
# get max number of vcpus to use for dom0 from config
|
||||
target = int(xroot.get_dom0_vcpus())
|
||||
log.debug("number of vcpus to use is %d", target)
|
||||
|
||||
# target == 0 means use all processors
|
||||
if target > 0:
|
||||
dom0.setVCpuCount(target)
|
||||
|
||||
|
||||
def _add_domain(self, info):
|
||||
@@ -171,25 +183,23 @@ class XendDomain:
|
||||
'Cannot recreate information for dying domain %d.'
|
||||
' Xend will ignore this domain from now on.',
|
||||
doms[d]['dom'])
|
||||
elif d == PRIV_DOMAIN:
|
||||
log.fatal(
|
||||
"No record of privileged domain %d! Terminating.", d)
|
||||
sys.exit(1)
|
||||
else:
|
||||
try:
|
||||
dominfo = XendDomainInfo.recreate(doms[d])
|
||||
self._add_domain(dominfo)
|
||||
self._add_domain(
|
||||
XendDomainInfo.recreate(doms[d], False))
|
||||
except:
|
||||
if d == PRIV_DOMAIN:
|
||||
log.exception(
|
||||
"Failed to recreate information for domain "
|
||||
"%d. Doing nothing except crossing my "
|
||||
"fingers.", d)
|
||||
else:
|
||||
log.exception(
|
||||
"Failed to recreate information for domain "
|
||||
"%d. Destroying it in the hope of "
|
||||
"recovery.", d)
|
||||
try:
|
||||
xc.domain_destroy(dom = d)
|
||||
except:
|
||||
log.exception('Destruction of %d failed.', d)
|
||||
log.exception(
|
||||
"Failed to recreate information for domain "
|
||||
"%d. Destroying it in the hope of "
|
||||
"recovery.", d)
|
||||
try:
|
||||
xc.domain_destroy(dom = d)
|
||||
except:
|
||||
log.exception('Destruction of %d failed.', d)
|
||||
|
||||
|
||||
## public:
|
||||
@@ -318,12 +328,6 @@ class XendDomain:
|
||||
n = len(matching)
|
||||
if n == 1:
|
||||
return matching[0]
|
||||
elif n > 1:
|
||||
log.error('Name uniqueness has been violated for name %s! '
|
||||
'Recovering by renaming:', name)
|
||||
for d in matching:
|
||||
d.renameUniquely()
|
||||
|
||||
return None
|
||||
finally:
|
||||
self.domains_lock.release()
|
||||
@@ -343,7 +347,7 @@ class XendDomain:
|
||||
dominfo = self.domain_lookup(domid)
|
||||
log.info("Domain %s (%d) unpaused.", dominfo.getName(),
|
||||
dominfo.getDomid())
|
||||
return xc.domain_unpause(dom=dominfo.getDomid())
|
||||
return dominfo.unpause()
|
||||
except Exception, ex:
|
||||
raise XendError(str(ex))
|
||||
|
||||
@@ -354,7 +358,7 @@ class XendDomain:
|
||||
dominfo = self.domain_lookup(domid)
|
||||
log.info("Domain %s (%d) paused.", dominfo.getName(),
|
||||
dominfo.getDomid())
|
||||
return xc.domain_pause(dom=dominfo.getDomid())
|
||||
return dominfo.pause()
|
||||
except Exception, ex:
|
||||
raise XendError(str(ex))
|
||||
|
||||
@@ -408,9 +412,12 @@ class XendDomain:
|
||||
def domain_pincpu(self, domid, vcpu, cpumap):
|
||||
"""Set which cpus vcpu can use
|
||||
|
||||
@param cpumap: bitmap of usable cpus
|
||||
@param cpumap: string repr of list of usable cpus
|
||||
"""
|
||||
dominfo = self.domain_lookup(domid)
|
||||
# convert cpumap string into a list of ints
|
||||
cpumap = map(lambda x: int(x),
|
||||
cpumap.replace("[", "").replace("]", "").split(","))
|
||||
try:
|
||||
return xc.domain_pincpu(dominfo.getDomid(), vcpu, cpumap)
|
||||
except Exception, ex:
|
||||
@@ -469,14 +476,7 @@ class XendDomain:
|
||||
if not dev:
|
||||
raise XendError("invalid vif")
|
||||
return dev.setCreditLimit(credit, period)
|
||||
|
||||
def domain_shadow_control(self, domid, op):
|
||||
"""Shadow page control."""
|
||||
dominfo = self.domain_lookup(domid)
|
||||
try:
|
||||
return xc.shadow_control(dominfo.getDomid(), op)
|
||||
except Exception, ex:
|
||||
raise XendError(str(ex))
|
||||
|
||||
|
||||
def domain_maxmem_set(self, domid, mem):
|
||||
"""Set the memory limit for a domain.
|
||||
|
||||
@@ -24,10 +24,10 @@ Author: Mike Wray <mike.wray@hp.com>
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import string
|
||||
import time
|
||||
import threading
|
||||
import errno
|
||||
|
||||
import xen.lowlevel.xc
|
||||
from xen.util import asserts
|
||||
@@ -38,11 +38,10 @@ from xen.xend import scheduler
|
||||
from xen.xend import sxp
|
||||
from xen.xend import XendRoot
|
||||
from xen.xend.XendBootloader import bootloader
|
||||
from xen.xend.XendLogging import log
|
||||
from xen.xend.XendError import XendError, VmError
|
||||
from xen.xend.XendRoot import get_component
|
||||
|
||||
from uuid import getUuid
|
||||
import uuid
|
||||
|
||||
from xen.xend.xenstore.xstransact import xstransact
|
||||
from xen.xend.xenstore.xsutil import GetDomainPath, IntroduceDomain
|
||||
@@ -78,30 +77,26 @@ restart_modes = [
|
||||
"rename-restart"
|
||||
]
|
||||
|
||||
STATE_VM_OK = "ok"
|
||||
STATE_VM_TERMINATED = "terminated"
|
||||
|
||||
"""Flag for a block device backend domain."""
|
||||
SIF_BLK_BE_DOMAIN = (1<<4)
|
||||
|
||||
"""Flag for a net device backend domain."""
|
||||
SIF_NET_BE_DOMAIN = (1<<5)
|
||||
|
||||
"""Flag for a TPM device backend domain."""
|
||||
SIF_TPM_BE_DOMAIN = (1<<7)
|
||||
|
||||
STATE_DOM_OK = 1
|
||||
STATE_DOM_SHUTDOWN = 2
|
||||
|
||||
SHUTDOWN_TIMEOUT = 30
|
||||
|
||||
|
||||
DOMROOT = '/local/domain/'
|
||||
VMROOT = '/vm/'
|
||||
|
||||
ZOMBIE_PREFIX = 'Zombie-'
|
||||
|
||||
"""Minimum time between domain restarts in seconds."""
|
||||
MINIMUM_RESTART_TIME = 20
|
||||
|
||||
|
||||
xc = xen.lowlevel.xc.new()
|
||||
xroot = XendRoot.instance()
|
||||
|
||||
log = logging.getLogger("xend.XendDomainInfo")
|
||||
#log.setLevel(logging.TRACE)
|
||||
|
||||
|
||||
## Configuration entries that we expect to round-trip -- be read from the
|
||||
# config file or xc, written to save-files (i.e. through sxpr), and reused as
|
||||
@@ -111,6 +106,7 @@ xroot = XendRoot.instance()
|
||||
# file, so those are handled separately.
|
||||
ROUNDTRIPPING_CONFIG_ENTRIES = [
|
||||
('name', str),
|
||||
('uuid', str),
|
||||
('ssidref', int),
|
||||
('vcpus', int),
|
||||
('vcpu_avail', int),
|
||||
@@ -130,8 +126,6 @@ ROUNDTRIPPING_CONFIG_ENTRIES = [
|
||||
# its VCPUs. This is translated to
|
||||
# <dompath>/cpu/<id>/availability = {online,offline} for use
|
||||
# by the guest domain.
|
||||
# vcpu_to_cpu: the current mapping between virtual CPUs and the physical
|
||||
# CPU it is using.
|
||||
# cpumap: a list of bitmaps, one for each VCPU, giving the physical
|
||||
# CPUs that that VCPU may use.
|
||||
# cpu: a configuration setting requesting that VCPU 0 is pinned to
|
||||
@@ -152,12 +146,10 @@ def create(config):
|
||||
|
||||
log.debug("XendDomainInfo.create(%s)", config)
|
||||
|
||||
vm = XendDomainInfo(getUuid(), parseConfig(config))
|
||||
vm = XendDomainInfo(parseConfig(config))
|
||||
try:
|
||||
vm.construct()
|
||||
vm.initDomain()
|
||||
vm.construct_image()
|
||||
vm.configure()
|
||||
vm.storeVmDetails()
|
||||
vm.storeDomDetails()
|
||||
vm.refreshShutdown()
|
||||
@@ -168,7 +160,7 @@ def create(config):
|
||||
raise
|
||||
|
||||
|
||||
def recreate(xeninfo):
|
||||
def recreate(xeninfo, priv):
|
||||
"""Create the VM object for an existing domain. The domain must not
|
||||
be dying, as the paths in the store should already have been removed,
|
||||
and asking us to recreate them causes problems."""
|
||||
@@ -178,40 +170,43 @@ def recreate(xeninfo):
|
||||
assert not xeninfo['dying']
|
||||
|
||||
domid = xeninfo['dom']
|
||||
uuid1 = xeninfo['handle']
|
||||
xeninfo['uuid'] = uuid.toString(uuid1)
|
||||
dompath = GetDomainPath(domid)
|
||||
if not dompath:
|
||||
raise XendError(
|
||||
'No domain path in store for existing domain %d' % domid)
|
||||
|
||||
log.info("Recreating domain %d, UUID %s.", domid, xeninfo['uuid'])
|
||||
try:
|
||||
dompath = GetDomainPath(domid)
|
||||
if not dompath:
|
||||
raise XendError(
|
||||
'No domain path in store for existing domain %d' % domid)
|
||||
vmpath = xstransact.Read(dompath, "vm")
|
||||
if not vmpath:
|
||||
raise XendError(
|
||||
'No vm path in store for existing domain %d' % domid)
|
||||
uuid = xstransact.Read(vmpath, "uuid")
|
||||
if not uuid:
|
||||
uuid2_str = xstransact.Read(vmpath, "uuid")
|
||||
if not uuid2_str:
|
||||
raise XendError(
|
||||
'No vm/uuid path in store for existing domain %d' % domid)
|
||||
|
||||
log.info("Recreating domain %d, UUID %s.", domid, uuid)
|
||||
uuid2 = uuid.fromString(uuid2_str)
|
||||
|
||||
vm = XendDomainInfo(uuid, xeninfo, domid, True)
|
||||
if uuid1 != uuid2:
|
||||
raise XendError(
|
||||
'Uuid in store does not match uuid for existing domain %d: '
|
||||
'%s != %s' % (domid, uuid2_str, xeninfo['uuid']))
|
||||
|
||||
vm = XendDomainInfo(xeninfo, domid, dompath, True)
|
||||
|
||||
except Exception, exn:
|
||||
log.warn(str(exn))
|
||||
if priv:
|
||||
log.warn(str(exn))
|
||||
|
||||
uuid = getUuid()
|
||||
|
||||
log.info("Recreating domain %d with new UUID %s.", domid, uuid)
|
||||
|
||||
vm = XendDomainInfo(uuid, xeninfo, domid, True)
|
||||
vm = XendDomainInfo(xeninfo, domid, dompath, True)
|
||||
vm.removeDom()
|
||||
vm.removeVm()
|
||||
vm.storeVmDetails()
|
||||
vm.storeDomDetails()
|
||||
|
||||
vm.create_channel()
|
||||
if domid == 0:
|
||||
vm.initStoreConnection()
|
||||
|
||||
vm.refreshShutdown(xeninfo)
|
||||
return vm
|
||||
|
||||
@@ -224,15 +219,13 @@ def restore(config):
|
||||
|
||||
log.debug("XendDomainInfo.restore(%s)", config)
|
||||
|
||||
uuid = sxp.child_value(config, 'uuid')
|
||||
vm = XendDomainInfo(uuid, parseConfig(config))
|
||||
vm = XendDomainInfo(parseConfig(config))
|
||||
try:
|
||||
vm.construct()
|
||||
vm.configure()
|
||||
vm.create_channel()
|
||||
vm.storeVmDetails()
|
||||
vm.createDevices()
|
||||
vm.createChannels()
|
||||
vm.storeDomDetails()
|
||||
vm.refreshShutdown()
|
||||
return vm
|
||||
except:
|
||||
vm.destroy()
|
||||
@@ -293,7 +286,7 @@ def parseConfig(config):
|
||||
restart = get_cfg('restart')
|
||||
if restart:
|
||||
def handle_restart(event, val):
|
||||
if not event in result:
|
||||
if result[event] is None:
|
||||
result[event] = val
|
||||
|
||||
if restart == "onreboot":
|
||||
@@ -346,19 +339,16 @@ def dom_get(dom):
|
||||
log.debug("domain_getinfo(%d) failed, ignoring: %s", dom, str(err))
|
||||
return None
|
||||
|
||||
|
||||
class XendDomainInfo:
|
||||
"""Virtual machine object."""
|
||||
|
||||
"""Minimum time between domain restarts in seconds.
|
||||
"""
|
||||
MINIMUM_RESTART_TIME = 20
|
||||
def __init__(self, info, domid = None, dompath = None, augment = False):
|
||||
|
||||
|
||||
def __init__(self, uuid, info, domid = None, augment = False):
|
||||
|
||||
self.uuid = uuid
|
||||
self.info = info
|
||||
|
||||
if not self.infoIsSet('uuid'):
|
||||
self.info['uuid'] = uuid.toString(uuid.create())
|
||||
|
||||
if domid is not None:
|
||||
self.domid = domid
|
||||
elif 'dom' in info:
|
||||
@@ -366,11 +356,8 @@ class XendDomainInfo:
|
||||
else:
|
||||
self.domid = None
|
||||
|
||||
self.vmpath = VMROOT + uuid
|
||||
if self.domid is None:
|
||||
self.dompath = None
|
||||
else:
|
||||
self.dompath = DOMROOT + str(self.domid)
|
||||
self.vmpath = VMROOT + self.info['uuid']
|
||||
self.dompath = dompath
|
||||
|
||||
if augment:
|
||||
self.augmentInfo()
|
||||
@@ -379,16 +366,18 @@ class XendDomainInfo:
|
||||
|
||||
self.image = None
|
||||
|
||||
self.store_channel = None
|
||||
self.store_port = None
|
||||
self.store_mfn = None
|
||||
self.console_channel = None
|
||||
self.console_port = None
|
||||
self.console_mfn = None
|
||||
|
||||
self.state = STATE_VM_OK
|
||||
self.state = STATE_DOM_OK
|
||||
self.state_updated = threading.Condition()
|
||||
self.refresh_shutdown_lock = threading.Condition()
|
||||
|
||||
|
||||
## private:
|
||||
|
||||
def augmentInfo(self):
|
||||
"""Augment self.info, as given to us through {@link #recreate}, with
|
||||
values taken from the store. This recovers those values known to xend
|
||||
@@ -436,7 +425,10 @@ class XendDomainInfo:
|
||||
defaultInfo('on_crash', lambda: "restart")
|
||||
defaultInfo('cpu', lambda: None)
|
||||
defaultInfo('cpu_weight', lambda: 1.0)
|
||||
defaultInfo('vcpus', lambda: 1)
|
||||
defaultInfo('vcpus', lambda: int(1))
|
||||
|
||||
self.info['vcpus'] = int(self.info['vcpus'])
|
||||
|
||||
defaultInfo('vcpu_avail', lambda: (1 << self.info['vcpus']) - 1)
|
||||
defaultInfo('bootloader', lambda: None)
|
||||
defaultInfo('backend', lambda: [])
|
||||
@@ -509,11 +501,6 @@ class XendDomainInfo:
|
||||
if self.info['maxmem_KiB'] > self.info['memory_KiB']:
|
||||
self.info['maxmem_KiB'] = self.info['memory_KiB']
|
||||
|
||||
# Validate the given backend names.
|
||||
for s in self.info['backend']:
|
||||
if s not in backendFlags:
|
||||
raise VmError('Invalid backend type: %s' % s)
|
||||
|
||||
for (n, c) in self.info['device']:
|
||||
if not n or not c or n not in controllerClasses:
|
||||
raise VmError('invalid device (%s, %s)' %
|
||||
@@ -541,28 +528,51 @@ class XendDomainInfo:
|
||||
def gatherVm(self, *args):
|
||||
return xstransact.Gather(self.vmpath, *args)
|
||||
|
||||
|
||||
## public:
|
||||
|
||||
def storeVm(self, *args):
|
||||
return xstransact.Store(self.vmpath, *args)
|
||||
|
||||
|
||||
## private:
|
||||
|
||||
def readDom(self, *args):
|
||||
return xstransact.Read(self.dompath, *args)
|
||||
|
||||
def writeDom(self, *args):
|
||||
return xstransact.Write(self.dompath, *args)
|
||||
|
||||
|
||||
## public:
|
||||
|
||||
def removeDom(self, *args):
|
||||
return xstransact.Remove(self.dompath, *args)
|
||||
|
||||
def gatherDom(self, *args):
|
||||
return xstransact.Gather(self.dompath, *args)
|
||||
|
||||
## private:
|
||||
|
||||
def storeDom(self, *args):
|
||||
return xstransact.Store(self.dompath, *args)
|
||||
|
||||
|
||||
## public:
|
||||
|
||||
def completeRestore(self, store_mfn, console_mfn):
|
||||
|
||||
log.debug("XendDomainInfo.completeRestore")
|
||||
|
||||
self.store_mfn = store_mfn
|
||||
self.console_mfn = console_mfn
|
||||
|
||||
self.introduceDomain()
|
||||
self.storeDomDetails()
|
||||
self.refreshShutdown()
|
||||
|
||||
|
||||
def storeVmDetails(self):
|
||||
to_store = {
|
||||
'uuid': self.uuid,
|
||||
'uuid': self.info['uuid'],
|
||||
|
||||
# XXX
|
||||
'memory/target': str(self.info['memory_KiB'])
|
||||
@@ -585,26 +595,39 @@ class XendDomainInfo:
|
||||
to_store = {
|
||||
'domid': str(self.domid),
|
||||
'vm': self.vmpath,
|
||||
|
||||
'console/limit': str(xroot.get_console_limit() * 1024),
|
||||
'memory/target': str(self.info['memory_KiB'])
|
||||
}
|
||||
|
||||
for (k, v) in self.info.items():
|
||||
if v:
|
||||
to_store[k] = str(v)
|
||||
def f(n, v):
|
||||
if v is not None:
|
||||
to_store[n] = str(v)
|
||||
|
||||
f('console/port', self.console_port)
|
||||
f('console/ring-ref', self.console_mfn)
|
||||
f('store/port', self.store_port)
|
||||
f('store/ring-ref', self.store_mfn)
|
||||
|
||||
to_store.update(self.vcpuDomDetails())
|
||||
|
||||
log.debug("Storing domain details: %s", to_store)
|
||||
|
||||
self.writeDom(to_store)
|
||||
|
||||
|
||||
## private:
|
||||
|
||||
def vcpuDomDetails(self):
|
||||
def availability(n):
|
||||
if self.info['vcpu_avail'] & (1 << n):
|
||||
return 'online'
|
||||
else:
|
||||
return 'offline'
|
||||
|
||||
result = {}
|
||||
for v in range(0, self.info['vcpus']):
|
||||
to_store["cpu/%d/availability" % v] = availability(v)
|
||||
|
||||
log.debug("Storing domain details: %s", to_store)
|
||||
|
||||
self.writeDom(to_store)
|
||||
result["cpu/%d/availability" % v] = availability(v)
|
||||
return result
|
||||
|
||||
|
||||
def setDomid(self, domid):
|
||||
@@ -629,12 +652,27 @@ class XendDomainInfo:
|
||||
def getDomainPath(self):
|
||||
return self.dompath
|
||||
|
||||
def getUuid(self):
|
||||
return self.uuid
|
||||
|
||||
def getStorePort(self):
|
||||
"""For use only by image.py and XendCheckpoint.py."""
|
||||
return self.store_port
|
||||
|
||||
|
||||
def getConsolePort(self):
|
||||
"""For use only by image.py and XendCheckpoint.py"""
|
||||
return self.console_port
|
||||
|
||||
|
||||
def getVCpuCount(self):
|
||||
return self.info['vcpus']
|
||||
|
||||
|
||||
def setVCpuCount(self, vcpus):
|
||||
self.info['vcpu_avail'] = (1 << vcpus) - 1
|
||||
self.storeVm('vcpu_avail', self.info['vcpu_avail'])
|
||||
self.writeDom(self.vcpuDomDetails())
|
||||
|
||||
|
||||
def getSsidref(self):
|
||||
return self.info['ssidref']
|
||||
|
||||
@@ -642,15 +680,6 @@ class XendDomainInfo:
|
||||
"""Get this domain's target memory size, in KiB."""
|
||||
return self.info['memory_KiB']
|
||||
|
||||
def setStoreRef(self, ref):
|
||||
self.store_mfn = ref
|
||||
self.storeDom("store/ring-ref", ref)
|
||||
|
||||
|
||||
def getBackendFlags(self):
|
||||
return reduce(lambda x, y: x | backendFlags[y],
|
||||
self.info['backend'], 0)
|
||||
|
||||
|
||||
def refreshShutdown(self, xeninfo = None):
|
||||
# If set at the end of this method, a restart is required, with the
|
||||
@@ -685,6 +714,11 @@ class XendDomainInfo:
|
||||
return
|
||||
|
||||
elif xeninfo['crashed']:
|
||||
if self.readDom('xend/shutdown_completed'):
|
||||
# We've seen this shutdown already, but we are preserving
|
||||
# the domain for debugging. Leave it alone.
|
||||
return
|
||||
|
||||
log.warn('Domain has crashed: name=%s id=%d.',
|
||||
self.info['name'], self.domid)
|
||||
|
||||
@@ -708,7 +742,7 @@ class XendDomainInfo:
|
||||
self.clearRestart()
|
||||
|
||||
if reason == 'suspend':
|
||||
self.state_set(STATE_VM_TERMINATED)
|
||||
self.state_set(STATE_DOM_SHUTDOWN)
|
||||
# Don't destroy the domain. XendCheckpoint will do
|
||||
# this once it has finished.
|
||||
elif reason in ['poweroff', 'reboot']:
|
||||
@@ -716,6 +750,11 @@ class XendDomainInfo:
|
||||
else:
|
||||
self.destroy()
|
||||
|
||||
elif self.dompath is None:
|
||||
# We have yet to manage to call introduceDomain on this
|
||||
# domain. This can happen if a restore is in progress, or has
|
||||
# failed. Ignore this domain.
|
||||
pass
|
||||
else:
|
||||
# Domain is alive. If we are shutting it down, then check
|
||||
# the timeout on that, and destroy it if necessary.
|
||||
@@ -783,11 +822,6 @@ class XendDomainInfo:
|
||||
|
||||
## public:
|
||||
|
||||
def setConsoleRef(self, ref):
|
||||
self.console_mfn = ref
|
||||
self.storeDom("console/ring-ref", ref)
|
||||
|
||||
|
||||
def setMemoryTarget(self, target):
|
||||
"""Set the memory target of this domain.
|
||||
@param target In MiB.
|
||||
@@ -802,7 +836,7 @@ class XendDomainInfo:
|
||||
"""Update with info from xc.domain_getinfo().
|
||||
"""
|
||||
|
||||
log.debug("XendDomainInfo.update(%s) on domain %d", info, self.domid)
|
||||
log.trace("XendDomainInfo.update(%s) on domain %d", info, self.domid)
|
||||
|
||||
if not info:
|
||||
info = dom_get(self.domid)
|
||||
@@ -813,7 +847,7 @@ class XendDomainInfo:
|
||||
self.validateInfo()
|
||||
self.refreshShutdown(info)
|
||||
|
||||
log.debug("XendDomainInfo.update done on domain %d: %s", self.domid,
|
||||
log.trace("XendDomainInfo.update done on domain %d: %s", self.domid,
|
||||
self.info)
|
||||
|
||||
|
||||
@@ -821,19 +855,23 @@ class XendDomainInfo:
|
||||
|
||||
def state_set(self, state):
|
||||
self.state_updated.acquire()
|
||||
if self.state != state:
|
||||
self.state = state
|
||||
self.state_updated.notifyAll()
|
||||
self.state_updated.release()
|
||||
try:
|
||||
if self.state != state:
|
||||
self.state = state
|
||||
self.state_updated.notifyAll()
|
||||
finally:
|
||||
self.state_updated.release()
|
||||
|
||||
|
||||
## public:
|
||||
|
||||
def waitForShutdown(self):
|
||||
self.state_updated.acquire()
|
||||
while self.state == STATE_VM_OK:
|
||||
self.state_updated.wait()
|
||||
self.state_updated.release()
|
||||
try:
|
||||
while self.state == STATE_DOM_OK:
|
||||
self.state_updated.wait()
|
||||
finally:
|
||||
self.state_updated.release()
|
||||
|
||||
|
||||
def __str__(self):
|
||||
@@ -865,12 +903,12 @@ class XendDomainInfo:
|
||||
return self.getDeviceController(deviceClass).destroyDevice(devid)
|
||||
|
||||
|
||||
## private:
|
||||
|
||||
def getDeviceSxprs(self, deviceClass):
|
||||
return self.getDeviceController(deviceClass).sxprs()
|
||||
|
||||
|
||||
## private:
|
||||
|
||||
def getDeviceConfigurations(self, deviceClass):
|
||||
return self.getDeviceController(deviceClass).configurations()
|
||||
|
||||
@@ -887,7 +925,6 @@ class XendDomainInfo:
|
||||
def sxpr(self):
|
||||
sxpr = ['domain',
|
||||
['domid', self.domid],
|
||||
['uuid', self.uuid],
|
||||
['memory', self.info['memory_KiB'] / 1024]]
|
||||
|
||||
for e in ROUNDTRIPPING_CONFIG_ENTRIES:
|
||||
@@ -925,11 +962,6 @@ class XendDomainInfo:
|
||||
if self.infoIsSet('cpu_time'):
|
||||
sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
|
||||
sxpr.append(['vcpus', self.info['vcpus']])
|
||||
if self.infoIsSet('cpumap'):
|
||||
sxpr.append(['cpumap', self.info['cpumap']])
|
||||
if self.infoIsSet('vcpu_to_cpu'):
|
||||
sxpr.append(['cpu', self.info['vcpu_to_cpu'][0]])
|
||||
sxpr.append(['vcpu_to_cpu', self.prettyVCpuMap()])
|
||||
|
||||
if self.infoIsSet('start_time'):
|
||||
up_time = time.time() - self.info['start_time']
|
||||
@@ -944,13 +976,38 @@ class XendDomainInfo:
|
||||
return sxpr
|
||||
|
||||
|
||||
def getVCPUInfo(self):
|
||||
try:
|
||||
def filter_cpumap(map, max):
|
||||
return filter(lambda x: x >= 0, map[0:max])
|
||||
|
||||
# We include the domain name and ID, to help xm.
|
||||
sxpr = ['domain',
|
||||
['domid', self.domid],
|
||||
['name', self.info['name']],
|
||||
['vcpu_count', self.info['vcpus']]]
|
||||
|
||||
for i in range(0, self.info['vcpus']):
|
||||
info = xc.vcpu_getinfo(self.domid, i)
|
||||
|
||||
sxpr.append(['vcpu',
|
||||
['number', i],
|
||||
['online', info['online']],
|
||||
['blocked', info['blocked']],
|
||||
['running', info['running']],
|
||||
['cpu_time', info['cpu_time'] / 1e9],
|
||||
['cpu', info['cpu']],
|
||||
['cpumap', filter_cpumap(info['cpumap'],
|
||||
self.info['vcpus'])]])
|
||||
|
||||
return sxpr
|
||||
|
||||
except RuntimeError, exn:
|
||||
raise XendError(str(exn))
|
||||
|
||||
|
||||
## private:
|
||||
|
||||
def prettyVCpuMap(self):
|
||||
return '|'.join(map(str,
|
||||
self.info['vcpu_to_cpu'][0:self.info['vcpus']]))
|
||||
|
||||
|
||||
def check_name(self, name):
|
||||
"""Check if a vm name is valid. Valid names contain alphabetic characters,
|
||||
digits, or characters in '_-.:/+'.
|
||||
@@ -988,18 +1045,29 @@ class XendDomainInfo:
|
||||
self.domid,
|
||||
self.info['ssidref'])
|
||||
|
||||
self.domid = xc.domain_create(dom = 0, ssidref = self.info['ssidref'])
|
||||
self.domid = xc.domain_create(
|
||||
dom = 0, ssidref = self.info['ssidref'],
|
||||
handle = uuid.fromString(self.info['uuid']))
|
||||
|
||||
if self.domid < 0:
|
||||
raise VmError('Creating domain failed: name=%s' %
|
||||
self.info['name'])
|
||||
|
||||
self.dompath = DOMROOT + str(self.domid)
|
||||
self.dompath = GetDomainPath(self.domid)
|
||||
|
||||
# Ensure that the domain entry is clean. This prevents a stale
|
||||
# shutdown_start_time from killing the domain, for example.
|
||||
self.removeDom()
|
||||
|
||||
# Set maximum number of vcpus in domain
|
||||
xc.domain_max_vcpus(self.domid, int(self.info['vcpus']))
|
||||
|
||||
|
||||
def introduceDomain(self):
|
||||
assert self.domid is not None
|
||||
assert self.store_mfn is not None
|
||||
assert self.store_port is not None
|
||||
|
||||
IntroduceDomain(self.domid, self.store_mfn, self.store_port)
|
||||
|
||||
|
||||
def initDomain(self):
|
||||
log.debug('XendDomainInfo.initDomain: %s %s %s',
|
||||
@@ -1018,29 +1086,29 @@ class XendDomainInfo:
|
||||
self.image.handleBootloading()
|
||||
|
||||
xc.domain_setcpuweight(self.domid, self.info['cpu_weight'])
|
||||
# XXX Merge with configure_maxmem?
|
||||
|
||||
m = self.image.getDomainMemory(self.info['memory_KiB'])
|
||||
xc.domain_setmaxmem(self.domid, m)
|
||||
xc.domain_setmaxmem(self.domid, maxmem_kb = m)
|
||||
xc.domain_memory_increase_reservation(self.domid, m, 0, 0)
|
||||
|
||||
cpu = self.info['cpu']
|
||||
if cpu is not None and cpu != -1:
|
||||
xc.domain_pincpu(self.domid, 0, 1 << cpu)
|
||||
|
||||
self.createChannels()
|
||||
|
||||
channel_details = self.image.createImage()
|
||||
|
||||
self.store_mfn = channel_details['store_mfn']
|
||||
if 'console_mfn' in channel_details:
|
||||
self.console_mfn = channel_details['console_mfn']
|
||||
|
||||
self.introduceDomain()
|
||||
|
||||
self.createDevices()
|
||||
|
||||
self.info['start_time'] = time.time()
|
||||
|
||||
log.debug('init_domain> Created domain=%d name=%s memory=%d',
|
||||
self.domid, self.info['name'], self.info['memory_KiB'])
|
||||
|
||||
|
||||
def construct_image(self):
|
||||
"""Construct the boot image for the domain.
|
||||
"""
|
||||
self.create_channel()
|
||||
self.image.createImage()
|
||||
IntroduceDomain(self.domid, self.store_mfn,
|
||||
self.store_channel, self.dompath)
|
||||
|
||||
|
||||
## public:
|
||||
|
||||
@@ -1065,11 +1133,11 @@ class XendDomainInfo:
|
||||
|
||||
try:
|
||||
if not self.info['name'].startswith(ZOMBIE_PREFIX):
|
||||
self.info['name'] = self.generateZombieName()
|
||||
self.info['name'] = ZOMBIE_PREFIX + self.info['name']
|
||||
except:
|
||||
log.exception("Renaming Zombie failed.")
|
||||
|
||||
self.state_set(STATE_VM_TERMINATED)
|
||||
self.state_set(STATE_DOM_SHUTDOWN)
|
||||
|
||||
|
||||
def cleanupVm(self):
|
||||
@@ -1124,51 +1192,38 @@ class XendDomainInfo:
|
||||
break
|
||||
|
||||
|
||||
def eventChannel(self, path=None):
|
||||
"""Create an event channel to the domain.
|
||||
|
||||
@param path under which port is stored in db
|
||||
def createChannels(self):
|
||||
"""Create the channels to the domain.
|
||||
"""
|
||||
if path:
|
||||
try:
|
||||
return int(self.readDom(path))
|
||||
except:
|
||||
# The port is not yet set, i.e. the channel has not yet been
|
||||
# created.
|
||||
pass
|
||||
self.store_port = self.createChannel()
|
||||
self.console_port = self.createChannel()
|
||||
|
||||
|
||||
def createChannel(self):
|
||||
"""Create an event channel to the domain.
|
||||
"""
|
||||
try:
|
||||
port = xc.evtchn_alloc_unbound(dom=self.domid, remote_dom=0)
|
||||
return xc.evtchn_alloc_unbound(dom=self.domid, remote_dom=0)
|
||||
except:
|
||||
log.exception("Exception in alloc_unbound(%d)", self.domid)
|
||||
raise
|
||||
|
||||
self.storeDom(path, port)
|
||||
return port
|
||||
|
||||
def create_channel(self):
|
||||
"""Create the channels to the domain.
|
||||
"""
|
||||
self.store_channel = self.eventChannel("store/port")
|
||||
self.console_channel = self.eventChannel("console/port")
|
||||
## public:
|
||||
|
||||
def create_configured_devices(self):
|
||||
for (n, c) in self.info['device']:
|
||||
self.createDevice(n, c)
|
||||
|
||||
|
||||
def create_devices(self):
|
||||
def createDevices(self):
|
||||
"""Create the devices for a vm.
|
||||
|
||||
@raise: VmError for invalid devices
|
||||
"""
|
||||
self.create_configured_devices()
|
||||
|
||||
for (n, c) in self.info['device']:
|
||||
self.createDevice(n, c)
|
||||
|
||||
if self.image:
|
||||
self.image.createDeviceModel()
|
||||
|
||||
|
||||
## public:
|
||||
|
||||
def device_create(self, dev_config):
|
||||
"""Create a new device.
|
||||
|
||||
@@ -1189,25 +1244,16 @@ class XendDomainInfo:
|
||||
self.reconfigureDevice(deviceClass, devid, dev_config)
|
||||
|
||||
|
||||
def pause(self):
|
||||
xc.domain_pause(self.domid)
|
||||
|
||||
|
||||
def unpause(self):
|
||||
xc.domain_unpause(self.domid)
|
||||
|
||||
|
||||
## private:
|
||||
|
||||
def restart_check(self):
|
||||
"""Check if domain restart is OK.
|
||||
To prevent restart loops, raise an error if it is
|
||||
less than MINIMUM_RESTART_TIME seconds since the last restart.
|
||||
"""
|
||||
tnow = time.time()
|
||||
if self.restart_time is not None:
|
||||
tdelta = tnow - self.restart_time
|
||||
if tdelta < self.MINIMUM_RESTART_TIME:
|
||||
self.restart_cancel()
|
||||
msg = 'VM %s restarting too fast' % self.info['name']
|
||||
log.error(msg)
|
||||
raise VmError(msg)
|
||||
self.restart_time = tnow
|
||||
self.restart_count += 1
|
||||
|
||||
|
||||
def restart(self, rename = False):
|
||||
"""Restart the domain after it has exited.
|
||||
|
||||
@@ -1215,8 +1261,6 @@ class XendDomainInfo:
|
||||
False if it is to be destroyed.
|
||||
"""
|
||||
|
||||
# self.restart_check()
|
||||
|
||||
config = self.sxpr()
|
||||
|
||||
if self.readVm('xend/restart_in_progress'):
|
||||
@@ -1228,17 +1272,33 @@ class XendDomainInfo:
|
||||
|
||||
self.writeVm('xend/restart_in_progress', 'True')
|
||||
|
||||
now = time.time()
|
||||
rst = self.readVm('xend/previous_restart_time')
|
||||
log.error(rst)
|
||||
if rst:
|
||||
rst = float(rst)
|
||||
timeout = now - rst
|
||||
if timeout < MINIMUM_RESTART_TIME:
|
||||
log.error(
|
||||
'VM %s restarting too fast (%f seconds since the last '
|
||||
'restart). Refusing to restart to avoid loops.',
|
||||
self.info['name'], timeout)
|
||||
self.destroy()
|
||||
return
|
||||
|
||||
self.writeVm('xend/previous_restart_time', str(now))
|
||||
|
||||
try:
|
||||
if rename:
|
||||
self.preserveForRestart()
|
||||
else:
|
||||
self.destroy()
|
||||
self.destroyDomain()
|
||||
|
||||
try:
|
||||
xd = get_component('xen.xend.XendDomain')
|
||||
new_dom = xd.domain_create(config)
|
||||
try:
|
||||
xc.domain_unpause(new_dom.getDomid())
|
||||
new_dom.unpause()
|
||||
except:
|
||||
new_dom.destroy()
|
||||
raise
|
||||
@@ -1259,12 +1319,13 @@ class XendDomainInfo:
|
||||
"""
|
||||
|
||||
new_name = self.generateUniqueName()
|
||||
new_uuid = getUuid()
|
||||
new_uuid = uuid.toString(uuid.create())
|
||||
log.info("Renaming dead domain %s (%d, %s) to %s (%s).",
|
||||
self.info['name'], self.domid, self.uuid, new_name, new_uuid)
|
||||
self.info['name'], self.domid, self.info['uuid'],
|
||||
new_name, new_uuid)
|
||||
self.release_devices()
|
||||
self.info['name'] = new_name
|
||||
self.uuid = new_uuid
|
||||
self.info['uuid'] = new_uuid
|
||||
self.vmpath = VMROOT + new_uuid
|
||||
self.storeVmDetails()
|
||||
self.preserve()
|
||||
@@ -1274,21 +1335,7 @@ class XendDomainInfo:
|
||||
log.info("Preserving dead domain %s (%d).", self.info['name'],
|
||||
self.domid)
|
||||
self.storeDom('xend/shutdown_completed', 'True')
|
||||
self.state_set(STATE_VM_TERMINATED)
|
||||
|
||||
|
||||
## public:
|
||||
|
||||
def renameUniquely(self):
|
||||
"""Rename this domain so that it has a unique name. This is used by
|
||||
XendDomain to recover from non-uniqueness errors; we should never have
|
||||
allowed the system to reach this state in the first place."""
|
||||
new_name = self.generateUniqueName()
|
||||
|
||||
log.error('Renaming %s (%d, %s) to %s', self.info['name'], self.domid,
|
||||
self.uuid, new_name)
|
||||
|
||||
self.setName(new_name)
|
||||
self.state_set(STATE_DOM_SHUTDOWN)
|
||||
|
||||
|
||||
# private:
|
||||
@@ -1304,18 +1351,6 @@ class XendDomainInfo:
|
||||
n += 1
|
||||
|
||||
|
||||
def generateZombieName(self):
|
||||
n = 0
|
||||
name = ZOMBIE_PREFIX + self.info['name']
|
||||
while True:
|
||||
try:
|
||||
self.check_name(name)
|
||||
return name
|
||||
except VmError:
|
||||
n += 1
|
||||
name = "%s%d-%s" % (ZOMBIE_PREFIX, n, self.info['name'])
|
||||
|
||||
|
||||
def configure_bootloader(self):
|
||||
if not self.info['bootloader']:
|
||||
return
|
||||
@@ -1337,75 +1372,12 @@ class XendDomainInfo:
|
||||
self.config = sxp.merge(['vm', ['image', blcfg]], self.config)
|
||||
|
||||
|
||||
def configure(self):
|
||||
"""Configure a vm.
|
||||
|
||||
"""
|
||||
self.configure_maxmem()
|
||||
self.create_devices()
|
||||
|
||||
|
||||
def configure_maxmem(self):
|
||||
if self.image:
|
||||
m = self.image.getDomainMemory(self.info['memory_KiB'])
|
||||
xc.domain_setmaxmem(self.domid, maxmem_kb = m)
|
||||
|
||||
|
||||
def vcpu_hotplug(self, vcpu, state):
|
||||
"""Disable or enable VCPU in domain.
|
||||
"""
|
||||
if vcpu > self.info['vcpus']:
|
||||
log.error("Invalid VCPU %d" % vcpu)
|
||||
return
|
||||
if int(state) == 0:
|
||||
self.info['vcpu_avail'] &= ~(1 << vcpu)
|
||||
availability = "offline"
|
||||
else:
|
||||
self.info['vcpu_avail'] &= (1 << vcpu)
|
||||
availability = "online"
|
||||
self.storeVm('vcpu_avail', self.info['vcpu_avail'])
|
||||
self.storeDom("cpu/%d/availability" % vcpu, availability)
|
||||
|
||||
|
||||
def send_sysrq(self, key):
|
||||
asserts.isCharConvertible(key)
|
||||
|
||||
self.storeDom("control/sysrq", '%c' % key)
|
||||
|
||||
|
||||
def initStoreConnection(self):
|
||||
ref = xc.init_store(self.store_channel)
|
||||
if ref and ref >= 0:
|
||||
self.setStoreRef(ref)
|
||||
try:
|
||||
IntroduceDomain(self.domid, ref, self.store_channel,
|
||||
self.dompath)
|
||||
except RuntimeError, ex:
|
||||
if ex.args[0] == errno.EISCONN:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def dom0_enforce_vcpus(self):
|
||||
dom = 0
|
||||
# get max number of vcpus to use for dom0 from config
|
||||
target = int(xroot.get_dom0_vcpus())
|
||||
log.debug("number of vcpus to use is %d", target)
|
||||
|
||||
# target = 0 means use all processors
|
||||
if target > 0:
|
||||
# count the number of online vcpus (cpu values in v2c map >= 0)
|
||||
vcpu_to_cpu = dom_get(dom)['vcpu_to_cpu']
|
||||
vcpus_online = len(filter(lambda x: x >= 0, vcpu_to_cpu))
|
||||
log.debug("found %d vcpus online", vcpus_online)
|
||||
|
||||
# disable any extra vcpus that are online over the requested target
|
||||
for vcpu in range(target, vcpus_online):
|
||||
log.info("enforcement is disabling DOM%d VCPU%d", dom, vcpu)
|
||||
self.vcpu_hotplug(vcpu, 0)
|
||||
|
||||
|
||||
def infoIsSet(self, name):
|
||||
return name in self.info and self.info[name] is not None
|
||||
|
||||
@@ -1417,25 +1389,16 @@ class XendDomainInfo:
|
||||
implements the device control specific to that device-class."""
|
||||
controllerClasses = {}
|
||||
|
||||
|
||||
"""A map of backend names and the corresponding flag."""
|
||||
backendFlags = {}
|
||||
|
||||
|
||||
def addControllerClass(device_class, backend_name, backend_flag, cls):
|
||||
def addControllerClass(device_class, cls):
|
||||
"""Register a subclass of DevController to handle the named device-class.
|
||||
|
||||
@param backend_flag One of the SIF_XYZ_BE_DOMAIN constants, or None if
|
||||
no flag is to be set.
|
||||
"""
|
||||
cls.deviceClass = device_class
|
||||
backendFlags[backend_name] = backend_flag
|
||||
controllerClasses[device_class] = cls
|
||||
|
||||
|
||||
from xen.xend.server import blkif, netif, tpmif, pciif, usbif
|
||||
addControllerClass('vbd', 'blkif', SIF_BLK_BE_DOMAIN, blkif.BlkifController)
|
||||
addControllerClass('vif', 'netif', SIF_NET_BE_DOMAIN, netif.NetifController)
|
||||
addControllerClass('vtpm', 'tpmif', SIF_TPM_BE_DOMAIN, tpmif.TPMifController)
|
||||
addControllerClass('pci', 'pciif', None, pciif.PciController)
|
||||
addControllerClass('usb', 'usbif', None, usbif.UsbifController)
|
||||
addControllerClass('vbd', blkif.BlkifController)
|
||||
addControllerClass('vif', netif.NetifController)
|
||||
addControllerClass('vtpm', tpmif.TPMifController)
|
||||
addControllerClass('pci', pciif.PciController)
|
||||
addControllerClass('usb', usbif.UsbifController)
|
||||
@@ -27,6 +27,14 @@ __all__ = [ 'log', 'init', 'getLogFilename', 'addLogStderr',
|
||||
'removeLogStderr' ]
|
||||
|
||||
|
||||
if not 'TRACE' in logging.__dict__:
|
||||
logging.TRACE = logging.DEBUG - 1
|
||||
logging.addLevelName(logging.TRACE,'TRACE')
|
||||
def trace(self, *args, **kwargs):
|
||||
self.log(logging.TRACE, *args, **kwargs)
|
||||
logging.Logger.trace = trace
|
||||
|
||||
|
||||
log = logging.getLogger("xend")
|
||||
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ class XendRoot:
|
||||
xend_address_default = ''
|
||||
|
||||
"""Default for the flag indicating whether xend should run a relocation server."""
|
||||
xend_relocation_server_default = 'yes'
|
||||
xend_relocation_server_default = 'no'
|
||||
|
||||
"""Default interface address the xend relocation server listens at. """
|
||||
xend_relocation_address_default = ''
|
||||
@@ -243,30 +243,36 @@ class XendRoot:
|
||||
"""
|
||||
return self.get_config_value("xend-unix-path", self.xend_unix_path_default)
|
||||
|
||||
def get_block_script(self, type):
|
||||
return self.get_config_value('block-%s' % type, '')
|
||||
|
||||
def get_network_script(self):
|
||||
return self.get_config_value('network-script', '')
|
||||
"""@return the script used to alter the network configuration when
|
||||
Xend starts and stops, or None if no such script is specified."""
|
||||
|
||||
s = self.get_config_value('network-script')
|
||||
|
||||
if s:
|
||||
return os.path.join(self.network_script_dir, s)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_enable_dump(self):
|
||||
return self.get_config_bool('enable-dump', 'no')
|
||||
|
||||
def get_vif_bridge(self):
|
||||
return self.get_config_value('vif-bridge', 'xen-br0')
|
||||
return self.get_config_value('vif-bridge', 'xenbr0')
|
||||
|
||||
def get_vif_script(self):
|
||||
return self.get_config_value('vif-script', 'vif-bridge')
|
||||
|
||||
def get_vif_antispoof(self):
|
||||
return self.get_config_bool('vif-antispoof', 'yes')
|
||||
|
||||
def get_dom0_min_mem(self):
|
||||
return self.get_config_int('dom0-min-mem', self.dom0_min_mem_default)
|
||||
|
||||
def get_dom0_vcpus(self):
|
||||
return self.get_config_int('dom0-cpus', self.dom0_vcpus_default)
|
||||
|
||||
def get_console_limit(self):
|
||||
return self.get_config_int('console-limit', 1024)
|
||||
|
||||
def instance():
|
||||
"""Get an instance of XendRoot.
|
||||
Use this instead of the constructor.
|
||||
|
||||
@@ -66,7 +66,6 @@ class ImageHandler:
|
||||
self.kernel = None
|
||||
self.ramdisk = None
|
||||
self.cmdline = None
|
||||
self.flags = 0
|
||||
|
||||
self.configure(imageConfig, deviceConfig)
|
||||
|
||||
@@ -112,13 +111,13 @@ class ImageHandler:
|
||||
"""Entry point to create domain memory image.
|
||||
Override in subclass if needed.
|
||||
"""
|
||||
self.createDomain()
|
||||
return self.createDomain()
|
||||
|
||||
|
||||
def createDomain(self):
|
||||
"""Build the domain boot image.
|
||||
"""
|
||||
# Set params and call buildDomain().
|
||||
self.flags = self.vm.getBackendFlags()
|
||||
|
||||
if not os.path.isfile(self.kernel):
|
||||
raise VmError('Kernel image does not exist: %s' % self.kernel)
|
||||
@@ -130,10 +129,15 @@ class ImageHandler:
|
||||
|
||||
log.info("buildDomain os=%s dom=%d vcpus=%d", self.ostype,
|
||||
self.vm.getDomid(), self.vm.getVCpuCount())
|
||||
err = self.buildDomain()
|
||||
if err != 0:
|
||||
raise VmError('Building domain failed: ostype=%s dom=%d err=%d'
|
||||
% (self.ostype, self.vm.getDomid(), err))
|
||||
|
||||
result = self.buildDomain()
|
||||
|
||||
if isinstance(result, dict):
|
||||
return result
|
||||
else:
|
||||
raise VmError('Building domain failed: ostype=%s dom=%d err=%s'
|
||||
% (self.ostype, self.vm.getDomid(), str(result)))
|
||||
|
||||
|
||||
def getDomainMemory(self, mem):
|
||||
"""@return The memory required, in KiB, by the domain to store the
|
||||
@@ -153,26 +157,14 @@ class ImageHandler:
|
||||
"""Extra cleanup on domain destroy (define in subclass if needed)."""
|
||||
pass
|
||||
|
||||
def set_vminfo(self, d):
|
||||
if d.has_key('store_mfn'):
|
||||
self.vm.setStoreRef(d.get('store_mfn'))
|
||||
if d.has_key('console_mfn'):
|
||||
self.vm.setConsoleRef(d.get('console_mfn'))
|
||||
|
||||
|
||||
class LinuxImageHandler(ImageHandler):
|
||||
|
||||
ostype = "linux"
|
||||
|
||||
def buildDomain(self):
|
||||
if self.vm.store_channel:
|
||||
store_evtchn = self.vm.store_channel
|
||||
else:
|
||||
store_evtchn = 0
|
||||
if self.vm.console_channel:
|
||||
console_evtchn = self.vm.console_channel
|
||||
else:
|
||||
console_evtchn = 0
|
||||
store_evtchn = self.vm.getStorePort()
|
||||
console_evtchn = self.vm.getConsolePort()
|
||||
|
||||
log.debug("dom = %d", self.vm.getDomid())
|
||||
log.debug("image = %s", self.kernel)
|
||||
@@ -180,21 +172,14 @@ class LinuxImageHandler(ImageHandler):
|
||||
log.debug("console_evtchn = %d", console_evtchn)
|
||||
log.debug("cmdline = %s", self.cmdline)
|
||||
log.debug("ramdisk = %s", self.ramdisk)
|
||||
log.debug("flags = %d", self.flags)
|
||||
log.debug("vcpus = %d", self.vm.getVCpuCount())
|
||||
|
||||
ret = xc.linux_build(dom = self.vm.getDomid(),
|
||||
image = self.kernel,
|
||||
store_evtchn = store_evtchn,
|
||||
console_evtchn = console_evtchn,
|
||||
cmdline = self.cmdline,
|
||||
ramdisk = self.ramdisk,
|
||||
flags = self.flags,
|
||||
vcpus = self.vm.getVCpuCount())
|
||||
if isinstance(ret, dict):
|
||||
self.set_vminfo(ret)
|
||||
return 0
|
||||
return ret
|
||||
return xc.linux_build(dom = self.vm.getDomid(),
|
||||
image = self.kernel,
|
||||
store_evtchn = store_evtchn,
|
||||
console_evtchn = console_evtchn,
|
||||
cmdline = self.cmdline,
|
||||
ramdisk = self.ramdisk)
|
||||
|
||||
class VmxImageHandler(ImageHandler):
|
||||
|
||||
@@ -219,45 +204,33 @@ class VmxImageHandler(ImageHandler):
|
||||
self.dmargs += self.configVNC(imageConfig)
|
||||
|
||||
|
||||
def createImage(self):
|
||||
"""Create a VM for the VMX environment.
|
||||
"""
|
||||
self.createDomain()
|
||||
|
||||
def buildDomain(self):
|
||||
# Create an event channel
|
||||
self.device_channel = xc.evtchn_alloc_unbound(dom=self.vm.getDomid(),
|
||||
remote_dom=0)
|
||||
log.info("VMX device model port: %d", self.device_channel)
|
||||
if self.vm.store_channel:
|
||||
store_evtchn = self.vm.store_channel
|
||||
else:
|
||||
store_evtchn = 0
|
||||
|
||||
store_evtchn = self.vm.getStorePort()
|
||||
|
||||
log.debug("dom = %d", self.vm.getDomid())
|
||||
log.debug("image = %s", self.kernel)
|
||||
log.debug("control_evtchn = %d", self.device_channel)
|
||||
log.debug("store_evtchn = %d", store_evtchn)
|
||||
log.debug("memsize = %d", self.vm.getMemoryTarget() / 1024)
|
||||
log.debug("flags = %d", self.flags)
|
||||
log.debug("vcpus = %d", self.vm.getVCpuCount())
|
||||
|
||||
ret = xc.vmx_build(dom = self.vm.getDomid(),
|
||||
image = self.kernel,
|
||||
control_evtchn = self.device_channel,
|
||||
store_evtchn = store_evtchn,
|
||||
memsize = self.vm.getMemoryTarget() / 1024,
|
||||
flags = self.flags,
|
||||
vcpus = self.vm.getVCpuCount())
|
||||
if isinstance(ret, dict):
|
||||
self.set_vminfo(ret)
|
||||
return 0
|
||||
return ret
|
||||
return xc.vmx_build(dom = self.vm.getDomid(),
|
||||
image = self.kernel,
|
||||
control_evtchn = self.device_channel,
|
||||
store_evtchn = store_evtchn,
|
||||
memsize = self.vm.getMemoryTarget() / 1024,
|
||||
vcpus = self.vm.getVCpuCount())
|
||||
|
||||
|
||||
# Return a list of cmd line args to the device models based on the
|
||||
# xm config file
|
||||
def parseDeviceModelArgs(self, imageConfig, deviceConfig):
|
||||
dmargs = [ 'cdrom', 'boot', 'fda', 'fdb',
|
||||
dmargs = [ 'cdrom', 'boot', 'fda', 'fdb', 'ne2000',
|
||||
'localtime', 'serial', 'stdvga', 'isa', 'vcpus' ]
|
||||
ret = []
|
||||
for a in dmargs:
|
||||
@@ -265,15 +238,17 @@ class VmxImageHandler(ImageHandler):
|
||||
|
||||
# python doesn't allow '-' in variable names
|
||||
if a == 'stdvga': a = 'std-vga'
|
||||
if a == 'ne2000': a = 'nic-ne2000'
|
||||
|
||||
# Handle booleans gracefully
|
||||
if a in ['localtime', 'std-vga', 'isa']:
|
||||
if a in ['localtime', 'std-vga', 'isa', 'nic-ne2000']:
|
||||
if v != None: v = int(v)
|
||||
|
||||
if v: ret.append("-%s" % a)
|
||||
else:
|
||||
if v:
|
||||
ret.append("-%s" % a)
|
||||
ret.append("%s" % v)
|
||||
log.debug("args: %s, val: %s" % (a,v))
|
||||
if v:
|
||||
ret.append("-%s" % a)
|
||||
ret.append("%s" % v)
|
||||
|
||||
# Handle disk/network related options
|
||||
for (name, info) in deviceConfig:
|
||||
@@ -337,7 +312,8 @@ class VmxImageHandler(ImageHandler):
|
||||
"-m", "%s" % (self.vm.getMemoryTarget() / 1024)])
|
||||
args = args + self.dmargs
|
||||
env = dict(os.environ)
|
||||
env['DISPLAY'] = self.display
|
||||
if self.display:
|
||||
env['DISPLAY'] = self.display
|
||||
log.info("spawning device models: %s %s", self.device_model, args)
|
||||
self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env)
|
||||
log.info("device model pid: %d", self.pid)
|
||||
|
||||
@@ -82,7 +82,7 @@ class DevController:
|
||||
if backpath:
|
||||
xstransact.Remove(backpath)
|
||||
else:
|
||||
raise VmError("Device not connected")
|
||||
raise VmError("Device %s not connected" % devid)
|
||||
|
||||
|
||||
def configurations(self):
|
||||
@@ -160,7 +160,7 @@ class DevController:
|
||||
if result:
|
||||
result = int(result)
|
||||
else:
|
||||
result = 1
|
||||
result = 0
|
||||
t.write("nextDeviceID", str(result + 1))
|
||||
if t.commit():
|
||||
return result
|
||||
|
||||
@@ -14,6 +14,8 @@ import pwd
|
||||
import re
|
||||
import traceback
|
||||
|
||||
import xen.lowlevel.xc
|
||||
|
||||
from xen.xend.server import SrvServer
|
||||
from xen.xend.XendLogging import log
|
||||
|
||||
@@ -32,34 +34,6 @@ class Daemon:
|
||||
self.traceindent = 0
|
||||
self.child = 0
|
||||
|
||||
def daemon_pids(self):
|
||||
pids = []
|
||||
pidex = '(?P<pid>\d+)'
|
||||
pythonex = '(?P<python>\S*python\S*)'
|
||||
cmdex = '(?P<cmd>.*)'
|
||||
procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex + '$')
|
||||
xendre = re.compile('^\S+/xend\s*(start|restart)\s*.*$')
|
||||
procs = os.popen('ps -e -o pid,args 2>/dev/null')
|
||||
for proc in procs:
|
||||
pm = procre.match(proc)
|
||||
if not pm: continue
|
||||
xm = xendre.match(pm.group('cmd'))
|
||||
if not xm: continue
|
||||
pids.append(int(pm.group('pid')))
|
||||
return pids
|
||||
|
||||
def new_cleanup(self, kill=0):
|
||||
err = 0
|
||||
pids = self.daemon_pids()
|
||||
if kill:
|
||||
for pid in pids:
|
||||
print "Killing daemon pid=%d" % pid
|
||||
os.kill(pid, signal.SIGHUP)
|
||||
elif pids:
|
||||
err = 1
|
||||
print "Daemon already running: ", pids
|
||||
return err
|
||||
|
||||
def read_pid(self, pidfile):
|
||||
"""Read process id from a file.
|
||||
|
||||
@@ -115,12 +89,9 @@ class Daemon:
|
||||
os.remove(pidfile)
|
||||
return running
|
||||
|
||||
def cleanup_xend(self, kill=False):
|
||||
def cleanup_xend(self, kill):
|
||||
return self.cleanup_process(XEND_PID_FILE, "xend", kill)
|
||||
|
||||
def cleanup(self, kill=False):
|
||||
self.cleanup_xend(kill=kill)
|
||||
|
||||
def status(self):
|
||||
"""Returns the status of the xend daemon.
|
||||
The return value is defined by the LSB:
|
||||
@@ -156,16 +127,13 @@ class Daemon:
|
||||
# Detach from TTY.
|
||||
os.setsid()
|
||||
|
||||
# Detach from standard file descriptors.
|
||||
# I do this at the file-descriptor level: the overlying Python file
|
||||
# objects also use fd's 0, 1 and 2.
|
||||
# Detach from standard file descriptors, and redirect them to
|
||||
# /dev/null or the log as appropriate.
|
||||
os.close(0)
|
||||
os.close(1)
|
||||
os.close(2)
|
||||
if XEND_DEBUG:
|
||||
os.open('/dev/null', os.O_RDONLY)
|
||||
# XXX KAF: Why doesn't this capture output from C extensions that
|
||||
# fprintf(stdout) or fprintf(stderr) ??
|
||||
os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT)
|
||||
os.dup(1)
|
||||
else:
|
||||
@@ -180,7 +148,7 @@ class Daemon:
|
||||
0 Success
|
||||
4 Insufficient privileges
|
||||
"""
|
||||
xend_pid = self.cleanup_xend()
|
||||
xend_pid = self.cleanup_xend(False)
|
||||
|
||||
if self.set_user():
|
||||
return 4
|
||||
@@ -294,11 +262,20 @@ class Daemon:
|
||||
return 1
|
||||
|
||||
def stop(self):
|
||||
return self.cleanup(kill=True)
|
||||
result = self.cleanup_xend(True)
|
||||
from xen.xend import Vifctl
|
||||
Vifctl.network("stop")
|
||||
return result
|
||||
|
||||
def run(self, status):
|
||||
try:
|
||||
log.info("Xend Daemon started")
|
||||
|
||||
xc = xen.lowlevel.xc.new()
|
||||
xinfo = xc.xeninfo()
|
||||
log.info("Xend changeset: %s.", xinfo['xen_changeset'])
|
||||
del xc
|
||||
|
||||
event.listenEvent(self)
|
||||
relocate.listenRelocation()
|
||||
servers = SrvServer.create()
|
||||
|
||||
@@ -89,7 +89,7 @@ class SrvDomain(SrvDir):
|
||||
fn = FormFn(self.xd.domain_pincpu,
|
||||
[['dom', 'int'],
|
||||
['vcpu', 'int'],
|
||||
['cpumap', 'int']])
|
||||
['cpumap', 'str']])
|
||||
val = fn(req.args, {'dom': self.dom.domid})
|
||||
return val
|
||||
|
||||
@@ -105,6 +105,13 @@ class SrvDomain(SrvDir):
|
||||
return val
|
||||
|
||||
|
||||
def op_cpu_sedf_get(self, op, req):
|
||||
fn = FormFn(self.xd.domain_cpu_sedf_get,
|
||||
[['dom', 'int']])
|
||||
val = fn(req.args, {'dom': self.dom.domid})
|
||||
return val
|
||||
|
||||
|
||||
def op_cpu_sedf_set(self, op, req):
|
||||
fn = FormFn(self.xd.domain_cpu_sedf_set,
|
||||
[['dom', 'int'],
|
||||
@@ -146,13 +153,13 @@ class SrvDomain(SrvDir):
|
||||
def op_device_destroy(self, op, req):
|
||||
return self.call(self.dom.destroyDevice,
|
||||
[['type', 'str'],
|
||||
['dev', 'int']],
|
||||
['dev', 'str']],
|
||||
req)
|
||||
|
||||
def op_device_configure(self, op, req):
|
||||
return self.call(self.dom.device_configure,
|
||||
[['config', 'sxpr'],
|
||||
['dev', 'int']],
|
||||
['dev', 'str']],
|
||||
req)
|
||||
|
||||
|
||||
@@ -165,17 +172,25 @@ class SrvDomain(SrvDir):
|
||||
val = fn(req.args, {'dom': self.dom.domid})
|
||||
return val
|
||||
|
||||
def op_vcpu_hotplug(self, op, req):
|
||||
return self.call(self.dom.vcpu_hotplug,
|
||||
[['vcpu', 'int'],
|
||||
['state', 'int']],
|
||||
def op_set_vcpus(self, op, req):
|
||||
return self.call(self.dom.setVCpuCount,
|
||||
[['vcpus', 'int']],
|
||||
req)
|
||||
|
||||
|
||||
def op_vcpuinfo(self, _1, req):
|
||||
return self.call(self.dom.getVCPUInfo, [], req)
|
||||
|
||||
|
||||
def render_POST(self, req):
|
||||
return self.perform(req)
|
||||
|
||||
def render_GET(self, req):
|
||||
op = req.args.get('op')
|
||||
|
||||
if op and op[0] in ['vcpuinfo']:
|
||||
return self.perform(req)
|
||||
|
||||
#
|
||||
# XXX SMH: below may be useful once again if we ever try to get
|
||||
# the raw 'web' interface to xend working once more. But for now
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
# todo Support security settings etc. in the config file.
|
||||
# todo Support command-line args.
|
||||
|
||||
import fcntl
|
||||
from threading import Thread
|
||||
|
||||
from xen.web.httpserver import HttpServer, UnixHttpServer
|
||||
@@ -64,6 +65,11 @@ class XendServers:
|
||||
self.servers.append(server)
|
||||
|
||||
def start(self, status):
|
||||
# Running the network script will spawn another process, which takes
|
||||
# the status fd with it unless we set FD_CLOEXEC. Failing to do this
|
||||
# causes the read in SrvDaemon to hang even when we have written here.
|
||||
fcntl.fcntl(status, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
|
||||
|
||||
Vifctl.network('start')
|
||||
threads = []
|
||||
for server in self.servers:
|
||||
|
||||
@@ -22,8 +22,9 @@ import string
|
||||
|
||||
from xen.util import blkif
|
||||
from xen.xend import sxp
|
||||
from xen.xend.XendError import VmError
|
||||
|
||||
from DevController import DevController
|
||||
from xen.xend.server.DevController import DevController
|
||||
|
||||
|
||||
class BlkifController(DevController):
|
||||
@@ -96,6 +97,4 @@ class BlkifController(DevController):
|
||||
if self.readBackend(i, 'dev') == devid:
|
||||
DevController.destroyDevice(self, i)
|
||||
return
|
||||
# Try this, but it's almost certainly going to throw VmError,
|
||||
# since we can't find the device.
|
||||
DevController.destroyDevice(self, int(devid))
|
||||
raise VmError("Device %s not connected" % devid)
|
||||
@@ -0,0 +1,30 @@
|
||||
import unittest
|
||||
|
||||
from xen.xend import uuid
|
||||
|
||||
|
||||
class test_uuid(unittest.TestCase):
|
||||
|
||||
def testStringRoundtrip(self):
|
||||
def t(inp):
|
||||
self.assertEqual(uuid.fromString(uuid.toString(inp)), inp)
|
||||
|
||||
t(uuid.create())
|
||||
t(uuid.create())
|
||||
t(uuid.create())
|
||||
t(uuid.create())
|
||||
t(uuid.create())
|
||||
|
||||
|
||||
def testToFromString(self):
|
||||
def t(inp, expected):
|
||||
self.assertEqual(uuid.toString(inp), expected)
|
||||
self.assertEqual(uuid.fromString(expected), inp)
|
||||
|
||||
t([0 for i in range(0, 16)], "00000000-0000-0000-0000-000000000000")
|
||||
t([185, 158, 125, 206, 250, 178, 125, 57, 2, 6, 162, 74, 178, 236,
|
||||
196, 5], "b99e7dce-fab2-7d39-0206-a24ab2ecc405")
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.makeSuite(test_uuid)
|
||||
@@ -36,23 +36,27 @@ def getUuidUuidgen(random = True):
|
||||
cmd += " -r"
|
||||
else:
|
||||
cmd += " -t"
|
||||
return commands.getoutput(cmd)
|
||||
return fromString(commands.getoutput(cmd))
|
||||
|
||||
|
||||
def getUuidRandom():
|
||||
"""Generate a random UUID."""
|
||||
|
||||
bytes = [ random.randint(0, 255) for i in range(0, 16) ]
|
||||
# Encode the variant.
|
||||
bytes[6] = (bytes[6] & 0x0f) | 0x40
|
||||
bytes[8] = (bytes[8] & 0x3f) | 0x80
|
||||
f = "%02x"
|
||||
return ( "-".join([f*4, f*2, f*2, f*2, f*6]) % tuple(bytes) )
|
||||
return [ random.randint(0, 255) for i in range(0, 16) ]
|
||||
|
||||
|
||||
#uuidFactory = getUuidUuidgen
|
||||
uuidFactory = getUuidRandom
|
||||
|
||||
|
||||
def getUuid():
|
||||
def create():
|
||||
return uuidFactory()
|
||||
|
||||
|
||||
def toString(u):
|
||||
f = "%02x"
|
||||
return ( "-".join([f*4, f*2, f*2, f*2, f*6]) % tuple(u) )
|
||||
|
||||
def fromString(s):
|
||||
s = s.replace('-', '')
|
||||
return [ int(s[i : i + 2], 16) for i in range(0, 32, 2) ]
|
||||
@@ -14,6 +14,9 @@ from xen.xend.xenstore.xsutil import xshandle
|
||||
class xstransact:
|
||||
|
||||
def __init__(self, path):
|
||||
self.in_transaction = False # Set this temporarily -- if this
|
||||
# constructor fails, then we need to
|
||||
# protect __del__.
|
||||
self.path = path.rstrip("/")
|
||||
self.transaction = xshandle().transaction_start()
|
||||
self.in_transaction = True
|
||||
|
||||
@@ -19,8 +19,8 @@ def xshandle():
|
||||
xs_lock.release()
|
||||
return xs_handle
|
||||
|
||||
def IntroduceDomain(domid, page, port, path):
|
||||
return xshandle().introduce_domain(domid, page, port, path)
|
||||
def IntroduceDomain(domid, page, port):
|
||||
return xshandle().introduce_domain(domid, page, port)
|
||||
|
||||
def GetDomainPath(domid):
|
||||
return xshandle().get_domain_path(domid)
|
||||
@@ -10,6 +10,9 @@ import threading
|
||||
from xen.lowlevel import xs
|
||||
from xen.xend.xenstore.xsutil import xshandle
|
||||
|
||||
from xen.xend.XendLogging import log
|
||||
|
||||
|
||||
class xswatch:
|
||||
|
||||
watchThread = None
|
||||
@@ -41,10 +44,13 @@ class xswatch:
|
||||
while True:
|
||||
try:
|
||||
we = cls.xs.read_watch()
|
||||
except RuntimeError, ex:
|
||||
print ex
|
||||
raise
|
||||
watch = we[1]
|
||||
watch.fn(*watch.args, **watch.kwargs)
|
||||
watch = we[1]
|
||||
watch.fn(*watch.args, **watch.kwargs)
|
||||
except:
|
||||
log.exception("read_watch failed")
|
||||
# Ignore this exception -- there's no point throwing it
|
||||
# further on because that will just kill the watcher thread,
|
||||
# which achieves nothing.
|
||||
|
||||
|
||||
watchMain = classmethod(watchMain)
|
||||
@@ -364,6 +364,10 @@ gopts.var('nographic', val='no|yes',
|
||||
fn=set_bool, default=0,
|
||||
use="Should device models use graphics?")
|
||||
|
||||
gopts.var('ne2000', val='no|yes',
|
||||
fn=set_bool, default=0,
|
||||
use="Should device models use ne2000?")
|
||||
|
||||
gopts.var('vnc', val='',
|
||||
fn=set_value, default=None,
|
||||
use="""Should the device model use VNC?""")
|
||||
@@ -540,7 +544,7 @@ def configure_vmx(opts, config_image, vals):
|
||||
"""
|
||||
args = [ 'memmap', 'device_model', 'vcpus', 'cdrom',
|
||||
'boot', 'fda', 'fdb', 'localtime', 'serial', 'macaddr', 'stdvga',
|
||||
'isa', 'nographic', 'vnc', 'vncviewer', 'sdl', 'display']
|
||||
'isa', 'nographic', 'vnc', 'vncviewer', 'sdl', 'display', 'ne2000']
|
||||
for a in args:
|
||||
if (vals.__dict__[a]):
|
||||
config_image.append([a, vals.__dict__[a]])
|
||||
|
||||
+173
-107
@@ -71,8 +71,7 @@ longhelp = """Usage: xm <subcommand> [args]
|
||||
xm full list of subcommands:
|
||||
|
||||
Domain Commands:
|
||||
console <DomId> attach to console of DomId
|
||||
cpus-list <DomId> <VCpu> get the list of cpus for a VCPU
|
||||
console <DomId> attach to console of DomId
|
||||
create <ConfigFile> create a domain
|
||||
destroy <DomId> terminate a domain immediately
|
||||
domid <DomName> convert a domain name to a domain id
|
||||
@@ -88,10 +87,9 @@ xm full list of subcommands:
|
||||
shutdown [-w|-a] <DomId> shutdown a domain
|
||||
sysrq <DomId> <letter> send a sysrq to a domain
|
||||
unpause <DomId> unpause a paused domain
|
||||
vcpu-enable <DomId> <VCPU> enable VCPU in a domain
|
||||
vcpu-disable <DomId> <VCPU> disable VCPU in a domain
|
||||
vcpu-list <DomId> get the list of VCPUs for a domain
|
||||
vcpu-pin <DomId> <VCpu> <CPUS> set which cpus a VCPU can use.
|
||||
set-vcpus <DomId> <VCPUs> enable the specified number of VCPUs in a domain
|
||||
vcpu-list <DomId> list the VCPUs for a domain
|
||||
vcpu-pin <DomId> <VCPU> <CPUs> set which cpus a VCPU can use.
|
||||
|
||||
Xen Host Commands:
|
||||
dmesg [--clear] read or clear Xen's message buffer
|
||||
@@ -169,11 +167,9 @@ def handle_xend_error(cmd, dom, ex):
|
||||
if error == "Not found" and dom != None:
|
||||
err("Domain '%s' not found when running 'xm %s'" % (dom, cmd))
|
||||
sys.exit(1)
|
||||
elif error == "Exception: Device not connected":
|
||||
err("Device not connected")
|
||||
sys.exit(1)
|
||||
else:
|
||||
raise ex
|
||||
err(error)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
#########################################################################
|
||||
@@ -211,6 +207,15 @@ def xm_restore(args):
|
||||
if id is not None:
|
||||
server.xend_domain_unpause(domid)
|
||||
|
||||
|
||||
def getDomains(domain_names):
|
||||
from xen.xend.XendClient import server
|
||||
if domain_names:
|
||||
return map(server.xend_domain, domain_names)
|
||||
else:
|
||||
return server.xend_list_domains()
|
||||
|
||||
|
||||
def xm_list(args):
|
||||
use_long = 0
|
||||
show_vcpus = 0
|
||||
@@ -220,80 +225,161 @@ def xm_list(args):
|
||||
err(opterr)
|
||||
sys.exit(1)
|
||||
|
||||
n = len(params)
|
||||
for (k, v) in options:
|
||||
if k in ['-l', '--long']:
|
||||
use_long = 1
|
||||
if k in ['-v', '--vcpus']:
|
||||
show_vcpus = 1
|
||||
|
||||
from xen.xend.XendClient import server
|
||||
if n == 0:
|
||||
doms = server.xend_list_domains()
|
||||
else:
|
||||
doms = map(server.xend_domain, params)
|
||||
|
||||
if use_long:
|
||||
for dom in doms:
|
||||
PrettyPrint.prettyprint(doms)
|
||||
else:
|
||||
domsinfo = map(parse_doms_info, doms)
|
||||
if show_vcpus:
|
||||
print >>sys.stderr, (
|
||||
"xm list -v is deprecated. Please use xm vcpu-list.")
|
||||
xm_vcpu_list(params)
|
||||
return
|
||||
|
||||
doms = getDomains(params)
|
||||
|
||||
if use_long:
|
||||
map(PrettyPrint.prettyprint, doms)
|
||||
else:
|
||||
xm_brief_list(doms)
|
||||
|
||||
if show_vcpus:
|
||||
xm_show_vcpus(domsinfo)
|
||||
else:
|
||||
xm_brief_list(domsinfo)
|
||||
|
||||
def parse_doms_info(info):
|
||||
dominfo = {}
|
||||
dominfo['dom'] = int(sxp.child_value(info, 'domid', '-1'))
|
||||
dominfo['name'] = sxp.child_value(info, 'name', '??')
|
||||
dominfo['mem'] = int(sxp.child_value(info, 'memory', '0'))
|
||||
dominfo['cpu'] = str(sxp.child_value(info, 'cpu', '0'))
|
||||
dominfo['vcpus'] = int(sxp.child_value(info, 'vcpus', '0'))
|
||||
# if there is more than 1 cpu, the value doesn't mean much
|
||||
if dominfo['vcpus'] > 1:
|
||||
dominfo['cpu'] = '-'
|
||||
dominfo['state'] = sxp.child_value(info, 'state', '??')
|
||||
dominfo['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
|
||||
# security identifiers
|
||||
if ((int(sxp.child_value(info, 'ssidref', '0'))) != 0):
|
||||
dominfo['ssidref1'] = int(sxp.child_value(info, 'ssidref', '0')) & 0xffff
|
||||
dominfo['ssidref2'] = (int(sxp.child_value(info, 'ssidref', '0')) >> 16) & 0xffff
|
||||
# get out the vcpu information
|
||||
dominfo['vcpulist'] = []
|
||||
vcpu_to_cpu = sxp.child_value(info, 'vcpu_to_cpu', '-1').split('|')
|
||||
cpumap = sxp.child_value(info, 'cpumap', [])
|
||||
mask = ((int(sxp.child_value(info, 'vcpus', '0')))**2) - 1
|
||||
count = 0
|
||||
for cpu in vcpu_to_cpu:
|
||||
vcpuinfo = {}
|
||||
vcpuinfo['name'] = sxp.child_value(info, 'name', '??')
|
||||
vcpuinfo['dom'] = int(sxp.child_value(info, 'domid', '-1'))
|
||||
vcpuinfo['vcpu'] = int(count)
|
||||
vcpuinfo['cpu'] = int(cpu)
|
||||
vcpuinfo['cpumap'] = int(cpumap[count])&mask
|
||||
count = count + 1
|
||||
dominfo['vcpulist'].append(vcpuinfo)
|
||||
return dominfo
|
||||
|
||||
def xm_brief_list(domsinfo):
|
||||
print 'Name ID Mem(MiB) CPU VCPUs State Time(s)'
|
||||
for dominfo in domsinfo:
|
||||
if dominfo.has_key("ssidref1"):
|
||||
print ("%(name)-16s %(dom)3d %(mem)8d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f s:%(ssidref2)02x/p:%(ssidref1)02x" % dominfo)
|
||||
else:
|
||||
print ("%(name)-16s %(dom)3d %(mem)8d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f" % dominfo)
|
||||
def get_info(n, t, d):
|
||||
return t(sxp.child_value(info, n, d))
|
||||
|
||||
return {
|
||||
'dom' : get_info('domid', int, -1),
|
||||
'name' : get_info('name', str, '??'),
|
||||
'mem' : get_info('memory', int, 0),
|
||||
'vcpus' : get_info('vcpus', int, 0),
|
||||
'state' : get_info('state', str, '??'),
|
||||
'cpu_time' : get_info('cpu_time', float, 0),
|
||||
'ssidref' : get_info('ssidref', int, 0),
|
||||
}
|
||||
|
||||
|
||||
def xm_brief_list(doms):
|
||||
print 'Name ID Mem(MiB) VCPUs State Time(s)'
|
||||
for dom in doms:
|
||||
d = parse_doms_info(dom)
|
||||
if (d['ssidref'] != 0):
|
||||
d['ssidstr'] = (" s:%04x/p:%04x" %
|
||||
((d['ssidref'] >> 16) & 0xffff,
|
||||
d['ssidref'] & 0xffff))
|
||||
else:
|
||||
d['ssidstr'] = ""
|
||||
print ("%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s %(cpu_time)7.1f%(ssidstr)s" % d)
|
||||
|
||||
def xm_show_vcpus(domsinfo):
|
||||
print 'Name Id VCPU CPU CPUMAP'
|
||||
for dominfo in domsinfo:
|
||||
for vcpuinfo in dominfo['vcpulist']:
|
||||
print ("%(name)-16s %(dom)3d %(vcpu)4d %(cpu)3d 0x%(cpumap)x" %
|
||||
vcpuinfo)
|
||||
|
||||
def xm_vcpu_list(args):
|
||||
xm_list(["-v"] + args)
|
||||
print 'Name ID VCPU CPU State Time(s) CPU Affinity'
|
||||
|
||||
from xen.xend.XendClient import server
|
||||
if args:
|
||||
dominfo = map(server.xend_domain_vcpuinfo, args)
|
||||
else:
|
||||
doms = server.xend_list_domains()
|
||||
dominfo = map(
|
||||
lambda x: server.xend_domain_vcpuinfo(sxp.child_value(x, 'name')),
|
||||
doms)
|
||||
|
||||
for dom in dominfo:
|
||||
def get_info(n):
|
||||
return sxp.child_value(dom, n)
|
||||
|
||||
#
|
||||
# convert a list of integers into a list of pairs indicating
|
||||
# continuous sequences in the list:
|
||||
#
|
||||
# [0,1,2,3] -> [(0,3)]
|
||||
# [1,2,4,5] -> [(1,2),(4,5)]
|
||||
# [0] -> [(0,0)]
|
||||
# [0,1,4,6,7] -> [(0,1),(4,4),(6,7)]
|
||||
#
|
||||
def list_to_rangepairs(cmap):
|
||||
cmap.sort()
|
||||
pairs = []
|
||||
x = y = 0
|
||||
for i in range(0,len(cmap)):
|
||||
try:
|
||||
if ((cmap[y+1] - cmap[i]) > 1):
|
||||
pairs.append((cmap[x],cmap[y]))
|
||||
x = y = i+1
|
||||
else:
|
||||
y = y + 1
|
||||
# if we go off the end, then just add x to y
|
||||
except IndexError:
|
||||
pairs.append((cmap[x],cmap[y]))
|
||||
|
||||
return pairs
|
||||
|
||||
#
|
||||
# Convert pairs to range string, e.g: [(1,2),(3,3),(5,7)] -> 1-2,3,5-7
|
||||
#
|
||||
def format_pairs(pairs):
|
||||
if not pairs:
|
||||
return "no cpus"
|
||||
out = ""
|
||||
for f,s in pairs:
|
||||
if (f==s):
|
||||
out += '%d'%f
|
||||
else:
|
||||
out += '%d-%d'%(f,s)
|
||||
out += ','
|
||||
# trim trailing ','
|
||||
return out[:-1]
|
||||
|
||||
def format_cpumap(cpumap):
|
||||
cpumap = map(lambda x: int(x), cpumap)
|
||||
cpumap.sort()
|
||||
|
||||
from xen.xend.XendClient import server
|
||||
for x in server.xend_node()[1:]:
|
||||
if len(x) > 1 and x[0] == 'nr_cpus':
|
||||
nr_cpus = int(x[1])
|
||||
cpumap = filter(lambda x: x < nr_cpus, cpumap)
|
||||
if len(cpumap) == nr_cpus:
|
||||
return "any cpu"
|
||||
break
|
||||
|
||||
return format_pairs(list_to_rangepairs(cpumap))
|
||||
|
||||
name = get_info('name')
|
||||
domid = int(get_info('domid'))
|
||||
|
||||
for vcpu in sxp.children(dom, 'vcpu'):
|
||||
def vinfo(n, t):
|
||||
return t(sxp.child_value(vcpu, n))
|
||||
|
||||
number = vinfo('number', int)
|
||||
cpu = vinfo('cpu', int)
|
||||
cpumap = format_cpumap(vinfo('cpumap', list))
|
||||
online = vinfo('online', int)
|
||||
cpu_time = vinfo('cpu_time', float)
|
||||
running = vinfo('running', int)
|
||||
blocked = vinfo('blocked', int)
|
||||
|
||||
if online:
|
||||
c = str(cpu)
|
||||
if running:
|
||||
s = 'r'
|
||||
else:
|
||||
s = '-'
|
||||
if blocked:
|
||||
s += 'b'
|
||||
else:
|
||||
s += '-'
|
||||
s += '-'
|
||||
else:
|
||||
c = "-"
|
||||
s = "--p"
|
||||
|
||||
print (
|
||||
"%(name)-32s %(domid)3d %(number)4d %(c)3s %(s)-3s %(cpu_time)7.1f %(cpumap)s" %
|
||||
locals())
|
||||
|
||||
|
||||
def xm_reboot(args):
|
||||
arg_check(args,1,"reboot")
|
||||
@@ -325,7 +411,6 @@ def xm_subcommand(command, args):
|
||||
|
||||
def cpu_make_map(cpulist):
|
||||
cpus = []
|
||||
cpumap = 0
|
||||
for c in cpulist.split(','):
|
||||
if c.find('-') != -1:
|
||||
(x,y) = c.split('-')
|
||||
@@ -334,14 +419,11 @@ def cpu_make_map(cpulist):
|
||||
else:
|
||||
cpus.append(int(c))
|
||||
cpus.sort()
|
||||
for c in cpus:
|
||||
cpumap = cpumap | 1<<c
|
||||
|
||||
return cpumap
|
||||
return cpus
|
||||
|
||||
def xm_vcpu_pin(args):
|
||||
arg_check(args, 3, "vcpu-pin")
|
||||
|
||||
|
||||
dom = args[0]
|
||||
vcpu = int(args[1])
|
||||
cpumap = cpu_make_map(args[2])
|
||||
@@ -351,7 +433,7 @@ def xm_vcpu_pin(args):
|
||||
|
||||
def xm_mem_max(args):
|
||||
arg_check(args, 2, "mem-max")
|
||||
|
||||
|
||||
dom = args[0]
|
||||
mem = int_unit(args[1], 'm')
|
||||
|
||||
@@ -360,35 +442,16 @@ def xm_mem_max(args):
|
||||
|
||||
def xm_mem_set(args):
|
||||
arg_check(args, 2, "mem-set")
|
||||
|
||||
|
||||
dom = args[0]
|
||||
mem_target = int_unit(args[1], 'm')
|
||||
|
||||
from xen.xend.XendClient import server
|
||||
server.xend_domain_mem_target_set(dom, mem_target)
|
||||
|
||||
# TODO: why does this lookup by name? and what if that fails!?
|
||||
def xm_vcpu_enable(args):
|
||||
arg_check(args, 2, "vcpu-enable")
|
||||
|
||||
name = args[0]
|
||||
vcpu = int(args[1])
|
||||
|
||||
def xm_set_vcpus(args):
|
||||
from xen.xend.XendClient import server
|
||||
dom = server.xend_domain(name)
|
||||
id = sxp.child_value(dom, 'domid')
|
||||
server.xend_domain_vcpu_hotplug(id, vcpu, 1)
|
||||
|
||||
def xm_vcpu_disable(args):
|
||||
arg_check(args, 2, "vcpu-disable")
|
||||
|
||||
name = args[0]
|
||||
vcpu = int(args[1])
|
||||
|
||||
from xen.xend.XendClient import server
|
||||
dom = server.xend_domain(name)
|
||||
id = sxp.child_value(dom, 'domid')
|
||||
server.xend_domain_vcpu_hotplug(id, vcpu, 0)
|
||||
server.xend_domain_set_vcpus(args[0], int(args[1]))
|
||||
|
||||
def xm_domid(args):
|
||||
name = args[0]
|
||||
@@ -588,9 +651,7 @@ commands = {
|
||||
"mem-set": xm_mem_set,
|
||||
# cpu commands
|
||||
"vcpu-pin": xm_vcpu_pin,
|
||||
# "cpus-list": xm_cpus_list,
|
||||
"vcpu-enable": xm_vcpu_enable,
|
||||
"vcpu-disable": xm_vcpu_disable,
|
||||
"set-vcpus": xm_set_vcpus,
|
||||
"vcpu-list": xm_vcpu_list,
|
||||
# special
|
||||
"pause": xm_pause,
|
||||
@@ -688,11 +749,16 @@ def main(argv=sys.argv):
|
||||
if rc:
|
||||
usage()
|
||||
except socket.error, ex:
|
||||
print >>sys.stderr, ex
|
||||
err("Error connecting to xend, is xend running?")
|
||||
if os.geteuid() != 0:
|
||||
err("Most commands need root access. Please try again as root.")
|
||||
else:
|
||||
err("Error connecting to xend: %s. Is xend running?" % ex[1])
|
||||
sys.exit(1)
|
||||
except IOError:
|
||||
err("Most commands need root access. Please try again as root")
|
||||
if os.geteuid() != 0:
|
||||
err("Most commands need root access. Please try again as root.")
|
||||
else:
|
||||
err("Error connecting to xend: %s." % ex[1])
|
||||
sys.exit(1)
|
||||
except xen.xend.XendError.XendError, ex:
|
||||
if len(args) > 0:
|
||||
|
||||