Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/wikioasis/salt/llms.txt

Use this file to discover all available pages before exploring further.

Salt uses a file called top.sls in both the state tree and the pillar tree to decide what each minion receives. When you run salt '*' state.apply or when a highstate is triggered, the master evaluates both top files and compiles a per-minion list of states and pillar data. Understanding these files is the key to understanding what happens on any server in the WikiOasis fleet. WikiOasis has two top files:
  • salt/top.sls — assigns state modules to minions (what software is installed and configured)
  • pillar/top.sls — assigns pillar data files to minions (the values used by those states)

Matching syntax

Default: glob

Lines without a match: directive use shell glob matching against the minion ID. The * wildcard matches any string; [0-9] matches a single digit in a character class.
'db*':         # matches db-c1-us-east-021, db-other-us-east-011, etc.
  - mariadb

Compound matching

Add - match: compound as the first item in the state list to unlock Boolean logic with or, and, and not keywords. The compound matcher evaluates the full minion ID.
'mw* or staging*':
  - match: compound
  - php
  - nginx
  - sentry_relay
match: compound must be the first item in the list. Salt treats it as a directive, not a state name — it will not try to load a state called compound.

Ranged glob

A character-class range like 0[0-9][0-9] targets numbered hosts without listing each one:
'*-us-east-0[0-9][0-9]*':
  - metal.vm_ipv6
This matches every VM whose ID follows the <role>-us-east-0NN convention (e.g. mw-us-east-011, redis-us-east-021) and applies IPv6 routing configuration managed by the metal state.

salt/top.sls

The state top file determines which Salt state trees are applied to each minion. States are cumulative — a mw-us-east-011 minion matches '*', 'mw*', 'mw* or staging*', and '*-us-east-0[0-9][0-9]*' and receives all states from every matching block.
base:
  # ── Applied to every minion ────────────────────────────────────────────
  '*':
    - base                        # timezone, APT sources
    - users                       # system users, SSH keys, sudo groups
    - monitoring.nrpe             # Icinga NRPE daemon
    - monitoring.nrpe_common      # common NRPE check scripts
    - monitoring.nrpe_salt        # NRPE checks for the Salt minion itself
    - monitoring.node_exporter    # Prometheus Node Exporter

  # ── Applications server ────────────────────────────────────────────────
  'apps*':
    - php
    - nginx
    - monitoring.nrpe_nginx
    - monitoring.nrpe_php
    - monitoring.phpfpm_exporter

  # ── Database servers ───────────────────────────────────────────────────
  'db*':
    - mariadb                     # MariaDB server + my.cnf
    - mariadb.monitoring_user     # Icinga check user
    - mariadb.prometheus_user     # mysqld_exporter user
    - mariadb.backup              # backup user + rsync cron
    - mariadb.nrpe_backup         # NRPE checks for backup age
    - monitoring.mysqld_exporter  # Prometheus mysqld_exporter

  # ── Bare-metal hypervisors ─────────────────────────────────────────────
  'metal*':
    - metal                       # DNS/DHCP, IP forwarding, bridges
    - monitoring.nrpe_metal

  # ── HAProxy load balancers ─────────────────────────────────────────────
  'proxy*':
    - haproxy                     # HAProxy config & service
    - monitoring.nrpe_haproxy
    - monitoring.haproxy_exporter
    - mediawiki.proxy             # deploy-user SSH key on proxy nodes

  # ── Monitoring server ──────────────────────────────────────────────────
  'monitoring*':
    - monitoring                  # Icinga 2, Icinga Web 2
    - monitoring.director         # Icinga Director module
    - monitoring.nrpe_nginx
    - monitoring.prometheus       # Prometheus server
    - monitoring.grafana          # Grafana dashboards
    - monitoring.statsd_exporter  # StatsD → Prometheus bridge

  # ── Staging / canary server ────────────────────────────────────────────
  'staging*':
    - mediawiki                   # mwdeploy user, SSH keys, deploy scripts

  # ── MediaWiki application servers ─────────────────────────────────────
  'mw*':
    - mediawiki.target            # deploy target configuration

  # ── MediaWiki + staging (compound) ────────────────────────────────────
  'mw* or staging*':
    - match: compound
    - php
    - nginx
    - sentry_relay
    - monitoring.nrpe_nginx
    - monitoring.nrpe_php
    - monitoring.nrpe_mediawiki
    - monitoring.phpfpm_exporter

  # ── Task / job runner ──────────────────────────────────────────────────
  'task*':
    - php
    - nginx
    - mediawiki.target
    - mediawiki.jobrunner         # job queue runner configuration
    - monitoring.nrpe_nginx
    - monitoring.nrpe_php
    - monitoring.phpfpm_exporter

  # ── OpenSearch nodes ──────────────────────────────────────────────────
  'opensearch*':
    - opensearch
    - monitoring.nrpe_opensearch
    - monitoring.opensearch_exporter

  # ── Redis cache servers ────────────────────────────────────────────────
  'redis*':
    - redis
    - monitoring.nrpe_redis
    - monitoring.redis_exporter

  # ── Salt master (self-monitoring only) ────────────────────────────────
  'salt*':
    - monitoring.nrpe_salt_master

  # ── All VMs with numbered names (IPv6 routing) ────────────────────────
  '*-us-east-0[0-9][0-9]*':
    - metal.vm_ipv6

State counts per role

Minion patternStates received
Every minion (*)base, users, monitoring.nrpe, monitoring.nrpe_common, monitoring.nrpe_salt, monitoring.node_exporter
mw*All of * + mediawiki.target + compound block (php, nginx, sentry_relay, monitoring checks) + metal.vm_ipv6
staging*All of * + mediawiki + compound block + metal.vm_ipv6
task*All of * + php, nginx, mediawiki.target, mediawiki.jobrunner, monitoring checks + metal.vm_ipv6
proxy*All of * + haproxy, monitoring.nrpe_haproxy, haproxy_exporter, mediawiki.proxy + metal.vm_ipv6
db*All of * + mariadb stack + mysqld_exporter + metal.vm_ipv6
redis*All of * + redis, nrpe_redis, redis_exporter + metal.vm_ipv6
opensearch*All of * + opensearch, nrpe_opensearch, opensearch_exporter + metal.vm_ipv6
monitoring*All of * + full monitoring stack + metal.vm_ipv6
metal*All of * + metal, nrpe_metal
apps*All of * + php, nginx, monitoring checks + metal.vm_ipv6
salt*All of * + monitoring.nrpe_salt_master + metal.vm_ipv6

pillar/top.sls

The pillar top file controls which pillar data files are merged and sent to each minion. Unlike state assignments, pillar assignments directly affect what values are available to Jinja templates in states.
base:
  # ── All minions receive base config, users, and secrets ───────────────
  '*':
    - base                        # timezone, apt mirror
    - users                       # user/group definitions
    - private                     # secrets (passwords, API keys)

  # ── Applications server ────────────────────────────────────────────────
  'apps*':
    - php
    - private

  # ── Bastion SSH gateway ────────────────────────────────────────────────
  'bastion*':
    - users.servers.bastion       # bastion-specific SSH key overrides

  # ── Database servers ───────────────────────────────────────────────────
  'db*':
    - mariadb                     # shared MariaDB defaults
    - private                     # backup credentials

  # Per-host MariaDB overrides (larger buffer pools, server IDs, etc.)
  'db-other-us-east-011*':
    - mariadb.db-other-us-east-011
  'db-pc-us-east-011*':
    - mariadb.db-pc-us-east-011
  'db-c1-us-east-021*':
    - mariadb.db-c1-us-east-021

  # ── Bare-metal + all numbered VMs (compound) ──────────────────────────
  'metal* or *-us-east-0[0-9][0-9]*':
    - match: compound
    - metal                       # DNS table, Proxmox config, public IPs

  # Per-hypervisor overrides (public IP, IP forwarding rules)
  'metal-us-east-01*':
    - metal.metal-us-east-01
  'metal-us-east-02*':
    - metal.metal-us-east-02

  # ── MediaWiki + staging (compound) ────────────────────────────────────
  'mw* or staging*':
    - match: compound
    - users.servers.mediawiki     # mediawiki-admins group enabled
    - php
    - nginx
    - mediawiki

  # ── HAProxy load balancers ─────────────────────────────────────────────
  'proxy*':
    - haproxy
    - mediawiki                   # needed for deploy user + proxy list

  # ── Monitoring server ──────────────────────────────────────────────────
  'monitoring*':
    - monitoring
    - metal                       # needs DNS host table for check targets
    - private                     # Icinga/Grafana passwords

  # ── Task / job runner ──────────────────────────────────────────────────
  'task*':
    - users.servers.mediawiki
    - php
    - nginx
    - mediawiki
    - mediawiki.jobrunner

  # ── OpenSearch nodes ──────────────────────────────────────────────────
  'opensearch*':
    - opensearch

  # ── Redis cache servers ────────────────────────────────────────────────
  'redis*':
    - redis

  # Per-host Redis overrides (maxmemory, eviction policy)
  'redis-us-east-011*':
    - redis.redis-us-east-011
  'redis-us-east-012*':
    - redis.redis-us-east-012
The private pillar is assigned to '*' as a catch-all so that every minion can access cross-cutting secrets such as the monitoring API host. Ensure pillar/private/init.sls exists on the master before running any highstate, or Salt will error on missing pillar keys.

Debugging pillar and state assignment

To inspect what pillar data a specific minion would receive:
# Show compiled pillar for a single minion
salt 'mw-us-east-011' pillar.items

# Show a single pillar key
salt 'db-c1-us-east-021' pillar.get mariadb:innodb:buffer_pool_size
To preview what states would be applied without actually running them:
# Dry-run highstate (shows changes that would be made)
salt 'proxy-us-east-011' state.apply test=True

# Show which state SLS files the top file assigns
salt 'proxy-us-east-011' state.show_top

Build docs developers (and LLMs) love