xen-vtx-unstable

annotate tools/python/xen/xend/XendDomainInfo.py @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents 219d96d545fc c5045197dcb7
children e7c7196fa329 8ca0f98ba8e2
rev   line source
kaf24@6064 1 #============================================================================
kaf24@6064 2 # This library is free software; you can redistribute it and/or
kaf24@6064 3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
kaf24@6064 4 # License as published by the Free Software Foundation.
kaf24@6064 5 #
kaf24@6064 6 # This library is distributed in the hope that it will be useful,
kaf24@6064 7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
kaf24@6064 8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
kaf24@6064 9 # Lesser General Public License for more details.
kaf24@6064 10 #
kaf24@6064 11 # You should have received a copy of the GNU Lesser General Public
kaf24@6064 12 # License along with this library; if not, write to the Free Software
kaf24@6064 13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
kaf24@6064 14 #============================================================================
kaf24@6064 15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
kaf24@6064 16 #============================================================================
mjw@1623 17
mjw@1623 18 """Representation of a single domain.
mjw@1623 19 Includes support for domain construction, using
mjw@1623 20 open-ended configurations.
mjw@1623 21
mjw@4617 22 Author: Mike Wray <mike.wray@hp.com>
mjw@1623 23
mjw@1623 24 """
mjw@1623 25
kaf24@6292 26 import string, re
mjw@1623 27 import os
tw275@1809 28 import time
cl349@5121 29 import threading
mjw@1623 30
mjw@1629 31 import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
cl349@5336 32 from xen.util.ip import check_subnet, get_current_ipgw
mjw@4679 33 from xen.util.blkif import blkdev_uname_to_file
mjw@1623 34
cl349@5351 35 from xen.xend.server import controller
cl349@5336 36 from xen.xend.server import SrvDaemon; xend = SrvDaemon.instance()
cl349@6668 37 from xen.xend.server.channel import EventChannel
cl349@6264 38 from xen.util.blkif import blkdev_name_to_number, expand_dev_name
mjw@1623 39
cl349@5336 40 from xen.xend import sxp
cl349@6264 41 from xen.xend import Blkctl
cl349@5336 42 from xen.xend.PrettyPrint import prettyprintstring
mjw@4677 43 from xen.xend.XendBootloader import bootloader
cl349@5336 44 from xen.xend.XendLogging import log
cl349@5568 45 from xen.xend.XendError import XendError, VmError
cl349@5336 46 from xen.xend.XendRoot import get_component
mjw@2296 47
cl349@5347 48 from xen.xend.uuid import getUuid
cl349@6474 49 from xen.xend.xenstore import DBVar, XenNode, DBMap
cl349@6709 50 from xen.xend.xenstore.xstransact import xstransact
cl349@5347 51
mjw@1729 52 """Shutdown code for poweroff."""
mjw@1729 53 DOMAIN_POWEROFF = 0
mjw@4580 54
mjw@1729 55 """Shutdown code for reboot."""
mjw@1729 56 DOMAIN_REBOOT = 1
mjw@4580 57
mjw@1729 58 """Shutdown code for suspend."""
mjw@1729 59 DOMAIN_SUSPEND = 2
mjw@1729 60
cl349@5304 61 """Shutdown code for crash."""
cl349@5304 62 DOMAIN_CRASH = 3
cl349@5304 63
mjw@1729 64 """Map shutdown codes to strings."""
mjw@1729 65 shutdown_reasons = {
mjw@1729 66 DOMAIN_POWEROFF: "poweroff",
mjw@1729 67 DOMAIN_REBOOT : "reboot",
cl349@5304 68 DOMAIN_SUSPEND : "suspend",
cl349@5304 69 DOMAIN_CRASH : "crash",
cl349@5304 70 }
mjw@1729 71
mjw@1785 72 RESTART_ALWAYS = 'always'
mjw@1785 73 RESTART_ONREBOOT = 'onreboot'
mjw@1785 74 RESTART_NEVER = 'never'
mjw@1785 75
mjw@1785 76 restart_modes = [
mjw@1785 77 RESTART_ALWAYS,
mjw@1785 78 RESTART_ONREBOOT,
mjw@1785 79 RESTART_NEVER,
mjw@1785 80 ]
mjw@1785 81
mjw@1893 82 STATE_RESTART_PENDING = 'pending'
mjw@1893 83 STATE_RESTART_BOOTING = 'booting'
mjw@1893 84
mjw@1900 85 STATE_VM_OK = "ok"
mjw@1900 86 STATE_VM_TERMINATED = "terminated"
cl349@5121 87 STATE_VM_SUSPENDED = "suspended"
mjw@1900 88
mjw@2229 89
mjw@2229 90 def domain_exists(name):
mjw@2229 91 # See comment in XendDomain constructor.
mjw@2229 92 xd = get_component('xen.xend.XendDomain')
cl349@5334 93 return xd.domain_lookup_by_name(name)
mjw@2229 94
mjw@1729 95 def shutdown_reason(code):
mjw@1729 96 """Get a shutdown reason from a code.
mjw@1729 97
mjw@1729 98 @param code: shutdown code
mjw@1729 99 @type code: int
mjw@1729 100 @return: shutdown reason
mjw@1729 101 @rtype: string
mjw@1729 102 """
mjw@1729 103 return shutdown_reasons.get(code, "?")
mjw@1729 104
mjw@1623 105 def dom_get(dom):
mjw@1975 106 """Get info from xen for an existing domain.
mjw@1975 107
mjw@1975 108 @param dom: domain id
mjw@1975 109 @return: info or None
mjw@1975 110 """
mjw@2166 111 domlist = xc.domain_getinfo(dom, 1)
mjw@1623 112 if domlist and dom == domlist[0]['dom']:
mjw@1623 113 return domlist[0]
mjw@1623 114 return None
kaf24@6131 115
mjw@1623 116 class XendDomainInfo:
mjw@1623 117 """Virtual machine object."""
mjw@1623 118
mjw@1900 119 """Minimum time between domain restarts in seconds.
mjw@1900 120 """
mjw@1975 121 MINIMUM_RESTART_TIME = 20
mjw@1629 122
cl349@5388 123 def create(cls, parentdb, config):
cl349@5388 124 """Create a VM from a configuration.
cl349@5306 125
cl349@5388 126 @param parentdb: parent db
cl349@5306 127 @param config configuration
cl349@5306 128 @raise: VmError for invalid configuration
cl349@5306 129 """
cl349@5388 130 uuid = getUuid()
cl349@5388 131 db = parentdb.addChild(uuid)
cl349@6708 132 path = parentdb.getPath()
cl349@6708 133 vm = cls(uuid, path, db)
cl349@5306 134 vm.construct(config)
cl349@5479 135 vm.saveToDB(sync=True)
kaf24@5934 136
cl349@5306 137 return vm
cl349@5306 138
cl349@5306 139 create = classmethod(create)
cl349@5306 140
cl349@5388 141 def recreate(cls, db, info):
cl349@5306 142 """Create the VM object for an existing domain.
cl349@5306 143
cl349@5388 144 @param db: domain db
cl349@5306 145 @param info: domain info from xc
cl349@5306 146 """
cl349@5388 147 dom = info['dom']
cl349@6708 148 path = "/".join(db.getPath().split("/")[0:-1])
cl349@6708 149 vm = cls(db.getName(), path, db)
cl349@5895 150 vm.setdom(dom)
cl349@5388 151 db.readDB()
cl349@5388 152 vm.importFromDB()
cl349@5388 153 config = vm.config
cl349@5388 154 log.debug('info=' + str(info))
cl349@5388 155 log.debug('config=' + prettyprintstring(config))
cl349@5306 156
cl349@5306 157 vm.memory = info['mem_kb']/1024
kaf24@5934 158 vm.target = info['mem_kb'] * 1024
cl349@5306 159
cl349@5388 160 if config:
cl349@5388 161 try:
cl349@5388 162 vm.recreate = True
cl349@5388 163 vm.construct(config)
cl349@5388 164 finally:
cl349@5388 165 vm.recreate = False
cl349@5388 166 else:
cl349@5388 167 vm.setName("Domain-%d" % dom)
cl349@5306 168
cl349@5388 169 vm.exportToDB(save=True)
cl349@5306 170 return vm
cl349@5306 171
cl349@5306 172 recreate = classmethod(recreate)
cl349@5306 173
cl349@6211 174 def restore(cls, parentdb, config, uuid=None):
cl349@5306 175 """Create a domain and a VM object to do a restore.
cl349@5306 176
cl349@5388 177 @param parentdb: parent db
cl349@5306 178 @param config: domain configuration
cl349@5349 179 @param uuid: uuid to use
cl349@5306 180 """
cl349@6211 181 if not uuid:
cl349@6211 182 uuid = getUuid()
cl349@5388 183 db = parentdb.addChild(uuid)
cl349@6708 184 path = parentdb.getPath()
cl349@6708 185 vm = cls(uuid, path, db)
smh22@5514 186 ssidref = int(sxp.child_value(config, 'ssidref'))
smh22@5514 187 log.debug('restoring with ssidref='+str(ssidref))
smh22@5514 188 id = xc.domain_create(ssidref = ssidref)
cl349@5479 189 vm.setdom(id)
cl349@6208 190 vm.clear_shutdown()
cl349@5479 191 try:
cl349@5479 192 vm.restore = True
cl349@5479 193 vm.construct(config)
cl349@5479 194 finally:
cl349@5479 195 vm.restore = False
cl349@5479 196 vm.exportToDB(save=True, sync=True)
cl349@5306 197 return vm
cl349@5306 198
cl349@5306 199 restore = classmethod(restore)
cl349@5306 200
cl349@5388 201 __exports__ = [
cl349@5479 202 DBVar('id', ty='int'),
cl349@5388 203 DBVar('name', ty='str'),
cl349@5388 204 DBVar('uuid', ty='str'),
cl349@5388 205 DBVar('config', ty='sxpr'),
cl349@5388 206 DBVar('start_time', ty='float'),
cl349@5388 207 DBVar('state', ty='str'),
cl349@5388 208 DBVar('store_mfn', ty='long'),
cl349@6637 209 DBVar('console_mfn', ty='long', path="console/ring-ref"),
cl349@5388 210 DBVar('restart_mode', ty='str'),
cl349@5388 211 DBVar('restart_state', ty='str'),
cl349@5388 212 DBVar('restart_time', ty='float'),
cl349@5388 213 DBVar('restart_count', ty='int'),
kaf24@5934 214 DBVar('target', ty='long', path="memory/target"),
kaf24@6101 215 DBVar('device_model_pid', ty='int'),
cl349@5388 216 ]
cl349@5388 217
cl349@6708 218 def __init__(self, uuid, path, db):
cl349@6708 219 self.uuid = uuid
cl349@6708 220 self.path = path + "/" + uuid
cl349@5388 221 self.db = db
cl349@5388 222
mjw@1623 223 self.recreate = 0
mjw@2160 224 self.restore = 0
cl349@5306 225
mjw@1623 226 self.config = None
mjw@1623 227 self.id = None
mjw@2250 228 self.cpu_weight = 1
mjw@1900 229 self.start_time = None
mjw@1623 230 self.name = None
mjw@1623 231 self.memory = None
smh22@5514 232 self.ssidref = None
mjw@1623 233 self.image = None
mjw@4580 234
kaf24@5934 235 self.target = None
kaf24@5934 236
cl349@5349 237 self.store_channel = None
cl349@5351 238 self.store_mfn = None
cl349@6474 239 self.console_channel = None
cl349@6474 240 self.console_mfn = None
mjw@4580 241 self.controllers = {}
mjw@4580 242
mjw@1623 243 self.info = None
mjw@4580 244 self.blkif_backend = False
mjw@4580 245 self.netif_backend = False
cl349@6404 246 self.netif_idx = 0
shand@6554 247 self.tpmif_backend = False
cl349@6404 248
mjw@1623 249 #todo: state: running, suspended
mjw@1900 250 self.state = STATE_VM_OK
cl349@5121 251 self.state_updated = threading.Condition()
cl349@5008 252 self.shutdown_pending = None
cl349@5008 253
mjw@1623 254 #todo: set to migrate info if migrating
mjw@1623 255 self.migrate = None
mjw@4580 256
mjw@1785 257 self.restart_mode = RESTART_ONREBOOT
mjw@1893 258 self.restart_state = None
mjw@1900 259 self.restart_time = None
mjw@4580 260 self.restart_count = 0
mjw@4580 261
cl349@3451 262 self.vcpus = 1
kaf24@6030 263 self.vcpusdb = {}
mjw@4677 264 self.bootloader = None
kaf24@6101 265 self.device_model_pid = 0
mjw@1623 266
cl349@5388 267 def setDB(self, db):
cl349@5388 268 self.db = db
cl349@5388 269
cl349@5479 270 def saveToDB(self, save=False, sync=False):
cl349@5388 271 self.db.saveDB(save=save, sync=sync)
cl349@5388 272
cl349@5388 273 def exportToDB(self, save=False, sync=False):
cl349@5388 274 if self.store_channel:
cl349@5479 275 self.store_channel.saveToDB(self.db.addChild("store_channel"),
cl349@5479 276 save=save)
cl349@6474 277 if self.console_channel:
cl349@6676 278 self.db['console/port'] = "%i" % self.console_channel.port1
cl349@5479 279 if self.image:
cl349@5479 280 self.image.exportToDB(save=save, sync=sync)
cl349@5388 281 self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync)
cl349@5388 282
cl349@5388 283 def importFromDB(self):
cl349@5388 284 self.db.importFromDB(self, fields=self.__exports__)
cl349@6676 285 self.store_channel = self.eventChannelOld("store_channel")
cl349@5388 286
mjw@1623 287 def setdom(self, dom):
mjw@1975 288 """Set the domain id.
mjw@1975 289
mjw@1975 290 @param dom: domain id
mjw@1975 291 """
cl349@5334 292 self.id = int(dom)
cl349@5388 293 #self.db.id = self.id
mjw@1975 294
mjw@4580 295 def getDomain(self):
cl349@5334 296 return self.id
mjw@4580 297
cl349@5339 298 def setName(self, name):
cl349@5339 299 self.name = name
cl349@5388 300 self.db.name = self.name
cl349@5339 301
mjw@4580 302 def getName(self):
mjw@4580 303 return self.name
mjw@4580 304
cl349@5351 305 def getStoreChannel(self):
cl349@5351 306 return self.store_channel
cl349@5351 307
cl349@6474 308 def getConsoleChannel(self):
cl349@6474 309 return self.console_channel
cl349@6474 310
cl349@6566 311 def update(self, info=None):
mjw@1623 312 """Update with info from xc.domain_getinfo().
mjw@1623 313 """
cl349@6566 314 self.info = info or dom_get(self.id)
mjw@1623 315 self.memory = self.info['mem_kb'] / 1024
smh22@5514 316 self.ssidref = self.info['ssidref']
kaf24@5934 317 self.target = self.info['mem_kb'] * 1024
mjw@1623 318
cl349@5121 319 def state_set(self, state):
cl349@5121 320 self.state_updated.acquire()
cl349@5121 321 if self.state != state:
cl349@5121 322 self.state = state
cl349@5121 323 self.state_updated.notifyAll()
cl349@5121 324 self.state_updated.release()
cl349@5479 325 self.saveToDB()
cl349@5121 326
cl349@5121 327 def state_wait(self, state):
cl349@5121 328 self.state_updated.acquire()
cl349@5121 329 while self.state != state:
cl349@5121 330 self.state_updated.wait()
cl349@5121 331 self.state_updated.release()
cl349@5121 332
mjw@1623 333 def __str__(self):
cl349@5479 334 s = "<domain"
cl349@5336 335 s += " id=" + str(self.id)
mjw@1623 336 s += " name=" + self.name
mjw@1623 337 s += " memory=" + str(self.memory)
smh22@5514 338 s += " ssidref=" + str(self.ssidref)
cl349@5479 339 s += ">"
mjw@1623 340 return s
mjw@1623 341
mjw@1623 342 __repr__ = __str__
mjw@1623 343
mjw@4580 344 def getDeviceController(self, type, error=True):
mjw@4580 345 ctrl = self.controllers.get(type)
mjw@4580 346 if not ctrl and error:
mjw@4580 347 raise XendError("invalid device type:" + type)
mjw@4580 348 return ctrl
mjw@4580 349
mjw@4580 350 def findDeviceController(self, type):
mjw@4580 351 return (self.getDeviceController(type, error=False)
mjw@4580 352 or self.createDeviceController(type))
mjw@4580 353
mjw@4580 354 def createDeviceController(self, type):
mjw@4580 355 ctrl = controller.createDevController(type, self, recreate=self.recreate)
mjw@4580 356 self.controllers[type] = ctrl
mjw@4580 357 return ctrl
mjw@4580 358
cl349@5344 359 def createDevice(self, type, devconfig, change=False):
cl349@6675 360 if self.recreate:
cl349@6675 361 return
cl349@6264 362 if type == 'vbd':
kaf24@6292 363 typedev = sxp.child_value(devconfig, 'dev')
kaf24@6292 364 if re.match('^ioemu:', typedev):
kaf24@6292 365 return;
cl349@6744 366
cl349@6264 367 backdom = domain_exists(sxp.child_value(devconfig, 'backend', '0'))
cl349@6264 368
cl349@6264 369 devnum = blkdev_name_to_number(sxp.child_value(devconfig, 'dev'))
cl349@6264 370
cl349@6744 371 backpath = "%s/backend/%s/%s/%d" % (backdom.path, type,
cl349@6744 372 self.uuid, devnum)
cl349@6744 373 frontpath = "%s/device/%s/%d" % (self.path, type, devnum)
cl349@6264 374
cl349@6744 375 front = { 'backend' : backpath,
cl349@6744 376 'backend-id' : "%i" % backdom.id,
cl349@6744 377 'virtual-device' : "%i" % devnum }
cl349@6744 378 xstransact.Write(frontpath, front)
cl349@6264 379
cl349@6744 380 (type, params) = string.split(sxp.child_value(devconfig,
cl349@6744 381 'uname'), ':', 1)
cl349@6744 382 back = { 'type' : type,
cl349@6744 383 'params' : params,
cl349@6744 384 'frontend' : frontpath,
cl349@6744 385 'frontend-id' : "%i" % self.id }
cl349@6744 386 xstransact.Write(backpath, back)
cl349@6264 387
cl349@6264 388 return
cl349@6404 389
cl349@6404 390 if type == 'vif':
cl349@6585 391 from xen.xend import XendRoot
cl349@6585 392 xroot = XendRoot.instance()
cl349@6585 393
cl349@6585 394 def _get_config_ipaddr(config):
cl349@6585 395 val = []
cl349@6585 396 for ipaddr in sxp.children(config, elt='ip'):
cl349@6585 397 val.append(sxp.child0(ipaddr))
cl349@6585 398 return val
cl349@6585 399
cl349@6404 400 backdom = domain_exists(sxp.child_value(devconfig, 'backend', '0'))
cl349@6404 401
cl349@6404 402 devnum = self.netif_idx
cl349@6404 403 self.netif_idx += 1
cl349@6404 404
cl349@6585 405 script = sxp.child_value(devconfig, 'script',
cl349@6585 406 xroot.get_vif_script())
cl349@6585 407 script = os.path.join(xroot.network_script_dir, script)
cl349@6585 408 bridge = sxp.child_value(devconfig, 'bridge',
cl349@6585 409 xroot.get_vif_bridge())
cl349@6585 410 mac = sxp.child_value(devconfig, 'mac')
cl349@6585 411 ipaddr = _get_config_ipaddr(devconfig)
cl349@6585 412
cl349@6709 413 backpath = "%s/backend/%s/%s/%d" % (backdom.path, type,
cl349@6709 414 self.uuid, devnum)
cl349@6709 415 frontpath = "%s/device/%s/%d" % (self.path, type, devnum)
cl349@6404 416
cl349@6712 417 front = { 'backend' : backpath,
cl349@6712 418 'backend-id' : "%i" % backdom.id,
cl349@6712 419 'handle' : "%i" % devnum,
cl349@6712 420 'mac' : mac }
cl349@6712 421 xstransact.Write(frontpath, front)
cl349@6709 422
cl349@6712 423 back = { 'script' : script,
cl349@6712 424 'domain' : self.name,
cl349@6712 425 'mac' : mac,
cl349@6712 426 'bridge' : bridge,
cl349@6712 427 'frontend' : frontpath,
cl349@6712 428 'frontend-id' : "%i" % self.id,
cl349@6712 429 'handle' : "%i" % devnum }
cl349@6585 430 if ipaddr:
cl349@6712 431 back['ip'] = ' '.join(ipaddr)
cl349@6712 432 xstransact.Write(backpath, back)
cl349@6404 433
cl349@6404 434 return
cl349@6404 435
shand@6554 436 if type == 'vtpm':
shand@6554 437 backdom = domain_exists(sxp.child_value(devconfig, 'backend', '0'))
shand@6554 438
shand@6554 439 devnum = int(sxp.child_value(devconfig, 'instance', '0'))
shand@6554 440 log.error("The domain has a TPM with instance %d." % devnum)
shand@6554 441
cl349@6745 442 backpath = "%s/backend/%s/%s/%d" % (backdom.path, type,
cl349@6745 443 self.uuid, devnum)
cl349@6745 444 frontpath = "%s/device/%s/%d" % (self.path, type, devnum)
shand@6554 445
cl349@6745 446 front = { 'backend' : backpath,
cl349@6745 447 'backend-id' : "%i" % backdom.id,
cl349@6745 448 'handle' : "%i" % devnum }
cl349@6745 449 xstransact.Write(frontpath, front)
shand@6554 450
cl349@6745 451 back = { 'instance' : "%i" % devnum,
cl349@6745 452 'frontend' : frontpath,
cl349@6745 453 'frontend-id' : "%i" % self.id }
cl349@6745 454 xstransact.Write(backpath, back)
shand@6554 455
shand@6554 456 return
shand@6554 457
mjw@4580 458 ctrl = self.findDeviceController(type)
cl349@5344 459 return ctrl.createDevice(devconfig, recreate=self.recreate,
cl349@5344 460 change=change)
mjw@4580 461
mjw@4580 462 def configureDevice(self, type, id, devconfig):
mjw@4580 463 ctrl = self.getDeviceController(type)
mjw@4580 464 return ctrl.configureDevice(id, devconfig)
mjw@4580 465
mjw@4580 466 def destroyDevice(self, type, id, change=False, reboot=False):
mjw@4580 467 ctrl = self.getDeviceController(type)
mjw@4580 468 return ctrl.destroyDevice(id, change=change, reboot=reboot)
mjw@4580 469
mjw@4580 470 def deleteDevice(self, type, id):
mjw@4580 471 ctrl = self.getDeviceController(type)
mjw@4580 472 return ctrl.deleteDevice(id)
mjw@4580 473
cl349@5338 474 def getDevice(self, type, id, error=True):
mjw@4580 475 ctrl = self.getDeviceController(type)
cl349@5338 476 return ctrl.getDevice(id, error=error)
cl349@5338 477
mjw@4580 478 def getDeviceIds(self, type):
mjw@4580 479 ctrl = self.getDeviceController(type)
mjw@4580 480 return ctrl.getDeviceIds()
mjw@4580 481
mjw@4580 482 def getDeviceSxprs(self, type):
mjw@4580 483 ctrl = self.getDeviceController(type)
mjw@4580 484 return ctrl.getDeviceSxprs()
mjw@4580 485
mjw@1623 486 def sxpr(self):
mjw@1623 487 sxpr = ['domain',
mjw@1623 488 ['id', self.id],
mjw@1623 489 ['name', self.name],
smh22@5514 490 ['memory', self.memory],
kaf24@5934 491 ['ssidref', self.ssidref],
kaf24@5934 492 ['target', self.target] ]
cl349@5347 493 if self.uuid:
cl349@5347 494 sxpr.append(['uuid', self.uuid])
mjw@1623 495 if self.info:
mjw@1928 496 sxpr.append(['maxmem', self.info['maxmem_kb']/1024 ])
mjw@1928 497 run = (self.info['running'] and 'r') or '-'
mjw@1928 498 block = (self.info['blocked'] and 'b') or '-'
mjw@1928 499 pause = (self.info['paused'] and 'p') or '-'
mjw@1928 500 shut = (self.info['shutdown'] and 's') or '-'
mjw@1928 501 crash = (self.info['crashed'] and 'c') or '-'
mjw@1928 502 state = run + block + pause + shut + crash
mjw@1623 503 sxpr.append(['state', state])
mjw@1623 504 if self.info['shutdown']:
mjw@1785 505 reason = shutdown_reason(self.info['shutdown_reason'])
mjw@1623 506 sxpr.append(['shutdown_reason', reason])
cl349@4853 507 sxpr.append(['cpu', self.info['vcpu_to_cpu'][0]])
tw275@1809 508 sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
cl349@4845 509 sxpr.append(['vcpus', self.info['vcpus']])
cl349@4845 510 sxpr.append(['cpumap', self.info['cpumap']])
iap10@5691 511 # build a string, using '|' to seperate items, show only up
iap10@5691 512 # to number of vcpus in domain, and trim the trailing '|'
iap10@5691 513 sxpr.append(['vcpu_to_cpu', ''.join(map(lambda x: str(x)+'|',
iap10@5691 514 self.info['vcpu_to_cpu'][0:self.info['vcpus']]))[:-1]])
tw275@1809 515
mjw@1900 516 if self.start_time:
mjw@1900 517 up_time = time.time() - self.start_time
mjw@1900 518 sxpr.append(['up_time', str(up_time) ])
mjw@1900 519 sxpr.append(['start_time', str(self.start_time) ])
tw275@1809 520
cl349@5351 521 if self.store_channel:
cl349@5351 522 sxpr.append(self.store_channel.sxpr())
cl349@5479 523 if self.store_mfn:
cl349@5479 524 sxpr.append(['store_mfn', self.store_mfn])
cl349@6474 525 if self.console_channel:
cl349@6474 526 sxpr.append(['console_channel', self.console_channel.sxpr()])
cl349@6474 527 if self.console_mfn:
cl349@6474 528 sxpr.append(['console_mfn', self.console_mfn])
cl349@6474 529 # already in (devices)
cl349@6474 530 # console = self.getConsole()
cl349@6474 531 # if console:
cl349@6474 532 # sxpr.append(console.sxpr())
cl349@5479 533
mjw@4580 534 if self.restart_count:
mjw@4580 535 sxpr.append(['restart_count', self.restart_count])
mjw@1900 536 if self.restart_state:
mjw@1900 537 sxpr.append(['restart_state', self.restart_state])
mjw@1900 538 if self.restart_time:
mjw@1900 539 sxpr.append(['restart_time', str(self.restart_time)])
cl349@5479 540
mjw@2699 541 devs = self.sxpr_devices()
mjw@2699 542 if devs:
mjw@2699 543 sxpr.append(devs)
mjw@1623 544 if self.config:
mjw@1623 545 sxpr.append(['config', self.config])
kaf24@6101 546 if self.device_model_pid:
kaf24@6101 547 sxpr.append(['device_model_pid',self.device_model_pid])
mjw@1623 548 return sxpr
mjw@1623 549
mjw@2699 550 def sxpr_devices(self):
mjw@4617 551 sxpr = []
ewan@6770 552 for ty in self.controllers.keys():
mjw@4617 553 devs = self.getDeviceSxprs(ty)
mjw@4617 554 sxpr += devs
mjw@4617 555 if sxpr:
mjw@4617 556 sxpr.insert(0, 'devices')
mjw@4617 557 else:
mjw@4617 558 sxpr = None
mjw@2699 559 return sxpr
mjw@2699 560
mjw@1975 561 def check_name(self, name):
mjw@4617 562 """Check if a vm name is valid. Valid names contain alphabetic characters,
mjw@4617 563 digits, or characters in '_-.:/+'.
mjw@1975 564 The same name cannot be used for more than one vm at the same time.
mjw@1975 565
mjw@1975 566 @param name: name
mjw@1975 567 @raise: VMerror if invalid
mjw@1975 568 """
mjw@2244 569 if self.recreate: return
mjw@1975 570 if name is None or name == '':
mjw@1975 571 raise VmError('missing vm name')
mjw@1975 572 for c in name:
mjw@1975 573 if c in string.digits: continue
mjw@2297 574 if c in '_-.:/+': continue
mjw@1975 575 if c in string.ascii_letters: continue
mjw@1975 576 raise VmError('invalid vm name')
mjw@2229 577 dominfo = domain_exists(name)
mjw@2160 578 # When creating or rebooting, a domain with my name should not exist.
mjw@2160 579 # When restoring, a domain with my name will exist, but it should have
mjw@2160 580 # my domain id.
mjw@2185 581 if not dominfo:
mjw@2185 582 return
mjw@2222 583 if dominfo.is_terminated():
mjw@2222 584 return
cl349@5334 585 if not self.id or (dominfo.id != self.id):
mjw@1975 586 raise VmError('vm name clash: ' + name)
mjw@1975 587
mjw@1623 588 def construct(self, config):
mjw@1975 589 """Construct the vm instance from its configuration.
mjw@1975 590
mjw@1975 591 @param config: configuration
mjw@1975 592 @raise: VmError on error
mjw@1975 593 """
mjw@1623 594 # todo - add support for scheduling params?
mjw@1623 595 self.config = config
mjw@1623 596 try:
mjw@4580 597 # Initial domain create.
cl349@5339 598 self.setName(sxp.child_value(config, 'name'))
mjw@1975 599 self.check_name(self.name)
cl349@5343 600 self.init_image()
mjw@4580 601 self.configure_cpus(config)
mjw@2542 602 self.init_domain()
mjw@4580 603 self.register_domain()
mjw@4677 604 self.configure_bootloader()
mjw@4580 605
mjw@4580 606 # Create domain devices.
kaf24@3558 607 self.configure_backends()
mjw@1785 608 self.configure_restart()
mjw@4580 609 self.construct_image()
mjw@4580 610 self.configure()
cl349@5505 611 self.exportToDB(save=True)
mjw@4580 612 except Exception, ex:
mjw@1623 613 # Catch errors, cleanup and re-raise.
mjw@4580 614 print 'Domain construction error:', ex
mjw@4580 615 import traceback
mjw@4580 616 traceback.print_exc()
mjw@1623 617 self.destroy()
mjw@1623 618 raise
mjw@4580 619
mjw@4580 620 def register_domain(self):
mjw@4580 621 xd = get_component('xen.xend.XendDomain')
mjw@4580 622 xd._add_domain(self)
cl349@5505 623 self.exportToDB(save=True)
mjw@4580 624
mjw@4580 625 def configure_cpus(self, config):
mjw@4580 626 try:
mjw@4580 627 self.cpu_weight = float(sxp.child_value(config, 'cpu_weight', '1'))
mjw@4580 628 except:
mjw@4580 629 raise VmError('invalid cpu weight')
mjw@4580 630 self.memory = int(sxp.child_value(config, 'memory'))
mjw@4580 631 if self.memory is None:
mjw@4580 632 raise VmError('missing memory size')
kaf24@5934 633 self.target = self.memory * (1 << 20)
smh22@5514 634 self.ssidref = int(sxp.child_value(config, 'ssidref'))
mjw@4580 635 cpu = sxp.child_value(config, 'cpu')
cl349@5334 636 if self.recreate and self.id and cpu is not None and int(cpu) >= 0:
cl349@5334 637 xc.domain_pincpu(self.id, 0, 1<<int(cpu))
mjw@4580 638 try:
mjw@4580 639 image = sxp.child_value(self.config, 'image')
mjw@4580 640 vcpus = sxp.child_value(image, 'vcpus')
mjw@4580 641 if vcpus:
mjw@4580 642 self.vcpus = int(vcpus)
mjw@4580 643 except:
mjw@4580 644 raise VmError('invalid vcpus value')
mjw@1623 645
kaf24@6030 646 def exportVCPUSToDB(self, vcpus):
kaf24@6030 647 for v in range(0,vcpus):
kaf24@6097 648 path = "/cpu/%d"%(v)
kaf24@6030 649 if not self.vcpusdb.has_key(path):
kaf24@6030 650 self.vcpusdb[path] = self.db.addChild(path)
kaf24@6030 651 db = self.vcpusdb[path]
kaf24@6097 652 log.debug("writing key availability=online to path %s in store"%(path))
kaf24@6097 653 db['availability'] = "online"
kaf24@6030 654 db.saveDB(save=True)
kaf24@6030 655
cl349@5343 656 def init_image(self):
cl349@5343 657 """Create boot image handler for the domain.
mjw@2542 658 """
mjw@2542 659 image = sxp.child_value(self.config, 'image')
mjw@2542 660 if image is None:
mjw@2542 661 raise VmError('missing image')
cl349@5343 662 self.image = ImageHandler.create(self, image)
iap10@3605 663
iap10@3605 664 def construct_image(self):
cl349@5343 665 """Construct the boot image for the domain.
cl349@5343 666 """
cl349@5343 667 self.create_channel()
cl349@5343 668 self.image.createImage()
cl349@5479 669 self.exportToDB()
cl349@6195 670 if self.store_channel and self.store_mfn >= 0:
cl349@5598 671 self.db.introduceDomain(self.id,
cl349@5598 672 self.store_mfn,
cl349@5598 673 self.store_channel)
kaf24@6030 674 # get the configured value of vcpus and update store
kaf24@6030 675 self.exportVCPUSToDB(self.vcpus)
mjw@2542 676
cl349@5388 677 def delete(self):
cl349@5388 678 """Delete the vm's db.
mjw@1629 679 """
smh22@6154 680 if dom_get(self.id):
cl349@5388 681 return
cl349@5388 682 self.id = None
cl349@5479 683 self.saveToDB(sync=True)
cl349@5351 684 try:
cl349@5388 685 # Todo: eventually will have to wait for devices to signal
cl349@5388 686 # destruction before can delete the db.
cl349@5388 687 if self.db:
cl349@5388 688 self.db.delete()
cl349@5351 689 except Exception, ex:
cl349@5388 690 log.warning("error in domain db delete: %s", ex)
cl349@5351 691 pass
mjw@1629 692
mjw@1629 693 def destroy_domain(self):
mjw@1629 694 """Destroy the vm's domain.
mjw@1629 695 The domain will not finally go away unless all vm
mjw@1629 696 devices have been released.
mjw@1629 697 """
cl349@5388 698 if self.id is None:
cl349@5388 699 return
cl349@5388 700 try:
cl349@5388 701 xc.domain_destroy(dom=self.id)
cl349@5388 702 except Exception, err:
cl349@5388 703 log.exception("Domain destroy failed: %s", self.name)
cl349@5388 704
cl349@5388 705 def cleanup(self):
cl349@5388 706 """Cleanup vm resources: release devices.
cl349@5388 707 """
cl349@5388 708 self.state = STATE_VM_TERMINATED
cl349@5388 709 self.release_devices()
cl349@5352 710 if self.store_channel:
cl349@5352 711 try:
cl349@5352 712 self.store_channel.close()
cl349@5352 713 self.store_channel = None
cl349@5352 714 except:
cl349@5352 715 pass
cl349@5598 716 try:
cl349@5598 717 self.db.releaseDomain(self.id)
cl349@5598 718 except Exception, ex:
cl349@5598 719 log.warning("error in domain release on xenstore: %s", ex)
cl349@5598 720 pass
cl349@6474 721 if self.console_channel:
cl349@6474 722 # notify processes using this cosole?
cl349@6474 723 try:
cl349@6474 724 self.console_channel.close()
cl349@6474 725 self.console_channel = None
cl349@6474 726 except:
cl349@6474 727 pass
cl349@5343 728 if self.image:
cl349@5343 729 try:
kaf24@6103 730 self.device_model_pid = 0
cl349@5343 731 self.image.destroy()
cl349@5343 732 self.image = None
cl349@5343 733 except:
cl349@5343 734 pass
mjw@1623 735
cl349@5388 736 def destroy(self):
cl349@5388 737 """Clenup vm and destroy domain.
mjw@1629 738 """
cl349@6645 739 self.destroy_domain()
cl349@5388 740 self.cleanup()
cl349@5479 741 self.saveToDB()
cl349@5388 742 return 0
mjw@1623 743
mjw@1629 744 def is_terminated(self):
mjw@1629 745 """Check if a domain has been terminated.
mjw@1629 746 """
mjw@1900 747 return self.state == STATE_VM_TERMINATED
mjw@1629 748
mjw@1623 749 def release_devices(self):
mjw@1629 750 """Release all vm devices.
mjw@1629 751 """
mjw@4580 752 reboot = self.restart_pending()
ewan@6770 753 for ctrl in self.controllers.values():
mjw@4580 754 if ctrl.isDestroyed(): continue
mjw@4580 755 ctrl.destroyController(reboot=reboot)
cl349@6712 756 t = xstransact("%s/device" % self.path)
cl349@6744 757 for d in t.list("vbd"):
cl349@6744 758 t.remove(d)
cl349@6712 759 for d in t.list("vif"):
cl349@6712 760 t.remove(d)
cl349@6745 761 for d in t.list("vtpm"):
cl349@6745 762 t.remove(d)
cl349@6712 763 t.commit()
mwilli2@3463 764
mjw@1623 765 def show(self):
mjw@1623 766 """Print virtual machine info.
mjw@1623 767 """
smh22@5514 768 print "[VM dom=%d name=%s memory=%d ssidref=%d" % (self.id, self.name, self.memory, self.ssidref)
mjw@1623 769 print "image:"
mjw@1623 770 sxp.show(self.image)
mjw@1623 771 print "]"
mjw@1623 772
mjw@1623 773 def init_domain(self):
mjw@1623 774 """Initialize the domain memory.
mjw@1623 775 """
mjw@2160 776 if self.recreate:
mjw@2160 777 return
mjw@2160 778 if self.start_time is None:
mjw@2160 779 self.start_time = time.time()
mjw@2290 780 try:
mjw@2290 781 cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
mjw@2290 782 except:
mjw@2290 783 raise VmError('invalid cpu')
smh22@5514 784 id = self.image.initDomain(self.id, self.memory, self.ssidref, cpu, self.cpu_weight)
cl349@5343 785 log.debug('init_domain> Created domain=%d name=%s memory=%d',
cl349@5479 786 id, self.name, self.memory)
cl349@5479 787 self.setdom(id)
mjw@1623 788
cl349@6676 789 def eventChannelOld(self, key):
cl349@5479 790 """Create an event channel to the domain.
cl349@5479 791 If saved info is available recreate the channel.
cl349@5479 792
cl349@5479 793 @param key db key for the saved data (if any)
cl349@5479 794 """
cl349@5388 795 db = self.db.addChild(key)
cl349@5388 796 return EventChannel.restoreFromDB(db, 0, self.id)
cl349@5388 797
cl349@6676 798 def eventChannel(self, path=None, key=None):
cl349@6676 799 """Create an event channel to the domain.
cl349@6676 800
cl349@6676 801 @param path under which port is stored in db
cl349@6676 802 """
cl349@6676 803 port = 0
cl349@6676 804 try:
cl349@6676 805 if path and key:
cl349@6676 806 if path:
cl349@6676 807 db = self.db.addChild(path)
cl349@6676 808 else:
cl349@6676 809 db = self.db
cl349@6676 810 port = int(db[key].getData())
cl349@6676 811 except: pass
cl349@6676 812 return EventChannel.interdomain(0, self.id, port1=port, port2=0)
cl349@6676 813
cl349@5351 814 def create_channel(self):
cl349@5351 815 """Create the channels to the domain.
cl349@5351 816 """
cl349@6676 817 self.store_channel = self.eventChannelOld("store_channel")
cl349@6676 818 self.console_channel = self.eventChannel("console", "port")
cl349@2865 819
ewan@6770 820
mjw@4580 821 def create_configured_devices(self):
mjw@4580 822 devices = sxp.children(self.config, 'device')
mjw@4580 823 for d in devices:
mjw@4580 824 dev_config = sxp.child0(d)
mjw@4580 825 if dev_config is None:
mjw@4580 826 raise VmError('invalid device')
mjw@4580 827 dev_type = sxp.name(dev_config)
ewan@6770 828
ewan@6770 829 if not controller.isDevControllerClass(dev_type):
mjw@4580 830 raise VmError('unknown device type: ' + dev_type)
ewan@6770 831
ewan@6770 832 self.createDevice(dev_type, dev_config)
ewan@6770 833
ewan@6770 834
mjw@1623 835 def create_devices(self):
mjw@1623 836 """Create the devices for a vm.
mjw@1623 837
mjw@1975 838 @raise: VmError for invalid devices
mjw@1623 839 """
mjw@4580 840 if self.rebooting():
ewan@6770 841 for ctrl in self.controllers.values():
mjw@4580 842 ctrl.initController(reboot=True)
mjw@4580 843 else:
adsharma@6186 844 self.create_configured_devices()
kaf24@6101 845 if not self.device_model_pid:
kaf24@6101 846 self.device_model_pid = self.image.createDeviceModel()
mjw@1623 847
mjw@1771 848 def device_create(self, dev_config):
mjw@1771 849 """Create a new device.
mjw@1771 850
mjw@1771 851 @param dev_config: device configuration
mjw@1771 852 """
mjw@4580 853 dev_type = sxp.name(dev_config)
kaf24@6131 854 dev = self.createDevice(dev_type, dev_config, change=True)
mjw@4580 855 self.config.append(['device', dev.getConfig()])
mjw@4580 856 return dev.sxpr()
mjw@1771 857
cl349@5338 858 def device_configure(self, dev_config, id):
mjw@2507 859 """Configure an existing device.
mjw@2507 860
mjw@2507 861 @param dev_config: device configuration
cl349@5338 862 @param id: device id
mjw@2507 863 """
mjw@2507 864 type = sxp.name(dev_config)
cl349@5338 865 dev = self.getDevice(type, id)
mjw@4580 866 old_config = dev.getConfig()
mjw@4580 867 new_config = dev.configure(dev_config, change=True)
mjw@2507 868 # Patch new config into vm config.
mjw@2507 869 new_full_config = ['device', new_config]
mjw@2507 870 old_full_config = ['device', old_config]
mjw@2507 871 old_index = self.config.index(old_full_config)
mjw@2507 872 self.config[old_index] = new_full_config
mjw@2507 873 return new_config
vh249@4423 874
cl349@5338 875 def device_refresh(self, type, id):
vh249@4423 876 """Refresh a device.
vh249@4423 877
vh249@4423 878 @param type: device type
cl349@5338 879 @param id: device id
vh249@4423 880 """
cl349@5338 881 dev = self.getDevice(type, id)
vh249@4423 882 dev.refresh()
mjw@2507 883
cl349@5338 884 def device_delete(self, type, id):
mjw@4580 885 """Destroy and remove a device.
mjw@1771 886
mjw@1771 887 @param type: device type
cl349@5338 888 @param id: device id
mjw@1771 889 """
cl349@5338 890 dev = self.getDevice(type, id)
mjw@4580 891 dev_config = dev.getConfig()
mjw@1771 892 if dev_config:
mjw@1771 893 self.config.remove(['device', dev_config])
mjw@4580 894 self.deleteDevice(type, dev.getId())
mjw@1771 895
mjw@4677 896 def configure_bootloader(self):
mjw@4677 897 """Configure boot loader.
mjw@2403 898 """
cl349@5343 899 self.bootloader = sxp.child_value(self.config, "bootloader")
mjw@2403 900
mjw@1785 901 def configure_restart(self):
mjw@1975 902 """Configure the vm restart mode.
mjw@1975 903 """
mjw@1785 904 r = sxp.child_value(self.config, 'restart', RESTART_ONREBOOT)
mjw@1785 905 if r not in restart_modes:
mjw@1785 906 raise VmError('invalid restart mode: ' + str(r))
mjw@1785 907 self.restart_mode = r;
mjw@1785 908
mjw@1785 909 def restart_needed(self, reason):
mjw@1975 910 """Determine if the vm needs to be restarted when shutdown
mjw@1975 911 for the given reason.
mjw@1975 912
mjw@1975 913 @param reason: shutdown reason
mjw@4580 914 @return True if needs restart, False otherwise
mjw@1975 915 """
mjw@1785 916 if self.restart_mode == RESTART_NEVER:
mjw@4580 917 return False
mjw@1785 918 if self.restart_mode == RESTART_ALWAYS:
mjw@4580 919 return True
mjw@1785 920 if self.restart_mode == RESTART_ONREBOOT:
mjw@1785 921 return reason == 'reboot'
mjw@4580 922 return False
mjw@1785 923
mjw@1893 924 def restart_cancel(self):
mjw@1975 925 """Cancel a vm restart.
mjw@1975 926 """
mjw@1893 927 self.restart_state = None
mjw@1893 928
mjw@1893 929 def restarting(self):
mjw@1975 930 """Put the vm into restart mode.
mjw@1975 931 """
mjw@1893 932 self.restart_state = STATE_RESTART_PENDING
mjw@1893 933
mjw@1900 934 def restart_pending(self):
mjw@1975 935 """Test if the vm has a pending restart.
mjw@1975 936 """
mjw@1900 937 return self.restart_state == STATE_RESTART_PENDING
mjw@1900 938
mjw@4580 939 def rebooting(self):
mjw@4580 940 return self.restart_state == STATE_RESTART_BOOTING
mjw@4580 941
mjw@1900 942 def restart_check(self):
mjw@1900 943 """Check if domain restart is OK.
mjw@2154 944 To prevent restart loops, raise an error if it is
mjw@1900 945 less than MINIMUM_RESTART_TIME seconds since the last restart.
mjw@1900 946 """
mjw@1900 947 tnow = time.time()
mjw@1900 948 if self.restart_time is not None:
mjw@1900 949 tdelta = tnow - self.restart_time
mjw@1900 950 if tdelta < self.MINIMUM_RESTART_TIME:
mjw@1985 951 self.restart_cancel()
mjw@1975 952 msg = 'VM %s restarting too fast' % self.name
mjw@1900 953 log.error(msg)
mjw@1900 954 raise VmError(msg)
mjw@1900 955 self.restart_time = tnow
mjw@4580 956 self.restart_count += 1
mjw@1900 957
mjw@1893 958 def restart(self):
mjw@1900 959 """Restart the domain after it has exited.
kaf24@6010 960 Reuses the domain id
mjw@1900 961
mjw@1900 962 """
mjw@1893 963 try:
kaf24@6576 964 self.clear_shutdown()
mjw@4580 965 self.state = STATE_VM_OK
cl349@5008 966 self.shutdown_pending = None
mjw@1900 967 self.restart_check()
cl349@5479 968 self.exportToDB()
mjw@1893 969 self.restart_state = STATE_RESTART_BOOTING
mjw@4677 970 if self.bootloader:
mjw@4677 971 self.config = self.bootloader_config()
mjw@4580 972 self.construct(self.config)
cl349@5479 973 self.saveToDB()
mjw@1893 974 finally:
mjw@1893 975 self.restart_state = None
mjw@1893 976
mjw@4677 977 def bootloader_config(self):
mjw@4677 978 # if we're restarting with a bootloader, we need to run it
mjw@4677 979 # FIXME: this assumes the disk is the first device and
mjw@4677 980 # that we're booting from the first disk
mjw@4677 981 blcfg = None
mjw@4677 982 # FIXME: this assumes that we want to use the first disk
mjw@4677 983 dev = sxp.child_value(self.config, "device")
mjw@4677 984 if dev:
mjw@4677 985 disk = sxp.child_value(dev, "uname")
mjw@4677 986 fn = blkdev_uname_to_file(disk)
mjw@4677 987 blcfg = bootloader(self.bootloader, fn, 1, self.vcpus)
mjw@4677 988 if blcfg is None:
mjw@4677 989 msg = "Had a bootloader specified, but can't find disk"
mjw@4677 990 log.error(msg)
mjw@4677 991 raise VmError(msg)
ewan@6770 992 config = sxp.merge(['vm', blcfg ], self.config)
mjw@4677 993 return config
mjw@1893 994
mjw@1623 995 def configure_backends(self):
mjw@2229 996 """Set configuration flags if the vm is a backend for netif or blkif.
mjw@2229 997 Configure the backends to use for vbd and vif if specified.
mjw@1623 998 """
mjw@1623 999 for c in sxp.children(self.config, 'backend'):
mjw@2229 1000 v = sxp.child0(c)
mjw@2229 1001 name = sxp.name(v)
mjw@1623 1002 if name == 'blkif':
mjw@4580 1003 self.blkif_backend = True
mjw@1623 1004 elif name == 'netif':
mjw@4580 1005 self.netif_backend = True
mwilli2@3463 1006 elif name == 'usbif':
mjw@4580 1007 self.usbif_backend = True
shand@6554 1008 elif name == 'tpmif':
shand@6554 1009 self.tpmif_backend = True
mjw@1623 1010 else:
mjw@1623 1011 raise VmError('invalid backend type:' + str(name))
mjw@1623 1012
mjw@1623 1013 def configure(self):
mjw@1623 1014 """Configure a vm.
mjw@1623 1015
mjw@1623 1016 """
mjw@4580 1017 self.configure_fields()
mjw@4580 1018 self.create_devices()
adsharma@6186 1019 self.create_blkif()
mjw@2267 1020
mjw@2313 1021 def create_blkif(self):
mjw@2313 1022 """Create the block device interface (blkif) for the vm.
mjw@2313 1023 The vm needs a blkif even if it doesn't have any disks
mjw@2313 1024 at creation time, for example when it uses NFS root.
mjw@2313 1025
mjw@2313 1026 """
cl349@6264 1027 return
mjw@4617 1028 blkif = self.getDeviceController("vbd", error=False)
mjw@4580 1029 if not blkif:
mjw@4617 1030 blkif = self.createDeviceController("vbd")
mjw@4580 1031 backend = blkif.getBackend(0)
mjw@4580 1032 backend.connect(recreate=self.recreate)
cl349@3125 1033
mjw@1623 1034 def configure_fields(self):
mjw@1975 1035 """Process the vm configuration fields using the registered handlers.
mjw@1975 1036 """
mjw@1623 1037 index = {}
mjw@1623 1038 for field in sxp.children(self.config):
mjw@1623 1039 field_name = sxp.name(field)
mjw@1623 1040 field_index = index.get(field_name, 0)
ewan@6770 1041 field_handler = config_handlers.get(field_name)
mjw@1623 1042 # Ignore unknown fields. Warn?
mjw@1623 1043 if field_handler:
mjw@1623 1044 v = field_handler(self, self.config, field, field_index)
mjw@1863 1045 else:
mjw@1863 1046 log.warning("Unknown config field %s", field_name)
mjw@1623 1047 index[field_name] = field_index + 1
mjw@1623 1048
mjw@4580 1049 def mem_target_set(self, target):
kaf24@5934 1050 """Set domain memory target in bytes.
mjw@4580 1051 """
kaf24@5934 1052 if target:
kaf24@5934 1053 self.target = target * (1 << 20)
kaf24@5934 1054 # Commit to XenStore immediately
kaf24@5934 1055 self.exportToDB()
mjw@4580 1056
cl349@5524 1057 def vcpu_hotplug(self, vcpu, state):
cl349@5524 1058 """Disable or enable VCPU in domain.
cl349@5524 1059 """
kaf24@6030 1060 db = ""
kaf24@6030 1061 try:
kaf24@6097 1062 db = self.vcpusdb['/cpu/%d'%(vcpu)]
kaf24@6030 1063 except:
kaf24@6030 1064 log.error("Invalid VCPU")
kaf24@6030 1065 return
kaf24@6030 1066
kaf24@6030 1067 if self.store_channel:
cl349@5524 1068 if int(state) == 0:
kaf24@6097 1069 db['availability'] = "offline"
cl349@5524 1070 else:
kaf24@6097 1071 db['availability'] = "online"
cl349@5524 1072
kaf24@6030 1073 db.saveDB(save=True)
cl349@5524 1074
kaf24@6019 1075 def shutdown(self, reason):
kaf24@6028 1076 if not reason in shutdown_reasons.values():
mjw@4580 1077 raise XendError('invalid reason:' + reason)
kaf24@6019 1078 db = self.db.addChild("/control");
kaf24@6028 1079 db['shutdown'] = reason;
kaf24@6019 1080 db.saveDB(save=True);
kaf24@6019 1081 if not reason in ['suspend']:
kaf24@6019 1082 self.shutdown_pending = {'start':time.time(), 'reason':reason}
kaf24@6019 1083
cl349@6208 1084 def clear_shutdown(self):
cl349@6208 1085 db = self.db.addChild("/control")
cl349@6208 1086 db['shutdown'] = ""
cl349@6208 1087 db.saveDB(save=True)
cl349@6208 1088
kaf24@6019 1089 def send_sysrq(self, key=0):
kaf24@6019 1090 db = self.db.addChild("/control");
kaf24@6019 1091 db['sysrq'] = '%c' % key;
kaf24@6019 1092 db.saveDB(save=True);
mjw@4580 1093
cl349@5008 1094 def shutdown_time_left(self, timeout):
cl349@5008 1095 if not self.shutdown_pending:
cl349@5008 1096 return 0
cl349@5008 1097 return timeout - (time.time() - self.shutdown_pending['start'])
mjw@4580 1098
cl349@5895 1099 def dom0_init_store(self):
cl349@5895 1100 if not self.store_channel:
cl349@6676 1101 self.store_channel = self.eventChannelOld("store_channel")
cl349@5895 1102 self.store_mfn = xc.init_store(self.store_channel.port2)
cl349@5895 1103 if self.store_mfn >= 0:
cl349@5896 1104 self.db.introduceDomain(self.id, self.store_mfn,
cl349@5896 1105 self.store_channel)
cl349@5895 1106 self.exportToDB(save=True, sync=True)
kaf24@6030 1107 # get run-time value of vcpus and update store
kaf24@6030 1108 self.exportVCPUSToDB(dom_get(self.id)['vcpus'])
cl349@5895 1109
ewan@6770 1110
ewan@6770 1111 def vm_field_ignore(_, _1, _2, _3):
mjw@1975 1112 """Dummy config field handler used for fields with built-in handling.
ewan@6770 1113 Matches the signature required by config_handlers.
mjw@1623 1114 """
mjw@1863 1115 pass
mjw@1863 1116
mjw@2403 1117
ewan@6770 1118 def vm_field_maxmem(vm, _1, val, _2):
ewan@6770 1119 """Config field handler to configure vm memory limit. Matches the
ewan@6770 1120 signature required by config_handlers.
mjw@2403 1121 """
mjw@2403 1122 maxmem = sxp.child0(val)
mjw@2403 1123 if maxmem is None:
mjw@2403 1124 maxmem = vm.memory
mjw@2403 1125 try:
mjw@2403 1126 maxmem = int(maxmem)
mjw@2403 1127 except:
mjw@2403 1128 raise VmError("invalid maxmem: " + str(maxmem))
cl349@5334 1129 xc.domain_setmaxmem(vm.id, maxmem_kb = maxmem * 1024)
mjw@2403 1130
ewan@6770 1131
mjw@4580 1132 #============================================================================
mjw@1975 1133 # Register image handlers.
ewan@6770 1134
cl349@5343 1135 from image import \
cl349@5343 1136 addImageHandlerClass, \
cl349@5343 1137 ImageHandler, \
cl349@5343 1138 LinuxImageHandler, \
cl349@5343 1139 VmxImageHandler
cl349@5343 1140
cl349@5343 1141 addImageHandlerClass(LinuxImageHandler)
cl349@5343 1142 addImageHandlerClass(VmxImageHandler)
mjw@1623 1143
ewan@6770 1144
ewan@6770 1145 """Table of handlers for field configuration.
mjw@1863 1146
ewan@6770 1147 field_name[String]: fn(vm, config, field, index) -> value(ignored)
ewan@6770 1148 """
ewan@6770 1149 config_handlers = {
ewan@6770 1150
ewan@6770 1151 # Ignore the fields we already handle.
ewan@6770 1152
ewan@6770 1153 'name': vm_field_ignore,
ewan@6770 1154 'memory': vm_field_ignore,
ewan@6770 1155 'ssidref': vm_field_ignore,
ewan@6770 1156 'cpu': vm_field_ignore,
ewan@6770 1157 'cpu_weight': vm_field_ignore,
ewan@6770 1158 'restart': vm_field_ignore,
ewan@6770 1159 'image': vm_field_ignore,
ewan@6770 1160 'device': vm_field_ignore,
ewan@6770 1161 'backend': vm_field_ignore,
ewan@6770 1162 'vcpus': vm_field_ignore,
ewan@6770 1163 'bootloader': vm_field_ignore,
ewan@6770 1164
ewan@6770 1165 # Register other config handlers.
ewan@6770 1166 'maxmem': vm_field_maxmem
ewan@6770 1167 }
ewan@6770 1168
mjw@4580 1169
mjw@4580 1170 #============================================================================
mjw@4580 1171 # Register device controllers and their device config types.
mjw@4580 1172
ewan@6770 1173 controller.addDevControllerClass("vbd", server.blkif.BlkifController)
ewan@6770 1174 controller.addDevControllerClass("vif", server.netif.NetifController)
ewan@6770 1175 controller.addDevControllerClass("vtpm", server.tpmif.TPMifController)
ewan@6770 1176 controller.addDevControllerClass("pci", server.pciif.PciController)
ewan@6770 1177 controller.addDevControllerClass("usb", server.usbif.UsbifController)