diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e8a0742..762a19e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,11 +3,9 @@ { "name": "Go", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/go:0-1-bullseye", + "image": "mcr.microsoft.com/devcontainers/go:1-1.21-bullseye", "features": { - "ghcr.io/devcontainers/features/go:1": {}, - "ghcr.io/devcontainers-contrib/features/protoc-asdf:1": {}, - "ghcr.io/jungaretti/features/make:1": {} + "ghcr.io/devcontainers-contrib/features/protoc-asdf:1": {} } // Features to add to the dev container. More info: https://containers.dev/features. diff --git a/api/v1/diagnostic.pb.go b/api/v1/diagnostic.pb.go index a1e33b2..e091501 100644 --- a/api/v1/diagnostic.pb.go +++ b/api/v1/diagnostic.pb.go @@ -136,6 +136,108 @@ func (x *ScreenshotResponse) GetFiletype() string { return "" } +type ClearSystemEventLogRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Authn *Authn `protobuf:"bytes,1,opt,name=authn,proto3" json:"authn,omitempty"` + Vendor *Vendor `protobuf:"bytes,2,opt,name=vendor,proto3" json:"vendor,omitempty"` +} + +func (x *ClearSystemEventLogRequest) Reset() { + *x = ClearSystemEventLogRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_v1_diagnostic_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ClearSystemEventLogRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClearSystemEventLogRequest) ProtoMessage() {} + +func (x *ClearSystemEventLogRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_v1_diagnostic_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 ClearSystemEventLogRequest.ProtoReflect.Descriptor instead. +func (*ClearSystemEventLogRequest) Descriptor() ([]byte, []int) { + return file_api_v1_diagnostic_proto_rawDescGZIP(), []int{2} +} + +func (x *ClearSystemEventLogRequest) GetAuthn() *Authn { + if x != nil { + return x.Authn + } + return nil +} + +func (x *ClearSystemEventLogRequest) GetVendor() *Vendor { + if x != nil { + return x.Vendor + } + return nil +} + +type ClearSystemEventLogResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TaskId string `protobuf:"bytes,1,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` +} + +func (x *ClearSystemEventLogResponse) Reset() { + *x = ClearSystemEventLogResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_v1_diagnostic_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ClearSystemEventLogResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClearSystemEventLogResponse) ProtoMessage() {} + +func (x *ClearSystemEventLogResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_v1_diagnostic_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 ClearSystemEventLogResponse.ProtoReflect.Descriptor instead. +func (*ClearSystemEventLogResponse) Descriptor() ([]byte, []int) { + return file_api_v1_diagnostic_proto_rawDescGZIP(), []int{3} +} + +func (x *ClearSystemEventLogResponse) GetTaskId() string { + if x != nil { + return x.TaskId + } + return "" +} + var File_api_v1_diagnostic_proto protoreflect.FileDescriptor var file_api_v1_diagnostic_proto_rawDesc = []byte{ @@ -158,19 +260,42 @@ var file_api_v1_diagnostic_proto_rawDesc = []byte{ 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x74, 0x79, - 0x70, 0x65, 0x32, 0x87, 0x01, 0x0a, 0x0a, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, - 0x63, 0x12, 0x79, 0x0a, 0x0a, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x12, - 0x34, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x69, 0x6e, + 0x70, 0x65, 0x22, 0x9f, 0x01, 0x0a, 0x1a, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x3e, 0x0a, 0x05, 0x61, 0x75, 0x74, 0x68, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x28, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x69, + 0x6e, 0x6b, 0x65, 0x72, 0x62, 0x65, 0x6c, 0x6c, 0x2e, 0x70, 0x62, 0x6e, 0x6a, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6e, 0x52, 0x05, 0x61, 0x75, 0x74, 0x68, + 0x6e, 0x12, 0x41, 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x74, + 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x62, 0x65, 0x6c, 0x6c, 0x2e, 0x70, 0x62, 0x6e, 0x6a, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x52, 0x06, 0x76, 0x65, + 0x6e, 0x64, 0x6f, 0x72, 0x22, 0x36, 0x0a, 0x1b, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x32, 0x9e, 0x02, 0x0a, + 0x0a, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x12, 0x79, 0x0a, 0x0a, 0x53, + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x34, 0x2e, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x62, 0x65, 0x6c, + 0x6c, 0x2e, 0x70, 0x62, 0x6e, 0x6a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, + 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x35, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x62, 0x65, 0x6c, 0x6c, 0x2e, 0x70, 0x62, 0x6e, 0x6a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2e, 0x74, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x62, 0x65, 0x6c, 0x6c, 0x2e, 0x70, 0x62, - 0x6e, 0x6a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, - 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, 0x21, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x69, 0x6e, 0x6b, 0x65, - 0x72, 0x62, 0x65, 0x6c, 0x6c, 0x2f, 0x70, 0x62, 0x6e, 0x6a, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0xea, 0x02, 0x0d, 0x50, 0x62, 0x6e, 0x6a, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, - 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x94, 0x01, 0x0a, 0x13, 0x43, 0x6c, 0x65, 0x61, 0x72, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x12, 0x3d, + 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x69, 0x6e, 0x6b, + 0x65, 0x72, 0x62, 0x65, 0x6c, 0x6c, 0x2e, 0x70, 0x62, 0x6e, 0x6a, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3e, 0x2e, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x69, 0x6e, 0x6b, 0x65, + 0x72, 0x62, 0x65, 0x6c, 0x6c, 0x2e, 0x70, 0x62, 0x6e, 0x6a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, + 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x69, 0x6e, 0x6b, + 0x65, 0x72, 0x62, 0x65, 0x6c, 0x6c, 0x2f, 0x70, 0x62, 0x6e, 0x6a, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0xea, 0x02, 0x0d, 0x50, 0x62, 0x6e, 0x6a, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, + 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -185,23 +310,29 @@ func file_api_v1_diagnostic_proto_rawDescGZIP() []byte { return file_api_v1_diagnostic_proto_rawDescData } -var file_api_v1_diagnostic_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_api_v1_diagnostic_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_api_v1_diagnostic_proto_goTypes = []interface{}{ - (*ScreenshotRequest)(nil), // 0: github.com.tinkerbell.pbnj.api.v1.ScreenshotRequest - (*ScreenshotResponse)(nil), // 1: github.com.tinkerbell.pbnj.api.v1.ScreenshotResponse - (*Authn)(nil), // 2: github.com.tinkerbell.pbnj.api.v1.Authn - (*Vendor)(nil), // 3: github.com.tinkerbell.pbnj.api.v1.Vendor + (*ScreenshotRequest)(nil), // 0: github.com.tinkerbell.pbnj.api.v1.ScreenshotRequest + (*ScreenshotResponse)(nil), // 1: github.com.tinkerbell.pbnj.api.v1.ScreenshotResponse + (*ClearSystemEventLogRequest)(nil), // 2: github.com.tinkerbell.pbnj.api.v1.ClearSystemEventLogRequest + (*ClearSystemEventLogResponse)(nil), // 3: github.com.tinkerbell.pbnj.api.v1.ClearSystemEventLogResponse + (*Authn)(nil), // 4: github.com.tinkerbell.pbnj.api.v1.Authn + (*Vendor)(nil), // 5: github.com.tinkerbell.pbnj.api.v1.Vendor } var file_api_v1_diagnostic_proto_depIdxs = []int32{ - 2, // 0: github.com.tinkerbell.pbnj.api.v1.ScreenshotRequest.authn:type_name -> github.com.tinkerbell.pbnj.api.v1.Authn - 3, // 1: github.com.tinkerbell.pbnj.api.v1.ScreenshotRequest.vendor:type_name -> github.com.tinkerbell.pbnj.api.v1.Vendor - 0, // 2: github.com.tinkerbell.pbnj.api.v1.Diagnostic.Screenshot:input_type -> github.com.tinkerbell.pbnj.api.v1.ScreenshotRequest - 1, // 3: github.com.tinkerbell.pbnj.api.v1.Diagnostic.Screenshot:output_type -> github.com.tinkerbell.pbnj.api.v1.ScreenshotResponse - 3, // [3:4] is the sub-list for method output_type - 2, // [2:3] 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 + 4, // 0: github.com.tinkerbell.pbnj.api.v1.ScreenshotRequest.authn:type_name -> github.com.tinkerbell.pbnj.api.v1.Authn + 5, // 1: github.com.tinkerbell.pbnj.api.v1.ScreenshotRequest.vendor:type_name -> github.com.tinkerbell.pbnj.api.v1.Vendor + 4, // 2: github.com.tinkerbell.pbnj.api.v1.ClearSystemEventLogRequest.authn:type_name -> github.com.tinkerbell.pbnj.api.v1.Authn + 5, // 3: github.com.tinkerbell.pbnj.api.v1.ClearSystemEventLogRequest.vendor:type_name -> github.com.tinkerbell.pbnj.api.v1.Vendor + 0, // 4: github.com.tinkerbell.pbnj.api.v1.Diagnostic.Screenshot:input_type -> github.com.tinkerbell.pbnj.api.v1.ScreenshotRequest + 2, // 5: github.com.tinkerbell.pbnj.api.v1.Diagnostic.ClearSystemEventLog:input_type -> github.com.tinkerbell.pbnj.api.v1.ClearSystemEventLogRequest + 1, // 6: github.com.tinkerbell.pbnj.api.v1.Diagnostic.Screenshot:output_type -> github.com.tinkerbell.pbnj.api.v1.ScreenshotResponse + 3, // 7: github.com.tinkerbell.pbnj.api.v1.Diagnostic.ClearSystemEventLog:output_type -> github.com.tinkerbell.pbnj.api.v1.ClearSystemEventLogResponse + 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 } func init() { file_api_v1_diagnostic_proto_init() } @@ -235,6 +366,30 @@ func file_api_v1_diagnostic_proto_init() { return nil } } + file_api_v1_diagnostic_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClearSystemEventLogRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_v1_diagnostic_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClearSystemEventLogResponse); 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{ @@ -242,7 +397,7 @@ func file_api_v1_diagnostic_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_api_v1_diagnostic_proto_rawDesc, NumEnums: 0, - NumMessages: 2, + NumMessages: 4, NumExtensions: 0, NumServices: 1, }, diff --git a/api/v1/diagnostic.proto b/api/v1/diagnostic.proto index 4973197..1120cdf 100644 --- a/api/v1/diagnostic.proto +++ b/api/v1/diagnostic.proto @@ -9,6 +9,7 @@ import "api/v1/common.proto"; service Diagnostic { rpc Screenshot (ScreenshotRequest) returns (ScreenshotResponse); + rpc ClearSystemEventLog (ClearSystemEventLogRequest) returns (ClearSystemEventLogResponse); } message ScreenshotRequest { @@ -19,4 +20,13 @@ message ScreenshotRequest { message ScreenshotResponse { bytes image = 1; string filetype = 2; +} + +message ClearSystemEventLogRequest { + v1.Authn authn = 1; + v1.Vendor vendor = 2; +} + +message ClearSystemEventLogResponse { + string task_id = 1; } \ No newline at end of file diff --git a/api/v1/diagnostic.validator.pb.go b/api/v1/diagnostic.validator.pb.go index 1789d43..7b56591 100644 --- a/api/v1/diagnostic.validator.pb.go +++ b/api/v1/diagnostic.validator.pb.go @@ -32,3 +32,19 @@ func (this *ScreenshotRequest) Validate() error { func (this *ScreenshotResponse) Validate() error { return nil } +func (this *ClearSystemEventLogRequest) Validate() error { + if this.Authn != nil { + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Authn); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("Authn", err) + } + } + if this.Vendor != nil { + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Vendor); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("Vendor", err) + } + } + return nil +} +func (this *ClearSystemEventLogResponse) Validate() error { + return nil +} diff --git a/api/v1/diagnostic_grpc.pb.go b/api/v1/diagnostic_grpc.pb.go index e129822..14f6c90 100644 --- a/api/v1/diagnostic_grpc.pb.go +++ b/api/v1/diagnostic_grpc.pb.go @@ -19,6 +19,7 @@ const _ = grpc.SupportPackageIsVersion7 // 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 DiagnosticClient interface { Screenshot(ctx context.Context, in *ScreenshotRequest, opts ...grpc.CallOption) (*ScreenshotResponse, error) + ClearSystemEventLog(ctx context.Context, in *ClearSystemEventLogRequest, opts ...grpc.CallOption) (*ClearSystemEventLogResponse, error) } type diagnosticClient struct { @@ -38,11 +39,21 @@ func (c *diagnosticClient) Screenshot(ctx context.Context, in *ScreenshotRequest return out, nil } +func (c *diagnosticClient) ClearSystemEventLog(ctx context.Context, in *ClearSystemEventLogRequest, opts ...grpc.CallOption) (*ClearSystemEventLogResponse, error) { + out := new(ClearSystemEventLogResponse) + err := c.cc.Invoke(ctx, "/github.com.tinkerbell.pbnj.api.v1.Diagnostic/ClearSystemEventLog", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // DiagnosticServer is the server API for Diagnostic service. // All implementations must embed UnimplementedDiagnosticServer // for forward compatibility type DiagnosticServer interface { Screenshot(context.Context, *ScreenshotRequest) (*ScreenshotResponse, error) + ClearSystemEventLog(context.Context, *ClearSystemEventLogRequest) (*ClearSystemEventLogResponse, error) mustEmbedUnimplementedDiagnosticServer() } @@ -53,6 +64,9 @@ type UnimplementedDiagnosticServer struct { func (UnimplementedDiagnosticServer) Screenshot(context.Context, *ScreenshotRequest) (*ScreenshotResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Screenshot not implemented") } +func (UnimplementedDiagnosticServer) ClearSystemEventLog(context.Context, *ClearSystemEventLogRequest) (*ClearSystemEventLogResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ClearSystemEventLog not implemented") +} func (UnimplementedDiagnosticServer) mustEmbedUnimplementedDiagnosticServer() {} // UnsafeDiagnosticServer may be embedded to opt out of forward compatibility for this service. @@ -84,6 +98,24 @@ func _Diagnostic_Screenshot_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } +func _Diagnostic_ClearSystemEventLog_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ClearSystemEventLogRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DiagnosticServer).ClearSystemEventLog(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/github.com.tinkerbell.pbnj.api.v1.Diagnostic/ClearSystemEventLog", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DiagnosticServer).ClearSystemEventLog(ctx, req.(*ClearSystemEventLogRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Diagnostic_serviceDesc = grpc.ServiceDesc{ ServiceName: "github.com.tinkerbell.pbnj.api.v1.Diagnostic", HandlerType: (*DiagnosticServer)(nil), @@ -92,6 +124,10 @@ var _Diagnostic_serviceDesc = grpc.ServiceDesc{ MethodName: "Screenshot", Handler: _Diagnostic_Screenshot_Handler, }, + { + MethodName: "ClearSystemEventLog", + Handler: _Diagnostic_ClearSystemEventLog_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "api/v1/diagnostic.proto", diff --git a/client/client.go b/client/client.go index 3f37c96..7ef2b06 100644 --- a/client/client.go +++ b/client/client.go @@ -124,3 +124,24 @@ func Screenshot(ctx context.Context, client v1.DiagnosticClient, request *v1.Scr return filename, nil } + +// ClearSystemEventLog clears the System Event Log of the server. +func ClearSystemEventLog(ctx context.Context, client v1.DiagnosticClient, taskClient v1.TaskClient, request *v1.ClearSystemEventLogRequest) (*v1.StatusResponse, error) { + var statusResp *v1.StatusResponse + response, err := client.ClearSystemEventLog(ctx, request) + if err != nil { + return nil, err + } + + for to := 1; to <= 120; to++ { + statusResp, err := taskClient.Status(ctx, &v1.StatusRequest{TaskId: response.TaskId}) + if err != nil { + return nil, err + } + if statusResp.Complete { + return statusResp, nil + } + time.Sleep(1 * time.Second) + } + return statusResp, nil +} diff --git a/cmd/diagnostic.go b/cmd/diagnostic.go index 7c56c60..0053e92 100644 --- a/cmd/diagnostic.go +++ b/cmd/diagnostic.go @@ -4,6 +4,13 @@ import ( "github.com/spf13/cobra" ) +var ( + bmcaddress string + bmcpass string + bmcuser string + bmcvendor string +) + // diagnosticCmd represents the diagnostic command. var diagnosticCmd = &cobra.Command{ Use: "diagnostic", @@ -12,5 +19,10 @@ var diagnosticCmd = &cobra.Command{ } func init() { + diagnosticCmd.PersistentFlags().StringVar(&bmcaddress, "bmcaddress", "", "bmc address") + diagnosticCmd.PersistentFlags().StringVar(&bmcuser, "bmcuser", "", "bmc user") + diagnosticCmd.PersistentFlags().StringVar(&bmcpass, "bmcpass", "", "bmc password") + diagnosticCmd.PersistentFlags().StringVar(&bmcvendor, "bmcvendor", "", "bmc vendor") + clientCmd.AddCommand(diagnosticCmd) } diff --git a/cmd/screenshot.go b/cmd/screenshot.go index 0d6067f..14d2277 100644 --- a/cmd/screenshot.go +++ b/cmd/screenshot.go @@ -12,11 +12,6 @@ import ( ) var ( - bmcaddress string - bmcpass string - bmcuser string - bmcvendor string - screenshotCmd = &cobra.Command{ Use: "screenshot", Short: "Take a screenshot", @@ -63,10 +58,5 @@ var ( ) func init() { - diagnosticCmd.PersistentFlags().StringVar(&bmcaddress, "bmcaddress", "", "bmc address") - diagnosticCmd.PersistentFlags().StringVar(&bmcuser, "bmcuser", "", "bmc user") - diagnosticCmd.PersistentFlags().StringVar(&bmcpass, "bmcpass", "", "bmc password") - diagnosticCmd.PersistentFlags().StringVar(&bmcvendor, "bmcvendor", "", "bmc vendor") - diagnosticCmd.AddCommand(screenshotCmd) } diff --git a/cmd/sel.go b/cmd/sel.go new file mode 100644 index 0000000..6f892f4 --- /dev/null +++ b/cmd/sel.go @@ -0,0 +1,64 @@ +package cmd + +import ( + "context" + "os" + + "github.com/spf13/cobra" + v1 "github.com/tinkerbell/pbnj/api/v1" + v1Client "github.com/tinkerbell/pbnj/client" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +var ( + clearSystemEventLogcommand = &cobra.Command{ + Use: "selclear", + Short: "Clear the System Event Log", + Long: `Clear the System Event Log of the target BMC`, + Run: func(cmd *cobra.Command, args []string) { + var opts []grpc.DialOption + ctx := context.Background() + + logger := defaultLogger(logLevel) + + opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err := grpc.Dial("localhost:"+port, opts...) + if err != nil { + logger.Error(err, "fail to dial server") + os.Exit(1) + } + defer conn.Close() + client := v1.NewDiagnosticClient(conn) + + taskClient := v1.NewTaskClient(conn) + + resp, err := v1Client.ClearSystemEventLog(ctx, client, taskClient, &v1.ClearSystemEventLogRequest{ + Authn: &v1.Authn{ + Authn: &v1.Authn_DirectAuthn{ + DirectAuthn: &v1.DirectAuthn{ + Host: &v1.Host{ + Host: bmcaddress, + }, + Username: bmcuser, + Password: bmcpass, + }, + }, + }, + Vendor: &v1.Vendor{ + Name: bmcvendor, + }, + }) + if err != nil { + logger.Error(err, "error calling") + os.Exit(1) + } + + logger.Info("resp", "resp", []interface{}{resp}) + }, + } +) + +func init() { + diagnosticCmd.AddCommand(clearSystemEventLogcommand) +} diff --git a/grpc/oob/diagnostic/clearsel.go b/grpc/oob/diagnostic/clearsel.go new file mode 100644 index 0000000..b39b7eb --- /dev/null +++ b/grpc/oob/diagnostic/clearsel.go @@ -0,0 +1,107 @@ +package diagnostic + +import ( + "context" + "fmt" + + "github.com/bmc-toolbox/bmclib/v2" + "github.com/bmc-toolbox/bmclib/v2/providers" + "github.com/prometheus/client_golang/prometheus" + v1 "github.com/tinkerbell/pbnj/api/v1" + common "github.com/tinkerbell/pbnj/grpc/oob" + "github.com/tinkerbell/pbnj/pkg/metrics" + "github.com/tinkerbell/pbnj/pkg/repository" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" +) + +func NewSystemEventLogClearer(req *v1.ClearSystemEventLogRequest, opts ...Option) (*Action, error) { + a := &Action{} + a.ClearSystemEventLogRequest = req + for _, opt := range opts { + err := opt(a) + if err != nil { + return nil, err + } + } + return a, nil +} + +func (m Action) ClearSystemEventLog(ctx context.Context) (result string, err error) { + labels := prometheus.Labels{ + "service": "diagnostic", + "action": "clear_system_event_log", + } + + timer := prometheus.NewTimer(metrics.ActionDuration.With(labels)) + defer timer.ObserveDuration() + + tracer := otel.Tracer("pbnj") + ctx, span := tracer.Start(ctx, "diagnostic.ClearSystemEventLog", trace.WithAttributes( + attribute.String("bmc.device", m.ClearSystemEventLogRequest.GetAuthn().GetDirectAuthn().GetHost().GetHost()), + )) + defer span.End() + + if v := m.ClearSystemEventLogRequest.GetVendor(); v != nil { + span.SetAttributes(attribute.String("bmc.vendor", v.GetName())) + } + + host, user, password, parseErr := m.ParseAuth(m.ClearSystemEventLogRequest.GetAuthn()) + if parseErr != nil { + span.SetStatus(codes.Error, "error parsing credentials: "+parseErr.Error()) + return result, parseErr + } + span.SetAttributes(attribute.String("bmc.host", host), attribute.String("bmc.username", user)) + + opts := []bmclib.Option{ + bmclib.WithLogger(m.Log), + bmclib.WithPerProviderTimeout(common.BMCTimeoutFromCtx(ctx)), + } + + client := bmclib.NewClient(host, user, password, opts...) + client.Registry.Drivers = client.Registry.Supports(providers.FeatureClearSystemEventLog) + + m.SendStatusMessage("connecting to BMC") + err = client.Open(ctx) + meta := client.GetMetadata() + span.SetAttributes(attribute.StringSlice("bmc.open.providersAttempted", meta.ProvidersAttempted), + attribute.StringSlice("bmc.open.successfulOpenConns", meta.SuccessfulOpenConns)) + if err != nil { + span.SetStatus(codes.Error, err.Error()) + return "", &repository.Error{ + Code: v1.Code_value["PERMISSION_DENIED"], + Message: err.Error(), + } + } + log := m.Log.WithValues("host", host, "user", user) + defer func() { + client.Close(ctx) + log.Info("closed connections", logMetadata(client.GetMetadata())...) + }() + log.Info("connected to BMC", logMetadata(client.GetMetadata())...) + m.SendStatusMessage("connected to BMC") + + err = client.ClearSystemEventLog(ctx) + log = m.Log.WithValues(logMetadata(client.GetMetadata())...) + meta = client.GetMetadata() + span.SetAttributes(attribute.String("bmc.clearsystemeventlog.successfulProvider", meta.SuccessfulProvider), + attribute.StringSlice("bmc.clearsystemeventlog.ProvidersAttempted", meta.ProvidersAttempted)) + if err != nil { + log.Error(err, "error clearing SystemEventLog") + span.SetStatus(codes.Error, "error clearing System Event Log: "+err.Error()) + m.SendStatusMessage(fmt.Sprintf("failed to clear System Event Log %v", host)) + + return "", &repository.Error{ + Code: v1.Code_value["UNKNOWN"], + Message: err.Error(), + } + } + + span.SetStatus(codes.Ok, "") + log.Info("cleared System Event Log", logMetadata(client.GetMetadata())...) + m.SendStatusMessage(fmt.Sprintf("cleared SystemEvent Log on %v", host)) + + return result, nil +} diff --git a/grpc/oob/diagnostic/diagnostic.go b/grpc/oob/diagnostic/diagnostic.go new file mode 100644 index 0000000..59846e3 --- /dev/null +++ b/grpc/oob/diagnostic/diagnostic.go @@ -0,0 +1,32 @@ +package diagnostic + +import ( + "github.com/go-logr/logr" + v1 "github.com/tinkerbell/pbnj/api/v1" + common "github.com/tinkerbell/pbnj/grpc/oob" +) + +type Action struct { + common.Accessory + ScreenshotRequest *v1.ScreenshotRequest + ClearSystemEventLogRequest *v1.ClearSystemEventLogRequest +} + +// WithLogger adds a logr to an Action struct. +func WithLogger(l logr.Logger) Option { + return func(a *Action) error { + a.Log = l + return nil + } +} + +// WithStatusMessage adds a status message chan to an Action struct. +func WithStatusMessage(s chan string) Option { + return func(a *Action) error { + a.StatusMessages = s + return nil + } +} + +// Option to add to an Actions. +type Option func(a *Action) error diff --git a/grpc/oob/diagnostic/screenshot.go b/grpc/oob/diagnostic/screenshot.go index c3c5076..33f54b0 100644 --- a/grpc/oob/diagnostic/screenshot.go +++ b/grpc/oob/diagnostic/screenshot.go @@ -7,7 +7,6 @@ import ( "github.com/bmc-toolbox/bmclib/v2" "github.com/bmc-toolbox/bmclib/v2/bmc" "github.com/bmc-toolbox/bmclib/v2/providers" - "github.com/go-logr/logr" "github.com/prometheus/client_golang/prometheus" v1 "github.com/tinkerbell/pbnj/api/v1" common "github.com/tinkerbell/pbnj/grpc/oob" @@ -19,22 +18,6 @@ import ( "go.opentelemetry.io/otel/trace" ) -type Action struct { - common.Accessory - ScreenshotRequest *v1.ScreenshotRequest -} - -// WithLogger adds a logr to an Action struct. -func WithLogger(l logr.Logger) Option { - return func(a *Action) error { - a.Log = l - return nil - } -} - -// Option to add to an Actions. -type Option func(a *Action) error - func NewScreenshotter(req *v1.ScreenshotRequest, opts ...Option) (*Action, error) { a := &Action{} a.ScreenshotRequest = req diff --git a/grpc/rpc/diagnostic.go b/grpc/rpc/diagnostic.go index f3c6696..bf4c001 100644 --- a/grpc/rpc/diagnostic.go +++ b/grpc/rpc/diagnostic.go @@ -2,14 +2,20 @@ package rpc import ( "context" + "time" + "github.com/rs/xid" v1 "github.com/tinkerbell/pbnj/api/v1" "github.com/tinkerbell/pbnj/grpc/oob/diagnostic" "github.com/tinkerbell/pbnj/pkg/logging" + "github.com/tinkerbell/pbnj/pkg/task" + "go.opentelemetry.io/otel/trace" ) type DiagnosticService struct { v1.UnimplementedDiagnosticServer + TaskRunner task.Task + Timeout time.Duration } func (d *DiagnosticService) Screenshot(ctx context.Context, in *v1.ScreenshotRequest) (*v1.ScreenshotResponse, error) { @@ -40,3 +46,36 @@ func (d *DiagnosticService) Screenshot(ctx context.Context, in *v1.ScreenshotReq Filetype: filetype, }, nil } + +func (d *DiagnosticService) ClearSystemEventLog(ctx context.Context, in *v1.ClearSystemEventLogRequest) (*v1.ClearSystemEventLogResponse, error) { + l := logging.ExtractLogr(ctx) + taskID := xid.New().String() + l = l.WithValues("taskID", taskID) + + l.Info( + "start Clear System Event Log request", + "username", in.Authn.GetDirectAuthn().GetUsername(), + "vendor", in.Vendor.GetName(), + ) + + execFunc := func(s chan string) (string, error) { + csl, err := diagnostic.NewSystemEventLogClearer( + in, + diagnostic.WithLogger(l), + diagnostic.WithStatusMessage(s), + ) + if err != nil { + return "", err + } + // Because this is a background task, we want to pass through the span context, but not be + // a child context. This allows us to correctly plumb otel into the background task. + c := trace.ContextWithSpanContext(context.Background(), trace.SpanContextFromContext(ctx)) + taskCtx, cancel := context.WithTimeout(c, d.Timeout) + defer cancel() + return csl.ClearSystemEventLog(taskCtx) + } + + d.TaskRunner.Execute(ctx, l, "clearing system event log", taskID, execFunc) + + return &v1.ClearSystemEventLogResponse{TaskId: taskID}, nil +} diff --git a/grpc/rpc/diagnostic_test.go b/grpc/rpc/diagnostic_test.go new file mode 100644 index 0000000..950e210 --- /dev/null +++ b/grpc/rpc/diagnostic_test.go @@ -0,0 +1,86 @@ +package rpc + +import ( + "context" + "errors" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/onsi/gomega" + "github.com/philippgille/gokv" + "github.com/philippgille/gokv/freecache" + v1 "github.com/tinkerbell/pbnj/api/v1" + "github.com/tinkerbell/pbnj/grpc/persistence" + "github.com/tinkerbell/pbnj/grpc/taskrunner" +) + +func TestClearSystemEventLog(t *testing.T) { + testCases := []struct { + name string + req *v1.ClearSystemEventLogRequest + expectedErr error + }{ + { + name: "status good; direct auth", + req: &v1.ClearSystemEventLogRequest{ + Authn: &v1.Authn{ + Authn: &v1.Authn_DirectAuthn{ + DirectAuthn: &v1.DirectAuthn{ + Host: &v1.Host{ + Host: "127.0.0.1", + }, + Username: "ADMIN", + Password: "ADMIN", + }, + }, + }, + Vendor: &v1.Vendor{ + Name: "", + }, + }, + }, + { + name: "validation failure", + req: &v1.ClearSystemEventLogRequest{Authn: &v1.Authn{Authn: &v1.Authn_DirectAuthn{DirectAuthn: &v1.DirectAuthn{}}}}, + expectedErr: errors.New("input arguments are invalid: invalid field Authn.DirectAuthn.Username: value '' must not be an empty string"), + }, + } + + for _, tc := range testCases { + testCase := tc + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + g := gomega.NewGomegaWithT(t) + + ctx := context.Background() + + f := freecache.NewStore(freecache.DefaultOptions) + s := gokv.Store(f) + repo := &persistence.GoKV{ + Store: s, + Ctx: ctx, + } + + taskRunner := &taskrunner.Runner{ + Repository: repo, + Ctx: ctx, + } + + diagnosticService := DiagnosticService{ + TaskRunner: taskRunner, + } + + response, err := diagnosticService.ClearSystemEventLog(ctx, testCase.req) + + t.Log("Got : ", response) + if err != nil { + diff := cmp.Diff(testCase.expectedErr.Error(), err.Error()) + if diff != "" { + t.Fatal(diff) + } + } else { + g.Expect(response.TaskId).Should(gomega.HaveLen(20)) + } + }) + } +} diff --git a/grpc/server.go b/grpc/server.go index d512f0a..c515e92 100644 --- a/grpc/server.go +++ b/grpc/server.go @@ -95,7 +95,10 @@ func RunServer(ctx context.Context, log logr.Logger, grpcServer *grpc.Server, po } v1.RegisterBMCServer(grpcServer, &bs) - ds := rpc.DiagnosticService{} + ds := rpc.DiagnosticService{ + TaskRunner: taskRunner, + Timeout: defaultServer.bmcTimeout, + } v1.RegisterDiagnosticServer(grpcServer, &ds) ts := rpc.TaskService{