From a68ecd0fe7cfccc7fc8f585daa6c1b4d6dd9ad6c Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Wed, 26 Jun 2019 00:05:24 +0200 Subject: [PATCH] Properly truncate TTL checks Check that OutputMaxSize is properly taken into account. BUGFIX: properly update local state on update of TTL --- agent/agent.go | 21 ++++++++++++++------- agent/agent_endpoint_test.go | 2 +- agent/agent_test.go | 18 ++++++++++++++++-- agent/checks/check.go | 4 +++- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 0ed64c82866d..e2f0985ebe8b 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -2259,10 +2259,11 @@ func (a *Agent) addCheck(check *structs.HealthCheck, chkType *structs.CheckType, } ttl := &checks.CheckTTL{ - Notify: a.State, - CheckID: check.CheckID, - TTL: chkType.TTL, - Logger: a.logger, + Notify: a.State, + CheckID: check.CheckID, + TTL: chkType.TTL, + Logger: a.logger, + OutputMaxSize: maxOutputSize, } // Restore persisted state, if any @@ -2878,8 +2879,14 @@ func (a *Agent) updateTTLCheck(checkID types.CheckID, status, output string) err } // Set the status through CheckTTL to reset the TTL. - check.SetStatus(status, output) - + outputTruncated := check.SetStatus(status, output) + stateCheck := a.State.Checks()[checkID] + if stateCheck != nil { + stateCheck.Output = outputTruncated + stateCheck.Status = status + } else { + a.logger.Printf("[WARN] agent: Unexpected missing state for check %v", checkID) + } // We don't write any files in dev mode so bail here. if a.config.DataDir == "" { return nil @@ -2887,7 +2894,7 @@ func (a *Agent) updateTTLCheck(checkID types.CheckID, status, output string) err // Persist the state so the TTL check can come up in a good state after // an agent restart, especially with long TTL values. - if err := a.persistCheckState(check, status, output); err != nil { + if err := a.persistCheckState(check, status, outputTruncated); err != nil { return fmt.Errorf("failed persisting state for check %q: %s", checkID, err) } diff --git a/agent/agent_endpoint_test.go b/agent/agent_endpoint_test.go index 44f619809397..18238dbe5f8a 100644 --- a/agent/agent_endpoint_test.go +++ b/agent/agent_endpoint_test.go @@ -2360,7 +2360,7 @@ func TestAgent_UpdateCheck(t *testing.T) { // isn't super brittle. state := a.State.Checks()["test"] if state.Status != api.HealthPassing || len(state.Output) > 2*checks.DefaultBufSize { - t.Fatalf("bad: %v", state) + t.Fatalf("bad: %v, (len:=%d)", state, len(state.Output)) } }) diff --git a/agent/agent_test.go b/agent/agent_test.go index fecd1c208d12..226ee32355bc 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -1405,7 +1405,7 @@ func TestAgent_updateTTLCheck(t *testing.T) { t.Parallel() a := NewTestAgent(t, t.Name(), "") defer a.Shutdown() - + checkBufSize := 100 health := &structs.HealthCheck{ Node: "foo", CheckID: "mem", @@ -1413,7 +1413,8 @@ func TestAgent_updateTTLCheck(t *testing.T) { Status: api.HealthCritical, } chk := &structs.CheckType{ - TTL: 15 * time.Second, + TTL: 15 * time.Second, + OutputMaxSize: checkBufSize, } // Add check and update it. @@ -1433,6 +1434,19 @@ func TestAgent_updateTTLCheck(t *testing.T) { if status.Output != "foo" { t.Fatalf("bad: %v", status) } + + if err := a.updateTTLCheck("mem", api.HealthCritical, strings.Repeat("--bad-- ", 5*checkBufSize)); err != nil { + t.Fatalf("err: %v", err) + } + + // Ensure we have a check mapping. + status = a.State.Checks()["mem"] + if status.Status != api.HealthCritical { + t.Fatalf("bad: %v", status) + } + if len(status.Output) > checkBufSize*2 { + t.Fatalf("bad: %v", len(status.Output)) + } } func TestAgent_PersistService(t *testing.T) { diff --git a/agent/checks/check.go b/agent/checks/check.go index 9997c0f807ca..8b6c4c971b3a 100644 --- a/agent/checks/check.go +++ b/agent/checks/check.go @@ -281,7 +281,8 @@ func (c *CheckTTL) getExpiredOutput() string { // SetStatus is used to update the status of the check, // and to renew the TTL. If expired, TTL is restarted. -func (c *CheckTTL) SetStatus(status, output string) { +// output is returned (might be truncated) +func (c *CheckTTL) SetStatus(status, output string) string { c.Logger.Printf("[DEBUG] agent: Check %q status is now %s", c.CheckID, status) c.Notify.UpdateCheck(c.CheckID, status, output) total := len(output) @@ -295,6 +296,7 @@ func (c *CheckTTL) SetStatus(status, output string) { c.lastOutputLock.Unlock() c.timer.Reset(c.TTL) + return output } // CheckHTTP is used to periodically make an HTTP request to