mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
194 lines
4.8 KiB
Go
194 lines
4.8 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/url"
|
|
"oneuptime-infrastructure-agent/model"
|
|
"oneuptime-infrastructure-agent/utils"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/go-co-op/gocron/v2"
|
|
)
|
|
|
|
type Agent struct {
|
|
SecretKey string
|
|
OneUptimeURL string
|
|
ProxyURL string
|
|
scheduler gocron.Scheduler
|
|
mainJob gocron.Job
|
|
shutdownHook Hook
|
|
}
|
|
|
|
func NewAgent(secretKey string, oneuptimeUrl string, proxyUrl string) *Agent {
|
|
|
|
ag := &Agent{
|
|
SecretKey: secretKey,
|
|
OneUptimeURL: oneuptimeUrl,
|
|
ProxyURL: proxyUrl,
|
|
}
|
|
|
|
slog.Info("Starting agent...")
|
|
slog.Info("Agent configuration:")
|
|
slog.Info("Secret key: " + ag.SecretKey)
|
|
slog.Info("OneUptime URL: " + ag.OneUptimeURL)
|
|
slog.Info("Proxy URL: " + ag.ProxyURL)
|
|
if ag.SecretKey == "" || ag.OneUptimeURL == "" {
|
|
slog.Error("Secret key and OneUptime URL are required")
|
|
os.Exit(1)
|
|
return ag
|
|
}
|
|
|
|
// check if secret key is valid
|
|
if !checkIfSecretKeyIsValid(ag.SecretKey, ag.OneUptimeURL, ag.ProxyURL) {
|
|
slog.Error("Secret key is invalid. If you are sure that the secret key is correct, please check your network connection, OneUptime URL (" + ag.OneUptimeURL + "), Proxy URL (" + ag.ProxyURL + ") and try again.")
|
|
os.Exit(1)
|
|
return ag
|
|
}
|
|
|
|
scheduler, err := gocron.NewScheduler()
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
os.Exit(1)
|
|
return ag
|
|
}
|
|
|
|
job, err := scheduler.NewJob(gocron.DurationJob(30*time.Second), gocron.NewTask(collectMetricsJob, ag.SecretKey, ag.OneUptimeURL, ag.ProxyURL))
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
os.Exit(1)
|
|
return ag
|
|
}
|
|
|
|
ag.scheduler = scheduler
|
|
ag.mainJob = job
|
|
|
|
return ag
|
|
}
|
|
|
|
func (ag *Agent) Start() {
|
|
ag.scheduler.Start()
|
|
err := ag.mainJob.RunNow()
|
|
if err != nil {
|
|
slog.Info(err.Error())
|
|
os.Exit(1)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (ag *Agent) Close() {
|
|
err := ag.scheduler.Shutdown()
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
}
|
|
}
|
|
|
|
func collectMetricsJob(secretKey string, oneuptimeUrl string, proxyUrl string) {
|
|
memMetrics := utils.GetMemoryMetrics()
|
|
if memMetrics == nil {
|
|
slog.Warn("Failed to get memory metrics")
|
|
}
|
|
|
|
cpuMetrics := utils.GetCpuMetrics()
|
|
if cpuMetrics == nil {
|
|
slog.Warn("Failed to get CPU metrics")
|
|
}
|
|
|
|
diskMetrics := utils.ListDiskMetrics()
|
|
if diskMetrics == nil {
|
|
slog.Warn("Failed to get disk metrics")
|
|
}
|
|
|
|
servProcesses := utils.GetServerProcesses()
|
|
if servProcesses == nil {
|
|
slog.Warn("Failed to get server processes")
|
|
}
|
|
|
|
metricsReport := &model.ServerMonitorReport{
|
|
SecretKey: secretKey,
|
|
BasicInfrastructureMetrics: &model.BasicInfrastructureMetrics{
|
|
MemoryMetrics: memMetrics,
|
|
CpuMetrics: cpuMetrics,
|
|
DiskMetrics: diskMetrics,
|
|
},
|
|
RequestReceivedAt: time.Now().UTC().Format("2006-01-02T15:04:05.000Z"),
|
|
OnlyCheckRequestReceivedAt: false,
|
|
Processes: servProcesses,
|
|
Hostname: utils.GetHostname(),
|
|
}
|
|
|
|
reqData := struct {
|
|
ServerMonitorResponse *model.ServerMonitorReport `json:"serverMonitorResponse"`
|
|
}{
|
|
ServerMonitorResponse: metricsReport,
|
|
}
|
|
reqBody, err := json.Marshal(reqData)
|
|
if err != nil {
|
|
slog.Error("Failed to marshal request data", "error", err)
|
|
return
|
|
}
|
|
|
|
client := &http.Client{}
|
|
|
|
if proxyUrl != "" {
|
|
proxyURL, _ := url.Parse(proxyUrl)
|
|
transport := &http.Transport{Proxy: http.ProxyURL(proxyURL)}
|
|
client = &http.Client{Transport: transport}
|
|
slog.Info("Using proxy to send request:" + proxyUrl)
|
|
}
|
|
|
|
resp, err := client.Post(oneuptimeUrl+"/server-monitor/response/ingest/"+secretKey, "application/json", bytes.NewBuffer(reqBody))
|
|
if err != nil {
|
|
slog.Error("Failed to send request to server", "error", err)
|
|
return
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode == http.StatusOK {
|
|
slog.Info("Metrics successfully pushed to OneUptime server", "status", resp.StatusCode, "endpoint", oneuptimeUrl+"/server-monitor/response/ingest/"+secretKey)
|
|
} else {
|
|
slog.Error("Failed to ingest metrics", "status_code", resp.StatusCode)
|
|
respBody, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
slog.Error("Failed to read error response body", "error", err)
|
|
} else {
|
|
slog.Error("Server response", "body", string(respBody))
|
|
}
|
|
}
|
|
}
|
|
|
|
func checkIfSecretKeyIsValid(secretKey string, oneuptimeUrl string, proxyUrl string) bool {
|
|
|
|
// if we have a proxy, we need to use that to make the request
|
|
|
|
client := &http.Client{}
|
|
|
|
if proxyUrl != "" {
|
|
proxyURL, _ := url.Parse(proxyUrl)
|
|
transport := &http.Transport{Proxy: http.ProxyURL(proxyURL)}
|
|
client = &http.Client{Transport: transport}
|
|
slog.Info("Using proxy to send request:" + proxyUrl)
|
|
}
|
|
|
|
if secretKey == "" {
|
|
slog.Error("Secret key is empty")
|
|
return false
|
|
}
|
|
resp, err := client.Get(oneuptimeUrl + "/server-monitor/secret-key/verify/" + secretKey)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return false
|
|
}
|
|
if resp.StatusCode != 200 {
|
|
slog.Error("Secret key verification failed with status code " + strconv.Itoa(resp.StatusCode))
|
|
return false
|
|
}
|
|
return true
|
|
}
|