| 1 | from xen.xend.server.DevController import DevController |
|---|
| 2 | from xen.xend.XendLogging import log |
|---|
| 3 | |
|---|
| 4 | from xen.xend.XendError import VmError |
|---|
| 5 | import xen.xend |
|---|
| 6 | import os |
|---|
| 7 | |
|---|
| 8 | def spawn_detached(path, args, env): |
|---|
| 9 | p = os.fork() |
|---|
| 10 | if p == 0: |
|---|
| 11 | os.spawnve(os.P_NOWAIT, path, args, env) |
|---|
| 12 | os._exit(0) |
|---|
| 13 | else: |
|---|
| 14 | os.waitpid(p, 0) |
|---|
| 15 | |
|---|
| 16 | CONFIG_ENTRIES = ['type', 'vncdisplay', 'vnclisten', 'vncpasswd', 'vncunused', |
|---|
| 17 | 'display', 'xauthority', 'keymap', |
|---|
| 18 | 'uuid', 'location', 'protocol'] |
|---|
| 19 | |
|---|
| 20 | class VfbifController(DevController): |
|---|
| 21 | """Virtual frame buffer controller. Handles all vfb devices for a domain. |
|---|
| 22 | Note that we only support a single vfb per domain at the moment. |
|---|
| 23 | """ |
|---|
| 24 | |
|---|
| 25 | def __init__(self, vm): |
|---|
| 26 | DevController.__init__(self, vm) |
|---|
| 27 | |
|---|
| 28 | def getDeviceDetails(self, config): |
|---|
| 29 | """@see DevController.getDeviceDetails""" |
|---|
| 30 | |
|---|
| 31 | back = dict([(k, str(config[k])) for k in CONFIG_ENTRIES |
|---|
| 32 | if config.has_key(k)]) |
|---|
| 33 | |
|---|
| 34 | devid = 0 |
|---|
| 35 | return (devid, back, {}) |
|---|
| 36 | |
|---|
| 37 | |
|---|
| 38 | def getDeviceConfiguration(self, devid): |
|---|
| 39 | result = DevController.getDeviceConfiguration(self, devid) |
|---|
| 40 | |
|---|
| 41 | devinfo = self.readBackend(devid, *CONFIG_ENTRIES) |
|---|
| 42 | return dict([(CONFIG_ENTRIES[i], devinfo[i]) |
|---|
| 43 | for i in range(len(CONFIG_ENTRIES)) |
|---|
| 44 | if devinfo[i] is not None]) |
|---|
| 45 | |
|---|
| 46 | |
|---|
| 47 | def createDevice(self, config): |
|---|
| 48 | DevController.createDevice(self, config) |
|---|
| 49 | if self.vm.info.is_hvm(): |
|---|
| 50 | # is HVM, so qemu-dm will handle the vfb. |
|---|
| 51 | return |
|---|
| 52 | |
|---|
| 53 | std_args = [ "--domid", "%d" % self.vm.getDomid(), |
|---|
| 54 | "--title", self.vm.getName() ] |
|---|
| 55 | t = config.get("type", None) |
|---|
| 56 | if t == "vnc": |
|---|
| 57 | passwd = None |
|---|
| 58 | if config.has_key("vncpasswd"): |
|---|
| 59 | passwd = config["vncpasswd"] |
|---|
| 60 | else: |
|---|
| 61 | passwd = xen.xend.XendOptions.instance().get_vncpasswd_default() |
|---|
| 62 | if passwd: |
|---|
| 63 | self.vm.storeVm("vncpasswd", passwd) |
|---|
| 64 | log.debug("Stored a VNC password for vfb access") |
|---|
| 65 | else: |
|---|
| 66 | log.debug("No VNC passwd configured for vfb access") |
|---|
| 67 | |
|---|
| 68 | # Try to start the vnc backend |
|---|
| 69 | args = [xen.util.auxbin.pathTo("xen-vncfb")] |
|---|
| 70 | if config.has_key("vncunused"): |
|---|
| 71 | args += ["--unused"] |
|---|
| 72 | elif config.has_key("vncdisplay"): |
|---|
| 73 | args += ["--vncport", "%d" % (5900 + int(config["vncdisplay"]))] |
|---|
| 74 | vnclisten = config.get("vnclisten", |
|---|
| 75 | xen.xend.XendOptions.instance().get_vnclisten_address()) |
|---|
| 76 | args += [ "--listen", vnclisten ] |
|---|
| 77 | if config.has_key("keymap"): |
|---|
| 78 | args += ["-k", "%s" % config["keymap"]] |
|---|
| 79 | spawn_detached(args[0], args + std_args, os.environ) |
|---|
| 80 | elif t == "sdl": |
|---|
| 81 | args = [xen.util.auxbin.pathTo("xen-sdlfb")] |
|---|
| 82 | env = dict(os.environ) |
|---|
| 83 | if config.has_key("display"): |
|---|
| 84 | env['DISPLAY'] = config["display"] |
|---|
| 85 | if config.has_key("xauthority"): |
|---|
| 86 | env['XAUTHORITY'] = config["xauthority"] |
|---|
| 87 | spawn_detached(args[0], args + std_args, env) |
|---|
| 88 | else: |
|---|
| 89 | raise VmError('Unknown vfb type %s (%s)' % (t, repr(config))) |
|---|
| 90 | |
|---|
| 91 | |
|---|
| 92 | def waitForDevice(self, devid): |
|---|
| 93 | if self.vm.info.get('HVM_boot_policy'): |
|---|
| 94 | log.debug('skip waiting for HVM vfb') |
|---|
| 95 | # is a qemu-dm managed device, don't wait for hotplug for these. |
|---|
| 96 | return |
|---|
| 97 | |
|---|
| 98 | DevController.waitForDevice(self, devid) |
|---|
| 99 | |
|---|
| 100 | |
|---|
| 101 | def reconfigureDevice(self, _, config): |
|---|
| 102 | """ Only allow appending location information of vnc port into |
|---|
| 103 | xenstore.""" |
|---|
| 104 | |
|---|
| 105 | if 'location' in config: |
|---|
| 106 | (devid, back, front) = self.getDeviceDetails(config) |
|---|
| 107 | self.writeBackend(devid, 'location', config['location']) |
|---|
| 108 | return back.get('uuid') |
|---|
| 109 | |
|---|
| 110 | raise VmError('Refusing to reconfigure device vfb:%d' % devid) |
|---|
| 111 | |
|---|
| 112 | def destroyDevice(self, devid, force): |
|---|
| 113 | if self.vm.info.get('HVM_boot_policy'): |
|---|
| 114 | # remove the backend xenstore entries for HVM guests no matter |
|---|
| 115 | # what |
|---|
| 116 | DevController.destroyDevice(self, devid, True) |
|---|
| 117 | else: |
|---|
| 118 | DevController.destroyDevice(self, devid, force) |
|---|
| 119 | |
|---|
| 120 | |
|---|
| 121 | def migrate(self, deviceConfig, network, dst, step, domName): |
|---|
| 122 | if self.vm.info.get('HVM_boot_policy'): |
|---|
| 123 | return 0 |
|---|
| 124 | return DevController.migrate(self, deviceConfig, network, dst, step, |
|---|
| 125 | domName) |
|---|
| 126 | |
|---|
| 127 | class VkbdifController(DevController): |
|---|
| 128 | """Virtual keyboard controller. Handles all vkbd devices for a domain. |
|---|
| 129 | """ |
|---|
| 130 | |
|---|
| 131 | def getDeviceDetails(self, config): |
|---|
| 132 | """@see DevController.getDeviceDetails""" |
|---|
| 133 | devid = 0 |
|---|
| 134 | back = {} |
|---|
| 135 | front = {} |
|---|
| 136 | return (devid, back, front) |
|---|
| 137 | |
|---|
| 138 | def waitForDevice(self, config): |
|---|
| 139 | if self.vm.info.get('HVM_boot_policy'): |
|---|
| 140 | # is a qemu-dm managed device, don't wait for hotplug for these. |
|---|
| 141 | return |
|---|
| 142 | |
|---|
| 143 | DevController.waitForDevice(self, config) |
|---|
| 144 | |
|---|
| 145 | def destroyDevice(self, devid, force): |
|---|
| 146 | if self.vm.info.get('HVM_boot_policy'): |
|---|
| 147 | # remove the backend xenstore entries for HVM guests no matter |
|---|
| 148 | # what |
|---|
| 149 | DevController.destroyDevice(self, devid, True) |
|---|
| 150 | else: |
|---|
| 151 | DevController.destroyDevice(self, devid, force) |
|---|
| 152 | |
|---|
| 153 | def migrate(self, deviceConfig, network, dst, step, domName): |
|---|
| 154 | if self.vm.info.get('HVM_boot_policy'): |
|---|
| 155 | return 0 |
|---|
| 156 | return DevController.migrate(self, deviceConfig, network, dst, step, |
|---|
| 157 | domName) |
|---|