Salt Resources: a 10-minute walk-through#

New in version 3008.0.

This tutorial takes the bundled dummy resource type from "what is this thing?" to a working state.apply against three dummy resources, using nothing but a single masterless minion config. By the end you'll have exercised every part of the framework: pillar declaration, registration, targeting, per-resource execution, and merge-mode state apply.

Why the dummy type?#

The dummy resource is a self-contained, filesystem-backed implementation that lives in salt.resources.dummy. It needs no external services, no SSH targets, no API tokens. It is the resource analogue of the salt.proxy.dummy proxy module — built so you can exercise the framework end-to-end without managing anything real.

Setup#

We'll run the whole thing with salt-call --local (masterless). One config file, one pillar file. Adjust paths to taste.

/etc/salt/minion.d/tutorial.conf:

file_client: local
file_roots:
  base:
    - /srv/salt
pillar_roots:
  base:
    - /srv/pillar

/srv/pillar/top.sls:

base:
  '*':
    - resources

/srv/pillar/resources.sls:

resources:
  dummy:
    resource_ids:
      - dummy-01
      - dummy-02
      - dummy-03

Confirm pillar reads correctly:

salt-call --local pillar.get resources unmask=True
# {'dummy': {'resource_ids': ['dummy-01', 'dummy-02', 'dummy-03']}}

(The unmask=True is required in 3008.0+: pillar values are masked by default at the CLI. SLS files render with masking disabled.)

Step 1 — confirm discovery#

The managing minion discovers resource types from the pillar on every pillar refresh. The first run after editing pillar will pick them up:

salt-call --local saltutil.refresh_pillar

In masterless mode there's no registry to populate, but the minion caches its own view. You can confirm:

salt-call -r --tgt '*' test.ping

If you see something like:

local:
    ----------
    <managing-minion-id>: True
    dummy-01: True
    dummy-02: True
    dummy-03: True

…the framework loaded the dummy resource type, called ping() against each declared id, and folded the results. If you only see the managing minion, double-check pillar.

Step 2 — per-resource targeting#

Every targeting form Salt offers against minions works against resources too. Try a few:

# All dummy resources by type
salt-call -r --tgt 'T@dummy' --tgt-type compound test.ping

# One specific resource
salt-call -r --tgt 'dummy-02' test.ping

# By per-resource grain
salt-call -r --tgt 'dummy_grain_1:one' --tgt-type grain test.ping

The dummy resource publishes a small fixed grain dict (dummy_grain_1, dummy_grain_2, dummy_grain_3, plus resource_id). All four match the same set of three resources here.

Step 3 — inspect grains#

grains.items works per-resource. Without -r you'd see the managing minion's grains; with -r and a resource target you see the resource's:

salt-call -r --tgt dummy-01 grains.items

# local:
#     ----------
#     dummy-01:
#         ----------
#         dummy_grain_1: one
#         dummy_grain_2: two
#         dummy_grain_3: three
#         resource_id:   dummy-01

Step 4 — exercise a state#

The dummy type ships an execution function test_from_state(). We can wrap it in a tiny state:

/srv/salt/dummy/test.sls:

say_hello:
  cmd.run:
    - name: echo "dummy resource state running"

do_the_thing:
  module.run:
    - dummy.test_from_state: []

Apply it against all dummy resources at once:

salt-call -r --tgt 'T@dummy' --tgt-type compound state.apply dummy.test

This exercises merge-mode state.apply: the managing minion runs the apply for each of the three resources inline and produces one combined output. Look at the keys — each state ID is prefixed with the resource id so provenance is visible:

cmd_|-dummy-01 say_hello_|-dummy-01 echo "..."_|-run
cmd_|-dummy-02 say_hello_|-dummy-02 echo "..."_|-run
cmd_|-dummy-03 say_hello_|-dummy-03 echo "..."_|-run
module_|-dummy-01 do_the_thing_|-dummy-01 dummy.test_from_state_|-run
module_|-dummy-02 do_the_thing_|-dummy-02 dummy.test_from_state_|-run
module_|-dummy-03 do_the_thing_|-dummy-03 dummy.test_from_state_|-run

One Summary line at the bottom shows the rolled-up pass/fail. See States against Salt Resources for the prefixing rules.

Step 5 — write your own#

You've used a resource type — now write one. The dummy module under salt.resources.dummy is ~300 lines and covers every hook the framework expects. Mirror its shape under saltext/<yourext>/resources/<yourtype>/ to ship a type in an extension; see Authoring a Salt resource type for the interface contract and Packaging as a Salt extension for the entry-point wiring.

What's next#