Loading tools/bootstrap.sh +129 −36 Original line number Diff line number Diff line Loading @@ -13,10 +13,33 @@ set -euo pipefail # - docker # - docker compose plugin # # Options: # -f, --force Kill running apt/dpkg related processes before continuing # # Example: # bash tools/bootstrap.sh # bash tools/bootstrap.sh -f # sudo USER="$USER" bash tools/bootstrap.sh FORCE_KILL_PACKAGE_MANAGER=0 while [[ $# -gt 0 ]]; do case "$1" in -f|--force) FORCE_KILL_PACKAGE_MANAGER=1 shift ;; -h|--help) sed -n '1,22p' "$0" | sed 's/^# \{0,1\}//' exit 0 ;; *) echo "Unknown option: $1" >&2 echo "Use -h for help." >&2 exit 1 ;; esac done if [[ "${EUID}" -ne 0 ]]; then echo "Please run as root (for example: sudo bash tools/bootstrap.sh)" >&2 exit 1 Loading Loading @@ -45,26 +68,94 @@ if [[ -z "${TARGET_USER}" || "${TARGET_USER}" == "root" ]]; then TARGET_USER="" fi list_package_manager_processes() { ps -eo pid=,args= | awk -v self="$$" ' $1 != self && $0 !~ /awk/ && $0 !~ /ps -eo/ && ($0 ~ /(^|[[:space:]])apt([[:space:]]|$)/ || $0 ~ /apt-get/ || $0 ~ /(^|[[:space:]])dpkg([[:space:]]|$)/ || $0 ~ /unattended-upgrade/) { print } ' } ensure_package_manager_available() { local blocking pids blocking="$(list_package_manager_processes)" if [[ -z "${blocking}" ]]; then return 0 fi if [[ "${FORCE_KILL_PACKAGE_MANAGER}" -ne 1 ]]; then echo "Another apt/dpkg process is running. Please wait for it to finish and retry, or rerun with -f." >&2 echo "${blocking}" >&2 exit 1 fi echo "Force-killing running apt/dpkg processes before continuing:" >&2 echo "${blocking}" >&2 pids="$(printf '%s\n' "${blocking}" | awk '{print $1}')" if [[ -n "${pids}" ]]; then kill ${pids} 2>/dev/null || true sleep 2 blocking="$(list_package_manager_processes)" if [[ -n "${blocking}" ]]; then pids="$(printf '%s\n' "${blocking}" | awk '{print $1}')" kill -9 ${pids} 2>/dev/null || true sleep 1 fi fi blocking="$(list_package_manager_processes)" if [[ -n "${blocking}" ]]; then echo "Failed to clear apt/dpkg processes:" >&2 echo "${blocking}" >&2 exit 1 fi } has_command() { command -v "$1" >/dev/null 2>&1 } echo "Bootstrapping Ubuntu ${VERSION_ID} control host..." export DEBIAN_FRONTEND=noninteractive base_packages=() has_command curl || base_packages+=(curl) has_command git || base_packages+=(git) has_command make || base_packages+=(make) has_command python3 || base_packages+=(python3) dpkg -s python3-pip >/dev/null 2>&1 || base_packages+=(python3-pip) has_command rsync || base_packages+=(rsync) dpkg -s ca-certificates >/dev/null 2>&1 || base_packages+=(ca-certificates) dpkg -s gnupg >/dev/null 2>&1 || base_packages+=(gnupg) dpkg -s lsb-release >/dev/null 2>&1 || base_packages+=(lsb-release) dpkg -s software-properties-common >/dev/null 2>&1 || base_packages+=(software-properties-common) if [[ ${#base_packages[@]} -gt 0 ]]; then ensure_package_manager_available apt-get update apt-get install -y --no-install-recommends "${base_packages[@]}" else echo "Base packages already available." fi if ! has_command ansible-playbook; then ensure_package_manager_available apt-get update apt-get install -y --no-install-recommends \ ca-certificates \ curl \ git \ gnupg \ lsb-release \ make \ python3 \ python3-pip \ rsync \ software-properties-common # Install ansible-playbook from Ubuntu packages. apt-get install -y --no-install-recommends ansible-core else echo "ansible-playbook already available." fi if has_command docker && docker compose version >/dev/null 2>&1; then echo "docker and docker compose already available." else # Install Docker Engine + Compose plugin from Docker's official apt repo. install -m 0755 -d /etc/apt/keyrings if [[ ! -f /etc/apt/keyrings/docker.asc ]]; then Loading @@ -78,6 +169,7 @@ echo \ "deb [arch=${ARCH} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu ${CODENAME} stable" \ > /etc/apt/sources.list.d/docker.list ensure_package_manager_available apt-get update apt-get install -y --no-install-recommends \ containerd.io \ Loading @@ -85,8 +177,9 @@ apt-get install -y --no-install-recommends \ docker-ce \ docker-ce-cli \ docker-compose-plugin fi systemctl enable --now docker has_command docker && systemctl enable --now docker if [[ -n "${TARGET_USER}" ]]; then usermod -aG docker "${TARGET_USER}" || true Loading Loading
tools/bootstrap.sh +129 −36 Original line number Diff line number Diff line Loading @@ -13,10 +13,33 @@ set -euo pipefail # - docker # - docker compose plugin # # Options: # -f, --force Kill running apt/dpkg related processes before continuing # # Example: # bash tools/bootstrap.sh # bash tools/bootstrap.sh -f # sudo USER="$USER" bash tools/bootstrap.sh FORCE_KILL_PACKAGE_MANAGER=0 while [[ $# -gt 0 ]]; do case "$1" in -f|--force) FORCE_KILL_PACKAGE_MANAGER=1 shift ;; -h|--help) sed -n '1,22p' "$0" | sed 's/^# \{0,1\}//' exit 0 ;; *) echo "Unknown option: $1" >&2 echo "Use -h for help." >&2 exit 1 ;; esac done if [[ "${EUID}" -ne 0 ]]; then echo "Please run as root (for example: sudo bash tools/bootstrap.sh)" >&2 exit 1 Loading Loading @@ -45,26 +68,94 @@ if [[ -z "${TARGET_USER}" || "${TARGET_USER}" == "root" ]]; then TARGET_USER="" fi list_package_manager_processes() { ps -eo pid=,args= | awk -v self="$$" ' $1 != self && $0 !~ /awk/ && $0 !~ /ps -eo/ && ($0 ~ /(^|[[:space:]])apt([[:space:]]|$)/ || $0 ~ /apt-get/ || $0 ~ /(^|[[:space:]])dpkg([[:space:]]|$)/ || $0 ~ /unattended-upgrade/) { print } ' } ensure_package_manager_available() { local blocking pids blocking="$(list_package_manager_processes)" if [[ -z "${blocking}" ]]; then return 0 fi if [[ "${FORCE_KILL_PACKAGE_MANAGER}" -ne 1 ]]; then echo "Another apt/dpkg process is running. Please wait for it to finish and retry, or rerun with -f." >&2 echo "${blocking}" >&2 exit 1 fi echo "Force-killing running apt/dpkg processes before continuing:" >&2 echo "${blocking}" >&2 pids="$(printf '%s\n' "${blocking}" | awk '{print $1}')" if [[ -n "${pids}" ]]; then kill ${pids} 2>/dev/null || true sleep 2 blocking="$(list_package_manager_processes)" if [[ -n "${blocking}" ]]; then pids="$(printf '%s\n' "${blocking}" | awk '{print $1}')" kill -9 ${pids} 2>/dev/null || true sleep 1 fi fi blocking="$(list_package_manager_processes)" if [[ -n "${blocking}" ]]; then echo "Failed to clear apt/dpkg processes:" >&2 echo "${blocking}" >&2 exit 1 fi } has_command() { command -v "$1" >/dev/null 2>&1 } echo "Bootstrapping Ubuntu ${VERSION_ID} control host..." export DEBIAN_FRONTEND=noninteractive base_packages=() has_command curl || base_packages+=(curl) has_command git || base_packages+=(git) has_command make || base_packages+=(make) has_command python3 || base_packages+=(python3) dpkg -s python3-pip >/dev/null 2>&1 || base_packages+=(python3-pip) has_command rsync || base_packages+=(rsync) dpkg -s ca-certificates >/dev/null 2>&1 || base_packages+=(ca-certificates) dpkg -s gnupg >/dev/null 2>&1 || base_packages+=(gnupg) dpkg -s lsb-release >/dev/null 2>&1 || base_packages+=(lsb-release) dpkg -s software-properties-common >/dev/null 2>&1 || base_packages+=(software-properties-common) if [[ ${#base_packages[@]} -gt 0 ]]; then ensure_package_manager_available apt-get update apt-get install -y --no-install-recommends "${base_packages[@]}" else echo "Base packages already available." fi if ! has_command ansible-playbook; then ensure_package_manager_available apt-get update apt-get install -y --no-install-recommends \ ca-certificates \ curl \ git \ gnupg \ lsb-release \ make \ python3 \ python3-pip \ rsync \ software-properties-common # Install ansible-playbook from Ubuntu packages. apt-get install -y --no-install-recommends ansible-core else echo "ansible-playbook already available." fi if has_command docker && docker compose version >/dev/null 2>&1; then echo "docker and docker compose already available." else # Install Docker Engine + Compose plugin from Docker's official apt repo. install -m 0755 -d /etc/apt/keyrings if [[ ! -f /etc/apt/keyrings/docker.asc ]]; then Loading @@ -78,6 +169,7 @@ echo \ "deb [arch=${ARCH} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu ${CODENAME} stable" \ > /etc/apt/sources.list.d/docker.list ensure_package_manager_available apt-get update apt-get install -y --no-install-recommends \ containerd.io \ Loading @@ -85,8 +177,9 @@ apt-get install -y --no-install-recommends \ docker-ce \ docker-ce-cli \ docker-compose-plugin fi systemctl enable --now docker has_command docker && systemctl enable --now docker if [[ -n "${TARGET_USER}" ]]; then usermod -aG docker "${TARGET_USER}" || true Loading