1 contributor
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
PROJECT_ID="autonas"
ORG_ID="xdev"
RUNTIME_DIR="/usr/local/lib/${ORG_ID}/${PROJECT_ID}"
DOC_DIR="/usr/local/share/doc/${ORG_ID}/${PROJECT_ID}"
COMMAND_PATH="/usr/local/sbin/autonas"
UNINSTALL_PATH="${RUNTIME_DIR}/uninstall.sh"
UNINSTALL_WRAPPER="/usr/local/sbin/${ORG_ID}-${PROJECT_ID}-uninstall"
DEFAULTS_PATH="/etc/default/${ORG_ID}-${PROJECT_ID}"
CONFIG_DIR="/etc/pve/autonas"
CONFIG_FILE="${CONFIG_DIR}/disks.conf"
MOUNT_BASE="/mnt/autonas"
UNIFIED_SCRIPT="autonas.sh"
CORE_SCRIPT="autonas-core.sh"
DISK_HANDLER_SCRIPT="autonas-disk-handler.sh"
UDEV_WRAPPER_SCRIPT="autonas-udev-wrapper.sh"
BOOT_SCAN_SCRIPT="autonas-boot-scan.sh"
NETWORK_HANDLER_SCRIPT="autonas-network-handler.sh"
MEDIA_IMPORTER_SCRIPT="autonas-media-importer.sh"
SYNC_ORDERING_SCRIPT="autonas-sync-systemd-ordering.sh"
DISK_RULES="99-autonas-disk.rules"
INTERFACE_RULES="98-autonas-interfaces.rules"
ATTACH_UNIT="autonas-attach@.service"
MAIN_UNIT="autonas.service"
BOOT_SCAN_UNIT="autonas-boot-scan.service"
require_root() {
if [[ "${EUID}" -ne 0 ]]; then
echo "ERROR: this action must be run as root" >&2
exit 1
fi
}
is_package_installed() {
local package="$1"
dpkg -l "$package" 2>/dev/null | grep -q "^ii"
}
check_dependencies() {
local missing_packages=()
local required_packages=("nfs-kernel-server" "autofs" "udev" "libimage-exiftool-perl")
local package=""
echo "Checking AutoNAS dependencies..."
for package in "${required_packages[@]}"; do
if is_package_installed "${package}"; then
echo "✓ ${package}"
else
echo "✗ ${package}"
missing_packages+=("${package}")
fi
done
if [[ ${#missing_packages[@]} -gt 0 ]]; then
echo ""
echo "Missing packages detected:"
printf " %s\n" "${missing_packages[@]}"
echo ""
echo "Run:"
echo " $0 install-deps"
return 1
fi
echo "✓ All dependencies are installed"
}
install_dependencies() {
require_root
if ! command -v apt >/dev/null 2>&1; then
echo "ERROR: automatic dependency installation requires apt" >&2
exit 1
fi
apt update
apt install -y nfs-kernel-server autofs udev libimage-exiftool-perl
}
run_existing_uninstall() {
if [[ -x "${UNINSTALL_PATH}" ]]; then
"${UNINSTALL_PATH}" --force || true
elif [[ -x "/usr/local/lib/autonas/autonas-uninstall.sh" ]]; then
bash /usr/local/lib/autonas/autonas-uninstall.sh --force || true
elif [[ -x "/usr/local/bin/autonas-uninstall.sh" ]]; then
bash /usr/local/bin/autonas-uninstall.sh --force || true
fi
}
install_runtime() {
mkdir -p "${RUNTIME_DIR}" "${DOC_DIR}" "${CONFIG_DIR}" "${MOUNT_BASE}" /usr/local/sbin /etc/default
install -m 0755 "${SCRIPT_DIR}/${UNIFIED_SCRIPT}" "${COMMAND_PATH}"
install -m 0755 "${SCRIPT_DIR}/${CORE_SCRIPT}" "${RUNTIME_DIR}/${CORE_SCRIPT}"
install -m 0755 "${SCRIPT_DIR}/${DISK_HANDLER_SCRIPT}" "${RUNTIME_DIR}/${DISK_HANDLER_SCRIPT}"
install -m 0755 "${SCRIPT_DIR}/${UDEV_WRAPPER_SCRIPT}" "${RUNTIME_DIR}/${UDEV_WRAPPER_SCRIPT}"
install -m 0755 "${SCRIPT_DIR}/${BOOT_SCAN_SCRIPT}" "${RUNTIME_DIR}/${BOOT_SCAN_SCRIPT}"
install -m 0755 "${SCRIPT_DIR}/${NETWORK_HANDLER_SCRIPT}" "${RUNTIME_DIR}/${NETWORK_HANDLER_SCRIPT}"
install -m 0755 "${SCRIPT_DIR}/${MEDIA_IMPORTER_SCRIPT}" "${RUNTIME_DIR}/${MEDIA_IMPORTER_SCRIPT}"
install -m 0755 "${SCRIPT_DIR}/${SYNC_ORDERING_SCRIPT}" "${RUNTIME_DIR}/${SYNC_ORDERING_SCRIPT}"
install -m 0755 "${SCRIPT_DIR}/autonas-uninstall.sh" "${UNINSTALL_PATH}"
ln -sfn "${UNINSTALL_PATH}" "${UNINSTALL_WRAPPER}"
if [[ ! -f "${DEFAULTS_PATH}" ]]; then
install -m 0644 "${PROJECT_DIR}/config/autonas" "${DEFAULTS_PATH}"
else
echo "Preserving existing defaults: ${DEFAULTS_PATH}"
fi
}
cleanup_legacy_paths() {
rm -f /usr/local/bin/autonas
rm -f /usr/local/bin/autonas.sh
rm -f /usr/local/bin/autonas-core.sh
rm -f /usr/local/bin/autonas-disk-handler.sh
rm -f /usr/local/bin/autonas-udev-wrapper.sh
rm -f /usr/local/bin/autonas-boot-scan.sh
rm -f /usr/local/bin/autonas-network-handler.sh
rm -f /usr/local/bin/autonas-media-importer.sh
rm -f /usr/local/bin/autonas-uninstall.sh
}
install_system_integration() {
install -m 0644 "${PROJECT_DIR}/config/${DISK_RULES}" "/etc/udev/rules.d/${DISK_RULES}"
install -m 0644 "${PROJECT_DIR}/config/${INTERFACE_RULES}" "/etc/udev/rules.d/${INTERFACE_RULES}"
install -m 0644 "${PROJECT_DIR}/config/${ATTACH_UNIT}" "/etc/systemd/system/${ATTACH_UNIT}"
install -m 0644 "${PROJECT_DIR}/config/${MAIN_UNIT}" "/etc/systemd/system/${MAIN_UNIT}"
install -m 0644 "${PROJECT_DIR}/config/${BOOT_SCAN_UNIT}" "/etc/systemd/system/${BOOT_SCAN_UNIT}"
}
install_config() {
if [[ ! -f "${CONFIG_FILE}" ]]; then
install -m 0644 "${PROJECT_DIR}/config/disks.conf" "${CONFIG_FILE}"
echo "Installed initial config template: ${CONFIG_FILE}"
else
echo "Preserving existing configuration: ${CONFIG_FILE}"
fi
if [[ ! -f /etc/exports ]]; then
touch /etc/exports
fi
}
install_docs() {
rm -rf "${DOC_DIR}"
mkdir -p "${DOC_DIR}"
cp "${PROJECT_DIR}/README.md" "${DOC_DIR}/README.md"
cp "${PROJECT_DIR}/DEVELOPMENT.md" "${DOC_DIR}/DEVELOPMENT.md"
cp "${PROJECT_DIR}/CHANGELOG.md" "${DOC_DIR}/CHANGELOG.md"
cp "${PROJECT_DIR}/INSTALL.md" "${DOC_DIR}/INSTALL.md"
}
activate_installation() {
"${RUNTIME_DIR}/${SYNC_ORDERING_SCRIPT}"
systemctl daemon-reload
systemctl enable --now nfs-kernel-server >/dev/null 2>&1 || true
systemctl enable --now autonas.service >/dev/null 2>&1 || true
systemctl enable --now autonas-boot-scan.service >/dev/null 2>&1 || true
udevadm control --reload-rules || true
udevadm trigger --subsystem-match=block --action=add || true
}
verify_installation() {
local required_paths=(
"${COMMAND_PATH}"
"${RUNTIME_DIR}/${CORE_SCRIPT}"
"${RUNTIME_DIR}/${DISK_HANDLER_SCRIPT}"
"${RUNTIME_DIR}/${UDEV_WRAPPER_SCRIPT}"
"${RUNTIME_DIR}/${BOOT_SCAN_SCRIPT}"
"${RUNTIME_DIR}/${NETWORK_HANDLER_SCRIPT}"
"${RUNTIME_DIR}/${MEDIA_IMPORTER_SCRIPT}"
"${RUNTIME_DIR}/${SYNC_ORDERING_SCRIPT}"
"${UNINSTALL_PATH}"
"${DOC_DIR}"
"${DEFAULTS_PATH}"
"/etc/udev/rules.d/${DISK_RULES}"
"/etc/udev/rules.d/${INTERFACE_RULES}"
"/etc/systemd/system/${ATTACH_UNIT}"
"/etc/systemd/system/${MAIN_UNIT}"
"/etc/systemd/system/${BOOT_SCAN_UNIT}"
"${CONFIG_FILE}"
)
local path=""
for path in "${required_paths[@]}"; do
if [[ ! -e "${path}" ]]; then
echo "ERROR: expected installed path missing: ${path}" >&2
exit 1
fi
done
}
do_start() {
require_root
"${RUNTIME_DIR}/${SYNC_ORDERING_SCRIPT}"
systemctl enable --now nfs-kernel-server >/dev/null 2>&1 || true
systemctl enable --now autonas.service >/dev/null 2>&1 || true
systemctl enable --now autonas-boot-scan.service >/dev/null 2>&1 || true
udevadm control --reload-rules || true
udevadm trigger --subsystem-match=block --action=add || true
echo "AutoNAS started."
}
do_restart() {
require_root
"${RUNTIME_DIR}/${SYNC_ORDERING_SCRIPT}"
systemctl restart nfs-kernel-server || true
systemctl restart autonas.service || true
systemctl restart autonas-boot-scan.service || true
udevadm control --reload-rules || true
udevadm trigger --subsystem-match=block --action=add || true
echo "AutoNAS restarted."
}
do_stop() {
require_root
systemctl stop autonas-boot-scan.service || true
systemctl stop autonas.service || true
systemctl stop nfs-kernel-server || true
echo "AutoNAS stopped."
}
do_status() {
echo "=== Services ==="
systemctl status nfs-kernel-server --no-pager -l || true
systemctl status autonas.service --no-pager -l || true
systemctl status autonas-boot-scan.service --no-pager -l || true
echo ""
echo "=== Config ==="
cat "${CONFIG_FILE}" 2>/dev/null || echo "No config found"
echo ""
echo "=== Mount Points ==="
ls -la "${MOUNT_BASE}/" 2>/dev/null || echo "No AutoNAS mount base"
echo ""
echo "=== Paths ==="
[ -x "${COMMAND_PATH}" ] && echo "✓ ${COMMAND_PATH}"
[ -d "${RUNTIME_DIR}" ] && echo "✓ ${RUNTIME_DIR}"
[ -x "${UNINSTALL_PATH}" ] && echo "✓ ${UNINSTALL_PATH}"
}
do_install() {
require_root
echo "=== Installing AutoNAS ==="
check_dependencies
run_existing_uninstall
install_runtime
cleanup_legacy_paths
install_system_integration
install_config
install_docs
activate_installation
verify_installation
echo "Installed paths:"
echo " command: ${COMMAND_PATH}"
echo " runtime: ${RUNTIME_DIR}"
echo " uninstall: ${UNINSTALL_PATH}"
echo " defaults: ${DEFAULTS_PATH}"
echo " docs: ${DOC_DIR}"
echo " config: ${CONFIG_FILE} (cluster-shared exception)"
echo " mounts: ${MOUNT_BASE} (operational data exception)"
echo " services: enabled and started"
echo ""
echo "Installation completed."
}
cmd="${1:-install}"
case "${cmd}" in
install)
do_install
;;
install-deps)
install_dependencies
;;
check-deps)
check_dependencies
;;
start)
do_start
;;
restart)
do_restart
;;
stop)
do_stop
;;
status)
do_status
;;
*)
echo "Usage: $0 [install|install-deps|check-deps|start|restart|stop|status]" >&2
exit 2
;;
esac