ia64/xen-unstable
annotate tools/python/xen/xend/XendDomain.py @ 19580:a63d20d7a941
xend: Fix for op_pincpu in SrvDomain.py
op_pincpu method in SrvDomain.py does not currently work because
op_pincpu method gives string objects to a cpumap argument of
domain_pincpu method in XendDomain.py though the cpumap argument
expects list objects.
This patch solves the above problem as follows.
op_pincpu method gives string objects to the cpumap argument as is,
because op_pincpu method cannot give list objects to the cpumap
argument.
Instead, domain_pincpu method expects that the cpumap argument is
string objects, then domain_pincpu method converts the cpumap
argument into list objects.
Also, the patch modifies two methods (except for op_pincpu method)
calling domain_pincpu method. The methods give string objects to
the cpumap argument instead of list objects.
Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
op_pincpu method in SrvDomain.py does not currently work because
op_pincpu method gives string objects to a cpumap argument of
domain_pincpu method in XendDomain.py though the cpumap argument
expects list objects.
This patch solves the above problem as follows.
op_pincpu method gives string objects to the cpumap argument as is,
because op_pincpu method cannot give list objects to the cpumap
argument.
Instead, domain_pincpu method expects that the cpumap argument is
string objects, then domain_pincpu method converts the cpumap
argument into list objects.
Also, the patch modifies two methods (except for op_pincpu method)
calling domain_pincpu method. The methods give string objects to
the cpumap argument instead of list objects.
Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author | Keir Fraser <keir.fraser@citrix.com> |
---|---|
date | Mon Apr 27 15:42:38 2009 +0100 (2009-04-27) |
parents | 01873414cfc1 |
children | 94bf7d4854eb |
rev | line source |
---|---|
kaf24@6079 | 1 #============================================================================ |
kaf24@6079 | 2 # This library is free software; you can redistribute it and/or |
kaf24@6079 | 3 # modify it under the terms of version 2.1 of the GNU Lesser General Public |
kaf24@6079 | 4 # License as published by the Free Software Foundation. |
kaf24@6079 | 5 # |
kaf24@6079 | 6 # This library is distributed in the hope that it will be useful, |
kaf24@6079 | 7 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
kaf24@6079 | 8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
kaf24@6079 | 9 # Lesser General Public License for more details. |
kaf24@6079 | 10 # |
kaf24@6079 | 11 # You should have received a copy of the GNU Lesser General Public |
kaf24@6079 | 12 # License along with this library; if not, write to the Free Software |
kaf24@6079 | 13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
kaf24@6079 | 14 #============================================================================ |
kaf24@6079 | 15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com> |
cl349@5124 | 16 # Copyright (C) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk> |
emellor@7006 | 17 # Copyright (C) 2005 XenSource Ltd |
kaf24@6079 | 18 #============================================================================ |
mjw@1623 | 19 |
mjw@1623 | 20 """Handler for domain operations. |
mjw@1623 | 21 Nothing here is persistent (across reboots). |
mjw@1623 | 22 Needs to be persistent for one uptime. |
mjw@1623 | 23 """ |
emellor@7414 | 24 |
cl349@5144 | 25 import os |
ewan@12725 | 26 import stat |
atse@12085 | 27 import shutil |
emellor@8144 | 28 import socket |
ewan@13073 | 29 import tempfile |
emellor@7151 | 30 import threading |
mjw@1623 | 31 |
emellor@7026 | 32 import xen.lowlevel.xc |
mjw@1623 | 33 |
emellor@7176 | 34 |
ewan@14141 | 35 from xen.xend import XendOptions, XendCheckpoint, XendDomainInfo |
atse@12085 | 36 from xen.xend.PrettyPrint import prettyprint |
keir@17849 | 37 from xen.xend import XendConfig, image |
atse@12510 | 38 from xen.xend.XendError import XendError, XendInvalidDomain, VmError |
ewan@13194 | 39 from xen.xend.XendError import VMBadState |
cl349@5336 | 40 from xen.xend.XendLogging import log |
ewan@12615 | 41 from xen.xend.XendAPIConstants import XEN_API_VM_POWER_STATE |
atse@12085 | 42 from xen.xend.XendConstants import XS_VMROOT |
ewan@12615 | 43 from xen.xend.XendConstants import DOM_STATE_HALTED, DOM_STATE_PAUSED |
ewan@12615 | 44 from xen.xend.XendConstants import DOM_STATE_RUNNING, DOM_STATE_SUSPENDED |
ewan@12615 | 45 from xen.xend.XendConstants import DOM_STATE_SHUTDOWN, DOM_STATE_UNKNOWN |
keir@17715 | 46 from xen.xend.XendConstants import DOM_STATE_CRASHED, HVM_PARAM_ACPI_S_STATE |
keir@17715 | 47 from xen.xend.XendConstants import TRIGGER_TYPE, TRIGGER_S3RESUME |
ewan@12530 | 48 from xen.xend.XendDevices import XendDevices |
tom@14887 | 49 from xen.xend.XendAPIConstants import * |
atse@12085 | 50 |
emellor@8190 | 51 from xen.xend.xenstore.xstransact import xstransact |
emellor@7837 | 52 from xen.xend.xenstore.xswatch import xswatch |
keir@18772 | 53 from xen.util import mkdir, rwlock |
atse@12085 | 54 from xen.xend import uuid |
emellor@7026 | 55 |
emellor@7973 | 56 xc = xen.lowlevel.xc.xc() |
ewan@13484 | 57 xoptions = XendOptions.instance() |
emellor@7026 | 58 |
mjw@1623 | 59 __all__ = [ "XendDomain" ] |
mjw@4580 | 60 |
atse@12085 | 61 CACHED_CONFIG_FILE = 'config.sxp' |
atse@12085 | 62 CHECK_POINT_FILE = 'checkpoint.chk' |
atse@12085 | 63 DOM0_UUID = "00000000-0000-0000-0000-000000000000" |
atse@12085 | 64 DOM0_NAME = "Domain-0" |
atse@12085 | 65 DOM0_ID = 0 |
cl349@6922 | 66 |
ewan@12615 | 67 POWER_STATE_NAMES = dict([(x, XEN_API_VM_POWER_STATE[x]) |
ewan@12615 | 68 for x in [DOM_STATE_HALTED, |
ewan@12615 | 69 DOM_STATE_PAUSED, |
ewan@12615 | 70 DOM_STATE_RUNNING, |
ewan@12615 | 71 DOM_STATE_SUSPENDED, |
ewan@12615 | 72 DOM_STATE_SHUTDOWN, |
keir@16883 | 73 DOM_STATE_CRASHED, |
ewan@12615 | 74 DOM_STATE_UNKNOWN]]) |
ewan@12615 | 75 POWER_STATE_ALL = 'all' |
ewan@12615 | 76 |
ewan@12615 | 77 |
mjw@1623 | 78 class XendDomain: |
mjw@1623 | 79 """Index of all domains. Singleton. |
atse@12085 | 80 |
atse@12330 | 81 @ivar domains: map of domains indexed by domid |
atse@12085 | 82 @type domains: dict of XendDomainInfo |
atse@12330 | 83 @ivar managed_domains: domains that are not running and managed by Xend |
atse@12330 | 84 @type managed_domains: dict of XendDomainInfo indexed by uuid |
atse@12085 | 85 @ivar domains_lock: lock that must be held when manipulating self.domains |
atse@12085 | 86 @type domains_lock: threaading.RLock |
atse@12085 | 87 @ivar _allow_new_domains: Flag to set that allows creating of new domains. |
atse@12085 | 88 @type _allow_new_domains: boolean |
mjw@1623 | 89 """ |
mjw@1673 | 90 |
mjw@1623 | 91 def __init__(self): |
emellor@7176 | 92 self.domains = {} |
atse@12230 | 93 self.managed_domains = {} |
emellor@7348 | 94 self.domains_lock = threading.RLock() |
emellor@7837 | 95 |
keir@18772 | 96 self.policy_lock = rwlock.RWLock() |
keir@18772 | 97 |
atse@12085 | 98 # xen api instance vars |
atse@12085 | 99 # TODO: nothing uses this at the moment |
atse@12085 | 100 self._allow_new_domains = True |
emellor@8144 | 101 |
emellor@8144 | 102 # This must be called only the once, by instance() below. It is separate |
emellor@8144 | 103 # from the constructor because XendDomainInfo calls back into this class |
emellor@8144 | 104 # in order to check the uniqueness of domain names. This means that |
emellor@8144 | 105 # instance() must be able to return a valid instance of this class even |
emellor@8144 | 106 # during this initialisation. |
emellor@8144 | 107 def init(self): |
atse@12085 | 108 """Singleton initialisation function.""" |
atse@12085 | 109 |
ewan@12206 | 110 dom_path = self._managed_path() |
ewan@12725 | 111 mkdir.parents(dom_path, stat.S_IRWXU) |
ewan@12206 | 112 |
atse@12085 | 113 xstransact.Mkdir(XS_VMROOT) |
atse@12085 | 114 xstransact.SetPermissions(XS_VMROOT, {'dom': DOM0_ID}) |
emellor@8190 | 115 |
emellor@7176 | 116 self.domains_lock.acquire() |
emellor@7176 | 117 try: |
atse@12085 | 118 try: |
atse@12085 | 119 dom0info = [d for d in self._running_domains() \ |
ewan@12144 | 120 if d.get('domid') == DOM0_ID][0] |
atse@12085 | 121 |
atse@12141 | 122 dom0info['name'] = DOM0_NAME |
atse@12085 | 123 dom0 = XendDomainInfo.recreate(dom0info, True) |
atse@12085 | 124 except IndexError: |
atse@12085 | 125 raise XendError('Unable to find Domain 0') |
atse@12085 | 126 |
atse@12085 | 127 self._setDom0CPUCount() |
emellor@7861 | 128 |
emellor@7861 | 129 # This watch registration needs to be before the refresh call, so |
emellor@7861 | 130 # that we're sure that we haven't missed any releases, but inside |
emellor@7861 | 131 # the domains_lock, as we don't want the watch to fire until after |
emellor@7861 | 132 # the refresh call has completed. |
atse@12085 | 133 xswatch("@introduceDomain", self._on_domains_changed) |
atse@12085 | 134 xswatch("@releaseDomain", self._on_domains_changed) |
atse@12085 | 135 |
atse@12085 | 136 self._init_domains() |
emellor@7176 | 137 finally: |
emellor@7176 | 138 self.domains_lock.release() |
emellor@7176 | 139 |
atse@12085 | 140 |
atse@12085 | 141 def _on_domains_changed(self, _): |
atse@12085 | 142 """ Callback method when xenstore changes. |
mjw@1623 | 143 |
atse@12085 | 144 Calls refresh which will keep the local cache of domains |
atse@12085 | 145 in sync. |
cl349@5014 | 146 |
atse@12085 | 147 @rtype: int |
atse@12085 | 148 @return: 1 |
cl349@5017 | 149 """ |
emellor@7176 | 150 self.domains_lock.acquire() |
emellor@7176 | 151 try: |
atse@12085 | 152 self._refresh() |
atse@12085 | 153 finally: |
atse@12085 | 154 self.domains_lock.release() |
atse@12085 | 155 return 1 |
atse@12085 | 156 |
atse@12085 | 157 def _init_domains(self): |
atse@12085 | 158 """Does the initial scan of managed and active domains to |
atse@12085 | 159 populate self.domains. |
atse@12085 | 160 |
atse@12085 | 161 Note: L{XendDomainInfo._checkName} will call back into XendDomain |
atse@12085 | 162 to make sure domain name is not a duplicate. |
atse@12085 | 163 |
atse@12085 | 164 """ |
atse@12085 | 165 self.domains_lock.acquire() |
atse@12085 | 166 try: |
atse@12085 | 167 running = self._running_domains() |
atse@12085 | 168 managed = self._managed_domains() |
atse@12085 | 169 |
atse@12114 | 170 # add all active domains |
atse@12085 | 171 for dom in running: |
ewan@12325 | 172 if dom['dying'] == 1: |
ewan@12325 | 173 log.warn('Ignoring dying domain %d from now on' % |
ewan@12325 | 174 dom['domid']) |
ewan@12325 | 175 continue |
ewan@12325 | 176 |
atse@12085 | 177 if dom['domid'] != DOM0_ID: |
atse@12085 | 178 try: |
atse@12085 | 179 new_dom = XendDomainInfo.recreate(dom, False) |
atse@12085 | 180 except Exception: |
atse@12085 | 181 log.exception("Failed to create reference to running " |
atse@12085 | 182 "domain id: %d" % dom['domid']) |
atse@12085 | 183 |
keir@17849 | 184 image.cleanup_stale_sentinel_fifos() |
keir@17849 | 185 |
atse@12085 | 186 # add all managed domains as dormant domains. |
atse@12085 | 187 for dom in managed: |
atse@12331 | 188 dom_uuid = dom.get('uuid') |
atse@12331 | 189 if not dom_uuid: |
atse@12331 | 190 continue |
atse@12331 | 191 |
ewan@12709 | 192 dom_name = dom.get('name_label', 'Domain-%s' % dom_uuid) |
atse@12085 | 193 try: |
atse@12114 | 194 running_dom = self.domain_lookup_nr(dom_name) |
atse@12114 | 195 if not running_dom: |
atse@12114 | 196 # instantiate domain if not started. |
atse@12085 | 197 new_dom = XendDomainInfo.createDormant(dom) |
atse@12114 | 198 self._managed_domain_register(new_dom) |
ewan@12714 | 199 else: |
ewan@12714 | 200 self._managed_domain_register(running_dom) |
ewan@14523 | 201 for key in XendConfig.XENAPI_CFG_TYPES.keys(): |
ewan@14523 | 202 if key not in XendConfig.LEGACY_XENSTORE_VM_PARAMS and \ |
ewan@14523 | 203 key in dom: |
ewan@14523 | 204 running_dom.info[key] = dom[key] |
atse@12085 | 205 except Exception: |
atse@12085 | 206 log.exception("Failed to create reference to managed " |
atse@12085 | 207 "domain: %s" % dom_name) |
atse@12085 | 208 |
emellor@7176 | 209 finally: |
emellor@7176 | 210 self.domains_lock.release() |
emellor@7176 | 211 |
cl349@6585 | 212 |
atse@12085 | 213 # ----------------------------------------------------------------- |
atse@12085 | 214 # Getting managed domains storage path names |
cl349@6585 | 215 |
atse@12085 | 216 def _managed_path(self, domuuid = None): |
atse@12085 | 217 """Returns the path of the directory where managed domain |
atse@12085 | 218 information is stored. |
atse@12085 | 219 |
atse@12085 | 220 @keyword domuuid: If not None, will return the path to the domain |
atse@12085 | 221 otherwise, will return the path containing |
atse@12085 | 222 the directories which represent each domain. |
atse@12085 | 223 @type: None or String. |
atse@12085 | 224 @rtype: String |
atse@12085 | 225 @return: Path. |
cl349@6585 | 226 """ |
ewan@13484 | 227 dom_path = xoptions.get_xend_domains_path() |
atse@12085 | 228 if domuuid: |
atse@12085 | 229 dom_path = os.path.join(dom_path, domuuid) |
atse@12085 | 230 return dom_path |
cl349@6585 | 231 |
atse@12085 | 232 def _managed_config_path(self, domuuid): |
atse@12085 | 233 """Returns the path to the configuration file of a managed domain. |
cl349@6585 | 234 |
atse@12085 | 235 @param domname: Domain uuid |
atse@12085 | 236 @type domname: String |
atse@12085 | 237 @rtype: String |
atse@12085 | 238 @return: path to config file. |
cl349@6585 | 239 """ |
atse@12085 | 240 return os.path.join(self._managed_path(domuuid), CACHED_CONFIG_FILE) |
atse@12085 | 241 |
atse@12085 | 242 def _managed_check_point_path(self, domuuid): |
atse@12085 | 243 """Returns absolute path to check point file for managed domain. |
atse@12085 | 244 |
atse@12085 | 245 @param domuuid: Name of managed domain |
atse@12085 | 246 @type domname: String |
atse@12085 | 247 @rtype: String |
atse@12085 | 248 @return: Path |
atse@12085 | 249 """ |
atse@12085 | 250 return os.path.join(self._managed_path(domuuid), CHECK_POINT_FILE) |
atse@12085 | 251 |
atse@12085 | 252 def _managed_config_remove(self, domuuid): |
atse@12085 | 253 """Removes a domain configuration from managed list |
atse@12085 | 254 |
atse@12085 | 255 @param domuuid: Name of managed domain |
atse@12085 | 256 @type domname: String |
atse@12085 | 257 @raise XendError: fails to remove the domain. |
atse@12085 | 258 """ |
atse@12085 | 259 config_path = self._managed_path(domuuid) |
atse@12085 | 260 try: |
atse@12085 | 261 if os.path.exists(config_path) and os.path.isdir(config_path): |
atse@12085 | 262 shutil.rmtree(config_path) |
atse@12085 | 263 except IOError: |
atse@12085 | 264 log.exception('managed_config_remove failed removing conf') |
atse@12085 | 265 raise XendError("Unable to remove managed configuration" |
atse@12085 | 266 " for domain: %s" % domuuid) |
atse@12085 | 267 |
atse@12085 | 268 def managed_config_save(self, dominfo): |
atse@12085 | 269 """Save a domain's configuration to disk |
atse@12085 | 270 |
atse@12085 | 271 @param domninfo: Managed domain to save. |
atse@12085 | 272 @type dominfo: XendDomainInfo |
atse@12085 | 273 @raise XendError: fails to save configuration. |
atse@12085 | 274 @rtype: None |
atse@12085 | 275 """ |
atse@12114 | 276 if not self.is_domain_managed(dominfo): |
atse@12114 | 277 return # refuse to save configuration this domain isn't managed |
atse@12114 | 278 |
atse@12085 | 279 if dominfo: |
atse@12085 | 280 domains_dir = self._managed_path() |
atse@12085 | 281 dom_uuid = dominfo.get_uuid() |
atse@12085 | 282 domain_config_dir = self._managed_path(dom_uuid) |
ewan@12725 | 283 |
ewan@12725 | 284 def make_or_raise(path): |
atse@12085 | 285 try: |
ewan@12725 | 286 mkdir.parents(path, stat.S_IRWXU) |
ewan@12725 | 287 except: |
ewan@12725 | 288 log.exception("%s could not be created." % path) |
ewan@12725 | 289 raise XendError("%s could not be created." % path) |
ewan@12725 | 290 |
ewan@12725 | 291 make_or_raise(domains_dir) |
ewan@12725 | 292 make_or_raise(domain_config_dir) |
ewan@12725 | 293 |
atse@12085 | 294 try: |
ewan@13073 | 295 fd, fn = tempfile.mkstemp() |
ewan@13073 | 296 f = os.fdopen(fd, 'w+b') |
ewan@13073 | 297 try: |
ewan@13074 | 298 prettyprint(dominfo.sxpr(legacy_only = False), f, |
ewan@13074 | 299 width = 78) |
ewan@13073 | 300 finally: |
ewan@13073 | 301 f.close() |
tom@14967 | 302 |
ewan@13073 | 303 try: |
tom@14967 | 304 shutil.move(fn, self._managed_config_path(dom_uuid)) |
ewan@13073 | 305 except: |
tom@14967 | 306 log.exception("Renaming %s to %s", fn, |
tom@14967 | 307 self._managed_config_path(dom_uuid)) |
ewan@13073 | 308 os.remove(fn) |
atse@12510 | 309 except: |
atse@12510 | 310 log.exception("Error occurred saving configuration file " + |
atse@12510 | 311 "to %s" % domain_config_dir) |
atse@12085 | 312 raise XendError("Failed to save configuration file to: %s" % |
atse@12085 | 313 domain_config_dir) |
atse@12085 | 314 else: |
atse@12085 | 315 log.warn("Trying to save configuration for invalid domain") |
cl349@6585 | 316 |
emellor@7151 | 317 |
atse@12085 | 318 def _managed_domains(self): |
atse@12085 | 319 """ Returns list of domains that are managed. |
atse@12085 | 320 |
atse@12085 | 321 Expects to be protected by domains_lock. |
cl349@6677 | 322 |
atse@12085 | 323 @rtype: list of XendConfig |
atse@12085 | 324 @return: List of domain configurations that are managed. |
mjw@1623 | 325 """ |
atse@12085 | 326 dom_path = self._managed_path() |
atse@12085 | 327 dom_uuids = os.listdir(dom_path) |
atse@12085 | 328 doms = [] |
atse@12085 | 329 for dom_uuid in dom_uuids: |
atse@12085 | 330 try: |
atse@12085 | 331 cfg_file = self._managed_config_path(dom_uuid) |
ewan@14523 | 332 cfg = XendConfig.XendConfig(filename = cfg_file) |
atse@12331 | 333 if cfg.get('uuid') != dom_uuid: |
atse@12331 | 334 # something is wrong with the SXP |
atse@12331 | 335 log.error("UUID mismatch in stored configuration: %s" % |
atse@12331 | 336 cfg_file) |
atse@12331 | 337 continue |
atse@12085 | 338 doms.append(cfg) |
atse@12085 | 339 except Exception: |
atse@12085 | 340 log.exception('Unable to open or parse config.sxp: %s' % \ |
atse@12085 | 341 cfg_file) |
mjw@4580 | 342 return doms |
mjw@4580 | 343 |
atse@12085 | 344 def _managed_domain_unregister(self, dom): |
atse@12085 | 345 try: |
atse@12230 | 346 if self.is_domain_managed(dom): |
atse@12342 | 347 self._managed_config_remove(dom.get_uuid()) |
atse@12230 | 348 del self.managed_domains[dom.get_uuid()] |
keir@18518 | 349 dom.destroy_xapi_instances() |
atse@12085 | 350 except ValueError: |
atse@12085 | 351 log.warn("Domain is not registered: %s" % dom.get_uuid()) |
emellor@7072 | 352 |
atse@12085 | 353 def _managed_domain_register(self, dom): |
atse@12230 | 354 self.managed_domains[dom.get_uuid()] = dom |
atse@12085 | 355 |
atse@12230 | 356 def is_domain_managed(self, dom = None): |
atse@12230 | 357 return (dom.get_uuid() in self.managed_domains) |
atse@12085 | 358 |
atse@12085 | 359 # End of Managed Domain Access |
atse@12085 | 360 # -------------------------------------------------------------------- |
atse@12085 | 361 |
atse@12085 | 362 def _running_domains(self): |
atse@12085 | 363 """Get table of domains indexed by id from xc. |
atse@12085 | 364 |
atse@12085 | 365 @requires: Expects to be protected by domains_lock. |
atse@12085 | 366 @rtype: list of dicts |
atse@12085 | 367 @return: A list of dicts representing the running domains. |
atse@12085 | 368 """ |
atse@12237 | 369 try: |
atse@12237 | 370 return xc.domain_getinfo() |
atse@12237 | 371 except RuntimeError, e: |
atse@12237 | 372 log.exception("Unable to get domain information.") |
atse@12237 | 373 return {} |
atse@12085 | 374 |
atse@12085 | 375 def _setDom0CPUCount(self): |
atse@12085 | 376 """Sets the number of VCPUs dom0 has. Retreived from the |
ewan@13484 | 377 Xend configuration, L{XendOptions}. |
atse@12085 | 378 |
atse@12085 | 379 @requires: Expects to be protected by domains_lock. |
atse@12085 | 380 @rtype: None |
atse@12085 | 381 """ |
atse@12085 | 382 dom0 = self.privilegedDomain() |
emellor@7410 | 383 |
emellor@7410 | 384 # get max number of vcpus to use for dom0 from config |
ewan@13484 | 385 target = int(xoptions.get_dom0_vcpus()) |
emellor@7410 | 386 log.debug("number of vcpus to use is %d", target) |
emellor@7410 | 387 |
emellor@7410 | 388 # target == 0 means use all processors |
emellor@7410 | 389 if target > 0: |
emellor@7426 | 390 dom0.setVCpuCount(target) |
cl349@5911 | 391 |
mjw@1623 | 392 |
ewan@13333 | 393 def _refresh(self, refresh_shutdown = True): |
atse@12085 | 394 """Refresh the domain list. Needs to be called when |
atse@12085 | 395 either xenstore has changed or when a method requires |
atse@12085 | 396 up to date information (like uptime, cputime stats). |
emellor@7240 | 397 |
ewan@12315 | 398 Expects to be protected by the domains_lock. |
ewan@12315 | 399 |
atse@12085 | 400 @rtype: None |
mjw@1629 | 401 """ |
atse@12085 | 402 |
keir@16268 | 403 txn = xstransact() |
keir@16268 | 404 try: |
keir@16268 | 405 self._refreshTxn(txn, refresh_shutdown) |
keir@16268 | 406 txn.commit() |
keir@16268 | 407 except: |
keir@16268 | 408 txn.abort() |
keir@16268 | 409 raise |
keir@16268 | 410 |
keir@16268 | 411 def _refreshTxn(self, transaction, refresh_shutdown): |
ewan@12315 | 412 running = self._running_domains() |
atse@12510 | 413 # Add domains that are not already tracked but running in Xen, |
atse@12510 | 414 # and update domain state for those that are running and tracked. |
ewan@12315 | 415 for dom in running: |
ewan@12315 | 416 domid = dom['domid'] |
atse@12511 | 417 if domid in self.domains: |
keir@16268 | 418 self.domains[domid].update(dom, refresh_shutdown, transaction) |
atse@12510 | 419 elif domid not in self.domains and dom['dying'] != 1: |
atse@12510 | 420 try: |
atse@12510 | 421 new_dom = XendDomainInfo.recreate(dom, False) |
atse@12510 | 422 except VmError: |
atse@12510 | 423 log.exception("Unable to recreate domain") |
atse@12510 | 424 try: |
keir@18374 | 425 xc.domain_pause(domid) |
keir@19068 | 426 XendDomainInfo.do_FLR(domid) |
atse@12510 | 427 xc.domain_destroy(domid) |
atse@12510 | 428 except: |
atse@12510 | 429 log.exception("Hard destruction of domain failed: %d" % |
atse@12510 | 430 domid) |
ewan@12315 | 431 |
atse@12511 | 432 # update information for all running domains |
atse@12511 | 433 # - like cpu_time, status, dying, etc. |
atse@12511 | 434 # remove domains that are not running from active domain list. |
atse@12511 | 435 # The list might have changed by now, because the update call may |
atse@12511 | 436 # cause new domains to be added, if the domain has rebooted. We get |
atse@12511 | 437 # the list again. |
atse@12511 | 438 running = self._running_domains() |
atse@12511 | 439 running_domids = [d['domid'] for d in running if d['dying'] != 1] |
atse@12511 | 440 for domid, dom in self.domains.items(): |
atse@12511 | 441 if domid not in running_domids and domid != DOM0_ID: |
ewan@14523 | 442 self._remove_domain(dom, domid) |
atse@12511 | 443 |
atse@12511 | 444 |
Tim@13554 | 445 def add_domain(self, info): |
atse@12331 | 446 """Add a domain to the list of running domains |
atse@12085 | 447 |
atse@12085 | 448 @requires: Expects to be protected by the domains_lock. |
atse@12085 | 449 @param info: XendDomainInfo of a domain to be added. |
atse@12085 | 450 @type info: XendDomainInfo |
mjw@1744 | 451 """ |
atse@12230 | 452 log.debug("Adding Domain: %s" % info.getDomid()) |
atse@12230 | 453 self.domains[info.getDomid()] = info |
atse@12686 | 454 |
atse@12686 | 455 # update the managed domains with a new XendDomainInfo object |
atse@12686 | 456 # if we are keeping track of it. |
atse@12686 | 457 if info.get_uuid() in self.managed_domains: |
atse@12686 | 458 self._managed_domain_register(info) |
cl349@5336 | 459 |
Tim@13554 | 460 def remove_domain(self, info, domid = None): |
ewan@14523 | 461 """Remove the domain from the list of running domains, taking the |
ewan@14523 | 462 domains_lock first. |
ewan@14523 | 463 """ |
ewan@14523 | 464 self.domains_lock.acquire() |
ewan@14523 | 465 try: |
ewan@14523 | 466 self._remove_domain(info, domid) |
ewan@14523 | 467 finally: |
ewan@14523 | 468 self.domains_lock.release() |
ewan@14523 | 469 |
ewan@14523 | 470 def _remove_domain(self, info, domid = None): |
atse@12331 | 471 """Remove the domain from the list of running domains |
atse@12085 | 472 |
atse@12085 | 473 @requires: Expects to be protected by the domains_lock. |
atse@12085 | 474 @param info: XendDomainInfo of a domain to be removed. |
atse@12085 | 475 @type info: XendDomainInfo |
atse@12085 | 476 """ |
atse@12230 | 477 if info: |
atse@12230 | 478 if domid == None: |
atse@12230 | 479 domid = info.getDomid() |
atse@12230 | 480 |
tom@14887 | 481 if info._stateGet() != DOM_STATE_HALTED: |
atse@12230 | 482 info.cleanupDomain() |
atse@12230 | 483 |
atse@12230 | 484 if domid in self.domains: |
atse@12230 | 485 del self.domains[domid] |
keir@17955 | 486 |
keir@18518 | 487 info.destroy_xapi_instances() |
atse@12085 | 488 else: |
atse@12085 | 489 log.warning("Attempted to remove non-existent domain.") |
emellor@7181 | 490 |
emellor@7181 | 491 def restore_(self, config): |
emellor@7181 | 492 """Create a domain as part of the restore process. This is called |
atse@12085 | 493 only from L{XendCheckpoint}. |
emellor@7181 | 494 |
atse@12085 | 495 A restore request comes into XendDomain through L{domain_restore} |
atse@12085 | 496 or L{domain_restore_fd}. That request is |
emellor@7181 | 497 forwarded immediately to XendCheckpoint which, when it is ready, will |
emellor@7181 | 498 call this method. It is necessary to come through here rather than go |
atse@12085 | 499 directly to L{XendDomainInfo.restore} because we need to |
emellor@7181 | 500 serialise the domain creation process, but cannot lock |
emellor@7181 | 501 domain_restore_fd as a whole, otherwise we will deadlock waiting for |
emellor@7181 | 502 the old domain to die. |
atse@12085 | 503 |
atse@12085 | 504 @param config: Configuration of domain to restore |
atse@12085 | 505 @type config: SXP Object (eg. list of lists) |
emellor@7181 | 506 """ |
emellor@7181 | 507 self.domains_lock.acquire() |
emellor@7181 | 508 try: |
emellor@7181 | 509 dominfo = XendDomainInfo.restore(config) |
emellor@7181 | 510 return dominfo |
emellor@7181 | 511 finally: |
emellor@7181 | 512 self.domains_lock.release() |
emellor@7181 | 513 |
emellor@7006 | 514 |
emellor@7213 | 515 def domain_lookup(self, domid): |
atse@12085 | 516 """Look up given I{domid} in the list of managed and running |
atse@12085 | 517 domains. |
atse@12085 | 518 |
atse@12085 | 519 @note: Will cause a refresh before lookup up domains, for |
atse@12085 | 520 a version that does not need to re-read xenstore |
atse@12085 | 521 use L{domain_lookup_nr}. |
atse@12085 | 522 |
atse@12085 | 523 @param domid: Domain ID or Domain Name. |
atse@12085 | 524 @type domid: int or string |
atse@12085 | 525 @return: Found domain. |
atse@12085 | 526 @rtype: XendDomainInfo |
kfraser@14201 | 527 @raise XendInvalidDomain: If domain is not found. |
atse@12085 | 528 """ |
emellor@7176 | 529 self.domains_lock.acquire() |
emellor@7176 | 530 try: |
ewan@13333 | 531 self._refresh(refresh_shutdown = False) |
atse@12085 | 532 dom = self.domain_lookup_nr(domid) |
atse@12085 | 533 if not dom: |
ewan@14358 | 534 raise XendInvalidDomain(str(domid)) |
atse@12085 | 535 return dom |
emellor@7176 | 536 finally: |
emellor@7176 | 537 self.domains_lock.release() |
cl349@5334 | 538 |
emellor@7176 | 539 |
emellor@7213 | 540 def domain_lookup_nr(self, domid): |
atse@12085 | 541 """Look up given I{domid} in the list of managed and running |
atse@12085 | 542 domains. |
atse@12085 | 543 |
atse@12085 | 544 @param domid: Domain ID or Domain Name. |
atse@12085 | 545 @type domid: int or string |
atse@12085 | 546 @return: Found domain. |
atse@12085 | 547 @rtype: XendDomainInfo or None |
atse@12085 | 548 """ |
emellor@7176 | 549 self.domains_lock.acquire() |
emellor@7176 | 550 try: |
atse@12085 | 551 # lookup by name |
atse@12085 | 552 match = [dom for dom in self.domains.values() \ |
atse@12085 | 553 if dom.getName() == domid] |
atse@12085 | 554 if match: |
atse@12085 | 555 return match[0] |
atse@12085 | 556 |
atse@12330 | 557 match = [dom for dom in self.managed_domains.values() \ |
atse@12330 | 558 if dom.getName() == domid] |
atse@12330 | 559 if match: |
atse@12330 | 560 return match[0] |
atse@12330 | 561 |
atse@12085 | 562 # lookup by id |
atse@12085 | 563 try: |
atse@12230 | 564 if int(domid) in self.domains: |
atse@12230 | 565 return self.domains[int(domid)] |
atse@12230 | 566 except ValueError: |
atse@12085 | 567 pass |
atse@12085 | 568 |
atse@12330 | 569 # lookup by uuid for running domains |
atse@12330 | 570 match = [dom for dom in self.domains.values() \ |
atse@12330 | 571 if dom.get_uuid() == domid] |
atse@12330 | 572 if match: |
atse@12330 | 573 return match[0] |
atse@12330 | 574 |
atse@12330 | 575 # lookup by uuid for inactive managed domains |
atse@12330 | 576 if domid in self.managed_domains: |
atse@12330 | 577 return self.managed_domains[domid] |
atse@12330 | 578 |
atse@12085 | 579 return None |
emellor@7176 | 580 finally: |
emellor@7176 | 581 self.domains_lock.release() |
emellor@7176 | 582 |
atse@12085 | 583 def privilegedDomain(self): |
atse@12085 | 584 """ Get the XendDomainInfo of a dom0 |
emellor@7176 | 585 |
atse@12085 | 586 @rtype: XendDomainInfo |
atse@12085 | 587 """ |
emellor@7176 | 588 self.domains_lock.acquire() |
emellor@7176 | 589 try: |
atse@12230 | 590 return self.domains[DOM0_ID] |
emellor@7176 | 591 finally: |
emellor@7176 | 592 self.domains_lock.release() |
emellor@7176 | 593 |
ewan@14606 | 594 def autostart_domains(self): |
ewan@14606 | 595 """ Autostart managed domains that are marked as such. """ |
ewan@14606 | 596 |
ewan@14606 | 597 need_starting = [] |
ewan@14606 | 598 |
ewan@14606 | 599 self.domains_lock.acquire() |
ewan@14606 | 600 try: |
ewan@14606 | 601 for dom_uuid, dom in self.managed_domains.items(): |
tom@14887 | 602 if dom and dom._stateGet() == DOM_STATE_HALTED: |
ewan@14606 | 603 on_xend_start = dom.info.get('on_xend_start', 'ignore') |
ewan@14606 | 604 auto_power_on = dom.info.get('auto_power_on', False) |
ewan@14606 | 605 should_start = (on_xend_start == 'start') or auto_power_on |
ewan@14606 | 606 if should_start: |
ewan@14606 | 607 need_starting.append(dom_uuid) |
ewan@14606 | 608 finally: |
ewan@14606 | 609 self.domains_lock.release() |
ewan@14606 | 610 |
ewan@14606 | 611 for dom_uuid in need_starting: |
ewan@14606 | 612 self.domain_start(dom_uuid, False) |
ewan@14606 | 613 |
atse@12085 | 614 def cleanup_domains(self): |
atse@12085 | 615 """Clean up domains that are marked as autostop. |
atse@12085 | 616 Should be called when Xend goes down. This is currently |
atse@12085 | 617 called from L{xen.xend.servers.XMLRPCServer}. |
emellor@7176 | 618 |
atse@12085 | 619 """ |
atse@12085 | 620 log.debug('cleanup_domains') |
emellor@7176 | 621 self.domains_lock.acquire() |
emellor@7176 | 622 try: |
atse@12085 | 623 for dom in self.domains.values(): |
atse@12085 | 624 if dom.getName() == DOM0_NAME: |
atse@12085 | 625 continue |
atse@12085 | 626 |
keir@16590 | 627 try: |
keir@16590 | 628 if dom._stateGet() == DOM_STATE_RUNNING: |
keir@16590 | 629 shutdownAction = dom.info.get('on_xend_stop', 'ignore') |
keir@16590 | 630 if shutdownAction == 'shutdown': |
keir@16590 | 631 log.debug('Shutting down domain: %s' % dom.getName()) |
keir@16590 | 632 dom.shutdown("poweroff") |
keir@16590 | 633 elif shutdownAction == 'suspend': |
keir@16590 | 634 self.domain_suspend(dom.getName()) |
keir@16590 | 635 else: |
keir@16590 | 636 log.debug('Domain %s continues to run.' % dom.getName()) |
keir@16590 | 637 except: |
keir@16590 | 638 log.exception('Domain %s failed to %s.' % \ |
keir@16590 | 639 (dom.getName(), shutdownAction)) |
emellor@7176 | 640 finally: |
emellor@7176 | 641 self.domains_lock.release() |
emellor@7176 | 642 |
emellor@7176 | 643 |
atse@12085 | 644 |
atse@12085 | 645 # ---------------------------------------------------------------- |
atse@12085 | 646 # Xen API |
atse@12085 | 647 |
atse@12085 | 648 |
atse@12085 | 649 def set_allow_new_domains(self, allow_new_domains): |
atse@12085 | 650 self._allow_new_domains = allow_new_domains |
atse@12085 | 651 |
atse@12085 | 652 def allow_new_domains(self): |
atse@12085 | 653 return self._allow_new_domains |
atse@12085 | 654 |
atse@12085 | 655 def get_domain_refs(self): |
atse@12085 | 656 result = [] |
atse@12085 | 657 try: |
atse@12085 | 658 self.domains_lock.acquire() |
atse@12101 | 659 result = [d.get_uuid() for d in self.domains.values()] |
jfehlig@13009 | 660 for d in self.managed_domains.keys(): |
jfehlig@13009 | 661 if d not in result: |
jfehlig@13009 | 662 result.append(d) |
atse@12230 | 663 return result |
atse@12085 | 664 finally: |
atse@12085 | 665 self.domains_lock.release() |
atse@12085 | 666 |
ewan@13204 | 667 def get_all_vms(self): |
ewan@13204 | 668 self.domains_lock.acquire() |
ewan@13204 | 669 try: |
ewan@13204 | 670 result = self.domains.values() |
ewan@13204 | 671 result += [x for x in self.managed_domains.values() if |
ewan@13204 | 672 x not in result] |
ewan@13204 | 673 return result |
ewan@13204 | 674 finally: |
ewan@13204 | 675 self.domains_lock.release() |
ewan@13204 | 676 |
atse@12085 | 677 def get_vm_by_uuid(self, vm_uuid): |
emellor@7176 | 678 self.domains_lock.acquire() |
emellor@7176 | 679 try: |
atse@12230 | 680 for dom in self.domains.values(): |
atse@12230 | 681 if dom.get_uuid() == vm_uuid: |
atse@12230 | 682 return dom |
atse@12230 | 683 |
atse@12230 | 684 if vm_uuid in self.managed_domains: |
atse@12230 | 685 return self.managed_domains[vm_uuid] |
atse@12230 | 686 |
emellor@7223 | 687 return None |
emellor@7176 | 688 finally: |
emellor@7176 | 689 self.domains_lock.release() |
mjw@1975 | 690 |
atse@12111 | 691 def get_vm_with_dev_uuid(self, klass, dev_uuid): |
atse@12111 | 692 self.domains_lock.acquire() |
atse@12085 | 693 try: |
atse@12230 | 694 for dom in self.domains.values() + self.managed_domains.values(): |
atse@12111 | 695 if dom.has_device(klass, dev_uuid): |
atse@12111 | 696 return dom |
atse@12111 | 697 return None |
atse@12111 | 698 finally: |
atse@12111 | 699 self.domains_lock.release() |
atse@12085 | 700 |
atse@12111 | 701 def get_dev_property_by_uuid(self, klass, dev_uuid, field): |
atse@13570 | 702 value = None |
atse@12111 | 703 self.domains_lock.acquire() |
ewan@14538 | 704 |
atse@12111 | 705 try: |
ewan@14538 | 706 try: |
ewan@14538 | 707 dom = self.get_vm_with_dev_uuid(klass, dev_uuid) |
ewan@14538 | 708 if dom: |
ewan@14538 | 709 value = dom.get_dev_property(klass, dev_uuid, field) |
ewan@14538 | 710 except ValueError, e: |
ewan@14538 | 711 pass |
ewan@14538 | 712 finally: |
ewan@14538 | 713 self.domains_lock.release() |
atse@12085 | 714 |
atse@13570 | 715 return value |
atse@12085 | 716 |
kfraser@15625 | 717 def set_dev_property_by_uuid(self, klass, dev_uuid, field, value, |
kfraser@15625 | 718 old_val = None): |
kfraser@15625 | 719 rc = True |
kfraser@15625 | 720 self.domains_lock.acquire() |
kfraser@15625 | 721 |
kfraser@15625 | 722 try: |
kfraser@15625 | 723 try: |
kfraser@15625 | 724 dom = self.get_vm_with_dev_uuid(klass, dev_uuid) |
kfraser@15625 | 725 if dom: |
kfraser@15625 | 726 o_val = dom.get_dev_property(klass, dev_uuid, field) |
kfraser@15625 | 727 log.info("o_val=%s, old_val=%s" % (o_val, old_val)) |
kfraser@15625 | 728 if old_val and old_val != o_val: |
kfraser@15625 | 729 return False |
kfraser@15625 | 730 |
kfraser@15625 | 731 dom.set_dev_property(klass, dev_uuid, field, value) |
kfraser@15625 | 732 self.managed_config_save(dom) |
kfraser@15625 | 733 except ValueError, e: |
kfraser@15625 | 734 pass |
kfraser@15625 | 735 finally: |
kfraser@15625 | 736 self.domains_lock.release() |
kfraser@15625 | 737 |
kfraser@15625 | 738 return rc |
kfraser@15625 | 739 |
atse@12085 | 740 def is_valid_vm(self, vm_ref): |
atse@12085 | 741 return (self.get_vm_by_uuid(vm_ref) != None) |
atse@12085 | 742 |
atse@12085 | 743 def is_valid_dev(self, klass, dev_uuid): |
atse@12111 | 744 return (self.get_vm_with_dev_uuid(klass, dev_uuid) != None) |
atse@12085 | 745 |
ewan@12642 | 746 def do_legacy_api_with_uuid(self, fn, vm_uuid, *args, **kwargs): |
ewan@12806 | 747 dom = self.uuid_to_dom(vm_uuid) |
ewan@12806 | 748 fn(dom, *args, **kwargs) |
ewan@12806 | 749 |
ewan@12806 | 750 def uuid_to_dom(self, vm_uuid): |
atse@12085 | 751 self.domains_lock.acquire() |
atse@12085 | 752 try: |
atse@12230 | 753 for domid, dom in self.domains.items(): |
ewan@12806 | 754 if dom.get_uuid() == vm_uuid: |
ewan@12806 | 755 return domid |
atse@12230 | 756 |
atse@12230 | 757 if vm_uuid in self.managed_domains: |
atse@12230 | 758 domid = self.managed_domains[vm_uuid].getDomid() |
ewan@12806 | 759 if domid is None: |
ewan@12806 | 760 return self.managed_domains[vm_uuid].getName() |
ewan@12806 | 761 else: |
ewan@12806 | 762 return domid |
atse@12230 | 763 |
ewan@14483 | 764 raise XendInvalidDomain(vm_uuid) |
atse@12085 | 765 finally: |
atse@12085 | 766 self.domains_lock.release() |
atse@12085 | 767 |
atse@12085 | 768 |
atse@12085 | 769 def create_domain(self, xenapi_vm): |
atse@12085 | 770 self.domains_lock.acquire() |
atse@12085 | 771 try: |
atse@12085 | 772 try: |
ewan@14523 | 773 xeninfo = XendConfig.XendConfig(xapi = xenapi_vm) |
atse@12085 | 774 dominfo = XendDomainInfo.createDormant(xeninfo) |
atse@12085 | 775 log.debug("Creating new managed domain: %s: %s" % |
atse@12085 | 776 (dominfo.getName(), dominfo.get_uuid())) |
atse@12230 | 777 self._managed_domain_register(dominfo) |
atse@12085 | 778 self.managed_config_save(dominfo) |
atse@12085 | 779 return dominfo.get_uuid() |
atse@12085 | 780 except XendError, e: |
atse@12085 | 781 raise |
atse@12085 | 782 except Exception, e: |
atse@12085 | 783 raise XendError(str(e)) |
atse@12085 | 784 finally: |
atse@12085 | 785 self.domains_lock.release() |
atse@12085 | 786 |
atse@12085 | 787 def rename_domain(self, dom, new_name): |
atse@12085 | 788 self.domains_lock.acquire() |
atse@12085 | 789 try: |
atse@12085 | 790 old_name = dom.getName() |
atse@12085 | 791 dom.setName(new_name) |
atse@12085 | 792 |
atse@12085 | 793 finally: |
atse@12085 | 794 self.domains_lock.release() |
atse@12085 | 795 |
atse@12085 | 796 |
atse@12085 | 797 # |
atse@12085 | 798 # End of Xen API |
atse@12085 | 799 # ---------------------------------------------------------------- |
atse@12085 | 800 |
atse@12085 | 801 # ------------------------------------------------------------ |
atse@12085 | 802 # Xen Legacy API |
atse@12085 | 803 |
ewan@12615 | 804 def list(self, state = DOM_STATE_RUNNING): |
atse@12085 | 805 """Get list of domain objects. |
atse@12085 | 806 |
ewan@12615 | 807 @param: the state in which the VMs should be -- one of the |
ewan@12615 | 808 DOM_STATE_XYZ constants, or the corresponding name, or 'all'. |
atse@12085 | 809 @return: domains |
atse@12085 | 810 @rtype: list of XendDomainInfo |
atse@12085 | 811 """ |
ewan@12615 | 812 if type(state) == int: |
ewan@12615 | 813 state = POWER_STATE_NAMES[state] |
ewan@12615 | 814 state = state.lower() |
ewan@12615 | 815 |
atse@12085 | 816 self.domains_lock.acquire() |
atse@12085 | 817 try: |
ewan@13333 | 818 self._refresh(refresh_shutdown = False) |
atse@12230 | 819 |
atse@12230 | 820 # active domains |
atse@12230 | 821 active_domains = self.domains.values() |
atse@12230 | 822 active_uuids = [d.get_uuid() for d in active_domains] |
atse@12230 | 823 |
atse@12230 | 824 # inactive domains |
atse@12230 | 825 inactive_domains = [] |
atse@12230 | 826 for dom_uuid, dom in self.managed_domains.items(): |
atse@12230 | 827 if dom_uuid not in active_uuids: |
atse@12230 | 828 inactive_domains.append(dom) |
atse@12230 | 829 |
ewan@12615 | 830 if state == POWER_STATE_ALL: |
ewan@12615 | 831 return active_domains + inactive_domains |
ewan@12615 | 832 else: |
ewan@12615 | 833 return filter(lambda x: |
tom@14887 | 834 POWER_STATE_NAMES[x._stateGet()].lower() == state, |
ewan@12615 | 835 active_domains + inactive_domains) |
atse@12085 | 836 finally: |
atse@12085 | 837 self.domains_lock.release() |
atse@12085 | 838 |
emellor@7172 | 839 |
ewan@12615 | 840 def list_sorted(self, state = DOM_STATE_RUNNING): |
atse@12085 | 841 """Get list of domain objects, sorted by name. |
atse@12085 | 842 |
ewan@12615 | 843 @param: the state in which the VMs should be -- one of the |
ewan@12615 | 844 DOM_STATE_XYZ constants, or the corresponding name, or 'all'. |
atse@12085 | 845 @return: domain objects |
atse@12085 | 846 @rtype: list of XendDomainInfo |
atse@12085 | 847 """ |
ewan@12615 | 848 doms = self.list(state) |
atse@12085 | 849 doms.sort(lambda x, y: cmp(x.getName(), y.getName())) |
atse@12085 | 850 return doms |
atse@12085 | 851 |
ewan@12615 | 852 def list_names(self, state = DOM_STATE_RUNNING): |
atse@12085 | 853 """Get list of domain names. |
atse@12085 | 854 |
ewan@12615 | 855 @param: the state in which the VMs should be -- one of the |
ewan@12615 | 856 DOM_STATE_XYZ constants, or the corresponding name, or 'all'. |
atse@12085 | 857 @return: domain names |
atse@12085 | 858 @rtype: list of strings. |
atse@12085 | 859 """ |
ewan@12615 | 860 return [d.getName() for d in self.list_sorted(state)] |
atse@12085 | 861 |
atse@12085 | 862 def domain_suspend(self, domname): |
atse@12085 | 863 """Suspends a domain that is persistently managed by Xend |
atse@12085 | 864 |
atse@12085 | 865 @param domname: Domain Name |
atse@12085 | 866 @type domname: string |
atse@12085 | 867 @rtype: None |
atse@12085 | 868 @raise XendError: Failure during checkpointing. |
atse@12085 | 869 """ |
atse@12085 | 870 |
atse@12085 | 871 try: |
atse@12085 | 872 dominfo = self.domain_lookup_nr(domname) |
atse@12085 | 873 if not dominfo: |
atse@12085 | 874 raise XendInvalidDomain(domname) |
atse@12085 | 875 |
atse@12085 | 876 if dominfo.getDomid() == DOM0_ID: |
keir@17144 | 877 raise XendError("Cannot suspend privileged domain %s" % domname) |
atse@12085 | 878 |
tom@14887 | 879 if dominfo._stateGet() != DOM_STATE_RUNNING: |
ewan@13194 | 880 raise VMBadState("Domain is not running", |
ewan@13194 | 881 POWER_STATE_NAMES[DOM_STATE_RUNNING], |
tom@14887 | 882 POWER_STATE_NAMES[dominfo._stateGet()]) |
atse@12085 | 883 |
ewan@12598 | 884 dom_uuid = dominfo.get_uuid() |
ewan@12598 | 885 |
ewan@12598 | 886 if not os.path.exists(self._managed_config_path(dom_uuid)): |
atse@12085 | 887 raise XendError("Domain is not managed by Xend lifecycle " + |
atse@12085 | 888 "support.") |
ewan@12598 | 889 |
ewan@12598 | 890 path = self._managed_check_point_path(dom_uuid) |
Tim@13872 | 891 oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC |
Tim@13872 | 892 if hasattr(os, "O_LARGEFILE"): |
Tim@13872 | 893 oflags |= os.O_LARGEFILE |
Tim@13872 | 894 fd = os.open(path, oflags) |
atse@12085 | 895 try: |
atse@12085 | 896 # For now we don't support 'live checkpoint' |
atse@12085 | 897 XendCheckpoint.save(fd, dominfo, False, False, path) |
atse@12085 | 898 finally: |
atse@12085 | 899 os.close(fd) |
atse@12085 | 900 except OSError, ex: |
atse@12085 | 901 raise XendError("can't write guest state file %s: %s" % |
atse@12085 | 902 (path, ex[1])) |
atse@12085 | 903 |
ewan@12642 | 904 def domain_resume(self, domname, start_paused = False): |
atse@12085 | 905 """Resumes a domain that is persistently managed by Xend. |
atse@12085 | 906 |
atse@12085 | 907 @param domname: Domain Name |
atse@12085 | 908 @type domname: string |
atse@12085 | 909 @rtype: None |
atse@12085 | 910 @raise XendError: If failed to restore. |
atse@12085 | 911 """ |
ewan@12598 | 912 self.domains_lock.acquire() |
atse@12085 | 913 try: |
ewan@12598 | 914 try: |
keir@16127 | 915 fd = None |
ewan@12598 | 916 dominfo = self.domain_lookup_nr(domname) |
atse@12085 | 917 |
ewan@12598 | 918 if not dominfo: |
ewan@12598 | 919 raise XendInvalidDomain(domname) |
atse@12085 | 920 |
ewan@12598 | 921 if dominfo.getDomid() == DOM0_ID: |
keir@17144 | 922 raise XendError("Cannot resume privileged domain %s" % domname) |
ewan@12598 | 923 |
tom@14887 | 924 if dominfo._stateGet() != XEN_API_VM_POWER_STATE_SUSPENDED: |
tom@14887 | 925 raise XendError("Cannot resume domain that is not suspended.") |
ewan@12598 | 926 |
keir@16637 | 927 dominfo.setResume(True) |
keir@16637 | 928 |
ewan@12598 | 929 dom_uuid = dominfo.get_uuid() |
ewan@12598 | 930 chkpath = self._managed_check_point_path(dom_uuid) |
ewan@12598 | 931 if not os.path.exists(chkpath): |
ewan@12598 | 932 raise XendError("Domain was not suspended by Xend") |
ewan@12598 | 933 |
ewan@12598 | 934 # Restore that replaces the existing XendDomainInfo |
ewan@12598 | 935 try: |
tom@14887 | 936 log.debug('Current DomainInfo state: %d' % dominfo._stateGet()) |
Tim@13872 | 937 oflags = os.O_RDONLY |
Tim@13872 | 938 if hasattr(os, "O_LARGEFILE"): |
Tim@13872 | 939 oflags |= os.O_LARGEFILE |
keir@16127 | 940 fd = os.open(chkpath, oflags) |
ewan@12598 | 941 XendCheckpoint.restore(self, |
keir@16127 | 942 fd, |
ewan@12642 | 943 dominfo, |
ewan@12642 | 944 paused = start_paused) |
ewan@12598 | 945 os.unlink(chkpath) |
ewan@12598 | 946 except OSError, ex: |
ewan@12598 | 947 raise XendError("Failed to read stored checkpoint file") |
ewan@12598 | 948 except IOError, ex: |
ewan@12598 | 949 raise XendError("Failed to delete checkpoint file") |
ewan@12598 | 950 except Exception, ex: |
ewan@12598 | 951 log.exception("Exception occurred when resuming") |
ewan@12598 | 952 raise XendError("Error occurred when resuming: %s" % str(ex)) |
ewan@12598 | 953 finally: |
keir@16127 | 954 if fd is not None: |
keir@16127 | 955 os.close(fd) |
ewan@12598 | 956 self.domains_lock.release() |
atse@12085 | 957 |
atse@12085 | 958 |
atse@12085 | 959 def domain_create(self, config): |
atse@12085 | 960 """Create a domain from a configuration. |
atse@12085 | 961 |
atse@12085 | 962 @param config: configuration |
atse@12085 | 963 @type config: SXP Object (list of lists) |
atse@12085 | 964 @rtype: XendDomainInfo |
atse@12085 | 965 """ |
emellor@7176 | 966 self.domains_lock.acquire() |
emellor@7176 | 967 try: |
ewan@12312 | 968 self._refresh() |
ewan@12312 | 969 |
atse@12085 | 970 dominfo = XendDomainInfo.create(config) |
atse@12085 | 971 return dominfo |
emellor@7176 | 972 finally: |
emellor@7176 | 973 self.domains_lock.release() |
emellor@7172 | 974 |
kfraser@10711 | 975 |
ewan@13164 | 976 def domain_create_from_dict(self, config_dict): |
ewan@13164 | 977 """Create a domain from a configuration dictionary. |
ewan@13164 | 978 |
ewan@13164 | 979 @param config_dict: configuration |
ewan@13164 | 980 @rtype: XendDomainInfo |
ewan@13164 | 981 """ |
ewan@13164 | 982 self.domains_lock.acquire() |
ewan@13164 | 983 try: |
ewan@13164 | 984 self._refresh() |
ewan@13164 | 985 |
ewan@13164 | 986 dominfo = XendDomainInfo.create_from_dict(config_dict) |
ewan@13164 | 987 return dominfo |
ewan@13164 | 988 finally: |
ewan@13164 | 989 self.domains_lock.release() |
ewan@13164 | 990 |
ewan@13164 | 991 |
atse@12085 | 992 def domain_new(self, config): |
atse@12085 | 993 """Create a domain from a configuration but do not start it. |
atse@12085 | 994 |
atse@12085 | 995 @param config: configuration |
atse@12085 | 996 @type config: SXP Object (list of lists) |
atse@12085 | 997 @rtype: XendDomainInfo |
atse@12085 | 998 """ |
atse@12085 | 999 self.domains_lock.acquire() |
atse@12085 | 1000 try: |
atse@12085 | 1001 try: |
ewan@14523 | 1002 domconfig = XendConfig.XendConfig(sxp_obj = config) |
atse@12686 | 1003 dominfo = XendDomainInfo.createDormant(domconfig) |
atse@12085 | 1004 log.debug("Creating new managed domain: %s" % |
atse@12085 | 1005 dominfo.getName()) |
atse@12230 | 1006 self._managed_domain_register(dominfo) |
atse@12085 | 1007 self.managed_config_save(dominfo) |
atse@12085 | 1008 # no return value because it isn't meaningful for client |
atse@12085 | 1009 except XendError, e: |
atse@12085 | 1010 raise |
atse@12085 | 1011 except Exception, e: |
atse@12085 | 1012 raise XendError(str(e)) |
atse@12085 | 1013 finally: |
atse@12085 | 1014 self.domains_lock.release() |
kfraser@10711 | 1015 |
ewan@12642 | 1016 def domain_start(self, domid, start_paused = True): |
atse@12085 | 1017 """Start a managed domain |
atse@12085 | 1018 |
atse@12085 | 1019 @require: Domain must not be running. |
atse@12085 | 1020 @param domid: Domain name or domain ID. |
atse@12085 | 1021 @type domid: string or int |
atse@12085 | 1022 @rtype: None |
atse@12085 | 1023 @raise XendError: If domain is still running |
atse@12085 | 1024 @rtype: None |
atse@12085 | 1025 """ |
atse@12085 | 1026 self.domains_lock.acquire() |
atse@12085 | 1027 try: |
ewan@12312 | 1028 self._refresh() |
ewan@12312 | 1029 |
atse@12085 | 1030 dominfo = self.domain_lookup_nr(domid) |
atse@12085 | 1031 if not dominfo: |
atse@12085 | 1032 raise XendInvalidDomain(str(domid)) |
atse@12085 | 1033 |
tom@14887 | 1034 if dominfo._stateGet() != DOM_STATE_HALTED: |
ewan@13194 | 1035 raise VMBadState("Domain is already running", |
ewan@13194 | 1036 POWER_STATE_NAMES[DOM_STATE_HALTED], |
tom@14887 | 1037 POWER_STATE_NAMES[dominfo._stateGet()]) |
atse@12085 | 1038 |
ewan@12643 | 1039 dominfo.start(is_managed = True) |
atse@12085 | 1040 finally: |
atse@12085 | 1041 self.domains_lock.release() |
kfraser@15208 | 1042 |
kfraser@15208 | 1043 try: |
kfraser@15208 | 1044 dominfo.waitForDevices() |
kfraser@15208 | 1045 except Exception, ex: |
kfraser@15208 | 1046 log.warn("Failed to setup devices for " + str(dominfo) + ": " + str(ex)) |
kfraser@15208 | 1047 dominfo.destroy() |
kfraser@15208 | 1048 raise |
kfraser@15208 | 1049 |
ewan@12643 | 1050 if not start_paused: |
ewan@12643 | 1051 dominfo.unpause() |
atse@12085 | 1052 |
atse@12085 | 1053 def domain_delete(self, domid): |
atse@12230 | 1054 """Remove a managed domain from database |
atse@12085 | 1055 |
atse@12085 | 1056 @require: Domain must not be running. |
atse@12085 | 1057 @param domid: Domain name or domain ID. |
atse@12085 | 1058 @type domid: string or int |
atse@12085 | 1059 @rtype: None |
atse@12085 | 1060 @raise XendError: If domain is still running |
atse@12085 | 1061 """ |
atse@12085 | 1062 self.domains_lock.acquire() |
atse@12085 | 1063 try: |
atse@12085 | 1064 try: |
atse@12085 | 1065 dominfo = self.domain_lookup_nr(domid) |
atse@12085 | 1066 if not dominfo: |
atse@12085 | 1067 raise XendInvalidDomain(str(domid)) |
atse@12085 | 1068 |
tom@14887 | 1069 if dominfo._stateGet() != XEN_API_VM_POWER_STATE_HALTED: |
tom@14887 | 1070 raise VMBadState("Domain is not halted.", |
ewan@13194 | 1071 POWER_STATE_NAMES[DOM_STATE_HALTED], |
tom@14887 | 1072 POWER_STATE_NAMES[dominfo._stateGet()]) |
ewan@14523 | 1073 |
ewan@14523 | 1074 self._domain_delete_by_info(dominfo) |
atse@12085 | 1075 except Exception, ex: |
atse@12085 | 1076 raise XendError(str(ex)) |
atse@12085 | 1077 finally: |
atse@12085 | 1078 self.domains_lock.release() |
ewan@14523 | 1079 |
ewan@14523 | 1080 |
ewan@14523 | 1081 def domain_delete_by_dominfo(self, dominfo): |
ewan@14523 | 1082 """Only for use by XendDomainInfo. |
ewan@14523 | 1083 """ |
ewan@14523 | 1084 self.domains_lock.acquire() |
ewan@14523 | 1085 try: |
ewan@14523 | 1086 self._domain_delete_by_info(dominfo) |
ewan@14523 | 1087 finally: |
ewan@14523 | 1088 self.domains_lock.release() |
ewan@14523 | 1089 |
ewan@14523 | 1090 |
ewan@14523 | 1091 def _domain_delete_by_info(self, dominfo): |
ewan@14523 | 1092 """Expects to be protected by domains_lock. |
ewan@14523 | 1093 """ |
ewan@14523 | 1094 log.info("Domain %s (%s) deleted." % |
ewan@14523 | 1095 (dominfo.getName(), dominfo.info.get('uuid'))) |
ewan@14523 | 1096 |
ewan@14523 | 1097 self._managed_domain_unregister(dominfo) |
ewan@14523 | 1098 self._remove_domain(dominfo) |
keir@18457 | 1099 XendDevices.destroy_device_state(dominfo) |
ewan@14523 | 1100 |
atse@12085 | 1101 |
atse@12085 | 1102 def domain_configure(self, config): |
atse@12085 | 1103 """Configure an existing domain. |
atse@12085 | 1104 |
atse@12085 | 1105 @param vmconfig: vm configuration |
atse@12085 | 1106 @type vmconfig: SXP Object (list of lists) |
atse@12085 | 1107 @todo: Not implemented |
atse@12085 | 1108 """ |
atse@12085 | 1109 # !!! |
atse@12085 | 1110 raise XendError("Unsupported") |
atse@12085 | 1111 |
brendan@12552 | 1112 def domain_restore(self, src, paused=False): |
atse@12085 | 1113 """Restore a domain from file. |
atse@12085 | 1114 |
atse@12085 | 1115 @param src: filename of checkpoint file to restore from |
atse@12085 | 1116 @type src: string |
atse@12085 | 1117 @return: Restored domain |
atse@12085 | 1118 @rtype: XendDomainInfo |
atse@12085 | 1119 @raise XendError: Failure to restore domain |
atse@12085 | 1120 """ |
atse@12085 | 1121 try: |
Tim@13872 | 1122 oflags = os.O_RDONLY |
Tim@13872 | 1123 if hasattr(os, "O_LARGEFILE"): |
Tim@13872 | 1124 oflags |= os.O_LARGEFILE |
Tim@13872 | 1125 fd = os.open(src, oflags) |
atse@12085 | 1126 try: |
brendan@12552 | 1127 return self.domain_restore_fd(fd, paused=paused) |
atse@12085 | 1128 finally: |
atse@12085 | 1129 os.close(fd) |
atse@12085 | 1130 except OSError, ex: |
atse@12085 | 1131 raise XendError("can't read guest state file %s: %s" % |
atse@12085 | 1132 (src, ex[1])) |
atse@12085 | 1133 |
keir@16937 | 1134 def domain_restore_fd(self, fd, paused=False, relocating=False): |
atse@12085 | 1135 """Restore a domain from the given file descriptor. |
atse@12085 | 1136 |
atse@12085 | 1137 @param fd: file descriptor of the checkpoint file |
atse@12085 | 1138 @type fd: File object |
atse@12085 | 1139 @rtype: XendDomainInfo |
atse@12085 | 1140 @raise XendError: if failed to restore |
atse@12085 | 1141 """ |
kfraser@10711 | 1142 |
mjw@1985 | 1143 try: |
keir@18772 | 1144 self.policy_lock.acquire_reader() |
keir@18772 | 1145 |
keir@18772 | 1146 try: |
keir@18772 | 1147 return XendCheckpoint.restore(self, fd, paused=paused, relocating=relocating) |
keir@18772 | 1148 except XendError, e: |
keir@18772 | 1149 log.exception("Restore failed") |
keir@18772 | 1150 raise |
keir@18772 | 1151 except: |
keir@18772 | 1152 # I don't really want to log this exception here, but the error |
keir@18772 | 1153 # handling in the relocation-socket handling code (relocate.py) is |
keir@18772 | 1154 # poor, so we need to log this for debugging. |
keir@18772 | 1155 log.exception("Restore failed") |
keir@18772 | 1156 raise XendError("Restore failed") |
keir@18772 | 1157 finally: |
keir@18772 | 1158 self.policy_lock.release() |
atse@12085 | 1159 |
atse@12085 | 1160 def domain_unpause(self, domid): |
atse@12085 | 1161 """Unpause domain execution. |
atse@12085 | 1162 |
atse@12085 | 1163 @param domid: Domain ID or Name |
atse@12085 | 1164 @type domid: int or string. |
atse@12085 | 1165 @rtype: None |
atse@12085 | 1166 @raise XendError: Failed to unpause |
atse@12085 | 1167 @raise XendInvalidDomain: Domain is not valid |
atse@12085 | 1168 """ |
atse@12085 | 1169 try: |
atse@12085 | 1170 dominfo = self.domain_lookup_nr(domid) |
atse@12085 | 1171 if not dominfo: |
atse@12085 | 1172 raise XendInvalidDomain(str(domid)) |
ewan@12485 | 1173 if dominfo.getDomid() == DOM0_ID: |
ewan@12485 | 1174 raise XendError("Cannot unpause privileged domain %s" % domid) |
kfraser@15555 | 1175 if dominfo._stateGet() not in (DOM_STATE_PAUSED, DOM_STATE_RUNNING): |
kfraser@15555 | 1176 raise VMBadState("Domain '%s' is not started" % domid, |
kfraser@15555 | 1177 POWER_STATE_NAMES[DOM_STATE_PAUSED], |
kfraser@15555 | 1178 POWER_STATE_NAMES[dominfo._stateGet()]) |
emellor@7215 | 1179 log.info("Domain %s (%d) unpaused.", dominfo.getName(), |
atse@12085 | 1180 int(dominfo.getDomid())) |
atse@12085 | 1181 dominfo.unpause() |
atse@12085 | 1182 except XendInvalidDomain: |
atse@12085 | 1183 log.exception("domain_unpause") |
atse@12085 | 1184 raise |
mjw@1985 | 1185 except Exception, ex: |
atse@12085 | 1186 log.exception("domain_unpause") |
mjw@1985 | 1187 raise XendError(str(ex)) |
emellor@7215 | 1188 |
kfraser@15912 | 1189 def domain_pause(self, domid, state=False): |
atse@12085 | 1190 """Pause domain execution. |
kfraser@10711 | 1191 |
atse@12085 | 1192 @param domid: Domain ID or Name |
atse@12085 | 1193 @type domid: int or string. |
kfraser@15912 | 1194 @keyword state: If True, will return the domain state before pause |
kfraser@15912 | 1195 @type state: bool |
kfraser@15912 | 1196 @rtype: int if state is True |
kfraser@15912 | 1197 @return: Domain state (DOM_STATE_*) |
kfraser@15912 | 1198 @rtype: None if state is False |
atse@12085 | 1199 @raise XendError: Failed to pause |
atse@12085 | 1200 @raise XendInvalidDomain: Domain is not valid |
atse@12085 | 1201 """ |
mjw@1985 | 1202 try: |
atse@12085 | 1203 dominfo = self.domain_lookup_nr(domid) |
atse@12085 | 1204 if not dominfo: |
atse@12085 | 1205 raise XendInvalidDomain(str(domid)) |
ewan@12485 | 1206 if dominfo.getDomid() == DOM0_ID: |
ewan@12485 | 1207 raise XendError("Cannot pause privileged domain %s" % domid) |
kfraser@15912 | 1208 ds = dominfo._stateGet() |
keir@16883 | 1209 if ds not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED, DOM_STATE_CRASHED): |
kfraser@15555 | 1210 raise VMBadState("Domain '%s' is not started" % domid, |
kfraser@15555 | 1211 POWER_STATE_NAMES[DOM_STATE_RUNNING], |
kfraser@15912 | 1212 POWER_STATE_NAMES[ds]) |
emellor@7215 | 1213 log.info("Domain %s (%d) paused.", dominfo.getName(), |
atse@12085 | 1214 int(dominfo.getDomid())) |
keir@16883 | 1215 if ds == DOM_STATE_RUNNING: |
keir@16883 | 1216 dominfo.pause() |
kfraser@15912 | 1217 if state: |
kfraser@15912 | 1218 return ds |
atse@12085 | 1219 except XendInvalidDomain: |
atse@12085 | 1220 log.exception("domain_pause") |
atse@12085 | 1221 raise |
mjw@1985 | 1222 except Exception, ex: |
atse@12085 | 1223 log.exception("domain_pause") |
mjw@1985 | 1224 raise XendError(str(ex)) |
emellor@7072 | 1225 |
keir@19356 | 1226 def domain_dump(self, domid, filename=None, live=False, crash=False, reset=False): |
root@11477 | 1227 """Dump domain core.""" |
root@11477 | 1228 |
atse@12148 | 1229 dominfo = self.domain_lookup_nr(domid) |
root@11477 | 1230 if not dominfo: |
root@11477 | 1231 raise XendInvalidDomain(str(domid)) |
root@11477 | 1232 |
atse@12148 | 1233 if dominfo.getDomid() == DOM0_ID: |
root@11477 | 1234 raise XendError("Cannot dump core for privileged domain %s" % domid) |
keir@16883 | 1235 if dominfo._stateGet() not in (DOM_STATE_PAUSED, DOM_STATE_RUNNING, DOM_STATE_CRASHED): |
kfraser@15577 | 1236 raise VMBadState("Domain '%s' is not started" % domid, |
kfraser@15577 | 1237 POWER_STATE_NAMES[DOM_STATE_PAUSED], |
kfraser@15577 | 1238 POWER_STATE_NAMES[dominfo._stateGet()]) |
root@11477 | 1239 |
keir@19336 | 1240 dopause = (not live and dominfo._stateGet() == DOM_STATE_RUNNING) |
keir@19336 | 1241 if dopause: |
keir@19336 | 1242 dominfo.pause() |
keir@19336 | 1243 |
root@11477 | 1244 try: |
keir@19336 | 1245 try: |
keir@19336 | 1246 log.info("Domain core dump requested for domain %s (%d) " |
keir@19356 | 1247 "live=%d crash=%d reset=%d.", |
keir@19356 | 1248 dominfo.getName(), dominfo.getDomid(), live, crash, reset) |
keir@19336 | 1249 dominfo.dumpCore(filename) |
keir@19336 | 1250 if crash: |
keir@19336 | 1251 self.domain_destroy(domid) |
keir@19356 | 1252 elif reset: |
keir@19356 | 1253 self.domain_reset(domid) |
keir@19336 | 1254 except Exception, ex: |
keir@19336 | 1255 raise XendError(str(ex)) |
keir@19336 | 1256 finally: |
keir@19356 | 1257 if dopause and not crash and not reset: |
keir@19336 | 1258 dominfo.unpause() |
emellor@7072 | 1259 |
emellor@7173 | 1260 def domain_destroy(self, domid): |
atse@12085 | 1261 """Terminate domain immediately. |
emellor@7015 | 1262 |
atse@12085 | 1263 @param domid: Domain ID or Name |
atse@12085 | 1264 @type domid: int or string. |
atse@12085 | 1265 @rtype: None |
atse@12085 | 1266 @raise XendError: Failed to destroy |
atse@12085 | 1267 @raise XendInvalidDomain: Domain is not valid |
atse@12085 | 1268 """ |
atse@12085 | 1269 |
atse@12085 | 1270 dominfo = self.domain_lookup_nr(domid) |
atse@12085 | 1271 if dominfo and dominfo.getDomid() == DOM0_ID: |
anthony@9421 | 1272 raise XendError("Cannot destroy privileged domain %s" % domid) |
anthony@9421 | 1273 |
cl349@6913 | 1274 if dominfo: |
cl349@6913 | 1275 val = dominfo.destroy() |
cl349@6913 | 1276 else: |
cl349@6913 | 1277 try: |
keir@18374 | 1278 xc.domain_pause(int(domid)) |
keir@19068 | 1279 XendDomainInfo.do_FLR(int(domid)) |
kaf24@10996 | 1280 val = xc.domain_destroy(int(domid)) |
atse@12085 | 1281 except ValueError: |
atse@12085 | 1282 raise XendInvalidDomain(domid) |
atse@12085 | 1283 except Exception, e: |
atse@12085 | 1284 raise XendError(str(e)) |
atse@12085 | 1285 |
cl349@6913 | 1286 return val |
mjw@1673 | 1287 |
keir@17713 | 1288 def domain_migrate(self, domid, dst, live=False, port=0, node=-1, ssl=None): |
atse@12085 | 1289 """Start domain migration. |
atse@12085 | 1290 |
atse@12085 | 1291 @param domid: Domain ID or Name |
atse@12085 | 1292 @type domid: int or string. |
atse@12085 | 1293 @param dst: Destination IP address |
atse@12085 | 1294 @type dst: string |
atse@12085 | 1295 @keyword live: Live migration |
atse@12085 | 1296 @type live: bool |
keir@17737 | 1297 @keyword port: relocation port on destination |
keir@17737 | 1298 @type port: int |
keir@17737 | 1299 @keyword node: use node number for target |
keir@17737 | 1300 @type node: int |
keir@17713 | 1301 @keyword ssl: use ssl connection |
keir@17713 | 1302 @type ssl: bool |
atse@12085 | 1303 @rtype: None |
atse@12085 | 1304 @raise XendError: Failed to migrate |
keir@17737 | 1305 @raise XendInvalidDomain: Domain is not valid |
atse@12085 | 1306 """ |
mjw@1629 | 1307 |
atse@12085 | 1308 dominfo = self.domain_lookup_nr(domid) |
emellor@9530 | 1309 if not dominfo: |
emellor@9530 | 1310 raise XendInvalidDomain(str(domid)) |
cl349@5155 | 1311 |
atse@12085 | 1312 if dominfo.getDomid() == DOM0_ID: |
ewan@12484 | 1313 raise XendError("Cannot migrate privileged domain %s" % domid) |
keir@17680 | 1314 if dominfo._stateGet() != DOM_STATE_RUNNING: |
keir@17680 | 1315 raise VMBadState("Domain is not running", |
keir@17680 | 1316 POWER_STATE_NAMES[DOM_STATE_RUNNING], |
keir@17680 | 1317 POWER_STATE_NAMES[dominfo._stateGet()]) |
emellor@8275 | 1318 |
emellor@9727 | 1319 """ The following call may raise a XendError exception """ |
kaf24@10039 | 1320 dominfo.testMigrateDevices(True, dst) |
emellor@9727 | 1321 |
tim@11442 | 1322 if live: |
tim@11442 | 1323 """ Make sure there's memory free for enabling shadow mode """ |
tim@11442 | 1324 dominfo.checkLiveMigrateMemory() |
tim@11442 | 1325 |
keir@17713 | 1326 if ssl is None: |
keir@17713 | 1327 ssl = xoptions.get_xend_relocation_ssl() |
keir@17713 | 1328 |
keir@17712 | 1329 if ssl: |
keir@17636 | 1330 from OpenSSL import SSL |
keir@17636 | 1331 from xen.web import connection |
keir@17712 | 1332 if port == 0: |
keir@17712 | 1333 port = xoptions.get_xend_relocation_ssl_port() |
keir@17636 | 1334 try: |
keir@17534 | 1335 ctx = SSL.Context(SSL.SSLv23_METHOD) |
keir@17636 | 1336 sock = SSL.Connection(ctx, |
keir@17636 | 1337 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) |
keir@17534 | 1338 sock.set_connect_state() |
keir@17636 | 1339 sock.connect((dst, port)) |
keir@17636 | 1340 sock.send("sslreceive\n") |
keir@17636 | 1341 sock.recv(80) |
keir@17636 | 1342 except SSL.Error, err: |
keir@17636 | 1343 raise XendError("SSL error: %s" % err) |
keir@17636 | 1344 except socket.error, err: |
keir@17636 | 1345 raise XendError("can't connect: %s" % err) |
keir@17636 | 1346 |
keir@17636 | 1347 p2cread, p2cwrite = os.pipe() |
keir@17636 | 1348 threading.Thread(target=connection.SSLSocketServerConnection.fd2send, |
keir@17636 | 1349 args=(sock, p2cread)).start() |
keir@17636 | 1350 |
keir@17636 | 1351 try: |
keir@17636 | 1352 XendCheckpoint.save(p2cwrite, dominfo, True, live, dst, |
keir@17636 | 1353 node=node) |
keir@17636 | 1354 finally: |
keir@17636 | 1355 sock.shutdown() |
keir@17636 | 1356 sock.close() |
keir@17636 | 1357 |
keir@17636 | 1358 os.close(p2cread) |
keir@17636 | 1359 os.close(p2cwrite) |
keir@17636 | 1360 else: |
keir@17712 | 1361 if port == 0: |
keir@17712 | 1362 port = xoptions.get_xend_relocation_port() |
keir@17636 | 1363 try: |
keir@17534 | 1364 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
keir@17636 | 1365 # When connecting to our ssl enabled relocation server using a |
keir@17636 | 1366 # plain socket, send will success but recv will block. Add a |
keir@17636 | 1367 # 30 seconds timeout to raise a socket.timeout exception to |
keir@17636 | 1368 # inform the client. |
keir@17636 | 1369 sock.settimeout(30.0) |
keir@17636 | 1370 sock.connect((dst, port)) |
keir@17636 | 1371 sock.send("receive\n") |
keir@17636 | 1372 sock.recv(80) |
keir@17636 | 1373 sock.settimeout(None) |
keir@17636 | 1374 except socket.error, err: |
keir@17636 | 1375 raise XendError("can't connect: %s" % err) |
cl349@5155 | 1376 |
keir@17636 | 1377 try: |
keir@17636 | 1378 XendCheckpoint.save(sock.fileno(), dominfo, True, live, |
keir@17636 | 1379 dst, node=node) |
keir@17636 | 1380 finally: |
keir@17636 | 1381 sock.close() |
mjw@1623 | 1382 |
kfraser@14992 | 1383 def domain_save(self, domid, dst, checkpoint=False): |
mjw@1744 | 1384 """Start saving a domain to file. |
mjw@1629 | 1385 |
atse@12085 | 1386 @param domid: Domain ID or Name |
atse@12085 | 1387 @type domid: int or string. |
atse@12085 | 1388 @param dst: Destination filename |
atse@12085 | 1389 @type dst: string |
atse@12085 | 1390 @rtype: None |
atse@12085 | 1391 @raise XendError: Failed to save domain |
atse@12085 | 1392 @raise XendInvalidDomain: Domain is not valid |
mjw@1623 | 1393 """ |
cl349@5121 | 1394 try: |
atse@12085 | 1395 dominfo = self.domain_lookup_nr(domid) |
emellor@9530 | 1396 if not dominfo: |
emellor@9530 | 1397 raise XendInvalidDomain(str(domid)) |
cl349@5121 | 1398 |
atse@12085 | 1399 if dominfo.getDomid() == DOM0_ID: |
kfraser@15538 | 1400 raise XendError("Cannot save privileged domain %s" % str(domid)) |
kfraser@15538 | 1401 if dominfo._stateGet() != DOM_STATE_RUNNING: |
kfraser@15538 | 1402 raise VMBadState("Domain is not running", |
kfraser@15538 | 1403 POWER_STATE_NAMES[DOM_STATE_RUNNING], |
kfraser@15538 | 1404 POWER_STATE_NAMES[dominfo._stateGet()]) |
emellor@8275 | 1405 |
Tim@13872 | 1406 oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC |
Tim@13872 | 1407 if hasattr(os, "O_LARGEFILE"): |
Tim@13872 | 1408 oflags |= os.O_LARGEFILE |
Tim@13872 | 1409 fd = os.open(dst, oflags) |
emellor@7213 | 1410 try: |
kfraser@14171 | 1411 XendCheckpoint.save(fd, dominfo, False, False, dst, |
kfraser@14171 | 1412 checkpoint=checkpoint) |
keir@15461 | 1413 except Exception, e: |
emellor@7213 | 1414 os.close(fd) |
keir@15461 | 1415 raise e |
keir@15461 | 1416 os.close(fd) |
cl349@5145 | 1417 except OSError, ex: |
cl349@5145 | 1418 raise XendError("can't write guest state file %s: %s" % |
cl349@5145 | 1419 (dst, ex[1])) |
cl349@5121 | 1420 |
emellor@7213 | 1421 def domain_pincpu(self, domid, vcpu, cpumap): |
cl349@4845 | 1422 """Set which cpus vcpu can use |
mjw@1623 | 1423 |
atse@12085 | 1424 @param domid: Domain ID or Name |
atse@12085 | 1425 @type domid: int or string. |
atse@12085 | 1426 @param vcpu: vcpu to pin to |
atse@12085 | 1427 @type vcpu: int |
atse@12085 | 1428 @param cpumap: string repr of usable cpus |
atse@12085 | 1429 @type cpumap: string |
atse@12085 | 1430 @rtype: 0 |
mjw@1629 | 1431 """ |
atse@12085 | 1432 dominfo = self.domain_lookup_nr(domid) |
emellor@9530 | 1433 if not dominfo: |
emellor@9530 | 1434 raise XendInvalidDomain(str(domid)) |
emellor@9530 | 1435 |
ack@11629 | 1436 # if vcpu is keyword 'all', apply the cpumap to all vcpus |
ack@11629 | 1437 if str(vcpu).lower() == "all": |
ack@11629 | 1438 vcpus = range(0, int(dominfo.getVCpuCount())) |
keir@17609 | 1439 else: |
keir@17609 | 1440 vcpus = [ int(vcpu) ] |
ack@11629 | 1441 |
ack@11629 | 1442 # set the same cpumask for all vcpus |
ack@11629 | 1443 rc = 0 |
keir@17609 | 1444 cpus = dominfo.getCpus() |
keir@19580 | 1445 cpumap = map(int, cpumap.split(",")) |
keir@17609 | 1446 for v in vcpus: |
keir@17609 | 1447 try: |
keir@17609 | 1448 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED): |
keir@17609 | 1449 rc = xc.vcpu_setaffinity(dominfo.getDomid(), v, cpumap) |
keir@17609 | 1450 cpus[v] = cpumap |
keir@17609 | 1451 except Exception, ex: |
keir@17609 | 1452 log.exception(ex) |
keir@17609 | 1453 raise XendError("Cannot pin vcpu: %d to cpu: %s - %s" % \ |
keir@17609 | 1454 (v, cpumap, str(ex))) |
keir@17609 | 1455 dominfo.setCpus(cpus) |
keir@17609 | 1456 self.managed_config_save(dominfo) |
keir@17173 | 1457 |
ack@11629 | 1458 return rc |
mjw@1623 | 1459 |
emellor@7213 | 1460 def domain_cpu_sedf_set(self, domid, period, slice_, latency, extratime, |
emellor@7213 | 1461 weight): |
sd386@3573 | 1462 """Set Simple EDF scheduler parameters for a domain. |
atse@12085 | 1463 |
atse@12085 | 1464 @param domid: Domain ID or Name |
atse@12085 | 1465 @type domid: int or string. |
atse@12085 | 1466 @rtype: 0 |
sd386@3449 | 1467 """ |
atse@12085 | 1468 dominfo = self.domain_lookup_nr(domid) |
emellor@9530 | 1469 if not dominfo: |
emellor@9530 | 1470 raise XendInvalidDomain(str(domid)) |
sd386@3449 | 1471 try: |
emellor@7213 | 1472 return xc.sedf_domain_set(dominfo.getDomid(), period, slice_, |
emellor@6943 | 1473 latency, extratime, weight) |
sd386@3449 | 1474 except Exception, ex: |
sd386@3449 | 1475 raise XendError(str(ex)) |
sd386@3449 | 1476 |
emellor@7213 | 1477 def domain_cpu_sedf_get(self, domid): |
cl349@5334 | 1478 """Get Simple EDF scheduler parameters for a domain. |
atse@12085 | 1479 |
atse@12085 | 1480 @param domid: Domain ID or Name |
atse@12085 | 1481 @type domid: int or string. |
atse@12085 | 1482 @rtype: SXP object |
atse@12085 | 1483 @return: The parameters for Simple EDF schedule for a domain. |
sd386@3449 | 1484 """ |
atse@12085 | 1485 dominfo = self.domain_lookup_nr(domid) |
emellor@9530 | 1486 if not dominfo: |
emellor@9530 | 1487 raise XendInvalidDomain(str(domid)) |
sd386@3449 | 1488 try: |
emellor@9217 | 1489 sedf_info = xc.sedf_domain_get(dominfo.getDomid()) |
emellor@9217 | 1490 # return sxpr |
emellor@9217 | 1491 return ['sedf', |
atse@12370 | 1492 ['domid', sedf_info['domid']], |
emellor@9217 | 1493 ['period', sedf_info['period']], |
emellor@9217 | 1494 ['slice', sedf_info['slice']], |
emellor@9217 | 1495 ['latency', sedf_info['latency']], |
emellor@9217 | 1496 ['extratime', sedf_info['extratime']], |
emellor@9217 | 1497 ['weight', sedf_info['weight']]] |
emellor@9217 | 1498 |
sd386@3449 | 1499 except Exception, ex: |
sd386@3449 | 1500 raise XendError(str(ex)) |
cl349@5304 | 1501 |
tdeegan@11172 | 1502 def domain_shadow_control(self, domid, op): |
atse@12085 | 1503 """Shadow page control. |
atse@12085 | 1504 |
atse@12085 | 1505 @param domid: Domain ID or Name |
atse@12085 | 1506 @type domid: int or string. |
atse@12085 | 1507 @param op: operation |
atse@12085 | 1508 @type op: int |
atse@12085 | 1509 @rtype: 0 |
atse@12085 | 1510 """ |
tdeegan@11172 | 1511 dominfo = self.domain_lookup(domid) |
tdeegan@11172 | 1512 try: |
tdeegan@11172 | 1513 return xc.shadow_control(dominfo.getDomid(), op) |
tdeegan@11172 | 1514 except Exception, ex: |
tdeegan@11172 | 1515 raise XendError(str(ex)) |
tdeegan@11172 | 1516 |
tdeegan@11172 | 1517 def domain_shadow_mem_get(self, domid): |
atse@12085 | 1518 """Get shadow pagetable memory allocation. |
atse@12085 | 1519 |
atse@12085 | 1520 @param domid: Domain ID or Name |
atse@12085 | 1521 @type domid: int or string. |
atse@12085 | 1522 @rtype: int |
atse@12085 | 1523 @return: shadow memory in MB |
atse@12085 | 1524 """ |
tdeegan@11172 | 1525 dominfo = self.domain_lookup(domid) |
tdeegan@11172 | 1526 try: |
tdeegan@11172 | 1527 return xc.shadow_mem_control(dominfo.getDomid()) |
tdeegan@11172 | 1528 except Exception, ex: |
tdeegan@11172 | 1529 raise XendError(str(ex)) |
tdeegan@11172 | 1530 |
tdeegan@11172 | 1531 def domain_shadow_mem_set(self, domid, mb): |
atse@12085 | 1532 """Set shadow pagetable memory allocation. |
atse@12085 | 1533 |
atse@12085 | 1534 @param domid: Domain ID or Name |
atse@12085 | 1535 @type domid: int or string. |
atse@12085 | 1536 @param mb: shadow memory to set in MB |
atse@12085 | 1537 @type: mb: int |
atse@12085 | 1538 @rtype: int |
atse@12085 | 1539 @return: shadow memory in MB |
atse@12085 | 1540 """ |
tdeegan@11172 | 1541 dominfo = self.domain_lookup(domid) |
tdeegan@11172 | 1542 try: |
tdeegan@11172 | 1543 return xc.shadow_mem_control(dominfo.getDomid(), mb=mb) |
tdeegan@11172 | 1544 except Exception, ex: |
tdeegan@11172 | 1545 raise XendError(str(ex)) |
tdeegan@11172 | 1546 |
kaf24@10206 | 1547 def domain_sched_credit_get(self, domid): |
ack@10188 | 1548 """Get credit scheduler parameters for a domain. |
atse@12085 | 1549 |
atse@12085 | 1550 @param domid: Domain ID or Name |
atse@12085 | 1551 @type domid: int or string. |
atse@12085 | 1552 @rtype: dict with keys 'weight' and 'cap' |
atse@12085 | 1553 @return: credit scheduler parameters |
ack@10188 | 1554 """ |
atse@12085 | 1555 dominfo = self.domain_lookup_nr(domid) |
ack@10188 | 1556 if not dominfo: |
ack@10188 | 1557 raise XendInvalidDomain(str(domid)) |
kfraser@15508 | 1558 |
kfraser@15508 | 1559 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED): |
kfraser@15508 | 1560 try: |
kfraser@15508 | 1561 return xc.sched_credit_domain_get(dominfo.getDomid()) |
kfraser@15508 | 1562 except Exception, ex: |
kfraser@15508 | 1563 raise XendError(str(ex)) |
kfraser@15508 | 1564 else: |
kfraser@15508 | 1565 return {'weight' : dominfo.getWeight(), |
kfraser@15508 | 1566 'cap' : dominfo.getCap()} |
ack@10188 | 1567 |
ack@11559 | 1568 def domain_sched_credit_set(self, domid, weight = None, cap = None): |
ack@10188 | 1569 """Set credit scheduler parameters for a domain. |
atse@12085 | 1570 |
atse@12085 | 1571 @param domid: Domain ID or Name |
atse@12085 | 1572 @type domid: int or string. |
atse@12085 | 1573 @type weight: int |
atse@12085 | 1574 @type cap: int |
atse@12085 | 1575 @rtype: 0 |
ack@10188 | 1576 """ |
kfraser@15204 | 1577 set_weight = False |
kfraser@15204 | 1578 set_cap = False |
atse@12085 | 1579 dominfo = self.domain_lookup_nr(domid) |
ack@10188 | 1580 if not dominfo: |
ack@10188 | 1581 raise XendInvalidDomain(str(domid)) |
ack@10188 | 1582 try: |
ack@11559 | 1583 if weight is None: |
ack@11559 | 1584 weight = int(0) |
ack@11559 | 1585 elif weight < 1 or weight > 65535: |
ack@11559 | 1586 raise XendError("weight is out of range") |
kfraser@15204 | 1587 else: |
kfraser@15204 | 1588 set_weight = True |
ack@11559 | 1589 |
ack@11559 | 1590 if cap is None: |
ack@11559 | 1591 cap = int(~0) |
ack@11559 | 1592 elif cap < 0 or cap > dominfo.getVCpuCount() * 100: |
ack@11559 | 1593 raise XendError("cap is out of range") |
kfraser@15204 | 1594 else: |
kfraser@15204 | 1595 set_cap = True |
ack@11559 | 1596 |
ewan@12315 | 1597 assert type(weight) == int |
ewan@12315 | 1598 assert type(cap) == int |
ewan@12315 | 1599 |
kfraser@15508 | 1600 rc = 0 |
kfraser@15508 | 1601 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED): |
kfraser@15508 | 1602 rc = xc.sched_credit_domain_set(dominfo.getDomid(), weight, cap) |
kfraser@15204 | 1603 if rc == 0: |
kfraser@15204 | 1604 if set_weight: |
kfraser@15204 | 1605 dominfo.setWeight(weight) |
kfraser@15204 | 1606 if set_cap: |
kfraser@15204 | 1607 dominfo.setCap(cap) |
kfraser@15485 | 1608 self.managed_config_save(dominfo) |
kfraser@15204 | 1609 return rc |
ack@10188 | 1610 except Exception, ex: |
ewan@12315 | 1611 log.exception(ex) |
ack@10188 | 1612 raise XendError(str(ex)) |
ack@10188 | 1613 |
emellor@7213 | 1614 def domain_maxmem_set(self, domid, mem): |
mjw@1928 | 1615 """Set the memory limit for a domain. |
mjw@1928 | 1616 |
atse@12085 | 1617 @param domid: Domain ID or Name |
atse@12085 | 1618 @type domid: int or string. |
emellor@7060 | 1619 @param mem: memory limit (in MiB) |
atse@12085 | 1620 @type mem: int |
atse@12085 | 1621 @raise XendError: fail to set memory |
atse@12085 | 1622 @rtype: 0 |
mjw@1928 | 1623 """ |
atse@12085 | 1624 dominfo = self.domain_lookup_nr(domid) |
emellor@9530 | 1625 if not dominfo: |
emellor@9530 | 1626 raise XendInvalidDomain(str(domid)) |
ewan@13061 | 1627 dominfo.setMemoryMaximum(mem) |
mjw@1928 | 1628 |
kaf24@7642 | 1629 def domain_ioport_range_enable(self, domid, first, last): |
kaf24@7642 | 1630 """Enable access to a range of IO ports for a domain |
kaf24@7642 | 1631 |
kaf24@7642 | 1632 @param first: first IO port |
kaf24@7642 | 1633 @param last: last IO port |
atse@12085 | 1634 @raise XendError: failed to set range |
atse@12085 | 1635 @rtype: 0 |
kaf24@7642 | 1636 """ |
atse@12085 | 1637 dominfo = self.domain_lookup_nr(domid) |
emellor@9530 | 1638 if not dominfo: |
emellor@9530 | 1639 raise XendInvalidDomain(str(domid)) |
kaf24@7642 | 1640 nr_ports = last - first + 1 |
kaf24@7642 | 1641 try: |
kaf24@7642 | 1642 return xc.domain_ioport_permission(dominfo.getDomid(), |
kaf24@7642 | 1643 first_port = first, |
kaf24@7642 | 1644 nr_ports = nr_ports, |
kaf24@7642 | 1645 allow_access = 1) |
kaf24@7642 | 1646 except Exception, ex: |
kaf24@7642 | 1647 raise XendError(str(ex)) |
kaf24@7642 | 1648 |
kaf24@7642 | 1649 def domain_ioport_range_disable(self, domid, first, last): |
kaf24@7642 | 1650 """Disable access to a range of IO ports for a domain |
kaf24@7642 | 1651 |
kaf24@7642 | 1652 @param first: first IO port |
kaf24@7642 | 1653 @param last: last IO port |
atse@12085 | 1654 @raise XendError: failed to set range |
atse@12085 | 1655 @rtype: 0 |
kaf24@7642 | 1656 """ |
atse@12085 | 1657 dominfo = self.domain_lookup_nr(domid) |
emellor@9530 | 1658 if not dominfo: |
emellor@9530 | 1659 raise XendInvalidDomain(str(domid)) |
kaf24@7642 | 1660 nr_ports = last - first + 1 |
kaf24@7642 | 1661 try: |
kaf24@7642 | 1662 return xc.domain_ioport_permission(dominfo.getDomid(), |
kaf24@7642 | 1663 first_port = first, |
kaf24@7642 | 1664 nr_ports = nr_ports, |
kaf24@7642 | 1665 allow_access = 0) |
kaf24@7642 | 1666 except Exception, ex: |
kaf24@7642 | 1667 raise XendError(str(ex)) |
kaf24@7642 | 1668 |
keir@14108 | 1669 def domain_send_trigger(self, domid, trigger_name, vcpu = 0): |
keir@14108 | 1670 """Send trigger to a domain. |
keir@14108 | 1671 |
keir@14108 | 1672 @param domid: Domain ID or Name |
keir@14108 | 1673 @type domid: int or string. |
keir@14108 | 1674 @param trigger_name: trigger type name |
keir@14108 | 1675 @type trigger_name: string |
keir@14108 | 1676 @param vcpu: VCPU to send trigger (default is 0) |
keir@14108 | 1677 @type vcpu: int |
keir@14108 | 1678 @raise XendError: failed to send trigger |
keir@14108 | 1679 @raise XendInvalidDomain: Domain is not valid |
keir@14108 | 1680 @rtype: 0 |
keir@14108 | 1681 """ |
keir@14108 | 1682 dominfo = self.domain_lookup_nr(domid) |
keir@14108 | 1683 if not dominfo: |
keir@14108 | 1684 raise XendInvalidDomain(str(domid)) |
kfraser@15578 | 1685 if dominfo._stateGet() not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED): |
kfraser@15578 | 1686 raise VMBadState("Domain '%s' is not started" % domid, |
kfraser@15578 | 1687 POWER_STATE_NAMES[DOM_STATE_RUNNING], |
kfraser@15578 | 1688 POWER_STATE_NAMES[dominfo._stateGet()]) |
kfraser@15852 | 1689 if trigger_name.lower() in TRIGGER_TYPE.keys(): |
keir@14108 | 1690 trigger = TRIGGER_TYPE[trigger_name.lower()] |
keir@14108 | 1691 else: |
kfraser@15852 | 1692 raise XendError("Invalid trigger: %s" % trigger_name) |
keir@17686 | 1693 if trigger == TRIGGER_S3RESUME: |
keir@17686 | 1694 xc.hvm_set_param(dominfo.getDomid(), HVM_PARAM_ACPI_S_STATE, 0) |
keir@17686 | 1695 return None |
keir@14108 | 1696 try: |
keir@14108 | 1697 return xc.domain_send_trigger(dominfo.getDomid(), |
keir@14108 | 1698 trigger, |
keir@14108 | 1699 vcpu) |
keir@14108 | 1700 except Exception, ex: |
keir@14108 | 1701 raise XendError(str(ex)) |
keir@17495 | 1702 |
keir@17495 | 1703 def domain_reset(self, domid): |
keir@17495 | 1704 """Terminate domain immediately, and then create domain. |
keir@17495 | 1705 |
keir@17495 | 1706 @param domid: Domain ID or Name |
keir@17495 | 1707 @type domid: int or string. |
keir@17495 | 1708 @rtype: None |
keir@17495 | 1709 @raise XendError: Failed to destroy or create |
keir@17495 | 1710 @raise XendInvalidDomain: Domain is not valid |
keir@17495 | 1711 """ |
keir@17495 | 1712 |
keir@17495 | 1713 dominfo = self.domain_lookup_nr(domid) |
keir@17495 | 1714 if not dominfo: |
keir@17495 | 1715 raise XendInvalidDomain(str(domid)) |
keir@17495 | 1716 if dominfo and dominfo.getDomid() == DOM0_ID: |
keir@17495 | 1717 raise XendError("Cannot reset privileged domain %s" % domid) |
keir@17495 | 1718 if dominfo._stateGet() not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED): |
keir@17495 | 1719 raise VMBadState("Domain '%s' is not started" % domid, |
keir@17495 | 1720 POWER_STATE_NAMES[DOM_STATE_RUNNING], |
keir@17495 | 1721 POWER_STATE_NAMES[dominfo._stateGet()]) |
keir@17495 | 1722 try: |
keir@17495 | 1723 dominfo.resetDomain() |
keir@17495 | 1724 except Exception, ex: |
keir@17495 | 1725 raise XendError(str(ex)) |
keir@17495 | 1726 |
emellor@7060 | 1727 |
mjw@1623 | 1728 def instance(): |
mjw@1629 | 1729 """Singleton constructor. Use this instead of the class constructor. |
mjw@1629 | 1730 """ |
mjw@1623 | 1731 global inst |
mjw@1623 | 1732 try: |
mjw@1623 | 1733 inst |
mjw@1623 | 1734 except: |
mjw@1623 | 1735 inst = XendDomain() |
emellor@8144 | 1736 inst.init() |
mjw@1623 | 1737 return inst |