ia64/xen-unstable

annotate tools/python/xen/xend/XendDomain.py @ 12729:3570295a44cb

Added log message for when a VM is deleted.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Fri Dec 01 13:07:19 2006 +0000 (2006-12-01)
parents 36fe7ca48e54
children 39509c8f5c09
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
emellor@7151 29 import threading
mjw@1623 30
emellor@7026 31 import xen.lowlevel.xc
mjw@1623 32
emellor@7176 33
atse@12085 34 from xen.xend import XendRoot, XendCheckpoint, XendDomainInfo
atse@12085 35 from xen.xend.PrettyPrint import prettyprint
atse@12085 36 from xen.xend.XendConfig import XendConfig
atse@12510 37 from xen.xend.XendError import XendError, XendInvalidDomain, VmError
cl349@5336 38 from xen.xend.XendLogging import log
ewan@12615 39 from xen.xend.XendAPIConstants import XEN_API_VM_POWER_STATE
atse@12085 40 from xen.xend.XendConstants import XS_VMROOT
ewan@12615 41 from xen.xend.XendConstants import DOM_STATE_HALTED, DOM_STATE_PAUSED
ewan@12615 42 from xen.xend.XendConstants import DOM_STATE_RUNNING, DOM_STATE_SUSPENDED
ewan@12615 43 from xen.xend.XendConstants import DOM_STATE_SHUTDOWN, DOM_STATE_UNKNOWN
ewan@12530 44 from xen.xend.XendDevices import XendDevices
atse@12085 45
emellor@8190 46 from xen.xend.xenstore.xstransact import xstransact
emellor@7837 47 from xen.xend.xenstore.xswatch import xswatch
ewan@12725 48 from xen.util import mkdir, security
atse@12085 49 from xen.xend import uuid
emellor@7026 50
emellor@7973 51 xc = xen.lowlevel.xc.xc()
atse@12085 52 xroot = XendRoot.instance()
emellor@7026 53
mjw@1623 54 __all__ = [ "XendDomain" ]
mjw@4580 55
atse@12085 56 CACHED_CONFIG_FILE = 'config.sxp'
atse@12085 57 CHECK_POINT_FILE = 'checkpoint.chk'
atse@12085 58 DOM0_UUID = "00000000-0000-0000-0000-000000000000"
atse@12085 59 DOM0_NAME = "Domain-0"
atse@12085 60 DOM0_ID = 0
cl349@6922 61
ewan@12615 62 POWER_STATE_NAMES = dict([(x, XEN_API_VM_POWER_STATE[x])
ewan@12615 63 for x in [DOM_STATE_HALTED,
ewan@12615 64 DOM_STATE_PAUSED,
ewan@12615 65 DOM_STATE_RUNNING,
ewan@12615 66 DOM_STATE_SUSPENDED,
ewan@12615 67 DOM_STATE_SHUTDOWN,
ewan@12615 68 DOM_STATE_UNKNOWN]])
ewan@12615 69 POWER_STATE_ALL = 'all'
ewan@12615 70
ewan@12615 71
mjw@1623 72 class XendDomain:
mjw@1623 73 """Index of all domains. Singleton.
atse@12085 74
atse@12330 75 @ivar domains: map of domains indexed by domid
atse@12085 76 @type domains: dict of XendDomainInfo
atse@12330 77 @ivar managed_domains: domains that are not running and managed by Xend
atse@12330 78 @type managed_domains: dict of XendDomainInfo indexed by uuid
atse@12085 79 @ivar domains_lock: lock that must be held when manipulating self.domains
atse@12085 80 @type domains_lock: threaading.RLock
atse@12085 81 @ivar _allow_new_domains: Flag to set that allows creating of new domains.
atse@12085 82 @type _allow_new_domains: boolean
mjw@1623 83 """
mjw@1673 84
mjw@1623 85 def __init__(self):
emellor@7176 86 self.domains = {}
atse@12230 87 self.managed_domains = {}
emellor@7348 88 self.domains_lock = threading.RLock()
emellor@7837 89
atse@12085 90 # xen api instance vars
atse@12085 91 # TODO: nothing uses this at the moment
atse@12085 92 self._allow_new_domains = True
emellor@8144 93
emellor@8144 94 # This must be called only the once, by instance() below. It is separate
emellor@8144 95 # from the constructor because XendDomainInfo calls back into this class
emellor@8144 96 # in order to check the uniqueness of domain names. This means that
emellor@8144 97 # instance() must be able to return a valid instance of this class even
emellor@8144 98 # during this initialisation.
emellor@8144 99 def init(self):
atse@12085 100 """Singleton initialisation function."""
atse@12085 101
ewan@12206 102 dom_path = self._managed_path()
ewan@12725 103 mkdir.parents(dom_path, stat.S_IRWXU)
ewan@12206 104
atse@12085 105 xstransact.Mkdir(XS_VMROOT)
atse@12085 106 xstransact.SetPermissions(XS_VMROOT, {'dom': DOM0_ID})
emellor@8190 107
emellor@7176 108 self.domains_lock.acquire()
emellor@7176 109 try:
atse@12085 110 try:
atse@12085 111 dom0info = [d for d in self._running_domains() \
ewan@12144 112 if d.get('domid') == DOM0_ID][0]
atse@12085 113
atse@12141 114 dom0info['name'] = DOM0_NAME
atse@12085 115 dom0 = XendDomainInfo.recreate(dom0info, True)
atse@12085 116 self._add_domain(dom0)
atse@12085 117 except IndexError:
atse@12085 118 raise XendError('Unable to find Domain 0')
atse@12085 119
atse@12085 120 self._setDom0CPUCount()
emellor@7861 121
emellor@7861 122 # This watch registration needs to be before the refresh call, so
emellor@7861 123 # that we're sure that we haven't missed any releases, but inside
emellor@7861 124 # the domains_lock, as we don't want the watch to fire until after
emellor@7861 125 # the refresh call has completed.
atse@12085 126 xswatch("@introduceDomain", self._on_domains_changed)
atse@12085 127 xswatch("@releaseDomain", self._on_domains_changed)
atse@12085 128
atse@12085 129 self._init_domains()
emellor@7176 130 finally:
emellor@7176 131 self.domains_lock.release()
emellor@7176 132
atse@12085 133
atse@12085 134 def _on_domains_changed(self, _):
atse@12085 135 """ Callback method when xenstore changes.
mjw@1623 136
atse@12085 137 Calls refresh which will keep the local cache of domains
atse@12085 138 in sync.
cl349@5014 139
atse@12085 140 @rtype: int
atse@12085 141 @return: 1
cl349@5017 142 """
emellor@7176 143 self.domains_lock.acquire()
emellor@7176 144 try:
atse@12085 145 self._refresh()
atse@12085 146 finally:
atse@12085 147 self.domains_lock.release()
atse@12085 148 return 1
atse@12085 149
atse@12085 150 def _init_domains(self):
atse@12085 151 """Does the initial scan of managed and active domains to
atse@12085 152 populate self.domains.
atse@12085 153
atse@12085 154 Note: L{XendDomainInfo._checkName} will call back into XendDomain
atse@12085 155 to make sure domain name is not a duplicate.
atse@12085 156
atse@12085 157 """
atse@12085 158 self.domains_lock.acquire()
atse@12085 159 try:
atse@12085 160 running = self._running_domains()
atse@12085 161 managed = self._managed_domains()
atse@12085 162
atse@12114 163 # add all active domains
atse@12085 164 for dom in running:
ewan@12325 165 if dom['dying'] == 1:
ewan@12325 166 log.warn('Ignoring dying domain %d from now on' %
ewan@12325 167 dom['domid'])
ewan@12325 168 continue
ewan@12325 169
atse@12085 170 if dom['domid'] != DOM0_ID:
atse@12085 171 try:
atse@12085 172 new_dom = XendDomainInfo.recreate(dom, False)
atse@12085 173 self._add_domain(new_dom)
atse@12085 174 except Exception:
atse@12085 175 log.exception("Failed to create reference to running "
atse@12085 176 "domain id: %d" % dom['domid'])
atse@12085 177
atse@12085 178 # add all managed domains as dormant domains.
atse@12085 179 for dom in managed:
atse@12331 180 dom_uuid = dom.get('uuid')
atse@12331 181 if not dom_uuid:
atse@12331 182 continue
atse@12331 183
ewan@12709 184 dom_name = dom.get('name_label', 'Domain-%s' % dom_uuid)
atse@12085 185 try:
atse@12114 186 running_dom = self.domain_lookup_nr(dom_name)
atse@12114 187 if not running_dom:
atse@12114 188 # instantiate domain if not started.
atse@12085 189 new_dom = XendDomainInfo.createDormant(dom)
atse@12114 190 self._managed_domain_register(new_dom)
ewan@12714 191 else:
ewan@12714 192 self._managed_domain_register(running_dom)
atse@12085 193 except Exception:
atse@12085 194 log.exception("Failed to create reference to managed "
atse@12085 195 "domain: %s" % dom_name)
atse@12085 196
emellor@7176 197 finally:
emellor@7176 198 self.domains_lock.release()
emellor@7176 199
cl349@6585 200
atse@12085 201 # -----------------------------------------------------------------
atse@12085 202 # Getting managed domains storage path names
cl349@6585 203
atse@12085 204 def _managed_path(self, domuuid = None):
atse@12085 205 """Returns the path of the directory where managed domain
atse@12085 206 information is stored.
atse@12085 207
atse@12085 208 @keyword domuuid: If not None, will return the path to the domain
atse@12085 209 otherwise, will return the path containing
atse@12085 210 the directories which represent each domain.
atse@12085 211 @type: None or String.
atse@12085 212 @rtype: String
atse@12085 213 @return: Path.
cl349@6585 214 """
atse@12085 215 dom_path = xroot.get_xend_domains_path()
atse@12085 216 if domuuid:
atse@12085 217 dom_path = os.path.join(dom_path, domuuid)
atse@12085 218 return dom_path
cl349@6585 219
atse@12085 220 def _managed_config_path(self, domuuid):
atse@12085 221 """Returns the path to the configuration file of a managed domain.
cl349@6585 222
atse@12085 223 @param domname: Domain uuid
atse@12085 224 @type domname: String
atse@12085 225 @rtype: String
atse@12085 226 @return: path to config file.
cl349@6585 227 """
atse@12085 228 return os.path.join(self._managed_path(domuuid), CACHED_CONFIG_FILE)
atse@12085 229
atse@12085 230 def _managed_check_point_path(self, domuuid):
atse@12085 231 """Returns absolute path to check point file for managed domain.
atse@12085 232
atse@12085 233 @param domuuid: Name of managed domain
atse@12085 234 @type domname: String
atse@12085 235 @rtype: String
atse@12085 236 @return: Path
atse@12085 237 """
atse@12085 238 return os.path.join(self._managed_path(domuuid), CHECK_POINT_FILE)
atse@12085 239
atse@12085 240 def _managed_config_remove(self, domuuid):
atse@12085 241 """Removes a domain configuration from managed list
atse@12085 242
atse@12085 243 @param domuuid: Name of managed domain
atse@12085 244 @type domname: String
atse@12085 245 @raise XendError: fails to remove the domain.
atse@12085 246 """
atse@12085 247 config_path = self._managed_path(domuuid)
atse@12085 248 try:
atse@12085 249 if os.path.exists(config_path) and os.path.isdir(config_path):
atse@12085 250 shutil.rmtree(config_path)
atse@12085 251 except IOError:
atse@12085 252 log.exception('managed_config_remove failed removing conf')
atse@12085 253 raise XendError("Unable to remove managed configuration"
atse@12085 254 " for domain: %s" % domuuid)
atse@12085 255
atse@12085 256 def managed_config_save(self, dominfo):
atse@12085 257 """Save a domain's configuration to disk
atse@12085 258
atse@12085 259 @param domninfo: Managed domain to save.
atse@12085 260 @type dominfo: XendDomainInfo
atse@12085 261 @raise XendError: fails to save configuration.
atse@12085 262 @rtype: None
atse@12085 263 """
atse@12114 264 if not self.is_domain_managed(dominfo):
atse@12114 265 return # refuse to save configuration this domain isn't managed
atse@12114 266
atse@12085 267 if dominfo:
atse@12085 268 domains_dir = self._managed_path()
atse@12085 269 dom_uuid = dominfo.get_uuid()
atse@12085 270 domain_config_dir = self._managed_path(dom_uuid)
ewan@12725 271
ewan@12725 272 def make_or_raise(path):
atse@12085 273 try:
ewan@12725 274 mkdir.parents(path, stat.S_IRWXU)
ewan@12725 275 except:
ewan@12725 276 log.exception("%s could not be created." % path)
ewan@12725 277 raise XendError("%s could not be created." % path)
ewan@12725 278
ewan@12725 279 make_or_raise(domains_dir)
ewan@12725 280 make_or_raise(domain_config_dir)
ewan@12725 281
atse@12085 282 try:
atse@12085 283 sxp_cache_file = open(self._managed_config_path(dom_uuid),'w')
atse@12085 284 prettyprint(dominfo.sxpr(), sxp_cache_file, width = 78)
atse@12085 285 sxp_cache_file.close()
atse@12510 286 except:
atse@12510 287 log.exception("Error occurred saving configuration file " +
atse@12510 288 "to %s" % domain_config_dir)
atse@12510 289 try:
atse@12510 290 self._managed_domain_remove(dom_uuid)
atse@12510 291 except:
atse@12510 292 pass
atse@12085 293 raise XendError("Failed to save configuration file to: %s" %
atse@12085 294 domain_config_dir)
atse@12085 295 else:
atse@12085 296 log.warn("Trying to save configuration for invalid domain")
cl349@6585 297
emellor@7151 298
atse@12085 299 def _managed_domains(self):
atse@12085 300 """ Returns list of domains that are managed.
atse@12085 301
atse@12085 302 Expects to be protected by domains_lock.
cl349@6677 303
atse@12085 304 @rtype: list of XendConfig
atse@12085 305 @return: List of domain configurations that are managed.
mjw@1623 306 """
atse@12085 307 dom_path = self._managed_path()
atse@12085 308 dom_uuids = os.listdir(dom_path)
atse@12085 309 doms = []
atse@12085 310 for dom_uuid in dom_uuids:
atse@12085 311 try:
atse@12085 312 cfg_file = self._managed_config_path(dom_uuid)
atse@12085 313 cfg = XendConfig(filename = cfg_file)
atse@12331 314 if cfg.get('uuid') != dom_uuid:
atse@12331 315 # something is wrong with the SXP
atse@12331 316 log.error("UUID mismatch in stored configuration: %s" %
atse@12331 317 cfg_file)
atse@12331 318 continue
atse@12085 319 doms.append(cfg)
atse@12085 320 except Exception:
atse@12085 321 log.exception('Unable to open or parse config.sxp: %s' % \
atse@12085 322 cfg_file)
mjw@4580 323 return doms
mjw@4580 324
atse@12085 325 def _managed_domain_unregister(self, dom):
atse@12085 326 try:
atse@12230 327 if self.is_domain_managed(dom):
atse@12342 328 self._managed_config_remove(dom.get_uuid())
atse@12230 329 del self.managed_domains[dom.get_uuid()]
atse@12085 330 except ValueError:
atse@12085 331 log.warn("Domain is not registered: %s" % dom.get_uuid())
emellor@7072 332
atse@12085 333 def _managed_domain_register(self, dom):
atse@12230 334 self.managed_domains[dom.get_uuid()] = dom
atse@12085 335
atse@12230 336 def is_domain_managed(self, dom = None):
atse@12230 337 return (dom.get_uuid() in self.managed_domains)
atse@12085 338
atse@12085 339 # End of Managed Domain Access
atse@12085 340 # --------------------------------------------------------------------
atse@12085 341
atse@12085 342 def _running_domains(self):
atse@12085 343 """Get table of domains indexed by id from xc.
atse@12085 344
atse@12085 345 @requires: Expects to be protected by domains_lock.
atse@12085 346 @rtype: list of dicts
atse@12085 347 @return: A list of dicts representing the running domains.
atse@12085 348 """
atse@12237 349 try:
atse@12237 350 return xc.domain_getinfo()
atse@12237 351 except RuntimeError, e:
atse@12237 352 log.exception("Unable to get domain information.")
atse@12237 353 return {}
atse@12085 354
atse@12085 355 def _setDom0CPUCount(self):
atse@12085 356 """Sets the number of VCPUs dom0 has. Retreived from the
atse@12085 357 Xend configuration, L{XendRoot}.
atse@12085 358
atse@12085 359 @requires: Expects to be protected by domains_lock.
atse@12085 360 @rtype: None
atse@12085 361 """
atse@12085 362 dom0 = self.privilegedDomain()
emellor@7410 363
emellor@7410 364 # get max number of vcpus to use for dom0 from config
emellor@7410 365 target = int(xroot.get_dom0_vcpus())
emellor@7410 366 log.debug("number of vcpus to use is %d", target)
emellor@7410 367
emellor@7410 368 # target == 0 means use all processors
emellor@7410 369 if target > 0:
emellor@7426 370 dom0.setVCpuCount(target)
cl349@5911 371
mjw@1623 372
atse@12085 373 def _refresh(self):
atse@12085 374 """Refresh the domain list. Needs to be called when
atse@12085 375 either xenstore has changed or when a method requires
atse@12085 376 up to date information (like uptime, cputime stats).
emellor@7240 377
ewan@12315 378 Expects to be protected by the domains_lock.
ewan@12315 379
atse@12085 380 @rtype: None
mjw@1629 381 """
atse@12085 382
ewan@12315 383 running = self._running_domains()
atse@12510 384 # Add domains that are not already tracked but running in Xen,
atse@12510 385 # and update domain state for those that are running and tracked.
ewan@12315 386 for dom in running:
ewan@12315 387 domid = dom['domid']
atse@12511 388 if domid in self.domains:
ewan@12315 389 self.domains[domid].update(dom)
atse@12510 390 elif domid not in self.domains and dom['dying'] != 1:
atse@12510 391 try:
atse@12510 392 new_dom = XendDomainInfo.recreate(dom, False)
atse@12510 393 self._add_domain(new_dom)
atse@12510 394 except VmError:
atse@12510 395 log.exception("Unable to recreate domain")
atse@12510 396 try:
atse@12510 397 xc.domain_destroy(domid)
atse@12510 398 except:
atse@12510 399 log.exception("Hard destruction of domain failed: %d" %
atse@12510 400 domid)
ewan@12315 401
atse@12511 402 # update information for all running domains
atse@12511 403 # - like cpu_time, status, dying, etc.
atse@12511 404 # remove domains that are not running from active domain list.
atse@12511 405 # The list might have changed by now, because the update call may
atse@12511 406 # cause new domains to be added, if the domain has rebooted. We get
atse@12511 407 # the list again.
atse@12511 408 running = self._running_domains()
atse@12511 409 running_domids = [d['domid'] for d in running if d['dying'] != 1]
atse@12511 410 for domid, dom in self.domains.items():
atse@12511 411 if domid not in running_domids and domid != DOM0_ID:
atse@12511 412 self._remove_domain(dom, domid)
atse@12511 413
atse@12511 414
atse@12230 415 def _add_domain(self, info):
atse@12331 416 """Add a domain to the list of running domains
atse@12085 417
atse@12085 418 @requires: Expects to be protected by the domains_lock.
atse@12085 419 @param info: XendDomainInfo of a domain to be added.
atse@12085 420 @type info: XendDomainInfo
mjw@1744 421 """
atse@12230 422 log.debug("Adding Domain: %s" % info.getDomid())
atse@12230 423 self.domains[info.getDomid()] = info
atse@12686 424
atse@12686 425 # update the managed domains with a new XendDomainInfo object
atse@12686 426 # if we are keeping track of it.
atse@12686 427 if info.get_uuid() in self.managed_domains:
atse@12686 428 self._managed_domain_register(info)
cl349@5336 429
atse@12230 430 def _remove_domain(self, info, domid = None):
atse@12331 431 """Remove the domain from the list of running domains
atse@12085 432
atse@12085 433 @requires: Expects to be protected by the domains_lock.
atse@12085 434 @param info: XendDomainInfo of a domain to be removed.
atse@12085 435 @type info: XendDomainInfo
atse@12085 436 """
atse@12230 437 if info:
atse@12230 438 if domid == None:
atse@12230 439 domid = info.getDomid()
atse@12230 440
atse@12230 441 if info.state != DOM_STATE_HALTED:
atse@12230 442 info.cleanupDomain()
atse@12230 443
atse@12230 444 if domid in self.domains:
atse@12230 445 del self.domains[domid]
atse@12085 446 else:
atse@12085 447 log.warning("Attempted to remove non-existent domain.")
emellor@7181 448
emellor@7181 449 def restore_(self, config):
emellor@7181 450 """Create a domain as part of the restore process. This is called
atse@12085 451 only from L{XendCheckpoint}.
emellor@7181 452
atse@12085 453 A restore request comes into XendDomain through L{domain_restore}
atse@12085 454 or L{domain_restore_fd}. That request is
emellor@7181 455 forwarded immediately to XendCheckpoint which, when it is ready, will
emellor@7181 456 call this method. It is necessary to come through here rather than go
atse@12085 457 directly to L{XendDomainInfo.restore} because we need to
emellor@7181 458 serialise the domain creation process, but cannot lock
emellor@7181 459 domain_restore_fd as a whole, otherwise we will deadlock waiting for
emellor@7181 460 the old domain to die.
atse@12085 461
atse@12085 462 @param config: Configuration of domain to restore
atse@12085 463 @type config: SXP Object (eg. list of lists)
emellor@7181 464 """
emellor@7181 465 self.domains_lock.acquire()
emellor@7181 466 try:
smh22@9836 467 security.refresh_ssidref(config)
emellor@7181 468 dominfo = XendDomainInfo.restore(config)
emellor@7181 469 self._add_domain(dominfo)
emellor@7181 470 return dominfo
emellor@7181 471 finally:
emellor@7181 472 self.domains_lock.release()
emellor@7181 473
emellor@7006 474
emellor@7213 475 def domain_lookup(self, domid):
atse@12085 476 """Look up given I{domid} in the list of managed and running
atse@12085 477 domains.
atse@12085 478
atse@12085 479 @note: Will cause a refresh before lookup up domains, for
atse@12085 480 a version that does not need to re-read xenstore
atse@12085 481 use L{domain_lookup_nr}.
atse@12085 482
atse@12085 483 @param domid: Domain ID or Domain Name.
atse@12085 484 @type domid: int or string
atse@12085 485 @return: Found domain.
atse@12085 486 @rtype: XendDomainInfo
atse@12085 487 @raise XendError: If domain is not found.
atse@12085 488 """
emellor@7176 489 self.domains_lock.acquire()
emellor@7176 490 try:
atse@12085 491 self._refresh()
atse@12085 492 dom = self.domain_lookup_nr(domid)
atse@12085 493 if not dom:
atse@12085 494 raise XendError("No domain named '%s'." % str(domid))
atse@12085 495 return dom
emellor@7176 496 finally:
emellor@7176 497 self.domains_lock.release()
cl349@5334 498
emellor@7176 499
emellor@7213 500 def domain_lookup_nr(self, domid):
atse@12085 501 """Look up given I{domid} in the list of managed and running
atse@12085 502 domains.
atse@12085 503
atse@12085 504 @param domid: Domain ID or Domain Name.
atse@12085 505 @type domid: int or string
atse@12085 506 @return: Found domain.
atse@12085 507 @rtype: XendDomainInfo or None
atse@12085 508 """
emellor@7176 509 self.domains_lock.acquire()
emellor@7176 510 try:
atse@12085 511 # lookup by name
atse@12085 512 match = [dom for dom in self.domains.values() \
atse@12085 513 if dom.getName() == domid]
atse@12085 514 if match:
atse@12085 515 return match[0]
atse@12085 516
atse@12330 517 match = [dom for dom in self.managed_domains.values() \
atse@12330 518 if dom.getName() == domid]
atse@12330 519 if match:
atse@12330 520 return match[0]
atse@12330 521
atse@12085 522 # lookup by id
atse@12085 523 try:
atse@12230 524 if int(domid) in self.domains:
atse@12230 525 return self.domains[int(domid)]
atse@12230 526 except ValueError:
atse@12085 527 pass
atse@12085 528
atse@12330 529 # lookup by uuid for running domains
atse@12330 530 match = [dom for dom in self.domains.values() \
atse@12330 531 if dom.get_uuid() == domid]
atse@12330 532 if match:
atse@12330 533 return match[0]
atse@12330 534
atse@12330 535 # lookup by uuid for inactive managed domains
atse@12330 536 if domid in self.managed_domains:
atse@12330 537 return self.managed_domains[domid]
atse@12330 538
atse@12085 539 return None
emellor@7176 540 finally:
emellor@7176 541 self.domains_lock.release()
emellor@7176 542
atse@12085 543 def privilegedDomain(self):
atse@12085 544 """ Get the XendDomainInfo of a dom0
emellor@7176 545
atse@12085 546 @rtype: XendDomainInfo
atse@12085 547 """
emellor@7176 548 self.domains_lock.acquire()
emellor@7176 549 try:
atse@12230 550 return self.domains[DOM0_ID]
emellor@7176 551 finally:
emellor@7176 552 self.domains_lock.release()
emellor@7176 553
atse@12085 554 def cleanup_domains(self):
atse@12085 555 """Clean up domains that are marked as autostop.
atse@12085 556 Should be called when Xend goes down. This is currently
atse@12085 557 called from L{xen.xend.servers.XMLRPCServer}.
emellor@7176 558
atse@12085 559 """
atse@12085 560 log.debug('cleanup_domains')
emellor@7176 561 self.domains_lock.acquire()
emellor@7176 562 try:
atse@12085 563 for dom in self.domains.values():
atse@12085 564 if dom.getName() == DOM0_NAME:
atse@12085 565 continue
atse@12085 566
atse@12230 567 if dom.state == DOM_STATE_RUNNING:
atse@12099 568 shutdownAction = dom.info.get('on_xend_stop', 'ignore')
atse@12148 569 if shutdownAction == 'shutdown':
atse@12085 570 log.debug('Shutting down domain: %s' % dom.getName())
atse@12085 571 dom.shutdown("poweroff")
atse@12148 572 elif shutdownAction == 'suspend':
ewan@12598 573 self.domain_suspend(dom.getName())
emellor@7176 574 finally:
emellor@7176 575 self.domains_lock.release()
emellor@7176 576
emellor@7176 577
atse@12085 578
atse@12085 579 # ----------------------------------------------------------------
atse@12085 580 # Xen API
atse@12085 581
atse@12085 582
atse@12085 583 def set_allow_new_domains(self, allow_new_domains):
atse@12085 584 self._allow_new_domains = allow_new_domains
atse@12085 585
atse@12085 586 def allow_new_domains(self):
atse@12085 587 return self._allow_new_domains
atse@12085 588
atse@12085 589 def get_domain_refs(self):
atse@12085 590 result = []
atse@12085 591 try:
atse@12085 592 self.domains_lock.acquire()
atse@12101 593 result = [d.get_uuid() for d in self.domains.values()]
atse@12230 594 result += self.managed_domains.keys()
atse@12230 595 return result
atse@12085 596 finally:
atse@12085 597 self.domains_lock.release()
atse@12085 598
atse@12085 599 def get_vm_by_uuid(self, vm_uuid):
emellor@7176 600 self.domains_lock.acquire()
emellor@7176 601 try:
atse@12230 602 for dom in self.domains.values():
atse@12230 603 if dom.get_uuid() == vm_uuid:
atse@12230 604 return dom
atse@12230 605
atse@12230 606 if vm_uuid in self.managed_domains:
atse@12230 607 return self.managed_domains[vm_uuid]
atse@12230 608
emellor@7223 609 return None
emellor@7176 610 finally:
emellor@7176 611 self.domains_lock.release()
mjw@1975 612
atse@12111 613 def get_vm_with_dev_uuid(self, klass, dev_uuid):
atse@12111 614 self.domains_lock.acquire()
atse@12085 615 try:
atse@12230 616 for dom in self.domains.values() + self.managed_domains.values():
atse@12111 617 if dom.has_device(klass, dev_uuid):
atse@12111 618 return dom
atse@12111 619 return None
atse@12111 620 finally:
atse@12111 621 self.domains_lock.release()
atse@12085 622
atse@12111 623 def get_dev_property_by_uuid(self, klass, dev_uuid, field):
atse@12111 624 self.domains_lock.acquire()
atse@12111 625 try:
atse@12111 626 dom = self.get_vm_with_dev_uuid(klass, dev_uuid)
atse@12111 627 if not dom:
atse@12111 628 return None
atse@12111 629
atse@12148 630 value = dom.get_device_property(klass, dev_uuid, field)
atse@12111 631 return value
atse@12085 632 except ValueError, e:
atse@12085 633 pass
atse@12085 634
atse@12085 635 return None
atse@12085 636
atse@12085 637 def is_valid_vm(self, vm_ref):
atse@12085 638 return (self.get_vm_by_uuid(vm_ref) != None)
atse@12085 639
atse@12085 640 def is_valid_dev(self, klass, dev_uuid):
atse@12111 641 return (self.get_vm_with_dev_uuid(klass, dev_uuid) != None)
atse@12085 642
ewan@12642 643 def do_legacy_api_with_uuid(self, fn, vm_uuid, *args, **kwargs):
atse@12085 644 self.domains_lock.acquire()
atse@12085 645 try:
atse@12230 646 for domid, dom in self.domains.items():
atse@12230 647 if dom.get_uuid == vm_uuid:
ewan@12642 648 return fn(domid, *args, **kwargs)
atse@12230 649
atse@12230 650 if vm_uuid in self.managed_domains:
atse@12230 651 domid = self.managed_domains[vm_uuid].getDomid()
atse@12085 652 if domid == None:
atse@12230 653 domid = self.managed_domains[vm_uuid].getName()
ewan@12642 654 return fn(domid, *args, **kwargs)
atse@12230 655
atse@12085 656 raise XendInvalidDomain("Domain does not exist")
atse@12085 657 finally:
atse@12085 658 self.domains_lock.release()
atse@12085 659
atse@12085 660
atse@12085 661 def create_domain(self, xenapi_vm):
atse@12085 662 self.domains_lock.acquire()
atse@12085 663 try:
atse@12085 664 try:
atse@12686 665 xeninfo = XendConfig(xapi = xenapi_vm)
atse@12085 666 dominfo = XendDomainInfo.createDormant(xeninfo)
atse@12085 667 log.debug("Creating new managed domain: %s: %s" %
atse@12085 668 (dominfo.getName(), dominfo.get_uuid()))
atse@12230 669 self._managed_domain_register(dominfo)
atse@12085 670 self.managed_config_save(dominfo)
atse@12085 671 return dominfo.get_uuid()
atse@12085 672 except XendError, e:
atse@12085 673 raise
atse@12085 674 except Exception, e:
atse@12085 675 raise XendError(str(e))
atse@12085 676 finally:
atse@12085 677 self.domains_lock.release()
atse@12085 678
atse@12085 679 def rename_domain(self, dom, new_name):
atse@12085 680 self.domains_lock.acquire()
atse@12085 681 try:
atse@12085 682 old_name = dom.getName()
atse@12085 683 dom.setName(new_name)
atse@12085 684
atse@12085 685 finally:
atse@12085 686 self.domains_lock.release()
atse@12085 687
atse@12085 688
atse@12085 689 #
atse@12085 690 # End of Xen API
atse@12085 691 # ----------------------------------------------------------------
atse@12085 692
atse@12085 693 # ------------------------------------------------------------
atse@12085 694 # Xen Legacy API
atse@12085 695
ewan@12615 696 def list(self, state = DOM_STATE_RUNNING):
atse@12085 697 """Get list of domain objects.
atse@12085 698
ewan@12615 699 @param: the state in which the VMs should be -- one of the
ewan@12615 700 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
atse@12085 701 @return: domains
atse@12085 702 @rtype: list of XendDomainInfo
atse@12085 703 """
ewan@12615 704 if type(state) == int:
ewan@12615 705 state = POWER_STATE_NAMES[state]
ewan@12615 706 state = state.lower()
ewan@12615 707
atse@12085 708 self.domains_lock.acquire()
atse@12085 709 try:
atse@12085 710 self._refresh()
atse@12230 711
atse@12230 712 # active domains
atse@12230 713 active_domains = self.domains.values()
atse@12230 714 active_uuids = [d.get_uuid() for d in active_domains]
atse@12230 715
atse@12230 716 # inactive domains
atse@12230 717 inactive_domains = []
atse@12230 718 for dom_uuid, dom in self.managed_domains.items():
atse@12230 719 if dom_uuid not in active_uuids:
atse@12230 720 inactive_domains.append(dom)
atse@12230 721
ewan@12615 722 if state == POWER_STATE_ALL:
ewan@12615 723 return active_domains + inactive_domains
ewan@12615 724 else:
ewan@12615 725 return filter(lambda x:
ewan@12615 726 POWER_STATE_NAMES[x.state].lower() == state,
ewan@12615 727 active_domains + inactive_domains)
atse@12085 728 finally:
atse@12085 729 self.domains_lock.release()
atse@12085 730
emellor@7172 731
ewan@12615 732 def list_sorted(self, state = DOM_STATE_RUNNING):
atse@12085 733 """Get list of domain objects, sorted by name.
atse@12085 734
ewan@12615 735 @param: the state in which the VMs should be -- one of the
ewan@12615 736 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
atse@12085 737 @return: domain objects
atse@12085 738 @rtype: list of XendDomainInfo
atse@12085 739 """
ewan@12615 740 doms = self.list(state)
atse@12085 741 doms.sort(lambda x, y: cmp(x.getName(), y.getName()))
atse@12085 742 return doms
atse@12085 743
ewan@12615 744 def list_names(self, state = DOM_STATE_RUNNING):
atse@12085 745 """Get list of domain names.
atse@12085 746
ewan@12615 747 @param: the state in which the VMs should be -- one of the
ewan@12615 748 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
atse@12085 749 @return: domain names
atse@12085 750 @rtype: list of strings.
atse@12085 751 """
ewan@12615 752 return [d.getName() for d in self.list_sorted(state)]
atse@12085 753
atse@12085 754 def domain_suspend(self, domname):
atse@12085 755 """Suspends a domain that is persistently managed by Xend
atse@12085 756
atse@12085 757 @param domname: Domain Name
atse@12085 758 @type domname: string
atse@12085 759 @rtype: None
atse@12085 760 @raise XendError: Failure during checkpointing.
atse@12085 761 """
atse@12085 762
atse@12085 763 try:
atse@12085 764 dominfo = self.domain_lookup_nr(domname)
atse@12085 765 if not dominfo:
atse@12085 766 raise XendInvalidDomain(domname)
atse@12085 767
atse@12085 768 if dominfo.getDomid() == DOM0_ID:
atse@12085 769 raise XendError("Cannot save privileged domain %s" % domname)
atse@12085 770
atse@12230 771 if dominfo.state != DOM_STATE_RUNNING:
atse@12085 772 raise XendError("Cannot suspend domain that is not running.")
atse@12085 773
ewan@12598 774 dom_uuid = dominfo.get_uuid()
ewan@12598 775
ewan@12598 776 if not os.path.exists(self._managed_config_path(dom_uuid)):
atse@12085 777 raise XendError("Domain is not managed by Xend lifecycle " +
atse@12085 778 "support.")
ewan@12598 779
ewan@12598 780 path = self._managed_check_point_path(dom_uuid)
atse@12085 781 fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
atse@12085 782 try:
atse@12085 783 # For now we don't support 'live checkpoint'
atse@12085 784 XendCheckpoint.save(fd, dominfo, False, False, path)
atse@12085 785 finally:
atse@12085 786 os.close(fd)
atse@12085 787 except OSError, ex:
atse@12085 788 raise XendError("can't write guest state file %s: %s" %
atse@12085 789 (path, ex[1]))
atse@12085 790
ewan@12642 791 def domain_resume(self, domname, start_paused = False):
atse@12085 792 """Resumes a domain that is persistently managed by Xend.
atse@12085 793
atse@12085 794 @param domname: Domain Name
atse@12085 795 @type domname: string
atse@12085 796 @rtype: None
atse@12085 797 @raise XendError: If failed to restore.
atse@12085 798 """
ewan@12598 799 self.domains_lock.acquire()
atse@12085 800 try:
ewan@12598 801 try:
ewan@12598 802 dominfo = self.domain_lookup_nr(domname)
atse@12085 803
ewan@12598 804 if not dominfo:
ewan@12598 805 raise XendInvalidDomain(domname)
atse@12085 806
ewan@12598 807 if dominfo.getDomid() == DOM0_ID:
ewan@12598 808 raise XendError("Cannot save privileged domain %s" % domname)
ewan@12598 809
ewan@12598 810 if dominfo.state != DOM_STATE_HALTED:
ewan@12598 811 raise XendError("Cannot suspend domain that is not running.")
ewan@12598 812
ewan@12598 813 dom_uuid = dominfo.get_uuid()
ewan@12598 814 chkpath = self._managed_check_point_path(dom_uuid)
ewan@12598 815 if not os.path.exists(chkpath):
ewan@12598 816 raise XendError("Domain was not suspended by Xend")
ewan@12598 817
ewan@12598 818 # Restore that replaces the existing XendDomainInfo
ewan@12598 819 try:
ewan@12598 820 log.debug('Current DomainInfo state: %d' % dominfo.state)
ewan@12598 821 XendCheckpoint.restore(self,
ewan@12598 822 os.open(chkpath, os.O_RDONLY),
ewan@12642 823 dominfo,
ewan@12642 824 paused = start_paused)
ewan@12598 825 self._add_domain(dominfo)
ewan@12598 826 os.unlink(chkpath)
ewan@12598 827 except OSError, ex:
ewan@12598 828 raise XendError("Failed to read stored checkpoint file")
ewan@12598 829 except IOError, ex:
ewan@12598 830 raise XendError("Failed to delete checkpoint file")
ewan@12598 831 except Exception, ex:
ewan@12598 832 log.exception("Exception occurred when resuming")
ewan@12598 833 raise XendError("Error occurred when resuming: %s" % str(ex))
ewan@12598 834 finally:
ewan@12598 835 self.domains_lock.release()
atse@12085 836
atse@12085 837
atse@12085 838 def domain_create(self, config):
atse@12085 839 """Create a domain from a configuration.
atse@12085 840
atse@12085 841 @param config: configuration
atse@12085 842 @type config: SXP Object (list of lists)
atse@12085 843 @rtype: XendDomainInfo
atse@12085 844 """
emellor@7176 845 self.domains_lock.acquire()
emellor@7176 846 try:
ewan@12312 847 self._refresh()
ewan@12312 848
atse@12085 849 dominfo = XendDomainInfo.create(config)
atse@12085 850 self._add_domain(dominfo)
ewan@12195 851 self.domain_sched_credit_set(dominfo.getDomid(),
ewan@12195 852 dominfo.getWeight(),
ewan@12195 853 dominfo.getCap())
atse@12085 854 return dominfo
emellor@7176 855 finally:
emellor@7176 856 self.domains_lock.release()
emellor@7172 857
kfraser@10711 858
atse@12085 859 def domain_new(self, config):
atse@12085 860 """Create a domain from a configuration but do not start it.
atse@12085 861
atse@12085 862 @param config: configuration
atse@12085 863 @type config: SXP Object (list of lists)
atse@12085 864 @rtype: XendDomainInfo
atse@12085 865 """
atse@12085 866 self.domains_lock.acquire()
atse@12085 867 try:
atse@12085 868 try:
atse@12686 869 domconfig = XendConfig(sxp_obj = config)
atse@12686 870 dominfo = XendDomainInfo.createDormant(domconfig)
atse@12085 871 log.debug("Creating new managed domain: %s" %
atse@12085 872 dominfo.getName())
atse@12230 873 self._managed_domain_register(dominfo)
atse@12085 874 self.managed_config_save(dominfo)
atse@12085 875 # no return value because it isn't meaningful for client
atse@12085 876 except XendError, e:
atse@12085 877 raise
atse@12085 878 except Exception, e:
atse@12085 879 raise XendError(str(e))
atse@12085 880 finally:
atse@12085 881 self.domains_lock.release()
kfraser@10711 882
ewan@12642 883 def domain_start(self, domid, start_paused = True):
atse@12085 884 """Start a managed domain
atse@12085 885
atse@12085 886 @require: Domain must not be running.
atse@12085 887 @param domid: Domain name or domain ID.
atse@12085 888 @type domid: string or int
atse@12085 889 @rtype: None
atse@12085 890 @raise XendError: If domain is still running
atse@12085 891 @rtype: None
atse@12085 892 """
atse@12085 893 self.domains_lock.acquire()
atse@12085 894 try:
ewan@12312 895 self._refresh()
ewan@12312 896
atse@12085 897 dominfo = self.domain_lookup_nr(domid)
atse@12085 898 if not dominfo:
atse@12085 899 raise XendInvalidDomain(str(domid))
atse@12085 900
atse@12230 901 if dominfo.state != DOM_STATE_HALTED:
atse@12085 902 raise XendError("Domain is already running")
atse@12085 903
ewan@12643 904 dominfo.start(is_managed = True)
atse@12331 905 self._add_domain(dominfo)
atse@12085 906 finally:
atse@12085 907 self.domains_lock.release()
ewan@12643 908 dominfo.waitForDevices()
ewan@12643 909 if not start_paused:
ewan@12643 910 dominfo.unpause()
atse@12085 911
atse@12085 912
atse@12085 913 def domain_delete(self, domid):
atse@12230 914 """Remove a managed domain from database
atse@12085 915
atse@12085 916 @require: Domain must not be running.
atse@12085 917 @param domid: Domain name or domain ID.
atse@12085 918 @type domid: string or int
atse@12085 919 @rtype: None
atse@12085 920 @raise XendError: If domain is still running
atse@12085 921 """
atse@12085 922 self.domains_lock.acquire()
atse@12085 923 try:
atse@12085 924 try:
atse@12085 925 dominfo = self.domain_lookup_nr(domid)
atse@12085 926 if not dominfo:
atse@12085 927 raise XendInvalidDomain(str(domid))
atse@12085 928
atse@12230 929 if dominfo.state != DOM_STATE_HALTED:
atse@12085 930 raise XendError("Domain is still running")
atse@12085 931
ewan@12729 932 log.info("Domain %s (%s) deleted." %
ewan@12729 933 (dominfo.getName(), dominfo.info.get('uuid')))
ewan@12729 934
atse@12230 935 self._managed_domain_unregister(dominfo)
atse@12085 936 self._remove_domain(dominfo)
ewan@12530 937 XendDevices.destroy_device_state(dominfo)
atse@12085 938 except Exception, ex:
atse@12085 939 raise XendError(str(ex))
atse@12085 940 finally:
atse@12085 941 self.domains_lock.release()
atse@12085 942
atse@12085 943
atse@12085 944 def domain_configure(self, config):
atse@12085 945 """Configure an existing domain.
atse@12085 946
atse@12085 947 @param vmconfig: vm configuration
atse@12085 948 @type vmconfig: SXP Object (list of lists)
atse@12085 949 @todo: Not implemented
atse@12085 950 """
atse@12085 951 # !!!
atse@12085 952 raise XendError("Unsupported")
atse@12085 953
brendan@12552 954 def domain_restore(self, src, paused=False):
atse@12085 955 """Restore a domain from file.
atse@12085 956
atse@12085 957 @param src: filename of checkpoint file to restore from
atse@12085 958 @type src: string
atse@12085 959 @return: Restored domain
atse@12085 960 @rtype: XendDomainInfo
atse@12085 961 @raise XendError: Failure to restore domain
atse@12085 962 """
atse@12085 963 try:
atse@12085 964 fd = os.open(src, os.O_RDONLY)
atse@12085 965 try:
brendan@12552 966 return self.domain_restore_fd(fd, paused=paused)
atse@12085 967 finally:
atse@12085 968 os.close(fd)
atse@12085 969 except OSError, ex:
atse@12085 970 raise XendError("can't read guest state file %s: %s" %
atse@12085 971 (src, ex[1]))
atse@12085 972
brendan@12552 973 def domain_restore_fd(self, fd, paused=False):
atse@12085 974 """Restore a domain from the given file descriptor.
atse@12085 975
atse@12085 976 @param fd: file descriptor of the checkpoint file
atse@12085 977 @type fd: File object
atse@12085 978 @rtype: XendDomainInfo
atse@12085 979 @raise XendError: if failed to restore
atse@12085 980 """
kfraser@10711 981
mjw@1985 982 try:
brendan@12552 983 return XendCheckpoint.restore(self, fd, paused=paused)
atse@12085 984 except:
atse@12085 985 # I don't really want to log this exception here, but the error
atse@12085 986 # handling in the relocation-socket handling code (relocate.py) is
atse@12085 987 # poor, so we need to log this for debugging.
atse@12085 988 log.exception("Restore failed")
atse@12085 989 raise XendError("Restore failed")
atse@12085 990
atse@12085 991 def domain_unpause(self, domid):
atse@12085 992 """Unpause domain execution.
atse@12085 993
atse@12085 994 @param domid: Domain ID or Name
atse@12085 995 @type domid: int or string.
atse@12085 996 @rtype: None
atse@12085 997 @raise XendError: Failed to unpause
atse@12085 998 @raise XendInvalidDomain: Domain is not valid
atse@12085 999 """
atse@12085 1000 try:
atse@12085 1001 dominfo = self.domain_lookup_nr(domid)
atse@12085 1002 if not dominfo:
atse@12085 1003 raise XendInvalidDomain(str(domid))
ewan@12485 1004 if dominfo.getDomid() == DOM0_ID:
ewan@12485 1005 raise XendError("Cannot unpause privileged domain %s" % domid)
emellor@7215 1006 log.info("Domain %s (%d) unpaused.", dominfo.getName(),
atse@12085 1007 int(dominfo.getDomid()))
atse@12085 1008 dominfo.unpause()
atse@12085 1009 except XendInvalidDomain:
atse@12085 1010 log.exception("domain_unpause")
atse@12085 1011 raise
mjw@1985 1012 except Exception, ex:
atse@12085 1013 log.exception("domain_unpause")
mjw@1985 1014 raise XendError(str(ex))
emellor@7215 1015
emellor@7213 1016 def domain_pause(self, domid):
atse@12085 1017 """Pause domain execution.
kfraser@10711 1018
atse@12085 1019 @param domid: Domain ID or Name
atse@12085 1020 @type domid: int or string.
atse@12085 1021 @rtype: None
atse@12085 1022 @raise XendError: Failed to pause
atse@12085 1023 @raise XendInvalidDomain: Domain is not valid
atse@12085 1024 """
mjw@1985 1025 try:
atse@12085 1026 dominfo = self.domain_lookup_nr(domid)
atse@12085 1027 if not dominfo:
atse@12085 1028 raise XendInvalidDomain(str(domid))
ewan@12485 1029 if dominfo.getDomid() == DOM0_ID:
ewan@12485 1030 raise XendError("Cannot pause privileged domain %s" % domid)
emellor@7215 1031 log.info("Domain %s (%d) paused.", dominfo.getName(),
atse@12085 1032 int(dominfo.getDomid()))
atse@12085 1033 dominfo.pause()
atse@12085 1034 except XendInvalidDomain:
atse@12085 1035 log.exception("domain_pause")
atse@12085 1036 raise
mjw@1985 1037 except Exception, ex:
atse@12085 1038 log.exception("domain_pause")
mjw@1985 1039 raise XendError(str(ex))
emellor@7072 1040
root@11477 1041 def domain_dump(self, domid, filename, live, crash):
root@11477 1042 """Dump domain core."""
root@11477 1043
atse@12148 1044 dominfo = self.domain_lookup_nr(domid)
root@11477 1045 if not dominfo:
root@11477 1046 raise XendInvalidDomain(str(domid))
root@11477 1047
atse@12148 1048 if dominfo.getDomid() == DOM0_ID:
root@11477 1049 raise XendError("Cannot dump core for privileged domain %s" % domid)
root@11477 1050
root@11477 1051 try:
atse@12148 1052 log.info("Domain core dump requested for domain %s (%d) "
atse@12148 1053 "live=%d crash=%d.",
root@11477 1054 dominfo.getName(), dominfo.getDomid(), live, crash)
root@11477 1055 return dominfo.dumpCore(filename)
root@11477 1056 except Exception, ex:
root@11477 1057 raise XendError(str(ex))
emellor@7072 1058
emellor@7173 1059 def domain_destroy(self, domid):
atse@12085 1060 """Terminate domain immediately.
emellor@7015 1061
atse@12085 1062 @param domid: Domain ID or Name
atse@12085 1063 @type domid: int or string.
atse@12085 1064 @rtype: None
atse@12085 1065 @raise XendError: Failed to destroy
atse@12085 1066 @raise XendInvalidDomain: Domain is not valid
atse@12085 1067 """
atse@12085 1068
atse@12085 1069 dominfo = self.domain_lookup_nr(domid)
atse@12085 1070 if dominfo and dominfo.getDomid() == DOM0_ID:
anthony@9421 1071 raise XendError("Cannot destroy privileged domain %s" % domid)
anthony@9421 1072
cl349@6913 1073 if dominfo:
cl349@6913 1074 val = dominfo.destroy()
cl349@6913 1075 else:
cl349@6913 1076 try:
kaf24@10996 1077 val = xc.domain_destroy(int(domid))
atse@12085 1078 except ValueError:
atse@12085 1079 raise XendInvalidDomain(domid)
atse@12085 1080 except Exception, e:
atse@12085 1081 raise XendError(str(e))
atse@12085 1082
cl349@6913 1083 return val
mjw@1673 1084
vhanquez@8274 1085 def domain_migrate(self, domid, dst, live=False, resource=0, port=0):
atse@12085 1086 """Start domain migration.
atse@12085 1087
atse@12085 1088 @param domid: Domain ID or Name
atse@12085 1089 @type domid: int or string.
atse@12085 1090 @param dst: Destination IP address
atse@12085 1091 @type dst: string
atse@12085 1092 @keyword port: relocation port on destination
atse@12085 1093 @type port: int
atse@12085 1094 @keyword live: Live migration
atse@12085 1095 @type live: bool
atse@12085 1096 @keyword resource: not used??
atse@12085 1097 @rtype: None
atse@12085 1098 @raise XendError: Failed to migrate
atse@12085 1099 @raise XendInvalidDomain: Domain is not valid
atse@12085 1100 """
mjw@1629 1101
atse@12085 1102 dominfo = self.domain_lookup_nr(domid)
emellor@9530 1103 if not dominfo:
emellor@9530 1104 raise XendInvalidDomain(str(domid))
cl349@5155 1105
atse@12085 1106 if dominfo.getDomid() == DOM0_ID:
ewan@12484 1107 raise XendError("Cannot migrate privileged domain %s" % domid)
emellor@8275 1108
emellor@9727 1109 """ The following call may raise a XendError exception """
kaf24@10039 1110 dominfo.testMigrateDevices(True, dst)
emellor@9727 1111
tim@11442 1112 if live:
tim@11442 1113 """ Make sure there's memory free for enabling shadow mode """
tim@11442 1114 dominfo.checkLiveMigrateMemory()
tim@11442 1115
vhanquez@8274 1116 if port == 0:
vhanquez@8274 1117 port = xroot.get_xend_relocation_port()
emellor@8144 1118 try:
emellor@8144 1119 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
emellor@8144 1120 sock.connect((dst, port))
emellor@8144 1121 except socket.error, err:
emellor@8144 1122 raise XendError("can't connect: %s" % err[1])
cl349@5155 1123
emellor@8144 1124 sock.send("receive\n")
emellor@9727 1125 sock.recv(80)
kaf24@10039 1126 XendCheckpoint.save(sock.fileno(), dominfo, True, live, dst)
steven@11349 1127 dominfo.testDeviceComplete()
steven@11349 1128 sock.close()
mjw@1623 1129
emellor@7213 1130 def domain_save(self, domid, dst):
mjw@1744 1131 """Start saving a domain to file.
mjw@1629 1132
atse@12085 1133 @param domid: Domain ID or Name
atse@12085 1134 @type domid: int or string.
atse@12085 1135 @param dst: Destination filename
atse@12085 1136 @type dst: string
atse@12085 1137 @rtype: None
atse@12085 1138 @raise XendError: Failed to save domain
atse@12085 1139 @raise XendInvalidDomain: Domain is not valid
mjw@1623 1140 """
cl349@5121 1141 try:
atse@12085 1142 dominfo = self.domain_lookup_nr(domid)
emellor@9530 1143 if not dominfo:
emellor@9530 1144 raise XendInvalidDomain(str(domid))
cl349@5121 1145
atse@12085 1146 if dominfo.getDomid() == DOM0_ID:
atse@12085 1147 raise XendError("Cannot save privileged domain %i" % domid)
emellor@8275 1148
cl349@5121 1149 fd = os.open(dst, os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
emellor@7213 1150 try:
emellor@7213 1151 # For now we don't support 'live checkpoint'
atse@12085 1152 XendCheckpoint.save(fd, dominfo, False, False, dst)
emellor@7213 1153 finally:
emellor@7213 1154 os.close(fd)
cl349@5145 1155 except OSError, ex:
cl349@5145 1156 raise XendError("can't write guest state file %s: %s" %
cl349@5145 1157 (dst, ex[1]))
cl349@5121 1158
emellor@7213 1159 def domain_pincpu(self, domid, vcpu, cpumap):
cl349@4845 1160 """Set which cpus vcpu can use
mjw@1623 1161
atse@12085 1162 @param domid: Domain ID or Name
atse@12085 1163 @type domid: int or string.
atse@12085 1164 @param vcpu: vcpu to pin to
atse@12085 1165 @type vcpu: int
atse@12085 1166 @param cpumap: string repr of usable cpus
atse@12085 1167 @type cpumap: string
atse@12085 1168 @rtype: 0
mjw@1629 1169 """
atse@12085 1170 dominfo = self.domain_lookup_nr(domid)
emellor@9530 1171 if not dominfo:
emellor@9530 1172 raise XendInvalidDomain(str(domid))
emellor@9530 1173
ack@11629 1174 # if vcpu is keyword 'all', apply the cpumap to all vcpus
ack@11629 1175 vcpus = [ vcpu ]
ack@11629 1176 if str(vcpu).lower() == "all":
ack@11629 1177 vcpus = range(0, int(dominfo.getVCpuCount()))
ack@11629 1178
ack@11629 1179 # set the same cpumask for all vcpus
ack@11629 1180 rc = 0
ack@11629 1181 for v in vcpus:
ack@11629 1182 try:
ack@11629 1183 rc = xc.vcpu_setaffinity(dominfo.getDomid(), int(v), cpumap)
ack@11629 1184 except Exception, ex:
ack@11629 1185 raise XendError(str(ex))
ack@11629 1186 return rc
mjw@1623 1187
emellor@7213 1188 def domain_cpu_sedf_set(self, domid, period, slice_, latency, extratime,
emellor@7213 1189 weight):
sd386@3573 1190 """Set Simple EDF scheduler parameters for a domain.
atse@12085 1191
atse@12085 1192 @param domid: Domain ID or Name
atse@12085 1193 @type domid: int or string.
atse@12085 1194 @rtype: 0
sd386@3449 1195 """
atse@12085 1196 dominfo = self.domain_lookup_nr(domid)
emellor@9530 1197 if not dominfo:
emellor@9530 1198 raise XendInvalidDomain(str(domid))
sd386@3449 1199 try:
emellor@7213 1200 return xc.sedf_domain_set(dominfo.getDomid(), period, slice_,
emellor@6943 1201 latency, extratime, weight)
sd386@3449 1202 except Exception, ex:
sd386@3449 1203 raise XendError(str(ex))
sd386@3449 1204
emellor@7213 1205 def domain_cpu_sedf_get(self, domid):
cl349@5334 1206 """Get Simple EDF scheduler parameters for a domain.
atse@12085 1207
atse@12085 1208 @param domid: Domain ID or Name
atse@12085 1209 @type domid: int or string.
atse@12085 1210 @rtype: SXP object
atse@12085 1211 @return: The parameters for Simple EDF schedule for a domain.
sd386@3449 1212 """
atse@12085 1213 dominfo = self.domain_lookup_nr(domid)
emellor@9530 1214 if not dominfo:
emellor@9530 1215 raise XendInvalidDomain(str(domid))
sd386@3449 1216 try:
emellor@9217 1217 sedf_info = xc.sedf_domain_get(dominfo.getDomid())
emellor@9217 1218 # return sxpr
emellor@9217 1219 return ['sedf',
atse@12370 1220 ['domid', sedf_info['domid']],
emellor@9217 1221 ['period', sedf_info['period']],
emellor@9217 1222 ['slice', sedf_info['slice']],
emellor@9217 1223 ['latency', sedf_info['latency']],
emellor@9217 1224 ['extratime', sedf_info['extratime']],
emellor@9217 1225 ['weight', sedf_info['weight']]]
emellor@9217 1226
sd386@3449 1227 except Exception, ex:
sd386@3449 1228 raise XendError(str(ex))
cl349@5304 1229
tdeegan@11172 1230 def domain_shadow_control(self, domid, op):
atse@12085 1231 """Shadow page control.
atse@12085 1232
atse@12085 1233 @param domid: Domain ID or Name
atse@12085 1234 @type domid: int or string.
atse@12085 1235 @param op: operation
atse@12085 1236 @type op: int
atse@12085 1237 @rtype: 0
atse@12085 1238 """
tdeegan@11172 1239 dominfo = self.domain_lookup(domid)
tdeegan@11172 1240 try:
tdeegan@11172 1241 return xc.shadow_control(dominfo.getDomid(), op)
tdeegan@11172 1242 except Exception, ex:
tdeegan@11172 1243 raise XendError(str(ex))
tdeegan@11172 1244
tdeegan@11172 1245 def domain_shadow_mem_get(self, domid):
atse@12085 1246 """Get shadow pagetable memory allocation.
atse@12085 1247
atse@12085 1248 @param domid: Domain ID or Name
atse@12085 1249 @type domid: int or string.
atse@12085 1250 @rtype: int
atse@12085 1251 @return: shadow memory in MB
atse@12085 1252 """
tdeegan@11172 1253 dominfo = self.domain_lookup(domid)
tdeegan@11172 1254 try:
tdeegan@11172 1255 return xc.shadow_mem_control(dominfo.getDomid())
tdeegan@11172 1256 except Exception, ex:
tdeegan@11172 1257 raise XendError(str(ex))
tdeegan@11172 1258
tdeegan@11172 1259 def domain_shadow_mem_set(self, domid, mb):
atse@12085 1260 """Set shadow pagetable memory allocation.
atse@12085 1261
atse@12085 1262 @param domid: Domain ID or Name
atse@12085 1263 @type domid: int or string.
atse@12085 1264 @param mb: shadow memory to set in MB
atse@12085 1265 @type: mb: int
atse@12085 1266 @rtype: int
atse@12085 1267 @return: shadow memory in MB
atse@12085 1268 """
tdeegan@11172 1269 dominfo = self.domain_lookup(domid)
tdeegan@11172 1270 try:
tdeegan@11172 1271 return xc.shadow_mem_control(dominfo.getDomid(), mb=mb)
tdeegan@11172 1272 except Exception, ex:
tdeegan@11172 1273 raise XendError(str(ex))
tdeegan@11172 1274
kaf24@10206 1275 def domain_sched_credit_get(self, domid):
ack@10188 1276 """Get credit scheduler parameters for a domain.
atse@12085 1277
atse@12085 1278 @param domid: Domain ID or Name
atse@12085 1279 @type domid: int or string.
atse@12085 1280 @rtype: dict with keys 'weight' and 'cap'
atse@12085 1281 @return: credit scheduler parameters
ack@10188 1282 """
atse@12085 1283 dominfo = self.domain_lookup_nr(domid)
ack@10188 1284 if not dominfo:
ack@10188 1285 raise XendInvalidDomain(str(domid))
ack@10188 1286 try:
kaf24@10206 1287 return xc.sched_credit_domain_get(dominfo.getDomid())
ack@10188 1288 except Exception, ex:
ack@10188 1289 raise XendError(str(ex))
ack@10188 1290
ack@11559 1291 def domain_sched_credit_set(self, domid, weight = None, cap = None):
ack@10188 1292 """Set credit scheduler parameters for a domain.
atse@12085 1293
atse@12085 1294 @param domid: Domain ID or Name
atse@12085 1295 @type domid: int or string.
atse@12085 1296 @type weight: int
atse@12085 1297 @type cap: int
atse@12085 1298 @rtype: 0
ack@10188 1299 """
atse@12085 1300 dominfo = self.domain_lookup_nr(domid)
ack@10188 1301 if not dominfo:
ack@10188 1302 raise XendInvalidDomain(str(domid))
ack@10188 1303 try:
ack@11559 1304 if weight is None:
ack@11559 1305 weight = int(0)
ack@11559 1306 elif weight < 1 or weight > 65535:
ack@11559 1307 raise XendError("weight is out of range")
ack@11559 1308
ack@11559 1309 if cap is None:
ack@11559 1310 cap = int(~0)
ack@11559 1311 elif cap < 0 or cap > dominfo.getVCpuCount() * 100:
ack@11559 1312 raise XendError("cap is out of range")
ack@11559 1313
ewan@12315 1314 assert type(weight) == int
ewan@12315 1315 assert type(cap) == int
ewan@12315 1316
kaf24@10206 1317 return xc.sched_credit_domain_set(dominfo.getDomid(), weight, cap)
ack@10188 1318 except Exception, ex:
ewan@12315 1319 log.exception(ex)
ack@10188 1320 raise XendError(str(ex))
ack@10188 1321
emellor@7213 1322 def domain_maxmem_set(self, domid, mem):
mjw@1928 1323 """Set the memory limit for a domain.
mjw@1928 1324
atse@12085 1325 @param domid: Domain ID or Name
atse@12085 1326 @type domid: int or string.
emellor@7060 1327 @param mem: memory limit (in MiB)
atse@12085 1328 @type mem: int
atse@12085 1329 @raise XendError: fail to set memory
atse@12085 1330 @rtype: 0
mjw@1928 1331 """
atse@12085 1332 dominfo = self.domain_lookup_nr(domid)
emellor@9530 1333 if not dominfo:
emellor@9530 1334 raise XendInvalidDomain(str(domid))
mjw@1928 1335 maxmem = int(mem) * 1024
mjw@1985 1336 try:
emellor@8086 1337 return xc.domain_setmaxmem(dominfo.getDomid(), maxmem)
mjw@1985 1338 except Exception, ex:
mjw@1985 1339 raise XendError(str(ex))
mjw@1928 1340
kaf24@7642 1341 def domain_ioport_range_enable(self, domid, first, last):
kaf24@7642 1342 """Enable access to a range of IO ports for a domain
kaf24@7642 1343
kaf24@7642 1344 @param first: first IO port
kaf24@7642 1345 @param last: last IO port
atse@12085 1346 @raise XendError: failed to set range
atse@12085 1347 @rtype: 0
kaf24@7642 1348 """
atse@12085 1349 dominfo = self.domain_lookup_nr(domid)
emellor@9530 1350 if not dominfo:
emellor@9530 1351 raise XendInvalidDomain(str(domid))
kaf24@7642 1352 nr_ports = last - first + 1
kaf24@7642 1353 try:
kaf24@7642 1354 return xc.domain_ioport_permission(dominfo.getDomid(),
kaf24@7642 1355 first_port = first,
kaf24@7642 1356 nr_ports = nr_ports,
kaf24@7642 1357 allow_access = 1)
kaf24@7642 1358 except Exception, ex:
kaf24@7642 1359 raise XendError(str(ex))
kaf24@7642 1360
kaf24@7642 1361 def domain_ioport_range_disable(self, domid, first, last):
kaf24@7642 1362 """Disable access to a range of IO ports for a domain
kaf24@7642 1363
kaf24@7642 1364 @param first: first IO port
kaf24@7642 1365 @param last: last IO port
atse@12085 1366 @raise XendError: failed to set range
atse@12085 1367 @rtype: 0
kaf24@7642 1368 """
atse@12085 1369 dominfo = self.domain_lookup_nr(domid)
emellor@9530 1370 if not dominfo:
emellor@9530 1371 raise XendInvalidDomain(str(domid))
kaf24@7642 1372 nr_ports = last - first + 1
kaf24@7642 1373 try:
kaf24@7642 1374 return xc.domain_ioport_permission(dominfo.getDomid(),
kaf24@7642 1375 first_port = first,
kaf24@7642 1376 nr_ports = nr_ports,
kaf24@7642 1377 allow_access = 0)
kaf24@7642 1378 except Exception, ex:
kaf24@7642 1379 raise XendError(str(ex))
kaf24@7642 1380
emellor@7060 1381
mjw@1623 1382 def instance():
mjw@1629 1383 """Singleton constructor. Use this instead of the class constructor.
mjw@1629 1384 """
mjw@1623 1385 global inst
mjw@1623 1386 try:
mjw@1623 1387 inst
mjw@1623 1388 except:
mjw@1623 1389 inst = XendDomain()
emellor@8144 1390 inst.init()
mjw@1623 1391 return inst