agent: persist CheckType with health checks

This commit is contained in:
Ryan Uber 2014-11-29 12:25:01 -08:00
parent 4f14ba6326
commit 9e52588cec
3 changed files with 52 additions and 30 deletions

View File

@ -564,10 +564,16 @@ func (a *Agent) restoreServices() error {
} }
// persistCheck saves a check definition to the local agent's state directory // persistCheck saves a check definition to the local agent's state directory
func (a *Agent) persistCheck(check *structs.HealthCheck) error { func (a *Agent) persistCheck(check *structs.HealthCheck, chkType *CheckType) error {
checkPath := filepath.Join(a.config.DataDir, checksDir, check.CheckID) checkPath := filepath.Join(a.config.DataDir, checksDir, check.CheckID)
if _, err := os.Stat(checkPath); os.IsNotExist(err) { if _, err := os.Stat(checkPath); !os.IsNotExist(err) {
encoded, err := json.Marshal(check) return err
}
// Create the persisted check
p := persistedCheck{check, chkType}
encoded, err := json.Marshal(p)
if err != nil { if err != nil {
return nil return nil
} }
@ -582,7 +588,6 @@ func (a *Agent) persistCheck(check *structs.HealthCheck) error {
if _, err := fh.Write(encoded); err != nil { if _, err := fh.Write(encoded); err != nil {
return err return err
} }
}
return nil return nil
} }
@ -619,23 +624,23 @@ func (a *Agent) restoreChecks() error {
return err return err
} }
var check *structs.HealthCheck var p persistedCheck
if err := json.Unmarshal(content, &check); err != nil { if err := json.Unmarshal(content, &p); err != nil {
return err return err
} }
if _, ok := a.state.checks[check.CheckID]; ok { if _, ok := a.state.checks[p.Check.CheckID]; ok {
// Purge previously persisted check. This allows config to be // Purge previously persisted check. This allows config to be
// preferred over persisted checks from the API. // preferred over persisted checks from the API.
a.logger.Printf("[DEBUG] Check %s exists, not restoring", check.CheckID) a.logger.Printf("[DEBUG] Check %s exists, not restoring", p.Check.CheckID)
return a.purgeCheck(check.CheckID) return a.purgeCheck(p.Check.CheckID)
} else { } else {
// Default check to critical to avoid placing potentially unhealthy // Default check to critical to avoid placing potentially unhealthy
// services into the active pool // services into the active pool
check.Status = structs.HealthCritical p.Check.Status = structs.HealthCritical
a.logger.Printf("[DEBUG] Restored health check: %s", check.CheckID) a.logger.Printf("[DEBUG] Restored health check: %s", p.Check.CheckID)
return a.AddCheck(check, nil, false) return a.AddCheck(p.Check, p.ChkType, false)
} }
}) })
return err return err
@ -766,7 +771,7 @@ func (a *Agent) AddCheck(check *structs.HealthCheck, chkType *CheckType, persist
// Persist the check // Persist the check
if persist { if persist {
return a.persistCheck(check) return a.persistCheck(check, chkType)
} }
return nil return nil

View File

@ -534,11 +534,15 @@ func TestAgent_PersistCheck(t *testing.T) {
ServiceID: "redis", ServiceID: "redis",
ServiceName: "redis", ServiceName: "redis",
} }
chkType := &CheckType{
Script: "/bin/true",
Interval: 10 * time.Second,
}
file := filepath.Join(agent.config.DataDir, checksDir, check.CheckID) file := filepath.Join(agent.config.DataDir, checksDir, check.CheckID)
// Not persisted if not requested // Not persisted if not requested
if err := agent.AddCheck(check, nil, false); err != nil { if err := agent.AddCheck(check, chkType, false); err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
if _, err := os.Stat(file); err == nil { if _, err := os.Stat(file); err == nil {
@ -546,7 +550,7 @@ func TestAgent_PersistCheck(t *testing.T) {
} }
// Should persist if requested // Should persist if requested
if err := agent.AddCheck(check, nil, true); err != nil { if err := agent.AddCheck(check, chkType, true); err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
@ -554,7 +558,8 @@ func TestAgent_PersistCheck(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
expected, err := json.Marshal(check) p := persistedCheck{check, chkType}
expected, err := json.Marshal(p)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
@ -574,13 +579,18 @@ func TestAgent_PersistCheck(t *testing.T) {
} }
defer agent2.Shutdown() defer agent2.Shutdown()
result, ok := agent2.state.checks[check.CheckID] result, ok := agent2.state.checks[p.Check.CheckID]
if !ok { if !ok {
t.Fatalf("bad: %#v", agent2.state.checks) t.Fatalf("bad: %#v", agent2.state.checks)
} }
if result.Status != structs.HealthCritical { if result.Status != structs.HealthCritical {
t.Fatalf("bad: %#v", result) t.Fatalf("bad: %#v", result)
} }
// Should have restored the monitor
if _, ok := agent2.checkMonitors[p.Check.CheckID]; !ok {
t.Fatalf("bad: %#v", agent2.checkMonitors)
}
} }
func TestAgent_PurgeCheck(t *testing.T) { func TestAgent_PurgeCheck(t *testing.T) {

View File

@ -234,3 +234,10 @@ func (c *CheckTTL) SetStatus(status, output string) {
c.Notify.UpdateCheck(c.CheckID, status, output) c.Notify.UpdateCheck(c.CheckID, status, output)
c.timer.Reset(c.TTL) c.timer.Reset(c.TTL)
} }
// persistedCheck is used to serialize a check and write it to disk
// so that it may be restored later on.
type persistedCheck struct {
Check *structs.HealthCheck
ChkType *CheckType
}