From dea3c4ad3f135ca611765167b8687f6fefb2fab5 Mon Sep 17 00:00:00 2001 From: Matee Ullah Malik Date: Fri, 1 Aug 2025 19:34:30 +0500 Subject: [PATCH 1/3] Refactor system status api --- README.md | 92 ++-- gen/supernode/supernode.pb.go | 441 ++++++++++++------ gen/supernode/supernode.swagger.json | 76 ++- proto/supernode/supernode.proto | 47 +- sdk/adapters/supernodeservice/adapter.go | 44 +- sdk/adapters/supernodeservice/types.go | 33 +- supernode/config/config.go | 6 +- supernode/node/supernode/gateway/swagger.json | 76 ++- .../node/supernode/server/status_server.go | 32 +- .../supernode/server/status_server_test.go | 23 +- supernode/services/cascade/status_test.go | 14 +- .../services/common/supernode/metrics.go | 44 +- .../services/common/supernode/service.go | 32 +- .../services/common/supernode/service_test.go | 12 +- supernode/services/common/supernode/types.go | 46 +- 15 files changed, 701 insertions(+), 317 deletions(-) diff --git a/README.md b/README.md index fd68b107..af610801 100644 --- a/README.md +++ b/README.md @@ -18,28 +18,40 @@ service SupernodeService { message StatusRequest {} message StatusResponse { - message CPU { - string usage = 1; - string remaining = 2; - } - - message Memory { - uint64 total = 1; - uint64 used = 2; - uint64 available = 3; - double used_perc = 4; + message Resources { + message CPU { + double usage_percent = 1; + } + + message Memory { + uint64 total_bytes = 1; + uint64 used_bytes = 2; + uint64 available_bytes = 3; + double usage_percent = 4; + } + + message Storage { + string path = 1; + uint64 total_bytes = 2; + uint64 used_bytes = 3; + uint64 available_bytes = 4; + double usage_percent = 5; + } + + CPU cpu = 1; + Memory memory = 2; + repeated Storage storage_volumes = 3; } - + message ServiceTasks { string service_name = 1; repeated string task_ids = 2; int32 task_count = 3; } - - CPU cpu = 1; - Memory memory = 2; - repeated ServiceTasks services = 3; - repeated string available_services = 4; + + Resources resources = 1; + repeated ServiceTasks running_tasks = 2; + repeated string registered_services = 3; } ``` @@ -115,42 +127,52 @@ The supernode provides an HTTP gateway that exposes the gRPC services via REST A ### Endpoints -#### GET /status -Returns the current supernode status including CPU, memory usage and active services. +#### GET /api/v1/status +Returns the current supernode status including system resources (CPU, memory, storage) and service information. ```bash -curl http://localhost:8002/status +curl http://localhost:8002/api/v1/status ``` Response: ```json { - "cpu": { - "usage": "15.2%", - "remaining": "84.8%" - }, - "memory": { - "total": "16777216000", - "used": "8388608000", - "available": "8388608000", - "usedPerc": 50.0 + "resources": { + "cpu": { + "usage_percent": 15.2 + }, + "memory": { + "total_bytes": "16777216000", + "used_bytes": "8388608000", + "available_bytes": "8388608000", + "usage_percent": 50.0 + }, + "storage_volumes": [ + { + "path": "/", + "total_bytes": "500000000000", + "used_bytes": "250000000000", + "available_bytes": "250000000000", + "usage_percent": 50.0 + } + ] }, - "services": [ + "running_tasks": [ { - "serviceName": "cascade", - "taskIds": ["task1", "task2"], - "taskCount": 2 + "service_name": "cascade", + "task_ids": ["task1", "task2"], + "task_count": 2 } ], - "availableServices": ["cascade", "sense"] + "registered_services": ["cascade", "sense"] } ``` -#### GET /services +#### GET /api/v1/services Returns the list of available services on the supernode. ```bash -curl http://localhost:8002/services +curl http://localhost:8002/api/v1/services ``` Response: diff --git a/gen/supernode/supernode.pb.go b/gen/supernode/supernode.pb.go index 167c03bd..6a49428f 100644 --- a/gen/supernode/supernode.pb.go +++ b/gen/supernode/supernode.pb.go @@ -199,16 +199,15 @@ func (x *ServiceInfo) GetMethods() []string { return nil } -// The StatusResponse represents system status. +// The StatusResponse represents system status with clear organization type StatusResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Cpu *StatusResponse_CPU `protobuf:"bytes,1,opt,name=cpu,proto3" json:"cpu,omitempty"` - Memory *StatusResponse_Memory `protobuf:"bytes,2,opt,name=memory,proto3" json:"memory,omitempty"` - RunningTasks []*StatusResponse_ServiceTasks `protobuf:"bytes,3,rep,name=running_tasks,json=runningTasks,proto3" json:"running_tasks,omitempty"` // Services with currently running tasks - RegisteredServices []string `protobuf:"bytes,4,rep,name=registered_services,json=registeredServices,proto3" json:"registered_services,omitempty"` // All registered/available services + Resources *StatusResponse_Resources `protobuf:"bytes,1,opt,name=resources,proto3" json:"resources,omitempty"` + RunningTasks []*StatusResponse_ServiceTasks `protobuf:"bytes,2,rep,name=running_tasks,json=runningTasks,proto3" json:"running_tasks,omitempty"` // Services with currently running tasks + RegisteredServices []string `protobuf:"bytes,3,rep,name=registered_services,json=registeredServices,proto3" json:"registered_services,omitempty"` // All registered/available services } func (x *StatusResponse) Reset() { @@ -241,16 +240,9 @@ func (*StatusResponse) Descriptor() ([]byte, []int) { return file_supernode_supernode_proto_rawDescGZIP(), []int{4} } -func (x *StatusResponse) GetCpu() *StatusResponse_CPU { +func (x *StatusResponse) GetResources() *StatusResponse_Resources { if x != nil { - return x.Cpu - } - return nil -} - -func (x *StatusResponse) GetMemory() *StatusResponse_Memory { - if x != nil { - return x.Memory + return x.Resources } return nil } @@ -269,29 +261,31 @@ func (x *StatusResponse) GetRegisteredServices() []string { return nil } -type StatusResponse_CPU struct { +// System resource information +type StatusResponse_Resources struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Usage string `protobuf:"bytes,1,opt,name=usage,proto3" json:"usage,omitempty"` - Remaining string `protobuf:"bytes,2,opt,name=remaining,proto3" json:"remaining,omitempty"` + Cpu *StatusResponse_Resources_CPU `protobuf:"bytes,1,opt,name=cpu,proto3" json:"cpu,omitempty"` + Memory *StatusResponse_Resources_Memory `protobuf:"bytes,2,opt,name=memory,proto3" json:"memory,omitempty"` + StorageVolumes []*StatusResponse_Resources_Storage `protobuf:"bytes,3,rep,name=storage_volumes,json=storageVolumes,proto3" json:"storage_volumes,omitempty"` } -func (x *StatusResponse_CPU) Reset() { - *x = StatusResponse_CPU{} +func (x *StatusResponse_Resources) Reset() { + *x = StatusResponse_Resources{} mi := &file_supernode_supernode_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *StatusResponse_CPU) String() string { +func (x *StatusResponse_Resources) String() string { return protoimpl.X.MessageStringOf(x) } -func (*StatusResponse_CPU) ProtoMessage() {} +func (*StatusResponse_Resources) ProtoMessage() {} -func (x *StatusResponse_CPU) ProtoReflect() protoreflect.Message { +func (x *StatusResponse_Resources) ProtoReflect() protoreflect.Message { mi := &file_supernode_supernode_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -303,50 +297,57 @@ func (x *StatusResponse_CPU) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use StatusResponse_CPU.ProtoReflect.Descriptor instead. -func (*StatusResponse_CPU) Descriptor() ([]byte, []int) { +// Deprecated: Use StatusResponse_Resources.ProtoReflect.Descriptor instead. +func (*StatusResponse_Resources) Descriptor() ([]byte, []int) { return file_supernode_supernode_proto_rawDescGZIP(), []int{4, 0} } -func (x *StatusResponse_CPU) GetUsage() string { +func (x *StatusResponse_Resources) GetCpu() *StatusResponse_Resources_CPU { if x != nil { - return x.Usage + return x.Cpu } - return "" + return nil } -func (x *StatusResponse_CPU) GetRemaining() string { +func (x *StatusResponse_Resources) GetMemory() *StatusResponse_Resources_Memory { if x != nil { - return x.Remaining + return x.Memory } - return "" + return nil +} + +func (x *StatusResponse_Resources) GetStorageVolumes() []*StatusResponse_Resources_Storage { + if x != nil { + return x.StorageVolumes + } + return nil } -type StatusResponse_Memory struct { +// ServiceTasks contains task information for a specific service +type StatusResponse_ServiceTasks struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Total uint64 `protobuf:"varint,1,opt,name=total,proto3" json:"total,omitempty"` - Used uint64 `protobuf:"varint,2,opt,name=used,proto3" json:"used,omitempty"` - Available uint64 `protobuf:"varint,3,opt,name=available,proto3" json:"available,omitempty"` - UsedPerc float64 `protobuf:"fixed64,4,opt,name=used_perc,json=usedPerc,proto3" json:"used_perc,omitempty"` + ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` + TaskIds []string `protobuf:"bytes,2,rep,name=task_ids,json=taskIds,proto3" json:"task_ids,omitempty"` + TaskCount int32 `protobuf:"varint,3,opt,name=task_count,json=taskCount,proto3" json:"task_count,omitempty"` } -func (x *StatusResponse_Memory) Reset() { - *x = StatusResponse_Memory{} +func (x *StatusResponse_ServiceTasks) Reset() { + *x = StatusResponse_ServiceTasks{} mi := &file_supernode_supernode_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *StatusResponse_Memory) String() string { +func (x *StatusResponse_ServiceTasks) String() string { return protoimpl.X.MessageStringOf(x) } -func (*StatusResponse_Memory) ProtoMessage() {} +func (*StatusResponse_ServiceTasks) ProtoMessage() {} -func (x *StatusResponse_Memory) ProtoReflect() protoreflect.Message { +func (x *StatusResponse_ServiceTasks) ProtoReflect() protoreflect.Message { mi := &file_supernode_supernode_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -358,65 +359,173 @@ func (x *StatusResponse_Memory) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use StatusResponse_Memory.ProtoReflect.Descriptor instead. -func (*StatusResponse_Memory) Descriptor() ([]byte, []int) { +// Deprecated: Use StatusResponse_ServiceTasks.ProtoReflect.Descriptor instead. +func (*StatusResponse_ServiceTasks) Descriptor() ([]byte, []int) { return file_supernode_supernode_proto_rawDescGZIP(), []int{4, 1} } -func (x *StatusResponse_Memory) GetTotal() uint64 { +func (x *StatusResponse_ServiceTasks) GetServiceName() string { + if x != nil { + return x.ServiceName + } + return "" +} + +func (x *StatusResponse_ServiceTasks) GetTaskIds() []string { + if x != nil { + return x.TaskIds + } + return nil +} + +func (x *StatusResponse_ServiceTasks) GetTaskCount() int32 { + if x != nil { + return x.TaskCount + } + return 0 +} + +type StatusResponse_Resources_CPU struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UsagePercent float64 `protobuf:"fixed64,1,opt,name=usage_percent,json=usagePercent,proto3" json:"usage_percent,omitempty"` // CPU usage percentage (0-100) +} + +func (x *StatusResponse_Resources_CPU) Reset() { + *x = StatusResponse_Resources_CPU{} + mi := &file_supernode_supernode_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StatusResponse_Resources_CPU) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatusResponse_Resources_CPU) ProtoMessage() {} + +func (x *StatusResponse_Resources_CPU) ProtoReflect() protoreflect.Message { + mi := &file_supernode_supernode_proto_msgTypes[7] + 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 StatusResponse_Resources_CPU.ProtoReflect.Descriptor instead. +func (*StatusResponse_Resources_CPU) Descriptor() ([]byte, []int) { + return file_supernode_supernode_proto_rawDescGZIP(), []int{4, 0, 0} +} + +func (x *StatusResponse_Resources_CPU) GetUsagePercent() float64 { if x != nil { - return x.Total + return x.UsagePercent } return 0 } -func (x *StatusResponse_Memory) GetUsed() uint64 { +type StatusResponse_Resources_Memory struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TotalBytes uint64 `protobuf:"varint,1,opt,name=total_bytes,json=totalBytes,proto3" json:"total_bytes,omitempty"` + UsedBytes uint64 `protobuf:"varint,2,opt,name=used_bytes,json=usedBytes,proto3" json:"used_bytes,omitempty"` + AvailableBytes uint64 `protobuf:"varint,3,opt,name=available_bytes,json=availableBytes,proto3" json:"available_bytes,omitempty"` + UsagePercent float64 `protobuf:"fixed64,4,opt,name=usage_percent,json=usagePercent,proto3" json:"usage_percent,omitempty"` // Memory usage percentage (0-100) +} + +func (x *StatusResponse_Resources_Memory) Reset() { + *x = StatusResponse_Resources_Memory{} + mi := &file_supernode_supernode_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StatusResponse_Resources_Memory) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatusResponse_Resources_Memory) ProtoMessage() {} + +func (x *StatusResponse_Resources_Memory) ProtoReflect() protoreflect.Message { + mi := &file_supernode_supernode_proto_msgTypes[8] + 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 StatusResponse_Resources_Memory.ProtoReflect.Descriptor instead. +func (*StatusResponse_Resources_Memory) Descriptor() ([]byte, []int) { + return file_supernode_supernode_proto_rawDescGZIP(), []int{4, 0, 1} +} + +func (x *StatusResponse_Resources_Memory) GetTotalBytes() uint64 { if x != nil { - return x.Used + return x.TotalBytes } return 0 } -func (x *StatusResponse_Memory) GetAvailable() uint64 { +func (x *StatusResponse_Resources_Memory) GetUsedBytes() uint64 { if x != nil { - return x.Available + return x.UsedBytes } return 0 } -func (x *StatusResponse_Memory) GetUsedPerc() float64 { +func (x *StatusResponse_Resources_Memory) GetAvailableBytes() uint64 { if x != nil { - return x.UsedPerc + return x.AvailableBytes } return 0 } -// ServiceTasks contains task information for a specific service -type StatusResponse_ServiceTasks struct { +func (x *StatusResponse_Resources_Memory) GetUsagePercent() float64 { + if x != nil { + return x.UsagePercent + } + return 0 +} + +type StatusResponse_Resources_Storage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` - TaskIds []string `protobuf:"bytes,2,rep,name=task_ids,json=taskIds,proto3" json:"task_ids,omitempty"` - TaskCount int32 `protobuf:"varint,3,opt,name=task_count,json=taskCount,proto3" json:"task_count,omitempty"` + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` // Storage path being monitored + TotalBytes uint64 `protobuf:"varint,2,opt,name=total_bytes,json=totalBytes,proto3" json:"total_bytes,omitempty"` + UsedBytes uint64 `protobuf:"varint,3,opt,name=used_bytes,json=usedBytes,proto3" json:"used_bytes,omitempty"` + AvailableBytes uint64 `protobuf:"varint,4,opt,name=available_bytes,json=availableBytes,proto3" json:"available_bytes,omitempty"` + UsagePercent float64 `protobuf:"fixed64,5,opt,name=usage_percent,json=usagePercent,proto3" json:"usage_percent,omitempty"` // Storage usage percentage (0-100) } -func (x *StatusResponse_ServiceTasks) Reset() { - *x = StatusResponse_ServiceTasks{} - mi := &file_supernode_supernode_proto_msgTypes[7] +func (x *StatusResponse_Resources_Storage) Reset() { + *x = StatusResponse_Resources_Storage{} + mi := &file_supernode_supernode_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *StatusResponse_ServiceTasks) String() string { +func (x *StatusResponse_Resources_Storage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*StatusResponse_ServiceTasks) ProtoMessage() {} +func (*StatusResponse_Resources_Storage) ProtoMessage() {} -func (x *StatusResponse_ServiceTasks) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[7] +func (x *StatusResponse_Resources_Storage) ProtoReflect() protoreflect.Message { + mi := &file_supernode_supernode_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -427,28 +536,42 @@ func (x *StatusResponse_ServiceTasks) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use StatusResponse_ServiceTasks.ProtoReflect.Descriptor instead. -func (*StatusResponse_ServiceTasks) Descriptor() ([]byte, []int) { - return file_supernode_supernode_proto_rawDescGZIP(), []int{4, 2} +// Deprecated: Use StatusResponse_Resources_Storage.ProtoReflect.Descriptor instead. +func (*StatusResponse_Resources_Storage) Descriptor() ([]byte, []int) { + return file_supernode_supernode_proto_rawDescGZIP(), []int{4, 0, 2} } -func (x *StatusResponse_ServiceTasks) GetServiceName() string { +func (x *StatusResponse_Resources_Storage) GetPath() string { if x != nil { - return x.ServiceName + return x.Path } return "" } -func (x *StatusResponse_ServiceTasks) GetTaskIds() []string { +func (x *StatusResponse_Resources_Storage) GetTotalBytes() uint64 { if x != nil { - return x.TaskIds + return x.TotalBytes } - return nil + return 0 } -func (x *StatusResponse_ServiceTasks) GetTaskCount() int32 { +func (x *StatusResponse_Resources_Storage) GetUsedBytes() uint64 { if x != nil { - return x.TaskCount + return x.UsedBytes + } + return 0 +} + +func (x *StatusResponse_Resources_Storage) GetAvailableBytes() uint64 { + if x != nil { + return x.AvailableBytes + } + return 0 +} + +func (x *StatusResponse_Resources_Storage) GetUsagePercent() float64 { + if x != nil { + return x.UsagePercent } return 0 } @@ -472,58 +595,82 @@ var file_supernode_supernode_proto_rawDesc = []byte{ 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0x90, 0x04, 0x0a, 0x0e, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, - 0x0a, 0x03, 0x63, 0x70, 0x75, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x75, - 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x43, 0x50, 0x55, 0x52, 0x03, 0x63, 0x70, 0x75, 0x12, - 0x38, 0x0a, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x20, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x6f, 0x72, - 0x79, 0x52, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x4b, 0x0a, 0x0d, 0x72, 0x75, 0x6e, - 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x26, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x0c, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, - 0x67, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x65, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x1a, 0x39, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x12, 0x14, - 0x0a, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x75, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, - 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, - 0x6e, 0x67, 0x1a, 0x6d, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x74, 0x6f, 0x74, - 0x61, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x04, 0x75, 0x73, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, - 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x61, 0x76, 0x61, 0x69, 0x6c, - 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x72, - 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x75, 0x73, 0x65, 0x64, 0x50, 0x65, 0x72, - 0x63, 0x1a, 0x6b, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, - 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x73, 0x12, - 0x1d, 0x0a, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0xd7, - 0x01, 0x0a, 0x10, 0x53, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x18, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x73, 0x75, 0x70, + 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0x94, 0x07, 0x0a, 0x0e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, + 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x12, 0x4b, 0x0a, 0x0d, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x73, + 0x52, 0x0c, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x2f, + 0x0a, 0x13, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x1a, + 0xd3, 0x04, 0x0a, 0x09, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x39, 0x0a, + 0x03, 0x63, 0x70, 0x75, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x69, 0x0a, - 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1e, 0x2e, - 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, - 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4c, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2f, - 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, + 0x43, 0x50, 0x55, 0x52, 0x03, 0x63, 0x70, 0x75, 0x12, 0x42, 0x0a, 0x06, 0x6d, 0x65, 0x6d, 0x6f, + 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x52, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x54, 0x0a, 0x0f, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, + 0x65, 0x73, 0x1a, 0x2a, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, + 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0x96, + 0x01, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, + 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, + 0x75, 0x73, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x76, 0x61, + 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x79, 0x74, + 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, + 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, + 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0xab, 0x01, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, + 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x64, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x75, 0x73, + 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, + 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, + 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0x6b, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x61, 0x73, 0x6b, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x73, 0x6b, + 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x32, 0xd7, 0x01, 0x0a, 0x10, 0x53, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, + 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x69, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x12, 0x1e, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x33, 0x5a, 0x31, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4c, 0x75, 0x6d, 0x65, 0x72, + 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, + 0x6f, 0x64, 0x65, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, + 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -538,31 +685,35 @@ func file_supernode_supernode_proto_rawDescGZIP() []byte { return file_supernode_supernode_proto_rawDescData } -var file_supernode_supernode_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_supernode_supernode_proto_msgTypes = make([]protoimpl.MessageInfo, 10) var file_supernode_supernode_proto_goTypes = []any{ - (*StatusRequest)(nil), // 0: supernode.StatusRequest - (*ListServicesRequest)(nil), // 1: supernode.ListServicesRequest - (*ListServicesResponse)(nil), // 2: supernode.ListServicesResponse - (*ServiceInfo)(nil), // 3: supernode.ServiceInfo - (*StatusResponse)(nil), // 4: supernode.StatusResponse - (*StatusResponse_CPU)(nil), // 5: supernode.StatusResponse.CPU - (*StatusResponse_Memory)(nil), // 6: supernode.StatusResponse.Memory - (*StatusResponse_ServiceTasks)(nil), // 7: supernode.StatusResponse.ServiceTasks + (*StatusRequest)(nil), // 0: supernode.StatusRequest + (*ListServicesRequest)(nil), // 1: supernode.ListServicesRequest + (*ListServicesResponse)(nil), // 2: supernode.ListServicesResponse + (*ServiceInfo)(nil), // 3: supernode.ServiceInfo + (*StatusResponse)(nil), // 4: supernode.StatusResponse + (*StatusResponse_Resources)(nil), // 5: supernode.StatusResponse.Resources + (*StatusResponse_ServiceTasks)(nil), // 6: supernode.StatusResponse.ServiceTasks + (*StatusResponse_Resources_CPU)(nil), // 7: supernode.StatusResponse.Resources.CPU + (*StatusResponse_Resources_Memory)(nil), // 8: supernode.StatusResponse.Resources.Memory + (*StatusResponse_Resources_Storage)(nil), // 9: supernode.StatusResponse.Resources.Storage } var file_supernode_supernode_proto_depIdxs = []int32{ 3, // 0: supernode.ListServicesResponse.services:type_name -> supernode.ServiceInfo - 5, // 1: supernode.StatusResponse.cpu:type_name -> supernode.StatusResponse.CPU - 6, // 2: supernode.StatusResponse.memory:type_name -> supernode.StatusResponse.Memory - 7, // 3: supernode.StatusResponse.running_tasks:type_name -> supernode.StatusResponse.ServiceTasks - 0, // 4: supernode.SupernodeService.GetStatus:input_type -> supernode.StatusRequest - 1, // 5: supernode.SupernodeService.ListServices:input_type -> supernode.ListServicesRequest - 4, // 6: supernode.SupernodeService.GetStatus:output_type -> supernode.StatusResponse - 2, // 7: supernode.SupernodeService.ListServices:output_type -> supernode.ListServicesResponse - 6, // [6:8] is the sub-list for method output_type - 4, // [4:6] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 5, // 1: supernode.StatusResponse.resources:type_name -> supernode.StatusResponse.Resources + 6, // 2: supernode.StatusResponse.running_tasks:type_name -> supernode.StatusResponse.ServiceTasks + 7, // 3: supernode.StatusResponse.Resources.cpu:type_name -> supernode.StatusResponse.Resources.CPU + 8, // 4: supernode.StatusResponse.Resources.memory:type_name -> supernode.StatusResponse.Resources.Memory + 9, // 5: supernode.StatusResponse.Resources.storage_volumes:type_name -> supernode.StatusResponse.Resources.Storage + 0, // 6: supernode.SupernodeService.GetStatus:input_type -> supernode.StatusRequest + 1, // 7: supernode.SupernodeService.ListServices:input_type -> supernode.ListServicesRequest + 4, // 8: supernode.SupernodeService.GetStatus:output_type -> supernode.StatusResponse + 2, // 9: supernode.SupernodeService.ListServices:output_type -> supernode.ListServicesResponse + 8, // [8:10] is the sub-list for method output_type + 6, // [6:8] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_supernode_supernode_proto_init() } @@ -576,7 +727,7 @@ func file_supernode_supernode_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_supernode_supernode_proto_rawDesc, NumEnums: 0, - NumMessages: 8, + NumMessages: 10, NumExtensions: 0, NumServices: 1, }, diff --git a/gen/supernode/supernode.swagger.json b/gen/supernode/supernode.swagger.json index 779075de..50e085a0 100644 --- a/gen/supernode/supernode.swagger.json +++ b/gen/supernode/supernode.swagger.json @@ -62,38 +62,83 @@ } }, "definitions": { - "StatusResponseCPU": { + "ResourcesCPU": { "type": "object", "properties": { - "usage": { - "type": "string" + "usagePercent": { + "type": "number", + "format": "double", + "title": "CPU usage percentage (0-100)" + } + } + }, + "ResourcesMemory": { + "type": "object", + "properties": { + "totalBytes": { + "type": "string", + "format": "uint64" }, - "remaining": { - "type": "string" + "usedBytes": { + "type": "string", + "format": "uint64" + }, + "availableBytes": { + "type": "string", + "format": "uint64" + }, + "usagePercent": { + "type": "number", + "format": "double", + "title": "Memory usage percentage (0-100)" } } }, - "StatusResponseMemory": { + "ResourcesStorage": { "type": "object", "properties": { - "total": { + "path": { + "type": "string", + "title": "Storage path being monitored" + }, + "totalBytes": { "type": "string", "format": "uint64" }, - "used": { + "usedBytes": { "type": "string", "format": "uint64" }, - "available": { + "availableBytes": { "type": "string", "format": "uint64" }, - "usedPerc": { + "usagePercent": { "type": "number", - "format": "double" + "format": "double", + "title": "Storage usage percentage (0-100)" } } }, + "StatusResponseResources": { + "type": "object", + "properties": { + "cpu": { + "$ref": "#/definitions/ResourcesCPU" + }, + "memory": { + "$ref": "#/definitions/ResourcesMemory" + }, + "storageVolumes": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/ResourcesStorage" + } + } + }, + "title": "System resource information" + }, "StatusResponseServiceTasks": { "type": "object", "properties": { @@ -174,11 +219,8 @@ "supernodeStatusResponse": { "type": "object", "properties": { - "cpu": { - "$ref": "#/definitions/StatusResponseCPU" - }, - "memory": { - "$ref": "#/definitions/StatusResponseMemory" + "resources": { + "$ref": "#/definitions/StatusResponseResources" }, "runningTasks": { "type": "array", @@ -196,7 +238,7 @@ "title": "All registered/available services" } }, - "description": "The StatusResponse represents system status." + "title": "The StatusResponse represents system status with clear organization" } } } diff --git a/proto/supernode/supernode.proto b/proto/supernode/supernode.proto index 9e7dfb09..efb98c27 100644 --- a/proto/supernode/supernode.proto +++ b/proto/supernode/supernode.proto @@ -33,29 +33,42 @@ message ServiceInfo { repeated string methods = 2; } -// The StatusResponse represents system status. +// The StatusResponse represents system status with clear organization message StatusResponse { - message CPU { - string usage = 1; - string remaining = 2; + // System resource information + message Resources { + message CPU { + double usage_percent = 1; // CPU usage percentage (0-100) + } + + message Memory { + uint64 total_bytes = 1; + uint64 used_bytes = 2; + uint64 available_bytes = 3; + double usage_percent = 4; // Memory usage percentage (0-100) + } + + message Storage { + string path = 1; // Storage path being monitored + uint64 total_bytes = 2; + uint64 used_bytes = 3; + uint64 available_bytes = 4; + double usage_percent = 5; // Storage usage percentage (0-100) + } + + CPU cpu = 1; + Memory memory = 2; + repeated Storage storage_volumes = 3; } - - message Memory { - uint64 total = 1; - uint64 used = 2; - uint64 available = 3; - double used_perc = 4; - } - + // ServiceTasks contains task information for a specific service message ServiceTasks { string service_name = 1; repeated string task_ids = 2; int32 task_count = 3; } - - CPU cpu = 1; - Memory memory = 2; - repeated ServiceTasks running_tasks = 3; // Services with currently running tasks - repeated string registered_services = 4; // All registered/available services + + Resources resources = 1; + repeated ServiceTasks running_tasks = 2; // Services with currently running tasks + repeated string registered_services = 3; // All registered/available services } \ No newline at end of file diff --git a/sdk/adapters/supernodeservice/adapter.go b/sdk/adapters/supernodeservice/adapter.go index 39000f37..d24f4df3 100644 --- a/sdk/adapters/supernodeservice/adapter.go +++ b/sdk/adapters/supernodeservice/adapter.go @@ -344,24 +344,38 @@ func toSdkEvent(e cascade.SupernodeEventType) event.EventType { func toSdkSupernodeStatus(resp *supernode.StatusResponse) *SupernodeStatusresponse { result := &SupernodeStatusresponse{} - // Convert CPU data - if resp.Cpu != nil { - result.CPU.Usage = resp.Cpu.Usage - result.CPU.Remaining = resp.Cpu.Remaining - } + // Convert Resources data + if resp.Resources != nil { + // Convert CPU data + if resp.Resources.Cpu != nil { + result.Resources.CPU.UsagePercent = resp.Resources.Cpu.UsagePercent + } + + // Convert Memory data + if resp.Resources.Memory != nil { + result.Resources.Memory.TotalBytes = resp.Resources.Memory.TotalBytes + result.Resources.Memory.UsedBytes = resp.Resources.Memory.UsedBytes + result.Resources.Memory.AvailableBytes = resp.Resources.Memory.AvailableBytes + result.Resources.Memory.UsagePercent = resp.Resources.Memory.UsagePercent + } - // Convert Memory data - if resp.Memory != nil { - result.Memory.Total = resp.Memory.Total - result.Memory.Used = resp.Memory.Used - result.Memory.Available = resp.Memory.Available - result.Memory.UsedPerc = resp.Memory.UsedPerc + // Convert Storage data + result.Resources.Storage = make([]StorageInfo, 0, len(resp.Resources.StorageVolumes)) + for _, storage := range resp.Resources.StorageVolumes { + result.Resources.Storage = append(result.Resources.Storage, StorageInfo{ + Path: storage.Path, + TotalBytes: storage.TotalBytes, + UsedBytes: storage.UsedBytes, + AvailableBytes: storage.AvailableBytes, + UsagePercent: storage.UsagePercent, + }) + } } // Convert RunningTasks data - result.Services = make([]ServiceTasks, 0, len(resp.RunningTasks)) + result.RunningTasks = make([]ServiceTasks, 0, len(resp.RunningTasks)) for _, service := range resp.RunningTasks { - result.Services = append(result.Services, ServiceTasks{ + result.RunningTasks = append(result.RunningTasks, ServiceTasks{ ServiceName: service.ServiceName, TaskIDs: service.TaskIds, TaskCount: service.TaskCount, @@ -369,8 +383,8 @@ func toSdkSupernodeStatus(resp *supernode.StatusResponse) *SupernodeStatusrespon } // Convert RegisteredServices data - result.AvailableServices = make([]string, len(resp.RegisteredServices)) - copy(result.AvailableServices, resp.RegisteredServices) + result.RegisteredServices = make([]string, len(resp.RegisteredServices)) + copy(result.RegisteredServices, resp.RegisteredServices) return result } diff --git a/sdk/adapters/supernodeservice/types.go b/sdk/adapters/supernodeservice/types.go index c6b88131..1d02cc9f 100644 --- a/sdk/adapters/supernodeservice/types.go +++ b/sdk/adapters/supernodeservice/types.go @@ -35,19 +35,30 @@ type ServiceTasks struct { TaskCount int32 } +// StorageInfo contains storage metrics for a specific path +type StorageInfo struct { + Path string + TotalBytes uint64 + UsedBytes uint64 + AvailableBytes uint64 + UsagePercent float64 +} + type SupernodeStatusresponse struct { - CPU struct { - Usage string - Remaining string - } - Memory struct { - Total uint64 - Used uint64 - Available uint64 - UsedPerc float64 + Resources struct { + CPU struct { + UsagePercent float64 + } + Memory struct { + TotalBytes uint64 + UsedBytes uint64 + AvailableBytes uint64 + UsagePercent float64 + } + Storage []StorageInfo } - Services []ServiceTasks - AvailableServices []string + RunningTasks []ServiceTasks // Services with running tasks + RegisteredServices []string // All available service names } type CascadeSupernodeDownloadRequest struct { ActionID string diff --git a/supernode/config/config.go b/supernode/config/config.go index 1f236df7..1ae876d0 100644 --- a/supernode/config/config.go +++ b/supernode/config/config.go @@ -21,9 +21,9 @@ type SupernodeConfig struct { type KeyringConfig struct { Backend string `yaml:"backend"` Dir string `yaml:"dir"` - PassPlain string `yaml:"passphrase_plain"` - PassEnv string `yaml:"passphrase_env"` - PassFile string `yaml:"passphrase_file"` + PassPlain string `yaml:"passphrase_plain,omitempty"` + PassEnv string `yaml:"passphrase_env,omitempty"` + PassFile string `yaml:"passphrase_file,omitempty"` } type P2PConfig struct { diff --git a/supernode/node/supernode/gateway/swagger.json b/supernode/node/supernode/gateway/swagger.json index 779075de..50e085a0 100644 --- a/supernode/node/supernode/gateway/swagger.json +++ b/supernode/node/supernode/gateway/swagger.json @@ -62,38 +62,83 @@ } }, "definitions": { - "StatusResponseCPU": { + "ResourcesCPU": { "type": "object", "properties": { - "usage": { - "type": "string" + "usagePercent": { + "type": "number", + "format": "double", + "title": "CPU usage percentage (0-100)" + } + } + }, + "ResourcesMemory": { + "type": "object", + "properties": { + "totalBytes": { + "type": "string", + "format": "uint64" }, - "remaining": { - "type": "string" + "usedBytes": { + "type": "string", + "format": "uint64" + }, + "availableBytes": { + "type": "string", + "format": "uint64" + }, + "usagePercent": { + "type": "number", + "format": "double", + "title": "Memory usage percentage (0-100)" } } }, - "StatusResponseMemory": { + "ResourcesStorage": { "type": "object", "properties": { - "total": { + "path": { + "type": "string", + "title": "Storage path being monitored" + }, + "totalBytes": { "type": "string", "format": "uint64" }, - "used": { + "usedBytes": { "type": "string", "format": "uint64" }, - "available": { + "availableBytes": { "type": "string", "format": "uint64" }, - "usedPerc": { + "usagePercent": { "type": "number", - "format": "double" + "format": "double", + "title": "Storage usage percentage (0-100)" } } }, + "StatusResponseResources": { + "type": "object", + "properties": { + "cpu": { + "$ref": "#/definitions/ResourcesCPU" + }, + "memory": { + "$ref": "#/definitions/ResourcesMemory" + }, + "storageVolumes": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/ResourcesStorage" + } + } + }, + "title": "System resource information" + }, "StatusResponseServiceTasks": { "type": "object", "properties": { @@ -174,11 +219,8 @@ "supernodeStatusResponse": { "type": "object", "properties": { - "cpu": { - "$ref": "#/definitions/StatusResponseCPU" - }, - "memory": { - "$ref": "#/definitions/StatusResponseMemory" + "resources": { + "$ref": "#/definitions/StatusResponseResources" }, "runningTasks": { "type": "array", @@ -196,7 +238,7 @@ "title": "All registered/available services" } }, - "description": "The StatusResponse represents system status." + "title": "The StatusResponse represents system status with clear organization" } } } diff --git a/supernode/node/supernode/server/status_server.go b/supernode/node/supernode/server/status_server.go index e46add36..a75e2cf5 100644 --- a/supernode/node/supernode/server/status_server.go +++ b/supernode/node/supernode/server/status_server.go @@ -60,20 +60,34 @@ func (s *SupernodeServer) GetStatus(ctx context.Context, req *pb.StatusRequest) // Convert to protobuf response response := &pb.StatusResponse{ - Cpu: &pb.StatusResponse_CPU{ - Usage: status.CPU.Usage, - Remaining: status.CPU.Remaining, - }, - Memory: &pb.StatusResponse_Memory{ - Total: status.Memory.Total, - Used: status.Memory.Used, - Available: status.Memory.Available, - UsedPerc: status.Memory.UsedPerc, + Resources: &pb.StatusResponse_Resources{ + Cpu: &pb.StatusResponse_Resources_CPU{ + UsagePercent: status.Resources.CPU.UsagePercent, + }, + Memory: &pb.StatusResponse_Resources_Memory{ + TotalBytes: status.Resources.Memory.TotalBytes, + UsedBytes: status.Resources.Memory.UsedBytes, + AvailableBytes: status.Resources.Memory.AvailableBytes, + UsagePercent: status.Resources.Memory.UsagePercent, + }, + StorageVolumes: make([]*pb.StatusResponse_Resources_Storage, 0, len(status.Resources.Storage)), }, RunningTasks: make([]*pb.StatusResponse_ServiceTasks, 0, len(status.RunningTasks)), RegisteredServices: status.RegisteredServices, } + // Convert storage information + for _, storage := range status.Resources.Storage { + storageInfo := &pb.StatusResponse_Resources_Storage{ + Path: storage.Path, + TotalBytes: storage.TotalBytes, + UsedBytes: storage.UsedBytes, + AvailableBytes: storage.AvailableBytes, + UsagePercent: storage.UsagePercent, + } + response.Resources.StorageVolumes = append(response.Resources.StorageVolumes, storageInfo) + } + // Convert service tasks for _, service := range status.RunningTasks { serviceTask := &pb.StatusResponse_ServiceTasks{ diff --git a/supernode/node/supernode/server/status_server_test.go b/supernode/node/supernode/server/status_server_test.go index 712d9a1a..6d3b3680 100644 --- a/supernode/node/supernode/server/status_server_test.go +++ b/supernode/node/supernode/server/status_server_test.go @@ -27,11 +27,24 @@ func TestSupernodeServer_GetStatus(t *testing.T) { assert.NotNil(t, resp) // Check basic structure - assert.NotNil(t, resp.Cpu) - assert.NotNil(t, resp.Memory) - assert.NotEmpty(t, resp.Cpu.Usage) - assert.NotEmpty(t, resp.Cpu.Remaining) - assert.True(t, resp.Memory.Total > 0) + assert.NotNil(t, resp.Resources) + assert.NotNil(t, resp.Resources.Cpu) + assert.NotNil(t, resp.Resources.Memory) + assert.NotNil(t, resp.RunningTasks) + assert.NotNil(t, resp.RegisteredServices) + + // Check CPU metrics + assert.True(t, resp.Resources.Cpu.UsagePercent >= 0) + assert.True(t, resp.Resources.Cpu.UsagePercent <= 100) + + // Check Memory metrics + assert.True(t, resp.Resources.Memory.TotalBytes > 0) + assert.True(t, resp.Resources.Memory.UsagePercent >= 0) + assert.True(t, resp.Resources.Memory.UsagePercent <= 100) + + // Check Storage (should have default root filesystem) + assert.NotEmpty(t, resp.Resources.StorageVolumes) + assert.Equal(t, "/", resp.Resources.StorageVolumes[0].Path) // Should have no services initially assert.Empty(t, resp.RunningTasks) diff --git a/supernode/services/cascade/status_test.go b/supernode/services/cascade/status_test.go index 543bdf90..aaaf73c9 100644 --- a/supernode/services/cascade/status_test.go +++ b/supernode/services/cascade/status_test.go @@ -65,13 +65,17 @@ func TestGetStatus(t *testing.T) { assert.NoError(t, err) // CPU checks - assert.NotEmpty(t, resp.CPU.Usage) - assert.NotEmpty(t, resp.CPU.Remaining) + assert.True(t, resp.Resources.CPU.UsagePercent >= 0) + assert.True(t, resp.Resources.CPU.UsagePercent <= 100) // Memory checks - assert.True(t, resp.Memory.Total > 0) - assert.True(t, resp.Memory.Used <= resp.Memory.Total) - assert.True(t, resp.Memory.UsedPerc >= 0 && resp.Memory.UsedPerc <= 100) + assert.True(t, resp.Resources.Memory.TotalBytes > 0) + assert.True(t, resp.Resources.Memory.UsedBytes <= resp.Resources.Memory.TotalBytes) + assert.True(t, resp.Resources.Memory.UsagePercent >= 0 && resp.Resources.Memory.UsagePercent <= 100) + + // Storage checks - should have default root filesystem + assert.NotEmpty(t, resp.Resources.Storage) + assert.Equal(t, "/", resp.Resources.Storage[0].Path) // Registered services check assert.Contains(t, resp.RegisteredServices, "cascade") diff --git a/supernode/services/common/supernode/metrics.go b/supernode/services/common/supernode/metrics.go index 180dd8f4..8c30b612 100644 --- a/supernode/services/common/supernode/metrics.go +++ b/supernode/services/common/supernode/metrics.go @@ -2,11 +2,11 @@ package supernode import ( "context" - "fmt" "time" "github.com/LumeraProtocol/supernode/pkg/logtrace" "github.com/shirou/gopsutil/v3/cpu" + "github.com/shirou/gopsutil/v3/disk" "github.com/shirou/gopsutil/v3/mem" ) @@ -19,18 +19,15 @@ func NewMetricsCollector() *MetricsCollector { } // CollectCPUMetrics gathers CPU usage information -// Returns usage and remaining percentages as formatted strings -func (m *MetricsCollector) CollectCPUMetrics(ctx context.Context) (usage, remaining string, err error) { +// Returns usage percentage as a float64 +func (m *MetricsCollector) CollectCPUMetrics(ctx context.Context) (float64, error) { percentages, err := cpu.Percent(time.Second, false) if err != nil { logtrace.Error(ctx, "failed to get cpu info", logtrace.Fields{logtrace.FieldError: err.Error()}) - return "", "", err + return 0, err } - usageFloat := percentages[0] - remainingFloat := 100 - usageFloat - - return fmt.Sprintf("%.2f", usageFloat), fmt.Sprintf("%.2f", remainingFloat), nil + return percentages[0], nil } // CollectMemoryMetrics gathers memory usage information @@ -44,3 +41,34 @@ func (m *MetricsCollector) CollectMemoryMetrics(ctx context.Context) (total, use return vmem.Total, vmem.Used, vmem.Available, vmem.UsedPercent, nil } + +// CollectStorageMetrics gathers storage usage information for specified paths +// If paths is empty, it will collect metrics for the root filesystem +func (m *MetricsCollector) CollectStorageMetrics(ctx context.Context, paths []string) []StorageInfo { + if len(paths) == 0 { + // Default to root filesystem + paths = []string{"/"} + } + + var storageInfos []StorageInfo + for _, path := range paths { + usage, err := disk.Usage(path) + if err != nil { + logtrace.Error(ctx, "failed to get storage info", logtrace.Fields{ + logtrace.FieldError: err.Error(), + "path": path, + }) + continue // Skip this path but continue with others + } + + storageInfos = append(storageInfos, StorageInfo{ + Path: path, + TotalBytes: usage.Total, + UsedBytes: usage.Used, + AvailableBytes: usage.Free, + UsagePercent: usage.UsedPercent, + }) + } + + return storageInfos +} diff --git a/supernode/services/common/supernode/service.go b/supernode/services/common/supernode/service.go index 4484e688..56bbc2a9 100644 --- a/supernode/services/common/supernode/service.go +++ b/supernode/services/common/supernode/service.go @@ -11,6 +11,7 @@ import ( type SupernodeStatusService struct { taskProviders []TaskProvider // List of registered services that provide task information metrics *MetricsCollector // System metrics collector for CPU and memory stats + storagePaths []string // Paths to monitor for storage metrics } // NewSupernodeStatusService creates a new supernode status service instance @@ -18,6 +19,7 @@ func NewSupernodeStatusService() *SupernodeStatusService { return &SupernodeStatusService{ taskProviders: make([]TaskProvider, 0), metrics: NewMetricsCollector(), + storagePaths: []string{"/"}, // Default to monitoring root filesystem } } @@ -39,22 +41,24 @@ func (s *SupernodeStatusService) GetStatus(ctx context.Context) (StatusResponse, var resp StatusResponse // Collect CPU metrics - cpuUsage, cpuRemaining, err := s.metrics.CollectCPUMetrics(ctx) + cpuUsage, err := s.metrics.CollectCPUMetrics(ctx) if err != nil { return resp, err } - resp.CPU.Usage = cpuUsage - resp.CPU.Remaining = cpuRemaining + resp.Resources.CPU.UsagePercent = cpuUsage // Collect memory metrics memTotal, memUsed, memAvailable, memUsedPerc, err := s.metrics.CollectMemoryMetrics(ctx) if err != nil { return resp, err } - resp.Memory.Total = memTotal - resp.Memory.Used = memUsed - resp.Memory.Available = memAvailable - resp.Memory.UsedPerc = memUsedPerc + resp.Resources.Memory.TotalBytes = memTotal + resp.Resources.Memory.UsedBytes = memUsed + resp.Resources.Memory.AvailableBytes = memAvailable + resp.Resources.Memory.UsagePercent = memUsedPerc + + // Collect storage metrics + resp.Resources.Storage = s.metrics.CollectStorageMetrics(ctx, s.storagePaths) // Collect service information from all registered providers resp.RunningTasks = make([]ServiceTasks, 0, len(s.taskProviders)) @@ -83,13 +87,13 @@ func (s *SupernodeStatusService) GetStatus(ctx context.Context) (StatusResponse, } logtrace.Info(ctx, "status data collected", logtrace.Fields{ - "cpu_usage": cpuUsage, - "cpu_remaining": cpuRemaining, - "mem_total": memTotal, - "mem_used": memUsed, - "mem_used%": memUsedPerc, - "service_count": len(resp.RunningTasks), - "total_tasks": totalTasks, + "cpu_usage%": cpuUsage, + "mem_total": memTotal, + "mem_used": memUsed, + "mem_usage%": memUsedPerc, + "storage_volumes": len(resp.Resources.Storage), + "service_count": len(resp.RunningTasks), + "total_tasks": totalTasks, }) return resp, nil diff --git a/supernode/services/common/supernode/service_test.go b/supernode/services/common/supernode/service_test.go index 5bc55cdc..d7956bf6 100644 --- a/supernode/services/common/supernode/service_test.go +++ b/supernode/services/common/supernode/service_test.go @@ -18,9 +18,15 @@ func TestSupernodeStatusService(t *testing.T) { assert.NoError(t, err) // Should have CPU and Memory info - assert.NotEmpty(t, resp.CPU.Usage) - assert.NotEmpty(t, resp.CPU.Remaining) - assert.True(t, resp.Memory.Total > 0) + assert.True(t, resp.Resources.CPU.UsagePercent >= 0) + assert.True(t, resp.Resources.CPU.UsagePercent <= 100) + assert.True(t, resp.Resources.Memory.TotalBytes > 0) + assert.True(t, resp.Resources.Memory.UsagePercent >= 0) + assert.True(t, resp.Resources.Memory.UsagePercent <= 100) + + // Should have storage info (default root filesystem) + assert.NotEmpty(t, resp.Resources.Storage) + assert.Equal(t, "/", resp.Resources.Storage[0].Path) // Should have empty services list assert.Empty(t, resp.RunningTasks) diff --git a/supernode/services/common/supernode/types.go b/supernode/services/common/supernode/types.go index 77e71d35..1f81a7b5 100644 --- a/supernode/services/common/supernode/types.go +++ b/supernode/services/common/supernode/types.go @@ -1,20 +1,40 @@ package supernode // StatusResponse represents the complete system status information -// including CPU usage, memory statistics, and service details +// with clear organization of resources and services type StatusResponse struct { - CPU struct { - Usage string // CPU usage percentage as string (e.g., "45.32") - Remaining string // Remaining CPU capacity as string (e.g., "54.68") - } - Memory struct { - Total uint64 // Total memory in bytes - Used uint64 // Used memory in bytes - Available uint64 // Available memory in bytes - UsedPerc float64 // Memory usage percentage (0-100) - } - RunningTasks []ServiceTasks // List of services with their running task counts - RegisteredServices []string // Names of all registered/available services + Resources Resources // System resource information + RunningTasks []ServiceTasks // Services with currently running tasks + RegisteredServices []string // All registered/available services +} + +// Resources contains system resource metrics +type Resources struct { + CPU CPUInfo // CPU usage information + Memory MemoryInfo // Memory usage information + Storage []StorageInfo // Storage volumes information +} + +// CPUInfo contains CPU usage metrics +type CPUInfo struct { + UsagePercent float64 // CPU usage percentage (0-100) +} + +// MemoryInfo contains memory usage metrics +type MemoryInfo struct { + TotalBytes uint64 // Total memory in bytes + UsedBytes uint64 // Used memory in bytes + AvailableBytes uint64 // Available memory in bytes + UsagePercent float64 // Memory usage percentage (0-100) +} + +// StorageInfo contains storage metrics for a specific path +type StorageInfo struct { + Path string // Storage path being monitored + TotalBytes uint64 // Total storage in bytes + UsedBytes uint64 // Used storage in bytes + AvailableBytes uint64 // Available storage in bytes + UsagePercent float64 // Storage usage percentage (0-100) } // ServiceTasks contains task information for a specific service From 481b013d9ed12fc402ddbb8e50f8f085733909e7 Mon Sep 17 00:00:00 2001 From: Matee Ullah Malik Date: Sat, 2 Aug 2025 06:41:16 +0500 Subject: [PATCH 2/3] feat: add version field to Supernode status response --- gen/supernode/supernode.pb.go | 166 ++++++++++-------- gen/supernode/supernode.swagger.json | 4 + proto/supernode/supernode.proto | 8 +- sdk/adapters/supernodeservice/adapter.go | 1 + sdk/adapters/supernodeservice/types.go | 1 + supernode/cmd/start.go | 3 + supernode/node/supernode/gateway/swagger.json | 4 + .../node/supernode/server/status_server.go | 1 + .../supernode/server/status_server_test.go | 3 + supernode/services/cascade/download.go | 2 - supernode/services/cascade/interfaces.go | 3 - .../cascade/mocks/cascade_interfaces_mock.go | 16 -- supernode/services/cascade/status.go | 5 - supernode/services/cascade/status_test.go | 3 + supernode/services/cascade/task.go | 1 + .../services/common/supernode/service.go | 4 + .../services/common/supernode/service_test.go | 3 + supernode/services/common/supernode/types.go | 1 + 18 files changed, 122 insertions(+), 107 deletions(-) diff --git a/gen/supernode/supernode.pb.go b/gen/supernode/supernode.pb.go index 6a49428f..3c574cd7 100644 --- a/gen/supernode/supernode.pb.go +++ b/gen/supernode/supernode.pb.go @@ -205,9 +205,10 @@ type StatusResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Resources *StatusResponse_Resources `protobuf:"bytes,1,opt,name=resources,proto3" json:"resources,omitempty"` - RunningTasks []*StatusResponse_ServiceTasks `protobuf:"bytes,2,rep,name=running_tasks,json=runningTasks,proto3" json:"running_tasks,omitempty"` // Services with currently running tasks - RegisteredServices []string `protobuf:"bytes,3,rep,name=registered_services,json=registeredServices,proto3" json:"registered_services,omitempty"` // All registered/available services + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` // Supernode version + Resources *StatusResponse_Resources `protobuf:"bytes,2,opt,name=resources,proto3" json:"resources,omitempty"` + RunningTasks []*StatusResponse_ServiceTasks `protobuf:"bytes,3,rep,name=running_tasks,json=runningTasks,proto3" json:"running_tasks,omitempty"` // Services with currently running tasks + RegisteredServices []string `protobuf:"bytes,4,rep,name=registered_services,json=registeredServices,proto3" json:"registered_services,omitempty"` // All registered/available services } func (x *StatusResponse) Reset() { @@ -240,6 +241,13 @@ func (*StatusResponse) Descriptor() ([]byte, []int) { return file_supernode_supernode_proto_rawDescGZIP(), []int{4} } +func (x *StatusResponse) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + func (x *StatusResponse) GetResources() *StatusResponse_Resources { if x != nil { return x.Resources @@ -595,82 +603,84 @@ var file_supernode_supernode_proto_rawDesc = []byte{ 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0x94, 0x07, 0x0a, 0x0e, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, - 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x12, 0x4b, 0x0a, 0x0d, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x73, - 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x73, - 0x52, 0x0c, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x2f, - 0x0a, 0x13, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x1a, - 0xd3, 0x04, 0x0a, 0x09, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x39, 0x0a, - 0x03, 0x63, 0x70, 0x75, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x75, 0x70, - 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, - 0x43, 0x50, 0x55, 0x52, 0x03, 0x63, 0x70, 0x75, 0x12, 0x42, 0x0a, 0x06, 0x6d, 0x65, 0x6d, 0x6f, - 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4d, 0x65, - 0x6d, 0x6f, 0x72, 0x79, 0x52, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x54, 0x0a, 0x0f, - 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, - 0x65, 0x73, 0x1a, 0x2a, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, - 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0x96, - 0x01, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, - 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, - 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, - 0x75, 0x73, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x76, 0x61, - 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x79, 0x74, - 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, - 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, - 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0xab, 0x01, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, - 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x64, - 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x75, 0x73, - 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x76, 0x61, 0x69, 0x6c, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, - 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, - 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, - 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0x6b, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x61, 0x73, 0x6b, - 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x73, 0x6b, - 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x32, 0xd7, 0x01, 0x0a, 0x10, 0x53, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, + 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0xae, 0x07, 0x0a, 0x0e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x75, + 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x0d, 0x72, + 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x0c, 0x72, 0x75, 0x6e, 0x6e, + 0x69, 0x6e, 0x67, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, + 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x1a, 0xd3, 0x04, 0x0a, 0x09, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x03, 0x63, 0x70, 0x75, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x43, 0x50, 0x55, 0x52, 0x03, 0x63, + 0x70, 0x75, 0x12, 0x42, 0x0a, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x52, 0x06, + 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x54, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x5f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x2b, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x0e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x1a, 0x2a, 0x0a, 0x03, + 0x43, 0x50, 0x55, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, + 0x63, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, + 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0x96, 0x01, 0x0a, 0x06, 0x4d, 0x65, 0x6d, + 0x6f, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, + 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x75, 0x73, 0x65, 0x64, 0x42, 0x79, + 0x74, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x61, 0x76, + 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, + 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, + 0x74, 0x1a, 0xab, 0x01, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, + 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, + 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x75, 0x73, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, + 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x61, 0x76, 0x61, 0x69, + 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, + 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, + 0x6b, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, + 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, + 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0xd7, 0x01, 0x0a, + 0x10, 0x53, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x58, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x69, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x12, 0x1e, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x33, 0x5a, 0x31, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4c, 0x75, 0x6d, 0x65, 0x72, - 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, - 0x6f, 0x64, 0x65, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, - 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x69, 0x0a, 0x0c, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x73, 0x75, + 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x75, + 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4c, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x67, 0x65, + 0x6e, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/gen/supernode/supernode.swagger.json b/gen/supernode/supernode.swagger.json index 50e085a0..f8ceac27 100644 --- a/gen/supernode/supernode.swagger.json +++ b/gen/supernode/supernode.swagger.json @@ -219,6 +219,10 @@ "supernodeStatusResponse": { "type": "object", "properties": { + "version": { + "type": "string", + "title": "Supernode version" + }, "resources": { "$ref": "#/definitions/StatusResponseResources" }, diff --git a/proto/supernode/supernode.proto b/proto/supernode/supernode.proto index efb98c27..61f85d8b 100644 --- a/proto/supernode/supernode.proto +++ b/proto/supernode/supernode.proto @@ -35,6 +35,8 @@ message ServiceInfo { // The StatusResponse represents system status with clear organization message StatusResponse { + string version = 1; // Supernode version + // System resource information message Resources { message CPU { @@ -68,7 +70,7 @@ message StatusResponse { int32 task_count = 3; } - Resources resources = 1; - repeated ServiceTasks running_tasks = 2; // Services with currently running tasks - repeated string registered_services = 3; // All registered/available services + Resources resources = 2; + repeated ServiceTasks running_tasks = 3; // Services with currently running tasks + repeated string registered_services = 4; // All registered/available services } \ No newline at end of file diff --git a/sdk/adapters/supernodeservice/adapter.go b/sdk/adapters/supernodeservice/adapter.go index d24f4df3..bbc0375d 100644 --- a/sdk/adapters/supernodeservice/adapter.go +++ b/sdk/adapters/supernodeservice/adapter.go @@ -343,6 +343,7 @@ func toSdkEvent(e cascade.SupernodeEventType) event.EventType { func toSdkSupernodeStatus(resp *supernode.StatusResponse) *SupernodeStatusresponse { result := &SupernodeStatusresponse{} + result.Version = resp.Version // Convert Resources data if resp.Resources != nil { diff --git a/sdk/adapters/supernodeservice/types.go b/sdk/adapters/supernodeservice/types.go index 1d02cc9f..d80edb0a 100644 --- a/sdk/adapters/supernodeservice/types.go +++ b/sdk/adapters/supernodeservice/types.go @@ -45,6 +45,7 @@ type StorageInfo struct { } type SupernodeStatusresponse struct { + Version string // Supernode version Resources struct { CPU struct { UsagePercent float64 diff --git a/supernode/cmd/start.go b/supernode/cmd/start.go index 7a991a40..30abcacc 100644 --- a/supernode/cmd/start.go +++ b/supernode/cmd/start.go @@ -101,6 +101,9 @@ The supernode will connect to the Lumera network and begin participating in the // Create cascade action server cascadeActionServer := cascade.NewCascadeActionServer(cService) + // Set the version in the status service package + supernodeService.Version = Version + // Create supernode status service statusService := supernodeService.NewSupernodeStatusService() statusService.RegisterTaskProvider(cService) diff --git a/supernode/node/supernode/gateway/swagger.json b/supernode/node/supernode/gateway/swagger.json index 50e085a0..f8ceac27 100644 --- a/supernode/node/supernode/gateway/swagger.json +++ b/supernode/node/supernode/gateway/swagger.json @@ -219,6 +219,10 @@ "supernodeStatusResponse": { "type": "object", "properties": { + "version": { + "type": "string", + "title": "Supernode version" + }, "resources": { "$ref": "#/definitions/StatusResponseResources" }, diff --git a/supernode/node/supernode/server/status_server.go b/supernode/node/supernode/server/status_server.go index a75e2cf5..4cd87d9e 100644 --- a/supernode/node/supernode/server/status_server.go +++ b/supernode/node/supernode/server/status_server.go @@ -60,6 +60,7 @@ func (s *SupernodeServer) GetStatus(ctx context.Context, req *pb.StatusRequest) // Convert to protobuf response response := &pb.StatusResponse{ + Version: status.Version, Resources: &pb.StatusResponse_Resources{ Cpu: &pb.StatusResponse_Resources_CPU{ UsagePercent: status.Resources.CPU.UsagePercent, diff --git a/supernode/node/supernode/server/status_server_test.go b/supernode/node/supernode/server/status_server_test.go index 6d3b3680..a47e18e5 100644 --- a/supernode/node/supernode/server/status_server_test.go +++ b/supernode/node/supernode/server/status_server_test.go @@ -32,6 +32,9 @@ func TestSupernodeServer_GetStatus(t *testing.T) { assert.NotNil(t, resp.Resources.Memory) assert.NotNil(t, resp.RunningTasks) assert.NotNil(t, resp.RegisteredServices) + + // Check version field + assert.NotEmpty(t, resp.Version) // Check CPU metrics assert.True(t, resp.Resources.Cpu.UsagePercent >= 0) diff --git a/supernode/services/cascade/download.go b/supernode/services/cascade/download.go index ddd80516..f9823a00 100644 --- a/supernode/services/cascade/download.go +++ b/supernode/services/cascade/download.go @@ -188,8 +188,6 @@ func (task *CascadeRegistrationTask) streamDownloadEvent(eventType SupernodeEven FilePath: filePath, DownloadedDir: tmpDir, }) - - return } // parseIndexFile parses compressed index file to extract IndexFile structure diff --git a/supernode/services/cascade/interfaces.go b/supernode/services/cascade/interfaces.go index 4885648f..e782bc23 100644 --- a/supernode/services/cascade/interfaces.go +++ b/supernode/services/cascade/interfaces.go @@ -2,8 +2,6 @@ package cascade import ( "context" - - "github.com/LumeraProtocol/supernode/supernode/services/common/supernode" ) // CascadeServiceFactory defines an interface to create cascade tasks @@ -16,7 +14,6 @@ type CascadeServiceFactory interface { // CascadeTask interface defines operations for cascade registration and data management type CascadeTask interface { Register(ctx context.Context, req *RegisterRequest, send func(resp *RegisterResponse) error) error - GetStatus(ctx context.Context) (supernode.StatusResponse, error) Download(ctx context.Context, req *DownloadRequest, send func(resp *DownloadResponse) error) error CleanupDownload(ctx context.Context, actionID string) error } diff --git a/supernode/services/cascade/mocks/cascade_interfaces_mock.go b/supernode/services/cascade/mocks/cascade_interfaces_mock.go index eae5b750..3552e517 100644 --- a/supernode/services/cascade/mocks/cascade_interfaces_mock.go +++ b/supernode/services/cascade/mocks/cascade_interfaces_mock.go @@ -14,7 +14,6 @@ import ( reflect "reflect" cascade "github.com/LumeraProtocol/supernode/supernode/services/cascade" - supernode "github.com/LumeraProtocol/supernode/supernode/services/common/supernode" gomock "go.uber.org/mock/gomock" ) @@ -108,21 +107,6 @@ func (mr *MockCascadeTaskMockRecorder) Download(ctx, req, send any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Download", reflect.TypeOf((*MockCascadeTask)(nil).Download), ctx, req, send) } -// GetStatus mocks base method. -func (m *MockCascadeTask) GetStatus(ctx context.Context) (supernode.StatusResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetStatus", ctx) - ret0, _ := ret[0].(supernode.StatusResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetStatus indicates an expected call of GetStatus. -func (mr *MockCascadeTaskMockRecorder) GetStatus(ctx any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStatus", reflect.TypeOf((*MockCascadeTask)(nil).GetStatus), ctx) -} - // Register mocks base method. func (m *MockCascadeTask) Register(ctx context.Context, req *cascade.RegisterRequest, send func(*cascade.RegisterResponse) error) error { m.ctrl.T.Helper() diff --git a/supernode/services/cascade/status.go b/supernode/services/cascade/status.go index f974ba36..5746f4c3 100644 --- a/supernode/services/cascade/status.go +++ b/supernode/services/cascade/status.go @@ -18,8 +18,3 @@ func (service *CascadeService) GetStatus(ctx context.Context) (StatusResponse, e // Get the status from the common service return statusService.GetStatus(ctx) } - -// GetStatus method for task interface compatibility -func (task *CascadeRegistrationTask) GetStatus(ctx context.Context) (StatusResponse, error) { - return task.CascadeService.GetStatus(ctx) -} diff --git a/supernode/services/cascade/status_test.go b/supernode/services/cascade/status_test.go index aaaf73c9..b594075c 100644 --- a/supernode/services/cascade/status_test.go +++ b/supernode/services/cascade/status_test.go @@ -64,6 +64,9 @@ func TestGetStatus(t *testing.T) { assert.NoError(t, err) + // Version check + assert.NotEmpty(t, resp.Version) + // CPU checks assert.True(t, resp.Resources.CPU.UsagePercent >= 0) assert.True(t, resp.Resources.CPU.UsagePercent <= 100) diff --git a/supernode/services/cascade/task.go b/supernode/services/cascade/task.go index 538214cf..66fe663f 100644 --- a/supernode/services/cascade/task.go +++ b/supernode/services/cascade/task.go @@ -2,6 +2,7 @@ package cascade import ( "context" + "github.com/LumeraProtocol/supernode/pkg/storage/files" "github.com/LumeraProtocol/supernode/supernode/services/common/base" "github.com/LumeraProtocol/supernode/supernode/services/common/storage" diff --git a/supernode/services/common/supernode/service.go b/supernode/services/common/supernode/service.go index 56bbc2a9..9000d8e5 100644 --- a/supernode/services/common/supernode/service.go +++ b/supernode/services/common/supernode/service.go @@ -6,6 +6,9 @@ import ( "github.com/LumeraProtocol/supernode/pkg/logtrace" ) +// Version is the supernode version, set by the main application +var Version = "dev" + // SupernodeStatusService provides centralized status information // by collecting system metrics and aggregating task information from registered services type SupernodeStatusService struct { @@ -39,6 +42,7 @@ func (s *SupernodeStatusService) GetStatus(ctx context.Context) (StatusResponse, logtrace.Info(ctx, "status request received", fields) var resp StatusResponse + resp.Version = Version // Collect CPU metrics cpuUsage, err := s.metrics.CollectCPUMetrics(ctx) diff --git a/supernode/services/common/supernode/service_test.go b/supernode/services/common/supernode/service_test.go index d7956bf6..cabc67cf 100644 --- a/supernode/services/common/supernode/service_test.go +++ b/supernode/services/common/supernode/service_test.go @@ -16,6 +16,9 @@ func TestSupernodeStatusService(t *testing.T) { resp, err := statusService.GetStatus(ctx) assert.NoError(t, err) + + // Should have version info + assert.NotEmpty(t, resp.Version) // Should have CPU and Memory info assert.True(t, resp.Resources.CPU.UsagePercent >= 0) diff --git a/supernode/services/common/supernode/types.go b/supernode/services/common/supernode/types.go index 1f81a7b5..3e70fa0e 100644 --- a/supernode/services/common/supernode/types.go +++ b/supernode/services/common/supernode/types.go @@ -3,6 +3,7 @@ package supernode // StatusResponse represents the complete system status information // with clear organization of resources and services type StatusResponse struct { + Version string // Supernode version Resources Resources // System resource information RunningTasks []ServiceTasks // Services with currently running tasks RegisteredServices []string // All registered/available services From a580fefd88080c9c455d2827668b3380b01f2195 Mon Sep 17 00:00:00 2001 From: Matee Ullah Malik Date: Mon, 4 Aug 2025 20:09:57 +0500 Subject: [PATCH 3/3] feat: Enhance supernode status response with additional metrics --- README.md | 58 ++- gen/supernode/supernode.pb.go | 355 ++++++++++++------ gen/supernode/supernode.swagger.json | 66 +++- proto/supernode/supernode.proto | 24 +- sdk/adapters/supernodeservice/adapter.go | 22 +- sdk/adapters/supernodeservice/types.go | 17 +- supernode/cmd/start.go | 2 +- supernode/node/supernode/gateway/swagger.json | 66 +++- .../node/supernode/server/status_server.go | 21 +- .../supernode/server/status_server_test.go | 26 +- supernode/services/cascade/status.go | 4 +- supernode/services/cascade/status_test.go | 21 +- .../services/common/supernode/metrics.go | 11 + .../services/common/supernode/service.go | 114 +++++- .../services/common/supernode/service_test.go | 25 +- supernode/services/common/supernode/types.go | 26 +- 16 files changed, 660 insertions(+), 198 deletions(-) diff --git a/README.md b/README.md index af610801..3de40c60 100644 --- a/README.md +++ b/README.md @@ -18,29 +18,34 @@ service SupernodeService { message StatusRequest {} message StatusResponse { + string version = 1; // Supernode version + uint64 uptime_seconds = 2; // Uptime in seconds + message Resources { message CPU { - double usage_percent = 1; + double usage_percent = 1; // CPU usage percentage (0-100) + int32 cores = 2; // Number of CPU cores } message Memory { - uint64 total_bytes = 1; - uint64 used_bytes = 2; - uint64 available_bytes = 3; - double usage_percent = 4; + double total_gb = 1; // Total memory in GB + double used_gb = 2; // Used memory in GB + double available_gb = 3; // Available memory in GB + double usage_percent = 4; // Memory usage percentage (0-100) } message Storage { - string path = 1; + string path = 1; // Storage path being monitored uint64 total_bytes = 2; uint64 used_bytes = 3; uint64 available_bytes = 4; - double usage_percent = 5; + double usage_percent = 5; // Storage usage percentage (0-100) } CPU cpu = 1; Memory memory = 2; repeated Storage storage_volumes = 3; + string hardware_summary = 4; // Formatted hardware summary (e.g., "8 cores / 32GB RAM") } message ServiceTasks { @@ -49,9 +54,17 @@ message StatusResponse { int32 task_count = 3; } - Resources resources = 1; - repeated ServiceTasks running_tasks = 2; - repeated string registered_services = 3; + message Network { + int32 peers_count = 1; // Number of connected peers in P2P network + repeated string peer_addresses = 2; // List of connected peer addresses (format: "ID@IP:Port") + } + + Resources resources = 3; + repeated ServiceTasks running_tasks = 4; // Services with currently running tasks + repeated string registered_services = 5; // All registered/available services + Network network = 6; // P2P network information + int32 rank = 7; // Rank in the top supernodes list (0 if not in top list) + string ip_address = 8; // Supernode IP address with port (e.g., "192.168.1.1:4445") } ``` @@ -137,14 +150,17 @@ curl http://localhost:8002/api/v1/status Response: ```json { + "version": "1.0.0", + "uptime_seconds": "3600", "resources": { "cpu": { - "usage_percent": 15.2 + "usage_percent": 15.2, + "cores": 8 }, "memory": { - "total_bytes": "16777216000", - "used_bytes": "8388608000", - "available_bytes": "8388608000", + "total_gb": 32.0, + "used_gb": 16.0, + "available_gb": 16.0, "usage_percent": 50.0 }, "storage_volumes": [ @@ -155,7 +171,8 @@ Response: "available_bytes": "250000000000", "usage_percent": 50.0 } - ] + ], + "hardware_summary": "8 cores / 32GB RAM" }, "running_tasks": [ { @@ -164,7 +181,16 @@ Response: "task_count": 2 } ], - "registered_services": ["cascade", "sense"] + "registered_services": ["cascade", "sense"], + "network": { + "peers_count": 11, + "peer_addresses": [ + "lumera13z4pkmgkr587sg6lkqnmqmqkkfpsau3rmjd5kx@156.67.29.226:4445", + "lumera1s55nzsyqsuwxsl3es0v7rxux7rypsa7zpzlqg5@18.216.80.56:4445" + ] + }, + "rank": 6, + "ip_address": "192.168.1.100:4445" } ``` diff --git a/gen/supernode/supernode.pb.go b/gen/supernode/supernode.pb.go index 3c574cd7..1ace0f23 100644 --- a/gen/supernode/supernode.pb.go +++ b/gen/supernode/supernode.pb.go @@ -205,10 +205,14 @@ type StatusResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` // Supernode version - Resources *StatusResponse_Resources `protobuf:"bytes,2,opt,name=resources,proto3" json:"resources,omitempty"` - RunningTasks []*StatusResponse_ServiceTasks `protobuf:"bytes,3,rep,name=running_tasks,json=runningTasks,proto3" json:"running_tasks,omitempty"` // Services with currently running tasks - RegisteredServices []string `protobuf:"bytes,4,rep,name=registered_services,json=registeredServices,proto3" json:"registered_services,omitempty"` // All registered/available services + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` // Supernode version + UptimeSeconds uint64 `protobuf:"varint,2,opt,name=uptime_seconds,json=uptimeSeconds,proto3" json:"uptime_seconds,omitempty"` // Uptime in seconds + Resources *StatusResponse_Resources `protobuf:"bytes,3,opt,name=resources,proto3" json:"resources,omitempty"` + RunningTasks []*StatusResponse_ServiceTasks `protobuf:"bytes,4,rep,name=running_tasks,json=runningTasks,proto3" json:"running_tasks,omitempty"` // Services with currently running tasks + RegisteredServices []string `protobuf:"bytes,5,rep,name=registered_services,json=registeredServices,proto3" json:"registered_services,omitempty"` // All registered/available services + Network *StatusResponse_Network `protobuf:"bytes,6,opt,name=network,proto3" json:"network,omitempty"` // P2P network information + Rank int32 `protobuf:"varint,7,opt,name=rank,proto3" json:"rank,omitempty"` // Rank in the top supernodes list (0 if not in top list) + IpAddress string `protobuf:"bytes,8,opt,name=ip_address,json=ipAddress,proto3" json:"ip_address,omitempty"` // Supernode IP address with port (e.g., "192.168.1.1:4445") } func (x *StatusResponse) Reset() { @@ -248,6 +252,13 @@ func (x *StatusResponse) GetVersion() string { return "" } +func (x *StatusResponse) GetUptimeSeconds() uint64 { + if x != nil { + return x.UptimeSeconds + } + return 0 +} + func (x *StatusResponse) GetResources() *StatusResponse_Resources { if x != nil { return x.Resources @@ -269,15 +280,37 @@ func (x *StatusResponse) GetRegisteredServices() []string { return nil } +func (x *StatusResponse) GetNetwork() *StatusResponse_Network { + if x != nil { + return x.Network + } + return nil +} + +func (x *StatusResponse) GetRank() int32 { + if x != nil { + return x.Rank + } + return 0 +} + +func (x *StatusResponse) GetIpAddress() string { + if x != nil { + return x.IpAddress + } + return "" +} + // System resource information type StatusResponse_Resources struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Cpu *StatusResponse_Resources_CPU `protobuf:"bytes,1,opt,name=cpu,proto3" json:"cpu,omitempty"` - Memory *StatusResponse_Resources_Memory `protobuf:"bytes,2,opt,name=memory,proto3" json:"memory,omitempty"` - StorageVolumes []*StatusResponse_Resources_Storage `protobuf:"bytes,3,rep,name=storage_volumes,json=storageVolumes,proto3" json:"storage_volumes,omitempty"` + Cpu *StatusResponse_Resources_CPU `protobuf:"bytes,1,opt,name=cpu,proto3" json:"cpu,omitempty"` + Memory *StatusResponse_Resources_Memory `protobuf:"bytes,2,opt,name=memory,proto3" json:"memory,omitempty"` + StorageVolumes []*StatusResponse_Resources_Storage `protobuf:"bytes,3,rep,name=storage_volumes,json=storageVolumes,proto3" json:"storage_volumes,omitempty"` + HardwareSummary string `protobuf:"bytes,4,opt,name=hardware_summary,json=hardwareSummary,proto3" json:"hardware_summary,omitempty"` // Formatted hardware summary (e.g., "8 cores / 32GB RAM") } func (x *StatusResponse_Resources) Reset() { @@ -331,6 +364,13 @@ func (x *StatusResponse_Resources) GetStorageVolumes() []*StatusResponse_Resourc return nil } +func (x *StatusResponse_Resources) GetHardwareSummary() string { + if x != nil { + return x.HardwareSummary + } + return "" +} + // ServiceTasks contains task information for a specific service type StatusResponse_ServiceTasks struct { state protoimpl.MessageState @@ -393,17 +433,72 @@ func (x *StatusResponse_ServiceTasks) GetTaskCount() int32 { return 0 } +// Network information +type StatusResponse_Network struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PeersCount int32 `protobuf:"varint,1,opt,name=peers_count,json=peersCount,proto3" json:"peers_count,omitempty"` // Number of connected peers in P2P network + PeerAddresses []string `protobuf:"bytes,2,rep,name=peer_addresses,json=peerAddresses,proto3" json:"peer_addresses,omitempty"` // List of connected peer addresses (optional, may be empty for privacy) +} + +func (x *StatusResponse_Network) Reset() { + *x = StatusResponse_Network{} + mi := &file_supernode_supernode_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StatusResponse_Network) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatusResponse_Network) ProtoMessage() {} + +func (x *StatusResponse_Network) ProtoReflect() protoreflect.Message { + mi := &file_supernode_supernode_proto_msgTypes[7] + 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 StatusResponse_Network.ProtoReflect.Descriptor instead. +func (*StatusResponse_Network) Descriptor() ([]byte, []int) { + return file_supernode_supernode_proto_rawDescGZIP(), []int{4, 2} +} + +func (x *StatusResponse_Network) GetPeersCount() int32 { + if x != nil { + return x.PeersCount + } + return 0 +} + +func (x *StatusResponse_Network) GetPeerAddresses() []string { + if x != nil { + return x.PeerAddresses + } + return nil +} + type StatusResponse_Resources_CPU struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields UsagePercent float64 `protobuf:"fixed64,1,opt,name=usage_percent,json=usagePercent,proto3" json:"usage_percent,omitempty"` // CPU usage percentage (0-100) + Cores int32 `protobuf:"varint,2,opt,name=cores,proto3" json:"cores,omitempty"` // Number of CPU cores } func (x *StatusResponse_Resources_CPU) Reset() { *x = StatusResponse_Resources_CPU{} - mi := &file_supernode_supernode_proto_msgTypes[7] + mi := &file_supernode_supernode_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -415,7 +510,7 @@ func (x *StatusResponse_Resources_CPU) String() string { func (*StatusResponse_Resources_CPU) ProtoMessage() {} func (x *StatusResponse_Resources_CPU) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[7] + mi := &file_supernode_supernode_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -438,20 +533,27 @@ func (x *StatusResponse_Resources_CPU) GetUsagePercent() float64 { return 0 } +func (x *StatusResponse_Resources_CPU) GetCores() int32 { + if x != nil { + return x.Cores + } + return 0 +} + type StatusResponse_Resources_Memory struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - TotalBytes uint64 `protobuf:"varint,1,opt,name=total_bytes,json=totalBytes,proto3" json:"total_bytes,omitempty"` - UsedBytes uint64 `protobuf:"varint,2,opt,name=used_bytes,json=usedBytes,proto3" json:"used_bytes,omitempty"` - AvailableBytes uint64 `protobuf:"varint,3,opt,name=available_bytes,json=availableBytes,proto3" json:"available_bytes,omitempty"` - UsagePercent float64 `protobuf:"fixed64,4,opt,name=usage_percent,json=usagePercent,proto3" json:"usage_percent,omitempty"` // Memory usage percentage (0-100) + TotalGb float64 `protobuf:"fixed64,1,opt,name=total_gb,json=totalGb,proto3" json:"total_gb,omitempty"` // Total memory in GB + UsedGb float64 `protobuf:"fixed64,2,opt,name=used_gb,json=usedGb,proto3" json:"used_gb,omitempty"` // Used memory in GB + AvailableGb float64 `protobuf:"fixed64,3,opt,name=available_gb,json=availableGb,proto3" json:"available_gb,omitempty"` // Available memory in GB + UsagePercent float64 `protobuf:"fixed64,4,opt,name=usage_percent,json=usagePercent,proto3" json:"usage_percent,omitempty"` // Memory usage percentage (0-100) } func (x *StatusResponse_Resources_Memory) Reset() { *x = StatusResponse_Resources_Memory{} - mi := &file_supernode_supernode_proto_msgTypes[8] + mi := &file_supernode_supernode_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -463,7 +565,7 @@ func (x *StatusResponse_Resources_Memory) String() string { func (*StatusResponse_Resources_Memory) ProtoMessage() {} func (x *StatusResponse_Resources_Memory) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[8] + mi := &file_supernode_supernode_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -479,23 +581,23 @@ func (*StatusResponse_Resources_Memory) Descriptor() ([]byte, []int) { return file_supernode_supernode_proto_rawDescGZIP(), []int{4, 0, 1} } -func (x *StatusResponse_Resources_Memory) GetTotalBytes() uint64 { +func (x *StatusResponse_Resources_Memory) GetTotalGb() float64 { if x != nil { - return x.TotalBytes + return x.TotalGb } return 0 } -func (x *StatusResponse_Resources_Memory) GetUsedBytes() uint64 { +func (x *StatusResponse_Resources_Memory) GetUsedGb() float64 { if x != nil { - return x.UsedBytes + return x.UsedGb } return 0 } -func (x *StatusResponse_Resources_Memory) GetAvailableBytes() uint64 { +func (x *StatusResponse_Resources_Memory) GetAvailableGb() float64 { if x != nil { - return x.AvailableBytes + return x.AvailableGb } return 0 } @@ -521,7 +623,7 @@ type StatusResponse_Resources_Storage struct { func (x *StatusResponse_Resources_Storage) Reset() { *x = StatusResponse_Resources_Storage{} - mi := &file_supernode_supernode_proto_msgTypes[9] + mi := &file_supernode_supernode_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -533,7 +635,7 @@ func (x *StatusResponse_Resources_Storage) String() string { func (*StatusResponse_Resources_Storage) ProtoMessage() {} func (x *StatusResponse_Resources_Storage) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[9] + mi := &file_supernode_supernode_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -603,84 +705,101 @@ var file_supernode_supernode_proto_rawDesc = []byte{ 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0xae, 0x07, 0x0a, 0x0e, + 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0xc7, 0x09, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x75, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x75, 0x70, 0x74, 0x69, + 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0d, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, + 0x41, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x0d, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, + 0x73, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x75, 0x70, 0x65, + 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x73, 0x52, 0x0c, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, + 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x12, 0x3b, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x12, 0x0a, + 0x04, 0x72, 0x61, 0x6e, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x72, 0x61, 0x6e, + 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x1a, 0x82, 0x05, 0x0a, 0x09, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x39, + 0x0a, 0x03, 0x63, 0x70, 0x75, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, - 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x0d, 0x72, - 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x0c, 0x72, 0x75, 0x6e, 0x6e, - 0x69, 0x6e, 0x67, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, - 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x1a, 0xd3, 0x04, 0x0a, 0x09, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x03, 0x63, 0x70, 0x75, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x43, 0x50, 0x55, 0x52, 0x03, 0x63, - 0x70, 0x75, 0x12, 0x42, 0x0a, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x52, 0x06, - 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x54, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, - 0x65, 0x5f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x2b, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x0e, 0x73, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x1a, 0x2a, 0x0a, 0x03, - 0x43, 0x50, 0x55, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, - 0x63, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, - 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0x96, 0x01, 0x0a, 0x06, 0x4d, 0x65, 0x6d, - 0x6f, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, - 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x75, 0x73, 0x65, 0x64, 0x42, 0x79, - 0x74, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, - 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x61, 0x76, - 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, - 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, - 0x74, 0x1a, 0xab, 0x01, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, - 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, - 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x75, 0x73, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, - 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, - 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x61, 0x76, 0x61, 0x69, - 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, - 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, - 0x6b, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, - 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, - 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0xd7, 0x01, 0x0a, - 0x10, 0x53, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x58, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, - 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x69, 0x0a, 0x0c, 0x4c, - 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x73, 0x75, - 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x75, - 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4c, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x67, 0x65, - 0x6e, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x2e, 0x43, 0x50, 0x55, 0x52, 0x03, 0x63, 0x70, 0x75, 0x12, 0x42, 0x0a, 0x06, 0x6d, 0x65, 0x6d, + 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x75, 0x70, 0x65, + 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4d, + 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x52, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x54, 0x0a, + 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x56, 0x6f, 0x6c, 0x75, + 0x6d, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, + 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x68, + 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x1a, 0x40, + 0x0a, 0x03, 0x43, 0x50, 0x55, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, + 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, 0x73, + 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, + 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x63, 0x6f, 0x72, 0x65, 0x73, + 0x1a, 0x84, 0x01, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x67, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x47, 0x62, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, + 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x75, 0x73, 0x65, 0x64, 0x47, 0x62, 0x12, + 0x21, 0x0a, 0x0c, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x67, 0x62, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, + 0x47, 0x62, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, + 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, + 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0xab, 0x01, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, + 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x64, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x75, 0x73, + 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, + 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, + 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0x6b, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x61, 0x73, 0x6b, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x73, 0x6b, + 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x1a, 0x51, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x1f, 0x0a, + 0x0b, 0x70, 0x65, 0x65, 0x72, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x25, + 0x0a, 0x0e, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x32, 0xd7, 0x01, 0x0a, 0x10, 0x53, 0x75, 0x70, 0x65, 0x72, 0x6e, + 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x09, 0x47, 0x65, + 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x19, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x69, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, + 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4c, 0x75, + 0x6d, 0x65, 0x72, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x75, 0x70, + 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, + 0x6e, 0x6f, 0x64, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -695,7 +814,7 @@ func file_supernode_supernode_proto_rawDescGZIP() []byte { return file_supernode_supernode_proto_rawDescData } -var file_supernode_supernode_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_supernode_supernode_proto_msgTypes = make([]protoimpl.MessageInfo, 11) var file_supernode_supernode_proto_goTypes = []any{ (*StatusRequest)(nil), // 0: supernode.StatusRequest (*ListServicesRequest)(nil), // 1: supernode.ListServicesRequest @@ -704,26 +823,28 @@ var file_supernode_supernode_proto_goTypes = []any{ (*StatusResponse)(nil), // 4: supernode.StatusResponse (*StatusResponse_Resources)(nil), // 5: supernode.StatusResponse.Resources (*StatusResponse_ServiceTasks)(nil), // 6: supernode.StatusResponse.ServiceTasks - (*StatusResponse_Resources_CPU)(nil), // 7: supernode.StatusResponse.Resources.CPU - (*StatusResponse_Resources_Memory)(nil), // 8: supernode.StatusResponse.Resources.Memory - (*StatusResponse_Resources_Storage)(nil), // 9: supernode.StatusResponse.Resources.Storage + (*StatusResponse_Network)(nil), // 7: supernode.StatusResponse.Network + (*StatusResponse_Resources_CPU)(nil), // 8: supernode.StatusResponse.Resources.CPU + (*StatusResponse_Resources_Memory)(nil), // 9: supernode.StatusResponse.Resources.Memory + (*StatusResponse_Resources_Storage)(nil), // 10: supernode.StatusResponse.Resources.Storage } var file_supernode_supernode_proto_depIdxs = []int32{ - 3, // 0: supernode.ListServicesResponse.services:type_name -> supernode.ServiceInfo - 5, // 1: supernode.StatusResponse.resources:type_name -> supernode.StatusResponse.Resources - 6, // 2: supernode.StatusResponse.running_tasks:type_name -> supernode.StatusResponse.ServiceTasks - 7, // 3: supernode.StatusResponse.Resources.cpu:type_name -> supernode.StatusResponse.Resources.CPU - 8, // 4: supernode.StatusResponse.Resources.memory:type_name -> supernode.StatusResponse.Resources.Memory - 9, // 5: supernode.StatusResponse.Resources.storage_volumes:type_name -> supernode.StatusResponse.Resources.Storage - 0, // 6: supernode.SupernodeService.GetStatus:input_type -> supernode.StatusRequest - 1, // 7: supernode.SupernodeService.ListServices:input_type -> supernode.ListServicesRequest - 4, // 8: supernode.SupernodeService.GetStatus:output_type -> supernode.StatusResponse - 2, // 9: supernode.SupernodeService.ListServices:output_type -> supernode.ListServicesResponse - 8, // [8:10] is the sub-list for method output_type - 6, // [6:8] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 3, // 0: supernode.ListServicesResponse.services:type_name -> supernode.ServiceInfo + 5, // 1: supernode.StatusResponse.resources:type_name -> supernode.StatusResponse.Resources + 6, // 2: supernode.StatusResponse.running_tasks:type_name -> supernode.StatusResponse.ServiceTasks + 7, // 3: supernode.StatusResponse.network:type_name -> supernode.StatusResponse.Network + 8, // 4: supernode.StatusResponse.Resources.cpu:type_name -> supernode.StatusResponse.Resources.CPU + 9, // 5: supernode.StatusResponse.Resources.memory:type_name -> supernode.StatusResponse.Resources.Memory + 10, // 6: supernode.StatusResponse.Resources.storage_volumes:type_name -> supernode.StatusResponse.Resources.Storage + 0, // 7: supernode.SupernodeService.GetStatus:input_type -> supernode.StatusRequest + 1, // 8: supernode.SupernodeService.ListServices:input_type -> supernode.ListServicesRequest + 4, // 9: supernode.SupernodeService.GetStatus:output_type -> supernode.StatusResponse + 2, // 10: supernode.SupernodeService.ListServices:output_type -> supernode.ListServicesResponse + 9, // [9:11] is the sub-list for method output_type + 7, // [7:9] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name } func init() { file_supernode_supernode_proto_init() } @@ -737,7 +858,7 @@ func file_supernode_supernode_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_supernode_supernode_proto_rawDesc, NumEnums: 0, - NumMessages: 10, + NumMessages: 11, NumExtensions: 0, NumServices: 1, }, diff --git a/gen/supernode/supernode.swagger.json b/gen/supernode/supernode.swagger.json index f8ceac27..af023816 100644 --- a/gen/supernode/supernode.swagger.json +++ b/gen/supernode/supernode.swagger.json @@ -69,23 +69,31 @@ "type": "number", "format": "double", "title": "CPU usage percentage (0-100)" + }, + "cores": { + "type": "integer", + "format": "int32", + "title": "Number of CPU cores" } } }, "ResourcesMemory": { "type": "object", "properties": { - "totalBytes": { - "type": "string", - "format": "uint64" + "totalGb": { + "type": "number", + "format": "double", + "title": "Total memory in GB" }, - "usedBytes": { - "type": "string", - "format": "uint64" + "usedGb": { + "type": "number", + "format": "double", + "title": "Used memory in GB" }, - "availableBytes": { - "type": "string", - "format": "uint64" + "availableGb": { + "type": "number", + "format": "double", + "title": "Available memory in GB" }, "usagePercent": { "type": "number", @@ -120,6 +128,24 @@ } } }, + "StatusResponseNetwork": { + "type": "object", + "properties": { + "peersCount": { + "type": "integer", + "format": "int32", + "title": "Number of connected peers in P2P network" + }, + "peerAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "title": "List of connected peer addresses (optional, may be empty for privacy)" + } + }, + "title": "Network information" + }, "StatusResponseResources": { "type": "object", "properties": { @@ -135,6 +161,10 @@ "type": "object", "$ref": "#/definitions/ResourcesStorage" } + }, + "hardwareSummary": { + "type": "string", + "title": "Formatted hardware summary (e.g., \"8 cores / 32GB RAM\")" } }, "title": "System resource information" @@ -223,6 +253,11 @@ "type": "string", "title": "Supernode version" }, + "uptimeSeconds": { + "type": "string", + "format": "uint64", + "title": "Uptime in seconds" + }, "resources": { "$ref": "#/definitions/StatusResponseResources" }, @@ -240,6 +275,19 @@ "type": "string" }, "title": "All registered/available services" + }, + "network": { + "$ref": "#/definitions/StatusResponseNetwork", + "title": "P2P network information" + }, + "rank": { + "type": "integer", + "format": "int32", + "title": "Rank in the top supernodes list (0 if not in top list)" + }, + "ipAddress": { + "type": "string", + "title": "Supernode IP address with port (e.g., \"192.168.1.1:4445\")" } }, "title": "The StatusResponse represents system status with clear organization" diff --git a/proto/supernode/supernode.proto b/proto/supernode/supernode.proto index 61f85d8b..d0582156 100644 --- a/proto/supernode/supernode.proto +++ b/proto/supernode/supernode.proto @@ -36,17 +36,19 @@ message ServiceInfo { // The StatusResponse represents system status with clear organization message StatusResponse { string version = 1; // Supernode version + uint64 uptime_seconds = 2; // Uptime in seconds // System resource information message Resources { message CPU { double usage_percent = 1; // CPU usage percentage (0-100) + int32 cores = 2; // Number of CPU cores } message Memory { - uint64 total_bytes = 1; - uint64 used_bytes = 2; - uint64 available_bytes = 3; + double total_gb = 1; // Total memory in GB + double used_gb = 2; // Used memory in GB + double available_gb = 3; // Available memory in GB double usage_percent = 4; // Memory usage percentage (0-100) } @@ -61,6 +63,7 @@ message StatusResponse { CPU cpu = 1; Memory memory = 2; repeated Storage storage_volumes = 3; + string hardware_summary = 4; // Formatted hardware summary (e.g., "8 cores / 32GB RAM") } // ServiceTasks contains task information for a specific service @@ -70,7 +73,16 @@ message StatusResponse { int32 task_count = 3; } - Resources resources = 2; - repeated ServiceTasks running_tasks = 3; // Services with currently running tasks - repeated string registered_services = 4; // All registered/available services + // Network information + message Network { + int32 peers_count = 1; // Number of connected peers in P2P network + repeated string peer_addresses = 2; // List of connected peer addresses (optional, may be empty for privacy) + } + + Resources resources = 3; + repeated ServiceTasks running_tasks = 4; // Services with currently running tasks + repeated string registered_services = 5; // All registered/available services + Network network = 6; // P2P network information + int32 rank = 7; // Rank in the top supernodes list (0 if not in top list) + string ip_address = 8; // Supernode IP address with port (e.g., "192.168.1.1:4445") } \ No newline at end of file diff --git a/sdk/adapters/supernodeservice/adapter.go b/sdk/adapters/supernodeservice/adapter.go index bbc0375d..0c2d12f3 100644 --- a/sdk/adapters/supernodeservice/adapter.go +++ b/sdk/adapters/supernodeservice/adapter.go @@ -344,19 +344,21 @@ func toSdkEvent(e cascade.SupernodeEventType) event.EventType { func toSdkSupernodeStatus(resp *supernode.StatusResponse) *SupernodeStatusresponse { result := &SupernodeStatusresponse{} result.Version = resp.Version + result.UptimeSeconds = resp.UptimeSeconds // Convert Resources data if resp.Resources != nil { // Convert CPU data if resp.Resources.Cpu != nil { result.Resources.CPU.UsagePercent = resp.Resources.Cpu.UsagePercent + result.Resources.CPU.Cores = resp.Resources.Cpu.Cores } // Convert Memory data if resp.Resources.Memory != nil { - result.Resources.Memory.TotalBytes = resp.Resources.Memory.TotalBytes - result.Resources.Memory.UsedBytes = resp.Resources.Memory.UsedBytes - result.Resources.Memory.AvailableBytes = resp.Resources.Memory.AvailableBytes + result.Resources.Memory.TotalGB = resp.Resources.Memory.TotalGb + result.Resources.Memory.UsedGB = resp.Resources.Memory.UsedGb + result.Resources.Memory.AvailableGB = resp.Resources.Memory.AvailableGb result.Resources.Memory.UsagePercent = resp.Resources.Memory.UsagePercent } @@ -371,6 +373,9 @@ func toSdkSupernodeStatus(resp *supernode.StatusResponse) *SupernodeStatusrespon UsagePercent: storage.UsagePercent, }) } + + // Copy hardware summary + result.Resources.HardwareSummary = resp.Resources.HardwareSummary } // Convert RunningTasks data @@ -387,5 +392,16 @@ func toSdkSupernodeStatus(resp *supernode.StatusResponse) *SupernodeStatusrespon result.RegisteredServices = make([]string, len(resp.RegisteredServices)) copy(result.RegisteredServices, resp.RegisteredServices) + // Convert Network data + if resp.Network != nil { + result.Network.PeersCount = resp.Network.PeersCount + result.Network.PeerAddresses = make([]string, len(resp.Network.PeerAddresses)) + copy(result.Network.PeerAddresses, resp.Network.PeerAddresses) + } + + // Copy rank and IP address + result.Rank = resp.Rank + result.IPAddress = resp.IpAddress + return result } diff --git a/sdk/adapters/supernodeservice/types.go b/sdk/adapters/supernodeservice/types.go index d80edb0a..0b2921b6 100644 --- a/sdk/adapters/supernodeservice/types.go +++ b/sdk/adapters/supernodeservice/types.go @@ -46,20 +46,29 @@ type StorageInfo struct { type SupernodeStatusresponse struct { Version string // Supernode version + UptimeSeconds uint64 // Uptime in seconds Resources struct { CPU struct { UsagePercent float64 + Cores int32 } Memory struct { - TotalBytes uint64 - UsedBytes uint64 - AvailableBytes uint64 - UsagePercent float64 + TotalGB float64 + UsedGB float64 + AvailableGB float64 + UsagePercent float64 } Storage []StorageInfo + HardwareSummary string // Formatted hardware summary } RunningTasks []ServiceTasks // Services with running tasks RegisteredServices []string // All available service names + Network struct { + PeersCount int32 // Number of connected peers + PeerAddresses []string // List of peer addresses + } + Rank int32 // Rank in top supernodes list (0 if not in top list) + IPAddress string // Supernode IP address with port } type CascadeSupernodeDownloadRequest struct { ActionID string diff --git a/supernode/cmd/start.go b/supernode/cmd/start.go index 30abcacc..bc9e207d 100644 --- a/supernode/cmd/start.go +++ b/supernode/cmd/start.go @@ -105,7 +105,7 @@ The supernode will connect to the Lumera network and begin participating in the supernodeService.Version = Version // Create supernode status service - statusService := supernodeService.NewSupernodeStatusService() + statusService := supernodeService.NewSupernodeStatusService(*p2pService, lumeraClient, appConfig) statusService.RegisterTaskProvider(cService) // Create supernode server diff --git a/supernode/node/supernode/gateway/swagger.json b/supernode/node/supernode/gateway/swagger.json index f8ceac27..af023816 100644 --- a/supernode/node/supernode/gateway/swagger.json +++ b/supernode/node/supernode/gateway/swagger.json @@ -69,23 +69,31 @@ "type": "number", "format": "double", "title": "CPU usage percentage (0-100)" + }, + "cores": { + "type": "integer", + "format": "int32", + "title": "Number of CPU cores" } } }, "ResourcesMemory": { "type": "object", "properties": { - "totalBytes": { - "type": "string", - "format": "uint64" + "totalGb": { + "type": "number", + "format": "double", + "title": "Total memory in GB" }, - "usedBytes": { - "type": "string", - "format": "uint64" + "usedGb": { + "type": "number", + "format": "double", + "title": "Used memory in GB" }, - "availableBytes": { - "type": "string", - "format": "uint64" + "availableGb": { + "type": "number", + "format": "double", + "title": "Available memory in GB" }, "usagePercent": { "type": "number", @@ -120,6 +128,24 @@ } } }, + "StatusResponseNetwork": { + "type": "object", + "properties": { + "peersCount": { + "type": "integer", + "format": "int32", + "title": "Number of connected peers in P2P network" + }, + "peerAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "title": "List of connected peer addresses (optional, may be empty for privacy)" + } + }, + "title": "Network information" + }, "StatusResponseResources": { "type": "object", "properties": { @@ -135,6 +161,10 @@ "type": "object", "$ref": "#/definitions/ResourcesStorage" } + }, + "hardwareSummary": { + "type": "string", + "title": "Formatted hardware summary (e.g., \"8 cores / 32GB RAM\")" } }, "title": "System resource information" @@ -223,6 +253,11 @@ "type": "string", "title": "Supernode version" }, + "uptimeSeconds": { + "type": "string", + "format": "uint64", + "title": "Uptime in seconds" + }, "resources": { "$ref": "#/definitions/StatusResponseResources" }, @@ -240,6 +275,19 @@ "type": "string" }, "title": "All registered/available services" + }, + "network": { + "$ref": "#/definitions/StatusResponseNetwork", + "title": "P2P network information" + }, + "rank": { + "type": "integer", + "format": "int32", + "title": "Rank in the top supernodes list (0 if not in top list)" + }, + "ipAddress": { + "type": "string", + "title": "Supernode IP address with port (e.g., \"192.168.1.1:4445\")" } }, "title": "The StatusResponse represents system status with clear organization" diff --git a/supernode/node/supernode/server/status_server.go b/supernode/node/supernode/server/status_server.go index 4cd87d9e..37f22b37 100644 --- a/supernode/node/supernode/server/status_server.go +++ b/supernode/node/supernode/server/status_server.go @@ -60,21 +60,30 @@ func (s *SupernodeServer) GetStatus(ctx context.Context, req *pb.StatusRequest) // Convert to protobuf response response := &pb.StatusResponse{ - Version: status.Version, + Version: status.Version, + UptimeSeconds: status.UptimeSeconds, Resources: &pb.StatusResponse_Resources{ Cpu: &pb.StatusResponse_Resources_CPU{ UsagePercent: status.Resources.CPU.UsagePercent, + Cores: status.Resources.CPU.Cores, }, Memory: &pb.StatusResponse_Resources_Memory{ - TotalBytes: status.Resources.Memory.TotalBytes, - UsedBytes: status.Resources.Memory.UsedBytes, - AvailableBytes: status.Resources.Memory.AvailableBytes, - UsagePercent: status.Resources.Memory.UsagePercent, + TotalGb: status.Resources.Memory.TotalGB, + UsedGb: status.Resources.Memory.UsedGB, + AvailableGb: status.Resources.Memory.AvailableGB, + UsagePercent: status.Resources.Memory.UsagePercent, }, - StorageVolumes: make([]*pb.StatusResponse_Resources_Storage, 0, len(status.Resources.Storage)), + StorageVolumes: make([]*pb.StatusResponse_Resources_Storage, 0, len(status.Resources.Storage)), + HardwareSummary: status.Resources.HardwareSummary, }, RunningTasks: make([]*pb.StatusResponse_ServiceTasks, 0, len(status.RunningTasks)), RegisteredServices: status.RegisteredServices, + Network: &pb.StatusResponse_Network{ + PeersCount: status.Network.PeersCount, + PeerAddresses: status.Network.PeerAddresses, + }, + Rank: status.Rank, + IpAddress: status.IPAddress, } // Convert storage information diff --git a/supernode/node/supernode/server/status_server_test.go b/supernode/node/supernode/server/status_server_test.go index a47e18e5..908e0753 100644 --- a/supernode/node/supernode/server/status_server_test.go +++ b/supernode/node/supernode/server/status_server_test.go @@ -16,7 +16,7 @@ func TestSupernodeServer_GetStatus(t *testing.T) { ctx := context.Background() // Create status service - statusService := supernode.NewSupernodeStatusService() + statusService := supernode.NewSupernodeStatusService(nil, nil, nil) // Create server server := NewSupernodeServer(statusService) @@ -35,15 +35,24 @@ func TestSupernodeServer_GetStatus(t *testing.T) { // Check version field assert.NotEmpty(t, resp.Version) + + // Check uptime field + assert.True(t, resp.UptimeSeconds >= 0) // Check CPU metrics assert.True(t, resp.Resources.Cpu.UsagePercent >= 0) assert.True(t, resp.Resources.Cpu.UsagePercent <= 100) + assert.True(t, resp.Resources.Cpu.Cores >= 0) - // Check Memory metrics - assert.True(t, resp.Resources.Memory.TotalBytes > 0) + // Check Memory metrics (now in GB) + assert.True(t, resp.Resources.Memory.TotalGb > 0) assert.True(t, resp.Resources.Memory.UsagePercent >= 0) assert.True(t, resp.Resources.Memory.UsagePercent <= 100) + + // Check hardware summary + if resp.Resources.Cpu.Cores > 0 && resp.Resources.Memory.TotalGb > 0 { + assert.NotEmpty(t, resp.Resources.HardwareSummary) + } // Check Storage (should have default root filesystem) assert.NotEmpty(t, resp.Resources.StorageVolumes) @@ -52,13 +61,20 @@ func TestSupernodeServer_GetStatus(t *testing.T) { // Should have no services initially assert.Empty(t, resp.RunningTasks) assert.Empty(t, resp.RegisteredServices) + + // Check new fields have default values + assert.NotNil(t, resp.Network) + assert.Equal(t, int32(0), resp.Network.PeersCount) + assert.Empty(t, resp.Network.PeerAddresses) + assert.Equal(t, int32(0), resp.Rank) + assert.Empty(t, resp.IpAddress) } func TestSupernodeServer_GetStatusWithService(t *testing.T) { ctx := context.Background() // Create status service - statusService := supernode.NewSupernodeStatusService() + statusService := supernode.NewSupernodeStatusService(nil, nil, nil) // Add a mock task provider mockProvider := &common.MockTaskProvider{ @@ -88,7 +104,7 @@ func TestSupernodeServer_GetStatusWithService(t *testing.T) { } func TestSupernodeServer_Desc(t *testing.T) { - statusService := supernode.NewSupernodeStatusService() + statusService := supernode.NewSupernodeStatusService(nil, nil, nil) server := NewSupernodeServer(statusService) desc := server.Desc() diff --git a/supernode/services/cascade/status.go b/supernode/services/cascade/status.go index 5746f4c3..677e3efb 100644 --- a/supernode/services/cascade/status.go +++ b/supernode/services/cascade/status.go @@ -12,7 +12,9 @@ type StatusResponse = supernode.StatusResponse // GetStatus delegates to the common supernode status service func (service *CascadeService) GetStatus(ctx context.Context) (StatusResponse, error) { // Create a status service and register the cascade service as a task provider - statusService := supernode.NewSupernodeStatusService() + // Pass nil for optional dependencies (P2P, lumera client, and config) + // as cascade service doesn't have access to them in this context + statusService := supernode.NewSupernodeStatusService(nil, nil, nil) statusService.RegisterTaskProvider(service) // Get the status from the common service diff --git a/supernode/services/cascade/status_test.go b/supernode/services/cascade/status_test.go index b594075c..b12d5bb4 100644 --- a/supernode/services/cascade/status_test.go +++ b/supernode/services/cascade/status_test.go @@ -66,15 +66,24 @@ func TestGetStatus(t *testing.T) { // Version check assert.NotEmpty(t, resp.Version) + + // Uptime check + assert.True(t, resp.UptimeSeconds >= 0) // CPU checks assert.True(t, resp.Resources.CPU.UsagePercent >= 0) assert.True(t, resp.Resources.CPU.UsagePercent <= 100) + assert.True(t, resp.Resources.CPU.Cores >= 0) - // Memory checks - assert.True(t, resp.Resources.Memory.TotalBytes > 0) - assert.True(t, resp.Resources.Memory.UsedBytes <= resp.Resources.Memory.TotalBytes) + // Memory checks (now in GB) + assert.True(t, resp.Resources.Memory.TotalGB > 0) + assert.True(t, resp.Resources.Memory.UsedGB <= resp.Resources.Memory.TotalGB) assert.True(t, resp.Resources.Memory.UsagePercent >= 0 && resp.Resources.Memory.UsagePercent <= 100) + + // Hardware summary check + if resp.Resources.CPU.Cores > 0 && resp.Resources.Memory.TotalGB > 0 { + assert.NotEmpty(t, resp.Resources.HardwareSummary) + } // Storage checks - should have default root filesystem assert.NotEmpty(t, resp.Resources.Storage) @@ -82,6 +91,12 @@ func TestGetStatus(t *testing.T) { // Registered services check assert.Contains(t, resp.RegisteredServices, "cascade") + + // Check new fields have default values (since service doesn't have access to P2P/lumera/config) + assert.Equal(t, int32(0), resp.Network.PeersCount) + assert.Empty(t, resp.Network.PeerAddresses) + assert.Equal(t, int32(0), resp.Rank) + assert.Empty(t, resp.IPAddress) // Task count check - look for cascade service in the running tasks list var cascadeService *supernode.ServiceTasks diff --git a/supernode/services/common/supernode/metrics.go b/supernode/services/common/supernode/metrics.go index 8c30b612..09384948 100644 --- a/supernode/services/common/supernode/metrics.go +++ b/supernode/services/common/supernode/metrics.go @@ -30,6 +30,17 @@ func (m *MetricsCollector) CollectCPUMetrics(ctx context.Context) (float64, erro return percentages[0], nil } +// GetCPUCores returns the number of CPU cores +func (m *MetricsCollector) GetCPUCores(ctx context.Context) (int32, error) { + cores, err := cpu.Counts(true) + if err != nil { + logtrace.Error(ctx, "failed to get cpu core count", logtrace.Fields{logtrace.FieldError: err.Error()}) + return 0, err + } + + return int32(cores), nil +} + // CollectMemoryMetrics gathers memory usage information // Returns memory statistics including total, used, available, and usage percentage func (m *MetricsCollector) CollectMemoryMetrics(ctx context.Context) (total, used, available uint64, usedPerc float64, err error) { diff --git a/supernode/services/common/supernode/service.go b/supernode/services/common/supernode/service.go index 9000d8e5..9a150d1e 100644 --- a/supernode/services/common/supernode/service.go +++ b/supernode/services/common/supernode/service.go @@ -2,8 +2,14 @@ package supernode import ( "context" + "fmt" + "time" + "github.com/LumeraProtocol/supernode/p2p" + "github.com/LumeraProtocol/supernode/p2p/kademlia" "github.com/LumeraProtocol/supernode/pkg/logtrace" + "github.com/LumeraProtocol/supernode/pkg/lumera" + "github.com/LumeraProtocol/supernode/supernode/config" ) // Version is the supernode version, set by the main application @@ -15,14 +21,22 @@ type SupernodeStatusService struct { taskProviders []TaskProvider // List of registered services that provide task information metrics *MetricsCollector // System metrics collector for CPU and memory stats storagePaths []string // Paths to monitor for storage metrics + startTime time.Time // Service start time for uptime calculation + p2pService p2p.Client // P2P service for network information + lumeraClient lumera.Client // Lumera client for blockchain queries + config *config.Config // Supernode configuration } // NewSupernodeStatusService creates a new supernode status service instance -func NewSupernodeStatusService() *SupernodeStatusService { +func NewSupernodeStatusService(p2pService p2p.Client, lumeraClient lumera.Client, cfg *config.Config) *SupernodeStatusService { return &SupernodeStatusService{ taskProviders: make([]TaskProvider, 0), metrics: NewMetricsCollector(), storagePaths: []string{"/"}, // Default to monitoring root filesystem + startTime: time.Now(), + p2pService: p2pService, + lumeraClient: lumeraClient, + config: cfg, } } @@ -43,6 +57,9 @@ func (s *SupernodeStatusService) GetStatus(ctx context.Context) (StatusResponse, var resp StatusResponse resp.Version = Version + + // Calculate uptime + resp.UptimeSeconds = uint64(time.Since(s.startTime).Seconds()) // Collect CPU metrics cpuUsage, err := s.metrics.CollectCPUMetrics(ctx) @@ -50,16 +67,33 @@ func (s *SupernodeStatusService) GetStatus(ctx context.Context) (StatusResponse, return resp, err } resp.Resources.CPU.UsagePercent = cpuUsage + + // Get CPU cores + cpuCores, err := s.metrics.GetCPUCores(ctx) + if err != nil { + // Log error but continue - non-critical + logtrace.Error(ctx, "failed to get cpu cores", logtrace.Fields{logtrace.FieldError: err.Error()}) + cpuCores = 0 + } + resp.Resources.CPU.Cores = cpuCores // Collect memory metrics memTotal, memUsed, memAvailable, memUsedPerc, err := s.metrics.CollectMemoryMetrics(ctx) if err != nil { return resp, err } - resp.Resources.Memory.TotalBytes = memTotal - resp.Resources.Memory.UsedBytes = memUsed - resp.Resources.Memory.AvailableBytes = memAvailable + + // Convert to GB + const bytesToGB = 1024 * 1024 * 1024 + resp.Resources.Memory.TotalGB = float64(memTotal) / bytesToGB + resp.Resources.Memory.UsedGB = float64(memUsed) / bytesToGB + resp.Resources.Memory.AvailableGB = float64(memAvailable) / bytesToGB resp.Resources.Memory.UsagePercent = memUsedPerc + + // Generate hardware summary + if cpuCores > 0 && resp.Resources.Memory.TotalGB > 0 { + resp.Resources.HardwareSummary = fmt.Sprintf("%d cores / %.0fGB RAM", cpuCores, resp.Resources.Memory.TotalGB) + } // Collect storage metrics resp.Resources.Storage = s.metrics.CollectStorageMetrics(ctx, s.storagePaths) @@ -84,6 +118,69 @@ func (s *SupernodeStatusService) GetStatus(ctx context.Context) (StatusResponse, resp.RunningTasks = append(resp.RunningTasks, serviceTask) } + // Initialize network info + resp.Network = NetworkInfo{ + PeersCount: 0, + PeerAddresses: []string{}, + } + + // Collect P2P network information + if s.p2pService != nil { + p2pStats, err := s.p2pService.Stats(ctx) + if err != nil { + // Log error but continue - non-critical + logtrace.Error(ctx, "failed to get p2p stats", logtrace.Fields{logtrace.FieldError: err.Error()}) + } else { + if dhtStats, ok := p2pStats["dht"].(map[string]interface{}); ok { + if peersCount, ok := dhtStats["peers_count"].(int); ok { + resp.Network.PeersCount = int32(peersCount) + } + + // Extract peer addresses + if peers, ok := dhtStats["peers"].([]*kademlia.Node); ok { + resp.Network.PeerAddresses = make([]string, 0, len(peers)) + for _, peer := range peers { + // Format peer address as "ID@IP:Port" + peerAddr := fmt.Sprintf("%s@%s:%d", string(peer.ID), peer.IP, peer.Port) + resp.Network.PeerAddresses = append(resp.Network.PeerAddresses, peerAddr) + } + } else { + resp.Network.PeerAddresses = []string{} + } + } + } + } + + // Calculate rank from top supernodes + if s.lumeraClient != nil && s.config != nil { + // Get current block height + blockInfo, err := s.lumeraClient.Node().GetLatestBlock(ctx) + if err != nil { + // Log error but continue - non-critical + logtrace.Error(ctx, "failed to get latest block", logtrace.Fields{logtrace.FieldError: err.Error()}) + } else { + // Get top supernodes for current block + topNodes, err := s.lumeraClient.SuperNode().GetTopSuperNodesForBlock(ctx, uint64(blockInfo.SdkBlock.Header.Height)) + if err != nil { + // Log error but continue - non-critical + logtrace.Error(ctx, "failed to get top supernodes", logtrace.Fields{logtrace.FieldError: err.Error()}) + } else { + // Find our rank + for idx, node := range topNodes.Supernodes { + if node.SupernodeAccount == s.config.SupernodeConfig.Identity { + resp.Rank = int32(idx + 1) // Rank starts from 1 + break + } + } + } + } + } + + // Set IP address from config + if s.config != nil { + resp.IPAddress = fmt.Sprintf("%s:%d", s.config.SupernodeConfig.IpAddress, s.config.P2PConfig.Port) + } + // Log summary statistics totalTasks := 0 for _, service := range resp.RunningTasks { @@ -92,12 +189,17 @@ func (s *SupernodeStatusService) GetStatus(ctx context.Context) (StatusResponse, logtrace.Info(ctx, "status data collected", logtrace.Fields{ "cpu_usage%": cpuUsage, - "mem_total": memTotal, - "mem_used": memUsed, + "cpu_cores": cpuCores, + "mem_total_gb": resp.Resources.Memory.TotalGB, + "mem_used_gb": resp.Resources.Memory.UsedGB, "mem_usage%": memUsedPerc, + "uptime_seconds": resp.UptimeSeconds, "storage_volumes": len(resp.Resources.Storage), "service_count": len(resp.RunningTasks), "total_tasks": totalTasks, + "network_peers": resp.Network.PeersCount, + "rank": resp.Rank, + "ip_address": resp.IPAddress, }) return resp, nil diff --git a/supernode/services/common/supernode/service_test.go b/supernode/services/common/supernode/service_test.go index cabc67cf..5a3197ca 100644 --- a/supernode/services/common/supernode/service_test.go +++ b/supernode/services/common/supernode/service_test.go @@ -12,20 +12,29 @@ func TestSupernodeStatusService(t *testing.T) { ctx := context.Background() t.Run("empty service", func(t *testing.T) { - statusService := NewSupernodeStatusService() + statusService := NewSupernodeStatusService(nil, nil, nil) resp, err := statusService.GetStatus(ctx) assert.NoError(t, err) // Should have version info assert.NotEmpty(t, resp.Version) + + // Should have uptime + assert.True(t, resp.UptimeSeconds >= 0) // Should have CPU and Memory info assert.True(t, resp.Resources.CPU.UsagePercent >= 0) assert.True(t, resp.Resources.CPU.UsagePercent <= 100) - assert.True(t, resp.Resources.Memory.TotalBytes > 0) + assert.True(t, resp.Resources.CPU.Cores >= 0) + assert.True(t, resp.Resources.Memory.TotalGB > 0) assert.True(t, resp.Resources.Memory.UsagePercent >= 0) assert.True(t, resp.Resources.Memory.UsagePercent <= 100) + + // Should have hardware summary if cores and memory are available + if resp.Resources.CPU.Cores > 0 && resp.Resources.Memory.TotalGB > 0 { + assert.NotEmpty(t, resp.Resources.HardwareSummary) + } // Should have storage info (default root filesystem) assert.NotEmpty(t, resp.Resources.Storage) @@ -34,10 +43,16 @@ func TestSupernodeStatusService(t *testing.T) { // Should have empty services list assert.Empty(t, resp.RunningTasks) assert.Empty(t, resp.RegisteredServices) + + // Should have default values for new fields + assert.Equal(t, int32(0), resp.Network.PeersCount) + assert.Empty(t, resp.Network.PeerAddresses) + assert.Equal(t, int32(0), resp.Rank) + assert.Empty(t, resp.IPAddress) }) t.Run("single service with tasks", func(t *testing.T) { - statusService := NewSupernodeStatusService() + statusService := NewSupernodeStatusService(nil, nil, nil) // Register a mock task provider mockProvider := &common.MockTaskProvider{ @@ -61,7 +76,7 @@ func TestSupernodeStatusService(t *testing.T) { }) t.Run("multiple services", func(t *testing.T) { - statusService := NewSupernodeStatusService() + statusService := NewSupernodeStatusService(nil, nil, nil) // Register multiple mock task providers cascadeProvider := &common.MockTaskProvider{ @@ -103,7 +118,7 @@ func TestSupernodeStatusService(t *testing.T) { }) t.Run("service with no tasks", func(t *testing.T) { - statusService := NewSupernodeStatusService() + statusService := NewSupernodeStatusService(nil, nil, nil) // Register a mock task provider with no tasks mockProvider := &common.MockTaskProvider{ diff --git a/supernode/services/common/supernode/types.go b/supernode/services/common/supernode/types.go index 3e70fa0e..fffeba8b 100644 --- a/supernode/services/common/supernode/types.go +++ b/supernode/services/common/supernode/types.go @@ -4,29 +4,35 @@ package supernode // with clear organization of resources and services type StatusResponse struct { Version string // Supernode version + UptimeSeconds uint64 // Uptime in seconds Resources Resources // System resource information RunningTasks []ServiceTasks // Services with currently running tasks RegisteredServices []string // All registered/available services + Network NetworkInfo // P2P network information + Rank int32 // Rank in the top supernodes list (0 if not in top list) + IPAddress string // Supernode IP address with port (e.g., "192.168.1.1:4445") } // Resources contains system resource metrics type Resources struct { - CPU CPUInfo // CPU usage information - Memory MemoryInfo // Memory usage information - Storage []StorageInfo // Storage volumes information + CPU CPUInfo // CPU usage information + Memory MemoryInfo // Memory usage information + Storage []StorageInfo // Storage volumes information + HardwareSummary string // Formatted hardware summary (e.g., "8 cores / 32GB RAM") } // CPUInfo contains CPU usage metrics type CPUInfo struct { UsagePercent float64 // CPU usage percentage (0-100) + Cores int32 // Number of CPU cores } // MemoryInfo contains memory usage metrics type MemoryInfo struct { - TotalBytes uint64 // Total memory in bytes - UsedBytes uint64 // Used memory in bytes - AvailableBytes uint64 // Available memory in bytes - UsagePercent float64 // Memory usage percentage (0-100) + TotalGB float64 // Total memory in GB + UsedGB float64 // Used memory in GB + AvailableGB float64 // Available memory in GB + UsagePercent float64 // Memory usage percentage (0-100) } // StorageInfo contains storage metrics for a specific path @@ -45,6 +51,12 @@ type ServiceTasks struct { TaskCount int32 // Total number of running tasks } +// NetworkInfo contains P2P network information +type NetworkInfo struct { + PeersCount int32 // Number of connected peers in P2P network + PeerAddresses []string // List of connected peer addresses (optional, may be empty for privacy) +} + // TaskProvider interface defines the contract for services to provide // their running task information to the status service type TaskProvider interface {