debuggers.hg

view tools/python/xen/xend/XendDomain.py @ 16675:9b37cabe0485

xend: Indicate a resume operation

Indicate that the domain is created as part of a resume operation
rather than a 'create'.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Dec 19 14:45:04 2007 +0000 (2007-12-19)
parents 7b4e560d6caf
children 666573856c59
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 dominfo.setResume(True)
918 dom_uuid = dominfo.get_uuid()
919 chkpath = self._managed_check_point_path(dom_uuid)
920 if not os.path.exists(chkpath):
921 raise XendError("Domain was not suspended by Xend")
923 # Restore that replaces the existing XendDomainInfo
924 try:
925 log.debug('Current DomainInfo state: %d' % dominfo._stateGet())
926 oflags = os.O_RDONLY
927 if hasattr(os, "O_LARGEFILE"):
928 oflags |= os.O_LARGEFILE
929 fd = os.open(chkpath, oflags)
930 XendCheckpoint.restore(self,
931 fd,
932 dominfo,
933 paused = start_paused)
934 os.unlink(chkpath)
935 except OSError, ex:
936 raise XendError("Failed to read stored checkpoint file")
937 except IOError, ex:
938 raise XendError("Failed to delete checkpoint file")
939 except Exception, ex:
940 log.exception("Exception occurred when resuming")
941 raise XendError("Error occurred when resuming: %s" % str(ex))
942 finally:
943 if fd is not None:
944 os.close(fd)
945 self.domains_lock.release()
948 def domain_create(self, config):
949 """Create a domain from a configuration.
951 @param config: configuration
952 @type config: SXP Object (list of lists)
953 @rtype: XendDomainInfo
954 """
955 self.domains_lock.acquire()
956 try:
957 self._refresh()
959 dominfo = XendDomainInfo.create(config)
960 return dominfo
961 finally:
962 self.domains_lock.release()
965 def domain_create_from_dict(self, config_dict):
966 """Create a domain from a configuration dictionary.
968 @param config_dict: configuration
969 @rtype: XendDomainInfo
970 """
971 self.domains_lock.acquire()
972 try:
973 self._refresh()
975 dominfo = XendDomainInfo.create_from_dict(config_dict)
976 return dominfo
977 finally:
978 self.domains_lock.release()
981 def domain_new(self, config):
982 """Create a domain from a configuration but do not start it.
984 @param config: configuration
985 @type config: SXP Object (list of lists)
986 @rtype: XendDomainInfo
987 """
988 self.domains_lock.acquire()
989 try:
990 try:
991 domconfig = XendConfig.XendConfig(sxp_obj = config)
992 dominfo = XendDomainInfo.createDormant(domconfig)
993 log.debug("Creating new managed domain: %s" %
994 dominfo.getName())
995 self._managed_domain_register(dominfo)
996 self.managed_config_save(dominfo)
997 # no return value because it isn't meaningful for client
998 except XendError, e:
999 raise
1000 except Exception, e:
1001 raise XendError(str(e))
1002 finally:
1003 self.domains_lock.release()
1005 def domain_start(self, domid, start_paused = True):
1006 """Start a managed domain
1008 @require: Domain must not be running.
1009 @param domid: Domain name or domain ID.
1010 @type domid: string or int
1011 @rtype: None
1012 @raise XendError: If domain is still running
1013 @rtype: None
1014 """
1015 self.domains_lock.acquire()
1016 try:
1017 self._refresh()
1019 dominfo = self.domain_lookup_nr(domid)
1020 if not dominfo:
1021 raise XendInvalidDomain(str(domid))
1023 if dominfo._stateGet() != DOM_STATE_HALTED:
1024 raise VMBadState("Domain is already running",
1025 POWER_STATE_NAMES[DOM_STATE_HALTED],
1026 POWER_STATE_NAMES[dominfo._stateGet()])
1028 dominfo.start(is_managed = True)
1029 finally:
1030 self.domains_lock.release()
1032 try:
1033 dominfo.waitForDevices()
1034 except Exception, ex:
1035 log.warn("Failed to setup devices for " + str(dominfo) + ": " + str(ex))
1036 dominfo.destroy()
1037 raise
1039 if not start_paused:
1040 dominfo.unpause()
1042 def domain_delete(self, domid):
1043 """Remove a managed domain from database
1045 @require: Domain must not be running.
1046 @param domid: Domain name or domain ID.
1047 @type domid: string or int
1048 @rtype: None
1049 @raise XendError: If domain is still running
1050 """
1051 self.domains_lock.acquire()
1052 try:
1053 try:
1054 dominfo = self.domain_lookup_nr(domid)
1055 if not dominfo:
1056 raise XendInvalidDomain(str(domid))
1058 if dominfo._stateGet() != XEN_API_VM_POWER_STATE_HALTED:
1059 raise VMBadState("Domain is not halted.",
1060 POWER_STATE_NAMES[DOM_STATE_HALTED],
1061 POWER_STATE_NAMES[dominfo._stateGet()])
1063 self._domain_delete_by_info(dominfo)
1064 except Exception, ex:
1065 raise XendError(str(ex))
1066 finally:
1067 self.domains_lock.release()
1070 def domain_delete_by_dominfo(self, dominfo):
1071 """Only for use by XendDomainInfo.
1072 """
1073 self.domains_lock.acquire()
1074 try:
1075 self._domain_delete_by_info(dominfo)
1076 finally:
1077 self.domains_lock.release()
1080 def _domain_delete_by_info(self, dominfo):
1081 """Expects to be protected by domains_lock.
1082 """
1083 log.info("Domain %s (%s) deleted." %
1084 (dominfo.getName(), dominfo.info.get('uuid')))
1086 dominfo.metrics.destroy()
1087 self._managed_domain_unregister(dominfo)
1088 self._remove_domain(dominfo)
1089 XendDevices.destroy_device_state(dominfo)
1092 def domain_configure(self, config):
1093 """Configure an existing domain.
1095 @param vmconfig: vm configuration
1096 @type vmconfig: SXP Object (list of lists)
1097 @todo: Not implemented
1098 """
1099 # !!!
1100 raise XendError("Unsupported")
1102 def domain_restore(self, src, paused=False):
1103 """Restore a domain from file.
1105 @param src: filename of checkpoint file to restore from
1106 @type src: string
1107 @return: Restored domain
1108 @rtype: XendDomainInfo
1109 @raise XendError: Failure to restore domain
1110 """
1111 try:
1112 oflags = os.O_RDONLY
1113 if hasattr(os, "O_LARGEFILE"):
1114 oflags |= os.O_LARGEFILE
1115 fd = os.open(src, oflags)
1116 try:
1117 return self.domain_restore_fd(fd, paused=paused)
1118 finally:
1119 os.close(fd)
1120 except OSError, ex:
1121 raise XendError("can't read guest state file %s: %s" %
1122 (src, ex[1]))
1124 def domain_restore_fd(self, fd, paused=False):
1125 """Restore a domain from the given file descriptor.
1127 @param fd: file descriptor of the checkpoint file
1128 @type fd: File object
1129 @rtype: XendDomainInfo
1130 @raise XendError: if failed to restore
1131 """
1133 try:
1134 return XendCheckpoint.restore(self, fd, paused=paused)
1135 except XendError, e:
1136 log.exception("Restore failed")
1137 raise
1138 except:
1139 # I don't really want to log this exception here, but the error
1140 # handling in the relocation-socket handling code (relocate.py) is
1141 # poor, so we need to log this for debugging.
1142 log.exception("Restore failed")
1143 raise XendError("Restore failed")
1145 def domain_unpause(self, domid):
1146 """Unpause domain execution.
1148 @param domid: Domain ID or Name
1149 @type domid: int or string.
1150 @rtype: None
1151 @raise XendError: Failed to unpause
1152 @raise XendInvalidDomain: Domain is not valid
1153 """
1154 try:
1155 dominfo = self.domain_lookup_nr(domid)
1156 if not dominfo:
1157 raise XendInvalidDomain(str(domid))
1158 if dominfo.getDomid() == DOM0_ID:
1159 raise XendError("Cannot unpause privileged domain %s" % domid)
1160 if dominfo._stateGet() not in (DOM_STATE_PAUSED, DOM_STATE_RUNNING):
1161 raise VMBadState("Domain '%s' is not started" % domid,
1162 POWER_STATE_NAMES[DOM_STATE_PAUSED],
1163 POWER_STATE_NAMES[dominfo._stateGet()])
1164 log.info("Domain %s (%d) unpaused.", dominfo.getName(),
1165 int(dominfo.getDomid()))
1166 dominfo.unpause()
1167 except XendInvalidDomain:
1168 log.exception("domain_unpause")
1169 raise
1170 except Exception, ex:
1171 log.exception("domain_unpause")
1172 raise XendError(str(ex))
1174 def domain_pause(self, domid, state=False):
1175 """Pause domain execution.
1177 @param domid: Domain ID or Name
1178 @type domid: int or string.
1179 @keyword state: If True, will return the domain state before pause
1180 @type state: bool
1181 @rtype: int if state is True
1182 @return: Domain state (DOM_STATE_*)
1183 @rtype: None if state is False
1184 @raise XendError: Failed to pause
1185 @raise XendInvalidDomain: Domain is not valid
1186 """
1187 try:
1188 dominfo = self.domain_lookup_nr(domid)
1189 if not dominfo:
1190 raise XendInvalidDomain(str(domid))
1191 if dominfo.getDomid() == DOM0_ID:
1192 raise XendError("Cannot pause privileged domain %s" % domid)
1193 ds = dominfo._stateGet()
1194 if ds not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1195 raise VMBadState("Domain '%s' is not started" % domid,
1196 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1197 POWER_STATE_NAMES[ds])
1198 log.info("Domain %s (%d) paused.", dominfo.getName(),
1199 int(dominfo.getDomid()))
1200 dominfo.pause()
1201 if state:
1202 return ds
1203 except XendInvalidDomain:
1204 log.exception("domain_pause")
1205 raise
1206 except Exception, ex:
1207 log.exception("domain_pause")
1208 raise XendError(str(ex))
1210 def domain_dump(self, domid, filename, live, crash):
1211 """Dump domain core."""
1213 dominfo = self.domain_lookup_nr(domid)
1214 if not dominfo:
1215 raise XendInvalidDomain(str(domid))
1217 if dominfo.getDomid() == DOM0_ID:
1218 raise XendError("Cannot dump core for privileged domain %s" % domid)
1219 if dominfo._stateGet() not in (DOM_STATE_PAUSED, DOM_STATE_RUNNING):
1220 raise VMBadState("Domain '%s' is not started" % domid,
1221 POWER_STATE_NAMES[DOM_STATE_PAUSED],
1222 POWER_STATE_NAMES[dominfo._stateGet()])
1224 try:
1225 log.info("Domain core dump requested for domain %s (%d) "
1226 "live=%d crash=%d.",
1227 dominfo.getName(), dominfo.getDomid(), live, crash)
1228 return dominfo.dumpCore(filename)
1229 except Exception, ex:
1230 raise XendError(str(ex))
1232 def domain_destroy(self, domid):
1233 """Terminate domain immediately.
1235 @param domid: Domain ID or Name
1236 @type domid: int or string.
1237 @rtype: None
1238 @raise XendError: Failed to destroy
1239 @raise XendInvalidDomain: Domain is not valid
1240 """
1242 dominfo = self.domain_lookup_nr(domid)
1243 if dominfo and dominfo.getDomid() == DOM0_ID:
1244 raise XendError("Cannot destroy privileged domain %s" % domid)
1246 if dominfo:
1247 val = dominfo.destroy()
1248 else:
1249 try:
1250 val = xc.domain_destroy(int(domid))
1251 except ValueError:
1252 raise XendInvalidDomain(domid)
1253 except Exception, e:
1254 raise XendError(str(e))
1256 return val
1258 def domain_migrate(self, domid, dst, live=False, resource=0, port=0):
1259 """Start domain migration.
1261 @param domid: Domain ID or Name
1262 @type domid: int or string.
1263 @param dst: Destination IP address
1264 @type dst: string
1265 @keyword port: relocation port on destination
1266 @type port: int
1267 @keyword live: Live migration
1268 @type live: bool
1269 @keyword resource: not used??
1270 @rtype: None
1271 @raise XendError: Failed to migrate
1272 @raise XendInvalidDomain: Domain is not valid
1273 """
1275 dominfo = self.domain_lookup_nr(domid)
1276 if not dominfo:
1277 raise XendInvalidDomain(str(domid))
1279 if dominfo.getDomid() == DOM0_ID:
1280 raise XendError("Cannot migrate privileged domain %s" % domid)
1282 """ The following call may raise a XendError exception """
1283 dominfo.testMigrateDevices(True, dst)
1285 if live:
1286 """ Make sure there's memory free for enabling shadow mode """
1287 dominfo.checkLiveMigrateMemory()
1289 if port == 0:
1290 port = xoptions.get_xend_relocation_port()
1291 try:
1292 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1293 sock.connect((dst, port))
1294 except socket.error, err:
1295 raise XendError("can't connect: %s" % err[1])
1297 sock.send("receive\n")
1298 sock.recv(80)
1299 XendCheckpoint.save(sock.fileno(), dominfo, True, live, dst)
1300 sock.close()
1302 def domain_save(self, domid, dst, checkpoint=False):
1303 """Start saving a domain to file.
1305 @param domid: Domain ID or Name
1306 @type domid: int or string.
1307 @param dst: Destination filename
1308 @type dst: string
1309 @rtype: None
1310 @raise XendError: Failed to save domain
1311 @raise XendInvalidDomain: Domain is not valid
1312 """
1313 try:
1314 dominfo = self.domain_lookup_nr(domid)
1315 if not dominfo:
1316 raise XendInvalidDomain(str(domid))
1318 if dominfo.getDomid() == DOM0_ID:
1319 raise XendError("Cannot save privileged domain %s" % str(domid))
1320 if dominfo._stateGet() != DOM_STATE_RUNNING:
1321 raise VMBadState("Domain is not running",
1322 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1323 POWER_STATE_NAMES[dominfo._stateGet()])
1325 oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
1326 if hasattr(os, "O_LARGEFILE"):
1327 oflags |= os.O_LARGEFILE
1328 fd = os.open(dst, oflags)
1329 try:
1330 XendCheckpoint.save(fd, dominfo, False, False, dst,
1331 checkpoint=checkpoint)
1332 except Exception, e:
1333 os.close(fd)
1334 raise e
1335 os.close(fd)
1336 except OSError, ex:
1337 raise XendError("can't write guest state file %s: %s" %
1338 (dst, ex[1]))
1340 def domain_pincpu(self, domid, vcpu, cpumap):
1341 """Set which cpus vcpu can use
1343 @param domid: Domain ID or Name
1344 @type domid: int or string.
1345 @param vcpu: vcpu to pin to
1346 @type vcpu: int
1347 @param cpumap: string repr of usable cpus
1348 @type cpumap: string
1349 @rtype: 0
1350 """
1351 dominfo = self.domain_lookup_nr(domid)
1352 if not dominfo:
1353 raise XendInvalidDomain(str(domid))
1355 # if vcpu is keyword 'all', apply the cpumap to all vcpus
1356 vcpus = [ vcpu ]
1357 if str(vcpu).lower() == "all":
1358 vcpus = range(0, int(dominfo.getVCpuCount()))
1360 # set the same cpumask for all vcpus
1361 rc = 0
1362 for v in vcpus:
1363 try:
1364 rc = xc.vcpu_setaffinity(dominfo.getDomid(), int(v), cpumap)
1365 except Exception, ex:
1366 log.exception(ex)
1367 raise XendError("Cannot pin vcpu: %s to cpu: %s - %s" % \
1368 (v, cpumap, str(ex)))
1369 return rc
1371 def domain_cpu_sedf_set(self, domid, period, slice_, latency, extratime,
1372 weight):
1373 """Set Simple EDF scheduler parameters for a domain.
1375 @param domid: Domain ID or Name
1376 @type domid: int or string.
1377 @rtype: 0
1378 """
1379 dominfo = self.domain_lookup_nr(domid)
1380 if not dominfo:
1381 raise XendInvalidDomain(str(domid))
1382 try:
1383 return xc.sedf_domain_set(dominfo.getDomid(), period, slice_,
1384 latency, extratime, weight)
1385 except Exception, ex:
1386 raise XendError(str(ex))
1388 def domain_cpu_sedf_get(self, domid):
1389 """Get Simple EDF scheduler parameters for a domain.
1391 @param domid: Domain ID or Name
1392 @type domid: int or string.
1393 @rtype: SXP object
1394 @return: The parameters for Simple EDF schedule for a domain.
1395 """
1396 dominfo = self.domain_lookup_nr(domid)
1397 if not dominfo:
1398 raise XendInvalidDomain(str(domid))
1399 try:
1400 sedf_info = xc.sedf_domain_get(dominfo.getDomid())
1401 # return sxpr
1402 return ['sedf',
1403 ['domid', sedf_info['domid']],
1404 ['period', sedf_info['period']],
1405 ['slice', sedf_info['slice']],
1406 ['latency', sedf_info['latency']],
1407 ['extratime', sedf_info['extratime']],
1408 ['weight', sedf_info['weight']]]
1410 except Exception, ex:
1411 raise XendError(str(ex))
1413 def domain_shadow_control(self, domid, op):
1414 """Shadow page control.
1416 @param domid: Domain ID or Name
1417 @type domid: int or string.
1418 @param op: operation
1419 @type op: int
1420 @rtype: 0
1421 """
1422 dominfo = self.domain_lookup(domid)
1423 try:
1424 return xc.shadow_control(dominfo.getDomid(), op)
1425 except Exception, ex:
1426 raise XendError(str(ex))
1428 def domain_shadow_mem_get(self, domid):
1429 """Get shadow pagetable memory allocation.
1431 @param domid: Domain ID or Name
1432 @type domid: int or string.
1433 @rtype: int
1434 @return: shadow memory in MB
1435 """
1436 dominfo = self.domain_lookup(domid)
1437 try:
1438 return xc.shadow_mem_control(dominfo.getDomid())
1439 except Exception, ex:
1440 raise XendError(str(ex))
1442 def domain_shadow_mem_set(self, domid, mb):
1443 """Set shadow pagetable memory allocation.
1445 @param domid: Domain ID or Name
1446 @type domid: int or string.
1447 @param mb: shadow memory to set in MB
1448 @type: mb: int
1449 @rtype: int
1450 @return: shadow memory in MB
1451 """
1452 dominfo = self.domain_lookup(domid)
1453 try:
1454 return xc.shadow_mem_control(dominfo.getDomid(), mb=mb)
1455 except Exception, ex:
1456 raise XendError(str(ex))
1458 def domain_sched_credit_get(self, domid):
1459 """Get credit scheduler parameters for a domain.
1461 @param domid: Domain ID or Name
1462 @type domid: int or string.
1463 @rtype: dict with keys 'weight' and 'cap'
1464 @return: credit scheduler parameters
1465 """
1466 dominfo = self.domain_lookup_nr(domid)
1467 if not dominfo:
1468 raise XendInvalidDomain(str(domid))
1470 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1471 try:
1472 return xc.sched_credit_domain_get(dominfo.getDomid())
1473 except Exception, ex:
1474 raise XendError(str(ex))
1475 else:
1476 return {'weight' : dominfo.getWeight(),
1477 'cap' : dominfo.getCap()}
1479 def domain_sched_credit_set(self, domid, weight = None, cap = None):
1480 """Set credit scheduler parameters for a domain.
1482 @param domid: Domain ID or Name
1483 @type domid: int or string.
1484 @type weight: int
1485 @type cap: int
1486 @rtype: 0
1487 """
1488 set_weight = False
1489 set_cap = False
1490 dominfo = self.domain_lookup_nr(domid)
1491 if not dominfo:
1492 raise XendInvalidDomain(str(domid))
1493 try:
1494 if weight is None:
1495 weight = int(0)
1496 elif weight < 1 or weight > 65535:
1497 raise XendError("weight is out of range")
1498 else:
1499 set_weight = True
1501 if cap is None:
1502 cap = int(~0)
1503 elif cap < 0 or cap > dominfo.getVCpuCount() * 100:
1504 raise XendError("cap is out of range")
1505 else:
1506 set_cap = True
1508 assert type(weight) == int
1509 assert type(cap) == int
1511 rc = 0
1512 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1513 rc = xc.sched_credit_domain_set(dominfo.getDomid(), weight, cap)
1514 if rc == 0:
1515 if set_weight:
1516 dominfo.setWeight(weight)
1517 if set_cap:
1518 dominfo.setCap(cap)
1519 self.managed_config_save(dominfo)
1520 return rc
1521 except Exception, ex:
1522 log.exception(ex)
1523 raise XendError(str(ex))
1525 def domain_maxmem_set(self, domid, mem):
1526 """Set the memory limit for a domain.
1528 @param domid: Domain ID or Name
1529 @type domid: int or string.
1530 @param mem: memory limit (in MiB)
1531 @type mem: int
1532 @raise XendError: fail to set memory
1533 @rtype: 0
1534 """
1535 dominfo = self.domain_lookup_nr(domid)
1536 if not dominfo:
1537 raise XendInvalidDomain(str(domid))
1538 dominfo.setMemoryMaximum(mem)
1540 def domain_ioport_range_enable(self, domid, first, last):
1541 """Enable access to a range of IO ports for a domain
1543 @param first: first IO port
1544 @param last: last IO port
1545 @raise XendError: failed to set range
1546 @rtype: 0
1547 """
1548 dominfo = self.domain_lookup_nr(domid)
1549 if not dominfo:
1550 raise XendInvalidDomain(str(domid))
1551 nr_ports = last - first + 1
1552 try:
1553 return xc.domain_ioport_permission(dominfo.getDomid(),
1554 first_port = first,
1555 nr_ports = nr_ports,
1556 allow_access = 1)
1557 except Exception, ex:
1558 raise XendError(str(ex))
1560 def domain_ioport_range_disable(self, domid, first, last):
1561 """Disable access to a range of IO ports for a domain
1563 @param first: first IO port
1564 @param last: last IO port
1565 @raise XendError: failed to set range
1566 @rtype: 0
1567 """
1568 dominfo = self.domain_lookup_nr(domid)
1569 if not dominfo:
1570 raise XendInvalidDomain(str(domid))
1571 nr_ports = last - first + 1
1572 try:
1573 return xc.domain_ioport_permission(dominfo.getDomid(),
1574 first_port = first,
1575 nr_ports = nr_ports,
1576 allow_access = 0)
1577 except Exception, ex:
1578 raise XendError(str(ex))
1580 def domain_send_trigger(self, domid, trigger_name, vcpu = 0):
1581 """Send trigger to a domain.
1583 @param domid: Domain ID or Name
1584 @type domid: int or string.
1585 @param trigger_name: trigger type name
1586 @type trigger_name: string
1587 @param vcpu: VCPU to send trigger (default is 0)
1588 @type vcpu: int
1589 @raise XendError: failed to send trigger
1590 @raise XendInvalidDomain: Domain is not valid
1591 @rtype: 0
1592 """
1593 dominfo = self.domain_lookup_nr(domid)
1594 if not dominfo:
1595 raise XendInvalidDomain(str(domid))
1596 if dominfo._stateGet() not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1597 raise VMBadState("Domain '%s' is not started" % domid,
1598 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1599 POWER_STATE_NAMES[dominfo._stateGet()])
1600 if trigger_name.lower() in TRIGGER_TYPE.keys():
1601 trigger = TRIGGER_TYPE[trigger_name.lower()]
1602 else:
1603 raise XendError("Invalid trigger: %s" % trigger_name)
1604 try:
1605 return xc.domain_send_trigger(dominfo.getDomid(),
1606 trigger,
1607 vcpu)
1608 except Exception, ex:
1609 raise XendError(str(ex))
1612 def instance():
1613 """Singleton constructor. Use this instead of the class constructor.
1614 """
1615 global inst
1616 try:
1617 inst
1618 except:
1619 inst = XendDomain()
1620 inst.init()
1621 return inst