From 7949beefd7e4c68cba3a4b7eea1234a5dd1e9b08 Mon Sep 17 00:00:00 2001 From: Thomas Ory Date: Tue, 26 May 2026 16:54:53 +0200 Subject: [PATCH 1/8] Fix vpn issue --- CHANGELOG.md | 14 +++++++- apt-packages/wireguard-setup.sh | 63 +++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb8378d..467c07d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,19 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [1.3.0] + +### Added +- **WireGuard dispatcher** : automatic VPN startup via NetworkManager dispatcher + - VPN is skipped when connected to the corporate network (`ITSF-Wifi`) + - VPN waits for a valid IP assignment on the WiFi interface before attempting to connect + - VPN waits for actual connectivity to the WireGuard endpoint (`vpn-user.itsf.io`) before starting + - All dispatcher decisions are logged to the system journal (`journalctl -t nm-dispatcher`) + +### Changed +- **WireGuard** : disabled NetworkManager `autoconnect` on the `itsf` connection — startup is now fully managed by the dispatcher + +## [1.2.0] ### Removed - **GNOME Configuration Module**: Removed entire gnome-config module due to installation issues diff --git a/apt-packages/wireguard-setup.sh b/apt-packages/wireguard-setup.sh index f109c42..1725753 100755 --- a/apt-packages/wireguard-setup.sh +++ b/apt-packages/wireguard-setup.sh @@ -179,9 +179,67 @@ import_networkmanager_connection() { # Import the configuration to NetworkManager sudo nmcli connection import type wireguard file /etc/wireguard/itsf.conf + # Disable autoconnect — the VPN will be started conditionally by the dispatcher + sudo nmcli connection modify itsf connection.autoconnect no print_success "WireGuard connection imported to NetworkManager" - print_warning "You can now manage the connection through NetworkManager" + print_warning "Autoconnect disabled — VPN will start automatically via dispatcher (see below)" +} + +# Function to install the NetworkManager dispatcher script +install_dispatcher() { + print_header "NetworkManager Dispatcher Setup" + local DISPATCHER_FILE="/etc/NetworkManager/dispatcher.d/99-wireguard-itsf" + local VPN_NAME="itsf" + local CORP_SSID="ITSF-Wifi" + print_status "Installing dispatcher script: $DISPATCHER_FILE" + sudo tee "$DISPATCHER_FILE" > /dev/null << 'DISPATCHER' +#!/bin/bash +IFACE=$1 +EVENT=$2 +VPN_NAME="itsf" +CORP_SSID="ITSF-Wifi" +VPN_ENDPOINT="vpn-user.itsf.io" +MAX_WAIT=20 # secondes max avant abandon + +wait_for_ip() { + local attempt=0 + while [[ $attempt -lt $MAX_WAIT ]]; do + ip addr show "$IFACE" | grep -q 'inet ' && return 0 + sleep 1 + (( attempt++ )) + done + logger -t nm-dispatcher "itsf-vpn: timeout waiting for IP on $IFACE" + return 1 +} + +wait_for_connectivity() { + local attempt=0 + while [[ $attempt -lt $MAX_WAIT ]]; do + ping -c 1 -W 1 "$VPN_ENDPOINT" &>/dev/null && return 0 + sleep 1 + (( attempt++ )) + done + logger -t nm-dispatcher "itsf-vpn: timeout waiting for connectivity to $VPN_ENDPOINT" + return 1 +} + +if [[ "$EVENT" == "up" && "$IFACE" =~ ^wl ]]; then + CURRENT_SSID=$(nmcli -t -f active,ssid dev wifi | grep '^yes' | cut -d: -f2) + if [[ "$CURRENT_SSID" != "$CORP_SSID" ]]; then + wait_for_ip || exit 1 + wait_for_connectivity || exit 1 + nmcli connection up "$VPN_NAME" + logger -t nm-dispatcher "itsf-vpn: VPN $VPN_NAME started on $IFACE (SSID: $CURRENT_SSID)" + else + logger -t nm-dispatcher "itsf-vpn: corporate network detected ($CORP_SSID), VPN skipped" + fi +fi +DISPATCHER + sudo chmod +x "$DISPATCHER_FILE" + print_success "Dispatcher script installed: $DISPATCHER_FILE" + print_status "The VPN '${VPN_NAME}' will auto-start on any WiFi except '${CORP_SSID}'." + print_warning "To add more corporate SSIDs, edit $DISPATCHER_FILE and extend the condition." } # Function to show WireGuard status @@ -205,7 +263,8 @@ create_itsf_config # Import to NetworkManager import_networkmanager_connection - +# Install dispatcher for conditional autostart +install_dispatcher # Show status show_wireguard_status From c06f3c4902f80b0eb587d370ba203520e9df84f9 Mon Sep 17 00:00:00 2001 From: Thomas Ory Date: Wed, 27 May 2026 10:23:16 +0200 Subject: [PATCH 2/8] upgrade vpn startup script --- apt-packages/wireguard-setup.sh | 37 ++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/apt-packages/wireguard-setup.sh b/apt-packages/wireguard-setup.sh index 1725753..15f5d68 100755 --- a/apt-packages/wireguard-setup.sh +++ b/apt-packages/wireguard-setup.sh @@ -199,8 +199,9 @@ IFACE=$1 EVENT=$2 VPN_NAME="itsf" CORP_SSID="ITSF-Wifi" -VPN_ENDPOINT="vpn-user.itsf.io" -MAX_WAIT=20 # secondes max avant abandon +CORP_DNS_1="10.195.28.20" +CORP_DNS_2="10.195.28.50" +MAX_WAIT=20 wait_for_ip() { local attempt=0 @@ -213,27 +214,39 @@ wait_for_ip() { return 1 } -wait_for_connectivity() { +wait_for_dns() { local attempt=0 while [[ $attempt -lt $MAX_WAIT ]]; do - ping -c 1 -W 1 "$VPN_ENDPOINT" &>/dev/null && return 0 + # Résolution via les DNS assignés à l'interface (pas les DNS système) + if resolvectl query --interface="$IFACE" gitlab.steelhome.internal &>/dev/null; then + return 0 + fi sleep 1 (( attempt++ )) done - logger -t nm-dispatcher "itsf-vpn: timeout waiting for connectivity to $VPN_ENDPOINT" + logger -t nm-dispatcher "itsf-vpn: timeout waiting for DNS on $IFACE" return 1 } +is_on_corp_network() { + local active_dns + active_dns=$(nmcli dev show "$IFACE" 2>/dev/null | grep 'IP4.DNS' | awk '{print $2}') + echo "$active_dns" | grep -qE "^($CORP_DNS_1|$CORP_DNS_2)$" +} + if [[ "$EVENT" == "up" && "$IFACE" =~ ^wl ]]; then CURRENT_SSID=$(nmcli -t -f active,ssid dev wifi | grep '^yes' | cut -d: -f2) - if [[ "$CURRENT_SSID" != "$CORP_SSID" ]]; then - wait_for_ip || exit 1 - wait_for_connectivity || exit 1 - nmcli connection up "$VPN_NAME" - logger -t nm-dispatcher "itsf-vpn: VPN $VPN_NAME started on $IFACE (SSID: $CURRENT_SSID)" - else - logger -t nm-dispatcher "itsf-vpn: corporate network detected ($CORP_SSID), VPN skipped" + + if [[ "$CURRENT_SSID" == "$CORP_SSID" ]] || is_on_corp_network; then + logger -t nm-dispatcher "itsf-vpn: corporate network detected, VPN skipped" + exit 0 fi + + wait_for_ip || exit 1 + wait_for_dns || exit 1 + + nmcli connection up "$VPN_NAME" + logger -t nm-dispatcher "itsf-vpn: VPN $VPN_NAME started on $IFACE (SSID: $CURRENT_SSID)" fi DISPATCHER sudo chmod +x "$DISPATCHER_FILE" From 4bb19841429d73567caad765c8e431cdb091b94a Mon Sep 17 00:00:00 2001 From: Thomas Ory Date: Fri, 12 Jun 2026 08:50:41 +0200 Subject: [PATCH 3/8] Disable vpn autoconnect + upgrade dispatcher --- apt-packages/wireguard-setup.sh | 112 +++++++++++++++++++------------- 1 file changed, 66 insertions(+), 46 deletions(-) diff --git a/apt-packages/wireguard-setup.sh b/apt-packages/wireguard-setup.sh index 15f5d68..a924bbb 100755 --- a/apt-packages/wireguard-setup.sh +++ b/apt-packages/wireguard-setup.sh @@ -52,7 +52,6 @@ print_header "WireGuard Setup and Configuration" # Ask user if they want to set up WireGuard print_status "This script will set up WireGuard VPN configuration for ITSF." -print_warning "You will need to provide the last digit of your IP address (e.g., 101 for 192.168.66.101)." echo read -p "$(echo -e "${YELLOW}Do you want to set up WireGuard VPN? (y/N): ${BASE}")" -n 1 -r echo @@ -177,23 +176,27 @@ EOF import_networkmanager_connection() { print_status "Importing WireGuard connection to NetworkManager" + # Check if connection already exists + if sudo nmcli connection show itsf >/dev/null 2>&1; then + print_warning "Connection 'itsf' already exists. Removing it first..." + sudo nmcli connection delete itsf >/dev/null 2>&1 || true + fi + # Import the configuration to NetworkManager sudo nmcli connection import type wireguard file /etc/wireguard/itsf.conf - # Disable autoconnect — the VPN will be started conditionally by the dispatcher + + # Disable autoconnect to prevent VPN from starting at boot sudo nmcli connection modify itsf connection.autoconnect no print_success "WireGuard connection imported to NetworkManager" - print_warning "Autoconnect disabled — VPN will start automatically via dispatcher (see below)" + print_warning "You can now manage the connection through NetworkManager" } -# Function to install the NetworkManager dispatcher script -install_dispatcher() { - print_header "NetworkManager Dispatcher Setup" - local DISPATCHER_FILE="/etc/NetworkManager/dispatcher.d/99-wireguard-itsf" - local VPN_NAME="itsf" - local CORP_SSID="ITSF-Wifi" - print_status "Installing dispatcher script: $DISPATCHER_FILE" - sudo tee "$DISPATCHER_FILE" > /dev/null << 'DISPATCHER' +# Function to install dispatcher script for auto VPN management +install_dispatcher_script() { + print_status "Installing dispatcher script for auto VPN management..." + DISPATCHER_SCRIPT="/etc/NetworkManager/dispatcher.d/20-itsf-vpn" + sudo tee "$DISPATCHER_SCRIPT" > /dev/null << 'DISPATCHER_EOF' #!/bin/bash IFACE=$1 EVENT=$2 @@ -201,13 +204,13 @@ VPN_NAME="itsf" CORP_SSID="ITSF-Wifi" CORP_DNS_1="10.195.28.20" CORP_DNS_2="10.195.28.50" -MAX_WAIT=20 +MAX_WAIT=8 wait_for_ip() { local attempt=0 while [[ $attempt -lt $MAX_WAIT ]]; do ip addr show "$IFACE" | grep -q 'inet ' && return 0 - sleep 1 + sleep 0.5 (( attempt++ )) done logger -t nm-dispatcher "itsf-vpn: timeout waiting for IP on $IFACE" @@ -217,11 +220,8 @@ wait_for_ip() { wait_for_dns() { local attempt=0 while [[ $attempt -lt $MAX_WAIT ]]; do - # Résolution via les DNS assignés à l'interface (pas les DNS système) - if resolvectl query --interface="$IFACE" gitlab.steelhome.internal &>/dev/null; then - return 0 - fi - sleep 1 + timeout 2 resolvectl query --interface="$IFACE" gitlab.steelhome.internal &>/dev/null && return 0 + sleep 0.5 (( attempt++ )) done logger -t nm-dispatcher "itsf-vpn: timeout waiting for DNS on $IFACE" @@ -234,25 +234,36 @@ is_on_corp_network() { echo "$active_dns" | grep -qE "^($CORP_DNS_1|$CORP_DNS_2)$" } -if [[ "$EVENT" == "up" && "$IFACE" =~ ^wl ]]; then - CURRENT_SSID=$(nmcli -t -f active,ssid dev wifi | grep '^yes' | cut -d: -f2) - - if [[ "$CURRENT_SSID" == "$CORP_SSID" ]] || is_on_corp_network; then - logger -t nm-dispatcher "itsf-vpn: corporate network detected, VPN skipped" - exit 0 - fi - - wait_for_ip || exit 1 - wait_for_dns || exit 1 - - nmcli connection up "$VPN_NAME" - logger -t nm-dispatcher "itsf-vpn: VPN $VPN_NAME started on $IFACE (SSID: $CURRENT_SSID)" -fi -DISPATCHER - sudo chmod +x "$DISPATCHER_FILE" - print_success "Dispatcher script installed: $DISPATCHER_FILE" - print_status "The VPN '${VPN_NAME}' will auto-start on any WiFi except '${CORP_SSID}'." - print_warning "To add more corporate SSIDs, edit $DISPATCHER_FILE and extend the condition." +case "$EVENT" in + up) + [[ "$IFACE" =~ ^wl ]] || exit 0 + CURRENT_SSID=$(nmcli -t -f active,ssid dev wifi | grep '^yes' | cut -d: -f2) || true + if [[ "$CURRENT_SSID" == "$CORP_SSID" ]] || is_on_corp_network; then + logger -t nm-dispatcher "itsf-vpn: corporate network detected, VPN skipped" + exit 0 + fi + wait_for_ip || logger -t nm-dispatcher "itsf-vpn: IP timeout, continuant" + wait_for_dns || logger -t nm-dispatcher "itsf-vpn: DNS timeout, continuant" + if nmcli connection show --active | grep -q "$VPN_NAME"; then + logger -t nm-dispatcher "itsf-vpn: VPN déjà actif, skipping" + exit 0 + fi + nmcli connection up "$VPN_NAME" + logger -t nm-dispatcher "itsf-vpn: VPN $VPN_NAME started on $IFACE (SSID: $CURRENT_SSID)" + ;; + down) + if nmcli connection show --active | grep -q "$VPN_NAME"; then + nmcli connection down "$VPN_NAME" + logger -t nm-dispatcher "itsf-vpn: VPN $VPN_NAME arrêté après WiFi down" + fi + ;; +esac + +exit 0 +DISPATCHER_EOF + sudo chmod 700 "$DISPATCHER_SCRIPT" + sudo chown root:root "$DISPATCHER_SCRIPT" + print_success "Dispatcher script installed: $DISPATCHER_SCRIPT" } # Function to show WireGuard status @@ -268,16 +279,25 @@ show_wireguard_status() { # Main setup process print_status "Starting ITSF WireGuard setup..." -# Generate keys -generate_keys - -# Create ITSF configuration -create_itsf_config +# Generate keys if the private key doesn't exist, or just install the dispatcher if it does +if sudo [ -f "$WIREGUARD_DIR/keys/private.key" ]; then + print_warning "Keys already exist. Skipping key generation..." + print_status "Updating dispatcher script and NetworkManager connection only..." + import_networkmanager_connection + install_dispatcher_script +else + generate_keys + + # Create ITSF configuration + create_itsf_config + + # Import to NetworkManager + import_networkmanager_connection + + # Install dispatcher script + install_dispatcher_script +fi -# Import to NetworkManager -import_networkmanager_connection -# Install dispatcher for conditional autostart -install_dispatcher # Show status show_wireguard_status From ced87e32d05f66bdeb4da3c8276757a16efaf7d7 Mon Sep 17 00:00:00 2001 From: Thomas Ory Date: Fri, 12 Jun 2026 12:29:19 +0200 Subject: [PATCH 4/8] Add infra-tools-kit module with diagnostic scripts and installation support - Introduced `diag-log-report.sh` and `diag-network-report.sh` for system diagnostics. - Added `install.sh` for module installation and symlink management. - Created `test.sh` for verifying command links in the module. - Included `update-dotfiles.sh` for managing dotfiles updates. - Updated `install_ubuntu.sh` to include the new infra-tools-kit module in the help menu. --- infra-tools-kit/diag-log-report.sh | 61 ++++ infra-tools-kit/diag-network-report.sh | 374 +++++++++++++++++++++++++ infra-tools-kit/install.sh | 125 +++++++++ infra-tools-kit/test.sh | 111 ++++++++ infra-tools-kit/update-dotfiles.sh | 35 +++ install_ubuntu.sh | 2 + 6 files changed, 708 insertions(+) create mode 100755 infra-tools-kit/diag-log-report.sh create mode 100755 infra-tools-kit/diag-network-report.sh create mode 100755 infra-tools-kit/install.sh create mode 100755 infra-tools-kit/test.sh create mode 100755 infra-tools-kit/update-dotfiles.sh diff --git a/infra-tools-kit/diag-log-report.sh b/infra-tools-kit/diag-log-report.sh new file mode 100755 index 0000000..76e0756 --- /dev/null +++ b/infra-tools-kit/diag-log-report.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +set -euo pipefail + +RUN_USER_HOME="${SUDO_USER:+$(getent passwd "$SUDO_USER" | cut -d: -f6)}" +OUTPUT_DIR="$(pwd)/log-diag-$(date +%Y%m%d-%H%M%S)" +mkdir -p "$OUTPUT_DIR" +LOG="$OUTPUT_DIR/report.txt" + +sep() { echo -e "\n========== $1 ==========\n" | tee -a "$LOG"; } +run() { echo "--- $1 ---" | tee -a "$LOG"; eval "$2" 2>&1 | tee -a "$LOG" || true; echo | tee -a "$LOG"; } +run_boot() { + local label="$1" + local boot="$2" + local cmd="$3" + echo "--- $label [boot $boot] ---" | tee -a "$LOG" + eval "$cmd" 2>&1 | tee -a "$LOG" || echo "(aucun résultat ou boot non disponible)" | tee -a "$LOG" + echo | tee -a "$LOG" +} + +echo "=== Log Diagnostic Report ===" | tee "$LOG" +echo "Date : $(date)" | tee -a "$LOG" +echo "Host : $(hostname)" | tee -a "$LOG" +echo "User : ${SUDO_USER:-$(whoami)}" | tee -a "$LOG" +echo "PWD : $(pwd)" | tee -a "$LOG" +echo | tee -a "$LOG" + +sep "BOOTS DISPONIBLES" +run "Liste des boots" "journalctl --list-boots --no-pager 2>/dev/null" + +sep "SYSTEME" +run "OS / Kernel" "uname -a && lsb_release -a 2>/dev/null || cat /etc/os-release" +run "Modele PC" "dmidecode -s system-product-name 2>/dev/null || cat /sys/devices/virtual/dmi/id/product_name 2>/dev/null" +run "CPU" "lscpu | grep -E 'Model name|Architecture|CPU\(s\)|Thread|Socket'" +run "RAM totale" "free -h" +run "Firmware / BIOS" "dmidecode -s bios-version 2>/dev/null || echo 'Non disponible'" + +for BOOT in -1 0; do + if [ "$BOOT" = "0" ]; then LABEL="BOOT ACTUEL (boot 0)"; else LABEL="BOOT PRECEDENT (boot -1)"; fi + sep "$LABEL" + run_boot "Erreurs critiques" "$BOOT" "journalctl -b $BOOT --priority=3 --no-pager" + run_boot "Freeze / Hang / OOM" "$BOOT" "journalctl -b $BOOT --no-pager | grep -iE 'freeze|hang|killed|oom|segfault|taint|panic|rcu_sched|soft lockup|hard lockup' || echo 'Rien trouve'" + run_boot "MCE / RAM errors" "$BOOT" "journalctl -b $BOOT --no-pager | grep -iE 'mce|memory error|edac|corrected' || echo 'Rien trouve'" + run_boot "fprintd logs" "$BOOT" "journalctl -b $BOOT -u fprintd --no-pager || echo 'Service fprintd non trouve'" + run_boot "PAM / unlock / auth" "$BOOT" "journalctl -b $BOOT --no-pager | grep -iE 'pam|fprintd|fingerprint|gdm|gnome-screensaver|unlock' | tail -40 || echo 'Rien trouve'" + run_boot "GPU / DRM" "$BOOT" "journalctl -b $BOOT --no-pager | grep -iE 'drm|gpu|i915|amdgpu|nouveau|xe|timeout|reset|hang' | tail -50 || echo 'Rien trouve'" + run_boot "GNOME Shell / GDM" "$BOOT" "journalctl -b $BOOT -u gdm -u gnome-shell --no-pager | tail -60 || echo 'Rien trouve'" + run_boot "Wayland / Mutter" "$BOOT" "journalctl -b $BOOT --no-pager | grep -iE 'mutter|wayland|compositor' | tail -30 || echo 'Rien trouve'" + run_boot "Thermal / throttling" "$BOOT" "journalctl -b $BOOT --no-pager | grep -iE 'thermal|temperature|overheat|throttl|critical trip' | tail -20 || echo 'Rien trouve'" + run_boot "IO / NVMe errors" "$BOOT" "journalctl -b $BOOT --no-pager | grep -iE 'nvme|sata|ata|io error|blk_update_request' | tail -30 || echo 'Rien trouve'" + run_boot "OOM killer" "$BOOT" "journalctl -b $BOOT --no-pager | grep -iE 'out of memory|oom.killer|killed process' || echo 'Pas de OOM detecte'" + run_boot "USB / HID / fingerprint" "$BOOT" "journalctl -b $BOOT --no-pager | grep -iE 'usb|hid|fingerprint reader|goodix|elan|validity' | tail -30 || echo 'Rien trouve'" +done + +sep "ETAT ACTUEL DU SYSTEME" +run "Swap" "swapon --show 2>/dev/null; free -h" +run "Processus lourds" "ps aux --sort=-%mem | head -15" +run "Kernel logs recents" "dmesg --level=err,crit,warn 2>/dev/null | tail -40" +run "fprintd status" "systemctl status fprintd --no-pager 2>/dev/null || echo 'Service non trouve'" +run "Modules kernel HID" "lsmod 2>/dev/null | grep -iE 'hid_sensor|i2c|thunderbolt|mei' || echo 'Rien trouve'" +run "Xorg errors user" "[ -n \"${RUN_USER_HOME:-}\" ] && grep '(EE)' \"$RUN_USER_HOME/.local/share/xorg/Xorg.0.log\" 2>/dev/null || echo 'Pas de log Xorg user'" \ No newline at end of file diff --git a/infra-tools-kit/diag-network-report.sh b/infra-tools-kit/diag-network-report.sh new file mode 100755 index 0000000..f529636 --- /dev/null +++ b/infra-tools-kit/diag-network-report.sh @@ -0,0 +1,374 @@ +#!/usr/bin/env bash +# +# Network & Wi-Fi diagnostic script — no extra tools needed +# Usage: chmod +x net_diagnose.sh && ./net_diagnose.sh +# + +set -u + +######################## +# CONFIGURABLE TARGETS # +######################## +TARGET_LAN_IP="172.25.3.240" +TARGET_DNS_IP="1.1.1.1" +TARGET_WAN_IP="8.8.8.8" +TARGET_WEBSITE="https://www.google.com" + +# Multiple fallback URLs for speed test (tried in order) +SPEEDTEST_URLS=( + "http://speedtest.tele2.net/10MB.zip" + "http://proof.ovh.net/files/10Mb.dat" + "http://ipv4.download.thinkbroadband.com/10MB.zip" +) + +##################### +# REPORT INITIALIZE # +##################### +HOSTNAME="$(hostname 2>/dev/null || echo unknown-host)" +DATE_STR="$(date '+%Y-%m-%d_%H-%M-%S' 2>/dev/null || echo unknown-date)" +REPORT_FILE="net_diagnose_${HOSTNAME}_${DATE_STR}.log" + +exec > >(tee -a "$REPORT_FILE") 2>&1 + +echo "===========================================" +echo " Network & Wi-Fi Diagnostic Report" +echo " Host: $HOSTNAME" +echo " Date: $(date)" +echo "===========================================" +echo + +##################### +# HELPER FUNCTIONS # +##################### +has_cmd() { command -v "$1" >/dev/null 2>&1; } + +section() { + echo + echo "--------------------------------------------------" + echo "$1" + echo "--------------------------------------------------" +} + +run_cmd() { + local desc="$1"; shift + echo + echo ">>> $desc" + echo "\$ $*" + "$@" 2>&1 || echo "[WARN] Command returned non-zero: $*" +} + +##################### +# 1. SYSTEM INFO # +##################### +section "1. System information" +has_cmd uname && uname -a +echo "User: $USER" +echo "Date: $(date)" + +##################### +# 2. NETWORK CONFIG # +##################### +section "2. Network configuration" + +if has_cmd ip; then + run_cmd "IP addresses" ip addr show + run_cmd "Routing table" ip route show +elif has_cmd ifconfig; then + run_cmd "IP addresses (ifconfig)" ifconfig -a +fi + +##################### +# 3. GATEWAY # +##################### +section "3. Default gateway detection" + +DEFAULT_GW="" +if has_cmd ip; then + DEFAULT_GW="$(ip route 2>/dev/null | awk '/default/ {print $3; exit}')" +elif has_cmd netstat; then + DEFAULT_GW="$(netstat -rn 2>/dev/null | awk '/^0\.0\.0\.0/ {print $2; exit}')" +fi + +if [ -n "$DEFAULT_GW" ]; then + echo "Detected default gateway: $DEFAULT_GW" +else + echo "[WARN] Could not detect default gateway automatically." +fi + +####################### +# 4. WIFI / INTERFACE # +####################### +section "4. Interface & Wi-Fi information" + +OS_TYPE="$(uname -s 2>/dev/null || echo Unknown)" + +case "$OS_TYPE" in + Linux) + # Active interface toward internet + if has_cmd ip; then + echo; echo "Active interface for 1.1.1.1:" + ip route get 1.1.1.1 2>/dev/null + fi + + # Detect active wireless interface + WIFI_IFACE="" + if has_cmd iw; then + WIFI_IFACE="$(iw dev 2>/dev/null | awk '/Interface/ {print $2; exit}')" + fi + if [ -z "$WIFI_IFACE" ] && has_cmd iwconfig; then + WIFI_IFACE="$(iwconfig 2>/dev/null | awk 'NR==1 {print $1}')" + fi + # Also try via /proc + if [ -z "$WIFI_IFACE" ]; then + for iface in /proc/net/wireless; do + [ -f "$iface" ] && WIFI_IFACE="$(awk 'NR==3 {gsub(/:/, ""); print $1}' "$iface")" + done + fi + echo; echo "Wi-Fi interface detected: ${WIFI_IFACE:-none found}" + + # nmcli (best info if available) + if has_cmd nmcli; then + run_cmd "nmcli - devices" nmcli device status + run_cmd "nmcli - active connection" nmcli connection show --active + run_cmd "nmcli - Wi-Fi link details" nmcli -f all dev wifi list 2>/dev/null | head -20 + if [ -n "$WIFI_IFACE" ]; then + run_cmd "nmcli - current AP signal" nmcli -f IN-USE,SSID,BSSID,MODE,CHAN,FREQ,RATE,SIGNAL,BARS,SECURITY dev wifi list ifname "$WIFI_IFACE" 2>/dev/null + fi + fi + + # iwconfig fallback + if has_cmd iwconfig; then + run_cmd "iwconfig (signal/tx/mode)" iwconfig 2>/dev/null + fi + + # iw detailed stats — TX/RX errors, retries, signal + if has_cmd iw && [ -n "$WIFI_IFACE" ]; then + run_cmd "iw dev - link info (RSSI, tx/rx bitrate)" iw dev "$WIFI_IFACE" link 2>/dev/null + run_cmd "iw dev - station statistics (tx_retries, tx_failed, rx_errors)" iw dev "$WIFI_IFACE" station dump 2>/dev/null + fi + + # /proc/net/wireless: per-interface real-time counters + if [ -f /proc/net/wireless ]; then + echo; echo ">>> /proc/net/wireless (signal, noise, nwid/discarded packets)" + cat /proc/net/wireless + fi + + # ethtool for wired adapters (errors) + if has_cmd ethtool; then + for iface in $(ip link show 2>/dev/null | awk -F': ' '/^[0-9]+:/{print $2}' | grep -v lo | grep -v '@'); do + echo; echo ">>> ethtool stats: $iface" + ethtool -S "$iface" 2>/dev/null | grep -i -E 'error|drop|miss|fail|crc|collision|discard|retry' || echo " (no relevant errors found)" + done + fi + ;; + + Darwin) + echo "macOS detected." + if has_cmd networksetup; then + run_cmd "Network hardware ports" networksetup -listallhardwareports + run_cmd "Wi-Fi info" networksetup -getinfo Wi-Fi + fi + AIRPORT="/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport" + if [ -x "$AIRPORT" ]; then + run_cmd "Airport link details (RSSI, noise, tx rate)" "$AIRPORT" -I + run_cmd "Airport scan nearby networks" "$AIRPORT" -s + fi + ;; +esac + +################## +# 5. PING TESTS # +################## +section "5. Connectivity tests (ping — 20 packets)" + +PING_COUNT=20 + +ping_target() { + local label="$1" target="$2" + [ -z "$target" ] && { echo "[SKIP] $label (no target set)"; return; } + echo; echo "### $label -> $target" + if has_cmd ping; then + # Detect Linux vs macOS syntax + if ping -c 1 -W 1 127.0.0.1 >/dev/null 2>&1; then + ping -c "$PING_COUNT" -W 2 "$target" 2>&1 || echo "[ERROR] ping to $target failed" + else + ping -c "$PING_COUNT" "$target" 2>&1 || echo "[ERROR] ping to $target failed" + fi + else + echo "[WARN] ping command not available" + fi +} + +ping_target "Default gateway" "$DEFAULT_GW" +ping_target "Internal LAN IP (OPNsense)" "$TARGET_LAN_IP" +ping_target "DNS (1.1.1.1)" "$TARGET_DNS_IP" +ping_target "Public IP (8.8.8.8)" "$TARGET_WAN_IP" + +################## +# 6. TRACEROUTE # +################## +section "6. Traceroute" + +trace_target() { + local label="$1" target="$2" + [ -z "$target" ] && { echo "[SKIP] $label"; return; } + echo; echo "### $label -> $target" + if has_cmd traceroute; then + traceroute -n -m 20 "$target" 2>&1 + elif has_cmd tracert; then + tracert -d "$target" 2>&1 + else + echo "[SKIP] no traceroute/tracert found" + fi +} + +trace_target "Traceroute to 8.8.8.8" "$TARGET_WAN_IP" + +################## +# 7. HTTP / DNS # +################## +section "7. HTTP and DNS tests" + +if has_cmd curl; then + run_cmd "HTTP HEAD $TARGET_WEBSITE" curl -sS -I --max-time 10 "$TARGET_WEBSITE" +fi + +for dns_tool in getent host nslookup; do + if has_cmd "$dns_tool"; then + case "$dns_tool" in + getent) run_cmd "DNS via getent" getent hosts www.google.com; break;; + host) run_cmd "DNS via host" host www.google.com; break;; + nslookup)run_cmd "DNS via nslookup" nslookup www.google.com; break;; + esac + fi +done + +################## +# 8. SPEED TEST # +################## +section "8. Approximate download speed test" + +if ! has_cmd curl; then + echo "[INFO] curl not available — skipping speed test" +else + SPEED_OK=0 + for url in "${SPEEDTEST_URLS[@]}"; do + echo; echo "Trying: $url" + # -L follows redirects, --max-time hard caps the total time + RESULT="$(curl -sS -L \ + --connect-timeout 10 \ + --max-time 30 \ + -o /dev/null \ + -w '%{size_download} %{time_total} %{speed_download}' \ + "$url" 2>&1)" + CURL_RC=$? + if [ $CURL_RC -eq 0 ]; then + BYTES="$(echo "$RESULT" | awk '{print $1}')" + TIME="$(echo "$RESULT" | awk '{print $2}')" + SPEED_BPS="$(echo "$RESULT" | awk '{print $3}')" # bytes/s from curl + if [ "$BYTES" -gt 0 ] 2>/dev/null; then + MBITS="$(echo "$BYTES $TIME" | awk '{if ($2>0) printf("%.2f", ($1*8)/($2*1000000)); else print "0"}')" + echo "Bytes downloaded : $BYTES" + echo "Total time (s) : $TIME" + echo "Approx. speed : $MBITS Mbit/s" + SPEED_OK=1 + break + else + echo "[WARN] 0 bytes downloaded from $url (rc=$CURL_RC)" + fi + else + echo "[WARN] curl failed on $url (rc=$CURL_RC)" + fi + done + [ $SPEED_OK -eq 0 ] && echo "[ERROR] All speed test URLs failed. Check firewall / proxy / DNS." +fi + +################## +# 9. WIFI ERRORS # +################## +section "9. Wi-Fi errors and retransmissions (kernel / driver level)" + +case "$OS_TYPE" in + Linux) + # dmesg — Wi-Fi driver errors, firmware issues, reconnects + if has_cmd dmesg; then + echo; echo ">>> dmesg: Wi-Fi related messages (errors, firmware, assoc, deauth)" + dmesg 2>/dev/null | grep -i -E \ + 'wlan|wlp|mt79|iwlwifi|ath|brcm|rtw|wifi|80211|deauth|disassoc|auth|reassoc|beacon|firmware|error|timeout|hang|reset|failed|disconnect|roam' \ + | tail -80 || echo "[INFO] No relevant dmesg output (may need sudo)" + fi + + # iw station dump — key wireless counters + if has_cmd iw && [ -n "${WIFI_IFACE:-}" ]; then + echo; echo ">>> iw station dump (tx_retries, tx_failed, beacon_loss, rx_errors)" + iw dev "$WIFI_IFACE" station dump 2>/dev/null | grep -E \ + 'tx bytes|rx bytes|tx packets|rx packets|tx retries|tx failed|rx drop|beacon loss|signal|tx bitrate|rx bitrate' \ + || echo "[INFO] no station dump (not associated?)" + fi + + # /proc/net/wireless — nwid/discard/miss counters + if [ -f /proc/net/wireless ]; then + echo; echo ">>> /proc/net/wireless counters (nwid discarded, crypt discarded, misc missed)" + cat /proc/net/wireless + fi + + # ip -s link — L2 TX/RX errors on all interfaces + if has_cmd ip; then + echo; echo ">>> ip -s link (L2 tx/rx errors, drops)" + ip -s link 2>/dev/null + fi + + # journalctl NetworkManager/wpa_supplicant — roam events + if has_cmd journalctl; then + echo; echo ">>> journalctl: NetworkManager (last 100 Wi-Fi lines)" + journalctl -u NetworkManager --no-pager -n 100 2>/dev/null \ + | grep -i -E 'wifi|wlan|80211|ap|bss|roam|deauth|disassoc|connect|disconnect|scan' \ + || echo "[INFO] No relevant NM journal (or access denied)" + + echo; echo ">>> journalctl: wpa_supplicant (last 50 lines)" + journalctl -u wpa_supplicant --no-pager -n 50 2>/dev/null \ + || echo "[INFO] No wpa_supplicant journal (or access denied)" + fi + ;; + + Darwin) + echo "[INFO] Collect Wi-Fi diagnostics on macOS: Wireless Diagnostics → Window → Wi-Fi Scan / Statistics." + echo " Or run: sudo /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I" + ;; +esac + +################## +# 10. SYS LOGS # +################## +section "10. System logs (general errors)" + +case "$OS_TYPE" in + Linux) + if has_cmd journalctl; then + echo; echo ">>> Last 30 system errors (priority err or higher)" + journalctl -p err --no-pager -n 30 2>/dev/null || true + fi + ;; +esac + +################## +# 11. SUMMARY # +################## +section "11. Summary & next steps" + +echo "Report includes:" +echo " 1. System info" +echo " 2. Network config (IPs, routes)" +echo " 3. Default gateway" +echo " 4. Wi-Fi interface details (RSSI, channel, tx/rx rates, driver errors)" +echo " 5. Ping tests (GW / LAN / DNS / WAN)" +echo " 6. Traceroute" +echo " 7. HTTP + DNS" +echo " 8. Download speed test" +echo " 9. Wi-Fi errors (dmesg, iw station, /proc/net/wireless, NM journal)" +echo " 10. System logs" +echo +echo "Report saved to: $REPORT_FILE" +echo "Please send this file to IT support for analysis." +echo +echo "End of report — $(date)" diff --git a/infra-tools-kit/install.sh b/infra-tools-kit/install.sh new file mode 100755 index 0000000..6f1e944 --- /dev/null +++ b/infra-tools-kit/install.sh @@ -0,0 +1,125 @@ +#!/bin/bash + +# Exit on any error +set -e + +# Script directory and module info +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +BACKUP_DIR="$SCRIPT_DIR/../backup" +MODULE_NAME="infra-tools-kit" +BIN_DIR="$HOME/.local/bin" + +# Catppuccin Mocha color scheme +# Base colors +BASE="\033[0m" +TEXT="\033[38;2;205;214;244m" # Text +SUBTEXT="\033[38;2;166;173;200m" # Subtext +OVERLAY="\033[38;2;108;112;134m" # Overlay +SURFACE="\033[38;2;49;50;68m" # Surface +BASE_COLOR="\033[38;2;30;30;46m" # Base +MANTLE="\033[38;2;24;24;37m" # Mantle +CRUST="\033[38;2;17;17;27m" # Crust + +# Accent colors +RED="\033[38;2;243;139;168m" # Red +GREEN="\033[38;2;166;227;161m" # Green +YELLOW="\033[38;2;249;226;175m" # Yellow +BLUE="\033[38;2;137;180;250m" # Blue +PINK="\033[38;2;245;194;231m" # Pink +MAUVE="\033[38;2;203;166;247m" # Mauve +TEAL="\033[38;2;148;226;213m" # Teal + +# Print functions +print_status() { + echo -e "${BLUE}[i]${BASE} $1" +} + +print_success() { + echo -e "${GREEN}[✓]${BASE} $1" +} + +print_error() { + echo -e "${RED}[✗]${BASE} $1" +} + +print_warning() { + echo -e "${YELLOW}[!]${BASE} $1" +} + +print_header() { + echo -e "\n${MAUVE}=== $1 ===${BASE}\n" +} + +# Print module header +print_header "Installing $MODULE_NAME configuration" + +# Check if running as root +if [ "$EUID" -eq 0 ]; then + print_error "Please do not run this script as root" + exit 1 +fi + +# Ensure the local bin directory exists and is on PATH +if [ ! -d "$BIN_DIR" ]; then + mkdir -p "$BIN_DIR" + print_success "Created $BIN_DIR" +fi + +case ":$PATH:" in + *":$BIN_DIR:"*) + print_status "$BIN_DIR is already on your PATH" + ;; + *) + print_warning "$BIN_DIR is not on your PATH" + print_warning "Add this line to your shell config (e.g. ~/.zshrc or ~/.bashrc):" + print_warning " export PATH=\"\$HOME/.local/bin:\$PATH\"" + ;; +esac + +# Create a symlink in BIN_DIR (named without the .sh extension) for every +# script in the module. Existing real files are backed up first; symlinks are +# refreshed in place. No file is ever copied. +link_count=0 +for script in "$SCRIPT_DIR"/*.sh; do + [ -e "$script" ] || continue + + script_name="$(basename "$script")" + + # Skip the module's own management scripts + if [ "$script_name" = "install.sh" ] || [ "$script_name" = "test.sh" ]; then + continue + fi + + command_name="${script_name%.sh}" + target="$BIN_DIR/$command_name" + + # Make sure the source script is executable + chmod +x "$script" + + if [ -L "$target" ]; then + # Existing symlink: refresh it to point at the current location + ln -sfn "$script" "$target" + print_success "Linked $command_name -> $script" + elif [ -e "$target" ]; then + # A real file/dir exists: back it up before replacing it + local_timestamp="$(date +%Y%m%d_%H%M%S)" + backup_path="$BACKUP_DIR/modules/$MODULE_NAME/$local_timestamp" + mkdir -p "$backup_path" + mv "$target" "$backup_path/" + print_warning "Backed up existing $command_name to $backup_path" + ln -sfn "$script" "$target" + print_success "Linked $command_name -> $script" + else + ln -sfn "$script" "$target" + print_success "Linked $command_name -> $script" + fi + + link_count=$((link_count + 1)) +done + +if [ "$link_count" -eq 0 ]; then + print_warning "No scripts found to link in $SCRIPT_DIR" +else + print_success "$MODULE_NAME configuration installed successfully! ($link_count command(s) available)" + print_status "You can now run the tools directly, e.g.: diag-network-report" +fi diff --git a/infra-tools-kit/test.sh b/infra-tools-kit/test.sh new file mode 100755 index 0000000..619e1ce --- /dev/null +++ b/infra-tools-kit/test.sh @@ -0,0 +1,111 @@ +#!/bin/bash + +# Exit on error +set -e + +# Script directory and module info +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +MODULE_NAME="infra-tools-kit" +BIN_DIR="$HOME/.local/bin" + +# Catppuccin Mocha color scheme +# Base colors +BASE="\033[0m" +TEXT="\033[38;2;205;214;244m" # Text +SUBTEXT="\033[38;2;166;173;200m" # Subtext +OVERLAY="\033[38;2;108;112;134m" # Overlay +SURFACE="\033[38;2;49;50;68m" # Surface +BASE_COLOR="\033[38;2;30;30;46m" # Base +MANTLE="\033[38;2;24;24;37m" # Mantle +CRUST="\033[38;2;17;17;27m" # Crust + +# Accent colors +RED="\033[38;2;243;139;168m" # Red +GREEN="\033[38;2;166;227;161m" # Green +YELLOW="\033[38;2;249;226;175m" # Yellow +BLUE="\033[38;2;137;180;250m" # Blue +PINK="\033[38;2;245;194;231m" # Pink +MAUVE="\033[38;2;203;166;247m" # Mauve +TEAL="\033[38;2;148;226;213m" # Teal + +# Print functions +print_status() { + echo -e "${BLUE}[i]${BASE} $1" +} + +print_success() { + echo -e "${GREEN}[✓]${BASE} $1" +} + +print_error() { + echo -e "${RED}[✗]${BASE} $1" +} + +print_warning() { + echo -e "${YELLOW}[!]${BASE} $1" +} + +print_header() { + echo -e "\n${MAUVE}=== $1 ===${BASE}\n" +} + +# Verify that a script is linked into BIN_DIR (without the .sh extension) and +# that the symlink resolves back to the module's source script. +test_command_link() { + local source="$1" + local command_name + command_name="$(basename "${source%.sh}")" + local target="$BIN_DIR/$command_name" + + print_status "Testing command link: $command_name" + + if [ ! -L "$target" ]; then + print_error "$target is not a symbolic link" + return 1 + fi + + local abs_source + abs_source="$(cd "$(dirname "$source")" && pwd)/$(basename "$source")" + local abs_target + abs_target="$(readlink -f "$target")" + + if [ "$abs_target" != "$abs_source" ]; then + print_error "$target does not point to $abs_source (got: $abs_target)" + return 1 + fi + + if [ ! -x "$target" ]; then + print_error "$command_name is not executable" + return 1 + fi + + if ! command -v "$command_name" >/dev/null 2>&1; then + print_error "$command_name is not resolvable from PATH" + return 1 + fi + + print_success "$command_name is correctly linked and on PATH" + return 0 +} + +print_header "Testing $MODULE_NAME configuration" + +failures=0 +for script in "$SCRIPT_DIR"/*.sh; do + [ -e "$script" ] || continue + script_name="$(basename "$script")" + if [ "$script_name" = "install.sh" ] || [ "$script_name" = "test.sh" ]; then + continue + fi + test_command_link "$script" || failures=$((failures + 1)) +done + +if [ "$failures" -ne 0 ]; then + print_error "$failures command(s) failed verification" + exit 1 +fi + +print_success "Testing completed!" +print_warning "Please verify the following manually:" +print_warning "1. Open a new terminal and run a tool by name (e.g. diag-network-report)" +print_warning "2. Ensure \$HOME/.local/bin is on your PATH" diff --git a/infra-tools-kit/update-dotfiles.sh b/infra-tools-kit/update-dotfiles.sh new file mode 100755 index 0000000..bbde6f2 --- /dev/null +++ b/infra-tools-kit/update-dotfiles.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Resolve the real path of this script, following symlinks (e.g. when invoked +# from ~/.local/bin). This makes the script work regardless of the current +# working directory and even if the dotfiles repo is moved. +source_path="${BASH_SOURCE[0]}" +while [ -L "$source_path" ]; do + link_target="$(readlink "$source_path")" + case "$link_target" in + /*) source_path="$link_target" ;; + *) source_path="$(cd "$(dirname "$source_path")" && pwd)/$link_target" ;; + esac +done +script_dir="$(cd "$(dirname "$source_path")" && pwd)" + +# Derive the repo root from the script's actual location, not the CWD. +repo_dir="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null || true)" +if [ -z "$repo_dir" ]; then + echo "This script is not located in a git dotfiles repository" + exit 1 +fi + + +# Check current branch and abort if not main +current_branch="$(git -C "$repo_dir" branch --show-current)" +if [ "$current_branch" != "main" ]; then + echo "⚠️ You are not on the 'main' branch (you are on '$current_branch')" + echo " No git pull will be performed. Only 'git fetch' was run." + echo " Switch to 'main' with: git checkout main" + exit 1 +fi + +git -C "$repo_dir" fetch origin +git -C "$repo_dir" pull --ff-only origin "$current_branch" \ No newline at end of file diff --git a/install_ubuntu.sh b/install_ubuntu.sh index 514b8b5..7b463c9 100755 --- a/install_ubuntu.sh +++ b/install_ubuntu.sh @@ -133,6 +133,7 @@ show_help() { echo -e " ${BLUE}12.${BASE} docker" echo -e " ${BLUE}13.${BASE} nvm" echo -e " ${BLUE}14.${BASE} gitlab-cli" + echo -e " ${BLUE}15.${BASE} infra-tools-kit" exit 0 } @@ -191,6 +192,7 @@ install_all_modules() { "docker" "nvm" "gitlab-cli" + "infra-tools-kit" ) for module in "${MODULE_ORDER[@]}"; do From c8218e1d3e5d65a01a5f2d537e564a9f6590ef37 Mon Sep 17 00:00:00 2001 From: Thomas Ory Date: Fri, 12 Jun 2026 14:42:02 +0200 Subject: [PATCH 5/8] Add develop branch --- infra-tools-kit/update-dotfiles.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra-tools-kit/update-dotfiles.sh b/infra-tools-kit/update-dotfiles.sh index bbde6f2..33aca5e 100755 --- a/infra-tools-kit/update-dotfiles.sh +++ b/infra-tools-kit/update-dotfiles.sh @@ -24,7 +24,7 @@ fi # Check current branch and abort if not main current_branch="$(git -C "$repo_dir" branch --show-current)" -if [ "$current_branch" != "main" ]; then +if [ "$current_branch" != "main" or "$current_branch" != "develop" ]; then echo "⚠️ You are not on the 'main' branch (you are on '$current_branch')" echo " No git pull will be performed. Only 'git fetch' was run." echo " Switch to 'main' with: git checkout main" From ca4277653646eea39b591195eb65f279b27cf27a Mon Sep 17 00:00:00 2001 From: Thomas Ory Date: Fri, 12 Jun 2026 14:42:48 +0200 Subject: [PATCH 6/8] Add kubectx --- kubectl/install.sh | 57 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/kubectl/install.sh b/kubectl/install.sh index 3a87935..72bffe0 100755 --- a/kubectl/install.sh +++ b/kubectl/install.sh @@ -176,6 +176,53 @@ install_kubelogin() { fi } +# Function to install kubectx +install_kubectx() { + local OS=$(detect_os) + local ARCH=$(detect_arch) + print_status "Installing kubectx for $OS..." + + if [ "$OS_TYPE" = "Darwin" ]; then + if ! command -v brew >/dev/null 2>&1; then + print_error "Homebrew is required to install kubectx on MacOS" + exit 1 + fi + brew install kubectx + return 0 + fi + + # Create temporary directory + local TEMP_DIR=$(mktemp -d) + cd "$TEMP_DIR" + + # Download kubectx (kubectl-context and kubectl-namespace) + print_status "Downloading kubectx..." + curl -LO "https://github.com/ahmetb/kubectx/releases/download/v0.9.5/kubectx" + curl -LO "https://github.com/ahmetb/kubectx/releases/download/v0.9.5/kubens" + + # Make them executable + chmod +x kubectx kubens + + # Install into the user's PATH + print_status "Installing kubectx and kubens to user bin directory..." + mkdir -p "$HOME/.local/bin" + mv kubectx "$HOME/.local/bin/kubectx" + mv kubens "$HOME/.local/bin/kubens" + + # Cleanup + cd - > /dev/null + rm -rf "$TEMP_DIR" + + # Verify installation + if [ -f "$HOME/.local/bin/kubectx" ] && [ -f "$HOME/.local/bin/kubens" ]; then + print_success "kubectx installed successfully!" + "$HOME/.local/bin/kubectx" --help + else + print_error "Failed to install kubectx" + exit 1 + fi +} + # Function to backup existing config backup_config() { local config_path="$HOME/.kube/config" @@ -220,6 +267,12 @@ if ! command -v kubelogin >/dev/null 2>&1 && [ ! -f "$HOME/.local/bin/kubelogin" install_kubelogin fi +# Check if kubectx is installed +if ! command -v kubectx >/dev/null 2>&1 && [ ! -f "$HOME/.local/bin/kubectx" ]; then + print_warning "kubectx is not installed." + install_kubectx +fi + # Create necessary directories print_status "Creating kubectl configuration directories..." mkdir -p ~/.kube/plugins @@ -254,4 +307,6 @@ print_warning "Please complete the following manually:" print_warning "1. Ensure user binaries are in your PATH if not already done:" print_warning " echo 'export PATH=\"\$PATH:\$HOME/.local/bin\"' >> ~/.zshrc" print_warning "2. Restart your shell or run 'source ~/.zshrc' to apply changes" -print_warning "3. Test kubelogin: kubelogin version" \ No newline at end of file +print_warning "3. Test kubelogin: kubelogin version" +print_warning "4. Test kubectx: kubectx --help" +print_warning "5. Test kubens: kubens --help" \ No newline at end of file From 2c0503f2185bc4d3bbe6aa26115b024bdce2a46e Mon Sep 17 00:00:00 2001 From: Thomas Ory Date: Fri, 12 Jun 2026 16:06:07 +0200 Subject: [PATCH 7/8] Add wifi script --- linux-config/install.sh | 63 ++++++++++++ linux-config/test.sh | 111 ++++++++++++++++++++ linux-config/upgrade_wifi.sh | 189 +++++++++++++++++++++++++++++++++++ 3 files changed, 363 insertions(+) create mode 100755 linux-config/install.sh create mode 100755 linux-config/test.sh create mode 100644 linux-config/upgrade_wifi.sh diff --git a/linux-config/install.sh b/linux-config/install.sh new file mode 100755 index 0000000..3dca4e6 --- /dev/null +++ b/linux-config/install.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# Exit on any error +set -e + +# Script directory and module info +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +BACKUP_DIR="$SCRIPT_DIR/../backup" +MODULE_NAME="linux-config" +BIN_DIR="$HOME/.local/bin" + +# Catppuccin Mocha color scheme +# Base colors +BASE="\033[0m" +TEXT="\033[38;2;205;214;244m" # Text +SUBTEXT="\033[38;2;166;173;200m" # Subtext +OVERLAY="\033[38;2;108;112;134m" # Overlay +SURFACE="\033[38;2;49;50;68m" # Surface +BASE_COLOR="\033[38;2;30;30;46m" # Base +MANTLE="\033[38;2;24;24;37m" # Mantle +CRUST="\033[38;2;17;17;27m" # Crust + +# Accent colors +RED="\033[38;2;243;139;168m" # Red +GREEN="\033[38;2;166;227;161m" # Green +YELLOW="\033[38;2;249;226;175m" # Yellow +BLUE="\033[38;2;137;180;250m" # Blue +PINK="\033[38;2;245;194;231m" # Pink +MAUVE="\033[38;2;203;166;247m" # Mauve +TEAL="\033[38;2;148;226;213m" # Teal + +# Print functions +print_status() { + echo -e "${BLUE}[i]${BASE} $1" +} + +print_success() { + echo -e "${GREEN}[✓]${BASE} $1" +} + +print_error() { + echo -e "${RED}[✗]${BASE} $1" +} + +print_warning() { + echo -e "${YELLOW}[!]${BASE} $1" +} + +print_header() { + echo -e "\n${MAUVE}=== $1 ===${BASE}\n" +} + +# Print module header +print_header "Installing $MODULE_NAME configuration" + +# Check if running as root +if [ "$EUID" -eq 0 ]; then + print_error "Please do not run this script as root" + exit 1 +fi + +# Call the upgrade_wifi.sh script +exec bash $SCRIPT_DIR/upgrade_wifi.sh \ No newline at end of file diff --git a/linux-config/test.sh b/linux-config/test.sh new file mode 100755 index 0000000..40a7b6a --- /dev/null +++ b/linux-config/test.sh @@ -0,0 +1,111 @@ +#!/bin/bash + +# Exit on error +set -e + +# Script directory and module info +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +MODULE_NAME="linux-config" +BIN_DIR="$HOME/.local/bin" + +# Catppuccin Mocha color scheme +# Base colors +BASE="\033[0m" +TEXT="\033[38;2;205;214;244m" # Text +SUBTEXT="\033[38;2;166;173;200m" # Subtext +OVERLAY="\033[38;2;108;112;134m" # Overlay +SURFACE="\033[38;2;49;50;68m" # Surface +BASE_COLOR="\033[38;2;30;30;46m" # Base +MANTLE="\033[38;2;24;24;37m" # Mantle +CRUST="\033[38;2;17;17;27m" # Crust + +# Accent colors +RED="\033[38;2;243;139;168m" # Red +GREEN="\033[38;2;166;227;161m" # Green +YELLOW="\033[38;2;249;226;175m" # Yellow +BLUE="\033[38;2;137;180;250m" # Blue +PINK="\033[38;2;245;194;231m" # Pink +MAUVE="\033[38;2;203;166;247m" # Mauve +TEAL="\033[38;2;148;226;213m" # Teal + +# Print functions +print_status() { + echo -e "${BLUE}[i]${BASE} $1" +} + +print_success() { + echo -e "${GREEN}[✓]${BASE} $1" +} + +print_error() { + echo -e "${RED}[✗]${BASE} $1" +} + +print_warning() { + echo -e "${YELLOW}[!]${BASE} $1" +} + +print_header() { + echo -e "\n${MAUVE}=== $1 ===${BASE}\n" +} + +# Verify that a script is linked into BIN_DIR (without the .sh extension) and +# that the symlink resolves back to the module's source script. +test_command_link() { + local source="$1" + local command_name + command_name="$(basename "${source%.sh}")" + local target="$BIN_DIR/$command_name" + + print_status "Testing command link: $command_name" + + if [ ! -L "$target" ]; then + print_error "$target is not a symbolic link" + return 1 + fi + + local abs_source + abs_source="$(cd "$(dirname "$source")" && pwd)/$(basename "$source")" + local abs_target + abs_target="$(readlink -f "$target")" + + if [ "$abs_target" != "$abs_source" ]; then + print_error "$target does not point to $abs_source (got: $abs_target)" + return 1 + fi + + if [ ! -x "$target" ]; then + print_error "$command_name is not executable" + return 1 + fi + + if ! command -v "$command_name" >/dev/null 2>&1; then + print_error "$command_name is not resolvable from PATH" + return 1 + fi + + print_success "$command_name is correctly linked and on PATH" + return 0 +} + +print_header "Testing $MODULE_NAME configuration" + +failures=0 +for script in "$SCRIPT_DIR"/*.sh; do + [ -e "$script" ] || continue + script_name="$(basename "$script")" + if [ "$script_name" = "install.sh" ] || [ "$script_name" = "test.sh" ]; then + continue + fi + test_command_link "$script" || failures=$((failures + 1)) +done + +if [ "$failures" -ne 0 ]; then + print_error "$failures command(s) failed verification" + exit 1 +fi + +print_success "Testing completed!" +print_warning "Please verify the following manually:" +print_warning "1. Open a new terminal and run a tool by name (e.g. diag-network-report)" +print_warning "2. Ensure \$HOME/.local/bin is on your PATH" diff --git a/linux-config/upgrade_wifi.sh b/linux-config/upgrade_wifi.sh new file mode 100644 index 0000000..8dc1faa --- /dev/null +++ b/linux-config/upgrade_wifi.sh @@ -0,0 +1,189 @@ +#!/bin/bash + +# Exit on any error +set -e + +# Script directory and module info +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +BACKUP_DIR="$SCRIPT_DIR/../backup" +MODULE_NAME="linux-config" +OS_TYPE="$(uname -s)" + +# Catppuccin Mocha color scheme +# Base colors +BASE="\033[0m" +TEXT="\033[38;2;205;214;244m" # Text +SUBTEXT="\033[38;2;166;173;200m" # Subtext +OVERLAY="\033[38;2;108;112;134m" # Overlay +SURFACE="\033[38;2;49;50;68m" # Surface +BASE_COLOR="\033[38;2;30;30;46m" # Base +MANTLE="\033[38;2;24;24;37m" # Mantle +CRUST="\033[38;2;17;17;27m" # Crust + +# Accent colors +RED="\033[38;2;243;139;168m" # Red +GREEN="\033[38;2;166;227;161m" # Green +YELLOW="\033[38;2;249;226;175m" # Yellow +BLUE="\033[38;2;137;180;250m" # Blue +PINK="\033[38;2;245;194;231m" # Pink +MAUVE="\033[38;2;203;166;247m" # Mauve +TEAL="\033[38;2;148;226;213m" # Teal + +# Print functions +print_status() { + echo -e "${BLUE}[i]${BASE} $1" +} + +print_success() { + echo -e "${GREEN}[✓]${BASE} $1" +} + +print_error() { + echo -e "${RED}[✗]${BASE} $1" +} + +print_warning() { + echo -e "${YELLOW}[!]${BASE} $1" +} + +print_header() { + echo -e "\n${MAUVE}=== $1 ===${BASE}\n" +} + +# Print module header +print_header "Upgrading WiFi configuration" + +# Check if running as root +if [ "$EUID" -eq 0 ]; then + print_error "Please do not run this script as root" + exit 1 +fi + +# Improve WiFi Framework (Intel or MediaTek) - Ubuntu 24.04 +# Compatible : Intel AX200/AX210/AX211, MediaTek RZ616/RZ608/RZ717 + +# Identify WiFi interface via /sys +WIFI_IF=$(ls /sys/class/ieee80211/*/device/net/ 2>/dev/null | head -1) +if [ -z "$WIFI_IF" ]; then + print_error "No WiFi interface detected." + exit 1 +fi +print_status "WiFi interface detected : $WIFI_IF" + +# Detect the WiFi chipset +print_status "Detection of the WiFi chipset" +WIFI_PCI=$(lspci | grep -i "network\|wireless") +print_status "$WIFI_PCI" + +# Detect the dynamically loaded driver +DRIVER=$(basename "$(readlink /sys/class/net/$WIFI_IF/device/driver/module)" 2>/dev/null) +print_status "Loaded driver : $DRIVER" + +if echo "$WIFI_PCI" | grep -qi "mediatek\|mt79\|RZ616\|RZ608\|RZ717\|0616\|0717"; then + CHIPSET="mediatek" + # The driver can be mt7921e, mt7925e, or other mt79xx variant + if [ -z "$DRIVER" ] || ! echo "$DRIVER" | grep -q "mt79"; then + print_error "MediaTek driver not detected (driver found : $DRIVER)" + print_warning "Check that the WiFi card is properly recognized." + exit 1 + fi + # Extract the module prefix (mt7921, mt7925, etc.) + # mt7921e → mt7921, mt7925e → mt7925 + MT_PREFIX=$(echo "$DRIVER" | sed 's/e$//') + print_status "→ Detected chipset : MediaTek (driver: $DRIVER, prefix: $MT_PREFIX)" +elif echo "$WIFI_PCI" | grep -qi "intel\|AX210\|AX211\|AX200\|AX201"; then + CHIPSET="intel" + DRIVER="iwlwifi" + print_status "→ Detected chipset : Intel (driver: $DRIVER)" +else + print_error "WiFi chipset not recognized." + print_warning "lspci output : $WIFI_PCI" + print_warning "Detected driver : $DRIVER" + print_warning "This script supports only Intel (iwlwifi) and MediaTek (mt79xx)." + exit 1 +fi + +# Create backup directory if it doesn't exist +mkdir -p "$BACKUP_DIR" + +# Backup existing configuration if it exists +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +BACKUP_FILE="$BACKUP_DIR/modules/$MODULE_NAME/wifi-backup_$TIMESTAMP.tar.gz" + +mkdir -p "$BACKUP_DIR/modules/$MODULE_NAME" + +tar -czf "$BACKUP_FILE" -C / \ + $( [ -f /etc/modprobe.d/wifi-fix.conf ] && echo etc/modprobe.d/wifi-fix.conf ) \ + $( [ -f /etc/NetworkManager/conf.d/wifi-powersave.conf ] && echo etc/NetworkManager/conf.d/wifi-powersave.conf ) \ + 2>/dev/null || true + +print_header "Current state" +print_status "--- WiFi card ---" +print_status "$WIFI_PCI" +print_status "--- Loaded driver ---" +ls -l /sys/class/net/"$WIFI_IF"/device/driver/module 2>/dev/null || print_warning "Driver not identified" +if [ "$CHIPSET" = "mediatek" ]; then + print_status "--- Loaded MediaTek modules ---" + lsmod | grep mt79 || print_warning "No mt79 module loaded" + print_status "--- Firmware MediaTek ---" + ls -la /lib/firmware/mediatek/WIFI_MT79* 2>/dev/null || print_warning "MediaTek firmware not found" +else + print_status "--- Loaded Intel module ---" + modinfo iwlwifi 2>/dev/null | grep -E "version|filename" || print_warning " iwlwifi module not loaded" +fi +print_status "--- Kernel ---" +uname -r + print_status "--- Current power save ---" +cat /sys/class/net/"$WIFI_IF"/power/control 2>/dev/null || print_warning "Not available" +print_status "--- Current connection ---" +nmcli -t -f GENERAL.STATE,WIFI.FREQ,WIFI.SIGNAL,WIFI.SSID device show "$WIFI_IF" 2>/dev/null || print_warning "Not connected" + +print_header "Update firmware and kernel HWE" +sudo apt update +sudo apt install -y linux-firmware linux-generic-hwe-24.04 + +echo "" +print_header "Configure module driver" +if [ "$CHIPSET" = "mediatek" ]; then + # MediaTek RZ616 (mt7921e) / RZ717 (mt7925e) / etc. + # power_save=0 : disable the power save of the module + # → the MediaTek power save is more aggressive than the Intel one + # → cause direct of the collapsed throughput + # Configure the specific driver + the common modules + cat << MODULE_EOF | sudo tee /etc/modprobe.d/wifi-fix.conf +options ${DRIVER} power_save=0 +options ${MT_PREFIX}_common power_save=0 +options mt792x_lib power_save=0 +MODULE_EOF +else + # Intel AX210 / AX211 + # power_scheme=1 : max performance mode + # → 1 = performance, 2 = balanced, 3 = economy + sudo tee /etc/modprobe.d/wifi-fix.conf << 'EOF' +options iwlmvm power_scheme=1 +EOF +fi +print_status "Module $DRIVER configured :" +cat /etc/modprobe.d/wifi-fix.conf + +print_header "Disable WiFi power save (NetworkManager)" +# wifi.powersave=2 : disable (1 = default, 3 = enable) +# → double protection with the module option +sudo tee /etc/NetworkManager/conf.d/wifi-powersave.conf << 'EOF' +[connection] +wifi.powersave=2 +EOF +print_success "Power save NetworkManager disabled" + +print_header "Apply the changes" +sudo systemctl restart NetworkManager +sleep 3 + +print_header "Post-configuration checks" +print_status "--- Chipset : $CHIPSET (driver: $DRIVER) ---" +print_status "--- Connection ---" +nmcli -t -f WIFI.FREQ,WIFI.SIGNAL,WIFI.SSID device show "$WIFI_IF" 2>/dev/null || echo "Reconnection in progress..." +print_status "--- Created files ---" +ls -la /etc/modprobe.d/wifi-fix.conf +ls -la /etc/NetworkManager/conf.d/wifi-powersave.conf +print_success "WiFi configuration upgraded successfully" From 93501c835c7983b54740acee397dc0adfe9d0331 Mon Sep 17 00:00:00 2001 From: Thomas Ory Date: Fri, 12 Jun 2026 16:07:51 +0200 Subject: [PATCH 8/8] restrict to main and master --- infra-tools-kit/update-dotfiles.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra-tools-kit/update-dotfiles.sh b/infra-tools-kit/update-dotfiles.sh index 33aca5e..9e14d0e 100755 --- a/infra-tools-kit/update-dotfiles.sh +++ b/infra-tools-kit/update-dotfiles.sh @@ -24,7 +24,7 @@ fi # Check current branch and abort if not main current_branch="$(git -C "$repo_dir" branch --show-current)" -if [ "$current_branch" != "main" or "$current_branch" != "develop" ]; then +if [ "$current_branch" != "main" ] && [ "$current_branch" != "develop" ]; then echo "⚠️ You are not on the 'main' branch (you are on '$current_branch')" echo " No git pull will be performed. Only 'git fetch' was run." echo " Switch to 'main' with: git checkout main"