chore: add logparser logic for agent and add parsed log to clickhouse
ci-agent / build (push) Failing after 3m30s

This commit is contained in:
d3m0k1d
2026-04-04 06:29:07 +03:00
parent c59d122e04
commit 477dd94227
16 changed files with 1226 additions and 409 deletions
+38 -28
View File
@@ -10,6 +10,7 @@ import (
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/docs"
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/config"
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/grpcsrv/collector"
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/grpcsrv/commander"
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/handlers"
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/repository"
@@ -57,9 +58,34 @@ func main() {
log.Printf("Warning: failed to initialize jobs table: %v", err)
}
// Initialize ClickHouse and log repository
var logRepo *repository.LogRepository
if cfg.Database.Clickhouse_host != "" {
chConn, err := storage.OpenClickHouse(storage.ClickHouseConfig{
Host: cfg.Database.Clickhouse_host,
User: cfg.Database.Clickhouse_user,
Password: cfg.Database.Clickhouse_password,
Database: cfg.Database.Clickhouse_database,
})
if err != nil {
log.Printf("Warning: ClickHouse connection failed: %v", err)
} else {
logRepo = repository.NewLogRepository(chConn)
if err := logRepo.Init(context.Background()); err != nil {
log.Printf("Warning: Failed to initialize logs table: %v", err)
} else {
log.Println("ClickHouse connected successfully")
}
defer chConn.Close()
}
}
// Initialize Collector gRPC service
coll := collector.New(logRepo)
cmdr := commander.New(jobRepo)
agents := handlers.NewAgentsGroup(h, cmdr)
agents := handlers.NewAgentsGroup(h, coll)
auth := handlers.AuthGroup{Handlers: h}
agentReg := handlers.NewAgentRegistrationGroup(h)
agentDeploy := handlers.NewAgentDeployGroup(h)
@@ -117,13 +143,13 @@ func main() {
authTokenGroup.GET("/tokens", handlers.RequireAdmin(), auth.ListTokens)
authTokenGroup.DELETE("/token", auth.DeleteMyToken)
authTokenGroup.DELETE("/tokens/:login", handlers.RequireAdmin(), auth.DeleteToken)
// User management (admin only) - Full CRUD
authTokenGroup.GET("/users/:login", handlers.RequireAdmin(), auth.GetUser)
authTokenGroup.PUT("/users/:login", handlers.RequireAdmin(), auth.UpdateUser)
authTokenGroup.PUT("/users/:login/permissions", handlers.RequireAdmin(), auth.UpdateUserPermissions)
authTokenGroup.PUT("/users/:login/password", handlers.RequireAdmin(), auth.ResetUserPassword)
// User activation management (admin only)
authTokenGroup.POST("/users/:login/activate", handlers.RequireAdmin(), auth.ActivateUser)
authTokenGroup.POST("/users/:login/deactivate", handlers.RequireAdmin(), auth.DeactivateUser)
@@ -157,31 +183,14 @@ func main() {
mockLogHandlers := handlers.NewLogHandlers(nil)
logsGroup.GET("/mock", mockLogHandlers.GetMockLogs)
if cfg.Database.Clickhouse_host != "" {
chConn, err := storage.OpenClickHouse(storage.ClickHouseConfig{
Host: cfg.Database.Clickhouse_host,
User: cfg.Database.Clickhouse_user,
Password: cfg.Database.Clickhouse_password,
Database: cfg.Database.Clickhouse_database,
})
if err != nil {
log.Printf("Warning: ClickHouse connection failed: %v", err)
} else {
defer chConn.Close()
logRepo := repository.NewLogRepository(chConn)
if err := logRepo.Init(context.Background()); err != nil {
log.Printf("Warning: Failed to initialize logs table: %v", err)
}
logHandlers := handlers.NewLogHandlers(logRepo)
logsGroup.POST("", logHandlers.Insert)
logsGroup.POST("/batch", logHandlers.InsertBatch)
logsGroup.GET("", logHandlers.Search)
logsGroup.GET("/services", logHandlers.GetServices)
logsGroup.GET("/agents", logHandlers.GetAgents)
logsGroup.GET("/levels", logHandlers.GetLevels)
}
if logRepo != nil {
logHandlers := handlers.NewLogHandlers(logRepo)
logsGroup.POST("", logHandlers.Insert)
logsGroup.POST("/batch", logHandlers.InsertBatch)
logsGroup.GET("", logHandlers.Search)
logsGroup.GET("/services", logHandlers.GetServices)
logsGroup.GET("/agents", logHandlers.GetAgents)
logsGroup.GET("/levels", logHandlers.GetLevels)
}
}
}
@@ -224,6 +233,7 @@ func main() {
grpcServer := grpc.NewServer(grpc.Creds(credentials.NewTLS(tlsConfig)))
proto.RegisterCommanderServer(grpcServer, cmdr)
proto.RegisterCollectorServer(grpcServer, coll)
lis, err := net.Listen("tcp", ":"+grpcPort)
if err != nil {
+127 -122
View File
@@ -31,7 +31,7 @@ const docTemplate = `{
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/handlers.AgentInfo"
"$ref": "#/definitions/internal_handlers.AgentInfo"
}
}
}
@@ -63,7 +63,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.DeployAgentsRequest"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployAgentsRequest"
}
}
],
@@ -71,7 +71,7 @@ const docTemplate = `{
"200": {
"description": "Deployment results with tokens for each server",
"schema": {
"$ref": "#/definitions/repository.DeployResponse"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployResponse"
}
},
"400": {
@@ -114,7 +114,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.RegisterRequest"
"$ref": "#/definitions/internal_handlers.RegisterRequest"
}
}
],
@@ -122,7 +122,7 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.RegisterResponse"
"$ref": "#/definitions/internal_handlers.RegisterResponse"
}
}
}
@@ -152,7 +152,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.RegistrationRequest"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.RegistrationRequest"
}
}
],
@@ -186,7 +186,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.LoginRequest"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginRequest"
}
}
],
@@ -194,7 +194,7 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/repository.LoginResponse"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginResponse"
}
},
"400": {
@@ -244,7 +244,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.TokenCreate"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenCreate"
}
}
],
@@ -340,7 +340,7 @@ const docTemplate = `{
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/repository.Tokens"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens"
}
}
},
@@ -426,7 +426,7 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/repository.Tokens"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens"
}
},
"400": {
@@ -481,7 +481,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.TokenUpdate"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenUpdate"
}
}
],
@@ -661,7 +661,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.TokenPasswordReset"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenPasswordReset"
}
}
],
@@ -729,7 +729,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.TokenUpdatePermissions"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenUpdatePermissions"
}
}
],
@@ -789,7 +789,7 @@ const docTemplate = `{
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/repository.Tokens"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens"
}
}
},
@@ -819,7 +819,7 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/repository.Tokens"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens"
}
},
"401": {
@@ -896,7 +896,7 @@ const docTemplate = `{
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/storage.LogEntry"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry"
}
}
}
@@ -921,7 +921,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.InsertLogRequest"
"$ref": "#/definitions/internal_handlers.InsertLogRequest"
}
}
],
@@ -981,7 +981,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.InsertLogsRequest"
"$ref": "#/definitions/internal_handlers.InsertLogsRequest"
}
}
],
@@ -1023,6 +1023,11 @@ const docTemplate = `{
},
"/logs/mock": {
"get": {
"security": [
{
"Bearer": []
}
],
"description": "Returns 100 mock log entries for frontend development (no ClickHouse required)",
"produces": [
"application/json"
@@ -1071,7 +1076,7 @@ const docTemplate = `{
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/storage.LogEntry"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry"
}
}
}
@@ -1103,90 +1108,7 @@ const docTemplate = `{
}
},
"definitions": {
"handlers.AgentInfo": {
"type": "object",
"properties": {
"label": {
"type": "string"
},
"services": {
"type": "array",
"items": {
"type": "string"
}
},
"token": {
"type": "string"
}
}
},
"handlers.InsertLogRequest": {
"type": "object",
"required": [
"agent",
"level",
"message",
"service"
],
"properties": {
"agent": {
"type": "string"
},
"level": {
"type": "string"
},
"message": {
"type": "string"
},
"service": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
},
"handlers.InsertLogsRequest": {
"type": "object",
"required": [
"logs"
],
"properties": {
"logs": {
"type": "array",
"items": {
"$ref": "#/definitions/handlers.InsertLogRequest"
}
}
}
},
"handlers.RegisterRequest": {
"type": "object",
"required": [
"csr",
"token"
],
"properties": {
"csr": {
"type": "string"
},
"token": {
"type": "string"
}
}
},
"handlers.RegisterResponse": {
"type": "object",
"properties": {
"ca_cert": {
"type": "string"
},
"client_cert": {
"type": "string"
}
}
},
"repository.AgentDeployConfig": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.AgentDeployConfig": {
"description": "Configuration for deploying HellreigN agent to a single server",
"type": "object",
"required": [
@@ -1204,7 +1126,7 @@ const docTemplate = `{
"authMethod": {
"allOf": [
{
"$ref": "#/definitions/repository.AuthMethod"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.AuthMethod"
}
],
"example": "key"
@@ -1212,7 +1134,7 @@ const docTemplate = `{
"deployType": {
"allOf": [
{
"$ref": "#/definitions/repository.DeployType"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployType"
}
],
"example": "docker"
@@ -1239,7 +1161,7 @@ const docTemplate = `{
}
}
},
"repository.AuthMethod": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.AuthMethod": {
"description": "SSH authentication method: key or password",
"type": "string",
"enum": [
@@ -1251,7 +1173,7 @@ const docTemplate = `{
"AuthMethodPassword"
]
},
"repository.DeployAgentsRequest": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployAgentsRequest": {
"description": "Request to deploy HellreigN agents to multiple servers",
"type": "object",
"required": [
@@ -1262,12 +1184,12 @@ const docTemplate = `{
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/definitions/repository.AgentDeployConfig"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.AgentDeployConfig"
}
}
}
},
"repository.DeployResponse": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployResponse": {
"description": "Response containing deployment results and registration tokens",
"type": "object",
"properties": {
@@ -1278,12 +1200,12 @@ const docTemplate = `{
"results": {
"type": "array",
"items": {
"$ref": "#/definitions/repository.DeployResult"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployResult"
}
}
}
},
"repository.DeployResult": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployResult": {
"description": "Result of deploying to a single server",
"type": "object",
"properties": {
@@ -1309,7 +1231,7 @@ const docTemplate = `{
}
}
},
"repository.DeployType": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployType": {
"description": "Type of deployment: docker or binary",
"type": "string",
"enum": [
@@ -1321,7 +1243,7 @@ const docTemplate = `{
"DeployTypeBinary"
]
},
"repository.LoginRequest": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginRequest": {
"type": "object",
"required": [
"login",
@@ -1336,7 +1258,7 @@ const docTemplate = `{
}
}
},
"repository.LoginResponse": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginResponse": {
"type": "object",
"properties": {
"is_active": {
@@ -1365,7 +1287,7 @@ const docTemplate = `{
}
}
},
"repository.RegistrationRequest": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.RegistrationRequest": {
"type": "object",
"required": [
"label"
@@ -1376,7 +1298,7 @@ const docTemplate = `{
}
}
},
"repository.TokenCreate": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenCreate": {
"type": "object",
"required": [
"last_name",
@@ -1411,7 +1333,7 @@ const docTemplate = `{
}
}
},
"repository.TokenPasswordReset": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenPasswordReset": {
"type": "object",
"required": [
"new_password"
@@ -1422,7 +1344,7 @@ const docTemplate = `{
}
}
},
"repository.TokenUpdate": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenUpdate": {
"type": "object",
"properties": {
"last_name": {
@@ -1433,7 +1355,7 @@ const docTemplate = `{
}
}
},
"repository.TokenUpdatePermissions": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenUpdatePermissions": {
"type": "object",
"properties": {
"is_active": {
@@ -1450,7 +1372,7 @@ const docTemplate = `{
}
}
},
"repository.Tokens": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens": {
"type": "object",
"properties": {
"id": {
@@ -1482,7 +1404,7 @@ const docTemplate = `{
}
}
},
"storage.LogEntry": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry": {
"type": "object",
"properties": {
"agent": {
@@ -1501,6 +1423,89 @@ const docTemplate = `{
"type": "string"
}
}
},
"internal_handlers.AgentInfo": {
"type": "object",
"properties": {
"label": {
"type": "string"
},
"services": {
"type": "array",
"items": {
"type": "string"
}
},
"token": {
"type": "string"
}
}
},
"internal_handlers.InsertLogRequest": {
"type": "object",
"required": [
"agent",
"level",
"message",
"service"
],
"properties": {
"agent": {
"type": "string"
},
"level": {
"type": "string"
},
"message": {
"type": "string"
},
"service": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
},
"internal_handlers.InsertLogsRequest": {
"type": "object",
"required": [
"logs"
],
"properties": {
"logs": {
"type": "array",
"items": {
"$ref": "#/definitions/internal_handlers.InsertLogRequest"
}
}
}
},
"internal_handlers.RegisterRequest": {
"type": "object",
"required": [
"csr",
"token"
],
"properties": {
"csr": {
"type": "string"
},
"token": {
"type": "string"
}
}
},
"internal_handlers.RegisterResponse": {
"type": "object",
"properties": {
"ca_cert": {
"type": "string"
},
"client_cert": {
"type": "string"
}
}
}
},
"securityDefinitions": {
+127 -122
View File
@@ -20,7 +20,7 @@
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/handlers.AgentInfo"
"$ref": "#/definitions/internal_handlers.AgentInfo"
}
}
}
@@ -52,7 +52,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.DeployAgentsRequest"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployAgentsRequest"
}
}
],
@@ -60,7 +60,7 @@
"200": {
"description": "Deployment results with tokens for each server",
"schema": {
"$ref": "#/definitions/repository.DeployResponse"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployResponse"
}
},
"400": {
@@ -103,7 +103,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.RegisterRequest"
"$ref": "#/definitions/internal_handlers.RegisterRequest"
}
}
],
@@ -111,7 +111,7 @@
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.RegisterResponse"
"$ref": "#/definitions/internal_handlers.RegisterResponse"
}
}
}
@@ -141,7 +141,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.RegistrationRequest"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.RegistrationRequest"
}
}
],
@@ -175,7 +175,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.LoginRequest"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginRequest"
}
}
],
@@ -183,7 +183,7 @@
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/repository.LoginResponse"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginResponse"
}
},
"400": {
@@ -233,7 +233,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.TokenCreate"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenCreate"
}
}
],
@@ -329,7 +329,7 @@
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/repository.Tokens"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens"
}
}
},
@@ -415,7 +415,7 @@
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/repository.Tokens"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens"
}
},
"400": {
@@ -470,7 +470,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.TokenUpdate"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenUpdate"
}
}
],
@@ -650,7 +650,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.TokenPasswordReset"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenPasswordReset"
}
}
],
@@ -718,7 +718,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repository.TokenUpdatePermissions"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenUpdatePermissions"
}
}
],
@@ -778,7 +778,7 @@
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/repository.Tokens"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens"
}
}
},
@@ -808,7 +808,7 @@
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/repository.Tokens"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens"
}
},
"401": {
@@ -885,7 +885,7 @@
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/storage.LogEntry"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry"
}
}
}
@@ -910,7 +910,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.InsertLogRequest"
"$ref": "#/definitions/internal_handlers.InsertLogRequest"
}
}
],
@@ -970,7 +970,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.InsertLogsRequest"
"$ref": "#/definitions/internal_handlers.InsertLogsRequest"
}
}
],
@@ -1012,6 +1012,11 @@
},
"/logs/mock": {
"get": {
"security": [
{
"Bearer": []
}
],
"description": "Returns 100 mock log entries for frontend development (no ClickHouse required)",
"produces": [
"application/json"
@@ -1060,7 +1065,7 @@
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/storage.LogEntry"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry"
}
}
}
@@ -1092,90 +1097,7 @@
}
},
"definitions": {
"handlers.AgentInfo": {
"type": "object",
"properties": {
"label": {
"type": "string"
},
"services": {
"type": "array",
"items": {
"type": "string"
}
},
"token": {
"type": "string"
}
}
},
"handlers.InsertLogRequest": {
"type": "object",
"required": [
"agent",
"level",
"message",
"service"
],
"properties": {
"agent": {
"type": "string"
},
"level": {
"type": "string"
},
"message": {
"type": "string"
},
"service": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
},
"handlers.InsertLogsRequest": {
"type": "object",
"required": [
"logs"
],
"properties": {
"logs": {
"type": "array",
"items": {
"$ref": "#/definitions/handlers.InsertLogRequest"
}
}
}
},
"handlers.RegisterRequest": {
"type": "object",
"required": [
"csr",
"token"
],
"properties": {
"csr": {
"type": "string"
},
"token": {
"type": "string"
}
}
},
"handlers.RegisterResponse": {
"type": "object",
"properties": {
"ca_cert": {
"type": "string"
},
"client_cert": {
"type": "string"
}
}
},
"repository.AgentDeployConfig": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.AgentDeployConfig": {
"description": "Configuration for deploying HellreigN agent to a single server",
"type": "object",
"required": [
@@ -1193,7 +1115,7 @@
"authMethod": {
"allOf": [
{
"$ref": "#/definitions/repository.AuthMethod"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.AuthMethod"
}
],
"example": "key"
@@ -1201,7 +1123,7 @@
"deployType": {
"allOf": [
{
"$ref": "#/definitions/repository.DeployType"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployType"
}
],
"example": "docker"
@@ -1228,7 +1150,7 @@
}
}
},
"repository.AuthMethod": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.AuthMethod": {
"description": "SSH authentication method: key or password",
"type": "string",
"enum": [
@@ -1240,7 +1162,7 @@
"AuthMethodPassword"
]
},
"repository.DeployAgentsRequest": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployAgentsRequest": {
"description": "Request to deploy HellreigN agents to multiple servers",
"type": "object",
"required": [
@@ -1251,12 +1173,12 @@
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/definitions/repository.AgentDeployConfig"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.AgentDeployConfig"
}
}
}
},
"repository.DeployResponse": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployResponse": {
"description": "Response containing deployment results and registration tokens",
"type": "object",
"properties": {
@@ -1267,12 +1189,12 @@
"results": {
"type": "array",
"items": {
"$ref": "#/definitions/repository.DeployResult"
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployResult"
}
}
}
},
"repository.DeployResult": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployResult": {
"description": "Result of deploying to a single server",
"type": "object",
"properties": {
@@ -1298,7 +1220,7 @@
}
}
},
"repository.DeployType": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployType": {
"description": "Type of deployment: docker or binary",
"type": "string",
"enum": [
@@ -1310,7 +1232,7 @@
"DeployTypeBinary"
]
},
"repository.LoginRequest": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginRequest": {
"type": "object",
"required": [
"login",
@@ -1325,7 +1247,7 @@
}
}
},
"repository.LoginResponse": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginResponse": {
"type": "object",
"properties": {
"is_active": {
@@ -1354,7 +1276,7 @@
}
}
},
"repository.RegistrationRequest": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.RegistrationRequest": {
"type": "object",
"required": [
"label"
@@ -1365,7 +1287,7 @@
}
}
},
"repository.TokenCreate": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenCreate": {
"type": "object",
"required": [
"last_name",
@@ -1400,7 +1322,7 @@
}
}
},
"repository.TokenPasswordReset": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenPasswordReset": {
"type": "object",
"required": [
"new_password"
@@ -1411,7 +1333,7 @@
}
}
},
"repository.TokenUpdate": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenUpdate": {
"type": "object",
"properties": {
"last_name": {
@@ -1422,7 +1344,7 @@
}
}
},
"repository.TokenUpdatePermissions": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenUpdatePermissions": {
"type": "object",
"properties": {
"is_active": {
@@ -1439,7 +1361,7 @@
}
}
},
"repository.Tokens": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens": {
"type": "object",
"properties": {
"id": {
@@ -1471,7 +1393,7 @@
}
}
},
"storage.LogEntry": {
"gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry": {
"type": "object",
"properties": {
"agent": {
@@ -1490,6 +1412,89 @@
"type": "string"
}
}
},
"internal_handlers.AgentInfo": {
"type": "object",
"properties": {
"label": {
"type": "string"
},
"services": {
"type": "array",
"items": {
"type": "string"
}
},
"token": {
"type": "string"
}
}
},
"internal_handlers.InsertLogRequest": {
"type": "object",
"required": [
"agent",
"level",
"message",
"service"
],
"properties": {
"agent": {
"type": "string"
},
"level": {
"type": "string"
},
"message": {
"type": "string"
},
"service": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
},
"internal_handlers.InsertLogsRequest": {
"type": "object",
"required": [
"logs"
],
"properties": {
"logs": {
"type": "array",
"items": {
"$ref": "#/definitions/internal_handlers.InsertLogRequest"
}
}
}
},
"internal_handlers.RegisterRequest": {
"type": "object",
"required": [
"csr",
"token"
],
"properties": {
"csr": {
"type": "string"
},
"token": {
"type": "string"
}
}
},
"internal_handlers.RegisterResponse": {
"type": "object",
"properties": {
"ca_cert": {
"type": "string"
},
"client_cert": {
"type": "string"
}
}
}
},
"securityDefinitions": {
+96 -94
View File
@@ -1,60 +1,5 @@
definitions:
handlers.AgentInfo:
properties:
label:
type: string
services:
items:
type: string
type: array
token:
type: string
type: object
handlers.InsertLogRequest:
properties:
agent:
type: string
level:
type: string
message:
type: string
service:
type: string
timestamp:
type: string
required:
- agent
- level
- message
- service
type: object
handlers.InsertLogsRequest:
properties:
logs:
items:
$ref: '#/definitions/handlers.InsertLogRequest'
type: array
required:
- logs
type: object
handlers.RegisterRequest:
properties:
csr:
type: string
token:
type: string
required:
- csr
- token
type: object
handlers.RegisterResponse:
properties:
ca_cert:
type: string
client_cert:
type: string
type: object
repository.AgentDeployConfig:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.AgentDeployConfig:
description: Configuration for deploying HellreigN agent to a single server
properties:
agentLabel:
@@ -62,11 +7,11 @@ definitions:
type: string
authMethod:
allOf:
- $ref: '#/definitions/repository.AuthMethod'
- $ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.AuthMethod'
example: key
deployType:
allOf:
- $ref: '#/definitions/repository.DeployType'
- $ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployType'
example: docker
ip:
example: 192.168.1.100
@@ -90,7 +35,7 @@ definitions:
- ip
- user
type: object
repository.AuthMethod:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.AuthMethod:
description: 'SSH authentication method: key or password'
enum:
- key
@@ -99,18 +44,18 @@ definitions:
x-enum-varnames:
- AuthMethodKey
- AuthMethodPassword
repository.DeployAgentsRequest:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployAgentsRequest:
description: Request to deploy HellreigN agents to multiple servers
properties:
servers:
items:
$ref: '#/definitions/repository.AgentDeployConfig'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.AgentDeployConfig'
minItems: 1
type: array
required:
- servers
type: object
repository.DeployResponse:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployResponse:
description: Response containing deployment results and registration tokens
properties:
message:
@@ -118,10 +63,10 @@ definitions:
type: string
results:
items:
$ref: '#/definitions/repository.DeployResult'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployResult'
type: array
type: object
repository.DeployResult:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployResult:
description: Result of deploying to a single server
properties:
agent_label:
@@ -140,7 +85,7 @@ definitions:
example: abc123...
type: string
type: object
repository.DeployType:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployType:
description: 'Type of deployment: docker or binary'
enum:
- docker
@@ -149,7 +94,7 @@ definitions:
x-enum-varnames:
- DeployTypeDocker
- DeployTypeBinary
repository.LoginRequest:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginRequest:
properties:
login:
type: string
@@ -159,7 +104,7 @@ definitions:
- login
- password
type: object
repository.LoginResponse:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginResponse:
properties:
is_active:
type: boolean
@@ -178,14 +123,14 @@ definitions:
token:
type: string
type: object
repository.RegistrationRequest:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.RegistrationRequest:
properties:
label:
type: string
required:
- label
type: object
repository.TokenCreate:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenCreate:
properties:
is_active:
type: boolean
@@ -209,21 +154,21 @@ definitions:
- name
- password
type: object
repository.TokenPasswordReset:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenPasswordReset:
properties:
new_password:
type: string
required:
- new_password
type: object
repository.TokenUpdate:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenUpdate:
properties:
last_name:
type: string
name:
type: string
type: object
repository.TokenUpdatePermissions:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenUpdatePermissions:
properties:
is_active:
type: boolean
@@ -234,7 +179,7 @@ definitions:
permission_view:
type: boolean
type: object
repository.Tokens:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens:
properties:
id:
type: integer
@@ -255,7 +200,7 @@ definitions:
token:
type: string
type: object
storage.LogEntry:
gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry:
properties:
agent:
type: string
@@ -268,6 +213,61 @@ definitions:
timestamp:
type: string
type: object
internal_handlers.AgentInfo:
properties:
label:
type: string
services:
items:
type: string
type: array
token:
type: string
type: object
internal_handlers.InsertLogRequest:
properties:
agent:
type: string
level:
type: string
message:
type: string
service:
type: string
timestamp:
type: string
required:
- agent
- level
- message
- service
type: object
internal_handlers.InsertLogsRequest:
properties:
logs:
items:
$ref: '#/definitions/internal_handlers.InsertLogRequest'
type: array
required:
- logs
type: object
internal_handlers.RegisterRequest:
properties:
csr:
type: string
token:
type: string
required:
- csr
- token
type: object
internal_handlers.RegisterResponse:
properties:
ca_cert:
type: string
client_cert:
type: string
type: object
info:
contact: {}
paths:
@@ -281,7 +281,7 @@ paths:
description: OK
schema:
items:
$ref: '#/definitions/handlers.AgentInfo'
$ref: '#/definitions/internal_handlers.AgentInfo'
type: array
summary: Get connected agents
tags:
@@ -298,14 +298,14 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/repository.DeployAgentsRequest'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployAgentsRequest'
produces:
- application/json
responses:
"200":
description: Deployment results with tokens for each server
schema:
$ref: '#/definitions/repository.DeployResponse'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.DeployResponse'
"400":
description: Invalid request
schema:
@@ -333,14 +333,14 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/handlers.RegisterRequest'
$ref: '#/definitions/internal_handlers.RegisterRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.RegisterResponse'
$ref: '#/definitions/internal_handlers.RegisterResponse'
summary: Register agent
tags:
- agents
@@ -354,7 +354,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/repository.RegistrationRequest'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.RegistrationRequest'
produces:
- application/json
responses:
@@ -380,12 +380,12 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/repository.LoginRequest'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginRequest'
responses:
"200":
description: OK
schema:
$ref: '#/definitions/repository.LoginResponse'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.LoginResponse'
"400":
description: Bad Request
schema:
@@ -442,7 +442,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/repository.TokenCreate'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenCreate'
responses:
"200":
description: OK
@@ -481,7 +481,7 @@ paths:
description: OK
schema:
items:
$ref: '#/definitions/repository.Tokens'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens'
type: array
"500":
description: Internal Server Error
@@ -538,7 +538,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/repository.Tokens'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens'
"400":
description: Bad Request
schema:
@@ -575,7 +575,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/repository.TokenUpdate'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenUpdate'
responses:
"200":
description: OK
@@ -694,7 +694,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/repository.TokenPasswordReset'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenPasswordReset'
responses:
"200":
description: OK
@@ -739,7 +739,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/repository.TokenUpdatePermissions'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.TokenUpdatePermissions'
responses:
"200":
description: OK
@@ -778,7 +778,7 @@ paths:
description: OK
schema:
items:
$ref: '#/definitions/repository.Tokens'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens'
type: array
"500":
description: Internal Server Error
@@ -798,7 +798,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/repository.Tokens'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_repository.Tokens'
"401":
description: Unauthorized
schema:
@@ -849,7 +849,7 @@ paths:
description: OK
schema:
items:
$ref: '#/definitions/storage.LogEntry'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry'
type: array
summary: Search logs
tags:
@@ -864,7 +864,7 @@ paths:
name: body
required: true
schema:
$ref: '#/definitions/handlers.InsertLogRequest'
$ref: '#/definitions/internal_handlers.InsertLogRequest'
produces:
- application/json
responses:
@@ -903,7 +903,7 @@ paths:
name: body
required: true
schema:
$ref: '#/definitions/handlers.InsertLogsRequest'
$ref: '#/definitions/internal_handlers.InsertLogsRequest'
produces:
- application/json
responses:
@@ -965,8 +965,10 @@ paths:
description: OK
schema:
items:
$ref: '#/definitions/storage.LogEntry'
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_HellreigN_backend_internal_storage.LogEntry'
type: array
security:
- Bearer: []
summary: Get mock logs
tags:
- logs
@@ -0,0 +1,180 @@
package collector
import (
"fmt"
"io"
"log"
"sync"
"time"
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/repository"
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/storage"
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/proto/proto"
"google.golang.org/grpc/metadata"
)
type Collector struct {
proto.UnimplementedCollectorServer
logRepo *repository.LogRepository
agents map[string]*Agent
mu sync.RWMutex
batchSize int
flushInterval time.Duration
}
type Agent struct {
ID string
Label string
Services []string
ConnectedAt time.Time
}
func New(logRepo *repository.LogRepository) *Collector {
return &Collector{
logRepo: logRepo,
agents: make(map[string]*Agent),
batchSize: 100,
flushInterval: 2 * time.Second,
}
}
func (c *Collector) Stream(stream proto.Collector_StreamServer) error {
md, ok := metadata.FromIncomingContext(stream.Context())
if !ok {
return fmt.Errorf("no metadata in context")
}
whoamiVals := md["whoami"]
if len(whoamiVals) == 0 {
return fmt.Errorf("whoami metadata missing")
}
agentName := whoamiVals[0]
serviceVals := md["service"]
if len(serviceVals) == 0 {
return fmt.Errorf("service metadata missing")
}
service := serviceVals[0]
servicesVals := md["services"]
var services []string
if len(servicesVals) > 0 {
services = servicesVals
}
// Register agent
c.mu.Lock()
c.agents[agentName] = &Agent{
ID: agentName,
Label: agentName,
Services: services,
ConnectedAt: time.Now(),
}
c.mu.Unlock()
defer func() {
c.mu.Lock()
delete(c.agents, agentName)
c.mu.Unlock()
}()
log.Printf("Agent %s connected, streaming logs for service: %s", agentName, service)
// If no ClickHouse, just consume the stream without storing
if c.logRepo == nil {
log.Printf("Warning: logRepo is nil, consuming logs without storing for agent %s", agentName)
for {
_, err := stream.Recv()
if err == io.EOF {
return nil
}
if err != nil {
return fmt.Errorf("failed to receive: %w", err)
}
}
}
// Channels for communication with recv goroutine
recvCh := make(chan *proto.CollectorRequest, 1)
errCh := make(chan error, 1)
// Goroutine that blocks on Recv
go func() {
for {
req, err := stream.Recv()
if err != nil {
errCh <- err
return
}
recvCh <- req
}
}()
// Buffer for batch inserts
var batch []storage.LogEntry
ticker := time.NewTicker(c.flushInterval)
defer ticker.Stop()
flush := func() error {
if len(batch) == 0 {
return nil
}
if err := c.logRepo.InsertBatch(stream.Context(), batch); err != nil {
log.Printf("Failed to insert batch for agent %s, service %s: %v", agentName, service, err)
return err
}
log.Printf("Flushed %d logs for agent %s, service %s", len(batch), agentName, service)
batch = batch[:0]
return nil
}
for {
select {
case <-stream.Context().Done():
// Context cancelled, flush remaining
_ = flush()
return stream.Context().Err()
case <-ticker.C:
if err := flush(); err != nil {
return err
}
case req := <-recvCh:
batch = append(batch, storage.LogEntry{
Timestamp: time.Now(),
Level: "info",
Service: service,
Agent: agentName,
Message: req.Message,
})
if len(batch) >= c.batchSize {
if err := flush(); err != nil {
return err
}
}
case err := <-errCh:
if err == io.EOF {
// Client closed stream
return flush()
}
return fmt.Errorf("failed to receive: %w", err)
}
}
}
func (c *Collector) GetAgent(name string) (*Agent, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
a, ok := c.agents[name]
return a, ok
}
func (c *Collector) Agents() []*Agent {
c.mu.RLock()
defer c.mu.RUnlock()
result := make([]*Agent, 0, len(c.agents))
for _, a := range c.agents {
result = append(result, a)
}
return result
}
+16 -13
View File
@@ -1,41 +1,44 @@
package handlers
import (
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/grpcsrv/commander"
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/grpcsrv/collector"
"github.com/gin-gonic/gin"
"net/http"
)
type AgentsGroup struct {
*Handlers
cmder *commander.Commander
collector *collector.Collector
}
func NewAgentsGroup(h *Handlers, cmder *commander.Commander) AgentsGroup {
return AgentsGroup{Handlers: h, cmder: cmder}
func NewAgentsGroup(h *Handlers, coll *collector.Collector) AgentsGroup {
return AgentsGroup{Handlers: h, collector: coll}
}
type AgentInfo struct {
Token string `json:"token"`
Label string `json:"label"`
Services []string `json:"services"`
Token string `json:"token"`
Label string `json:"label"`
Services []string `json:"services"`
ConnectedAt string `json:"connected_at"`
}
// @Summary Get connected agents
// @Description Returns a list of all agents currently connected via gRPC streaming
// @Description Returns a list of all agents currently connected via Collector (log streaming)
// @Tags agents
// @Produce json
// @Success 200 {array} AgentInfo
// @Router /agents [get]
func (ag *AgentsGroup) List(c *gin.Context) {
agents := make([]AgentInfo, 0)
// iterate over the commander's agents map
for _, agent := range ag.cmder.Agents() {
for _, agent := range ag.collector.Agents() {
agents = append(agents, AgentInfo{
Token: agent.Token,
Label: agent.Label,
Services: agent.Services,
Token: agent.ID,
Label: agent.Label,
Services: agent.Services,
ConnectedAt: agent.ConnectedAt.Format("2006-01-02 15:04:05"),
})
}
c.JSON(http.StatusOK, agents)
}
+1
View File
@@ -21,6 +21,7 @@ import (
// @Param limit query int false "Limit results" default(100)
// @Param offset query int false "Offset results" default(0)
// @Success 200 {array} storage.LogEntry
// @Security Bearer
// @Router /logs/mock [get]
func (lh *LogHandlers) GetMockLogs(c *gin.Context) {
levelFilter := c.Query("level")