From 70892128bcd8dd9eaf7acb03c9bd14af76d80524 Mon Sep 17 00:00:00 2001 From: Matthias Riegler Date: Tue, 25 Jul 2023 23:53:27 +0200 Subject: [PATCH] feat: add rudimentary API & bladectl client Signed-off-by: Matthias Riegler --- .gitignore | 4 + Makefile | 22 +- api/bladeapi/v1alpha1/blade.pb.go | 597 +++++++++++++++++++++++++ api/bladeapi/v1alpha1/blade.proto | 61 +++ api/bladeapi/v1alpha1/blade_grpc.pb.go | 262 +++++++++++ buf.gen.yaml | 10 + buf.yaml | 7 + cmd/agent/main.go | 35 +- cmd/bladectl/cmd_fan.go | 45 ++ cmd/bladectl/cmd_identify.go | 58 +++ cmd/bladectl/main.go | 85 ++++ go.mod | 11 +- go.sum | 29 +- internal/agent/api.go | 65 +++ 14 files changed, 1277 insertions(+), 14 deletions(-) create mode 100644 .gitignore create mode 100644 api/bladeapi/v1alpha1/blade.pb.go create mode 100644 api/bladeapi/v1alpha1/blade.proto create mode 100644 api/bladeapi/v1alpha1/blade_grpc.pb.go create mode 100644 buf.gen.yaml create mode 100644 buf.yaml create mode 100644 cmd/bladectl/cmd_fan.go create mode 100644 cmd/bladectl/cmd_identify.go create mode 100644 cmd/bladectl/main.go create mode 100644 internal/agent/api.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..97bf923 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +bin/ + +*.test +*.out diff --git a/Makefile b/Makefile index 52d55de..847d49d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,27 @@ +all: lint + .PHONY: run run: go run cmd/agent/main.go +.PHONY: lint lint: - golangci-lint run \ No newline at end of file + golangci-lint run + +.PHONY: generate +generate: buf + $(BUF) generate + +# Dependencies +LOCALBIN ?= $(shell pwd)/bin +$(LOCALBIN): + mkdir -p $(LOCALBIN) + +BUF ?= $(LOCALBIN)/buf +BUF_VERSION ?= v1.25.0 + +.PHONY: buf +buf: $(BUF) +$(BUF): $(LOCALBIN) + GOBIN=$(LOCALBIN) go install github.com/bufbuild/buf/cmd/buf@$(BUF_VERSION) diff --git a/api/bladeapi/v1alpha1/blade.pb.go b/api/bladeapi/v1alpha1/blade.pb.go new file mode 100644 index 0000000..4728228 --- /dev/null +++ b/api/bladeapi/v1alpha1/blade.pb.go @@ -0,0 +1,597 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: api/bladeapi/v1alpha1/blade.proto + +package bladeapiv1alpha1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Event is an event the agent reacts to +type Event int32 + +const ( + Event_IDENTIFY Event = 0 + Event_IDENTIFY_CONFIRM Event = 1 + Event_CRITICAL Event = 2 + Event_CRITICAL_RESET Event = 3 +) + +// Enum value maps for Event. +var ( + Event_name = map[int32]string{ + 0: "IDENTIFY", + 1: "IDENTIFY_CONFIRM", + 2: "CRITICAL", + 3: "CRITICAL_RESET", + } + Event_value = map[string]int32{ + "IDENTIFY": 0, + "IDENTIFY_CONFIRM": 1, + "CRITICAL": 2, + "CRITICAL_RESET": 3, + } +) + +func (x Event) Enum() *Event { + p := new(Event) + *p = x + return p +} + +func (x Event) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Event) Descriptor() protoreflect.EnumDescriptor { + return file_api_bladeapi_v1alpha1_blade_proto_enumTypes[0].Descriptor() +} + +func (Event) Type() protoreflect.EnumType { + return &file_api_bladeapi_v1alpha1_blade_proto_enumTypes[0] +} + +func (x Event) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Event.Descriptor instead. +func (Event) EnumDescriptor() ([]byte, []int) { + return file_api_bladeapi_v1alpha1_blade_proto_rawDescGZIP(), []int{0} +} + +// FanUnit defines the fan unit detected by the blade +type FanUnit int32 + +const ( + FanUnit_DEFAULT FanUnit = 0 + FanUnit_SMART FanUnit = 1 +) + +// Enum value maps for FanUnit. +var ( + FanUnit_name = map[int32]string{ + 0: "DEFAULT", + 1: "SMART", + } + FanUnit_value = map[string]int32{ + "DEFAULT": 0, + "SMART": 1, + } +) + +func (x FanUnit) Enum() *FanUnit { + p := new(FanUnit) + *p = x + return p +} + +func (x FanUnit) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (FanUnit) Descriptor() protoreflect.EnumDescriptor { + return file_api_bladeapi_v1alpha1_blade_proto_enumTypes[1].Descriptor() +} + +func (FanUnit) Type() protoreflect.EnumType { + return &file_api_bladeapi_v1alpha1_blade_proto_enumTypes[1] +} + +func (x FanUnit) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use FanUnit.Descriptor instead. +func (FanUnit) EnumDescriptor() ([]byte, []int) { + return file_api_bladeapi_v1alpha1_blade_proto_rawDescGZIP(), []int{1} +} + +// PowerStatus defines the power status of the blade +type PowerStatus int32 + +const ( + PowerStatus_POE_OR_USBC PowerStatus = 0 + PowerStatus_POE_802_AT PowerStatus = 1 +) + +// Enum value maps for PowerStatus. +var ( + PowerStatus_name = map[int32]string{ + 0: "POE_OR_USBC", + 1: "POE_802_AT", + } + PowerStatus_value = map[string]int32{ + "POE_OR_USBC": 0, + "POE_802_AT": 1, + } +) + +func (x PowerStatus) Enum() *PowerStatus { + p := new(PowerStatus) + *p = x + return p +} + +func (x PowerStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (PowerStatus) Descriptor() protoreflect.EnumDescriptor { + return file_api_bladeapi_v1alpha1_blade_proto_enumTypes[2].Descriptor() +} + +func (PowerStatus) Type() protoreflect.EnumType { + return &file_api_bladeapi_v1alpha1_blade_proto_enumTypes[2] +} + +func (x PowerStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use PowerStatus.Descriptor instead. +func (PowerStatus) EnumDescriptor() ([]byte, []int) { + return file_api_bladeapi_v1alpha1_blade_proto_rawDescGZIP(), []int{2} +} + +type StealthModeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Enable bool `protobuf:"varint,1,opt,name=enable,proto3" json:"enable,omitempty"` +} + +func (x *StealthModeRequest) Reset() { + *x = StealthModeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_bladeapi_v1alpha1_blade_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StealthModeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StealthModeRequest) ProtoMessage() {} + +func (x *StealthModeRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_bladeapi_v1alpha1_blade_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StealthModeRequest.ProtoReflect.Descriptor instead. +func (*StealthModeRequest) Descriptor() ([]byte, []int) { + return file_api_bladeapi_v1alpha1_blade_proto_rawDescGZIP(), []int{0} +} + +func (x *StealthModeRequest) GetEnable() bool { + if x != nil { + return x.Enable + } + return false +} + +type SetFanSpeedRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Percent int64 `protobuf:"varint,1,opt,name=percent,proto3" json:"percent,omitempty"` +} + +func (x *SetFanSpeedRequest) Reset() { + *x = SetFanSpeedRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_bladeapi_v1alpha1_blade_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetFanSpeedRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetFanSpeedRequest) ProtoMessage() {} + +func (x *SetFanSpeedRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_bladeapi_v1alpha1_blade_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetFanSpeedRequest.ProtoReflect.Descriptor instead. +func (*SetFanSpeedRequest) Descriptor() ([]byte, []int) { + return file_api_bladeapi_v1alpha1_blade_proto_rawDescGZIP(), []int{1} +} + +func (x *SetFanSpeedRequest) GetPercent() int64 { + if x != nil { + return x.Percent + } + return 0 +} + +type EmitEventRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Event Event `protobuf:"varint,1,opt,name=event,proto3,enum=api.bladeapi.v1alpha1.Event" json:"event,omitempty"` +} + +func (x *EmitEventRequest) Reset() { + *x = EmitEventRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_bladeapi_v1alpha1_blade_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EmitEventRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EmitEventRequest) ProtoMessage() {} + +func (x *EmitEventRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_bladeapi_v1alpha1_blade_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EmitEventRequest.ProtoReflect.Descriptor instead. +func (*EmitEventRequest) Descriptor() ([]byte, []int) { + return file_api_bladeapi_v1alpha1_blade_proto_rawDescGZIP(), []int{2} +} + +func (x *EmitEventRequest) GetEvent() Event { + if x != nil { + return x.Event + } + return Event_IDENTIFY +} + +type StatusResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StealthMode bool `protobuf:"varint,1,opt,name=stealth_mode,json=stealthMode,proto3" json:"stealth_mode,omitempty"` + IdentifyActive bool `protobuf:"varint,2,opt,name=identify_active,json=identifyActive,proto3" json:"identify_active,omitempty"` + CriticalActive bool `protobuf:"varint,3,opt,name=critical_active,json=criticalActive,proto3" json:"critical_active,omitempty"` + Temperature int64 `protobuf:"varint,4,opt,name=temperature,proto3" json:"temperature,omitempty"` + FanRpm int64 `protobuf:"varint,5,opt,name=fan_rpm,json=fanRpm,proto3" json:"fan_rpm,omitempty"` + PowerStatus PowerStatus `protobuf:"varint,6,opt,name=power_status,json=powerStatus,proto3,enum=api.bladeapi.v1alpha1.PowerStatus" json:"power_status,omitempty"` +} + +func (x *StatusResponse) Reset() { + *x = StatusResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_bladeapi_v1alpha1_blade_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatusResponse) ProtoMessage() {} + +func (x *StatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_bladeapi_v1alpha1_blade_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && 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.ProtoReflect.Descriptor instead. +func (*StatusResponse) Descriptor() ([]byte, []int) { + return file_api_bladeapi_v1alpha1_blade_proto_rawDescGZIP(), []int{3} +} + +func (x *StatusResponse) GetStealthMode() bool { + if x != nil { + return x.StealthMode + } + return false +} + +func (x *StatusResponse) GetIdentifyActive() bool { + if x != nil { + return x.IdentifyActive + } + return false +} + +func (x *StatusResponse) GetCriticalActive() bool { + if x != nil { + return x.CriticalActive + } + return false +} + +func (x *StatusResponse) GetTemperature() int64 { + if x != nil { + return x.Temperature + } + return 0 +} + +func (x *StatusResponse) GetFanRpm() int64 { + if x != nil { + return x.FanRpm + } + return 0 +} + +func (x *StatusResponse) GetPowerStatus() PowerStatus { + if x != nil { + return x.PowerStatus + } + return PowerStatus_POE_OR_USBC +} + +var File_api_bladeapi_v1alpha1_blade_proto protoreflect.FileDescriptor + +var file_api_bladeapi_v1alpha1_blade_proto_rawDesc = []byte{ + 0x0a, 0x21, 0x61, 0x70, 0x69, 0x2f, 0x62, 0x6c, 0x61, 0x64, 0x65, 0x61, 0x70, 0x69, 0x2f, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x62, 0x6c, 0x61, 0x64, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x61, 0x70, 0x69, 0x2e, 0x62, 0x6c, 0x61, 0x64, 0x65, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2c, 0x0a, 0x12, 0x53, 0x74, 0x65, 0x61, 0x6c, + 0x74, 0x68, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, + 0x06, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x2e, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x46, 0x61, 0x6e, 0x53, + 0x70, 0x65, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, + 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x65, + 0x72, 0x63, 0x65, 0x6e, 0x74, 0x22, 0x46, 0x0a, 0x10, 0x45, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x62, + 0x6c, 0x61, 0x64, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x87, 0x02, + 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x6d, 0x6f, 0x64, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x74, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x4d, + 0x6f, 0x64, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x5f, + 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x27, 0x0a, 0x0f, + 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x41, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x65, 0x6d, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x61, 0x6e, 0x5f, 0x72, + 0x70, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x66, 0x61, 0x6e, 0x52, 0x70, 0x6d, + 0x12, 0x45, 0x0a, 0x0c, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x62, 0x6c, 0x61, + 0x64, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, + 0x6f, 0x77, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0b, 0x70, 0x6f, 0x77, 0x65, + 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2a, 0x4d, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x44, 0x45, 0x4e, 0x54, 0x49, 0x46, 0x59, 0x10, 0x00, 0x12, 0x14, + 0x0a, 0x10, 0x49, 0x44, 0x45, 0x4e, 0x54, 0x49, 0x46, 0x59, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, + 0x52, 0x4d, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x49, 0x54, 0x49, 0x43, 0x41, 0x4c, + 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x52, 0x49, 0x54, 0x49, 0x43, 0x41, 0x4c, 0x5f, 0x52, + 0x45, 0x53, 0x45, 0x54, 0x10, 0x03, 0x2a, 0x21, 0x0a, 0x07, 0x46, 0x61, 0x6e, 0x55, 0x6e, 0x69, + 0x74, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x09, + 0x0a, 0x05, 0x53, 0x4d, 0x41, 0x52, 0x54, 0x10, 0x01, 0x2a, 0x2e, 0x0a, 0x0b, 0x50, 0x6f, 0x77, + 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x4f, 0x45, 0x5f, + 0x4f, 0x52, 0x5f, 0x55, 0x53, 0x42, 0x43, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x4f, 0x45, + 0x5f, 0x38, 0x30, 0x32, 0x5f, 0x41, 0x54, 0x10, 0x01, 0x32, 0xa8, 0x03, 0x0a, 0x11, 0x42, 0x6c, + 0x61, 0x64, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x4e, 0x0a, 0x09, 0x45, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x62, 0x6c, 0x61, 0x64, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x31, 0x2e, 0x45, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, + 0x4a, 0x0a, 0x16, 0x57, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0b, 0x53, + 0x65, 0x74, 0x46, 0x61, 0x6e, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x29, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x62, 0x6c, 0x61, 0x64, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x46, 0x61, 0x6e, 0x53, 0x70, 0x65, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, + 0x55, 0x0a, 0x0e, 0x53, 0x65, 0x74, 0x53, 0x74, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x4d, 0x6f, 0x64, + 0x65, 0x12, 0x29, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x62, 0x6c, 0x61, 0x64, 0x65, 0x61, 0x70, 0x69, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x74, 0x65, 0x61, 0x6c, 0x74, + 0x68, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x25, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x62, 0x6c, 0x61, 0x64, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x78, 0x76, 0x7a, 0x66, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x62, + 0x6c, 0x61, 0x64, 0x65, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x62, + 0x6c, 0x61, 0x64, 0x65, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x62, 0x6c, + 0x61, 0x64, 0x65, 0x61, 0x70, 0x69, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_api_bladeapi_v1alpha1_blade_proto_rawDescOnce sync.Once + file_api_bladeapi_v1alpha1_blade_proto_rawDescData = file_api_bladeapi_v1alpha1_blade_proto_rawDesc +) + +func file_api_bladeapi_v1alpha1_blade_proto_rawDescGZIP() []byte { + file_api_bladeapi_v1alpha1_blade_proto_rawDescOnce.Do(func() { + file_api_bladeapi_v1alpha1_blade_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_bladeapi_v1alpha1_blade_proto_rawDescData) + }) + return file_api_bladeapi_v1alpha1_blade_proto_rawDescData +} + +var file_api_bladeapi_v1alpha1_blade_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_api_bladeapi_v1alpha1_blade_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_api_bladeapi_v1alpha1_blade_proto_goTypes = []interface{}{ + (Event)(0), // 0: api.bladeapi.v1alpha1.Event + (FanUnit)(0), // 1: api.bladeapi.v1alpha1.FanUnit + (PowerStatus)(0), // 2: api.bladeapi.v1alpha1.PowerStatus + (*StealthModeRequest)(nil), // 3: api.bladeapi.v1alpha1.StealthModeRequest + (*SetFanSpeedRequest)(nil), // 4: api.bladeapi.v1alpha1.SetFanSpeedRequest + (*EmitEventRequest)(nil), // 5: api.bladeapi.v1alpha1.EmitEventRequest + (*StatusResponse)(nil), // 6: api.bladeapi.v1alpha1.StatusResponse + (*emptypb.Empty)(nil), // 7: google.protobuf.Empty +} +var file_api_bladeapi_v1alpha1_blade_proto_depIdxs = []int32{ + 0, // 0: api.bladeapi.v1alpha1.EmitEventRequest.event:type_name -> api.bladeapi.v1alpha1.Event + 2, // 1: api.bladeapi.v1alpha1.StatusResponse.power_status:type_name -> api.bladeapi.v1alpha1.PowerStatus + 5, // 2: api.bladeapi.v1alpha1.BladeAgentService.EmitEvent:input_type -> api.bladeapi.v1alpha1.EmitEventRequest + 7, // 3: api.bladeapi.v1alpha1.BladeAgentService.WaitForIdentifyConfirm:input_type -> google.protobuf.Empty + 4, // 4: api.bladeapi.v1alpha1.BladeAgentService.SetFanSpeed:input_type -> api.bladeapi.v1alpha1.SetFanSpeedRequest + 3, // 5: api.bladeapi.v1alpha1.BladeAgentService.SetStealthMode:input_type -> api.bladeapi.v1alpha1.StealthModeRequest + 7, // 6: api.bladeapi.v1alpha1.BladeAgentService.GetStatus:input_type -> google.protobuf.Empty + 7, // 7: api.bladeapi.v1alpha1.BladeAgentService.EmitEvent:output_type -> google.protobuf.Empty + 7, // 8: api.bladeapi.v1alpha1.BladeAgentService.WaitForIdentifyConfirm:output_type -> google.protobuf.Empty + 7, // 9: api.bladeapi.v1alpha1.BladeAgentService.SetFanSpeed:output_type -> google.protobuf.Empty + 7, // 10: api.bladeapi.v1alpha1.BladeAgentService.SetStealthMode:output_type -> google.protobuf.Empty + 6, // 11: api.bladeapi.v1alpha1.BladeAgentService.GetStatus:output_type -> api.bladeapi.v1alpha1.StatusResponse + 7, // [7:12] is the sub-list for method output_type + 2, // [2:7] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_api_bladeapi_v1alpha1_blade_proto_init() } +func file_api_bladeapi_v1alpha1_blade_proto_init() { + if File_api_bladeapi_v1alpha1_blade_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_api_bladeapi_v1alpha1_blade_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StealthModeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_bladeapi_v1alpha1_blade_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetFanSpeedRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_bladeapi_v1alpha1_blade_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EmitEventRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_bladeapi_v1alpha1_blade_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StatusResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_api_bladeapi_v1alpha1_blade_proto_rawDesc, + NumEnums: 3, + NumMessages: 4, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_api_bladeapi_v1alpha1_blade_proto_goTypes, + DependencyIndexes: file_api_bladeapi_v1alpha1_blade_proto_depIdxs, + EnumInfos: file_api_bladeapi_v1alpha1_blade_proto_enumTypes, + MessageInfos: file_api_bladeapi_v1alpha1_blade_proto_msgTypes, + }.Build() + File_api_bladeapi_v1alpha1_blade_proto = out.File + file_api_bladeapi_v1alpha1_blade_proto_rawDesc = nil + file_api_bladeapi_v1alpha1_blade_proto_goTypes = nil + file_api_bladeapi_v1alpha1_blade_proto_depIdxs = nil +} diff --git a/api/bladeapi/v1alpha1/blade.proto b/api/bladeapi/v1alpha1/blade.proto new file mode 100644 index 0000000..ab63a9e --- /dev/null +++ b/api/bladeapi/v1alpha1/blade.proto @@ -0,0 +1,61 @@ +syntax = "proto4"; + +import "google/protobuf/empty.proto"; +package api.bladeapi.v1alpha1; + +option go_package = "github.com/xvzf/computeblade-agent/api/blade/v1alpha1;bladeapiv1alpha1"; + +// Event is an event the agent reacts to +enum Event { + IDENTIFY = 0; + IDENTIFY_CONFIRM = 1; + CRITICAL = 2; + CRITICAL_RESET = 3; +} + +// FanUnit defines the fan unit detected by the blade +enum FanUnit { + DEFAULT = 0; + SMART = 1; +} + +// PowerStatus defines the power status of the blade +enum PowerStatus { + POE_OR_USBC = 0; + POE_802_AT = 1; +} + +message StealthModeRequest { + bool enable = 1; +} + +message SetFanSpeedRequest { + int64 percent = 1; +} + +message EmitEventRequest { + Event event = 1; +} + +message StatusResponse { + bool stealth_mode = 1; + bool identify_active = 2; + bool critical_active = 3; + int64 temperature = 4; + int64 fan_rpm = 5; + PowerStatus power_status = 6; +} + +service BladeAgentService { + // EmitEvent emits an event to the blade + rpc EmitEvent(EmitEventRequest) returns (google.protobuf.Empty) {} + + // WaitForIdentifyConfirm blocks until the blades button is pressed + rpc WaitForIdentifyConfirm(google.protobuf.Empty) returns (google.protobuf.Empty) {} + + rpc SetFanSpeed(SetFanSpeedRequest) returns (google.protobuf.Empty) {} + + rpc SetStealthMode(StealthModeRequest) returns (google.protobuf.Empty) {} + + rpc GetStatus(google.protobuf.Empty) returns (StatusResponse) {} +} diff --git a/api/bladeapi/v1alpha1/blade_grpc.pb.go b/api/bladeapi/v1alpha1/blade_grpc.pb.go new file mode 100644 index 0000000..6e6cddb --- /dev/null +++ b/api/bladeapi/v1alpha1/blade_grpc.pb.go @@ -0,0 +1,262 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: api/bladeapi/v1alpha1/blade.proto + +package bladeapiv1alpha1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + BladeAgentService_EmitEvent_FullMethodName = "/api.bladeapi.v1alpha1.BladeAgentService/EmitEvent" + BladeAgentService_WaitForIdentifyConfirm_FullMethodName = "/api.bladeapi.v1alpha1.BladeAgentService/WaitForIdentifyConfirm" + BladeAgentService_SetFanSpeed_FullMethodName = "/api.bladeapi.v1alpha1.BladeAgentService/SetFanSpeed" + BladeAgentService_SetStealthMode_FullMethodName = "/api.bladeapi.v1alpha1.BladeAgentService/SetStealthMode" + BladeAgentService_GetStatus_FullMethodName = "/api.bladeapi.v1alpha1.BladeAgentService/GetStatus" +) + +// BladeAgentServiceClient is the client API for BladeAgentService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type BladeAgentServiceClient interface { + // EmitEvent emits an event to the blade + EmitEvent(ctx context.Context, in *EmitEventRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + // WaitForIdentifyConfirm blocks until the blades button is pressed + WaitForIdentifyConfirm(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) + SetFanSpeed(ctx context.Context, in *SetFanSpeedRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + SetStealthMode(ctx context.Context, in *StealthModeRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + GetStatus(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*StatusResponse, error) +} + +type bladeAgentServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewBladeAgentServiceClient(cc grpc.ClientConnInterface) BladeAgentServiceClient { + return &bladeAgentServiceClient{cc} +} + +func (c *bladeAgentServiceClient) EmitEvent(ctx context.Context, in *EmitEventRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, BladeAgentService_EmitEvent_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bladeAgentServiceClient) WaitForIdentifyConfirm(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, BladeAgentService_WaitForIdentifyConfirm_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bladeAgentServiceClient) SetFanSpeed(ctx context.Context, in *SetFanSpeedRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, BladeAgentService_SetFanSpeed_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bladeAgentServiceClient) SetStealthMode(ctx context.Context, in *StealthModeRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, BladeAgentService_SetStealthMode_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bladeAgentServiceClient) GetStatus(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*StatusResponse, error) { + out := new(StatusResponse) + err := c.cc.Invoke(ctx, BladeAgentService_GetStatus_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// BladeAgentServiceServer is the server API for BladeAgentService service. +// All implementations must embed UnimplementedBladeAgentServiceServer +// for forward compatibility +type BladeAgentServiceServer interface { + // EmitEvent emits an event to the blade + EmitEvent(context.Context, *EmitEventRequest) (*emptypb.Empty, error) + // WaitForIdentifyConfirm blocks until the blades button is pressed + WaitForIdentifyConfirm(context.Context, *emptypb.Empty) (*emptypb.Empty, error) + SetFanSpeed(context.Context, *SetFanSpeedRequest) (*emptypb.Empty, error) + SetStealthMode(context.Context, *StealthModeRequest) (*emptypb.Empty, error) + GetStatus(context.Context, *emptypb.Empty) (*StatusResponse, error) + mustEmbedUnimplementedBladeAgentServiceServer() +} + +// UnimplementedBladeAgentServiceServer must be embedded to have forward compatible implementations. +type UnimplementedBladeAgentServiceServer struct { +} + +func (UnimplementedBladeAgentServiceServer) EmitEvent(context.Context, *EmitEventRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method EmitEvent not implemented") +} +func (UnimplementedBladeAgentServiceServer) WaitForIdentifyConfirm(context.Context, *emptypb.Empty) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method WaitForIdentifyConfirm not implemented") +} +func (UnimplementedBladeAgentServiceServer) SetFanSpeed(context.Context, *SetFanSpeedRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetFanSpeed not implemented") +} +func (UnimplementedBladeAgentServiceServer) SetStealthMode(context.Context, *StealthModeRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetStealthMode not implemented") +} +func (UnimplementedBladeAgentServiceServer) GetStatus(context.Context, *emptypb.Empty) (*StatusResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetStatus not implemented") +} +func (UnimplementedBladeAgentServiceServer) mustEmbedUnimplementedBladeAgentServiceServer() {} + +// UnsafeBladeAgentServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to BladeAgentServiceServer will +// result in compilation errors. +type UnsafeBladeAgentServiceServer interface { + mustEmbedUnimplementedBladeAgentServiceServer() +} + +func RegisterBladeAgentServiceServer(s grpc.ServiceRegistrar, srv BladeAgentServiceServer) { + s.RegisterService(&BladeAgentService_ServiceDesc, srv) +} + +func _BladeAgentService_EmitEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EmitEventRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BladeAgentServiceServer).EmitEvent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: BladeAgentService_EmitEvent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BladeAgentServiceServer).EmitEvent(ctx, req.(*EmitEventRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _BladeAgentService_WaitForIdentifyConfirm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BladeAgentServiceServer).WaitForIdentifyConfirm(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: BladeAgentService_WaitForIdentifyConfirm_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BladeAgentServiceServer).WaitForIdentifyConfirm(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _BladeAgentService_SetFanSpeed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetFanSpeedRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BladeAgentServiceServer).SetFanSpeed(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: BladeAgentService_SetFanSpeed_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BladeAgentServiceServer).SetFanSpeed(ctx, req.(*SetFanSpeedRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _BladeAgentService_SetStealthMode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StealthModeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BladeAgentServiceServer).SetStealthMode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: BladeAgentService_SetStealthMode_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BladeAgentServiceServer).SetStealthMode(ctx, req.(*StealthModeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _BladeAgentService_GetStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BladeAgentServiceServer).GetStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: BladeAgentService_GetStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BladeAgentServiceServer).GetStatus(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +// BladeAgentService_ServiceDesc is the grpc.ServiceDesc for BladeAgentService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var BladeAgentService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "api.bladeapi.v1alpha1.BladeAgentService", + HandlerType: (*BladeAgentServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "EmitEvent", + Handler: _BladeAgentService_EmitEvent_Handler, + }, + { + MethodName: "WaitForIdentifyConfirm", + Handler: _BladeAgentService_WaitForIdentifyConfirm_Handler, + }, + { + MethodName: "SetFanSpeed", + Handler: _BladeAgentService_SetFanSpeed_Handler, + }, + { + MethodName: "SetStealthMode", + Handler: _BladeAgentService_SetStealthMode_Handler, + }, + { + MethodName: "GetStatus", + Handler: _BladeAgentService_GetStatus_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "api/bladeapi/v1alpha1/blade.proto", +} diff --git a/buf.gen.yaml b/buf.gen.yaml new file mode 100644 index 0000000..162c640 --- /dev/null +++ b/buf.gen.yaml @@ -0,0 +1,10 @@ +version: v1 +plugins: + - plugin: buf.build/protocolbuffers/go:v1.31.0 + out: . + opt: + - paths=source_relative + - plugin: buf.build/grpc/go:v1.3.0 + out: . + opt: + - paths=source_relative diff --git a/buf.yaml b/buf.yaml new file mode 100644 index 0000000..1a51945 --- /dev/null +++ b/buf.yaml @@ -0,0 +1,7 @@ +version: v1 +breaking: + use: + - FILE +lint: + use: + - DEFAULT diff --git a/cmd/agent/main.go b/cmd/agent/main.go index 68b4282..9d5aaa1 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "net" "net/http" "os" "os/signal" @@ -11,10 +12,12 @@ import ( "time" "github.com/prometheus/client_golang/prometheus/promhttp" + bladeapiv1alpha1 "github.com/xvzf/computeblade-agent/api/bladeapi/v1alpha1" "github.com/xvzf/computeblade-agent/internal/agent" "github.com/xvzf/computeblade-agent/pkg/ledengine" "github.com/xvzf/computeblade-agent/pkg/log" "go.uber.org/zap" + "google.golang.org/grpc" ) func main() { @@ -29,7 +32,7 @@ func main() { ctx, cancelCtx := context.WithCancelCause(baseCtx) defer cancelCtx(context.Canceled) - agent, err := agent.NewComputeBladeAgent(agent.ComputeBladeAgentConfig{ + computebladeAgent, err := agent.NewComputeBladeAgent(agent.ComputeBladeAgentConfig{ IdleLedColor: ledengine.LedColorGreen(0.05), IdentifyLedColor: ledengine.LedColorPurple(0.05), CriticalLedColor: ledengine.LedColorRed(0.3), @@ -61,13 +64,41 @@ func main() { wg.Add(1) go func() { defer wg.Done() - err := agent.Run(ctx) + err := computebladeAgent.Run(ctx) if err != nil && err != context.Canceled { log.FromContext(ctx).Error("Failed to run agent", zap.Error(err)) cancelCtx(err) } }() + // Setup GRPC server + // FIXME add logging middleware + grpcServer := grpc.NewServer() + bladeapiv1alpha1.RegisterBladeAgentServiceServer(grpcServer, agent.NewGrpcServiceFor(computebladeAgent)) + wg.Add(1) + go func() { + defer wg.Done() + socketPath := "/tmp/computeblade-agent.sock" + grpcListen, err := net.Listen("unix", "/tmp/computeblade-agent.sock") + if err != nil { + log.FromContext(ctx).Error("Failed to create grpc listener", zap.Error(err)) + cancelCtx(err) + return + } + log.FromContext(ctx).Info("Starting grpc server", zap.String("address", socketPath)) + if err := grpcServer.Serve(grpcListen); err != nil && err != grpc.ErrServerStopped { + log.FromContext(ctx).Error("Failed to start grpc server", zap.Error(err)) + cancelCtx(err) + } + }() + wg.Add(1) + go func() { + defer wg.Done() + <-ctx.Done() + log.FromContext(ctx).Info("Shutting down grpc server") + grpcServer.GracefulStop() + }() + // setup prometheus endpoint promHandler := http.NewServeMux() promHandler.Handle("/metrics", promhttp.Handler()) diff --git a/cmd/bladectl/cmd_fan.go b/cmd/bladectl/cmd_fan.go new file mode 100644 index 0000000..a897d8a --- /dev/null +++ b/cmd/bladectl/cmd_fan.go @@ -0,0 +1,45 @@ +package main + +import ( + "strconv" + + "github.com/spf13/cobra" + bladeapiv1alpha1 "github.com/xvzf/computeblade-agent/api/bladeapi/v1alpha1" +) + +func init() { + cmdFan.AddCommand(cmdFanSetPercent) + rootCmd.AddCommand(cmdFan) +} + +var ( + cmdFan = &cobra.Command{ + Use: "fan", + Short: "Fan-related commands for the compute blade", + } + + cmdFanSetPercent = &cobra.Command{ + Use: "set-percent ", + Example: "bladectl fan set-percent 50", + Short: "Set the fan speed in percent", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + var err error + + ctx := cmd.Context() + client := clientFromContext(ctx) + + // convert string to int + percent, err := strconv.Atoi(args[0]) + if err != nil { + return err + } + + _, err = client.SetFanSpeed(ctx, &bladeapiv1alpha1.SetFanSpeedRequest{ + Percent: int64(percent), + }) + + return err + }, + } +) diff --git a/cmd/bladectl/cmd_identify.go b/cmd/bladectl/cmd_identify.go new file mode 100644 index 0000000..f6e44f5 --- /dev/null +++ b/cmd/bladectl/cmd_identify.go @@ -0,0 +1,58 @@ +package main + +import ( + "github.com/spf13/cobra" + bladeapiv1alpha1 "github.com/xvzf/computeblade-agent/api/bladeapi/v1alpha1" + "google.golang.org/protobuf/types/known/emptypb" +) + +func init() { + cmdIdentify.Flags().Bool("confirm", false, "confirm the identify state") + cmdIdentify.Flags().Bool("wait", false, "Wait for the identify state to be confirmed (e.g. by a physical button press)") + rootCmd.AddCommand(cmdIdentify) +} + +var cmdIdentify = &cobra.Command{ + Use: "identify", + Short: "interact with the compute-blade identity LED", + RunE: runIdentity, +} + +func runIdentity(cmd *cobra.Command, _ []string) error { + var err error + + ctx := cmd.Context() + client := clientFromContext(ctx) + + // Get flags + confirm, err := cmd.Flags().GetBool("confirm") + if err != nil { + return err + } + wait, err := cmd.Flags().GetBool("wait") + if err != nil { + return err + } + + // Check if we should wait for the identify state to be confirmed + event := bladeapiv1alpha1.Event_IDENTIFY + if confirm { + event = bladeapiv1alpha1.Event_IDENTIFY_CONFIRM + } + + // Emit the event to the computeblade-agent + _, err = client.EmitEvent(ctx, &bladeapiv1alpha1.EmitEventRequest{Event: event}) + if err != nil { + return err + } + + // Check if we should wait for the identify state to be confirmed + if wait { + _, err := client.WaitForIdentifyConfirm(ctx, &emptypb.Empty{}) + if err != nil { + return err + } + } + + return nil +} diff --git a/cmd/bladectl/main.go b/cmd/bladectl/main.go new file mode 100644 index 0000000..68d8703 --- /dev/null +++ b/cmd/bladectl/main.go @@ -0,0 +1,85 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + "os/signal" + "syscall" + "time" + + "github.com/spf13/cobra" + bladeapiv1alpha1 "github.com/xvzf/computeblade-agent/api/bladeapi/v1alpha1" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type grpcClientContextKey int + +const defaultGrpcClientContextKey grpcClientContextKey = 0 + +var ( + grpcAddr string + timeout time.Duration +) + +func init() { + rootCmd.PersistentFlags(). + StringVar(&grpcAddr, "addr", "unix:///tmp/computeblade-agent.sock", "address of the computeblade-agent gRPC server") + rootCmd.PersistentFlags().DurationVar(&timeout, "timeout", time.Minute, "timeout for gRPC requests") +} + +func clientIntoContext(ctx context.Context, client bladeapiv1alpha1.BladeAgentServiceClient) context.Context { + return context.WithValue(ctx, defaultGrpcClientContextKey, client) +} + +func clientFromContext(ctx context.Context) (bladeapiv1alpha1.BladeAgentServiceClient) { + client, ok := ctx.Value(defaultGrpcClientContextKey).(bladeapiv1alpha1.BladeAgentServiceClient) + if !ok { + panic("grpc client not found in context") + } + return client +} + + +var rootCmd = &cobra.Command{ + Use: "bladectl", + Short: "bladectl interacts with the computeblade-agent and allows you to manage hardware-features of your compute blade(s)", + PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { + origCtx := cmd.Context() + + // setup signal handlers for SIGINT and SIGTERM + ctx, cancelCtx := context.WithTimeout(origCtx, timeout) + + // setup signal handler channels + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + go func() { + // Wait for context cancel or signal + select { + case <-ctx.Done(): + case <-sigs: + // On signal, cancel context + cancelCtx() + } + }() + + // FIXME handle conn teardown properly + // setup grpc client + conn, err := grpc.Dial(grpcAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return fmt.Errorf("failed to dial grpc server: %w", err) + } + client := bladeapiv1alpha1.NewBladeAgentServiceClient(conn) + + cmd.SetContext(clientIntoContext(ctx, client)) + return nil + }, +} + +func main() { + if err := rootCmd.Execute(); err != nil { + log.Fatal(err) + } +} diff --git a/go.mod b/go.mod index 8fe6bef..68d232c 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,12 @@ go 1.20 require ( github.com/prometheus/client_golang v1.16.0 + github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.1 github.com/warthog618/gpiod v0.8.1 + go.uber.org/zap v1.24.0 + google.golang.org/grpc v1.56.2 + google.golang.org/protobuf v1.31.0 ) require ( @@ -13,17 +17,20 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.24.0 // indirect + golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.10.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 489348d..fa85444 100644 --- a/go.sum +++ b/go.sum @@ -1,31 +1,29 @@ +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/pilebones/go-udev v0.9.0 h1:N1uEO/SxUwtIctc0WLU0t69JeBxIYEYnj8lT/Nabl9Q= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= @@ -37,6 +35,11 @@ github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= @@ -49,21 +52,29 @@ github.com/warthog618/gpiod v0.8.1 h1:+8iHpHd3fljAd6l4AT8jPbMDQNKdvBIpW/hmLgAcHi github.com/warthog618/gpiod v0.8.1/go.mod h1:A7v1hGR2eTsnkN+e9RoAPYgJG9bLJWtwyIIK+pgqC7s= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= +google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/agent/api.go b/internal/agent/api.go new file mode 100644 index 0000000..f2faf48 --- /dev/null +++ b/internal/agent/api.go @@ -0,0 +1,65 @@ +package agent + +import ( + "context" + + bladeapiv1alpha1 "github.com/xvzf/computeblade-agent/api/bladeapi/v1alpha1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/emptypb" +) + +// ComputeBladeAgent implementing the BladeAgentServiceServer +type agentGrpcService struct { + bladeapiv1alpha1.UnimplementedBladeAgentServiceServer + + Agent ComputeBladeAgent +} + +// NewGrpcServiceFor creates a new gRPC service for a given agent +func NewGrpcServiceFor(agent ComputeBladeAgent) *agentGrpcService { + return &agentGrpcService{ + Agent: agent, + } +} + +// EmitEvent emits an event to the agent runtime +func (service *agentGrpcService) EmitEvent( + ctx context.Context, + req *bladeapiv1alpha1.EmitEventRequest, +) (*emptypb.Empty, error) { + switch req.GetEvent() { + case bladeapiv1alpha1.Event_IDENTIFY: + return &emptypb.Empty{}, service.Agent.EmitEvent(ctx, IdentifyEvent) + case bladeapiv1alpha1.Event_IDENTIFY_CONFIRM: + return &emptypb.Empty{}, service.Agent.EmitEvent(ctx, IdentifyConfirmEvent) + case bladeapiv1alpha1.Event_CRITICAL: + return &emptypb.Empty{}, service.Agent.EmitEvent(ctx, CriticalEvent) + case bladeapiv1alpha1.Event_CRITICAL_RESET: + return &emptypb.Empty{}, service.Agent.EmitEvent(ctx, CriticalResetEvent) + default: + return &emptypb.Empty{}, status.Errorf(codes.InvalidArgument, "invalid event type") + } +} + +func (service *agentGrpcService) WaitForIdentifyConfirm(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) { + return &emptypb.Empty{}, service.Agent.WaitForIdentifyConfirm(ctx) +} + +// SetFanSpeed sets the fan speed of the blade +func (service *agentGrpcService) SetFanSpeed( + ctx context.Context, + req *bladeapiv1alpha1.SetFanSpeedRequest, +) (*emptypb.Empty, error) { + return &emptypb.Empty{}, service.Agent.SetFanSpeed(ctx, uint8(req.GetPercent())) +} + +// SetStealthMode enables/disables stealth mode on the blade +func (service *agentGrpcService) SetStealthMode(ctx context.Context, req *bladeapiv1alpha1.StealthModeRequest) (*emptypb.Empty, error) { + return &emptypb.Empty{}, service.Agent.SetStealthMode(ctx, req.GetEnable()) +} + +// GetStatus aggregates the status of the blade +func (service *agentGrpcService) GetStatus(context.Context, *emptypb.Empty) (*bladeapiv1alpha1.StatusResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetStatus not implemented") +}