Custom Dynamic Inventory Plugin - How best to handle configuration variables known only at runtime?

I could use some advice on how to deal with a custom dynamic inventory plugin whose configuration relies on runtime variables.

I am writing a dynamic inventory plugin for Zerotier which requires an API token. My project has 3 different environments - Dev, Stage, Prod - with each one having its own API token. As a consequence one of my configuration variables would be “token” and at runtime it would be replaced by the token associated with the runtime environment.

How best to manage this. A few ideas I have include:

  • Looking up a non-global inventory variable that already exists. Problems here include uncertainty whether that inventory variable and its value are even available and how to load an inventory variable in the plugin.

  • Having separate inventory configs - one per environment. Works but is not very DRY.

  • Embedding the token into an environment variable by processing a known environment variable - ZEROTIER_TOKEN within the plugin. Works but is a bit difficult to document since it’s not really part of the configuration, and I’m not really fond of embedding sensitive data in an environment variable.

Any recommendations would be most welcome.

  • 2 Having separate inventory configs - one per environment. Works but is not very DRY.
  • 3 Embedding the token into an environment variable by processing a known environment variable - ZEROTIER_TOKEN within the plugin. Works but is a bit difficult to document since it’s not really part of the configuration, and I’m not really fond of embedding sensitive data in an environment variable.

points 2 and 3 are super common… for example in Automation controller many credentials are stored as environment variables and this is protected by only being accessible to particular users on the system. Not sure I understand the DRY comment for point 2.

How are you running this automation? What is your CI system here? AWX? Github Actions? AAP?

1 Like

Hi Sean!

Thanks for the info - it’s very helpful in getting a sense of how the community approaches this problem. Your observation that embedding the token in an environment variable is standard practice alleviates my concern that in doing so, I was being stupid. :slight_smile:

Let me answer your questions and then provide some discoveries I made yesterday.

With respect to CI system, none presently. This is just a small home project allowing me to explore Ansible and putting together a personal service mesh.

DRYness is the fact that I would have to maintain 3 different inventory configurations - one for each environment - which would be identical except for the token. At this point in time there are no other configuration options that might differ among environments.

With respect to new findings, here’s what I found yesterday:

  • It doesn’t appear that I can access any inventory variables. When the dynamic script is run, no variables seem to be defined.

  • I can use jinja templates and lookup plugins though!
    I found this when reviewing the digitalocean inventory plugin documentation and was able to get it to work. Basically what I did was the following:

  • Set an environment variable - AWT_DEVOPS_ENV - which indicates the current environment. This was already in place.

  • Create a yaml file with a known location and name (these could be parameterized as plugin options) containing a dictionary keyed by environment with the value the API token like this:

---
zerotier_tokens:
  Dev:
     central: abc123
  • Assign the following value to a configuration option for the token:

test: ‘{{ (lookup(“ansible.builtin.unvault”, “credentials/zerotier_tokens.yml”) | ansible.builtin.from_yaml).zerotier_tokens[lookup(“ansible.builtin.env”, “AWT_DEVOPS_ENV”)].central }}’

  • In the inventory plugin implementation as part call the following:
token = self.get_option(option)
token = self.templar.template(token)

As far as I can tell the self.templar.template call is ‘safe’ The correct result is returned whether the value provided is a jinja statement or just a string.

There is another method which I need to explore. In the digitalocean inventory the self.templar.template call is preceded by self.templar.available_variables = {}

Hope this makes sense and is useful to someone else. I’ve not located any documentation on this.

I’ll continue playing with this, and if it works as expected I will summarize in a follow-up and mark it solved.

  • steve

Hope I got the formatting right. Doesn’t appear to be a preview option.

Preview is to the right of the compose pane. There’s “stuff” in front of it that you can click on the upper-right of to make it go away.
The “preview as you type” is really nice, IMO.

1 Like

Hitting ESC works too for removing those info screens, for those who want keyboard shortcuts. Also if the formatting isn’t right, you have a grace period to edit your post.

This is something I want to standarize in core, so the plugin author can document which fields are templatable
https://github.com/ansible/ansible/pull/79244

3 Likes