saltstack / saltstack/salt

[Bug]: Minion skips own job when target id equals a managed resource id

Open
#69,867 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Python
Stars
15.7k
Forks
5.6k
Avg merge
2d 44m
Merged PRs (30d)
80

Description

What happened?

When a publication uses a bare-id glob target that matches one of the minion's managed resource ids, Minion._is_pure_resource_target() returns True and _target_load() sets minion_is_target = False (for non-merge functions). The managing minion still accepts the job so it can run the resource path, but it does not execute the function as itself.

That is wrong when the bare id is also the minion's own id (minion_id == resource_id == tgt). In that collision case the minion job is silently dropped and only the resource job runs.

Expected behavior: when tgt equals both the minion id and a managed resource id, the minion should execute both:

  1. the normal minion job, and
  2. the resource job

(as already happens for merge functions like state.apply, where minion_is_target is forced true when resource_targets is non-empty).

Actual behavior: for ordinary functions (test.ping, grains.item, saltutil.refresh_resources, etc.) only the resource path runs. Returns look like they came from the targeted id, but they are resource-loader results (or "not supported for resource type …"), not the minion's own modules/grains.

Where

salt/minion.py:

  • _is_pure_resource_target() — bare-id glob branch returns True whenever tgt appears in opts["resources"], with no check against opts["id"]
  • _target_load() — uses that verdict to clear minion_is_target unless the function is in _MERGE_RESOURCE_FUNS

salt/cli/caller.py reuses the same helpers for salt-call -r, so the same collision semantics apply there.

Minimal reproduction

Minion config / pillar such that:

id: appliance-01
# opts["resources"] after discovery/registration:
resources:
  ops:
    - appliance-01

Then:

salt 'appliance-01' test.ping
salt 'appliance-01' grains.item id fqdn
salt 'appliance-01' saltutil.refresh_resources

Observed with current 3008.1 code:

function resource_targets minion_is_target
test.ping [{id: appliance-01, type: ops}] False
grains.item same False
saltutil.refresh_resources same False
state.apply same True (merge fun)

Only state.apply runs on the minion itself. The others run only as the resource.

Suggested fix direction

In _is_pure_resource_target, do not treat a bare-id glob as pure-resource when tgt == self.opts["id"]. That keeps resource_targets populated (so the resource job still runs) while allowing _target_load to set minion_is_target = True, yielding both executions.

Why this matters

Any deployment where a resource is keyed with the same id as its managing minion cannot reliably target that minion by id for non-merge functions. Housekeeping that is not listed in _NO_RESOURCE_FUNS (for example saltutil.refresh_resources) is swallowed by the resource path, which makes the collision self-reinforcing: the minion cannot refresh/re-key itself via the obvious target.

Type of salt install
  • other (please specify in bug details) — Salt 3008.1 onedir / official packaging with Salt Resources enabled
Major version
  • 3008.x (Resources feature; not listed in the issue form dropdown yet)
What supported OS are you seeing the problem on?
  • photon-5
  • (logic is OS-independent; reproduced against salt/minion.py on the 3008.1 line)
salt --versions-report output
Salt Version:
          Salt: 3008.1

(Exact versions-report from the affected minion can be attached if needed; the defect is in shared minion target-routing code on the 3008.x Resources path.)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in salt/minion.py with _is_pure_resource_target() and _target_load(), then compare the behavior with salt/cli/caller.py, which reuses the helpers. Reproduce the collision using the appliance-01 resource configuration and the listed salt commands; done means the minion executes both its normal job and the resource job for ordinary functions while preserving state.apply behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
infrastructure
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.