debuggers.hg

view tools/python/xen/xend/XendDomain.py @ 4655:a838a908e38e

bitkeeper revision 1.1327.2.2 (4267a9b3MhPpljnjQ5IbfLdzcW2K3w)

Remove twisted from the HTTP server and replace with a
threaded server. Add classes to provide tcp and unix servers
using threads instead of twisted. Remove use of twisted from
the consoles, event server and HTTP resources

Signed-off-by: Mike Wray <mike.wray@hp.com>
author mjw@wray-m-3.hpl.hp.com
date Thu Apr 21 13:25:07 2005 +0000 (2005-04-21)
parents c69fbe48a357
children d781b9d08e80
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 = 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 @return: deferred
458 """
459 xmigrate = XendMigrate.instance()
460 return xmigrate.restore_begin(src)
462 def domain_get(self, id):
463 """Get up-to-date info about a domain.
465 @param id: domain id
466 @return: domain object (or None)
467 """
468 id = str(id)
469 self.refresh_domain(id)
470 return self.domain_by_id.get(id)
472 def domain_lookup(self, name):
473 name = str(name)
474 dominfo = self.domain_by_name.get(name) or self.domain_by_id.get(name)
475 if dominfo:
476 return dominfo
477 raise XendError('invalid domain: ' + name)
479 def domain_exists(self, name):
480 name = str(name)
481 return self.domain_by_name.get(name) or self.domain_by_id.get(name)
483 def domain_unpause(self, id):
484 """Unpause domain execution.
486 @param id: domain id
487 """
488 dominfo = self.domain_lookup(id)
489 eserver.inject('xend.domain.unpause', [dominfo.name, dominfo.id])
490 try:
491 return xc.domain_unpause(dom=dominfo.dom)
492 except Exception, ex:
493 raise XendError(str(ex))
495 def domain_pause(self, id):
496 """Pause domain execution.
498 @param id: domain id
499 """
500 dominfo = self.domain_lookup(id)
501 eserver.inject('xend.domain.pause', [dominfo.name, dominfo.id])
502 try:
503 return xc.domain_pause(dom=dominfo.dom)
504 except Exception, ex:
505 raise XendError(str(ex))
507 def domain_shutdown(self, id, reason='poweroff', key=0):
508 """Shutdown domain (nicely).
509 - poweroff: restart according to exit code and restart mode
510 - reboot: restart on exit
511 - halt: do not restart
513 Returns immediately.
515 @param id: domain id
516 @param reason: shutdown type: poweroff, reboot, suspend, halt
517 """
518 dominfo = self.domain_lookup(id)
519 if reason == 'halt':
520 self.domain_restart_cancel(dominfo.id)
521 else:
522 self.domain_restart_schedule(dominfo.id, reason, force=True)
523 eserver.inject('xend.domain.shutdown', [dominfo.name, dominfo.id, reason])
524 if reason == 'halt':
525 reason = 'poweroff'
526 val = dominfo.shutdown(reason, key=key)
527 self.add_shutdown(dominfo, reason, key)
528 self.refresh_schedule(delay=10)
529 return val
531 def add_shutdown(self, dominfo, reason, key):
532 """Add a pending shutdown for a domain.
533 This will destroy the domain if the shutdown times out.
534 """
535 if dominfo.id in self.shutdowns_by_id:
536 return
537 self.shutdowns_by_id[dominfo.id] = DomainShutdown(dominfo, reason, key)
538 self.domain_shutdowns()
540 def domain_shutdowns(self):
541 """Process pending domain shutdowns.
542 Destroys domains whose shutdowns have timed out.
543 """
544 self.schedule_cancel('domain_shutdowns')
545 timeout = SHUTDOWN_TIMEOUT
546 for shutdown in self.shutdowns_by_id.values():
547 id = shutdown.getDomain()
548 if shutdown.isShutdown():
549 # Shutdown done - remove.
550 print 'domain_shutdowns> done: ', id
551 del self.shutdowns_by_id[id]
552 elif shutdown.isExpired():
553 # Shutdown expired - remove and destroy domain.
554 del self.shutdowns_by_id[id]
555 try:
556 log.info("Domain shutdown timeout expired: name=%s id=%s",
557 shutdown.getDomainName(), id)
558 self.domain_destroy(id, reason=shutdown.getReason())
559 except Exception:
560 pass
561 else:
562 # Shutdown still pending.
563 print 'domain_shutdowns> pending: ', id
564 timeout = min(timeout, shutdown.getTimeout())
565 if self.shutdowns_by_id:
566 # Pending shutdowns remain - reschedule.
567 self.schedule_later(timeout, 'domain_shutdowns', self.domain_shutdowns)
569 def domain_restart_schedule(self, id, reason, force=False):
570 """Schedule a restart for a domain if it needs one.
572 @param id: domain id
573 @param reason: shutdown reason
574 """
575 log.debug('domain_restart_schedule> %s %s %d', id, reason, force)
576 dominfo = self.domain_lookup(id)
577 if not dominfo:
578 return
579 if dominfo.id in self.restarts_by_id:
580 return
581 restart = (force and reason == 'reboot') or dominfo.restart_needed(reason)
582 if restart:
583 dominfo.restarting()
584 self.domain_restart_add(dominfo)
586 def domain_restart_add(self, dominfo):
587 self.restarts_by_name[dominfo.name] = dominfo
588 self.restarts_by_id[dominfo.id] = dominfo
589 log.info('Scheduling restart for domain: name=%s id=%s', dominfo.name, dominfo.id)
590 eserver.inject("xend.domain.restart",
591 [dominfo.name, dominfo.id, "schedule"])
592 self.domain_restarts_schedule()
594 def domain_restart_cancel(self, id):
595 """Cancel any restart scheduled for a domain.
597 @param id: domain id
598 """
599 dominfo = self.restarts_by_id.get(id) or self.restarts_by_name.get(id)
600 if dominfo:
601 log.info('Cancelling restart for domain: name=%s id=%s',
602 dominfo.name, dominfo.id)
603 eserver.inject("xend.domain.restart",
604 [dominfo.name, dominfo.id, "cancel"])
605 dominfo.restart_cancel()
606 del self.restarts_by_id[dominfo.id]
607 del self.restarts_by_name[dominfo.name]
609 def domain_restarts(self):
610 """Execute any scheduled domain restarts for domains that have gone.
611 """
612 self.domain_restarts_cancel()
613 doms = self.xen_domains()
614 for dominfo in self.restarts_by_id.values():
615 print 'domain_restarts>', dominfo.name, dominfo.id
616 info = doms.get(dominfo.id)
617 if info:
618 # Don't execute restart for domains still running.
619 print 'domain_restarts> still runnning: ', dominfo.name
620 continue
621 # Remove it from the restarts.
622 del self.restarts_by_id[dominfo.id]
623 del self.restarts_by_name[dominfo.name]
624 print 'domain_restarts> restarting: ', dominfo.name
625 self.domain_restart(dominfo)
626 if self.domain_restarts_exist():
627 # Run again later if any restarts remain.
628 self.refresh_schedule(delay=10)
630 def domain_restarts_exist(self):
631 return len(self.restarts_by_id)
633 def final_domain_destroy(self, id):
634 """Final destruction of a domain..
636 @param id: domain id
637 """
638 try:
639 dominfo = self.domain_lookup(id)
640 log.info('Destroying domain: name=%s', dominfo.name)
641 eserver.inject('xend.domain.destroy', [dominfo.name, dominfo.id])
642 val = dominfo.destroy()
643 except:
644 #todo
645 try:
646 val = xc.domain_destroy(dom=int(id))
647 except Exception, ex:
648 raise XendError(str(ex))
649 return val
651 def domain_destroy(self, id, reason='halt'):
652 """Terminate domain immediately.
653 - halt: cancel any restart for the domain
654 - reboot schedule a restart for the domain
656 @param id: domain id
657 """
658 if reason == 'halt':
659 self.domain_restart_cancel(id)
660 elif reason == 'reboot':
661 self.domain_restart_schedule(id, reason, force=True)
662 val = self.final_domain_destroy(id)
663 self.refresh_schedule()
664 return val
666 def domain_migrate(self, id, dst, live=False, resource=0):
667 """Start domain migration.
669 @param id: domain id
670 @return: deferred
671 """
672 # Need a cancel too?
673 # Don't forget to cancel restart for it.
674 dominfo = self.domain_lookup(id)
675 xmigrate = XendMigrate.instance()
676 return xmigrate.migrate_begin(dominfo, dst, live=live, resource=resource)
678 def domain_save(self, id, dst, progress=False):
679 """Start saving a domain to file.
681 @param id: domain id
682 @param dst: destination file
683 @param progress: output progress if true
684 @return: deferred
685 """
686 dominfo = self.domain_lookup(id)
687 xmigrate = XendMigrate.instance()
688 return xmigrate.save_begin(dominfo, dst)
690 def domain_pincpu(self, id, cpu):
691 """Pin a domain to a cpu.
693 @param id: domain
694 @param cpu: cpu number
695 """
696 dominfo = self.domain_lookup(id)
697 try:
698 return xc.domain_pincpu(int(dominfo.id), cpu)
699 except Exception, ex:
700 raise XendError(str(ex))
702 def domain_cpu_bvt_set(self, id, mcuadv, warpback, warpvalue, warpl, warpu):
703 """Set BVT (Borrowed Virtual Time) scheduler parameters for a domain.
704 """
705 dominfo = self.domain_lookup(id)
706 try:
707 return xc.bvtsched_domain_set(dom=dominfo.dom, mcuadv=mcuadv,
708 warpback=warpback, warpvalue=warpvalue,
709 warpl=warpl, warpu=warpu)
710 except Exception, ex:
711 raise XendError(str(ex))
713 def domain_cpu_bvt_get(self, id):
714 """Get BVT (Borrowed Virtual Time) scheduler parameters for a domain.
715 """
716 dominfo = self.domain_lookup(id)
717 try:
718 return xc.bvtsched_domain_get(dominfo.dom)
719 except Exception, ex:
720 raise XendError(str(ex))
722 def domain_device_create(self, id, devconfig):
723 """Create a new device for a domain.
725 @param id: domain id
726 @param devconfig: device configuration
727 """
728 dominfo = self.domain_lookup(id)
729 val = dominfo.device_create(devconfig)
730 self.update_domain(dominfo.id)
731 self.refresh_schedule()
732 return val
734 def domain_device_configure(self, id, devconfig, idx):
735 """Configure an existing device for a domain.
737 @param id: domain id
738 @param devconfig: device configuration
739 @param idx: device index
740 @return: updated device configuration
741 """
742 dominfo = self.domain_lookup(id)
743 val = dominfo.device_configure(devconfig, idx)
744 self.update_domain(dominfo.id)
745 self.refresh_schedule()
746 return val
748 def domain_device_refresh(self, id, type, idx):
749 """Refresh a device.
751 @param id: domain id
752 @param idx: device index
753 @param type: device type
754 """
755 dominfo = self.domain_lookup(id)
756 val = dominfo.device_refresh(type, idx)
757 self.update_domain(dominfo.id)
758 self.refresh_schedule()
759 return val
761 def domain_device_destroy(self, id, type, idx):
762 """Destroy a device.
764 @param id: domain id
765 @param idx: device index
766 @param type: device type
767 """
768 dominfo = self.domain_lookup(id)
769 val = dominfo.device_destroy(type, idx)
770 self.update_domain(dominfo.id)
771 self.refresh_schedule()
772 return val
774 def domain_devtype_ls(self, id, type):
775 """Get list of device indexes for a domain.
777 @param id: domain
778 @param type: device type
779 @return: device indexes
780 """
781 dominfo = self.domain_lookup(id)
782 return dominfo.getDeviceIndexes(type)
784 def domain_devtype_get(self, id, type, idx):
785 """Get a device from a domain.
787 @param id: domain
788 @param type: device type
789 @param idx: device index
790 @return: device object (or None)
791 """
792 dominfo = self.domain_lookup(id)
793 return dominfo.getDeviceByIndex(type, idx)
795 def domain_vif_credit_limit(self, id, vif, credit, period):
796 """Limit the vif's transmission rate
797 """
798 dominfo = self.domain_lookup(id)
799 dev = dominfo.getDeviceById('vif', vif)
800 if not dev:
801 raise XendError("invalid vif")
802 return dev.setCreditLimit(credit, period)
804 def domain_vif_ls(self, id):
805 """Get list of virtual network interface (vif) indexes for a domain.
807 @param id: domain
808 @return: vif indexes
809 """
810 return self.domain_devtype_ls(id, 'vif')
812 def domain_vif_get(self, id, vif):
813 """Get a virtual network interface (vif) from a domain.
815 @param id: domain
816 @param vif: vif index
817 @return: vif device object (or None)
818 """
819 return self.domain_devtype_get(id, 'vif', vif)
821 def domain_vbd_ls(self, id):
822 """Get list of virtual block device (vbd) indexes for a domain.
824 @param id: domain
825 @return: vbd indexes
826 """
827 return self.domain_devtype_ls(id, 'vbd')
829 def domain_vbd_get(self, id, vbd):
830 """Get a virtual block device (vbd) from a domain.
832 @param id: domain
833 @param vbd: vbd index
834 @return: vbd device (or None)
835 """
836 return self.domain_devtype_get(id, 'vbd', vbd)
838 def domain_shadow_control(self, id, op):
839 """Shadow page control.
841 @param id: domain
842 @param op: operation
843 """
844 dominfo = self.domain_lookup(id)
845 try:
846 return xc.shadow_control(dominfo.dom, op)
847 except Exception, ex:
848 raise XendError(str(ex))
850 def domain_maxmem_set(self, id, mem):
851 """Set the memory limit for a domain.
853 @param dom: domain
854 @param mem: memory limit (in MB)
855 @return: 0 on success, -1 on error
856 """
857 dominfo = self.domain_lookup(id)
858 maxmem = int(mem) * 1024
859 try:
860 return xc.domain_setmaxmem(dominfo.dom, maxmem_kb = maxmem)
861 except Exception, ex:
862 raise XendError(str(ex))
864 def domain_mem_target_set(self, id, target):
865 dominfo = self.domain_lookup(id)
866 return dominfo.mem_target_set(target)
870 def instance():
871 """Singleton constructor. Use this instead of the class constructor.
872 """
873 global inst
874 try:
875 inst
876 except:
877 inst = XendDomain()
878 return inst