Compare commits

..

No commits in common. "main" and "09-03-2024" have entirely different histories.

11 changed files with 131 additions and 649 deletions

View file

@ -1,6 +1,5 @@
iso: iso:
sed "s|%REL_VER%|$(shell grep -E 'release_version.' profiledef.sh | cut -d= -f2 | jq -r '.')|g; s|%ALP_VER%|$(shell grep -E 'iso_version.' profiledef.sh | cut -d= -f2 | jq -r '.')|" template/root/install.sh > airootfs/root/install.sh sudo mkteaiso -o ${PWD}/out -p ${PWD}
sudo mkalpineiso -o ${PWD}/out
clean: clean:
sudo rm -f ${PWD}/out/*.iso sudo rm -f ${PWD}/out/*.iso

View file

@ -1,6 +1,6 @@
# Novos files # NoveriaOS files
This are the official Novos files. This are the official NoveriaOS files.
The ISO is generated using mkalpineiso. The ISO is generated using teaiso.
Within the ISO, you'll be greeted by an installation-script to guide you through the installation-process of Novos. Within the ISO, you'll be greeted by a installation-script to guide you through the installation-process of NoveriaOS.

View file

@ -0,0 +1,3 @@
https://dl-cdn.alpinelinux.org/alpine/v3.19/main
https://dl-cdn.alpinelinux.org/alpine/v3.19/community
@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing

View file

@ -0,0 +1,5 @@
state_verbose: False
file_client: local
file_roots:
base:
- /srv/salt

View file

@ -2,7 +2,7 @@
### ###
## ##
## Novos Install script ## NoveriaOS Install script
## ##
### ###
@ -22,10 +22,11 @@ readonly INSTALLATION_ESP_PARTITION_SIZE=4
readonly INSTALLATION_MOUNTPOINT='/mnt' readonly INSTALLATION_MOUNTPOINT='/mnt'
readonly INSTALLATION_NOVERIA_BIN='/usr/local/noveria/bin' readonly INSTALLATION_NOVERIA_BIN='/usr/local/noveria/bin'
readonly INSTALLATION_SECRETS_FILE="/root/installation.secrets" readonly INSTALLATION_SECRETS_FILE="/root/installation.secrets"
readonly INSTALLATION_ANSIBLE_ROOT="srv/ansible" readonly INSTALLATION_SALT_ROOT="srv/salt"
readonly INSTALLATION_ANSIBLE_GIT="https://git.noveria.org/Novos/ansible-playbooks.git" readonly INSTALLATION_SALT_GIT="https://git.noveria.org/NoveriaOS/salt-statetree.git"
readonly INSTALLATION_PILLAR_ROOT="srv/pillar"
readonly INSTALLATION_PILLAR_GIT="https://git.noveria.org/NoveriaOS/salt-pillartree.git"
readonly INSTALLATION_ALPINE_VERSION=$(cat /etc/os-release | grep VERSION_ID | cut -d= -f2) readonly INSTALLATION_ALPINE_VERSION=$(cat /etc/os-release | grep VERSION_ID | cut -d= -f2)
readonly INSTALLATION_REL_VERSION=2412
# Colors # Colors
readonly RED='\033[0;31m' readonly RED='\033[0;31m'
@ -45,14 +46,6 @@ trap "errorHardExit 'Interrupted with CTRL+C'" SIGINT SIGHUP SIGTERM SIGABRT
## Helper Functions ## Helper Functions
### ###
##
# Run commands in chroot
# - $1: command
##
function runInChroot() {
chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "$1"
}
## ##
# Installation subtask title output # Installation subtask title output
# - $1: subtask title # - $1: subtask title
@ -120,7 +113,7 @@ function preChecks() {
0) 0)
clear clear
COUNTER=5 COUNTER=5
echo "Novos is shutting down in: " echo "NoveriaOS is shutting down in: "
while [ 1 ]; do while [ 1 ]; do
if [ ${COUNTER} -eq 0 ]; then if [ ${COUNTER} -eq 0 ]; then
break break
@ -155,15 +148,16 @@ function preChecks() {
function introDialogue() { function introDialogue() {
local introtext="\n\n\n local introtext="\n\n\n
Velkommen til Velkommen til
_ _\n _ _ _
| \ | | _____ _____ ___\n | \ | | _____ _____ _ __(_) __ _
| \| |/ _ \ \ / / _ \/ __|\n | \| |/ _ \ \ / / _ \ '__| |/ _ |
| |\ | (_) \ V / (_) \__ \ \n | |\ | (_) \ V / __/ | | | (_| |
|_| \_|\___/ \_/ \___/|___/\n\n |_| \_|\___/ \_/ \___|_| |_|\__,_|
OS: Novos
Version: $INSTALLATION_REL_VERSION
IP: $(ifconfig eth0 | grep "inet addr" | awk '{$1=$1};1' | awk '{print $2}' | cut -d: -f2)
OS: NoveriaOS
Version: $(date "+%Y%m")
IP: $(ifconfig eth0 | grep "inet addr" | awk '{$1=$1};1' | awk '{print $2}' | cut -d: -f2)
How do you want to continue? How do you want to continue?
" "
dialog --stdout --clear --cr-wrap --no-collapse --yes-label "Graphical Guide" --no-label "Alpine shell" --yesno "$introtext" 31 93 dialog --stdout --clear --cr-wrap --no-collapse --yes-label "Graphical Guide" --no-label "Alpine shell" --yesno "$introtext" 31 93
@ -229,8 +223,9 @@ function prepareInstallation() {
INSTALLATION_DOMAIN=$(dialog --clear --title "What's the domain of this device?" --inputbox "Enter domain (leave empty for localhost)" 10 70 3>&1 1>&2 2>&3 3>&-) INSTALLATION_DOMAIN=$(dialog --clear --title "What's the domain of this device?" --inputbox "Enter domain (leave empty for localhost)" 10 70 3>&1 1>&2 2>&3 3>&-)
[[ -z "$INSTALLATION_DOMAIN" ]] && INSTALLATION_DOMAIN="localhost" [[ -z "$INSTALLATION_DOMAIN" ]] && INSTALLATION_DOMAIN="localhost"
# installation type # additional states
INSTALLATION_TYPE=$(dialog --clear --title "Choose the main installation type of this host" --radiolist "Select one" 10 70 3 gaming Game-Server false proxy Proxy-Server false build Build-Server false 3>&1 1>&2 2>&3 3>&-) ADDITIONAL_STATES=$(dialog --clear --title "Select additional states to execute" --checklist "available states" 10 70 3 podman "" false 3>&1 1>&2 2>&3 3>&-)
IFS=' ' read -ra ADDITIONAL_STATES_ARR <<< "$ADDITIONAL_STATES"
# show summary # show summary
summary summary
@ -242,8 +237,7 @@ function prepareInstallation() {
function summary() { function summary() {
dialog --stdout --clear --title "Summary" --yes-label "Confirm" --no-label "Abort" --yesno "\n dialog --stdout --clear --title "Summary" --yes-label "Confirm" --no-label "Abort" --yesno "\n
Hostname: ${INSTALLATION_HOSTNAME}.${INSTALLATION_DOMAIN}\n Hostname: ${INSTALLATION_HOSTNAME}.${INSTALLATION_DOMAIN}\n
Type: ${INSTALLATION_TYPE}\n Disk: $INSTALLATION_DISK
Disk: ${INSTALLATION_DISK}
" 9 60 " 9 60
case $? in case $? in
@ -265,7 +259,7 @@ Disk: ${INSTALLATION_DISK}
function installation() { function installation() {
# clear display # clear display
clear clear
# lock file # lock file
touch "$INSTALLATION_LOCK_FILE" || installationFailed touch "$INSTALLATION_LOCK_FILE" || installationFailed
@ -329,7 +323,7 @@ function installation() {
installationSubtaskTitle "Mount ESP" installationSubtaskTitle "Mount ESP"
mount -o nodev,nosuid,noexec "${ESP_PARTITION}" "${INSTALLATION_MOUNTPOINT}/efi" || installationFailed mount -o nodev,nosuid,noexec "${ESP_PARTITION}" "${INSTALLATION_MOUNTPOINT}/efi" || installationFailed
echo "" echo ""
echo "┌──────────────────────────────────────────┐" echo "┌──────────────────────────────────────────┐"
echo "│ Install and configure OS │" echo "│ Install and configure OS │"
@ -347,8 +341,8 @@ function installation() {
cp /etc/resolv.conf "${INSTALLATION_MOUNTPOINT}/etc/resolv.conf" || installationFailed cp /etc/resolv.conf "${INSTALLATION_MOUNTPOINT}/etc/resolv.conf" || installationFailed
installationSubtaskTitle "Setup PATH" installationSubtaskTitle "Setup PATH"
runInChroot "export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'" || installationFailed
installationSubtaskTitle "Mount extra mounts for chroot" installationSubtaskTitle "Mount extra mounts for chroot"
mount -t proc /proc "${INSTALLATION_MOUNTPOINT}/proc" || installationFailed mount -t proc /proc "${INSTALLATION_MOUNTPOINT}/proc" || installationFailed
mount -t sysfs /sys "${INSTALLATION_MOUNTPOINT}/sys" || installationFailed mount -t sysfs /sys "${INSTALLATION_MOUNTPOINT}/sys" || installationFailed
@ -358,94 +352,102 @@ function installation() {
installationSubtaskTitle "Install base-packages" installationSubtaskTitle "Install base-packages"
runInChroot "apk add alpine-base tzdata eudev udev-init-scripts --no-cache" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "apk add alpine-base --no-cache" || installationFailed
installationSubtaskTitle "Overwrite default repositories" installationSubtaskTitle "Overwrite default repositories"
cp /etc/apk/repositories "${INSTALLATION_MOUNTPOINT}/etc/apk/repositories" || installationFailed cp /etc/apk/repositories "${INSTALLATION_MOUNTPOINT}/etc/apk/repositories" || installationFailed
installationSubtaskTitle "Install Ansible" installationSubtaskTitle "Install SaltStack"
runInChroot "apk add ansible envsubst" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "apk add salt-minion envsubst" || installationFailed
installationSubtaskTitle "Setup keymap" installationSubtaskTitle "Setup keymap"
runInChroot "setup-keymap ch ch" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "setup-keymap ch ch" || installationFailed
installationSubtaskTitle "Setting localtime to Europe/Zurich" installationSubtaskTitle "Setting localtime to Europe/Zurich"
runInChroot "ln -s /usr/share/zoneinfo/Europe/Zurich /etc/localtime" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "setup-timezone Europe/Zurich" || installationFailed
installationSubtaskTitle "Time sync" installationSubtaskTitle "Time sync"
runInChroot "hwclock --systohc" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "hwclock --systohc" || installationFailed
installationSubtaskTitle "Setup hostname" installationSubtaskTitle "Setup hostname"
runInChroot "echo '${INSTALLATION_HOSTNAME}.${INSTALLATION_DOMAIN}' > /etc/hostname" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo '${INSTALLATION_HOSTNAME}.${INSTALLATION_DOMAIN}' > /etc/hostname" || installationFailed
runInChroot "hostname -F /etc/hostname" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "hostname -F /etc/hostname" || installationFailed
runInChroot "rc-update add hostname" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "rc-update add hostname" || installationFailed
installationSubtaskTitle "Setup hosts" installationSubtaskTitle "Setup hosts"
cp /etc/hosts "${INSTALLATION_MOUNTPOINT}/etc/hosts" || installationFailed cp /etc/hosts "${INSTALLATION_MOUNTPOINT}/etc/hosts" || installationFailed
installationSubtaskTitle "Set root password" installationSubtaskTitle "Set root password"
runInChroot "echo -e \"${INSTALLATION_ROOT_PW}\n${INSTALLATION_ROOT_PW}\" | passwd" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo -e \"${INSTALLATION_ROOT_PW}\n${INSTALLATION_ROOT_PW}\" | passwd" || installationFailed
installationSubtaskTitle "Enable btrfs module" installationSubtaskTitle "Enable btrfs module"
runInChroot "echo 'btrfs' >> /etc/modules" chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo 'btrfs' >> /etc/modules"
runInChroot "echo 'efivarfs' >> /etc/modules" chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo 'efivarfs' >> /etc/modules"
installationSubtaskTitle "Enable udev services"
runInChroot "rc-update add udev sysinit"
runInChroot "rc-update add udev-trigger sysinit"
runInChroot "rc-update add udev-settle sysinit"
runInChroot "rc-update add udev-postmount default"
echo "" echo ""
echo "┌──────────────────────────────────────────┐" echo "┌──────────────────────────────────────────┐"
echo "│ Configure Ansible and playbook-run │" echo "│ Configure SaltStack and highstate │"
echo "└──────────────────────────────────────────┘" echo "└──────────────────────────────────────────┘"
installationSubtaskTitle "Clone Playbook-repo" installationSubtaskTitle "Clone Salt-Repo"
mkdir -p ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_ANSIBLE_ROOT}/playbooks mkdir -p ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_SALT_ROOT}
git clone ${INSTALLATION_ANSIBLE_GIT} ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_ANSIBLE_ROOT}/playbooks git clone ${INSTALLATION_SALT_GIT} ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_SALT_ROOT}
mkdir -p ${INSTALLATION_MOUNTPOINT}/etc/ansible cat >"${INSTALLATION_MOUNTPOINT}/etc/salt/minion" <<EOT || installationFailed
cat >"${INSTALLATION_MOUNTPOINT}/etc/ansible/ansible.cfg" <<EOT || installationFailed ---
[defaults] state_verbose: False
inventory=/${INSTALLATION_ANSIBLE_ROOT}/inventory.yml file_client: local
file_roots:
base:
- /srv/salt
pillar_roots:
base:
- /srv/pillar
...
EOT EOT
cat >"${INSTALLATION_MOUNTPOINT}/${INSTALLATION_ANSIBLE_ROOT}/inventory.yml" <<EOT cat >"${INSTALLATION_MOUNTPOINT}/etc/salt/grains" <<EOT || installationFailed
ungrouped: os: Alpine
hosts: os_family: Alpine
localhost
vars:
ansible_connection: local
start_timestamp: ${START_TIMESTAMP}
tmpfs_size: 4G
installation_type: ${INSTALLATION_TYPE}
mysql_root_password: $(randomPasswordGen 32)
release_version: 2412
alpine_version: v3.21
EOT EOT
installationSubtaskTitle "Execute Ansible playbooks" installationSubtaskTitle "Populate Pillars"
runInChroot "ansible-playbook /${INSTALLATION_ANSIBLE_ROOT}/playbooks/top.ansible.yml" || installationFailed mkdir -p ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_PILLAR_ROOT}
#git clone ${INSTALLATION_PILLAR_GIT} ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_PILLAR_ROOT}
cat >"${INSTALLATION_MOUNTPOINT}/${INSTALLATION_PILLAR_ROOT}/top.sls" << EOT
base:
'*':
EOT
for state in $(find ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_SALT_ROOT} -mindepth 1 -maxdepth 1 -not -path '*/.*' -type d -exec basename {} \;); do
mkdir -p ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_PILLAR_ROOT}/${state}
touch ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_PILLAR_ROOT}/${state}/init.sls
echo -e " - $state" >> ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_PILLAR_ROOT}/top.sls
done
cat >"${INSTALLATION_MOUNTPOINT}/${INSTALLATION_PILLAR_ROOT}/system/init.sls" << EOT
system.disks.timestamp: ${START_TIMESTAMP}
EOT
installationSubtaskTitle "Salt highstate"
chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "salt-call state.highstate" || installationFailed
echo "" echo ""
echo "┌──────────────────────────────────────────┐" echo "┌──────────────────────────────────────────┐"
echo "│ Boot │" echo "│ Boot │"
echo "└──────────────────────────────────────────┘" echo "└──────────────────────────────────────────┘"
installationSubtaskTitle "Make EFI boot image with mkinitfs" installationSubtaskTitle "Make EFI boot image with mkinitfs"
latest_kernel="$(chroot $INSTALLATION_MOUNTPOINT /bin/ash -c 'echo $(apk search linux-lts | head -n1 | cut -d- -f3- | sed "s|r||")-lts')" latest_kernel="$(chroot $INSTALLATION_MOUNTPOINT /bin/ash -c 'echo $(apk search linux-lts | head -n1 | cut -d- -f3- | sed "s|r||")-lts')"
runInChroot "mkinitfs $latest_kernel" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "mkinitfs $latest_kernel" || installationFailed
installationSubtaskTitle "Installing grub to /efi" installationSubtaskTitle "Installing grub to /efi"
runInChroot "grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=alpine" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=alpine" || installationFailed
installationSubtaskTitle "Generating Bootmenu entries" installationSubtaskTitle "Generating Bootmenu entries"
chroot "${INSTALLATION_MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/noveriablcgen --noconfirm" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/noveriablcgen --noconfirm" || installationFailed
installationSubtaskTitle "Generating motd" installationSubtaskTitle "Generating motd"
chroot "${INSTALLATION_MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/generate_motd" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/generate_motd" || installationFailed
chroot "${INSTALLATION_MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/nsm check remote" || installationFailed
echo "" echo ""
echo "┌──────────────────────────────────────────┐" echo "┌──────────────────────────────────────────┐"
@ -469,18 +471,17 @@ EOT
# remove shell histories # remove shell histories
rm -f /root/.zsh_history rm -f /root/.zsh_history
selected_option=$(dialog --output-fd 1 --menu "What would you like to do?" 10 70 5 reboot "Reboot into your newly installed system" poweroff "Shut down the current live system" alpine-shell "Switch to an interactive shell") dialog --stdout --clear --cr-wrap --no-collapse --yes-label "Reboot" --no-label "Alpine shell" --yesno "\n Installation finished" 7 50
case "$selected_option" in case $? in
"reboot") 0) reboot ;;
reboot 1)
;; clear
"poweroff") exit
poweroff ;;
;; 255)
"alpine-shell") clear
clear exit
exit ;;
;;
esac esac
} }

View file

@ -1,7 +1,7 @@
#!/usr/bin/env ash #!/usr/bin/env ash
# overwrite default-hostname # overwrite default-hostname
echo "novos-live" > /etc/hostname echo "noveriaos-live" > /etc/hostname
hostname -F /etc/hostname hostname -F /etc/hostname
# Enable networking on boot # Enable networking on boot
@ -10,6 +10,8 @@ rc-update add networking
# Enable hostname service # Enable hostname service
rc-update add hostname rc-update add hostname
rc-update add sshd
# Set Swiss keymap # Set Swiss keymap
setup-keymap ch ch setup-keymap ch ch
@ -18,9 +20,9 @@ setup-timezone Europe/Zurich
hwclock --systohc hwclock --systohc
# Change default shell of root from ash => zsh # Change default shell of root from ash => zsh
sed -i 's~root:/bin/sh~root:/bin/zsh~' /etc/passwd sed -i 's~root:/bin/ash~root:/bin/zsh~' /etc/passwd
sed -i 's~/sbin/getty 38400~/usr/sbin/mingetty --autologin root --noclear~' /etc/inittab sed -i 's~/sbin/getty 38400~/sbin/mingetty --autologin root --noclear~' /etc/inittab
# Add btrfs module # Add btrfs module
echo "btrfs" | tee -a /etc/modules echo "btrfs" | tee -a /etc/modules

6
grub.cfg Executable file
View file

@ -0,0 +1,6 @@
insmod all_video
insmod part_msdos
insmod part_gpt
insmod fat
set timeout=1

View file

@ -1,6 +1,6 @@
linux-lts linux-lts
linux-firmware linux-firmware-none
ansible salt-minion
zsh zsh
vim vim
btrfs-progs btrfs-progs

17
profile.yaml Executable file
View file

@ -0,0 +1,17 @@
name: noveriaos
distro: alpine
publisher: Noveria Network <https://noveria.org>
label: NOVERIAOS
codename: latest-stable
application_id: Alpine Linux Live Media
airootfs_directory: airootfs
#iso_merge: iso_merge
compression: squashfs||-comp gzip
grub_cfg: grub.cfg
packages:
- packages.x86_64
file_permissions:
- /etc/shadow|0:0:400
- /root/install.sh|0:0:755
customize_airootfs:
- customize-airootfs.sh

View file

@ -1,18 +0,0 @@
#!/usr/bin/env bash
# shellcheck disable=SC2034
iso_name="novos-ansible"
iso_label="NOVOS_$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y%m%d)-ANSIBLE"
iso_publisher="Noveria Network <https://noveria.org>"
iso_application="Alpine-Linux Based Server OS for Noveria"
iso_version="v3.21"
release_version="2412"
airootfs_image_type="squashfs"
airootfs_image_tool_options="-comp gzip"
declare -gA file_permissions=(
["/etc/shadow"]="0:0:400"
["/root/install.sh"]="0:0:755"
)
customize_airootfs=(
"novos-base.sh"
)

View file

@ -1,533 +0,0 @@
#!/usr/bin/env bash
###
##
## Novos Install script
##
###
###
## Definitions
###
# Checks
readonly CHECK_INTERNET_URL='www.alpinelinux.org'
# Installation
readonly INSTALLATION_LOCK_FILE='/root/.installation.lock'
readonly INSTALLATION_LOGFILE='/root/installation.log'
readonly INSTALLATION_PARTLABEL_ESP="ESP"
readonly INSTALLATION_PARTLABEL_ROOT="ROOT"
readonly INSTALLATION_ESP_PARTITION_SIZE=4
readonly INSTALLATION_MOUNTPOINT='/mnt'
readonly INSTALLATION_NOVERIA_BIN='/usr/local/noveria/bin'
readonly INSTALLATION_SECRETS_FILE="/root/installation.secrets"
readonly INSTALLATION_ANSIBLE_ROOT="srv/ansible"
readonly INSTALLATION_ANSIBLE_GIT="https://git.noveria.org/Novos/ansible-playbooks.git"
readonly INSTALLATION_ALPINE_VERSION=$(cat /etc/os-release | grep VERSION_ID | cut -d= -f2)
readonly INSTALLATION_REL_VERSION=%REL_VER%
# Colors
readonly RED='\033[0;31m'
readonly NC='\033[0m' # No Color
###
## Errorhandling
###
# set -e exit script when a command fails
# set -o pipefail check any command in pipeline for error, not just last one
# set -eo pipefail
# catch ^C and other signals and clean up
trap "errorHardExit 'Interrupted with CTRL+C'" SIGINT SIGHUP SIGTERM SIGABRT
###
## Helper Functions
###
##
# Run commands in chroot
# - $1: command
##
function runInChroot() {
chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "$1"
}
##
# Installation subtask title output
# - $1: subtask title
##
function installationSubtaskTitle() {
echo -e "\n=> $1"
}
##
# Random password generator (alphanumeric)
# - $1: password length (default 11)
# - $2: avoid poorly readable characters: l/I/1, O/0 (default false)
##
function randomPasswordGen() {
# character set
if ${2:-false}; then
local character_set='a-km-zA-HJ-NP-Z2-9'
else
local character_set='a-zA-Z0-9'
fi
# https://en.wikipedia.org/wiki/randomPasswordGen#Bash
LC_ALL=C tr -dc "$character_set" </dev/urandom | head -c "${1:-11}"
echo
}
##
# Hard exit with console error message
##
function errorHardExit() {
echo -e "${RED}$1${NC} \nAborting \n"
exit 1
}
###
## Functions
###
##
# Pre checks
##
function preChecks() {
# Check if another installation is in progress
if [ -f $INSTALLATION_LOCK_FILE ]; then
dialog --stdout --clear --no-collapse --yes-label "Exit" --no-label "Start anyway" --yesno " Another installation is in progress" 6 50
case $? in
0)
clear
exit
;;
1) rm "$INSTALLATION_LOCK_FILE" ;;
255)
clear
exit
;;
esac
fi
# Check if booted in UEFI
if [ ! -d /sys/firmware/efi ]; then
dialog --stdout --clear --no-collapse --yes-label "Shutdown" --nolabel "Alpine shell" --yesno "The ISO hasn't been booted in UEFI mode. Please boot the ISO in UEFI to proceed installation" 6 50
case $? in
0)
clear
COUNTER=5
echo "Novos is shutting down in: "
while [ 1 ]; do
if [ ${COUNTER} -eq 0 ]; then
break
fi
echo -n "${COUNTER}"
COUNTER=$( echo "${COUNTER}-1" | bc )
sleep 0.2
for (( i=0; i<4; i++ )); do
echo -n "."
sleep 0.2
done
done
poweroff
;;
1)
clear
exit 0
;;
255)
clear
exit
;;
esac
fi
introDialogue
}
##
# Introduction dialog
##
function introDialogue() {
local introtext="\n\n\n
Velkommen til
_ _\n
| \ | | _____ _____ ___\n
| \| |/ _ \ \ / / _ \/ __|\n
| |\ | (_) \ V / (_) \__ \ \n
|_| \_|\___/ \_/ \___/|___/\n\n
OS: Novos
Version: $INSTALLATION_REL_VERSION
IP: $(ifconfig eth0 | grep "inet addr" | awk '{$1=$1};1' | awk '{print $2}' | cut -d: -f2)
How do you want to continue?
"
dialog --stdout --clear --cr-wrap --no-collapse --yes-label "Graphical Guide" --no-label "Alpine shell" --yesno "$introtext" 31 93
case $? in
1)
clear
exit
;;
255)
clear
exit
;;
esac
checkInternetConnection
}
##
# Internet connection
##
function checkInternetConnection() {
dialog --no-collapse --infobox "\n Check internet connection" 5 35
# wait 5 seconds to give some more time for network initialization
sleep 5
while ! ping -c 1 "$CHECK_INTERNET_URL" >/dev/null 2>&1; do
dialog --clear --title "No internet connection" --msgbox "
Insert network cable, wait 5 seconds and press 'OK'" 7 65
done
prepareInstallation
}
##
# Installation preparation
##
function prepareInstallation() {
# disk
readonly AVAILABLE_DISKS=($(lsblk | grep -vE "p[0-9]+" | grep -vE "[s,v]d[a-z][0-9]+" | grep -v "luks" | grep -v "rom" | grep -vE "sd[a-z][0-9]+" | grep -v "/" | tail -n +2 | awk '{print $1}'))
for available_disk in ${AVAILABLE_DISKS[@]}; do
if [[ -z "$diskString" ]]; then
diskString="$available_disk /dev/$available_disk off"
else
diskString="$diskString $available_disk /dev/$available_disk off"
fi
done
INSTALLATION_DISK=$(dialog --clear --radiolist "Select Disk to install the system" 10 70 3 $(echo $diskString) 3>&1 1>&2 2>&3 3>&-)
INSTALLATION_DISK_BYID=$(lshw -class disk | grep ${INSTALLATION_DISK} | tr -d "[:space:]" | cut -d: -f2)
# root password
INSTALLATION_ROOT_PW=$(randomPasswordGen 5)
for _ in {0..2}; do
INSTALLATION_ROOT_PW="${INSTALLATION_ROOT_PW}-$(randomPasswordGen 5)"
done
# hostname
INSTALLATION_HOSTNAME=$(dialog --clear --title "What's the hostname of this device?" --inputbox "Enter hostname" 10 70 3>&1 1>&2 2>&3 3>&-)
# domain
INSTALLATION_DOMAIN=$(dialog --clear --title "What's the domain of this device?" --inputbox "Enter domain (leave empty for localhost)" 10 70 3>&1 1>&2 2>&3 3>&-)
[[ -z "$INSTALLATION_DOMAIN" ]] && INSTALLATION_DOMAIN="localhost"
# installation type
INSTALLATION_TYPE=$(dialog --clear --title "Choose the main installation type of this host" --radiolist "Select one" 10 70 3 gaming Game-Server false proxy Proxy-Server false build Build-Server false 3>&1 1>&2 2>&3 3>&-)
# show summary
summary
}
##
# Summary to confirm
##
function summary() {
dialog --stdout --clear --title "Summary" --yes-label "Confirm" --no-label "Abort" --yesno "\n
Hostname: ${INSTALLATION_HOSTNAME}.${INSTALLATION_DOMAIN}\n
Type: ${INSTALLATION_TYPE}\n
Disk: ${INSTALLATION_DISK}
" 9 60
case $? in
0) installation ;;
1)
clear
errorHardExit "Abort on summary dialog"
;;
255)
clear
errorHardExit "Abort on summary dialog"
;;
esac
}
##
# Installation
##
function installation() {
# clear display
clear
# lock file
touch "$INSTALLATION_LOCK_FILE" || installationFailed
# log all output to logfile
rm -f "$INSTALLATION_LOGFILE" || installationFailed
exec &> >(tee -a "$INSTALLATION_LOGFILE")
# create boot environment timestamp
START_TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S") || installationFailed
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ Swipe and repartition disk │"
echo "└──────────────────────────────────────────┘"
installationSubtaskTitle "Wipe disk"
blkdiscard -f "${INSTALLATION_DISK_BYID}" || installationFailed
installationSubtaskTitle "Repartitioning disk"
parted -s "${INSTALLATION_DISK_BYID}" mklabel gpt || installationFailed
parted -s "${INSTALLATION_DISK_BYID}" mkpart "${INSTALLATION_PARTLABEL_ESP}" fat32 1MiB ${INSTALLATION_ESP_PARTITION_SIZE}GiB || installationFailed
parted -s "${INSTALLATION_DISK_BYID}" set 1 esp on || installationFailed
parted -s "${INSTALLATION_DISK_BYID}" mkpart "${INSTALLATION_PARTLABEL_ROOT}" btrfs ${INSTALLATION_ESP_PARTITION_SIZE}GiB 100% || installationFailed
# Informing the Kernel of the changes.
sleep 0.1
partprobe "${INSTALLATION_DISK_BYID}" || installationFailed
# loop until lsblk is updated and gives the partition back
while
sleep 0.1
ESP_PARTITION="/dev/$(lsblk "${INSTALLATION_DISK_BYID}" -o NAME,PARTLABEL | grep "${INSTALLATION_PARTLABEL_ESP}" | cut -d " " -f1 | cut -c7-)" || installationFailed
ROOT_PARTITION="/dev/$(lsblk "${INSTALLATION_DISK_BYID}" -o NAME,PARTLABEL | grep "${INSTALLATION_PARTLABEL_ROOT}" | cut -d " " -f1 | cut -c7-)" || installationFailed
[[ "${ESP_PARTITION}" == '/dev/' || "${ROOT_PARTITION}" == '/dev/' ]]
do :; done
installationSubtaskTitle "File system creation"
mkfs.vfat -F 32 -n EFI "${ESP_PARTITION}" || installationFailed
mkfs.btrfs -f -L ROOT "${ROOT_PARTITION}" || installationFailed
installationSubtaskTitle "Create btrfs subvolumes"
mount -t btrfs "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}" || installationFailed
btrfs sub create "${INSTALLATION_MOUNTPOINT}/@root_${START_TIMESTAMP}" || installationFailed
btrfs sub create "${INSTALLATION_MOUNTPOINT}/@home" || installationFailed
btrfs sub create "${INSTALLATION_MOUNTPOINT}/@podman" || installationFailed
btrfs sub create "${INSTALLATION_MOUNTPOINT}/@mysql" || installationFailed
umount "${INSTALLATION_MOUNTPOINT}" || installationFailed
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ Mount filesystems │"
echo "└──────────────────────────────────────────┘"
installationSubtaskTitle "Mount btrfs subvolumes"
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@root_"${START_TIMESTAMP}" "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}" || installationFailed
mkdir -p ${INSTALLATION_MOUNTPOINT}/{efi,home,btrfs,var/lib/mysql,opt/podman,sys/firmware/efi/efivars} || installationFailed
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@home "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}/home" || installationFailed
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@podman "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}/opt/podman" || installationFailed
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@mysql "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}/var/lib/mysql" || installationFailed
mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=/ "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}/btrfs" || installationFailed
installationSubtaskTitle "Mount ESP"
mount -o nodev,nosuid,noexec "${ESP_PARTITION}" "${INSTALLATION_MOUNTPOINT}/efi" || installationFailed
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ Install and configure OS │"
echo "└──────────────────────────────────────────┘"
installationSubtaskTitle "Install base packages"
wget https://raw.githubusercontent.com/alpinelinux/alpine-make-rootfs/v0.7.0/alpine-make-rootfs
chmod u+x alpine-make-rootfs
./alpine-make-rootfs --no-cleanup --branch 'v'$(echo ${INSTALLATION_ALPINE_VERSION} | rev | cut -d. -f2- | rev) --packages "apk-tools alpine-base linux-lts linux-firmware-none zsh vim btrfs-progs dialog wget git mkinitfs lsblk parted lshw shadow" ${INSTALLATION_MOUNTPOINT}
installationSubtaskTitle "Setup resolv.conf"
if [[ -f "${INSTALLATION_MOUNTPOINT}/etc/resolv.conf" ]]; then
rm -f "${INSTALLATION_MOUNTPOINT}/etc/resolv.conf"
fi
cp /etc/resolv.conf "${INSTALLATION_MOUNTPOINT}/etc/resolv.conf" || installationFailed
installationSubtaskTitle "Setup PATH"
runInChroot "export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'" || installationFailed
installationSubtaskTitle "Mount extra mounts for chroot"
mount -t proc /proc "${INSTALLATION_MOUNTPOINT}/proc" || installationFailed
mount -t sysfs /sys "${INSTALLATION_MOUNTPOINT}/sys" || installationFailed
mount -t efivarfs efivarfs "${INSTALLATION_MOUNTPOINT}/sys/firmware/efi/efivars" || installationFailed
mount -o bind /dev "${INSTALLATION_MOUNTPOINT}/dev" || installationFailed
mount -o bind /run "${INSTALLATION_MOUNTPOINT}/run" || installationFailed
installationSubtaskTitle "Install base-packages"
runInChroot "apk add alpine-base tzdata eudev udev-init-scripts --no-cache" || installationFailed
installationSubtaskTitle "Overwrite default repositories"
cp /etc/apk/repositories "${INSTALLATION_MOUNTPOINT}/etc/apk/repositories" || installationFailed
installationSubtaskTitle "Install Ansible"
runInChroot "apk add ansible envsubst" || installationFailed
installationSubtaskTitle "Setup keymap"
runInChroot "setup-keymap ch ch" || installationFailed
installationSubtaskTitle "Setting localtime to Europe/Zurich"
runInChroot "ln -s /usr/share/zoneinfo/Europe/Zurich /etc/localtime" || installationFailed
installationSubtaskTitle "Time sync"
runInChroot "hwclock --systohc" || installationFailed
installationSubtaskTitle "Setup hostname"
runInChroot "echo '${INSTALLATION_HOSTNAME}.${INSTALLATION_DOMAIN}' > /etc/hostname" || installationFailed
runInChroot "hostname -F /etc/hostname" || installationFailed
runInChroot "rc-update add hostname" || installationFailed
installationSubtaskTitle "Setup hosts"
cp /etc/hosts "${INSTALLATION_MOUNTPOINT}/etc/hosts" || installationFailed
installationSubtaskTitle "Set root password"
runInChroot "echo -e \"${INSTALLATION_ROOT_PW}\n${INSTALLATION_ROOT_PW}\" | passwd" || installationFailed
installationSubtaskTitle "Enable btrfs module"
runInChroot "echo 'btrfs' >> /etc/modules"
runInChroot "echo 'efivarfs' >> /etc/modules"
installationSubtaskTitle "Enable udev services"
runInChroot "rc-update add udev sysinit"
runInChroot "rc-update add udev-trigger sysinit"
runInChroot "rc-update add udev-settle sysinit"
runInChroot "rc-update add udev-postmount default"
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ Configure Ansible and playbook-run │"
echo "└──────────────────────────────────────────┘"
installationSubtaskTitle "Clone Playbook-repo"
mkdir -p ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_ANSIBLE_ROOT}/playbooks
git clone ${INSTALLATION_ANSIBLE_GIT} ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_ANSIBLE_ROOT}/playbooks
mkdir -p ${INSTALLATION_MOUNTPOINT}/etc/ansible
cat >"${INSTALLATION_MOUNTPOINT}/etc/ansible/ansible.cfg" <<EOT || installationFailed
[defaults]
inventory=/${INSTALLATION_ANSIBLE_ROOT}/inventory.yml
EOT
cat >"${INSTALLATION_MOUNTPOINT}/${INSTALLATION_ANSIBLE_ROOT}/inventory.yml" <<EOT
ungrouped:
hosts:
localhost
vars:
ansible_connection: local
start_timestamp: ${START_TIMESTAMP}
tmpfs_size: 4G
installation_type: ${INSTALLATION_TYPE}
mysql_root_password: $(randomPasswordGen 32)
release_version: %REL_VER%
alpine_version: %ALP_VER%
EOT
installationSubtaskTitle "Execute Ansible playbooks"
runInChroot "ansible-playbook /${INSTALLATION_ANSIBLE_ROOT}/playbooks/top.ansible.yml" || installationFailed
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ Boot │"
echo "└──────────────────────────────────────────┘"
installationSubtaskTitle "Make EFI boot image with mkinitfs"
latest_kernel="$(chroot $INSTALLATION_MOUNTPOINT /bin/ash -c 'echo $(apk search linux-lts | head -n1 | cut -d- -f3- | sed "s|r||")-lts')"
runInChroot "mkinitfs $latest_kernel" || installationFailed
installationSubtaskTitle "Installing grub to /efi"
runInChroot "grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=alpine" || installationFailed
installationSubtaskTitle "Generating Bootmenu entries"
chroot "${INSTALLATION_MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/noveriablcgen --noconfirm" || installationFailed
installationSubtaskTitle "Generating motd"
chroot "${INSTALLATION_MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/generate_motd" || installationFailed
chroot "${INSTALLATION_MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/nsm check remote" || installationFailed
echo ""
echo "┌──────────────────────────────────────────┐"
echo "│ Finishing │"
echo "└──────────────────────────────────────────┘"
#installationSubtaskTitle "Unmount"
#umount -l ${INSTALLATION_MOUNTPOINT} || installationFailed
installationSubtaskTitle "End of installation"
# end log all output to logfile
exec &>"$(tty)"
# write secrets file
writeInstallationSecretsToFile
# remove installation lock file
rm -f "$INSTALLATION_LOCK_FILE"
# remove shell histories
rm -f /root/.zsh_history
selected_option=$(dialog --output-fd 1 --menu "What would you like to do?" 10 70 5 reboot "Reboot into your newly installed system" poweroff "Shut down the current live system" alpine-shell "Switch to an interactive shell")
case "$selected_option" in
"reboot")
reboot
;;
"poweroff")
poweroff
;;
"alpine-shell")
clear
exit
;;
esac
}
##
# Write installation secrets to file
##
writeInstallationSecretsToFile() {
rm -f "$INSTALLATION_SECRETS_FILE"
{
echo "# Installation secrets from $START_TIMESTAMP"
echo ""
echo "FQDN: $(cat /mnt/etc/hostname)"
echo ""
echo "root_pw: ${INSTALLATION_ROOT_PW}"
echo ""
} >>"$INSTALLATION_SECRETS_FILE"
}
##
# Installation failed
# - $1: comment
##
installationFailed() {
# log error
echo -e "\n=> ERROR"
if [ -n "$1" ]; then
echo -e "=> Comment: $1"
fi
# end log all output to logfile
exec &>"$(tty)"
# Remove lock file
rm -f $INSTALLATION_LOCK_FILE
dialog --no-collapse --ok-label "Exit" --msgbox "\n Installation failed\n\nLog: ${INSTALLATION_LOGFILE} " 9 32
clear
exit 1
}
###
## Script Start
###
preChecks
###
## Script End
###