Search code examples
pythonpython-3.8salt-project

Pillar Data Doesn't Get Updated within Custom Execution Module


I am writing a custom Salt execution module that runs some basic tests against state files that contain a YAML file with different tests and parameters. The module will read these YAML files, and set grains accordingly to the testing requirement and then run a state.show_sls against the state using the grain data provided. This works well until I need something from pillar. The grains get set, however the pillar data never gets updated according to the new grains set. We also run a masterless setup, so the minion does all the work.

# pillar/top.sls
base:
  'G@roles:bind and G@location:MyTown':
    - match: compound
    - bind.MyTown

Within my execution module I set:

#_/modules/my_execution_module.py
def all():
    tests = _get_tests()
    for test in tests:
        __grains__.update(test['grains'])
        __pillar__.update(__grains__)
        print(__salt__['grains.get']('roles'))      # Comes back with expected data.
        print(__salt__['grains.get']('location'))   # Comes back with expected data.
        print(__salt__['pillar.get']('bind_conf'))  # This comes back as blank.
        __salt__['state.show_sls'](test['state'])

Running the same test, but running all the salt commands individually to set the grains and print the grain/pillar information works as expected. It's only within this custom module that, while it sets the grains, does not update the pillar information.

salt-call.bat --versions
Salt Version:
          Salt: 3004.1

Dependency Versions:
          cffi: 1.14.6
      cherrypy: 18.6.1
      dateutil: 2.8.1
     docker-py: Not Installed
         gitdb: 4.0.7
     gitpython: 3.1.18
        Jinja2: 2.10.1
       libgit2: Not Installed
      M2Crypto: Not Installed
          Mako: 1.1.4
       msgpack: 0.6.2
  msgpack-pure: Not Installed
  mysql-python: Not Installed
     pycparser: 2.20
      pycrypto: Not Installed
  pycryptodome: 3.10.1
        pygit2: Not Installed
        Python: 3.8.8 (tags/v3.8.8:024d805, Feb 19 2021, 13:18:16) [MSC v.1928 64 bit (AMD64)]
  python-gnupg: 0.4.7
        PyYAML: 5.4.1
         PyZMQ: 19.0.0
         smmap: 4.0.0
       timelib: 0.2.4
       Tornado: 4.5.3
           ZMQ: 4.3.2

System Versions:
          dist:
        locale: cp1252
       machine: AMD64
       release: 10
        system: Windows
       version: 10 10.0.22621 SP0 Multiprocessor Free

Solution

  • Both grains and pillar are cached and the refreshes are asynchronous.

    Running this after changing the grains should hopefully work:

    __salt__["saltutil.refresh_grains"](refresh_pillar=False)
    __salt__["saltutil.refresh_pillar"](wait=True)
    

    Trying to add the grains into the pillar (__pillar__.update(__grains__)) isn't going to work though. It will always be replaced with the latest compiled pillar.

    Further information: https://docs.saltproject.io/en/3005/topics/pillar/#in-memory-pillar-data-vs-on-demand-pillar-data


    It turns out that in a masterless setup the refresh never completes, because there's no master to do it.

    A hack like this works, but you'll need a bit more in case the new pillar has some keys removed.

    __pillar__.update(__salt__["pillar.items"]())
    

    Consider whether you actually need pillar in a masterless setup, or whether this could be a runner or orchestration instead of an execution module.