Last active
March 30, 2026 16:06
-
-
Save sony-level/cc7cea1bbc154009949fde84b00b5c27 to your computer and use it in GitHub Desktop.
Automated install ansible
This file contains hidden or 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 | |
| set -Eeuo pipefail | |
| # ============================================================ | |
| # _ _ _ ____ ___ ____ _ _____ | |
| # / \ | \ | / ___|_ _| __ )| | | ____| | |
| # / _ \ | \| \___ \| || _ \| | | _| | |
| # / ___ \| |\ |___) | || |_) | |___| |___ | |
| # /_/ \_\_| \_|____/___|____/|_____|_____| | |
| # | |
| # Ansible Installer | |
| # | |
| # Description: | |
| # Cross-platform Ansible installation script designed to | |
| # automate installation using the official recommended method | |
| # for each supported operating system. | |
| # | |
| # Features: | |
| # - Automatic OS detection | |
| # - Official package source setup | |
| # - Ansible PPA GPG key installation and verification | |
| # - Debian/Ubuntu fingerprint validation | |
| # - Ansible post-install verification | |
| # - Bash/Zsh autocomplete support | |
| # - Timestamped logs | |
| # | |
| # Website : https://level-sony.fr | |
| # Contact : https://level-sony.fr/en/contact/ | |
| # GitHub : https://github.com/sony-level | |
| # ============================================================ | |
| readonly SCRIPT_NAME="$(basename "$0")" | |
| readonly SITE_NAME="level-sony.fr" | |
| readonly SITE_CONTACT_URL="https://level-sony.fr/en/contact/" | |
| readonly ANSIBLE_PPA_KEY_URL="https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=get&search=0x6125E2A8C77F2818FB7BD15B93C4A3FD7BB9C367" | |
| readonly ANSIBLE_KEYRING="/usr/share/keyrings/ansible-archive-keyring.gpg" | |
| readonly ANSIBLE_APT_LIST="/etc/apt/sources.list.d/ansible.list" | |
| readonly EXPECTED_ANSIBLE_FINGERPRINT="6125E2A8C77F2818FB7BD15B93C4A3FD7BB9C367" | |
| readonly LOG_TS_FORMAT="+%Y-%m-%d %H:%M:%S" | |
| log() { | |
| local level="$1" | |
| shift | |
| printf '[%s] [%s] [%s] %s\n' "$(date "$LOG_TS_FORMAT")" "$level" "$SCRIPT_NAME" "$*" | |
| } | |
| info() { | |
| log "INFO" "$@" | |
| } | |
| warn() { | |
| log "WARN" "$@" >&2 | |
| } | |
| error() { | |
| log "ERROR" "$@" >&2 | |
| } | |
| die() { | |
| error "$@" | |
| error "Support / contact: ${SITE_CONTACT_URL}" | |
| exit 1 | |
| } | |
| on_error() { | |
| local exit_code=$? | |
| error "Script failed at line ${BASH_LINENO[0]} with exit code ${exit_code}." | |
| error "Website: ${SITE_NAME} | Contact: ${SITE_CONTACT_URL}" | |
| exit "$exit_code" | |
| } | |
| trap on_error ERR | |
| require_command() { | |
| local cmd="$1" | |
| command -v "$cmd" >/dev/null 2>&1 || die "Required command not found: $cmd" | |
| } | |
| run_sudo() { | |
| if [[ "${EUID}" -eq 0 ]]; then | |
| "$@" | |
| else | |
| sudo "$@" | |
| fi | |
| } | |
| normalize_fingerprint() { | |
| tr -d '[:space:]' | tr '[:lower:]' '[:upper:]' | |
| } | |
| verify_ansible() { | |
| info "Verifying Ansible installation..." | |
| require_command ansible | |
| ansible --version >/dev/null 2>&1 || die "ansible --version failed." | |
| info "Ansible installation verified successfully." | |
| } | |
| detect_shell_rc_file() { | |
| local current_shell shell_name | |
| current_shell="${SHELL:-}" | |
| shell_name="$(basename "$current_shell")" | |
| case "$shell_name" in | |
| bash) echo "${HOME}/.bashrc" ;; | |
| zsh) echo "${HOME}/.zshrc" ;; | |
| *) echo "" ;; | |
| esac | |
| } | |
| enable_autocomplete() { | |
| local rc_file | |
| rc_file="$(detect_shell_rc_file)" | |
| if ! command -v ansible >/dev/null 2>&1; then | |
| warn "Ansible is not available in PATH yet. Skipping autocomplete." | |
| return 0 | |
| fi | |
| if [[ -z "$rc_file" ]]; then | |
| warn "Unsupported shell for automatic autocomplete setup. Skipping." | |
| return 0 | |
| fi | |
| if [[ ! -f "$rc_file" ]]; then | |
| info "Creating shell configuration file: $rc_file" | |
| touch "$rc_file" | |
| fi | |
| info "Ansible autocomplete is typically enabled by default. Restart your shell to activate it." | |
| } | |
| install_macos() { | |
| info "Detected macOS." | |
| require_command brew | |
| info "Installing Ansible with Homebrew..." | |
| brew install ansible | |
| verify_ansible | |
| enable_autocomplete | |
| } | |
| install_windows_choco() { | |
| info "Detected Windows-like environment with Chocolatey available." | |
| require_command choco | |
| info "Installing Ansible with Chocolatey..." | |
| choco install ansible -y | |
| verify_ansible | |
| } | |
| get_linux_id() { | |
| if [[ -r /etc/os-release ]]; then | |
| . /etc/os-release | |
| echo "${ID:-unknown}" | |
| else | |
| echo "unknown" | |
| fi | |
| } | |
| get_linux_like() { | |
| if [[ -r /etc/os-release ]]; then | |
| . /etc/os-release | |
| echo "${ID_LIKE:-}" | |
| else | |
| echo "" | |
| fi | |
| } | |
| get_debian_codename() { | |
| local codename | |
| if [[ -r /etc/os-release ]]; then | |
| . /etc/os-release | |
| if [[ -n "${UBUNTU_CODENAME:-}" ]]; then | |
| codename="$UBUNTU_CODENAME" | |
| elif [[ -n "${VERSION_CODENAME:-}" ]]; then | |
| codename="$VERSION_CODENAME" | |
| fi | |
| fi | |
| if [[ -z "$codename" ]] && command -v lsb_release >/dev/null 2>&1; then | |
| codename="$(lsb_release -cs)" | |
| fi | |
| if [[ -z "$codename" ]]; then | |
| die "Unable to determine Debian/Ubuntu codename." | |
| fi | |
| # Map Raspberry Pi Ubuntu and unsupported codenames to supported versions | |
| case "$codename" in | |
| questing) echo "noble" ;; # Raspberry Pi Ubuntu -> Ubuntu 24.04 | |
| trixie) echo "noble" ;; # Debian 13 -> Ubuntu 24.04 | |
| bookworm) echo "jammy" ;; # Debian 12 -> Ubuntu 22.04 | |
| bullseye) echo "focal" ;; # Debian 11 -> Ubuntu 20.04 | |
| buster) echo "bionic" ;; # Debian 10 -> Ubuntu 18.04 | |
| noble|jammy|focal|bionic) echo "$codename" ;; | |
| *) die "Unsupported codename for Ansible installation: ${codename}" ;; | |
| esac | |
| } | |
| verify_ansible_gpg_fingerprint() { | |
| info "Verifying Ansible PPA GPG fingerprint..." | |
| local fingerprint | |
| fingerprint="$( | |
| gpg --no-default-keyring \ | |
| --keyring "$ANSIBLE_KEYRING" \ | |
| --fingerprint --with-colons 2>/dev/null \ | |
| | awk -F: '/^fpr:/ { print $10; exit }' | |
| )" | |
| [[ -n "$fingerprint" ]] || die "Unable to read GPG fingerprint from $ANSIBLE_KEYRING" | |
| fingerprint="$(printf '%s' "$fingerprint" | normalize_fingerprint)" | |
| if [[ "$fingerprint" != "$EXPECTED_ANSIBLE_FINGERPRINT" ]]; then | |
| die "Ansible PPA GPG fingerprint mismatch. Expected: $EXPECTED_ANSIBLE_FINGERPRINT | Actual: $fingerprint" | |
| fi | |
| info "Ansible PPA GPG fingerprint verified successfully." | |
| } | |
| install_ubuntu() { | |
| info "Detected Ubuntu." | |
| run_sudo apt-get update | |
| run_sudo apt-get install -y software-properties-common curl wget lsb-release | |
| info "Adding Ansible PPA..." | |
| run_sudo add-apt-repository --yes --update ppa:ansible/ansible | |
| info "Installing Ansible..." | |
| run_sudo apt-get install -y ansible | |
| verify_ansible | |
| enable_autocomplete | |
| } | |
| install_debian() { | |
| info "Detected Debian." | |
| # Clean up any stale Ansible PPA config from previous runs to prevent | |
| # apt-get update failures (e.g. sqv SHA1 rejection on Trixie+). | |
| [[ -f "$ANSIBLE_APT_LIST" ]] && run_sudo rm -f "$ANSIBLE_APT_LIST" | |
| [[ -f "$ANSIBLE_KEYRING" ]] && run_sudo rm -f "$ANSIBLE_KEYRING" | |
| run_sudo apt-get update | |
| local codename="" | |
| if [[ -r /etc/os-release ]]; then | |
| . /etc/os-release | |
| codename="${VERSION_CODENAME:-}" | |
| fi | |
| # Debian Trixie+ uses Sequoia PGP (sqv) which rejects SHA1 binding | |
| # signatures in the Ansible PPA InRelease. Use pipx instead. | |
| case "$codename" in | |
| trixie|forky) | |
| install_debian_pipx | |
| return | |
| ;; | |
| esac | |
| run_sudo apt-get install -y gnupg curl wget lsb-release ca-certificates | |
| # Remove existing keyring to avoid interactive gpg --dearmor prompt | |
| [[ -f "$ANSIBLE_KEYRING" ]] && run_sudo rm -f "$ANSIBLE_KEYRING" | |
| info "Downloading Ansible PPA GPG key..." | |
| wget -O- "$ANSIBLE_PPA_KEY_URL" | run_sudo gpg --dearmor -o "$ANSIBLE_KEYRING" | |
| verify_ansible_gpg_fingerprint | |
| local ubuntu_codename | |
| ubuntu_codename="$(get_debian_codename)" | |
| info "Configuring Ansible PPA for Debian (using Ubuntu ${ubuntu_codename})..." | |
| echo "deb [signed-by=${ANSIBLE_KEYRING}] http://ppa.launchpad.net/ansible/ansible/ubuntu ${ubuntu_codename} main" \ | |
| | run_sudo tee "$ANSIBLE_APT_LIST" >/dev/null | |
| info "Refreshing APT package index..." | |
| run_sudo apt-get update | |
| info "Installing Ansible..." | |
| run_sudo apt-get install -y ansible | |
| verify_ansible | |
| enable_autocomplete | |
| } | |
| install_debian_pipx() { | |
| info "Installing Ansible via pipx (PPA unavailable on this Debian version due to SHA1 policy)..." | |
| run_sudo apt-get install -y pipx python3-full | |
| pipx install --include-deps ansible | |
| # Ensure ~/.local/bin is in PATH for verification | |
| export PATH="${HOME}/.local/bin:${PATH}" | |
| pipx ensurepath | |
| verify_ansible | |
| enable_autocomplete | |
| } | |
| install_fedora() { | |
| info "Detected Fedora." | |
| require_command dnf | |
| info "Installing Ansible with DNF..." | |
| run_sudo dnf install -y ansible | |
| verify_ansible | |
| enable_autocomplete | |
| } | |
| install_arch() { | |
| info "Detected Arch Linux." | |
| require_command pacman | |
| info "Installing Ansible with Pacman..." | |
| run_sudo pacman -S ansible | |
| verify_ansible | |
| enable_autocomplete | |
| } | |
| install_opensuse() { | |
| info "Detected openSUSE." | |
| require_command zypper | |
| info "Installing Ansible with Zypper..." | |
| run_sudo zypper install ansible | |
| verify_ansible | |
| enable_autocomplete | |
| } | |
| install_rhel_centos_amzn() { | |
| info "Detected RHEL/CentOS/Amazon Linux family." | |
| if command -v dnf >/dev/null 2>&1; then | |
| info "Using DNF..." | |
| run_sudo dnf install -y epel-release | |
| run_sudo dnf install -y ansible | |
| elif command -v yum >/dev/null 2>&1; then | |
| info "Using YUM..." | |
| run_sudo yum install -y epel-release | |
| run_sudo yum install -y ansible | |
| else | |
| die "Neither dnf nor yum is available." | |
| fi | |
| verify_ansible | |
| enable_autocomplete | |
| } | |
| install_linux() { | |
| local distro like | |
| distro="$(get_linux_id)" | |
| like="$(get_linux_like)" | |
| info "Linux distribution detected: ID=${distro}, ID_LIKE=${like}" | |
| case "$distro" in | |
| ubuntu) | |
| install_ubuntu | |
| ;; | |
| debian) | |
| install_debian | |
| ;; | |
| fedora) | |
| install_fedora | |
| ;; | |
| arch) | |
| install_arch | |
| ;; | |
| opensuse-leap|opensuse-tumbleweed) | |
| install_opensuse | |
| ;; | |
| amzn|rhel|centos|rocky|almalinux|ol) | |
| install_rhel_centos_amzn | |
| ;; | |
| *) | |
| case "$like" in | |
| *debian*) | |
| install_debian | |
| ;; | |
| *rhel*|*fedora*) | |
| install_rhel_centos_amzn | |
| ;; | |
| *) | |
| die "Unsupported Linux distribution: ${distro}. Use manual installation for this system." | |
| ;; | |
| esac | |
| ;; | |
| esac | |
| } | |
| detect_platform() { | |
| local uname_out | |
| uname_out="$(uname -s 2>/dev/null || true)" | |
| case "$uname_out" in | |
| Darwin) echo "macos" ;; | |
| Linux) echo "linux" ;; | |
| MINGW*|MSYS*|CYGWIN*) echo "windows_like" ;; | |
| *) | |
| if command -v choco >/dev/null 2>&1; then | |
| echo "windows_like" | |
| else | |
| echo "unknown" | |
| fi | |
| ;; | |
| esac | |
| } | |
| main() { | |
| info "Starting Ansible installation..." | |
| info "This script will install Ansible using the official package repositories." | |
| info "Maintainer website: ${SITE_NAME}" | |
| info "Support page: ${SITE_CONTACT_URL}" | |
| info "Platform: $(detect_platform)" | |
| info "Architecture: $(uname -m)" | |
| local platform | |
| platform="$(detect_platform)" | |
| case "$platform" in | |
| macos) | |
| install_macos | |
| ;; | |
| linux) | |
| install_linux | |
| ;; | |
| windows_like) | |
| install_windows_choco | |
| ;; | |
| *) | |
| die "Unsupported operating system." | |
| ;; | |
| esac | |
| info "Ansible setup completed successfully." | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment