mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
bitkeeper revision 1.1041.5.5 (40e97f82YUOF-rGuIapKOE73WUHZcg)
Add control over domain restart on shutdown.
This commit is contained in:
1 parent
6a30406587
commit
1c894096e7
8 files changed
+193
-36
No files matched your search
@@ -225,9 +225,10 @@ class Xend:
|
||||
return xend_call(self.domainurl(id),
|
||||
{'op' : 'pause'})
|
||||
|
||||
def xend_domain_shutdown(self, id):
|
||||
def xend_domain_shutdown(self, id, reason):
|
||||
return xend_call(self.domainurl(id),
|
||||
{'op' : 'shutdown'})
|
||||
{'op' : 'shutdown',
|
||||
'reason' : reason })
|
||||
|
||||
def xend_domain_destroy(self, id):
|
||||
return xend_call(self.domainurl(id),
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
Needs to be persistent for one uptime.
|
||||
"""
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from twisted.internet import defer
|
||||
from twisted.internet import reactor
|
||||
|
||||
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
|
||||
|
||||
@@ -28,10 +30,19 @@ __all__ = [ "XendDomain" ]
|
||||
class XendDomain:
|
||||
"""Index of all domains. Singleton.
|
||||
"""
|
||||
|
||||
|
||||
"""Path to domain database."""
|
||||
dbpath = "domain"
|
||||
|
||||
"""Table of domain info indexed by domain id."""
|
||||
domain = {}
|
||||
|
||||
"""Table of configs for domain restart, indexed by domain id."""
|
||||
restarts = {}
|
||||
|
||||
"""Table of delayed calls."""
|
||||
schedule = {}
|
||||
|
||||
def __init__(self):
|
||||
self.xconsole = XendConsole.instance()
|
||||
# Table of domain info indexed by domain id.
|
||||
@@ -49,6 +60,53 @@ class XendDomain:
|
||||
print 'XendDomain> virq', val
|
||||
self.reap()
|
||||
|
||||
def schedule_later(self, _delay, _name, _fn, *args):
|
||||
"""Schedule a function to be called later (if not already scheduled).
|
||||
|
||||
_delay delay in seconds
|
||||
_name schedule name
|
||||
_fn function
|
||||
args arguments
|
||||
"""
|
||||
if self.schedule.get(_name): return
|
||||
self.schedule[_name] = reactor.callLater(_delay, _fn, *args)
|
||||
|
||||
def schedule_cancel(self, name):
|
||||
"""Cancel a scheduled function call.
|
||||
|
||||
name schedule name to cancel
|
||||
"""
|
||||
callid = self.schedule.get(name)
|
||||
if not callid:
|
||||
return
|
||||
if callid.active():
|
||||
callid.cancel()
|
||||
del self.schedule[name]
|
||||
|
||||
def reap_schedule(self, delay=0):
|
||||
"""Schedule reap to be called later.
|
||||
|
||||
delay delay in seconds
|
||||
"""
|
||||
self.schedule_later(delay, 'reap', self.reap)
|
||||
|
||||
def reap_cancel(self):
|
||||
"""Cancel any scheduled reap.
|
||||
"""
|
||||
self.schedule_cancel('reap')
|
||||
|
||||
def refresh_schedule(self, delay=0):
|
||||
"""Schedule refresh to be called later.
|
||||
|
||||
delay delay in seconds
|
||||
"""
|
||||
self.schedule_later(delay, 'refresh', self.refresh)
|
||||
|
||||
def refresh_cancel(self):
|
||||
"""Cancel any scheduled refresh.
|
||||
"""
|
||||
self.schedule_cancel('refresh')
|
||||
|
||||
def rm_all(self):
|
||||
"""Remove all domain info. Used after reboot.
|
||||
"""
|
||||
@@ -145,6 +203,7 @@ class XendDomain:
|
||||
"""Look for domains that have crashed or stopped.
|
||||
Tidy them up.
|
||||
"""
|
||||
self.reap_cancel()
|
||||
print 'XendDomain>reap>'
|
||||
domlist = xc.domain_getinfo()
|
||||
casualties = []
|
||||
@@ -158,12 +217,14 @@ class XendDomain:
|
||||
for d in casualties:
|
||||
id = str(d['dom'])
|
||||
print 'XendDomain>reap> died id=', id, d
|
||||
self.domain_destroy(id, refresh=0)
|
||||
self.final_domain_destroy(id)
|
||||
print 'XendDomain>reap<'
|
||||
|
||||
def refresh(self):
|
||||
"""Refresh domain list from Xen.
|
||||
"""
|
||||
self.refresh_cancel()
|
||||
print 'XendDomain>refresh>'
|
||||
domlist = xc.domain_getinfo()
|
||||
# Index the domlist by id.
|
||||
# Add entries for any domains we don't know about.
|
||||
@@ -184,7 +245,7 @@ class XendDomain:
|
||||
d.update(dominfo)
|
||||
else:
|
||||
self._delete_domain(d.id)
|
||||
self.reap()
|
||||
self.reap_schedule(1)
|
||||
|
||||
def refresh_domain(self, id):
|
||||
"""Refresh information for a single domain.
|
||||
@@ -267,21 +328,70 @@ class XendDomain:
|
||||
"""Shutdown domain (nicely).
|
||||
|
||||
id domain id
|
||||
reason shutdown type: poweroff, reboot, halt
|
||||
reason shutdown type: poweroff, reboot, suspend, halt
|
||||
"""
|
||||
dom = int(id)
|
||||
if dom <= 0:
|
||||
return 0
|
||||
self.domain_restart_schedule(id, reason)
|
||||
eserver.inject('xend.domain.shutdown', [id, reason])
|
||||
if reason == 'halt':
|
||||
reason = 'poweroff'
|
||||
val = xend.domain_shutdown(dom, reason)
|
||||
self.refresh()
|
||||
self.refresh_schedule()
|
||||
return val
|
||||
|
||||
def domain_destroy(self, id, refresh=1):
|
||||
"""Terminate domain immediately.
|
||||
|
||||
def domain_restart_schedule(self, id, reason):
|
||||
"""Schedule a restart for a domain if it needs one.
|
||||
|
||||
id domain id
|
||||
reason shutdown reason
|
||||
"""
|
||||
if id in self.restarts:
|
||||
# Don't schedule if already there.
|
||||
return
|
||||
restart = 0
|
||||
if reason in ['poweroff', 'reboot']:
|
||||
dominfo = self.domain.get(id)
|
||||
if dominfo and (dominfo.autorestart or reason == 'reboot'):
|
||||
restart = 1
|
||||
# Clear autorestart flag to avoid multiple restarts.
|
||||
dominfo.autorestart = 0
|
||||
|
||||
if restart:
|
||||
self.restarts[id] = dominfo.config
|
||||
|
||||
def domain_restart_cancel(self, id):
|
||||
"""Cancel any restart scheduled for a domain.
|
||||
|
||||
id domain id
|
||||
"""
|
||||
dominfo = self.domain.get(id)
|
||||
if dominfo:
|
||||
dominfo.autorestart = 0
|
||||
if id in self.restarts:
|
||||
del self.restarts[id]
|
||||
|
||||
def domain_restarts(self):
|
||||
"""Execute any scheduled domain restarts for domains that have gone.
|
||||
"""
|
||||
for id in self.restarts.keys():
|
||||
if id in self.domain:
|
||||
# Don't execute restart for domains still running.
|
||||
continue
|
||||
config = self.restarts[id]
|
||||
# Remove it from the restarts.
|
||||
del self.restarts[id]
|
||||
try:
|
||||
self.domain_create(config)
|
||||
except:
|
||||
print >>sys.stderr, "XendDomain> Exception restarting domain"
|
||||
traceback.print_exc(sys.stderr)
|
||||
|
||||
def final_domain_destroy(self, id):
|
||||
"""Final destruction of a domain..
|
||||
|
||||
id domain id
|
||||
refresh send a domain destroy event if true
|
||||
"""
|
||||
dom = int(id)
|
||||
if dom <= 0:
|
||||
@@ -292,15 +402,26 @@ class XendDomain:
|
||||
val = dominfo.destroy()
|
||||
else:
|
||||
val = xc.domain_destroy(dom=dom)
|
||||
if refresh: self.refresh()
|
||||
return val
|
||||
|
||||
def domain_destroy(self, id):
|
||||
"""Terminate domain immediately.
|
||||
Camcels any restart for the domain.
|
||||
|
||||
id domain id
|
||||
"""
|
||||
self.domain_restart_cancel(id)
|
||||
val = self.final_domain_destroy(id)
|
||||
self.refresh_schedule()
|
||||
return val
|
||||
|
||||
def domain_migrate(self, id, dst):
|
||||
"""Start domain migration.
|
||||
|
||||
id domain id
|
||||
"""
|
||||
# Need a cancel too?
|
||||
# Don't forget to cancel restart for it.
|
||||
pass
|
||||
|
||||
def domain_save(self, id, dst, progress=0):
|
||||
|
||||
@@ -362,6 +362,8 @@ class XendDomainInfo:
|
||||
self.state = self.STATE_OK
|
||||
#todo: set to migrate info if migrating
|
||||
self.migrate = None
|
||||
#Whether to auto-restart
|
||||
self.autorestart = 0
|
||||
|
||||
def setdom(self, dom):
|
||||
self.dom = int(dom)
|
||||
@@ -418,6 +420,8 @@ class XendDomainInfo:
|
||||
try:
|
||||
self.name = sxp.child_value(config, 'name')
|
||||
self.memory = int(sxp.child_value(config, 'memory', '128'))
|
||||
if sxp.child(config, 'autorestart', None):
|
||||
self.autorestart = 1
|
||||
self.configure_backends()
|
||||
image = sxp.child_value(config, 'image')
|
||||
image_name = sxp.name(image)
|
||||
|
||||
@@ -27,7 +27,11 @@ class SrvDomain(SrvDir):
|
||||
return val
|
||||
|
||||
def op_shutdown(self, op, req):
|
||||
val = self.xd.domain_shutdown(self.dom.id)
|
||||
#val = self.xd.domain_shutdown(self.dom.id)
|
||||
fn = FormFn(self.xd.domain_shutdown,
|
||||
[['dom', 'int'],
|
||||
['reason', 'str']])
|
||||
val = fn(req.args, {'dom': self.dom.id})
|
||||
req.setResponseCode(202)
|
||||
req.setHeader("Location", "%s/.." % req.prePathURL())
|
||||
return val
|
||||
|
||||
@@ -101,6 +101,10 @@ gopts.opt('memory', short='m', val='MEMORY',
|
||||
fn=set_value, default=128,
|
||||
use="Domain memory in MB.")
|
||||
|
||||
gopts.opt('autorestart',
|
||||
fn=set_true, default=0,
|
||||
use="Whether to restart the domain on exit.")
|
||||
|
||||
gopts.opt('blkif',
|
||||
fn=set_true, default=0,
|
||||
use="Make the domain a block device backend.")
|
||||
@@ -271,6 +275,8 @@ def make_config(opts):
|
||||
config.append(['backend', ['blkif']])
|
||||
if opts.netif:
|
||||
config.append(['backend', ['netif']])
|
||||
if opts.autorestart:
|
||||
config.append(['autorestart'])
|
||||
|
||||
configure_image(config, opts)
|
||||
config_devs = []
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
|
||||
|
||||
"""Domain shutdown.
|
||||
"""
|
||||
import string
|
||||
@@ -10,7 +11,8 @@ from xen.xm.opts import *
|
||||
|
||||
gopts = Opts(use="""[options] [DOM]
|
||||
|
||||
Shutdown one or more domains gracefully.""")
|
||||
Shutdown one or more domains gracefully.
|
||||
""")
|
||||
|
||||
gopts.opt('help', short='h',
|
||||
fn=set_true, default=0,
|
||||
@@ -24,18 +26,22 @@ gopts.opt('wait', short='w',
|
||||
fn=set_true, default=0,
|
||||
use='Wait for shutdown to complete.')
|
||||
|
||||
gopts.opt('norestart', short='n',
|
||||
gopts.opt('halt', short='H',
|
||||
fn=set_true, default=0,
|
||||
use='Prevent domain restart.')
|
||||
use='Shutdown without reboot.')
|
||||
|
||||
def shutdown(opts, doms, wait):
|
||||
gopts.opt('reboot', short='R',
|
||||
fn=set_true, default=0,
|
||||
use='Shutdown and reboot.')
|
||||
|
||||
def shutdown(opts, doms, mode, wait):
|
||||
def domains():
|
||||
return [ int(a) for a in server.xend_domains() ]
|
||||
if doms == None: doms = domains()
|
||||
if 0 in doms:
|
||||
doms.remove(0)
|
||||
for d in doms:
|
||||
server.xend_domain_shutdown(d)
|
||||
server.xend_domain_shutdown(d, mode)
|
||||
if wait:
|
||||
while doms:
|
||||
alive = domains()
|
||||
@@ -49,6 +55,21 @@ def shutdown(opts, doms, wait):
|
||||
time.sleep(1)
|
||||
opts.info("All domains terminated")
|
||||
|
||||
def shutdown_mode(opts):
|
||||
mode = 'poweroff'
|
||||
if opts.vals.wait:
|
||||
mode = 'halt'
|
||||
if opts.vals.reboot:
|
||||
opts.err("Can't specify wait and reboot")
|
||||
else:
|
||||
if opts.vals.halt and opts.vals.reboot:
|
||||
opts.err("Can't specify halt and reboot")
|
||||
if opts.vals.halt:
|
||||
mode = 'halt'
|
||||
elif opts.vals.reboot:
|
||||
mode = 'reboot'
|
||||
return mode
|
||||
|
||||
def main_all(opts, args):
|
||||
shutdown(opts, None, opts.vals.wait)
|
||||
|
||||
@@ -59,7 +80,9 @@ def main_dom(opts, args):
|
||||
domid = int(dom)
|
||||
except:
|
||||
opts.err('Invalid domain: ' + dom)
|
||||
shutdown(opts, [ domid ], opts.vals.wait)
|
||||
|
||||
mode = shutdown_mode(opts)
|
||||
shutdown(opts, [ domid ], mode, opts.vals.wait)
|
||||
|
||||
def main(argv):
|
||||
opts = gopts
|
||||
|
||||