autoNAS / scripts / install.sh
5bf8614 3 months ago History
1 contributor
300 lines | 9.847kb
#!/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