Include jinja template files in module utils

I have a collection that relies on a graphql API. The queries are pretty unpleasant, and to make them a bit more manageable I store them as jinja templates. However, I struggled getting ansible to include/find the jinja text files when I executed my modules. So now all of the jinja templates are stored in static python methods, which is not great.

I am wondering if someone has a better solution, or can help me simplify my current approach. I like that this has been extensible (there is a lot of abstraction/subclassing), but managing the jinja through a python lens makes linting and variable context more difficult.

Here is a (much abbreviated) example of my setup. In short, my module imports an API class in module_utils, which imports object classes in module_utils, which import jinja templates stored in python classes in module_utils.

# plugins/modules/my-module.py
.....
from ansible_collections.my.collection.plugins.module_utils.api import (
    SomeApi,
)
.....
# plugins/module_utils/api.py
.....
from ansible_collections.my.collection.plugins.module_utils.objects import (
    Event,
)

class SomeApi():
    .....
    def get_events_for_guid(
        self, guid: str,
    ) -> Generator[Event, None, None]:
        query_template = self.jinja_env.from_string(Event.J2_SEARCH_QUERY)
        query = query_template.render(
            guid=guid
        )
        r = self.run_query(query=query)
        .....
# plugins/module_utils/objects.py
.....
from ansible_collections.my.collection.plugins.module_utils.query_templates import (
    EventTemplates,
    ChangeEventTemplates,
)


class Event(ObjectBase):
    J2_SEARCH_QUERY = EventTemplates.j2_get_from_search()
    J2_CREATE_QUERY = EventTemplates.j2_create()

class ChangeEvent(Event):
    J2_CREATE_QUERY = ChangeEventTemplates.j2_create()

    def __init__():
    .....
# plugins/module_utils/query_templates.py
class EventTemplates:
    def __init__(self):
        pass

    @staticmethod
    def j2_get_from_search():
        return """{
            mutation {
                entity(guid: "{{ entity_guid }}") {
                    .....
                 }
            }
        }"""
.....

There are several reasons against, this.

First, modules are designed to execute on the target system, which might not have Jinja installed, it is only required on the controller.

Also, modules only get the minimal data they need to execute, they do NOT get access to variables, only values explicitly passed to them. This is done both for security and efficiency, you do not want to pass the whole inventory + current variables to a remote machine.

Do you have another recommendation?

I can just make Jinja a requirement on the remote. The collection interacts with an API so it’s would likely be run on the controller anyway…

I think your misunderstanding the variable context I am talking about. I am not having trouble passing variables from the user/Ansible context to Jinja. I am having trouble passing more complex python data/variables into the Jinja templates. The templates can be nested (one one static method uses another static method to complete a template), which is where things get hairy

if you are running templating on the controller, just use an action plugin, this is how the built in template action works.

As to your trouble passing complex data to the templates, I’m unsure how that is related to Ansible itself.

1 Like

Oh that’s a great suggestion. I think that would resolve a lot of my issues, maybe all of them. Thanks!