How to System Provisioning
This chapter walks you through the typical bois workflow of managing a system’s state.
This means managing files in /etc, installed packages and enabled services.
It won’t go into too much detail, the idea is to get a feel for what working with bois looks like in practice.
Every topic that is touched in this guide also has its own chapter with more detailed documentation.
Note
The How to Dotfiles chapter covers the same workflow, but for managing your user’s dotfiles.
Now, let’s get to it. Let’s assume you have a laptop with the hostname milo whose system configuration you’d like to manage.
System mode
By default, bois determines its run mode from the user that calls it.
Run as a normal user, it operates in user mode and manages the dotfiles in your home directory.
But when run as root, it switches to system mode:
- Files are deployed to
/etc. - Packages are installed and removed via your system’s package manager.
- Service managers are run in system mode (e.g.
systemctlis called without--user)
This whole chapter takes place in system mode, which is why we assume that all commands are executed as root.
Creating the bois directory
Everything bois manages lives in a single directory, the bois directory.
In system mode, bois expects it at /etc/bois:
bois init /etc/bois
cd /etc/bois
Note
Alternatively, you can also put your bois directory anywhere else and create a
/etc/bois/bois.ymlthat points to your desired directory location.
All paths from here on are relative to this directory.
After running bois init, you’ll end up with this structure:
📁 traits/
│ 📂 base/
│ │ └ base.yml
📂 hosts/
│ 📂 milo/
│ │ milo.yml
│ │ └ vars.yml
└ bois.yml
The host’s config file lives inside the host’s directory at hosts/milo/milo.yml.
The important part for now is hosts/milo/.
Everything inside it (except the milo.yml config file and the vars.yml special file) is configuration that will be deployed for this host only.
Your first managed file
Let’s put a config file you already have under bois’ control like, for example, your sysctl config:
cp /etc/sysctl.conf hosts/milo/
That’s all there is to it.
Files in a host directory mirror their path relative to the target directory, which is /etc in system mode:
hosts/milo/sysctl.conf will be deployed to /etc/sysctl.conf.
Plan and deploy
bois plan is a dry-run that shows everything a deployment would do, without touching your system:
bois plan
Since we just copied the file, the source and the deployed file are identical and there’s nothing to do.
bois only ever touches things that actually changed.
So let’s change something!
Open hosts/milo/sysctl.conf in the bois directory and tweak a value.
bois plan now shows a diff of exactly what would change on your system.
If you’re happy with it, apply the change:
bois deploy
That’s the basic workflow you’ll be using most of the time.
I.e. edit some files in the bois directory → bois plan → bois deploy
Safety features
In case some deployed (and thereby managed) file is edited on your host directly, it won’t just be overwritten.
bois compares the actual state of each managed file against the previous state from the last deployment.
If any changes are detected, bois warns you about non-adopted changes and only overwrites those changes if you explicitly say so:
These changes will be overwritten. Are you sure that's okay?
Nothing gets overwritten without you being notified about it. If you want to keep those changes, simply abort, adopt the changes into your bois directory and rerun the deployment.
Sharing config between hosts with traits
So far, everything lives in hosts/milo/ and is exclusive to your laptop.
But it would be nice to also have that sysctl config on your desktop.
That’s what traits are for: A trait is basically a bundle of configuration that any host can opt into.
The template generated by bois init already created a trait called base, and the generated hosts/milo/milo.yml already enables it:
# hosts/milo/milo.yml
traits:
- base
To move the sysctl config to the trait, simply run:
mv hosts/milo/sysctl.conf traits/base/sysctl.conf
If you were to now run bois plan, nothing would change as milo opted into the base trait and as such, the file is still part of the configuration that’s active for milo.
Now, setting up configuration for your desktop with the name cleo boils down to:
- Adding a
hosts/cleo.yml, which also opts into thebasetrait. Sincecleobrings no files of its own (yet), a stand-alone config file without a host directory is all it needs:traits: - base - Cloning your bois directory on
cleoto/etc/bois. - Running
bois deploy.
Check the Trait Config chapter for everything else traits can do.
Removing files
To stop managing a file, just delete it from the bois directory.
The next bois deploy will notice the removal and delete the deployed file from your system.
Important
Directories will never be removed as long as they still contain files.
Also, directories aren’t removed by default. For that you have to set the following in your host/trait config:
cleanup:
directories: true
Overriding target paths
Not every file lives in /etc though.
Let’s say you’re using systemd-boot and want to manage your boot entries, which live in /boot/loader/entries.
For cases like this, a folder’s target path can be overridden with a dir.yml file inside it:
📂 hosts/
└ 📂 milo/
└ 📂 boot_entries/
│ dir.yml
└ arch.conf
# hosts/milo/boot_entries/dir.yml
target_path: /boot/loader/entries
All files in that folder are now deployed to /boot/loader/entries/.
Ownership and permissions can be configured as well, if needed.
Check out the Folder Configuration and File Configuration chapters for all available options.
Managing packages
Bois can also be used to declare and synchronize packages on your machines. For this, you simply declare them in your host or trait config:
# hosts/milo/milo.yml
traits:
- base
packages:
pacman:
- tlp # Laptop battery management, only needed on milo.
Packages declared in a trait’s config are installed on every host that opts into that trait. This is useful for everyday tools you want want on multiple of your machines:
# traits/base/base.yml
packages:
pacman:
- git
- vim
- openssh
On the next bois deploy, everything that’s declared but missing will be installed.
If a package is removed from the list, it will be uninstalled on the next deploy.
Only packages that were part of the bois directory will be uninstalled. Packages that are not managed by bois won’t be touched.
Both bois plan and bois deploy show all installs and removals before anything actually happens.
Check the Package Management chapter for the list of supported package managers.
Tip
There’s also a way to see which installed packages on your system aren’t managed by bois yet:
bois diffThis is a really convenient way to incrementally sync your system with bois and to keep track of drift between hosts. Run
bois diffand then either add the packages to your config, uninstall them or simply just ignore them until you decide what to do with them.
System services
Installing a package is often only half the job, and installed services usually need to be enabled afterwards.
bois also manages system services, which are declared in host, trait or dir.yml configs like this:
# traits/base/base.yml
services:
systemd:
- systemd-timesyncd
- sshd
During deployment, bois installs packages first, then deploys files and only then enables services.
That way, unit files are guaranteed to exist by the time their services are enabled.
If a service is removed from your configuration, it is stopped and disabled during the next deploy.
Check the Service Management chapter for more info.
Important
By default, services are only enabled, not started.
If a service should be started immediately, you have to explicitly say so:
services: systemd: - name: docker start: trueEven then, services are only started when they are initially enabled.
boisdoes not manage the running state of services.