mirror of https://github.com/linkerd/linkerd2.git
Simplify SelfCheck API (#5665)
Fixes #5575 Now that only viz makes use of the `SelfCheck` api, merged the `healthcheck.proto` into `viz.proto`. Also removed the "checkRPC" functionality that was used for handling multiple API responses and was only used by `SelfCheck`, because the extra complexity was not granted. Revert to use the plain vanilla "check" by just concatenating error responses. ## Success Output ```bash $ bin/linkerd viz check ... linkerd-viz ----------- ... √ viz extension self-check ``` ## Failure Examples Failure when viz fails to connect to the k8s api: ```bash $ bin/linkerd viz check ... linkerd-viz ----------- ... × viz extension self-check Error calling the Kubernetes API: someerror see https://linkerd.io/checks/#l5d-api-control-api for hints Status check results are × ``` Failure when viz fails to connect to Prometheus: ```bash $ bin/linkerd viz check ... linkerd-viz ----------- ... × viz extension self-check Error calling Prometheus from the control plane: someerror see https://linkerd.io/checks/#l5d-api-control-api for hints Status check results are × ``` Failure when viz fails to connect to both the k8s api and Prometheus: ```bash $ bin/linkerd viz check ... linkerd-viz ----------- ... × viz extension self-check Error calling the Kubernetes API: someerror Error calling Prometheus from the control plane: someerror see https://linkerd.io/checks/#l5d-api-control-api for hints Status check results are × ```
This commit is contained in:
parent
704ed00a49
commit
a04b30d2ab
|
@ -7,16 +7,14 @@ bindir=$( cd "${0%/*}" && pwd )
|
|||
go install -mod=readonly github.com/golang/protobuf/protoc-gen-go
|
||||
|
||||
rm -rf controller/gen/common controller/gen/public controller/gen/config viz/metrics-api/gen
|
||||
mkdir -p controller/gen/common/healthcheck controller/gen/common/net controller/gen/public viz/metrics-api/gen/viz
|
||||
mkdir -p controller/gen/common/net controller/gen/public viz/metrics-api/gen/viz
|
||||
|
||||
"$bindir"/protoc -I proto --go_out=plugins=grpc,paths=source_relative:controller/gen proto/common/net.proto
|
||||
"$bindir"/protoc -I proto --go_out=plugins=grpc,paths=source_relative:controller/gen proto/public.proto
|
||||
"$bindir"/protoc -I proto --go_out=plugins=grpc,paths=source_relative:controller/gen proto/config/config.proto
|
||||
"$bindir"/protoc -I proto --go_out=plugins=grpc,paths=source_relative:controller/gen proto/common/healthcheck.proto
|
||||
"$bindir"/protoc -I proto -I viz/metrics-api/proto --go_out=plugins=grpc,paths=source_relative:viz/metrics-api/gen viz/metrics-api/proto/viz.proto
|
||||
|
||||
mv controller/gen/common/net.pb.go controller/gen/common/net/
|
||||
mv controller/gen/public.pb.go controller/gen/public/
|
||||
mv controller/gen/common/healthcheck.pb.go controller/gen/common/healthcheck/
|
||||
mv viz/metrics-api/gen/viz.pb.go viz/metrics-api/gen/viz/viz.pb.go
|
||||
|
||||
|
|
|
@ -1,362 +0,0 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.24.0
|
||||
// protoc v3.6.0
|
||||
// source: common/healthcheck.proto
|
||||
|
||||
package healthcheck
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
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)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type CheckStatus int32
|
||||
|
||||
const (
|
||||
CheckStatus_OK CheckStatus = 0
|
||||
CheckStatus_FAIL CheckStatus = 1
|
||||
CheckStatus_ERROR CheckStatus = 2
|
||||
)
|
||||
|
||||
// Enum value maps for CheckStatus.
|
||||
var (
|
||||
CheckStatus_name = map[int32]string{
|
||||
0: "OK",
|
||||
1: "FAIL",
|
||||
2: "ERROR",
|
||||
}
|
||||
CheckStatus_value = map[string]int32{
|
||||
"OK": 0,
|
||||
"FAIL": 1,
|
||||
"ERROR": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x CheckStatus) Enum() *CheckStatus {
|
||||
p := new(CheckStatus)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x CheckStatus) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (CheckStatus) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_common_healthcheck_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (CheckStatus) Type() protoreflect.EnumType {
|
||||
return &file_common_healthcheck_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x CheckStatus) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CheckStatus.Descriptor instead.
|
||||
func (CheckStatus) EnumDescriptor() ([]byte, []int) {
|
||||
return file_common_healthcheck_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type CheckResult struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
SubsystemName string `protobuf:"bytes,1,opt,name=SubsystemName,proto3" json:"SubsystemName,omitempty"`
|
||||
CheckDescription string `protobuf:"bytes,2,opt,name=CheckDescription,proto3" json:"CheckDescription,omitempty"`
|
||||
Status CheckStatus `protobuf:"varint,3,opt,name=Status,proto3,enum=linkerd2.common.healthcheck.CheckStatus" json:"Status,omitempty"`
|
||||
FriendlyMessageToUser string `protobuf:"bytes,4,opt,name=FriendlyMessageToUser,proto3" json:"FriendlyMessageToUser,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CheckResult) Reset() {
|
||||
*x = CheckResult{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_common_healthcheck_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CheckResult) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CheckResult) ProtoMessage() {}
|
||||
|
||||
func (x *CheckResult) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_healthcheck_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 CheckResult.ProtoReflect.Descriptor instead.
|
||||
func (*CheckResult) Descriptor() ([]byte, []int) {
|
||||
return file_common_healthcheck_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *CheckResult) GetSubsystemName() string {
|
||||
if x != nil {
|
||||
return x.SubsystemName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CheckResult) GetCheckDescription() string {
|
||||
if x != nil {
|
||||
return x.CheckDescription
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CheckResult) GetStatus() CheckStatus {
|
||||
if x != nil {
|
||||
return x.Status
|
||||
}
|
||||
return CheckStatus_OK
|
||||
}
|
||||
|
||||
func (x *CheckResult) GetFriendlyMessageToUser() string {
|
||||
if x != nil {
|
||||
return x.FriendlyMessageToUser
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SelfCheckRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *SelfCheckRequest) Reset() {
|
||||
*x = SelfCheckRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_common_healthcheck_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SelfCheckRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SelfCheckRequest) ProtoMessage() {}
|
||||
|
||||
func (x *SelfCheckRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_healthcheck_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 SelfCheckRequest.ProtoReflect.Descriptor instead.
|
||||
func (*SelfCheckRequest) Descriptor() ([]byte, []int) {
|
||||
return file_common_healthcheck_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
type SelfCheckResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Results []*CheckResult `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SelfCheckResponse) Reset() {
|
||||
*x = SelfCheckResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_common_healthcheck_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SelfCheckResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SelfCheckResponse) ProtoMessage() {}
|
||||
|
||||
func (x *SelfCheckResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_healthcheck_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 SelfCheckResponse.ProtoReflect.Descriptor instead.
|
||||
func (*SelfCheckResponse) Descriptor() ([]byte, []int) {
|
||||
return file_common_healthcheck_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *SelfCheckResponse) GetResults() []*CheckResult {
|
||||
if x != nil {
|
||||
return x.Results
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_common_healthcheck_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_common_healthcheck_proto_rawDesc = []byte{
|
||||
0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63,
|
||||
0x68, 0x65, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x6c, 0x69, 0x6e, 0x6b,
|
||||
0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x68, 0x65, 0x61, 0x6c,
|
||||
0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x22, 0xd7, 0x01, 0x0a, 0x0b, 0x43, 0x68, 0x65, 0x63,
|
||||
0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x75, 0x62, 0x73, 0x79,
|
||||
0x73, 0x74, 0x65, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
|
||||
0x53, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a,
|
||||
0x10, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x44, 0x65,
|
||||
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x06, 0x53, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x6c, 0x69, 0x6e, 0x6b,
|
||||
0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x68, 0x65, 0x61, 0x6c,
|
||||
0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x46,
|
||||
0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x6f,
|
||||
0x55, 0x73, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x46, 0x72, 0x69, 0x65,
|
||||
0x6e, 0x64, 0x6c, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x55, 0x73, 0x65,
|
||||
0x72, 0x22, 0x12, 0x0a, 0x10, 0x53, 0x65, 0x6c, 0x66, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x57, 0x0a, 0x11, 0x53, 0x65, 0x6c, 0x66, 0x43, 0x68, 0x65,
|
||||
0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x07, 0x72, 0x65,
|
||||
0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6c, 0x69,
|
||||
0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x68, 0x65,
|
||||
0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52,
|
||||
0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2a, 0x2a,
|
||||
0x0a, 0x0b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x06, 0x0a,
|
||||
0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x41, 0x49, 0x4c, 0x10, 0x01, 0x12,
|
||||
0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x42, 0x3f, 0x5a, 0x3d, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64,
|
||||
0x2f, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x64, 0x32, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f,
|
||||
0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_common_healthcheck_proto_rawDescOnce sync.Once
|
||||
file_common_healthcheck_proto_rawDescData = file_common_healthcheck_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_common_healthcheck_proto_rawDescGZIP() []byte {
|
||||
file_common_healthcheck_proto_rawDescOnce.Do(func() {
|
||||
file_common_healthcheck_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_healthcheck_proto_rawDescData)
|
||||
})
|
||||
return file_common_healthcheck_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_common_healthcheck_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_common_healthcheck_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_common_healthcheck_proto_goTypes = []interface{}{
|
||||
(CheckStatus)(0), // 0: linkerd2.common.healthcheck.CheckStatus
|
||||
(*CheckResult)(nil), // 1: linkerd2.common.healthcheck.CheckResult
|
||||
(*SelfCheckRequest)(nil), // 2: linkerd2.common.healthcheck.SelfCheckRequest
|
||||
(*SelfCheckResponse)(nil), // 3: linkerd2.common.healthcheck.SelfCheckResponse
|
||||
}
|
||||
var file_common_healthcheck_proto_depIdxs = []int32{
|
||||
0, // 0: linkerd2.common.healthcheck.CheckResult.Status:type_name -> linkerd2.common.healthcheck.CheckStatus
|
||||
1, // 1: linkerd2.common.healthcheck.SelfCheckResponse.results:type_name -> linkerd2.common.healthcheck.CheckResult
|
||||
2, // [2:2] is the sub-list for method output_type
|
||||
2, // [2:2] 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_common_healthcheck_proto_init() }
|
||||
func file_common_healthcheck_proto_init() {
|
||||
if File_common_healthcheck_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_common_healthcheck_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CheckResult); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_common_healthcheck_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SelfCheckRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_common_healthcheck_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SelfCheckResponse); 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_common_healthcheck_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 3,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_common_healthcheck_proto_goTypes,
|
||||
DependencyIndexes: file_common_healthcheck_proto_depIdxs,
|
||||
EnumInfos: file_common_healthcheck_proto_enumTypes,
|
||||
MessageInfos: file_common_healthcheck_proto_msgTypes,
|
||||
}.Build()
|
||||
File_common_healthcheck_proto = out.File
|
||||
file_common_healthcheck_proto_rawDesc = nil
|
||||
file_common_healthcheck_proto_goTypes = nil
|
||||
file_common_healthcheck_proto_depIdxs = nil
|
||||
}
|
|
@ -12,7 +12,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/linkerd/linkerd2/controller/api/public"
|
||||
healthcheckPb "github.com/linkerd/linkerd2/controller/gen/common/healthcheck"
|
||||
configPb "github.com/linkerd/linkerd2/controller/gen/config"
|
||||
l5dcharts "github.com/linkerd/linkerd2/pkg/charts/linkerd2"
|
||||
"github.com/linkerd/linkerd2/pkg/config"
|
||||
|
@ -304,11 +303,6 @@ type Checker struct {
|
|||
// check is the function that's called to execute the check; if the function
|
||||
// returns an error, the check fails
|
||||
check func(context.Context) error
|
||||
|
||||
// checkRPC is an alternative to check that can be used to perform a remote
|
||||
// check using the SelfCheck gRPC endpoint; check status is based on the value
|
||||
// of the gRPC response
|
||||
checkRPC func(context.Context) (*healthcheckPb.SelfCheckResponse, error)
|
||||
}
|
||||
|
||||
// NewChecker returns a new instance of checker type
|
||||
|
@ -355,12 +349,6 @@ func (c *Checker) WithCheck(check func(context.Context) error) *Checker {
|
|||
return c
|
||||
}
|
||||
|
||||
// WithCheckRPC returns a checker with the provided checkRPC func
|
||||
func (c *Checker) WithCheckRPC(checkRPC func(context.Context) (*healthcheckPb.SelfCheckResponse, error)) *Checker {
|
||||
c.checkRPC = checkRPC
|
||||
return c
|
||||
}
|
||||
|
||||
// CheckResult encapsulates a check's identifying information and output
|
||||
// Note there exists an analogous user-facing type, `cmd.check`, for output via
|
||||
// `linkerd check -o json`.
|
||||
|
@ -1477,17 +1465,6 @@ func (hc *HealthChecker) RunChecks(observer CheckObserver) bool {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if checker.checkRPC != nil {
|
||||
if !hc.runCheckRPC(c.ID, &checker, observer) {
|
||||
if !checker.warning {
|
||||
success = false
|
||||
}
|
||||
if checker.fatal {
|
||||
return success
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1539,77 +1516,6 @@ func (hc *HealthChecker) runCheck(categoryID CategoryID, c *Checker, observer Ch
|
|||
}
|
||||
}
|
||||
|
||||
// runCheckRPC calls `c` which itself should make a gRPC call returning `*healthcheckPb.SelfCheckResponse`
|
||||
// (which can contain multiple responses) or error.
|
||||
// If that call returns an error, we send it to `observer` and return false.
|
||||
// Otherwise, we send to `observer` a success message with `c.description` and then proceed to check the
|
||||
// multiple responses contained in the response.
|
||||
// We keep on retrying the same call until all the responses have an OK status
|
||||
// (or until timeout/deadline is reached), sending a message to `observer` for each response,
|
||||
// while making sure no duplicate messages are sent.
|
||||
func (hc *HealthChecker) runCheckRPC(categoryID CategoryID, c *Checker, observer CheckObserver) bool {
|
||||
observedResults := []CheckResult{}
|
||||
for {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), RequestTimeout)
|
||||
defer cancel()
|
||||
checkRsp, err := c.checkRPC(ctx)
|
||||
if se, ok := err.(*SkipError); ok {
|
||||
log.Debugf("Skipping check: %s. Reason: %s", c.description, se.Reason)
|
||||
return true
|
||||
}
|
||||
|
||||
checkResult := &CheckResult{
|
||||
Category: categoryID,
|
||||
Description: c.description,
|
||||
HintAnchor: c.hintAnchor,
|
||||
Warning: c.warning,
|
||||
}
|
||||
|
||||
if vs, ok := err.(*VerboseSuccess); ok {
|
||||
checkResult.Description = fmt.Sprintf("%s\n%s", checkResult.Description, vs.Message)
|
||||
} else if err != nil {
|
||||
// errors at the gRPC-call level are not retried
|
||||
// but we do retry below if the response Status is not OK
|
||||
checkResult.Err = &CategoryError{categoryID, err}
|
||||
observer(checkResult)
|
||||
return false
|
||||
}
|
||||
|
||||
// General description, only shown once.
|
||||
// The following calls to `observer()` track specific result entries.
|
||||
if !checkResult.alreadyObserved(observedResults) {
|
||||
observer(checkResult)
|
||||
observedResults = append(observedResults, *checkResult)
|
||||
}
|
||||
|
||||
for _, check := range checkRsp.Results {
|
||||
checkResult.Err = nil
|
||||
checkResult.Description = fmt.Sprintf("[%s] %s", check.SubsystemName, check.CheckDescription)
|
||||
if check.Status != healthcheckPb.CheckStatus_OK {
|
||||
checkResult.Err = &CategoryError{categoryID, fmt.Errorf(check.FriendlyMessageToUser)}
|
||||
checkResult.Retry = time.Now().Before(c.retryDeadline)
|
||||
// only show the waiting message during retries,
|
||||
// and send the underlying error on the last try
|
||||
if !c.surfaceErrorOnRetry && checkResult.Retry {
|
||||
checkResult.Err = errors.New("waiting for check to complete")
|
||||
}
|
||||
observer(checkResult)
|
||||
} else if !checkResult.alreadyObserved(observedResults) {
|
||||
observer(checkResult)
|
||||
}
|
||||
observedResults = append(observedResults, *checkResult)
|
||||
}
|
||||
|
||||
if checkResult.Retry {
|
||||
log.Debug("Retrying on error")
|
||||
time.Sleep(retryWindow)
|
||||
continue
|
||||
}
|
||||
|
||||
return checkResult.Err == nil
|
||||
}
|
||||
}
|
||||
|
||||
func (hc *HealthChecker) controlPlaneComponentsSelector() string {
|
||||
return fmt.Sprintf("%s,!%s", k8s.ControllerNSLabel, LinkerdCNIResourceLabel)
|
||||
}
|
||||
|
@ -2323,15 +2229,6 @@ func (hc *HealthChecker) checkClockSkew(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (cr *CheckResult) alreadyObserved(previousResults []CheckResult) bool {
|
||||
for _, result := range previousResults {
|
||||
if result.Description == cr.Description && result.Err == cr.Err {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// CheckRoles checks that the expected roles exist.
|
||||
func CheckRoles(ctx context.Context, kubeAPI *k8s.KubernetesAPI, shouldExist bool, namespace string, expectedNames []string, labelSelector string) error {
|
||||
options := metav1.ListOptions{
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/duration"
|
||||
healthcheckPb "github.com/linkerd/linkerd2/controller/gen/common/healthcheck"
|
||||
configPb "github.com/linkerd/linkerd2/controller/gen/config"
|
||||
"github.com/linkerd/linkerd2/pkg/charts/linkerd2"
|
||||
"github.com/linkerd/linkerd2/pkg/identity"
|
||||
|
@ -148,8 +147,8 @@ func TestHealthChecker(t *testing.T) {
|
|||
checkers: []Checker{
|
||||
{
|
||||
description: "skipRpc",
|
||||
checkRPC: func(context.Context) (*healthcheckPb.SelfCheckResponse, error) {
|
||||
return nil, &SkipError{Reason: "needs skipping"}
|
||||
check: func(context.Context) error {
|
||||
return &SkipError{Reason: "needs skipping"}
|
||||
},
|
||||
retryDeadline: time.Time{},
|
||||
},
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package linkerd2.common.healthcheck;
|
||||
|
||||
option go_package = "github.com/linkerd/linkerd2/controller/gen/common/healthcheck";
|
||||
|
||||
enum CheckStatus {
|
||||
OK = 0;
|
||||
FAIL = 1;
|
||||
ERROR = 2;
|
||||
}
|
||||
|
||||
message CheckResult {
|
||||
string SubsystemName = 1;
|
||||
string CheckDescription = 2;
|
||||
CheckStatus Status = 3;
|
||||
string FriendlyMessageToUser = 4;
|
||||
}
|
||||
|
||||
message SelfCheckRequest {}
|
||||
|
||||
message SelfCheckResponse {
|
||||
repeated CheckResult results = 1;
|
||||
}
|
|
@ -27,7 +27,5 @@ linkerd-viz
|
|||
√ grafana is installed and configured correctly
|
||||
√ can initialize the client
|
||||
√ viz extension self-check
|
||||
√ [kubernetes] linkerd viz can talk to Kubernetes
|
||||
√ [prometheus] linkerd viz can talk to Prometheus
|
||||
|
||||
Status check results are √
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"net/url"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
healthcheckPb "github.com/linkerd/linkerd2/controller/gen/common/healthcheck"
|
||||
"github.com/linkerd/linkerd2/pkg/k8s"
|
||||
"github.com/linkerd/linkerd2/pkg/protohttp"
|
||||
pb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
|
||||
|
@ -62,8 +61,8 @@ func (c *grpcOverHTTPClient) Gateways(ctx context.Context, req *pb.GatewaysReque
|
|||
return &msg, err
|
||||
}
|
||||
|
||||
func (c *grpcOverHTTPClient) SelfCheck(ctx context.Context, req *healthcheckPb.SelfCheckRequest, _ ...grpc.CallOption) (*healthcheckPb.SelfCheckResponse, error) {
|
||||
var msg healthcheckPb.SelfCheckResponse
|
||||
func (c *grpcOverHTTPClient) SelfCheck(ctx context.Context, req *pb.SelfCheckRequest, _ ...grpc.CallOption) (*pb.SelfCheckResponse, error) {
|
||||
var msg pb.SelfCheckResponse
|
||||
err := c.apiRequest(ctx, "SelfCheck", req, &msg)
|
||||
return &msg, err
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,7 +7,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/duration"
|
||||
healthcheckPb "github.com/linkerd/linkerd2/controller/gen/common/healthcheck"
|
||||
"github.com/linkerd/linkerd2/controller/k8s"
|
||||
pkgK8s "github.com/linkerd/linkerd2/pkg/k8s"
|
||||
"github.com/linkerd/linkerd2/pkg/prometheus"
|
||||
|
@ -175,33 +174,33 @@ func (s *grpcServer) ListPods(ctx context.Context, req *pb.ListPodsRequest) (*pb
|
|||
return &rsp, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) SelfCheck(ctx context.Context, in *healthcheckPb.SelfCheckRequest) (*healthcheckPb.SelfCheckResponse, error) {
|
||||
k8sClientCheck := &healthcheckPb.CheckResult{
|
||||
func (s *grpcServer) SelfCheck(ctx context.Context, in *pb.SelfCheckRequest) (*pb.SelfCheckResponse, error) {
|
||||
k8sClientCheck := &pb.CheckResult{
|
||||
SubsystemName: k8sClientSubsystemName,
|
||||
CheckDescription: k8sClientCheckDescription,
|
||||
Status: healthcheckPb.CheckStatus_OK,
|
||||
Status: pb.CheckStatus_OK,
|
||||
}
|
||||
_, err := s.k8sAPI.Pod().Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
k8sClientCheck.Status = healthcheckPb.CheckStatus_ERROR
|
||||
k8sClientCheck.Status = pb.CheckStatus_ERROR
|
||||
k8sClientCheck.FriendlyMessageToUser = fmt.Sprintf("Error calling the Kubernetes API: %s", err)
|
||||
}
|
||||
|
||||
response := &healthcheckPb.SelfCheckResponse{
|
||||
Results: []*healthcheckPb.CheckResult{
|
||||
response := &pb.SelfCheckResponse{
|
||||
Results: []*pb.CheckResult{
|
||||
k8sClientCheck,
|
||||
},
|
||||
}
|
||||
|
||||
if s.prometheusAPI != nil {
|
||||
promClientCheck := &healthcheckPb.CheckResult{
|
||||
promClientCheck := &pb.CheckResult{
|
||||
SubsystemName: promClientSubsystemName,
|
||||
CheckDescription: promClientCheckDescription,
|
||||
Status: healthcheckPb.CheckStatus_OK,
|
||||
Status: pb.CheckStatus_OK,
|
||||
}
|
||||
_, err = s.queryProm(ctx, fmt.Sprintf(podQuery, ""))
|
||||
if err != nil {
|
||||
promClientCheck.Status = healthcheckPb.CheckStatus_ERROR
|
||||
promClientCheck.Status = pb.CheckStatus_ERROR
|
||||
promClientCheck.FriendlyMessageToUser = fmt.Sprintf("Error calling Prometheus from the control plane: %s", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
|
||||
healthcheckPb "github.com/linkerd/linkerd2/controller/gen/common/healthcheck"
|
||||
"github.com/linkerd/linkerd2/controller/k8s"
|
||||
"github.com/linkerd/linkerd2/pkg/prometheus"
|
||||
"github.com/linkerd/linkerd2/pkg/protohttp"
|
||||
|
@ -146,7 +145,7 @@ func (h *handler) handleTopRoutes(w http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
|
||||
func (h *handler) handleSelfCheck(w http.ResponseWriter, req *http.Request) {
|
||||
var protoRequest healthcheckPb.SelfCheckRequest
|
||||
var protoRequest pb.SelfCheckRequest
|
||||
err := protohttp.HTTPRequestToProto(req, &protoRequest)
|
||||
if err != nil {
|
||||
protohttp.WriteErrorToHTTPResponse(w, err)
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
healthcheckPb "github.com/linkerd/linkerd2/controller/gen/common/healthcheck"
|
||||
vizClient "github.com/linkerd/linkerd2/viz/metrics-api/client"
|
||||
pb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
|
||||
)
|
||||
|
@ -53,9 +52,9 @@ func (m *mockGrpcServer) ListServices(ctx context.Context, req *pb.ListServicesR
|
|||
return m.ResponseToReturn.(*pb.ListServicesResponse), m.ErrorToReturn
|
||||
}
|
||||
|
||||
func (m *mockGrpcServer) SelfCheck(ctx context.Context, req *healthcheckPb.SelfCheckRequest) (*healthcheckPb.SelfCheckResponse, error) {
|
||||
func (m *mockGrpcServer) SelfCheck(ctx context.Context, req *pb.SelfCheckRequest) (*pb.SelfCheckResponse, error) {
|
||||
m.LastRequestReceived = req
|
||||
return m.ResponseToReturn.(*healthcheckPb.SelfCheckResponse), m.ErrorToReturn
|
||||
return m.ResponseToReturn.(*pb.SelfCheckResponse), m.ErrorToReturn
|
||||
}
|
||||
|
||||
type grpcCallTestCase struct {
|
||||
|
|
|
@ -3,13 +3,31 @@ syntax = "proto3";
|
|||
package linkerd2.viz;
|
||||
|
||||
import "google/protobuf/duration.proto";
|
||||
import "common/healthcheck.proto";
|
||||
import "common/net.proto";
|
||||
|
||||
option go_package = "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz";
|
||||
|
||||
message Empty {}
|
||||
|
||||
enum CheckStatus {
|
||||
OK = 0;
|
||||
FAIL = 1;
|
||||
ERROR = 2;
|
||||
}
|
||||
|
||||
message CheckResult {
|
||||
string SubsystemName = 1;
|
||||
string CheckDescription = 2;
|
||||
CheckStatus Status = 3;
|
||||
string FriendlyMessageToUser = 4;
|
||||
}
|
||||
|
||||
message SelfCheckRequest {}
|
||||
|
||||
message SelfCheckResponse {
|
||||
repeated CheckResult results = 1;
|
||||
}
|
||||
|
||||
message ListServicesRequest {
|
||||
string namespace = 1;
|
||||
}
|
||||
|
@ -504,7 +522,7 @@ service Api {
|
|||
|
||||
rpc ListServices(ListServicesRequest) returns (ListServicesResponse) {}
|
||||
|
||||
rpc SelfCheck(linkerd2.common.healthcheck.SelfCheckRequest) returns (linkerd2.common.healthcheck.SelfCheckResponse) {}
|
||||
rpc SelfCheck(SelfCheckRequest) returns (SelfCheckResponse) {}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
healthcheckPb "github.com/linkerd/linkerd2/controller/gen/common/healthcheck"
|
||||
"github.com/linkerd/linkerd2/controller/k8s"
|
||||
pb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
|
||||
promv1 "github.com/prometheus/client_golang/api/prometheus/v1"
|
||||
|
@ -25,7 +24,7 @@ type MockAPIClient struct {
|
|||
GatewaysResponseToReturn *pb.GatewaysResponse
|
||||
TopRoutesResponseToReturn *pb.TopRoutesResponse
|
||||
EdgesResponseToReturn *pb.EdgesResponse
|
||||
SelfCheckResponseToReturn *healthcheckPb.SelfCheckResponse
|
||||
SelfCheckResponseToReturn *pb.SelfCheckResponse
|
||||
}
|
||||
|
||||
// StatSummary provides a mock of a Public API method.
|
||||
|
@ -59,7 +58,7 @@ func (c *MockAPIClient) ListServices(ctx context.Context, in *pb.ListServicesReq
|
|||
}
|
||||
|
||||
// SelfCheck provides a mock of a Public API method.
|
||||
func (c *MockAPIClient) SelfCheck(ctx context.Context, in *healthcheckPb.SelfCheckRequest, _ ...grpc.CallOption) (*healthcheckPb.SelfCheckResponse, error) {
|
||||
func (c *MockAPIClient) SelfCheck(ctx context.Context, in *pb.SelfCheckRequest, _ ...grpc.CallOption) (*pb.SelfCheckResponse, error) {
|
||||
return c.SelfCheckResponseToReturn, c.ErrorToReturn
|
||||
}
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@ package healthcheck
|
|||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
healthcheckPb "github.com/linkerd/linkerd2/controller/gen/common/healthcheck"
|
||||
"github.com/linkerd/linkerd2/pkg/healthcheck"
|
||||
"github.com/linkerd/linkerd2/pkg/k8s"
|
||||
"github.com/linkerd/linkerd2/pkg/tls"
|
||||
|
@ -233,8 +233,28 @@ func (hc *HealthChecker) VizCategory() healthcheck.Category {
|
|||
// "waiting for check to complete" while things converge. If after the timeout
|
||||
// it still hasn't converged, we show the real error (a 503 usually).
|
||||
WithRetryDeadline(hc.RetryDeadline).
|
||||
WithCheckRPC(func(ctx context.Context) (*healthcheckPb.SelfCheckResponse, error) {
|
||||
return hc.vizAPIClient.SelfCheck(ctx, &healthcheckPb.SelfCheckRequest{})
|
||||
WithCheck(func(ctx context.Context) error {
|
||||
results, err := hc.vizAPIClient.SelfCheck(ctx, &pb.SelfCheckRequest{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(results.GetResults()) == 0 {
|
||||
return errors.New("No results returned")
|
||||
}
|
||||
|
||||
errs := []string{}
|
||||
for _, res := range results.GetResults() {
|
||||
if res.GetStatus() != pb.CheckStatus_OK {
|
||||
errs = append(errs, res.GetFriendlyMessageToUser())
|
||||
}
|
||||
}
|
||||
if len(errs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
errsStr := strings.Join(errs, "\n ")
|
||||
return errors.New(errsStr)
|
||||
}),
|
||||
}, true)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue