mirror of
https://github.com/hanzoai/insights.git
synced 2026-11-03 00:52:32 +00:00
The fork half-carried the upstream vendor's name: env vars had been moved to DATASTORE_*, but every module path, identifier and doc string underneath still said ClickHouse. A fork that reads like someone else's product in every import is a vendored copy that never got renamed. insights/clickhouse/ -> insights/datastore/ insights/insightsql/functions/ -> .../functions/datastore/ products/live_debugger/backend/ -> .../backend/datastore/ docker/, docs/handbook/ -> datastore/ CLICKHOUSE_* identifiers -> DATASTORE_* (164 files) manage.py migrate_clickhouse -> migrate_datastore prose, comments, docstrings -> Datastore (1000+ files) The ORM moved with it: hanzoai/infi.clickhouse_orm now ships `datastore_orm`, so consumers write `from datastore_orm import ...` rather than threading the original vendor's `infi` org namespace through their imports. Repinned here to that revision. MIGRATION HISTORY. A package rename orphans the history table, because it keys on package_name: the runner then sees zero applied migrations, replays from 0001 and dies on 0026. That already happened once here, silently blocking every datastore migration until the rows were re-keyed by hand. So the rename carries its own fixup — migrate_datastore now adopts history from prior package names before migrating, idempotent and a no-op on a fresh database, with the list of former names as the single place a future rename has to touch. The history TABLE name is unchanged: it is persisted state, and renaming it is a data migration rather than a rename. Left with the vendor's name, because they are the vendor's: clickhouse-driver, clickhouse-pool and clickhouse-connect are third-party PyPI packages we do not fork, CLICKHOUSE_SKIP_USER_SETUP and CLICKHOUSE_SERVER_IMAGE configure the upstream server image, and clickhouse.com doc links point at the real engine's documentation. Verified: 4257 Python files parse with 0 syntax errors, no `insights.clickhouse` or `infi.clickhouse` references survive, and clickhouse_pool/_driver imports are untouched.
188 lines
5.7 KiB
Go
188 lines
5.7 KiB
Go
package core
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type CheckStatus int
|
|
|
|
const (
|
|
CheckPending CheckStatus = iota
|
|
CheckRunning
|
|
CheckPassed
|
|
CheckFailed
|
|
CheckWarning
|
|
)
|
|
|
|
type CheckResult struct {
|
|
Passed bool
|
|
Warning bool
|
|
Detail string
|
|
Err error
|
|
}
|
|
|
|
type Check struct {
|
|
Name string
|
|
Run func() CheckResult
|
|
}
|
|
|
|
func GetChecks() []Check {
|
|
return []Check{
|
|
{Name: "Docker installed", Run: checkDocker},
|
|
{Name: "Docker Compose available", Run: checkDockerCompose},
|
|
{Name: "Memory (8GB+ recommended)", Run: checkMemory},
|
|
{Name: "Disk space available", Run: checkDiskSpace},
|
|
{Name: "Network connectivity", Run: checkNetwork},
|
|
{Name: "Docker volumes", Run: checkDockerVolumes},
|
|
}
|
|
}
|
|
|
|
func checkDocker() CheckResult {
|
|
logger := GetLogger()
|
|
logger.WriteString("Checking for Docker...\n")
|
|
|
|
_, err := exec.LookPath("docker")
|
|
if err != nil {
|
|
logger.WriteString("⚠ Docker not found, will be installed\n")
|
|
return CheckResult{Passed: true, Warning: true, Detail: "not installed, will install"}
|
|
}
|
|
|
|
logger.WriteString("$ docker info\n")
|
|
cmd := exec.Command("docker", "info")
|
|
if err := cmd.Run(); err != nil {
|
|
logger.WriteString("⚠ Docker daemon not running\n")
|
|
return CheckResult{Passed: true, Warning: true, Detail: "daemon not running for this user, might need sudo to detect or add current user to `docker` group"}
|
|
}
|
|
|
|
logger.WriteString("✓ Docker is running\n")
|
|
return CheckResult{Passed: true, Detail: "Docker is running"}
|
|
}
|
|
|
|
func checkDockerCompose() CheckResult {
|
|
logger := GetLogger()
|
|
logger.WriteString("Checking for Docker Compose...\n")
|
|
|
|
_, err := exec.LookPath("docker-compose")
|
|
if err == nil {
|
|
logger.WriteString("✓ docker-compose available\n")
|
|
return CheckResult{Passed: true, Detail: "docker-compose available"}
|
|
}
|
|
|
|
logger.WriteString("$ docker compose version\n")
|
|
cmd := exec.Command("docker", "compose", "version")
|
|
if err := cmd.Run(); err == nil {
|
|
logger.WriteString("✓ docker compose available\n")
|
|
return CheckResult{Passed: true, Detail: "docker compose available"}
|
|
}
|
|
|
|
logger.WriteString("⚠ Docker Compose not found, will be installed\n")
|
|
return CheckResult{Passed: true, Warning: true, Detail: "not installed, will install"}
|
|
}
|
|
|
|
func checkMemory() CheckResult {
|
|
logger := GetLogger()
|
|
logger.WriteString("Checking system memory...\n")
|
|
|
|
scale := int64(1024 * 1024)
|
|
cmd := exec.Command("sh", "-c", "grep MemTotal /proc/meminfo | awk '{print $2}'")
|
|
out, err := cmd.Output()
|
|
logger.Debug("Memory check /proc/meminfo: out=%q, err=%v", strings.TrimSpace(string(out)), err)
|
|
|
|
if err != nil || string(out) == "" {
|
|
scale = int64(1024 * 1024 * 1024)
|
|
logger.WriteString("$ sysctl -n hw.memsize\n")
|
|
cmd = exec.Command("sysctl", "-n", "hw.memsize")
|
|
out, err = cmd.Output()
|
|
logger.Debug("Memory check sysctl: out=%q, err=%v", strings.TrimSpace(string(out)), err)
|
|
|
|
if err != nil || string(out) == "" {
|
|
logger.WriteString("⚠ Could not check memory\n")
|
|
return CheckResult{Passed: true, Warning: true, Detail: "Could not check memory"}
|
|
}
|
|
}
|
|
|
|
memKB, _ := strconv.ParseInt(strings.TrimSpace(string(out)), 10, 64)
|
|
memGB := memKB / scale
|
|
logger.Debug("Memory: raw=%d, scale=%d, GB=%d", memKB, scale, memGB)
|
|
logger.WriteString(fmt.Sprintf("Memory: %dGB\n", memGB))
|
|
|
|
if memGB < 8 {
|
|
return CheckResult{Passed: true, Warning: true, Detail: fmt.Sprintf("%dGB (8GB+ recommended)", memGB)}
|
|
}
|
|
return CheckResult{Passed: true, Detail: fmt.Sprintf("%dGB available", memGB)}
|
|
}
|
|
|
|
func checkDiskSpace() CheckResult {
|
|
logger := GetLogger()
|
|
logger.WriteString("$ df -h .\n")
|
|
|
|
cmd := exec.Command("df", "-h", ".")
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
logger.WriteString("⚠ Could not check disk space\n")
|
|
return CheckResult{Passed: true, Warning: true, Detail: "Could not check disk space"}
|
|
}
|
|
|
|
lines := strings.Split(string(out), "\n")
|
|
if len(lines) < 2 {
|
|
return CheckResult{Passed: true, Warning: true, Detail: "Could not parse disk info"}
|
|
}
|
|
|
|
fields := strings.Fields(lines[1])
|
|
if len(fields) >= 4 {
|
|
available := fields[3]
|
|
logger.WriteString(fmt.Sprintf("Disk available: %s\n", available))
|
|
return CheckResult{Passed: true, Detail: fmt.Sprintf("%s available", available)}
|
|
}
|
|
|
|
return CheckResult{Passed: true, Detail: "OK"}
|
|
}
|
|
|
|
func checkNetwork() CheckResult {
|
|
logger := GetLogger()
|
|
logger.WriteString("$ curl -s https://github.com\n")
|
|
|
|
cmd := exec.Command("curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "--connect-timeout", "5", "https://github.com")
|
|
out, err := cmd.Output()
|
|
httpCode := strings.TrimSpace(string(out))
|
|
logger.Debug("Network check: http_code=%q, err=%v", httpCode, err)
|
|
|
|
if err != nil || httpCode != "200" {
|
|
logger.WriteString("✗ Cannot reach github.com\n")
|
|
return CheckResult{Passed: false, Err: fmt.Errorf("cannot reach github.com")}
|
|
}
|
|
logger.WriteString("✓ Connected to github.com\n")
|
|
return CheckResult{Passed: true, Detail: "Connected"}
|
|
}
|
|
|
|
func checkDockerVolumes() CheckResult {
|
|
logger := GetLogger()
|
|
|
|
if !DirExists("insights") {
|
|
logger.Debug("insights directory not found, skipping volume check")
|
|
logger.WriteString("New installation, skipping volume check\n")
|
|
return CheckResult{Passed: true, Detail: "new install"}
|
|
}
|
|
|
|
logger.WriteString("Checking for named Docker volumes...\n")
|
|
hasPostgres, hasDatastore := CheckDockerVolumes()
|
|
logger.Debug("Docker volumes: postgres=%v, datastore=%v", hasPostgres, hasDatastore)
|
|
|
|
if hasPostgres && hasDatastore {
|
|
logger.WriteString("✓ Named volumes found\n")
|
|
return CheckResult{Passed: true, Detail: "postgres-data, datastore-data"}
|
|
}
|
|
|
|
warning := GetVolumeWarning()
|
|
logger.Debug("Volume warning: %q", warning)
|
|
if warning != "" {
|
|
logger.WriteString("⚠ " + warning + "\n")
|
|
return CheckResult{Passed: true, Warning: true, Detail: "volumes may be anonymous (pre-1.39)"}
|
|
}
|
|
|
|
return CheckResult{Passed: true, Detail: "OK"}
|
|
}
|