ia64/xen-unstable

view tools/python/xen/xend/XendDomain.py @ 15538:99143d572521

Fix xm save command for a inactive managed domain.
Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author kfraser@localhost.localdomain
date Mon Jul 09 09:41:45 2007 +0100 (2007-07-09)
parents d6078c942355
children aa640601575f
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
16 # Copyright (C) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
17 # Copyright (C) 2005 XenSource Ltd
18 #============================================================================
20 """Handler for domain operations.
21 Nothing here is persistent (across reboots).
22 Needs to be persistent for one uptime.
23 """
25 import os
26 import stat
27 import shutil
28 import socket
29 import tempfile
30 import threading
32 import xen.lowlevel.xc
35 from xen.xend import XendOptions, XendCheckpoint, XendDomainInfo
36 from xen.xend.PrettyPrint import prettyprint
37 from xen.xend import XendConfig
38 from xen.xend.XendError import XendError, XendInvalidDomain, VmError
39 from xen.xend.XendError import VMBadState
40 from xen.xend.XendLogging import log
41 from xen.xend.XendAPIConstants import XEN_API_VM_POWER_STATE
42 from xen.xend.XendConstants import XS_VMROOT
43 from xen.xend.XendConstants import DOM_STATE_HALTED, DOM_STATE_PAUSED
44 from xen.xend.XendConstants import DOM_STATE_RUNNING, DOM_STATE_SUSPENDED
45 from xen.xend.XendConstants import DOM_STATE_SHUTDOWN, DOM_STATE_UNKNOWN
46 from xen.xend.XendConstants import TRIGGER_TYPE
47 from xen.xend.XendDevices import XendDevices
48 from xen.xend.XendAPIConstants import *
50 from xen.xend.xenstore.xstransact import xstransact
51 from xen.xend.xenstore.xswatch import xswatch
52 from xen.util import mkdir, security
53 from xen.xend import uuid
55 xc = xen.lowlevel.xc.xc()
56 xoptions = XendOptions.instance()
58 __all__ = [ "XendDomain" ]
60 CACHED_CONFIG_FILE = 'config.sxp'
61 CHECK_POINT_FILE = 'checkpoint.chk'
62 DOM0_UUID = "00000000-0000-0000-0000-000000000000"
63 DOM0_NAME = "Domain-0"
64 DOM0_ID = 0
66 POWER_STATE_NAMES = dict([(x, XEN_API_VM_POWER_STATE[x])
67 for x in [DOM_STATE_HALTED,
68 DOM_STATE_PAUSED,
69 DOM_STATE_RUNNING,
70 DOM_STATE_SUSPENDED,
71 DOM_STATE_SHUTDOWN,
72 DOM_STATE_UNKNOWN]])
73 POWER_STATE_ALL = 'all'
76 class XendDomain:
77 """Index of all domains. Singleton.
79 @ivar domains: map of domains indexed by domid
80 @type domains: dict of XendDomainInfo
81 @ivar managed_domains: domains that are not running and managed by Xend
82 @type managed_domains: dict of XendDomainInfo indexed by uuid
83 @ivar domains_lock: lock that must be held when manipulating self.domains
84 @type domains_lock: threaading.RLock
85 @ivar _allow_new_domains: Flag to set that allows creating of new domains.
86 @type _allow_new_domains: boolean
87 """
89 def __init__(self):
90 self.domains = {}
91 self.managed_domains = {}
92 self.domains_lock = threading.RLock()
94 # xen api instance vars
95 # TODO: nothing uses this at the moment
96 self._allow_new_domains = True
98 # This must be called only the once, by instance() below. It is separate
99 # from the constructor because XendDomainInfo calls back into this class
100 # in order to check the uniqueness of domain names. This means that
101 # instance() must be able to return a valid instance of this class even
102 # during this initialisation.
103 def init(self):
104 """Singleton initialisation function."""
106 dom_path = self._managed_path()
107 mkdir.parents(dom_path, stat.S_IRWXU)
109 xstransact.Mkdir(XS_VMROOT)
110 xstransact.SetPermissions(XS_VMROOT, {'dom': DOM0_ID})
112 self.domains_lock.acquire()
113 try:
114 try:
115 dom0info = [d for d in self._running_domains() \
116 if d.get('domid') == DOM0_ID][0]
118 dom0info['name'] = DOM0_NAME
119 dom0 = XendDomainInfo.recreate(dom0info, True)
120 except IndexError:
121 raise XendError('Unable to find Domain 0')
123 self._setDom0CPUCount()
125 # This watch registration needs to be before the refresh call, so
126 # that we're sure that we haven't missed any releases, but inside
127 # the domains_lock, as we don't want the watch to fire until after
128 # the refresh call has completed.
129 xswatch("@introduceDomain", self._on_domains_changed)
130 xswatch("@releaseDomain", self._on_domains_changed)
132 self._init_domains()
133 finally:
134 self.domains_lock.release()
137 def _on_domains_changed(self, _):
138 """ Callback method when xenstore changes.
140 Calls refresh which will keep the local cache of domains
141 in sync.
143 @rtype: int
144 @return: 1
145 """
146 self.domains_lock.acquire()
147 try:
148 self._refresh()
149 finally:
150 self.domains_lock.release()
151 return 1
153 def _init_domains(self):
154 """Does the initial scan of managed and active domains to
155 populate self.domains.
157 Note: L{XendDomainInfo._checkName} will call back into XendDomain
158 to make sure domain name is not a duplicate.
160 """
161 self.domains_lock.acquire()
162 try:
163 running = self._running_domains()
164 managed = self._managed_domains()
166 # add all active domains
167 for dom in running:
168 if dom['dying'] == 1:
169 log.warn('Ignoring dying domain %d from now on' %
170 dom['domid'])
171 continue
173 if dom['domid'] != DOM0_ID:
174 try:
175 new_dom = XendDomainInfo.recreate(dom, False)
176 except Exception:
177 log.exception("Failed to create reference to running "
178 "domain id: %d" % dom['domid'])
180 # add all managed domains as dormant domains.
181 for dom in managed:
182 dom_uuid = dom.get('uuid')
183 if not dom_uuid:
184 continue
186 dom_name = dom.get('name_label', 'Domain-%s' % dom_uuid)
187 try:
188 running_dom = self.domain_lookup_nr(dom_name)
189 if not running_dom:
190 # instantiate domain if not started.
191 new_dom = XendDomainInfo.createDormant(dom)
192 self._managed_domain_register(new_dom)
193 else:
194 self._managed_domain_register(running_dom)
195 for key in XendConfig.XENAPI_CFG_TYPES.keys():
196 if key not in XendConfig.LEGACY_XENSTORE_VM_PARAMS and \
197 key in dom:
198 running_dom.info[key] = dom[key]
199 except Exception:
200 log.exception("Failed to create reference to managed "
201 "domain: %s" % dom_name)
203 finally:
204 self.domains_lock.release()
207 # -----------------------------------------------------------------
208 # Getting managed domains storage path names
210 def _managed_path(self, domuuid = None):
211 """Returns the path of the directory where managed domain
212 information is stored.
214 @keyword domuuid: If not None, will return the path to the domain
215 otherwise, will return the path containing
216 the directories which represent each domain.
217 @type: None or String.
218 @rtype: String
219 @return: Path.
220 """
221 dom_path = xoptions.get_xend_domains_path()
222 if domuuid:
223 dom_path = os.path.join(dom_path, domuuid)
224 return dom_path
226 def _managed_config_path(self, domuuid):
227 """Returns the path to the configuration file of a managed domain.
229 @param domname: Domain uuid
230 @type domname: String
231 @rtype: String
232 @return: path to config file.
233 """
234 return os.path.join(self._managed_path(domuuid), CACHED_CONFIG_FILE)
236 def _managed_check_point_path(self, domuuid):
237 """Returns absolute path to check point file for managed domain.
239 @param domuuid: Name of managed domain
240 @type domname: String
241 @rtype: String
242 @return: Path
243 """
244 return os.path.join(self._managed_path(domuuid), CHECK_POINT_FILE)
246 def _managed_config_remove(self, domuuid):
247 """Removes a domain configuration from managed list
249 @param domuuid: Name of managed domain
250 @type domname: String
251 @raise XendError: fails to remove the domain.
252 """
253 config_path = self._managed_path(domuuid)
254 try:
255 if os.path.exists(config_path) and os.path.isdir(config_path):
256 shutil.rmtree(config_path)
257 except IOError:
258 log.exception('managed_config_remove failed removing conf')
259 raise XendError("Unable to remove managed configuration"
260 " for domain: %s" % domuuid)
262 def managed_config_save(self, dominfo):
263 """Save a domain's configuration to disk
265 @param domninfo: Managed domain to save.
266 @type dominfo: XendDomainInfo
267 @raise XendError: fails to save configuration.
268 @rtype: None
269 """
270 if not self.is_domain_managed(dominfo):
271 return # refuse to save configuration this domain isn't managed
273 if dominfo:
274 domains_dir = self._managed_path()
275 dom_uuid = dominfo.get_uuid()
276 domain_config_dir = self._managed_path(dom_uuid)
278 def make_or_raise(path):
279 try:
280 mkdir.parents(path, stat.S_IRWXU)
281 except:
282 log.exception("%s could not be created." % path)
283 raise XendError("%s could not be created." % path)
285 make_or_raise(domains_dir)
286 make_or_raise(domain_config_dir)
288 try:
289 fd, fn = tempfile.mkstemp()
290 f = os.fdopen(fd, 'w+b')
291 try:
292 prettyprint(dominfo.sxpr(legacy_only = False), f,
293 width = 78)
294 finally:
295 f.close()
297 try:
298 shutil.move(fn, self._managed_config_path(dom_uuid))
299 except:
300 log.exception("Renaming %s to %s", fn,
301 self._managed_config_path(dom_uuid))
302 os.remove(fn)
303 except:
304 log.exception("Error occurred saving configuration file " +
305 "to %s" % domain_config_dir)
306 raise XendError("Failed to save configuration file to: %s" %
307 domain_config_dir)
308 else:
309 log.warn("Trying to save configuration for invalid domain")
312 def _managed_domains(self):
313 """ Returns list of domains that are managed.
315 Expects to be protected by domains_lock.
317 @rtype: list of XendConfig
318 @return: List of domain configurations that are managed.
319 """
320 dom_path = self._managed_path()
321 dom_uuids = os.listdir(dom_path)
322 doms = []
323 for dom_uuid in dom_uuids:
324 try:
325 cfg_file = self._managed_config_path(dom_uuid)
326 cfg = XendConfig.XendConfig(filename = cfg_file)
327 if cfg.get('uuid') != dom_uuid:
328 # something is wrong with the SXP
329 log.error("UUID mismatch in stored configuration: %s" %
330 cfg_file)
331 continue
332 doms.append(cfg)
333 except Exception:
334 log.exception('Unable to open or parse config.sxp: %s' % \
335 cfg_file)
336 return doms
338 def _managed_domain_unregister(self, dom):
339 try:
340 if self.is_domain_managed(dom):
341 self._managed_config_remove(dom.get_uuid())
342 del self.managed_domains[dom.get_uuid()]
343 except ValueError:
344 log.warn("Domain is not registered: %s" % dom.get_uuid())
346 def _managed_domain_register(self, dom):
347 self.managed_domains[dom.get_uuid()] = dom
349 def is_domain_managed(self, dom = None):
350 return (dom.get_uuid() in self.managed_domains)
352 # End of Managed Domain Access
353 # --------------------------------------------------------------------
355 def _running_domains(self):
356 """Get table of domains indexed by id from xc.
358 @requires: Expects to be protected by domains_lock.
359 @rtype: list of dicts
360 @return: A list of dicts representing the running domains.
361 """
362 try:
363 return xc.domain_getinfo()
364 except RuntimeError, e:
365 log.exception("Unable to get domain information.")
366 return {}
368 def _setDom0CPUCount(self):
369 """Sets the number of VCPUs dom0 has. Retreived from the
370 Xend configuration, L{XendOptions}.
372 @requires: Expects to be protected by domains_lock.
373 @rtype: None
374 """
375 dom0 = self.privilegedDomain()
377 # get max number of vcpus to use for dom0 from config
378 target = int(xoptions.get_dom0_vcpus())
379 log.debug("number of vcpus to use is %d", target)
381 # target == 0 means use all processors
382 if target > 0:
383 dom0.setVCpuCount(target)
386 def _refresh(self, refresh_shutdown = True):
387 """Refresh the domain list. Needs to be called when
388 either xenstore has changed or when a method requires
389 up to date information (like uptime, cputime stats).
391 Expects to be protected by the domains_lock.
393 @rtype: None
394 """
396 running = self._running_domains()
397 # Add domains that are not already tracked but running in Xen,
398 # and update domain state for those that are running and tracked.
399 for dom in running:
400 domid = dom['domid']
401 if domid in self.domains:
402 self.domains[domid].update(dom, refresh_shutdown)
403 elif domid not in self.domains and dom['dying'] != 1:
404 try:
405 new_dom = XendDomainInfo.recreate(dom, False)
406 except VmError:
407 log.exception("Unable to recreate domain")
408 try:
409 xc.domain_destroy(domid)
410 except:
411 log.exception("Hard destruction of domain failed: %d" %
412 domid)
414 # update information for all running domains
415 # - like cpu_time, status, dying, etc.
416 # remove domains that are not running from active domain list.
417 # The list might have changed by now, because the update call may
418 # cause new domains to be added, if the domain has rebooted. We get
419 # the list again.
420 running = self._running_domains()
421 running_domids = [d['domid'] for d in running if d['dying'] != 1]
422 for domid, dom in self.domains.items():
423 if domid not in running_domids and domid != DOM0_ID:
424 self._remove_domain(dom, domid)
427 def add_domain(self, info):
428 """Add a domain to the list of running domains
430 @requires: Expects to be protected by the domains_lock.
431 @param info: XendDomainInfo of a domain to be added.
432 @type info: XendDomainInfo
433 """
434 log.debug("Adding Domain: %s" % info.getDomid())
435 self.domains[info.getDomid()] = info
437 # update the managed domains with a new XendDomainInfo object
438 # if we are keeping track of it.
439 if info.get_uuid() in self.managed_domains:
440 self._managed_domain_register(info)
442 def remove_domain(self, info, domid = None):
443 """Remove the domain from the list of running domains, taking the
444 domains_lock first.
445 """
446 self.domains_lock.acquire()
447 try:
448 self._remove_domain(info, domid)
449 finally:
450 self.domains_lock.release()
452 def _remove_domain(self, info, domid = None):
453 """Remove the domain from the list of running domains
455 @requires: Expects to be protected by the domains_lock.
456 @param info: XendDomainInfo of a domain to be removed.
457 @type info: XendDomainInfo
458 """
459 if info:
460 if domid == None:
461 domid = info.getDomid()
463 if info._stateGet() != DOM_STATE_HALTED:
464 info.cleanupDomain()
466 if domid in self.domains:
467 del self.domains[domid]
468 else:
469 log.warning("Attempted to remove non-existent domain.")
471 def restore_(self, config):
472 """Create a domain as part of the restore process. This is called
473 only from L{XendCheckpoint}.
475 A restore request comes into XendDomain through L{domain_restore}
476 or L{domain_restore_fd}. That request is
477 forwarded immediately to XendCheckpoint which, when it is ready, will
478 call this method. It is necessary to come through here rather than go
479 directly to L{XendDomainInfo.restore} because we need to
480 serialise the domain creation process, but cannot lock
481 domain_restore_fd as a whole, otherwise we will deadlock waiting for
482 the old domain to die.
484 @param config: Configuration of domain to restore
485 @type config: SXP Object (eg. list of lists)
486 """
487 self.domains_lock.acquire()
488 try:
489 security.refresh_ssidref(config)
490 dominfo = XendDomainInfo.restore(config)
491 return dominfo
492 finally:
493 self.domains_lock.release()
496 def domain_lookup(self, domid):
497 """Look up given I{domid} in the list of managed and running
498 domains.
500 @note: Will cause a refresh before lookup up domains, for
501 a version that does not need to re-read xenstore
502 use L{domain_lookup_nr}.
504 @param domid: Domain ID or Domain Name.
505 @type domid: int or string
506 @return: Found domain.
507 @rtype: XendDomainInfo
508 @raise XendInvalidDomain: If domain is not found.
509 """
510 self.domains_lock.acquire()
511 try:
512 self._refresh(refresh_shutdown = False)
513 dom = self.domain_lookup_nr(domid)
514 if not dom:
515 raise XendInvalidDomain(str(domid))
516 return dom
517 finally:
518 self.domains_lock.release()
521 def domain_lookup_nr(self, domid):
522 """Look up given I{domid} in the list of managed and running
523 domains.
525 @param domid: Domain ID or Domain Name.
526 @type domid: int or string
527 @return: Found domain.
528 @rtype: XendDomainInfo or None
529 """
530 self.domains_lock.acquire()
531 try:
532 # lookup by name
533 match = [dom for dom in self.domains.values() \
534 if dom.getName() == domid]
535 if match:
536 return match[0]
538 match = [dom for dom in self.managed_domains.values() \
539 if dom.getName() == domid]
540 if match:
541 return match[0]
543 # lookup by id
544 try:
545 if int(domid) in self.domains:
546 return self.domains[int(domid)]
547 except ValueError:
548 pass
550 # lookup by uuid for running domains
551 match = [dom for dom in self.domains.values() \
552 if dom.get_uuid() == domid]
553 if match:
554 return match[0]
556 # lookup by uuid for inactive managed domains
557 if domid in self.managed_domains:
558 return self.managed_domains[domid]
560 return None
561 finally:
562 self.domains_lock.release()
564 def privilegedDomain(self):
565 """ Get the XendDomainInfo of a dom0
567 @rtype: XendDomainInfo
568 """
569 self.domains_lock.acquire()
570 try:
571 return self.domains[DOM0_ID]
572 finally:
573 self.domains_lock.release()
575 def autostart_domains(self):
576 """ Autostart managed domains that are marked as such. """
578 need_starting = []
580 self.domains_lock.acquire()
581 try:
582 for dom_uuid, dom in self.managed_domains.items():
583 if dom and dom._stateGet() == DOM_STATE_HALTED:
584 on_xend_start = dom.info.get('on_xend_start', 'ignore')
585 auto_power_on = dom.info.get('auto_power_on', False)
586 should_start = (on_xend_start == 'start') or auto_power_on
587 if should_start:
588 need_starting.append(dom_uuid)
589 finally:
590 self.domains_lock.release()
592 for dom_uuid in need_starting:
593 self.domain_start(dom_uuid, False)
595 def cleanup_domains(self):
596 """Clean up domains that are marked as autostop.
597 Should be called when Xend goes down. This is currently
598 called from L{xen.xend.servers.XMLRPCServer}.
600 """
601 log.debug('cleanup_domains')
602 self.domains_lock.acquire()
603 try:
604 for dom in self.domains.values():
605 if dom.getName() == DOM0_NAME:
606 continue
608 if dom._stateGet() == DOM_STATE_RUNNING:
609 shutdownAction = dom.info.get('on_xend_stop', 'ignore')
610 if shutdownAction == 'shutdown':
611 log.debug('Shutting down domain: %s' % dom.getName())
612 dom.shutdown("poweroff")
613 elif shutdownAction == 'suspend':
614 self.domain_suspend(dom.getName())
615 finally:
616 self.domains_lock.release()
620 # ----------------------------------------------------------------
621 # Xen API
624 def set_allow_new_domains(self, allow_new_domains):
625 self._allow_new_domains = allow_new_domains
627 def allow_new_domains(self):
628 return self._allow_new_domains
630 def get_domain_refs(self):
631 result = []
632 try:
633 self.domains_lock.acquire()
634 result = [d.get_uuid() for d in self.domains.values()]
635 for d in self.managed_domains.keys():
636 if d not in result:
637 result.append(d)
638 return result
639 finally:
640 self.domains_lock.release()
642 def get_all_vms(self):
643 self.domains_lock.acquire()
644 try:
645 result = self.domains.values()
646 result += [x for x in self.managed_domains.values() if
647 x not in result]
648 return result
649 finally:
650 self.domains_lock.release()
652 def get_vm_by_uuid(self, vm_uuid):
653 self.domains_lock.acquire()
654 try:
655 for dom in self.domains.values():
656 if dom.get_uuid() == vm_uuid:
657 return dom
659 if vm_uuid in self.managed_domains:
660 return self.managed_domains[vm_uuid]
662 return None
663 finally:
664 self.domains_lock.release()
666 def get_vm_with_dev_uuid(self, klass, dev_uuid):
667 self.domains_lock.acquire()
668 try:
669 for dom in self.domains.values() + self.managed_domains.values():
670 if dom.has_device(klass, dev_uuid):
671 return dom
672 return None
673 finally:
674 self.domains_lock.release()
676 def get_dev_property_by_uuid(self, klass, dev_uuid, field):
677 value = None
678 self.domains_lock.acquire()
680 try:
681 try:
682 dom = self.get_vm_with_dev_uuid(klass, dev_uuid)
683 if dom:
684 value = dom.get_dev_property(klass, dev_uuid, field)
685 except ValueError, e:
686 pass
687 finally:
688 self.domains_lock.release()
690 return value
692 def is_valid_vm(self, vm_ref):
693 return (self.get_vm_by_uuid(vm_ref) != None)
695 def is_valid_dev(self, klass, dev_uuid):
696 return (self.get_vm_with_dev_uuid(klass, dev_uuid) != None)
698 def do_legacy_api_with_uuid(self, fn, vm_uuid, *args, **kwargs):
699 dom = self.uuid_to_dom(vm_uuid)
700 fn(dom, *args, **kwargs)
702 def uuid_to_dom(self, vm_uuid):
703 self.domains_lock.acquire()
704 try:
705 for domid, dom in self.domains.items():
706 if dom.get_uuid() == vm_uuid:
707 return domid
709 if vm_uuid in self.managed_domains:
710 domid = self.managed_domains[vm_uuid].getDomid()
711 if domid is None:
712 return self.managed_domains[vm_uuid].getName()
713 else:
714 return domid
716 raise XendInvalidDomain(vm_uuid)
717 finally:
718 self.domains_lock.release()
721 def create_domain(self, xenapi_vm):
722 self.domains_lock.acquire()
723 try:
724 try:
725 xeninfo = XendConfig.XendConfig(xapi = xenapi_vm)
726 dominfo = XendDomainInfo.createDormant(xeninfo)
727 log.debug("Creating new managed domain: %s: %s" %
728 (dominfo.getName(), dominfo.get_uuid()))
729 self._managed_domain_register(dominfo)
730 self.managed_config_save(dominfo)
731 return dominfo.get_uuid()
732 except XendError, e:
733 raise
734 except Exception, e:
735 raise XendError(str(e))
736 finally:
737 self.domains_lock.release()
739 def rename_domain(self, dom, new_name):
740 self.domains_lock.acquire()
741 try:
742 old_name = dom.getName()
743 dom.setName(new_name)
745 finally:
746 self.domains_lock.release()
749 #
750 # End of Xen API
751 # ----------------------------------------------------------------
753 # ------------------------------------------------------------
754 # Xen Legacy API
756 def list(self, state = DOM_STATE_RUNNING):
757 """Get list of domain objects.
759 @param: the state in which the VMs should be -- one of the
760 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
761 @return: domains
762 @rtype: list of XendDomainInfo
763 """
764 if type(state) == int:
765 state = POWER_STATE_NAMES[state]
766 state = state.lower()
768 self.domains_lock.acquire()
769 try:
770 self._refresh(refresh_shutdown = False)
772 # active domains
773 active_domains = self.domains.values()
774 active_uuids = [d.get_uuid() for d in active_domains]
776 # inactive domains
777 inactive_domains = []
778 for dom_uuid, dom in self.managed_domains.items():
779 if dom_uuid not in active_uuids:
780 inactive_domains.append(dom)
782 if state == POWER_STATE_ALL:
783 return active_domains + inactive_domains
784 else:
785 return filter(lambda x:
786 POWER_STATE_NAMES[x._stateGet()].lower() == state,
787 active_domains + inactive_domains)
788 finally:
789 self.domains_lock.release()
792 def list_sorted(self, state = DOM_STATE_RUNNING):
793 """Get list of domain objects, sorted by name.
795 @param: the state in which the VMs should be -- one of the
796 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
797 @return: domain objects
798 @rtype: list of XendDomainInfo
799 """
800 doms = self.list(state)
801 doms.sort(lambda x, y: cmp(x.getName(), y.getName()))
802 return doms
804 def list_names(self, state = DOM_STATE_RUNNING):
805 """Get list of domain names.
807 @param: the state in which the VMs should be -- one of the
808 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
809 @return: domain names
810 @rtype: list of strings.
811 """
812 return [d.getName() for d in self.list_sorted(state)]
814 def domain_suspend(self, domname):
815 """Suspends a domain that is persistently managed by Xend
817 @param domname: Domain Name
818 @type domname: string
819 @rtype: None
820 @raise XendError: Failure during checkpointing.
821 """
823 try:
824 dominfo = self.domain_lookup_nr(domname)
825 if not dominfo:
826 raise XendInvalidDomain(domname)
828 if dominfo.getDomid() == DOM0_ID:
829 raise XendError("Cannot save privileged domain %s" % domname)
831 if dominfo._stateGet() != DOM_STATE_RUNNING:
832 raise VMBadState("Domain is not running",
833 POWER_STATE_NAMES[DOM_STATE_RUNNING],
834 POWER_STATE_NAMES[dominfo._stateGet()])
836 dom_uuid = dominfo.get_uuid()
838 if not os.path.exists(self._managed_config_path(dom_uuid)):
839 raise XendError("Domain is not managed by Xend lifecycle " +
840 "support.")
842 path = self._managed_check_point_path(dom_uuid)
843 oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
844 if hasattr(os, "O_LARGEFILE"):
845 oflags |= os.O_LARGEFILE
846 fd = os.open(path, oflags)
847 try:
848 # For now we don't support 'live checkpoint'
849 XendCheckpoint.save(fd, dominfo, False, False, path)
850 finally:
851 os.close(fd)
852 except OSError, ex:
853 raise XendError("can't write guest state file %s: %s" %
854 (path, ex[1]))
856 def domain_resume(self, domname, start_paused = False):
857 """Resumes a domain that is persistently managed by Xend.
859 @param domname: Domain Name
860 @type domname: string
861 @rtype: None
862 @raise XendError: If failed to restore.
863 """
864 self.domains_lock.acquire()
865 try:
866 try:
867 dominfo = self.domain_lookup_nr(domname)
869 if not dominfo:
870 raise XendInvalidDomain(domname)
872 if dominfo.getDomid() == DOM0_ID:
873 raise XendError("Cannot save privileged domain %s" % domname)
875 if dominfo._stateGet() != XEN_API_VM_POWER_STATE_SUSPENDED:
876 raise XendError("Cannot resume domain that is not suspended.")
878 dom_uuid = dominfo.get_uuid()
879 chkpath = self._managed_check_point_path(dom_uuid)
880 if not os.path.exists(chkpath):
881 raise XendError("Domain was not suspended by Xend")
883 # Restore that replaces the existing XendDomainInfo
884 try:
885 log.debug('Current DomainInfo state: %d' % dominfo._stateGet())
886 oflags = os.O_RDONLY
887 if hasattr(os, "O_LARGEFILE"):
888 oflags |= os.O_LARGEFILE
889 XendCheckpoint.restore(self,
890 os.open(chkpath, oflags),
891 dominfo,
892 paused = start_paused)
893 os.unlink(chkpath)
894 except OSError, ex:
895 raise XendError("Failed to read stored checkpoint file")
896 except IOError, ex:
897 raise XendError("Failed to delete checkpoint file")
898 except Exception, ex:
899 log.exception("Exception occurred when resuming")
900 raise XendError("Error occurred when resuming: %s" % str(ex))
901 finally:
902 self.domains_lock.release()
905 def domain_create(self, config):
906 """Create a domain from a configuration.
908 @param config: configuration
909 @type config: SXP Object (list of lists)
910 @rtype: XendDomainInfo
911 """
912 self.domains_lock.acquire()
913 try:
914 self._refresh()
916 dominfo = XendDomainInfo.create(config)
917 return dominfo
918 finally:
919 self.domains_lock.release()
922 def domain_create_from_dict(self, config_dict):
923 """Create a domain from a configuration dictionary.
925 @param config_dict: configuration
926 @rtype: XendDomainInfo
927 """
928 self.domains_lock.acquire()
929 try:
930 self._refresh()
932 dominfo = XendDomainInfo.create_from_dict(config_dict)
933 return dominfo
934 finally:
935 self.domains_lock.release()
938 def domain_new(self, config):
939 """Create a domain from a configuration but do not start it.
941 @param config: configuration
942 @type config: SXP Object (list of lists)
943 @rtype: XendDomainInfo
944 """
945 self.domains_lock.acquire()
946 try:
947 try:
948 domconfig = XendConfig.XendConfig(sxp_obj = config)
949 dominfo = XendDomainInfo.createDormant(domconfig)
950 log.debug("Creating new managed domain: %s" %
951 dominfo.getName())
952 self._managed_domain_register(dominfo)
953 self.managed_config_save(dominfo)
954 # no return value because it isn't meaningful for client
955 except XendError, e:
956 raise
957 except Exception, e:
958 raise XendError(str(e))
959 finally:
960 self.domains_lock.release()
962 def domain_start(self, domid, start_paused = True):
963 """Start a managed domain
965 @require: Domain must not be running.
966 @param domid: Domain name or domain ID.
967 @type domid: string or int
968 @rtype: None
969 @raise XendError: If domain is still running
970 @rtype: None
971 """
972 self.domains_lock.acquire()
973 try:
974 self._refresh()
976 dominfo = self.domain_lookup_nr(domid)
977 if not dominfo:
978 raise XendInvalidDomain(str(domid))
980 if dominfo._stateGet() != DOM_STATE_HALTED:
981 raise VMBadState("Domain is already running",
982 POWER_STATE_NAMES[DOM_STATE_HALTED],
983 POWER_STATE_NAMES[dominfo._stateGet()])
985 dominfo.start(is_managed = True)
986 finally:
987 self.domains_lock.release()
989 try:
990 dominfo.waitForDevices()
991 except Exception, ex:
992 log.warn("Failed to setup devices for " + str(dominfo) + ": " + str(ex))
993 dominfo.destroy()
994 raise
996 if not start_paused:
997 dominfo.unpause()
999 def domain_delete(self, domid):
1000 """Remove a managed domain from database
1002 @require: Domain must not be running.
1003 @param domid: Domain name or domain ID.
1004 @type domid: string or int
1005 @rtype: None
1006 @raise XendError: If domain is still running
1007 """
1008 self.domains_lock.acquire()
1009 try:
1010 try:
1011 dominfo = self.domain_lookup_nr(domid)
1012 if not dominfo:
1013 raise XendInvalidDomain(str(domid))
1015 if dominfo._stateGet() != XEN_API_VM_POWER_STATE_HALTED:
1016 raise VMBadState("Domain is not halted.",
1017 POWER_STATE_NAMES[DOM_STATE_HALTED],
1018 POWER_STATE_NAMES[dominfo._stateGet()])
1020 self._domain_delete_by_info(dominfo)
1021 except Exception, ex:
1022 raise XendError(str(ex))
1023 finally:
1024 self.domains_lock.release()
1027 def domain_delete_by_dominfo(self, dominfo):
1028 """Only for use by XendDomainInfo.
1029 """
1030 self.domains_lock.acquire()
1031 try:
1032 self._domain_delete_by_info(dominfo)
1033 finally:
1034 self.domains_lock.release()
1037 def _domain_delete_by_info(self, dominfo):
1038 """Expects to be protected by domains_lock.
1039 """
1040 log.info("Domain %s (%s) deleted." %
1041 (dominfo.getName(), dominfo.info.get('uuid')))
1043 self._managed_domain_unregister(dominfo)
1044 self._remove_domain(dominfo)
1045 XendDevices.destroy_device_state(dominfo)
1048 def domain_configure(self, config):
1049 """Configure an existing domain.
1051 @param vmconfig: vm configuration
1052 @type vmconfig: SXP Object (list of lists)
1053 @todo: Not implemented
1054 """
1055 # !!!
1056 raise XendError("Unsupported")
1058 def domain_restore(self, src, paused=False):
1059 """Restore a domain from file.
1061 @param src: filename of checkpoint file to restore from
1062 @type src: string
1063 @return: Restored domain
1064 @rtype: XendDomainInfo
1065 @raise XendError: Failure to restore domain
1066 """
1067 try:
1068 oflags = os.O_RDONLY
1069 if hasattr(os, "O_LARGEFILE"):
1070 oflags |= os.O_LARGEFILE
1071 fd = os.open(src, oflags)
1072 try:
1073 return self.domain_restore_fd(fd, paused=paused)
1074 finally:
1075 os.close(fd)
1076 except OSError, ex:
1077 raise XendError("can't read guest state file %s: %s" %
1078 (src, ex[1]))
1080 def domain_restore_fd(self, fd, paused=False):
1081 """Restore a domain from the given file descriptor.
1083 @param fd: file descriptor of the checkpoint file
1084 @type fd: File object
1085 @rtype: XendDomainInfo
1086 @raise XendError: if failed to restore
1087 """
1089 try:
1090 return XendCheckpoint.restore(self, fd, paused=paused)
1091 except XendError, e:
1092 log.exception("Restore failed")
1093 raise
1094 except:
1095 # I don't really want to log this exception here, but the error
1096 # handling in the relocation-socket handling code (relocate.py) is
1097 # poor, so we need to log this for debugging.
1098 log.exception("Restore failed")
1099 raise XendError("Restore failed")
1101 def domain_unpause(self, domid):
1102 """Unpause domain execution.
1104 @param domid: Domain ID or Name
1105 @type domid: int or string.
1106 @rtype: None
1107 @raise XendError: Failed to unpause
1108 @raise XendInvalidDomain: Domain is not valid
1109 """
1110 try:
1111 dominfo = self.domain_lookup_nr(domid)
1112 if not dominfo:
1113 raise XendInvalidDomain(str(domid))
1114 if dominfo.getDomid() == DOM0_ID:
1115 raise XendError("Cannot unpause privileged domain %s" % domid)
1116 log.info("Domain %s (%d) unpaused.", dominfo.getName(),
1117 int(dominfo.getDomid()))
1118 dominfo.unpause()
1119 except XendInvalidDomain:
1120 log.exception("domain_unpause")
1121 raise
1122 except Exception, ex:
1123 log.exception("domain_unpause")
1124 raise XendError(str(ex))
1126 def domain_pause(self, domid):
1127 """Pause domain execution.
1129 @param domid: Domain ID or Name
1130 @type domid: int or string.
1131 @rtype: None
1132 @raise XendError: Failed to pause
1133 @raise XendInvalidDomain: Domain is not valid
1134 """
1135 try:
1136 dominfo = self.domain_lookup_nr(domid)
1137 if not dominfo:
1138 raise XendInvalidDomain(str(domid))
1139 if dominfo.getDomid() == DOM0_ID:
1140 raise XendError("Cannot pause privileged domain %s" % domid)
1141 log.info("Domain %s (%d) paused.", dominfo.getName(),
1142 int(dominfo.getDomid()))
1143 dominfo.pause()
1144 except XendInvalidDomain:
1145 log.exception("domain_pause")
1146 raise
1147 except Exception, ex:
1148 log.exception("domain_pause")
1149 raise XendError(str(ex))
1151 def domain_dump(self, domid, filename, live, crash):
1152 """Dump domain core."""
1154 dominfo = self.domain_lookup_nr(domid)
1155 if not dominfo:
1156 raise XendInvalidDomain(str(domid))
1158 if dominfo.getDomid() == DOM0_ID:
1159 raise XendError("Cannot dump core for privileged domain %s" % domid)
1161 try:
1162 log.info("Domain core dump requested for domain %s (%d) "
1163 "live=%d crash=%d.",
1164 dominfo.getName(), dominfo.getDomid(), live, crash)
1165 return dominfo.dumpCore(filename)
1166 except Exception, ex:
1167 raise XendError(str(ex))
1169 def domain_destroy(self, domid):
1170 """Terminate domain immediately.
1172 @param domid: Domain ID or Name
1173 @type domid: int or string.
1174 @rtype: None
1175 @raise XendError: Failed to destroy
1176 @raise XendInvalidDomain: Domain is not valid
1177 """
1179 dominfo = self.domain_lookup_nr(domid)
1180 if dominfo and dominfo.getDomid() == DOM0_ID:
1181 raise XendError("Cannot destroy privileged domain %s" % domid)
1183 if dominfo:
1184 val = dominfo.destroy()
1185 else:
1186 try:
1187 val = xc.domain_destroy(int(domid))
1188 except ValueError:
1189 raise XendInvalidDomain(domid)
1190 except Exception, e:
1191 raise XendError(str(e))
1193 return val
1195 def domain_migrate(self, domid, dst, live=False, resource=0, port=0):
1196 """Start domain migration.
1198 @param domid: Domain ID or Name
1199 @type domid: int or string.
1200 @param dst: Destination IP address
1201 @type dst: string
1202 @keyword port: relocation port on destination
1203 @type port: int
1204 @keyword live: Live migration
1205 @type live: bool
1206 @keyword resource: not used??
1207 @rtype: None
1208 @raise XendError: Failed to migrate
1209 @raise XendInvalidDomain: Domain is not valid
1210 """
1212 dominfo = self.domain_lookup_nr(domid)
1213 if not dominfo:
1214 raise XendInvalidDomain(str(domid))
1216 if dominfo.getDomid() == DOM0_ID:
1217 raise XendError("Cannot migrate privileged domain %s" % domid)
1219 """ The following call may raise a XendError exception """
1220 dominfo.testMigrateDevices(True, dst)
1222 if live:
1223 """ Make sure there's memory free for enabling shadow mode """
1224 dominfo.checkLiveMigrateMemory()
1226 if port == 0:
1227 port = xoptions.get_xend_relocation_port()
1228 try:
1229 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1230 sock.connect((dst, port))
1231 except socket.error, err:
1232 raise XendError("can't connect: %s" % err[1])
1234 sock.send("receive\n")
1235 sock.recv(80)
1236 XendCheckpoint.save(sock.fileno(), dominfo, True, live, dst)
1237 sock.close()
1239 def domain_save(self, domid, dst, checkpoint=False):
1240 """Start saving a domain to file.
1242 @param domid: Domain ID or Name
1243 @type domid: int or string.
1244 @param dst: Destination filename
1245 @type dst: string
1246 @rtype: None
1247 @raise XendError: Failed to save domain
1248 @raise XendInvalidDomain: Domain is not valid
1249 """
1250 try:
1251 dominfo = self.domain_lookup_nr(domid)
1252 if not dominfo:
1253 raise XendInvalidDomain(str(domid))
1255 if dominfo.getDomid() == DOM0_ID:
1256 raise XendError("Cannot save privileged domain %s" % str(domid))
1257 if dominfo._stateGet() != DOM_STATE_RUNNING:
1258 raise VMBadState("Domain is not running",
1259 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1260 POWER_STATE_NAMES[dominfo._stateGet()])
1262 oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
1263 if hasattr(os, "O_LARGEFILE"):
1264 oflags |= os.O_LARGEFILE
1265 fd = os.open(dst, oflags)
1266 try:
1267 XendCheckpoint.save(fd, dominfo, False, False, dst,
1268 checkpoint=checkpoint)
1269 except Exception, e:
1270 os.close(fd)
1271 raise e
1272 os.close(fd)
1273 except OSError, ex:
1274 raise XendError("can't write guest state file %s: %s" %
1275 (dst, ex[1]))
1277 def domain_pincpu(self, domid, vcpu, cpumap):
1278 """Set which cpus vcpu can use
1280 @param domid: Domain ID or Name
1281 @type domid: int or string.
1282 @param vcpu: vcpu to pin to
1283 @type vcpu: int
1284 @param cpumap: string repr of usable cpus
1285 @type cpumap: string
1286 @rtype: 0
1287 """
1288 dominfo = self.domain_lookup_nr(domid)
1289 if not dominfo:
1290 raise XendInvalidDomain(str(domid))
1292 # if vcpu is keyword 'all', apply the cpumap to all vcpus
1293 vcpus = [ vcpu ]
1294 if str(vcpu).lower() == "all":
1295 vcpus = range(0, int(dominfo.getVCpuCount()))
1297 # set the same cpumask for all vcpus
1298 rc = 0
1299 for v in vcpus:
1300 try:
1301 rc = xc.vcpu_setaffinity(dominfo.getDomid(), int(v), cpumap)
1302 except Exception, ex:
1303 log.exception(ex)
1304 raise XendError("Cannot pin vcpu: %s to cpu: %s - %s" % \
1305 (v, cpumap, str(ex)))
1306 return rc
1308 def domain_cpu_sedf_set(self, domid, period, slice_, latency, extratime,
1309 weight):
1310 """Set Simple EDF scheduler parameters for a domain.
1312 @param domid: Domain ID or Name
1313 @type domid: int or string.
1314 @rtype: 0
1315 """
1316 dominfo = self.domain_lookup_nr(domid)
1317 if not dominfo:
1318 raise XendInvalidDomain(str(domid))
1319 try:
1320 return xc.sedf_domain_set(dominfo.getDomid(), period, slice_,
1321 latency, extratime, weight)
1322 except Exception, ex:
1323 raise XendError(str(ex))
1325 def domain_cpu_sedf_get(self, domid):
1326 """Get Simple EDF scheduler parameters for a domain.
1328 @param domid: Domain ID or Name
1329 @type domid: int or string.
1330 @rtype: SXP object
1331 @return: The parameters for Simple EDF schedule for a domain.
1332 """
1333 dominfo = self.domain_lookup_nr(domid)
1334 if not dominfo:
1335 raise XendInvalidDomain(str(domid))
1336 try:
1337 sedf_info = xc.sedf_domain_get(dominfo.getDomid())
1338 # return sxpr
1339 return ['sedf',
1340 ['domid', sedf_info['domid']],
1341 ['period', sedf_info['period']],
1342 ['slice', sedf_info['slice']],
1343 ['latency', sedf_info['latency']],
1344 ['extratime', sedf_info['extratime']],
1345 ['weight', sedf_info['weight']]]
1347 except Exception, ex:
1348 raise XendError(str(ex))
1350 def domain_shadow_control(self, domid, op):
1351 """Shadow page control.
1353 @param domid: Domain ID or Name
1354 @type domid: int or string.
1355 @param op: operation
1356 @type op: int
1357 @rtype: 0
1358 """
1359 dominfo = self.domain_lookup(domid)
1360 try:
1361 return xc.shadow_control(dominfo.getDomid(), op)
1362 except Exception, ex:
1363 raise XendError(str(ex))
1365 def domain_shadow_mem_get(self, domid):
1366 """Get shadow pagetable memory allocation.
1368 @param domid: Domain ID or Name
1369 @type domid: int or string.
1370 @rtype: int
1371 @return: shadow memory in MB
1372 """
1373 dominfo = self.domain_lookup(domid)
1374 try:
1375 return xc.shadow_mem_control(dominfo.getDomid())
1376 except Exception, ex:
1377 raise XendError(str(ex))
1379 def domain_shadow_mem_set(self, domid, mb):
1380 """Set shadow pagetable memory allocation.
1382 @param domid: Domain ID or Name
1383 @type domid: int or string.
1384 @param mb: shadow memory to set in MB
1385 @type: mb: int
1386 @rtype: int
1387 @return: shadow memory in MB
1388 """
1389 dominfo = self.domain_lookup(domid)
1390 try:
1391 return xc.shadow_mem_control(dominfo.getDomid(), mb=mb)
1392 except Exception, ex:
1393 raise XendError(str(ex))
1395 def domain_sched_credit_get(self, domid):
1396 """Get credit scheduler parameters for a domain.
1398 @param domid: Domain ID or Name
1399 @type domid: int or string.
1400 @rtype: dict with keys 'weight' and 'cap'
1401 @return: credit scheduler parameters
1402 """
1403 dominfo = self.domain_lookup_nr(domid)
1404 if not dominfo:
1405 raise XendInvalidDomain(str(domid))
1407 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1408 try:
1409 return xc.sched_credit_domain_get(dominfo.getDomid())
1410 except Exception, ex:
1411 raise XendError(str(ex))
1412 else:
1413 return {'weight' : dominfo.getWeight(),
1414 'cap' : dominfo.getCap()}
1416 def domain_sched_credit_set(self, domid, weight = None, cap = None):
1417 """Set credit scheduler parameters for a domain.
1419 @param domid: Domain ID or Name
1420 @type domid: int or string.
1421 @type weight: int
1422 @type cap: int
1423 @rtype: 0
1424 """
1425 set_weight = False
1426 set_cap = False
1427 dominfo = self.domain_lookup_nr(domid)
1428 if not dominfo:
1429 raise XendInvalidDomain(str(domid))
1430 try:
1431 if weight is None:
1432 weight = int(0)
1433 elif weight < 1 or weight > 65535:
1434 raise XendError("weight is out of range")
1435 else:
1436 set_weight = True
1438 if cap is None:
1439 cap = int(~0)
1440 elif cap < 0 or cap > dominfo.getVCpuCount() * 100:
1441 raise XendError("cap is out of range")
1442 else:
1443 set_cap = True
1445 assert type(weight) == int
1446 assert type(cap) == int
1448 rc = 0
1449 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1450 rc = xc.sched_credit_domain_set(dominfo.getDomid(), weight, cap)
1451 if rc == 0:
1452 if set_weight:
1453 dominfo.setWeight(weight)
1454 if set_cap:
1455 dominfo.setCap(cap)
1456 self.managed_config_save(dominfo)
1457 return rc
1458 except Exception, ex:
1459 log.exception(ex)
1460 raise XendError(str(ex))
1462 def domain_maxmem_set(self, domid, mem):
1463 """Set the memory limit for a domain.
1465 @param domid: Domain ID or Name
1466 @type domid: int or string.
1467 @param mem: memory limit (in MiB)
1468 @type mem: int
1469 @raise XendError: fail to set memory
1470 @rtype: 0
1471 """
1472 dominfo = self.domain_lookup_nr(domid)
1473 if not dominfo:
1474 raise XendInvalidDomain(str(domid))
1475 dominfo.setMemoryMaximum(mem)
1477 def domain_ioport_range_enable(self, domid, first, last):
1478 """Enable access to a range of IO ports for a domain
1480 @param first: first IO port
1481 @param last: last IO port
1482 @raise XendError: failed to set range
1483 @rtype: 0
1484 """
1485 dominfo = self.domain_lookup_nr(domid)
1486 if not dominfo:
1487 raise XendInvalidDomain(str(domid))
1488 nr_ports = last - first + 1
1489 try:
1490 return xc.domain_ioport_permission(dominfo.getDomid(),
1491 first_port = first,
1492 nr_ports = nr_ports,
1493 allow_access = 1)
1494 except Exception, ex:
1495 raise XendError(str(ex))
1497 def domain_ioport_range_disable(self, domid, first, last):
1498 """Disable access to a range of IO ports for a domain
1500 @param first: first IO port
1501 @param last: last IO port
1502 @raise XendError: failed to set range
1503 @rtype: 0
1504 """
1505 dominfo = self.domain_lookup_nr(domid)
1506 if not dominfo:
1507 raise XendInvalidDomain(str(domid))
1508 nr_ports = last - first + 1
1509 try:
1510 return xc.domain_ioport_permission(dominfo.getDomid(),
1511 first_port = first,
1512 nr_ports = nr_ports,
1513 allow_access = 0)
1514 except Exception, ex:
1515 raise XendError(str(ex))
1517 def domain_send_trigger(self, domid, trigger_name, vcpu = 0):
1518 """Send trigger to a domain.
1520 @param domid: Domain ID or Name
1521 @type domid: int or string.
1522 @param trigger_name: trigger type name
1523 @type trigger_name: string
1524 @param vcpu: VCPU to send trigger (default is 0)
1525 @type vcpu: int
1526 @raise XendError: failed to send trigger
1527 @raise XendInvalidDomain: Domain is not valid
1528 @rtype: 0
1529 """
1530 dominfo = self.domain_lookup_nr(domid)
1531 if not dominfo:
1532 raise XendInvalidDomain(str(domid))
1533 if trigger_name.lower() in TRIGGER_TYPE:
1534 trigger = TRIGGER_TYPE[trigger_name.lower()]
1535 else:
1536 raise XendError("Invalid trigger: %s", trigger_name)
1537 try:
1538 return xc.domain_send_trigger(dominfo.getDomid(),
1539 trigger,
1540 vcpu)
1541 except Exception, ex:
1542 raise XendError(str(ex))
1545 def instance():
1546 """Singleton constructor. Use this instead of the class constructor.
1547 """
1548 global inst
1549 try:
1550 inst
1551 except:
1552 inst = XendDomain()
1553 inst.init()
1554 return inst