Compare commits

...

18 Commits

Author SHA1 Message Date
d2108276a0 Merge pull request '21-assist-in-env-setup' (#23) from 21-assist-in-env-setup into main
Reviewed-on: #23
2023-11-06 00:39:32 +00:00
ed441299bc fix(iso): Asking for an SSH pub key is mandatory with SSH daemon (#21) 2023-11-06 00:48:40 +01:00
37cafc1f20 fix(iso): Don't reassign settings_file locally (#21) 2023-11-06 00:25:47 +01:00
1bc09b7f8b refactor(os): Install paru-bin instead of paru (#21)
We straight up install paru-bi via its PKGBUILD from
AUR, we skip the additional step we used to do
where we first installed paru from its GitHub
project. This saves time and most importantly
scarce RAM that Rust otherwise needs during
paru compilation.

On systems with little RAM (as in 4 GiB) paru's
compilation process would sometimes fail when
/etc/makepkg.conf when its MAKEFLAGS was
set to use many cores e.g. via "-j$(nproc --ignore 1)".

Without the manual paru compilation step we now
don't need the ability anymore to
--replace-conflicting packages.
2023-11-05 23:29:54 +01:00
1b94e7e3b8 refactor(zbm): Ask for rerun (#21) 2023-11-05 16:57:50 +01:00
e39d60cb00 refactor(zbm): Exit after setting up vars (#21) 2023-11-05 16:55:06 +01:00
055f970f43 docs(zbm): Render asciinema gif with larger typeface (#21) 2023-11-05 16:41:15 +01:00
16e67c8b28 docs(zbm): Typo (#21) 2023-11-05 16:30:48 +01:00
4fb7a91703 docs(zbm): Link to giv instead of mp4 (#21) 2023-11-05 16:30:16 +01:00
2b5d4b4ec8 docs(zbm): Testing HTML image tag in Markdown (#21) 2023-11-05 16:28:17 +01:00
b885bde3c6 docs(zbm): Explain network device naming (#21) 2023-11-05 16:23:00 +01:00
316aa56a55 docs(zbm): Explain interactive questionnaire (#21) 2023-11-05 16:04:57 +01:00
39039ce3fd docs(zbm): No idea if IPv6 works (#21) 2023-11-05 04:53:52 +01:00
1183f3f025 refactor(iso): Rename .gitignore file (#21) 2023-11-05 04:53:17 +01:00
be76d6b0f8 feat(meta): Ignore loca settings file while testing (#21) 2023-11-05 04:52:21 +01:00
67ea72de51 feat(iso): Add setup function to generate answer file (#21) 2023-11-05 04:51:32 +01:00
9f3ada2a36 feat(iso): Parse arguments (#21) 2023-11-05 04:50:31 +01:00
28414af039 refactor(iso): Globally define name of settings file (#21) 2023-11-05 04:49:32 +01:00
3 changed files with 273 additions and 51 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
archzbm_settings.env

View File

@@ -99,7 +99,9 @@ The script will create a single ZFS zpool `zpool` on the zpool partition with da
## Options
The following options can be given either by exporting them as shell variables prior to script execution or in a file named `archzbm_settings.env` that lives in your current working directory where you're about to execute the script. File format is identical to shell variable assignments of the form `VAR=value` or `VAR='value'`.
The following options can be given either by exporting them as shell variables prior to script execution or in a file named `archzbm_settings.env` that lives in your current working directory where you're about to execute the script. You can walk yourself through an interactive questionnaire that helps create a valid `archzbm_settings.env` file. Check out [Command line setup help](#command-line-setup-help) for details on the questionnaire.
If you instead want to define settings yourself with an `archzbm_settings.env` file its file format is identical to shell variable assignments of the form `VAR=value` or `VAR='value'`.
If `./archzbm_settings.env` exists the script will `source` its content and `export` all variables for use in future steps.
@@ -149,6 +151,8 @@ By default the script configures plain ZFSBootMenu without networking nor an SSH
#### IP address
> IPv6 addresses are untested. Script has been confirmed working with IPv4 addresses.
```
ARCHZBM_NET_CLIENT_IP=''
ARCHZBM_NET_SERVER_IP=''
@@ -203,6 +207,18 @@ ARCHZBM_NET_DEVICE='eth0'
ARCHZBM_NET_AUTOCONF='dhcp'
```
> In ZFSBootMenu the device names that go into `ARCHZBM_NET_DEVICE` are raw unchanged kernel device names such as `eth0`. If you're unsure which device name to use in your Arch Linux live CD ISO image check `dmesg` output. During boot typically a kernel module will first assign the raw kernel device name then later `systemd` will enforce [Predictable Network Interface Names](https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/).
>
> In `dmesg | grep` on a physical PC with an MSI B550-A Pro mainboard from 2020 that comes with one onboard Realtek RTL8111H network adapter governed by the Realtek RTL-8169 Gigabit Ethernet driver from the `r8169` kernel module you will for example see:
> ```
> # dmesg -T | grep eth
> [time] r8169 0000:2a:00.0 eth0: RTL8168h/8111h, 04:7c:16:00:01:02, XID 541, IRQ 95
> [time] r8169 0000:2a:00.0 eth0: jumbo features [frames: 9194 bytes, tx checksumming: ko]
> [time] r8169 0000:2a:00.0 enp42s0: renamed from eth0
> ```
>
> Notice how a Predictable Network Interface Name comes in on line 3. What *__you__* need here is the `eth0` part.
#### SSH
If you want networking indicated by the fact that at least one of the `ARCHZBM_NET_*` variables is set or one of the `ARCHZBM_SSH_*` vars we assume that you want an SSH daemon as well. This comes in the form of a `dropbear` daemon with minimal configurability. Use the following variables to define Dropbear's behavior.
@@ -223,6 +239,24 @@ ssh-rsa Eahajei8,,ssh-ed25519 kaeD0mas ...
This syntax crutch allows you to use the full range of Dropbear-supported `authorized_keys` stanzas, see [man 8 dropbear](https://man.archlinux.org/man/extra/dropbear/dropbear.8.en) for what's available. Whether or not this is useful to you is another topic :) At least the functionality for stanzas is there by separating values in `ARCHZBM_SSH_AUTH_KEYS` with double-commas.
## Command line setup help
An interactive questionnaire can guide you through settings and goes like this:
![Command line setup questionnaire](https://i.imgur.com/RhCStdu.gif)
To do the questionnaire yourself start this script with the `setup` argument:
```
export SCRIPT_URL='https://quico.space/quico-os-setup/arch-zbm/raw/branch/main/setup.sh' && curl -s "${SCRIPT_URL}" | bash -s -- setup
```
When done rerun it without that argument:
```
export SCRIPT_URL='https://quico.space/quico-os-setup/arch-zbm/raw/branch/main/setup.sh' && curl -s "${SCRIPT_URL}" | bash
```
# Steps
The script takes the following installation steps.
@@ -286,7 +320,7 @@ After installation you're going to want to at least touch these points in your n
- Unless you had a settings file or exported shell env vars per [Passwords](#passwords) you're going to want to change passwords now:
- ZFS: The password for all datasets underneath `zpool` is `password`.
- Local `root` account: The local `root` account's password is `password`.
- Arch User Repository (AUR) helper: We installed [paru](https://github.com/Morganamilo/paru) as our AUR helper, we installed from GitHub via `makepkg -si` then replaced it with its [paru-bin](https://aur.archlinux.org/packages/paru-bin) version from AUR.
- Arch User Repository (AUR) helper: We installed [paru](https://github.com/Morganamilo/paru) as our AUR helper, we installed from AUR as [paru-bin](https://aur.archlinux.org/packages/paru-bin).
- In `/etc/systemd/network/50-wired.network` instead of a DHCP-based network config you can get a static one. The DHCP-based one for reference looks like:
```
...

285
setup.sh
View File

@@ -19,9 +19,10 @@ exec 3>&1
declare this_script_url
this_script_url="${SCRIPT_URL:?}"
declare zpool_name zfs_arch_dataset_name
declare zpool_name zfs_arch_dataset_name settings_file
zpool_name='zpool'
zfs_arch_dataset_name='archlinux'
settings_file='archzbm_settings.env'
declare -A partition_types
partition_types[gpt_zfs]='6a85cf4d-1dd2-11b2-99a6-080020736631'
@@ -35,6 +36,230 @@ trap '[ "$?" -ne 77 ] || exit 77' ERR
declare zpool_drive efi_drive boot_drive part_schema
function setup_env_vars () {
printf -- '%s\n' \
'We will go over a series of questions to create an answer file with' \
'options you want the script to use.' \
'' \
'Current working directory is:'\
"$(pwd)" \
'' \
'After we'"'"'re done answer file will be written to current working dir:' \
'./'"${settings_file}" \
'' \
'Press <Ctrl>+C to abort this process. No answer file will' \
'be written to ./'"${settings_file}"' if you abort the script.' \
'' \
'When done rerun the same command you just did without '"'"'setup'"'"' argument.' \
''
read -u3 -n 1 -s -r -p "Press any key to begin questionnaire"
echo
echo '----------------------------------------'
echo
echo "Do you want compressed datasets?"
select arg_compressed in "Compressed" "Uncompressed"; do
case "${arg_compressed}" in
Compressed)
break
;;
Uncompressed)
ARCHZBM_ZFSPROPS_NO_COMPRESSION='true'
break
;;
esac
done <&3 && echo
echo "Do you want encrypted datasets?"
select arg_encrypted in "Encrypted" "Unencrypted"; do
case "${arg_encrypted}" in
Encrypted)
break
;;
Unencrypted)
ARCHZBM_ZFSPROPS_NO_ENCRYPTION='true'
break
;;
esac
done <&3 && echo
if [[ "${arg_encrypted}" = 'Encrypted' ]]; then
echo "Do you want a custom dataset decryption password?"
select arg_custom_dataset_pw in "Yes" "No"; do
case "${arg_custom_dataset_pw}" in
Yes)
want_custom_dataset_pw='true'
break
;;
No)
break
;;
esac
done <&3 && echo
if [[ "${want_custom_dataset_pw}" ]]; then
read -u3 -p 'Please type password, confirm with <Enter>: ' -s ARCHZBM_ZPOOL_PASSWORD
echo
echo
fi
fi
echo "Do you want a custom 'root' user password?"
select arg_custom_root_pw in "Yes" "No"; do
case "${arg_custom_root_pw}" in
Yes)
want_custom_root_pw='true'
break
;;
No)
break
;;
esac
done <&3 && echo
if [[ "${want_custom_root_pw}" ]]; then
read -u3 -p 'Please type password, confirm with <Enter>: ' -s ARCHZBM_ROOT_PASSWORD
echo
echo
fi
echo "Do you want an SSH daemon in ZFSBootMenu?"
select arg_ssh_in_zbm in "Yes" "No"; do
case "${arg_ssh_in_zbm}" in
Yes)
want_ssh_in_zbm='true'
break
;;
No)
break
;;
esac
done <&3 && echo
if [[ "${want_ssh_in_zbm}" ]]; then
echo "How do you want to assign an IP address in ZFSBootMenu?"
select arg_ip_autoconf_method in "Statically" "Dynamically, DHCP" "Dynamically, BOOTP" "Dynamically, RARP"; do
case "${arg_ip_autoconf_method}" in
'Statically')
ARCHZBM_NET_AUTOCONF='none'
break
;;
'Dynamically, DHCP')
ARCHZBM_NET_AUTOCONF='dhcp'
break
;;
'Dynamically, BOOTP')
ARCHZBM_NET_AUTOCONF='bootp'
break
;;
'Dynamically, RARP')
ARCHZBM_NET_AUTOCONF='rarp'
break
;;
esac
done <&3 && echo
read -u3 -p 'Which device to configure (eth0 is a good guess): ' ARCHZBM_NET_DEVICE
echo
if [[ "${arg_ip_autoconf_method}" = 'Statically' ]]; then
read -u3 -p 'Interface IP address: ' ARCHZBM_NET_CLIENT_IP
echo
read -u3 -p 'Netmask: ' ARCHZBM_NET_NETMASK
echo
read -u3 -p 'Gateway IP address: ' ARCHZBM_NET_GATEWAY_IP
echo
fi
echo "Do you want a custom SSH listening port?"
select arg_custom_ssh_port in "Yes (let me specify)" "No (keep port 22)"; do
case "${arg_custom_ssh_port}" in
'Yes (let me specify)')
want_custom_ssh_port='true'
break
;;
'No (keep port 22)')
break
;;
esac
done <&3 && echo
if [[ "${want_custom_ssh_port}" ]]; then
read -u3 -p 'Please type SSH port, confirm with <Enter>: ' ARCHZBM_SSH_PORT
echo
fi
echo "Do you want the SSH daemon to use a custom keepalive send interval?"
select arg_custom_ssh_keepalive_intvl in "Yes (let me specify)" "No (keep 1)"; do
case "${arg_custom_ssh_keepalive_intvl}" in
'Yes (let me specify)')
want_custom_keepalive_intvl='true'
break
;;
'No (keep 1)')
break
;;
esac
done <&3 && echo
if [[ "${want_custom_keepalive_intvl}" ]]; then
read -u3 -p 'Please type server keepalive send interval, confirm with <Enter>: ' ARCHZBM_SSH_KEEPALIVE_INTVL
echo
fi
read -u3 -p 'Please type SSH pub keys on one line separated by double-commas (,,) and confirm with <Enter>: ' ARCHZBM_SSH_AUTH_KEYS
echo
fi
for env_var in 'ARCHZBM_ZFSPROPS_NO_COMPRESSION' 'ARCHZBM_ZFSPROPS_NO_ENCRYPTION' 'ARCHZBM_ZPOOL_PASSWORD' 'ARCHZBM_ROOT_PASSWORD' 'ARCHZBM_NET_AUTOCONF' 'ARCHZBM_NET_DEVICE' 'ARCHZBM_NET_CLIENT_IP' 'ARCHZBM_NET_NETMASK' 'ARCHZBM_NET_GATEWAY_IP' 'ARCHZBM_SSH_PORT' 'ARCHZBM_SSH_KEEPALIVE_INTVL' 'ARCHZBM_SSH_AUTH_KEYS'; do
if [[ "${!env_var}" ]]; then
printf -- '%s='"'"'%s'"'"'\n' \
"${env_var}" "${!env_var}" \
>> "${settings_file}"
fi
done
printf -- '%s\n' \
'Done, please rerun script now with just' \
'... | bash' \
'so without the '"'"'setup'"'"' argument's
exit 77
}
function arg_parse () {
[[ "${1}" ]] && while :; do
case "${1}" in
-[[:alnum:]]*)
>&3 printf -- '%s\n' \
'Short options '"'${1}'"' detected. Only known option is' \
'literal string '"'"'setup'"'"'. No idea what '"'${1}'"' is.' \
'Exiting ...'
exit 77
;;
--*)
>&3 printf -- '%s\n' \
'Long-form option '"'${1}'"' detected. Only known option is' \
'literal string '"'"'setup'"'"'. No idea what '"'${1}'"' is.' \
'Exiting ...'
exit 77
;;
setup)
setup_env_vars
return
;;
*)
>&3 printf -- '%s\n' \
'Argument '"'${1}'"' detected. Only known option is literal' \
'string '"'"'setup'"'"'. No idea what '"'${1}'"' is.' \
'Exiting ...'
exit 77
;;
esac
done
}
function we_are_changerooted () {
if [ "$(stat -c '%d:%i' '/')" != "$(stat -c '%d:%i' '/proc/1/root/.')" ]; then
return 0
@@ -328,9 +553,8 @@ function export_pool () {
function load_settings_file () {
#1.8
local working_dir settings_file settings_abs
local working_dir settings_abs
working_dir="$(pwd)"
settings_file='archzbm_settings.env'
settings_abs="${working_dir}"'/'"${settings_file}"
if [[ -r "${settings_abs}" ]]; then
set -a
@@ -677,56 +901,17 @@ function get_aur_helper () {
usermod --append --groups 'wheel' 'build'
printf -- '%s\n' '%wheel ALL=(ALL:ALL) NOPASSWD: ALL' > '/etc/sudoers.d/10-wheel-group-no-passwd-prompt'
pushd /tmp
git clone 'https://aur.archlinux.org/paru.git'
chown -R 'build:' 'paru'
pushd 'paru'
git clone https://aur.archlinux.org/paru-bin.git
chown -R 'build:' 'paru-bin'
pushd 'paru-bin'
sudo --user 'build' makepkg -si --noconfirm
popd
rm -rf 'paru'
rm -rf 'paru-bin'
popd
}
function paru_install () {
declare -a paru_install_packages
[[ "${1}" ]] && while :; do
case "${1}" in
-[[:alnum:]]*)
>&3 printf -- '%s\n' \
'Short-form argument '"'${1}'"' not supported for function '"'${FUNCNAME[0]}()'"'. Only known accepted argument' \
'is '"'"'--replace-conflicting'"'"' without a value given. Exiting ...'
exit 77
;;
--replace-conflicting)
pacman_force_yes='true'
shift
continue
;;
--*)
>&3 printf -- '%s\n' \
'Long-form argument '"'${1}'"' not supported for function '"'${FUNCNAME[0]}()'"'. Only known accepted argument' \
'is '"'"'--replace-conflicting'"'"' without a value given. Exiting ...'
exit 77
;;
'')
# All arguments processed
break
;;
*)
paru_install_packages+=("${1}")
shift
;;
esac
done || {
>&3 printf -- '%s\n' \
'No argument '"'${1}'"' given for function '"'${FUNCNAME[0]}'"'. Exiting ...'
exit 77
}
if [[ "${pacman_force_yes}" ]]; then
yes 'y' | sudo --user 'build' paru -S "${paru_install_packages[@]}"
unset -v pacman_force_yes
else
sudo --user 'build' paru -S --noconfirm "${paru_install_packages[@]}"
fi
sudo --user build paru -S --noconfirm "${@}"
}
function configure_syslinux () {
@@ -988,7 +1173,6 @@ function install_os_in_chroot () {
unleash_makepkg #2.5
add_motd_getting_started_msg #2.6
get_aur_helper #2.7
paru_install --replace-conflicting 'paru-bin'
paru_install 'zfs-dkms' 'zfs-utils' 'jq'
hwclock --systohc
mkinitcpio -P
@@ -1137,6 +1321,9 @@ function finalize_os_setup () {
}
function main () {
if [[ "${#@}" -gt '0' ]]; then
arg_parse "${@}"
fi
if we_are_changerooted; then
install_os_in_chroot #2.2
else
@@ -1164,4 +1351,4 @@ function main () {
fi
}
main
main "${@}"