8.4 What versus How
Notice that our configuration is really a script detailing ‘how’ to impose our configuration. To use this configuration we need to know some things about our target system. For example, we need to know that the system supports installation of packages using apt-get, and we need the system to run bash shell scripts.
The second requirements (the need to run bash) could be a simple prerequisite, we are using bash as our configuration tool. The former though is more questionable.
What if I want to run this configuration on an Arch based distribution? These distributions use pacman rather than apt. What about on RedHat distributions where dnf is the preferred package manager?
The issue is this; my configuration is really saying ‘I want to ensure Git is available’. This requirement is independent of the underlying operating system or distribution or that operating system. All I really want is to have Git available after I have applied my configuration.
Configuration management tends, therefore, to be based on a declarative system. The configuration is a statement of ‘what’ should be true on the system if it is configured correctly. The configuration manager is unconcerned with ‘how’ the configuration is asserted and only concerned ‘that’ it is asserted. In other words, I don’t care about which installation method is used to install Git I only care that once my configuration is applied Git is available.
In a trivial sense my script could be something like the following (if you’re following along there is no need to make these changes, I’m just illustrating a point).
1#!/usr/bin/env bash 2# vi :set ft=bash: 3 4. config-tool.sh 5 6set -euo pipefail 7 8git-installed
Our configuration now just states ‘after running this configuration the system must have git-installed’, or put another way, ‘any system that meets the requirements of this configuration must have git-installed’. All of the detail about how the configuration tool should verify that Git is in fact installed or how if should be installed if it is not already, is irrelevant to the configuration itself.
A naive implementation of config-tool.sh might look something like the following.
1#!/usr/bin/env bash 2# vi :set ft=bash: 3 4set -euo pipefail 5 6 7# Figure out package tool 8PKG="" 9for pm in "apt dnf pacman"; do 10 if command -v "${pm}"; then 11 PKG="${pm}" 12 break 13 fi 14done 15 16git-installed () { 17 # If git IS installed, we're done 18 command -v git && return 19 20 # Otherwise try to install it 21 case "${PKG}" in 22 "apt") 23 apt -y install git 24 ;; 25 "dnf") 26 dnf -y install git 27 ;; 28 "pacman") 29 pacman --sync --noconfirm git 30 ;; 31 *) 32 echo "No package manager found" >2 33 exit 1 34 esac 35}
Obviously this script is deficient in many ways (not being very generalised, not accounting for different package names, not covering many distributions, not handling errors, etc.) but in principle it allows us to say git-installed (the thing we want to be true) in our configuration and leave all the messy details (of how to make it true) to be figured out by the configuration tool.
As you might imagine, we are not going to be writing our own configuration management system!