fedora-csb-system-manager
  1#+TITLE: Imperative Configuration
  2#+FILETAGS: imperative configuration scripts
  3
  4Idempotent configuration scripts for systems not managed by NixOS.
  5
  6* Overview
  7
  8This directory contains configuration scripts for hosts that cannot or do not use NixOS. Unlike the declarative NixOS configurations in =/systems=, these scripts use an imperative approach but are designed to be idempotent - safe to run multiple times.
  9
 10** Philosophy
 11
 12While NixOS provides declarative configuration management, some systems need to use traditional Linux distributions for various reasons:
 13- Hardware compatibility requirements
 14- Organizational constraints
 15- Testing different distributions
 16- Transition periods before migrating to NixOS
 17
 18These scripts bridge the gap by providing repeatable, documented configuration management for non-NixOS systems.
 19
 20** Key Principles
 21
 221. *Idempotent* - Scripts can be run multiple times safely
 232. *Self-contained* - Each host directory is independent
 243. *Documented* - Each host has a README explaining its setup
 254. *Versioned* - Configuration is tracked in git like NixOS configs
 26
 27* Directory Structure
 28
 29Each host has its own directory containing:
 30
 31#+begin_example
 32imperative/
 33├── README.org          # This file
 34├── nagoya/             # Debian server
 35│   ├── README.org      # Host-specific documentation
 36│   └── apply.sh        # Main configuration script
 37└── wakasu/             # Fedora desktop
 38    ├── README.org      # Host-specific documentation
 39    └── apply.sh        # Main configuration script
 40#+end_example
 41
 42* Current Hosts
 43
 44** nagoya - Debian Server
 45- *OS:* Debian (aarch64)
 46- *Type:* Server
 47- *Components:* Docker, Kind, Wireguard, Syncthing
 48- *VPN IP:* 10.100.0.80/24
 49
 50See [[file:nagoya/README.org][nagoya/README.org]] for details.
 51
 52** wakasu - Fedora Desktop
 53- *OS:* Fedora
 54- *Type:* Desktop
 55- *User:* vincent
 56- *Components:* Helix, ACPI, Wireguard, Syncthing
 57- *VPN IP:* 10.100.0.90/24
 58
 59See [[file:wakasu/README.org][wakasu/README.org]] for details.
 60
 61* Usage
 62
 63** Running Configuration Scripts
 64
 65From the repository root:
 66
 67#+begin_src bash
 68# Apply configuration for a specific host
 69sudo ./imperative/<hostname>/apply.sh
 70
 71# With environment variables (e.g., for wireguard)
 72sudo WG_PRIVATE_KEY="..." ./imperative/<hostname>/apply.sh
 73#+end_src
 74
 75** Adding a New Host
 76
 771. Create a new directory for the host:
 78   #+begin_src bash
 79   mkdir imperative/<hostname>
 80   #+end_src
 81
 822. Create an =apply.sh= script following the existing patterns:
 83   - Use =set -euo pipefail= for safety
 84   - Implement colored logging functions
 85   - Make functions idempotent
 86   - Use =setup.*= naming convention for functions
 87
 883. Create a =README.org= documenting:
 89   - System information
 90   - Components installed
 91   - Usage instructions
 92   - Environment variables needed
 93
 944. Make the script executable:
 95   #+begin_src bash
 96   chmod +x imperative/<hostname>/apply.sh
 97   #+end_src
 98
 995. Update this README to include the new host
100
101** Testing Scripts
102
103Test scripts in a VM or container before running on production systems:
104
105#+begin_src bash
106# Example with Docker
107docker run -it --rm -v $(pwd):/repo debian:latest
108cd /repo
109./imperative/<hostname>/apply.sh
110#+end_src
111
112* Script Conventions
113
114** Error Handling
115
116All scripts use strict error handling:
117#+begin_src bash
118set -euo pipefail
119#+end_src
120
121This ensures:
122- =set -e= - Exit on any error
123- =set -u= - Exit on undefined variable
124- =set -o pipefail= - Catch errors in pipes
125
126** Logging
127
128Use colored logging functions for clarity:
129
130#+begin_src bash
131log_info "Normal operation message"
132log_warn "Warning message"
133log_error "Error message"
134#+end_src
135
136** Function Naming
137
138Use =setup.*= prefix for setup functions:
139
140#+begin_src bash
141setup.docker() { ... }
142setup.wireguard() { ... }
143setup.syncthing() { ... }
144#+end_src
145
146** Environment Variables
147
148- Document all required environment variables in the host's README
149- Provide sensible defaults where possible
150- Fail gracefully or warn when optional variables are missing
151
152** Idempotency
153
154Make operations idempotent by:
155- Checking if software is already installed
156- Using =||= for commands that might fail on re-run
157- Avoiding destructive operations
158- Using configuration management tools when available
159
160* Integration with NixOS Configs
161
162While these scripts are imperative, they share concepts with the NixOS configurations:
163
164- *Wireguard configuration* matches the network topology in =globals.nix=
165- *Syncthing* IDs should be coordinated with NixOS hosts
166- *VPN IP addressing* follows the same scheme (10.100.0.0/24)
167
168* Transitioning to NixOS
169
170When ready to migrate a host to NixOS:
171
1721. Document the current system state using the imperative script as reference
1732. Create a new NixOS configuration in =/systems/<hostname>=
1743. Test the NixOS configuration in a VM
1754. Perform the migration
1765. Archive or remove the imperative configuration
177
178* Maintenance
179
180** Updating Scripts
181
182When updating scripts:
183
1841. Test changes in a VM or non-production system
1852. Update the host's README if behavior changes
1863. Run shellcheck to catch common issues:
187   #+begin_src bash
188   shellcheck imperative/<hostname>/apply.sh
189   #+end_src
190
191** Version Control
192
193All changes to imperative configurations should be:
194- Committed to git
195- Documented in commit messages
196- Tagged if significant milestones are reached
197
198* Comparison: Imperative vs NixOS
199
200| Aspect           | Imperative (this directory) | NixOS (=/systems=)          |
201|------------------+-----------------------------+---------------------------|
202| *Approach*         | Scripts to reach state      | Declare desired state     |
203| *Idempotency*      | Manual (via careful coding) | Automatic                 |
204| *Rollback*         | Manual/difficult            | Built-in generations      |
205| *Reproducibility*  | Best effort                 | Guaranteed                |
206| *Documentation*    | README + comments           | Code is documentation     |
207| *OS Support*       | Any Linux distro            | NixOS only                |
208| *Learning Curve*   | Familiar bash scripts       | Steeper (Nix language)    |
209| *State Management* | Imperative commands         | Declarative configuration |
210
211* Resources
212
213** Similar Approaches
214- Ansible playbooks (declarative automation)
215- Chef/Puppet recipes (configuration management)
216- Shell scripts (traditional approach)
217
218** Why Not Use These Tools?
219
220For simple single-host configurations, a well-written bash script:
221- Has no dependencies beyond bash and standard tools
222- Is easy to understand and modify
223- Runs quickly without agent overhead
224- Keeps everything in this repository
225
226For managing many similar hosts, consider tools like Ansible.