def template( state, host, template_filename, remote_filename, user=None, group=None, mode=None, **data ): ''' Generate a template and write it to the remote system. + template_filename: local template filename + remote_filename: remote filename + user: user to own the files + group: group to own the files + mode: permissions of the files ''' if state.deploy_dir: template_filename = path.join(state.deploy_dir, template_filename) # Load the template into memory template = get_template(template_filename) # Ensure host is always available inside templates data['host'] = host data['inventory'] = state.inventory # Render and make file-like it's output try: output = template.render(data) except UndefinedError as e: _, _, trace = sys.exc_info() # Jump through to the *second last* traceback, which contains the line number # of the error within the in-memory Template object while trace.tb_next: if trace.tb_next.tb_next: trace = trace.tb_next else: break line_number = trace.tb_frame.f_lineno # Quickly read the line in question and one above/below for nicer debugging template_lines = open(template_filename, 'r').readlines() template_lines = [line.strip() for line in template_lines] relevant_lines = template_lines[max(line_number - 2, 0):line_number + 1] raise OperationError('Error in template: {0} (L{1}): {2}\n...\n{3}\n...'.format( template_filename, line_number, e, '\n'.join(relevant_lines), )) output_file = six.StringIO(output) # Set the name attribute for nicer debugging output_file.name = template_filename # Pass to the put function yield put( state, host, output_file, remote_filename, user=user, group=group, mode=mode, add_deploy_dir=False, )
def template(src, dest, user=None, group=None, mode=None, create_remote_dir=True, state=None, host=None, **data): ''' Generate a template using jinja2 and write it to the remote system. + src: local template filename + dest: remote filename + user: user to own the files + group: group to own the files + mode: permissions of the files + create_remote_dir: create the remote directory if it doesn't exist ``create_remote_dir``: If the remote directory does not exist it will be created using the same user & group as passed to ``files.put``. The mode will *not* be copied over, if this is required call ``files.directory`` separately. Notes: Common convention is to store templates in a "templates" directory and have a filename suffix with '.j2' (for jinja2). For information on the template syntax, see `the jinja2 docs <https://jinja.palletsprojects.com>`_. Examples: .. code:: python files.template( name='Create a templated file', src='templates/somefile.conf.j2', dest='/etc/somefile.conf', ) files.template( name='Create service file', src='templates/myweb.service.j2', dest='/etc/systemd/system/myweb.service', mode='755', user='******', group='root', ) # Example showing how to pass python variable to template file. # The .j2 file can use `{{ foo_variable }}` to be interpolated. foo_variable = 'This is some foo variable contents' files.template( name='Create a templated file', src='templates/foo.j2', dest='/tmp/foo', foo_variable=foo_variable, ) ''' dest = escape_unix_path(dest) if state.deploy_dir: src = os_path.join(state.deploy_dir, src) # Ensure host is always available inside templates data['host'] = host data['inventory'] = state.inventory # Render and make file-like it's output try: output = get_template(src).render(data) except (TemplateSyntaxError, UndefinedError) as e: _, _, trace = sys.exc_info() # Jump through to the *second last* traceback, which contains the line number # of the error within the in-memory Template object while trace.tb_next: if trace.tb_next.tb_next: trace = trace.tb_next else: # pragma: no cover break line_number = trace.tb_frame.f_lineno # Quickly read the line in question and one above/below for nicer debugging with open(src, 'r') as f: template_lines = f.readlines() template_lines = [line.strip() for line in template_lines] relevant_lines = template_lines[max(line_number - 2, 0):line_number + 1] raise OperationError( 'Error in template: {0} (L{1}): {2}\n...\n{3}\n...'.format( src, line_number, e, '\n'.join(relevant_lines), )) output_file = six.StringIO(output) # Set the template attribute for nicer debugging output_file.template = src # Pass to the put function yield put( output_file, dest, user=user, group=group, mode=mode, add_deploy_dir=False, create_remote_dir=create_remote_dir, state=state, host=host, )
def template(src, dest, user=None, group=None, mode=None, create_remote_dir=True, **data): ''' Generate a template using jinja2 and write it to the remote system. + src: template filename or IO-like object + dest: remote filename + user: user to own the files + group: group to own the files + mode: permissions of the files + create_remote_dir: create the remote directory if it doesn't exist ``create_remote_dir``: If the remote directory does not exist it will be created using the same user & group as passed to ``files.put``. The mode will *not* be copied over, if this is required call ``files.directory`` separately. Notes: Common convention is to store templates in a "templates" directory and have a filename suffix with '.j2' (for jinja2). For information on the template syntax, see `the jinja2 docs <https://jinja.palletsprojects.com>`_. **Examples:** .. code:: python files.template( name="Create a templated file", src="templates/somefile.conf.j2", dest="/etc/somefile.conf", ) files.template( name="Create service file", src="templates/myweb.service.j2", dest="/etc/systemd/system/myweb.service", mode="755", user="******", group="root", ) # Example showing how to pass python variable to template file. You can also # use dicts and lists. The .j2 file can use `{{ foo_variable }}` to be interpolated. foo_variable = 'This is some foo variable contents' foo_dict = { "str1": "This is string 1", "str2": "This is string 2" } foo_list = [ "entry 1", "entry 2" ] template = StringIO(""" name: "{{ foo_variable }}" dict_contents: str1: "{{ foo_dict.str1 }}" str2: "{{ foo_dict.str2 }}" list_contents: {% for entry in foo_list %} - "{{ entry }}" {% endfor %} """) files.template( name="Create a templated file", src=template, dest="/tmp/foo.yml", foo_variable=foo_variable, foo_dict=foo_dict, foo_list=foo_list ) ''' if not hasattr(src, "read") and state.cwd: src = os.path.join(state.cwd, src) # Ensure host/state/inventory are available inside templates (if not set) data.setdefault("host", host) data.setdefault("state", state) data.setdefault("inventory", state.inventory) data.setdefault("facts", pyinfra.facts) # Render and make file-like it's output try: output = get_template(src).render(data) except (TemplateRuntimeError, TemplateSyntaxError, UndefinedError) as e: trace_frames = traceback.extract_tb(sys.exc_info()[2]) trace_frames = [ frame for frame in trace_frames if frame[2] in ("template", "<module>", "top-level template code") ] # thank you https://github.com/saltstack/salt/blob/master/salt/utils/templates.py line_number = trace_frames[-1][1] # Quickly read the line in question and one above/below for nicer debugging with open(src, "r") as f: template_lines = f.readlines() template_lines = [line.strip() for line in template_lines] relevant_lines = template_lines[max(line_number - 2, 0):line_number + 1] raise OperationError( "Error in template: {0} (L{1}): {2}\n...\n{3}\n...".format( src, line_number, e, "\n".join(relevant_lines), ), ) output_file = StringIO(output) # Set the template attribute for nicer debugging output_file.template = src # Pass to the put function yield from put( output_file, dest, user=user, group=group, mode=mode, add_deploy_dir=False, create_remote_dir=create_remote_dir, )
def template( src, dest, user=None, group=None, mode=None, create_remote_dir=True, state=None, host=None, **data ): ''' Generate a template using jinja2 and write it to the remote system. + src: local template filename + dest: remote filename + user: user to own the files + group: group to own the files + mode: permissions of the files + create_remote_dir: create the remote directory if it doesn't exist ``create_remote_dir``: If the remote directory does not exist it will be created using the same user & group as passed to ``files.put``. The mode will *not* be copied over, if this is required call ``files.directory`` separately. Notes: Common convention is to store templates in a "templates" directory and have a filename suffix with '.j2' (for jinja2). For information on the template syntax, see `the jinja2 docs <https://jinja.palletsprojects.com>`_. Examples: .. code:: python files.template( name='Create a templated file', src='templates/somefile.conf.j2', dest='/etc/somefile.conf', ) files.template( name='Create service file', src='templates/myweb.service.j2', dest='/etc/systemd/system/myweb.service', mode='755', user='******', group='root', ) # Example showing how to pass python variable to template file. # The .j2 file can use `{{ foo_variable }}` to be interpolated. foo_variable = 'This is some foo variable contents' files.template( name='Create a templated file', src='templates/foo.j2', dest='/tmp/foo', foo_variable=foo_variable, ) ''' dest = escape_unix_path(dest) if state.deploy_dir: src = os_path.join(state.deploy_dir, src) # Ensure host/state/inventory are available inside templates (if not set) data.setdefault('host', host) data.setdefault('state', state) data.setdefault('inventory', state.inventory) # Render and make file-like it's output try: output = get_template(src).render(data) except (TemplateRuntimeError, TemplateSyntaxError, UndefinedError) as e: trace_frames = traceback.extract_tb(sys.exc_info()[2]) trace_frames = [ frame for frame in trace_frames if frame[2] in ('template', '<module>', 'top-level template code') ] # thank you https://github.com/saltstack/salt/blob/master/salt/utils/templates.py line_number = trace_frames[-1][1] # Quickly read the line in question and one above/below for nicer debugging with open(src, 'r') as f: template_lines = f.readlines() template_lines = [line.strip() for line in template_lines] relevant_lines = template_lines[max(line_number - 2, 0):line_number + 1] raise OperationError('Error in template: {0} (L{1}): {2}\n...\n{3}\n...'.format( src, line_number, e, '\n'.join(relevant_lines), )) output_file = six.StringIO(output) # Set the template attribute for nicer debugging output_file.template = src # Pass to the put function yield put( output_file, dest, user=user, group=group, mode=mode, add_deploy_dir=False, create_remote_dir=create_remote_dir, state=state, host=host, )
config=VaultAutoAuthAWS( role= f"concourse-{concourse_config._node_type}" # noqa: WPS437 ), ), sinks=[ VaultAutoAuthSink(type="file", config=VaultAutoAuthFileSink()) ], ), template=[ partial_func() for partial_func in vault_template_map[node_type] ] + [ VaultTemplate( contents=get_template( "{% for env_var, env_value in concourse_env.items() -%}\n" "{{ env_var }}={{ env_value }}\n{% endfor -%}", is_string=True, ).render(concourse_env=concourse_config.concourse_env()), destination=concourse_base_config.env_file_path, ), ], )), Consul(version=VERSIONS["consul"], configuration=consul_configuration), ] install_hashicorp_products(hashicorp_products) # Manage services if host.fact.has_systemd: register_concourse_service(concourse_config, restart=concourse_install_changed or concourse_config_changed)