1package structs 2 3import ( 4 "fmt" 5 "reflect" 6 "time" 7 8 "github.com/hashicorp/consul/lib" 9 "github.com/hashicorp/consul/types" 10) 11 12type CheckTypes []*CheckType 13 14// CheckType is used to create either the CheckMonitor or the CheckTTL. 15// The following types are supported: Script, HTTP, TCP, Docker, TTL, GRPC, Alias. Script, 16// HTTP, Docker, TCP and GRPC all require Interval. Only one of the types may 17// to be provided: TTL or Script/Interval or HTTP/Interval or TCP/Interval or 18// Docker/Interval or GRPC/Interval or AliasService. 19// Since types like CheckHTTP and CheckGRPC derive from CheckType, there are 20// helper conversion methods that do the reverse conversion. ie. checkHTTP.CheckType() 21type CheckType struct { 22 // fields already embedded in CheckDefinition 23 // Note: CheckType.CheckID == CheckDefinition.ID 24 25 CheckID types.CheckID 26 Name string 27 Status string 28 Notes string 29 30 // fields copied to CheckDefinition 31 // Update CheckDefinition when adding fields here 32 33 ScriptArgs []string 34 HTTP string 35 Header map[string][]string 36 Method string 37 Body string 38 TCP string 39 Interval time.Duration 40 AliasNode string 41 AliasService string 42 DockerContainerID string 43 Shell string 44 GRPC string 45 GRPCUseTLS bool 46 TLSSkipVerify bool 47 Timeout time.Duration 48 TTL time.Duration 49 SuccessBeforePassing int 50 FailuresBeforeCritical int 51 52 // Definition fields used when exposing checks through a proxy 53 ProxyHTTP string 54 ProxyGRPC string 55 56 // DeregisterCriticalServiceAfter, if >0, will cause the associated 57 // service, if any, to be deregistered if this check is critical for 58 // longer than this duration. 59 DeregisterCriticalServiceAfter time.Duration 60 OutputMaxSize int 61} 62 63func (t *CheckType) UnmarshalJSON(data []byte) (err error) { 64 type Alias CheckType 65 aux := &struct { 66 Interval interface{} 67 Timeout interface{} 68 TTL interface{} 69 DeregisterCriticalServiceAfter interface{} 70 71 // Translate fields 72 73 // "args" -> ScriptArgs 74 Args []string `json:"args"` 75 ScriptArgsSnake []string `json:"script_args"` 76 DeregisterCriticalServiceAfterSnake interface{} `json:"deregister_critical_service_after"` 77 DockerContainerIDSnake string `json:"docker_container_id"` 78 TLSSkipVerifySnake bool `json:"tls_skip_verify"` 79 80 // These are going to be ignored but since we are disallowing unknown fields 81 // during parsing we have to be explicit about parsing but not using these. 82 ServiceID string `json:"ServiceID"` 83 ServiceIDSnake string `json:"service_id"` 84 85 *Alias 86 }{ 87 Alias: (*Alias)(t), 88 } 89 if err = lib.UnmarshalJSON(data, aux); err != nil { 90 return err 91 } 92 if aux.DeregisterCriticalServiceAfter == nil { 93 aux.DeregisterCriticalServiceAfter = aux.DeregisterCriticalServiceAfterSnake 94 } 95 if len(t.ScriptArgs) == 0 { 96 t.ScriptArgs = aux.Args 97 } 98 if len(t.ScriptArgs) == 0 { 99 t.ScriptArgs = aux.ScriptArgsSnake 100 } 101 if t.DockerContainerID == "" { 102 t.DockerContainerID = aux.DockerContainerIDSnake 103 } 104 if aux.TLSSkipVerifySnake { 105 t.TLSSkipVerify = aux.TLSSkipVerifySnake 106 } 107 108 if aux.Interval != nil { 109 switch v := aux.Interval.(type) { 110 case string: 111 if t.Interval, err = time.ParseDuration(v); err != nil { 112 return err 113 } 114 case float64: 115 t.Interval = time.Duration(v) 116 } 117 } 118 if aux.Timeout != nil { 119 switch v := aux.Timeout.(type) { 120 case string: 121 if t.Timeout, err = time.ParseDuration(v); err != nil { 122 return err 123 } 124 case float64: 125 t.Timeout = time.Duration(v) 126 } 127 } 128 if aux.TTL != nil { 129 switch v := aux.TTL.(type) { 130 case string: 131 if t.TTL, err = time.ParseDuration(v); err != nil { 132 return err 133 } 134 case float64: 135 t.TTL = time.Duration(v) 136 } 137 } 138 if aux.DeregisterCriticalServiceAfter != nil { 139 switch v := aux.DeregisterCriticalServiceAfter.(type) { 140 case string: 141 if t.DeregisterCriticalServiceAfter, err = time.ParseDuration(v); err != nil { 142 return err 143 } 144 case float64: 145 t.DeregisterCriticalServiceAfter = time.Duration(v) 146 } 147 } 148 149 return nil 150 151} 152 153// Validate returns an error message if the check is invalid 154func (c *CheckType) Validate() error { 155 intervalCheck := c.IsScript() || c.HTTP != "" || c.TCP != "" || c.GRPC != "" 156 157 if c.Interval > 0 && c.TTL > 0 { 158 return fmt.Errorf("Interval and TTL cannot both be specified") 159 } 160 if intervalCheck && c.Interval <= 0 { 161 return fmt.Errorf("Interval must be > 0 for Script, HTTP, or TCP checks") 162 } 163 if intervalCheck && c.IsAlias() { 164 return fmt.Errorf("Interval cannot be set for Alias checks") 165 } 166 if c.IsAlias() && c.TTL > 0 { 167 return fmt.Errorf("TTL must be not be set for Alias checks") 168 } 169 if !intervalCheck && !c.IsAlias() && c.TTL <= 0 { 170 return fmt.Errorf("TTL must be > 0 for TTL checks") 171 } 172 if c.OutputMaxSize < 0 { 173 return fmt.Errorf("MaxOutputMaxSize must be positive") 174 } 175 return nil 176} 177 178// Empty checks if the CheckType has no fields defined. Empty checks parsed from json configs are filtered out 179func (c *CheckType) Empty() bool { 180 return reflect.DeepEqual(c, &CheckType{}) 181} 182 183// IsAlias checks if this is an alias check. 184func (c *CheckType) IsAlias() bool { 185 return c.AliasNode != "" || c.AliasService != "" 186} 187 188// IsScript checks if this is a check that execs some kind of script. 189func (c *CheckType) IsScript() bool { 190 return len(c.ScriptArgs) > 0 191} 192 193// IsTTL checks if this is a TTL type 194func (c *CheckType) IsTTL() bool { 195 return c.TTL > 0 196} 197 198// IsMonitor checks if this is a Monitor type 199func (c *CheckType) IsMonitor() bool { 200 return c.IsScript() && c.DockerContainerID == "" && c.Interval > 0 201} 202 203// IsHTTP checks if this is a HTTP type 204func (c *CheckType) IsHTTP() bool { 205 return c.HTTP != "" && c.Interval > 0 206} 207 208// IsTCP checks if this is a TCP type 209func (c *CheckType) IsTCP() bool { 210 return c.TCP != "" && c.Interval > 0 211} 212 213// IsDocker returns true when checking a docker container. 214func (c *CheckType) IsDocker() bool { 215 return c.IsScript() && c.DockerContainerID != "" && c.Interval > 0 216} 217 218// IsGRPC checks if this is a GRPC type 219func (c *CheckType) IsGRPC() bool { 220 return c.GRPC != "" && c.Interval > 0 221} 222 223func (c *CheckType) Type() string { 224 switch { 225 case c.IsGRPC(): 226 return "grpc" 227 case c.IsHTTP(): 228 return "http" 229 case c.IsTTL(): 230 return "ttl" 231 case c.IsTCP(): 232 return "tcp" 233 case c.IsAlias(): 234 return "alias" 235 case c.IsDocker(): 236 return "docker" 237 case c.IsScript(): 238 return "script" 239 default: 240 return "" 241 } 242} 243