debuggers.hg

view tools/python/xen/xend/XendDomain.py @ 16625:7b4e560d6caf

xend: Fix cleanup_domains() for suspending managed domains

When unmanaged domains with on_xend_stop="suspend" exist, managed
domains are not suspended by xend stop command. The processing of
cleanup_domains() is aborted by exception. This patch keeps suspending
managed domains even if unmanaged domains exist.

Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Dec 12 10:08:14 2007 +0000 (2007-12-12)
parents 09d8b6eb3131
children 9b37cabe0485
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 txn = xstransact()
397 try:
398 self._refreshTxn(txn, refresh_shutdown)
399 txn.commit()
400 except:
401 txn.abort()
402 raise
404 def _refreshTxn(self, transaction, refresh_shutdown):
405 running = self._running_domains()
406 # Add domains that are not already tracked but running in Xen,
407 # and update domain state for those that are running and tracked.
408 for dom in running:
409 domid = dom['domid']
410 if domid in self.domains:
411 self.domains[domid].update(dom, refresh_shutdown, transaction)
412 elif domid not in self.domains and dom['dying'] != 1:
413 try:
414 new_dom = XendDomainInfo.recreate(dom, False)
415 except VmError:
416 log.exception("Unable to recreate domain")
417 try:
418 xc.domain_destroy(domid)
419 except:
420 log.exception("Hard destruction of domain failed: %d" %
421 domid)
423 # update information for all running domains
424 # - like cpu_time, status, dying, etc.
425 # remove domains that are not running from active domain list.
426 # The list might have changed by now, because the update call may
427 # cause new domains to be added, if the domain has rebooted. We get
428 # the list again.
429 running = self._running_domains()
430 running_domids = [d['domid'] for d in running if d['dying'] != 1]
431 for domid, dom in self.domains.items():
432 if domid not in running_domids and domid != DOM0_ID:
433 self._remove_domain(dom, domid)
436 def add_domain(self, info):
437 """Add a domain to the list of running domains
439 @requires: Expects to be protected by the domains_lock.
440 @param info: XendDomainInfo of a domain to be added.
441 @type info: XendDomainInfo
442 """
443 log.debug("Adding Domain: %s" % info.getDomid())
444 self.domains[info.getDomid()] = info
446 # update the managed domains with a new XendDomainInfo object
447 # if we are keeping track of it.
448 if info.get_uuid() in self.managed_domains:
449 self._managed_domain_register(info)
451 def remove_domain(self, info, domid = None):
452 """Remove the domain from the list of running domains, taking the
453 domains_lock first.
454 """
455 self.domains_lock.acquire()
456 try:
457 self._remove_domain(info, domid)
458 finally:
459 self.domains_lock.release()
461 def _remove_domain(self, info, domid = None):
462 """Remove the domain from the list of running domains
464 @requires: Expects to be protected by the domains_lock.
465 @param info: XendDomainInfo of a domain to be removed.
466 @type info: XendDomainInfo
467 """
468 if info:
469 if domid == None:
470 domid = info.getDomid()
472 if info._stateGet() != DOM_STATE_HALTED:
473 info.cleanupDomain()
475 if domid in self.domains:
476 del self.domains[domid]
477 else:
478 log.warning("Attempted to remove non-existent domain.")
480 def restore_(self, config):
481 """Create a domain as part of the restore process. This is called
482 only from L{XendCheckpoint}.
484 A restore request comes into XendDomain through L{domain_restore}
485 or L{domain_restore_fd}. That request is
486 forwarded immediately to XendCheckpoint which, when it is ready, will
487 call this method. It is necessary to come through here rather than go
488 directly to L{XendDomainInfo.restore} because we need to
489 serialise the domain creation process, but cannot lock
490 domain_restore_fd as a whole, otherwise we will deadlock waiting for
491 the old domain to die.
493 @param config: Configuration of domain to restore
494 @type config: SXP Object (eg. list of lists)
495 """
496 self.domains_lock.acquire()
497 try:
498 dominfo = XendDomainInfo.restore(config)
499 return dominfo
500 finally:
501 self.domains_lock.release()
504 def domain_lookup(self, domid):
505 """Look up given I{domid} in the list of managed and running
506 domains.
508 @note: Will cause a refresh before lookup up domains, for
509 a version that does not need to re-read xenstore
510 use L{domain_lookup_nr}.
512 @param domid: Domain ID or Domain Name.
513 @type domid: int or string
514 @return: Found domain.
515 @rtype: XendDomainInfo
516 @raise XendInvalidDomain: If domain is not found.
517 """
518 self.domains_lock.acquire()
519 try:
520 self._refresh(refresh_shutdown = False)
521 dom = self.domain_lookup_nr(domid)
522 if not dom:
523 raise XendInvalidDomain(str(domid))
524 return dom
525 finally:
526 self.domains_lock.release()
529 def domain_lookup_nr(self, domid):
530 """Look up given I{domid} in the list of managed and running
531 domains.
533 @param domid: Domain ID or Domain Name.
534 @type domid: int or string
535 @return: Found domain.
536 @rtype: XendDomainInfo or None
537 """
538 self.domains_lock.acquire()
539 try:
540 # lookup by name
541 match = [dom for dom in self.domains.values() \
542 if dom.getName() == domid]
543 if match:
544 return match[0]
546 match = [dom for dom in self.managed_domains.values() \
547 if dom.getName() == domid]
548 if match:
549 return match[0]
551 # lookup by id
552 try:
553 if int(domid) in self.domains:
554 return self.domains[int(domid)]
555 except ValueError:
556 pass
558 # lookup by uuid for running domains
559 match = [dom for dom in self.domains.values() \
560 if dom.get_uuid() == domid]
561 if match:
562 return match[0]
564 # lookup by uuid for inactive managed domains
565 if domid in self.managed_domains:
566 return self.managed_domains[domid]
568 return None
569 finally:
570 self.domains_lock.release()
572 def privilegedDomain(self):
573 """ Get the XendDomainInfo of a dom0
575 @rtype: XendDomainInfo
576 """
577 self.domains_lock.acquire()
578 try:
579 return self.domains[DOM0_ID]
580 finally:
581 self.domains_lock.release()
583 def autostart_domains(self):
584 """ Autostart managed domains that are marked as such. """
586 need_starting = []
588 self.domains_lock.acquire()
589 try:
590 for dom_uuid, dom in self.managed_domains.items():
591 if dom and dom._stateGet() == DOM_STATE_HALTED:
592 on_xend_start = dom.info.get('on_xend_start', 'ignore')
593 auto_power_on = dom.info.get('auto_power_on', False)
594 should_start = (on_xend_start == 'start') or auto_power_on
595 if should_start:
596 need_starting.append(dom_uuid)
597 finally:
598 self.domains_lock.release()
600 for dom_uuid in need_starting:
601 self.domain_start(dom_uuid, False)
603 def cleanup_domains(self):
604 """Clean up domains that are marked as autostop.
605 Should be called when Xend goes down. This is currently
606 called from L{xen.xend.servers.XMLRPCServer}.
608 """
609 log.debug('cleanup_domains')
610 self.domains_lock.acquire()
611 try:
612 for dom in self.domains.values():
613 if dom.getName() == DOM0_NAME:
614 continue
616 try:
617 if dom._stateGet() == DOM_STATE_RUNNING:
618 shutdownAction = dom.info.get('on_xend_stop', 'ignore')
619 if shutdownAction == 'shutdown':
620 log.debug('Shutting down domain: %s' % dom.getName())
621 dom.shutdown("poweroff")
622 elif shutdownAction == 'suspend':
623 self.domain_suspend(dom.getName())
624 else:
625 log.debug('Domain %s continues to run.' % dom.getName())
626 except:
627 log.exception('Domain %s failed to %s.' % \
628 (dom.getName(), shutdownAction))
629 finally:
630 self.domains_lock.release()
634 # ----------------------------------------------------------------
635 # Xen API
638 def set_allow_new_domains(self, allow_new_domains):
639 self._allow_new_domains = allow_new_domains
641 def allow_new_domains(self):
642 return self._allow_new_domains
644 def get_domain_refs(self):
645 result = []
646 try:
647 self.domains_lock.acquire()
648 result = [d.get_uuid() for d in self.domains.values()]
649 for d in self.managed_domains.keys():
650 if d not in result:
651 result.append(d)
652 return result
653 finally:
654 self.domains_lock.release()
656 def get_all_vms(self):
657 self.domains_lock.acquire()
658 try:
659 result = self.domains.values()
660 result += [x for x in self.managed_domains.values() if
661 x not in result]
662 return result
663 finally:
664 self.domains_lock.release()
666 def get_vm_by_uuid(self, vm_uuid):
667 self.domains_lock.acquire()
668 try:
669 for dom in self.domains.values():
670 if dom.get_uuid() == vm_uuid:
671 return dom
673 if vm_uuid in self.managed_domains:
674 return self.managed_domains[vm_uuid]
676 return None
677 finally:
678 self.domains_lock.release()
680 def get_vm_with_dev_uuid(self, klass, dev_uuid):
681 self.domains_lock.acquire()
682 try:
683 for dom in self.domains.values() + self.managed_domains.values():
684 if dom.has_device(klass, dev_uuid):
685 return dom
686 return None
687 finally:
688 self.domains_lock.release()
690 def get_dev_property_by_uuid(self, klass, dev_uuid, field):
691 value = None
692 self.domains_lock.acquire()
694 try:
695 try:
696 dom = self.get_vm_with_dev_uuid(klass, dev_uuid)
697 if dom:
698 value = dom.get_dev_property(klass, dev_uuid, field)
699 except ValueError, e:
700 pass
701 finally:
702 self.domains_lock.release()
704 return value
706 def set_dev_property_by_uuid(self, klass, dev_uuid, field, value,
707 old_val = None):
708 rc = True
709 self.domains_lock.acquire()
711 try:
712 try:
713 dom = self.get_vm_with_dev_uuid(klass, dev_uuid)
714 if dom:
715 o_val = dom.get_dev_property(klass, dev_uuid, field)
716 log.info("o_val=%s, old_val=%s" % (o_val, old_val))
717 if old_val and old_val != o_val:
718 return False
720 dom.set_dev_property(klass, dev_uuid, field, value)
721 self.managed_config_save(dom)
722 except ValueError, e:
723 pass
724 finally:
725 self.domains_lock.release()
727 return rc
729 def is_valid_vm(self, vm_ref):
730 return (self.get_vm_by_uuid(vm_ref) != None)
732 def is_valid_dev(self, klass, dev_uuid):
733 return (self.get_vm_with_dev_uuid(klass, dev_uuid) != None)
735 def do_legacy_api_with_uuid(self, fn, vm_uuid, *args, **kwargs):
736 dom = self.uuid_to_dom(vm_uuid)
737 fn(dom, *args, **kwargs)
739 def uuid_to_dom(self, vm_uuid):
740 self.domains_lock.acquire()
741 try:
742 for domid, dom in self.domains.items():
743 if dom.get_uuid() == vm_uuid:
744 return domid
746 if vm_uuid in self.managed_domains:
747 domid = self.managed_domains[vm_uuid].getDomid()
748 if domid is None:
749 return self.managed_domains[vm_uuid].getName()
750 else:
751 return domid
753 raise XendInvalidDomain(vm_uuid)
754 finally:
755 self.domains_lock.release()
758 def create_domain(self, xenapi_vm):
759 self.domains_lock.acquire()
760 try:
761 try:
762 xeninfo = XendConfig.XendConfig(xapi = xenapi_vm)
763 dominfo = XendDomainInfo.createDormant(xeninfo)
764 log.debug("Creating new managed domain: %s: %s" %
765 (dominfo.getName(), dominfo.get_uuid()))
766 self._managed_domain_register(dominfo)
767 self.managed_config_save(dominfo)
768 return dominfo.get_uuid()
769 except XendError, e:
770 raise
771 except Exception, e:
772 raise XendError(str(e))
773 finally:
774 self.domains_lock.release()
776 def rename_domain(self, dom, new_name):
777 self.domains_lock.acquire()
778 try:
779 old_name = dom.getName()
780 dom.setName(new_name)
782 finally:
783 self.domains_lock.release()
786 #
787 # End of Xen API
788 # ----------------------------------------------------------------
790 # ------------------------------------------------------------
791 # Xen Legacy API
793 def list(self, state = DOM_STATE_RUNNING):
794 """Get list of domain objects.
796 @param: the state in which the VMs should be -- one of the
797 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
798 @return: domains
799 @rtype: list of XendDomainInfo
800 """
801 if type(state) == int:
802 state = POWER_STATE_NAMES[state]
803 state = state.lower()
805 self.domains_lock.acquire()
806 try:
807 self._refresh(refresh_shutdown = False)
809 # active domains
810 active_domains = self.domains.values()
811 active_uuids = [d.get_uuid() for d in active_domains]
813 # inactive domains
814 inactive_domains = []
815 for dom_uuid, dom in self.managed_domains.items():
816 if dom_uuid not in active_uuids:
817 inactive_domains.append(dom)
819 if state == POWER_STATE_ALL:
820 return active_domains + inactive_domains
821 else:
822 return filter(lambda x:
823 POWER_STATE_NAMES[x._stateGet()].lower() == state,
824 active_domains + inactive_domains)
825 finally:
826 self.domains_lock.release()
829 def list_sorted(self, state = DOM_STATE_RUNNING):
830 """Get list of domain objects, sorted by name.
832 @param: the state in which the VMs should be -- one of the
833 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
834 @return: domain objects
835 @rtype: list of XendDomainInfo
836 """
837 doms = self.list(state)
838 doms.sort(lambda x, y: cmp(x.getName(), y.getName()))
839 return doms
841 def list_names(self, state = DOM_STATE_RUNNING):
842 """Get list of domain names.
844 @param: the state in which the VMs should be -- one of the
845 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
846 @return: domain names
847 @rtype: list of strings.
848 """
849 return [d.getName() for d in self.list_sorted(state)]
851 def domain_suspend(self, domname):
852 """Suspends a domain that is persistently managed by Xend
854 @param domname: Domain Name
855 @type domname: string
856 @rtype: None
857 @raise XendError: Failure during checkpointing.
858 """
860 try:
861 dominfo = self.domain_lookup_nr(domname)
862 if not dominfo:
863 raise XendInvalidDomain(domname)
865 if dominfo.getDomid() == DOM0_ID:
866 raise XendError("Cannot save privileged domain %s" % domname)
868 if dominfo._stateGet() != DOM_STATE_RUNNING:
869 raise VMBadState("Domain is not running",
870 POWER_STATE_NAMES[DOM_STATE_RUNNING],
871 POWER_STATE_NAMES[dominfo._stateGet()])
873 dom_uuid = dominfo.get_uuid()
875 if not os.path.exists(self._managed_config_path(dom_uuid)):
876 raise XendError("Domain is not managed by Xend lifecycle " +
877 "support.")
879 path = self._managed_check_point_path(dom_uuid)
880 oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
881 if hasattr(os, "O_LARGEFILE"):
882 oflags |= os.O_LARGEFILE
883 fd = os.open(path, oflags)
884 try:
885 # For now we don't support 'live checkpoint'
886 XendCheckpoint.save(fd, dominfo, False, False, path)
887 finally:
888 os.close(fd)
889 except OSError, ex:
890 raise XendError("can't write guest state file %s: %s" %
891 (path, ex[1]))
893 def domain_resume(self, domname, start_paused = False):
894 """Resumes a domain that is persistently managed by Xend.
896 @param domname: Domain Name
897 @type domname: string
898 @rtype: None
899 @raise XendError: If failed to restore.
900 """
901 self.domains_lock.acquire()
902 try:
903 try:
904 fd = None
905 dominfo = self.domain_lookup_nr(domname)
907 if not dominfo:
908 raise XendInvalidDomain(domname)
910 if dominfo.getDomid() == DOM0_ID:
911 raise XendError("Cannot save privileged domain %s" % domname)
913 if dominfo._stateGet() != XEN_API_VM_POWER_STATE_SUSPENDED:
914 raise XendError("Cannot resume domain that is not suspended.")
916 dom_uuid = dominfo.get_uuid()
917 chkpath = self._managed_check_point_path(dom_uuid)
918 if not os.path.exists(chkpath):
919 raise XendError("Domain was not suspended by Xend")
921 # Restore that replaces the existing XendDomainInfo
922 try:
923 log.debug('Current DomainInfo state: %d' % dominfo._stateGet())
924 oflags = os.O_RDONLY
925 if hasattr(os, "O_LARGEFILE"):
926 oflags |= os.O_LARGEFILE
927 fd = os.open(chkpath, oflags)
928 XendCheckpoint.restore(self,
929 fd,
930 dominfo,
931 paused = start_paused)
932 os.unlink(chkpath)
933 except OSError, ex:
934 raise XendError("Failed to read stored checkpoint file")
935 except IOError, ex:
936 raise XendError("Failed to delete checkpoint file")
937 except Exception, ex:
938 log.exception("Exception occurred when resuming")
939 raise XendError("Error occurred when resuming: %s" % str(ex))
940 finally:
941 if fd is not None:
942 os.close(fd)
943 self.domains_lock.release()
946 def domain_create(self, config):
947 """Create a domain from a configuration.
949 @param config: configuration
950 @type config: SXP Object (list of lists)
951 @rtype: XendDomainInfo
952 """
953 self.domains_lock.acquire()
954 try:
955 self._refresh()
957 dominfo = XendDomainInfo.create(config)
958 return dominfo
959 finally:
960 self.domains_lock.release()
963 def domain_create_from_dict(self, config_dict):
964 """Create a domain from a configuration dictionary.
966 @param config_dict: configuration
967 @rtype: XendDomainInfo
968 """
969 self.domains_lock.acquire()
970 try:
971 self._refresh()
973 dominfo = XendDomainInfo.create_from_dict(config_dict)
974 return dominfo
975 finally:
976 self.domains_lock.release()
979 def domain_new(self, config):
980 """Create a domain from a configuration but do not start it.
982 @param config: configuration
983 @type config: SXP Object (list of lists)
984 @rtype: XendDomainInfo
985 """
986 self.domains_lock.acquire()
987 try:
988 try:
989 domconfig = XendConfig.XendConfig(sxp_obj = config)
990 dominfo = XendDomainInfo.createDormant(domconfig)
991 log.debug("Creating new managed domain: %s" %
992 dominfo.getName())
993 self._managed_domain_register(dominfo)
994 self.managed_config_save(dominfo)
995 # no return value because it isn't meaningful for client
996 except XendError, e:
997 raise
998 except Exception, e:
999 raise XendError(str(e))
1000 finally:
1001 self.domains_lock.release()
1003 def domain_start(self, domid, start_paused = True):
1004 """Start a managed domain
1006 @require: Domain must not be running.
1007 @param domid: Domain name or domain ID.
1008 @type domid: string or int
1009 @rtype: None
1010 @raise XendError: If domain is still running
1011 @rtype: None
1012 """
1013 self.domains_lock.acquire()
1014 try:
1015 self._refresh()
1017 dominfo = self.domain_lookup_nr(domid)
1018 if not dominfo:
1019 raise XendInvalidDomain(str(domid))
1021 if dominfo._stateGet() != DOM_STATE_HALTED:
1022 raise VMBadState("Domain is already running",
1023 POWER_STATE_NAMES[DOM_STATE_HALTED],
1024 POWER_STATE_NAMES[dominfo._stateGet()])
1026 dominfo.start(is_managed = True)
1027 finally:
1028 self.domains_lock.release()
1030 try:
1031 dominfo.waitForDevices()
1032 except Exception, ex:
1033 log.warn("Failed to setup devices for " + str(dominfo) + ": " + str(ex))
1034 dominfo.destroy()
1035 raise
1037 if not start_paused:
1038 dominfo.unpause()
1040 def domain_delete(self, domid):
1041 """Remove a managed domain from database
1043 @require: Domain must not be running.
1044 @param domid: Domain name or domain ID.
1045 @type domid: string or int
1046 @rtype: None
1047 @raise XendError: If domain is still running
1048 """
1049 self.domains_lock.acquire()
1050 try:
1051 try:
1052 dominfo = self.domain_lookup_nr(domid)
1053 if not dominfo:
1054 raise XendInvalidDomain(str(domid))
1056 if dominfo._stateGet() != XEN_API_VM_POWER_STATE_HALTED:
1057 raise VMBadState("Domain is not halted.",
1058 POWER_STATE_NAMES[DOM_STATE_HALTED],
1059 POWER_STATE_NAMES[dominfo._stateGet()])
1061 self._domain_delete_by_info(dominfo)
1062 except Exception, ex:
1063 raise XendError(str(ex))
1064 finally:
1065 self.domains_lock.release()
1068 def domain_delete_by_dominfo(self, dominfo):
1069 """Only for use by XendDomainInfo.
1070 """
1071 self.domains_lock.acquire()
1072 try:
1073 self._domain_delete_by_info(dominfo)
1074 finally:
1075 self.domains_lock.release()
1078 def _domain_delete_by_info(self, dominfo):
1079 """Expects to be protected by domains_lock.
1080 """
1081 log.info("Domain %s (%s) deleted." %
1082 (dominfo.getName(), dominfo.info.get('uuid')))
1084 dominfo.metrics.destroy()
1085 self._managed_domain_unregister(dominfo)
1086 self._remove_domain(dominfo)
1087 XendDevices.destroy_device_state(dominfo)
1090 def domain_configure(self, config):
1091 """Configure an existing domain.
1093 @param vmconfig: vm configuration
1094 @type vmconfig: SXP Object (list of lists)
1095 @todo: Not implemented
1096 """
1097 # !!!
1098 raise XendError("Unsupported")
1100 def domain_restore(self, src, paused=False):
1101 """Restore a domain from file.
1103 @param src: filename of checkpoint file to restore from
1104 @type src: string
1105 @return: Restored domain
1106 @rtype: XendDomainInfo
1107 @raise XendError: Failure to restore domain
1108 """
1109 try:
1110 oflags = os.O_RDONLY
1111 if hasattr(os, "O_LARGEFILE"):
1112 oflags |= os.O_LARGEFILE
1113 fd = os.open(src, oflags)
1114 try:
1115 return self.domain_restore_fd(fd, paused=paused)
1116 finally:
1117 os.close(fd)
1118 except OSError, ex:
1119 raise XendError("can't read guest state file %s: %s" %
1120 (src, ex[1]))
1122 def domain_restore_fd(self, fd, paused=False):
1123 """Restore a domain from the given file descriptor.
1125 @param fd: file descriptor of the checkpoint file
1126 @type fd: File object
1127 @rtype: XendDomainInfo
1128 @raise XendError: if failed to restore
1129 """
1131 try:
1132 return XendCheckpoint.restore(self, fd, paused=paused)
1133 except XendError, e:
1134 log.exception("Restore failed")
1135 raise
1136 except:
1137 # I don't really want to log this exception here, but the error
1138 # handling in the relocation-socket handling code (relocate.py) is
1139 # poor, so we need to log this for debugging.
1140 log.exception("Restore failed")
1141 raise XendError("Restore failed")
1143 def domain_unpause(self, domid):
1144 """Unpause domain execution.
1146 @param domid: Domain ID or Name
1147 @type domid: int or string.
1148 @rtype: None
1149 @raise XendError: Failed to unpause
1150 @raise XendInvalidDomain: Domain is not valid
1151 """
1152 try:
1153 dominfo = self.domain_lookup_nr(domid)
1154 if not dominfo:
1155 raise XendInvalidDomain(str(domid))
1156 if dominfo.getDomid() == DOM0_ID:
1157 raise XendError("Cannot unpause privileged domain %s" % domid)
1158 if dominfo._stateGet() not in (DOM_STATE_PAUSED, DOM_STATE_RUNNING):
1159 raise VMBadState("Domain '%s' is not started" % domid,
1160 POWER_STATE_NAMES[DOM_STATE_PAUSED],
1161 POWER_STATE_NAMES[dominfo._stateGet()])
1162 log.info("Domain %s (%d) unpaused.", dominfo.getName(),
1163 int(dominfo.getDomid()))
1164 dominfo.unpause()
1165 except XendInvalidDomain:
1166 log.exception("domain_unpause")
1167 raise
1168 except Exception, ex:
1169 log.exception("domain_unpause")
1170 raise XendError(str(ex))
1172 def domain_pause(self, domid, state=False):
1173 """Pause domain execution.
1175 @param domid: Domain ID or Name
1176 @type domid: int or string.
1177 @keyword state: If True, will return the domain state before pause
1178 @type state: bool
1179 @rtype: int if state is True
1180 @return: Domain state (DOM_STATE_*)
1181 @rtype: None if state is False
1182 @raise XendError: Failed to pause
1183 @raise XendInvalidDomain: Domain is not valid
1184 """
1185 try:
1186 dominfo = self.domain_lookup_nr(domid)
1187 if not dominfo:
1188 raise XendInvalidDomain(str(domid))
1189 if dominfo.getDomid() == DOM0_ID:
1190 raise XendError("Cannot pause privileged domain %s" % domid)
1191 ds = dominfo._stateGet()
1192 if ds not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1193 raise VMBadState("Domain '%s' is not started" % domid,
1194 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1195 POWER_STATE_NAMES[ds])
1196 log.info("Domain %s (%d) paused.", dominfo.getName(),
1197 int(dominfo.getDomid()))
1198 dominfo.pause()
1199 if state:
1200 return ds
1201 except XendInvalidDomain:
1202 log.exception("domain_pause")
1203 raise
1204 except Exception, ex:
1205 log.exception("domain_pause")
1206 raise XendError(str(ex))
1208 def domain_dump(self, domid, filename, live, crash):
1209 """Dump domain core."""
1211 dominfo = self.domain_lookup_nr(domid)
1212 if not dominfo:
1213 raise XendInvalidDomain(str(domid))
1215 if dominfo.getDomid() == DOM0_ID:
1216 raise XendError("Cannot dump core for privileged domain %s" % domid)
1217 if dominfo._stateGet() not in (DOM_STATE_PAUSED, DOM_STATE_RUNNING):
1218 raise VMBadState("Domain '%s' is not started" % domid,
1219 POWER_STATE_NAMES[DOM_STATE_PAUSED],
1220 POWER_STATE_NAMES[dominfo._stateGet()])
1222 try:
1223 log.info("Domain core dump requested for domain %s (%d) "
1224 "live=%d crash=%d.",
1225 dominfo.getName(), dominfo.getDomid(), live, crash)
1226 return dominfo.dumpCore(filename)
1227 except Exception, ex:
1228 raise XendError(str(ex))
1230 def domain_destroy(self, domid):
1231 """Terminate domain immediately.
1233 @param domid: Domain ID or Name
1234 @type domid: int or string.
1235 @rtype: None
1236 @raise XendError: Failed to destroy
1237 @raise XendInvalidDomain: Domain is not valid
1238 """
1240 dominfo = self.domain_lookup_nr(domid)
1241 if dominfo and dominfo.getDomid() == DOM0_ID:
1242 raise XendError("Cannot destroy privileged domain %s" % domid)
1244 if dominfo:
1245 val = dominfo.destroy()
1246 else:
1247 try:
1248 val = xc.domain_destroy(int(domid))
1249 except ValueError:
1250 raise XendInvalidDomain(domid)
1251 except Exception, e:
1252 raise XendError(str(e))
1254 return val
1256 def domain_migrate(self, domid, dst, live=False, resource=0, port=0):
1257 """Start domain migration.
1259 @param domid: Domain ID or Name
1260 @type domid: int or string.
1261 @param dst: Destination IP address
1262 @type dst: string
1263 @keyword port: relocation port on destination
1264 @type port: int
1265 @keyword live: Live migration
1266 @type live: bool
1267 @keyword resource: not used??
1268 @rtype: None
1269 @raise XendError: Failed to migrate
1270 @raise XendInvalidDomain: Domain is not valid
1271 """
1273 dominfo = self.domain_lookup_nr(domid)
1274 if not dominfo:
1275 raise XendInvalidDomain(str(domid))
1277 if dominfo.getDomid() == DOM0_ID:
1278 raise XendError("Cannot migrate privileged domain %s" % domid)
1280 """ The following call may raise a XendError exception """
1281 dominfo.testMigrateDevices(True, dst)
1283 if live:
1284 """ Make sure there's memory free for enabling shadow mode """
1285 dominfo.checkLiveMigrateMemory()
1287 if port == 0:
1288 port = xoptions.get_xend_relocation_port()
1289 try:
1290 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1291 sock.connect((dst, port))
1292 except socket.error, err:
1293 raise XendError("can't connect: %s" % err[1])
1295 sock.send("receive\n")
1296 sock.recv(80)
1297 XendCheckpoint.save(sock.fileno(), dominfo, True, live, dst)
1298 sock.close()
1300 def domain_save(self, domid, dst, checkpoint=False):
1301 """Start saving a domain to file.
1303 @param domid: Domain ID or Name
1304 @type domid: int or string.
1305 @param dst: Destination filename
1306 @type dst: string
1307 @rtype: None
1308 @raise XendError: Failed to save domain
1309 @raise XendInvalidDomain: Domain is not valid
1310 """
1311 try:
1312 dominfo = self.domain_lookup_nr(domid)
1313 if not dominfo:
1314 raise XendInvalidDomain(str(domid))
1316 if dominfo.getDomid() == DOM0_ID:
1317 raise XendError("Cannot save privileged domain %s" % str(domid))
1318 if dominfo._stateGet() != DOM_STATE_RUNNING:
1319 raise VMBadState("Domain is not running",
1320 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1321 POWER_STATE_NAMES[dominfo._stateGet()])
1323 oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
1324 if hasattr(os, "O_LARGEFILE"):
1325 oflags |= os.O_LARGEFILE
1326 fd = os.open(dst, oflags)
1327 try:
1328 XendCheckpoint.save(fd, dominfo, False, False, dst,
1329 checkpoint=checkpoint)
1330 except Exception, e:
1331 os.close(fd)
1332 raise e
1333 os.close(fd)
1334 except OSError, ex:
1335 raise XendError("can't write guest state file %s: %s" %
1336 (dst, ex[1]))
1338 def domain_pincpu(self, domid, vcpu, cpumap):
1339 """Set which cpus vcpu can use
1341 @param domid: Domain ID or Name
1342 @type domid: int or string.
1343 @param vcpu: vcpu to pin to
1344 @type vcpu: int
1345 @param cpumap: string repr of usable cpus
1346 @type cpumap: string
1347 @rtype: 0
1348 """
1349 dominfo = self.domain_lookup_nr(domid)
1350 if not dominfo:
1351 raise XendInvalidDomain(str(domid))
1353 # if vcpu is keyword 'all', apply the cpumap to all vcpus
1354 vcpus = [ vcpu ]
1355 if str(vcpu).lower() == "all":
1356 vcpus = range(0, int(dominfo.getVCpuCount()))
1358 # set the same cpumask for all vcpus
1359 rc = 0
1360 for v in vcpus:
1361 try:
1362 rc = xc.vcpu_setaffinity(dominfo.getDomid(), int(v), cpumap)
1363 except Exception, ex:
1364 log.exception(ex)
1365 raise XendError("Cannot pin vcpu: %s to cpu: %s - %s" % \
1366 (v, cpumap, str(ex)))
1367 return rc
1369 def domain_cpu_sedf_set(self, domid, period, slice_, latency, extratime,
1370 weight):
1371 """Set Simple EDF scheduler parameters for a domain.
1373 @param domid: Domain ID or Name
1374 @type domid: int or string.
1375 @rtype: 0
1376 """
1377 dominfo = self.domain_lookup_nr(domid)
1378 if not dominfo:
1379 raise XendInvalidDomain(str(domid))
1380 try:
1381 return xc.sedf_domain_set(dominfo.getDomid(), period, slice_,
1382 latency, extratime, weight)
1383 except Exception, ex:
1384 raise XendError(str(ex))
1386 def domain_cpu_sedf_get(self, domid):
1387 """Get Simple EDF scheduler parameters for a domain.
1389 @param domid: Domain ID or Name
1390 @type domid: int or string.
1391 @rtype: SXP object
1392 @return: The parameters for Simple EDF schedule for a domain.
1393 """
1394 dominfo = self.domain_lookup_nr(domid)
1395 if not dominfo:
1396 raise XendInvalidDomain(str(domid))
1397 try:
1398 sedf_info = xc.sedf_domain_get(dominfo.getDomid())
1399 # return sxpr
1400 return ['sedf',
1401 ['domid', sedf_info['domid']],
1402 ['period', sedf_info['period']],
1403 ['slice', sedf_info['slice']],
1404 ['latency', sedf_info['latency']],
1405 ['extratime', sedf_info['extratime']],
1406 ['weight', sedf_info['weight']]]
1408 except Exception, ex:
1409 raise XendError(str(ex))
1411 def domain_shadow_control(self, domid, op):
1412 """Shadow page control.
1414 @param domid: Domain ID or Name
1415 @type domid: int or string.
1416 @param op: operation
1417 @type op: int
1418 @rtype: 0
1419 """
1420 dominfo = self.domain_lookup(domid)
1421 try:
1422 return xc.shadow_control(dominfo.getDomid(), op)
1423 except Exception, ex:
1424 raise XendError(str(ex))
1426 def domain_shadow_mem_get(self, domid):
1427 """Get shadow pagetable memory allocation.
1429 @param domid: Domain ID or Name
1430 @type domid: int or string.
1431 @rtype: int
1432 @return: shadow memory in MB
1433 """
1434 dominfo = self.domain_lookup(domid)
1435 try:
1436 return xc.shadow_mem_control(dominfo.getDomid())
1437 except Exception, ex:
1438 raise XendError(str(ex))
1440 def domain_shadow_mem_set(self, domid, mb):
1441 """Set shadow pagetable memory allocation.
1443 @param domid: Domain ID or Name
1444 @type domid: int or string.
1445 @param mb: shadow memory to set in MB
1446 @type: mb: int
1447 @rtype: int
1448 @return: shadow memory in MB
1449 """
1450 dominfo = self.domain_lookup(domid)
1451 try:
1452 return xc.shadow_mem_control(dominfo.getDomid(), mb=mb)
1453 except Exception, ex:
1454 raise XendError(str(ex))
1456 def domain_sched_credit_get(self, domid):
1457 """Get credit scheduler parameters for a domain.
1459 @param domid: Domain ID or Name
1460 @type domid: int or string.
1461 @rtype: dict with keys 'weight' and 'cap'
1462 @return: credit scheduler parameters
1463 """
1464 dominfo = self.domain_lookup_nr(domid)
1465 if not dominfo:
1466 raise XendInvalidDomain(str(domid))
1468 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1469 try:
1470 return xc.sched_credit_domain_get(dominfo.getDomid())
1471 except Exception, ex:
1472 raise XendError(str(ex))
1473 else:
1474 return {'weight' : dominfo.getWeight(),
1475 'cap' : dominfo.getCap()}
1477 def domain_sched_credit_set(self, domid, weight = None, cap = None):
1478 """Set credit scheduler parameters for a domain.
1480 @param domid: Domain ID or Name
1481 @type domid: int or string.
1482 @type weight: int
1483 @type cap: int
1484 @rtype: 0
1485 """
1486 set_weight = False
1487 set_cap = False
1488 dominfo = self.domain_lookup_nr(domid)
1489 if not dominfo:
1490 raise XendInvalidDomain(str(domid))
1491 try:
1492 if weight is None:
1493 weight = int(0)
1494 elif weight < 1 or weight > 65535:
1495 raise XendError("weight is out of range")
1496 else:
1497 set_weight = True
1499 if cap is None:
1500 cap = int(~0)
1501 elif cap < 0 or cap > dominfo.getVCpuCount() * 100:
1502 raise XendError("cap is out of range")
1503 else:
1504 set_cap = True
1506 assert type(weight) == int
1507 assert type(cap) == int
1509 rc = 0
1510 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1511 rc = xc.sched_credit_domain_set(dominfo.getDomid(), weight, cap)
1512 if rc == 0:
1513 if set_weight:
1514 dominfo.setWeight(weight)
1515 if set_cap:
1516 dominfo.setCap(cap)
1517 self.managed_config_save(dominfo)
1518 return rc
1519 except Exception, ex:
1520 log.exception(ex)
1521 raise XendError(str(ex))
1523 def domain_maxmem_set(self, domid, mem):
1524 """Set the memory limit for a domain.
1526 @param domid: Domain ID or Name
1527 @type domid: int or string.
1528 @param mem: memory limit (in MiB)
1529 @type mem: int
1530 @raise XendError: fail to set memory
1531 @rtype: 0
1532 """
1533 dominfo = self.domain_lookup_nr(domid)
1534 if not dominfo:
1535 raise XendInvalidDomain(str(domid))
1536 dominfo.setMemoryMaximum(mem)
1538 def domain_ioport_range_enable(self, domid, first, last):
1539 """Enable access to a range of IO ports for a domain
1541 @param first: first IO port
1542 @param last: last IO port
1543 @raise XendError: failed to set range
1544 @rtype: 0
1545 """
1546 dominfo = self.domain_lookup_nr(domid)
1547 if not dominfo:
1548 raise XendInvalidDomain(str(domid))
1549 nr_ports = last - first + 1
1550 try:
1551 return xc.domain_ioport_permission(dominfo.getDomid(),
1552 first_port = first,
1553 nr_ports = nr_ports,
1554 allow_access = 1)
1555 except Exception, ex:
1556 raise XendError(str(ex))
1558 def domain_ioport_range_disable(self, domid, first, last):
1559 """Disable access to a range of IO ports for a domain
1561 @param first: first IO port
1562 @param last: last IO port
1563 @raise XendError: failed to set range
1564 @rtype: 0
1565 """
1566 dominfo = self.domain_lookup_nr(domid)
1567 if not dominfo:
1568 raise XendInvalidDomain(str(domid))
1569 nr_ports = last - first + 1
1570 try:
1571 return xc.domain_ioport_permission(dominfo.getDomid(),
1572 first_port = first,
1573 nr_ports = nr_ports,
1574 allow_access = 0)
1575 except Exception, ex:
1576 raise XendError(str(ex))
1578 def domain_send_trigger(self, domid, trigger_name, vcpu = 0):
1579 """Send trigger to a domain.
1581 @param domid: Domain ID or Name
1582 @type domid: int or string.
1583 @param trigger_name: trigger type name
1584 @type trigger_name: string
1585 @param vcpu: VCPU to send trigger (default is 0)
1586 @type vcpu: int
1587 @raise XendError: failed to send trigger
1588 @raise XendInvalidDomain: Domain is not valid
1589 @rtype: 0
1590 """
1591 dominfo = self.domain_lookup_nr(domid)
1592 if not dominfo:
1593 raise XendInvalidDomain(str(domid))
1594 if dominfo._stateGet() not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1595 raise VMBadState("Domain '%s' is not started" % domid,
1596 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1597 POWER_STATE_NAMES[dominfo._stateGet()])
1598 if trigger_name.lower() in TRIGGER_TYPE.keys():
1599 trigger = TRIGGER_TYPE[trigger_name.lower()]
1600 else:
1601 raise XendError("Invalid trigger: %s" % trigger_name)
1602 try:
1603 return xc.domain_send_trigger(dominfo.getDomid(),
1604 trigger,
1605 vcpu)
1606 except Exception, ex:
1607 raise XendError(str(ex))
1610 def instance():
1611 """Singleton constructor. Use this instead of the class constructor.
1612 """
1613 global inst
1614 try:
1615 inst
1616 except:
1617 inst = XendDomain()
1618 inst.init()
1619 return inst