finalize handlers even when another handler fails.

Instead of previously initializing and not finalizing the handles that
completed successfully when a handler initializing or running failed we
should attempt to always give said handlers a chance to finalize (even
when another handler fails).
This commit is contained in:
Joshua Harlow
2013-07-23 11:57:25 -04:00
committed by Scott Moser
4 changed files with 85 additions and 56 deletions

View File

@@ -151,10 +151,9 @@ def walker_handle_handler(pdata, _ctype, _filename, payload):
try:
mod = fixup_handler(importer.import_module(modname))
call_begin(mod, pdata['data'], frequency)
# Only register and increment
# after the above have worked (so we don't if it
# fails)
handlers.register(mod)
# Only register and increment after the above have worked, so we don't
# register if it fails starting.
handlers.register(mod, initialized=True)
pdata['handlercount'] = curcount + 1
except:
util.logexc(LOG, "Failed at registering python file: %s (part "

View File

@@ -281,6 +281,7 @@ class ContentHandlers(object):
def __init__(self):
self.registered = {}
self.initialized = []
def __contains__(self, item):
return self.is_registered(item)
@@ -291,11 +292,13 @@ class ContentHandlers(object):
def is_registered(self, content_type):
return content_type in self.registered
def register(self, mod):
def register(self, mod, initialized=False):
types = set()
for t in mod.list_types():
self.registered[t] = mod
types.add(t)
if initialized and mod not in self.initialized:
self.initialized.append(mod)
return types
def _get_handler(self, content_type):

View File

@@ -344,12 +344,13 @@ class Init(object):
cdir = self.paths.get_cpath("handlers")
idir = self._get_ipath("handlers")
# Add the path to the plugins dir to the top of our list for import
# instance dir should be read before cloud-dir
if cdir and cdir not in sys.path:
sys.path.insert(0, cdir)
if idir and idir not in sys.path:
sys.path.insert(0, idir)
# Add the path to the plugins dir to the top of our list for importing
# new handlers.
#
# Note(harlowja): instance dir should be read before cloud-dir
for d in [cdir, idir]:
if d and d not in sys.path:
sys.path.insert(0, d)
# Ensure datasource fetched before activation (just incase)
user_data_msg = self.datasource.get_userdata(True)
@@ -357,24 +358,34 @@ class Init(object):
# This keeps track of all the active handlers
c_handlers = helpers.ContentHandlers()
# Add handlers in cdir
potential_handlers = util.find_modules(cdir)
for (fname, mod_name) in potential_handlers.iteritems():
try:
mod_locs = importer.find_module(mod_name, [''],
['list_types',
'handle_part'])
if not mod_locs:
LOG.warn(("Could not find a valid user-data handler"
" named %s in file %s"), mod_name, fname)
continue
mod = importer.import_module(mod_locs[0])
mod = handlers.fixup_handler(mod)
types = c_handlers.register(mod)
LOG.debug("Added handler for %s from %s", types, fname)
except:
util.logexc(LOG, "Failed to register handler from %s", fname)
def register_handlers_in_dir(path):
# Attempts to register any handler modules under the given path.
if not path or not os.path.isdir(path):
return
potential_handlers = util.find_modules(path)
for (fname, mod_name) in potential_handlers.iteritems():
try:
mod_locs = importer.find_module(mod_name, [''],
['list_types',
'handle_part'])
if not mod_locs:
LOG.warn(("Could not find a valid user-data handler"
" named %s in file %s"), mod_name, fname)
continue
mod = importer.import_module(mod_locs[0])
mod = handlers.fixup_handler(mod)
types = c_handlers.register(mod)
LOG.debug("Added handler for %s from %s", types, fname)
except Exception:
util.logexc(LOG, "Failed to register handler from %s",
fname)
# Add any handlers in the cloud-dir
register_handlers_in_dir(cdir)
# Register any other handlers that come from the default set. This
# is done after the cloud-dir handlers so that the cdir modules can
# take over the default user-data handler content-types.
def_handlers = self._default_userdata_handlers()
applied_def_handlers = c_handlers.register_defaults(def_handlers)
if applied_def_handlers:
@@ -383,36 +394,51 @@ class Init(object):
# Form our cloud interface
data = self.cloudify()
# Init the handlers first
called = []
for (_ctype, mod) in c_handlers.iteritems():
if mod in called:
continue
handlers.call_begin(mod, data, frequency)
called.append(mod)
def init_handlers():
# Init the handlers first
for (_ctype, mod) in c_handlers.iteritems():
if mod in c_handlers.initialized:
# Avoid initing the same module twice (if said module
# is registered to more than one content-type).
continue
handlers.call_begin(mod, data, frequency)
c_handlers.initialized.append(mod)
# Walk the user data
part_data = {
'handlers': c_handlers,
# Any new handlers that are encountered get writen here
'handlerdir': idir,
'data': data,
# The default frequency if handlers don't have one
'frequency': frequency,
# This will be used when new handlers are found
# to help write there contents to files with numbered
# names...
'handlercount': 0,
}
handlers.walk(user_data_msg, handlers.walker_callback, data=part_data)
def walk_handlers():
# Walk the user data
part_data = {
'handlers': c_handlers,
# Any new handlers that are encountered get writen here
'handlerdir': idir,
'data': data,
# The default frequency if handlers don't have one
'frequency': frequency,
# This will be used when new handlers are found
# to help write there contents to files with numbered
# names...
'handlercount': 0,
}
handlers.walk(user_data_msg, handlers.walker_callback,
data=part_data)
# Give callbacks opportunity to finalize
called = []
for (_ctype, mod) in c_handlers.iteritems():
if mod in called:
continue
handlers.call_end(mod, data, frequency)
called.append(mod)
def finalize_handlers():
# Give callbacks opportunity to finalize
for (_ctype, mod) in c_handlers.iteritems():
if mod not in c_handlers.initialized:
# Said module was never inited in the first place, so lets
# not attempt to finalize those that never got called.
continue
c_handlers.initialized.remove(mod)
try:
handlers.call_end(mod, data, frequency)
except:
util.logexc(LOG, "Failed to finalize handler: %s", mod)
try:
init_handlers()
walk_handlers()
finally:
finalize_handlers()
# Perform post-consumption adjustments so that
# modules that run during the init stage reflect