jinja with grains

132 views
Skip to first unread message

brad.v...@gmail.com

unread,
Nov 17, 2022, 8:21:10 AM11/17/22
to Salt-users
We have a grain that shows the installed GPUs on a server.  On one with just the onboard GPU, it looks like:

local:
    ---------------
    gpus:
             |_
               --------------
               model:
                        MGA G200eH3
                vendor:
                        matrox

On a server with added GPUs, it looks like:

local:
    ---------------
    gpus:
             |_
               --------------
               model:
                        MGA G200eH3
                vendor:
                        matrox
             |_
               --------------
               model:
                        GP102GL [Tesla P40]
                vendor:
                        nvidia
             |_
               --------------
               model:
                        GP102GL [Tesla P40]
                vendor:
                        nvidia

I'm trying to test for servers with an Nvidia GPU.

I have so far:

{% if salt['grains.get']('gpus:vendor') == 'nvidia' %}
{%- do salt.log.error('This server has an Nvidia GPU') -%}
{% else %}
{%- do salt.log.error('No GPU on this server') -%}
{% endif %}

and I get the 'No GPU on this server' whether or not there is an Nvidia GPU.  So, I'm obviously doing something wrong.  Any ideas?

brad.v...@gmail.com

unread,
Nov 17, 2022, 10:29:01 AM11/17/22
to Salt-users
In the grain display above, what does the |_ indicate?  We have a similar grain lvm which displays as:

local:
     ---------------
     lvm:
           ---------------
          vg_nvme0:
                - lv_nvme0
          vg_sys:
               - lv_audit
               - lv_data
               - lv_home
               - lv_log
               - lv_root
               - lv_tmp
              - lv_var

and we have a state that correctly identifies  when lv_nvme0 exists within vg_nvme0.  I tried to adopt that syntax to the GPUs, but it does not work.  I think the display of the grains is a hint, but I'm not sure what the '|_' indicates when displaying the gpus grains.  Does anyone know?  Thanks!

sayf.eddi...@gmail.com

unread,
Nov 17, 2022, 10:37:44 AM11/17/22
to Salt-users
Hello, you have access to grains directly in the jinja template throught the variable `grains`. notice that grains.gpu is a list of objects
try
{% for gpu in grains.gpu %}
  {% if gpu.vendor == 'nvidia' %}
    {%- do salt.log.error('This server has an Nvidia GPU') -%}
  {% else %}
    {%- do salt.log.error('No GPU on this server') -%}
{% endif %}
{% endfor %}

sayf.eddi...@gmail.com

unread,
Nov 17, 2022, 10:38:30 AM11/17/22
to Salt-users
+ {% for gpu in grains.gpus %}
-  {% for gpu in grains.gpu %}

brad.v...@gmail.com

unread,
Nov 17, 2022, 11:33:14 AM11/17/22
to Salt-users
That works!  I have:

{% for gpu in grains.gpus %}
{% if gpu.vendor == 'nvidia' %}
{%- do salt.log.error('This server has an Nvidia GPU') -%}
{% else %}
{%- do salt.log.error('No GPU on this server') -%}
{% endif %}
{% endfor %}

which prints out:

[ERROR  ] No GPU on this server
[ERROR  ] This server has an Nvidia GPU
[ERROR  ] This server has an Nvidia GPU

Since it hits the matrox GPU first, then the two Nvidia GPUs.  Now, I just need to figure out how to eliminate the "extra" tests.

Wait, I think I just found a simpler method.  I see we have a grain, num_gpus.  I just got on all of our salt masters and displayed that grain on every server.  They all have either 1 or 3.  So, I just need to test that grain and see if it is greater than 1!  I'll give that a shot.

Thanks!

brad.v...@gmail.com

unread,
Nov 17, 2022, 12:05:34 PM11/17/22
to Salt-users
I have it working with:

{% if grains['num_gpus'] > 1 %}

{%- do salt.log.error('This server has an Nvidia GPU') -%}
{% else %}
{%- do salt.log.error('No GPU on this server') -%}
{% endif %}

Now, the reason I'm trying to determine this is for servers with the Nvidia GPUs, I want to make sure the kernel-devel versions of the installed kernel packages are also installed.  On those without an Nvidia GPU, I want to remove the kernel-devel rpms.  First, we have the number of kernels installed limited to two.  I know from a command line I can run:

# This will install the devel kernel of the running kernel:
yum install "kernel-devel-uname-r == $(uname -r)"
#
# This will install the devel kernel of the non-running kernel:
yum install "kernel-devel-uname-r == $(salt-call kernelpkg.list_installed | grep -v 'local:' | head -1 | awk '{ print $2 }').x86_64"

I just need to figure out how to translate that into salt state files.  I guess my first step is get a list of installed kernels and see if there is a corresponding installed kernel-devel rpm.

brad.v...@gmail.com

unread,
Nov 18, 2022, 8:20:32 AM11/18/22
to Salt-users
I have it all working with doing the kernel-devel installs/removes:

{% set KERN = salt.pkg.version('kernel') %}
{% set DEVEL = salt.pkg.version('kernel-devel') %}

{% if grains['num_gpus'] > 1 %}
{%- do salt.log.error('This server has an Nvidia GPU') -%}
{% if KERN == DEVEL %}
{%- do salt.log.error('The devel packages to match the installed kernels are already installed.') -%}

print-kernel-info:
  cmd.run:
    - name: echo "kernel = {{ KREN }} - kernel-devel = {{ DEVEL }}"
   
{% else %}
{%- do salt.log.error('The devel packages do not match the installed kernels.') -%}
{% set SPLT1,SPLT2 = KERN.split(',') %}
{% if DEVEL == SPLT1 %}
{%- do salt.log.error('Missing the SPLT2 kernel-devel') -%}
 
kernel-devel2:
  pkg.installed:
    - name: kernel-devel
    - version: {{ SPLT2 }}

{% else %}

kernel-devel1:
  pkg.installed:
    - name: kernel-devel
    - version: {{ SPLT1 }}

{% endif %}
{% endif %}

{% else %}
{%- do salt.log.error('No GPU on this server') -%}
{% if DEVEL is defined %}

remove-devel-kernel:
  pkg.removed:
    - name: kernel-devel

{% endif %}
{% endif %}

thanks to everyone for their help!

Andreas Thienemann

unread,
Nov 18, 2022, 11:18:27 AM11/18/22
to salt-...@googlegroups.com
First thing you are not handling is that gpus is a list and not a dict.
You need salt['grains.get']('gpus') | first or similar to get a value you can then lookup the vendor for.

The perfect jinja filter however is map() if you want to do operate on list members.


What also helps in your situation is to write things step by step and send them through the slsutil.renderer module call:

Some example code that would illustrate what you need to do:

---
{% set data = {
    'gpus': [
      {'model': 'MGA G200eH3', 'vendor': 'matrox'},
      {'model': 'GP102GL [Tesla P40]', 'vendor': 'nvidia'},
      {'model': 'GP102GL [Tesla P40]', 'vendor': 'nvidia'},
    ]
  }
%}

simulated_grains:
  {{ data | tojson }}

mapped_vendors: {{ data.gpus | map(attribute="vendor") | join(', ') }}

{% if "nvidia" in data.gpus | map(attribute="vendor") %}
nvidia_found: true
{% else %}
nvidia_found: false
{% endif %}

If you send that through slsutil.renderer, you get some nifty output:

# salt-call slsutil.renderer /tmp/test.sls
local:
    ----------
    simulated_grains:
        ----------
        gpus:
            |_
              ----------
              model:
                  MGA G200eH3
              vendor:
                  matrox
            |_
              ----------
              model:
                  GP102GL [Tesla P40]
              vendor:
                  nvidia
            |_
              ----------
              model:
                  GP102GL [Tesla P40]
              vendor:
                  nvidia
    mapped_vendors:
        matrox, nvidia, nvidia
    nvidia_found:
        True

You can adapt that accordingly to your requirements.

Cheers,
 Andreas


--
You received this message because you are subscribed to the Google Groups "Salt-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to salt-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/salt-users/77b0b921-4fd1-4476-8e35-196a6969fb8dn%40googlegroups.com.

Raf Czlonka

unread,
Nov 18, 2022, 11:18:27 AM11/18/22
to salt-...@googlegroups.com, brad.v...@gmail.com
Hi Brad,

I hadn't noticed this issue until now. Thanks for bringing it up!

This is very interesting - the above code works on some of my machine
but not on others.

# salt-call grains.item gpus
local:
----------
gpus:
|_
----------
model:
G200eR2
vendor:
matrox
|_
----------
model:
GK110GL [Tesla K20m]
vendor:
nvidia

But:

# salt-call grains.item gpus:vendor
local:
----------
gpus:vendor:
matrox

On other machines with mix of GPUs, I get 'nvidia' only instead of
'matrox' as per above.

This seems like a bug to me.

Regards,

Raf

Raf Czlonka

unread,
Nov 18, 2022, 11:18:27 AM11/18/22
to salt-...@googlegroups.com, brad.v...@gmail.com
On Thu, Nov 17, 2022 at 02:59:07PM GMT, Raf Czlonka wrote:
>
> This seems like a bug to me.

Given that I rely on this daily it, I've reported it as such[0].

Please feel free to provide additional information in the comments.

Thanks again for highlighting this issue, Brad!

[0] https://github.com/saltstack/salt/issues/63079

Regards,

Raf

brad.v...@gmail.com

unread,
Nov 18, 2022, 11:34:32 AM11/18/22
to Salt-users
Thanks!  I will review those!  always need to learn!  :)

Dirk Heinrichs

unread,
Nov 19, 2022, 6:54:12 AM11/19/22
to salt-...@googlegroups.com
Raf Czlonka:

> {% if salt['grains.get']('gpus:vendor') == 'nvidia' %}

gpus in your example is an array. You're missing an index here, or some
kind of filter.

HTH...

    Dirk

--
Dirk Heinrichs <dirk.he...@altum.de>
Matrix-Adresse: @heini:chat.altum.de
GPG Public Key: 80F1540E03A3968F3D79C382853C32C427B48049
Privacy Handbuch: https://www.privacy-handbuch.de

OpenPGP_signature

Dirk Heinrichs

unread,
Nov 19, 2022, 7:12:21 AM11/19/22
to salt-...@googlegroups.com
brad.v...@gmail.com:

> and I get the 'No GPU on this server' whether or not there is an
> Nvidia GPU.  So, I'm obviously doing something wrong.  Any ideas?

Yes. gpus is an array, so you'll need an index or some kind of filter,
like map: https://jinja.palletsprojects.com/en/2.11.x/templates/#map
OpenPGP_signature
Reply all
Reply to author
Forward
0 new messages