salt-project

How to automatically add custom grains attributes to minions using SaltStack Reactor?


I want to automatically add grains attributes to a minion when it authenticates or starts. I have added the following configuration to the reactor configuration file:

reactor:
  - 'salt/auth':
    - /srv/salt/reactor/grains_add.sls
  - 'salt/minion/*/start':
    - /srv/salt/reactor/grains_add.sls

The grains_add.sls file contains the following:

add_custom_grains:
  local.grains.setvals:
    - tgt: {{ data['id'] }}
    - arg: 
      - {"code":"2","code_ename":"tt"}

This approach hardcodes the values. I want to set the grains attributes by retrieving the code variable from the minion's pillar data. Based on the official documentation, I tried using an orchestrate runner, and rewrote the grains_add.sls file as follows:

invoke_orchestrate_file:
  runner.state.orchestrate:
    - args:
        - mods: orchestrate.add_granis
        - pillar:
            minion_id: {{ data['id'] }}       

The orchestrate.add_granis file contains the following:

{% set minion_id = salt.pillar.get('minion_id') %}
get_grains:
  local.grains.item:
    - tgt: {{ minion_id }}
    - arg:
      - code

set_grains:
  local.grains.setvals:
    - tgt: {{ minion_id }}
    - arg:
      - {"code":"2","code_ename":"tt"}

At this point, I am not sure how to proceed. It seems that SaltStack does not have a direct method to pass the result of one task to the next task, similar to how Ansible registers variables.

How can I achieve my goal of setting grains attributes by retrieving the code variable from the minion's pillar data? Or is there a better approach to achieve this?


Solution

  • How can I achieve my goal of setting grains attributes by retrieving the code variable from the minion's pillar data?

    This can be done with a simple state:

    code:
      grains.present:
       - value: {{ pillar['code'] }}
    
    code_ename:
      grains.present:
       - value: {{ pillar['code_ename'] }}
    

    You can apply that via a reactor, or just have it be part of the minion's highstate and/or startup_states.

    !! N.B. This stores the grain in /etc/salt/grains, which by default is world-readable. The secret data in your pillar (because that is what pillar is for) will be exposed to all processes on the minion unless you e.g. include this state:

    /etc/salt/grains:
      file.managed:
        - replace: false
        - mode: '0600'
        - require_in:
          - grains: '*'
    

    Or is there a better approach to achieve this?

    If the grain is just the same value as the pillar, there's no point copying it to a grain. Just use the pillar directly.