- Packages go in
provisioning/packages.sls- states import, never hardcode - Files live in
provisioning/- states orchestrate, files deploy - Grep before moving anything - silent failures suck
grep -Hnr "old_path" srv/salt/ srv/pillar/ provisioning/ scripts/ .github/ tests/ *.md Makefilemake test # All (ubuntu + rhel)
make test-ubuntu # Ubuntu only
make test-rhel # RHEL only
make test-windows # Windows (requires KVM)| Problem | Fix |
|---|---|
| State not found | Check top.sls matches filename |
| File not found | Check provisioning/ mounted |
| Jinja undefined | Add {% import_yaml "provisioning/packages.sls" as packages %} |
| Minion hanging | Master needs 15s after restart |
| Permissions | Run ./scripts/fix-permissions.sh |
For cmd.run states needing NVM/Conda paths:
{%- from "macros/windows.sls" import win_cmd %}
install_node:
cmd.run:
- name: {{ win_cmd('nvm install lts') }}
- shell: pwshSets NVM_HOME, NVM_SYMLINK, CONDA_HOME automatically.
Pillar template files (committed) show structure and defaults. Copy templates to create instance files:
| Template | Purpose | Instance | Notes |
|---|---|---|---|
srv/pillar/host/example.sls |
Per-host config template | srv/pillar/host/{hostname}.sls |
Loaded if exists, never tracked |
srv/pillar/class/example.sls |
Hardware class template | srv/pillar/class/{classname}.sls |
Reference for structure |
srv/pillar/users/demo.sls |
User config template | srv/pillar/users/{username}.sls |
Local files only, demo.sls tracked |
srv/pillar/common/users.sls.example |
User metadata template | srv/pillar/common/users.sls |
Shows structure (tracked) |
srv/pillar/secrets/init.sls.example |
Secrets template | srv/pillar/secrets/init.sls |
Gitignored, create locally |
Creating a new host configuration:
cp srv/pillar/host/example.sls srv/pillar/host/myhost.sls
# Edit myhost.sls, set any host-specific pillar values
# File is auto-loaded based on minion hostnameAdding a new managed user:
cp srv/pillar/users/demo.sls srv/pillar/users/newuser.sls
# Edit newuser.sls:
# - Change "example_user" to "newuser" in pillar
# - Set groups, SSH keys, github config, tokens
# - Add "newuser" to managed_users list in srv/pillar/common/users.sls
# - User config remains local (see .gitignore)Git credentials and user config:
- Credentials stored in
.git-credentials:https://username:token@github.com - User email/name auto-deploy to
.gitconfig.local [user]section - Tokens merge: global (common/users.sls) + per-user (users/{username}.sls)
- See
srv/pillar/users/demo.slsfor github config structure
Module documentation lives in docs/modules/ (not as inline comments in .sls files).
Examples:
- Salt Scheduler - Pillar configuration and usage for
schedulemodule - State files - Minimal header comment pointing to
docs/modules/
When adding a new module:
- Create
docs/modules/<name>.mdwith configuration, options, and examples - Reference it from the state file:
# See docs/modules/<name>.md for usage - Minimal pillar template with just a reference to the docs
- Branch from main
- Make changes following the 3 rules
- Run tests
- Commit, push, PR
| repo | path |
|---|---|
| vegcom/cozy-salt-enrollment.git | scripts/enrollment/ |
| repo | deployment |
|---|---|
| vegcom/cozy-vim | ~/.vim (per-user via git_repo macro in common/vim.sls) |
| vegcom/cozy-pwsh | C:\Program Files\PowerShell\7 (system-wide via windows/profiles.sls) |
| vegcom/cozy-presence | /opt/cozy/cozy-presence (linux service via linux/cozy-presence.sls) |
| vegcom/cozy-fragments | C:\opt\cozy\cozy-fragments (Windows Terminal fragments via windows/wt.sls) |
| vegcom/cozy-ssh | ~/.ssh (per-user via common/ssh.sls, cross-platform) |
| repo | description |
|---|---|
| vegcom/cozy-share | SMB/file share management |
| vegcom/cozy-scale | scaling / infra tooling |
| vegcom/cozy-dash | dashboard |
| vegcom/cozy-archiso | Arch ISO builder |
| vegcom/cozy-pxe | PXE boot |
| vegcom/cozy-ipa | IPA / identity management |