From 60be959c24301ee003265c4e78fd47a0bec70567 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Wed, 3 Aug 2022 15:45:27 +0200 Subject: [PATCH] Implement health check infrastructure This commit adds health check capabilities to the hsm.Access and health response data to the messages returned by the health command. --- cmd/signer/main.go | 78 +++-- pkg/health/health.go | 47 ++- pkg/hsm/hsm.go | 56 ++++ pkg/messages/messages.go | 8 + pkg/messages/resolver.msgpackgen.go | 451 +++++++++++++++++++++++++++- pkg/protocol/protocol.go | 27 +- 6 files changed, 622 insertions(+), 45 deletions(-) diff --git a/cmd/signer/main.go b/cmd/signer/main.go index 842941f..53bff77 100644 --- a/cmd/signer/main.go +++ b/cmd/signer/main.go @@ -62,45 +62,15 @@ func main() { return } - configFile, err := os.Open(signerConfigFile) - if err != nil { - errorLog.Fatalf("could not open signer configuration file %s: %v", signerConfigFile, err) - } + caConfig := LoadConfig(signerConfigFile, errorLog) - opts := make([]hsm.ConfigOption, 0) - - caConfig, err := config.LoadConfiguration(configFile) - if err != nil { - errorLog.Fatalf("could not load CA hierarchy: %v", err) - } - - opts = append(opts, hsm.CaConfigOption(caConfig)) - - if setupMode { - infoLog.Print("running in setup mode") - - opts = append(opts, hsm.SetupModeOption()) - } - - if verbose { - opts = append(opts, hsm.VerboseLoggingOption()) - } - - acc, err := hsm.NewAccess(infoLog, opts...) - if err != nil { - errorLog.Fatalf("could not setup HSM access: %v", err) - } - - err = acc.EnsureCAKeysAndCertificates() - if err != nil { - errorLog.Fatalf("could not ensure CA keys and certificates exist: %v", err) - } + access := initializeHSM(caConfig, setupMode, verbose, infoLog, errorLog) if setupMode { return } - healthHandler := health.New(version) + healthHandler := health.New(version, access) proto, err := protocol.New(infoLog, errorLog, protocol.RegisterHealthHandler(healthHandler)) if err != nil { @@ -120,3 +90,45 @@ func main() { infoLog.Print("setup complete, starting signer operation") } + +func initializeHSM(caConfig *config.SignerConfig, setupMode, verbose bool, infoLog, errorLog *log.Logger) *hsm.Access { + opts := make([]hsm.ConfigOption, 0) + + opts = append(opts, hsm.CaConfigOption(caConfig)) + + if setupMode { + infoLog.Print("running in setup mode") + + opts = append(opts, hsm.SetupModeOption()) + } + + if verbose { + opts = append(opts, hsm.VerboseLoggingOption()) + } + + access, err := hsm.NewAccess(infoLog, opts...) + if err != nil { + errorLog.Fatalf("could not setup HSM access: %v", err) + } + + err = access.EnsureCAKeysAndCertificates() + if err != nil { + errorLog.Fatalf("could not ensure CA keys and certificates exist: %v", err) + } + + return access +} + +func LoadConfig(signerConfigFile string, errorLog *log.Logger) *config.SignerConfig { + configFile, err := os.Open(signerConfigFile) + if err != nil { + errorLog.Fatalf("could not open signer configuration file %s: %v", signerConfigFile, err) + } + + caConfig, err := config.LoadConfiguration(configFile) + if err != nil { + errorLog.Fatalf("could not load CA hierarchy: %v", err) + } + + return caConfig +} diff --git a/pkg/health/health.go b/pkg/health/health.go index 368f829..9df0a7e 100644 --- a/pkg/health/health.go +++ b/pkg/health/health.go @@ -18,10 +18,49 @@ limitations under the License. // Package health implements Health checks package health -type Handler struct { - Version string +import ( + "fmt" +) + +type Info struct { + Healthy bool + Source string + MoreInfo map[string]string } -func New(version string) *Handler { - return &Handler{Version: version} +type Aware interface { + Healthy() (*Info, error) +} + +type Handler struct { + version string + healthAware []Aware +} + +type Result struct { + Healthy bool + Version string + Info []*Info +} + +func (h *Handler) CheckHealth() (*Result, error) { + healthInfo := make([]*Info, len(h.healthAware)) + + healthy := true + + for idx, aware := range h.healthAware { + info, err := aware.Healthy() + if err != nil { + return nil, fmt.Errorf("health check failed: %w", err) + } + + healthInfo[idx] = info + healthy = healthy && info.Healthy + } + + return &Result{Healthy: healthy, Version: h.version, Info: healthInfo}, nil +} + +func New(version string, healthAware ...Aware) *Handler { + return &Handler{version: version, healthAware: healthAware} } diff --git a/pkg/hsm/hsm.go b/pkg/hsm/hsm.go index 93e1985..ac20999 100644 --- a/pkg/hsm/hsm.go +++ b/pkg/hsm/hsm.go @@ -37,6 +37,8 @@ import ( "github.com/ThalesIgnite/crypto11" + "git.cacert.org/cacert-gosigner/pkg/health" + "git.cacert.org/cacert-gosigner/pkg/config" ) @@ -62,6 +64,60 @@ type Access struct { verbose bool } +func (a *Access) Healthy() (*health.Info, error) { + healthy := true + + moreInfo := make(map[string]string) + + const checkFailed = "failed" + + for _, ca := range a.signerConfig.RootCAs() { + infoKey := fmt.Sprintf("root-%s", ca) + + cert, err := a.GetRootCACertificate(ca) + if err != nil { + healthy = false + + moreInfo[infoKey] = checkFailed + } + + moreInfo[infoKey] = fmt.Sprintf("ok, valid until %s", cert.NotAfter.UTC().Format(time.RFC3339)) + } + + for _, ca := range a.signerConfig.IntermediaryCAs() { + infoKey := fmt.Sprintf("sub-%s", ca) + + cert, err := a.GetIntermediaryCACertificate(ca) + if err != nil { + healthy = false + + moreInfo[infoKey] = checkFailed + } + + def, err := a.signerConfig.GetCADefinition(ca) + if err != nil { + healthy = false + + moreInfo[infoKey] = checkFailed + } + + _, err = a.getKeyPair(ca, def.KeyInfo) + if err != nil { + healthy = false + + moreInfo[infoKey] = checkFailed + } + + moreInfo[infoKey] = fmt.Sprintf("ok, valid until %s", cert.NotAfter.UTC().Format(time.RFC3339)) + } + + return &health.Info{ + Healthy: healthy, + Source: "HSM", + MoreInfo: moreInfo, + }, nil +} + func NewAccess(infoLog *log.Logger, options ...ConfigOption) (*Access, error) { access := &Access{infoLog: infoLog} access.setupContext(options...) diff --git a/pkg/messages/messages.go b/pkg/messages/messages.go index 93e66be..5bee1d1 100644 --- a/pkg/messages/messages.go +++ b/pkg/messages/messages.go @@ -59,8 +59,16 @@ type Response struct { Payload interface{} `msgpack:"payload"` } +type HealthInfo struct { + Source string + Healthy bool + MoreInfo map[string]string +} + type HealthResponse struct { Version string `msgpack:"version"` + Healthy bool + Info []HealthInfo } type ErrorResponse struct { diff --git a/pkg/messages/resolver.msgpackgen.go b/pkg/messages/resolver.msgpackgen.go index 1f34803..a999ce5 100644 --- a/pkg/messages/resolver.msgpackgen.go +++ b/pkg/messages/resolver.msgpackgen.go @@ -26,6 +26,36 @@ func ___encode(i interface{}) ([]byte, error) { // encodeAsArray func ___encodeAsArray(i interface{}) ([]byte, error) { switch v := i.(type) { + case HealthInfo: + encoder := enc.NewEncoder() + size, err := ___calcArraySizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder) + if err != nil { + return nil, err + } + encoder.MakeBytes(size) + b, offset, err := ___encodeArrayHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder, 0) + if err != nil { + return nil, err + } + if size != offset { + return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthInfo", size, offset) + } + return b, err + case *HealthInfo: + encoder := enc.NewEncoder() + size, err := ___calcArraySizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder) + if err != nil { + return nil, err + } + encoder.MakeBytes(size) + b, offset, err := ___encodeArrayHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder, 0) + if err != nil { + return nil, err + } + if size != offset { + return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthInfo", size, offset) + } + return b, err case HealthResponse: encoder := enc.NewEncoder() size, err := ___calcArraySizeHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder) @@ -93,6 +123,36 @@ func ___encodeAsArray(i interface{}) ([]byte, error) { // encodeAsMap func ___encodeAsMap(i interface{}) ([]byte, error) { switch v := i.(type) { + case HealthInfo: + encoder := enc.NewEncoder() + size, err := ___calcMapSizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder) + if err != nil { + return nil, err + } + encoder.MakeBytes(size) + b, offset, err := ___encodeMapHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder, 0) + if err != nil { + return nil, err + } + if size != offset { + return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthInfo", size, offset) + } + return b, err + case *HealthInfo: + encoder := enc.NewEncoder() + size, err := ___calcMapSizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder) + if err != nil { + return nil, err + } + encoder.MakeBytes(size) + b, offset, err := ___encodeMapHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder, 0) + if err != nil { + return nil, err + } + if size != offset { + return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthInfo", size, offset) + } + return b, err case HealthResponse: encoder := enc.NewEncoder() size, err := ___calcMapSizeHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder) @@ -169,6 +229,20 @@ func ___decode(data []byte, i interface{}) (bool, error) { // decodeAsArray func ___decodeAsArray(data []byte, i interface{}) (bool, error) { switch v := i.(type) { + case *HealthInfo: + decoder := dec.NewDecoder(data) + offset, err := ___decodeArrayHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0) + if err == nil && offset != decoder.Len() { + return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len()) + } + return true, err + case **HealthInfo: + decoder := dec.NewDecoder(data) + offset, err := ___decodeArrayHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, decoder, 0) + if err == nil && offset != decoder.Len() { + return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len()) + } + return true, err case *HealthResponse: decoder := dec.NewDecoder(data) offset, err := ___decodeArrayHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0) @@ -204,6 +278,20 @@ func ___decodeAsArray(data []byte, i interface{}) (bool, error) { // decodeAsMap func ___decodeAsMap(data []byte, i interface{}) (bool, error) { switch v := i.(type) { + case *HealthInfo: + decoder := dec.NewDecoder(data) + offset, err := ___decodeMapHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0) + if err == nil && offset != decoder.Len() { + return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len()) + } + return true, err + case **HealthInfo: + decoder := dec.NewDecoder(data) + offset, err := ___decodeMapHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, decoder, 0) + if err == nil && offset != decoder.Len() { + return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len()) + } + return true, err case *HealthResponse: decoder := dec.NewDecoder(data) offset, err := ___decodeMapHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0) @@ -236,43 +324,330 @@ func ___decodeAsMap(data []byte, i interface{}) (bool, error) { return false, nil } +// calculate size from git.cacert.org/cacert-gosigner/pkg/messages.HealthInfo +func ___calcArraySizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthInfo, encoder *enc.Encoder) (int, error) { + size := 0 + size += encoder.CalcStructHeaderFix(3) + size += encoder.CalcString(v.Source) + size += encoder.CalcBool(v.Healthy) + if v.MoreInfo != nil { + s, err := encoder.CalcMapLength(len(v.MoreInfo)) + if err != nil { + return 0, err + } + size += s + for kk, vv := range v.MoreInfo { + size += encoder.CalcString(kk) + size += encoder.CalcString(vv) + } + } else { + size += encoder.CalcNil() + } + return size, nil +} + +// calculate size from git.cacert.org/cacert-gosigner/pkg/messages.HealthInfo +func ___calcMapSizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthInfo, encoder *enc.Encoder) (int, error) { + size := 0 + size += encoder.CalcStructHeaderFix(3) + size += encoder.CalcStringFix(6) + size += encoder.CalcString(v.Source) + size += encoder.CalcStringFix(7) + size += encoder.CalcBool(v.Healthy) + size += encoder.CalcStringFix(8) + if v.MoreInfo != nil { + s, err := encoder.CalcMapLength(len(v.MoreInfo)) + if err != nil { + return 0, err + } + size += s + for kk, vv := range v.MoreInfo { + size += encoder.CalcString(kk) + size += encoder.CalcString(vv) + } + } else { + size += encoder.CalcNil() + } + return size, nil +} + +// encode from git.cacert.org/cacert-gosigner/pkg/messages.HealthInfo +func ___encodeArrayHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthInfo, encoder *enc.Encoder, offset int) ([]byte, int, error) { + var err error + offset = encoder.WriteStructHeaderFixAsArray(3, offset) + offset = encoder.WriteString(v.Source, offset) + offset = encoder.WriteBool(v.Healthy, offset) + if v.MoreInfo != nil { + offset = encoder.WriteMapLength(len(v.MoreInfo), offset) + for kk, vv := range v.MoreInfo { + offset = encoder.WriteString(kk, offset) + offset = encoder.WriteString(vv, offset) + } + } else { + offset = encoder.WriteNil(offset) + } + return encoder.EncodedBytes(), offset, err +} + +// encode from git.cacert.org/cacert-gosigner/pkg/messages.HealthInfo +func ___encodeMapHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthInfo, encoder *enc.Encoder, offset int) ([]byte, int, error) { + var err error + offset = encoder.WriteStructHeaderFixAsMap(3, offset) + offset = encoder.WriteStringFix("Source", 6, offset) + offset = encoder.WriteString(v.Source, offset) + offset = encoder.WriteStringFix("Healthy", 7, offset) + offset = encoder.WriteBool(v.Healthy, offset) + offset = encoder.WriteStringFix("MoreInfo", 8, offset) + if v.MoreInfo != nil { + offset = encoder.WriteMapLength(len(v.MoreInfo), offset) + for kk, vv := range v.MoreInfo { + offset = encoder.WriteString(kk, offset) + offset = encoder.WriteString(vv, offset) + } + } else { + offset = encoder.WriteNil(offset) + } + return encoder.EncodedBytes(), offset, err +} + +// decode to git.cacert.org/cacert-gosigner/pkg/messages.HealthInfo +func ___decodeArrayHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *HealthInfo, decoder *dec.Decoder, offset int) (int, error) { + offset, err := decoder.CheckStructHeader(3, offset) + if err != nil { + return 0, err + } + { + var vv string + vv, offset, err = decoder.AsString(offset) + if err != nil { + return 0, err + } + v.Source = vv + } + { + var vv bool + vv, offset, err = decoder.AsBool(offset) + if err != nil { + return 0, err + } + v.Healthy = vv + } + if !decoder.IsCodeNil(offset) { + var vv map[string]string + var vvl int + vvl, offset, err = decoder.MapLength(offset) + if err != nil { + return 0, err + } + vv = make(map[string]string, vvl) + for vvi := 0; vvi < vvl; vvi++ { + var kkv string + kkv, offset, err = decoder.AsString(offset) + if err != nil { + return 0, err + } + var vvv string + vvv, offset, err = decoder.AsString(offset) + if err != nil { + return 0, err + } + vv[kkv] = vvv + } + v.MoreInfo = vv + } else { + offset++ + } + return offset, err +} + +// decode to git.cacert.org/cacert-gosigner/pkg/messages.HealthInfo +func ___decodeMapHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *HealthInfo, decoder *dec.Decoder, offset int) (int, error) { + keys := [][]byte{ + {uint8(0x53), uint8(0x6f), uint8(0x75), uint8(0x72), uint8(0x63), uint8(0x65)}, // Source + {uint8(0x48), uint8(0x65), uint8(0x61), uint8(0x6c), uint8(0x74), uint8(0x68), uint8(0x79)}, // Healthy + {uint8(0x4d), uint8(0x6f), uint8(0x72), uint8(0x65), uint8(0x49), uint8(0x6e), uint8(0x66), uint8(0x6f)}, // MoreInfo + } + offset, err := decoder.CheckStructHeader(3, offset) + if err != nil { + return 0, err + } + count := 0 + for count < 3 { + var dataKey []byte + dataKey, offset, err = decoder.AsStringBytes(offset) + if err != nil { + return 0, err + } + fieldIndex := -1 + for i, key := range keys { + if len(dataKey) != len(key) { + continue + } + fieldIndex = i + for dataKeyIndex := range dataKey { + if dataKey[dataKeyIndex] != key[dataKeyIndex] { + fieldIndex = -1 + break + } + } + if fieldIndex >= 0 { + break + } + } + switch fieldIndex { + case 0: + { + var vv string + vv, offset, err = decoder.AsString(offset) + if err != nil { + return 0, err + } + v.Source = vv + } + count++ + case 1: + { + var vv bool + vv, offset, err = decoder.AsBool(offset) + if err != nil { + return 0, err + } + v.Healthy = vv + } + count++ + case 2: + if !decoder.IsCodeNil(offset) { + var vv map[string]string + var vvl int + vvl, offset, err = decoder.MapLength(offset) + if err != nil { + return 0, err + } + vv = make(map[string]string, vvl) + for vvi := 0; vvi < vvl; vvi++ { + var kkv string + kkv, offset, err = decoder.AsString(offset) + if err != nil { + return 0, err + } + var vvv string + vvv, offset, err = decoder.AsString(offset) + if err != nil { + return 0, err + } + vv[kkv] = vvv + } + v.MoreInfo = vv + } else { + offset++ + } + count++ + default: + return 0, fmt.Errorf("unknown key[%s] found", string(dataKey)) + } + } + return offset, err +} + // calculate size from git.cacert.org/cacert-gosigner/pkg/messages.HealthResponse func ___calcArraySizeHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthResponse, encoder *enc.Encoder) (int, error) { size := 0 - size += encoder.CalcStructHeaderFix(1) + size += encoder.CalcStructHeaderFix(3) size += encoder.CalcString(v.Version) + size += encoder.CalcBool(v.Healthy) + if v.Info != nil { + s, err := encoder.CalcSliceLength(len(v.Info), false) + if err != nil { + return 0, err + } + size += s + for _, vv := range v.Info { + size_vv, err := ___calcArraySizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(vv, encoder) + if err != nil { + return 0, err + } + size += size_vv + } + } else { + size += encoder.CalcNil() + } return size, nil } // calculate size from git.cacert.org/cacert-gosigner/pkg/messages.HealthResponse func ___calcMapSizeHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthResponse, encoder *enc.Encoder) (int, error) { size := 0 - size += encoder.CalcStructHeaderFix(1) + size += encoder.CalcStructHeaderFix(3) size += encoder.CalcStringFix(7) size += encoder.CalcString(v.Version) + size += encoder.CalcStringFix(7) + size += encoder.CalcBool(v.Healthy) + size += encoder.CalcStringFix(4) + if v.Info != nil { + s, err := encoder.CalcSliceLength(len(v.Info), false) + if err != nil { + return 0, err + } + size += s + for _, vv := range v.Info { + size_vv, err := ___calcMapSizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(vv, encoder) + if err != nil { + return 0, err + } + size += size_vv + } + } else { + size += encoder.CalcNil() + } return size, nil } // encode from git.cacert.org/cacert-gosigner/pkg/messages.HealthResponse func ___encodeArrayHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthResponse, encoder *enc.Encoder, offset int) ([]byte, int, error) { var err error - offset = encoder.WriteStructHeaderFixAsArray(1, offset) + offset = encoder.WriteStructHeaderFixAsArray(3, offset) offset = encoder.WriteString(v.Version, offset) + offset = encoder.WriteBool(v.Healthy, offset) + if v.Info != nil { + offset = encoder.WriteSliceLength(len(v.Info), offset, false) + for _, vv := range v.Info { + _, offset, err = ___encodeArrayHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(vv, encoder, offset) + if err != nil { + return nil, 0, err + } + } + } else { + offset = encoder.WriteNil(offset) + } return encoder.EncodedBytes(), offset, err } // encode from git.cacert.org/cacert-gosigner/pkg/messages.HealthResponse func ___encodeMapHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthResponse, encoder *enc.Encoder, offset int) ([]byte, int, error) { var err error - offset = encoder.WriteStructHeaderFixAsMap(1, offset) + offset = encoder.WriteStructHeaderFixAsMap(3, offset) offset = encoder.WriteStringFix("version", 7, offset) offset = encoder.WriteString(v.Version, offset) + offset = encoder.WriteStringFix("Healthy", 7, offset) + offset = encoder.WriteBool(v.Healthy, offset) + offset = encoder.WriteStringFix("Info", 4, offset) + if v.Info != nil { + offset = encoder.WriteSliceLength(len(v.Info), offset, false) + for _, vv := range v.Info { + _, offset, err = ___encodeMapHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(vv, encoder, offset) + if err != nil { + return nil, 0, err + } + } + } else { + offset = encoder.WriteNil(offset) + } return encoder.EncodedBytes(), offset, err } // decode to git.cacert.org/cacert-gosigner/pkg/messages.HealthResponse func ___decodeArrayHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *HealthResponse, decoder *dec.Decoder, offset int) (int, error) { - offset, err := decoder.CheckStructHeader(1, offset) + offset, err := decoder.CheckStructHeader(3, offset) if err != nil { return 0, err } @@ -284,6 +659,34 @@ func ___decodeArrayHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a8137 } v.Version = vv } + { + var vv bool + vv, offset, err = decoder.AsBool(offset) + if err != nil { + return 0, err + } + v.Healthy = vv + } + if !decoder.IsCodeNil(offset) { + var vv []HealthInfo + var vvl int + vvl, offset, err = decoder.SliceLength(offset) + if err != nil { + return 0, err + } + vv = make([]HealthInfo, vvl) + for vvi := range vv { + var vvv HealthInfo + offset, err = ___decodeArrayHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(&vvv, decoder, offset) + if err != nil { + return 0, err + } + vv[vvi] = vvv + } + v.Info = vv + } else { + offset++ + } return offset, err } @@ -291,13 +694,15 @@ func ___decodeArrayHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a8137 func ___decodeMapHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *HealthResponse, decoder *dec.Decoder, offset int) (int, error) { keys := [][]byte{ {uint8(0x76), uint8(0x65), uint8(0x72), uint8(0x73), uint8(0x69), uint8(0x6f), uint8(0x6e)}, // version + {uint8(0x48), uint8(0x65), uint8(0x61), uint8(0x6c), uint8(0x74), uint8(0x68), uint8(0x79)}, // Healthy + {uint8(0x49), uint8(0x6e), uint8(0x66), uint8(0x6f)}, // Info } - offset, err := decoder.CheckStructHeader(1, offset) + offset, err := decoder.CheckStructHeader(3, offset) if err != nil { return 0, err } count := 0 - for count < 1 { + for count < 3 { var dataKey []byte dataKey, offset, err = decoder.AsStringBytes(offset) if err != nil { @@ -330,6 +735,38 @@ func ___decodeMapHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f v.Version = vv } count++ + case 1: + { + var vv bool + vv, offset, err = decoder.AsBool(offset) + if err != nil { + return 0, err + } + v.Healthy = vv + } + count++ + case 2: + if !decoder.IsCodeNil(offset) { + var vv []HealthInfo + var vvl int + vvl, offset, err = decoder.SliceLength(offset) + if err != nil { + return 0, err + } + vv = make([]HealthInfo, vvl) + for vvi := range vv { + var vvv HealthInfo + offset, err = ___decodeMapHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(&vvv, decoder, offset) + if err != nil { + return 0, err + } + vv[vvi] = vvv + } + v.Info = vv + } else { + offset++ + } + count++ default: return 0, fmt.Errorf("unknown key[%s] found", string(dataKey)) } diff --git a/pkg/protocol/protocol.go b/pkg/protocol/protocol.go index 086e45a..8f45bfe 100644 --- a/pkg/protocol/protocol.go +++ b/pkg/protocol/protocol.go @@ -78,17 +78,42 @@ func (m *MsgPackHandler) HandleFrame(frame []byte) ([]byte, error) { func (m *MsgPackHandler) handleCommand(command *messages.Command) (*messages.Response, error) { var ( + err error payload interface{} responseCode messages.ResponseCode ) switch command.Code { case messages.CmdHealth: - responseCode, payload = messages.RspHealth, messages.HealthResponse{Version: m.healthHandler.Version} + var res *health.Result + + res, err = m.healthHandler.CheckHealth() + if err != nil { + break + } + + response := messages.HealthResponse{ + Version: res.Version, + Healthy: res.Healthy, + } + + for _, info := range res.Info { + response.Info = append(response.Info, messages.HealthInfo{ + Source: info.Source, + Healthy: info.Healthy, + MoreInfo: info.MoreInfo, + }) + } + + responseCode, payload = messages.RspHealth, response default: return nil, fmt.Errorf("unhandled command %s", command) } + if err != nil { + return nil, fmt.Errorf("error from command handler: %w", err) + } + return &messages.Response{TimeStamp: time.Now().UTC(), Code: responseCode, Payload: payload}, nil }