Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split up jlmkr.py into smaller files as-is #233

Merged
merged 58 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
109491c
Initialize developer environment
jonct Jul 13, 2024
47f332b
Introduce a formal build system
jonct Jul 15, 2024
de5223f
Shift script path awareness to the exterior zipapp
jonct Jul 15, 2024
351cef7
Extract the config file parser
jonct Jul 15, 2024
34f2164
Name modules in snake_case
jonct Jul 15, 2024
18150bf
Bypass root ownership check by setting JLMKR_DEBUG
jonct Jul 15, 2024
c155404
Run basic lint/style check during build action
jonct Jul 15, 2024
b25c964
Extract jail dataset utils
jonct Jul 15, 2024
2718c89
Extract more config parser
jonct Jul 15, 2024
a6c5ebb
Extract more config parser
jonct Jul 15, 2024
461cdf7
Extract parent dataset utils
jonct Jul 15, 2024
f2a020f
Extract console utils
jonct Jul 15, 2024
1461af8
Extract list action
jonct Jul 15, 2024
36ba561
Extract filesystem path inference utils
jonct Jul 15, 2024
b7a6fdd
Extract chroot utils
jonct Jul 15, 2024
673e77e
Extract more jail dataset utils
jonct Jul 15, 2024
3a83392
Extract file utils
jonct Jul 15, 2024
c523974
Extract start action
jonct Jul 15, 2024
ef479d7
Extract stop action
jonct Jul 15, 2024
d26e8cc
Extract restart action
jonct Jul 15, 2024
dbb3dd4
Extract exec action
jonct Jul 15, 2024
f686bbb
Extract shell action
jonct Jul 15, 2024
f29e0bc
Extract status action
jonct Jul 15, 2024
a08149d
Extract log action
jonct Jul 15, 2024
a0c0599
Extract download utils
jonct Jul 15, 2024
ff2416b
Extract images action
jonct Jul 15, 2024
fbf6e4d
Extract default configuration data
jonct Jul 15, 2024
1c0a7a4
Extract create action
jonct Jul 15, 2024
58e8b10
Extract remove action
jonct Jul 15, 2024
25100ef
Extract text editor utils
jonct Jul 15, 2024
7e6754c
Extract edit action
jonct Jul 15, 2024
3125b13
Rename dataset utils
jonct Jul 15, 2024
2feb873
Extract startup action
jonct Jul 15, 2024
3a0fb92
Extract command-line dispatch
jonct Jul 15, 2024
b52e5a4
Nip and tuck; tidy and sort
jonct Jul 15, 2024
49f751f
Restore CLI dependencies
jonct Jul 15, 2024
9eddfce
Fix CLI non-root developer mode
jonct Jul 15, 2024
8769d30
Restore config parser dependencies
jonct Jul 15, 2024
22cb05a
Restore dataset util dependency
jonct Jul 15, 2024
c554673
Restore download util dependencies
jonct Jul 15, 2024
80f6c0e
Remove unused dependency from zip builder
jonct Jul 15, 2024
7e07121
Realign create action dependencies
jonct Jul 15, 2024
a1aaea8
Drop unused edit action dependency
jonct Jul 15, 2024
6d64562
Restore list action dependency
jonct Jul 15, 2024
8dae934
Drop unused restart action dependencies
jonct Jul 15, 2024
c41ac9c
Restore start action dependencies
jonct Jul 15, 2024
a385453
Improve the developer bootstrap docs
jonct Jul 15, 2024
d4bc1c8
Add missing imports
Jip-Hop Jul 16, 2024
2266d89
Restore jlmkr.py to make tests happy
Jip-Hop Jul 16, 2024
1679d27
Chown files as root
Jip-Hop Jul 16, 2024
9bdcfed
Fix import
Jip-Hop Jul 16, 2024
2256d31
Run jlmkr as zipapp
Jip-Hop Jul 16, 2024
5e78f3e
Fail early
Jip-Hop Jul 16, 2024
67f3f45
Add apt-get update
Jip-Hop Jul 16, 2024
9d10898
Use python 3.11
Jip-Hop Jul 16, 2024
22ea984
Upload build artifact
Jip-Hop Jul 16, 2024
962b238
Remove Hatch
Jip-Hop Jul 16, 2024
0b96723
Update README.md
Jip-Hop Jul 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,24 @@ jobs:
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: '3.11' # TrueNAS SCALE 24.04 Dragonfish
- name: Tune GitHub-hosted runner network
uses: smorimoto/tune-github-hosted-runner-network@v1

# Create a network namespace in the GitHub-hosted runner VM,
# simulating a primary bridge network on TrueNAS SCALE
- name: Set up networking resources
- name: Install packages and setup networking
run: |
sudo -s <<END
set -euo pipefail

systemctl disable systemd-resolved --now
rm /etc/resolv.conf
echo 'nameserver 1.1.1.1' > /etc/resolv.conf

apt-get update
apt-get install -qq -y systemd-container

cat <<NETWORKCONFIG >/etc/systemd/network/10-br1.network
Expand Down Expand Up @@ -82,11 +86,20 @@ jobs:
# zpool --version
# END

- name: Build
run: |
python3 -m zipapp src/jlmkr -p "/usr/bin/env python3" -o jlmkr

- uses: actions/upload-artifact@v4
with:
path: jlmkr

# Run multiple commands using the runners shell
- name: Run the test script
env:
PYTHONUNBUFFERED: 1
run: |
sudo chown 0:0 jlmkr.py ./test/test-jlmkr
set -euo pipefail
sudo chown 0:0 jlmkr ./test/test-jlmkr
sudo bash ./test/test-jlmkr
sudo ./test/test.sh
23 changes: 22 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# SPDX-FileCopyrightText: © 2024 Jip-Hop and the Jailmakers <https://github.com/Jip-Hop/jailmaker>
#
# SPDX-License-Identifier: LGPL-3.0-only

dist/

# jail-specific
/.lxc/
/jails/
.DS_Store
jlmkr

# Mac-specific
.DS_Store
._.DS_Store

# <https://github.com/github/gitignore/blob/main/Python.gitignore>

/.venv/

__pycache__/
*.py[cod]

.pytest_cache/
.ruff_cache/
79 changes: 44 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Persistent Linux 'jails' on TrueNAS SCALE to install software (k3s, docker, port

## Summary

TrueNAS SCALE can create persistent Linux 'jails' with systemd-nspawn. This script helps with the following:
TrueNAS SCALE can create persistent Linux 'jails' with systemd-nspawn. This app helps with the following:

- Setting up the jail so it won't be lost when you update SCALE
- Choosing a distro (Debian 12 strongly recommended, but Ubuntu, Arch Linux or Rocky Linux seem good choices too)
Expand All @@ -23,148 +23,157 @@ TrueNAS SCALE can create persistent Linux 'jails' with systemd-nspawn. This scri

## Installation

Beginning with 24.04 (Dragonfish), TrueNAS SCALE officially includes the systemd-nspawn containerization program in the base system. Technically there's nothing to install. You only need the `jlmkr.py` script file in the right place. [Instructions with screenshots](https://www.truenas.com/docs/scale/scaletutorials/apps/sandboxes/) are provided on the TrueNAS website. Start by creating a new dataset called `jailmaker` with the default settings (from TrueNAS web interface). Then login as the root user and download `jlmkr.py`.
Beginning with 24.04 (Dragonfish), TrueNAS SCALE officially includes the systemd-nspawn containerization program in the base system. Technically there's nothing to install. You only need the `jlmkr` app in the right place. [Instructions with screenshots](https://www.truenas.com/docs/scale/scaletutorials/apps/sandboxes/) are provided on the TrueNAS website. Start by creating a new dataset called `jailmaker` with the default settings (from TrueNAS web interface). Then login as the root user and download `jlmkr`.

TODO: update install instructions. For now one may clone or download the repo and run the below commands to create the `jlmkr` zipapp.

```shell
cd /mnt/mypool/jailmaker
curl --location --remote-name https://raw.githubusercontent.com/Jip-Hop/jailmaker/main/jlmkr.py
chmod +x jlmkr.py
rm -rf /tmp/jlmkr-build
mkdir -p /tmp/jlmkr-build
cd /tmp/jlmkr-build
curl -L https://github.com/Jip-Hop/jailmaker/archive/refs/heads/v3.0.0.tar.gz | tar xvz --strip-components=1
python3 -m zipapp src/jlmkr -p "/usr/bin/env python3" -o jlmkr
cp jlmkr /mnt/mypool/jailmaker/
```

The `jlmkr.py` script (and the jails + config it creates) are now stored on the `jailmaker` dataset and will survive updates of TrueNAS SCALE. If the automatically created `jails` directory is also a ZFS dataset (which is true for new users), then the `jlmkr.py` script will automatically create a new dataset for every jail created. This allows you to snapshot individual jails. For legacy users (where the `jails` directory is not a dataset) each jail will be stored in a plain directory.
Alternatively one may download and extract `jlmkr` from the build artifacts of the [GitHub Actions](https://github.com/Jip-Hop/jailmaker/actions).

The `jlmkr` app (and the jails + config it creates) are now stored on the `jailmaker` dataset and will survive updates of TrueNAS SCALE. If the automatically created `jails` directory is also a ZFS dataset (which is true for new users), then the `jlmkr` app will automatically create a new dataset for every jail created. This allows you to snapshot individual jails. For legacy users (where the `jails` directory is not a dataset) each jail will be stored in a plain directory.

### Alias

Optionally you may create a shell alias for the currently logged in (admin) user to conveniently run `jlmkr.py` without having to change into the `jailmaker` directory or specify the full absolute path. I suggest to create the `jlmkr` alias like this:
TODO: explain how to run `jlmkr` without using the absolute path. This probably involves building and releasing the `zipapp` on GitHub, downloading it into a directory added to the `PATH`. But this also requires the `jailmaker` directory to be configurable (instead of using the directory the `jlmkr` app itself is in) by using the `JAILMAKER_DIR` env variable.

```shell
echo "alias jlmkr=\"sudo -E '/mnt/mypool/jailmaker/jlmkr.py'\"" >> ~/.bashrc
```bash
mkdir /root/bin
cd /root/bin
curl -o jlmkr --location --remote-name https://some_url
chmod +x jlmkr
cd ../
echo 'export PATH="/root/bin:$PATH"' | tee -a .bashrc .zshrc
echo 'export JAILMAKER_DIR=/mnt/tank/path/to/desired/jailmaker/dir' | tee -a .bashrc .zshrc
```

Please replace `/mnt/mypool/jailmaker/` with the actual path to where you stored `jlmkr.py`. If you're using zsh instead of bash, then you should replace `.bashrc` in the command above with `.zshrc`. If you've created the alias, you may use it instead of `./jlmkr.py`.

The alias will be available the next time you load the shell, but to use the alias immediately you can `source ~/.bashrc` or `source ~/.zshrc`, as appropriate.

## Usage

### Create Jail

Creating a jail with the default settings is as simple as:

```shell
./jlmkr.py create --start myjail
./jlmkr create --start myjail
```

You may also specify a path to a config template, for a quick and consistent jail creation process.

```shell
./jlmkr.py create --start --config /path/to/config/template myjail
./jlmkr create --start --config /path/to/config/template myjail
```

Or you can override the default config by using flags. See `./jlmkr.py create --help` for the available options. Anything passed after the jail name will be passed to `systemd-nspawn` when starting the jail. See the `systemd-nspawn` manual for available options, specifically [Mount Options](https://manpages.debian.org/bookworm/systemd-container/systemd-nspawn.1.en.html#Mount_Options) and [Networking Options](https://manpages.debian.org/bookworm/systemd-container/systemd-nspawn.1.en.html#Networking_Options) are frequently used.
Or you can override the default config by using flags. See `./jlmkr create --help` for the available options. Anything passed after the jail name will be passed to `systemd-nspawn` when starting the jail. See the `systemd-nspawn` manual for available options, specifically [Mount Options](https://manpages.debian.org/bookworm/systemd-container/systemd-nspawn.1.en.html#Mount_Options) and [Networking Options](https://manpages.debian.org/bookworm/systemd-container/systemd-nspawn.1.en.html#Networking_Options) are frequently used.

```shell
./jlmkr.py create --start --distro=ubuntu --release=jammy myjail --bind-ro=/mnt
./jlmkr create --start --distro=ubuntu --release=jammy myjail --bind-ro=/mnt
```

If you omit the jail name, the create process is interactive. You'll be presented with questions which guide you through the process.

```shell
./jlmkr.py create
./jlmkr create
```

After answering some questions you should have created your first jail (and it should be running if you chose to start it after creating)!

### Startup Jails on Boot

```shell
# Call startup using the absolute path to jlmkr.py
/mnt/mypool/jailmaker/jlmkr.py startup
# Call startup using the absolute path to jlmkr
/mnt/mypool/jailmaker/jlmkr startup
```

In order to start jails automatically after TrueNAS boots, run `/mnt/mypool/jailmaker/jlmkr.py startup` as Post Init Script with Type `Command` from the TrueNAS web interface. This will start all the jails with `startup=1` in the config file.
In order to start jails automatically after TrueNAS boots, run `/mnt/mypool/jailmaker/jlmkr startup` as Post Init Script with Type `Command` from the TrueNAS web interface. This will start all the jails with `startup=1` in the config file.

### Start Jail

```shell
./jlmkr.py start myjail
./jlmkr start myjail
```

### List Jails

See list of jails (including running, startup state, GPU passthrough, distro, and IP).

```shell
./jlmkr.py list
./jlmkr list
```

### Execute Command in Jail

You may want to execute a command inside a jail, for example manually from the TrueNAS shell, a shell script or a CRON job. The example below executes the `env` command inside the jail.

```shell
./jlmkr.py exec myjail env
./jlmkr exec myjail env
```

This example executes bash inside the jail with a command as additional argument.

```shell
./jlmkr.py exec myjail bash -c 'echo test; echo $RANDOM;'
./jlmkr exec myjail bash -c 'echo test; echo $RANDOM;'
```

### Edit Jail Config

```shell
./jlmkr.py edit myjail
./jlmkr edit myjail
```

Once you've created a jail, it will exist in a directory inside the `jails` dir next to `jlmkr.py`. For example `/mnt/mypool/jailmaker/jails/myjail` if you've named your jail `myjail`. You may edit the jail configuration file using the `./jlmkr.py edit myjail` command. This opens the config file in your favorite editor, as determined by following [Debian's guidelines](https://www.debian.org/doc/debian-policy/ch-customized-programs.html#editors-and-pagers) on the matter. You'll have to stop the jail and start it again with `jlmkr` for these changes to take effect.
Once you've created a jail, it will exist in a directory inside the `jails` dir next to `jlmkr`. For example `/mnt/mypool/jailmaker/jails/myjail` if you've named your jail `myjail`. You may edit the jail configuration file using the `./jlmkr edit myjail` command. This opens the config file in your favorite editor, as determined by following [Debian's guidelines](https://www.debian.org/doc/debian-policy/ch-customized-programs.html#editors-and-pagers) on the matter. You'll have to stop the jail and start it again with `jlmkr` for these changes to take effect.

### Remove Jail

Delete a jail and remove it's files (requires confirmation).

```shell
./jlmkr.py remove myjail
./jlmkr remove myjail
```

### Stop Jail

```shell
./jlmkr.py stop myjail
./jlmkr stop myjail
```

### Restart Jail

```shell
./jlmkr.py restart myjail
./jlmkr restart myjail
```

### Jail Shell

Switch into the jail's shell.

```shell
./jlmkr.py shell myjail
./jlmkr shell myjail
```

### Jail Status

```shell
./jlmkr.py status myjail
./jlmkr status myjail
```

### Jail Logs

View a jail's logs.

```shell
./jlmkr.py log myjail
./jlmkr log myjail
```

### Additional Commands

Expert users may use the following additional commands to manage jails directly: `machinectl`, `systemd-nspawn`, `systemd-run`, `systemctl` and `journalctl`. The `jlmkr` script uses these commands under the hood and implements a subset of their functions. If you use them directly you will bypass any safety checks or configuration done by `jlmkr` and not everything will work in the context of TrueNAS SCALE.
Expert users may use the following additional commands to manage jails directly: `machinectl`, `systemd-nspawn`, `systemd-run`, `systemctl` and `journalctl`. The `jlmkr` app uses these commands under the hood and implements a subset of their functions. If you use them directly you will bypass any safety checks or configuration done by `jlmkr` and not everything will work in the context of TrueNAS SCALE.

## Security

Expand Down Expand Up @@ -210,7 +219,7 @@ TODO: write comparison between systemd-nspawn (without `jailmaker`), LXC, VMs, D

## Incompatible Distros

The rootfs image `jlmkr.py` downloads comes from the [Linux Containers Image server](https://images.linuxcontainers.org). These images are made for LXC. We can use them with systemd-nspawn too, although not all of them work properly. For example, the `alpine` image doesn't work well. If you stick with common systemd based distros (Debian, Ubuntu, Arch Linux...) you should be fine.
The rootfs image `jlmkr` downloads comes from the [Linux Containers Image server](https://images.linuxcontainers.org). These images are made for LXC. We can use them with systemd-nspawn too, although not all of them work properly. For example, the `alpine` image doesn't work well. If you stick with common systemd based distros (Debian, Ubuntu, Arch Linux...) you should be fine.

## Filing Issues and Community Support

Expand Down
Loading