Search code examples
salt-project

Execution module function similar to 'file.managed'?


I am trying to find an execution module that will allow me to pass a file through the Jinja templating engine and supply the arguments that should be replaced. There exists a file.managed state module that accomplishes this behavior:

my cool state:
  file.managed:
    - source: salt://my/cool/file.xml
    - name: 'C:\Program Files\My dir\file.xml'
    - template: jinja
    - context:
      someVar: 'some value'
      another_var: 12345

However, I cannot find an execution module that can do this. There is file.manage_file but it has a bunch of required arguments that I don't care about: sfn, ret, source, source_sum, user, group, mode, attrs, saltenv, backup -- file.manage_file will fail if you do not provide values for these.

The closest module function I've found is cp.get_template but it doesn't allow you to pass in context or defaults, so I've had to templatize my XML file to read in data from the pillar like so:

{%- from "map.jinja" import my_vars with context %}

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <some-element>{{ my_vars.some-element }}</some-element>
  <another-thing>{{ my_vars.another-thing }}</another-thing>
</root>

This works, but then I can only render my XML with pillar data -- I want to be able to pass in variables when calling my execution module and use those variables to render my XML. Is there any way to accomplish this behavior with an execution module?


Solution

  • I figured this out using a combination of execution modules:

    # Get template file
    templateContent = __salt__['cp.get_file_str'](
       'salt://my/cool/file.xml'
    )
    
    # Render file with Jinja
    renderedContent = __salt__['file.apply_template_on_contents'](
       contents = templateContent,
       template = 'jinja',
       saltenv = 'base',
       defaults = defaults,
       context = context
    )
    
    # Write the rendered file to disk
    __salt__['file.write'](
       '/opt/some/path/on/minion/file.xml',
       renderedContent
    )
    

    Two things to consider:

    file.apply_template_on_contents requires that you supply both the defaults and context args. This actually worked out pretty well for my use-case because I set defaults using values from a pillar that is applied to all minions, and context is the user-supplied overrides.

    cp.get_file_str returns the file contents as a string -- I don't know how this would perform on a very large file, but for smaller configuration files I don't see an issue.