debuggers.hg

view tools/python/xen/xend/XendDomain.py @ 2628:98bdf2c88015

bitkeeper revision 1.1159.1.201 (41600e1fkVMoQU0dVgk1h6vT502hEg)

Merge
author iap10@labyrinth.cl.cam.ac.uk
date Sun Oct 03 14:35:11 2004 +0000 (2004-10-03)
parents 0bd31a3188c2 a15ab016f0c6
children 081dd58e4d58 cc42f35f9597
line source
1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
3 """Handler for domain operations.
4 Nothing here is persistent (across reboots).
5 Needs to be persistent for one uptime.
6 """
7 import sys
8 import traceback
10 from twisted.internet import defer
11 #defer.Deferred.debug = 1
12 from twisted.internet import reactor
14 import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
16 import sxp
17 import XendRoot
18 xroot = XendRoot.instance()
19 import XendDB
20 import XendDomainInfo
21 import XendMigrate
22 import EventServer
23 from XendError import XendError
24 from XendLogging import log
27 from xen.xend.server import SrvDaemon
28 xend = SrvDaemon.instance()
30 eserver = EventServer.instance()
32 __all__ = [ "XendDomain" ]
34 class XendDomain:
35 """Index of all domains. Singleton.
36 """
38 """Path to domain database."""
39 dbpath = "domain"
41 """Table of domain info indexed by domain id."""
42 domain_by_id = {}
43 domain_by_name = {}
45 """Table of domains to restart, indexed by domain id."""
46 restarts_by_id = {}
47 restarts_by_name = {}
49 """Table of delayed calls."""
50 schedule = {}
52 def __init__(self):
53 # Hack alert. Python does not support mutual imports, but XendDomainInfo
54 # needs access to the XendDomain instance to look up domains. Attempting
55 # to import XendDomain from XendDomainInfo causes unbounded recursion.
56 # So we stuff the XendDomain instance (self) into xroot's components.
57 xroot.add_component("xen.xend.XendDomain", self)
58 # Table of domain info indexed by domain id.
59 self.db = XendDB.XendDB(self.dbpath)
60 self.domain_db = self.db.fetchall("")
61 if xroot.get_rebooted():
62 log.info('XendDomain> rebooted: removing all domain info')
63 self.rm_all()
64 eserver.subscribe('xend.virq', self.onVirq)
65 self.initial_refresh()
67 def onVirq(self, event, val):
68 """Event handler for virq.
69 """
70 self.reap()
72 def schedule_later(self, _delay, _name, _fn, *args):
73 """Schedule a function to be called later (if not already scheduled).
75 @param _delay: delay in seconds
76 @param _name: schedule name
77 @param _fn: function
78 @param args: arguments
79 """
80 if self.schedule.get(_name): return
81 self.schedule[_name] = reactor.callLater(_delay, _fn, *args)
83 def schedule_cancel(self, name):
84 """Cancel a scheduled function call.
86 @param name: schedule name to cancel
87 """
88 callid = self.schedule.get(name)
89 if not callid:
90 return
91 if callid.active():
92 callid.cancel()
93 del self.schedule[name]
95 def reap_schedule(self, delay=0):
96 """Schedule reap to be called later.
98 @param delay: delay in seconds
99 """
100 self.schedule_later(delay, 'reap', self.reap)
102 def reap_cancel(self):
103 """Cancel any scheduled reap.
104 """
105 self.schedule_cancel('reap')
107 def refresh_schedule(self, delay=0):
108 """Schedule refresh to be called later.
110 @param delay: delay in seconds
111 """
112 self.schedule_later(delay, 'refresh', self.refresh)
114 def refresh_cancel(self):
115 """Cancel any scheduled refresh.
116 """
117 self.schedule_cancel('refresh')
119 def domain_restarts_schedule(self, delay=0):
120 """Schedule domain_restarts to be called later.
122 @param delay: delay in seconds
123 """
124 self.schedule_later(delay, 'domain_restarts', self.domain_restarts)
126 def domain_restarts_cancel(self):
127 """Cancel any scheduled call of domain_restarts.
128 """
129 self.schedule_cancel('domain_restarts')
131 def rm_all(self):
132 """Remove all domain info. Used after reboot.
133 """
134 for (k, v) in self.domain_db.items():
135 self._delete_domain(k, notify=0)
137 def initial_refresh(self):
138 """Refresh initial domain info from domain_db.
139 """
141 def cb_all_ok(val):
142 self.refresh()
144 domlist = xc.domain_getinfo()
145 doms = {}
146 for d in domlist:
147 domid = str(d['dom'])
148 doms[domid] = d
149 dlist = []
150 for config in self.domain_db.values():
151 domid = str(sxp.child_value(config, 'id'))
152 if domid in doms:
153 d_dom = self._new_domain(config, doms[domid])
154 dlist.append(d_dom)
155 else:
156 self._delete_domain(domid)
157 d_all = defer.DeferredList(dlist, fireOnOneErrback=1)
158 d_all.addCallback(cb_all_ok)
160 def sync(self):
161 """Sync domain db to disk.
162 """
163 self.db.saveall("", self.domain_db)
165 def sync_domain(self, dom):
166 """Sync info for a domain to disk.
168 dom domain id (string)
169 """
170 self.db.save(dom, self.domain_db[dom])
172 def close(self):
173 pass
175 def _new_domain(self, savedinfo, info):
176 """Create a domain entry from saved info.
178 @param savedinfo: saved info from the db
179 @param info: domain info from xen
180 @return: deferred
181 """
182 def cbok(dominfo):
183 self.domain_by_id[dominfo.id] = dominfo
184 self.domain_by_name[dominfo.name] = dominfo
185 if dominfo.restart_pending():
186 self.domain_restart_add(dominfo)
188 deferred = XendDomainInfo.vm_recreate(savedinfo, info)
189 deferred.addCallback(cbok)
190 return deferred
192 def _add_domain(self, info, notify=1):
193 """Add a domain entry to the tables.
195 @param info: domain info object
196 @param notify: send a domain created event if true
197 """
198 self.domain_by_id[info.id] = info
199 self.domain_db[info.id] = info.sxpr()
200 for k, d in self.domain_by_name.items():
201 if k != d.name:
202 del self.domain_by_name[k]
203 if info.name:
204 self.domain_by_name[info.name] = info
205 self.sync_domain(info.id)
206 if notify: eserver.inject('xend.domain.create', [info.name, info.id])
208 def _delete_domain(self, id, notify=1):
209 """Remove a domain from the tables.
211 @param id: domain id
212 @param notify: send a domain died event if true
213 """
214 for (k, info) in self.domain_by_name.items():
215 if info.id == id:
216 del self.domain_by_name[k]
217 if id in self.domain_by_id:
218 info = self.domain_by_id[id]
219 del self.domain_by_id[id]
220 if notify: eserver.inject('xend.domain.died', [info.name, info.id])
221 if id in self.domain_db:
222 del self.domain_db[id]
223 self.db.delete(id)
225 def reap(self):
226 """Look for domains that have crashed or stopped.
227 Tidy them up.
228 """
229 self.reap_cancel()
230 domlist = xc.domain_getinfo()
231 casualties = []
232 for d in domlist:
233 dead = 0
234 dead = dead or (d['crashed'] or d['shutdown'])
235 dead = dead or (d['dying'] and
236 not(d['running'] or d['paused'] or d['blocked']))
237 if dead:
238 casualties.append(d)
239 destroyed = 0
240 for d in casualties:
241 id = str(d['dom'])
242 dominfo = self.domain_by_id.get(id)
243 name = (dominfo and dominfo.name) or '??'
244 log.debug('XendDomain>reap> domain died name=%s id=%s', name, id)
245 if d['shutdown']:
246 reason = XendDomainInfo.shutdown_reason(d['shutdown_reason'])
247 log.debug('XendDomain>reap> shutdown id=%s reason=%s', id, reason)
248 if reason in ['suspend']:
249 if dominfo and dominfo.is_terminated():
250 log.debug('XendDomain>reap> Suspended domain died id=%s', id)
251 else:
252 eserver.inject('xend.domain.suspended', [name, id])
253 continue
254 if reason in ['poweroff', 'reboot']:
255 eserver.inject('xend.domain.exit', [name, id, reason])
256 self.domain_restart_schedule(id, reason)
257 else:
258 eserver.inject('xend.domain.exit', [name, id, 'crash'])
259 destroyed += 1
260 self.final_domain_destroy(id)
261 if self.domain_restarts_exist():
262 self.domain_restarts_schedule()
263 if destroyed:
264 self.refresh_schedule(delay=1)
266 def refresh(self):
267 """Refresh domain list from Xen.
268 """
269 self.refresh_cancel()
270 domlist = xc.domain_getinfo()
271 # Index the domlist by id.
272 # Add entries for any domains we don't know about.
273 doms = {}
274 for d in domlist:
275 id = str(d['dom'])
276 doms[id] = d
277 if id not in self.domain_by_id:
278 savedinfo = None
279 deferred = XendDomainInfo.vm_recreate(savedinfo, d)
280 def cbok(dominfo):
281 self._add_domain(dominfo)
282 deferred.addCallback(cbok)
283 # Remove entries for domains that no longer exist.
284 for d in self.domain_by_id.values():
285 info = doms.get(d.id)
286 if info:
287 d.update(info)
288 else:
289 self._delete_domain(d.id)
290 self.reap_schedule(delay=1)
292 def update_domain(self, id):
293 """Update the saved info for a domain.
295 @param id: domain id
296 """
297 dominfo = self.domain_by_id.get(id)
298 if dominfo:
299 self.domain_db[id] = dominfo.sxpr()
300 self.sync_domain(id)
302 def refresh_domain(self, id):
303 """Refresh information for a single domain.
305 @param id: domain id
306 """
307 dom = int(id)
308 dominfo = xc.domain_getinfo(dom, 1)
309 if dominfo == [] or dominfo[0]['dom'] != dom:
310 try:
311 self._delete_domain(id)
312 except:
313 log.exception('refresh_domain> error')
314 raise
315 pass
316 else:
317 d = self.domain_by_id.get(id)
318 if d:
319 d.update(dominfo[0])
321 def domain_ls(self):
322 """Get list of domain names.
324 @return: domain names
325 """
326 self.refresh()
327 return self.domain_by_name.keys()
329 def domain_ls_ids(self):
330 """Get list of domain ids.
332 @return: domain names
333 """
334 self.refresh()
335 return self.domain_by_id.keys()
337 def domains(self):
338 """Get list of domain objects.
340 @return: domain objects
341 """
342 self.refresh()
343 return self.domain_by_id.values()
345 def domain_create(self, config):
346 """Create a domain from a configuration.
348 @param config: configuration
349 @return: deferred
350 """
351 def cbok(dominfo):
352 self._add_domain(dominfo)
353 return dominfo
354 deferred = XendDomainInfo.vm_create(config)
355 deferred.addCallback(cbok)
356 return deferred
358 def domain_setname(self, dom, name):
359 """Set the name of a domain.
360 For internal use only.
362 @param dom: domain id
363 @param name: domain name
364 """
365 return xc.domain_setname(dom=dom, name=name)
367 def domain_restart(self, dominfo):
368 """Restart a domain.
370 @param dominfo: domain object
371 @return: deferred
372 """
373 def cbok(dominfo):
374 self._add_domain(dominfo)
375 return dominfo
376 log.info("Restarting domain: id=%s name=%s", dominfo.id, dominfo.name)
377 eserver.inject("xend.domain.restart",
378 [dominfo.name, dominfo.id, "begin"])
379 deferred = dominfo.restart()
380 deferred.addCallback(cbok)
381 return deferred
383 def domain_configure(self, id, vmconfig):
384 """Configure an existing domain. This is intended for internal
385 use by domain restore and migrate.
387 @param id: domain id
388 @param vmconfig: vm configuration
389 @return: deferred
390 """
391 config = sxp.child_value(vmconfig, 'config')
392 dominfo = self.domain_lookup(id)
393 log.debug('domain_configure> id=%s config=%s', str(id), str(config))
394 if dominfo.config:
395 raise XendError("Domain already configured: " + dominfo.id)
396 def cbok(dominfo):
397 self._add_domain(dominfo)
398 return dominfo
399 deferred = dominfo.dom_construct(dominfo.dom, config)
400 deferred.addCallback(cbok)
401 return deferred
403 def domain_restore(self, src, progress=0):
404 """Restore a domain from file.
406 @param src: source file
407 @param progress: output progress if true
408 @return: deferred
409 """
411 if 0:
412 def cbok(dominfo):
413 self._add_domain(dominfo)
414 return dominfo
415 deferred = XendDomainInfo.vm_restore(src, progress=progress)
416 deferred.addCallback(cbok)
417 else:
418 xmigrate = XendMigrate.instance()
419 deferred = xmigrate.restore_begin(src)
420 return deferred
422 def domain_get(self, id):
423 """Get up-to-date info about a domain.
425 @param id: domain id
426 @return: domain object (or None)
427 """
428 id = str(id)
429 self.refresh_domain(id)
430 return self.domain_by_id.get(id)
432 def domain_lookup(self, name):
433 name = str(name)
434 dominfo = self.domain_by_name.get(name) or self.domain_by_id.get(name)
435 if dominfo:
436 return dominfo
437 raise XendError('invalid domain:' + name)
439 def domain_exists(self, name):
440 name = str(name)
441 return self.domain_by_name.get(name) or self.domain_by_id.get(name)
443 def domain_unpause(self, id):
444 """Unpause domain execution.
446 @param id: domain id
447 """
448 dominfo = self.domain_lookup(id)
449 eserver.inject('xend.domain.unpause', [dominfo.name, dominfo.id])
450 try:
451 return xc.domain_unpause(dom=dominfo.dom)
452 except Exception, ex:
453 raise XendError(str(ex))
455 def domain_pause(self, id):
456 """Pause domain execution.
458 @param id: domain id
459 """
460 dominfo = self.domain_lookup(id)
461 eserver.inject('xend.domain.pause', [dominfo.name, dominfo.id])
462 try:
463 return xc.domain_pause(dom=dominfo.dom)
464 except Exception, ex:
465 raise XendError(str(ex))
467 def domain_shutdown(self, id, reason='poweroff'):
468 """Shutdown domain (nicely).
469 - poweroff: restart according to exit code and restart mode
470 - reboot: restart on exit
471 - halt: do not restart
473 Returns immediately.
475 @param id: domain id
476 @param reason: shutdown type: poweroff, reboot, suspend, halt
477 """
478 dominfo = self.domain_lookup(id)
479 if reason == 'halt':
480 self.domain_restart_cancel(dominfo.id)
481 else:
482 self.domain_restart_schedule(dominfo.id, reason, force=1)
483 eserver.inject('xend.domain.shutdown', [dominfo.name, dominfo.id, reason])
484 if reason == 'halt':
485 reason = 'poweroff'
486 val = xend.domain_shutdown(dominfo.id, reason)
487 self.refresh_schedule()
488 return val
490 def domain_restart_schedule(self, id, reason, force=0):
491 """Schedule a restart for a domain if it needs one.
493 @param id: domain id
494 @param reason: shutdown reason
495 """
496 log.debug('domain_restart_schedule> %s %s %d', id, reason, force)
497 dominfo = self.domain_lookup(id)
498 if not dominfo:
499 return
500 if dominfo.id in self.restarts_by_id:
501 return
502 restart = (force and reason == 'reboot') or dominfo.restart_needed(reason)
503 if restart:
504 dominfo.restarting()
505 self.domain_restart_add(dominfo)
507 def domain_restart_add(self, dominfo):
508 self.restarts_by_name[dominfo.name] = dominfo
509 self.restarts_by_id[dominfo.id] = dominfo
510 log.info('Scheduling restart for domain: name=%s id=%s', dominfo.name, dominfo.id)
511 eserver.inject("xend.domain.restart",
512 [dominfo.name, dominfo.id, "schedule"])
513 self.domain_restarts_schedule()
515 def domain_restart_cancel(self, id):
516 """Cancel any restart scheduled for a domain.
518 @param id: domain id
519 """
520 dominfo = self.restarts_by_id.get(id) or self.restarts_by_name.get(id)
521 if dominfo:
522 log.info('Cancelling restart for domain: name=%s id=%s', dominfo.name, dominfo.id)
523 eserver.inject("xend.domain.restart",
524 [dominfo.name, dominfo.id, "cancel"])
525 dominfo.restart_cancel()
526 del self.restarts_by_id[dominfo.id]
527 del self.restarts_by_name[dominfo.name]
529 def domain_restarts(self):
530 """Execute any scheduled domain restarts for domains that have gone.
531 """
532 self.domain_restarts_cancel()
533 for dominfo in self.restarts_by_id.values():
534 if dominfo.id in self.domain_by_id:
535 # Don't execute restart for domains still running.
536 continue
537 # Remove it from the restarts.
538 del self.restarts_by_id[dominfo.id]
539 del self.restarts_by_name[dominfo.name]
540 try:
541 def cbok(dominfo):
542 log.info('Restarted domain name=%s id=%s', dominfo.name, dominfo.id)
543 eserver.inject("xend.domain.restart",
544 [dominfo.name, dominfo.id, "success"])
545 self.domain_unpause(dominfo.id)
546 def cberr(err):
547 log.exception("Delayed exception restarting domain: name=%s id=%s",
548 dominfo.name, dominfo.id)
549 eserver.inject("xend.domain.restart",
550 [dominfo.name, dominfo.id, "fail"])
552 deferred = self.domain_restart(dominfo)
553 deferred.addCallback(cbok)
554 deferred.addErrback(cberr)
555 except:
556 log.exception("Exception restarting domain: name=%s id=%s",
557 dominfo.name, dominfo.id)
558 eserver.inject("xend.domain.restart",
559 [dominfo.name, dominfo.id, "fail"])
560 if self.domain_restarts_exist():
561 # Run again later if any restarts remain.
562 self.refresh_schedule(delay=5)
564 def domain_restarts_exist(self):
565 return len(self.restarts_by_id)
567 def final_domain_destroy(self, id):
568 """Final destruction of a domain..
570 @param id: domain id
571 """
572 dominfo = self.domain_lookup(id)
573 log.info('Destroying domain: name=%s', dominfo.name)
574 eserver.inject('xend.domain.destroy', [dominfo.name, dominfo.id])
575 if dominfo:
576 val = dominfo.destroy()
577 else:
578 #todo
579 val = xc.domain_destroy(dom=dominfo.dom)
580 return val
582 def domain_destroy(self, id, reason='halt'):
583 """Terminate domain immediately.
584 - halt: cancel any restart for the domain
585 - reboot schedule a restart for the domain
587 @param id: domain id
588 """
589 if reason == 'halt':
590 self.domain_restart_cancel(id)
591 elif reason == 'reboot':
592 self.domain_restart_schedule(id, reason, force=1)
593 val = self.final_domain_destroy(id)
594 self.refresh_schedule()
595 return val
597 def domain_migrate(self, id, dst, live):
598 """Start domain migration.
600 @param id: domain id
601 @return: deferred
602 """
603 # Need a cancel too?
604 # Don't forget to cancel restart for it.
605 dominfo = self.domain_lookup(id)
606 xmigrate = XendMigrate.instance()
607 val = xmigrate.migrate_begin(dominfo, dst, live=live)
608 return val
610 def domain_save(self, id, dst, progress=0):
611 """Start saving a domain to file.
613 @param id: domain id
614 @param dst: destination file
615 @param progress: output progress if true
616 @return: deferred
617 """
618 dominfo = self.domain_lookup(id)
619 xmigrate = XendMigrate.instance()
620 return xmigrate.save_begin(dominfo, dst)
622 def domain_pincpu(self, id, cpu):
623 """Pin a domain to a cpu.
625 @param id: domain
626 @param cpu: cpu number
627 """
628 dominfo = self.domain_lookup(id)
629 try:
630 return xc.domain_pincpu(int(dominfo.id), cpu)
631 except Exception, ex:
632 raise XendError(str(ex))
634 def domain_cpu_bvt_set(self, id, mcuadv, warpback, warpvalue, warpl, warpu):
635 """Set BVT (Borrowed Virtual Time) scheduler parameters for a domain.
636 """
637 dominfo = self.domain_lookup(id)
638 try:
639 return xc.bvtsched_domain_set(dom=dominfo.dom, mcuadv=mcuadv,
640 warpback=warpback, warpvalue=warpvalue,
641 warpl=warpl, warpu=warpu)
642 except Exception, ex:
643 raise XendError(str(ex))
645 def domain_cpu_bvt_get(self, id):
646 """Get BVT (Borrowed Virtual Time) scheduler parameters for a domain.
647 """
648 dominfo = self.domain_lookup(id)
649 try:
650 return xc.bvtsched_domain_get(dominfo.dom)
651 except Exception, ex:
652 raise XendError(str(ex))
654 def domain_cpu_fbvt_set(self, id, mcuadv, warp, warpl, warpu):
655 """Set FBVT (Fair Borrowed Virtual Time) scheduler parameters for a domain.
656 """
657 dominfo = self.domain_lookup(id)
658 try:
659 return xc.fbvtsched_domain_set(dom=dominfo.dom, mcuadv=mcuadv,
660 warp=warp, warpl=warpl, warpu=warpu)
661 except Exception, ex:
662 raise XendError(str(ex))
664 def domain_cpu_fbvt_get(self, id):
665 """Get FBVT (Fair Borrowed Virtual Time) scheduler parameters for a domain.
666 """
667 dominfo = self.domain_lookup(id)
668 try:
669 return xc.fbvtsched_domain_get(dominfo.dom)
670 except Exception, ex:
671 raise XendError(str(ex))
673 def domain_cpu_atropos_set(self, id, period, slice, latency, xtratime):
674 """Set Atropos scheduler parameters for a domain.
675 """
676 dominfo = self.domain_lookup(id)
677 try:
678 return xc.atropos_domain_set(dominfo.dom, period, slice, latency, xtratime)
679 except Exception, ex:
680 raise XendError(str(ex))
682 def domain_cpu_atropos_get(self, id):
683 """Get Atropos scheduler parameters for a domain.
684 """
685 dominfo = self.domain_lookup(id)
686 try:
687 return xc.atropos_domain_get(dominfo.dom)
688 except Exception, ex:
689 raise XendError(str(ex))
691 def domain_device_create(self, id, devconfig):
692 """Create a new device for a domain.
694 @param id: domain id
695 @param devconfig: device configuration
696 @return: deferred
697 """
698 dominfo = self.domain_lookup(id)
699 self.refresh_schedule()
700 val = dominfo.device_create(devconfig)
701 self.update_domain(dominfo.id)
702 return val
704 def domain_device_configure(self, id, devconfig, idx):
705 """Configure an existing device for a domain.
707 @param id: domain id
708 @param devconfig: device configuration
709 @param idx: device index
710 @return: updated device configuration
711 """
712 dominfo = self.domain_lookup(id)
713 self.refresh_schedule()
714 val = dominfo.device_configure(devconfig, idx)
715 self.update_domain(dominfo.id)
716 return val
719 def domain_device_destroy(self, id, type, idx):
720 """Destroy a device.
722 @param id: domain id
723 @param idx: device index
724 @param type: device type
725 """
726 dominfo = self.domain_lookup(id)
727 self.refresh_schedule()
728 val = dominfo.device_destroy(type, idx)
729 self.update_domain(dominfo.id)
730 return val
732 def domain_devtype_ls(self, id, type):
733 """Get list of device indexes for a domain.
735 @param id: domain
736 @param type: device type
737 @return: device indexes
738 """
739 dominfo = self.domain_lookup(id)
740 devs = dominfo.get_devices(type)
741 return devs
743 def domain_devtype_get(self, id, type, idx):
744 """Get a device from a domain.
746 @param id: domain
747 @param type: device type
748 @param idx: device index
749 @return: device object (or None)
750 """
751 dominfo = self.domain_lookup(id)
752 return dominfo.get_device_by_index(type, idx)
754 def domain_vif_ls(self, id):
755 """Get list of virtual network interface (vif) indexes for a domain.
757 @param id: domain
758 @return: vif indexes
759 """
760 return self.domain_devtype_ls(id, 'vif')
762 def domain_vif_get(self, id, vif):
763 """Get a virtual network interface (vif) from a domain.
765 @param id: domain
766 @param vif: vif index
767 @return: vif device object (or None)
768 """
769 return self.domain_devtype_get(id, 'vif', vif)
771 def domain_vbd_ls(self, id):
772 """Get list of virtual block device (vbd) indexes for a domain.
774 @param id: domain
775 @return: vbd indexes
776 """
777 return self.domain_devtype_ls(id, 'vbd')
779 def domain_vbd_get(self, id, vbd):
780 """Get a virtual block device (vbd) from a domain.
782 @param id: domain
783 @param vbd: vbd index
784 @return: vbd device (or None)
785 """
786 return self.domain_devtype_get(id, 'vbd', vbd)
788 def domain_shadow_control(self, id, op):
789 """Shadow page control.
791 @param id: domain
792 @param op: operation
793 """
794 dominfo = self.domain_lookup(id)
795 try:
796 return xc.shadow_control(dominfo.dom, op)
797 except Exception, ex:
798 raise XendError(str(ex))
800 def domain_maxmem_set(self, id, mem):
801 """Set the memory limit for a domain.
803 @param dom: domain
804 @param mem: memory limit (in MB)
805 @return: 0 on success, -1 on error
806 """
807 dominfo = self.domain_lookup(id)
808 maxmem = int(mem) * 1024
809 try:
810 return xc.domain_setmaxmem(dominfo.dom, maxmem_kb = maxmem)
811 except Exception, ex:
812 raise XendError(str(ex))
815 def instance():
816 """Singleton constructor. Use this instead of the class constructor.
817 """
818 global inst
819 try:
820 inst
821 except:
822 inst = XendDomain()
823 return inst