Created
April 19, 2019 14:29
-
-
Save ThomasTJdev/898e9de422d5a1c4f33f9b546b46e6b0 to your computer and use it in GitHub Desktop.
NimHA install script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# INSPIRED BY PIHOLE. PLEASE SEE PIHOLE LICENSE FOR USE. | |
# Pi-hole: A black hole for Internet advertisements | |
# (c) 2017-2018 Pi-hole, LLC (https://pi-hole.net) | |
# | |
# PIHOLE FILE CAN BE FOUND AT https://install.pi-hole.net | |
# | |
# THIS FILE IS NOT PUBLIC DOMAIN AND MAY NOT BE USED. | |
# THIS IS A PRIVATE DEVELOPMENT FILE. | |
# NimHA automated installer | |
# -e option instructs bash to immediately exit if any command [1] has a non-zero exit status | |
# We do not want users to end up with a partially working install, so we exit the script | |
# instead of continuing the installation with something broken | |
set -e | |
# Location for final installation log storage | |
installLoc=/var/tmp/nimha | |
configFile=/etc/nimha/nimha.cfg | |
CFG_SYSTEM_USERNAME=nimha | |
CFG_SYSTEM_USERGROUP=nimha | |
# Git url | |
gitRepoUrl="https://github.com/ThomasTJdev/nim_homeassistant.git" | |
# Colors | |
COL_NC='\e[0m' # No Color | |
COL_LIGHT_GREEN='\e[1;32m' | |
COL_LIGHT_RED='\e[1;31m' | |
COL_LIGHT_YELLOW='\e[1;33m' | |
COL_LIGHT_BLUE='\e[1;34m' | |
TICK="[${COL_LIGHT_GREEN}✓${COL_NC}]" | |
CROSS="[${COL_LIGHT_RED}✗${COL_NC}]" | |
INFO="[i]" | |
# shellcheck disable=SC2034 | |
DONE="${COL_LIGHT_GREEN} done!${COL_NC}" | |
OVER="\\r\\033[K" | |
# Params | |
CFG_SYSTEMCTL=false | |
CFG_SYSTEMCTLNAME="nimha" | |
CFG_SYMBOLIC=false | |
CFG_USERNAME="admin" | |
CFG_EMAIL="admin@admin.com" | |
CFG_PASS="nimhaadmin" | |
CFG_APPNAME="nimha_main" | |
# BinBash | |
# Find the rows and columns will default to 80x24 if it can not be detected | |
screen_size=$(stty size || printf '%d %d' 24 80) | |
# Set rows variable to contain first number | |
printf -v rows '%d' "${screen_size%% *}" | |
# Set columns variable to contain second number | |
printf -v columns '%d' "${screen_size##* }" | |
# Divide by two so the dialogs take up half of the screen, which looks nice. | |
r=$(( rows / 2 )) | |
c=$(( columns / 2 )) | |
# Unless the screen is tiny | |
r=$(( r < 20 ? 20 : r )) | |
c=$(( c < 70 ? 70 : c )) | |
# | |
# NIMHA | |
# | |
show_ascii_logo() { | |
echo -e "${COL_LIGHT_BLUE} | |
_ ___ __ _____ | |
/ | / (_)___ ___ / / / / | | |
/ |/ / / __ '__ \/ /_/ / /| | | |
/ /| / / / / / / / __ / ___ | | |
/_/ |_/_/_/ /_/ /_/_/ /_/_/ |_| | |
${COL_NC}" | |
} | |
# | |
# USERS | |
# | |
setup_user() { | |
printf " %b %s\\n" "${INFO}" "Adding NimHA user" | |
# force: This option causes the command to exit with success status if the specified group already exists. | |
groupadd --system --force ${CFG_SYSTEM_USERGROUP} || return 1 | |
useradd --system -M -N --gid ${CFG_SYSTEM_USERGROUP} --home /var/lib/${CFG_SYSTEM_USERNAME} ${CFG_SYSTEM_USERNAME} &> /dev/null || printf " %b %s\\n" "${TICK}" "User already exists" | |
printf " %b %s\\n" "${TICK}" "User created" | |
} | |
# | |
# FOLDERS | |
# | |
setup_folder() { | |
local directory="${1}" | |
if [[ -d "${directory}" ]]; then | |
printf " %b %s\\n" "${TICK}" "Directory exists: ${directory}" | |
else | |
printf " %b %s\\n" "${INFO}" "Directory does not exists. Creating ${directory}" | |
mkdir -p "${directory}" || return 1 | |
printf " %b %s\\n" "${TICK}" "Directory created" | |
fi | |
} | |
setup_folder_permission() { | |
local directory="${1}" | |
local user="${2}" | |
local group="${3}" | |
printf " %b %s\\n" "${INFO}" "Setting folder permissions" | |
chown -R ${user}:${group} /var/lib/nimha || return 1 | |
printf " %b %s\\n" "${TICK}" "Folder permission set to ${user}:${group}" | |
} | |
# | |
# CHECK REQUIRED | |
# | |
is_command() { | |
local check_command="$1" | |
command -v "${check_command}" >/dev/null 2>&1 | |
} | |
check_req() { | |
if is_command ${1} ; then | |
local str="${1} is installed" | |
printf " %b %s\\n" "${TICK}" "${str}" | |
else | |
local str="${1} is requied" | |
printf " %b %s\\n" "${CROSS}" "${str}" | |
exit 1 | |
fi | |
} | |
# | |
# GIT REPO | |
# | |
is_repo() { | |
local directory="${1}" | |
local curdir | |
local rc | |
curdir="${PWD}" | |
# If the first argument passed to this function is a directory, | |
if [[ -d "${directory}" ]]; then | |
# move into the directory | |
cd "${directory}" | |
# Use git to check if the directory is a repo | |
# git -C is not used here to support git versions older than 1.8.4 | |
git status --short &> /dev/null || rc=$? | |
# If the command was not successful, | |
else | |
# Set a non-zero return code if directory does not exist | |
rc=1 | |
fi | |
# Move back into the directory the user started in | |
cd "${curdir}" | |
# Return the code; if one is not set, return 0 | |
return "${rc:-0}" | |
} | |
make_repo() { | |
# Set named variables for better readability | |
local directory="${1}" | |
local remoteRepo="${2}" | |
# The message to display when this function is running | |
str="Clone ${remoteRepo} into ${directory}" | |
# Display the message and use the color table to preface the message with an "info" indicator | |
printf " %b %s..." "${INFO}" "${str}" | |
# If the directory exists, | |
if [[ -d "${directory}" ]]; then | |
# delete everything in it so git can clone into it | |
rm -rf "${directory}" | |
fi | |
# Clone the repo and return the return code from this command | |
git clone -q --depth 1 "${remoteRepo}" "${directory}" &> /dev/null || return $? | |
# Show a colored message showing it's status | |
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" | |
# Always return 0? Not sure this is correct | |
return 0 | |
} | |
update_repo() { | |
local directory="${1}" | |
local curdir | |
local str="Update repo in ${1}" | |
curdir="${PWD}" | |
# Move into the directory that was passed as an argument | |
cd "${directory}" &> /dev/null || return 1 | |
printf " %b %s..." "${INFO}" "${str}" | |
# Stash any local commits as they conflict with our working code | |
git stash --all --quiet &> /dev/null || true # Okay for stash failure | |
git clean --quiet --force -d || true # Okay for already clean directory | |
git pull --quiet &> /dev/null || return $? | |
# Show a completion message | |
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" | |
# Move back into the original directory | |
cd "${curdir}" &> /dev/null || return 1 | |
return 0 | |
} | |
# A function that combines the functions previously made | |
getGitFiles() { | |
local directory="${1}" | |
local remoteRepo="${2}" | |
local str="Check for existing repository in ${1}" | |
printf " %b %s..." "${INFO}" "${str}" | |
# Check if the directory is a repository | |
if is_repo "${directory}"; then | |
# Show that we're checking it | |
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" | |
# Update the repo, returning an error message on failure | |
update_repo "${directory}" || { printf "\\n %b: Could not update local repository. Contact support.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; } | |
# If it's not a .git repo, | |
else | |
# Show an error | |
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" | |
# Attempt to make the repository, showing an error on failure | |
make_repo "${directory}" "${remoteRepo}" || { printf "\\n %bError: Could not update local repository. Contact support.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; } | |
fi | |
echo "" | |
return 0 | |
} | |
# Reset a repo to get rid of any local changed | |
resetRepo() { | |
# Use named variables for arguments | |
local directory="${1}" | |
# Move into the directory | |
cd "${directory}" &> /dev/null || return 1 | |
# Store the message in a variable | |
str="Resetting repository within ${1}..." | |
# Show the message | |
printf " %b %s..." "${INFO}" "${str}" | |
# Use git to remove the local changes | |
git reset --hard &> /dev/null || return $? | |
# And show the status | |
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" | |
# Returning success anyway? | |
return 0 | |
} | |
clone_or_update_repos() { | |
# We need the directory | |
local directory="${1}" | |
# as well as the repo URL | |
local remoteRepo="${2}" | |
# so get git files for Core | |
getGitFiles ${directory} ${remoteRepo} || return 1 | |
} | |
welcomeDialogs() { | |
whiptail --msgbox --backtitle "Welcome" --title "Nim Website Creator" "\\n\\nThis installer will install and enable NimHA!" ${r} ${c} | |
} | |
setInstallFolder() { | |
local directory=${1} | |
local installDir=$(whiptail --inputbox "Full path to install" 8 78 "${directory}" --title "Install location" 3>&1 1>&2 2>&3) | |
installLoc=${installDir} | |
printf " %b %s\\n" "${INFO}" "Install directory: ${installLoc}" | |
} | |
setUserParams() { | |
CFG_USERNAME=$(whiptail --inputbox "Username (x > 3)" 8 78 "${CFG_USERNAME}" --title "Admin user" 3>&1 1>&2 2>&3) | |
CFG_EMAIL=$(whiptail --inputbox "Email (x > 5)" 8 78 "${CFG_EMAIL}" --title "Admin user" 3>&1 1>&2 2>&3) | |
CFG_PASS=$(whiptail --inputbox "Password (x > 9)" 8 78 "${CFG_PASS}" --title "Admin user" 3>&1 1>&2 2>&3) | |
printf " %b %s\\n" "${TICK}" "User data updated. You can always edit them within the browser." | |
} | |
setSystemctl() { | |
local ToggleCommand | |
local ChooseOptions | |
local Choices | |
ToggleCommand=(whiptail --separate-output --radiolist "Enable systemctl?" ${r} ${c} 6) | |
ChooseOptions=("On (Recommended)" "" on | |
Off "" off) | |
Choices=$("${ToggleCommand[@]}" "${ChooseOptions[@]}" 2>&1 >/dev/tty) || (printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" && exit 1) | |
case ${Choices} in | |
"On (Recommended)") | |
printf " %b Systemctl On\\n" "${INFO}" | |
#enable_service ${CFG_SYSTEMCTLNAME} | |
CFG_SYSTEMCTL=true | |
;; | |
Off) | |
printf " %b Systemctl Off\\n" "${INFO}" | |
#disable_service ${CFG_SYSTEMCTLNAME} | |
CFG_SYSTEMCTL=false | |
;; | |
esac | |
} | |
setSymbolicLink() { | |
local ToggleCommand | |
local ChooseOptions | |
local Choices | |
ToggleCommand=(whiptail --separate-output --radiolist "Make symbolic link to NimHA?" ${r} ${c} 6) | |
ChooseOptions=("On (Recommended)" "" on | |
Off "" off) | |
Choices=$("${ToggleCommand[@]}" "${ChooseOptions[@]}" 2>&1 >/dev/tty) || (printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" && exit 1) | |
case ${Choices} in | |
"On (Recommended)") | |
printf " %b Symbolic link On\\n" "${INFO}" | |
check_req firejail | |
# Set it to true | |
CFG_SYMBOLIC=true | |
;; | |
Off) | |
printf " %b Symbolic link Off\\n" "${INFO}" | |
# or false | |
CFG_SYMBOLIC=false | |
;; | |
esac | |
} | |
setCompileFlag() { | |
local ToggleCommand | |
local ChooseOptions | |
local Choices | |
ToggleCommand=(whiptail --separate-output --radiolist "Use firejail?" ${r} ${c} 6) | |
ChooseOptions=("On (Recommended)" "" on | |
Off "" off) | |
Choices=$("${ToggleCommand[@]}" "${ChooseOptions[@]}" 2>&1 >/dev/tty) || (printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" && exit 1) | |
case ${Choices} in | |
"On (Recommended)") | |
printf " %b Firejail On\\n" "${INFO}" | |
check_req firejail | |
# Set it to true | |
CFG_FIREJAIL=true | |
;; | |
Off) | |
printf " %b Firejail Off\\n" "${INFO}" | |
# or false | |
CFG_FIREJAIL=false | |
;; | |
esac | |
} | |
config_nimha() { | |
local directory=${1} | |
local strConfig=${2} | |
local strConfigDefault=${directory}"/config/config_default.cfg" | |
# Check if config.cfg exists or create it | |
if [ ! -f ${strConfig} ]; then | |
printf " %b %s\\n" "${INFO}" "Copy default config file to ${strConfig}" | |
cp -v ${strConfigDefault} ${strConfig} &> /dev/null || return 1 | |
printf " %b %s\\n" "${TICK}" "Config file created" | |
else | |
printf " %b %s\\n" "${TICK}" "Config exists: ${strConfig}" | |
fi | |
} | |
compile_nimha() { | |
local directory=${1} | |
local nimUser=$(logname) | |
# Stop service if running | |
if check_service_active ${CFG_SYSTEMCTLNAME} ; then | |
stop_service ${CFG_SYSTEMCTLNAME} &> /dev/null | |
printf " %b %s\\n" "${TICK}" "Service stopped" | |
fi | |
# Cd to directory | |
cd "${directory}" &> /dev/null || return 1 | |
# Delete sub runner | |
if [ -f ${CFG_APPNAME} ]; then | |
rm ${CFG_APPNAME} &> /dev/null || return 1 | |
printf " %b %s\\n" "${TICK}" "Old compile file removed" | |
fi | |
# Compile | |
printf " %b %s\\n" "${INFO}" "Compiling" | |
local strCompile="nim c -d:release -d:ssl nimha" | |
eval $strCompile | |
# Admin user and standard data | |
printf " %b %s\\n" "${INFO}" "Adding admin user" | |
printf " %b %s\\n" "${INFO}" "Inserting standard data" | |
local strRunData="./nimha newuser -u:${CFG_USERNAME} -e:${CFG_EMAIL} -p:${CFG_PASS} ${CFG_STANDARDDATA}" | |
eval $strRunData | |
# Symbolic link | |
if [[ "${CFG_SYMBOLIC}" == true ]]; then | |
ln -s ${directory}/nimha /usr/bin/nimha || return 1 | |
printf " %b %s\\n" "${TICK}" "Symbolic link created" | |
fi | |
# Systemctl | |
if [[ "${CFG_SYSTEMCTL}" == true ]]; then | |
enable_service ${CFG_SYSTEMCTLNAME} | |
printf " %b %s\\n" "${TICK}" "Systemctl enabled" | |
fi | |
} | |
stop_service() { | |
# Stop service passed in as argument. | |
# Can softfail, as process may not be installed when this is called | |
local str="Stopping ${1} service" | |
printf " %b %s..." "${INFO}" "${str}" | |
if is_command systemctl ; then | |
systemctl stop "${1}" &> /dev/null || true | |
else | |
service "${1}" stop &> /dev/null || true | |
fi | |
printf "%b %b %s...\\n" "${OVER}" "${TICK}" "${str}" | |
} | |
# Start/Restart service passed in as argument | |
restart_service() { | |
# Local, named variables | |
local str="Restarting ${1} service" | |
printf " %b %s..." "${INFO}" "${str}" | |
# If systemctl exists, | |
if is_command systemctl ; then | |
# use that to restart the service | |
systemctl restart "${1}" &> /dev/null | |
# Otherwise, | |
else | |
# fall back to the service command | |
service "${1}" restart &> /dev/null | |
fi | |
printf "%b %b %s...\\n" "${OVER}" "${TICK}" "${str}" | |
} | |
# Enable service so that it will start with next reboot | |
enable_service() { | |
# Local, named variables | |
local str="Enabling ${1} service to start on reboot" | |
printf " %b %s..." "${INFO}" "${str}" | |
# If systemctl exists, | |
if is_command systemctl ; then | |
# use that to enable the service | |
systemctl enable "${1}" &> /dev/null | |
# Otherwise, | |
else | |
# use update-rc.d to accomplish this | |
update-rc.d "${1}" defaults &> /dev/null | |
fi | |
printf "%b %b %s...\\n" "${OVER}" "${TICK}" "${str}" | |
} | |
# Disable service so that it will not with next reboot | |
disable_service() { | |
# Local, named variables | |
local str="Disabling ${1} service" | |
printf " %b %s..." "${INFO}" "${str}" | |
# If systemctl exists, | |
if is_command systemctl ; then | |
# use that to disable the service | |
systemctl disable "${1}" &> /dev/null | |
# Otherwise, | |
else | |
# use update-rc.d to accomplish this | |
update-rc.d "${1}" disable &> /dev/null | |
fi | |
printf "%b %b %s...\\n" "${OVER}" "${TICK}" "${str}" | |
} | |
check_service_active() { | |
# If systemctl exists, | |
if is_command systemctl ; then | |
# use that to check the status of the service | |
systemctl is-enabled "${1}" &> /dev/null | |
# Otherwise, | |
else | |
# fall back to service command | |
service "${1}" status &> /dev/null | |
fi | |
} | |
main() { | |
######## FIRST CHECK ######## | |
# Must not be root to install! | |
printf "\\n\\n" | |
show_ascii_logo | |
printf " %b %s\\n" "${INFO}" "User priviligies" | |
if [[ "${EUID}" -eq 0 ]]; then | |
# Root | |
printf " %b %s\\n" "${INFO}" "You are running as root - take care" | |
printf " Make sure to download this script from a trusted source\\n\\n" | |
printf " %b %s\\n" "${TICK}" "NimHA will be enabled with systemctl" | |
# Otherwise, | |
else | |
# They do not have enough privileges, so let the user know | |
printf " %b %s\\n" "${CROSS}" "You are running as a non-root user" | |
printf " Please enable root and run again\\n\\n" | |
fi | |
# Check req | |
printf "\\n\\n" | |
printf " %b %s\\n" "${INFO}" "Checking required software" | |
check_req nim | |
# Display welcome dialogs | |
welcomeDialogs | |
# Install folder | |
setInstallFolder ${installLoc} | |
# Login details | |
setUserParams | |
# Flags | |
#setCompileFlag | |
# Symbolic link | |
setSymbolicLink | |
# Enable with systemctl | |
setSystemctl | |
# Create user | |
setup_user | |
# Create folder | |
setup_folder ${installLoc} | |
# Clone/Update the repos | |
clone_or_update_repos ${installLoc} ${gitRepoUrl} | |
# Config NimHA | |
config_nimha ${installLoc} ${configFile} | |
# Set folder permission | |
#setup_folder_permission ${installLoc} ${CFG_SYSTEM_USERNAME} ${CFG_SYSTEM_USERGROUP} | |
# Compile | |
# TODO: Use normal users Nim env path. If Nim is not installed or exported for root or nimha-user, this breaks | |
compile_nimha ${installLoc} | |
# Set folder permission | |
#setup_folder_permission ${installLoc} ${CFG_SYSTEM_USERNAME} ${CFG_SYSTEM_USERGROUP} | |
} | |
if [[ "${PH_TEST}" != true ]] ; then | |
main "$@" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment