I like this. I had a few comments inline. One thing i worry about is bytes versus string. It seems like our binary-safe json handler has the effect that sometimes a value is a string and sometimes it is bytes depending on the content that was in it.
>From a consumer perspective, that is annoying. I'd rather know that a given path is *always* bytes or *always* a string. Otherwise you get code like in cloud-init's decode_binary() that decodes to string if not a string. I think it just kind of results in sloppy code. I'm bit by having lots of places in cloud-init where we accidently got by without failure in python2 and the most of the time get by in python3. thoughts? Diff comments: > diff --git a/cloudinit/handlers/jinja_template.py > b/cloudinit/handlers/jinja_template.py > new file mode 100644 > index 0000000..d29a107 > --- /dev/null > +++ b/cloudinit/handlers/jinja_template.py > @@ -0,0 +1,86 @@ > +# Copyright (C) 2012 Canonical Ltd. > +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. > +# Copyright (C) 2012 Yahoo! Inc. new file, drop the copied Copyright and Author, just go with the shortest header possible. > +# > +# Author: Scott Moser <[email protected]> > +# Author: Juerg Haefliger <[email protected]> > +# Author: Joshua Harlow <[email protected]> > +# > +# This file is part of cloud-init. See LICENSE file for license information. > + > +import os > + > +from cloudinit import handlers > +from cloudinit import log as logging > +from cloudinit.sources import INSTANCE_JSON_FILE > +from cloudinit.templater import render_string > +from cloudinit.util import b64d, load_file, load_json > + > +from cloudinit.settings import PER_ALWAYS > + > +LOG = logging.getLogger(__name__) > + > + > +class JinjaTemplatePartHandler(handlers.Handler): > + > + prefixes = ['## template: jinja'] > + > + def __init__(self, paths, **_kwargs): > + handlers.Handler.__init__(self, PER_ALWAYS, version=3) > + self.paths = paths > + self.sub_handlers = {} > + for handler in _kwargs.get('sub_handlers', []): > + for ctype in handler.list_types(): > + self.sub_handlers[ctype] = handler > + > + def handle_part(self, data, ctype, filename, payload, frequency, > headers): > + if ctype in handlers.CONTENT_SIGNALS: > + return > + instance_data = {} > + json_file_path = os.path.join(self.paths.run_dir, INSTANCE_JSON_FILE) > + if os.path.exists(json_file_path): > + instance_data = load_json(load_file(json_file_path)) > + else: > + LOG.warning( > + 'Instance data not yet present at > {0}'.format(json_file_path)) how real of a case is this? I dont thin it should happen. or will it *always* happen? > + instance_jinja_vars = convert_jinja_instance_data(instance_data) > + rendered_payload = render_string(payload, instance_jinja_vars) > + rendered_payload = rendered_payload.replace( > + self.prefixes[0] + '\n', '') > + subtype = handlers.type_from_starts_with(rendered_payload) > + sub_handler = self.sub_handlers.get(subtype) > + if not sub_handler: > + LOG.warning( > + 'Ignoring jinja template for {0}. Could not find supported' > + ' sub-handler for type {1}'.format( > + filename, subtype)) > + return > + if sub_handler.handler_version == 3: > + sub_handler.handle_part( > + data, ctype, filename, rendered_payload, frequency, headers) > + elif sub_handler.handler_version == 2: > + sub_handler.handle_part( > + data, ctype, filename, rendered_payload, frequency) > + > + > +def convert_jinja_instance_data(d, prefix='', sep='/', decode_paths=()): > + """Process instance-data.json dict for use in jinja templates. > + i think we might as well just store the '_' versions of keys. no? > + Replace hyphens with underscores for jinja templates and decode any > + base64-encoded-keys. > + """ > + result = {} > + for key, value in d.items(): > + key_path = '{0}{1}{2}'.format(prefix, sep, key) if prefix else key > + if key_path in decode_paths: > + value = b64d(value) > + key = key.replace('-', '_') > + if isinstance(value, dict): > + result[key] = convert_jinja_instance_data( > + value, key_path, sep=sep, decode_paths=decode_paths) > + else: > + result[key] = value > + return result > + > + > +# vi: ts=4 expandtab -- https://code.launchpad.net/~chad.smith/cloud-init/+git/cloud-init/+merge/334030 Your team cloud-init commiters is requested to review the proposed merge of ~chad.smith/cloud-init:parameterize-cloud-config into cloud-init:master. _______________________________________________ Mailing list: https://launchpad.net/~cloud-init-dev Post to : [email protected] Unsubscribe : https://launchpad.net/~cloud-init-dev More help : https://help.launchpad.net/ListHelp

