150 lines
4.1 KiB
Go
150 lines
4.1 KiB
Go
|
|
package meshagent
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"crypto/tls"
|
||
|
|
"fmt"
|
||
|
|
"io"
|
||
|
|
"log"
|
||
|
|
"net/http"
|
||
|
|
"os"
|
||
|
|
"os/exec"
|
||
|
|
"path/filepath"
|
||
|
|
"runtime"
|
||
|
|
"strings"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// IsInstalled prüft ob der MeshAgent-Prozess läuft oder das Binary vorhanden ist.
|
||
|
|
func IsInstalled() bool {
|
||
|
|
if runtime.GOOS == "windows" {
|
||
|
|
// Prüfe ob MeshAgent Service läuft
|
||
|
|
cmd := exec.Command("sc", "query", "Mesh Agent")
|
||
|
|
return cmd.Run() == nil
|
||
|
|
}
|
||
|
|
// Linux: prüfe ob meshagent Prozess läuft
|
||
|
|
cmd := exec.Command("pgrep", "-x", "meshagent")
|
||
|
|
return cmd.Run() == nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// Install lädt den MeshAgent von MeshCentral herunter und installiert ihn.
|
||
|
|
// meshCentralUrl: z.B. "https://192.168.1.100:4430"
|
||
|
|
func Install(ctx context.Context, meshCentralUrl string) error {
|
||
|
|
if IsInstalled() {
|
||
|
|
log.Println("MeshAgent ist bereits installiert")
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
log.Printf("MeshAgent wird von %s heruntergeladen...", meshCentralUrl)
|
||
|
|
|
||
|
|
// Agent-ID je nach OS
|
||
|
|
agentID := "6" // Linux x64
|
||
|
|
if runtime.GOOS == "windows" {
|
||
|
|
agentID = "3" // Windows x64
|
||
|
|
}
|
||
|
|
|
||
|
|
downloadUrl := fmt.Sprintf("%s/meshagents?id=%s", strings.TrimRight(meshCentralUrl, "/"), agentID)
|
||
|
|
|
||
|
|
// SSL-Fehler ignorieren (selbstsigniertes Zertifikat in Dev)
|
||
|
|
httpClient := &http.Client{
|
||
|
|
Timeout: 5 * time.Minute,
|
||
|
|
Transport: &http.Transport{
|
||
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, downloadUrl, nil)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("HTTP Request konnte nicht erstellt werden: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
resp, err := httpClient.Do(req)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("Download fehlgeschlagen: %w", err)
|
||
|
|
}
|
||
|
|
defer resp.Body.Close()
|
||
|
|
|
||
|
|
if resp.StatusCode != http.StatusOK {
|
||
|
|
return fmt.Errorf("MeshCentral antwortete mit Status %d — ist MeshCentral gestartet?", resp.StatusCode)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Temp-Datei speichern
|
||
|
|
var tmpPath string
|
||
|
|
if runtime.GOOS == "windows" {
|
||
|
|
tmpPath = filepath.Join(os.TempDir(), "meshagent.exe")
|
||
|
|
} else {
|
||
|
|
tmpPath = filepath.Join(os.TempDir(), "meshagent")
|
||
|
|
}
|
||
|
|
|
||
|
|
f, err := os.OpenFile(tmpPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("Temp-Datei konnte nicht erstellt werden: %w", err)
|
||
|
|
}
|
||
|
|
if _, err := io.Copy(f, resp.Body); err != nil {
|
||
|
|
f.Close()
|
||
|
|
return fmt.Errorf("Fehler beim Schreiben: %w", err)
|
||
|
|
}
|
||
|
|
f.Close()
|
||
|
|
|
||
|
|
log.Printf("MeshAgent heruntergeladen nach %s", tmpPath)
|
||
|
|
|
||
|
|
// Installieren
|
||
|
|
return installBinary(ctx, tmpPath, meshCentralUrl)
|
||
|
|
}
|
||
|
|
|
||
|
|
func installBinary(ctx context.Context, binaryPath, meshCentralUrl string) error {
|
||
|
|
if runtime.GOOS == "windows" {
|
||
|
|
// Windows: als Service installieren
|
||
|
|
cmd := exec.CommandContext(ctx, binaryPath, "-install", "-url", meshCentralUrl)
|
||
|
|
cmd.Stdout = os.Stdout
|
||
|
|
cmd.Stderr = os.Stderr
|
||
|
|
if err := cmd.Run(); err != nil {
|
||
|
|
return fmt.Errorf("MeshAgent Windows-Installation fehlgeschlagen: %w", err)
|
||
|
|
}
|
||
|
|
log.Println("MeshAgent als Windows Service installiert")
|
||
|
|
} else {
|
||
|
|
// Linux: in /usr/local/bin installieren und als Service starten
|
||
|
|
installPath := "/usr/local/bin/meshagent"
|
||
|
|
if err := os.Rename(binaryPath, installPath); err != nil {
|
||
|
|
// Falls rename scheitert (cross-device), kopieren
|
||
|
|
if err2 := copyFile(binaryPath, installPath); err2 != nil {
|
||
|
|
return fmt.Errorf("MeshAgent konnte nicht nach %s verschoben werden: %w", installPath, err2)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if err := os.Chmod(installPath, 0755); err != nil {
|
||
|
|
return fmt.Errorf("chmod fehlgeschlagen: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Als Service starten (systemd oder direkt)
|
||
|
|
cmd := exec.CommandContext(ctx, installPath, "-install", "-url", meshCentralUrl)
|
||
|
|
cmd.Stdout = os.Stdout
|
||
|
|
cmd.Stderr = os.Stderr
|
||
|
|
if err := cmd.Run(); err != nil {
|
||
|
|
// Direkt starten als Fallback
|
||
|
|
log.Printf("Service-Installation fehlgeschlagen, starte direkt: %v", err)
|
||
|
|
go func() {
|
||
|
|
exec.Command(installPath, "-url", meshCentralUrl).Run()
|
||
|
|
}()
|
||
|
|
}
|
||
|
|
log.Println("MeshAgent auf Linux installiert")
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func copyFile(src, dst string) error {
|
||
|
|
srcFile, err := os.Open(src)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
defer srcFile.Close()
|
||
|
|
|
||
|
|
dstFile, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
defer dstFile.Close()
|
||
|
|
|
||
|
|
_, err = io.Copy(dstFile, srcFile)
|
||
|
|
return err
|
||
|
|
}
|