diff --git a/README.md b/README.md index 689a7ca..0b64b78 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,20 @@ jlmkr start myjail jlmkr list ``` +## Execute Command in Jail + +You may want to execute a command inside a jail, for example from a shell script or a CRON job. The example below executes the `env` command inside the jail. + +```shell +jlmkr exec myjail env +``` + +This example executes bash inside the jail with a command as additional argument. + +```shell +jlmkr exec myjail bash -c 'echo test; echo $RANDOM;' +``` + ## Edit Jail Config ```shell @@ -110,14 +124,6 @@ jlmkr log myjail 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 capabilities. 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. -### Run Command in Jail - -If you want to run a command inside a jail, for example from a shell script or a CRON job, you may use `systemd-run` with the `--machine` flag. The example below runs the `env` command inside the jail. - -``` -systemd-run --machine myjail --quiet --pipe --wait --collect --service-type=exec env -``` - ## Networking By default the jail will have full access to the host network. No further setup is required. You may download and install additional packages inside the jail. Note that some ports are already occupied by TrueNAS SCALE (e.g. 443 for the web interface), so your jail can't listen on these ports. This is inconvenient if you want to host some services (e.g. traefik) inside the jail. To workaround this issue when using host networking, you may disable DHCP and add several static IP addresses (Aliases) through the TrueNAS web interface. If you setup the TrueNAS web interface to only listen on one of these IP addresses, the ports on the remaining IP addresses remain available for the jail to listen on. diff --git a/jlmkr.py b/jlmkr.py index 8160cef..b984045 100755 --- a/jlmkr.py +++ b/jlmkr.py @@ -172,9 +172,17 @@ def passthrough_nvidia(gpu_passthrough_nvidia, systemd_nspawn_additional_args, j systemd_nspawn_additional_args += nvidia_mounts +def exec_jail(jail_name, cmd, args): + """ + Execute a command in the jail with given name. + """ + subprocess.run(['systemd-run', '--machine', jail_name, '--quiet', '--pipe', + '--wait', '--collect', '--service-type=exec', cmd] + args, check=True) + + def status_jail(jail_name): """ - Show the status of the systemd service wrapping the jail. + Show the status of the systemd service wrapping the jail with given name. """ # Alternatively `machinectl status jail_name` could be used subprocess.run(["systemctl", "status", f"{SYMLINK_NAME}-{jail_name}"]) @@ -987,6 +995,11 @@ def main(): help='open shell in running jail').add_argument( 'name', help='name of the jail') + exec_parser = subparsers.add_parser(name='exec', epilog=DISCLAIMER, + help='execute a command in the jail') + exec_parser.add_argument('name', help='name of the jail') + exec_parser.add_argument('cmd', help='command to execute') + subparsers.add_parser(name='status', epilog=DISCLAIMER, help='show jail status').add_argument( 'name', help='name of the jail') @@ -1023,7 +1036,7 @@ def main(): # Work relative to this script os.chdir(SCRIPT_DIR_PATH) - args = parser.parse_args() + args, additional_args = parser.parse_known_args() if args.subcommand == 'start': start_jail(args.name) @@ -1031,6 +1044,9 @@ def main(): elif args.subcommand == 'shell': shell_jail(args.name) + elif args.subcommand == 'exec': + exec_jail(args.name, args.cmd, additional_args) + elif args.subcommand == 'status': status_jail(args.name)