debuggers.hg

view tools/python/xen/xend/XendDomain.py @ 4672:d781b9d08e80

bitkeeper revision 1.1327.2.4 (426918a34Af7gihN8mTkq-P3KrAZXg)

Remove twisted from save/migrate handling.
This needs to use threads, so add thread support for
http server requests.

Signed-off-by: Mike Wray <mike.wray@hp.com>
author mjw@wray-m-3.hpl.hp.com
date Fri Apr 22 15:30:43 2005 +0000 (2005-04-22)
parents a838a908e38e
children bd15906125a7
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
9 import time
11 import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
13 import sxp
14 import XendRoot; xroot = XendRoot.instance()
15 import XendDB
16 import XendDomainInfo
17 import XendMigrate
18 import EventServer; eserver = EventServer.instance()
19 from XendError import XendError
20 from XendLogging import log
22 from scheduler import Scheduler
24 from xen.xend.server import channel
27 __all__ = [ "XendDomain" ]
29 SHUTDOWN_TIMEOUT = 30
31 class DomainShutdown:
32 """A pending domain shutdown. The domain is asked to shut down,
33 if it has not terminated or rebooted when the timeout expires it
34 is destroyed.
35 """
37 def __init__(self, dominfo, reason, key, timeout=None):
38 if timeout is None:
39 timeout = SHUTDOWN_TIMEOUT
40 self.start = time.time()
41 self.timeout = timeout
42 self.dominfo = dominfo
43 self.last_restart_time = dominfo.restart_time
44 self.last_restart_count = dominfo.restart_count
45 self.reason = reason
46 self.key = key
48 def getDomain(self):
49 return self.dominfo.id
51 def getDomainName(self):
52 return self.dominfo.name
54 def getReason(self):
55 return self.reason
57 def getTimeout(self):
58 return self.timeout
60 def isTerminated(self):
61 return self.dominfo.is_terminated()
63 def isRestarted(self):
64 return (self.dominfo.restart_count > self.last_restart_count)
66 def isShutdown(self):
67 return self.isTerminated() or self.isRestarted()
69 def isExpired(self):
70 return (time.time() - self.start) > self.timeout
72 class XendDomain:
73 """Index of all domains. Singleton.
74 """
76 """Path to domain database."""
77 dbpath = "domain"
79 """Table of domain info indexed by domain id."""
80 domain_by_id = {}
81 domain_by_name = {}
83 """Table of domains to restart, indexed by domain id."""
84 restarts_by_id = {}
85 restarts_by_name = {}
87 """Table of pending domain shutdowns, indexed by domain id."""
88 shutdowns_by_id = {}
90 """Table of delayed calls."""
91 scheduler = Scheduler()
93 def __init__(self):
94 # Hack alert. Python does not support mutual imports, but XendDomainInfo
95 # needs access to the XendDomain instance to look up domains. Attempting
96 # to import XendDomain from XendDomainInfo causes unbounded recursion.
97 # So we stuff the XendDomain instance (self) into xroot's components.
98 xroot.add_component("xen.xend.XendDomain", self)
99 # Table of domain info indexed by domain id.
100 self.db = XendDB.XendDB(self.dbpath)
101 self.domain_db = self.db.fetchall("")
102 # XXXcl maybe check if there's only dom0 if we _really_ need
103 # to remove the db
104 # self.rm_all()
105 eserver.subscribe('xend.virq', self.onVirq)
106 self.initial_refresh()
108 def onVirq(self, event, val):
109 """Event handler for virq.
110 """
111 print 'onVirq>', val
112 self.reap()
114 def schedule_later(self, _delay, _name, _fn, *args):
115 """Schedule a function to be called later (if not already scheduled).
117 @param _delay: delay in seconds
118 @param _name: schedule name
119 @param _fn: function
120 @param args: arguments
121 """
122 self.scheduler.later(_delay, _name, _fn, args)
124 def schedule_cancel(self, name):
125 """Cancel a scheduled function call.
127 @param name: schedule name to cancel
128 """
129 self.scheduler.cancel(name)
131 def reap_schedule(self, delay=1):
132 """Schedule reap to be called later.
134 @param delay: delay in seconds
135 """
136 self.schedule_later(delay, 'reap', self.reap)
138 def reap_cancel(self):
139 """Cancel any scheduled reap.
140 """
141 self.schedule_cancel('reap')
143 def refresh_schedule(self, delay=1):
144 """Schedule refresh to be called later.
146 @param delay: delay in seconds
147 """
148 self.schedule_later(delay, 'refresh', self.refresh)
150 def refresh_cancel(self):
151 """Cancel any scheduled refresh.
152 """
153 self.schedule_cancel('refresh')
155 def domain_restarts_schedule(self, delay=1):
156 """Schedule domain_restarts to be called later.
158 @param delay: delay in seconds
159 """
160 self.schedule_later(delay, 'domain_restarts', self.domain_restarts)
162 def domain_restarts_cancel(self):
163 """Cancel any scheduled call of domain_restarts.
164 """
165 self.schedule_cancel('domain_restarts')
167 def rm_all(self):
168 """Remove all domain info. Used after reboot.
169 """
170 for (k, v) in self.domain_db.items():
171 self._delete_domain(k, notify=False)
173 def xen_domains(self):
174 """Get table of domains indexed by id from xc.
175 """
176 domlist = xc.domain_getinfo()
177 doms = {}
178 for d in domlist:
179 domid = str(d['dom'])
180 doms[domid] = d
181 return doms
183 def xen_domain(self, dom):
184 """Get info about a single domain from xc.
185 Returns None if not found.
186 """
187 dom = int(dom)
188 dominfo = xc.domain_getinfo(dom, 1)
189 if dominfo == [] or dominfo[0]['dom'] != dom:
190 dominfo = None
191 else:
192 dominfo = dominfo[0]
193 return dominfo
195 def initial_refresh(self):
196 """Refresh initial domain info from domain_db.
197 """
198 doms = self.xen_domains()
199 for config in self.domain_db.values():
200 domid = str(sxp.child_value(config, 'id'))
201 if domid in doms:
202 try:
203 self._new_domain(config, doms[domid])
204 self.update_domain(domid)
205 except Exception, ex:
206 log.exception("Error recreating domain info: id=%s", domid)
207 self._delete_domain(domid)
208 else:
209 self._delete_domain(domid)
210 self.refresh()
212 def sync(self):
213 """Sync domain db to disk.
214 """
215 self.db.saveall("", self.domain_db)
217 def sync_domain(self, dom):
218 """Sync info for a domain to disk.
220 dom domain id (string)
221 """
222 self.db.save(dom, self.domain_db[dom])
224 def close(self):
225 pass
227 def _new_domain(self, savedinfo, info):
228 """Create a domain entry from saved info.
230 @param savedinfo: saved info from the db
231 @param info: domain info from xen
232 @return: domain
233 """
234 dominfo = XendDomainInfo.vm_recreate(savedinfo, info)
235 self.domain_by_id[dominfo.id] = dominfo
236 self.domain_by_name[dominfo.name] = dominfo
237 if dominfo.restart_pending():
238 self.domain_restart_add(dominfo)
239 return dominfo
241 def _add_domain(self, info, notify=True):
242 """Add a domain entry to the tables.
244 @param info: domain info object
245 @param notify: send a domain created event if true
246 """
247 # Remove entries under the wrong id.
248 for i, d in self.domain_by_id.items():
249 if i != d.id:
250 del self.domain_by_id[i]
251 if i in self.domain_db:
252 del self.domain_db[i]
253 self.db.delete(i)
254 # Remove entries under the wrong name.
255 for n, d in self.domain_by_name.items():
256 if n != d.name:
257 del self.domain_by_name[n]
258 # But also need to make sure are indexed under correct name.
259 # What about entries under info.name ?
260 if info.id in self.domain_by_id:
261 notify = False
262 self.domain_by_id[info.id] = info
263 self.domain_db[info.id] = info.sxpr()
264 if info.name:
265 self.domain_by_name[info.name] = info
266 self.sync_domain(info.id)
267 if notify:
268 eserver.inject('xend.domain.create', [info.name, info.id])
270 def _delete_domain(self, id, notify=True):
271 """Remove a domain from the tables.
273 @param id: domain id
274 @param notify: send a domain died event if true
275 """
276 for (k, info) in self.domain_by_name.items():
277 if info.id == id:
278 del self.domain_by_name[k]
279 info = self.domain_by_id.get(id)
280 if info:
281 del self.domain_by_id[id]
282 if notify:
283 eserver.inject('xend.domain.died', [info.name, info.id])
284 if id in self.domain_db:
285 del self.domain_db[id]
286 self.db.delete(id)
288 def reap(self):
289 """Look for domains that have crashed or stopped.
290 Tidy them up.
291 """
292 self.reap_cancel()
293 casualties = []
294 doms = self.xen_domains()
295 for d in doms.values():
296 dead = 0
297 dead = dead or (d['crashed'] or d['shutdown'])
298 dead = dead or (d['dying'] and
299 not(d['running'] or d['paused'] or d['blocked']))
300 if dead:
301 casualties.append(d)
302 destroyed = 0
303 for d in casualties:
304 id = str(d['dom'])
305 #print 'reap>', id
306 dominfo = self.domain_by_id.get(id)
307 name = (dominfo and dominfo.name) or '??'
308 if dominfo and dominfo.is_terminated():
309 #print 'reap> already terminated:', id
310 continue
311 log.debug('XendDomain>reap> domain died name=%s id=%s', name, id)
312 if d['shutdown']:
313 reason = XendDomainInfo.shutdown_reason(d['shutdown_reason'])
314 log.debug('XendDomain>reap> shutdown id=%s reason=%s', id, reason)
315 if reason in ['suspend']:
316 if dominfo and dominfo.is_terminated():
317 log.debug('XendDomain>reap> Suspended domain died id=%s', id)
318 else:
319 eserver.inject('xend.domain.suspended', [name, id])
320 continue
321 if reason in ['poweroff', 'reboot']:
322 eserver.inject('xend.domain.exit', [name, id, reason])
323 self.domain_restart_schedule(id, reason)
324 else:
325 eserver.inject('xend.domain.exit', [name, id, 'crash'])
326 destroyed += 1
327 self.final_domain_destroy(id)
328 if self.domain_restarts_exist():
329 self.domain_restarts_schedule()
330 if destroyed:
331 self.refresh_schedule(delay=5)
333 def refresh(self):
334 """Refresh domain list from Xen.
335 """
336 self.refresh_cancel()
337 doms = self.xen_domains()
338 # Add entries for any domains we don't know about.
339 for (id, d) in doms.items():
340 if id not in self.domain_by_id:
341 log.warning("Created entry for unknown domain: %s", id)
342 savedinfo = None
343 dominfo = XendDomainInfo.vm_recreate(savedinfo, d)
344 self._add_domain(dominfo)
345 # Remove entries for domains that no longer exist.
346 # Update entries for existing domains.
347 for d in self.domain_by_id.values():
348 info = doms.get(d.id)
349 if info:
350 d.update(info)
351 elif d.restart_pending():
352 pass
353 else:
354 self._delete_domain(d.id)
355 self.reap_schedule(delay=1)
357 def update_domain(self, id):
358 """Update the saved info for a domain.
360 @param id: domain id
361 """
362 dominfo = self.domain_by_id.get(id)
363 if dominfo:
364 self.domain_db[id] = dominfo.sxpr()
365 self.sync_domain(id)
367 def refresh_domain(self, id):
368 """Refresh information for a single domain.
370 @param id: domain id
371 """
372 dominfo = self.xen_domain(id)
373 if dominfo:
374 d = self.domain_by_id.get(id)
375 if d:
376 d.update(dominfo)
377 else:
378 self._delete_domain(id)
380 def domain_ls(self):
381 """Get list of domain names.
383 @return: domain names
384 """
385 self.refresh()
386 return self.domain_by_name.keys()
388 def domain_ls_ids(self):
389 """Get list of domain ids.
391 @return: domain names
392 """
393 self.refresh()
394 return self.domain_by_id.keys()
396 def domains(self):
397 """Get list of domain objects.
399 @return: domain objects
400 """
401 self.refresh()
402 return self.domain_by_id.values()
404 def domain_create(self, config):
405 """Create a domain from a configuration.
407 @param config: configuration
408 @return: domain
409 """
410 dominfo = XendDomainInfo.vm_create(config)
411 self._add_domain(dominfo)
412 return dominfo
414 def domain_restart(self, dominfo):
415 """Restart a domain.
417 @param dominfo: domain object
418 """
419 log.info("Restarting domain: id=%s name=%s", dominfo.id, dominfo.name)
420 eserver.inject("xend.domain.restart",
421 [dominfo.name, dominfo.id, "begin"])
422 try:
423 dominfo.restart()
424 self._add_domain(dominfo)
425 log.info('Restarted domain name=%s id=%s', dominfo.name, dominfo.id)
426 eserver.inject("xend.domain.restart",
427 [dominfo.name, dominfo.id, "success"])
428 self.domain_unpause(dominfo.id)
429 except Exception, ex:
430 log.exception("Exception restarting domain: name=%s id=%s",
431 dominfo.name, dominfo.id)
432 eserver.inject("xend.domain.restart",
433 [dominfo.name, dominfo.id, "fail"])
434 return dominfo
436 def domain_configure(self, id, vmconfig):
437 """Configure an existing domain. This is intended for internal
438 use by domain restore and migrate.
440 @param id: domain id
441 @param vmconfig: vm configuration
442 """
443 config = sxp.child_value(vmconfig, 'config')
444 dominfo = self.domain_lookup(id)
445 log.debug('domain_configure> id=%s config=%s', str(id), str(config))
446 if dominfo.config:
447 raise XendError("Domain already configured: " + dominfo.id)
448 dominfo.dom_construct(dominfo.dom, config)
449 self._add_domain(dominfo)
450 return dominfo
452 def domain_restore(self, src, progress=False):
453 """Restore a domain from file.
455 @param src: source file
456 @param progress: output progress if true
457 """
458 xmigrate = XendMigrate.instance()
459 return xmigrate.restore_begin(src)
461 def domain_get(self, id):
462 """Get up-to-date info about a domain.
464 @param id: domain id
465 @return: domain object (or None)
466 """
467 id = str(id)
468 self.refresh_domain(id)
469 return self.domain_by_id.get(id)
471 def domain_lookup(self, name):
472 name = str(name)
473 dominfo = self.domain_by_name.get(name) or self.domain_by_id.get(name)
474 if dominfo:
475 return dominfo
476 raise XendError('invalid domain: ' + name)
478 def domain_exists(self, name):
479 name = str(name)
480 return self.domain_by_name.get(name) or self.domain_by_id.get(name)
482 def domain_unpause(self, id):
483 """Unpause domain execution.
485 @param id: domain id
486 """
487 dominfo = self.domain_lookup(id)
488 eserver.inject('xend.domain.unpause', [dominfo.name, dominfo.id])
489 try:
490 return xc.domain_unpause(dom=dominfo.dom)
491 except Exception, ex:
492 raise XendError(str(ex))
494 def domain_pause(self, id):
495 """Pause domain execution.
497 @param id: domain id
498 """
499 dominfo = self.domain_lookup(id)
500 eserver.inject('xend.domain.pause', [dominfo.name, dominfo.id])
501 try:
502 return xc.domain_pause(dom=dominfo.dom)
503 except Exception, ex:
504 raise XendError(str(ex))
506 def domain_shutdown(self, id, reason='poweroff', key=0):
507 """Shutdown domain (nicely).
508 - poweroff: restart according to exit code and restart mode
509 - reboot: restart on exit
510 - halt: do not restart
512 Returns immediately.
514 @param id: domain id
515 @param reason: shutdown type: poweroff, reboot, suspend, halt
516 """
517 dominfo = self.domain_lookup(id)
518 if reason == 'halt':
519 self.domain_restart_cancel(dominfo.id)
520 else:
521 self.domain_restart_schedule(dominfo.id, reason, force=True)
522 eserver.inject('xend.domain.shutdown', [dominfo.name, dominfo.id, reason])
523 if reason == 'halt':
524 reason = 'poweroff'
525 val = dominfo.shutdown(reason, key=key)
526 self.add_shutdown(dominfo, reason, key)
527 self.refresh_schedule(delay=10)
528 return val
530 def add_shutdown(self, dominfo, reason, key):
531 """Add a pending shutdown for a domain.
532 This will destroy the domain if the shutdown times out.
533 """
534 if dominfo.id in self.shutdowns_by_id:
535 return
536 self.shutdowns_by_id[dominfo.id] = DomainShutdown(dominfo, reason, key)
537 self.domain_shutdowns()
539 def domain_shutdowns(self):
540 """Process pending domain shutdowns.
541 Destroys domains whose shutdowns have timed out.
542 """
543 self.schedule_cancel('domain_shutdowns')
544 timeout = SHUTDOWN_TIMEOUT
545 for shutdown in self.shutdowns_by_id.values():
546 id = shutdown.getDomain()
547 if shutdown.isShutdown():
548 # Shutdown done - remove.
549 print 'domain_shutdowns> done: ', id
550 del self.shutdowns_by_id[id]
551 elif shutdown.isExpired():
552 # Shutdown expired - remove and destroy domain.
553 del self.shutdowns_by_id[id]
554 try:
555 log.info("Domain shutdown timeout expired: name=%s id=%s",
556 shutdown.getDomainName(), id)
557 self.domain_destroy(id, reason=shutdown.getReason())
558 except Exception:
559 pass
560 else:
561 # Shutdown still pending.
562 print 'domain_shutdowns> pending: ', id
563 timeout = min(timeout, shutdown.getTimeout())
564 if self.shutdowns_by_id:
565 # Pending shutdowns remain - reschedule.
566 self.schedule_later(timeout, 'domain_shutdowns', self.domain_shutdowns)
568 def domain_restart_schedule(self, id, reason, force=False):
569 """Schedule a restart for a domain if it needs one.
571 @param id: domain id
572 @param reason: shutdown reason
573 """
574 log.debug('domain_restart_schedule> %s %s %d', id, reason, force)
575 dominfo = self.domain_lookup(id)
576 if not dominfo:
577 return
578 if dominfo.id in self.restarts_by_id:
579 return
580 restart = (force and reason == 'reboot') or dominfo.restart_needed(reason)
581 if restart:
582 dominfo.restarting()
583 self.domain_restart_add(dominfo)
585 def domain_restart_add(self, dominfo):
586 self.restarts_by_name[dominfo.name] = dominfo
587 self.restarts_by_id[dominfo.id] = dominfo
588 log.info('Scheduling restart for domain: name=%s id=%s', dominfo.name, dominfo.id)
589 eserver.inject("xend.domain.restart",
590 [dominfo.name, dominfo.id, "schedule"])
591 self.domain_restarts_schedule()
593 def domain_restart_cancel(self, id):
594 """Cancel any restart scheduled for a domain.
596 @param id: domain id
597 """
598 dominfo = self.restarts_by_id.get(id) or self.restarts_by_name.get(id)
599 if dominfo:
600 log.info('Cancelling restart for domain: name=%s id=%s',
601 dominfo.name, dominfo.id)
602 eserver.inject("xend.domain.restart",
603 [dominfo.name, dominfo.id, "cancel"])
604 dominfo.restart_cancel()
605 del self.restarts_by_id[dominfo.id]
606 del self.restarts_by_name[dominfo.name]
608 def domain_restarts(self):
609 """Execute any scheduled domain restarts for domains that have gone.
610 """
611 self.domain_restarts_cancel()
612 doms = self.xen_domains()
613 for dominfo in self.restarts_by_id.values():
614 print 'domain_restarts>', dominfo.name, dominfo.id
615 info = doms.get(dominfo.id)
616 if info:
617 # Don't execute restart for domains still running.
618 print 'domain_restarts> still runnning: ', dominfo.name
619 continue
620 # Remove it from the restarts.
621 del self.restarts_by_id[dominfo.id]
622 del self.restarts_by_name[dominfo.name]
623 print 'domain_restarts> restarting: ', dominfo.name
624 self.domain_restart(dominfo)
625 if self.domain_restarts_exist():
626 # Run again later if any restarts remain.
627 self.refresh_schedule(delay=10)
629 def domain_restarts_exist(self):
630 return len(self.restarts_by_id)
632 def final_domain_destroy(self, id):
633 """Final destruction of a domain..
635 @param id: domain id
636 """
637 try:
638 dominfo = self.domain_lookup(id)
639 log.info('Destroying domain: name=%s', dominfo.name)
640 eserver.inject('xend.domain.destroy', [dominfo.name, dominfo.id])
641 val = dominfo.destroy()
642 except:
643 #todo
644 try:
645 val = xc.domain_destroy(dom=int(id))
646 except Exception, ex:
647 raise XendError(str(ex))
648 return val
650 def domain_destroy(self, id, reason='halt'):
651 """Terminate domain immediately.
652 - halt: cancel any restart for the domain
653 - reboot schedule a restart for the domain
655 @param id: domain id
656 """
657 if reason == 'halt':
658 self.domain_restart_cancel(id)
659 elif reason == 'reboot':
660 self.domain_restart_schedule(id, reason, force=True)
661 val = self.final_domain_destroy(id)
662 self.refresh_schedule()
663 return val
665 def domain_migrate(self, id, dst, live=False, resource=0):
666 """Start domain migration.
668 @param id: domain id
669 """
670 # Need a cancel too?
671 # Don't forget to cancel restart for it.
672 dominfo = self.domain_lookup(id)
673 xmigrate = XendMigrate.instance()
674 return xmigrate.migrate_begin(dominfo, dst, live=live, resource=resource)
676 def domain_save(self, id, dst, progress=False):
677 """Start saving a domain to file.
679 @param id: domain id
680 @param dst: destination file
681 @param progress: output progress if true
682 """
683 dominfo = self.domain_lookup(id)
684 xmigrate = XendMigrate.instance()
685 return xmigrate.save_begin(dominfo, dst)
687 def domain_pincpu(self, id, cpu):
688 """Pin a domain to a cpu.
690 @param id: domain
691 @param cpu: cpu number
692 """
693 dominfo = self.domain_lookup(id)
694 try:
695 return xc.domain_pincpu(int(dominfo.id), cpu)
696 except Exception, ex:
697 raise XendError(str(ex))
699 def domain_cpu_bvt_set(self, id, mcuadv, warpback, warpvalue, warpl, warpu):
700 """Set BVT (Borrowed Virtual Time) scheduler parameters for a domain.
701 """
702 dominfo = self.domain_lookup(id)
703 try:
704 return xc.bvtsched_domain_set(dom=dominfo.dom, mcuadv=mcuadv,
705 warpback=warpback, warpvalue=warpvalue,
706 warpl=warpl, warpu=warpu)
707 except Exception, ex:
708 raise XendError(str(ex))
710 def domain_cpu_bvt_get(self, id):
711 """Get BVT (Borrowed Virtual Time) scheduler parameters for a domain.
712 """
713 dominfo = self.domain_lookup(id)
714 try:
715 return xc.bvtsched_domain_get(dominfo.dom)
716 except Exception, ex:
717 raise XendError(str(ex))
719 def domain_device_create(self, id, devconfig):
720 """Create a new device for a domain.
722 @param id: domain id
723 @param devconfig: device configuration
724 """
725 dominfo = self.domain_lookup(id)
726 val = dominfo.device_create(devconfig)
727 self.update_domain(dominfo.id)
728 self.refresh_schedule()
729 return val
731 def domain_device_configure(self, id, devconfig, idx):
732 """Configure an existing device for a domain.
734 @param id: domain id
735 @param devconfig: device configuration
736 @param idx: device index
737 @return: updated device configuration
738 """
739 dominfo = self.domain_lookup(id)
740 val = dominfo.device_configure(devconfig, idx)
741 self.update_domain(dominfo.id)
742 self.refresh_schedule()
743 return val
745 def domain_device_refresh(self, id, type, idx):
746 """Refresh a device.
748 @param id: domain id
749 @param idx: device index
750 @param type: device type
751 """
752 dominfo = self.domain_lookup(id)
753 val = dominfo.device_refresh(type, idx)
754 self.update_domain(dominfo.id)
755 self.refresh_schedule()
756 return val
758 def domain_device_destroy(self, id, type, idx):
759 """Destroy a device.
761 @param id: domain id
762 @param idx: device index
763 @param type: device type
764 """
765 dominfo = self.domain_lookup(id)
766 val = dominfo.device_destroy(type, idx)
767 self.update_domain(dominfo.id)
768 self.refresh_schedule()
769 return val
771 def domain_devtype_ls(self, id, type):
772 """Get list of device indexes for a domain.
774 @param id: domain
775 @param type: device type
776 @return: device indexes
777 """
778 dominfo = self.domain_lookup(id)
779 return dominfo.getDeviceIndexes(type)
781 def domain_devtype_get(self, id, type, idx):
782 """Get a device from a domain.
784 @param id: domain
785 @param type: device type
786 @param idx: device index
787 @return: device object (or None)
788 """
789 dominfo = self.domain_lookup(id)
790 return dominfo.getDeviceByIndex(type, idx)
792 def domain_vif_credit_limit(self, id, vif, credit, period):
793 """Limit the vif's transmission rate
794 """
795 dominfo = self.domain_lookup(id)
796 dev = dominfo.getDeviceById('vif', vif)
797 if not dev:
798 raise XendError("invalid vif")
799 return dev.setCreditLimit(credit, period)
801 def domain_vif_ls(self, id):
802 """Get list of virtual network interface (vif) indexes for a domain.
804 @param id: domain
805 @return: vif indexes
806 """
807 return self.domain_devtype_ls(id, 'vif')
809 def domain_vif_get(self, id, vif):
810 """Get a virtual network interface (vif) from a domain.
812 @param id: domain
813 @param vif: vif index
814 @return: vif device object (or None)
815 """
816 return self.domain_devtype_get(id, 'vif', vif)
818 def domain_vbd_ls(self, id):
819 """Get list of virtual block device (vbd) indexes for a domain.
821 @param id: domain
822 @return: vbd indexes
823 """
824 return self.domain_devtype_ls(id, 'vbd')
826 def domain_vbd_get(self, id, vbd):
827 """Get a virtual block device (vbd) from a domain.
829 @param id: domain
830 @param vbd: vbd index
831 @return: vbd device (or None)
832 """
833 return self.domain_devtype_get(id, 'vbd', vbd)
835 def domain_shadow_control(self, id, op):
836 """Shadow page control.
838 @param id: domain
839 @param op: operation
840 """
841 dominfo = self.domain_lookup(id)
842 try:
843 return xc.shadow_control(dominfo.dom, op)
844 except Exception, ex:
845 raise XendError(str(ex))
847 def domain_maxmem_set(self, id, mem):
848 """Set the memory limit for a domain.
850 @param dom: domain
851 @param mem: memory limit (in MB)
852 @return: 0 on success, -1 on error
853 """
854 dominfo = self.domain_lookup(id)
855 maxmem = int(mem) * 1024
856 try:
857 return xc.domain_setmaxmem(dominfo.dom, maxmem_kb = maxmem)
858 except Exception, ex:
859 raise XendError(str(ex))
861 def domain_mem_target_set(self, id, target):
862 dominfo = self.domain_lookup(id)
863 return dominfo.mem_target_set(target)
867 def instance():
868 """Singleton constructor. Use this instead of the class constructor.
869 """
870 global inst
871 try:
872 inst
873 except:
874 inst = XendDomain()
875 return inst