44d91ea56f
Signed-off-by: Jakub Sokołowski <jakub@status.im> * agent: add failures_before_warning setting The new setting allows users to specify the number of check failures that have to happen before a service status us updated to be `warning`. This allows for more visibility for detected issues without creating alerts and pinging administrators. Unlike the previous behavior, which caused the service status to not update until it reached the configured `failures_before_critical` setting, now Consul updates the Web UI view with the `warning` state and the output of the service check when `failures_before_warning` is breached. The default value of `FailuresBeforeWarning` is the same as the value of `FailuresBeforeCritical`, which allows for retaining the previous default behavior of not triggering a warning. When `FailuresBeforeWarning` is set to a value higher than that of `FailuresBeforeCritical it has no effect as `FailuresBeforeCritical` takes precedence. Resolves: https://github.com/hashicorp/consul/issues/10680 Signed-off-by: Jakub Sokołowski <jakub@status.im> Co-authored-by: Jakub Sokołowski <jakub@status.im>
153 lines
4.1 KiB
Go
153 lines
4.1 KiB
Go
package structs
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/go-multierror"
|
|
|
|
"github.com/hashicorp/consul/lib"
|
|
)
|
|
|
|
// ServiceDefinition is used to JSON decode the Service definitions. For
|
|
// documentation on specific fields see NodeService which is better documented.
|
|
type ServiceDefinition struct {
|
|
Kind ServiceKind `json:",omitempty"`
|
|
ID string
|
|
Name string
|
|
Tags []string
|
|
Address string
|
|
TaggedAddresses map[string]ServiceAddress
|
|
Meta map[string]string
|
|
Port int
|
|
SocketPath string
|
|
Check CheckType
|
|
Checks CheckTypes
|
|
Weights *Weights
|
|
Token string
|
|
EnableTagOverride bool
|
|
|
|
// Proxy is the configuration set for Kind = connect-proxy. It is mandatory in
|
|
// that case and an error to be set for any other kind. This config is part of
|
|
// a proxy service definition. ProxyConfig may be a more natural name here, but
|
|
// it's confusing for the UX because one of the fields in ConnectProxyConfig is
|
|
// also called just "Config"
|
|
Proxy *ConnectProxyConfig
|
|
|
|
EnterpriseMeta `hcl:",squash" mapstructure:",squash"`
|
|
|
|
Connect *ServiceConnect
|
|
}
|
|
|
|
func (t *ServiceDefinition) UnmarshalJSON(data []byte) (err error) {
|
|
type Alias ServiceDefinition
|
|
|
|
aux := &struct {
|
|
EnableTagOverrideSnake bool `json:"enable_tag_override"`
|
|
TaggedAddressesSnake map[string]ServiceAddress `json:"tagged_addresses"`
|
|
|
|
*Alias
|
|
}{
|
|
Alias: (*Alias)(t),
|
|
}
|
|
if err = lib.UnmarshalJSON(data, &aux); err != nil {
|
|
return err
|
|
}
|
|
if aux.EnableTagOverrideSnake {
|
|
t.EnableTagOverride = aux.EnableTagOverrideSnake
|
|
}
|
|
if len(t.TaggedAddresses) == 0 {
|
|
t.TaggedAddresses = aux.TaggedAddressesSnake
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *ServiceDefinition) NodeService() *NodeService {
|
|
ns := &NodeService{
|
|
Kind: s.Kind,
|
|
ID: s.ID,
|
|
Service: s.Name,
|
|
Tags: s.Tags,
|
|
Address: s.Address,
|
|
Meta: s.Meta,
|
|
Port: s.Port,
|
|
SocketPath: s.SocketPath,
|
|
Weights: s.Weights,
|
|
EnableTagOverride: s.EnableTagOverride,
|
|
EnterpriseMeta: s.EnterpriseMeta,
|
|
}
|
|
ns.EnterpriseMeta.Normalize()
|
|
|
|
if s.Connect != nil {
|
|
ns.Connect = *s.Connect
|
|
}
|
|
if s.Proxy != nil {
|
|
ns.Proxy = *s.Proxy
|
|
for i := range ns.Proxy.Upstreams {
|
|
// Ensure the Upstream type is defaulted
|
|
if ns.Proxy.Upstreams[i].DestinationType == "" {
|
|
ns.Proxy.Upstreams[i].DestinationType = UpstreamDestTypeService
|
|
}
|
|
|
|
// If a proxy's namespace is not defined, inherit the proxied service's namespace.
|
|
// Applicable only to Consul Enterprise.
|
|
if ns.Proxy.Upstreams[i].DestinationNamespace == "" {
|
|
ns.Proxy.Upstreams[i].DestinationNamespace = ns.EnterpriseMeta.NamespaceOrEmpty()
|
|
}
|
|
if ns.Proxy.Upstreams[i].DestinationPartition == "" {
|
|
ns.Proxy.Upstreams[i].DestinationPartition = ns.EnterpriseMeta.PartitionOrEmpty()
|
|
}
|
|
}
|
|
ns.Proxy.Expose = s.Proxy.Expose
|
|
}
|
|
if ns.ID == "" && ns.Service != "" {
|
|
ns.ID = ns.Service
|
|
}
|
|
if len(s.TaggedAddresses) > 0 {
|
|
taggedAddrs := make(map[string]ServiceAddress)
|
|
for k, v := range s.TaggedAddresses {
|
|
taggedAddrs[k] = v
|
|
}
|
|
|
|
ns.TaggedAddresses = taggedAddrs
|
|
}
|
|
return ns
|
|
}
|
|
|
|
// Validate validates the service definition. This also calls the underlying
|
|
// Validate method on the NodeService.
|
|
//
|
|
// NOTE(mitchellh): This currently only validates fields related to Connect
|
|
// and is incomplete with regards to other fields.
|
|
func (s *ServiceDefinition) Validate() error {
|
|
var result error
|
|
|
|
// Validate the NodeService which covers a lot
|
|
if err := s.NodeService().Validate(); err != nil {
|
|
result = multierror.Append(result, err)
|
|
}
|
|
for _, c := range s.Checks {
|
|
if err := c.Validate(); err != nil {
|
|
return fmt.Errorf("check %q: %s", c.Name, err)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (s *ServiceDefinition) CheckTypes() (checks CheckTypes, err error) {
|
|
if !s.Check.Empty() {
|
|
err := s.Check.Validate()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
checks = append(checks, &s.Check)
|
|
}
|
|
for _, check := range s.Checks {
|
|
if err := check.Validate(); err != nil {
|
|
return nil, err
|
|
}
|
|
checks = append(checks, check)
|
|
}
|
|
return checks, nil
|
|
}
|