mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
bitkeeper revision 1.1546 (42944efdY94XWSK3i6H669MdigOOzw)
XendDomain.py: Move save/restore code in seperate file. XendCheckpoint.py: Support code for save/restore of domains. Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
This commit is contained in:
1 parent
eb739ebddc
commit
42736be47b
3 files changed
+150
-136
No files matched your search
@@ -0,0 +1,143 @@
|
||||
# Copyright (C) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
|
||||
|
||||
# This file is subject to the terms and conditions of the GNU General
|
||||
# Public License. See the file "COPYING" in the main directory of
|
||||
# this archive for more details.
|
||||
|
||||
import errno
|
||||
import os
|
||||
import select
|
||||
import sxp
|
||||
from string import join
|
||||
from struct import pack, unpack, calcsize
|
||||
from xen.util.xpopen import xPopen3
|
||||
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
|
||||
|
||||
from XendLogging import log
|
||||
|
||||
SIGNATURE = "LinuxGuestRecord"
|
||||
PAGE_SIZE = 4096
|
||||
PATH_XC_SAVE = "/usr/libexec/xen/xc_save"
|
||||
PATH_XC_RESTORE = "/usr/libexec/xen/xc_restore"
|
||||
|
||||
sizeof_int = calcsize("i")
|
||||
sizeof_unsigned_long = calcsize("L")
|
||||
|
||||
def save(xd, fd, dominfo):
|
||||
if os.write(fd, SIGNATURE) != len(SIGNATURE):
|
||||
raise XendError("could not write guest state file: signature")
|
||||
|
||||
config = sxp.to_string(dominfo.sxpr())
|
||||
if os.write(fd, pack("!i", len(config))) != sizeof_int:
|
||||
raise XendError("could not write guest state file: config len")
|
||||
if os.write(fd, config) != len(config):
|
||||
raise XendError("could not write guest state file: config")
|
||||
|
||||
cmd = [PATH_XC_SAVE, str(xc.handle()), str(fd),
|
||||
dominfo.id]
|
||||
log.info("[xc_save] " + join(cmd))
|
||||
child = xPopen3(cmd, True, -1, [fd, xc.handle()])
|
||||
|
||||
lasterr = ""
|
||||
p = select.poll()
|
||||
p.register(child.fromchild.fileno())
|
||||
p.register(child.childerr.fileno())
|
||||
while True:
|
||||
r = p.poll()
|
||||
for (fd, event) in r:
|
||||
if not event & select.POLLIN:
|
||||
continue
|
||||
if fd == child.childerr.fileno():
|
||||
l = child.childerr.readline()
|
||||
log.error(l.rstrip())
|
||||
lasterr = l.rstrip()
|
||||
if fd == child.fromchild.fileno():
|
||||
l = child.fromchild.readline()
|
||||
if l.rstrip() == "suspend":
|
||||
log.info("suspending %s" % dominfo.id)
|
||||
xd.domain_shutdown(dominfo.id, reason='suspend')
|
||||
dominfo.state_wait("suspended")
|
||||
log.info("suspend %s done" % dominfo.id)
|
||||
child.tochild.write("done\n")
|
||||
child.tochild.flush()
|
||||
if filter(lambda (fd, event): event & select.POLLHUP, r):
|
||||
break
|
||||
|
||||
if child.wait() >> 8 == 127:
|
||||
lasterr = "popen %s failed" % PATH_XC_SAVE
|
||||
if child.wait() != 0:
|
||||
raise XendError("xc_save failed: %s" % lasterr)
|
||||
|
||||
xd.domain_destroy(dominfo.id)
|
||||
return None
|
||||
|
||||
def restore(xd, fd):
|
||||
try:
|
||||
signature = fd.read_exact(len(SIGNATURE),
|
||||
"not a valid guest state file: signature read")
|
||||
if signature != SIGNATURE:
|
||||
raise XendError("not a valid guest state file: found '%s'" %
|
||||
signature)
|
||||
|
||||
l = fd.read_exact(sizeof_int,
|
||||
"not a valid guest state file: config size read")
|
||||
vmconfig_size = unpack("!i", l)[0]
|
||||
vmconfig_buf = fd.read_exact(vmconfig_size,
|
||||
"not a valid guest state file: config read")
|
||||
|
||||
p = sxp.Parser()
|
||||
p.input(vmconfig_buf)
|
||||
if not p.ready:
|
||||
raise XendError("not a valid guest state file: config parse")
|
||||
|
||||
vmconfig = p.get_val()
|
||||
dominfo = xd.domain_configure(vmconfig)
|
||||
|
||||
l = fd.read_exact(sizeof_unsigned_long,
|
||||
"not a valid guest state file: pfn count read")
|
||||
nr_pfns = unpack("=L", l)[0] # XXX endianess
|
||||
if nr_pfns > 1024*1024: # XXX
|
||||
raise XendError(
|
||||
"not a valid guest state file: pfn count out of range")
|
||||
|
||||
# XXXcl hack: fd.tell will sync up the object and
|
||||
# underlying file descriptor
|
||||
ignore = fd.tell()
|
||||
|
||||
cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd.fileno()),
|
||||
dominfo.id, str(nr_pfns)]
|
||||
log.info("[xc_restore] " + join(cmd))
|
||||
child = xPopen3(cmd, True, -1, [fd.fileno(), xc.handle()])
|
||||
child.tochild.close()
|
||||
|
||||
lasterr = ""
|
||||
p = select.poll()
|
||||
p.register(child.fromchild.fileno())
|
||||
p.register(child.childerr.fileno())
|
||||
while True:
|
||||
r = p.poll()
|
||||
for (fd, event) in r:
|
||||
if not event & select.POLLIN:
|
||||
continue
|
||||
if fd == child.childerr.fileno():
|
||||
l = child.childerr.readline()
|
||||
log.error(l.rstrip())
|
||||
lasterr = l.rstrip()
|
||||
if fd == child.fromchild.fileno():
|
||||
l = child.fromchild.readline()
|
||||
log.info(l.rstrip())
|
||||
if filter(lambda (fd, event): event & select.POLLHUP, r):
|
||||
break
|
||||
|
||||
if child.wait() >> 8 == 127:
|
||||
lasterr = "popen %s failed" % PATH_XC_RESTORE
|
||||
if child.wait() != 0:
|
||||
raise XendError("xc_restore failed: %s" % lasterr)
|
||||
|
||||
return dominfo
|
||||
|
||||
except IOError, ex:
|
||||
if ex.errno == errno.ENOENT:
|
||||
raise XendError("can't open guest state file %s" % src)
|
||||
else:
|
||||
raise
|
||||
@@ -5,6 +5,8 @@
|
||||
Nothing here is persistent (across reboots).
|
||||
Needs to be persistent for one uptime.
|
||||
"""
|
||||
import os
|
||||
import scheduler
|
||||
import sys
|
||||
import traceback
|
||||
import time
|
||||
@@ -13,6 +15,7 @@ import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
|
||||
|
||||
import sxp
|
||||
import XendRoot; xroot = XendRoot.instance()
|
||||
import XendCheckpoint
|
||||
import XendDB
|
||||
import XendDomainInfo
|
||||
import XendMigrate
|
||||
@@ -20,18 +23,8 @@ import EventServer; eserver = EventServer.instance()
|
||||
from XendError import XendError
|
||||
from XendLogging import log
|
||||
|
||||
import scheduler
|
||||
|
||||
from xen.xend.server import channel
|
||||
|
||||
|
||||
import errno
|
||||
import os
|
||||
import select
|
||||
from string import join
|
||||
from struct import pack, unpack, calcsize
|
||||
from xen.util.xpopen import xPopen3
|
||||
|
||||
__all__ = [ "XendDomain" ]
|
||||
|
||||
SHUTDOWN_TIMEOUT = 30
|
||||
@@ -330,91 +323,17 @@ class XendDomain:
|
||||
@param progress: output progress if true
|
||||
"""
|
||||
|
||||
SIGNATURE = "LinuxGuestRecord"
|
||||
sizeof_int = calcsize("i")
|
||||
sizeof_unsigned_long = calcsize("L")
|
||||
PAGE_SIZE = 4096
|
||||
PATH_XC_RESTORE = "/usr/libexec/xen/xc_restore"
|
||||
|
||||
class XendFile(file):
|
||||
def read_exact(self, size, error_msg):
|
||||
buf = self.read(size)
|
||||
if len(buf) != size:
|
||||
raise XendError(error_msg)
|
||||
return buf
|
||||
|
||||
try:
|
||||
fd = XendFile(src, 'rb')
|
||||
|
||||
signature = fd.read_exact(len(SIGNATURE),
|
||||
"not a valid guest state file: signature read")
|
||||
if signature != SIGNATURE:
|
||||
raise XendError("not a valid guest state file: found '%s'" %
|
||||
signature)
|
||||
fd = XendFile(src, 'rb')
|
||||
|
||||
l = fd.read_exact(sizeof_int,
|
||||
"not a valid guest state file: config size read")
|
||||
vmconfig_size = unpack("!i", l)[0]
|
||||
vmconfig_buf = fd.read_exact(vmconfig_size,
|
||||
"not a valid guest state file: config read")
|
||||
return XendCheckpoint.restore(self, fd)
|
||||
|
||||
p = sxp.Parser()
|
||||
p.input(vmconfig_buf)
|
||||
if not p.ready:
|
||||
raise XendError("not a valid guest state file: config parse")
|
||||
|
||||
vmconfig = p.get_val()
|
||||
dominfo = self.domain_configure(vmconfig)
|
||||
|
||||
l = fd.read_exact(sizeof_unsigned_long,
|
||||
"not a valid guest state file: pfn count read")
|
||||
nr_pfns = unpack("=L", l)[0] # XXX endianess
|
||||
if nr_pfns > 1024*1024: # XXX
|
||||
raise XendError(
|
||||
"not a valid guest state file: pfn count out of range")
|
||||
|
||||
# XXXcl hack: fd.tell will sync up the object and
|
||||
# underlying file descriptor
|
||||
ignore = fd.tell()
|
||||
|
||||
cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd.fileno()),
|
||||
dominfo.id, str(nr_pfns)]
|
||||
log.info("[xc_restore] " + join(cmd))
|
||||
child = xPopen3(cmd, True, -1, [fd.fileno(), xc.handle()])
|
||||
child.tochild.close()
|
||||
|
||||
lasterr = ""
|
||||
p = select.poll()
|
||||
p.register(child.fromchild.fileno())
|
||||
p.register(child.childerr.fileno())
|
||||
while True:
|
||||
r = p.poll()
|
||||
for (fd, event) in r:
|
||||
if not event & select.POLLIN:
|
||||
continue
|
||||
if fd == child.childerr.fileno():
|
||||
l = child.childerr.readline()
|
||||
log.error(l.rstrip())
|
||||
lasterr = l.rstrip()
|
||||
if fd == child.fromchild.fileno():
|
||||
l = child.fromchild.readline()
|
||||
log.info(l.rstrip())
|
||||
if filter(lambda (fd, event): event & select.POLLHUP, r):
|
||||
break
|
||||
|
||||
if child.wait() >> 8 == 127:
|
||||
lasterr = "popen %s failed" % PATH_XC_RESTORE
|
||||
if child.wait() != 0:
|
||||
raise XendError("xc_restore failed: %s" % lasterr)
|
||||
|
||||
return dominfo
|
||||
|
||||
except IOError, ex:
|
||||
if ex.errno == errno.ENOENT:
|
||||
raise XendError("can't open guest state file %s" % src)
|
||||
else:
|
||||
raise
|
||||
|
||||
def domain_get(self, id):
|
||||
"""Get up-to-date info about a domain.
|
||||
|
||||
@@ -604,61 +523,12 @@ class XendDomain:
|
||||
@param progress: output progress if true
|
||||
"""
|
||||
|
||||
SIGNATURE = "LinuxGuestRecord"
|
||||
sizeof_int = calcsize("i")
|
||||
PATH_XC_SAVE = "/usr/libexec/xen/xc_save"
|
||||
|
||||
try:
|
||||
dominfo = self.domain_lookup(id)
|
||||
|
||||
fd = os.open(dst, os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
|
||||
|
||||
if os.write(fd, SIGNATURE) != len(SIGNATURE):
|
||||
raise XendError("could not write guest state file: signature")
|
||||
|
||||
config = sxp.to_string(dominfo.sxpr())
|
||||
if os.write(fd, pack("!i", len(config))) != sizeof_int:
|
||||
raise XendError("could not write guest state file: config len")
|
||||
if os.write(fd, config) != len(config):
|
||||
raise XendError("could not write guest state file: config")
|
||||
|
||||
cmd = [PATH_XC_SAVE, str(xc.handle()), str(fd),
|
||||
dominfo.id]
|
||||
log.info("[xc_save] " + join(cmd))
|
||||
child = xPopen3(cmd, True, -1, [fd, xc.handle()])
|
||||
|
||||
lasterr = ""
|
||||
p = select.poll()
|
||||
p.register(child.fromchild.fileno())
|
||||
p.register(child.childerr.fileno())
|
||||
while True:
|
||||
r = p.poll()
|
||||
for (fd, event) in r:
|
||||
if not event & select.POLLIN:
|
||||
continue
|
||||
if fd == child.childerr.fileno():
|
||||
l = child.childerr.readline()
|
||||
log.error(l.rstrip())
|
||||
lasterr = l.rstrip()
|
||||
if fd == child.fromchild.fileno():
|
||||
l = child.fromchild.readline()
|
||||
if l.rstrip() == "suspend":
|
||||
log.info("suspending %s" % dominfo.id)
|
||||
self.domain_shutdown(dominfo.id, reason='suspend')
|
||||
dominfo.state_wait("suspended")
|
||||
log.info("suspend %s done" % dominfo.id)
|
||||
child.tochild.write("done\n")
|
||||
child.tochild.flush()
|
||||
if filter(lambda (fd, event): event & select.POLLHUP, r):
|
||||
break
|
||||
|
||||
if child.wait() >> 8 == 127:
|
||||
lasterr = "popen %s failed" % PATH_XC_SAVE
|
||||
if child.wait() != 0:
|
||||
raise XendError("xc_save failed: %s" % lasterr)
|
||||
|
||||
self.domain_destroy(dominfo.id)
|
||||
return None
|
||||
return XendCheckpoint.save(self, fd, dominfo)
|
||||
|
||||
except:
|
||||
raise
|
||||
|
||||