// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 package structs import ( "time" "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/types" ) // CheckDefinition is used to JSON decode the Check definitions type CheckDefinition struct { ID types.CheckID Name string Notes string ServiceID string Token string Status string // Copied fields from CheckType without the fields // already present in CheckDefinition: // // ID (CheckID), Name, Status, Notes // ScriptArgs []string HTTP string H2PING string H2PingUseTLS bool Header map[string][]string Method string Body string DisableRedirects bool TCP string TCPUseTLS bool UDP string Interval time.Duration DockerContainerID string Shell string GRPC string GRPCUseTLS bool OSService string TLSServerName string TLSSkipVerify bool AliasNode string AliasService string Timeout time.Duration TTL time.Duration SuccessBeforePassing int FailuresBeforeWarning int FailuresBeforeCritical int DeregisterCriticalServiceAfter time.Duration OutputMaxSize int acl.EnterpriseMeta `hcl:",squash" mapstructure:",squash"` } func (t *CheckDefinition) UnmarshalJSON(data []byte) (err error) { type Alias CheckDefinition aux := &struct { // Parse special values Interval interface{} Timeout interface{} TTL interface{} DeregisterCriticalServiceAfter interface{} // Translate fields // "args" -> ScriptArgs Args []string `json:"args"` ScriptArgsSnake []string `json:"script_args"` DeregisterCriticalServiceAfterSnake interface{} `json:"deregister_critical_service_after"` DockerContainerIDSnake string `json:"docker_container_id"` TLSServerNameSnake string `json:"tls_server_name"` TLSSkipVerifySnake bool `json:"tls_skip_verify"` TCPUseTLSSnake bool `json:"tcp_use_tls"` GRPCUseTLSSnake bool `json:"grpc_use_tls"` ServiceIDSnake string `json:"service_id"` H2PingUseTLSSnake bool `json:"h2ping_use_tls"` DisableRedirectsSnake bool `json:"disable_redirects"` *Alias }{ Alias: (*Alias)(t), } // Preevaluate struct values to determine where to set defaults if err = lib.UnmarshalJSON(data, &aux); err != nil { return err } // Set defaults if aux.H2PING != "" { aux.H2PingUseTLS = true aux.H2PingUseTLSSnake = true } if err = lib.UnmarshalJSON(data, &aux); err != nil { return err } // Translate Fields if aux.DeregisterCriticalServiceAfter == nil { aux.DeregisterCriticalServiceAfter = aux.DeregisterCriticalServiceAfterSnake } if len(t.ScriptArgs) == 0 { t.ScriptArgs = aux.Args } if len(t.ScriptArgs) == 0 { t.ScriptArgs = aux.ScriptArgsSnake } if t.DockerContainerID == "" { t.DockerContainerID = aux.DockerContainerIDSnake } if t.TLSServerName == "" { t.TLSServerName = aux.TLSServerNameSnake } if aux.TLSSkipVerifySnake { t.TLSSkipVerify = aux.TLSSkipVerifySnake } if aux.TCPUseTLSSnake { t.TCPUseTLS = aux.TCPUseTLSSnake } if aux.GRPCUseTLSSnake { t.GRPCUseTLS = aux.GRPCUseTLSSnake } if t.ServiceID == "" { t.ServiceID = aux.ServiceIDSnake } if aux.DisableRedirectsSnake { t.DisableRedirects = aux.DisableRedirectsSnake } if (aux.H2PING != "" && !aux.H2PingUseTLSSnake) || (aux.H2PING == "" && aux.H2PingUseTLSSnake) { t.H2PingUseTLS = aux.H2PingUseTLSSnake } // Parse special values if aux.Interval != nil { switch v := aux.Interval.(type) { case string: if t.Interval, err = time.ParseDuration(v); err != nil { return err } case float64: t.Interval = time.Duration(v) } } if aux.Timeout != nil { switch v := aux.Timeout.(type) { case string: if t.Timeout, err = time.ParseDuration(v); err != nil { return err } case float64: t.Timeout = time.Duration(v) } } if aux.TTL != nil { switch v := aux.TTL.(type) { case string: if t.TTL, err = time.ParseDuration(v); err != nil { return err } case float64: t.TTL = time.Duration(v) } } if aux.DeregisterCriticalServiceAfter != nil { switch v := aux.DeregisterCriticalServiceAfter.(type) { case string: if t.DeregisterCriticalServiceAfter, err = time.ParseDuration(v); err != nil { return err } case float64: t.DeregisterCriticalServiceAfter = time.Duration(v) } } return nil } func (c *CheckDefinition) HealthCheck(node string) *HealthCheck { health := &HealthCheck{ Node: node, CheckID: c.ID, Name: c.Name, Status: api.HealthCritical, Notes: c.Notes, ServiceID: c.ServiceID, Interval: c.Interval.String(), Timeout: c.Timeout.String(), EnterpriseMeta: c.EnterpriseMeta, } if c.Status != "" { health.Status = c.Status } if health.CheckID == "" && health.Name != "" { health.CheckID = types.CheckID(health.Name) } return health } func (c *CheckDefinition) CheckType() *CheckType { return &CheckType{ CheckID: c.ID, Name: c.Name, Status: c.Status, Notes: c.Notes, ScriptArgs: c.ScriptArgs, AliasNode: c.AliasNode, AliasService: c.AliasService, HTTP: c.HTTP, H2PING: c.H2PING, H2PingUseTLS: c.H2PingUseTLS, GRPC: c.GRPC, GRPCUseTLS: c.GRPCUseTLS, Header: c.Header, Method: c.Method, Body: c.Body, DisableRedirects: c.DisableRedirects, OutputMaxSize: c.OutputMaxSize, TCP: c.TCP, TCPUseTLS: c.TCPUseTLS, UDP: c.UDP, Interval: c.Interval, DockerContainerID: c.DockerContainerID, Shell: c.Shell, OSService: c.OSService, TLSServerName: c.TLSServerName, TLSSkipVerify: c.TLSSkipVerify, Timeout: c.Timeout, TTL: c.TTL, SuccessBeforePassing: c.SuccessBeforePassing, FailuresBeforeWarning: c.FailuresBeforeWarning, FailuresBeforeCritical: c.FailuresBeforeCritical, DeregisterCriticalServiceAfter: c.DeregisterCriticalServiceAfter, } }