أنظمة التشغيل المدعومة
يدعم Gorelo فقط أنظمة التشغيل المدعومة حاليًا من المورّد نفسه (Microsoft/Apple).فحص المتطلبات المسبقة
يوفر Gorelo فحصًا للمتطلبات المسبقة لنظامي Windows وmacOS. يتأكد الفحص من أن الجهاز يستوفي المتطلبات ويمكنه الوصول إلى خدمات Gorelo، وينتهي بنتيجة واضحة PASS أو FAIL. يطلب منك كلا النصين البرمجيين اختيار منطقة Gorelo الخاصة بك: USW (غرب الولايات المتحدة) أو AUE (شرق أستراليا). ثم يفحصان خوادم Gorelo وIoT Hub ومصدر التنزيل المطابق لتلك المنطقة. عند تشغيل نص برمجي بشكل تفاعلي، يطلب منك اختيار منطقة. لتخطي هذا الطلب، مثلًا عند التشغيل دون تدخل، اضبط متغير البيئةGORELO_REGION على USW أو AUE مسبقًا.
- Windows
- macOS
- افتح نافذة PowerShell مرتفعة الصلاحيات على الكمبيوتر الذي يواجه مشكلات في الوكيل.
- انسخ النص البرمجي أدناه بالكامل، والصقه في النافذة، واضغط Enter:
gorelo-check-windows.ps1
$scriptContent = @'
# Gorelo Agent Pre-Installation Check Script
# Updated: 2026-03-22
# Checks system requirements, connectivity (including Cloudflare R2), TLS, and permissions
function Write-ColorOutput {
param (
[string]$Message,
[string]$Color = "White",
[bool]$IsError = $false
)
if ($IsError) {
Write-Host $Message -ForegroundColor Red
} else {
Write-Host $Message -ForegroundColor $Color
}
}
$hasError = $false
Write-Host ""
Write-Host "======================================" -ForegroundColor Cyan
Write-Host " Gorelo Agent Pre-Installation Check" -ForegroundColor Cyan
Write-Host "======================================" -ForegroundColor Cyan
Write-Host ""
# --- REGION SELECTION ---
# Run via Invoke-Expression, so there are no script parameters. Set $env:GORELO_REGION = "USW" or "AUE"
# beforehand to skip the prompt (e.g. for unattended runs).
$regions = @{
"USW" = "usw"
"AUE" = "aue"
}
$region = $env:GORELO_REGION
if ($region) { $region = $region.Trim().ToUpper() }
while (-not $regions.ContainsKey("$region")) {
Write-Host "Select your Gorelo region:" -ForegroundColor Cyan
Write-Host " 1) USW (United States West)"
Write-Host " 2) AUE (Australia East)"
$choice = (Read-Host "Enter 1 or 2 (or USW / AUE)").Trim().ToUpper()
switch ($choice) {
"1" { $region = "USW" }
"2" { $region = "AUE" }
default { $region = $choice }
}
if (-not $regions.ContainsKey("$region")) {
Write-ColorOutput "Invalid selection '$choice'. Please choose USW or AUE." -Color Yellow
}
}
$regionCode = $regions[$region]
Write-ColorOutput "INFO: Region selected: $region" -Color White
Write-Host ""
# --- SYSTEM CHECKS ---
Write-Host "[System Checks]" -ForegroundColor Cyan
# OS Version
$osInfo = Get-CimInstance Win32_OperatingSystem
Write-ColorOutput "INFO: $($osInfo.Caption) ($($osInfo.Version))" -Color White
# PowerShell version
$requiredVersion = [version]'5.1'
$installedVersion = $PSVersionTable.PSVersion
if ($installedVersion -lt $requiredVersion) {
Write-ColorOutput "FAIL: PowerShell version $($installedVersion) is below required $requiredVersion" -IsError $true
$hasError = $true
} else {
Write-ColorOutput "PASS: PowerShell version $($installedVersion)" -Color Green
}
# 64-bit check
if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") {
Write-ColorOutput "PASS: 64-bit processor architecture" -Color Green
} else {
Write-ColorOutput "FAIL: Non-64-bit architecture detected: $($env:PROCESSOR_ARCHITECTURE)" -IsError $true
$hasError = $true
}
# 64-bit Program Files
if ($Env:ProgramW6432) {
Write-ColorOutput "PASS: 64-bit Program Files folder exists ($($Env:ProgramW6432))" -Color Green
} else {
Write-ColorOutput "FAIL: 64-bit Program Files folder not found" -IsError $true
$hasError = $true
}
# System drive space
$systemDrive = $env:SystemDrive
if ($systemDrive) {
$driveInfo = Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Name -eq $systemDrive[0] }
if ($driveInfo) {
$freeSpaceMB = [math]::Round($driveInfo.Free / 1MB, 2)
if ($freeSpaceMB -le 300) {
Write-ColorOutput "FAIL: Free space is less than 300 MB (Current: $freeSpaceMB MB)" -IsError $true
$hasError = $true
} else {
Write-ColorOutput "PASS: System drive space ($freeSpaceMB MB free)" -Color Green
}
} else {
Write-ColorOutput "FAIL: Unable to get drive info" -IsError $true
$hasError = $true
}
}
# Administrator check
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-ColorOutput "PASS: Running as Administrator" -Color Green
} else {
Write-ColorOutput "FAIL: Not running as Administrator (required for installation)" -IsError $true
$hasError = $true
}
Write-Host ""
Write-Host "[TLS / Security Checks]" -ForegroundColor Cyan
# TLS 1.2 check
$tlsProtocols = [Net.ServicePointManager]::SecurityProtocol
if ($tlsProtocols -band [Net.SecurityProtocolType]::Tls12) {
Write-ColorOutput "PASS: TLS 1.2 is enabled in SecurityProtocol ($tlsProtocols)" -Color Green
} else {
Write-ColorOutput "WARN: TLS 1.2 not in default SecurityProtocol ($tlsProtocols). Enabling..." -Color Yellow
try {
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
Write-ColorOutput "PASS: TLS 1.2 enabled successfully" -Color Green
} catch {
Write-ColorOutput "FAIL: Could not enable TLS 1.2. Error: $_" -IsError $true
$hasError = $true
}
}
# Ensure TLS 1.2 is active for all subsequent web requests
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
Write-Host ""
Write-Host "[Connectivity Checks]" -ForegroundColor Cyan
# URL connectivity checks
$urls = @(
@{
Url = "https://www.google.com/"
ExpectedStatus = 200
Description = "Internet connectivity"
},
@{
Url = "https://gw.$regionCode.gorelo.tech/rmm-login/api/login/_health"
ExpectedStatus = 200
Description = "Gorelo Gateway ($region)"
},
@{
Url = "https://sr.rmm.pod1.$regionCode.gorelo.tech/api/_health"
ExpectedStatus = 200
Description = "Gorelo API ($region)"
},
@{
Url = "https://hub.rmm.pod1.$regionCode.gorelo.tech/hc"
ExpectedStatus = 200
Description = "Gorelo Hub ($region)"
}
)
$urlChecksPassed = $true
foreach ($urlCheck in $urls) {
try {
$response = Invoke-WebRequest -Uri $urlCheck.Url -Method Get -UseBasicParsing -TimeoutSec 15
if ($response.StatusCode -eq $urlCheck.ExpectedStatus) {
Write-ColorOutput "PASS: $($urlCheck.Description) ($($urlCheck.Url))" -Color Green
} else {
Write-ColorOutput "WARN: $($urlCheck.Description) returned $($response.StatusCode) (expected $($urlCheck.ExpectedStatus))" -Color Yellow
}
} catch {
Write-ColorOutput "FAIL: $($urlCheck.Description) ($($urlCheck.Url)). Error: $($_.Exception.Message)" -IsError $true
$urlChecksPassed = $false
$hasError = $true
}
}
# Cloudflare R2 connectivity (the installer download source)
Write-Host ""
Write-Host "[Cloudflare R2 Download Check]" -ForegroundColor Cyan
$r2Domain = "600c23d50c6ee4462ecb200a47f6b627.r2.cloudflarestorage.com"
try {
$dnsResult = [System.Net.Dns]::GetHostAddresses($r2Domain)
if ($dnsResult.Count -gt 0) {
Write-ColorOutput "PASS: DNS resolution for Cloudflare R2 ($r2Domain -> $($dnsResult[0]))" -Color Green
} else {
Write-ColorOutput "FAIL: DNS resolution returned no addresses for $r2Domain" -IsError $true
$hasError = $true
}
} catch {
Write-ColorOutput "FAIL: Cannot resolve Cloudflare R2 domain ($r2Domain). Error: $($_.Exception.Message)" -IsError $true
$hasError = $true
}
# Test HTTPS connection to R2 (HEAD request to bucket root - will get 403 which is fine, proves connectivity)
try {
$r2Response = Invoke-WebRequest -Uri "https://$r2Domain/" -Method Head -UseBasicParsing -TimeoutSec 15 -ErrorAction Stop
Write-ColorOutput "PASS: HTTPS connection to Cloudflare R2" -Color Green
} catch [System.Net.WebException] {
$statusCode = $null
if ($_.Exception.Response) {
$statusCode = [int]$_.Exception.Response.StatusCode
}
if ($statusCode -eq 400 -or $statusCode -eq 403 -or $statusCode -eq 404 -or $statusCode -eq 405) {
# 400/403/404/405 means we connected successfully - just not authorized (expected without presigned URL)
Write-ColorOutput "PASS: HTTPS connection to Cloudflare R2 (got HTTP $statusCode - connection works, auth expected to fail without presigned URL)" -Color Green
} else {
Write-ColorOutput "FAIL: HTTPS connection to Cloudflare R2 ($r2Domain). Error: $($_.Exception.Message)" -IsError $true
$hasError = $true
}
} catch {
Write-ColorOutput "FAIL: HTTPS connection to Cloudflare R2 ($r2Domain). Error: $($_.Exception.Message)" -IsError $true
$hasError = $true
}
# Azure IoT Hub connectivity (needed post-install for agent communication)
Write-Host ""
Write-Host "[Post-Install Connectivity (IoT Hub)]" -ForegroundColor Cyan
$iotHubsByRegion = @{
"USW" = "gorelo.azure-devices.net"
"AUE" = "gorelo-aue.azure-devices.net"
}
$iotHubDomains = @(
$iotHubsByRegion[$region]
)
foreach ($domain in $iotHubDomains) {
try {
$dnsResult = [System.Net.Dns]::GetHostAddresses($domain)
if ($dnsResult.Count -gt 0) {
Write-ColorOutput "PASS: DNS resolution for IoT Hub ($domain)" -Color Green
}
} catch {
Write-ColorOutput "WARN: Cannot resolve IoT Hub domain ($domain). Agent may not connect after install." -Color Yellow
}
}
Write-Host ""
Write-Host "[Permission Checks]" -ForegroundColor Cyan
# Registry read/write
try {
$registryPath = "HKLM:\SOFTWARE\Gorelo"
if (-not (Test-Path $registryPath)) {
New-Item -Path $registryPath -Force -ErrorAction Stop | Out-Null
}
Set-ItemProperty -Path $registryPath -Name "PreCheck" -Value "test" -Type String -ErrorAction Stop
$testVal = (Get-ItemProperty -Path $registryPath -Name "PreCheck" -ErrorAction Stop).PreCheck
Remove-ItemProperty -Path $registryPath -Name "PreCheck" -Force -ErrorAction Stop
Write-ColorOutput "PASS: Registry read/write permission" -Color Green
} catch {
Write-ColorOutput "FAIL: Registry read/write permission. Error: $_" -IsError $true
$hasError = $true
}
# Event log
$logName = 'Application'
$sourceName = 'GoreloRmmTest'
try {
if (-not [System.Diagnostics.EventLog]::SourceExists($sourceName)) {
New-EventLog -LogName $logName -Source $sourceName -ErrorAction Stop
}
Write-EventLog -LogName $logName -Source $sourceName -EventId 0 -EntryType Information -Message "Gorelo pre-check test event" -ErrorAction Stop
Write-ColorOutput "PASS: Event log read/write permission" -Color Green
} catch {
Write-ColorOutput "FAIL: Event log read/write permission. Error: $_" -IsError $true
$hasError = $true
}
# PATH check
$path = [System.Environment]::GetEnvironmentVariable("PATH")
$system32Check = $path -like "*system32*"
$psCheck = $path -like "*System32\WindowsPowerShell\v1.0*"
if ($system32Check -and $psCheck) {
Write-ColorOutput "PASS: PATH contains system32 and PowerShell paths" -Color Green
} else {
$missing = @()
if (-not $system32Check) { $missing += "system32" }
if (-not $psCheck) { $missing += "WindowsPowerShell" }
Write-ColorOutput "FAIL: PATH missing: $($missing -join ', ')" -IsError $true
$hasError = $true
}
Write-Host ""
Write-Host "[Time Sync Check]" -ForegroundColor Cyan
# NTP time check
function Get-NTPTime {
try {
$NTPServer = "time.windows.com"
$NTPData = New-Object byte[] 48
$NTPData[0] = 27
$Socket = New-Object Net.Sockets.Socket([Net.Sockets.AddressFamily]::InterNetwork, [Net.Sockets.SocketType]::Dgram, [Net.Sockets.ProtocolType]::Udp)
$Socket.ReceiveTimeout = 5000
$Socket.SendTimeout = 5000
$Socket.Connect($NTPServer, 123)
$null = $Socket.Send($NTPData)
$null = $Socket.Receive($NTPData)
$Socket.Close()
$IntPart = [BitConverter]::ToUInt32($NTPData[43..40], 0)
$FracPart = [BitConverter]::ToUInt32($NTPData[47..44], 0)
$Milliseconds = ($IntPart * 1000) + (($FracPart * 1000) / 0x100000000)
return (New-Object DateTime(1900, 1, 1, 0, 0, 0, [DateTimeKind]::Utc)).AddMilliseconds($Milliseconds)
} catch {
return $null
}
}
$ntpTime = Get-NTPTime
if ($ntpTime) {
$currentTimeZone = Get-TimeZone
$expectedTime = [System.TimeZoneInfo]::ConvertTimeFromUtc($ntpTime, $currentTimeZone)
$currentTime = Get-Date
$timeDifference = ($currentTime - $expectedTime).TotalMinutes
if ([Math]::Abs($timeDifference) -gt 5) {
Write-ColorOutput "FAIL: Time mismatch! System: $($currentTime.ToString('yyyy-MM-dd HH:mm:ss')) | NTP: $($expectedTime.ToString('yyyy-MM-dd HH:mm:ss')) | Diff: $([Math]::Round($timeDifference, 1)) min" -IsError $true
$hasError = $true
} else {
Write-ColorOutput "PASS: Time sync OK (diff: $([Math]::Round($timeDifference, 1)) min) | TZ: $($currentTimeZone.Id)" -Color Green
}
} else {
Write-ColorOutput "WARN: Could not reach NTP server (time.windows.com:123 UDP) - skipping time check" -Color Yellow
}
# --- EXISTING INSTALLATION CHECK ---
Write-Host ""
Write-Host "[Existing Installation]" -ForegroundColor Cyan
$goreloDir = "$Env:ProgramW6432\Gorelo"
if (Test-Path $goreloDir) {
$goreloProcesses = @("Gorelo.Rmm.Installer", "Gorelo.RemoteManagement.Shell", "Gorelo.RemoteManagement.Agent")
$processList = (Get-Process).ProcessName
$runningProcesses = $goreloProcesses | Where-Object { $_ -in $processList }
if ($runningProcesses.Count -gt 0) {
Write-ColorOutput "INFO: Gorelo agent is already installed and running ($($runningProcesses -join ', '))" -Color White
} else {
Write-ColorOutput "INFO: Gorelo directory exists but agent processes are not running" -Color Yellow
}
} else {
Write-ColorOutput "INFO: No existing Gorelo installation found (clean install)" -Color White
}
# --- SUMMARY ---
Write-Host ""
Write-Host "======================================" -ForegroundColor Cyan
if ($hasError) {
Write-ColorOutput "RESULT: FAIL - One or more checks failed" -IsError $true
Write-Host "Fix the issues above and re-run this script." -ForegroundColor Yellow
} else {
Write-ColorOutput "RESULT: PASS - All checks passed. Ready to install." -Color Green
}
Write-Host "======================================" -ForegroundColor Cyan
Write-Host ""
'@
$scriptPath = Join-Path $env:TEMP "gorelo-check-windows.ps1"
Set-Content -Path $scriptPath -Value $scriptContent
& $scriptPath
Remove-Item $scriptPath -Force
- اختر منطقتك (USW أو AUE) عند المطالبة.
- حُلّ أي إخفاقات باستخدام الجدول أدناه، وتأكد من استمرار إصلاحاتك عبر جلسات PowerShell وعمليات إعادة التشغيل.
| الفحص | ❌ رسالة الفشل | ✅ استكشاف الأخطاء وإصلاحها |
|---|---|---|
| فحص إصدار PowerShell | FAIL: PowerShell version X.X is below the required version 5.1 |
|
| فحص مساحة محرك أقراص النظام |
|
|
| فحص بنية المعالج | FAIL: Non-64-bit processor architecture detected: X |
|
| فحص أذونات السجل | FAIL: Registry read/write permission check. Error: [specific error] |
|
| فحوصات إمكانية الوصول إلى عنوان URL | FAIL: URL check for [Description] ([URL]). Error: [specific error] | يفحص خوادم البوابة وAPI والمحور الخاصة بـ Gorelo للمنطقة التي اخترتها.
|
| فحص التنزيل من Cloudflare R2 |
|
|
| فحص أذونات سجل الأحداث | FAIL: Event log read/write permission check. Error: [specific error] |
|
| فحص متغير البيئة |
|
|
| فحص مزامنة الوقت | FAIL: Time mismatch detected! [time details] |
|
gorelo.azure-devices.net لـ USW، وgorelo-aue.azure-devices.net لـ AUE). إذا تعذّر حل IoT Hub، يعرض النص البرمجي تحذيرًا وليس فشلًا. لا يمنع التحذير فحص المثبّت من النجاح، لكن قد يفشل الوكيل في الاتصال بعد التثبيت، لذا يستحق الأمر الإصلاح.- افتح Terminal على جهاز Mac الذي يواجه مشكلات في الوكيل.
- انسخ الأمر أدناه بالكامل، والصقه في النافذة، واضغط Enter. سيُطلب منك إدخال كلمة المرور، لأن الفحص يحتاج إلى التشغيل بصلاحيات root.
gorelo-check-mac.sh
cat > /tmp/gorelo-check-mac.sh <<'EOF'
#!/bin/bash
# Gorelo Agent Pre-Installation Check Script (macOS)
# Updated: 2026-09-23
# Checks system requirements, connectivity (including Cloudflare R2), TLS, and permissions
#
# Run: curl -fsSL <raw-url>/gorelo-check-mac.sh | sudo bash
# Skip the region prompt: curl -fsSL <raw-url>/gorelo-check-mac.sh | sudo GORELO_REGION=AUE bash
#
# Written for the bash 3.2 that ships with macOS (no associative arrays).
RED=$'\033[31m'; GREEN=$'\033[32m'; YELLOW=$'\033[33m'; CYAN=$'\033[36m'; RESET=$'\033[0m'
has_error=0
pass() { echo "${GREEN}PASS: $*${RESET}"; }
fail() { echo "${RED}FAIL: $*${RESET}"; has_error=1; }
warn() { echo "${YELLOW}WARN: $*${RESET}"; }
info() { echo "INFO: $*"; }
section() { echo; echo "${CYAN}[$*]${RESET}"; }
echo
echo "${CYAN}======================================${RESET}"
echo "${CYAN} Gorelo Agent Pre-Installation Check${RESET}"
echo "${CYAN}======================================${RESET}"
echo
# --- REGION SELECTION ---
# When piped (curl | bash) stdin is the script itself, so the prompt reads from /dev/tty.
region=$(echo "${GORELO_REGION:-}" | tr '[:lower:]' '[:upper:]' | tr -d '[:space:]')
while [ "$region" != "USW" ] && [ "$region" != "AUE" ]; do
if [ ! -r /dev/tty ]; then
echo "${RED}No terminal to prompt on. Set GORELO_REGION=USW or GORELO_REGION=AUE.${RESET}"
exit 2
fi
echo "${CYAN}Select your Gorelo region:${RESET}"
echo " 1) USW (United States West)"
echo " 2) AUE (Australia East)"
printf "Enter 1 or 2 (or USW / AUE): "
read -r choice < /dev/tty
choice=$(echo "$choice" | tr '[:lower:]' '[:upper:]' | tr -d '[:space:]')
case "$choice" in
1) region="USW" ;;
2) region="AUE" ;;
*) region="$choice" ;;
esac
if [ "$region" != "USW" ] && [ "$region" != "AUE" ]; then
echo "${YELLOW}Invalid selection '$choice'. Please choose USW or AUE.${RESET}"
fi
done
if [ "$region" = "USW" ]; then
region_code="usw"
iot_hub="gorelo.azure-devices.net"
else
region_code="aue"
iot_hub="gorelo-aue.azure-devices.net"
fi
info "Region selected: $region"
# --- SYSTEM CHECKS ---
section "System Checks"
info "macOS $(sw_vers -productVersion) (build $(sw_vers -buildVersion))"
arch=$(uname -m)
if [ "$arch" = "arm64" ] || [ "$arch" = "x86_64" ]; then
pass "64-bit processor architecture ($arch)"
else
fail "Unsupported architecture detected: $arch"
fi
# Free space on the system volume (df -k: 1K blocks, column 4 = available)
free_kb=$(df -k / | awk 'NR==2 {print $4}')
if [ -n "$free_kb" ]; then
free_mb=$((free_kb / 1024))
if [ "$free_mb" -le 300 ]; then
fail "Free space is less than 300 MB (Current: $free_mb MB)"
else
pass "System drive space ($free_mb MB free)"
fi
else
fail "Unable to get drive info"
fi
if [ "$(id -u)" -eq 0 ]; then
pass "Running as root (sudo)"
else
fail "Not running as root (required for installation) - re-run with sudo"
fi
# --- TLS / SECURITY CHECKS ---
section "TLS / Security Checks"
if curl -s -o /dev/null --tlsv1.2 --max-time 15 "https://www.google.com/"; then
pass "TLS 1.2 connections work ($(curl --version | head -n 1 | awk '{print $1, $2}'))"
else
fail "Could not make a TLS 1.2 connection"
fi
# --- CONNECTIVITY CHECKS ---
section "Connectivity Checks"
check_url() {
# $1 = url, $2 = description, $3 = expected status
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 15 "$1")
if [ "$code" = "000" ]; then
fail "$2 ($1). Could not connect"
elif [ "$code" = "$3" ]; then
pass "$2 ($1)"
else
warn "$2 returned $code (expected $3)"
fi
}
check_url "https://www.google.com/" "Internet connectivity" 200
check_url "https://gw.$region_code.gorelo.tech/rmm-login/api/login/_health" "Gorelo Gateway ($region)" 200
check_url "https://sr.rmm.pod1.$region_code.gorelo.tech/api/_health" "Gorelo API ($region)" 200
check_url "https://hub.rmm.pod1.$region_code.gorelo.tech/hc" "Gorelo Hub ($region)" 200
# --- CLOUDFLARE R2 (installer download source, same for all regions) ---
section "Cloudflare R2 Download Check"
r2_domain="600c23d50c6ee4462ecb200a47f6b627.r2.cloudflarestorage.com"
r2_ip=$(dscacheutil -q host -a name "$r2_domain" | awk '/^ip_address:/ {print $2; exit}')
if [ -n "$r2_ip" ]; then
pass "DNS resolution for Cloudflare R2 ($r2_domain -> $r2_ip)"
else
fail "Cannot resolve Cloudflare R2 domain ($r2_domain)"
fi
# HEAD to the bucket root: 400/403/404/405 proves connectivity (no presigned URL, so auth fails)
r2_code=$(curl -s -o /dev/null -I -w "%{http_code}" --max-time 15 "https://$r2_domain/")
case "$r2_code" in
2??) pass "HTTPS connection to Cloudflare R2" ;;
400|403|404|405) pass "HTTPS connection to Cloudflare R2 (got HTTP $r2_code - connection works, auth expected to fail without presigned URL)" ;;
*) fail "HTTPS connection to Cloudflare R2 ($r2_domain). Got: $r2_code" ;;
esac
# --- IOT HUB (needed post-install for agent communication) ---
section "Post-Install Connectivity (IoT Hub)"
if dscacheutil -q host -a name "$iot_hub" | grep -q '^ip_address:'; then
pass "DNS resolution for IoT Hub ($iot_hub)"
else
warn "Cannot resolve IoT Hub domain ($iot_hub). Agent may not connect after install."
fi
# --- PERMISSION CHECKS ---
section "Permission Checks"
test_dir="/Library/Gorelo"
created_dir=0
if [ ! -d "$test_dir" ]; then
mkdir -p "$test_dir" 2>/dev/null && created_dir=1
fi
test_file="$test_dir/.precheck-$$"
if echo "test" > "$test_file" 2>/dev/null && [ "$(cat "$test_file")" = "test" ]; then
pass "Write permission to $test_dir"
else
fail "Write permission to $test_dir"
fi
rm -f "$test_file" 2>/dev/null
[ "$created_dir" -eq 1 ] && rmdir "$test_dir" 2>/dev/null
if [ -w /Library/LaunchDaemons ]; then
pass "Write permission to /Library/LaunchDaemons"
else
fail "Write permission to /Library/LaunchDaemons"
fi
case ":$PATH:" in
*:/usr/bin:*) pass "PATH contains /usr/bin" ;;
*) fail "PATH missing /usr/bin" ;;
esac
# --- TIME SYNC CHECK ---
section "Time Sync Check"
# sntp prints e.g. "+0.012345 +/- 0.0123 time.apple.com 17.253.x.x"; first field = offset in seconds
offset=$(sntp -t 5 time.apple.com 2>/dev/null | awk '$1 ~ /^[+-]?[0-9.]+$/ {print $1; exit}')
if [ -n "$offset" ]; then
abs_min=$(awk -v o="$offset" 'BEGIN { if (o < 0) o = -o; printf "%.1f", o / 60 }')
if awk -v m="$abs_min" 'BEGIN { exit !(m > 5) }'; then
fail "Time mismatch! Offset from NTP: $abs_min min | System: $(date '+%Y-%m-%d %H:%M:%S')"
else
pass "Time sync OK (diff: $abs_min min) | TZ: $(readlink /etc/localtime | sed 's#.*/zoneinfo/##')"
fi
else
warn "Could not reach NTP server (time.apple.com:123 UDP) - skipping time check"
fi
# --- EXISTING INSTALLATION ---
section "Existing Installation"
if [ -d "/Library/Gorelo" ]; then
running=$(pgrep -il gorelo | awk '{print $2}' | sort -u | tr '\n' ' ')
if [ -n "$running" ]; then
info "Gorelo agent is already installed and running ($running)"
else
echo "${YELLOW}INFO: Gorelo directory exists but agent processes are not running${RESET}"
fi
else
info "No existing Gorelo installation found (clean install)"
fi
# --- SUMMARY ---
echo
echo "${CYAN}======================================${RESET}"
if [ "$has_error" -eq 1 ]; then
echo "${RED}RESULT: FAIL - One or more checks failed${RESET}"
echo "${YELLOW}Fix the issues above and re-run this script.${RESET}"
else
echo "${GREEN}RESULT: PASS - All checks passed. Ready to install.${RESET}"
fi
echo "${CYAN}======================================${RESET}"
echo
exit "$has_error"
EOF
chmod +x /tmp/gorelo-check-mac.sh
sudo /tmp/gorelo-check-mac.sh
rm -f /tmp/gorelo-check-mac.sh
- اختر منطقتك (USW أو AUE) عند المطالبة.
- حُلّ أي إخفاقات باستخدام الجدول أدناه، وتأكد من استمرار إصلاحاتك عبر جلسات Terminal وعمليات إعادة التشغيل.
| الفحص | ❌ رسالة الفشل | ✅ استكشاف الأخطاء وإصلاحها |
|---|---|---|
| فحص بنية المعالج | FAIL: Unsupported architecture detected: [arch] |
|
| فحص مساحة القرص |
|
|
| فحص صلاحيات المسؤول | FAIL: Not running as root (required for installation) - re-run with sudo |
|
| فحص TLS | FAIL: Could not make a TLS 1.2 connection |
|
| فحوصات خوادم Gorelo (Gateway / API / Hub) | FAIL: [Description] ([URL]). Could not connect | يفحص خوادم البوابة وAPI والمحور الخاصة بـ Gorelo للمنطقة التي اخترتها.
|
| فحص التنزيل من Cloudflare R2 |
|
|
| فحص أذونات مجلد التثبيت |
|
|
| فحص PATH | FAIL: PATH missing /usr/bin |
|
| فحص مزامنة الوقت | FAIL: Time mismatch! Offset from NTP: X min |
|
gorelo.azure-devices.net لـ USW، وgorelo-aue.azure-devices.net لـ AUE). إذا تعذّر حل IoT Hub، يعرض النص البرمجي تحذيرًا وليس فشلًا. لا يمنع التحذير فحص المثبّت من النجاح، لكن قد يفشل الوكيل في الاتصال بعد التثبيت، لذا يستحق الأمر الإصلاح.الوكيل مثبّت لكن الأصل يظهر غير متصل
تأتي حالة الاتصال أو عدم الاتصال للأصل في Gorelo من Gorelo Agent. أما Gorelo Connect فهو مكوّن منفصل للتحكم عن بُعد. يمكن أن يعمل Gorelo Connect، ويمكنك بدء جلسات عن بُعد، بينما يتعذّر على Gorelo Agent الوصول إلى سحابة Gorelo. راجع Gorelo Agent مقابل Gorelo Connect. إذا كان Gorelo Agent مثبّتًا لكن الأصل يظهر غير متصل في قائمة الأصول:- شغّل فحص المتطلبات المسبقة على الجهاز المتأثر.
- راجع فحوصات عناوين URL لخوادم البوابة وAPI والمحور الخاصة بـ Gorelo. يعني الفشل أن إعدادًا في جدار الحماية أو الوكيل (proxy) أو DNS يحظر Gorelo Agent.
- راجع تحذير DNS الخاص بـ IoT Hub. قد يفشل Gorelo Agent في الاتصال إذا تعذّر على الجهاز حل
gorelo.azure-devices.net(USW) أوgorelo-aue.azure-devices.net(AUE)، حتى عندما تعمل حركة الإنترنت الأخرى وGorelo Connect. - راجع فحص مزامنة الوقت. أصلح أي عدم تطابق في الوقت.
- تحقق من سجل Gorelo Agent بحثًا عن أخطاء الاتصال. راجع السجلات لمعرفة موقع سجل الوكيل على Windows وmacOS.
السجلات
- Windows
- macOS
يسجل Gorelo كل شيء في:أثناء تقدم التثبيت، يقوم المثبّت بإنشاء مجلدات إضافية في كل مرحلة مع ملفات سجل بداخلها:InstallerHandler > Installer > Shell > Agentتظهر أكثر المشكلات شيوعًا في السجلات التالية:إذا طلب دعم Gorelo ملفات السجل، أرسل مجلد LogFiles بالكامل في صورة ملف .zip.
%programfiles%\Gorelo\LogFiles\
%programfiles%\Gorelo\LogFiles\Installer\diagnostics**.log
%programfiles%\Gorelo\LogFiles\Agent\diagnostics**.log
يسجل Gorelo كل شيء في:تظهر أكثر المشكلات شيوعًا في السجلات التالية:إذا طلب دعم Gorelo ملفات السجل، أرسل مجلد LogFiles بالكامل في صورة ملف .zip.
/Library/Gorelo/LogFiles/
/Library/Gorelo/LogFiles/ServiceLogs/installer_logs_info.log
/Library/Gorelo/LogFiles/ServiceLogs/installer_logs_error.log
/Library/Gorelo/LogFiles/ServiceLogs/agent_logs_info.log
/Library/Gorelo/LogFiles/ServiceLogs/agent_logs_error.log