Compare commits

...

27 Commits
1.2.0 ... main

Author SHA1 Message Date
Solène Rapenne 6418bd64ec
bento: use flake-utils to support all systems 2023-06-24 11:46:41 +02:00
Solène Rapenne 05c95104a9
rework README 2023-06-24 11:32:09 +02:00
Solène Rapenne 98361e3555
add a reboot timer 2023-06-24 11:31:49 +02:00
Solène Rapenne 189d476424
Merge pull request #7 from wamserma/patch-1
Update README.md (typo fix)
2023-06-01 23:30:52 +02:00
Solène Rapenne 6c9ae97537
Merge pull request #8 from wamserma/patch-2
bento: typo fix in status message
2023-06-01 23:29:20 +02:00
Markus Wamser 428bd2d374
bento: typo fix in status message 2023-05-30 13:25:12 +02:00
Markus Wamser 56b269cc5c
Update README.md (typo fix) 2023-05-30 12:34:56 +02:00
Solène Rapenne 33fc1e2772
Merge pull request #6 from gador/dry-build
add a config option to not build the config locally
2023-05-04 16:50:57 +02:00
Florian Brandes 3e7125d32e
add a config option to not build the config locally
Signed-off-by: Florian Brandes <florian.brandes@posteo.de>
2023-05-02 21:44:07 +02:00
Solène Rapenne f85a445532
Merge pull request #3 from Blackhole1504/main
Add lib.mkDefault tag to the systemd timer value
2023-01-07 16:18:47 +01:00
Bastien b844a0b203
Make timer the default value
Add lib.mkDefault in front of the timer value to be able to specify per host values
2023-01-07 12:43:56 +01:00
Solène Rapenne 220b3de622
Merge pull request #2 from gador/add-port-setting
add REMOTE_PORT setting
2022-12-26 17:49:37 +01:00
Florian Brandes fcefd9e815
remote_port: bugfix for existing bento configurations
now REMOTE_PORT is set in `bento`, just like TIMEOUT
and therefore optional.

Signed-off-by: Florian Brandes <florian.brandes@posteo.de>
2022-12-20 10:47:58 +01:00
Florian Brandes 6ec3dd7b4e
add REMOTE_PORT setting
this allows the deployment server to run on a different
SSH port than the default port 22.

Signed-off-by: Florian Brandes <florian.brandes@posteo.de>
2022-12-19 19:25:15 +01:00
Solene Rapenne d8c28c8ebd bento: recreate the state file for every rebuild 2022-12-08 00:09:02 +01:00
Solene Rapenne 88f124b5b1 bento: only display two biggest time unit in the elapsed time in status 2022-12-08 00:08:37 +01:00
Solene Rapenne 018880d464 bento: use nvd when available 2022-12-08 00:07:27 +01:00
Solene Rapenne dbfd792609 README: fix a typo 2022-12-08 00:07:14 +01:00
Solene Rapenne be3183d764 README: cleanup DONE tasks 2022-10-06 22:34:44 +02:00
Solene Rapenne 171e9cfe17 lock: bump nixpkgs version 2022-10-06 22:29:56 +02:00
Solene Rapenne fcb949881a bento: status now waits for changes in chroot dir in an infinite loop 2022-10-06 22:29:41 +02:00
Solene Rapenne 2392b7720f utils: use startAt in bento-upgrade service to auto create the timer 2022-10-06 20:52:11 +02:00
Solene Rapenne a8ab5c476d flake: remove version 2022-10-04 23:03:41 +02:00
Solene Rapenne ba692bbf34 doc: fix a typo 2022-10-04 23:03:08 +02:00
Solene Rapenne 6b0eecb7f3 bento: diff shouldn't display an error for new machines 2022-10-04 23:02:59 +02:00
Solene Rapenne 80c0de326b bento: add a new feature to work in a push model 2022-10-04 23:02:41 +02:00
Solene Rapenne 9223913444 bento: remove useless comment 2022-09-29 18:15:02 +02:00
8 changed files with 198 additions and 81 deletions

View File

@ -27,7 +27,7 @@ Bento has a different approach with a "pull" model:
- organized 💼: system administrators have all configurations files in one repository to ease management
- peace of mind 🧘🏿: configurations can be validated locally by system administrators
- smart 💡: secrets (arbitrary files) can (soon) be deployed without storing them in the nix store
- robustness in mind 🦾: clients ony need to connect to a remote ssh server, there are many ways to bypass firewalls (corkscrew, VPN, Tor hidden service, I2P, ...)
- robustness in mind 🦾: clients only need to connect to a remote ssh server, there are many ways to bypass firewalls (corkscrew, VPN, Tor hidden service, I2P, ...)
- extensible 🧰 🪡: you can change every component, if you prefer using GitHub repositories to fetch configuration files instead of a remote sftp server, you can change it
- for all NixOS 💻🏭📱: it can be used for anything running NixOS: remote workstations, smartphones or servers in a datacenter
@ -35,7 +35,9 @@ Bento has a different approach with a "pull" model:
This setup need a machine to be online most of the time. NixOS systems (clients) will regularly check for updates on this machine over ssh.
**Bentoo** doesn't necesserarily require a public IP, don't worry, you can use tor hidden service, i2p tunnels, a VPN or whatever floats your boat given it permit to connect to ssh.
**Bento** doesn't necesserarily require a public IP, don't worry, you can use tor hidden service, i2p tunnels, a VPN or whatever floats your boat given it permit to connect to ssh.
**Bento** will use `nvd` instead of `nix store diff-closures` if it's available in the `$PATH`.
# How it works
@ -64,24 +66,15 @@ There is a diagram showing the design pattern of **bento**:
## Major priority
- DONE ~~client should report their current version after an upgrade, we should be able to compute the same value from the config on the server side, this would allow to check if a client is correctly up to date~~
- being able to create a podman compatible NixOS image that would be used as the chroot server, to avoid reconfiguring the host and use sudo to distribute files
- DONE ~~auto rollback like "magicrollback" by deploy-rs in case of losing connectivity after an upgrade~~
- DONE ~~`local_build.sh` and `populate_chroot` should be only one command installed in `$PATH`~~
- DONE ~~upgrades could be triggered by the user by accessing a local socket, like opening a web page in a web browser to trigger it, if it returns output that'd be better~~
- a way to tell a client (when using flakes) to try to update flakes every time even if no configuration changed, to keep them up to date
- DONE ~~being able to use a single flakes with multiple hosts that **bento** will automatically assign to the nixosConfiguration names as hosts~~
- DONE ~~handle automatic reboot if the kernel changed~~
- automatic reboot should be scheduled if desired, this may require making bento a NixOS module to set a timer in it, if no timer then it would reboot immediately
- being able to create a NixOS rootless container that would be used as the chroot server, to avoid reconfiguring the host and use sudo to distribute files
- a way to allow remote client to update their flakes lock file every time even if no configuration changed, this would be useful to let them stay up to date
- document config.sh in the reference
- figure out how to make a tutorial for bento
- DONE ~~sftp timeout should be configurable in `config.sh`~~
- `config.sh` should have variables for the local / remote / both `nixos-rebuild` parameters (useful for `--fallback`)
## Minor
- a systray info widget could tell the user an upgrade has been done
- DONE ~~updates should add a log file in the sftp chroot if successful or not~~
- the sftp server could be on another server than the one with the configuration files
- provide more useful modules in the utility nix file (automatically use the host as a binary cache for instance)
- have a local information how to ssh to the client to ease the rebuild trigger (like a SSH file containing ssh command line)

104
bento
View File

@ -1,11 +1,13 @@
#!/usr/bin/env bash
TIMEOUT=20
REMOTE_PORT=22
NOLOCALBUILD=0
# FUNCTION LIBRARIES
usage() {
cat <<EOF
usage: bento init | deploy | diff | build [dry-run|test|switch] | status [delay] | flake-update [input]
usage: bento init | deploy | diff | build [dry-run|test|switch] | status | flake-update [input]
bento init
: create the layout for bento in the current directory
@ -19,8 +21,10 @@ bento diff
bento build [dry-run|test|switch]
: build configurations, can activate (test or switch) a build locally
bento status [delay]
bento status
: display information for remote hosts
: if the script isn't run in an interactive terminal, exit after display
: in an interactive terminal, display status and poll for changes to display again
bento flake-update [input]
: recursively update flakes lock files
@ -52,7 +56,6 @@ version_diff() {
do
test -d "${i}" || continue
# date calculation
LASTLOG=$(find "${i}/logs/" -type f | sort -n | tail -n 1)
LASTLOGVERSION="$(basename "$LASTLOG" | awk -F '_' '{ print $2 }' )"
EXPECTED_CONFIG="$(awk -F '=' -v host="${i}" 'host == $1 { print $2 }' states.txt)"
@ -65,7 +68,14 @@ version_diff() {
if [ ! "${LASTLOGVERSION}" = "${EXPECTED_CONFIG}" ]
then
echo "Changes in $i between ${LASTLOGVERSION} and ${EXPECTED_CONFIG}"
nix store diff-closures "/nix/store/${LASTLOGVERSION}" "/nix/store/${EXPECTED_CONFIG}"
# better output if nvd is available
if type nvd 2>/dev/null >/dev/null
then
nvd diff "/nix/store/${LASTLOGVERSION}" "/nix/store/${EXPECTED_CONFIG}"
else
nix store diff-closures "/nix/store/${LASTLOGVERSION}" "/nix/store/${EXPECTED_CONFIG}"
fi
else
echo "$i is running the latest version"
fi
@ -228,14 +238,14 @@ cd /var/bento || exit 5
touch .state
# don't get stuck if we change the host
ssh-keygen -F "${REMOTE_IP}" >/dev/null || ssh-keyscan "${REMOTE_IP}" >> /root/.ssh/known_hosts
ssh-keygen -F "${REMOTE_IP}" >/dev/null || ssh-keyscan -p "${REMOTE_PORT}" "${REMOTE_IP}" >> /root/.ssh/known_hosts
STATEFILE="\$(mktemp /tmp/bento-state.XXXXXXXXXXXXXXXX)"
echo "ls -l last_change_date" | sftp -oConnectTimeout="${TIMEOUT}" ${dest}@${REMOTE_IP} >"\${STATEFILE}"
echo "ls -l last_change_date" | sftp -oConnectTimeout="${TIMEOUT}" -P "${REMOTE_PORT}" ${dest}@${REMOTE_IP} >"\${STATEFILE}"
if [ "\$?" -ne 0 ]
then
echo "There is certainly a network problem with ${REMOTE_IP}"
echo "There is certainly a network problem with ${REMOTE_IP} on port ${REMOTE_PORT}"
echo "Aborting"
rm "\${STATEFILE}"
exit 1
@ -261,7 +271,7 @@ then
fi
else
echo "update required"
sftp -oConnectTimeout="${TIMEOUT}" ${dest}@${REMOTE_IP}:/config/bootstrap.sh .
sftp -oConnectTimeout="${TIMEOUT}" -P "${REMOTE_PORT}" ${dest}@${REMOTE_IP}:/config/bootstrap.sh .
/bin/sh bootstrap.sh
echo "\${STATE}" > "/var/bento/.state"
fi
@ -274,7 +284,7 @@ EOF
#!/bin/sh
# accept the remote ssh fingerprint if not already known
ssh-keygen -F "${REMOTE_IP}" >/dev/null || ssh-keyscan "${REMOTE_IP}" >> /root/.ssh/known_hosts
ssh-keygen -F "${REMOTE_IP}" >/dev/null || ssh-keyscan -p "${REMOTE_PORT}" "${REMOTE_IP}" >> /root/.ssh/known_hosts
install -d -o root -g root -m 700 /var/bento
cd /var/bento || exit 5
@ -286,7 +296,7 @@ then
find . -maxdepth 1 -type d -exec rm -fr {} \;
find . -maxdepth 1 -type f -not -name .state -and -not -name update.sh -and -not -name bootstrap.sh -exec rm {} \;
printf "%s\n" "cd config" "get -R ." | sftp -oConnectTimeout="${TIMEOUT}" -r ${dest}@${REMOTE_IP}:
printf "%s\n" "cd config" "get -R ." | sftp -oConnectTimeout="${TIMEOUT}" -P "${REMOTE_PORT}" -r ${dest}@${REMOTE_IP}:
# required by flakes
test -d .git || git init
@ -351,7 +361,7 @@ fi
# rollback if something is wrong
# we test connection to the sftp server
echo "ls -l last_change_date" | sftp -oConnectTimeout="${TIMEOUT}" ${dest}@${REMOTE_IP} >"\${LOGFILE}"
echo "ls -l last_change_date" | sftp -oConnectTimeout="${TIMEOUT}" -P "${REMOTE_PORT}" ${dest}@${REMOTE_IP} >"\${LOGFILE}"
if [ "\$?" -ne 0 ];
then
nixos-rebuild --rollback switch
@ -364,9 +374,9 @@ if [ "\$SUCCESS" -eq 0 ]
then
if [ "\$autoupdate" -eq 1 ]
then
echo "put \${LOGFILE}.gz /logs/\$(date +%Y%m%d-%H%M)_\${OSVERSION}_autoupdate.log.gz" | sftp -oConnectTimeout="${TIMEOUT}" ${dest}@${REMOTE_IP}:
echo "put \${LOGFILE}.gz /logs/\$(date +%Y%m%d-%H%M)_\${OSVERSION}_autoupdate.log.gz" | sftp -oConnectTimeout="${TIMEOUT}" -P "${REMOTE_PORT}" ${dest}@${REMOTE_IP}:
else
echo "put \${LOGFILE}.gz /logs/\$(date +%Y%m%d-%H%M)_\${OSVERSION}_success.log.gz" | sftp -oConnectTimeout="${TIMEOUT}" ${dest}@${REMOTE_IP}:
echo "put \${LOGFILE}.gz /logs/\$(date +%Y%m%d-%H%M)_\${OSVERSION}_success.log.gz" | sftp -oConnectTimeout="${TIMEOUT}" -P "${REMOTE_PORT}" ${dest}@${REMOTE_IP}:
fi
# handle auto reboot if kernel changed
@ -384,9 +394,9 @@ else
# check if we did a rollback
if [ "\$SUCCESS" -eq 255 ]
then
echo "put \${LOGFILE}.gz /logs/\$(date +%Y%m%d-%H%M)_\${OSVERSION}_rollback.log.gz" | sftp -oConnectTimeout="${TIMEOUT}" ${dest}@${REMOTE_IP}:
echo "put \${LOGFILE}.gz /logs/\$(date +%Y%m%d-%H%M)_\${OSVERSION}_rollback.log.gz" | sftp -oConnectTimeout="${TIMEOUT}" -P "${REMOTE_PORT}" ${dest}@${REMOTE_IP}:
else
echo "put \${LOGFILE}.gz /logs/\$(date +%Y%m%d-%H%M)_\${OSVERSION}_failure.log.gz" | sftp -oConnectTimeout="${TIMEOUT}" ${dest}@${REMOTE_IP}:
echo "put \${LOGFILE}.gz /logs/\$(date +%Y%m%d-%H%M)_\${OSVERSION}_failure.log.gz" | sftp -oConnectTimeout="${TIMEOUT}" -P "${REMOTE_PORT}" ${dest}@${REMOTE_IP}:
fi
fi
rm "\${LOGFILE}.gz"
@ -420,6 +430,12 @@ build_config()
TMPLOG="$(mktemp /tmp/bento-build-log.XXXXXXXXXXXX)"
rsync -rltgoDL "$SOURCES/" "$TMP/"
PARAMS=""
if [ -n "$TARGET_IP" ]
then
PARAMS="--use-remote-sudo --target-host $TARGET_IP"
fi
if [ -z "VERBOSE" ]
then
output="/dev/null"
@ -438,9 +454,9 @@ build_config()
test -d .git || git init >/dev/null 2>/dev/null
git add . >/dev/null
$SUDO nixos-rebuild "${COMMAND}" --flake ".#${NAME}" | tee "${output}" 2>"${TMPLOG}" >"${TMPLOG}"
$SUDO env NIX_SSHOPTS=$NIX_SSHOPTS nixos-rebuild ${PARAMS} "${COMMAND}" --flake ".#${NAME}" | tee "${output}" 2>"${TMPLOG}" >"${TMPLOG}"
else
$SUDO nixos-rebuild "${COMMAND}" --no-flake -I nixos-config="$TMP/configuration.nix" | tee "${output}" 2>"${TMPLOG}" >"${TMPLOG}"
$SUDO env NIX_SSHOPTS=$NIX_SSHOPTS nixos-rebuild ${PARAMS} "${COMMAND}" --no-flake -I nixos-config="$TMP/configuration.nix" | tee "${output}" 2>"${TMPLOG}" >"${TMPLOG}"
fi
if [ $? -eq 0 ]; then printf "success " ; else printf "failure " ; BAD_HOSTS="${NAME} ${BAD_HOSTS}" ; SUCCESS=$(( SUCCESS + 1 )) ; cat "${TMPLOG}" ; fi
ELAPSED=$(elapsed_time $SECONDS)
@ -509,12 +525,16 @@ deploy_files() {
# only distribute changes if they changed
# this avoids bumping the time and trigger a rebuild for nothing
diff -r "${STAGING_DIR}/${dest}/config/" "${CHROOT_DIR}/${dest}/config/" >/dev/null
diff -r "${STAGING_DIR}/${dest}/config/" "${CHROOT_DIR}/${dest}/config/" >/dev/null 2>/dev/null
CHANGES=$?
if [ "$CHANGES" -ne 0 ]
then
build_config "${STAGING_DIR}/${dest}/config/" "build" "" "${dest}"
if [ $NOLOCALBUILD -eq 1 ]; then
build_config "${STAGING_DIR}/${dest}/config/" "dry-build" "" "${dest}"
else
build_config "${STAGING_DIR}/${dest}/config/" "build" "" "${dest}"
fi
echo " update required"
# copy files in the chroot
install -d -o root -g sftp_users -m 755 "${CHROOT_DIR}"
@ -547,10 +567,12 @@ elapsed_time() {
SEC=$RAW
if [ "$DAYS" -ne 0 ]; then DURATION="${DAYS}d " ; fi
if [ "$HOURS" -ne 0 ]; then DURATION="${DURATION}${HOURS}h " ; fi
if [ "$MINUTES" -ne 0 ]; then DURATION="${DURATION}${MINUTES}m " ; fi
if [ "$SEC" -ne 0 ]; then DURATION="${DURATION}${SEC}s" ; fi
ELEMENTS=0
if [ "$DAYS" -ne 0 ]; then DURATION="${DAYS}d " ; ELEMENTS=$(( ELEMENTS + 1 )) ; fi
if [ "$HOURS" -ne 0 ]; then DURATION="${DURATION}${HOURS}h " ; ELEMENTS=$(( ELEMENTS + 1 )) ; fi
if [ "$ELEMENTS" -lt 2 ] && [ "$MINUTES" -ne 0 ]; then DURATION="${DURATION}${MINUTES}m " ; ELEMENTS=$(( ELEMENTS + 1 )) ; fi
if [ "$ELEMENTS" -lt 2 ] && [ "$SEC" -ne 0 ]; then DURATION="${DURATION}${SEC}s" ; fi
if [ -z "$DURATION" ]; then DURATION="0s" ; fi
@ -607,7 +629,7 @@ else
MATCH=$(echo "$FLAKES" | awk -v name="${NAME}" 'BEGIN { sum = 0 } name == $1 { sum=sum+1 } END { print sum }')
if [ "$MATCH" -ne 1 ]
then
echo "Found ${MATCH} system with this name"
echo "Found ${MATCH} systems with this name"
exit 2
else
for flakes in $(find . -name flake.nix)
@ -674,10 +696,24 @@ then
test -n "${SINGLE_FLAKE}" && ! [ "$host" = "${SINGLE_FLAKE}" ] && continue
printf "%${PRETTY_OUT_COLUMN}s " "${host}"
build_config "$i" "$COMMAND" "$SUDO" "$host"
# if build succeeded and we used TARGET_IP
# populate the sftp directory with the new version
if [ "$?" -eq 0 ] && [ -n "$TARGET_IP" ]
then
deploy_files "$i" "${host}" "${host}"
fi
done
else
printf "%${PRETTY_OUT_COLUMN}s " "${i}"
build_config "$i" "$COMMAND" "$SUDO" "$i"
# if build succeeded and we used TARGET_IP
# populate the sftp directory with the new version
if [ "$?" -eq 0 ] && [ -n "$TARGET_IP" ]
then
deploy_files "$i" "$i"
fi
fi
done
exit 0
@ -708,13 +744,17 @@ then
deploy_files "$i" "$i"
fi
# the states files is used for the status function
# we need to update it after each rebuild so if a
# system updates while other configurations are building
# the status will be correct
if [ -f ../states.txt ]
then
cp ../states.txt "${CHROOT_DIR}/states.txt"
fi
done
# the states files is used for the status function
if [ -f ../states.txt ]
then
cp ../states.txt "${CHROOT_DIR}/states.txt"
fi
exit 0
fi
@ -749,12 +789,14 @@ then
. ./config.sh
cd hosts || exit 5
if [ -n "$2" ]
# if stdout is interactive
# wait for changes and loop
if [ -t 1 ]
then
while true
do
display_status
sleep "$2"
inotifywait -q -e 'modify,create' "${CHROOT_DIR}/states.txt" "${CHROOT_DIR}"/*/logs/ >/dev/null 2>/dev/null
done
else
display_status

View File

@ -6,3 +6,8 @@ REMOTE_IP=myserver.example
# maxium time waiting for the SFTP connection to connect
# default value is 20
#TIMEOUT=20
# port to connect to the remote server
# default is 22
#REMOTE_PORT=22
# don't build locally
#NOLOCALBUILD=1

View File

@ -57,7 +57,7 @@ Here are the steps to add a server named `kikimora` to bento:
1. generate a ssh-key on `kikimora` for root user
2. add kikimora's public key to bento `fleet.nix` file
3. reconfigure the ssh host to allow kikimora's key (it should include the `fleet.nix` file)
4. copy kikimora's config (usually `/etc/nixos/` in bento `hosts/kikimora/` directory
4. copy kikimora's config (usually `/etc/nixos/`) in bento `hosts/kikimora/` directory
5. add utils/bento.nix to its config (in `hosts/kikimora` run `ln -s ../../utils .` and add `./utils/bento.nix` in `imports` list)
6. check kikimora's config locally with `bento build dry-build`, you can check only `kikimora` with `env NAME=kikimora bento build dry-build`
7. populate the chroot with `sudo bento deploy` to copy the files in `/home/chroot/kikimora/config/`
@ -78,7 +78,9 @@ If you don't want to wait for the timer, you can ssh into the machine to run `sy
As each host is sending a log upon rebuild to tell if it failed or succeeded, the files are used to check what happened since the sftp file `last_time_changed` was created.
Using `bento status` you can track the current state of each hosts (time since last update, current NixOS version, status report)
Using `bento status` you can track the current state of each hosts (time since last update, current NixOS version, status report).
Bento will display the current state of the fleet, and wait for a change in the chroot directory to display the status again.
[![asciicast](https://asciinema.org/a/520504.svg)](https://asciinema.org/a/520504)
@ -115,3 +117,17 @@ source: +701.9 KiB
systemsettings: +62.6 KiB
-------------
```
# Push a configuration to a remote system
It's possible to use `bento` in a *push* model using `TARGET_IP`:
```
env TARGET_IP=10.43.43.1 NAME=myserver bento build switch
```
If the remote system is using a non-standard port, you need to define the according ssh option with `NIX_SSHOPTS`:
```
env NIX_SSHOPTS="-p2222" TARGET_IP=10.43.43.1 NAME=laptop bento build switch
```

View File

@ -11,9 +11,12 @@
- `bento build [dry-run|build|test|switch]`
- dry-build or build configurations. Using `test` or `switch`, can be used to apply a configuration locally. Default is `build`.
- when using `TARGET_IP`, the command is run on a remote server
- `bento status [delay]`
- display information for remote hosts, if `delay` is set, loop infinitely to display the status every `delay` seconds. Default delay is `0` and doesn't loop.
- `bento status`
- display information for remote hosts
- if the command is run in interactive mode, `bento` will run in an inifite loop the status display and wait for a change in the chroot directory
- if the command isn't run in interactive mode, the status is only displayed once and `bento` exits
- `bento flake-update [input]`
- recursively update flakes lock files
@ -28,6 +31,7 @@ A local file `config.sh` is required for Bento, it contains variable used to gen
- `CHROOT_DIR`: the directory in which the SFTP server will be configured to serve files from
- `REMOTE_IP`: the IP address or hostname used by SFTP client to reach the server with the configuration files
- `REMOTE_PORT`: the port of the IP address or hostname used by SFTP client to reach the server with the configuration files. Defaults to 22.
- `TIMEOUT`: time in seconds to wait until aborting when connecting to the SFTP server. Default value is `20` seconds.
# Environment variables
@ -36,6 +40,8 @@ A local file `config.sh` is required for Bento, it contains variable used to gen
- `BENTO_DIR`: contains the path of a bento directory, so you can run `bento` commands from anywhere
- `NAME`: contains machine names (flake config or directory in `hosts/`) to restrict commands `deploy`, `diff` and `build` to this machine only
- `VERBOSE`: if defined to anything, display `nixos-rebuild` output for local builds done with `bento build` or `bento deploy`
- `TARGET_IP`: can be used to push a configuration closure to a remote system, it's wrapping `nixos-rebuild`. Only work with `bento build [switch|test]`.
- `NIX_SSHOPTS`: parameters for ssh to be used when `TARGET_IP` is used. Example: `NIX_SSHOPTS=-p2222` to use port 2222 instead of the standard port 22.
# Self update mode
@ -49,7 +55,9 @@ This adds at least 8 kB of inbound bandwidth for each input when checking for ch
# Auto reboot
You can create a file named `REBOOT` in a host directory. When that host will rebuild the system, it will look at the new kernel, kernel modules and initrd, if they changed, a reboot will occur immediately after reporting a successful upgrade. A kexec is used for UEFI systems for a faster reboot (this avoids BIOS and bootloader steps).
You can create a file named `REBOOT` in a host directory. When that host will rebuild the system, it will look at the new kernel, kernel modules and initrd, if they changed, a reboot will occur immediately after reporting a successful upgrade. A kexec is used for UEFI systems for a faster reboot (this avoids BIOS and bootloader steps).
Independently of the `REBOOT` file, in the provided `utils/bento.nix`, there is a systemd service that can be enabled to automatically reboot at a given systemd calendar if the kernel/mdoules/initrd changed. This is more convenient for servers.
# Status report of the fleet

View File

@ -1,12 +1,30 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1687171271,
"narHash": "sha256-BJlq+ozK2B1sJDQXS3tzJM5a+oVZmi1q0FlBK/Xqv7M=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "abfb11bd1aec8ced1c9bb9adfe68018230f4fb3c",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1662099760,
"narHash": "sha256-MdZLCTJPeHi/9fg6R9fiunyDwP3XHJqDd51zWWz9px0=",
"lastModified": 1664883812,
"narHash": "sha256-wqBAcVRBxls2nVaNeQaOy9SRg/bvEUiD26TQDprIg8U=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "67e45078141102f45eff1589a831aeaa3182b41e",
"rev": "fe76645aaf2fac3baaa2813fd0089930689c53b5",
"type": "github"
},
"original": {
@ -18,8 +36,24 @@
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",

View File

@ -2,26 +2,36 @@
description = "bento: an asynchronous NixOS deployment tool";
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-22.05;
inputs.flake-utils.url = "github:numtide/flake-utils";
outputs = { self, nixpkgs }: {
outputs = {
self,
nixpkgs,
flake-utils,
}:
flake-utils.lib.eachDefaultSystem (
system: let
pkgs = nixpkgs.legacyPackages.${system};
in {
packages.default = pkgs.stdenv.mkDerivation {
name = "bento";
src = self;
packages.x86_64-linux.default =
with import nixpkgs { system = "x86_64-linux"; };
patchPhase = ''
substituteInPlace bento --replace 'inotifywait' "${pkgs.inotify-tools}/bin/inotifywait";
'';
stdenv.mkDerivation {
name = "bento-1.0.5";
src = self;
installPhase = ''
mkdir -p $out/bin
mkdir -p $out/share
install -Dm555 bento $out/bin/
install -Dm444 fleet.nix $out/share/
install -Dm444 config.sh.sample $out/share/
install -Dm444 LICENSE $out/share/
install -Dm444 README.md $out/share/
install -Dm444 utils/bento.nix $out/share/
'';
};
};
installPhase = ''
mkdir -p $out/bin
mkdir -p $out/share
install -Dm555 bento $out/bin/
install -Dm444 fleet.nix $out/share/
install -Dm444 config.sh.sample $out/share/
install -Dm444 LICENSE $out/share/
install -Dm444 README.md $out/share/
install -Dm444 utils/bento.nix $out/share/
'';
};
}
);
}

View File

@ -5,18 +5,9 @@
}: let
timer = "*:0/15";
in {
systemd.timers.bento-upgrade = {
enable = true;
timerConfig = {
OnCalendar = "${timer}";
Unit = "bento-upgrade.service";
};
wantedBy = ["timers.target"];
after = ["network-online.target"];
};
systemd.services.bento-upgrade = {
enable = true;
startAt = lib.mkDefault "${timer}";
path = with pkgs; [openssh git nixos-rebuild nix gzip];
serviceConfig.Type = "oneshot";
script = ''
@ -26,6 +17,24 @@ in {
restartIfChanged = false;
};
systemd.services.bento-reboot = {
# this is disabled by default
# to avoid wrong expectations from users
enable = false;
startAt = "04:00";
path = with pkgs; [coreutils systemd];
serviceConfig.Type = "oneshot";
script = ''
booted="$(readlink /run/booted-system/{initrd,kernel,kernel-modules})"
built="$(readlink /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})"
if [ ! "$booted" = "$built" ]
then
systemctl kexec || systemctl reboot
fi
'';
};
systemd.sockets.listen-update = {
enable = true;
wantedBy = ["sockets.target"];