diff --git a/api/gen/homeops/hub.pb.go b/api/gen/homeops/hub.pb.go index 29da217..284f28c 100644 --- a/api/gen/homeops/hub.pb.go +++ b/api/gen/homeops/hub.pb.go @@ -70,7 +70,9 @@ type RegisterAgentRequest struct { state protoimpl.MessageState `protogen:"open.v1"` AgentId string `protobuf:"bytes,1,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` AgentName string `protobuf:"bytes,2,opt,name=agent_name,json=agentName,proto3" json:"agent_name,omitempty"` - Config *AgentConfig `protobuf:"bytes,3,opt,name=config,proto3" json:"config,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + Host *HostInfo `protobuf:"bytes,4,opt,name=host,proto3" json:"host,omitempty"` + Capability []*Capability `protobuf:"bytes,5,rep,name=capability,proto3" json:"capability,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -119,38 +121,50 @@ func (x *RegisterAgentRequest) GetAgentName() string { return "" } -func (x *RegisterAgentRequest) GetConfig() *AgentConfig { +func (x *RegisterAgentRequest) GetVersion() string { if x != nil { - return x.Config + return x.Version + } + return "" +} + +func (x *RegisterAgentRequest) GetHost() *HostInfo { + if x != nil { + return x.Host } return nil } -type AgentConfig struct { +func (x *RegisterAgentRequest) GetCapability() []*Capability { + if x != nil { + return x.Capability + } + return nil +} + +type HostInfo struct { state protoimpl.MessageState `protogen:"open.v1"` System string `protobuf:"bytes,1,opt,name=system,proto3" json:"system,omitempty"` - Docker bool `protobuf:"varint,2,opt,name=docker,proto3" json:"docker,omitempty"` - Hostname string `protobuf:"bytes,3,opt,name=hostname,proto3" json:"hostname,omitempty"` - Version string `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"` - Arch string `protobuf:"bytes,5,opt,name=arch,proto3" json:"arch,omitempty"` + Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3" json:"hostname,omitempty"` + Arch string `protobuf:"bytes,3,opt,name=arch,proto3" json:"arch,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *AgentConfig) Reset() { - *x = AgentConfig{} +func (x *HostInfo) Reset() { + *x = HostInfo{} mi := &file_homeops_hub_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *AgentConfig) String() string { +func (x *HostInfo) String() string { return protoimpl.X.MessageStringOf(x) } -func (*AgentConfig) ProtoMessage() {} +func (*HostInfo) ProtoMessage() {} -func (x *AgentConfig) ProtoReflect() protoreflect.Message { +func (x *HostInfo) ProtoReflect() protoreflect.Message { mi := &file_homeops_hub_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -162,42 +176,96 @@ func (x *AgentConfig) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use AgentConfig.ProtoReflect.Descriptor instead. -func (*AgentConfig) Descriptor() ([]byte, []int) { +// Deprecated: Use HostInfo.ProtoReflect.Descriptor instead. +func (*HostInfo) Descriptor() ([]byte, []int) { return file_homeops_hub_proto_rawDescGZIP(), []int{2} } -func (x *AgentConfig) GetSystem() string { +func (x *HostInfo) GetSystem() string { if x != nil { return x.System } return "" } -func (x *AgentConfig) GetDocker() bool { - if x != nil { - return x.Docker - } - return false -} - -func (x *AgentConfig) GetHostname() string { +func (x *HostInfo) GetHostname() string { if x != nil { return x.Hostname } return "" } -func (x *AgentConfig) GetVersion() string { +func (x *HostInfo) GetArch() string { + if x != nil { + return x.Arch + } + return "" +} + +type Capability struct { + state protoimpl.MessageState `protogen:"open.v1"` + Available bool `protobuf:"varint,1,opt,name=available,proto3" json:"available,omitempty"` + Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Capability) Reset() { + *x = Capability{} + mi := &file_homeops_hub_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Capability) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Capability) ProtoMessage() {} + +func (x *Capability) ProtoReflect() protoreflect.Message { + mi := &file_homeops_hub_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Capability.ProtoReflect.Descriptor instead. +func (*Capability) Descriptor() ([]byte, []int) { + return file_homeops_hub_proto_rawDescGZIP(), []int{3} +} + +func (x *Capability) GetAvailable() bool { + if x != nil { + return x.Available + } + return false +} + +func (x *Capability) GetVersion() string { if x != nil { return x.Version } return "" } -func (x *AgentConfig) GetArch() string { +func (x *Capability) GetName() string { if x != nil { - return x.Arch + return x.Name + } + return "" +} + +func (x *Capability) GetReason() string { + if x != nil { + return x.Reason } return "" } @@ -205,13 +273,14 @@ func (x *AgentConfig) GetArch() string { type RegisterAgentResponse struct { state protoimpl.MessageState `protogen:"open.v1"` HeartbeatIntervalSecond int64 `protobuf:"varint,1,opt,name=heartbeat_interval_second,json=heartbeatIntervalSecond,proto3" json:"heartbeat_interval_second,omitempty"` + AgentId string `protobuf:"bytes,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *RegisterAgentResponse) Reset() { *x = RegisterAgentResponse{} - mi := &file_homeops_hub_proto_msgTypes[3] + mi := &file_homeops_hub_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -223,7 +292,7 @@ func (x *RegisterAgentResponse) String() string { func (*RegisterAgentResponse) ProtoMessage() {} func (x *RegisterAgentResponse) ProtoReflect() protoreflect.Message { - mi := &file_homeops_hub_proto_msgTypes[3] + mi := &file_homeops_hub_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -236,7 +305,7 @@ func (x *RegisterAgentResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterAgentResponse.ProtoReflect.Descriptor instead. func (*RegisterAgentResponse) Descriptor() ([]byte, []int) { - return file_homeops_hub_proto_rawDescGZIP(), []int{3} + return file_homeops_hub_proto_rawDescGZIP(), []int{4} } func (x *RegisterAgentResponse) GetHeartbeatIntervalSecond() int64 { @@ -246,26 +315,42 @@ func (x *RegisterAgentResponse) GetHeartbeatIntervalSecond() int64 { return 0 } +func (x *RegisterAgentResponse) GetAgentId() string { + if x != nil { + return x.AgentId + } + return "" +} + var File_homeops_hub_proto protoreflect.FileDescriptor const file_homeops_hub_proto_rawDesc = "" + "\n" + "\x11homeops/hub.proto\x1a\x1bgoogle/protobuf/empty.proto\"\"\n" + "\fPongResponse\x12\x12\n" + - "\x04pong\x18\x01 \x01(\tR\x04pong\"v\n" + + "\x04pong\x18\x01 \x01(\tR\x04pong\"\xb6\x01\n" + "\x14RegisterAgentRequest\x12\x19\n" + "\bagent_id\x18\x01 \x01(\tR\aagentId\x12\x1d\n" + "\n" + - "agent_name\x18\x02 \x01(\tR\tagentName\x12$\n" + - "\x06config\x18\x03 \x01(\v2\f.AgentConfigR\x06config\"\x87\x01\n" + - "\vAgentConfig\x12\x16\n" + - "\x06system\x18\x01 \x01(\tR\x06system\x12\x16\n" + - "\x06docker\x18\x02 \x01(\bR\x06docker\x12\x1a\n" + - "\bhostname\x18\x03 \x01(\tR\bhostname\x12\x18\n" + - "\aversion\x18\x04 \x01(\tR\aversion\x12\x12\n" + - "\x04arch\x18\x05 \x01(\tR\x04arch\"S\n" + + "agent_name\x18\x02 \x01(\tR\tagentName\x12\x18\n" + + "\aversion\x18\x03 \x01(\tR\aversion\x12\x1d\n" + + "\x04host\x18\x04 \x01(\v2\t.HostInfoR\x04host\x12+\n" + + "\n" + + "capability\x18\x05 \x03(\v2\v.CapabilityR\n" + + "capability\"R\n" + + "\bHostInfo\x12\x16\n" + + "\x06system\x18\x01 \x01(\tR\x06system\x12\x1a\n" + + "\bhostname\x18\x02 \x01(\tR\bhostname\x12\x12\n" + + "\x04arch\x18\x03 \x01(\tR\x04arch\"p\n" + + "\n" + + "Capability\x12\x1c\n" + + "\tavailable\x18\x01 \x01(\bR\tavailable\x12\x18\n" + + "\aversion\x18\x02 \x01(\tR\aversion\x12\x12\n" + + "\x04name\x18\x03 \x01(\tR\x04name\x12\x16\n" + + "\x06reason\x18\x04 \x01(\tR\x06reason\"n\n" + "\x15RegisterAgentResponse\x12:\n" + - "\x19heartbeat_interval_second\x18\x01 \x01(\x03R\x17heartbeatIntervalSecond2x\n" + + "\x19heartbeat_interval_second\x18\x01 \x01(\x03R\x17heartbeatIntervalSecond\x12\x19\n" + + "\bagent_id\x18\x02 \x01(\tR\aagentId2x\n" + "\x03Hub\x12/\n" + "\x04Ping\x12\x16.google.protobuf.Empty\x1a\r.PongResponse\"\x00\x12@\n" + "\rRegisterAgent\x12\x15.RegisterAgentRequest\x1a\x16.RegisterAgentResponse\"\x00B AgentConfig - 4, // 1: Hub.Ping:input_type -> google.protobuf.Empty - 1, // 2: Hub.RegisterAgent:input_type -> RegisterAgentRequest - 0, // 3: Hub.Ping:output_type -> PongResponse - 3, // 4: Hub.RegisterAgent:output_type -> RegisterAgentResponse - 3, // [3:5] is the sub-list for method output_type - 1, // [1:3] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 2, // 0: RegisterAgentRequest.host:type_name -> HostInfo + 3, // 1: RegisterAgentRequest.capability:type_name -> Capability + 5, // 2: Hub.Ping:input_type -> google.protobuf.Empty + 1, // 3: Hub.RegisterAgent:input_type -> RegisterAgentRequest + 0, // 4: Hub.Ping:output_type -> PongResponse + 4, // 5: Hub.RegisterAgent:output_type -> RegisterAgentResponse + 4, // [4:6] is the sub-list for method output_type + 2, // [2:4] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name } func init() { file_homeops_hub_proto_init() } @@ -314,7 +401,7 @@ func file_homeops_hub_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_homeops_hub_proto_rawDesc), len(file_homeops_hub_proto_rawDesc)), NumEnums: 0, - NumMessages: 4, + NumMessages: 5, NumExtensions: 0, NumServices: 1, }, diff --git a/api/proto/homeops/hub.proto b/api/proto/homeops/hub.proto index cd91796..e7f32d9 100644 --- a/api/proto/homeops/hub.proto +++ b/api/proto/homeops/hub.proto @@ -16,17 +16,25 @@ message PongResponse { message RegisterAgentRequest { string agent_id = 1; string agent_name = 2; - AgentConfig config = 3; + string version = 3; + HostInfo host = 4; + repeated Capability capability = 5; } -message AgentConfig { +message HostInfo { string system = 1; - bool docker = 2; - string hostname = 3; - string version = 4; - string arch = 5; + string hostname = 2; + string arch = 3; +} + +message Capability { + bool available = 1; + string version = 2; + string name = 3; + string reason = 4; } message RegisterAgentResponse { int64 heartbeat_interval_second = 1; + string agent_id = 2; } \ No newline at end of file diff --git a/internal/agent/domain/agent.go b/internal/agent/domain/agent.go new file mode 100644 index 0000000..cc21078 --- /dev/null +++ b/internal/agent/domain/agent.go @@ -0,0 +1,27 @@ +package domain + +type RegisterAgentData struct { + AgentId string + AgentName string + AgentVersion string + Host HostInfo + Capabilities []Capability +} + +type HostInfo struct { + System string + Hostname string + Arch string +} + +type Capability struct { + Available bool + Version string + Name string + Reason string +} + +type RegisterAgentDataResponse struct { + Heartbeat int + AgentID string +} diff --git a/internal/agent/rpc/client.go b/internal/agent/rpc/client.go index 174d0c4..c7e452d 100644 --- a/internal/agent/rpc/client.go +++ b/internal/agent/rpc/client.go @@ -1,9 +1,11 @@ package rpc import ( + "context" "fmt" pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops" + "github.com/lorsanstand/HomeOps-Hub/internal/agent/domain" "google.golang.org/grpc" ) @@ -30,3 +32,8 @@ func (c *Connection) Close() error { func (c *Connection) Hub() pb.HubClient { return c.hub } + +func (c *Connection) RegisterAgent(ctx context.Context, RegisterData domain.RegisterAgentData) (domain.RegisterAgentDataResponse, error) { + ResponseData, err := c.Hub().RegisterAgent(ctx, new(toAgentRegisterRequest(RegisterData))) + return toAgentRegisterDataResponse(ResponseData), err +} diff --git a/internal/agent/rpc/mapper.go b/internal/agent/rpc/mapper.go new file mode 100644 index 0000000..79c45dc --- /dev/null +++ b/internal/agent/rpc/mapper.go @@ -0,0 +1,40 @@ +package rpc + +import ( + pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops" + "github.com/lorsanstand/HomeOps-Hub/internal/agent/domain" +) + +func toAgentRegisterRequest(request domain.RegisterAgentData) pb.RegisterAgentRequest { + return pb.RegisterAgentRequest{ + AgentId: request.AgentId, + AgentName: request.AgentName, + Host: &pb.HostInfo{ + Hostname: request.Host.Hostname, + Arch: request.Host.Arch, + System: request.Host.System, + }, + Version: request.AgentVersion, + Capability: toGRPCCapability(request.Capabilities), + } +} + +func toGRPCCapability(caps []domain.Capability) []*pb.Capability { + var capability []*pb.Capability + for _, capi := range caps { + capability = append(capability, &pb.Capability{ + Name: capi.Name, + Available: capi.Available, + Version: capi.Version, + Reason: capi.Reason, + }) + } + return capability +} + +func toAgentRegisterDataResponse(response *pb.RegisterAgentResponse) domain.RegisterAgentDataResponse { + return domain.RegisterAgentDataResponse{ + AgentID: response.AgentId, + Heartbeat: int(response.HeartbeatIntervalSecond), + } +} diff --git a/internal/agent/service/hub_service/hub.go b/internal/agent/service/hub_service/hub.go deleted file mode 100644 index d8d3b10..0000000 --- a/internal/agent/service/hub_service/hub.go +++ /dev/null @@ -1,21 +0,0 @@ -package hub_service - -import ( - "github.com/lorsanstand/HomeOps-Hub/internal/agent/rpc" - "github.com/lorsanstand/HomeOps-Hub/internal/agent/service/docker_service" - "github.com/rs/zerolog" -) - -type HubService struct { - docker *docker_service.DockerService - log zerolog.Logger - hubConn *rpc.Connection -} - -func NewHubService(docker *docker_service.DockerService, log zerolog.Logger) *HubService { - return &HubService{docker: docker, log: log} -} - -func (h *HubService) GatherInfoSystem() { - -} diff --git a/internal/agent/service/hub_service/model.go b/internal/agent/service/hub_service/model.go deleted file mode 100644 index 4944d8d..0000000 --- a/internal/agent/service/hub_service/model.go +++ /dev/null @@ -1,15 +0,0 @@ -package hub_service - -type AgentRegistrationData struct { - AgentID string - AgentName string - Config AgentConfig -} - -type AgentConfig struct { - System string - Docker bool - Hostname string - Version string - Arch string -} diff --git a/internal/agent/utils/config_yaml/config_yaml_test.go b/internal/agent/utils/config_yaml/config_yaml_test.go new file mode 100644 index 0000000..f662117 --- /dev/null +++ b/internal/agent/utils/config_yaml/config_yaml_test.go @@ -0,0 +1,41 @@ +package config_yaml + +import ( + "testing" + + "github.com/rs/zerolog" +) + +func TestAgentConfig_GetLogLevel(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + cfg AgentConfig + wantLogLevel zerolog.Level + }{ + { + name: "success", + cfg: AgentConfig{LogLevel: "DEBUG"}, + wantLogLevel: zerolog.DebugLevel, + }, + { + name: "failed parse", + cfg: AgentConfig{LogLevel: "TEST"}, + wantLogLevel: zerolog.InfoLevel, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + logLevel := tt.cfg.GetLogLevel() + + if logLevel != tt.wantLogLevel { + t.Fatalf("expected %v, got: %v", tt.wantLogLevel, logLevel) + } + }) + } +} diff --git a/internal/shared/config/config_test.go b/internal/shared/config/config_test.go new file mode 100644 index 0000000..1ad1bc1 --- /dev/null +++ b/internal/shared/config/config_test.go @@ -0,0 +1,76 @@ +package config + +import ( + "testing" + + "github.com/rs/zerolog" +) + +func TestConfig_GetLogLevel(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + cfg Config + wantLogLevel zerolog.Level + }{ + { + name: "success", + cfg: Config{LogLevel: "DEBUG"}, + wantLogLevel: zerolog.DebugLevel, + }, + { + name: "failed parse", + cfg: Config{LogLevel: "TEST"}, + wantLogLevel: zerolog.InfoLevel, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + logLevel := tt.cfg.GetLogLevel() + + if logLevel != tt.wantLogLevel { + t.Fatalf("expected %v, got: %v", tt.wantLogLevel, logLevel) + } + }) + } +} + +func TestConfig_GetURLPostgres(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + cfg Config + wantURLPostgres string + }{ + { + name: "success", + cfg: Config{ + DBHost: "TestHost", + DBName: "TestName", + DBPassword: "TestPassword", + DBPort: 1234, + DBUser: "TestUser", + }, + wantURLPostgres: "postgres://TestUser:TestPassword@TestHost:1234/TestName?sslmode=disable", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + url := tt.cfg.GetURLPostgres() + + if url != tt.wantURLPostgres { + t.Fatalf("expected %v, got: %v", tt.wantURLPostgres, url) + } + }) + } +}