aboutsummaryrefslogtreecommitdiff
path: root/scripts/testing/lib/network-diagnostics.sh
blob: dc54334d686c37641a96193af5499b00221361ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/bin/bash
# SPDX-License-Identifier: GPL-3.0-or-later
# Network diagnostics for VM testing
# Author: Craig Jennings <craigmartinjennings@gmail.com>
# License: GNU GPLv3

# Note: logging.sh and vm-utils.sh should already be sourced by the calling script
# Uses globals: ROOT_PASSWORD, SSH_PORT, SSH_OPTS, VM_IP (from vm-utils.sh or calling script)
# Optional global: TEST_RESULTS_DIR (raw command outputs are saved there when set)

# Gather one read-only fact from the VM, print it, and save the raw output.
# Facts are collected regardless of pass/fail so a failing install still leaves
# the IP/route/resolver evidence in the log and the results dir.
#   $1 label   human-readable label for the fact
#   $2 slug    filename slug for the saved raw output
#   $3 cmd     remote command to run over the shared ssh_base
# Uses the caller's locals ssh_base and results_dir (dynamic scope).
_netdiag_fact() {
    local label="$1" slug="$2" cmd="$3" out
    out="$($ssh_base "$cmd" 2>&1)"
    info "${label}:"
    printf '%s\n' "$out" | while IFS= read -r line; do
        info "  $line"
    done
    if [ -n "$results_dir" ]; then
        printf '%s\n' "$out" > "$results_dir/netdiag-${slug}.txt" 2>/dev/null || true
    fi
}

# Run quick network diagnostics.
#
# Evidence first: collect read-only facts (interfaces, route, resolver)
# unconditionally, then run every reachability check and report all failures at
# the end. A DNS failure is named as a DNS failure, not masked as a generic "no
# internet" or misattributed to the Arch mirror. Returns 0 when all checks pass,
# non-zero when any check fails, so callers keep their success/failure contract.
run_network_diagnostics() {
    local password="${ROOT_PASSWORD:-archsetup}"
    local port="${SSH_PORT:-22}"
    local host="${VM_IP:-localhost}"
    local ssh_base="sshpass -p $password ssh $SSH_OPTS -p $port root@$host"
    local results_dir="${TEST_RESULTS_DIR:-}"
    local failures=()

    section "Pre-flight Network Diagnostics"

    # --- Phase 1: collect read-only facts, unconditionally ---
    # These never gate the outcome; they exist so a failed install still has
    # the interface/route/resolver evidence to diagnose from.
    step "Collecting interface addresses"
    _netdiag_fact "Interface addresses (ip -brief addr)" "ip-addr" "ip -brief addr"

    step "Collecting default route"
    _netdiag_fact "Default route (ip route show default)" "ip-route" "ip route show default"

    step "Reading resolver configuration"
    _netdiag_fact "Resolver (/etc/resolv.conf)" "resolv-conf" "cat /etc/resolv.conf"

    # --- Phase 2: generic connectivity checks (run all, don't short-circuit) ---
    # DNS, egress, and TLS are independent failure modes. Keeping them separate
    # means a resolver problem reads as DNS, not as a downstream mirror failure.
    step "Testing DNS resolution"
    if $ssh_base "getent hosts archlinux.org >/dev/null 2>&1" 2>/dev/null; then
        success "DNS resolution OK"
    else
        error "DNS resolution failed"
        failures+=("DNS resolution (getent hosts archlinux.org)")
    fi

    step "Testing HTTP egress"
    if $ssh_base "curl -s --connect-timeout 5 -o /dev/null http://archlinux.org" 2>/dev/null; then
        success "HTTP egress OK"
    else
        error "HTTP egress failed"
        failures+=("HTTP egress (http://archlinux.org)")
    fi

    step "Testing TLS/HTTPS egress"
    if $ssh_base "curl -s --connect-timeout 5 -o /dev/null https://archlinux.org" 2>/dev/null; then
        success "TLS/HTTPS egress OK"
    else
        error "TLS/HTTPS egress failed"
        failures+=("TLS/HTTPS egress (https://archlinux.org)")
    fi

    # --- Phase 3: Arch-specific checks (run all, don't short-circuit) ---
    step "Testing Arch mirror access"
    if $ssh_base "curl -s -I https://geo.mirror.pkgbuild.com/ | head -1 | grep -qE '(200|301|302)'" 2>/dev/null; then
        success "Arch mirrors accessible"
    else
        error "Cannot reach Arch mirrors"
        failures+=("Arch mirror (https://geo.mirror.pkgbuild.com/)")
    fi

    step "Testing AUR access"
    if $ssh_base "curl -s -I https://aur.archlinux.org/ | head -1 | grep -qE '(200|405)'" 2>/dev/null; then
        success "AUR accessible"
    else
        error "Cannot reach AUR"
        failures+=("AUR (https://aur.archlinux.org/)")
    fi

    # --- Summary: report every failure, not just the first ---
    if [ ${#failures[@]} -eq 0 ]; then
        success "Network diagnostics complete - all checks passed"
        return 0
    fi

    error "Network diagnostics found ${#failures[@]} failure(s):"
    local f
    for f in "${failures[@]}"; do
        error "  - $f"
    done
    return 1
}