simplify consume_vendordata, move exclusion, consume_vendordata per instance
this simplifies consume_vendordata a bit, changes consume_vendordata to be by default "PER_INSTANCE" (like userdata). The other thing we do here is move the exlusion to be handled when walking the data. The benefit of doing it then is that we can exclude part-handlers. Without the ability to exlude part handlers, exclusion is basically useless (since part-handlers could accomplish anything they wanted).
This commit is contained in:
parent
5dd23c78de
commit
e6db6cb0e5
@ -187,6 +187,10 @@ def _escape_string(text):
|
|||||||
|
|
||||||
def walker_callback(data, filename, payload, headers):
|
def walker_callback(data, filename, payload, headers):
|
||||||
content_type = headers['Content-Type']
|
content_type = headers['Content-Type']
|
||||||
|
if content_type in data.get('excluded'):
|
||||||
|
LOG.debug('content_type "%s" is excluded', content_type)
|
||||||
|
return
|
||||||
|
|
||||||
if content_type in PART_CONTENT_TYPES:
|
if content_type in PART_CONTENT_TYPES:
|
||||||
walker_handle_handler(data, content_type, filename, payload)
|
walker_handle_handler(data, content_type, filename, payload)
|
||||||
return
|
return
|
||||||
|
@ -338,56 +338,40 @@ class Init(object):
|
|||||||
processed_vd = "%s" % (self.datasource.get_vendordata())
|
processed_vd = "%s" % (self.datasource.get_vendordata())
|
||||||
util.write_file(self._get_ipath('vendordata'), processed_vd, 0600)
|
util.write_file(self._get_ipath('vendordata'), processed_vd, 0600)
|
||||||
|
|
||||||
def _get_default_handlers(self, user_data=False, vendor_data=False,
|
def _default_handlers(self, opts=None):
|
||||||
excluded=None):
|
if opts is None:
|
||||||
opts = {
|
opts = {}
|
||||||
|
|
||||||
|
opts.update({
|
||||||
'paths': self.paths,
|
'paths': self.paths,
|
||||||
'datasource': self.datasource,
|
'datasource': self.datasource,
|
||||||
}
|
})
|
||||||
|
|
||||||
def conditional_get(cls, mod):
|
|
||||||
cls_name = cls.__name__.split('.')[-1]
|
|
||||||
_mod = getattr(cls, mod)
|
|
||||||
if not excluded:
|
|
||||||
return _mod(**opts)
|
|
||||||
|
|
||||||
if cls_name not in excluded:
|
|
||||||
_mod = getattr(cls, mod)
|
|
||||||
return _mod(**opts)
|
|
||||||
|
|
||||||
# TODO(harlowja) Hmmm, should we dynamically import these??
|
# TODO(harlowja) Hmmm, should we dynamically import these??
|
||||||
def_handlers = [
|
def_handlers = [
|
||||||
conditional_get(bh_part, 'BootHookPartHandler'),
|
cc_part.CloudConfigPartHandler(**opts),
|
||||||
conditional_get(up_part, 'UpstartJobPartHandler'),
|
ss_part.ShellScriptPartHandler(**opts),
|
||||||
|
bh_part.BootHookPartHandler(**opts),
|
||||||
|
up_part.UpstartJobPartHandler(**opts),
|
||||||
]
|
]
|
||||||
|
return def_handlers
|
||||||
# Add in the shell script part handler
|
|
||||||
if user_data:
|
|
||||||
def_handlers.extend([
|
|
||||||
conditional_get(cc_part, 'CloudConfigPartHandler'),
|
|
||||||
conditional_get(ss_part, 'ShellScriptPartHandler')])
|
|
||||||
|
|
||||||
# This changes the path for the vendor script execution
|
|
||||||
if vendor_data:
|
|
||||||
opts['script_path'] = "vendor_scripts"
|
|
||||||
opts['cloud_config_path'] = "vendor_cloud_config"
|
|
||||||
def_handlers.extend([
|
|
||||||
conditional_get(cc_part, 'CloudConfigPartHandler'),
|
|
||||||
conditional_get(ss_part, 'ShellScriptPartHandler')])
|
|
||||||
|
|
||||||
return [x for x in def_handlers if x is not None]
|
|
||||||
|
|
||||||
def _default_userdata_handlers(self):
|
def _default_userdata_handlers(self):
|
||||||
return self._get_default_handlers(user_data=True)
|
return self._default_handlers()
|
||||||
|
|
||||||
def _default_vendordata_handlers(self, excluded=None):
|
def _default_vendordata_handlers(self):
|
||||||
return self._get_default_handlers(vendor_data=True, excluded=excluded)
|
return self._default_handlers(
|
||||||
|
opts={'script_path': 'vendor_scripts',
|
||||||
|
'cloud_config_path': 'vendor_cloud_config'})
|
||||||
|
|
||||||
def _do_handlers(self, data_msg, c_handlers_list, frequency):
|
def _do_handlers(self, data_msg, c_handlers_list, frequency,
|
||||||
|
excluded=None):
|
||||||
"""
|
"""
|
||||||
Generalized handlers suitable for use with either vendordata
|
Generalized handlers suitable for use with either vendordata
|
||||||
or userdata
|
or userdata
|
||||||
"""
|
"""
|
||||||
|
if excluded is None:
|
||||||
|
excluded = []
|
||||||
|
|
||||||
cdir = self.paths.get_cpath("handlers")
|
cdir = self.paths.get_cpath("handlers")
|
||||||
idir = self._get_ipath("handlers")
|
idir = self._get_ipath("handlers")
|
||||||
|
|
||||||
@ -450,7 +434,7 @@ class Init(object):
|
|||||||
handlers.call_begin(mod, data, frequency)
|
handlers.call_begin(mod, data, frequency)
|
||||||
c_handlers.initialized.append(mod)
|
c_handlers.initialized.append(mod)
|
||||||
|
|
||||||
def walk_handlers():
|
def walk_handlers(excluded):
|
||||||
# Walk the user data
|
# Walk the user data
|
||||||
part_data = {
|
part_data = {
|
||||||
'handlers': c_handlers,
|
'handlers': c_handlers,
|
||||||
@ -463,9 +447,9 @@ class Init(object):
|
|||||||
# to help write there contents to files with numbered
|
# to help write there contents to files with numbered
|
||||||
# names...
|
# names...
|
||||||
'handlercount': 0,
|
'handlercount': 0,
|
||||||
|
'excluded': excluded,
|
||||||
}
|
}
|
||||||
handlers.walk(data_msg, handlers.walker_callback,
|
handlers.walk(data_msg, handlers.walker_callback, data=part_data)
|
||||||
data=part_data)
|
|
||||||
|
|
||||||
def finalize_handlers():
|
def finalize_handlers():
|
||||||
# Give callbacks opportunity to finalize
|
# Give callbacks opportunity to finalize
|
||||||
@ -482,7 +466,7 @@ class Init(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
init_handlers()
|
init_handlers()
|
||||||
walk_handlers()
|
walk_handlers(excluded)
|
||||||
finally:
|
finally:
|
||||||
finalize_handlers()
|
finalize_handlers()
|
||||||
|
|
||||||
@ -503,67 +487,49 @@ class Init(object):
|
|||||||
# objects before the load of the userdata happened,
|
# objects before the load of the userdata happened,
|
||||||
# this is expected.
|
# this is expected.
|
||||||
|
|
||||||
def _consume_vendordata(self, frequency=PER_ALWAYS):
|
def _consume_vendordata(self, frequency=PER_INSTANCE):
|
||||||
"""
|
"""
|
||||||
Consume the vendordata and run the part handlers on it
|
Consume the vendordata and run the part handlers on it
|
||||||
"""
|
"""
|
||||||
if not self.datasource.has_vendordata():
|
# User-data should have been consumed first.
|
||||||
LOG.info("datasource did not provide vendor data")
|
# So we merge the other available cloud-configs (everything except
|
||||||
|
# vendor provided), and check whether or not we should consume
|
||||||
|
# vendor data at all. That gives user or system a chance to override.
|
||||||
|
if not self.datasource.get_vendordata_raw():
|
||||||
|
LOG.debug("no vendordata from datasource")
|
||||||
return
|
return
|
||||||
|
|
||||||
# User-data should have been consumed first. If it has, then we can
|
|
||||||
# read it and simply parse it. This means that the datasource can
|
|
||||||
# define if the vendordata can be consumed too....i.e this method
|
|
||||||
# gives us a lot of flexibility.
|
|
||||||
_cc_merger = helpers.ConfigMerger(paths=self._paths,
|
_cc_merger = helpers.ConfigMerger(paths=self._paths,
|
||||||
datasource=self.datasource,
|
datasource=self.datasource,
|
||||||
additional_fns=[],
|
additional_fns=[],
|
||||||
base_cfg=self.cfg,
|
base_cfg=self.cfg,
|
||||||
include_vendor=False)
|
include_vendor=False)
|
||||||
_cc = _cc_merger.cfg
|
vdcfg = _cc_merger.cfg.get('vendor_data', {})
|
||||||
|
|
||||||
if not self.datasource.consume_vendordata():
|
if not isinstance(vdcfg, dict):
|
||||||
if not isinstance(_cc, dict):
|
vdcfg = {'enabled': False}
|
||||||
LOG.info(("userdata does explicitly allow vendordata "
|
LOG.warn("invalid 'vendor_data' setting. resetting to: %s", vdcfg)
|
||||||
"consumption"))
|
|
||||||
|
if not util.is_true(vdcfg.get('enabled')):
|
||||||
|
LOG.debug("vendordata consumption is disabled.")
|
||||||
return
|
return
|
||||||
|
|
||||||
if 'vendor_data' not in _cc:
|
|
||||||
LOG.info(("no 'vendor_data' directive found in the"
|
|
||||||
"conf files. Skipping consumption of vendordata"))
|
|
||||||
return
|
|
||||||
|
|
||||||
# This allows for the datasource to signal explicit conditions when
|
|
||||||
# when the user has opted in to user-data
|
|
||||||
if self.datasource.consume_vendordata():
|
|
||||||
LOG.info(("datasource has indicated that vendordata that user"
|
|
||||||
" opted-in via another channel"))
|
|
||||||
|
|
||||||
vdc = _cc.get('vendor_data')
|
|
||||||
no_handlers = None
|
|
||||||
if isinstance(vdc, dict):
|
|
||||||
enabled = vdc.get('enabled')
|
enabled = vdc.get('enabled')
|
||||||
no_handlers = vdc.get('no_run')
|
no_handlers = vdc.get('disabled_handlers', None)
|
||||||
|
|
||||||
if enabled is None:
|
LOG.debug("vendor data will be consumed. disabled_handlers=%s",
|
||||||
LOG.info("vendordata will not be consumed: user has not opted-in")
|
no_handlers)
|
||||||
return
|
|
||||||
elif util.is_false(enabled):
|
|
||||||
LOG.info("user has requested NO vendordata consumption")
|
|
||||||
return
|
|
||||||
|
|
||||||
LOG.info("vendor data will be consumed")
|
|
||||||
|
|
||||||
# Ensure vendordata source fetched before activation (just incase)
|
# Ensure vendordata source fetched before activation (just incase)
|
||||||
vendor_data_msg = self.datasource.get_vendordata(True)
|
vendor_data_msg = self.datasource.get_vendordata()
|
||||||
|
|
||||||
# This keeps track of all the active handlers, while excluding what the
|
# This keeps track of all the active handlers, while excluding what the
|
||||||
# users doesn't want run, i.e. boot_hook, cloud_config, shell_script
|
# users doesn't want run, i.e. boot_hook, cloud_config, shell_script
|
||||||
c_handlers_list = self._default_vendordata_handlers(
|
c_handlers_list = self._default_vendordata_handlers()
|
||||||
excluded=no_handlers)
|
|
||||||
|
|
||||||
# Run the handlers
|
# Run the handlers
|
||||||
self._do_handlers(vendor_data_msg, c_handlers_list, frequency)
|
self._do_handlers(vendor_data_msg, c_handlers_list, frequency,
|
||||||
|
excluded=no_handlers)
|
||||||
|
|
||||||
def _consume_userdata(self, frequency=PER_INSTANCE):
|
def _consume_userdata(self, frequency=PER_INSTANCE):
|
||||||
"""
|
"""
|
||||||
@ -574,7 +540,7 @@ class Init(object):
|
|||||||
user_data_msg = self.datasource.get_userdata(True)
|
user_data_msg = self.datasource.get_userdata(True)
|
||||||
|
|
||||||
# This keeps track of all the active handlers
|
# This keeps track of all the active handlers
|
||||||
c_handlers_list = self._default_userdata_handlers()
|
c_handlers_list = self._default_handlers()
|
||||||
|
|
||||||
# Run the handlers
|
# Run the handlers
|
||||||
self._do_handlers(user_data_msg, c_handlers_list, frequency)
|
self._do_handlers(user_data_msg, c_handlers_list, frequency)
|
||||||
|
Loading…
Reference in New Issue
Block a user