mirror of https://github.com/status-im/consul.git
agent: Limit health check output to 4K. Fixes #83.
This commit is contained in:
parent
eb6b85510d
commit
64efde9be0
|
@ -1,8 +1,8 @@
|
||||||
package agent
|
package agent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/armon/circbuf"
|
||||||
"github.com/hashicorp/consul/consul/structs"
|
"github.com/hashicorp/consul/consul/structs"
|
||||||
"log"
|
"log"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -16,6 +16,11 @@ const (
|
||||||
// Do not allow for a interval below this value.
|
// Do not allow for a interval below this value.
|
||||||
// Otherwise we risk fork bombing a system.
|
// Otherwise we risk fork bombing a system.
|
||||||
MinInterval = time.Second
|
MinInterval = time.Second
|
||||||
|
|
||||||
|
// Limit the size of a check's output to the
|
||||||
|
// last CheckBufSize. Prevents an enormous buffer
|
||||||
|
// from being captured
|
||||||
|
CheckBufSize = 4 * 1024 // 4KB
|
||||||
)
|
)
|
||||||
|
|
||||||
// CheckType is used to create either the CheckMonitor
|
// CheckType is used to create either the CheckMonitor
|
||||||
|
@ -115,9 +120,9 @@ func (c *CheckMonitor) check() {
|
||||||
cmd := exec.Command(shell, flag, c.Script)
|
cmd := exec.Command(shell, flag, c.Script)
|
||||||
|
|
||||||
// Collect the output
|
// Collect the output
|
||||||
var output bytes.Buffer
|
output, _ := circbuf.NewBuffer(CheckBufSize)
|
||||||
cmd.Stdout = &output
|
cmd.Stdout = output
|
||||||
cmd.Stderr = &output
|
cmd.Stderr = output
|
||||||
|
|
||||||
// Start the check
|
// Start the check
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
|
@ -137,7 +142,13 @@ func (c *CheckMonitor) check() {
|
||||||
}()
|
}()
|
||||||
err := <-errCh
|
err := <-errCh
|
||||||
|
|
||||||
|
// Get the output, add a message about truncation
|
||||||
outputStr := string(output.Bytes())
|
outputStr := string(output.Bytes())
|
||||||
|
if output.TotalWritten() > output.Size() {
|
||||||
|
outputStr = fmt.Sprintf("Captured %d of %d bytes\n...\n%s",
|
||||||
|
output.Size(), output.TotalWritten(), outputStr)
|
||||||
|
}
|
||||||
|
|
||||||
c.Logger.Printf("[DEBUG] agent: check '%s' script '%s' output: %s",
|
c.Logger.Printf("[DEBUG] agent: check '%s' script '%s' output: %s",
|
||||||
c.CheckID, c.Script, outputStr)
|
c.CheckID, c.Script, outputStr)
|
||||||
|
|
||||||
|
|
|
@ -11,18 +11,21 @@ import (
|
||||||
type MockNotify struct {
|
type MockNotify struct {
|
||||||
state map[string]string
|
state map[string]string
|
||||||
updates map[string]int
|
updates map[string]int
|
||||||
|
output map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockNotify) UpdateCheck(id, status, note string) {
|
func (m *MockNotify) UpdateCheck(id, status, output string) {
|
||||||
m.state[id] = status
|
m.state[id] = status
|
||||||
old := m.updates[id]
|
old := m.updates[id]
|
||||||
m.updates[id] = old + 1
|
m.updates[id] = old + 1
|
||||||
|
m.output[id] = output
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectStatus(t *testing.T, script, status string) {
|
func expectStatus(t *testing.T, script, status string) {
|
||||||
mock := &MockNotify{
|
mock := &MockNotify{
|
||||||
state: make(map[string]string),
|
state: make(map[string]string),
|
||||||
updates: make(map[string]int),
|
updates: make(map[string]int),
|
||||||
|
output: make(map[string]string),
|
||||||
}
|
}
|
||||||
check := &CheckMonitor{
|
check := &CheckMonitor{
|
||||||
Notify: mock,
|
Notify: mock,
|
||||||
|
@ -62,10 +65,35 @@ func TestCheckMonitor_BadCmd(t *testing.T) {
|
||||||
expectStatus(t, "foobarbaz", structs.HealthCritical)
|
expectStatus(t, "foobarbaz", structs.HealthCritical)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCheckMonitor_LimitOutput(t *testing.T) {
|
||||||
|
mock := &MockNotify{
|
||||||
|
state: make(map[string]string),
|
||||||
|
updates: make(map[string]int),
|
||||||
|
output: make(map[string]string),
|
||||||
|
}
|
||||||
|
check := &CheckMonitor{
|
||||||
|
Notify: mock,
|
||||||
|
CheckID: "foo",
|
||||||
|
Script: "dd if=/dev/urandom bs=8192 count=10",
|
||||||
|
Interval: 25 * time.Millisecond,
|
||||||
|
Logger: log.New(os.Stderr, "", log.LstdFlags),
|
||||||
|
}
|
||||||
|
check.Start()
|
||||||
|
defer check.Stop()
|
||||||
|
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
|
||||||
|
// Allow for extra bytes for the truncation message
|
||||||
|
if len(mock.output["foo"]) > CheckBufSize+100 {
|
||||||
|
t.Fatalf("output size is too long")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheckTTL(t *testing.T) {
|
func TestCheckTTL(t *testing.T) {
|
||||||
mock := &MockNotify{
|
mock := &MockNotify{
|
||||||
state: make(map[string]string),
|
state: make(map[string]string),
|
||||||
updates: make(map[string]int),
|
updates: make(map[string]int),
|
||||||
|
output: make(map[string]string),
|
||||||
}
|
}
|
||||||
check := &CheckTTL{
|
check := &CheckTTL{
|
||||||
Notify: mock,
|
Notify: mock,
|
||||||
|
|
Loading…
Reference in New Issue