mirror of
https://github.com/lorsanstand/HomeOps-Hub.git
synced 2026-06-19 14:25:16 +03:00
Merge remote-tracking branch 'origin/main' into feat/stream-hub
This commit is contained in:
+2
-1
@@ -1,2 +1,3 @@
|
|||||||
.env
|
.env
|
||||||
agent.dev.yaml
|
config.yaml
|
||||||
|
.idea
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
version: "2"
|
||||||
|
|
||||||
|
run:
|
||||||
|
# Сколько времени давать линтеру на проверку (для больших проектов лучше ставить 5m)
|
||||||
|
timeout: 3m
|
||||||
|
# Проверять ли тесты
|
||||||
|
tests: true
|
||||||
|
|
||||||
|
linters:
|
||||||
|
# Отключаем все по умолчанию, чтобы включить только нужные нам
|
||||||
|
disable-all: true
|
||||||
|
enable:
|
||||||
|
# --- ОБЯЗАТЕЛЬНЫЕ (База) ---
|
||||||
|
- errcheck # Проверяет, не забыл ли ты обработать ошибку (if err != nil)
|
||||||
|
- govet # Официальный инструмент Go, ищет подозрительные конструкции
|
||||||
|
- ineffassign # Находит переменные, которым присвоили значение, но не использовали
|
||||||
|
- staticcheck # Огромный набор проверок на логические ошибки
|
||||||
|
- unused # Ищет неиспользуемый код (функции, переменные, типы)
|
||||||
|
|
||||||
|
# --- ОБУЧАЮЩИЕ (Помогут новичку) ---
|
||||||
|
- revive # Замена старому golint: следит за именованием и комментариями
|
||||||
|
- errname # Проверяет, что ошибки названы по стандарту (например, ErrSentinel)
|
||||||
|
- goconst # Находит строки, которые часто повторяются (подскажет сделать константу)
|
||||||
|
- makezero # Следит, чтобы ты не делал лишних аллокаций в slice
|
||||||
|
|
||||||
|
settings:
|
||||||
|
revive:
|
||||||
|
# Настраиваем правила
|
||||||
|
rules:
|
||||||
|
# Отключаем обязательные комментарии для экспортируемых сущностей
|
||||||
|
- name: exported
|
||||||
|
disabled: true
|
||||||
|
# Отключаем требование комментариев к пакетам
|
||||||
|
- name: package-comments
|
||||||
|
disabled: true
|
||||||
|
# Оставляем полезное: проверка именования (var_name -> varName)
|
||||||
|
- name: var-naming
|
||||||
|
severity: warning
|
||||||
|
|
||||||
|
issues:
|
||||||
|
# Не ограничивай количество ошибок, пока учишься
|
||||||
|
max-issues-per-linter: 0
|
||||||
|
max-same-issues: 0
|
||||||
|
|
||||||
|
# Исключаем некоторые папки (например, сгенерированный код)
|
||||||
|
exclude-dirs:
|
||||||
|
- vendor
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="GoLinterSettings">
|
||||||
|
<option name="customConfigFile" value="$PROJECT_DIR$/.golangci.yml" />
|
||||||
|
<option name="useCustomConfigFile" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="AutoImportSettings">
|
||||||
|
<option name="autoReloadType" value="ALL" />
|
||||||
|
</component>
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="abe4019d-78ad-4b09-9aa4-c503fa264179" name="Changes" comment="">
|
||||||
|
<change beforePath="$PROJECT_DIR$/internal/hub/app/app.go" beforeDir="false" afterPath="$PROJECT_DIR$/internal/hub/app/app.go" afterDir="false" />
|
||||||
|
</list>
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="FileTemplateManagerImpl">
|
||||||
|
<option name="RECENT_TEMPLATES">
|
||||||
|
<list>
|
||||||
|
<option value="Go File" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="GOROOT" url="file:///usr/lib/go" />
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectColorInfo">{
|
||||||
|
"associatedIndex": 6
|
||||||
|
}</component>
|
||||||
|
<component name="ProjectId" id="3Bz7LjOuV8KsTCrmtXpgkPdosIV" />
|
||||||
|
<component name="ProjectViewState">
|
||||||
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
|
<option name="showLibraryContents" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent"><![CDATA[{
|
||||||
|
"keyToString": {
|
||||||
|
"DefaultGoTemplateProperty": "Go File",
|
||||||
|
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
||||||
|
"RunOnceActivity.GoLinterPluginOnboardingV2": "true",
|
||||||
|
"RunOnceActivity.GoLinterPluginStorageMigration": "true",
|
||||||
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
|
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
||||||
|
"RunOnceActivity.git.unshallow": "true",
|
||||||
|
"RunOnceActivity.go.analysis.ui.options.defaults": "true",
|
||||||
|
"RunOnceActivity.go.formatter.settings.were.checked": "true",
|
||||||
|
"RunOnceActivity.go.modules.go.list.on.any.changes.was.set": "true",
|
||||||
|
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
||||||
|
"git-widget-placeholder": "feat/register-agent",
|
||||||
|
"go.sdk.automatically.set": "true",
|
||||||
|
"last_opened_file_path": "/home/lorsan/projects/lazyssh",
|
||||||
|
"node.js.detected.package.eslint": "true",
|
||||||
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
|
"nodejs_package_manager_path": "npm",
|
||||||
|
"run.code.analysis.last.selected.profile": "pProject Default",
|
||||||
|
"settings.editor.selected.configurable": "preferences.lookFeel"
|
||||||
|
}
|
||||||
|
}]]></component>
|
||||||
|
<component name="RecentsManager">
|
||||||
|
<key name="MoveFile.RECENT_KEYS">
|
||||||
|
<recent name="$PROJECT_DIR$/internal" />
|
||||||
|
</key>
|
||||||
|
</component>
|
||||||
|
<component name="SharedIndexes">
|
||||||
|
<attachedChunks>
|
||||||
|
<set>
|
||||||
|
<option value="bundled-gosdk-72a9cf600ed8-dfa3e7267ae0-org.jetbrains.plugins.go.sharedIndexes.bundled-GO-253.30387.193" />
|
||||||
|
<option value="bundled-js-predefined-d6986cc7102b-9b0f141eb926-JavaScript-GO-253.30387.193" />
|
||||||
|
</set>
|
||||||
|
</attachedChunks>
|
||||||
|
</component>
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="abe4019d-78ad-4b09-9aa4-c503fa264179" name="Changes" comment="" />
|
||||||
|
<created>1775479991162</created>
|
||||||
|
<option name="number" value="Default" />
|
||||||
|
<option name="presentableId" value="Default" />
|
||||||
|
<updated>1775479991162</updated>
|
||||||
|
</task>
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
<option name="version" value="3" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/lorsanstand/HomeOps-Hub/internal/agent/app"
|
import (
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/agent/internal/app"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
start, err := app.NewApp()
|
start, err := app.NewApp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
panic(err)
|
||||||
}
|
}
|
||||||
start.Run()
|
start.Run()
|
||||||
}
|
}
|
||||||
@@ -5,13 +5,13 @@ import (
|
|||||||
standartlog "log"
|
standartlog "log"
|
||||||
|
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/agent/rpc"
|
"github.com/lorsanstand/HomeOps-Hub/agent/internal/rpc"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/agent/service/agent_service"
|
"github.com/lorsanstand/HomeOps-Hub/agent/internal/service/agent_service"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/agent/service/collector"
|
"github.com/lorsanstand/HomeOps-Hub/agent/internal/service/collector"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/agent/service/docker_service"
|
"github.com/lorsanstand/HomeOps-Hub/agent/internal/service/docker_service"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/agent/utils/config_yaml"
|
"github.com/lorsanstand/HomeOps-Hub/agent/internal/utils/config_yaml"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/agent/utils/settings"
|
"github.com/lorsanstand/HomeOps-Hub/agent/internal/utils/settings"
|
||||||
log2 "github.com/lorsanstand/HomeOps-Hub/internal/shared/log"
|
"github.com/lorsanstand/HomeOps-Hub/shared/log"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
@@ -25,23 +25,23 @@ type App struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewApp() (*App, error) {
|
func NewApp() (*App, error) {
|
||||||
|
|
||||||
cfg, err := config_yaml.NewConfig()
|
cfg, err := config_yaml.NewConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
standartlog.Fatalf("failed to get config: %v", err)
|
standartlog.Fatalf("failed to get config: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log := log2.NewLogger(cfg)
|
logger := log.NewLogger(cfg)
|
||||||
log = log.With().Str("component", "agent.app").Logger()
|
logger = logger.With().Str("component", "internal.app").Logger()
|
||||||
|
logger = logger.With().Str("name", cfg.AppName).Logger()
|
||||||
|
|
||||||
sett, err := settings.ReadSettings(cfg.SettingsPath)
|
sett, err := settings.ReadSettings(cfg.SettingsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("failed to get settings")
|
logger.Error().Err(err).Msg("failed to get settings")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &App{cfg: cfg, log: log, settings: sett}, nil
|
return &App{cfg: cfg, log: logger, settings: sett}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Run() {
|
func (a *App) Run() {
|
||||||
@@ -49,12 +49,17 @@ func (a *App) Run() {
|
|||||||
|
|
||||||
GRPCConn, err := grpc.NewClient(a.cfg.GetGRPCAddress(), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
GRPCConn, err := grpc.NewClient(a.cfg.GetGRPCAddress(), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.log.Error().Err(err).Msg("failed to get hub connections")
|
a.log.Error().Err(err).Msg("failed to connection hub")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
a.log.Info().Msg("connection to the hub successful")
|
||||||
|
|
||||||
conn := rpc.NewConnectAgent(GRPCConn, a.log)
|
conn := rpc.NewConnectAgent(GRPCConn)
|
||||||
defer conn.Close()
|
defer func() {
|
||||||
|
if err := conn.Close(); err != nil {
|
||||||
|
a.log.Warn().Err(err).Msg("failed to close rpc connection")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
var DockerService collector.Docker
|
var DockerService collector.Docker
|
||||||
|
|
||||||
@@ -63,11 +68,15 @@ func (a *App) Run() {
|
|||||||
a.log.Warn().Err(err).Msg("failed to get docker API")
|
a.log.Warn().Err(err).Msg("failed to get docker API")
|
||||||
DockerService = docker_service.NewBadDocker("not_installed")
|
DockerService = docker_service.NewBadDocker("not_installed")
|
||||||
} else {
|
} else {
|
||||||
|
a.log.Info().Msg("successfully to get docker API")
|
||||||
DockerService = docker_service.NewDockerService(DockerClient, a.log)
|
DockerService = docker_service.NewDockerService(DockerClient, a.log)
|
||||||
}
|
}
|
||||||
|
|
||||||
collect := collector.NewCollector(DockerService, a.log)
|
collect := collector.NewCollector(DockerService, a.log)
|
||||||
|
|
||||||
agent := agent_service.NewAgentService(collect, conn, a.settings, a.cfg, a.log)
|
agent := agent_service.NewAgentService(collect, conn, a.settings, a.cfg, a.log)
|
||||||
agent.RegisterAgentConn(ctx)
|
if err := agent.RegisterAgentConn(ctx); err != nil {
|
||||||
|
a.log.Error().Err(err).Msg("failed to agent registration")
|
||||||
|
}
|
||||||
|
a.log.Info().Msg("agent registration complete")
|
||||||
}
|
}
|
||||||
@@ -4,27 +4,21 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/domain"
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
"github.com/rs/zerolog"
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Connection struct {
|
type Connection struct {
|
||||||
hub pb.HubClient
|
hub pb.HubClient
|
||||||
conn *grpc.ClientConn
|
conn *grpc.ClientConn
|
||||||
log zerolog.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConnectAgent(conn *grpc.ClientConn, logger zerolog.Logger) *Connection {
|
func NewConnectAgent(conn *grpc.ClientConn) *Connection {
|
||||||
logger = logger.With().Str("component", "agent.rpc").Logger()
|
|
||||||
|
|
||||||
client := pb.NewHubClient(conn)
|
client := pb.NewHubClient(conn)
|
||||||
|
return &Connection{hub: client, conn: conn}
|
||||||
return &Connection{hub: client, conn: conn, log: logger}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Connection) Close() error {
|
func (c *Connection) Close() error {
|
||||||
c.log.Warn().Msg("connection close")
|
|
||||||
return c.conn.Close()
|
return c.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +28,5 @@ func (c *Connection) Hub() pb.HubClient {
|
|||||||
|
|
||||||
func (c *Connection) RegisterAgent(ctx context.Context, RegisterData domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error) {
|
func (c *Connection) RegisterAgent(ctx context.Context, RegisterData domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error) {
|
||||||
ResponseData, err := c.Hub().RegisterAgent(ctx, new(domain.ToGRPCAgentRequest(RegisterData)))
|
ResponseData, err := c.Hub().RegisterAgent(ctx, new(domain.ToGRPCAgentRequest(RegisterData)))
|
||||||
c.log.Info().Msg("register agent")
|
|
||||||
return domain.ToDomainAgentResponse(ResponseData), err
|
return domain.ToDomainAgentResponse(ResponseData), err
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package agent_service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/agent/internal/utils/config_yaml"
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Collector interface {
|
||||||
|
GatherInfoSystem() (domain.HostInfo, []domain.Capability)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Settings interface {
|
||||||
|
InsertAgentID(agentID string) error
|
||||||
|
GetAgentID() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type HubConnection interface {
|
||||||
|
RegisterAgent(ctx context.Context, RegisterData domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentService struct {
|
||||||
|
collect Collector
|
||||||
|
conn HubConnection
|
||||||
|
log zerolog.Logger
|
||||||
|
cfg *config_yaml.AgentConfig
|
||||||
|
heartBeat int
|
||||||
|
settings Settings
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAgentService(
|
||||||
|
collector Collector,
|
||||||
|
conn HubConnection,
|
||||||
|
settings Settings,
|
||||||
|
cfg *config_yaml.AgentConfig,
|
||||||
|
logger zerolog.Logger,
|
||||||
|
) *AgentService {
|
||||||
|
logger = logger.With().Str("component", "internal.service.agent_serivce").Logger()
|
||||||
|
|
||||||
|
return &AgentService{collect: collector, conn: conn, cfg: cfg, log: logger, settings: settings}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AgentService) RegisterAgentConn(ctx context.Context) error {
|
||||||
|
a.log.Debug().Msg("getting info by system")
|
||||||
|
info, caps := a.collect.GatherInfoSystem()
|
||||||
|
a.log.Debug().Msg("create request data for register agent")
|
||||||
|
AgentID := a.settings.GetAgentID()
|
||||||
|
AgentName := a.cfg.AppName
|
||||||
|
AgentData := domain.RegisterAgentRequest{
|
||||||
|
AgentID: AgentID,
|
||||||
|
AgentName: AgentName,
|
||||||
|
Host: info,
|
||||||
|
Capabilities: caps,
|
||||||
|
AgentVersion: a.cfg.GetAgentVersion(),
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := a.conn.RegisterAgent(ctx, AgentData)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("register agent: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = a.settings.InsertAgentID(data.AgentID); err != nil {
|
||||||
|
return fmt.Errorf("save agent ID: %w", err)
|
||||||
|
}
|
||||||
|
a.log.Info().Str("agentID", data.AgentID).Msg("agent registration end")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package agent_service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/agent/internal/utils/config_yaml"
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CollectorMock struct {
|
||||||
|
host domain.HostInfo
|
||||||
|
caps []domain.Capability
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CollectorMock) GatherInfoSystem() (domain.HostInfo, []domain.Capability) {
|
||||||
|
return c.host, c.caps
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectionMock struct {
|
||||||
|
regAgentErr error
|
||||||
|
regResp domain.RegisterAgentResponse
|
||||||
|
regData domain.RegisterAgentRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnectionMock) RegisterAgent(ctx context.Context, RegisterData domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error) {
|
||||||
|
c.regData = RegisterData
|
||||||
|
return c.regResp, c.regAgentErr
|
||||||
|
}
|
||||||
|
|
||||||
|
type SettingsMock struct {
|
||||||
|
insertErr error
|
||||||
|
agentID string
|
||||||
|
countUse int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SettingsMock) InsertAgentID(agentID string) error {
|
||||||
|
s.agentID = agentID
|
||||||
|
s.countUse++
|
||||||
|
return s.insertErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SettingsMock) GetAgentID() string {
|
||||||
|
return s.agentID
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAgentService_RegisterAgentConn(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
wantErr error
|
||||||
|
insertAgentIDUse int
|
||||||
|
settings SettingsMock
|
||||||
|
collector CollectorMock
|
||||||
|
conn ConnectionMock
|
||||||
|
cfg config_yaml.AgentConfig
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "success",
|
||||||
|
wantErr: nil,
|
||||||
|
insertAgentIDUse: 1,
|
||||||
|
settings: SettingsMock{agentID: "", insertErr: nil},
|
||||||
|
collector: CollectorMock{
|
||||||
|
host: domain.HostInfo{System: "Linux", Hostname: "test", Arch: "x64"},
|
||||||
|
caps: []domain.Capability{
|
||||||
|
{Available: true, Version: "0", Name: "testCaps", Reason: ""},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
conn: ConnectionMock{regAgentErr: nil, regResp: domain.RegisterAgentResponse{AgentID: "123", Heartbeat: 4}},
|
||||||
|
cfg: config_yaml.AgentConfig{AppName: "test"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
svc := NewAgentService(&tt.collector,
|
||||||
|
&tt.conn,
|
||||||
|
&tt.settings,
|
||||||
|
&tt.cfg,
|
||||||
|
zerolog.New(nil),
|
||||||
|
)
|
||||||
|
|
||||||
|
err := svc.RegisterAgentConn(ctx)
|
||||||
|
if !errors.Is(err, tt.wantErr) {
|
||||||
|
t.Fatalf("expected error %v, got: %v", tt.wantErr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.insertAgentIDUse != tt.settings.countUse {
|
||||||
|
t.Errorf("expected count insert agent id %v, got: %v", tt.insertAgentIDUse, tt.settings.countUse)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.settings.agentID != tt.conn.regResp.AgentID {
|
||||||
|
t.Errorf("expected insert agent id %v, got: %v", tt.conn.regResp.AgentID, tt.settings.agentID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.cfg.AppName != tt.conn.regData.AgentName {
|
||||||
|
t.Fatalf("expected agent name %v, got: %v", tt.cfg.AppName, tt.conn.regData.AgentName)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -4,7 +4,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/domain"
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ type Collector struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewCollector(docker Docker, logger zerolog.Logger) *Collector {
|
func NewCollector(docker Docker, logger zerolog.Logger) *Collector {
|
||||||
logger = logger.With().Str("component", "agent.service.collector").Logger()
|
logger = logger.With().Str("component", "internal.service.collector").Logger()
|
||||||
|
|
||||||
return &Collector{log: logger, dockerReader: docker}
|
return &Collector{log: logger, dockerReader: docker}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package docker_service
|
package docker_service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/domain"
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BadDocker struct {
|
type BadDocker struct {
|
||||||
+3
-3
@@ -5,7 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/domain"
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
)
|
)
|
||||||
@@ -23,13 +23,13 @@ type DockerService struct {
|
|||||||
func NewDockerService(api dockerAPI, logger zerolog.Logger) *DockerService {
|
func NewDockerService(api dockerAPI, logger zerolog.Logger) *DockerService {
|
||||||
return &DockerService{
|
return &DockerService{
|
||||||
dockerClient: api,
|
dockerClient: api,
|
||||||
log: logger.With().Str("component", "agent.serivce.docker").Logger(),
|
log: logger.With().Str("component", "internal.serivce.docker").Logger(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DockerService) CheckDockerDaemon(ctx context.Context) error {
|
func (d *DockerService) CheckDockerDaemon(ctx context.Context) error {
|
||||||
_, err := d.dockerClient.Ping(ctx)
|
_, err := d.dockerClient.Ping(ctx)
|
||||||
d.log.Debug().Msg("check docker")
|
d.log.Debug().Msg("ping docker")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
+5
-5
@@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testError error = errors.New("test")
|
var errTest error = errors.New("test")
|
||||||
|
|
||||||
type DockerMock struct {
|
type DockerMock struct {
|
||||||
pingErr error
|
pingErr error
|
||||||
@@ -46,11 +46,11 @@ func TestCheckDockerDaemon(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "docker error",
|
name: "docker error",
|
||||||
mock: DockerMock{
|
mock: DockerMock{
|
||||||
pingErr: testError,
|
pingErr: errTest,
|
||||||
containers: nil,
|
containers: nil,
|
||||||
containerErr: nil,
|
containerErr: nil,
|
||||||
},
|
},
|
||||||
wantErr: testError,
|
wantErr: errTest,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,10 +98,10 @@ func TestContainersList(t *testing.T) {
|
|||||||
mock: DockerMock{
|
mock: DockerMock{
|
||||||
pingErr: nil,
|
pingErr: nil,
|
||||||
containers: nil,
|
containers: nil,
|
||||||
containerErr: testError,
|
containerErr: errTest,
|
||||||
},
|
},
|
||||||
wantLen: 0,
|
wantLen: 0,
|
||||||
wantErr: testError,
|
wantErr: errTest,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "docker empty container",
|
name: "docker empty container",
|
||||||
+9
-2
@@ -8,6 +8,9 @@ import (
|
|||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const MODE = "DEV"
|
||||||
|
const AgentVersion = "0.0"
|
||||||
|
|
||||||
type AgentConfig struct {
|
type AgentConfig struct {
|
||||||
AppName string `yaml:"app_name"`
|
AppName string `yaml:"app_name"`
|
||||||
HubConnect struct {
|
HubConnect struct {
|
||||||
@@ -19,7 +22,7 @@ type AgentConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewConfig() (*AgentConfig, error) {
|
func NewConfig() (*AgentConfig, error) {
|
||||||
yamlFile, err := os.ReadFile("agent.dev.yaml")
|
yamlFile, err := os.ReadFile("config.yaml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed open file: %v", err)
|
return nil, fmt.Errorf("failed open file: %v", err)
|
||||||
}
|
}
|
||||||
@@ -42,7 +45,11 @@ func (c *AgentConfig) GetLogLevel() zerolog.Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *AgentConfig) GetMode() string {
|
func (c *AgentConfig) GetMode() string {
|
||||||
return "DEV"
|
return MODE
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *AgentConfig) GetAgentVersion() string {
|
||||||
|
return AgentVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AgentConfig) GetGRPCAddress() string {
|
func (c *AgentConfig) GetGRPCAddress() string {
|
||||||
+21
-5
@@ -13,7 +13,7 @@ type Settings struct {
|
|||||||
path string
|
path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadSettings(path string) (*Settings, error) {
|
func ReadSettings(path string) (sett *Settings, err error) {
|
||||||
if path == "" {
|
if path == "" {
|
||||||
homeDir, err := os.UserHomeDir()
|
homeDir, err := os.UserHomeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -22,7 +22,7 @@ func ReadSettings(path string) (*Settings, error) {
|
|||||||
path = filepath.Join(homeDir, ".config", "homeops")
|
path = filepath.Join(homeDir, ".config", "homeops")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := os.Mkdir(path, 0755)
|
err = os.Mkdir(path, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, os.ErrExist) {
|
if !errors.Is(err, os.ErrExist) {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -39,7 +39,12 @@ func ReadSettings(path string) (*Settings, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
defer file.Close()
|
defer func() {
|
||||||
|
closeErr := file.Close()
|
||||||
|
if err == nil {
|
||||||
|
err = closeErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
err = json.NewDecoder(file).Decode(&settings)
|
err = json.NewDecoder(file).Decode(&settings)
|
||||||
if err != nil && !errors.Is(err, io.EOF) {
|
if err != nil && !errors.Is(err, io.EOF) {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -51,12 +56,19 @@ func ReadSettings(path string) (*Settings, error) {
|
|||||||
return &settings, nil
|
return &settings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Settings) Insert(sett Settings) error {
|
func (s *Settings) InsertAgentID(agentID string) (err error) {
|
||||||
file, err := os.OpenFile(s.path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
file, err := os.OpenFile(s.path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer func() {
|
||||||
|
closeErr := file.Close()
|
||||||
|
if err == nil {
|
||||||
|
err = closeErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
sett := Settings{AgentID: agentID}
|
||||||
|
|
||||||
if err = json.NewEncoder(file).Encode(sett); err != nil {
|
if err = json.NewEncoder(file).Encode(sett); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -64,3 +76,7 @@ func (s *Settings) Insert(sett Settings) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Settings) GetAgentID() string {
|
||||||
|
return s.AgentID
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
package main
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/lorsanstand/HomeOps-Hub/internal/hub/app"
|
import (
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/hub/internal/app"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
start := app.NewApp()
|
start := app.NewApp()
|
||||||
@@ -8,13 +8,13 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
hubdir "github.com/lorsanstand/HomeOps-Hub/internal/hub"
|
hubdir "github.com/lorsanstand/HomeOps-Hub/hub/internal"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/hub/migrator"
|
"github.com/lorsanstand/HomeOps-Hub/hub/internal/migrator"
|
||||||
grpcserv "github.com/lorsanstand/HomeOps-Hub/internal/hub/rpc"
|
grpcserv "github.com/lorsanstand/HomeOps-Hub/hub/internal/rpc"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/hub/service/hub_service"
|
"github.com/lorsanstand/HomeOps-Hub/hub/internal/service/hub_service"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/hub/store"
|
"github.com/lorsanstand/HomeOps-Hub/hub/internal/store"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/shared/config"
|
"github.com/lorsanstand/HomeOps-Hub/shared/config"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/shared/log"
|
"github.com/lorsanstand/HomeOps-Hub/shared/log"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,6 +27,7 @@ func NewApp() *App {
|
|||||||
cfg, err := config.NewConfig()
|
cfg, err := config.NewConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
standartlog.Fatalf("failed get config: %v", err)
|
standartlog.Fatalf("failed get config: %v", err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
logger := log.NewLogger(cfg)
|
logger := log.NewLogger(cfg)
|
||||||
@@ -42,7 +43,6 @@ func (a *App) Run() {
|
|||||||
a.log.Error().Err(err).Msg("failed to connect to the database for migrations")
|
a.log.Error().Err(err).Msg("failed to connect to the database for migrations")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer migratePGConn.Close()
|
|
||||||
|
|
||||||
mgrt, err := migrator.NewMigrator(hubdir.MigrationsFS, "migrations")
|
mgrt, err := migrator.NewMigrator(hubdir.MigrationsFS, "migrations")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -56,7 +56,9 @@ func (a *App) Run() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
a.log.Info().Msg("migrations applied successfully")
|
a.log.Info().Msg("migrations applied successfully")
|
||||||
migratePGConn.Close()
|
if err := migratePGConn.Close(); err != nil {
|
||||||
|
a.log.Warn().Err(err).Msg("failed to close migrate postgres connection")
|
||||||
|
}
|
||||||
|
|
||||||
a.log.Info().Msg("creating database connection pool")
|
a.log.Info().Msg("creating database connection pool")
|
||||||
pool, err := pgxpool.New(ctx, a.cfg.GetURLPostgres())
|
pool, err := pgxpool.New(ctx, a.cfg.GetURLPostgres())
|
||||||
@@ -80,7 +82,6 @@ func (a *App) Run() {
|
|||||||
|
|
||||||
func (a *App) hubServe(hubService *hub_service.HubService) error {
|
func (a *App) hubServe(hubService *hub_service.HubService) error {
|
||||||
address := fmt.Sprintf("0.0.0.0:%v", a.cfg.Port)
|
address := fmt.Sprintf("0.0.0.0:%v", a.cfg.Port)
|
||||||
a.log.Info().Str("address", address).Msg("starting gRPC server")
|
|
||||||
|
|
||||||
server := grpcserv.NewHubHandler(hubService, a.log)
|
server := grpcserv.NewHubHandler(hubService, a.log)
|
||||||
|
|
||||||
@@ -3,7 +3,7 @@ package domain
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/domain"
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreateAgentModel struct {
|
type CreateAgentModel struct {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package hub
|
package internal
|
||||||
|
|
||||||
import "embed"
|
import "embed"
|
||||||
|
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"embed"
|
"embed"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
_ "github.com/jackc/pgx/v5/stdlib"
|
_ "github.com/jackc/pgx/v5/stdlib"
|
||||||
|
|
||||||
"github.com/golang-migrate/migrate/v4"
|
"github.com/golang-migrate/migrate/v4"
|
||||||
@@ -25,7 +26,7 @@ func NewMigrator(sqlFiles embed.FS, dirname string) (*Migrator, error) {
|
|||||||
return &Migrator{srcDriver: d}, nil
|
return &Migrator{srcDriver: d}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Migrator) ApplyMigrations(db *sql.DB) error {
|
func (m *Migrator) ApplyMigrations(db *sql.DB) (err error) {
|
||||||
driver, err := postgres.WithInstance(db, &postgres.Config{})
|
driver, err := postgres.WithInstance(db, &postgres.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create db instance: %w", err)
|
return fmt.Errorf("unable to create db instance: %w", err)
|
||||||
@@ -36,7 +37,12 @@ func (m *Migrator) ApplyMigrations(db *sql.DB) error {
|
|||||||
return fmt.Errorf("unable to create migration: %w", err)
|
return fmt.Errorf("unable to create migration: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer migrator.Close()
|
defer func() {
|
||||||
|
closeErr, _ := migrator.Close()
|
||||||
|
if err == nil {
|
||||||
|
err = closeErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if err = migrator.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) {
|
if err = migrator.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) {
|
||||||
return fmt.Errorf("unable to apply migrations: %w", err)
|
return fmt.Errorf("unable to apply migrations: %w", err)
|
||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/domain"
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/protobuf/types/known/emptypb"
|
"google.golang.org/protobuf/types/known/emptypb"
|
||||||
@@ -38,13 +38,13 @@ func (h *HubHandler) Ping(ctx context.Context, _ *emptypb.Empty) (*pb.PongRespon
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *HubHandler) RegisterAgent(ctx context.Context, request *pb.RegisterAgentRequest) (*pb.RegisterAgentResponse, error) {
|
func (h *HubHandler) RegisterAgent(ctx context.Context, request *pb.RegisterAgentRequest) (*pb.RegisterAgentResponse, error) {
|
||||||
h.log.Debug().Str("agentId", request.AgentId).Str("agentName", request.AgentName).Msg("register agent request received")
|
h.log.Debug().Str("agentID", request.AgentId).Str("agentName", request.AgentName).Msg("register agent request received")
|
||||||
data := domain.ToDomainAgentRequest(request)
|
data := domain.ToDomainAgentRequest(request)
|
||||||
resp, err := h.hub.RegisterAgent(ctx, data)
|
resp, err := h.hub.RegisterAgent(ctx, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.log.Error().Err(err).Str("agentId", request.AgentId).Msg("register agent request failed")
|
h.log.Error().Err(err).Str("agentID", request.AgentId).Msg("register agent request failed")
|
||||||
return domain.ToGRPCAgentResponse(resp), err
|
return domain.ToGRPCAgentResponse(resp), err
|
||||||
}
|
}
|
||||||
h.log.Debug().Str("agentId", resp.AgentID).Msg("register agent request completed")
|
h.log.Info().Str("agentID", resp.AgentID).Msg("register agent request completed")
|
||||||
return domain.ToGRPCAgentResponse(resp), nil
|
return domain.ToGRPCAgentResponse(resp), nil
|
||||||
}
|
}
|
||||||
@@ -6,12 +6,14 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/domain"
|
domainHub "github.com/lorsanstand/HomeOps-Hub/hub/internal/domain"
|
||||||
domainHub "github.com/lorsanstand/HomeOps-Hub/internal/hub/domain"
|
"github.com/lorsanstand/HomeOps-Hub/hub/internal/utils/hasher"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/hub/utils/hasher"
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const HEARTBEAT = 5
|
||||||
|
|
||||||
type Store interface {
|
type Store interface {
|
||||||
NewAgent(ctx context.Context, agent domainHub.CreateAgentModel) error
|
NewAgent(ctx context.Context, agent domainHub.CreateAgentModel) error
|
||||||
GetAgentByAgentID(ctx context.Context, AgentID string) (domainHub.AgentModel, error)
|
GetAgentByAgentID(ctx context.Context, AgentID string) (domainHub.AgentModel, error)
|
||||||
@@ -28,43 +30,37 @@ func NewHubService(store Store, logger zerolog.Logger) *HubService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *HubService) RegisterAgent(ctx context.Context, data domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error) {
|
func (h *HubService) RegisterAgent(ctx context.Context, data domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error) {
|
||||||
h.log.Debug().Str("agentId", data.AgentId).Str("agentName", data.AgentName).Msg("started registering agent")
|
h.log.Debug().Str("agentID", data.AgentID).Str("agentName", data.AgentName).Msg("started registering agent")
|
||||||
agent, err := h.store.GetAgentByAgentID(ctx, data.AgentId)
|
agent, err := h.store.GetAgentByAgentID(ctx, data.AgentID)
|
||||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
h.log.Error().Err(err).Str("agentId", data.AgentId).Msg("failed to get agent from database")
|
|
||||||
return domain.RegisterAgentResponse{}, fmt.Errorf("failed select agent to db: %w", err)
|
return domain.RegisterAgentResponse{}, fmt.Errorf("failed select agent to db: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.AgentId != "" && !errors.Is(err, sql.ErrNoRows) {
|
if data.AgentID != "" && !errors.Is(err, sql.ErrNoRows) {
|
||||||
h.log.Debug().Str("agentId", agent.AgentID).Str("agentName", data.AgentName).Msg("agent exists, updating")
|
h.log.Debug().Str("agentID", agent.AgentID).Str("agentName", data.AgentName).Msg("agent exists, updating")
|
||||||
|
|
||||||
data.AgentId = agent.AgentID
|
data.AgentID = agent.AgentID
|
||||||
|
|
||||||
agentStore := toCreateAgentModel(data)
|
agentStore := toCreateAgentModel(data)
|
||||||
|
|
||||||
if err := h.store.UpdateAgentByID(ctx, agent.ID, agentStore); err != nil {
|
if err := h.store.UpdateAgentByID(ctx, agent.ID, agentStore); err != nil {
|
||||||
h.log.Error().Err(err).Str("agentId", agent.AgentID).Msg("failed to update agent in database")
|
return domain.RegisterAgentResponse{}, fmt.Errorf("update agent in db: %w", err)
|
||||||
return domain.RegisterAgentResponse{}, err
|
|
||||||
}
|
}
|
||||||
h.log.Info().Str("agentId", agent.AgentID).Msg("agent updated successfully")
|
h.log.Debug().Str("agentId", agent.AgentID).Msg("agent updated successfully")
|
||||||
return domain.RegisterAgentResponse{AgentID: agent.AgentID, Heartbeat: 5}, nil
|
return domain.RegisterAgentResponse{AgentID: agent.AgentID, Heartbeat: HEARTBEAT}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
AgentID, err := hasher.MakeID(data.Host, data.AgentName)
|
AgentID, err := hasher.MakeID(data.Host, data.AgentName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.log.Error().Err(err).Str("agentName", data.AgentName).Str("hostname", data.Host.Hostname).Msg("failed to generate agent id")
|
return domain.RegisterAgentResponse{}, fmt.Errorf("generate agent ID: %w", err)
|
||||||
return domain.RegisterAgentResponse{}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data.AgentId = AgentID
|
data.AgentID = AgentID
|
||||||
|
|
||||||
agentStore := toCreateAgentModel(data)
|
agentStore := toCreateAgentModel(data)
|
||||||
|
|
||||||
if err := h.store.NewAgent(ctx, agentStore); err != nil {
|
if err := h.store.NewAgent(ctx, agentStore); err != nil {
|
||||||
h.log.Error().Err(err).Str("agentId", AgentID).Str("agentName", data.AgentName).Msg("failed to create new agent in database")
|
return domain.RegisterAgentResponse{}, fmt.Errorf("insert new agent: %w", err)
|
||||||
return domain.RegisterAgentResponse{}, err
|
|
||||||
}
|
}
|
||||||
|
return domain.RegisterAgentResponse{AgentID: AgentID, Heartbeat: HEARTBEAT}, nil
|
||||||
h.log.Info().Str("agentId", AgentID).Str("agentName", data.AgentName).Str("hostname", data.Host.Hostname).Msg("agent registered successfully")
|
|
||||||
return domain.RegisterAgentResponse{AgentID: AgentID, Heartbeat: 5}, nil
|
|
||||||
}
|
}
|
||||||
+3
-3
@@ -1,13 +1,13 @@
|
|||||||
package hub_service
|
package hub_service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/domain"
|
domainHub "github.com/lorsanstand/HomeOps-Hub/hub/internal/domain"
|
||||||
domainHub "github.com/lorsanstand/HomeOps-Hub/internal/hub/domain"
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
func toCreateAgentModel(agent domain.RegisterAgentRequest) domainHub.CreateAgentModel {
|
func toCreateAgentModel(agent domain.RegisterAgentRequest) domainHub.CreateAgentModel {
|
||||||
return domainHub.CreateAgentModel{
|
return domainHub.CreateAgentModel{
|
||||||
AgentID: agent.AgentId,
|
AgentID: agent.AgentID,
|
||||||
AgentName: agent.AgentName,
|
AgentName: agent.AgentName,
|
||||||
Architecture: agent.Host.Arch,
|
Architecture: agent.Host.Arch,
|
||||||
System: agent.Host.System,
|
System: agent.Host.System,
|
||||||
@@ -3,36 +3,36 @@ package store
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/domain"
|
domainHub "github.com/lorsanstand/HomeOps-Hub/hub/internal/domain"
|
||||||
domainHub "github.com/lorsanstand/HomeOps-Hub/internal/hub/domain"
|
gen2 "github.com/lorsanstand/HomeOps-Hub/hub/internal/store/sqlc/gen"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/hub/store/sqlc/gen"
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
func toDBAgent(agent domainHub.CreateAgentModel) gen.CreateAgentParams {
|
func toDBAgent(agent domainHub.CreateAgentModel) gen2.CreateAgentParams {
|
||||||
return gen.CreateAgentParams{
|
return gen2.CreateAgentParams{
|
||||||
AgentID: agent.AgentID,
|
AgentID: agent.AgentID,
|
||||||
AgentName: &agent.AgentName,
|
AgentName: &agent.AgentName,
|
||||||
Architecture: agent.Architecture,
|
Architecture: agent.Architecture,
|
||||||
System: agent.System,
|
System: agent.System,
|
||||||
Hostname: agent.Hostname,
|
Hostname: agent.Hostname,
|
||||||
Version: agent.Version,
|
Version: agent.Version,
|
||||||
Capabilities: toJsonCapabilities(agent.Capabilities),
|
Capabilities: toJSONCapabilities(agent.Capabilities),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toUpdateDBAgent(agent domainHub.CreateAgentModel) gen.UpdateAgentByIDParams {
|
func toUpdateDBAgent(agent domainHub.CreateAgentModel) gen2.UpdateAgentByIDParams {
|
||||||
return gen.UpdateAgentByIDParams{
|
return gen2.UpdateAgentByIDParams{
|
||||||
AgentID: agent.AgentID,
|
AgentID: agent.AgentID,
|
||||||
AgentName: &agent.AgentName,
|
AgentName: &agent.AgentName,
|
||||||
Architecture: agent.Architecture,
|
Architecture: agent.Architecture,
|
||||||
System: agent.System,
|
System: agent.System,
|
||||||
Hostname: agent.Hostname,
|
Hostname: agent.Hostname,
|
||||||
Version: agent.Version,
|
Version: agent.Version,
|
||||||
Capabilities: toJsonCapabilities(agent.Capabilities),
|
Capabilities: toJSONCapabilities(agent.Capabilities),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toJsonCapabilities(caps []domain.Capability) []byte {
|
func toJSONCapabilities(caps []domain.Capability) []byte {
|
||||||
data, err := json.Marshal(caps)
|
data, err := json.Marshal(caps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Note: Error is silently handled - consider logging in production
|
// Note: Error is silently handled - consider logging in production
|
||||||
@@ -41,7 +41,7 @@ func toJsonCapabilities(caps []domain.Capability) []byte {
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func toAgentModel(dbAgent gen.Agent) domainHub.AgentModel {
|
func toAgentModel(dbAgent gen2.Agent) domainHub.AgentModel {
|
||||||
var dbAgentName string
|
var dbAgentName string
|
||||||
if dbAgent.AgentName != nil {
|
if dbAgent.AgentName != nil {
|
||||||
dbAgentName = *dbAgent.AgentName
|
dbAgentName = *dbAgent.AgentName
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.30.0
|
// sqlc v1.30.0
|
||||||
// source: agent.sql
|
// source: cmd.sql
|
||||||
|
|
||||||
package gen
|
package gen
|
||||||
|
|
||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
domainHub "github.com/lorsanstand/HomeOps-Hub/internal/hub/domain"
|
domainHub "github.com/lorsanstand/HomeOps-Hub/hub/internal/domain"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/hub/store/sqlc/gen"
|
"github.com/lorsanstand/HomeOps-Hub/hub/internal/store/sqlc/gen"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HubStore struct {
|
type HubStore struct {
|
||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/domain"
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newSalt(n int) ([]byte, error) {
|
func newSalt(n int) ([]byte, error) {
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package agent_service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/agent/utils/config_yaml"
|
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/agent/utils/settings"
|
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/domain"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
const AgentVersion = "0.0"
|
|
||||||
|
|
||||||
type Collector interface {
|
|
||||||
GatherInfoSystem() (domain.HostInfo, []domain.Capability)
|
|
||||||
}
|
|
||||||
|
|
||||||
type HubConnection interface {
|
|
||||||
RegisterAgent(ctx context.Context, RegisterData domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type AgentService struct {
|
|
||||||
collect Collector
|
|
||||||
conn HubConnection
|
|
||||||
log zerolog.Logger
|
|
||||||
cfg *config_yaml.AgentConfig
|
|
||||||
heartBeat int
|
|
||||||
settings *settings.Settings
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAgentService(
|
|
||||||
collector Collector,
|
|
||||||
conn HubConnection,
|
|
||||||
settings *settings.Settings,
|
|
||||||
cfg *config_yaml.AgentConfig,
|
|
||||||
logger zerolog.Logger,
|
|
||||||
) *AgentService {
|
|
||||||
logger = logger.With().Str("component", "agent.service.agent_serivce").Logger()
|
|
||||||
|
|
||||||
return &AgentService{collect: collector, conn: conn, cfg: cfg, log: logger, settings: settings}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AgentService) RegisterAgentConn(ctx context.Context) {
|
|
||||||
info, caps := a.collect.GatherInfoSystem()
|
|
||||||
AgentID := a.settings.AgentID
|
|
||||||
AgentName := a.cfg.AppName
|
|
||||||
AgentData := domain.RegisterAgentRequest{AgentId: AgentID, AgentName: AgentName, Host: info, Capabilities: caps, AgentVersion: AgentVersion}
|
|
||||||
|
|
||||||
data, err := a.conn.RegisterAgent(ctx, AgentData)
|
|
||||||
if err != nil {
|
|
||||||
a.log.Error().Err(err).Msg("failed register agent")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = a.settings.Insert(settings.Settings{AgentID: data.AgentID}); err != nil {
|
|
||||||
a.log.Warn().Err(err).Msg("failed to save agent id")
|
|
||||||
}
|
|
||||||
fmt.Println(data)
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package agent_service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/lorsanstand/HomeOps-Hub/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CollectorMock struct {
|
|
||||||
host domain.HostInfo
|
|
||||||
caps []domain.Capability
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CollectorMock) GatherInfoSystem() (domain.HostInfo, []domain.Capability) {
|
|
||||||
return c.host, c.caps
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConnectionMock struct {
|
|
||||||
regAgentErr error
|
|
||||||
regResp domain.RegisterAgentResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionMock) RegisterAgent(ctx context.Context, RegisterData domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error) {
|
|
||||||
return c.regResp, c.regAgentErr
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
type RegisterAgentRequest struct {
|
type RegisterAgentRequest struct {
|
||||||
AgentId string
|
AgentID string
|
||||||
AgentName string
|
AgentName string
|
||||||
AgentVersion string
|
AgentVersion string
|
||||||
Host HostInfo
|
Host HostInfo
|
||||||
@@ -10,7 +10,7 @@ func ToDomainAgentRequest(request *pb.RegisterAgentRequest) RegisterAgentRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
return RegisterAgentRequest{
|
return RegisterAgentRequest{
|
||||||
AgentId: request.AgentId,
|
AgentID: request.AgentId,
|
||||||
AgentName: request.AgentName,
|
AgentName: request.AgentName,
|
||||||
Host: HostInfo{
|
Host: HostInfo{
|
||||||
System: request.Host.System,
|
System: request.Host.System,
|
||||||
@@ -53,7 +53,7 @@ func ToDomainCapabilities(capability []*pb.Capability) []Capability {
|
|||||||
|
|
||||||
func ToGRPCAgentRequest(request RegisterAgentRequest) pb.RegisterAgentRequest {
|
func ToGRPCAgentRequest(request RegisterAgentRequest) pb.RegisterAgentRequest {
|
||||||
return pb.RegisterAgentRequest{
|
return pb.RegisterAgentRequest{
|
||||||
AgentId: request.AgentId,
|
AgentId: request.AgentID,
|
||||||
AgentName: request.AgentName,
|
AgentName: request.AgentName,
|
||||||
Host: &pb.HostInfo{
|
Host: &pb.HostInfo{
|
||||||
Hostname: request.Host.Hostname,
|
Hostname: request.Host.Hostname,
|
||||||
@@ -2,11 +2,11 @@ version: "2"
|
|||||||
|
|
||||||
sql:
|
sql:
|
||||||
- engine: "postgresql"
|
- engine: "postgresql"
|
||||||
queries: "internal/hub/store/sqlc/queries"
|
queries: "hub/internal/store/sqlc/queries"
|
||||||
schema: "./internal/hub/migrations/"
|
schema: "./hub/internal/migrations/"
|
||||||
gen:
|
gen:
|
||||||
go:
|
go:
|
||||||
sql_package: "pgx/v5"
|
sql_package: "pgx/v5"
|
||||||
package: "gen"
|
package: "gen"
|
||||||
out: "internal/hub/store/sqlc/gen"
|
out: "hub/internal/store/sqlc/gen"
|
||||||
emit_pointers_for_null_types: true
|
emit_pointers_for_null_types: true
|
||||||
Reference in New Issue
Block a user