219 lines
8.7 KiB
Bash
219 lines
8.7 KiB
Bash
#!/bin/bash
|
|
|
|
# Color codes for better output readability
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Array of mirrors to test
|
|
mapfile -t mirrors < <(
|
|
curl -fsSL "https://gitamin.ir/smx/irs/raw/branch/main/mirrors.md" \
|
|
| grep -oP '"\Khttps?://[^"]+' \
|
|
| sed 's|^https://||'
|
|
)
|
|
|
|
|
|
# Timeout in seconds
|
|
# Warn if no timeout provided
|
|
if [ -z "$TIMEOUT" ] && [ -z "$1" ]; then
|
|
echo "Warning: No timeout specified, using default 14 seconds"
|
|
echo "Usage: TIMEOUT=30 curl ... | bash"
|
|
echo " or: curl ... | bash -s -- 30"
|
|
fi
|
|
|
|
TIMEOUT="${TIMEOUT:-${1:-14}}"
|
|
timeout $TIMEOUT
|
|
|
|
# Function to format time with milliseconds
|
|
format_time() {
|
|
local seconds=$1
|
|
if (( $(echo "$seconds < 0.1" | bc -l 2>/dev/null || echo "0") )); then
|
|
printf "%.0fms" "$(echo "$seconds * 1000" | bc 2>/dev/null || echo "0")"
|
|
else
|
|
printf "%.2fs" "$seconds"
|
|
fi
|
|
}
|
|
|
|
# Function to test a single mirror
|
|
test_mirror() {
|
|
local mirror=$1
|
|
local timeout=$2
|
|
|
|
echo -e "\n${CYAN}Testing:${NC} ${YELLOW}${mirror}${NC}"
|
|
echo "──────────────────────────────────────────────"
|
|
|
|
# Create temporary file for response headers and body
|
|
local temp_file=$(mktemp)
|
|
local headers_file=$(mktemp)
|
|
|
|
# Measure time and capture response
|
|
local start_time=$(date +%s.%N)
|
|
|
|
# Attempt connection with detailed output capture
|
|
local http_code=$(curl -s -w "%{http_code}" \
|
|
-o "$temp_file" \
|
|
-D "$headers_file" \
|
|
--max-time "$timeout" \
|
|
--connect-timeout "$timeout" \
|
|
"${mirror}/ubuntu/" 2>&1)
|
|
|
|
local end_time=$(date +%s.%N)
|
|
local elapsed=$(echo "$end_time - $start_time" | bc 2>/dev/null || echo "0")
|
|
local formatted_time=$(format_time "$elapsed")
|
|
|
|
# Check if curl succeeded or failed
|
|
local curl_exit_code=$?
|
|
|
|
# Parse response
|
|
if [ $curl_exit_code -eq 0 ]; then
|
|
# Success - got HTTP response
|
|
echo -e " ${BLUE}Response Time:${NC} ${formatted_time}"
|
|
echo -e " ${BLUE}HTTP Status:${NC} ${http_code}"
|
|
|
|
# Check for Docker-Distribution-API-Version header
|
|
local api_version=$(grep -i "^Docker-Distribution-Api-Version:" "$headers_file" | cut -d' ' -f2 | tr -d '\r')
|
|
if [ -n "$api_version" ]; then
|
|
echo -e " ${BLUE}API Version:${NC} ${api_version}"
|
|
fi
|
|
|
|
# Analyze response based on HTTP code
|
|
case $http_code in
|
|
200)
|
|
echo -e " ${GREEN}✓ Status:${NC} Mirror is fully accessible (no auth required)"
|
|
echo -e " ${GREEN}✓ Message:${NC} Connection successful - ready to pull"
|
|
rm -f "$temp_file" "$headers_file"
|
|
return 0
|
|
;;
|
|
401)
|
|
echo -e " ${GREEN}✓ Status:${NC} Mirror is accessible (authentication required)"
|
|
# Check for WWW-Authenticate header
|
|
local auth_header=$(grep -i "^WWW-Authenticate:" "$headers_file" | cut -d' ' -f2- | tr -d '\r')
|
|
if [ -n "$auth_header" ]; then
|
|
echo -e " ${BLUE}Auth Method:${NC} ${auth_header:0:50}..."
|
|
fi
|
|
echo -e " ${GREEN}✓ Message:${NC} Ready to pull (login required)"
|
|
rm -f "$temp_file" "$headers_file"
|
|
return 0
|
|
;;
|
|
403)
|
|
echo -e " ${YELLOW}⚠ Status:${NC} Access forbidden"
|
|
local body=$(cat "$temp_file" | head -c 200)
|
|
if [ -n "$body" ]; then
|
|
echo -e " ${YELLOW}⚠ Message:${NC} ${body}"
|
|
else
|
|
echo -e " ${YELLOW}⚠ Message:${NC} Authentication required or IP restricted"
|
|
fi
|
|
rm -f "$temp_file" "$headers_file"
|
|
return 1
|
|
;;
|
|
404)
|
|
echo -e " ${RED}✗ Status:${NC} Mirror API endpoint not found"
|
|
echo -e " ${RED}✗ Message:${NC} This may not be a valid Ubuntu Mirrors or /ubuntu/ endpoint is disabled"
|
|
rm -f "$temp_file" "$headers_file"
|
|
return 1
|
|
;;
|
|
50[0-9])
|
|
echo -e " ${RED}✗ Status:${NC} Mirror server error"
|
|
echo -e " ${RED}✗ Message:${NC} Mirror is experiencing issues (HTTP $http_code)"
|
|
rm -f "$temp_file" "$headers_file"
|
|
return 1
|
|
;;
|
|
*)
|
|
echo -e " ${YELLOW}⚠ Status:${NC} Unexpected HTTP response"
|
|
echo -e " ${YELLOW}⚠ Message:${NC} HTTP $http_code - check mirror configuration"
|
|
rm -f "$temp_file" "$headers_file"
|
|
return 1
|
|
;;
|
|
esac
|
|
else
|
|
# Curl failed - connection issue
|
|
echo -e " ${BLUE}Response Time:${NC} ${formatted_time}"
|
|
echo -e " ${BLUE}HTTP Status:${NC} ${RED}Connection Failed${NC}"
|
|
|
|
case $curl_exit_code in
|
|
6)
|
|
echo -e " ${RED}✗ Error:${NC} Could not resolve hostname (DNS failure)"
|
|
echo -e " ${RED}✗ Message:${NC} Check mirror URL or DNS configuration"
|
|
;;
|
|
7)
|
|
echo -e " ${RED}✗ Error:${NC} Failed to connect to host"
|
|
echo -e " ${RED}✗ Message:${NC} Firewall blocking or mirror is down"
|
|
;;
|
|
28)
|
|
echo -e " ${RED}✗ Error:${NC} Connection timeout after ${timeout}s"
|
|
echo -e " ${RED}✗ Message:${NC} Network too slow or mirror unresponsive"
|
|
;;
|
|
35)
|
|
echo -e " ${RED}✗ Error:${NC} SSL/TLS connection failed"
|
|
echo -e " ${RED}✗ Message:${NC} Certificate issue or mirror requires different SSL settings"
|
|
;;
|
|
60)
|
|
echo -e " ${RED}✗ Error:${NC} SSL certificate problem"
|
|
echo -e " ${RED}✗ Message:${NC} Certificate is invalid or self-signed"
|
|
;;
|
|
*)
|
|
echo -e " ${RED}✗ Error:${NC} Connection failed (curl exit code: $curl_exit_code)"
|
|
echo -e " ${RED}✗ Message:${NC} Unknown connection error"
|
|
;;
|
|
esac
|
|
|
|
# Try to get more details if available
|
|
if [ -s "$temp_file" ]; then
|
|
local error_output=$(cat "$temp_file" | head -c 200)
|
|
if [ -n "$error_output" ]; then
|
|
echo -e " ${BLUE}Details:${NC} $error_output"
|
|
fi
|
|
fi
|
|
|
|
rm -f "$temp_file" "$headers_file"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Main execution
|
|
echo -e "${CYAN}╔══════════════════════════════════════════════════════════╗${NC}"
|
|
echo -e "${CYAN}║ Ubuntu Mirrors Connectivity Test Script ║${NC}"
|
|
echo -e "${CYAN}╚══════════════════════════════════════════════════════════╝${NC}"
|
|
echo -e "${BLUE}Timeout setting:${NC} ${TIMEOUT}s"
|
|
echo -e "${BLUE}Started at:${NC} $(date '+%Y-%m-%d %H:%M:%S')\n"
|
|
|
|
# Test all mirrors
|
|
total=${#mirrors[@]}
|
|
successful=0
|
|
failed=0
|
|
declare -a failed_mirrors
|
|
|
|
for reg in "${mirrors[@]}"; do
|
|
if test_mirror "$reg" "$TIMEOUT"; then
|
|
((successful++))
|
|
else
|
|
((failed++))
|
|
failed_mirrors+=("$reg")
|
|
fi
|
|
done
|
|
|
|
# Summary report
|
|
echo -e "\n${CYAN}════════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN} SUMMARY REPORT ${NC}"
|
|
echo -e "${CYAN}════════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${BLUE}Total Mirrors Tested:${NC} $total"
|
|
echo -e "${GREEN}✓ Successfully Reachable:${NC} $successful"
|
|
echo -e "${RED}✗ Failed/Unreachable:${NC} $failed"
|
|
|
|
if [ $failed -gt 0 ]; then
|
|
echo -e "\n${RED}Failed Mirrors:${NC}"
|
|
for failed_reg in "${failed_mirrors[@]}"; do
|
|
echo -e " ${RED}✗${NC} $failed_reg"
|
|
done
|
|
echo -e "\n${YELLOW}⚠ WARNING:${NC} $failed mirror/ies are unreachable"
|
|
echo -e "${YELLOW}Recommendation:${NC} Check network connectivity or mirror status before pulling images"
|
|
exit 1
|
|
else
|
|
echo -e "\n${GREEN}✓ SUCCESS:${NC} All mirrors are reachable!"
|
|
echo -e "${GREEN}✓ Ready to proceed with Docker pulls${NC}"
|
|
exit 0
|
|
fi
|