summaryrefslogtreecommitdiff
path: root/server/kvm.py
diff options
context:
space:
mode:
Diffstat (limited to 'server/kvm.py')
-rw-r--r--server/kvm.py848
1 files changed, 424 insertions, 424 deletions
diff --git a/server/kvm.py b/server/kvm.py
index 72e3e7d7..0e577317 100644
--- a/server/kvm.py
+++ b/server/kvm.py
@@ -5,7 +5,7 @@
"""
This module defines the KVM class
- KVM: a KVM virtual machine monitor
+ KVM: a KVM virtual machine monitor
"""
__author__ = """
@@ -31,15 +31,15 @@ brctl addif br0 $1
_check_process_script= """\
if [ -f "%(pid_file_name)s" ]
then
- pid=$(cat "%(pid_file_name)s")
- if [ -L /proc/$pid/exe ] && stat /proc/$pid/exe |
- grep -q -- "-> \`%(qemu_binary)s\'\$"
- then
- echo "process present"
- else
- rm -f "%(pid_file_name)s"
- rm -f "%(monitor_file_name)s"
- fi
+ pid=$(cat "%(pid_file_name)s")
+ if [ -L /proc/$pid/exe ] && stat /proc/$pid/exe |
+ grep -q -- "-> \`%(qemu_binary)s\'\$"
+ then
+ echo "process present"
+ else
+ rm -f "%(pid_file_name)s"
+ rm -f "%(monitor_file_name)s"
+ fi
fi
"""
@@ -54,430 +54,430 @@ monitor_socket.send("system_reset\\n")\n')
_remove_modules_script= """\
if $(grep -q "^kvm_intel [[:digit:]]\+ 0" /proc/modules)
then
- rmmod kvm-intel
+ rmmod kvm-intel
fi
if $(grep -q "^kvm_amd [[:digit:]]\+ 0" /proc/modules)
then
- rmmod kvm-amd
+ rmmod kvm-amd
fi
if $(grep -q "^kvm [[:digit:]]\+ 0" /proc/modules)
then
- rmmod kvm
+ rmmod kvm
fi
"""
class KVM(hypervisor.Hypervisor):
- """
- This class represents a KVM virtual machine monitor.
-
- Implementation details:
- This is a leaf class in an abstract class hierarchy, it must
- implement the unimplemented methods in parent classes.
- """
-
- build_dir= None
- pid_dir= None
- support_dir= None
- addresses= []
- insert_modules= True
- modules= {}
-
-
- def __del__(self):
- """
- Destroy a KVM object.
-
- Guests managed by this hypervisor that are still running will
- be killed.
- """
- self.deinitialize()
-
-
- def _insert_modules(self):
- """
- Insert the kvm modules into the kernel.
-
- The modules inserted are the ones from the build directory, NOT
- the ones from the kernel.
-
- This function should only be called after install(). It will
- check that the modules are not already loaded before attempting
- to insert them.
- """
- cpu_flags= self.host.run('cat /proc/cpuinfo | '
- 'grep -e "^flags" | head -1 | cut -d " " -f 2-'
- ).stdout.strip()
-
- if cpu_flags.find('vmx') != -1:
- module_type= "intel"
- elif cpu_flags.find('svm') != -1:
- module_type= "amd"
- else:
- raise error.AutoservVirtError("No harware "
- "virtualization extensions found, "
- "KVM cannot run")
-
- self.host.run('if ! $(grep -q "^kvm " /proc/modules); '
- 'then insmod "%s"; fi' % (utils.sh_escape(
- os.path.join(self.build_dir, "kernel/kvm.ko")),))
- if module_type == "intel":
- self.host.run('if ! $(grep -q "^kvm_intel " '
- '/proc/modules); then insmod "%s"; fi' %
- (utils.sh_escape(os.path.join(self.build_dir,
- "kernel/kvm-intel.ko")),))
- elif module_type == "amd":
- self.host.run('if ! $(grep -q "^kvm_amd " '
- '/proc/modules); then insmod "%s"; fi' %
- (utils.sh_escape(os.path.join(self.build_dir,
- "kernel/kvm-amd.ko")),))
-
-
- def _remove_modules(self):
- """
- Remove the kvm modules from the kernel.
-
- This function checks that they're not in use before trying to
- remove them.
- """
- self.host.run(_remove_modules_script)
-
-
- def install(self, addresses, build=True, insert_modules=True, syncdir=None):
- """
- Compile the kvm software on the host that the object was
- initialized with.
-
- The kvm kernel modules are compiled, for this, the kernel
- sources must be available. A custom qemu is also compiled.
- Note that 'make install' is not run, the kernel modules and
- qemu are run from where they were built, therefore not
- conflicting with what might already be installed.
-
- Args:
- addresses: a list of dict entries of the form
- {"mac" : "xx:xx:xx:xx:xx:xx",
- "ip" : "yyy.yyy.yyy.yyy"} where x and y
- are replaced with sensible values. The ip
- address may be a hostname or an IPv6 instead.
-
- When a new virtual machine is created, the
- first available entry in that list will be
- used. The network card in the virtual machine
- will be assigned the specified mac address and
- autoserv will use the specified ip address to
- connect to the virtual host via ssh. The virtual
- machine os must therefore be configured to
- configure its network with the ip corresponding
- to the mac.
- build: build kvm from the source material, if False,
- it is assumed that the package contains the
- source tree after a 'make'.
- insert_modules: build kvm modules from the source
- material and insert them. Otherwise, the
- running kernel is assumed to already have
- kvm support and nothing will be done concerning
- the modules.
-
- TODO(poirier): check dependencies before building
- kvm needs:
- libasound2-dev
- libsdl1.2-dev (or configure qemu with --disable-gfx-check, how?)
- bridge-utils
- """
- self.addresses= [
- {"mac" : address["mac"],
- "ip" : address["ip"],
- "is_used" : False} for address in addresses]
-
- self.build_dir = self.host.get_tmp_dir()
- self.support_dir= self.host.get_tmp_dir()
-
- self.host.run('echo "%s" > "%s"' % (
- utils.sh_escape(_qemu_ifup_script),
- utils.sh_escape(os.path.join(self.support_dir,
- "qemu-ifup.sh")),))
- self.host.run('chmod a+x "%s"' % (
- utils.sh_escape(os.path.join(self.support_dir,
- "qemu-ifup.sh")),))
-
- self.host.send_file(self.source_material, self.build_dir)
- remote_source_material= os.path.join(self.build_dir,
- os.path.basename(self.source_material))
-
- self.build_dir= utils.unarchive(self.host,
- remote_source_material)
-
- if insert_modules:
- configure_modules= ""
- self.insert_modules= True
- else:
- configure_modules= "--with-patched-kernel "
- self.insert_modules= False
-
- # build
- if build:
- try:
- self.host.run('make -C "%s" clean' % (
- utils.sh_escape(self.build_dir),),
- timeout=600)
- except error.AutoservRunError:
- # directory was already clean and contained
- # no makefile
- pass
- self.host.run('cd "%s" && ./configure %s' % (
- utils.sh_escape(self.build_dir),
- configure_modules,), timeout=600)
- if syncdir:
- cmd = 'cd "%s/kernel" && make sync LINUX=%s' % (
- utils.sh_escape(self.build_dir),
- utils.sh_escape(syncdir))
- self.host.run(cmd)
- self.host.run('make -j%d -C "%s"' % (
- self.host.get_num_cpu() * 2,
- utils.sh_escape(self.build_dir),), timeout=3600)
- # remember path to modules
- self.modules['kvm'] = "%s" %(
- utils.sh_escape(os.path.join(self.build_dir,
- "kernel/kvm.ko")))
- self.modules['kvm-intel'] = "%s" %(
- utils.sh_escape(os.path.join(self.build_dir,
- "kernel/kvm-intel.ko")))
- self.modules['kvm-amd'] = "%s" %(
- utils.sh_escape(os.path.join(self.build_dir,
- "kernel/kvm-amd.ko")))
- print self.modules
-
- self.initialize()
-
-
- def initialize(self):
- """
- Initialize the hypervisor.
-
- Loads needed kernel modules and creates temporary directories.
- The logic is that you could compile once and
- initialize - deinitialize many times. But why you would do that
- has yet to be figured.
-
- Raises:
- AutoservVirtError: cpuid doesn't report virtualization
- extentions (vmx for intel or svm for amd), in
- this case, kvm cannot run.
- """
- self.pid_dir= self.host.get_tmp_dir()
-
- if self.insert_modules:
- self._remove_modules()
- self._insert_modules()
-
-
- def deinitialize(self):
- """
- Terminate the hypervisor.
-
- Kill all the virtual machines that are still running and
- unload the kernel modules.
- """
- self.refresh_guests()
- for address in self.addresses:
- if address["is_used"]:
- self.delete_guest(address["ip"])
- self.pid_dir= None
-
- if self.insert_modules:
- self._remove_modules()
-
-
- def new_guest(self, qemu_options):
- """
- Start a new guest ("virtual machine").
-
- Returns:
- The ip that was picked from the list supplied to
- install() and assigned to this guest.
-
- Raises:
- AutoservVirtError: no more addresses are available.
- """
- for address in self.addresses:
- if not address["is_used"]:
- break
- else:
- raise error.AutoservVirtError(
- "No more addresses available")
-
- retval= self.host.run(
- '%s'
- # this is the line of options that can be modified
- ' %s '
- '-pidfile "%s" -daemonize -nographic '
- #~ '-serial telnet::4444,server '
- '-monitor unix:"%s",server,nowait '
- '-net nic,macaddr="%s" -net tap,script="%s" -L "%s"' % (
- utils.sh_escape(os.path.join(
- self.build_dir,
- "qemu/x86_64-softmmu/qemu-system-x86_64")),
- qemu_options,
- utils.sh_escape(os.path.join(
- self.pid_dir,
- "vhost%s_pid" % (address["ip"],))),
- utils.sh_escape(os.path.join(
- self.pid_dir,
- "vhost%s_monitor" % (address["ip"],))),
- utils.sh_escape(address["mac"]),
- utils.sh_escape(os.path.join(
- self.support_dir,
- "qemu-ifup.sh")),
- utils.sh_escape(os.path.join(
- self.build_dir,
- "qemu/pc-bios")),))
-
- address["is_used"]= True
- return address["ip"]
-
-
- def refresh_guests(self):
- """
- Refresh the list of guests addresses.
-
- The is_used status will be updated according to the presence
- of the process specified in the pid file that was written when
- the virtual machine was started.
-
- TODO(poirier): there are a lot of race conditions in this code
- because the process might terminate on its own anywhere in
- between
- """
- for address in self.addresses:
- if address["is_used"]:
- pid_file_name= utils.sh_escape(os.path.join(
- self.pid_dir,
- "vhost%s_pid" % (address["ip"],)))
- monitor_file_name= utils.sh_escape(os.path.join(
- self.pid_dir,
- "vhost%s_monitor" % (address["ip"],)))
- retval= self.host.run(
- _check_process_script % {
- "pid_file_name" : pid_file_name,
- "monitor_file_name" : monitor_file_name,
- "qemu_binary" : utils.sh_escape(
- os.path.join(self.build_dir,
- "qemu/x86_64-softmmu/"
- "qemu-system-x86_64")),})
- if (retval.stdout.strip() !=
- "process present"):
- address["is_used"]= False
-
-
- def delete_guest(self, guest_hostname):
- """
- Terminate a virtual machine.
-
- Args:
- guest_hostname: the ip (as it was specified in the
- address list given to install()) of the guest
- to terminate.
-
- Raises:
- AutoservVirtError: the guest_hostname argument is
- invalid
-
- TODO(poirier): is there a difference in qemu between
- sending SIGTEM or quitting from the monitor?
- TODO(poirier): there are a lot of race conditions in this code
- because the process might terminate on its own anywhere in
- between
- """
- for address in self.addresses:
- if address["ip"] == guest_hostname:
- if address["is_used"]:
- break
- else:
- # Will happen if deinitialize() is
- # called while guest objects still
- # exit and these are del'ed after.
- # In that situation, nothing is to
- # be done here, don't throw an error
- # either because it will print an
- # ugly message during garbage
- # collection. The solution would be to
- # delete the guest objects before
- # calling deinitialize(), this can't be
- # done by the KVM class, it has no
- # reference to those objects and it
- # cannot have any either. The Guest
- # objects already need to have a
- # reference to their managing
- # hypervisor. If the hypervisor had a
- # reference to the Guest objects it
- # manages, it would create a circular
- # reference and those objects would
- # not be elligible for garbage
- # collection. In turn, this means that
- # the KVM object would not be
- # automatically del'ed at the end of
- # the program and guests that are still
- # running would be left unattended.
- # Note that this circular reference
- # problem could be avoided by using
- # weakref's in class KVM but the
- # control file will most likely also
- # have references to the guests.
- return
- else:
- raise error.AutoservVirtError("Unknown guest hostname")
-
- pid_file_name= utils.sh_escape(os.path.join(self.pid_dir,
- "vhost%s_pid" % (address["ip"],)))
- monitor_file_name= utils.sh_escape(os.path.join(self.pid_dir,
- "vhost%s_monitor" % (address["ip"],)))
-
- retval= self.host.run(
- _check_process_script % {
- "pid_file_name" : pid_file_name,
- "monitor_file_name" : monitor_file_name,
- "qemu_binary" : utils.sh_escape(os.path.join(
- self.build_dir,
- "qemu/x86_64-softmmu/qemu-system-x86_64")),})
- if retval.stdout.strip() == "process present":
- self.host.run('kill $(cat "%s")' %(
- pid_file_name,))
- self.host.run('rm -f "%s"' %(
- pid_file_name,))
- self.host.run('rm -f "%s"' %(
- monitor_file_name,))
- address["is_used"]= False
-
-
- def reset_guest(self, guest_hostname):
- """
- Perform a hard reset on a virtual machine.
-
- Args:
- guest_hostname: the ip (as it was specified in the
- address list given to install()) of the guest
- to terminate.
-
- Raises:
- AutoservVirtError: the guest_hostname argument is
- invalid
- """
- for address in self.addresses:
- if address["ip"] is guest_hostname:
- if address["is_used"]:
- break
- else:
- raise error.AutoservVirtError("guest "
- "hostname not in use")
- else:
- raise error.AutoservVirtError("Unknown guest hostname")
-
- monitor_file_name= utils.sh_escape(os.path.join(self.pid_dir,
- "vhost%s_monitor" % (address["ip"],)))
-
- self.host.run('python -c "%s"' % (utils.sh_escape(
- _hard_reset_script % {
- "monitor_file_name" : monitor_file_name,}),))
+ """
+ This class represents a KVM virtual machine monitor.
+
+ Implementation details:
+ This is a leaf class in an abstract class hierarchy, it must
+ implement the unimplemented methods in parent classes.
+ """
+
+ build_dir= None
+ pid_dir= None
+ support_dir= None
+ addresses= []
+ insert_modules= True
+ modules= {}
+
+
+ def __del__(self):
+ """
+ Destroy a KVM object.
+
+ Guests managed by this hypervisor that are still running will
+ be killed.
+ """
+ self.deinitialize()
+
+
+ def _insert_modules(self):
+ """
+ Insert the kvm modules into the kernel.
+
+ The modules inserted are the ones from the build directory, NOT
+ the ones from the kernel.
+
+ This function should only be called after install(). It will
+ check that the modules are not already loaded before attempting
+ to insert them.
+ """
+ cpu_flags= self.host.run('cat /proc/cpuinfo | '
+ 'grep -e "^flags" | head -1 | cut -d " " -f 2-'
+ ).stdout.strip()
+
+ if cpu_flags.find('vmx') != -1:
+ module_type= "intel"
+ elif cpu_flags.find('svm') != -1:
+ module_type= "amd"
+ else:
+ raise error.AutoservVirtError("No harware "
+ "virtualization extensions found, "
+ "KVM cannot run")
+
+ self.host.run('if ! $(grep -q "^kvm " /proc/modules); '
+ 'then insmod "%s"; fi' % (utils.sh_escape(
+ os.path.join(self.build_dir, "kernel/kvm.ko")),))
+ if module_type == "intel":
+ self.host.run('if ! $(grep -q "^kvm_intel " '
+ '/proc/modules); then insmod "%s"; fi' %
+ (utils.sh_escape(os.path.join(self.build_dir,
+ "kernel/kvm-intel.ko")),))
+ elif module_type == "amd":
+ self.host.run('if ! $(grep -q "^kvm_amd " '
+ '/proc/modules); then insmod "%s"; fi' %
+ (utils.sh_escape(os.path.join(self.build_dir,
+ "kernel/kvm-amd.ko")),))
+
+
+ def _remove_modules(self):
+ """
+ Remove the kvm modules from the kernel.
+
+ This function checks that they're not in use before trying to
+ remove them.
+ """
+ self.host.run(_remove_modules_script)
+
+
+ def install(self, addresses, build=True, insert_modules=True, syncdir=None):
+ """
+ Compile the kvm software on the host that the object was
+ initialized with.
+
+ The kvm kernel modules are compiled, for this, the kernel
+ sources must be available. A custom qemu is also compiled.
+ Note that 'make install' is not run, the kernel modules and
+ qemu are run from where they were built, therefore not
+ conflicting with what might already be installed.
+
+ Args:
+ addresses: a list of dict entries of the form
+ {"mac" : "xx:xx:xx:xx:xx:xx",
+ "ip" : "yyy.yyy.yyy.yyy"} where x and y
+ are replaced with sensible values. The ip
+ address may be a hostname or an IPv6 instead.
+
+ When a new virtual machine is created, the
+ first available entry in that list will be
+ used. The network card in the virtual machine
+ will be assigned the specified mac address and
+ autoserv will use the specified ip address to
+ connect to the virtual host via ssh. The virtual
+ machine os must therefore be configured to
+ configure its network with the ip corresponding
+ to the mac.
+ build: build kvm from the source material, if False,
+ it is assumed that the package contains the
+ source tree after a 'make'.
+ insert_modules: build kvm modules from the source
+ material and insert them. Otherwise, the
+ running kernel is assumed to already have
+ kvm support and nothing will be done concerning
+ the modules.
+
+ TODO(poirier): check dependencies before building
+ kvm needs:
+ libasound2-dev
+ libsdl1.2-dev (or configure qemu with --disable-gfx-check, how?)
+ bridge-utils
+ """
+ self.addresses= [
+ {"mac" : address["mac"],
+ "ip" : address["ip"],
+ "is_used" : False} for address in addresses]
+
+ self.build_dir = self.host.get_tmp_dir()
+ self.support_dir= self.host.get_tmp_dir()
+
+ self.host.run('echo "%s" > "%s"' % (
+ utils.sh_escape(_qemu_ifup_script),
+ utils.sh_escape(os.path.join(self.support_dir,
+ "qemu-ifup.sh")),))
+ self.host.run('chmod a+x "%s"' % (
+ utils.sh_escape(os.path.join(self.support_dir,
+ "qemu-ifup.sh")),))
+
+ self.host.send_file(self.source_material, self.build_dir)
+ remote_source_material= os.path.join(self.build_dir,
+ os.path.basename(self.source_material))
+
+ self.build_dir= utils.unarchive(self.host,
+ remote_source_material)
+
+ if insert_modules:
+ configure_modules= ""
+ self.insert_modules= True
+ else:
+ configure_modules= "--with-patched-kernel "
+ self.insert_modules= False
+
+ # build
+ if build:
+ try:
+ self.host.run('make -C "%s" clean' % (
+ utils.sh_escape(self.build_dir),),
+ timeout=600)
+ except error.AutoservRunError:
+ # directory was already clean and contained
+ # no makefile
+ pass
+ self.host.run('cd "%s" && ./configure %s' % (
+ utils.sh_escape(self.build_dir),
+ configure_modules,), timeout=600)
+ if syncdir:
+ cmd = 'cd "%s/kernel" && make sync LINUX=%s' % (
+ utils.sh_escape(self.build_dir),
+ utils.sh_escape(syncdir))
+ self.host.run(cmd)
+ self.host.run('make -j%d -C "%s"' % (
+ self.host.get_num_cpu() * 2,
+ utils.sh_escape(self.build_dir),), timeout=3600)
+ # remember path to modules
+ self.modules['kvm'] = "%s" %(
+ utils.sh_escape(os.path.join(self.build_dir,
+ "kernel/kvm.ko")))
+ self.modules['kvm-intel'] = "%s" %(
+ utils.sh_escape(os.path.join(self.build_dir,
+ "kernel/kvm-intel.ko")))
+ self.modules['kvm-amd'] = "%s" %(
+ utils.sh_escape(os.path.join(self.build_dir,
+ "kernel/kvm-amd.ko")))
+ print self.modules
+
+ self.initialize()
+
+
+ def initialize(self):
+ """
+ Initialize the hypervisor.
+
+ Loads needed kernel modules and creates temporary directories.
+ The logic is that you could compile once and
+ initialize - deinitialize many times. But why you would do that
+ has yet to be figured.
+
+ Raises:
+ AutoservVirtError: cpuid doesn't report virtualization
+ extentions (vmx for intel or svm for amd), in
+ this case, kvm cannot run.
+ """
+ self.pid_dir= self.host.get_tmp_dir()
+
+ if self.insert_modules:
+ self._remove_modules()
+ self._insert_modules()
+
+
+ def deinitialize(self):
+ """
+ Terminate the hypervisor.
+
+ Kill all the virtual machines that are still running and
+ unload the kernel modules.
+ """
+ self.refresh_guests()
+ for address in self.addresses:
+ if address["is_used"]:
+ self.delete_guest(address["ip"])
+ self.pid_dir= None
+
+ if self.insert_modules:
+ self._remove_modules()
+
+
+ def new_guest(self, qemu_options):
+ """
+ Start a new guest ("virtual machine").
+
+ Returns:
+ The ip that was picked from the list supplied to
+ install() and assigned to this guest.
+
+ Raises:
+ AutoservVirtError: no more addresses are available.
+ """
+ for address in self.addresses:
+ if not address["is_used"]:
+ break
+ else:
+ raise error.AutoservVirtError(
+ "No more addresses available")
+
+ retval= self.host.run(
+ '%s'
+ # this is the line of options that can be modified
+ ' %s '
+ '-pidfile "%s" -daemonize -nographic '
+ #~ '-serial telnet::4444,server '
+ '-monitor unix:"%s",server,nowait '
+ '-net nic,macaddr="%s" -net tap,script="%s" -L "%s"' % (
+ utils.sh_escape(os.path.join(
+ self.build_dir,
+ "qemu/x86_64-softmmu/qemu-system-x86_64")),
+ qemu_options,
+ utils.sh_escape(os.path.join(
+ self.pid_dir,
+ "vhost%s_pid" % (address["ip"],))),
+ utils.sh_escape(os.path.join(
+ self.pid_dir,
+ "vhost%s_monitor" % (address["ip"],))),
+ utils.sh_escape(address["mac"]),
+ utils.sh_escape(os.path.join(
+ self.support_dir,
+ "qemu-ifup.sh")),
+ utils.sh_escape(os.path.join(
+ self.build_dir,
+ "qemu/pc-bios")),))
+
+ address["is_used"]= True
+ return address["ip"]
+
+
+ def refresh_guests(self):
+ """
+ Refresh the list of guests addresses.
+
+ The is_used status will be updated according to the presence
+ of the process specified in the pid file that was written when
+ the virtual machine was started.
+
+ TODO(poirier): there are a lot of race conditions in this code
+ because the process might terminate on its own anywhere in
+ between
+ """
+ for address in self.addresses:
+ if address["is_used"]:
+ pid_file_name= utils.sh_escape(os.path.join(
+ self.pid_dir,
+ "vhost%s_pid" % (address["ip"],)))
+ monitor_file_name= utils.sh_escape(os.path.join(
+ self.pid_dir,
+ "vhost%s_monitor" % (address["ip"],)))
+ retval= self.host.run(
+ _check_process_script % {
+ "pid_file_name" : pid_file_name,
+ "monitor_file_name" : monitor_file_name,
+ "qemu_binary" : utils.sh_escape(
+ os.path.join(self.build_dir,
+ "qemu/x86_64-softmmu/"
+ "qemu-system-x86_64")),})
+ if (retval.stdout.strip() !=
+ "process present"):
+ address["is_used"]= False
+
+
+ def delete_guest(self, guest_hostname):
+ """
+ Terminate a virtual machine.
+
+ Args:
+ guest_hostname: the ip (as it was specified in the
+ address list given to install()) of the guest
+ to terminate.
+
+ Raises:
+ AutoservVirtError: the guest_hostname argument is
+ invalid
+
+ TODO(poirier): is there a difference in qemu between
+ sending SIGTEM or quitting from the monitor?
+ TODO(poirier): there are a lot of race conditions in this code
+ because the process might terminate on its own anywhere in
+ between
+ """
+ for address in self.addresses:
+ if address["ip"] == guest_hostname:
+ if address["is_used"]:
+ break
+ else:
+ # Will happen if deinitialize() is
+ # called while guest objects still
+ # exit and these are del'ed after.
+ # In that situation, nothing is to
+ # be done here, don't throw an error
+ # either because it will print an
+ # ugly message during garbage
+ # collection. The solution would be to
+ # delete the guest objects before
+ # calling deinitialize(), this can't be
+ # done by the KVM class, it has no
+ # reference to those objects and it
+ # cannot have any either. The Guest
+ # objects already need to have a
+ # reference to their managing
+ # hypervisor. If the hypervisor had a
+ # reference to the Guest objects it
+ # manages, it would create a circular
+ # reference and those objects would
+ # not be elligible for garbage
+ # collection. In turn, this means that
+ # the KVM object would not be
+ # automatically del'ed at the end of
+ # the program and guests that are still
+ # running would be left unattended.
+ # Note that this circular reference
+ # problem could be avoided by using
+ # weakref's in class KVM but the
+ # control file will most likely also
+ # have references to the guests.
+ return
+ else:
+ raise error.AutoservVirtError("Unknown guest hostname")
+
+ pid_file_name= utils.sh_escape(os.path.join(self.pid_dir,
+ "vhost%s_pid" % (address["ip"],)))
+ monitor_file_name= utils.sh_escape(os.path.join(self.pid_dir,
+ "vhost%s_monitor" % (address["ip"],)))
+
+ retval= self.host.run(
+ _check_process_script % {
+ "pid_file_name" : pid_file_name,
+ "monitor_file_name" : monitor_file_name,
+ "qemu_binary" : utils.sh_escape(os.path.join(
+ self.build_dir,
+ "qemu/x86_64-softmmu/qemu-system-x86_64")),})
+ if retval.stdout.strip() == "process present":
+ self.host.run('kill $(cat "%s")' %(
+ pid_file_name,))
+ self.host.run('rm -f "%s"' %(
+ pid_file_name,))
+ self.host.run('rm -f "%s"' %(
+ monitor_file_name,))
+ address["is_used"]= False
+
+
+ def reset_guest(self, guest_hostname):
+ """
+ Perform a hard reset on a virtual machine.
+
+ Args:
+ guest_hostname: the ip (as it was specified in the
+ address list given to install()) of the guest
+ to terminate.
+
+ Raises:
+ AutoservVirtError: the guest_hostname argument is
+ invalid
+ """
+ for address in self.addresses:
+ if address["ip"] is guest_hostname:
+ if address["is_used"]:
+ break
+ else:
+ raise error.AutoservVirtError("guest "
+ "hostname not in use")
+ else:
+ raise error.AutoservVirtError("Unknown guest hostname")
+
+ monitor_file_name= utils.sh_escape(os.path.join(self.pid_dir,
+ "vhost%s_monitor" % (address["ip"],)))
+
+ self.host.run('python -c "%s"' % (utils.sh_escape(
+ _hard_reset_script % {
+ "monitor_file_name" : monitor_file_name,}),))