mirror of
https://github.com/dw-0/kiauh.git
synced 2025-12-11 17:44:28 +05:00
417 lines
13 KiB
Bash
417 lines
13 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
#=======================================================================#
|
|
# Copyright (C) 2020 - 2024 Dominik Willner <th33xitus@gmail.com> #
|
|
# #
|
|
# This file is part of KIAUH - Klipper Installation And Update Helper #
|
|
# https://github.com/dw-0/kiauh #
|
|
# #
|
|
# This file may be distributed under the terms of the GNU GPLv3 license #
|
|
#=======================================================================#
|
|
|
|
set -e
|
|
|
|
#=================================================#
|
|
#=============== INSTALL OCTOPRINT ===============#
|
|
#=================================================#
|
|
|
|
function octoprint_systemd() {
|
|
local services
|
|
services=$(find "${SYSTEMD}" -maxdepth 1 -regextype posix-extended -regex "${SYSTEMD}/octoprint(-[0-9a-zA-Z]+)?.service" | sort)
|
|
echo "${services}"
|
|
}
|
|
|
|
function octoprint_setup_dialog() {
|
|
status_msg "Initializing OctoPrint installation ..."
|
|
|
|
local klipper_services
|
|
klipper_services=$(klipper_systemd)
|
|
if [[ -z ${klipper_services} ]]; then
|
|
local error="Klipper not installed! Please install Klipper first!"
|
|
log_error "OctoPrint setup started without Klipper being installed. Aborting setup."
|
|
print_error "${error}" && return
|
|
fi
|
|
|
|
local klipper_count user_input=() klipper_names=()
|
|
klipper_count=$(echo "${klipper_services}" | wc -w )
|
|
for service in ${klipper_services}; do
|
|
klipper_names+=( "$(get_instance_name "${service}")" )
|
|
done
|
|
|
|
local octoprint_count
|
|
if (( klipper_count == 1 )); then
|
|
ok_msg "Klipper installation found!\n"
|
|
octoprint_count=1
|
|
|
|
elif (( klipper_count > 1 )); then
|
|
top_border
|
|
printf "|${green}%-55s${white}|\n" " ${klipper_count} Klipper instances found!"
|
|
for name in "${klipper_names[@]}"; do
|
|
printf "|${cyan}%-57s${white}|\n" " ● ${name}"
|
|
done
|
|
blank_line
|
|
echo -e "| The setup will apply the same names to OctoPrint! |"
|
|
blank_line
|
|
echo -e "| Please select the number of OctoPrint instances to |"
|
|
echo -e "| install. Usually one OctoPrint instance per Klipper |"
|
|
echo -e "| instance is required, but you may not install more |"
|
|
echo -e "| OctoPrint instances than available Klipper instances. |"
|
|
bottom_border
|
|
|
|
local re="^[1-9][0-9]*$"
|
|
while [[ ! ${octoprint_count} =~ ${re} || ${octoprint_count} -gt ${klipper_count} ]]; do
|
|
read -p "${cyan}###### Number of OctoPrint instances to set up:${white} " -i "${klipper_count}" -e octoprint_count
|
|
### break if input is valid
|
|
[[ ${octoprint_count} =~ ${re} ]] && break
|
|
### conditional error messages
|
|
[[ ! ${octoprint_count} =~ ${re} ]] && error_msg "Input not a number"
|
|
(( octoprint_count > klipper_count )) && error_msg "Number of OctoPrint instances larger than existing Klipper instances"
|
|
done && select_msg "${octoprint_count}"
|
|
|
|
else
|
|
log_error "Internal error. klipper_count of '${klipper_count}' not equal or grather than one!"
|
|
return 1
|
|
fi
|
|
|
|
user_input+=("${octoprint_count}")
|
|
|
|
### confirm instance amount
|
|
local yn
|
|
while true; do
|
|
(( octoprint_count == 1 )) && local question="Install OctoPrint?"
|
|
(( octoprint_count > 1 )) && local question="Install ${octoprint_count} OctoPrint instances?"
|
|
read -p "${cyan}###### ${question} (Y/n):${white} " yn
|
|
case "${yn}" in
|
|
Y|y|Yes|yes|"")
|
|
select_msg "Yes"
|
|
break;;
|
|
N|n|No|no)
|
|
select_msg "No"
|
|
abort_msg "Exiting OctoPrint setup ...\n"
|
|
return;;
|
|
*)
|
|
error_msg "Invalid Input!";;
|
|
esac
|
|
done
|
|
|
|
### write existing klipper names into user_input array to use them as names for octoprint
|
|
if (( klipper_count > 1 )); then
|
|
for name in "${klipper_names[@]}"; do
|
|
user_input+=("${name}")
|
|
done
|
|
fi
|
|
|
|
(( octoprint_count > 1 )) && status_msg "Installing ${octoprint_count} OctoPrint instances ..."
|
|
(( octoprint_count == 1 )) && status_msg "Installing OctoPrint ..."
|
|
octoprint_setup "${user_input[@]}"
|
|
}
|
|
|
|
function octoprint_setup() {
|
|
local instance_arr=("${@}")
|
|
### check and install all dependencies
|
|
local dep=(
|
|
git
|
|
wget
|
|
python3-pip
|
|
python3-dev
|
|
libyaml-dev
|
|
build-essential
|
|
python3-setuptools
|
|
python3-virtualenv
|
|
)
|
|
dependency_check "${dep[@]}"
|
|
|
|
### step 1: check for tty and dialout usergroups and add reboot permissions
|
|
check_usergroups
|
|
add_reboot_permission
|
|
|
|
### step 2: install octoprint
|
|
install_octoprint "${instance_arr[@]}"
|
|
|
|
### step 3: set up service
|
|
create_octoprint_service "${instance_arr[@]}"
|
|
|
|
### step 4: enable and start all instances
|
|
do_action_service "enable" "octoprint"
|
|
do_action_service "start" "octoprint"
|
|
|
|
### confirm message
|
|
local confirm=""
|
|
(( instance_arr[0] == 1 )) && confirm="OctoPrint has been set up!"
|
|
(( instance_arr[0] > 1 )) && confirm="${instance_arr[0]} OctoPrint instances have been set up!"
|
|
print_confirm "${confirm}" && print_op_ip_list "${instance_arr[0]}" && return
|
|
}
|
|
|
|
function install_octoprint() {
|
|
|
|
function install_octoprint_python_env() {
|
|
local tmp="${1}"
|
|
### create and activate the virtualenv
|
|
status_msg "Installing python virtual environment..."
|
|
|
|
if [[ ! -d ${tmp} ]]; then
|
|
mkdir -p "${tmp}"
|
|
else
|
|
error_msg "Cannot create temporary directory in ${HOME}!"
|
|
error_msg "Folder 'TMP_OCTO_ENV' exists and may not be empty!"
|
|
error_msg "Please remove/rename that folder and start again."
|
|
return 1
|
|
fi
|
|
|
|
cd "${tmp}"
|
|
|
|
if virtualenv --python=python3 venv; then
|
|
### activate virtualenv
|
|
source venv/bin/activate
|
|
pip install pip --upgrade
|
|
pip install --no-cache-dir octoprint
|
|
### leave virtualenv
|
|
deactivate
|
|
else
|
|
log_error "failure while creating python3 OctoPrint env"
|
|
error_msg "Creation of OctoPrint virtualenv failed!"
|
|
exit 1
|
|
fi
|
|
|
|
cd "${HOME}"
|
|
}
|
|
|
|
local input=("${@}")
|
|
local octoprint_count=${input[0]} && unset "input[0]"
|
|
local names=("${input[@]}") && unset "input[@]"
|
|
local j=0 octo_env
|
|
local tmp="${HOME}/TMP_OCTO_ENV"
|
|
|
|
### handle single instance installs
|
|
if (( octoprint_count == 1 )); then
|
|
if install_octoprint_python_env "${tmp}"; then
|
|
status_msg "Installing OctoPrint ..."
|
|
octo_env="${HOME}/OctoPrint"
|
|
|
|
### rename the temporary directory to the correct name
|
|
[[ -d ${octo_env} ]] && rm -rf "${octo_env}"
|
|
mv "${tmp}" "${octo_env}"
|
|
|
|
### replace the temporary directory name with the actual one in ${octo_env}/venv/bin/python/octoprint
|
|
sed -i "s|${tmp}|${octo_env}|" "${octo_env}/venv/bin/octoprint"
|
|
else
|
|
error_msg "OctoPrint installation failed!"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
### handle multi instance installs
|
|
if (( octoprint_count > 1 )); then
|
|
if install_octoprint_python_env "${tmp}"; then
|
|
for (( i=1; i <= octoprint_count; i++ )); do
|
|
status_msg "Installing OctoPrint instance ${i}(${names[${j}]}) ..."
|
|
octo_env="${HOME}/OctoPrint_${names[${j}]}"
|
|
|
|
### rename the temporary directory to the correct name
|
|
[[ -d ${octo_env} ]] && rm -rf "${octo_env}"
|
|
cp -r "${tmp}" "${octo_env}"
|
|
|
|
### replace the temporary directory name with the actual one in ${octo_env}/venv/bin/python/octoprint
|
|
sed -i "s|${tmp}|${octo_env}|" "${octo_env}/venv/bin/octoprint"
|
|
j=$(( j + 1 ))
|
|
done && rm -rf "${tmp}"
|
|
else
|
|
error_msg "OctoPrint installation failed!"
|
|
return 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function create_octoprint_service() {
|
|
local input=("${@}")
|
|
local octoprint_count=${input[0]} && unset "input[0]"
|
|
local names=("${input[@]}") && unset "input[@]"
|
|
local j=0 port=5000
|
|
local printer_data octo_env service basedir printer config_yaml restart_cmd
|
|
|
|
for (( i=1; i <= octoprint_count; i++ )); do
|
|
if (( octoprint_count == 1 )); then
|
|
printer_data="${HOME}/printer_data"
|
|
octo_env="${HOME}/OctoPrint"
|
|
service="${SYSTEMD}/octoprint.service"
|
|
basedir="${HOME}/.octoprint"
|
|
printer="${printer_data}/comms/klippy.serial"
|
|
config_yaml="${basedir}/config.yaml"
|
|
restart_cmd="sudo service octoprint restart"
|
|
elif (( octoprint_count > 1 )); then
|
|
|
|
local re="^[1-9][0-9]*$"
|
|
if [[ ${names[j]} =~ ${re} ]]; then
|
|
printer_data="${HOME}/printer_${names[${j}]}_data"
|
|
else
|
|
printer_data="${HOME}/${names[${j}]}_data"
|
|
fi
|
|
|
|
octo_env="${HOME}/OctoPrint_${names[${j}]}"
|
|
service="${SYSTEMD}/octoprint-${names[${j}]}.service"
|
|
basedir="${HOME}/.octoprint_${names[${j}]}"
|
|
printer="${printer_data}/comms/klippy.serial"
|
|
config_yaml="${basedir}/config.yaml"
|
|
restart_cmd="sudo service octoprint-${names[${j}]} restart"
|
|
fi
|
|
|
|
(( octoprint_count == 1 )) && status_msg "Creating OctoPrint Service ..."
|
|
(( octoprint_count > 1 )) && status_msg "Creating OctoPrint Service ${i}(${names[${j}]}) ..."
|
|
|
|
sudo /bin/sh -c "cat > ${service}" << OCTOPRINT
|
|
[Unit]
|
|
Description=Starts OctoPrint on startup
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Environment="LC_ALL=C.UTF-8"
|
|
Environment="LANG=C.UTF-8"
|
|
Type=simple
|
|
User=${USER}
|
|
ExecStart=${octo_env}/venv/bin/octoprint --basedir ${basedir} --config ${config_yaml} --port=${port} serve
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
OCTOPRINT
|
|
|
|
port=$(( port + 1 ))
|
|
j=$(( j + 1 ))
|
|
ok_msg "Ok!"
|
|
|
|
### create config.yaml
|
|
if [[ ! -f ${basedir}/config.yaml ]]; then
|
|
[[ ! -d ${basedir} ]] && mkdir "${basedir}"
|
|
|
|
(( octoprint_count == 1 )) && status_msg "Creating config.yaml ..."
|
|
(( octoprint_count > 1 )) && status_msg "Creating config.yaml for instance ${i}(${names[${j}]}) ..."
|
|
|
|
/bin/sh -c "cat > ${basedir}/config.yaml" << CONFIGYAML
|
|
serial:
|
|
additionalPorts:
|
|
- ${printer}
|
|
disconnectOnErrors: false
|
|
port: ${printer}
|
|
server:
|
|
commands:
|
|
serverRestartCommand: ${restart_cmd}
|
|
systemRestartCommand: sudo shutdown -r now
|
|
systemShutdownCommand: sudo shutdown -h now
|
|
CONFIGYAML
|
|
ok_msg "Ok!"
|
|
fi
|
|
done
|
|
}
|
|
|
|
function add_reboot_permission() {
|
|
#create a backup if file already exists
|
|
if [[ -f /etc/sudoers.d/octoprint-shutdown ]]; then
|
|
sudo mv /etc/sudoers.d/octoprint-shutdown /etc/sudoers.d/octoprint-shutdown.old
|
|
fi
|
|
|
|
#create new permission file
|
|
status_msg "Add reboot permission to user '${USER}' ..."
|
|
cd "${HOME}" && echo "${USER} ALL=NOPASSWD: /sbin/shutdown" > octoprint-shutdown
|
|
sudo chown 0 octoprint-shutdown
|
|
sudo mv octoprint-shutdown /etc/sudoers.d/octoprint-shutdown
|
|
ok_msg "Permission set!"
|
|
}
|
|
|
|
function print_op_ip_list() {
|
|
local ip octoprint_count="${1}" port=5000
|
|
ip=$(hostname -I | cut -d" " -f1)
|
|
|
|
for (( i=1; i <= octoprint_count; i++ )); do
|
|
echo -e " ${cyan}● Instance ${i}:${white} ${ip}:${port}"
|
|
port=$(( port + 1 ))
|
|
done && echo
|
|
}
|
|
|
|
#=================================================#
|
|
#=============== REMOVE OCTOPRINT ================#
|
|
#=================================================#
|
|
|
|
function remove_octoprint_service() {
|
|
[[ -z $(octoprint_systemd) ]] && return
|
|
|
|
###remove all octoprint services
|
|
status_msg "Removing OctoPrint Systemd Services ..."
|
|
|
|
for service in $(octoprint_systemd | cut -d"/" -f5); do
|
|
status_msg "Removing ${service} ..."
|
|
sudo systemctl stop "${service}"
|
|
sudo systemctl disable "${service}"
|
|
sudo rm -f "${SYSTEMD}/${service}"
|
|
ok_msg "Done!"
|
|
done
|
|
|
|
### reloading units
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl reset-failed
|
|
}
|
|
|
|
function remove_octoprint_sudoers() {
|
|
[[ ! -f /etc/sudoers.d/octoprint-shutdown ]] && return
|
|
|
|
### remove sudoers file
|
|
sudo rm -f /etc/sudoers.d/octoprint-shutdown
|
|
}
|
|
|
|
function remove_octoprint_env() {
|
|
local files
|
|
files=$(find "${HOME}" -maxdepth 1 -regextype posix-extended -regex "${HOME}/OctoPrint(_[0-9a-zA-Z]+)?" | sort)
|
|
|
|
if [[ -n ${files} ]]; then
|
|
for file in ${files}; do
|
|
status_msg "Removing ${file} ..."
|
|
rm -rf "${file}"
|
|
ok_msg "${file} removed!"
|
|
done
|
|
fi
|
|
}
|
|
|
|
function remove_octoprint_dir() {
|
|
local files
|
|
files=$(find "${HOME}" -maxdepth 1 -regextype posix-extended -regex "${HOME}/.octoprint(_[0-9a-zA-Z]+)?" | sort)
|
|
|
|
if [[ -n ${files} ]]; then
|
|
for file in ${files}; do
|
|
status_msg "Removing ${file} ..."
|
|
rm -rf "${file}"
|
|
ok_msg "${file} removed!"
|
|
done
|
|
fi
|
|
}
|
|
|
|
function remove_octoprint() {
|
|
remove_octoprint_service
|
|
remove_octoprint_sudoers
|
|
remove_octoprint_env
|
|
remove_octoprint_dir
|
|
|
|
local confirm="OctoPrint was successfully removed!"
|
|
|
|
print_confirm "${confirm}" && return
|
|
}
|
|
|
|
#=================================================#
|
|
#=============== OCTOPRINT STATUS ================#
|
|
#=================================================#
|
|
|
|
function get_octoprint_status() {
|
|
local sf_count env_count dir_count status
|
|
sf_count="$(octoprint_systemd | wc -w)"
|
|
env_count=$(find "${HOME}" -maxdepth 1 -regextype posix-extended -regex "${HOME}/OctoPrint(_[0-9a-zA-Z]+)?" | wc -w)
|
|
dir_count=$(find "${HOME}" -maxdepth 1 -regextype posix-extended -regex "${HOME}/.octoprint(_[0-9a-zA-Z]+)?" | wc -w)
|
|
|
|
if (( sf_count == 0 )) && (( env_count == 0 )) && (( dir_count == 0 )); then
|
|
status="Not installed!"
|
|
elif (( sf_count == env_count )) && (( sf_count == dir_count )); then
|
|
status="Installed: ${sf_count}"
|
|
else
|
|
status="Incomplete!"
|
|
fi
|
|
|
|
echo "${status}"
|
|
}
|