diff --git a/agent/agent.go b/agent/agent.go index 54628bca13..b40696e434 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -1407,7 +1407,7 @@ func (a *Agent) reapServicesInternal() { } // reapServices is a long running goroutine that looks for checks that have been -// critical too long and dregisters their associated services. +// critical too long and deregisters their associated services. func (a *Agent) reapServices() { for { select { diff --git a/agent/catalog_endpoint.go b/agent/catalog_endpoint.go index 175b0d4a26..1eb30fc3a6 100644 --- a/agent/catalog_endpoint.go +++ b/agent/catalog_endpoint.go @@ -8,13 +8,15 @@ import ( "github.com/hashicorp/consul/agent/structs" ) +var durations = NewDurationFixer("interval", "timeout", "deregistercriticalserviceafter") + func (s *HTTPServer) CatalogRegister(resp http.ResponseWriter, req *http.Request) (interface{}, error) { if req.Method != "PUT" { return nil, MethodNotAllowedError{req.Method, []string{"PUT"}} } var args structs.RegisterRequest - if err := decodeBody(req, &args, nil); err != nil { + if err := decodeBody(req, &args, durations.FixupDurations); err != nil { resp.WriteHeader(http.StatusBadRequest) fmt.Fprintf(resp, "Request decode failed: %v", err) return nil, nil diff --git a/agent/operator_endpoint.go b/agent/operator_endpoint.go index 5a3c0d38a9..240a9fc726 100644 --- a/agent/operator_endpoint.go +++ b/agent/operator_endpoint.go @@ -220,7 +220,8 @@ func (s *HTTPServer) OperatorAutopilotConfiguration(resp http.ResponseWriter, re s.parseToken(req, &args.Token) var conf api.AutopilotConfiguration - if err := decodeBody(req, &conf, FixupConfigDurations); err != nil { + durations := NewDurationFixer("lastcontactthreshold", "serverstabilizationtime") + if err := decodeBody(req, &conf, durations.FixupDurations); err != nil { resp.WriteHeader(http.StatusBadRequest) fmt.Fprintf(resp, "Error parsing autopilot config: %v", err) return nil, nil @@ -265,23 +266,50 @@ func (s *HTTPServer) OperatorAutopilotConfiguration(resp http.ResponseWriter, re } } -// FixupConfigDurations is used to handle parsing the duration fields in -// the Autopilot config struct -func FixupConfigDurations(raw interface{}) error { +type durationFixer map[string]struct{} + +func NewDurationFixer(fields ...string) durationFixer { + d := make(map[string]struct{}) + for _, field := range fields { + d[field] = struct{}{} + } + return d +} + +// FixupDurations is used to handle parsing any field names in the map to time.Durations +func (d durationFixer) FixupDurations(raw interface{}) error { rawMap, ok := raw.(map[string]interface{}) if !ok { return nil } for key, val := range rawMap { - if strings.ToLower(key) == "lastcontactthreshold" || - strings.ToLower(key) == "serverstabilizationtime" { - // Convert a string value into an integer - if vStr, ok := val.(string); ok { - dur, err := time.ParseDuration(vStr) - if err != nil { + if key == "NodeMeta" { + continue + } + + switch val.(type) { + case map[string]interface{}: + if err := d.FixupDurations(val); err != nil { + return err + } + + case []interface{}: + for _, v := range val.([]interface{}) { + if err := d.FixupDurations(v); err != nil { return err } - rawMap[key] = dur + } + + default: + if _, ok := d[strings.ToLower(key)]; ok { + // Convert a string value into an integer + if vStr, ok := val.(string); ok { + dur, err := time.ParseDuration(vStr) + if err != nil { + return err + } + rawMap[key] = dur + } } } } diff --git a/agent/structs/structs.go b/agent/structs/structs.go index a837c5277d..2c997ae2af 100644 --- a/agent/structs/structs.go +++ b/agent/structs/structs.go @@ -482,13 +482,14 @@ type HealthCheck struct { ServiceName string // optional service name ServiceTags []string // optional service tags - HTTP string `json:",omitempty"` - TLSSkipVerify bool `json:",omitempty"` - Header map[string][]string `json:",omitempty"` - Method string `json:",omitempty"` - TCP string `json:",omitempty"` - Interval string `json:",omitempty"` - Timeout string `json:",omitempty"` + HTTP string `json:",omitempty"` + TLSSkipVerify bool `json:",omitempty"` + Header map[string][]string `json:",omitempty"` + Method string `json:",omitempty"` + TCP string `json:",omitempty"` + Interval api.ReadableDuration `json:",omitempty"` + Timeout api.ReadableDuration `json:",omitempty"` + DeregisterCriticalServiceAfter api.ReadableDuration `json:",omitempty"` RaftIndex } diff --git a/api/agent.go b/api/agent.go index 53e600aedd..c4ec96f1c1 100644 --- a/api/agent.go +++ b/api/agent.go @@ -7,21 +7,22 @@ import ( // AgentCheck represents a check known to the agent type AgentCheck struct { - Node string - CheckID string - Name string - Status string - Notes string - Output string - ServiceID string - ServiceName string - HTTP string - Header map[string][]string - Method string - TLSSkipVerify bool - TCP string - Interval string - Timeout string + Node string + CheckID string + Name string + Status string + Notes string + Output string + ServiceID string + ServiceName string + HTTP string + Header map[string][]string + Method string + TLSSkipVerify bool + TCP string + Interval ReadableDuration + Timeout ReadableDuration + DeregisterCriticalServiceAfter ReadableDuration } // AgentService represents a service known to the agent diff --git a/api/health.go b/api/health.go index b5503fb2e9..3f132759e7 100644 --- a/api/health.go +++ b/api/health.go @@ -35,13 +35,14 @@ type HealthCheck struct { ServiceName string ServiceTags []string - HTTP string - Header map[string][]string - Method string - TLSSkipVerify bool - TCP string - Interval string - Timeout string + HTTP string + Header map[string][]string + Method string + TLSSkipVerify bool + TCP string + Interval ReadableDuration + Timeout ReadableDuration + DeregisterCriticalServiceAfter ReadableDuration } // HealthChecks is a collection of HealthCheck structs.