-
-
Save unique1984/fabcead63e0ff999a158a6e360f70220 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash | |
########################################################################################################### | |
# Bash Script of this Documentation : | |
# https://openzfs.github.io/openzfs-docs/Getting%20Started/Debian/Debian%20Bullseye%20Root%20on%20ZFS.html#debian-bullseye-root-on-zfs | |
# | |
# Copyright © 2022 - installer.sh | |
# Yasin Karabulak | |
# info@yasinkarabulak.com | |
# https://github.com/unique1984 | |
# | |
########################################################################################################### | |
# this will open step by step progress [ 1 / 0 ] | |
STEP_BY_STEP=1 | |
export RAID_TAGS=("" "mirror" "raidz1" "raidz2" "raidz3" "mirror" "raidz1" "raidz2" "raidz3") | |
export RAID_MINIMUM_DISKS=("1" "2" "2" "3" "4" "4" "4" "6" "8") | |
export RAID_TYPES=("[single | stripe] (RAID-0)" | |
"[mirror] (RAID-1)" | |
"[raidz1] (RAID-5)" | |
"[raidz2] (RAID-6)" | |
"[raidz3]" | |
"[mirror + stripe] (RAID-10)" | |
"[raidz1 + stripe] (RAID-50)" | |
"[raidz2 + stripe] (RAID-60)" | |
"[raidz3 + stripe]") | |
export RAID_EXPL=("(1+n)" | |
"(2+n)" | |
"(2+n)" | |
"(3+n)" | |
"(4+n)" | |
"(2+n)*X" | |
"(2+n)*X" | |
"(3+n)*X" | |
"(4+n)*X") | |
APT_SOURCES_HTTP=$( | |
cat <<EOF | |
deb http://deb.debian.org/debian/ bullseye main contrib non-free | |
deb-src http://deb.debian.org/debian/ bullseye main contrib non-free | |
deb http://deb.debian.org/debian/ bullseye-updates main contrib non-free | |
deb-src http://deb.debian.org/debian/ bullseye-updates main contrib non-free | |
deb http://deb.debian.org/debian-security bullseye-security main contrib | |
deb-src http://deb.debian.org/debian-security bullseye-security main contrib | |
EOF | |
) | |
export APT_SOURCES_HTTP | |
APT_SOURCES_HTTPS=$( | |
cat <<EOF | |
deb https://deb.debian.org/debian/ bullseye main contrib non-free | |
deb-src https://deb.debian.org/debian/ bullseye main contrib non-free | |
deb https://deb.debian.org/debian/ bullseye-updates main contrib non-free | |
deb-src https://deb.debian.org/debian/ bullseye-updates main contrib non-free | |
deb https://deb.debian.org/debian-security bullseye-security main contrib | |
deb-src https://deb.debian.org/debian-security bullseye-security main contrib | |
EOF | |
) | |
export APT_SOURCES_HTTPS | |
function dividerLine() { | |
echo -e "\n######################################################################" | |
echo -e "# $1" | |
echo -e "######################################################################\n" | |
} | |
function innerSeperator() { | |
echo -e "----------------------------------------------------------------------" | |
echo -e " $1" | |
echo -e "----------------------------------------------------------------------" | |
} | |
function amiAllowed() { | |
dividerLine "USE AT YOUR OWN RISK !!! THIS THING DOES BAD THINGS TO YOUR PHYSICAL HARD DRIVE !!!" | |
read -r -p "If you want to continue then [ Enter ]" | |
if [ "$(whoami)" != "root" ]; then | |
echo -e "$(whoami) !" | |
echo -e "Start this script as root!" | |
exit 1 | |
fi | |
} | |
function getPath { | |
FULL="$1" | |
F_PATH=${FULL%/*} | |
F_BASE=${FULL##*/} | |
F_NAME=${F_BASE%.*} | |
F_EXT=${F_BASE##*.} | |
# echo $F_PATH | |
# echo $F_BASE | |
# echo $F_NAME | |
# echo $F_EXT | |
} | |
function stepByStep() { | |
if [[ $STEP_BY_STEP -eq 1 ]]; then | |
echo -e "\n" | |
read -p "Function : $1 [ Press Enter to Continue ... ]" | |
echo -e "\n" | |
clear | |
return | |
fi | |
clear | |
} | |
function aptSourcesHttp() { | |
dividerLine "APT Sources HTTP" | |
if [ ! -z $1 ]; then | |
echo -e "${APT_SOURCES_HTTP}" >/mnt/etc/apt/sources.list | |
else | |
echo -e "${APT_SOURCES_HTTP}" >/etc/apt/sources.list | |
fi | |
stepByStep "aptSourcesHttp" | |
} | |
function aptSourcesHttps() { | |
dividerLine "APT Sources HTTPS" | |
if [ ! -z $1 ]; then | |
echo -e "${APT_SOURCES_HTTPS}" >/mnt/etc/apt/sources.list | |
else | |
echo -e "${APT_SOURCES_HTTPS}" >/etc/apt/sources.list | |
fi | |
stepByStep "aptSourcesHttps" | |
} | |
function aptUpdateUpgrade() { | |
dividerLine "Apt Update & Upgrade & Autoremove" | |
apt -qqq update -y | |
isAliveSystem=$(lsblk | grep -Po "^loop[0-9]+") | |
if [ -z "${isAliveSystem}" ]; then | |
apt -qq upgrade -y | |
apt -qq autoremove -y | |
fi | |
stepByStep "aptUpdateUpgrade" | |
} | |
function installBaseApps() { | |
dividerLine "System ZFS Build Applications Installation" | |
apt -qqq update -y | |
apt -qq install -y bash-completion debootstrap dpkg-dev dkms gdisk parted mdadm ovmf | |
apt -qq install -y zfsutils-linux | |
modprobe zfs | |
stepByStep "installBaseApps" | |
} | |
function selectSystemDisk() { | |
dividerLine "Selecting System Disk" | |
lsblk | grep -v -P "sr[0-9]+" | |
echo -e "\n" | |
read -r -p "Select the system disk wich is you are using right now e.g ( sda | vda | nvme ) without /dev/ : " SYSTEM_DISK | |
echo -e "\n" | |
if [ -z "${SYSTEM_DISK}" ]; then | |
unset SYSTEM_DISK | |
selectSystemDisk | |
return | |
fi | |
checkIsThereAdisk=$(lsblk | grep -v -P "sr[0-9]+" | grep -Po "^[a-z0-9]{3,}") | |
thereIs=0 | |
for i in $checkIsThereAdisk; do | |
if [ $i == "${SYSTEM_DISK}" ]; then | |
thereIs=1 | |
fi | |
done | |
if [[ $thereIs -eq 0 ]]; then | |
dividerLine "There is no such a disk like ${SYSTEM_DISK}" | |
unset SYSTEM_DISK | |
sleep 3 | |
selectSystemDisk | |
return | |
fi | |
innerSeperator "\n $(lsblk /dev/"${SYSTEM_DISK}")\n" | |
read -r -p "System disk is - /dev/${SYSTEM_DISK} - [ Enter / N ] : " systemDiskConfirm | |
if [ "${systemDiskConfirm}" == "N" ] || [ "${systemDiskConfirm}" == "n" ]; then | |
unset SYSTEM_DISK | |
unset systemDiskConfirm | |
selectSystemDisk | |
return | |
fi | |
# dividerLine "Disks Except System Disk" | |
disksExceptSystemDisk=$(lsblk | grep -v -P "sr[0-9]+" | grep -v "loop*" | grep -v "${SYSTEM_DISK}" | grep -Po '^[a-z0-9]+') | |
DISKS_EXCEPT_SYSTEM_DISK=() | |
DISKS_EXCEPT_SYSTEM_DISK_BY_ID=() | |
DISKS_EXCEPT_SYSTEM_DISK_BY_PATH=() | |
# innerSeperator "Disk Name\tDisk by-path\t\t\tDisk by-id" | |
DISK_COUNT=0 | |
for i in ${disksExceptSystemDisk}; do | |
# diskById=$(ls -l /dev/disk/by-id/ | grep -v "part[0-9]*" | grep -P "$i" | awk '{print $9}') | |
diskByPath=$(ls -l /dev/disk/by-path/ | grep -v "part[0-9]*" | grep -P "$i" | awk '{print $9}' | head -n 1) | |
# DISKS_EXCEPT_SYSTEM_DISK_BY_ID+=("${diskById}") | |
DISKS_EXCEPT_SYSTEM_DISK_BY_PATH+=("${diskByPath}") | |
# echo -e " $DISK_COUNT : $i\t${diskBypath}\t${diskById}\n" | |
DISK_COUNT=$((DISK_COUNT + 1)) | |
done | |
innerSeperator "Total : ( $DISK_COUNT ) disks except System Disk (${SYSTEM_DISK})" | |
# IFS=$'\n' sorted=($(sort <<<"${DISKS_EXCEPT_SYSTEM_DISK_BY_ID[*]}")) | |
# unset IFS | |
# DISKS_EXCEPT_SYSTEM_DISK_BY_ID=("${sorted[@]}") | |
IFS=$'\n' sorted=($(sort <<<"${DISKS_EXCEPT_SYSTEM_DISK_BY_PATH[*]}")) | |
unset IFS | |
DISKS_EXCEPT_SYSTEM_DISK_BY_PATH=("${sorted[@]}") | |
# for i in "${DISKS_EXCEPT_SYSTEM_DISK_BY_ID[@]}"; do | |
# DISKS_EXCEPT_SYSTEM_DISK+=($(ls -l /dev/disk/by-id/$i | grep -iPo "[a-z]{3,}$")) | |
# done | |
for i in "${DISKS_EXCEPT_SYSTEM_DISK_BY_PATH[@]}"; do | |
# echo -e $(ls -l /dev/disk/by-path/$i | grep -iPo "[a-z]{3,}$|[n]vme[0-9][a-z][0-9]$") | |
DISKS_EXCEPT_SYSTEM_DISK+=($(ls -l /dev/disk/by-path/$i | grep -iPo "[a-z]{3,}$|[n]vme[0-9][a-z][0-9]$")) | |
done | |
#echo -e "${DISKS_EXCEPT_SYSTEM_DISK[*]} \n" | |
#echo -e "${DISKS_EXCEPT_SYSTEM_DISK_BY_ID[*]} \n" | |
#echo -e "${DISKS_EXCEPT_SYSTEM_DISK_BY_PATH[*]} \n" | |
export SYSTEM_DISK | |
export DISK_COUNT | |
export DISKS_EXCEPT_SYSTEM_DISK | |
# export DISKS_EXCEPT_SYSTEM_DISK_BY_ID | |
export DISKS_EXCEPT_SYSTEM_DISK_BY_PATH | |
innerSeperator "Disk Name\t\tDisk by-path" | |
cnt=0 | |
for i in "${DISKS_EXCEPT_SYSTEM_DISK_BY_PATH[@]}"; do | |
echo -e "$cnt : ${DISKS_EXCEPT_SYSTEM_DISK[$cnt]}\t\t\t${DISKS_EXCEPT_SYSTEM_DISK_BY_PATH[$cnt]}" | |
cnt=$((cnt+1)) | |
done | |
stepByStep "selectSystemDisk" | |
} | |
function selectRaidType() { | |
dividerLine "Raid Type Selection" | |
length=${#RAID_TYPES[@]} | |
innerSeperator "Select the RAID Type\n\t[ n = (0,1,2,...inf) ]\n\t[ X = (1,2,3,...inf) ] :" | |
count=0 | |
for i in "${RAID_TYPES[@]}"; do | |
echo -e $count" : $i [ ${RAID_EXPL[$count]} ]\n" | |
count=$((count + 1)) | |
done | |
read -r -p "Select One [ 0 ] : " selectedRaid | |
if [ -z "${selectedRaid}" ]; then | |
selectedRaid=0 | |
fi | |
if [[ $selectedRaid -ge 0 ]] && [[ $selectedRaid -le $((length - 1)) ]]; then | |
echo -e "\n" | |
read -r -p "${RAID_TYPES[$selectedRaid]} is this true ? [ Y / n] : " selectedRaidConfirm | |
if [ -z "${selectedRaidConfirm}" ]; then | |
selectedRaidConfirm="Y" | |
fi | |
if [ ! -z "${selectedRaidConfirm}" ] && [ "${selectedRaidConfirm}" == "Y" ] || [ "${selectedRaidConfirm}" == "y" ]; then | |
# dividerLine "Selected Raid Configuration is \n\ | |
# \n\t${RAID_TYPES[$selectedRaid]}\ | |
# \n\n\tYou need at least ${RAID_EXPL[$selectedRaid]} disks!\n" | |
export SELECTED_RAID_CONF="${RAID_TYPES[$selectedRaid]}" | |
export selectedRaid | |
else | |
innerSeperator "Select between 0 and $((length - 1))" | |
unset count | |
unset selectedRaid | |
unset SELECTED_RAID_CONF | |
selectRaidType | |
return | |
fi | |
else | |
innerSeperator "Select between 0 and $((length - 1))" | |
unset count | |
unset selectedRaid | |
unset SELECTED_RAID_CONF | |
selectRaidType | |
return | |
fi | |
if [[ $DISK_COUNT -lt ${RAID_MINIMUM_DISKS[$selectedRaid]} ]]; then | |
dividerLine "Your disk count ( $DISK_COUNT ) is not supported ${SELECTED_RAID_CONF} setup ! at least ( ${RAID_MINIMUM_DISKS[$selectedRaid]} ) disks!" | |
sleep 3 | |
unset count | |
unset selectedRaid | |
unset SELECTED_RAID_CONF | |
selectRaidType | |
return | |
fi | |
stepByStep "selectRaidType" | |
} | |
function selectInstallationDisks() { | |
dividerLine "Installation Disks Selection" | |
innerSeperator "\nYour raid type is ${SELECTED_RAID_CONF}\n\n | |
Minimum Disks : ${RAID_MINIMUM_DISKS[$selectedRaid]}\n | |
Maximum Disks : ${RAID_EXPL[$selectedRaid]}\n | |
You Have : $DISK_COUNT disks !\n" | |
dividerLine "\n | |
For Example Your Raid Type is [raidz1 + stripe] (RAID-50) | |
You need at least 4 disks for this setup, the equation is : (2+n)*X | |
n = stands by disk count those append (default 0) | |
X = stands by Array count (default 2) | |
e.g You have 9 disks, for this setup, you can use : | |
---------- | |
n = 1 & X = 3 | |
(2+1)*3 = 9 Disks | |
---------- | |
n = 0 & X = 2 | |
(2+0)*2 = 4 Disks | |
---------- | |
n = 2 & X = 2 | |
(2+2)*2 = 8 Disks | |
---------- | |
\n" | |
canAppendable=$((DISK_COUNT - ${RAID_MINIMUM_DISKS[$selectedRaid]})) | |
dividerLine "Appendable disk count is : $canAppendable (array ignored)" | |
# check appendable disks if exists | |
if [[ $canAppendable -ge 0 ]]; then | |
case $selectedRaid in | |
# first disk is bootable except mirror (both) | |
0 | 1 | 2 | 3 | 4) # stripe | mirror | raidz1 | raidz2 | raidz3 | |
read -r -p " Add disk(s) to the conf | n = [ 0 - $canAppendable ] : " n | |
if [ -z $n ]; then | |
n=0 | |
fi | |
if [[ $n -gt $canAppendable ]]; then | |
dividerLine "Disk count can't be greater then $canAppendable" | |
sleep 3 | |
selectInstallationDisks | |
return | |
fi | |
x=1 | |
minimalDiskCountforSetup=${RAID_MINIMUM_DISKS[$selectedRaid]} | |
;; | |
# first array's all disks are bootable | |
5 | 6 | 7 | 8) # mirror + stripe | raidz1 + stripe | raidz2 + stripe | raidz3 + stripe | |
canAppendableForSetup=$((canAppendable / 2)) | |
read -r -p "Add disk(s) to the array | n = [ 0 - $canAppendableForSetup ] : " n | |
if [ -z $n ]; then n=0; fi | |
if [[ $n -gt $canAppendableForSetup ]]; then | |
dividerLine "Disk count can't be greater then $canAppendableForSetup" | |
sleep 3 | |
selectInstallationDisks | |
return | |
fi | |
minimalDiskCountforSetup=$((${RAID_MINIMUM_DISKS[$selectedRaid]} / 2)) | |
canCreateMinimalArray=$(((minimalDiskCountforSetup + n) * 2)) | |
if [[ $canCreateMinimalArray -gt $DISK_COUNT ]]; then | |
dividerLine "Can't create a minimal Array Using $canCreateMinimalArray disks for this setup" | |
sleep 3 | |
selectInstallationDisks | |
return | |
fi | |
howManyArrayCanCreate=$((DISK_COUNT / $((minimalDiskCountforSetup + n)))) | |
read -r -p "Add array(s) to the conf | X = [ 2 - $howManyArrayCanCreate ] : " x | |
if [ -z $x ]; then | |
x=2 | |
fi | |
if [[ $x -lt 2 ]]; then | |
dividerLine "Can't create an Array less then 2 selecting 2" | |
sleep 3 | |
x=2 | |
fi | |
if [[ $x -gt $howManyArrayCanCreate ]]; then | |
dividerLine "Can't create an Array greater then ($howManyArrayCanCreate)" | |
sleep 3 | |
selectInstallationDisks | |
return | |
fi | |
canCreateSettedupArray=$(((minimalDiskCountforSetup + n) * x)) | |
if [[ $canCreateSettedupArray -gt $DISK_COUNT ]]; then | |
dividerLine "Can't create an Array greater then the disk count ($DISK_COUNT)" | |
sleep 3 | |
selectInstallationDisks | |
return | |
fi | |
;; | |
*) # return | |
clear | |
selectInstallationDisks | |
return | |
;; | |
esac | |
fi | |
settedupDiskCount=$(((minimalDiskCountforSetup + n) * x)) | |
count=0 | |
setupMessage="Your Pool Setup Is :\n\n\tzpool create poolName \n" | |
for a in $(seq 1 $x); do | |
setupMessage+="\t\t\t${RAID_TAGS[$selectedRaid]}\t" | |
for d in $(seq 0 $((settedupDiskCount / x - 1))); do | |
setupMessage+="<disk$count> " | |
count=$((count + 1)) | |
done | |
setupMessage+="\n" | |
done | |
dividerLine "${setupMessage}" | |
read -r -p "Is This Setup Acceptable ? [ Y / n ] : " diskSetupConfirm | |
case $diskSetupConfirm in | |
"" | "Y" | "y") ;; | |
"N" | "n") | |
selectInstallationDisks | |
return | |
;; | |
*) | |
selectInstallationDisks | |
return | |
;; | |
esac | |
clear | |
dividerLine "INSTALLATION DISK SELECTION | |
Selected disks will be wiped and partitioned after this selection! | |
After partitioning we'll use the disk's PARTUUID info rather then block name (sdX), id name or parth name ...\n" | |
innerSeperator " | |
Select Disks for the ${RAID_TAGS[$selectedRaid]} configuration, | |
boot pool and root pool will be automatically configured. | |
[ Enter to select first $settedupDiskCount disk(s) ] | |
or | |
e.g (sda sdb sdc sdd ...) input dev names with space, | |
(selected disks will be processed given order!) | |
----- | |
*** All disks of 1st array has boot partition and boot pool. | |
*** striped (raid0 and all striped) configurations is exception, | |
First disk of the array has boot partition and boot pool, | |
\n" | |
innerSeperator "Disk By Dev Name" | |
for i in $(seq 0 $((${#DISKS_EXCEPT_SYSTEM_DISK[@]} - 1))); do | |
# echo -e "$i : ${DISKS_EXCEPT_SYSTEM_DISK[$i]}\t\t${DISKS_EXCEPT_SYSTEM_DISK_BY_ID[$i]}\n" | |
echo -e "$i : ${DISKS_EXCEPT_SYSTEM_DISK[$i]}\t\t${DISKS_EXCEPT_SYSTEM_DISK_BY_PATH[$i]}\n" | |
done | |
# echo -e "${DISKS_EXCEPT_SYSTEM_DISK[@]}" | |
# echo -e "${DISKS_EXCEPT_SYSTEM_DISK_BY_ID[@]}" | |
# echo -e "${DISKS_EXCEPT_SYSTEM_DISK_BY_PATH[@]}" | |
read -r -p "Select Installation Disks ($settedupDiskCount of them, use sdX names) [ Enter / input ] : " selectedDisks | |
# first time, seperated. After partition part UUID | |
BOOT_PARTED_DISKS=() | |
POOL_PARTED_DISKS=() | |
case ${selectedDisks} in | |
"") | |
SELECTED_DISKS=("${DISKS_EXCEPT_SYSTEM_DISK[@]}") | |
;; | |
[a-z0-9]*) | |
count=0 | |
for i in ${selectedDisks}; do | |
SELECTED_DISKS+=("$i") | |
done | |
# sayı ve isimleri kontrol et... | |
if [[ ${#SELECTED_DISKS[@]} -ne $settedupDiskCount ]]; then | |
clear | |
dividerLine " | |
You have to choose ($settedupDiskCount) piece of disk(s) | |
Raid Configuration is : ${RAID_TAGS[$selectedRaid]} configuration | |
Minimal disks \t : ($minimalDiskCountforSetup) | |
Appened disks \t : ($n) | |
Array count \t : ($x) | |
" | |
sleep 3 | |
selectInstallationDisks | |
return | |
fi | |
CONFIRM_SELECTED_DISKS=() | |
# ERROR_SELECTED_DISKS=() | |
for i in "${SELECTED_DISKS[@]}"; do | |
for d in "${DISKS_EXCEPT_SYSTEM_DISK[@]}"; do | |
if [ "$i" == "$d" ]; then | |
CONFIRM_SELECTED_DISKS+=("$i") | |
fi | |
done | |
done | |
# if [[ "${#ERROR_SELECTED_DISKS[@]}" -gt 0 ]]; then | |
# array_uniq=("$(printf "%s\n" "${ERROR_SELECTED_DISKS[@]}" | sort -u | tr '\n' ' ')") | |
# fi | |
if [[ "${#SELECTED_DISKS[@]}" != "${#CONFIRM_SELECTED_DISKS[@]}" ]]; then | |
clear | |
dividerLine " | |
There is a problem, we don't have some of these disks on the system ! | |
Selected Disks \t: ${SELECTED_DISKS[*]} | |
Disks on System\t: ${DISKS_EXCEPT_SYSTEM_DISK[*]} | |
" | |
unset CONFIRM_SELECTED_DISKS | |
unset ERROR_SELECTED_DISKS | |
unset array_uniq | |
sleep 3 | |
selectInstallationDisks | |
return | |
fi | |
;; | |
esac | |
count=0 | |
for a in $(seq 1 $x); do | |
for d in $(seq 0 $((settedupDiskCount / x - 1))); do | |
if [[ $a -eq 1 ]] && [ "${RAID_TAGS[$selectedRaid]}" != "" ]; then | |
BOOT_PARTED_DISKS+=("${SELECTED_DISKS[$count]}") | |
fi | |
if [[ $a -gt 1 ]] && [ "${RAID_TAGS[$selectedRaid]}" != "" ]; then | |
POOL_PARTED_DISKS+=("${SELECTED_DISKS[$count]}") | |
fi | |
if [[ $a -eq 1 ]] && [[ $d -eq 0 ]] && [ "${RAID_TAGS[$selectedRaid]}" == "" ]; then | |
BOOT_PARTED_DISKS+=("${SELECTED_DISKS[$count]}") | |
fi | |
if [[ $a -eq 1 ]] && [[ $d -gt 0 ]] && [ "${RAID_TAGS[$selectedRaid]}" == "" ]; then | |
POOL_PARTED_DISKS+=("${SELECTED_DISKS[$count]}") | |
fi | |
if [[ $a -gt 1 ]] && [[ $d -gt 0 ]] && [ "${RAID_TAGS[$selectedRaid]}" == "" ]; then | |
POOL_PARTED_DISKS+=("${SELECTED_DISKS[$count]}") | |
fi | |
count=$((count + 1)) | |
done | |
done | |
# confirm setup | |
innerSeperator "Boot parted disks are : \n\n\t${BOOT_PARTED_DISKS[*]}\n" | |
innerSeperator "Stripe parted disks are : \n\n\t${POOL_PARTED_DISKS[*]}\n" | |
echo -e "\n" | |
read -r -p "Confirm Installation Disk Setup [ Enter / n ] : " installationDisksConfirm | |
case "${installationDisksConfirm}" in | |
"n" | "N") | |
unset CONFIRM_SELECTED_DISKS | |
unset ERROR_SELECTED_DISKS | |
unset array_uniq | |
selectInstallationDisks | |
return | |
;; | |
esac | |
ARRAY_COUNT=$x | |
export ARRAY_COUNT | |
export BOOT_PARTED_DISKS | |
stepByStep "selectInstallationDisks" | |
} | |
function labelClear() { | |
dividerLine "ZFS Label Clear If Exist on Selected Disks" | |
for i in "${BOOT_PARTED_DISKS[@]}"; do | |
if [ ! -z $(grep "nvme[0-9][a-z][0-9]" <<< $i) ]; then | |
diskType="${i}p[0-9]+" | |
else | |
diskType="${i}[0-9]+" | |
fi | |
for d in $(lsblk | grep -v -P "sr[0-9]+" | grep -iPo "${diskType}"); do | |
innerSeperator "ZFS Label Clear on /dev/$d" | |
zpool labelclear -f "/dev/$d" | |
echo -e "\n" | |
done | |
done | |
for i in "${POOL_PARTED_DISKS[@]}"; do | |
if [ ! -z $(grep "nvme[0-9][a-z][0-9]" <<< $i) ]; then | |
diskType="${i}p[0-9]+" | |
else | |
diskType="${i}[0-9]+" | |
fi | |
for d in $(lsblk | grep -v -P "sr[0-9]+" | grep -iPo "${diskType}"); do | |
innerSeperator "ZFS Label Clear on /dev/$d" | |
zpool labelclear -f "/dev/$d" | |
echo -e "\n" | |
done | |
done | |
stepByStep "labelClear" | |
} | |
function wipeDisks() { | |
dividerLine "Wipe Partitions and Filesystem on Selected Disks" | |
for i in "${BOOT_PARTED_DISKS[@]}"; do | |
innerSeperator "Wipe Filesystem on /dev/$i" | |
wipefs -a "/dev/$i" | |
innerSeperator "Clear Partitions on /dev/$i" | |
sgdisk --zap-all "/dev/$i" | |
echo -e "\n" | |
done | |
for i in "${POOL_PARTED_DISKS[@]}"; do | |
innerSeperator "Wipe Filesystem on /dev/$i" | |
wipefs -a "/dev/$i" | |
innerSeperator "Clear Partitions on /dev/$i" | |
sgdisk --zap-all "/dev/$i" | |
echo -e "\n" | |
done | |
stepByStep "wipeDisks" | |
} | |
function createPartitions() { | |
dividerLine "Create Partitions on Selected Disks" | |
innerSeperator "BOOT DISKS ARE PARTITIONING" | |
for i in "${BOOT_PARTED_DISKS[@]}"; do | |
innerSeperator "UEFI Boot Partition on /dev/$i" | |
sgdisk -n2:1M:+512M -t2:EF00 "/dev/$i" # boot UEFI sdX2 | |
sleep 0.5 | |
innerSeperator "Boot Pool Partition on /dev/$i" | |
sgdisk -n3:0:+1G -t3:BF01 "/dev/$i" # boot pool sdX3 | |
sleep 0.5 | |
innerSeperator "Root Pool Partition on /dev/$i" | |
sgdisk -n4:0:0 -t4:BF00 "/dev/$i" #root pool sdX4 | |
sleep 0.5 | |
innerSeperator "Read the partition changes, inform the system!" | |
partprobe | |
sleep 0.5 | |
echo -e "\n" | |
done | |
innerSeperator "STRIPE DISK PARTITIONING" | |
for i in "${POOL_PARTED_DISKS[@]}"; do | |
innerSeperator "Root Pool Partition on /dev/$i" | |
sgdisk -n1:0:0 -t1:BF00 "/dev/$i" # root pool sdX1|nvme0n1 | |
sleep 0.5 | |
innerSeperator "Read the partition changes, inform the system!" | |
partprobe | |
sleep 0.5 | |
echo -e "\n" | |
done | |
innerSeperator "Active Partitions are : " | |
lsblk | |
stepByStep "createPartitions" | |
} | |
function getPartUUIDofDisks() { | |
dividerLine "Getting PARTUUID of Disks, it's never changes !" | |
# /dev/sdX2 | part2 | |
BOOT_PARTITIONS=() | |
BOOT_PARTITIONS_PARTUUID=() | |
# /dev/sdX3 | part3 | |
BOOT_POOLS_PARTITIONS=() | |
BOOT_POOLS_PARTITIONS_PARTUUID=() | |
# /dev/sdX4 | part4 | |
ROOT_PARTITIONS=() | |
ROOT_PARTITIONS_PARTUUID=() | |
for i in "${BOOT_PARTED_DISKS[@]}"; do | |
# Get Boot Partitions of disk | |
# nvme disks implementation | |
if [ ! -z $(grep "nvme[0-9][a-z][0-9]" <<< $i) ]; then | |
BOOT_PARTITIONS+=("/dev/${i}p2") | |
partUuidvalue=$(blkid -s PARTUUID -o value "/dev/${i}p2") | |
innerSeperator "PARTUUID of /dev/${i}p2\t${partUuidvalue}" | |
else | |
BOOT_PARTITIONS+=("/dev/${i}2") | |
partUuidvalue=$(blkid -s PARTUUID -o value "/dev/${i}2") | |
innerSeperator "PARTUUID of /dev/${i}2\t${partUuidvalue}" | |
fi | |
BOOT_PARTITIONS_PARTUUID+=("${partUuidvalue}") | |
# Get Boot Pools of disk | |
if [ ! -z $(grep "nvme[0-9][a-z][0-9]" <<< $i) ]; then | |
BOOT_POOLS_PARTITIONS+=("/dev/${i}p3") | |
partUuidvalue=$(blkid -s PARTUUID -o value "/dev/${i}p3") | |
innerSeperator "PARTUUID of /dev/${i}p3\t${partUuidvalue}" | |
else | |
BOOT_POOLS_PARTITIONS+=("/dev/${i}3") | |
partUuidvalue=$(blkid -s PARTUUID -o value "/dev/${i}3") | |
innerSeperator "PARTUUID of /dev/${i}3\t${partUuidvalue}" | |
fi | |
BOOT_POOLS_PARTITIONS_PARTUUID+=("${partUuidvalue}") | |
# Get Root Pools of disk | |
if [ ! -z $(grep "nvme[0-9][a-z][0-9]" <<< $i) ]; then | |
ROOT_PARTITIONS+=("/dev/${i}p4") | |
partUuidvalue=$(blkid -s PARTUUID -o value "/dev/${i}p4") | |
innerSeperator "PARTUUID of /dev/${i}p4\t${partUuidvalue}" | |
else | |
ROOT_PARTITIONS+=("/dev/${i}4") | |
partUuidvalue=$(blkid -s PARTUUID -o value "/dev/${i}4") | |
innerSeperator "PARTUUID of /dev/${i}4\t${partUuidvalue}" | |
fi | |
ROOT_PARTITIONS_PARTUUID+=("${partUuidvalue}") | |
done | |
# /dev/sdX1 | part1 (full disk) | |
POOL_PARTITIONS=() | |
POOL_PARTITIONS_PARTUUID=() | |
for i in "${POOL_PARTED_DISKS[@]}"; do | |
# Get Pool Partitions of disk | |
if [ ! -z $(grep "nvme[0-9][a-z][0-9]" <<< $i) ]; then | |
POOL_PARTITIONS+=("/dev/${i}p1") | |
partUuidvalue=$(blkid -s PARTUUID -o value "/dev/${i}p1") | |
innerSeperator "PARTUUID of /dev/${i}p1\t${partUuidvalue}" | |
else | |
POOL_PARTITIONS+=("/dev/${i}1") | |
partUuidvalue=$(blkid -s PARTUUID -o value "/dev/${i}1") | |
innerSeperator "PARTUUID of /dev/${i}1\t${partUuidvalue}" | |
fi | |
POOL_PARTITIONS_PARTUUID+=("${partUuidvalue}") | |
done | |
# sdX2 | |
export BOOT_PARTITIONS | |
export BOOT_PARTITIONS_PARTUUID | |
# sdX3 | |
export BOOT_POOLS_PARTITIONS | |
export BOOT_POOLS_PARTITIONS_PARTUUID | |
# sdX4 | |
export ROOT_PARTITIONS | |
export ROOT_PARTITIONS_PARTUUID | |
# sdX1 | |
export POOL_PARTITIONS | |
export POOL_PARTITIONS_PARTUUID | |
stepByStep "getPartUUIDofDisks" | |
} | |
function cloneableUefiPart() { | |
BOOT_DISK_PARTUUID="/dev/disk/by-partuuid/${BOOT_PARTITIONS_PARTUUID[0]}" | |
BOOT_CLONES=() | |
count=$((${#BOOT_PARTITIONS_PARTUUID[@]} - 1)) | |
for i in $(seq 1 $count); do | |
BOOT_CLONES+=("/dev/disk/by-partuuid/${BOOT_PARTITIONS_PARTUUID[$i]}") | |
done | |
export BOOT_DISK_PARTUUID | |
export BOOT_CLONES | |
} | |
function cloneUefiPartFunctionBuilder() { | |
if [[ "${#BOOT_CLONES[@]}" -gt 0 ]]; then | |
CLONE_FUNCTION=$(cat <<EOF | |
function cloneUefiPart() { | |
dividerLine "Clone UEFI Partition" | |
umount /boot/efi | |
count=2 | |
PARTITIONS=(${BOOT_CLONES[@]}) | |
for i in \${PARTITIONS[@]}; do | |
dd if=${BOOT_DISK_PARTUUID} of=\$i status=progress | |
sync | |
sleep 0.5 | |
disk=\$(ls -l \$i | grep -iPo "[a-z]+[0-9]+$" | grep -Po "[a-z]+") | |
diskById=\$(ls -l /dev/disk/by-id/ | grep -P "\$disk$" | awk '{print \$9}') | |
efibootmgr -c -g -d /dev/\$disk -p 2 -L "debian-\$count" -l '\\\EFI\debian\grubx64.efi' | |
sleep 0.5 | |
count=\$((count + 1)) | |
done | |
mount /boot/efi | |
} | |
EOF | |
) | |
else | |
CLONE_FUNCTION="" | |
fi | |
export CLONE_FUNCTION | |
} | |
function swapsOffline() { | |
dividerLine "All swaps off!" | |
swapoff --all | |
} | |
function checkMdadmArray() { | |
dividerLine "Check mdadm raid configuration!" | |
cat /proc/mdstat | |
MDADM_CHECK=$( | |
cat <<EOF | |
mdadm --stop /dev/md0 # If so, stop them (replace $()md0$() as required): | |
mdadm --zero-superblock --force /dev/sdX # For an array using the whole disk: | |
mdadm --zero-superblock --force /dev/sdX2 # For an array using a partition: | |
EOF | |
) | |
echo -e "${MDADM_CHECK}" | |
stepByStep "checkMdadmArray" | |
} | |
function selectPoolNames() { | |
dividerLine "Set pool names" | |
bPoolName="bpool" | |
rPoolName="rpool" | |
read -r -p "Default Boot pool name is - ${bPoolName} - if you want to change it, input the new name [a-z0-9] : " newBpoolName | |
if [ ! -z "${newBpoolName}" ]; then | |
unset bPoolName | |
bPoolName="${newBpoolName}" | |
fi | |
read -r -p "Default Root pool name is - ${rPoolName} - if you want to change it, input the new name [a-z0-9] : " newRpoolName | |
if [ ! -z "${newRpoolName}" ]; then | |
unset rPoolName | |
rPoolName="${newRpoolName}" | |
fi | |
export bPoolName | |
export rPoolName | |
innerSeperator " | |
Boot Pool name is : ${bPoolName} | |
Root Pool name is : ${rPoolName} | |
" | |
stepByStep "selectPoolNames" | |
} | |
function setBpoolName() { | |
read -r -p "Set new bpool name [a-z] : e.g [ bootpool ] " bPoolNameNew | |
if [ -z "${bPoolNameNew}" ]; then | |
bPoolNameNew="bootpool" | |
fi | |
read -r -p "New bpool name is ${bPoolNameNew} : [ Y / n ]" bPoolNameConfirm | |
if [ -z "${bPoolNameConfirm}" ] || [ "${bPoolNameConfirm}" == "Y" ] || [ "${bPoolNameConfirm}" == "y" ]; then | |
unset bPoolName | |
bPoolName="${bPoolNameNew}" | |
export bPoolName | |
else | |
setBpoolName | |
return | |
fi | |
} | |
function setRpoolName() { | |
read -r -p "Set new rpool name [a-z] : e.g [ rootpool ] " rPoolNameNew | |
if [ -z "${rPoolNameNew}" ]; then | |
rPoolNameNew="rootpool" | |
fi | |
read -r -p "New rpool name is ${rPoolNameNew} : [ Y / n ]" rPoolNameConfirm | |
if [ -z "${rPoolNameConfirm}" ] || [ "${rPoolNameConfirm}" == "Y" ] || [ "${rPoolNameConfirm}" == "y" ]; then | |
unset rPoolName | |
rPoolName="${rPoolNameNew}" | |
export rPoolName | |
else | |
setRpoolName | |
return | |
fi | |
} | |
function checkSystemHaveZfsPool() { | |
dividerLine "Check System ZFS Pools" | |
innerSeperator "Default Pool Names : ${bPoolName} & ${rPoolName}" | |
innerSeperator "Active : \n$(zpool list)" | |
systemPools=$(zpool status 2>/dev/null | grep -iPo "pool: \K.*") | |
if [ ! -z "${systemPools}" ]; then | |
zpool status | |
hasBpool=$(grep "${bPoolName}" <<<"${systemPools}") | |
hasRpool=$(grep "${rPoolName}" <<<"${systemPools}") | |
if [ ! -z "${hasBpool}" ]; then | |
innerSeperator "Setting Boot Pool Name" | |
setBpoolName | |
fi | |
if [ ! -z "${hasRpool}" ]; then | |
innerSeperator "Setting Root Pool Name" | |
setRpoolName | |
fi | |
fi | |
stepByStep "checkSystemHaveZfsPool" | |
} | |
function createBootPool() { | |
# BOOT_POOLS_PARTITIONS_PARTUUID | |
settedupDiskCount=${#BOOT_POOLS_PARTITIONS_PARTUUID[@]} | |
count=0 | |
setupString="${bPoolName} ${RAID_TAGS[$selectedRaid]} " | |
for d in $(seq 0 $settedupDiskCount ); do | |
setupString+="${BOOT_POOLS_PARTITIONS_PARTUUID[$count]} " | |
count=$((count + 1)) | |
done | |
dividerLine "Creating BOOT pool" | |
innerSeperator "${setupString}" | |
zpool create -f \ | |
-o cachefile=/etc/zfs/zpool.cache \ | |
-o ashift=12 -d \ | |
-o feature@async_destroy=enabled \ | |
-o feature@bookmarks=enabled \ | |
-o feature@embedded_data=enabled \ | |
-o feature@empty_bpobj=enabled \ | |
-o feature@enabled_txg=enabled \ | |
-o feature@extensible_dataset=enabled \ | |
-o feature@filesystem_limits=enabled \ | |
-o feature@hole_birth=enabled \ | |
-o feature@large_blocks=enabled \ | |
-o feature@livelist=enabled \ | |
-o feature@lz4_compress=enabled \ | |
-o feature@spacemap_histogram=enabled \ | |
-o feature@zpool_checkpoint=enabled \ | |
-O acltype=posixacl -O canmount=off -O compression=lz4 \ | |
-O devices=off -O normalization=formD -O relatime=on -O xattr=sa \ | |
-O mountpoint=/boot -R /mnt \ | |
${setupString} | |
innerSeperator "Listing ZFS Filesystem" | |
zfs list -t filesystem | |
stepByStep "createBootPool" | |
} | |
function createRootPool() { | |
mergedArray=("${ROOT_PARTITIONS_PARTUUID[@]}") | |
mergedArray+=("${POOL_PARTITIONS_PARTUUID[@]}") | |
settedupDiskCount="${#mergedArray[@]}" | |
count=0 | |
setupString="${rPoolName} " | |
for a in $(seq 1 $ARRAY_COUNT); do | |
setupString+="${RAID_TAGS[$selectedRaid]} " | |
for d in $(seq 0 $((settedupDiskCount / ARRAY_COUNT - 1))); do | |
setupString+="${mergedArray[$count]} " | |
count=$((count + 1)) | |
done | |
done | |
dividerLine "Creating ROOT pool" | |
innerSeperator "${setupString}" | |
zpool create -f \ | |
-o ashift=12 -O acltype=posixacl -O canmount=off -O compression=lz4 \ | |
-O dnodesize=auto -O normalization=formD -O relatime=on \-O xattr=sa \ | |
-O mountpoint=/ -R /mnt \ | |
${setupString} | |
innerSeperator "Listing ZFS Filesystem" | |
zfs list -t filesystem | |
stepByStep "createRootPool" | |
} | |
function createPoolsAndMounts() { | |
dividerLine "Creating Mount Pools" | |
innerSeperator "Creating ${rPoolName}/BOOT & ${bPoolName}/BOOT" | |
zfs create -o canmount=off -o mountpoint=none ${rPoolName}/ROOT | |
zfs create -o canmount=off -o mountpoint=none ${bPoolName}/BOOT | |
innerSeperator "Creating and mounting root ( / ) filesystem" | |
zfs create -o canmount=noauto -o mountpoint=/ ${rPoolName}/ROOT/debian | |
zfs mount ${rPoolName}/ROOT/debian | |
innerSeperator "Creating ${bPoolName}/BOOT/debian pool [ EFI system nesting directory]" | |
zfs create -o mountpoint=/boot ${bPoolName}/BOOT/debian | |
innerSeperator "Creating ${rPoolName}/home" | |
zfs create ${rPoolName}/home | |
innerSeperator "Creating and mounting ${rPoolName}/home/root to /root" | |
zfs create -o mountpoint=/root ${rPoolName}/home/root | |
chmod 700 /mnt/root | |
stepByStep "createPoolsAndMounts" | |
} | |
function askAndCreateDataset() { | |
# echo -e "${DATASET_DIRS[@]}" | |
# echo -e "${DATASET_OPTS[@]}" | |
if [[ ${#DATASET_DIRS[@]} -gt 0 ]]; then | |
count=0 | |
echo -e "----------------------------------------------------------" | |
for i in "${DATASET_DIRS[@]}"; do | |
read -r -p "Create ZFS Dataset ( ${rPoolName}$i ) ? [ Y / n ] " zfsDataset | |
case $zfsDataset in | |
"" | "Y" | "y") | |
echo -e "zfs create ${DATASET_OPTS[$count]} ${rPoolName}$i" | |
zfs create ${DATASET_OPTS[$count]} ${rPoolName}$i | |
;; | |
"N" | "n") | |
if [[ $count -eq 0 ]]; then | |
return | |
fi | |
;; | |
*) | |
# selectInstallationDisks | |
return | |
;; | |
esac | |
count=$((count+1)) | |
echo -e "----------------------------------------------------------" | |
done | |
fi | |
unset DATASET_DIRS | |
unset DATASET_OPTS | |
} | |
function createOtherDatasets() { | |
dividerLine "Creating Other ZFS Datasets" | |
DATASET_DIRS=("/var" \ | |
"/var/lib" \ | |
"/var/log" \ | |
"/var/mail" \ | |
"/var/vmail" \ | |
"/var/www" \ | |
"/var/spool" \ | |
"/var/cache" \ | |
"/var/tmp" \ | |
"/var/opt") | |
DATASET_OPTS=("-o canmount=off -o mountpoint=none" \ | |
"-o canmount=off" \ | |
"" \ | |
"" \ | |
"" \ | |
"" \ | |
"" \ | |
"-o com.sun:auto-snapshot=false" \ | |
"-o com.sun:auto-snapshot=false" \ | |
"") | |
export DATASET_DIRS | |
export DATASET_OPTS | |
askAndCreateDataset | |
getPath "/var/lib/docker" | |
upperDir=$(zfs list | grep "${F_PATH}") | |
echo "$upperDir" | |
if [ ! -z "$upperDir" ]; then | |
DATASET_DIRS=("/var/lib/docker" \ | |
"/var/lib/nfs") | |
DATASET_OPTS=("-o com.sun:auto-snapshot=false" \ | |
"-o com.sun:auto-snapshot=false") | |
export DATASET_DIRS | |
export DATASET_OPTS | |
askAndCreateDataset | |
fi | |
DATASET_DIRS=("/opt") | |
DATASET_OPTS=("") | |
export DATASET_DIRS | |
export DATASET_OPTS | |
askAndCreateDataset | |
DATASET_DIRS=("/usr" \ | |
"/usr/local") | |
DATASET_OPTS=("-o canmount=off" \ | |
"") | |
export DATASET_DIRS | |
export DATASET_OPTS | |
askAndCreateDataset | |
innerSeperator "Creating /mnt/run" | |
mkdir /mnt/run | |
innerSeperator "Mounting /mnt/run using tmp filesystem" | |
mount -t tmpfs tmpfs /mnt/run | |
innerSeperator "Creating /mnt/run/lock" | |
mkdir /mnt/run/lock | |
innerSeperator "Listing ZFS Filesystem" | |
zfs list -t filesystem | |
stepByStep "createOtherDatasets" | |
} | |
function installBaseSystem() { | |
dividerLine "Installing Debian bullseye base system !" | |
sleep 2 | |
if [ -f "/root/debootstrap/bullseye.tar.gz" ]; then | |
tar -xvzf /root/debootstrap/bullseye.tar.gz -C /mnt/ | |
elif [ -f "/root/debootstrap/bullseye_clean.tar.gz" ]; then | |
tar -xvzf /root/debootstrap/bullseye_clean.tar.gz -C /mnt/ | |
else | |
debootstrap bullseye /mnt | |
fi | |
chmod 1777 /mnt/var/tmp | |
stepByStep "installBaseSystem" | |
} | |
function copyPoolCache() { | |
dividerLine "Copy pool cache to base system" | |
if [ ! -d /mnt/etc/zfs ]; then | |
mkdir /mnt/etc/zfs | |
fi | |
cp /etc/zfs/zpool.cache /mnt/etc/zfs/ | |
stepByStep "copyPoolCache" | |
} | |
function changeHostNameBaseSystem() { | |
dividerLine "Changing base system's hostname" | |
read -r -p "What will be the name of your ZFS bullseye e.g. [ $(hostname)-zfs ? ] " newHostname | |
if [ -z "${newHostname}" ]; then | |
newHostname=$(hostname)-zfs | |
fi | |
sed '2 i 127.0.1.1\t'"${newHostname}" /etc/hosts > /mnt/etc/hosts | |
stepByStep "changeHostNameBaseSystem" | |
} | |
function changeNetworkConfOfBaseSystem() { | |
dividerLine "Changing base system's network configuration" | |
CHANGE_NET_IF=$( | |
cat <<EOF | |
auto eth0 | |
iface eth0 inet dhcp | |
EOF | |
) | |
if [ ! -d /mnt/etc/network/interfaces.d/ ]; then | |
mkdir /mnt/etc/network/interfaces.d/ | |
fi | |
echo -e "${CHANGE_NET_IF}" >/mnt/etc/network/interfaces.d/eth0 | |
stepByStep "changeNetworkConfOfBaseSystem" | |
} | |
function addAptSourcesToBaseSystem() { | |
dividerLine "Adding /etc/apt/sources.list to base system" | |
aptSourcesHttp "mnt" | |
stepByStep "addAptSourcesToBaseSystem" | |
} | |
function makePrivateDirectories() { | |
mount --make-private --rbind /dev /mnt/dev | |
mount --make-private --rbind /proc /mnt/proc | |
mount --make-private --rbind /sys /mnt/sys | |
stepByStep "makePrivateDirectories" | |
} | |
function chrootUpdate() { | |
dividerLine "chroot and apt update the base system" | |
chroot /mnt apt -qq update | |
stepByStep "chrootUpdate" | |
} | |
function chrootUpgrade() { | |
dividerLine "chroot and apt upgrade the base system" | |
chroot /mnt apt -qq upgrade -y | |
stepByStep "chrootUpgrade" | |
} | |
function chrootAutoremove() { | |
dividerLine "chroot and apt autoremove the base system" | |
chroot /mnt apt -qq autoremove -y | |
stepByStep "chrootAutoremove" | |
} | |
function chrootInstallBaseApps() { | |
dividerLine "Apt install chrooted system's applications" | |
chroot /mnt apt -qq install -y sudo parted htop screen net-tools dnsutils whois curl wget bash-completion \ | |
apt-transport-https openssh-server ca-certificates console-setup locales dosfstools grub-efi-amd64 \ | |
shim-signed gdisk iproute2 mdadm ovmf lsof | |
stepByStep "chrootInstallBaseApps" | |
} | |
function chrootSymlinkMounts() { | |
dividerLine "Chroot Symlink Mounts" | |
chroot /mnt ln -s /proc/self/mounts /etc/mtab | |
stepByStep "chrootSymlinkMounts" | |
} | |
function chrootDpkgReconfigure() { | |
dividerLine "Chroot DPKG reconfigure" | |
chroot /mnt dpkg-reconfigure locales tzdata keyboard-configuration console-setup | |
stepByStep "chrootDpkgReconfigure" | |
} | |
function chrootInstallKernelHeaders() { | |
dividerLine "Chroot Install Kernel headers" | |
chroot /mnt apt -qq install -y dpkg-dev linux-headers-amd64 linux-image-amd64 | |
chroot /mnt apt -qq install -y dkms | |
chroot /mnt apt -qq install -y zfs-initramfs | |
chroot /mnt echo REMAKE_INITRD=yes >/etc/dkms/zfs.conf | |
stepByStep "chrootInstallKernelHeaders" | |
} | |
function chrootWriteUefiPart() { | |
#BOOT_PARTED_DISKS | |
#BOOT_PARTITIONS | |
#BOOT_PARTITIONS_PARTUUID | |
dividerLine "Chroot Write UEFI boot" | |
innerSeperator "Grub Probe [ you should see 'zfs']" | |
innerSeperator $(chroot /mnt grub-probe /boot) | |
read -p " [ Enter ] " keypress | |
lsblk | |
innerSeperator "mkdosfs EFI part" | |
partUuid=${BOOT_PARTITIONS_PARTUUID[0]} | |
export partUuid | |
chroot /mnt /bin/bash -c 'echo "/dev/disk/by-partuuid/$partUuid"; mkdosfs -F 32 -s 1 -n EFI /dev/disk/by-partuuid/$partUuid' | |
read -p " [ Enter ] " keypress | |
innerSeperator "Create /boot/efi" | |
chroot /mnt mkdir /boot/efi | |
read -p " [ Enter ] " keypress | |
innerSeperator "Write /etc/fstab" | |
chroot /mnt echo -e "PARTUUID=\"${BOOT_PARTITIONS_PARTUUID[0]}\" /boot/efi vfat defaults 0 0" >> /mnt/etc/fstab | |
unset partUuid | |
innerSeperator "Mount EFI" | |
chroot /mnt mount /boot/efi | |
read -p " [ Enter ] " keypress | |
innerSeperator "Purge os-prober [ Dual boot systems don't needed ]" | |
chroot /mnt apt remove -y --purge os-prober | |
stepByStep "chrootWriteUefiPart" | |
} | |
function chrootCreateRootPassword() { | |
dividerLine "Chrooted System Change 'root' password" | |
# read -rs -p "Create root password : " chrootRootPassword | |
chroot /mnt passwd | |
stepByStep "chrootCreateRootPassword" | |
} | |
function chrootImportBpoolService() { | |
dividerLine "Chroot Create and enable Bpool service" | |
BPOOL_SERVICE=$( | |
cat <<EOF | |
[Unit] | |
DefaultDependencies=no | |
Before=zfs-import-scan.service | |
Before=zfs-import-cache.service | |
[Service] | |
Type=oneshot | |
RemainAfterExit=yes | |
ExecStart=/sbin/zpool import -N -o cachefile=none ${bPoolName} | |
# Work-around to preserve zpool cache: | |
ExecStartPre=-/bin/mv /etc/zfs/zpool.cache /etc/zfs/preboot_zpool.cache | |
ExecStartPost=-/bin/mv /etc/zfs/preboot_zpool.cache /etc/zfs/zpool.cache | |
[Install] | |
WantedBy=zfs-import.target | |
EOF | |
) | |
innerSeperator "Write service file" | |
echo -e "${BPOOL_SERVICE}" >/mnt/etc/systemd/system/zfs-import-${bPoolName}.service | |
innerSeperator "Enable service" | |
chroot /mnt /usr/bin/env bPoolName=${bPoolName} systemctl enable zfs-import-${bPoolName}.service | |
innerSeperator "Enable tmp.mount service" | |
chroot /mnt cp /usr/share/systemd/tmp.mount /etc/systemd/system/ | |
chroot /mnt systemctl enable tmp.mount | |
stepByStep "chrootImportBpoolService" | |
} | |
function chrootUpdateInitRamFs() { | |
dividerLine "Chroot Update Init Ram Filesystem" | |
chroot /mnt update-initramfs -c -k all | |
stepByStep "chrootUpdateInitRamFs" | |
} | |
function chrootChangeGrubDefaults() { | |
dividerLine "Chroot set /etc/default/grub file" | |
chroot /mnt sed -i 's/GRUB_TIMEOUT=5/GRUB_TIMEOUT=2/g' /etc/default/grub | |
chroot /mnt sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="quiet"/GRUB_CMDLINE_LINUX_DEFAULT="console"/g' /etc/default/grub | |
chroot /mnt /usr/bin/env rPoolName=${rPoolName} sed -i 's/GRUB_CMDLINE_LINUX=""/GRUB_CMDLINE_LINUX="root=ZFS='${rPoolName}'\/ROOT\/debian net.ifnames=0 biosdevname=0"/g' /etc/default/grub | |
chroot /mnt echo -e "GRUB_SAVEDEFAULT=false\nGRUB_DEFAULT=saved" >> /etc/default/grub | |
chroot /mnt update-grub | |
stepByStep "chrootChangeGrubDefaults" | |
} | |
function chrootGrubInstall() { | |
# after reboot all boot disks... | |
dividerLine "Chroot grub install" | |
chroot /mnt grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=debian --recheck --no-floppy | |
stepByStep "chrootGrubInstall" | |
} | |
function chrootZfsListCaches() { | |
dividerLine "Chroot ZFS list caches" | |
chroot /mnt mkdir /etc/zfs/zfs-list.cache | |
chroot /mnt /usr/bin/env bPoolName=${bPoolName} touch /etc/zfs/zfs-list.cache/${bPoolName} | |
chroot /mnt /usr/bin/env rPoolName=${rPoolName} touch /etc/zfs/zfs-list.cache/${rPoolName} | |
chroot /mnt ln -s /usr/lib/zfs-linux/zed.d/history_event-zfs-list-cacher.sh /etc/zfs/zed.d | |
chroot /mnt zed -F & | |
innerSeperator "When you see changes on the screen [ Ctrl + C ]" | |
sleep 3 | |
chroot /mnt /usr/bin/env bPoolName=${bPoolName} watch -n1 cat /etc/zfs/zfs-list.cache/${bPoolName} | |
innerSeperator "When you see changes on the screen [ Ctrl + C ]" | |
sleep 3 | |
chroot /mnt /usr/bin/env rPoolName=${rPoolName} watch -n1 cat /etc/zfs/zfs-list.cache/${rPoolName} | |
innerSeperator "Chroot get the zed application and exit automatically ( pkill -15 zed)" | |
chroot /mnt pkill -15 zed | |
stepByStep "chrootZfsListCaches" | |
} | |
function chrootChangeMntDir() { | |
dividerLine "Chroot change '/mnt/' to '/' root file system" | |
sed -Ei "s|/mnt/?|/|" /mnt/etc/zfs/zfs-list.cache/* | |
stepByStep "chrootChangeMntDir" | |
} | |
function afterReboot() { | |
dividerLine "After the reboot you might want to start 'after-reboot.sh':" | |
AFTER_REBOOT_SH=$( | |
cat <<EOF | |
#!/usr/bin/env bash | |
function dividerLine() { | |
echo -e "\\\n######################################################################" | |
echo -e "# \$1" | |
echo -e "######################################################################\\\n" | |
} | |
function innerSeperator() { | |
echo -e "----------------------------------------------------------------------" | |
echo -e " \$1" | |
echo -e "----------------------------------------------------------------------" | |
} | |
${CLONE_FUNCTION} | |
function getUserPassword() { | |
read -rs -p "Password : " userPass | |
echo "" | |
read -rs -p "Password (Re) : " userPassSecond | |
if [ "\${userPass}" != "\${userPassSecond}" ]; then | |
echo -e "Passwords don't match!" | |
unset userPass | |
unset userPassSecond | |
getUserPassword | |
fi | |
} | |
function addNewUserToBaseSystem() { | |
dividerLine "Add New User to System" | |
read -r -p "Username : [ Username / N (continue without) ] " username | |
if [ -z "\${username}" ]; then | |
echo -e "You should give a username or 'N' to continue without one!" | |
addNewUserToBaseSystem | |
fi | |
if [ ! "\${username}" == "n" ] || [ ! "\${username}" == "N" ]; then | |
innerSeperator "The username is : \${username}" | |
innerSeperator "ZFS Create \${username} 's pool" | |
zfs create ${rPoolName}/home/\${username} | |
chown -R \${username}:\${username} /home/\${username} | |
adduser "\${username}" | |
cp -a /etc/skel/. /home/\${username} | |
chown -R \${username}:\${username} /home/\${username} | |
usermod -a -G audio,cdrom,dip,floppy,netdev,plugdev,sudo,video \${username} | |
innerSeperator "Set user password" | |
# getUserPassword | |
# echo "\${username}:\${userPass}" | chpasswd | |
innerSeperator "\${username} 's Password has Changed" | |
fi | |
} | |
function startTaskSel() { | |
dividerLine "TASKSEL" | |
tasksel | |
} | |
cloneUefiPart | |
read -p "To Continue [ Enter ] " keypress | |
addNewUserToBaseSystem | |
startTaskSel | |
EOF | |
) | |
innerSeperator "/root/after-reboot.sh script generated." | |
echo -e "${AFTER_REBOOT_SH}" >/mnt/root/after-reboot.sh | |
# echo -e "${AFTER_REBOOT_SH}" > "$(pwd)"/after-reboot.sh | |
chmod 700 /mnt/root/after-reboot.sh | |
# chmod 700 "$(pwd)"/after-reboot.sh | |
stepByStep "afterReboot" | |
} | |
function copyZfsCompletion { | |
dividerLine "Copy zfs bash completion to zpool | Activates zpool completion" | |
chroot /mnt cp /usr/share/bash-completion/completions/zfs /usr/share/bash-completion/completions/zpool | |
stepByStep "copyZfsCompletion" | |
} | |
function chrootTakeInitialSnapshots() { | |
dividerLine "Chroot take initial snapshots" | |
chroot /mnt /usr/bin/env bPoolName=${bPoolName} zfs snapshot ${bPoolName}/BOOT/debian@initial | |
chroot /mnt /usr/bin/env rPoolName=${rPoolName} zfs snapshot ${rPoolName}/ROOT/debian@initial | |
stepByStep "chrootTakeInitialSnapshots" | |
} | |
function unmountAllFilesystems() { | |
dividerLine "Unmount all ZFS /mnt partitions" | |
mount | grep -v zfs | tac | awk '/\/mnt/ {print $3}' | xargs -i{} umount -lf {} # LiveCD environment to unmount all filesystems | |
zfs unmount -a | |
stepByStep "unmountAllFilesystems" | |
} | |
function exportZfsPools() { | |
dividerLine "Export ZFS Pools" | |
zpool export "${bPoolName}" | |
zpool export "${rPoolName}" | |
stepByStep "exportZfsPools" | |
} | |
function rebootSystem() { | |
read -r -p "Reboot the system : [ Y / n ] " rebootConfirm | |
if [ -z "${rebootConfirm}" ] || [ "${rebootConfirm}" == "Y" ] || [ "${rebootConfirm}" == "y" ]; then | |
dividerLine "System will reboot in 5 seconds..." | |
sleep 5 | |
reboot | |
fi | |
stepByStep "rebootSystem" | |
} | |
##### START ##### | |
amiAllowed | |
aptSourcesHttp | |
installBaseApps | |
aptSourcesHttps | |
aptUpdateUpgrade | |
selectPoolNames | |
checkSystemHaveZfsPool | |
selectSystemDisk | |
selectRaidType | |
selectInstallationDisks | |
labelClear | |
wipeDisks | |
createPartitions | |
labelClear # if ZFS installed before on that partition same name, it's there, clear it again. | |
getPartUUIDofDisks | |
cloneableUefiPart | |
cloneUefiPartFunctionBuilder | |
swapsOffline | |
checkMdadmArray | |
createBootPool | |
createRootPool | |
createPoolsAndMounts | |
createOtherDatasets | |
installBaseSystem | |
copyPoolCache | |
changeHostNameBaseSystem | |
changeNetworkConfOfBaseSystem | |
addAptSourcesToBaseSystem | |
makePrivateDirectories | |
chrootUpdate | |
chrootUpgrade | |
chrootAutoremove | |
chrootInstallBaseApps | |
aptSourcesHttps "mnt" | |
chrootUpdate | |
chrootUpgrade | |
chrootAutoremove | |
chrootSymlinkMounts | |
chrootDpkgReconfigure | |
chrootInstallKernelHeaders | |
chrootWriteUefiPart | |
chrootCreateRootPassword | |
chrootImportBpoolService | |
chrootUpdateInitRamFs | |
chrootChangeGrubDefaults | |
chrootGrubInstall | |
chrootZfsListCaches | |
chrootChangeMntDir | |
afterReboot | |
copyZfsCompletion | |
chrootTakeInitialSnapshots | |
unmountAllFilesystems | |
exportZfsPools | |
rebootSystem |
I would like to express my heartfelt thanks to you @unique1984 for your effort put into writing this script and making it available to other users. I don't want to know how many hours you dedicated to its creation, but I can tell you how many hours it has helped me save: a lot! I plan to use it for all of my computers, both for Debian Bookworm and future releases.
I wish you plenty of energy to keep it up to date, and perhaps in the future, you can consider adding encryption! Once again, thank you, and best regards!
I would like to express my heartfelt thanks to you @unique1984 for your effort put into writing this script and making it available to other users.
I am genuinely happy to hear that, i didn't test it this script on bookworm, simply changing apt sources list functions (line 40) and debootstrap (line 1139) to bookworm will probably do the job. Have a nice day.
Some notes of mine,
The ZED cache part would be a problematic i think... zed function
Every experience is valuable! You should try as much scenarios as possible for yourself.
I create a VM for the VM creation and my gitlab instance using root ZFS file system on it.
Last one is autoexpand=true option if you want to use this you must use the entire disk area! if you don't autoexpand won't work, i need to reinstall my gitlab instance because of this.
I wish you luck, i've tried to write this script as clean as possible. If you stuck somewhere i would love to explain it.
Don't mention it, I hope I can add something valuable to you.