+
+class _VM(object):
+ """Windows Virtual Machine"""
+ def __init__(self, disk, serial):
+ """Create _VM instance
+
+ disk: VM's hard disk
+ serial: File to save the output of the serial port
+ """
+
+ self.disk = disk
+ self.serial = serial
+
+ def random_mac():
+ mac = [0x00, 0x16, 0x3e,
+ random.randint(0x00, 0x7f),
+ random.randint(0x00, 0xff),
+ random.randint(0x00, 0xff)]
+
+ return ':'.join(map(lambda x: "%02x" % x, mac))
+
+ # Use ganeti's VNC port range for a random vnc port
+ self.display = random.randint(11000, 14999) - 5900
+
+ args = [
+ 'kvm', '-smp', '1', '-m', '1024', '-drive',
+ 'file=%s,format=raw,cache=unsafe,if=virtio' % self.disk,
+ '-netdev', 'type=user,hostfwd=tcp::445-:445,id=netdev0',
+ '-device', 'virtio-net-pci,mac=%s,netdev=netdev0' % random_mac(),
+ '-vnc', ':%d' % self.display, '-serial', 'file:%s' % self.serial,
+ '-monitor', 'stdio']
+
+ self.process = subprocess.Popen(args, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+
+ def isalive(self):
+ """Check if the VM is still alive"""
+ return self.process.poll() is None
+
+ def destroy(self):
+ """Destroy the VM"""
+
+ if not self.isalive():
+ return
+
+ def handler(signum, frame):
+ self.process.terminate()
+ time.sleep(1)
+ if self.isalive():
+ self.process.kill()
+ self.process.wait()
+ self.out.output("timed-out")
+ raise FatalError("VM destroy timed-out")
+
+ signal.signal(signal.SIGALRM, handler)
+
+ signal.alarm(SHUTDOWN_TIMEOUT)
+ self.process.communicate(input="system_powerdown\n")
+ signal.alarm(0)
+
+ def wait(self, timeout=0):
+ """Wait for the VM to terminate"""
+
+ def handler(signum, frame):
+ self.destroy()
+ raise FatalError("VM wait timed-out.")
+
+ signal.signal(signal.SIGALRM, handler)
+
+ signal.alarm(timeout)
+ stdout, stderr = self.process.communicate()
+ signal.alarm(0)
+
+ return (stdout, stderr, self.process.poll())
+