Search code examples
pythonyamljinja2salt-project

How to use a jinja2 variable as an arg in a call to salt function inside a jinja2 statement


Here is what I am doing.

  1. I am looping through pillar key values and assigning to variable shopt_option
  2. If the string 'shopt_' is in the value of the variable shopt_option, it runs a nested if statement
  3. Then inside a jinja2 encapsulated statement I need to set a variable to equal the output of a call to a salt function.
  4. One of the args to that salt functions also needs to be a variable from the loop.
  5. I have tried 2 hours worth of different ways to write this and what I will paste below of course is wrong syntax but helps to illustrate what I want to do as I know when referencing a variable inside a jinja2 statement you do not encapsulate it in double curly braces.
  6. However being an arg inside of parentheses seems to screw up any way of using a jinja2 variable.
  7. When looking below this is the line where it will need fixing, I am also open to other ways to write this as well

    {% set shopt_option_value = salt['pillar.get']('user_management:bash_configurations:global:bashrc:{{ shopt_option }}') %}
    

There is a ticket on stackoverflow where they nest a variable in a variable which come close, but doesnt working when inside a call to a salt function. That stackoverflow url is Python (Jinja2) variable inside a variable

Here is the loop:

{# Loop through all global shopt option key names and set values accordingly #}
{% for shopt_option in salt['pillar.keys']('user_management:bash_configurations:global:bashrc') %}
  {% if 'shopt_' in shopt_option %}
    {% set shopt_option_value = salt['pillar.get']('user_management:bash_configurations:global:bashrc:{{ shopt_option }}') %}
    {% if shopt_option_value == 'True' %}
  shopt -s {{ shopt_option|replace("shopt_","") }}
    {% elif shopt_option_value == 'False' %}
  shopt -u {{ shopt_option|replace("shopt_","") }}
    {% elif shopt_option_value == 'default' %}
      # {{ shopt_option|replace("shopt_","") }} OS Default implied
    {% endif %}
      shopt_option_value is {{ shopt_option_value }} for debugging this
  {% endif %}
{% endfor %}

Here is the pillar yaml data structure snippet:

user_management:
  bash_configurations:
    global:
      bashrc:
        system_reserved_uid: 199
        system_reserved_umask: '077'
        non_system_reserved_umask: '077'
        shopt_autocd: default
        shopt_cdable_vars: default
        shopt_cdspell: False
        shopt_checkhash: default

Solution

  • I found a better way to iterate through the pillars key names and or values.

    Solution:

    {%- for shopt_option_key in pillar['user_management']['bash_configurations']['global']['bashrc'] %}
    

    seems is alternate way to say:

    Original attempt:

    {% for shopt_option in salt['pillar.keys']('user_management:bash_configurations:global:bashrc') %}
    

    However in this way literal values are taken with single quotes and without the quotes in a jinja2 statement as you would expect it references the value of the jinja2 variable.

    There were many other ways to solve this, I was looking at, this was just one of the way and maybe not the most elegant, so I would consider this a good solution (not the worst I found and not the best).

    Here was the final solution:

    {#- Loop through all global shopt option key names and set values accordingly #}
    {%- for shopt_option_key in pillar['user_management']['bash_configurations']['global']['bashrc'] %}
      {%- set shopt_option_value = pillar['user_management']['bash_configurations']['global']['bashrc'][shopt_option_key] %}
      {%- if 'shopt_' in shopt_option_key %}
        {%- if shopt_option_value %}
          shopt -s {{ shopt_option_key|replace("shopt_","") }}
        {%- elif shopt_option_value == False %}
          shopt -u {{ shopt_option_key|replace("shopt_","") }}
        {%- elif shopt_option_value == 'default' %}
          # {{ shopt_option_key|replace("shopt_","") }} OS Default implied
        {%- endif %}
      {%- endif %}
    {%- endfor %}
    

    Some additional notes of improvement here:

    1. The minus symbol here, {%- trimmed the leading white space so I would not have blank lines in the file this creates
    2. In jinja2 if the value of the key was set to a Boolean, you can not use quotes around the 'True' or 'False' comparison, because it will treat the compared value as a string, I had to remove the quotes to treat it as a Boolean