ia64/xen-unstable

view tools/python/xen/xend/XendDomainInfo.py @ 5352:3917e69c7587

bitkeeper revision 1.1662.1.14 (42a4b1f1ZyB5X1YlXHuUGf5X8C-gvQ)

XendDomainInfo.py:
Cleanup store channel.
Signed-off-by: Mike Wray <mike.wray@hp.com>
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Mon Jun 06 20:28:33 2005 +0000 (2005-06-06)
parents 6ffbb7f12940
children cb9679a15acd
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 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 EventChannel, 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 from xen.xend.uuid import getUuid
34 """Flag for a block device backend domain."""
35 SIF_BLK_BE_DOMAIN = (1<<4)
37 """Flag for a net device backend domain."""
38 SIF_NET_BE_DOMAIN = (1<<5)
40 """Shutdown code for poweroff."""
41 DOMAIN_POWEROFF = 0
43 """Shutdown code for reboot."""
44 DOMAIN_REBOOT = 1
46 """Shutdown code for suspend."""
47 DOMAIN_SUSPEND = 2
49 """Shutdown code for crash."""
50 DOMAIN_CRASH = 3
52 """Map shutdown codes to strings."""
53 shutdown_reasons = {
54 DOMAIN_POWEROFF: "poweroff",
55 DOMAIN_REBOOT : "reboot",
56 DOMAIN_SUSPEND : "suspend",
57 DOMAIN_CRASH : "crash",
58 }
60 """Map shutdown reasons to the message type to use.
61 """
62 shutdown_messages = {
63 'poweroff' : 'shutdown_poweroff_t',
64 'reboot' : 'shutdown_reboot_t',
65 'suspend' : 'shutdown_suspend_t',
66 'sysrq' : 'shutdown_sysrq_t',
67 }
69 RESTART_ALWAYS = 'always'
70 RESTART_ONREBOOT = 'onreboot'
71 RESTART_NEVER = 'never'
73 restart_modes = [
74 RESTART_ALWAYS,
75 RESTART_ONREBOOT,
76 RESTART_NEVER,
77 ]
79 STATE_RESTART_PENDING = 'pending'
80 STATE_RESTART_BOOTING = 'booting'
82 STATE_VM_OK = "ok"
83 STATE_VM_TERMINATED = "terminated"
84 STATE_VM_SUSPENDED = "suspended"
87 def domain_exists(name):
88 # See comment in XendDomain constructor.
89 xd = get_component('xen.xend.XendDomain')
90 return xd.domain_lookup_by_name(name)
92 def shutdown_reason(code):
93 """Get a shutdown reason from a code.
95 @param code: shutdown code
96 @type code: int
97 @return: shutdown reason
98 @rtype: string
99 """
100 return shutdown_reasons.get(code, "?")
102 config_handlers = {}
104 def add_config_handler(name, h):
105 """Add a handler for a config field.
107 @param name: field name
108 @param h: handler: fn(vm, config, field, index)
109 """
110 config_handlers[name] = h
112 def get_config_handler(name):
113 """Get a handler for a config field.
115 returns handler or None
116 """
117 return config_handlers.get(name)
119 """Table of handlers for devices.
120 Indexed by device type.
121 """
122 device_handlers = {}
124 def add_device_handler(name, type):
125 device_handlers[name] = type
127 def get_device_handler(name):
128 return device_handlers[name]
130 def dom_get(dom):
131 """Get info from xen for an existing domain.
133 @param dom: domain id
134 @return: info or None
135 """
136 domlist = xc.domain_getinfo(dom, 1)
137 if domlist and dom == domlist[0]['dom']:
138 return domlist[0]
139 return None
141 class XendDomainInfo:
142 """Virtual machine object."""
144 """Minimum time between domain restarts in seconds.
145 """
146 MINIMUM_RESTART_TIME = 20
148 def _create(cls, uuid=None):
149 """Create a vm object with a uuid.
151 @param uuid uuid to use
152 @return vm
153 """
154 if uuid is None:
155 uuid = getUuid()
156 vm = cls()
157 vm.uuid = uuid
158 return vm
160 _create = classmethod(_create)
162 def create(cls, config):
163 """Create a VM from a configuration.
164 If a vm has been partially created and there is an error it
165 is destroyed.
167 @param config configuration
168 @raise: VmError for invalid configuration
169 """
170 vm = cls._create()
171 vm.construct(config)
172 return vm
174 create = classmethod(create)
176 def recreate(cls, savedinfo, info, uuid=None):
177 """Create the VM object for an existing domain.
179 @param savedinfo: saved info from the domain DB
180 @param info: domain info from xc
181 @param uuid: uuid to use
182 @type info: xc domain dict
183 """
184 vm = cls._create(uuid=uuid)
186 log.debug('savedinfo=' + prettyprintstring(savedinfo))
187 log.debug('info=' + str(info))
189 vm.recreate = True
190 vm.savedinfo = savedinfo
191 vm.setdom(info['dom'])
192 vm.memory = info['mem_kb']/1024
194 start_time = sxp.child_value(savedinfo, 'start_time')
195 if start_time is not None:
196 vm.start_time = float(start_time)
197 vm.restart_state = sxp.child_value(savedinfo, 'restart_state')
198 vm.restart_count = int(sxp.child_value(savedinfo, 'restart_count', 0))
199 restart_time = sxp.child_value(savedinfo, 'restart_time')
200 if restart_time is not None:
201 vm.restart_time = float(restart_time)
202 config = sxp.child_value(savedinfo, 'config')
204 if config:
205 vm.construct(config)
206 else:
207 vm.setName(sxp.child_value(savedinfo, 'name',
208 "Domain-%d" % info['dom']))
209 vm.recreate = False
210 vm.savedinfo = None
212 return vm
214 recreate = classmethod(recreate)
216 def restore(cls, config, uuid=None):
217 """Create a domain and a VM object to do a restore.
219 @param config: domain configuration
220 @param uuid: uuid to use
221 """
222 vm = cls._create(uuid=uuid)
223 dom = xc.domain_create()
224 vm.setdom(dom)
225 vm.dom_construct(vm.id, config)
226 return vm
228 restore = classmethod(restore)
230 def __init__(self):
231 self.recreate = 0
232 self.restore = 0
234 self.config = None
235 self.uuid = None
236 self.id = None
237 self.cpu_weight = 1
238 self.start_time = None
239 self.name = None
240 self.memory = None
241 self.image = None
243 self.channel = None
244 self.store_channel = None
245 self.store_mfn = None
246 self.controllers = {}
248 self.info = None
249 self.blkif_backend = False
250 self.netif_backend = False
251 #todo: state: running, suspended
252 self.state = STATE_VM_OK
253 self.state_updated = threading.Condition()
254 self.shutdown_pending = None
256 #todo: set to migrate info if migrating
257 self.migrate = None
259 self.restart_mode = RESTART_ONREBOOT
260 self.restart_state = None
261 self.restart_time = None
262 self.restart_count = 0
264 self.console_port = None
265 self.savedinfo = None
266 self.vcpus = 1
267 self.bootloader = None
269 def setdom(self, dom):
270 """Set the domain id.
272 @param dom: domain id
273 """
274 self.id = int(dom)
276 def getDomain(self):
277 return self.id
279 def setName(self, name):
280 self.name = name
281 #self.db.name = self.name
283 def getName(self):
284 return self.name
286 def getChannel(self):
287 return self.channel
289 def getStoreChannel(self):
290 return self.store_channel
292 def update(self, info):
293 """Update with info from xc.domain_getinfo().
294 """
295 self.info = info
296 self.memory = self.info['mem_kb'] / 1024
298 def state_set(self, state):
299 self.state_updated.acquire()
300 if self.state != state:
301 self.state = state
302 self.state_updated.notifyAll()
303 self.state_updated.release()
305 def state_wait(self, state):
306 self.state_updated.acquire()
307 while self.state != state:
308 self.state_updated.wait()
309 self.state_updated.release()
311 def __str__(self):
312 s = "domain"
313 s += " id=" + str(self.id)
314 s += " name=" + self.name
315 s += " memory=" + str(self.memory)
316 console = self.getConsole()
317 if console:
318 s += " console=" + str(console.console_port)
319 s += ""
320 return s
322 __repr__ = __str__
324 def getDeviceTypes(self):
325 return self.controllers.keys()
327 def getDeviceControllers(self):
328 return self.controllers.values()
330 def getDeviceController(self, type, error=True):
331 ctrl = self.controllers.get(type)
332 if not ctrl and error:
333 raise XendError("invalid device type:" + type)
334 return ctrl
336 def findDeviceController(self, type):
337 return (self.getDeviceController(type, error=False)
338 or self.createDeviceController(type))
340 def createDeviceController(self, type):
341 ctrl = controller.createDevController(type, self, recreate=self.recreate)
342 self.controllers[type] = ctrl
343 return ctrl
345 def createDevice(self, type, devconfig, change=False):
346 ctrl = self.findDeviceController(type)
347 return ctrl.createDevice(devconfig, recreate=self.recreate,
348 change=change)
350 def configureDevice(self, type, id, devconfig):
351 ctrl = self.getDeviceController(type)
352 return ctrl.configureDevice(id, devconfig)
354 def destroyDevice(self, type, id, change=False, reboot=False):
355 ctrl = self.getDeviceController(type)
356 return ctrl.destroyDevice(id, change=change, reboot=reboot)
358 def deleteDevice(self, type, id):
359 ctrl = self.getDeviceController(type)
360 return ctrl.deleteDevice(id)
362 def getDevice(self, type, id, error=True):
363 ctrl = self.getDeviceController(type)
364 return ctrl.getDevice(id, error=error)
366 def getDeviceIds(self, type):
367 ctrl = self.getDeviceController(type)
368 return ctrl.getDeviceIds()
370 def getDeviceSxprs(self, type):
371 ctrl = self.getDeviceController(type)
372 return ctrl.getDeviceSxprs()
374 def sxpr(self):
375 sxpr = ['domain',
376 ['id', self.id],
377 ['name', self.name],
378 ['memory', self.memory] ]
379 if self.uuid:
380 sxpr.append(['uuid', self.uuid])
381 if self.info:
382 sxpr.append(['maxmem', self.info['maxmem_kb']/1024 ])
383 run = (self.info['running'] and 'r') or '-'
384 block = (self.info['blocked'] and 'b') or '-'
385 pause = (self.info['paused'] and 'p') or '-'
386 shut = (self.info['shutdown'] and 's') or '-'
387 crash = (self.info['crashed'] and 'c') or '-'
388 state = run + block + pause + shut + crash
389 sxpr.append(['state', state])
390 if self.info['shutdown']:
391 reason = shutdown_reason(self.info['shutdown_reason'])
392 sxpr.append(['shutdown_reason', reason])
393 sxpr.append(['cpu', self.info['vcpu_to_cpu'][0]])
394 sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
395 sxpr.append(['vcpus', self.info['vcpus']])
396 sxpr.append(['cpumap', self.info['cpumap']])
397 sxpr.append(['vcpu_to_cpu', ''.join(map(lambda x: str(x),
398 self.info['vcpu_to_cpu'][0:self.info['vcpus']]))])
400 if self.start_time:
401 up_time = time.time() - self.start_time
402 sxpr.append(['up_time', str(up_time) ])
403 sxpr.append(['start_time', str(self.start_time) ])
405 if self.channel:
406 sxpr.append(self.channel.sxpr())
407 if self.store_channel:
408 sxpr.append(self.store_channel.sxpr())
409 console = self.getConsole()
410 if console:
411 sxpr.append(console.sxpr())
412 if self.restart_count:
413 sxpr.append(['restart_count', self.restart_count])
414 if self.restart_state:
415 sxpr.append(['restart_state', self.restart_state])
416 if self.restart_time:
417 sxpr.append(['restart_time', str(self.restart_time)])
418 devs = self.sxpr_devices()
419 if devs:
420 sxpr.append(devs)
421 if self.config:
422 sxpr.append(['config', self.config])
423 return sxpr
425 def sxpr_devices(self):
426 sxpr = []
427 for ty in self.getDeviceTypes():
428 devs = self.getDeviceSxprs(ty)
429 sxpr += devs
430 if sxpr:
431 sxpr.insert(0, 'devices')
432 else:
433 sxpr = None
434 return sxpr
436 def check_name(self, name):
437 """Check if a vm name is valid. Valid names contain alphabetic characters,
438 digits, or characters in '_-.:/+'.
439 The same name cannot be used for more than one vm at the same time.
441 @param name: name
442 @raise: VMerror if invalid
443 """
444 if self.recreate: return
445 if name is None or name == '':
446 raise VmError('missing vm name')
447 for c in name:
448 if c in string.digits: continue
449 if c in '_-.:/+': continue
450 if c in string.ascii_letters: continue
451 raise VmError('invalid vm name')
452 dominfo = domain_exists(name)
453 # When creating or rebooting, a domain with my name should not exist.
454 # When restoring, a domain with my name will exist, but it should have
455 # my domain id.
456 if not dominfo:
457 return
458 if dominfo.is_terminated():
459 return
460 if not self.id or (dominfo.id != self.id):
461 raise VmError('vm name clash: ' + name)
463 def construct(self, config):
464 """Construct the vm instance from its configuration.
466 @param config: configuration
467 @raise: VmError on error
468 """
469 # todo - add support for scheduling params?
470 self.config = config
471 try:
472 # Initial domain create.
473 self.setName(sxp.child_value(config, 'name'))
474 self.check_name(self.name)
475 self.init_image()
476 self.configure_cpus(config)
477 self.init_domain()
478 self.register_domain()
479 self.configure_bootloader()
481 # Create domain devices.
482 self.configure_backends()
483 self.configure_console()
484 self.configure_restart()
485 self.construct_image()
486 self.configure()
487 except Exception, ex:
488 # Catch errors, cleanup and re-raise.
489 print 'Domain construction error:', ex
490 import traceback
491 traceback.print_exc()
492 self.destroy()
493 raise
495 def register_domain(self):
496 xd = get_component('xen.xend.XendDomain')
497 xd._add_domain(self)
499 def configure_cpus(self, config):
500 try:
501 self.cpu_weight = float(sxp.child_value(config, 'cpu_weight', '1'))
502 except:
503 raise VmError('invalid cpu weight')
504 self.memory = int(sxp.child_value(config, 'memory'))
505 if self.memory is None:
506 raise VmError('missing memory size')
507 cpu = sxp.child_value(config, 'cpu')
508 if self.recreate and self.id and cpu is not None and int(cpu) >= 0:
509 xc.domain_pincpu(self.id, 0, 1<<int(cpu))
510 try:
511 image = sxp.child_value(self.config, 'image')
512 vcpus = sxp.child_value(image, 'vcpus')
513 if vcpus:
514 self.vcpus = int(vcpus)
515 except:
516 raise VmError('invalid vcpus value')
518 def init_image(self):
519 """Create boot image handler for the domain.
520 """
521 image = sxp.child_value(self.config, 'image')
522 if image is None:
523 raise VmError('missing image')
524 self.image = ImageHandler.create(self, image)
526 def construct_image(self):
527 """Construct the boot image for the domain.
528 """
529 self.create_channel()
530 self.image.createImage()
531 #self.image.exportToDB()
532 #if self.store_channel:
533 # self.db.introduceDomain(self.id,
534 # self.store_mfn,
535 # self.store_channel)
537 def get_device_savedinfo(self, type, id):
538 val = None
539 if self.savedinfo is None:
540 return val
541 devices = sxp.child(self.savedinfo, 'devices')
542 if devices is None:
543 return val
544 for d in sxp.children(devices, type):
545 did = sxp.child_value(d, 'id')
546 if did is None: continue
547 if int(did) == id:
548 val = d
549 break
550 return val
552 def get_device_recreate(self, type, id):
553 return self.get_device_savedinfo(type, id) or self.recreate
555 def destroy(self):
556 """Completely destroy the vm.
557 """
558 try:
559 self.cleanup()
560 except Exception, ex:
561 log.warning("error in domain cleanup: %s", ex)
562 pass
563 try:
564 self.destroy_domain()
565 except Exception, ex:
566 log.warning("error in domain destroy: %s", ex)
567 pass
569 def destroy_domain(self):
570 """Destroy the vm's domain.
571 The domain will not finally go away unless all vm
572 devices have been released.
573 """
574 if self.channel:
575 try:
576 self.channel.close()
577 self.channel = None
578 except:
579 pass
580 if self.store_channel:
581 try:
582 self.store_channel.close()
583 self.store_channel = None
584 except:
585 pass
586 if self.image:
587 try:
588 self.image.destroy()
589 self.image = None
590 except:
591 pass
592 if self.id is None: return 0
593 try:
594 xc.domain_destroy(dom=self.id)
595 except Exception, err:
596 log.exception("Domain destroy failed: %s", self.name)
598 def cleanup(self):
599 """Cleanup vm resources: release devices.
600 """
601 self.state = STATE_VM_TERMINATED
602 self.release_devices()
604 def is_terminated(self):
605 """Check if a domain has been terminated.
606 """
607 return self.state == STATE_VM_TERMINATED
609 def release_devices(self):
610 """Release all vm devices.
611 """
612 reboot = self.restart_pending()
613 for ctrl in self.getDeviceControllers():
614 if ctrl.isDestroyed(): continue
615 ctrl.destroyController(reboot=reboot)
617 def show(self):
618 """Print virtual machine info.
619 """
620 print "[VM dom=%d name=%s memory=%d" % (self.id, self.name, self.memory)
621 print "image:"
622 sxp.show(self.image)
623 print "]"
625 def init_domain(self):
626 """Initialize the domain memory.
627 """
628 if self.recreate:
629 return
630 if self.start_time is None:
631 self.start_time = time.time()
632 try:
633 cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
634 except:
635 raise VmError('invalid cpu')
636 dom = self.image.initDomain(self.id, self.memory, cpu, self.cpu_weight)
637 log.debug('init_domain> Created domain=%d name=%s memory=%d',
638 dom, self.name, self.memory)
639 if not self.restore:
640 self.setdom(dom)
642 def openChannel(self, name, local, remote):
643 """Create a channel to the domain.
644 If saved info is available recreate the channel.
646 @param local default local port
647 @param remote default remote port
648 """
649 local = 0
650 remote = 1
651 if self.savedinfo:
652 info = sxp.child(self.savedinfo, name)
653 if info:
654 local = int(sxp.child_value(info, "local_port", 0))
655 remote = int(sxp.child_value(info, "remote_port", 1))
656 chan = channelFactory().openChannel(self.id, local_port=local,
657 remote_port=remote)
658 return chan
660 def eventChannel(self, name):
661 return EventChannel.interdomain(0, self.id)
663 def create_channel(self):
664 """Create the channels to the domain.
665 """
666 self.channel = self.openChannel("channel", 0, 1)
667 self.store_channel = self.eventChannel("store_channel")
669 def create_configured_devices(self):
670 devices = sxp.children(self.config, 'device')
671 for d in devices:
672 dev_config = sxp.child0(d)
673 if dev_config is None:
674 raise VmError('invalid device')
675 dev_type = sxp.name(dev_config)
676 ctrl_type = get_device_handler(dev_type)
677 if ctrl_type is None:
678 raise VmError('unknown device type: ' + dev_type)
679 self.createDevice(ctrl_type, dev_config)
681 def create_devices(self):
682 """Create the devices for a vm.
684 @raise: VmError for invalid devices
685 """
686 if self.rebooting():
687 for ctrl in self.getDeviceControllers():
688 ctrl.initController(reboot=True)
689 else:
690 self.create_configured_devices()
692 def device_create(self, dev_config):
693 """Create a new device.
695 @param dev_config: device configuration
696 """
697 dev_type = sxp.name(dev_config)
698 dev = self.createDevice(self, dev_config, change=True)
699 self.config.append(['device', dev.getConfig()])
700 return dev.sxpr()
702 def device_configure(self, dev_config, id):
703 """Configure an existing device.
705 @param dev_config: device configuration
706 @param id: device id
707 """
708 type = sxp.name(dev_config)
709 dev = self.getDevice(type, id)
710 old_config = dev.getConfig()
711 new_config = dev.configure(dev_config, change=True)
712 # Patch new config into vm config.
713 new_full_config = ['device', new_config]
714 old_full_config = ['device', old_config]
715 old_index = self.config.index(old_full_config)
716 self.config[old_index] = new_full_config
717 return new_config
719 def device_refresh(self, type, id):
720 """Refresh a device.
722 @param type: device type
723 @param id: device id
724 """
725 dev = self.getDevice(type, id)
726 dev.refresh()
728 def device_delete(self, type, id):
729 """Destroy and remove a device.
731 @param type: device type
732 @param id: device id
733 """
734 dev = self.getDevice(type, id)
735 dev_config = dev.getConfig()
736 if dev_config:
737 self.config.remove(['device', dev_config])
738 self.deleteDevice(type, dev.getId())
740 def configure_bootloader(self):
741 """Configure boot loader.
742 """
743 self.bootloader = sxp.child_value(self.config, "bootloader")
745 def configure_console(self):
746 """Configure the vm console port.
747 """
748 x = sxp.child_value(self.config, 'console')
749 if x:
750 try:
751 port = int(x)
752 except:
753 raise VmError('invalid console:' + str(x))
754 self.console_port = port
756 def configure_restart(self):
757 """Configure the vm restart mode.
758 """
759 r = sxp.child_value(self.config, 'restart', RESTART_ONREBOOT)
760 if r not in restart_modes:
761 raise VmError('invalid restart mode: ' + str(r))
762 self.restart_mode = r;
764 def restart_needed(self, reason):
765 """Determine if the vm needs to be restarted when shutdown
766 for the given reason.
768 @param reason: shutdown reason
769 @return True if needs restart, False otherwise
770 """
771 if self.restart_mode == RESTART_NEVER:
772 return False
773 if self.restart_mode == RESTART_ALWAYS:
774 return True
775 if self.restart_mode == RESTART_ONREBOOT:
776 return reason == 'reboot'
777 return False
779 def restart_cancel(self):
780 """Cancel a vm restart.
781 """
782 self.restart_state = None
784 def restarting(self):
785 """Put the vm into restart mode.
786 """
787 self.restart_state = STATE_RESTART_PENDING
789 def restart_pending(self):
790 """Test if the vm has a pending restart.
791 """
792 return self.restart_state == STATE_RESTART_PENDING
794 def rebooting(self):
795 return self.restart_state == STATE_RESTART_BOOTING
797 def restart_check(self):
798 """Check if domain restart is OK.
799 To prevent restart loops, raise an error if it is
800 less than MINIMUM_RESTART_TIME seconds since the last restart.
801 """
802 tnow = time.time()
803 if self.restart_time is not None:
804 tdelta = tnow - self.restart_time
805 if tdelta < self.MINIMUM_RESTART_TIME:
806 self.restart_cancel()
807 msg = 'VM %s restarting too fast' % self.name
808 log.error(msg)
809 raise VmError(msg)
810 self.restart_time = tnow
811 self.restart_count += 1
813 def restart(self):
814 """Restart the domain after it has exited.
815 Reuses the domain id and console port.
817 """
818 try:
819 self.state = STATE_VM_OK
820 self.shutdown_pending = None
821 self.restart_check()
822 self.restart_state = STATE_RESTART_BOOTING
823 if self.bootloader:
824 self.config = self.bootloader_config()
825 self.construct(self.config)
826 finally:
827 self.restart_state = None
829 def bootloader_config(self):
830 # if we're restarting with a bootloader, we need to run it
831 # FIXME: this assumes the disk is the first device and
832 # that we're booting from the first disk
833 blcfg = None
834 # FIXME: this assumes that we want to use the first disk
835 dev = sxp.child_value(self.config, "device")
836 if dev:
837 disk = sxp.child_value(dev, "uname")
838 fn = blkdev_uname_to_file(disk)
839 blcfg = bootloader(self.bootloader, fn, 1, self.vcpus)
840 if blcfg is None:
841 msg = "Had a bootloader specified, but can't find disk"
842 log.error(msg)
843 raise VmError(msg)
844 config = sxp.merge(['vm', blconfig ], self.config)
845 return config
847 def configure_backends(self):
848 """Set configuration flags if the vm is a backend for netif or blkif.
849 Configure the backends to use for vbd and vif if specified.
850 """
851 for c in sxp.children(self.config, 'backend'):
852 v = sxp.child0(c)
853 name = sxp.name(v)
854 if name == 'blkif':
855 self.blkif_backend = True
856 elif name == 'netif':
857 self.netif_backend = True
858 elif name == 'usbif':
859 self.usbif_backend = True
860 else:
861 raise VmError('invalid backend type:' + str(name))
863 def configure(self):
864 """Configure a vm.
866 """
867 self.configure_fields()
868 self.create_console()
869 self.create_devices()
870 self.create_blkif()
872 def create_console(self):
873 console = self.getConsole()
874 if not console:
875 config = ['console']
876 if self.console_port:
877 config.append(['console_port', self.console_port])
878 console = self.createDevice('console', config)
879 return console
881 def getConsole(self):
882 console_ctrl = self.getDeviceController("console", error=False)
883 if console_ctrl:
884 return console_ctrl.getDevice(0)
885 return None
887 def create_blkif(self):
888 """Create the block device interface (blkif) for the vm.
889 The vm needs a blkif even if it doesn't have any disks
890 at creation time, for example when it uses NFS root.
892 """
893 blkif = self.getDeviceController("vbd", error=False)
894 if not blkif:
895 blkif = self.createDeviceController("vbd")
896 backend = blkif.getBackend(0)
897 backend.connect(recreate=self.recreate)
899 def dom_construct(self, dom, config):
900 """Construct a vm for an existing domain.
902 @param dom: domain id
903 @param config: domain configuration
904 """
905 d = dom_get(dom)
906 if not d:
907 raise VmError("Domain not found: %d" % dom)
908 try:
909 self.restore = True
910 self.setdom(dom)
911 self.memory = d['mem_kb']/1024
912 self.construct(config)
913 finally:
914 self.restore = False
916 def configure_fields(self):
917 """Process the vm configuration fields using the registered handlers.
918 """
919 index = {}
920 for field in sxp.children(self.config):
921 field_name = sxp.name(field)
922 field_index = index.get(field_name, 0)
923 field_handler = get_config_handler(field_name)
924 # Ignore unknown fields. Warn?
925 if field_handler:
926 v = field_handler(self, self.config, field, field_index)
927 else:
928 log.warning("Unknown config field %s", field_name)
929 index[field_name] = field_index + 1
931 def mem_target_set(self, target):
932 """Set domain memory target in pages.
933 """
934 if self.channel:
935 msg = messages.packMsg('mem_request_t', { 'target' : target * (1 << 8)} )
936 self.channel.writeRequest(msg)
938 def shutdown(self, reason, key=0):
939 msgtype = shutdown_messages.get(reason)
940 if not msgtype:
941 raise XendError('invalid reason:' + reason)
942 extra = {}
943 if reason == 'sysrq':
944 extra['key'] = key
945 if self.channel:
946 msg = messages.packMsg(msgtype, extra)
947 self.channel.writeRequest(msg)
948 if not reason in ['suspend', 'sysrq']:
949 self.shutdown_pending = {'start':time.time(), 'reason':reason,
950 'key':key}
952 def shutdown_time_left(self, timeout):
953 if not self.shutdown_pending:
954 return 0
955 return timeout - (time.time() - self.shutdown_pending['start'])
957 def vm_field_ignore(vm, config, val, index):
958 """Dummy config field handler used for fields with built-in handling.
960 @param vm: virtual machine
961 @param config: vm config
962 @param val: config field
963 @param index: field index
964 """
965 pass
967 def vm_field_maxmem(vm, config, val, index):
968 """Configure vm memory limit.
970 @param vm: virtual machine
971 @param config: vm config
972 @param val: config field
973 @param index: field index
974 """
975 maxmem = sxp.child0(val)
976 if maxmem is None:
977 maxmem = vm.memory
978 try:
979 maxmem = int(maxmem)
980 except:
981 raise VmError("invalid maxmem: " + str(maxmem))
982 xc.domain_setmaxmem(vm.id, maxmem_kb = maxmem * 1024)
984 #============================================================================
985 # Register image handlers.
986 from image import \
987 addImageHandlerClass, \
988 ImageHandler, \
989 LinuxImageHandler, \
990 Plan9ImageHandler, \
991 VmxImageHandler
993 addImageHandlerClass(LinuxImageHandler)
994 addImageHandlerClass(Plan9ImageHandler)
995 addImageHandlerClass(VmxImageHandler)
997 # Ignore the fields we already handle.
998 add_config_handler('name', vm_field_ignore)
999 add_config_handler('memory', vm_field_ignore)
1000 add_config_handler('cpu', vm_field_ignore)
1001 add_config_handler('cpu_weight', vm_field_ignore)
1002 add_config_handler('console', vm_field_ignore)
1003 add_config_handler('restart', vm_field_ignore)
1004 add_config_handler('image', vm_field_ignore)
1005 add_config_handler('device', vm_field_ignore)
1006 add_config_handler('backend', vm_field_ignore)
1007 add_config_handler('vcpus', vm_field_ignore)
1008 add_config_handler('bootloader', vm_field_ignore)
1010 # Register other config handlers.
1011 add_config_handler('maxmem', vm_field_maxmem)
1013 #============================================================================
1014 # Register device controllers and their device config types.
1016 from server import console
1017 controller.addDevControllerClass("console", console.ConsoleController)
1019 from server import blkif
1020 controller.addDevControllerClass("vbd", blkif.BlkifController)
1021 add_device_handler("vbd", "vbd")
1023 from server import netif
1024 controller.addDevControllerClass("vif", netif.NetifController)
1025 add_device_handler("vif", "vif")
1027 from server import pciif
1028 controller.addDevControllerClass("pci", pciif.PciController)
1029 add_device_handler("pci", "pci")
1031 from xen.xend.server import usbif
1032 controller.addDevControllerClass("usb", usbif.UsbifController)
1033 add_device_handler("usb", "usb")
1035 #============================================================================