direct-io.hg

view tools/python/xen/xend/XendDomain.py @ 15519:80099a459d7a

xend: Fix xm pause/unpause for inactive managed domains.
Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author kfraser@localhost.localdomain
date Tue Jul 10 10:15:01 2007 +0100 (2007-07-10)
parents aa640601575f
children
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
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 dominfo = XendDomainInfo.restore(config)
490 return dominfo
491 finally:
492 self.domains_lock.release()
495 def domain_lookup(self, domid):
496 """Look up given I{domid} in the list of managed and running
497 domains.
499 @note: Will cause a refresh before lookup up domains, for
500 a version that does not need to re-read xenstore
501 use L{domain_lookup_nr}.
503 @param domid: Domain ID or Domain Name.
504 @type domid: int or string
505 @return: Found domain.
506 @rtype: XendDomainInfo
507 @raise XendInvalidDomain: If domain is not found.
508 """
509 self.domains_lock.acquire()
510 try:
511 self._refresh(refresh_shutdown = False)
512 dom = self.domain_lookup_nr(domid)
513 if not dom:
514 raise XendInvalidDomain(str(domid))
515 return dom
516 finally:
517 self.domains_lock.release()
520 def domain_lookup_nr(self, domid):
521 """Look up given I{domid} in the list of managed and running
522 domains.
524 @param domid: Domain ID or Domain Name.
525 @type domid: int or string
526 @return: Found domain.
527 @rtype: XendDomainInfo or None
528 """
529 self.domains_lock.acquire()
530 try:
531 # lookup by name
532 match = [dom for dom in self.domains.values() \
533 if dom.getName() == domid]
534 if match:
535 return match[0]
537 match = [dom for dom in self.managed_domains.values() \
538 if dom.getName() == domid]
539 if match:
540 return match[0]
542 # lookup by id
543 try:
544 if int(domid) in self.domains:
545 return self.domains[int(domid)]
546 except ValueError:
547 pass
549 # lookup by uuid for running domains
550 match = [dom for dom in self.domains.values() \
551 if dom.get_uuid() == domid]
552 if match:
553 return match[0]
555 # lookup by uuid for inactive managed domains
556 if domid in self.managed_domains:
557 return self.managed_domains[domid]
559 return None
560 finally:
561 self.domains_lock.release()
563 def privilegedDomain(self):
564 """ Get the XendDomainInfo of a dom0
566 @rtype: XendDomainInfo
567 """
568 self.domains_lock.acquire()
569 try:
570 return self.domains[DOM0_ID]
571 finally:
572 self.domains_lock.release()
574 def autostart_domains(self):
575 """ Autostart managed domains that are marked as such. """
577 need_starting = []
579 self.domains_lock.acquire()
580 try:
581 for dom_uuid, dom in self.managed_domains.items():
582 if dom and dom._stateGet() == DOM_STATE_HALTED:
583 on_xend_start = dom.info.get('on_xend_start', 'ignore')
584 auto_power_on = dom.info.get('auto_power_on', False)
585 should_start = (on_xend_start == 'start') or auto_power_on
586 if should_start:
587 need_starting.append(dom_uuid)
588 finally:
589 self.domains_lock.release()
591 for dom_uuid in need_starting:
592 self.domain_start(dom_uuid, False)
594 def cleanup_domains(self):
595 """Clean up domains that are marked as autostop.
596 Should be called when Xend goes down. This is currently
597 called from L{xen.xend.servers.XMLRPCServer}.
599 """
600 log.debug('cleanup_domains')
601 self.domains_lock.acquire()
602 try:
603 for dom in self.domains.values():
604 if dom.getName() == DOM0_NAME:
605 continue
607 if dom._stateGet() == DOM_STATE_RUNNING:
608 shutdownAction = dom.info.get('on_xend_stop', 'ignore')
609 if shutdownAction == 'shutdown':
610 log.debug('Shutting down domain: %s' % dom.getName())
611 dom.shutdown("poweroff")
612 elif shutdownAction == 'suspend':
613 self.domain_suspend(dom.getName())
614 finally:
615 self.domains_lock.release()
619 # ----------------------------------------------------------------
620 # Xen API
623 def set_allow_new_domains(self, allow_new_domains):
624 self._allow_new_domains = allow_new_domains
626 def allow_new_domains(self):
627 return self._allow_new_domains
629 def get_domain_refs(self):
630 result = []
631 try:
632 self.domains_lock.acquire()
633 result = [d.get_uuid() for d in self.domains.values()]
634 for d in self.managed_domains.keys():
635 if d not in result:
636 result.append(d)
637 return result
638 finally:
639 self.domains_lock.release()
641 def get_all_vms(self):
642 self.domains_lock.acquire()
643 try:
644 result = self.domains.values()
645 result += [x for x in self.managed_domains.values() if
646 x not in result]
647 return result
648 finally:
649 self.domains_lock.release()
651 def get_vm_by_uuid(self, vm_uuid):
652 self.domains_lock.acquire()
653 try:
654 for dom in self.domains.values():
655 if dom.get_uuid() == vm_uuid:
656 return dom
658 if vm_uuid in self.managed_domains:
659 return self.managed_domains[vm_uuid]
661 return None
662 finally:
663 self.domains_lock.release()
665 def get_vm_with_dev_uuid(self, klass, dev_uuid):
666 self.domains_lock.acquire()
667 try:
668 for dom in self.domains.values() + self.managed_domains.values():
669 if dom.has_device(klass, dev_uuid):
670 return dom
671 return None
672 finally:
673 self.domains_lock.release()
675 def get_dev_property_by_uuid(self, klass, dev_uuid, field):
676 value = None
677 self.domains_lock.acquire()
679 try:
680 try:
681 dom = self.get_vm_with_dev_uuid(klass, dev_uuid)
682 if dom:
683 value = dom.get_dev_property(klass, dev_uuid, field)
684 except ValueError, e:
685 pass
686 finally:
687 self.domains_lock.release()
689 return value
691 def is_valid_vm(self, vm_ref):
692 return (self.get_vm_by_uuid(vm_ref) != None)
694 def is_valid_dev(self, klass, dev_uuid):
695 return (self.get_vm_with_dev_uuid(klass, dev_uuid) != None)
697 def do_legacy_api_with_uuid(self, fn, vm_uuid, *args, **kwargs):
698 dom = self.uuid_to_dom(vm_uuid)
699 fn(dom, *args, **kwargs)
701 def uuid_to_dom(self, vm_uuid):
702 self.domains_lock.acquire()
703 try:
704 for domid, dom in self.domains.items():
705 if dom.get_uuid() == vm_uuid:
706 return domid
708 if vm_uuid in self.managed_domains:
709 domid = self.managed_domains[vm_uuid].getDomid()
710 if domid is None:
711 return self.managed_domains[vm_uuid].getName()
712 else:
713 return domid
715 raise XendInvalidDomain(vm_uuid)
716 finally:
717 self.domains_lock.release()
720 def create_domain(self, xenapi_vm):
721 self.domains_lock.acquire()
722 try:
723 try:
724 xeninfo = XendConfig.XendConfig(xapi = xenapi_vm)
725 dominfo = XendDomainInfo.createDormant(xeninfo)
726 log.debug("Creating new managed domain: %s: %s" %
727 (dominfo.getName(), dominfo.get_uuid()))
728 self._managed_domain_register(dominfo)
729 self.managed_config_save(dominfo)
730 return dominfo.get_uuid()
731 except XendError, e:
732 raise
733 except Exception, e:
734 raise XendError(str(e))
735 finally:
736 self.domains_lock.release()
738 def rename_domain(self, dom, new_name):
739 self.domains_lock.acquire()
740 try:
741 old_name = dom.getName()
742 dom.setName(new_name)
744 finally:
745 self.domains_lock.release()
748 #
749 # End of Xen API
750 # ----------------------------------------------------------------
752 # ------------------------------------------------------------
753 # Xen Legacy API
755 def list(self, state = DOM_STATE_RUNNING):
756 """Get list of domain objects.
758 @param: the state in which the VMs should be -- one of the
759 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
760 @return: domains
761 @rtype: list of XendDomainInfo
762 """
763 if type(state) == int:
764 state = POWER_STATE_NAMES[state]
765 state = state.lower()
767 self.domains_lock.acquire()
768 try:
769 self._refresh(refresh_shutdown = False)
771 # active domains
772 active_domains = self.domains.values()
773 active_uuids = [d.get_uuid() for d in active_domains]
775 # inactive domains
776 inactive_domains = []
777 for dom_uuid, dom in self.managed_domains.items():
778 if dom_uuid not in active_uuids:
779 inactive_domains.append(dom)
781 if state == POWER_STATE_ALL:
782 return active_domains + inactive_domains
783 else:
784 return filter(lambda x:
785 POWER_STATE_NAMES[x._stateGet()].lower() == state,
786 active_domains + inactive_domains)
787 finally:
788 self.domains_lock.release()
791 def list_sorted(self, state = DOM_STATE_RUNNING):
792 """Get list of domain objects, sorted by name.
794 @param: the state in which the VMs should be -- one of the
795 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
796 @return: domain objects
797 @rtype: list of XendDomainInfo
798 """
799 doms = self.list(state)
800 doms.sort(lambda x, y: cmp(x.getName(), y.getName()))
801 return doms
803 def list_names(self, state = DOM_STATE_RUNNING):
804 """Get list of domain names.
806 @param: the state in which the VMs should be -- one of the
807 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
808 @return: domain names
809 @rtype: list of strings.
810 """
811 return [d.getName() for d in self.list_sorted(state)]
813 def domain_suspend(self, domname):
814 """Suspends a domain that is persistently managed by Xend
816 @param domname: Domain Name
817 @type domname: string
818 @rtype: None
819 @raise XendError: Failure during checkpointing.
820 """
822 try:
823 dominfo = self.domain_lookup_nr(domname)
824 if not dominfo:
825 raise XendInvalidDomain(domname)
827 if dominfo.getDomid() == DOM0_ID:
828 raise XendError("Cannot save privileged domain %s" % domname)
830 if dominfo._stateGet() != DOM_STATE_RUNNING:
831 raise VMBadState("Domain is not running",
832 POWER_STATE_NAMES[DOM_STATE_RUNNING],
833 POWER_STATE_NAMES[dominfo._stateGet()])
835 dom_uuid = dominfo.get_uuid()
837 if not os.path.exists(self._managed_config_path(dom_uuid)):
838 raise XendError("Domain is not managed by Xend lifecycle " +
839 "support.")
841 path = self._managed_check_point_path(dom_uuid)
842 oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
843 if hasattr(os, "O_LARGEFILE"):
844 oflags |= os.O_LARGEFILE
845 fd = os.open(path, oflags)
846 try:
847 # For now we don't support 'live checkpoint'
848 XendCheckpoint.save(fd, dominfo, False, False, path)
849 finally:
850 os.close(fd)
851 except OSError, ex:
852 raise XendError("can't write guest state file %s: %s" %
853 (path, ex[1]))
855 def domain_resume(self, domname, start_paused = False):
856 """Resumes a domain that is persistently managed by Xend.
858 @param domname: Domain Name
859 @type domname: string
860 @rtype: None
861 @raise XendError: If failed to restore.
862 """
863 self.domains_lock.acquire()
864 try:
865 try:
866 dominfo = self.domain_lookup_nr(domname)
868 if not dominfo:
869 raise XendInvalidDomain(domname)
871 if dominfo.getDomid() == DOM0_ID:
872 raise XendError("Cannot save privileged domain %s" % domname)
874 if dominfo._stateGet() != XEN_API_VM_POWER_STATE_SUSPENDED:
875 raise XendError("Cannot resume domain that is not suspended.")
877 dom_uuid = dominfo.get_uuid()
878 chkpath = self._managed_check_point_path(dom_uuid)
879 if not os.path.exists(chkpath):
880 raise XendError("Domain was not suspended by Xend")
882 # Restore that replaces the existing XendDomainInfo
883 try:
884 log.debug('Current DomainInfo state: %d' % dominfo._stateGet())
885 oflags = os.O_RDONLY
886 if hasattr(os, "O_LARGEFILE"):
887 oflags |= os.O_LARGEFILE
888 XendCheckpoint.restore(self,
889 os.open(chkpath, oflags),
890 dominfo,
891 paused = start_paused)
892 os.unlink(chkpath)
893 except OSError, ex:
894 raise XendError("Failed to read stored checkpoint file")
895 except IOError, ex:
896 raise XendError("Failed to delete checkpoint file")
897 except Exception, ex:
898 log.exception("Exception occurred when resuming")
899 raise XendError("Error occurred when resuming: %s" % str(ex))
900 finally:
901 self.domains_lock.release()
904 def domain_create(self, config):
905 """Create a domain from a configuration.
907 @param config: configuration
908 @type config: SXP Object (list of lists)
909 @rtype: XendDomainInfo
910 """
911 self.domains_lock.acquire()
912 try:
913 self._refresh()
915 dominfo = XendDomainInfo.create(config)
916 return dominfo
917 finally:
918 self.domains_lock.release()
921 def domain_create_from_dict(self, config_dict):
922 """Create a domain from a configuration dictionary.
924 @param config_dict: configuration
925 @rtype: XendDomainInfo
926 """
927 self.domains_lock.acquire()
928 try:
929 self._refresh()
931 dominfo = XendDomainInfo.create_from_dict(config_dict)
932 return dominfo
933 finally:
934 self.domains_lock.release()
937 def domain_new(self, config):
938 """Create a domain from a configuration but do not start it.
940 @param config: configuration
941 @type config: SXP Object (list of lists)
942 @rtype: XendDomainInfo
943 """
944 self.domains_lock.acquire()
945 try:
946 try:
947 domconfig = XendConfig.XendConfig(sxp_obj = config)
948 dominfo = XendDomainInfo.createDormant(domconfig)
949 log.debug("Creating new managed domain: %s" %
950 dominfo.getName())
951 self._managed_domain_register(dominfo)
952 self.managed_config_save(dominfo)
953 # no return value because it isn't meaningful for client
954 except XendError, e:
955 raise
956 except Exception, e:
957 raise XendError(str(e))
958 finally:
959 self.domains_lock.release()
961 def domain_start(self, domid, start_paused = True):
962 """Start a managed domain
964 @require: Domain must not be running.
965 @param domid: Domain name or domain ID.
966 @type domid: string or int
967 @rtype: None
968 @raise XendError: If domain is still running
969 @rtype: None
970 """
971 self.domains_lock.acquire()
972 try:
973 self._refresh()
975 dominfo = self.domain_lookup_nr(domid)
976 if not dominfo:
977 raise XendInvalidDomain(str(domid))
979 if dominfo._stateGet() != DOM_STATE_HALTED:
980 raise VMBadState("Domain is already running",
981 POWER_STATE_NAMES[DOM_STATE_HALTED],
982 POWER_STATE_NAMES[dominfo._stateGet()])
984 dominfo.start(is_managed = True)
985 finally:
986 self.domains_lock.release()
988 try:
989 dominfo.waitForDevices()
990 except Exception, ex:
991 log.warn("Failed to setup devices for " + str(dominfo) + ": " + str(ex))
992 dominfo.destroy()
993 raise
995 if not start_paused:
996 dominfo.unpause()
998 def domain_delete(self, domid):
999 """Remove a managed domain from database
1001 @require: Domain must not be running.
1002 @param domid: Domain name or domain ID.
1003 @type domid: string or int
1004 @rtype: None
1005 @raise XendError: If domain is still running
1006 """
1007 self.domains_lock.acquire()
1008 try:
1009 try:
1010 dominfo = self.domain_lookup_nr(domid)
1011 if not dominfo:
1012 raise XendInvalidDomain(str(domid))
1014 if dominfo._stateGet() != XEN_API_VM_POWER_STATE_HALTED:
1015 raise VMBadState("Domain is not halted.",
1016 POWER_STATE_NAMES[DOM_STATE_HALTED],
1017 POWER_STATE_NAMES[dominfo._stateGet()])
1019 self._domain_delete_by_info(dominfo)
1020 except Exception, ex:
1021 raise XendError(str(ex))
1022 finally:
1023 self.domains_lock.release()
1026 def domain_delete_by_dominfo(self, dominfo):
1027 """Only for use by XendDomainInfo.
1028 """
1029 self.domains_lock.acquire()
1030 try:
1031 self._domain_delete_by_info(dominfo)
1032 finally:
1033 self.domains_lock.release()
1036 def _domain_delete_by_info(self, dominfo):
1037 """Expects to be protected by domains_lock.
1038 """
1039 log.info("Domain %s (%s) deleted." %
1040 (dominfo.getName(), dominfo.info.get('uuid')))
1042 self._managed_domain_unregister(dominfo)
1043 self._remove_domain(dominfo)
1044 XendDevices.destroy_device_state(dominfo)
1047 def domain_configure(self, config):
1048 """Configure an existing domain.
1050 @param vmconfig: vm configuration
1051 @type vmconfig: SXP Object (list of lists)
1052 @todo: Not implemented
1053 """
1054 # !!!
1055 raise XendError("Unsupported")
1057 def domain_restore(self, src, paused=False):
1058 """Restore a domain from file.
1060 @param src: filename of checkpoint file to restore from
1061 @type src: string
1062 @return: Restored domain
1063 @rtype: XendDomainInfo
1064 @raise XendError: Failure to restore domain
1065 """
1066 try:
1067 oflags = os.O_RDONLY
1068 if hasattr(os, "O_LARGEFILE"):
1069 oflags |= os.O_LARGEFILE
1070 fd = os.open(src, oflags)
1071 try:
1072 return self.domain_restore_fd(fd, paused=paused)
1073 finally:
1074 os.close(fd)
1075 except OSError, ex:
1076 raise XendError("can't read guest state file %s: %s" %
1077 (src, ex[1]))
1079 def domain_restore_fd(self, fd, paused=False):
1080 """Restore a domain from the given file descriptor.
1082 @param fd: file descriptor of the checkpoint file
1083 @type fd: File object
1084 @rtype: XendDomainInfo
1085 @raise XendError: if failed to restore
1086 """
1088 try:
1089 return XendCheckpoint.restore(self, fd, paused=paused)
1090 except XendError, e:
1091 log.exception("Restore failed")
1092 raise
1093 except:
1094 # I don't really want to log this exception here, but the error
1095 # handling in the relocation-socket handling code (relocate.py) is
1096 # poor, so we need to log this for debugging.
1097 log.exception("Restore failed")
1098 raise XendError("Restore failed")
1100 def domain_unpause(self, domid):
1101 """Unpause domain execution.
1103 @param domid: Domain ID or Name
1104 @type domid: int or string.
1105 @rtype: None
1106 @raise XendError: Failed to unpause
1107 @raise XendInvalidDomain: Domain is not valid
1108 """
1109 try:
1110 dominfo = self.domain_lookup_nr(domid)
1111 if not dominfo:
1112 raise XendInvalidDomain(str(domid))
1113 if dominfo.getDomid() == DOM0_ID:
1114 raise XendError("Cannot unpause privileged domain %s" % domid)
1115 if dominfo._stateGet() not in (DOM_STATE_PAUSED, DOM_STATE_RUNNING):
1116 raise VMBadState("Domain '%s' is not started" % domid,
1117 POWER_STATE_NAMES[DOM_STATE_PAUSED],
1118 POWER_STATE_NAMES[dominfo._stateGet()])
1119 log.info("Domain %s (%d) unpaused.", dominfo.getName(),
1120 int(dominfo.getDomid()))
1121 dominfo.unpause()
1122 except XendInvalidDomain:
1123 log.exception("domain_unpause")
1124 raise
1125 except Exception, ex:
1126 log.exception("domain_unpause")
1127 raise XendError(str(ex))
1129 def domain_pause(self, domid):
1130 """Pause domain execution.
1132 @param domid: Domain ID or Name
1133 @type domid: int or string.
1134 @rtype: None
1135 @raise XendError: Failed to pause
1136 @raise XendInvalidDomain: Domain is not valid
1137 """
1138 try:
1139 dominfo = self.domain_lookup_nr(domid)
1140 if not dominfo:
1141 raise XendInvalidDomain(str(domid))
1142 if dominfo.getDomid() == DOM0_ID:
1143 raise XendError("Cannot pause privileged domain %s" % domid)
1144 if dominfo._stateGet() not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1145 raise VMBadState("Domain '%s' is not started" % domid,
1146 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1147 POWER_STATE_NAMES[dominfo._stateGet()])
1148 log.info("Domain %s (%d) paused.", dominfo.getName(),
1149 int(dominfo.getDomid()))
1150 dominfo.pause()
1151 except XendInvalidDomain:
1152 log.exception("domain_pause")
1153 raise
1154 except Exception, ex:
1155 log.exception("domain_pause")
1156 raise XendError(str(ex))
1158 def domain_dump(self, domid, filename, live, crash):
1159 """Dump domain core."""
1161 dominfo = self.domain_lookup_nr(domid)
1162 if not dominfo:
1163 raise XendInvalidDomain(str(domid))
1165 if dominfo.getDomid() == DOM0_ID:
1166 raise XendError("Cannot dump core for privileged domain %s" % domid)
1168 try:
1169 log.info("Domain core dump requested for domain %s (%d) "
1170 "live=%d crash=%d.",
1171 dominfo.getName(), dominfo.getDomid(), live, crash)
1172 return dominfo.dumpCore(filename)
1173 except Exception, ex:
1174 raise XendError(str(ex))
1176 def domain_destroy(self, domid):
1177 """Terminate domain immediately.
1179 @param domid: Domain ID or Name
1180 @type domid: int or string.
1181 @rtype: None
1182 @raise XendError: Failed to destroy
1183 @raise XendInvalidDomain: Domain is not valid
1184 """
1186 dominfo = self.domain_lookup_nr(domid)
1187 if dominfo and dominfo.getDomid() == DOM0_ID:
1188 raise XendError("Cannot destroy privileged domain %s" % domid)
1190 if dominfo:
1191 val = dominfo.destroy()
1192 else:
1193 try:
1194 val = xc.domain_destroy(int(domid))
1195 except ValueError:
1196 raise XendInvalidDomain(domid)
1197 except Exception, e:
1198 raise XendError(str(e))
1200 return val
1202 def domain_migrate(self, domid, dst, live=False, resource=0, port=0):
1203 """Start domain migration.
1205 @param domid: Domain ID or Name
1206 @type domid: int or string.
1207 @param dst: Destination IP address
1208 @type dst: string
1209 @keyword port: relocation port on destination
1210 @type port: int
1211 @keyword live: Live migration
1212 @type live: bool
1213 @keyword resource: not used??
1214 @rtype: None
1215 @raise XendError: Failed to migrate
1216 @raise XendInvalidDomain: Domain is not valid
1217 """
1219 dominfo = self.domain_lookup_nr(domid)
1220 if not dominfo:
1221 raise XendInvalidDomain(str(domid))
1223 if dominfo.getDomid() == DOM0_ID:
1224 raise XendError("Cannot migrate privileged domain %s" % domid)
1226 """ The following call may raise a XendError exception """
1227 dominfo.testMigrateDevices(True, dst)
1229 if live:
1230 """ Make sure there's memory free for enabling shadow mode """
1231 dominfo.checkLiveMigrateMemory()
1233 if port == 0:
1234 port = xoptions.get_xend_relocation_port()
1235 try:
1236 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1237 sock.connect((dst, port))
1238 except socket.error, err:
1239 raise XendError("can't connect: %s" % err[1])
1241 sock.send("receive\n")
1242 sock.recv(80)
1243 XendCheckpoint.save(sock.fileno(), dominfo, True, live, dst)
1244 sock.close()
1246 def domain_save(self, domid, dst, checkpoint=False):
1247 """Start saving a domain to file.
1249 @param domid: Domain ID or Name
1250 @type domid: int or string.
1251 @param dst: Destination filename
1252 @type dst: string
1253 @rtype: None
1254 @raise XendError: Failed to save domain
1255 @raise XendInvalidDomain: Domain is not valid
1256 """
1257 try:
1258 dominfo = self.domain_lookup_nr(domid)
1259 if not dominfo:
1260 raise XendInvalidDomain(str(domid))
1262 if dominfo.getDomid() == DOM0_ID:
1263 raise XendError("Cannot save privileged domain %s" % str(domid))
1264 if dominfo._stateGet() != DOM_STATE_RUNNING:
1265 raise VMBadState("Domain is not running",
1266 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1267 POWER_STATE_NAMES[dominfo._stateGet()])
1269 oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
1270 if hasattr(os, "O_LARGEFILE"):
1271 oflags |= os.O_LARGEFILE
1272 fd = os.open(dst, oflags)
1273 try:
1274 XendCheckpoint.save(fd, dominfo, False, False, dst,
1275 checkpoint=checkpoint)
1276 except Exception, e:
1277 os.close(fd)
1278 raise e
1279 os.close(fd)
1280 except OSError, ex:
1281 raise XendError("can't write guest state file %s: %s" %
1282 (dst, ex[1]))
1284 def domain_pincpu(self, domid, vcpu, cpumap):
1285 """Set which cpus vcpu can use
1287 @param domid: Domain ID or Name
1288 @type domid: int or string.
1289 @param vcpu: vcpu to pin to
1290 @type vcpu: int
1291 @param cpumap: string repr of usable cpus
1292 @type cpumap: string
1293 @rtype: 0
1294 """
1295 dominfo = self.domain_lookup_nr(domid)
1296 if not dominfo:
1297 raise XendInvalidDomain(str(domid))
1299 # if vcpu is keyword 'all', apply the cpumap to all vcpus
1300 vcpus = [ vcpu ]
1301 if str(vcpu).lower() == "all":
1302 vcpus = range(0, int(dominfo.getVCpuCount()))
1304 # set the same cpumask for all vcpus
1305 rc = 0
1306 for v in vcpus:
1307 try:
1308 rc = xc.vcpu_setaffinity(dominfo.getDomid(), int(v), cpumap)
1309 except Exception, ex:
1310 log.exception(ex)
1311 raise XendError("Cannot pin vcpu: %s to cpu: %s - %s" % \
1312 (v, cpumap, str(ex)))
1313 return rc
1315 def domain_cpu_sedf_set(self, domid, period, slice_, latency, extratime,
1316 weight):
1317 """Set Simple EDF scheduler parameters for a domain.
1319 @param domid: Domain ID or Name
1320 @type domid: int or string.
1321 @rtype: 0
1322 """
1323 dominfo = self.domain_lookup_nr(domid)
1324 if not dominfo:
1325 raise XendInvalidDomain(str(domid))
1326 try:
1327 return xc.sedf_domain_set(dominfo.getDomid(), period, slice_,
1328 latency, extratime, weight)
1329 except Exception, ex:
1330 raise XendError(str(ex))
1332 def domain_cpu_sedf_get(self, domid):
1333 """Get Simple EDF scheduler parameters for a domain.
1335 @param domid: Domain ID or Name
1336 @type domid: int or string.
1337 @rtype: SXP object
1338 @return: The parameters for Simple EDF schedule for a domain.
1339 """
1340 dominfo = self.domain_lookup_nr(domid)
1341 if not dominfo:
1342 raise XendInvalidDomain(str(domid))
1343 try:
1344 sedf_info = xc.sedf_domain_get(dominfo.getDomid())
1345 # return sxpr
1346 return ['sedf',
1347 ['domid', sedf_info['domid']],
1348 ['period', sedf_info['period']],
1349 ['slice', sedf_info['slice']],
1350 ['latency', sedf_info['latency']],
1351 ['extratime', sedf_info['extratime']],
1352 ['weight', sedf_info['weight']]]
1354 except Exception, ex:
1355 raise XendError(str(ex))
1357 def domain_shadow_control(self, domid, op):
1358 """Shadow page control.
1360 @param domid: Domain ID or Name
1361 @type domid: int or string.
1362 @param op: operation
1363 @type op: int
1364 @rtype: 0
1365 """
1366 dominfo = self.domain_lookup(domid)
1367 try:
1368 return xc.shadow_control(dominfo.getDomid(), op)
1369 except Exception, ex:
1370 raise XendError(str(ex))
1372 def domain_shadow_mem_get(self, domid):
1373 """Get shadow pagetable memory allocation.
1375 @param domid: Domain ID or Name
1376 @type domid: int or string.
1377 @rtype: int
1378 @return: shadow memory in MB
1379 """
1380 dominfo = self.domain_lookup(domid)
1381 try:
1382 return xc.shadow_mem_control(dominfo.getDomid())
1383 except Exception, ex:
1384 raise XendError(str(ex))
1386 def domain_shadow_mem_set(self, domid, mb):
1387 """Set shadow pagetable memory allocation.
1389 @param domid: Domain ID or Name
1390 @type domid: int or string.
1391 @param mb: shadow memory to set in MB
1392 @type: mb: int
1393 @rtype: int
1394 @return: shadow memory in MB
1395 """
1396 dominfo = self.domain_lookup(domid)
1397 try:
1398 return xc.shadow_mem_control(dominfo.getDomid(), mb=mb)
1399 except Exception, ex:
1400 raise XendError(str(ex))
1402 def domain_sched_credit_get(self, domid):
1403 """Get credit scheduler parameters for a domain.
1405 @param domid: Domain ID or Name
1406 @type domid: int or string.
1407 @rtype: dict with keys 'weight' and 'cap'
1408 @return: credit scheduler parameters
1409 """
1410 dominfo = self.domain_lookup_nr(domid)
1411 if not dominfo:
1412 raise XendInvalidDomain(str(domid))
1414 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1415 try:
1416 return xc.sched_credit_domain_get(dominfo.getDomid())
1417 except Exception, ex:
1418 raise XendError(str(ex))
1419 else:
1420 return {'weight' : dominfo.getWeight(),
1421 'cap' : dominfo.getCap()}
1423 def domain_sched_credit_set(self, domid, weight = None, cap = None):
1424 """Set credit scheduler parameters for a domain.
1426 @param domid: Domain ID or Name
1427 @type domid: int or string.
1428 @type weight: int
1429 @type cap: int
1430 @rtype: 0
1431 """
1432 set_weight = False
1433 set_cap = False
1434 dominfo = self.domain_lookup_nr(domid)
1435 if not dominfo:
1436 raise XendInvalidDomain(str(domid))
1437 try:
1438 if weight is None:
1439 weight = int(0)
1440 elif weight < 1 or weight > 65535:
1441 raise XendError("weight is out of range")
1442 else:
1443 set_weight = True
1445 if cap is None:
1446 cap = int(~0)
1447 elif cap < 0 or cap > dominfo.getVCpuCount() * 100:
1448 raise XendError("cap is out of range")
1449 else:
1450 set_cap = True
1452 assert type(weight) == int
1453 assert type(cap) == int
1455 rc = 0
1456 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1457 rc = xc.sched_credit_domain_set(dominfo.getDomid(), weight, cap)
1458 if rc == 0:
1459 if set_weight:
1460 dominfo.setWeight(weight)
1461 if set_cap:
1462 dominfo.setCap(cap)
1463 self.managed_config_save(dominfo)
1464 return rc
1465 except Exception, ex:
1466 log.exception(ex)
1467 raise XendError(str(ex))
1469 def domain_maxmem_set(self, domid, mem):
1470 """Set the memory limit for a domain.
1472 @param domid: Domain ID or Name
1473 @type domid: int or string.
1474 @param mem: memory limit (in MiB)
1475 @type mem: int
1476 @raise XendError: fail to set memory
1477 @rtype: 0
1478 """
1479 dominfo = self.domain_lookup_nr(domid)
1480 if not dominfo:
1481 raise XendInvalidDomain(str(domid))
1482 dominfo.setMemoryMaximum(mem)
1484 def domain_ioport_range_enable(self, domid, first, last):
1485 """Enable access to a range of IO ports for a domain
1487 @param first: first IO port
1488 @param last: last IO port
1489 @raise XendError: failed to set range
1490 @rtype: 0
1491 """
1492 dominfo = self.domain_lookup_nr(domid)
1493 if not dominfo:
1494 raise XendInvalidDomain(str(domid))
1495 nr_ports = last - first + 1
1496 try:
1497 return xc.domain_ioport_permission(dominfo.getDomid(),
1498 first_port = first,
1499 nr_ports = nr_ports,
1500 allow_access = 1)
1501 except Exception, ex:
1502 raise XendError(str(ex))
1504 def domain_ioport_range_disable(self, domid, first, last):
1505 """Disable access to a range of IO ports for a domain
1507 @param first: first IO port
1508 @param last: last IO port
1509 @raise XendError: failed to set range
1510 @rtype: 0
1511 """
1512 dominfo = self.domain_lookup_nr(domid)
1513 if not dominfo:
1514 raise XendInvalidDomain(str(domid))
1515 nr_ports = last - first + 1
1516 try:
1517 return xc.domain_ioport_permission(dominfo.getDomid(),
1518 first_port = first,
1519 nr_ports = nr_ports,
1520 allow_access = 0)
1521 except Exception, ex:
1522 raise XendError(str(ex))
1524 def domain_send_trigger(self, domid, trigger_name, vcpu = 0):
1525 """Send trigger to a domain.
1527 @param domid: Domain ID or Name
1528 @type domid: int or string.
1529 @param trigger_name: trigger type name
1530 @type trigger_name: string
1531 @param vcpu: VCPU to send trigger (default is 0)
1532 @type vcpu: int
1533 @raise XendError: failed to send trigger
1534 @raise XendInvalidDomain: Domain is not valid
1535 @rtype: 0
1536 """
1537 dominfo = self.domain_lookup_nr(domid)
1538 if not dominfo:
1539 raise XendInvalidDomain(str(domid))
1540 if trigger_name.lower() in TRIGGER_TYPE:
1541 trigger = TRIGGER_TYPE[trigger_name.lower()]
1542 else:
1543 raise XendError("Invalid trigger: %s", trigger_name)
1544 try:
1545 return xc.domain_send_trigger(dominfo.getDomid(),
1546 trigger,
1547 vcpu)
1548 except Exception, ex:
1549 raise XendError(str(ex))
1552 def instance():
1553 """Singleton constructor. Use this instead of the class constructor.
1554 """
1555 global inst
1556 try:
1557 inst
1558 except:
1559 inst = XendDomain()
1560 inst.init()
1561 return inst