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>
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