ia64/xen-unstable

view tools/python/xen/xend/XendDomainInfo.py @ 5346:cf712d7c809c

bitkeeper revision 1.1662.1.9 (42a485d0ePlJLabsERQDyPFBJ1tF9Q)

controller.py:
Rename name -> type and use cls instead of klass.
XendDomainInfo.py:
g/c unneeded code.
Use vm.id after setdom.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Mon Jun 06 17:20:16 2005 +0000 (2005-06-06)
parents e1cd6bd22fb9
children 9f893f674211
line source
1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
3 """Representation of a single domain.
4 Includes support for domain construction, using
5 open-ended configurations.
7 Author: Mike Wray <mike.wray@hp.com>
9 """
11 import string
12 import os
13 import time
14 import threading
16 import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
17 from xen.util.ip import check_subnet, get_current_ipgw
18 from xen.util.blkif import blkdev_uname_to_file
20 from xen.xend.server import channel, controller
21 from xen.xend.server import SrvDaemon; xend = SrvDaemon.instance()
22 from xen.xend.server import messages
23 from xen.xend.server.channel import channelFactory
25 from xen.xend import sxp
26 from xen.xend.PrettyPrint import prettyprintstring
27 from xen.xend.XendBootloader import bootloader
28 from xen.xend.XendLogging import log
29 from XendError import XendError, VmError
30 from xen.xend.XendRoot import get_component
32 """Flag for a block device backend domain."""
33 SIF_BLK_BE_DOMAIN = (1<<4)
35 """Flag for a net device backend domain."""
36 SIF_NET_BE_DOMAIN = (1<<5)
38 """Shutdown code for poweroff."""
39 DOMAIN_POWEROFF = 0
41 """Shutdown code for reboot."""
42 DOMAIN_REBOOT = 1
44 """Shutdown code for suspend."""
45 DOMAIN_SUSPEND = 2
47 """Shutdown code for crash."""
48 DOMAIN_CRASH = 3
50 """Map shutdown codes to strings."""
51 shutdown_reasons = {
52 DOMAIN_POWEROFF: "poweroff",
53 DOMAIN_REBOOT : "reboot",
54 DOMAIN_SUSPEND : "suspend",
55 DOMAIN_CRASH : "crash",
56 }
58 """Map shutdown reasons to the message type to use.
59 """
60 shutdown_messages = {
61 'poweroff' : 'shutdown_poweroff_t',
62 'reboot' : 'shutdown_reboot_t',
63 'suspend' : 'shutdown_suspend_t',
64 'sysrq' : 'shutdown_sysrq_t',
65 }
67 RESTART_ALWAYS = 'always'
68 RESTART_ONREBOOT = 'onreboot'
69 RESTART_NEVER = 'never'
71 restart_modes = [
72 RESTART_ALWAYS,
73 RESTART_ONREBOOT,
74 RESTART_NEVER,
75 ]
77 STATE_RESTART_PENDING = 'pending'
78 STATE_RESTART_BOOTING = 'booting'
80 STATE_VM_OK = "ok"
81 STATE_VM_TERMINATED = "terminated"
82 STATE_VM_SUSPENDED = "suspended"
85 def domain_exists(name):
86 # See comment in XendDomain constructor.
87 xd = get_component('xen.xend.XendDomain')
88 return xd.domain_lookup_by_name(name)
90 def shutdown_reason(code):
91 """Get a shutdown reason from a code.
93 @param code: shutdown code
94 @type code: int
95 @return: shutdown reason
96 @rtype: string
97 """
98 return shutdown_reasons.get(code, "?")
100 config_handlers = {}
102 def add_config_handler(name, h):
103 """Add a handler for a config field.
105 @param name: field name
106 @param h: handler: fn(vm, config, field, index)
107 """
108 config_handlers[name] = h
110 def get_config_handler(name):
111 """Get a handler for a config field.
113 returns handler or None
114 """
115 return config_handlers.get(name)
117 """Table of handlers for devices.
118 Indexed by device type.
119 """
120 device_handlers = {}
122 def add_device_handler(name, type):
123 device_handlers[name] = type
125 def get_device_handler(name):
126 return device_handlers[name]
128 def dom_get(dom):
129 """Get info from xen for an existing domain.
131 @param dom: domain id
132 @return: info or None
133 """
134 domlist = xc.domain_getinfo(dom, 1)
135 if domlist and dom == domlist[0]['dom']:
136 return domlist[0]
137 return None
139 class XendDomainInfo:
140 """Virtual machine object."""
142 """Minimum time between domain restarts in seconds.
143 """
144 MINIMUM_RESTART_TIME = 20
146 def _create(cls):
147 """Create a vm object.
149 @return vm
150 """
151 vm = cls()
152 return vm
154 _create = classmethod(_create)
156 def create(cls, config):
157 """Create a VM from a configuration.
158 If a vm has been partially created and there is an error it
159 is destroyed.
161 @param config configuration
162 @raise: VmError for invalid configuration
163 """
164 vm = cls._create()
165 vm.construct(config)
166 return vm
168 create = classmethod(create)
170 def recreate(cls, savedinfo, info, unknown=False):
171 """Create the VM object for an existing domain.
173 @param savedinfo: saved info from the domain DB
174 @param info: domain info from xc
175 @type info: xc domain dict
176 """
177 if unknown:
178 vm = cls._create()
179 else:
180 vm = cls()
182 log.debug('savedinfo=' + prettyprintstring(savedinfo))
183 log.debug('info=' + str(info))
185 vm.recreate = True
186 vm.savedinfo = savedinfo
187 vm.setdom(info['dom'])
188 vm.memory = info['mem_kb']/1024
190 start_time = sxp.child_value(savedinfo, 'start_time')
191 if start_time is not None:
192 vm.start_time = float(start_time)
193 vm.restart_state = sxp.child_value(savedinfo, 'restart_state')
194 vm.restart_count = int(sxp.child_value(savedinfo, 'restart_count', 0))
195 restart_time = sxp.child_value(savedinfo, 'restart_time')
196 if restart_time is not None:
197 vm.restart_time = float(restart_time)
198 config = sxp.child_value(savedinfo, 'config')
200 if config:
201 vm.construct(config)
202 else:
203 vm.setName(sxp.child_value(savedinfo, 'name',
204 "Domain-%d" % info['dom']))
205 vm.recreate = False
206 vm.savedinfo = None
208 return vm
210 recreate = classmethod(recreate)
212 def restore(cls, config):
213 """Create a domain and a VM object to do a restore.
215 @param config: domain configuration
216 """
217 vm = cls._create()
218 dom = xc.domain_create()
219 vm.setdom(dom)
220 vm.dom_construct(vm.id, config)
221 return vm
223 restore = classmethod(restore)
225 def __init__(self):
226 self.recreate = 0
227 self.restore = 0
229 self.config = None
230 self.id = None
231 self.cpu_weight = 1
232 self.start_time = None
233 self.name = None
234 self.memory = None
235 self.image = None
237 self.channel = None
238 self.controllers = {}
240 self.info = None
241 self.blkif_backend = False
242 self.netif_backend = False
243 #todo: state: running, suspended
244 self.state = STATE_VM_OK
245 self.state_updated = threading.Condition()
246 self.shutdown_pending = None
248 #todo: set to migrate info if migrating
249 self.migrate = None
251 self.restart_mode = RESTART_ONREBOOT
252 self.restart_state = None
253 self.restart_time = None
254 self.restart_count = 0
256 self.console_port = None
257 self.savedinfo = None
258 self.vcpus = 1
259 self.bootloader = None
261 def setdom(self, dom):
262 """Set the domain id.
264 @param dom: domain id
265 """
266 self.id = int(dom)
268 def getDomain(self):
269 return self.id
271 def setName(self, name):
272 self.name = name
273 #self.db.name = self.name
275 def getName(self):
276 return self.name
278 def getChannel(self):
279 return self.channel
281 def update(self, info):
282 """Update with info from xc.domain_getinfo().
283 """
284 self.info = info
285 self.memory = self.info['mem_kb'] / 1024
287 def state_set(self, state):
288 self.state_updated.acquire()
289 if self.state != state:
290 self.state = state
291 self.state_updated.notifyAll()
292 self.state_updated.release()
294 def state_wait(self, state):
295 self.state_updated.acquire()
296 while self.state != state:
297 self.state_updated.wait()
298 self.state_updated.release()
300 def __str__(self):
301 s = "domain"
302 s += " id=" + str(self.id)
303 s += " name=" + self.name
304 s += " memory=" + str(self.memory)
305 console = self.getConsole()
306 if console:
307 s += " console=" + str(console.console_port)
308 s += ""
309 return s
311 __repr__ = __str__
313 def getDeviceTypes(self):
314 return self.controllers.keys()
316 def getDeviceControllers(self):
317 return self.controllers.values()
319 def getDeviceController(self, type, error=True):
320 ctrl = self.controllers.get(type)
321 if not ctrl and error:
322 raise XendError("invalid device type:" + type)
323 return ctrl
325 def findDeviceController(self, type):
326 return (self.getDeviceController(type, error=False)
327 or self.createDeviceController(type))
329 def createDeviceController(self, type):
330 ctrl = controller.createDevController(type, self, recreate=self.recreate)
331 self.controllers[type] = ctrl
332 return ctrl
334 def createDevice(self, type, devconfig, change=False):
335 ctrl = self.findDeviceController(type)
336 return ctrl.createDevice(devconfig, recreate=self.recreate,
337 change=change)
339 def configureDevice(self, type, id, devconfig):
340 ctrl = self.getDeviceController(type)
341 return ctrl.configureDevice(id, devconfig)
343 def destroyDevice(self, type, id, change=False, reboot=False):
344 ctrl = self.getDeviceController(type)
345 return ctrl.destroyDevice(id, change=change, reboot=reboot)
347 def deleteDevice(self, type, id):
348 ctrl = self.getDeviceController(type)
349 return ctrl.deleteDevice(id)
351 def getDevice(self, type, id, error=True):
352 ctrl = self.getDeviceController(type)
353 return ctrl.getDevice(id, error=error)
355 def getDeviceIds(self, type):
356 ctrl = self.getDeviceController(type)
357 return ctrl.getDeviceIds()
359 def getDeviceSxprs(self, type):
360 ctrl = self.getDeviceController(type)
361 return ctrl.getDeviceSxprs()
363 def sxpr(self):
364 sxpr = ['domain',
365 ['id', self.id],
366 ['name', self.name],
367 ['memory', self.memory] ]
369 if self.info:
370 sxpr.append(['maxmem', self.info['maxmem_kb']/1024 ])
371 run = (self.info['running'] and 'r') or '-'
372 block = (self.info['blocked'] and 'b') or '-'
373 pause = (self.info['paused'] and 'p') or '-'
374 shut = (self.info['shutdown'] and 's') or '-'
375 crash = (self.info['crashed'] and 'c') or '-'
376 state = run + block + pause + shut + crash
377 sxpr.append(['state', state])
378 if self.info['shutdown']:
379 reason = shutdown_reason(self.info['shutdown_reason'])
380 sxpr.append(['shutdown_reason', reason])
381 sxpr.append(['cpu', self.info['vcpu_to_cpu'][0]])
382 sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
383 sxpr.append(['vcpus', self.info['vcpus']])
384 sxpr.append(['cpumap', self.info['cpumap']])
385 sxpr.append(['vcpu_to_cpu', ''.join(map(lambda x: str(x),
386 self.info['vcpu_to_cpu'][0:self.info['vcpus']]))])
388 if self.start_time:
389 up_time = time.time() - self.start_time
390 sxpr.append(['up_time', str(up_time) ])
391 sxpr.append(['start_time', str(self.start_time) ])
393 if self.channel:
394 sxpr.append(self.channel.sxpr())
395 console = self.getConsole()
396 if console:
397 sxpr.append(console.sxpr())
398 if self.restart_count:
399 sxpr.append(['restart_count', self.restart_count])
400 if self.restart_state:
401 sxpr.append(['restart_state', self.restart_state])
402 if self.restart_time:
403 sxpr.append(['restart_time', str(self.restart_time)])
404 devs = self.sxpr_devices()
405 if devs:
406 sxpr.append(devs)
407 if self.config:
408 sxpr.append(['config', self.config])
409 return sxpr
411 def sxpr_devices(self):
412 sxpr = []
413 for ty in self.getDeviceTypes():
414 devs = self.getDeviceSxprs(ty)
415 sxpr += devs
416 if sxpr:
417 sxpr.insert(0, 'devices')
418 else:
419 sxpr = None
420 return sxpr
422 def check_name(self, name):
423 """Check if a vm name is valid. Valid names contain alphabetic characters,
424 digits, or characters in '_-.:/+'.
425 The same name cannot be used for more than one vm at the same time.
427 @param name: name
428 @raise: VMerror if invalid
429 """
430 if self.recreate: return
431 if name is None or name == '':
432 raise VmError('missing vm name')
433 for c in name:
434 if c in string.digits: continue
435 if c in '_-.:/+': continue
436 if c in string.ascii_letters: continue
437 raise VmError('invalid vm name')
438 dominfo = domain_exists(name)
439 # When creating or rebooting, a domain with my name should not exist.
440 # When restoring, a domain with my name will exist, but it should have
441 # my domain id.
442 if not dominfo:
443 return
444 if dominfo.is_terminated():
445 return
446 if not self.id or (dominfo.id != self.id):
447 raise VmError('vm name clash: ' + name)
449 def construct(self, config):
450 """Construct the vm instance from its configuration.
452 @param config: configuration
453 @raise: VmError on error
454 """
455 # todo - add support for scheduling params?
456 self.config = config
457 try:
458 # Initial domain create.
459 self.setName(sxp.child_value(config, 'name'))
460 self.check_name(self.name)
461 self.init_image()
462 self.configure_cpus(config)
463 self.init_domain()
464 self.register_domain()
465 self.configure_bootloader()
467 # Create domain devices.
468 self.configure_backends()
469 self.configure_console()
470 self.configure_restart()
471 self.construct_image()
472 self.configure()
473 except Exception, ex:
474 # Catch errors, cleanup and re-raise.
475 print 'Domain construction error:', ex
476 import traceback
477 traceback.print_exc()
478 self.destroy()
479 raise
481 def register_domain(self):
482 xd = get_component('xen.xend.XendDomain')
483 xd._add_domain(self)
485 def configure_cpus(self, config):
486 try:
487 self.cpu_weight = float(sxp.child_value(config, 'cpu_weight', '1'))
488 except:
489 raise VmError('invalid cpu weight')
490 self.memory = int(sxp.child_value(config, 'memory'))
491 if self.memory is None:
492 raise VmError('missing memory size')
493 cpu = sxp.child_value(config, 'cpu')
494 if self.recreate and self.id and cpu is not None and int(cpu) >= 0:
495 xc.domain_pincpu(self.id, 0, 1<<int(cpu))
496 try:
497 image = sxp.child_value(self.config, 'image')
498 vcpus = sxp.child_value(image, 'vcpus')
499 if vcpus:
500 self.vcpus = int(vcpus)
501 except:
502 raise VmError('invalid vcpus value')
504 def init_image(self):
505 """Create boot image handler for the domain.
506 """
507 image = sxp.child_value(self.config, 'image')
508 if image is None:
509 raise VmError('missing image')
510 self.image = ImageHandler.create(self, image)
512 def construct_image(self):
513 """Construct the boot image for the domain.
514 """
515 self.create_channel()
516 self.image.createImage()
517 #self.image.exportToDB()
518 #if self.store_channel:
519 # self.db.introduceDomain(self.id,
520 # self.store_mfn,
521 # self.store_channel)
523 def get_device_savedinfo(self, type, id):
524 val = None
525 if self.savedinfo is None:
526 return val
527 devices = sxp.child(self.savedinfo, 'devices')
528 if devices is None:
529 return val
530 for d in sxp.children(devices, type):
531 did = sxp.child_value(d, 'id')
532 if did is None: continue
533 if int(did) == id:
534 val = d
535 break
536 return val
538 def get_device_recreate(self, type, id):
539 return self.get_device_savedinfo(type, id) or self.recreate
541 def destroy(self):
542 """Completely destroy the vm.
543 """
544 self.cleanup()
545 self.destroy_domain()
547 def destroy_domain(self):
548 """Destroy the vm's domain.
549 The domain will not finally go away unless all vm
550 devices have been released.
551 """
552 if self.channel:
553 self.channel.close()
554 self.channel = None
555 if self.image:
556 try:
557 self.image.destroy()
558 self.image = None
559 except:
560 pass
561 if self.id is None: return 0
562 try:
563 xc.domain_destroy(dom=self.id)
564 except Exception, err:
565 log.exception("Domain destroy failed: %s", self.name)
567 def cleanup(self):
568 """Cleanup vm resources: release devices.
569 """
570 self.state = STATE_VM_TERMINATED
571 self.release_devices()
573 def is_terminated(self):
574 """Check if a domain has been terminated.
575 """
576 return self.state == STATE_VM_TERMINATED
578 def release_devices(self):
579 """Release all vm devices.
580 """
581 reboot = self.restart_pending()
582 for ctrl in self.getDeviceControllers():
583 if ctrl.isDestroyed(): continue
584 ctrl.destroyController(reboot=reboot)
586 def show(self):
587 """Print virtual machine info.
588 """
589 print "[VM dom=%d name=%s memory=%d" % (self.id, self.name, self.memory)
590 print "image:"
591 sxp.show(self.image)
592 print "]"
594 def init_domain(self):
595 """Initialize the domain memory.
596 """
597 if self.recreate:
598 return
599 if self.start_time is None:
600 self.start_time = time.time()
601 try:
602 cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
603 except:
604 raise VmError('invalid cpu')
605 dom = self.image.initDomain(self.id, self.memory, cpu, self.cpu_weight)
606 log.debug('init_domain> Created domain=%d name=%s memory=%d',
607 dom, self.name, self.memory)
608 if not self.restore:
609 self.setdom(dom)
611 def create_channel(self):
612 """Create the control channel to the domain.
613 If saved info is available recreate the channel using the saved ports.
614 """
615 local = 0
616 remote = 1
617 if self.savedinfo:
618 info = sxp.child(self.savedinfo, "channel")
619 if info:
620 local = int(sxp.child_value(info, "local_port", 0))
621 remote = int(sxp.child_value(info, "remote_port", 1))
622 self.channel = channelFactory().openChannel(str(self.id),
623 local_port=local,
624 remote_port=remote)
626 def create_configured_devices(self):
627 devices = sxp.children(self.config, 'device')
628 for d in devices:
629 dev_config = sxp.child0(d)
630 if dev_config is None:
631 raise VmError('invalid device')
632 dev_type = sxp.name(dev_config)
633 ctrl_type = get_device_handler(dev_type)
634 if ctrl_type is None:
635 raise VmError('unknown device type: ' + dev_type)
636 self.createDevice(ctrl_type, dev_config)
638 def create_devices(self):
639 """Create the devices for a vm.
641 @raise: VmError for invalid devices
642 """
643 if self.rebooting():
644 for ctrl in self.getDeviceControllers():
645 ctrl.initController(reboot=True)
646 else:
647 self.create_configured_devices()
649 def device_create(self, dev_config):
650 """Create a new device.
652 @param dev_config: device configuration
653 """
654 dev_type = sxp.name(dev_config)
655 dev = self.createDevice(self, dev_config, change=True)
656 self.config.append(['device', dev.getConfig()])
657 return dev.sxpr()
659 def device_configure(self, dev_config, id):
660 """Configure an existing device.
662 @param dev_config: device configuration
663 @param id: device id
664 """
665 type = sxp.name(dev_config)
666 dev = self.getDevice(type, id)
667 old_config = dev.getConfig()
668 new_config = dev.configure(dev_config, change=True)
669 # Patch new config into vm config.
670 new_full_config = ['device', new_config]
671 old_full_config = ['device', old_config]
672 old_index = self.config.index(old_full_config)
673 self.config[old_index] = new_full_config
674 return new_config
676 def device_refresh(self, type, id):
677 """Refresh a device.
679 @param type: device type
680 @param id: device id
681 """
682 dev = self.getDevice(type, id)
683 dev.refresh()
685 def device_delete(self, type, id):
686 """Destroy and remove a device.
688 @param type: device type
689 @param id: device id
690 """
691 dev = self.getDevice(type, id)
692 dev_config = dev.getConfig()
693 if dev_config:
694 self.config.remove(['device', dev_config])
695 self.deleteDevice(type, dev.getId())
697 def configure_bootloader(self):
698 """Configure boot loader.
699 """
700 self.bootloader = sxp.child_value(self.config, "bootloader")
702 def configure_console(self):
703 """Configure the vm console port.
704 """
705 x = sxp.child_value(self.config, 'console')
706 if x:
707 try:
708 port = int(x)
709 except:
710 raise VmError('invalid console:' + str(x))
711 self.console_port = port
713 def configure_restart(self):
714 """Configure the vm restart mode.
715 """
716 r = sxp.child_value(self.config, 'restart', RESTART_ONREBOOT)
717 if r not in restart_modes:
718 raise VmError('invalid restart mode: ' + str(r))
719 self.restart_mode = r;
721 def restart_needed(self, reason):
722 """Determine if the vm needs to be restarted when shutdown
723 for the given reason.
725 @param reason: shutdown reason
726 @return True if needs restart, False otherwise
727 """
728 if self.restart_mode == RESTART_NEVER:
729 return False
730 if self.restart_mode == RESTART_ALWAYS:
731 return True
732 if self.restart_mode == RESTART_ONREBOOT:
733 return reason == 'reboot'
734 return False
736 def restart_cancel(self):
737 """Cancel a vm restart.
738 """
739 self.restart_state = None
741 def restarting(self):
742 """Put the vm into restart mode.
743 """
744 self.restart_state = STATE_RESTART_PENDING
746 def restart_pending(self):
747 """Test if the vm has a pending restart.
748 """
749 return self.restart_state == STATE_RESTART_PENDING
751 def rebooting(self):
752 return self.restart_state == STATE_RESTART_BOOTING
754 def restart_check(self):
755 """Check if domain restart is OK.
756 To prevent restart loops, raise an error if it is
757 less than MINIMUM_RESTART_TIME seconds since the last restart.
758 """
759 tnow = time.time()
760 if self.restart_time is not None:
761 tdelta = tnow - self.restart_time
762 if tdelta < self.MINIMUM_RESTART_TIME:
763 self.restart_cancel()
764 msg = 'VM %s restarting too fast' % self.name
765 log.error(msg)
766 raise VmError(msg)
767 self.restart_time = tnow
768 self.restart_count += 1
770 def restart(self):
771 """Restart the domain after it has exited.
772 Reuses the domain id and console port.
774 """
775 try:
776 self.state = STATE_VM_OK
777 self.shutdown_pending = None
778 self.restart_check()
779 self.restart_state = STATE_RESTART_BOOTING
780 if self.bootloader:
781 self.config = self.bootloader_config()
782 self.construct(self.config)
783 finally:
784 self.restart_state = None
786 def bootloader_config(self):
787 # if we're restarting with a bootloader, we need to run it
788 # FIXME: this assumes the disk is the first device and
789 # that we're booting from the first disk
790 blcfg = None
791 # FIXME: this assumes that we want to use the first disk
792 dev = sxp.child_value(self.config, "device")
793 if dev:
794 disk = sxp.child_value(dev, "uname")
795 fn = blkdev_uname_to_file(disk)
796 blcfg = bootloader(self.bootloader, fn, 1, self.vcpus)
797 if blcfg is None:
798 msg = "Had a bootloader specified, but can't find disk"
799 log.error(msg)
800 raise VmError(msg)
801 config = sxp.merge(['vm', blconfig ], self.config)
802 return config
804 def configure_backends(self):
805 """Set configuration flags if the vm is a backend for netif or blkif.
806 Configure the backends to use for vbd and vif if specified.
807 """
808 for c in sxp.children(self.config, 'backend'):
809 v = sxp.child0(c)
810 name = sxp.name(v)
811 if name == 'blkif':
812 self.blkif_backend = True
813 elif name == 'netif':
814 self.netif_backend = True
815 elif name == 'usbif':
816 self.usbif_backend = True
817 else:
818 raise VmError('invalid backend type:' + str(name))
820 def configure(self):
821 """Configure a vm.
823 """
824 self.configure_fields()
825 self.create_console()
826 self.create_devices()
827 self.create_blkif()
829 def create_console(self):
830 console = self.getConsole()
831 if not console:
832 config = ['console']
833 if self.console_port:
834 config.append(['console_port', self.console_port])
835 console = self.createDevice('console', config)
836 return console
838 def getConsole(self):
839 console_ctrl = self.getDeviceController("console", error=False)
840 if console_ctrl:
841 return console_ctrl.getDevice(0)
842 return None
844 def create_blkif(self):
845 """Create the block device interface (blkif) for the vm.
846 The vm needs a blkif even if it doesn't have any disks
847 at creation time, for example when it uses NFS root.
849 """
850 blkif = self.getDeviceController("vbd", error=False)
851 if not blkif:
852 blkif = self.createDeviceController("vbd")
853 backend = blkif.getBackend(0)
854 backend.connect(recreate=self.recreate)
856 def dom_construct(self, dom, config):
857 """Construct a vm for an existing domain.
859 @param dom: domain id
860 @param config: domain configuration
861 """
862 d = dom_get(dom)
863 if not d:
864 raise VmError("Domain not found: %d" % dom)
865 try:
866 self.restore = True
867 self.setdom(dom)
868 self.memory = d['mem_kb']/1024
869 self.construct(config)
870 finally:
871 self.restore = False
873 def configure_fields(self):
874 """Process the vm configuration fields using the registered handlers.
875 """
876 index = {}
877 for field in sxp.children(self.config):
878 field_name = sxp.name(field)
879 field_index = index.get(field_name, 0)
880 field_handler = get_config_handler(field_name)
881 # Ignore unknown fields. Warn?
882 if field_handler:
883 v = field_handler(self, self.config, field, field_index)
884 else:
885 log.warning("Unknown config field %s", field_name)
886 index[field_name] = field_index + 1
888 def mem_target_set(self, target):
889 """Set domain memory target in pages.
890 """
891 if self.channel:
892 msg = messages.packMsg('mem_request_t', { 'target' : target * (1 << 8)} )
893 self.channel.writeRequest(msg)
895 def shutdown(self, reason, key=0):
896 msgtype = shutdown_messages.get(reason)
897 if not msgtype:
898 raise XendError('invalid reason:' + reason)
899 extra = {}
900 if reason == 'sysrq':
901 extra['key'] = key
902 if self.channel:
903 msg = messages.packMsg(msgtype, extra)
904 self.channel.writeRequest(msg)
905 if not reason in ['suspend', 'sysrq']:
906 self.shutdown_pending = {'start':time.time(), 'reason':reason,
907 'key':key}
909 def shutdown_time_left(self, timeout):
910 if not self.shutdown_pending:
911 return 0
912 return timeout - (time.time() - self.shutdown_pending['start'])
914 def vm_field_ignore(vm, config, val, index):
915 """Dummy config field handler used for fields with built-in handling.
917 @param vm: virtual machine
918 @param config: vm config
919 @param val: config field
920 @param index: field index
921 """
922 pass
924 def vm_field_maxmem(vm, config, val, index):
925 """Configure vm memory limit.
927 @param vm: virtual machine
928 @param config: vm config
929 @param val: config field
930 @param index: field index
931 """
932 maxmem = sxp.child0(val)
933 if maxmem is None:
934 maxmem = vm.memory
935 try:
936 maxmem = int(maxmem)
937 except:
938 raise VmError("invalid maxmem: " + str(maxmem))
939 xc.domain_setmaxmem(vm.id, maxmem_kb = maxmem * 1024)
941 #============================================================================
942 # Register image handlers.
943 from image import \
944 addImageHandlerClass, \
945 ImageHandler, \
946 LinuxImageHandler, \
947 Plan9ImageHandler, \
948 VmxImageHandler
950 addImageHandlerClass(LinuxImageHandler)
951 addImageHandlerClass(Plan9ImageHandler)
952 addImageHandlerClass(VmxImageHandler)
954 # Ignore the fields we already handle.
955 add_config_handler('name', vm_field_ignore)
956 add_config_handler('memory', vm_field_ignore)
957 add_config_handler('cpu', vm_field_ignore)
958 add_config_handler('cpu_weight', vm_field_ignore)
959 add_config_handler('console', vm_field_ignore)
960 add_config_handler('restart', vm_field_ignore)
961 add_config_handler('image', vm_field_ignore)
962 add_config_handler('device', vm_field_ignore)
963 add_config_handler('backend', vm_field_ignore)
964 add_config_handler('vcpus', vm_field_ignore)
965 add_config_handler('bootloader', vm_field_ignore)
967 # Register other config handlers.
968 add_config_handler('maxmem', vm_field_maxmem)
970 #============================================================================
971 # Register device controllers and their device config types.
973 from server import console
974 controller.addDevControllerClass("console", console.ConsoleController)
976 from server import blkif
977 controller.addDevControllerClass("vbd", blkif.BlkifController)
978 add_device_handler("vbd", "vbd")
980 from server import netif
981 controller.addDevControllerClass("vif", netif.NetifController)
982 add_device_handler("vif", "vif")
984 from server import pciif
985 controller.addDevControllerClass("pci", pciif.PciController)
986 add_device_handler("pci", "pci")
988 from xen.xend.server import usbif
989 controller.addDevControllerClass("usb", usbif.UsbifController)
990 add_device_handler("usb", "usb")
992 #============================================================================