diff --git a/apis/monitoring/v1alpha1/cluster_alert.go b/apis/monitoring/v1alpha1/cluster_alert.go index 02b3d4ae9..663500703 100644 --- a/apis/monitoring/v1alpha1/cluster_alert.go +++ b/apis/monitoring/v1alpha1/cluster_alert.go @@ -102,11 +102,11 @@ func (a ClusterAlert) IsValid(kc kubernetes.Interface) error { if !ok { return fmt.Errorf("'%s' is not a valid cluster check command", a.Spec.Check) } - for k := range a.Spec.Vars { - if _, ok := cmd.Vars[k]; !ok { - return fmt.Errorf("var '%s' is unsupported for check command %s", k, a.Spec.Check) - } + + if err := validateVariables(cmd.Vars, a.Spec.Vars); err != nil { + return err } + for _, rcv := range a.Spec.Receivers { found := false for _, state := range cmd.States { diff --git a/apis/monitoring/v1alpha1/crds.yaml b/apis/monitoring/v1alpha1/crds.yaml index d153429d1..9924718f1 100644 --- a/apis/monitoring/v1alpha1/crds.yaml +++ b/apis/monitoring/v1alpha1/crds.yaml @@ -1782,9 +1782,15 @@ spec: host: type: object vars: - items: - type: string - type: array + properties: + Item: + type: object + required: + items: + type: string + type: array + required: + - Item command: description: Check Command type: string diff --git a/apis/monitoring/v1alpha1/icinga.go b/apis/monitoring/v1alpha1/icinga.go index d86affb63..b9b20595f 100644 --- a/apis/monitoring/v1alpha1/icinga.go +++ b/apis/monitoring/v1alpha1/icinga.go @@ -5,23 +5,19 @@ import ( "sync" "github.com/appscode/go-notify/unified" - "github.com/appscode/go/log" - "github.com/appscode/searchlight/data" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) const ( - CheckPodInfluxQuery = "influx-query" - CheckPodStatus = "pod-status" - CheckPodVolume = "pod-volume" - CheckPodExec = "pod-exec" + CheckPodStatus = "pod-status" + CheckPodVolume = "pod-volume" + CheckPodExec = "pod-exec" ) const ( - CheckNodeInfluxQuery = "influx-query" - CheckNodeVolume = "node-volume" - CheckNodeStatus = "node-status" + CheckNodeVolume = "node-volume" + CheckNodeStatus = "node-status" ) const ( @@ -31,12 +27,6 @@ const ( CheckPodExists = "pod-exists" CheckEvent = "event" CheckCACert = "ca-cert" - CheckHttp = "any-http" - CheckEnv = "env" - CheckDummy = "dummy" - //CheckICMP = "icmp" - //CheckDIG = "dig" - //CheckDNS = "dns" ) // +k8s:deepcopy-gen=false @@ -67,7 +57,7 @@ func (c *Registry) Delete(cmd string) { // +k8s:deepcopy-gen=false type IcingaCommand struct { Name string - Vars map[string]data.CommandVar + Vars *PluginVars States []string } @@ -77,56 +67,6 @@ var ( ClusterCommands = &Registry{reg: map[string]IcingaCommand{}} ) -func init() { - clusterChecks, err := data.LoadClusterChecks() - if err != nil { - log.Fatal(err) - } - for _, cmd := range clusterChecks.Command { - vars := make(map[string]data.CommandVar) - for _, v := range cmd.Vars { - vars[v.Name] = v - } - ClusterCommands.Insert(cmd.Name, IcingaCommand{ - Name: cmd.Name, - Vars: vars, - States: cmd.States, - }) - } - - nodeChecks, err := data.LoadNodeChecks() - if err != nil { - log.Fatal(err) - } - for _, cmd := range nodeChecks.Command { - vars := make(map[string]data.CommandVar) - for _, v := range cmd.Vars { - vars[v.Name] = v - } - NodeCommands.Insert(cmd.Name, IcingaCommand{ - Name: cmd.Name, - Vars: vars, - States: cmd.States, - }) - } - - podChecks, err := data.LoadPodChecks() - if err != nil { - log.Fatal(err) - } - for _, cmd := range podChecks.Command { - vars := make(map[string]data.CommandVar) - for _, v := range cmd.Vars { - vars[v.Name] = v - } - PodCommands.Insert(cmd.Name, IcingaCommand{ - Name: cmd.Name, - Vars: vars, - States: cmd.States, - }) - } -} - func checkNotifiers(kc kubernetes.Interface, alert Alert) error { if alert.GetNotifierSecretName() == "" && len(alert.GetReceivers()) == 0 { return nil diff --git a/apis/monitoring/v1alpha1/node_alert.go b/apis/monitoring/v1alpha1/node_alert.go index bee57b498..552bcb705 100644 --- a/apis/monitoring/v1alpha1/node_alert.go +++ b/apis/monitoring/v1alpha1/node_alert.go @@ -110,11 +110,11 @@ func (a NodeAlert) IsValid(kc kubernetes.Interface) error { if !ok { return fmt.Errorf("%s is not a valid node check command", a.Spec.Check) } - for k := range a.Spec.Vars { - if _, ok := cmd.Vars[k]; !ok { - return fmt.Errorf("var %s is unsupported for check command %s", k, a.Spec.Check) - } + + if err := validateVariables(cmd.Vars, a.Spec.Vars); err != nil { + return err } + for _, rcv := range a.Spec.Receivers { found := false for _, state := range cmd.States { diff --git a/apis/monitoring/v1alpha1/openapi_generated.go b/apis/monitoring/v1alpha1/openapi_generated.go index 21216eb1a..767338959 100644 --- a/apis/monitoring/v1alpha1/openapi_generated.go +++ b/apis/monitoring/v1alpha1/openapi_generated.go @@ -193,14 +193,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA }, "Vars": { SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/appscode/searchlight/data.CommandVar"), - }, - }, - }, + Ref: ref("github.com/appscode/searchlight/apis/monitoring/v1alpha1.PluginVars"), }, }, "States": { @@ -221,7 +214,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA }, }, Dependencies: []string{ - "github.com/appscode/searchlight/data.CommandVar"}, + "github.com/appscode/searchlight/apis/monitoring/v1alpha1.PluginVars"}, }, "github.com/appscode/searchlight/apis/monitoring/v1alpha1.Incident": { Schema: spec.Schema{ @@ -570,8 +563,13 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA Properties: map[string]spec.Schema{ "vars": { SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ + Ref: ref("github.com/appscode/searchlight/apis/monitoring/v1alpha1.PluginVars"), + }, + }, + "host": { + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"string"}, @@ -581,10 +579,54 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA }, }, }, - "host": { + }, + }, + }, + Dependencies: []string{ + "github.com/appscode/searchlight/apis/monitoring/v1alpha1.PluginVars"}, + }, + "github.com/appscode/searchlight/apis/monitoring/v1alpha1.PluginVarItem": { + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Properties: map[string]spec.Schema{ + "description": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "type": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"type"}, + }, + }, + Dependencies: []string{}, + }, + "github.com/appscode/searchlight/apis/monitoring/v1alpha1.PluginVars": { + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Properties: map[string]spec.Schema{ + "Item": { SchemaProps: spec.SchemaProps{ Type: []string{"object"}, AdditionalProperties: &spec.SchemaOrBool{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/appscode/searchlight/apis/monitoring/v1alpha1.PluginVarItem"), + }, + }, + }, + }, + }, + "required": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"string"}, @@ -595,9 +637,11 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA }, }, }, + Required: []string{"Item"}, }, }, - Dependencies: []string{}, + Dependencies: []string{ + "github.com/appscode/searchlight/apis/monitoring/v1alpha1.PluginVarItem"}, }, "github.com/appscode/searchlight/apis/monitoring/v1alpha1.PodAlert": { Schema: spec.Schema{ diff --git a/apis/monitoring/v1alpha1/plugin.go b/apis/monitoring/v1alpha1/plugin.go index 6cee8b1ea..13fddfcbf 100644 --- a/apis/monitoring/v1alpha1/plugin.go +++ b/apis/monitoring/v1alpha1/plugin.go @@ -1,6 +1,10 @@ package v1alpha1 import ( + "fmt" + + "github.com/appscode/kutil/meta" + "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -48,8 +52,28 @@ type WebhookServiceSpec struct { Name string `json:"name"` } +type VarType string + +const ( + VarTypeInteger VarType = "integer" + VarTypeNumber VarType = "number" + VarTypeBoolean VarType = "boolean" + VarTypeString VarType = "string" + VarTypeDuration VarType = "duration" +) + +type PluginVarItem struct { + Description string `json:"description,omitempty"` + Type VarType `json:"type"` +} + +type PluginVars struct { + Items map[string]PluginVarItem `json:"Item"` + Required []string `json:"required,omitempty"` +} + type PluginArguments struct { - Vars []string `json:"vars,omitempty"` + Vars *PluginVars `json:"vars,omitempty"` Host map[string]string `json:"host,omitempty"` } @@ -65,3 +89,48 @@ type SearchlightPluginList struct { // Items is the list of SearchlightPlugin. Items []SearchlightPlugin `json:"items"` } + +var ( + validateVarValue = map[VarType]meta.ParserFunc{} +) + +func registerVarValueParser(key VarType, fn meta.ParserFunc) { + validateVarValue[key] = fn +} + +func init() { + registerVarValueParser(VarTypeInteger, meta.GetInt) + registerVarValueParser(VarTypeNumber, meta.GetFloat) + registerVarValueParser(VarTypeBoolean, meta.GetBool) + registerVarValueParser(VarTypeString, meta.GetString) + registerVarValueParser(VarTypeDuration, meta.GetDuration) +} + +func validateVariables(pluginVars *PluginVars, vars map[string]string) error { + if pluginVars == nil { + return nil + } + // Check if any invalid variable is provided + var err error + for k := range vars { + p, found := pluginVars.Items[k] + if !found { + return fmt.Errorf("var '%s' is unsupported", k) + } + + fn, found := validateVarValue[p.Type] + if !found { + return errors.Errorf(`type "%v" is not registered`, p.Type) + } + if _, err = fn(vars, k); err != nil { + return errors.Wrapf(err, `validation failure: variable "%s" must be of type %v`, k, p.Type) + } + } + for _, k := range pluginVars.Required { + if _, ok := vars[k]; !ok { + return fmt.Errorf("plugin variable '%s' is required", k) + } + } + + return nil +} diff --git a/apis/monitoring/v1alpha1/pod_alert.go b/apis/monitoring/v1alpha1/pod_alert.go index a9d0aa8c5..afec42035 100644 --- a/apis/monitoring/v1alpha1/pod_alert.go +++ b/apis/monitoring/v1alpha1/pod_alert.go @@ -119,11 +119,11 @@ func (a PodAlert) IsValid(kc kubernetes.Interface) error { if !ok { return fmt.Errorf("%s is not a valid pod check command", a.Spec.Check) } - for k := range a.Spec.Vars { - if _, ok := cmd.Vars[k]; !ok { - return fmt.Errorf("var %s is unsupported for check command %s", k, a.Spec.Check) - } + + if err := validateVariables(cmd.Vars, a.Spec.Vars); err != nil { + return err } + for _, rcv := range a.Spec.Receivers { found := false for _, state := range cmd.States { diff --git a/apis/monitoring/v1alpha1/zz_generated.deepcopy.go b/apis/monitoring/v1alpha1/zz_generated.deepcopy.go index 3fff2f826..618fb563f 100644 --- a/apis/monitoring/v1alpha1/zz_generated.deepcopy.go +++ b/apis/monitoring/v1alpha1/zz_generated.deepcopy.go @@ -355,8 +355,12 @@ func (in *PluginArguments) DeepCopyInto(out *PluginArguments) { *out = *in if in.Vars != nil { in, out := &in.Vars, &out.Vars - *out = make([]string, len(*in)) - copy(*out, *in) + if *in == nil { + *out = nil + } else { + *out = new(PluginVars) + (*in).DeepCopyInto(*out) + } } if in.Host != nil { in, out := &in.Host, &out.Host @@ -378,6 +382,50 @@ func (in *PluginArguments) DeepCopy() *PluginArguments { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginVarItem) DeepCopyInto(out *PluginVarItem) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginVarItem. +func (in *PluginVarItem) DeepCopy() *PluginVarItem { + if in == nil { + return nil + } + out := new(PluginVarItem) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginVars) DeepCopyInto(out *PluginVars) { + *out = *in + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make(map[string]PluginVarItem, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Required != nil { + in, out := &in.Required, &out.Required + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginVars. +func (in *PluginVars) DeepCopy() *PluginVars { + if in == nil { + return nil + } + out := new(PluginVars) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PodAlert) DeepCopyInto(out *PodAlert) { *out = *in diff --git a/data/README.md b/data/README.md deleted file mode 100644 index 0717074ef..000000000 --- a/data/README.md +++ /dev/null @@ -1,3 +0,0 @@ -[Website](https://appscode.com) • [Slack](https://appscode.slack.com) • [Twitter](https://twitter.com/AppsCodeHQ) - -Searchlight by AppsCode is a Kubernetes operator for [Icinga](https://www.icinga.com/). If you are running production workloads in Kubernetes, you probably want to be alerted when things go wrong. Icinga periodically runs various checks on a Kubernetes cluster and sends notifications if detects an issue. It also nicely supplements whitebox monitoring tools like, [Prometheus](https://prometheus.io/) with blackbox monitoring can catch problems that are otherwise invisible, and also serves as a fallback in case internal systems completely fail. Searchlight is a CRD controller for Kubernetes built around Icinga to address these issues. This package contains static data files used by Searchlight. diff --git a/data/files/bindata.go b/data/files/bindata.go deleted file mode 100644 index e53a20aa9..000000000 --- a/data/files/bindata.go +++ /dev/null @@ -1,304 +0,0 @@ -// Code generated by go-bindata. -// sources: -// cluster_checks.json -// icinga.gen.json -// node_checks.json -// pod_checks.json -// DO NOT EDIT! - -package files - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data []byte, name string) ([]byte, error) { - gz, err := gzip.NewReader(bytes.NewBuffer(data)) - if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -func (fi bindataFileInfo) Name() string { - return fi.name -} -func (fi bindataFileInfo) Size() int64 { - return fi.size -} -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} -func (fi bindataFileInfo) IsDir() bool { - return false -} -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -var _cluster_checksJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5c\x5d\x53\xe3\x38\xb3\xbe\x9f\x5f\xd1\xaf\x6f\x02\x55\x21\xcc\x0e\x53\x5b\xa7\xa8\xe2\x82\x85\x9c\x9d\x2c\x0c\xe4\x90\x70\xf6\x62\xa0\x18\xc5\xea\xc4\x9a\xc8\x92\x57\x92\x13\x32\x53\xfb\xdf\xdf\x92\x6c\x87\x38\x89\x83\x3d\x43\x3e\xa8\xe2\x86\x22\x91\xd4\x6a\x3d\x6e\x3d\xdd\x2d\xb5\xf3\xe3\x1d\x80\xe7\x07\xe8\x0f\x1f\x7c\x19\x86\x44\x50\xef\x18\xbe\xbc\x03\x00\xf8\xe1\xfe\x02\x78\x14\xb5\xaf\x58\x64\x98\x14\xde\x31\x78\xdd\x80\x69\x60\x1a\x62\x8d\x14\x8c\x04\x37\x1a\x2e\xe2\x1e\x2a\x81\x06\x35\xf8\x32\x8c\xa4\x40\x61\xb4\x57\xcf\x64\xe0\x23\x09\x23\x8e\xda\x0a\x08\x26\x11\x2a\xc2\x51\x19\x98\xce\x9c\x0c\x78\xd0\x86\x98\x78\x66\x98\x20\x21\xda\x21\xc5\x3d\x50\x8c\xf4\x54\x65\xf7\x8d\x14\xd8\x93\x8f\xd3\x1e\x00\x5e\xa4\x24\x9d\xfd\xfc\x0f\x99\xfd\x44\x71\xe4\xa5\x9f\xee\xa7\x62\x47\x44\xe5\xc5\xfe\x98\xfe\xb7\x88\x48\x07\x39\xfa\x46\x2a\xd8\xe3\xa4\x87\x1c\xfe\x89\x51\x4d\xf6\x2d\x36\x7d\xc6\x0d\x2a\x90\xa2\x0e\x3a\x8e\x22\xa9\x8c\x86\xda\x49\xad\x0e\xb5\x13\xfb\x97\x08\x0a\xb5\xff\x9c\xd4\x1a\x33\xfa\x00\x78\x7d\x4e\x06\xde\x71\x6e\x4a\x00\x4f\x07\x52\x19\x3b\x1d\xcf\xf5\x06\xf0\xb8\x14\xb6\xbf\xa7\x53\x3d\xbc\x99\xe6\x7f\x73\x92\x33\x3c\xa7\x3d\x73\xad\x66\x12\xb9\xd6\x4e\xf7\xa6\x75\xf5\x67\xbe\x2d\x22\x8a\x84\x68\x50\xb1\xef\x68\x6d\xa4\x4f\xb8\xc6\x5c\x8f\x11\xd3\xac\xc7\x38\x33\x13\xef\x18\x8c\x8a\xf3\xad\xd2\xa1\x45\x78\xda\xf6\x6e\x89\x7e\xab\x20\xbe\x22\x21\x82\xec\x3f\xd9\x16\x8c\x03\xa9\x11\x12\x73\xb0\xe6\xe8\x4c\x09\x69\x19\x24\x33\xbc\xa6\xc2\xac\xf4\xe7\x41\xcb\x77\xdf\x3e\x72\xf3\x46\x0b\x9e\x45\x03\xf3\x76\x0b\xde\xf5\xc5\xac\x3e\xde\x99\x62\x86\xf9\x24\x67\x44\xde\xad\x18\x0a\x39\x16\x53\x0c\xee\xdf\xcd\xe2\x50\x8d\x09\x88\x98\xc0\x69\xbb\x05\x0a\x75\x24\x85\x46\x88\x88\xd2\x4c\x0c\xe0\xaf\xce\xf5\x15\xc4\xc9\xbf\xff\xe7\x36\x09\xc3\xb2\x14\xf1\x4d\x4b\xf1\x10\x11\x13\xc0\xc1\x41\xac\xf8\x49\x2d\x30\x26\xd2\xc7\x87\x87\x24\x62\x0d\x12\x45\xda\x97\x14\x1b\xbe\x0c\x0f\x03\x24\xdc\x04\x35\x38\x38\xf0\xd3\x95\x9e\xd4\x7e\x34\x12\x3b\xf9\x17\xfe\x73\x02\xd7\x17\xb5\x45\x82\x99\xca\xdf\x2d\x66\xb9\xbd\xb9\xb4\xc0\x0e\xd0\x00\x25\x86\x54\xa2\x89\xb8\x88\x26\x62\xc5\x9f\x37\x76\xdb\x69\xfb\x26\x5e\x8e\x1c\x66\x7c\x8f\x46\x5f\xa1\x01\xb1\xb0\x43\x9f\x01\x4b\x17\x73\xaa\x15\x58\x8e\x20\x66\xfa\xae\x0b\xba\xc5\xe6\x5f\xc4\xee\x6f\xa2\x84\xdd\x91\x76\x03\xb8\xfd\xe5\x9c\x17\x8c\x03\xe6\x07\xa0\xd0\xc4\x4a\x68\xf8\x62\x25\x1f\xba\xb9\xef\x2b\xc1\x3a\x2e\x82\x75\x9c\x4c\xfb\x3c\xa6\x59\xc7\xd7\x62\x8b\x19\xbd\xae\x09\x50\xbf\x08\xd0\x8c\xec\x4a\xb8\xb1\x25\x0e\x60\x63\x90\xba\xa1\xc5\x2e\x6c\x99\x07\xcb\x3b\xb0\xcc\x60\x67\xbf\x5a\xe2\xd2\xe6\x3d\x5a\xe2\xd0\x7e\xca\x9f\x19\x69\x08\x07\x11\x87\x3d\x1b\xc9\xf5\x67\x23\x5d\x21\x29\x96\x74\x60\xb6\xeb\x03\x3e\x32\x6d\xb4\x75\x4d\x32\x16\xe6\xe4\x68\xd1\x0f\xcd\x74\xdb\x2d\x4f\x74\x35\x5d\x3f\x3e\x46\xe8\x1b\xa4\xb3\x40\x5c\xcd\x02\x01\xbf\x64\xc7\x16\x99\x32\xb1\x98\xed\xb6\xd4\x82\x5b\x57\xdd\xe6\x9f\xcd\x9b\x4d\x99\x70\x39\x5a\x78\x4b\x11\x36\x96\x22\xd8\x2d\x94\x66\x07\x6e\x23\xa1\xf0\xb1\x62\x82\x30\xc5\x51\x14\xe1\x68\x27\x29\x17\x14\x4c\x7b\x6e\x1f\xc7\x9f\x60\xdb\xf5\x52\xeb\x0c\x83\x44\x92\x3e\x3d\xae\x45\x5e\x8c\x24\x7d\x85\xb4\xd8\x96\xd5\xcc\xed\x15\xb3\xe2\xcf\xec\xd8\x37\x52\xdc\x18\x29\xda\xed\xf5\x42\x9c\x18\x15\xc1\x18\x49\x5a\x8e\x12\xb3\x8e\xdb\x07\x71\x97\x19\x11\x47\x28\x8c\x6e\x80\xeb\x18\xf1\x78\xc0\x44\xd2\x49\x43\x5f\x2a\x20\x9c\x43\x96\xbc\x25\x5d\x21\x20\x51\x84\x02\x29\x30\x01\x9c\x68\x03\x35\xbf\x66\x33\x62\x29\xa8\x6e\x40\xcb\x67\x62\x40\xd2\x70\x94\x09\x83\x6a\x44\xb8\xd5\x20\x52\x72\xc4\x28\x52\x20\xda\x8e\x68\x2c\xb2\xaf\x93\xbf\x5b\xc4\x7b\xc6\xa5\x3f\x04\x3d\xc4\xb1\x5d\xed\x79\xac\x88\x6d\x69\xc0\x97\x73\xec\x93\x98\x9b\x63\x38\x7a\xaf\xef\x53\xf4\x0c\x0b\x9d\xb9\x13\x6a\x97\x39\x66\x26\x98\x87\x61\x1c\x30\x8e\xc9\x97\x4f\x80\xbe\xcc\x09\x82\x6f\x35\xed\x0c\x71\x5c\x82\xbf\xa7\x5d\xb7\xbf\x35\xaa\xf1\x8b\xec\x7d\x43\xdf\x00\x13\x23\xc9\x47\x89\x05\x12\x01\x79\xbb\x59\x81\x62\x86\x55\x36\xfe\xda\x89\x2b\xc7\x26\x4b\xc6\xbc\x26\xf4\x74\x44\xfc\xf5\x42\xe8\x66\xf8\x19\x1c\x93\x81\xaf\x05\xcc\x0b\x26\xe8\xda\x70\xb4\xc2\xab\x42\xe8\xc6\xbc\x16\xf4\x6e\x5b\xe7\x6b\x03\xef\xb6\x75\x5e\x15\x3b\x3b\x64\xfb\xd0\xfd\x44\x78\xb0\xe4\x78\x6a\x2d\xd1\x01\x89\x18\x68\x54\x23\x54\x70\x76\x0a\x67\xa8\x0c\xeb\x33\x9f\x18\x1b\xe0\x45\x2c\xf1\x86\x40\x89\x29\x7b\x3e\xe5\x93\x07\x1f\x95\x59\x72\xf5\x3a\xdf\xb0\x0b\xde\x3f\x0b\x7c\x38\x8e\x90\xc3\x88\xf0\x18\x61\x2f\xd6\x64\x80\x40\xe3\x6c\xf1\x49\x20\xa0\x2d\x7c\x47\xbf\xbf\x0f\xf6\xdf\x4e\xae\xcb\x9d\x5c\x97\x05\xf5\xb7\x0f\x55\x41\x7d\xed\xa7\xd7\xeb\x60\x87\x75\xe5\x13\x06\xb5\x81\x11\x51\x4c\xc6\x1a\xb4\x89\xfb\xfd\x25\x71\xbd\x18\xad\x7d\x5f\xef\x14\x28\x09\x8d\xae\x60\xcb\xf4\x7e\xba\xe3\x6e\xf2\xca\x52\xe7\x72\xde\xdc\x39\xd2\x7c\x3b\x6e\xd9\x58\x3a\x64\x02\x4c\x6d\x08\xc6\x01\x2a\x04\x7f\xc6\xe4\x98\xdd\x8f\x52\x55\x3c\x76\x79\x2d\x37\xd4\x2f\xee\x96\x64\x18\x12\xd0\x68\xd5\x30\x48\x33\x58\x87\x38\xa9\x96\x9f\x0f\x57\xe3\x77\x81\x93\xb2\xf0\xd9\xae\xaf\x05\xbd\xb7\x40\xe9\x2d\x50\xda\x3a\xac\xbb\x1d\x13\xbc\x05\x4a\x0e\x14\x84\x2f\x49\x38\x43\xe3\x30\x9c\xdc\xef\x65\x05\x76\xe3\xf1\xb8\x11\x4a\xc1\x8c\x54\x4c\x0c\x0e\x92\x83\x68\xdd\x90\x6a\x70\x48\xa5\x7f\x18\x12\x71\x38\x33\xae\x11\x98\x90\xef\x67\xc7\xd5\x63\xc6\x39\x68\x16\x46\x7c\x92\x96\xbe\x38\xcf\xe8\x56\x0a\xbe\x54\x49\x89\x20\xb5\x04\x65\x1f\x44\x80\x20\xe2\x10\x15\xf3\xd3\x4d\x95\x7a\xd2\xaf\x4e\xb4\x2b\xfd\xc5\xaf\x40\xd4\x20\x0e\x5d\x05\x28\x33\x01\x64\x46\x07\x06\x1f\xcd\x92\xa3\x6b\x37\x74\xb7\xe2\xb0\x6e\x06\x41\x03\xce\x88\x80\x1e\x82\x14\x6e\xad\xef\x61\x4f\x0e\xf7\xeb\xf0\x1b\xec\xa5\x9c\xb8\x5f\x87\x0f\xb0\x97\x6d\xe5\x7d\x17\x89\x1d\xc1\x5e\x9c\x3c\xe1\xfd\x06\x9c\xcf\xd0\xcc\xfb\xb9\xf8\x2c\x07\x41\x82\x9e\xf7\x92\x3c\xd8\x4e\x1e\xb2\x8c\x4d\x14\x9b\xbc\x2a\x77\xde\x99\x8b\xb4\xc7\x44\x83\x8e\x7d\x1f\xb5\xee\xc7\xbc\x71\xe7\xad\x54\xd1\x3e\xc2\x92\x1a\x56\xb1\xed\xcf\x92\xb2\x3e\x43\x0a\xb9\x3a\x77\xf8\x62\x2d\xfc\x3e\x8d\xcf\x62\x8d\x0a\x7c\x22\xb2\xcb\x10\xf0\x63\x6d\x64\x08\xb6\xcf\x03\xa1\x54\xa1\x5e\x52\x96\x4e\xc4\xe4\xc1\xf6\xd8\x3d\xfb\x0a\xa4\x36\x35\x77\xe1\x61\x35\x9f\x3e\x1c\xc0\x30\x32\x93\xe5\xcf\xc0\x2e\xe4\x74\x6e\xa5\xf0\x9c\xcf\xf8\x45\x13\xb2\xaa\x8e\x98\x32\x31\xe1\x4e\x65\x30\x01\x31\xa0\x03\x19\x73\x6a\x37\x86\xb6\xfb\x9c\x25\xac\x71\xe7\x7d\x92\xda\xdc\x79\x10\x20\xa1\xa8\x0a\x2c\xc9\xae\xe2\xff\xad\xa8\x8d\xae\x41\xe1\x3f\xb1\x75\x23\xb7\x37\x2d\x77\x39\xf7\x67\xb3\x0b\x52\x41\xfb\xba\xd3\xcd\x6f\x8c\xaf\x87\x5f\x57\x28\x7e\x7b\xd3\xda\xa8\xda\xdd\xb3\x36\xd8\x6c\x2f\xaf\xe3\xff\xbc\xb7\x9b\x42\x80\x90\x26\x4b\x87\x3b\x97\x75\xf8\xf8\xf1\x08\xa4\x09\x50\x8d\x99\xc6\x52\xa9\xe0\xd3\xc5\xb0\x32\xf3\x01\xcd\xcc\x75\xf2\xb3\xa1\x8c\x85\xa6\x3d\x2f\x63\x7e\xfd\x4b\x71\xcb\xaa\x1e\x2a\x87\xcd\x01\xda\x95\x5a\x34\x62\x8d\x76\xfd\x79\x88\x5c\x68\x54\x09\x03\xad\x17\xf2\xe1\x29\x04\x9d\x72\x10\x74\x3a\x97\xd5\x11\x48\x2d\xe7\x17\x00\xe8\x4b\xe5\x23\x74\x2f\x3b\xa3\xdf\xb6\xb0\xe2\xff\xb5\xb3\xbb\xc9\xb7\xbd\xf6\xed\xae\xfe\x61\xeb\xeb\xff\xb0\xdd\xf5\x7f\xd8\xde\xfa\x3b\x9d\xcb\xd1\xd6\x56\xef\x26\xdf\xee\xda\x8f\xb6\xb9\xf6\xa3\x2d\xdb\xbd\xf5\xe3\x01\x1b\x04\x0b\x11\xc7\x86\xed\x5f\xaa\x87\x44\x8d\x6d\xf3\xc0\xce\x20\xb2\x43\x98\x7c\xd8\x15\x4c\x3e\xec\x02\x26\x8e\xb2\xb6\x8f\x88\x53\x63\x57\xf0\x38\xda\x0d\x3c\x8e\xb6\x8b\x87\x0b\xa6\xaf\x5a\xcf\x07\xd3\x39\xfd\xaf\x5a\x2f\x9a\xf9\x9c\x52\x0a\x35\x9b\xf0\xdb\x49\x8e\x23\xa2\xf5\x58\x2a\x5a\x03\x12\x9b\x40\x2a\xf6\x3d\x39\xc0\x8d\x08\x5b\x95\x63\x9e\xc6\x26\x68\x13\xb6\x1a\xc5\xf5\x69\xe6\xb2\xcc\x48\xc9\xc7\xc9\x0a\x1d\xdb\xb6\x7d\x2d\x8a\x9e\x4b\x51\x33\x40\xe5\x58\x70\x49\xa8\x4b\xcf\x7b\x92\x4e\xea\xf0\x2d\x76\x49\x3c\xa6\x49\xba\x5e\xa1\x5d\x6b\x20\xa4\xc2\x3f\x24\x9d\xbc\x2c\x86\x9c\xcb\x31\x28\x1c\xe0\xa3\x35\x2e\x1d\x11\x01\x02\xc7\x9c\x89\x55\x36\x76\xc9\x04\xda\xae\x2f\xab\x8a\x55\x23\xe6\x44\x01\x3e\x46\x0a\xb5\xb6\x4f\x2f\x79\x11\x30\x43\x0c\x42\x0b\x58\x48\x8c\x1f\x00\x19\x10\x26\xb4\x69\x40\x4b\xf8\x32\x8c\x88\x61\x3d\x8e\xc9\x29\x67\x1e\xaf\x4a\x04\x92\xbc\x97\x50\xc8\x21\x25\x2e\x0d\xed\xe4\x4d\x27\xc5\x4e\x7e\x63\x91\xdd\x18\x77\x9c\x82\x4f\x34\x1e\x30\xa1\x51\x68\x66\xd8\x08\xb7\x8a\xa5\xc2\x01\x2b\x84\xf2\xa6\x2a\x94\xcd\x05\x71\xeb\x84\xf2\x2c\x20\x62\x80\x1a\x7a\x18\x90\x11\x93\xb1\x7b\x6b\x65\xc9\xb3\x75\x87\xcc\x4b\x14\xb5\xbb\x29\x3d\xc4\x9f\xde\x80\xb1\x3e\xf4\x65\x2c\x68\x1d\xae\x2f\xec\x07\x21\xcd\xaa\x1d\x2f\x46\xa8\x8c\x7a\xd6\x80\xaa\xae\xac\x1b\x20\xa4\x07\xe6\x60\x02\x85\x3a\x90\x9c\xae\xd0\xe3\x6f\xa2\x44\x97\xcd\xdf\x81\xbf\x80\x12\xd9\x41\x7d\xa1\x16\xcf\xfc\x1e\xc5\xb2\x2b\xbb\xfc\xb5\x60\x29\x0b\xcb\x1e\xcf\xb3\x6b\x5c\x6a\x5e\xe7\xd7\xb7\x7f\x5c\x36\xab\x9b\x97\x0c\x43\x72\x40\x91\xb3\x90\x19\xa4\xc0\x99\x36\xd6\xc2\xb4\x51\x4c\x0c\x74\x1d\x88\x01\x8e\xc4\x7e\x29\xb2\x9b\x9d\x10\x98\x7e\x7a\x71\x2a\x3d\xe7\xed\x33\xa5\x0d\xec\x25\xbf\xd8\xb0\x0f\x96\xb8\xb3\x8b\xa0\xb4\xe0\x31\xfb\x65\x89\x69\x18\x71\x0c\x9f\xba\xdd\xf6\x61\xb5\x13\x9a\x97\x24\xc6\x8d\x6d\xe2\xcf\x4c\xb0\x30\x0e\x67\x5e\x47\xa6\x64\xa2\x81\xe4\x0a\x4c\x02\xe2\xe2\xaa\x1e\xc2\x88\x70\x46\xb3\x57\x48\xb2\xeb\x5d\x8b\x38\x67\x3e\x33\xc8\x27\xa0\xd1\x06\x61\x01\xba\x73\x60\x3b\xea\xe3\xc7\x23\xc7\x00\xcc\x51\x64\xd2\x76\x7b\x73\x69\x77\xb7\x0d\x48\xb0\xa2\x49\x3f\xa9\x55\x88\xf4\x59\x49\xab\x2e\x10\xb5\xd6\x83\xe0\xac\xa0\xa7\xef\x5e\x0f\x91\xc2\x58\xb7\xe2\x30\xf1\x39\x43\x61\x72\xb8\xef\xb5\x9b\x9f\x6d\x60\x16\x12\xb3\x5f\x0d\x25\x27\xeb\x20\x57\x32\x36\x8f\xd2\x5f\x25\x51\x72\xa2\x16\x24\xad\xd3\x26\x8b\x31\x8a\x14\x1b\x59\x60\x86\x38\xf9\x79\x70\x52\x21\x07\xc3\xb9\xb2\x9b\x59\x70\x2e\x4a\x5e\x22\x24\xa2\xe6\x25\xad\x13\x9c\x8e\xa3\x3f\xbb\xb1\x12\xbe\xc9\x58\x6e\xfa\xeb\x38\xcb\x03\xe5\xd5\x90\x24\x63\x0a\xd1\x18\x96\x43\xe3\x53\x32\xb3\x53\x70\xeb\x78\x58\xbb\x41\x31\x1f\x3d\x3c\x93\x1b\x2f\xaa\x9e\xaf\x98\x2b\x97\x1e\x6f\x16\x00\xcb\xa5\x28\x7c\x49\x31\x89\xb2\xdc\x25\xa1\xfb\x75\x9f\x8a\x77\x6a\xba\x98\x2b\xda\x65\xef\xd4\xe6\xaf\x49\xd7\xf9\xe0\xd1\x24\xeb\x0d\xd1\x04\x92\xc2\x9e\xcd\x60\xd3\xba\xda\x63\xf8\xd4\x3c\x3d\xaf\xc3\x75\xbb\xdb\xba\xbe\xea\xd4\xa1\x7b\x73\x7a\xd6\xac\x43\xfb\xb6\x5b\x87\xf3\xe6\x65\xb3\xdb\xac\xc6\x19\xc9\x1c\x85\xf8\x7c\x2b\x87\xcf\xe7\x45\x29\x6b\x3d\x27\x21\x4a\x58\x37\x4b\xa5\x9f\x14\xb8\x30\x0d\xa1\x54\x08\x26\x20\x22\x7b\x8f\x13\xaa\x06\x95\x21\x79\x3c\x20\x83\x62\xef\xfb\xb9\x24\x16\xe4\x71\x5e\xca\x5a\x1d\x6f\x27\x42\x9f\xf5\x27\x70\x96\xf0\xc2\x41\x77\x12\x65\x5c\x99\xdc\x4e\xdb\x6d\xc3\xc4\xa0\x9a\x9f\x4d\x85\x39\xe5\x8a\x00\xe9\x96\x74\xb4\x89\xac\x05\x51\x9b\x21\xcf\x99\xda\x08\xb7\xa9\x52\x64\x88\x86\x5b\x8d\x0a\x4e\x07\x55\xb9\x34\xd6\xa8\xc8\x60\xfe\x35\xaf\x59\x5c\x4e\xcb\xe1\x72\xbb\x54\xd0\x5a\xcf\x08\xc4\x24\x29\x4c\x00\x43\x06\xba\x18\x9d\xad\xb9\xd8\x8d\x21\xd1\x56\x4c\x18\x20\x94\xb2\xb4\x28\x2e\x42\xd5\x77\xae\xa5\xd2\x81\x6b\xf3\xd1\xa0\xa0\x48\xb3\xd1\x2f\x9a\x27\x7f\x92\x63\xab\x43\x40\x04\xe5\x36\x0c\xa2\x4c\xd9\x30\x20\x22\x03\xd4\x0d\x68\x4b\xad\xdd\x51\x8d\x2b\x00\xd4\xc7\x70\xe7\xc9\xe1\x9d\x07\x7b\x69\x3d\xed\x7e\x1d\xee\xb2\x82\xe1\x3b\xcf\x7e\xc8\x92\xe6\xe4\x53\x5f\x72\x2e\xc7\xc9\xff\xda\x30\x7f\x38\xb1\x83\x39\x1b\x22\x24\x4d\xd0\x8b\x0d\xb8\x16\xab\x45\x5a\x1f\xb5\xff\xd4\xdd\xa6\x41\xd3\x21\xc9\x57\x6e\x08\xe1\x5a\xda\x11\xb6\xbd\x54\x2d\x6f\x66\x48\x52\x64\x6b\x2c\x34\xa6\x7e\xb1\x31\x25\x01\xb3\xcb\x47\x45\x1c\x16\x3f\xb2\xeb\xe5\xb3\x54\x31\xb6\x5c\x5b\x02\x7f\xfe\x97\x24\x9d\xbc\x85\x32\xfa\x65\xd5\xdb\x50\x7c\x96\x91\x3c\x85\x05\x28\x1c\xd0\xcb\xbf\x75\xd5\x43\x33\x0d\xf7\x55\x2d\x2e\xcb\x99\xad\x89\x81\x66\xdf\x93\x72\x2d\xa6\x90\x1e\x7f\x26\x8f\x05\x4d\xd5\x82\x31\x6b\xbc\xec\x7b\xb1\x4f\x09\x4b\x06\x64\xcb\xe4\xac\x37\x28\x4b\x82\x8a\x1e\xf6\x6d\xa0\xe1\x4b\x21\xd0\x77\x97\x0c\x86\x85\xa8\x41\xc6\xd5\xbc\x88\x1d\x25\xe3\x62\x4b\x2f\xf1\x1b\x36\x16\x87\xee\x12\x31\x6b\x8d\x36\x6e\x35\x42\xab\x3d\xfa\x38\x83\x40\x35\xca\xb4\x83\x5f\x94\x26\x53\x8d\x7e\xff\x15\x8d\x7e\x2f\xa9\x51\xfa\x5f\x5a\x4c\xfb\xce\xfe\xf7\xef\xbb\xff\x06\x00\x00\xff\xff\xb4\xca\xdb\xda\x1a\x5a\x00\x00") - -func cluster_checksJsonBytes() ([]byte, error) { - return bindataRead( - _cluster_checksJson, - "cluster_checks.json", - ) -} - -func cluster_checksJson() (*asset, error) { - bytes, err := cluster_checksJsonBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "cluster_checks.json", size: 23066, mode: os.FileMode(420), modTime: time.Unix(1453795200, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _icingaGenJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\x6b\x77\xdb\xb8\xb5\x37\xfe\xbe\x9f\x62\x2f\xaf\x4e\x6d\x9f\x47\x92\x2f\x49\xe6\xe9\x64\xda\xb3\x1e\xc7\x76\x26\x3e\xe3\x5b\x2d\x65\xa6\x3d\x75\xff\x36\x4c\x42\x12\xc6\x24\xc0\x00\xa0\x15\xf5\xac\xf3\xdd\xff\x0b\x1b\xa0\x44\x49\x24\x25\x4a\xa4\x6c\x4f\xd4\x17\x1d\x87\x22\x80\x8d\x1f\xc0\x8d\x8d\x7d\xfd\x9f\x3f\x00\x6c\x45\x41\xdc\x63\x7c\xeb\x3d\xfc\xf3\x0f\x00\x00\xff\x83\xff\x0f\xb0\xe5\x53\xe5\x49\x16\x69\x26\xcc\x8f\x5b\x9d\x3e\x85\x7f\x7a\x7d\xea\x3d\xde\x3d\x48\x4a\xff\x4d\xff\xb5\xd3\xd7\x3a\x52\xef\xf7\xf6\x06\x83\x41\x2b\x14\x9c\x69\x21\x19\xef\x35\x6d\x87\xaa\x25\x64\x6f\xcf\x17\xde\x5e\x48\xf8\x5e\xba\x61\xab\xaf\xc3\x60\x17\xec\x6b\x20\x69\x24\xa4\x56\xa0\xfb\x14\x14\xeb\x71\x12\x80\xd2\x92\xf2\x9e\xee\x83\xe8\x02\x81\x0f\xd8\xc8\x13\x21\x0c\x98\xa4\x01\x55\x0a\xe8\x97\x98\x45\x21\xe5\xba\xb5\xd5\x48\xc8\xe5\x24\xa4\x86\x4e\x3b\xc6\xf8\xf9\x13\x91\x6a\x34\xb9\xf4\x04\xb3\x26\x79\x63\x7a\x96\xd4\x87\x4b\x12\x52\x10\x12\xce\xae\x81\xf8\xbe\x34\x83\x8a\x2e\xf4\x85\xd2\xa0\x05\xe0\x6c\x5a\x70\x42\xbb\x24\x0e\x0c\xed\x02\x6e\xb7\xfe\xe8\x5e\xfc\xe3\xed\x16\xb0\x2e\xce\xc7\xbc\xbf\xad\xe0\xde\xfd\x72\x0f\x44\x6b\xc9\x1e\x62\x4d\x81\x29\x50\x54\x37\x52\xed\xbe\x37\x0d\x85\xee\x53\x39\x60\x8a\x8e\x67\x86\x74\x76\x03\xd2\xdb\x7a\x3f\x41\x3b\xc0\x56\x20\xb8\x79\xba\x65\xc6\xc1\xf9\x37\x26\x7f\x57\x7d\x21\xb5\x79\xe1\xd3\x56\xea\x87\xff\x9d\xec\x59\xc8\x90\xd8\x97\xae\xda\x9d\xc9\x51\x27\x31\xbd\xcb\x1c\x66\x4b\x20\x7a\x24\xd8\x7a\x0f\x5d\x12\x28\x3a\xf1\xa3\x1e\x46\xd8\x43\xbb\x73\x73\x76\xf9\xd3\x98\x8a\x14\x0d\x45\xeb\xd1\xbe\xbc\xb8\x7e\x3a\x00\x4f\x84\x61\xcc\x99\x1e\x4e\x63\x1e\xc5\x0f\x01\xf3\x6e\xb7\x4a\xa1\x35\xea\x2d\x17\xae\xe3\x45\xe0\xca\xee\x66\x1a\xb3\x9c\xb7\x52\xa0\x69\x19\x57\x8a\xd9\x68\x0f\x5f\x53\xe9\x51\xae\x49\x8f\x8e\xbf\xa8\x07\x1a\x88\x01\x0c\xfa\xcc\xeb\x03\x81\x5f\x89\xe4\x8c\xf7\x40\x69\xa2\x63\x05\x03\x16\x04\x20\xa9\x8a\x03\x3d\x09\xf4\xbb\xfd\x52\x00\x0f\x6c\xb7\xb9\xf0\x0e\xf2\xe1\x9d\x42\x2f\xab\xa7\xc5\x36\xdc\xd9\x65\xe7\xf4\xa7\xd3\x9b\x97\x80\xde\x61\x39\xf4\x3c\xc9\x34\xf3\x48\x90\x0b\x9f\xb7\x30\x7c\x99\x5d\x2d\x8b\x9f\xfb\xeb\x5f\x7f\x48\x0d\xbb\xc8\x61\x31\xbc\x53\xaa\xbf\xcc\x61\x81\x0d\x27\x0f\x8b\x58\x51\x05\xed\xf6\x27\x03\x2b\xfd\x4a\x3d\xc3\x49\xcd\x17\x46\xb8\xaf\x40\x70\x20\x20\x69\x28\xb4\xe5\xbc\xa9\xc3\x81\x7e\x25\x61\x14\x50\x73\x10\x6c\xfd\x11\xd2\xfd\x43\xf3\x13\x04\xc2\x23\x01\xf2\xf6\x26\x87\xa0\x0f\x4d\x05\xde\xc1\x7b\xef\xf0\xbd\xf7\x06\x9a\xc7\x10\x47\x9a\x85\x34\xfb\xaf\x2b\xd8\xd3\x61\xb4\xd7\x15\xe2\x96\xc3\x1f\xc1\x23\x3a\xfd\xe0\x9f\x07\xfb\x7f\xde\xff\xe1\xcd\x9b\xff\xbb\xbf\xff\x2f\xb8\xbe\xb9\x3a\x3e\x6d\xb7\xef\xda\xa7\x37\xbf\x9c\x1d\x9f\xde\x1d\x7f\x3a\x3d\xfe\xf9\xee\xe6\xb4\xfd\xf9\xbc\xf3\x63\x37\x60\x5c\xff\xe8\x1d\xfc\xb8\xff\x23\xc4\x11\x1c\x82\x4f\x86\x6a\x99\x1e\x0e\x57\xee\xe1\xcd\x44\x0f\x19\x07\x2c\xe2\xb6\xe4\x01\xdb\x19\x9f\x8a\xee\xd8\x5b\xeb\x31\x3a\x39\x87\x3b\xd7\xa4\x90\x35\x97\x65\x20\x66\x86\x66\x87\x1a\xa9\x66\x8a\x0f\x1c\x96\xe2\x03\xa6\x83\x5c\x1e\x10\x2d\xc0\x03\xec\x1c\x67\xba\x59\xe8\xec\x59\x99\x7d\x1a\x18\xdc\x97\x09\xba\x4f\x34\xa8\xbe\x88\x03\x1f\x1e\x68\xf2\xe1\xfa\x2d\x38\x26\xdc\x3c\x20\x1c\x88\x94\x64\x68\xd6\x3b\x8c\x03\xcd\xa2\x80\x02\x91\xbd\xd8\x88\x78\x2a\xd5\x32\x22\x4a\x51\xdf\x60\x79\x9f\xfe\x86\xef\x4b\x1f\xff\x84\xfb\xab\x1d\xfe\xc7\x57\x17\x17\x47\x97\x27\x85\xbb\x2b\x6b\xa0\x5a\xa5\xa5\x23\xf0\x99\x87\xdd\xcb\x21\x0c\x98\xee\xa7\x40\xec\x0a\x89\xdf\x92\x23\xaa\x05\x9d\x3e\x53\x30\x10\xf2\x51\x01\xfd\x4a\x3c\x1d\x0c\x21\x60\x8f\x14\x5f\xda\x1e\xb5\xdb\x4e\x77\x69\xfa\x10\xd2\x67\xf8\x8f\x63\xb3\x00\xc7\x8e\xf7\xce\xf9\xcc\x92\xde\x6a\xf9\xd0\x62\x45\xa5\x19\xb0\xd4\x26\x28\x94\x96\xf9\x22\x3b\xe0\xf2\xe8\xe2\xb4\x70\xd6\x81\xe8\x15\x0a\xcb\x55\xcb\x7d\x09\x1e\xcc\xa7\x5c\x1b\x59\xb9\x0c\x1e\x49\xa3\x5c\x4c\xd8\x22\x98\xfc\x7c\xfa\x8f\x8f\x67\xe7\xc5\xb0\x64\x8e\x54\x27\x2e\xbf\xf6\xa9\x39\x0d\x0c\xd7\x50\x71\x14\xe1\x5d\xce\xe0\xe4\x64\xcb\xa9\x03\x08\x3f\xca\xe2\xed\xfc\x25\x66\xb4\x98\xa5\x2e\xb3\x74\x8e\x1c\xd0\x7d\x49\x55\x5f\x04\x7e\x31\x11\xe6\xf5\xca\x69\x48\xe4\xc5\x45\x89\x30\xef\x57\x4e\x84\x11\xac\x44\xac\x81\x71\x50\xd4\x13\xb3\xdc\xa5\x78\x27\xbb\xe6\xb9\x1b\x59\x2f\x7c\x72\x66\xf5\x54\xeb\xe1\x79\x4c\x82\x00\x8c\x4c\x8a\xbc\x7b\xbb\x29\xe0\xea\xba\x73\x76\x75\xb9\x0d\x3b\xa3\x63\xd1\x8e\xaf\x20\x24\x43\x73\x22\xaa\x88\x7a\xac\xcb\xa8\x0f\x44\x8d\xce\xd1\xdd\x52\x80\x29\xd5\x6f\xda\x5e\x73\x31\x13\x8b\x7c\xfc\x96\xd6\xc2\xfd\xe2\x88\x5f\xdb\xa7\xff\x59\x51\x38\xbb\x7e\x7a\x0b\x9e\xe0\x9c\xe2\x39\x56\xfa\x6b\x67\xd1\xd3\xdb\x4a\xf7\xb8\x23\xea\xfb\x15\x89\xfa\x7e\x41\xa2\x96\xbc\xb6\x79\x01\x09\xfd\x25\x6e\x6d\xd8\x6e\xf2\xd2\xa6\xa9\xd2\x0a\x8e\xcf\x8f\x2e\x4e\x52\x73\x56\x76\x97\xa3\xda\x6f\xb4\x89\xf1\x12\xb6\x23\x24\xc4\x9c\x7d\x05\x25\xbc\x47\xaa\x77\x33\x94\x7c\x38\xca\xaa\x3a\xbe\xd9\xbb\x08\x4c\x8e\x6c\x3e\x3b\xa5\x13\x09\xf5\x41\x89\xc0\x5c\x39\x22\xa2\xfb\xd3\x5f\xd8\x04\x5d\x73\xaf\x15\xb8\xc0\x65\xb7\xcd\xb5\x90\x1a\x78\x1c\x3e\x50\x09\x3b\xbe\xdd\x2e\xef\x81\x0b\x4e\xcb\x7d\xee\xab\x5e\x2b\xec\x14\xd7\x7b\xab\x68\x6b\x89\x47\xa3\xb9\xf4\x47\xd4\x73\x67\x83\x7c\xa2\x12\x24\x55\x91\xe0\x8a\xb6\xe0\x22\x61\x91\x0a\xdf\x56\x90\x2c\x9e\x4f\xbb\x8c\x3b\x0e\x69\xd8\x63\x29\xb8\xec\x80\xb9\x80\xd1\x45\x01\xcb\xe8\xa7\x4e\xce\x77\x14\x04\x09\x56\x09\x1c\x9c\xda\xab\x93\xf0\xbc\x58\x66\x22\xb8\x28\x13\x72\xbb\x3c\xc8\xd7\x2b\x2d\xc3\x17\x4f\x39\x79\x08\x28\xc4\x8a\xf4\x28\x88\x2e\xdc\xde\xde\xde\xf2\x06\xfe\x47\xda\xff\x68\xf3\x7d\xde\xba\xff\xd9\x19\x70\xdf\xcd\xaf\xdc\x91\x47\x0b\xee\x7f\x6a\xe1\x25\x55\x1e\x89\xe8\xdd\x4c\x67\x75\xae\xeb\xf8\x4b\xc0\xb9\x6b\x61\x19\x28\xae\xe4\x33\x40\xb0\xd6\xb9\x2f\xb1\x41\xbe\xc4\x4c\x2f\xb3\x41\x4c\xbb\x5c\x74\xbe\x94\xdc\x20\x33\x9d\xad\x71\x83\xb8\x6f\x5c\x0b\x60\x9c\x69\x46\x34\x05\x02\x5e\x40\x09\x07\x2f\x10\x0a\x71\xb4\x6a\x81\x91\x2c\xb2\x7e\x9c\xd6\x0a\xd0\x91\xe7\xd1\x48\x43\xe7\xf8\x1a\x24\xed\xc6\x8a\x04\x4e\x12\x51\x9a\x68\xaa\x40\x3c\x36\xf0\x2e\xd6\xc0\xdb\xd0\x24\x53\xc4\x27\x65\xf0\xc1\x11\xf2\x15\x0d\x72\x11\xb9\x9a\xf2\x38\x2c\xe2\xc3\x19\x63\x94\xc1\x6f\xe2\xb7\x27\x12\xc4\x74\x52\x94\xb2\xfd\x3d\x4e\xcf\x61\xe6\xfe\x09\xd6\x72\x91\x9e\xd1\xbf\x96\x5c\x1b\x7b\x70\xd1\x84\xb5\x43\xc8\x54\x48\xb4\xd7\xa7\x8b\xaf\x94\x79\x5e\x6a\xa5\x92\x31\x72\xd7\xea\xa2\x8a\xb5\xca\x1c\xe5\xb5\xae\xd6\x27\xe6\x53\x10\xb1\x8e\x62\x0d\x5d\x29\x42\xfc\xa6\xac\xe4\x5c\x28\x38\xfc\x46\x58\xb5\x92\xc3\x31\x72\xb2\x31\x0b\x03\xc1\x3d\x0a\xa1\x90\x14\x74\x9f\x70\xd0\x7d\xa6\x12\xd1\x59\x74\xe1\x61\x68\x76\x0f\x91\x14\x24\xf5\x28\x7b\xa2\xd3\x5a\x8e\x39\x3b\x85\x7c\xc5\x1e\x72\x77\x4a\xb8\x28\xdf\xcb\xec\xa9\x5e\x41\xda\x2a\x54\xec\x17\xc2\x8c\x74\xac\x07\x94\x5a\x41\xca\x9a\x32\xf1\x83\x23\xdc\x87\x48\x04\x81\xf9\xbb\x2b\x52\x22\x62\x19\x9c\x7c\x1a\x90\x7c\x7d\xa2\xbf\x28\x48\xb3\xdd\xd4\x8a\xd0\x05\xe3\x2c\x8c\xc3\xd4\x76\xf1\xc9\x50\x99\x43\x93\x4a\xcd\xba\xcc\x33\x47\x68\x9f\x20\x84\x0f\x14\x9e\x48\xc0\xfc\x16\x1c\x28\x0d\xf8\x35\xc2\xc4\x4e\xc3\xa6\x06\x40\xa7\xdc\x6b\xc0\x21\xf7\xcd\x2b\x23\x45\xdb\x0e\xeb\x02\x17\x7a\x7c\x05\x7e\x0f\xfb\xbb\xd0\x6c\x82\xa2\x11\x91\xc4\x30\xc1\x87\xa1\x55\xda\x97\x33\x72\x8c\xa9\xcd\x5d\x82\x93\x45\x97\x20\xaf\xb3\x5a\x17\xe2\xb3\xa2\xd0\x6e\x9f\xa7\x0c\x17\xe5\xb5\x25\x4e\x48\x55\xd5\xb2\x9b\x1b\xf7\x35\xa0\xa6\xd2\x90\x60\x8d\xfe\x46\xde\x1c\x4c\xba\x04\xec\x38\x05\x66\xb1\xba\x60\x60\xfa\x59\x17\x85\xa3\x9d\x57\x8a\x44\xaf\x72\x12\x13\x4e\xf4\x40\xbb\x86\x4f\xa7\x98\xb7\x19\x4a\x99\x73\x65\x72\x9d\x0f\xca\x79\x51\x54\xa0\x06\xb6\x53\x5f\xbb\x16\x78\x25\xa5\xa5\xa5\xf9\x65\xe9\x2c\x47\x34\xd5\xac\xb2\xf4\xfb\x5e\xb4\x84\xc6\xd2\x34\xcb\x52\x58\x1a\xa6\x43\x9e\x08\x0b\xc8\x03\x0b\x98\x1e\x1a\x86\x7e\xf2\xc9\x88\x38\x78\xa7\x72\xfe\x26\x9c\xea\x81\x90\x8f\x19\x3a\x4a\xd3\xef\x0a\x5e\x12\x93\x9e\x87\x86\x98\xd4\xe0\xce\x07\x69\x40\x13\xe3\x78\x8f\x6a\x74\x7e\x71\xdf\xbd\x11\xc7\x4a\xaa\x03\x4c\xb7\x2c\x5a\x46\x25\x30\x16\x7f\xcf\xae\x8f\x4e\x4e\x6e\x4e\xdb\xed\xec\x8d\x60\x10\xb9\xcb\x1c\xa9\x6e\xbb\x68\x0a\xcc\x69\xe4\x1e\xcc\x1d\xb8\x4b\xa5\x3d\x69\x49\x1a\xe5\x92\x57\xbd\x2f\x31\x55\x9a\xfa\x05\x20\x2e\x74\xdf\x5b\x04\xc4\xbc\xc1\xea\xc6\xf1\xf9\x6d\x73\x38\xfd\xb5\xf3\x64\x33\x77\xc6\x35\x95\x5d\xe2\xe1\x81\x1a\x97\x14\x86\x47\x8d\x97\x31\xb0\x4f\xcc\x3d\xbb\xa7\xba\x17\xfe\xe2\xe8\x78\xf4\x05\xd9\xe9\x9b\x3d\x30\xe2\x4a\x6e\x3f\x96\xbc\x47\x79\xab\x5c\xa1\x10\x8c\xe9\x3e\xd6\xe4\x47\x60\xa6\x1f\x73\xe6\x11\xa5\x93\xa9\x97\x70\x23\x40\xca\x5d\xf3\x9a\x4f\x44\xd6\x5b\xe6\x40\x64\xbd\xd9\xf3\xd0\xae\xf5\x65\x1b\x59\x23\xf3\xa8\x39\xfd\x32\x6c\x77\xb1\x32\xe2\xaf\xe9\x21\xdb\xf9\x72\x34\x02\x34\x3f\x99\xee\xda\xa7\x37\xbf\x9c\xde\x40\x33\x00\x43\x9e\x7b\xb3\xe5\x89\x10\x9a\x47\x70\xbb\xf5\x7f\xb4\x17\xdd\x6e\xdd\x72\xe7\xad\xc4\x82\xc0\xaa\x35\x09\x68\x2f\x82\x2f\x31\x95\x43\x83\xf6\xb8\x23\xbc\x6c\x4d\xf6\x94\x71\x32\xb3\xde\x0a\x07\x73\x02\x82\xdd\x0a\x48\xc3\xb4\x0f\xe3\xc1\xe1\xff\x6d\xed\xb7\xf6\x5b\x07\x33\x9e\xe9\x29\x12\xdc\x49\x58\xa9\x9c\x96\x6d\x24\x7c\xf7\x66\xbd\x26\x42\x33\xb9\x67\x74\x3b\x1c\xf1\xa9\x49\xb7\xc3\x40\x88\x47\xea\x43\x1c\x15\x2c\x89\x79\x27\xce\x3f\x52\x97\x32\xdc\xde\x50\x4f\x48\x1f\xcc\x14\xcd\xee\xb0\x43\xa4\x56\xe7\xa8\xdc\xe2\x48\xec\xee\x0e\x11\xcb\x5b\xa3\xce\x62\x6b\x94\xd7\x55\xad\xea\x77\x3e\x5a\x9f\x91\x9a\xd7\xaa\x52\xdc\x79\x42\xb8\x1a\x50\x69\xc4\x0b\x7b\xcb\x38\x73\x0a\x12\xaa\x1b\xd6\xfd\x7b\xd0\x27\x9a\xa2\x0c\x4c\x94\x69\xd4\x0c\x96\x30\xe8\xd2\x6c\x2b\x7d\x1a\x44\xb2\x18\x88\x85\xfd\xd5\x89\xe4\x35\x51\x0a\x6c\x5b\x6b\xda\xb6\x4e\x96\x3b\x6a\xd7\x00\x3a\xc1\x82\x17\x80\xc5\x67\xbd\x66\xb6\x9f\x66\x1a\x93\xa3\xc5\x30\x59\xcc\xe1\xb3\x4a\x30\x2e\x47\x3a\x37\x49\xb5\x64\x54\xa5\x7c\x85\x7d\xd6\x6b\x8c\x25\x57\x05\x3e\x7b\x62\xbe\x15\xf7\x51\x33\x6c\x15\x77\x3b\x27\xc9\x07\x39\xc3\x2d\x27\xbf\x19\xec\xfe\x85\x29\x94\x6a\x8f\xc7\x31\x53\x9f\x17\x8c\x93\xbb\xa6\x27\x57\x9f\x3f\x9c\x9f\x2e\xc1\xd4\x57\xd6\x62\xd5\x1f\x69\x63\x80\x99\x1b\x66\x53\x35\x32\x0b\x28\xcf\x52\x07\xcc\xc1\x7e\x39\x58\xaa\xb8\xa5\xb1\xde\xfa\x2f\x69\x1f\x85\xf4\xa8\xf9\xda\xd1\xcb\x85\x07\x43\x94\xd3\x51\x95\xe6\x24\x45\x49\xb8\x9a\x8d\xcb\x28\x94\xd5\x59\xaf\x7a\x6d\x5a\x2e\xa1\xdf\xaf\x4c\x68\xdd\x2a\x36\xa6\x1e\x97\xba\x51\xa8\xc7\xc9\x2b\x05\x3e\x77\x3a\xb6\x50\xc4\x5c\x1b\xd6\x1d\x1b\x86\x6d\xde\x05\x15\x11\x7b\xc5\x20\x80\xbf\x52\x1f\xba\x2c\xa0\xa0\x86\x4a\xd3\x10\xed\x53\x3d\xca\xa9\x44\x3b\x30\xe1\x40\x02\x2a\x35\xb0\x2e\x74\x25\xa5\xae\x35\x53\x10\x38\x31\x90\x83\xe0\x23\x57\x87\x91\x6f\xb3\x65\xfc\x6a\xce\x4d\x45\x3d\x42\x73\x00\x07\xfb\xdf\x41\xd3\x83\x77\xdf\x41\x33\xc2\x08\x2f\xfc\xef\x13\x91\xd0\x3c\xb6\xbf\x9b\xff\xe1\x2b\xf6\x8f\x08\xf6\x6e\xb9\xe9\xf4\xd8\xce\x14\xdb\x18\xba\xb1\x11\xd1\xd8\xa3\xf9\xf7\xbb\xef\x1a\xf6\xb9\x7d\xb8\x7f\xf1\xc1\x3e\xde\xbf\xf8\x70\xeb\x70\x4a\x51\xe1\x86\x48\x8d\xea\xc6\x84\x66\x0f\x14\xf3\x4f\x8e\x3a\x47\xd0\x94\xb0\xfd\xff\xed\x09\x49\xbc\x80\xee\xb5\xcf\x4e\xf6\x7c\xa2\x49\xeb\x3f\xfe\xb8\x3d\x41\x11\x09\x02\x04\xd5\x62\xaa\x50\xca\x42\xe3\xb4\x39\x6f\x9a\x32\x21\x27\xa1\xa6\x85\xb2\x75\x57\x8d\xdf\x31\x60\x36\x25\x48\xda\xa3\x5f\x6d\xcf\x44\x52\xe8\x49\x11\x47\xd4\x77\x7a\xb6\x90\x12\x6e\x97\xd9\xac\x8c\x5d\x98\xd1\x02\x58\x23\x2c\x89\xa2\x80\xd9\x93\xda\x90\x64\xe6\x6a\x76\x7b\x0f\x6f\xdb\xe5\x20\x88\x60\xaf\x2b\x84\xfb\xe5\x1d\xae\xd8\x1b\xbb\x62\x0f\x44\x4e\x2e\x87\x79\xcf\x5c\x16\x4d\xfb\x8b\xbd\x77\xc9\x44\xcd\x8b\xf8\xfc\xdd\xde\x9b\xef\x5a\x70\x84\x21\x9d\x21\x61\x78\x08\x3f\x89\x20\x36\xec\xd5\x7c\xad\x07\xb6\xd9\x45\xd6\xed\x52\x3d\xae\x70\xbd\x4c\xed\xe0\xd9\x90\x80\xa9\x7b\xe6\xe1\xfe\x77\xb7\x5b\x28\x22\x1b\x84\x23\x1b\xb1\x8a\x51\xf4\x66\xf7\x8b\x90\x69\x4d\xfd\x06\xc4\x9c\x69\x65\x4d\xf4\xf7\x86\xba\x3b\x7c\x70\x8f\xe8\x9b\x6f\x2e\x97\xa5\xa8\xc7\xbb\x81\xa1\xa7\x52\xee\x37\x35\xc9\x8c\x98\x83\xe9\xdb\x74\xfd\xb3\xf4\xea\x9b\x25\xe3\xc2\x5f\x3c\xba\x03\xa9\xc1\x26\x75\x22\x6f\x69\x5a\x38\xda\x23\x45\x54\x3d\x40\x45\x44\x6a\x96\x18\x95\x22\x49\x3d\x34\x7c\x33\x0e\x87\xad\x37\x05\x24\x8d\x9a\x55\x4e\x10\xfd\xea\x05\xb1\xb9\x23\xac\x4a\xd9\x5d\xd2\x53\x7d\x98\xed\xa8\xdd\x94\xf3\xf3\xe8\xf1\xc2\xfe\xcf\xd9\x84\x57\x1f\xab\x37\x8b\x69\x4d\x94\xd7\x83\xf9\x71\x40\x89\x4c\x9d\x5d\x85\xec\xc4\xbc\x5b\xb5\xc8\x88\x81\x07\x18\xa2\x90\x42\x6a\xac\x7e\x45\xcf\xb8\x66\xd4\xb0\x02\x25\x1e\x9a\x78\x90\x61\x70\xa7\x6d\x5b\x44\x32\xbe\x76\x37\xdf\x39\xad\x2c\xe1\x27\x4c\x45\x01\x19\x5a\xaa\x7c\xfa\xc4\x3c\xaa\xf6\x50\xa6\x8b\x04\xe3\xda\x79\xf4\x51\x29\x85\x54\x2d\xb8\xb0\x51\x4d\x66\x20\x33\xd1\x62\x81\xd7\x50\x8d\xed\xee\x4c\xe7\x95\x52\x7d\xd6\xb5\x0a\x27\xe2\x79\x28\x9c\x4a\x21\x74\x53\x52\xd4\xd8\xfa\xf0\x10\x08\x14\xa0\x24\x45\xa1\xc9\xbd\x64\x64\x54\x43\xf3\x48\xce\x61\xdc\x1c\x56\x5d\x14\xbe\x8a\x18\x6b\x8f\x0b\x49\xef\x92\xde\x2b\x9d\xc7\x4f\x46\x18\x73\x8b\x0f\x9d\x94\xdc\x15\x45\x01\x6a\xce\x77\x0c\xb9\xcd\x5d\x27\x6f\x77\x51\x02\x4b\x6d\xaf\x44\x0c\x2b\x75\x7f\x44\x09\x30\xf7\xf6\xd8\x5b\x2d\xb8\x16\x21\x9b\x1d\xa1\x56\x97\x6a\x12\x52\xc3\x82\x9a\x4d\x2b\x62\x3c\x7e\x28\xbf\x51\x1f\x59\x20\xe6\xfb\xfa\x95\xa5\xec\x6a\xfc\xa9\x63\x0e\x8b\xb4\x3c\x5f\x9e\x46\xec\x62\x6d\xf4\x01\xe9\x11\xc6\xd1\xb0\x34\x62\xa9\xf0\x0f\xaa\xc1\xc3\x28\x48\x4d\xb4\xb9\xff\xb9\x74\x1e\xe9\x76\x5a\x58\x83\x94\x4d\x0e\x31\xb4\x77\x08\xcf\xa3\x4a\xb1\x87\x80\xc2\x0e\x6d\xf5\x5a\xa8\xf6\xa3\x9a\x7a\x1a\xda\x9a\x04\x14\x2e\x3f\xb6\xe1\x13\xe1\x7e\x40\xf1\xcc\x29\x89\x8c\xa1\xe6\xce\x92\x72\xd7\xad\x76\x09\x13\xfe\x68\x44\xdb\x31\x5b\x04\x83\x0c\x25\x7e\x72\x67\x4d\x89\x21\x65\x69\x1f\x77\x5a\xad\xff\xd6\xd4\x47\x71\xb1\xc4\x47\x11\xd2\x1e\xa9\xfe\xa3\x38\xfd\x1a\x05\xcc\x63\x3a\x18\x82\xa2\x81\xd9\x02\x96\xa9\x39\x1e\xc8\x94\xb9\x35\xd0\x2f\x31\x7b\x22\x81\xb9\x48\x68\x01\xcd\x1b\xd8\x6e\xdd\xde\xfe\xc7\x76\xf9\x39\x54\x1d\x05\x75\x4c\xd0\xb4\xae\x28\x57\x4c\xb3\x27\x6a\xae\xd7\x71\x40\xcc\x39\x8e\xa1\xeb\x4c\x70\x3c\x66\xcc\x7c\xf6\xd2\xdb\x22\x11\xa3\x32\xde\xaf\x36\x20\x4e\xd2\x1e\x6b\x9a\xe1\x73\x59\xfc\xcd\x22\x2c\xfe\xfa\xa8\xf3\xa9\x51\x78\xb4\xd3\x1e\xbb\x9b\x19\xa7\xde\xcc\x59\xb9\x50\x4f\x88\x5d\x6b\x46\xbb\x18\xec\x85\x7c\x8a\x16\x01\xfb\xd9\xb1\xd6\x02\xac\x2c\xe4\xbe\x5b\xbc\x2a\xa4\x77\x39\xec\x78\x53\x5f\xc7\xee\x1a\x97\xc2\xd2\xd6\x5c\x60\xff\x9f\x55\xb1\x24\x4e\x2c\x7c\x19\x9f\x41\xce\xd2\x3c\xd7\x57\x91\x5a\x8a\xe2\x95\x58\x28\x6b\x49\x89\x95\x58\xef\x42\xbc\x02\x33\x8f\x7a\x7c\x86\x34\x19\x7d\x21\x14\xb5\x61\x3c\x0d\x78\xfc\xd0\x80\x8b\x0f\x0d\xf8\xe9\x43\x03\x3a\x1f\x52\x78\x5c\x7c\x28\x87\x07\xca\x31\xb9\x68\xc4\x0b\xa2\x31\xdb\x4b\x9d\x3b\xe4\xcc\x7e\x94\xd3\xaa\x7c\xd1\x05\xc6\x7d\x66\x95\x55\x66\x88\x75\x9e\x58\x56\xf9\xd2\x2c\x74\x50\xf9\xfb\x22\xdf\x65\xe7\x1f\xd7\x45\x97\x40\x37\x50\x55\xee\x2b\xee\xaf\x65\x2c\x62\x77\x2a\x7c\x58\xd2\x2a\x66\x9a\x66\xa4\x38\x34\x32\xff\xbd\x0a\x1f\xbc\x80\x51\xae\xef\xe1\xc1\xe6\xdc\x4a\x52\xcf\x42\xfb\xe2\x03\xa8\x3e\x91\x13\xd6\xab\xc9\x2b\x4b\xf8\xb0\xa4\x11\x62\x9c\x03\x97\xea\x0f\x67\x57\x6d\xe0\x98\x0b\xb7\xbb\x6c\xa4\x79\xdd\xc9\x69\x93\xe9\x3e\x43\x7a\xda\x11\x54\xed\x3e\x2a\x83\x0c\x50\x0f\x94\xf1\x1e\xda\x71\x59\xc9\xc0\x42\x5c\xd0\x65\x1c\xf0\x67\x90\x98\xed\xa9\x56\x18\x7e\x15\xf2\x11\x55\x32\x46\x1e\x38\x11\x21\xb1\xdb\xd8\x1f\x31\x63\xbc\xb4\x6f\xff\x7a\x75\xf3\xf3\x4f\x37\x57\x9f\xaf\xb7\xcd\xdd\xdd\xd9\x6d\x4a\x7a\xb2\x24\x23\xe5\xc2\xf4\x6b\x09\x98\xb2\x7b\xab\x95\x5f\xcf\x04\x75\xb8\x8c\x37\x3c\x18\x02\xa7\x1e\x55\xca\x7c\xe7\xcc\xa5\x9a\x7e\xa0\x66\xe2\x88\x1e\xe1\x98\xd3\x32\x89\x37\x29\x07\xdb\x0a\xae\x6e\xe9\xb8\x84\x39\xdf\xdf\xba\x1d\xe0\x3e\xbb\xc4\x7f\x78\x49\x73\x1e\xb9\x81\xe8\x35\x19\x9f\xda\x78\xbd\x98\x2a\xbd\xfc\xa6\x8b\xd5\x94\x97\xee\x32\x72\x81\x01\x28\xc9\x54\xb8\x56\x17\xc1\x81\x90\xfe\x3c\x84\x08\x07\x1a\x46\x7a\x88\x4e\x73\xd8\x60\x59\xac\x92\x0e\x56\x73\x1f\x76\x78\x65\x76\x56\x77\xa4\x03\x32\xae\x05\xed\xef\x7f\x7e\xb7\x98\x65\x5a\x25\x79\xdb\x88\xf5\x6f\xb0\xb6\xea\x42\x8d\xa3\x61\x4f\x86\x94\xca\xcd\x70\xa9\xf9\xcd\x37\xbd\xff\x50\xeb\x04\xbd\xca\x27\x78\x3c\xbe\x22\x45\x42\xea\x06\xa0\x32\xf8\xfe\xe0\xcd\x0f\xf7\xe6\x6c\xba\x7f\xfb\xf6\xdd\xfd\xe4\x1c\xd3\x52\x96\xfb\x24\x52\x9b\xbf\x3a\xb7\xf9\xeb\x32\xfb\xbe\x22\xdf\xf9\x65\x45\x5a\xae\x96\x91\x66\xb9\xca\x11\x64\xb9\x72\x3e\xef\x91\x14\x3d\x49\x42\xf4\x7a\x7b\xd0\xc4\x39\x7c\xa7\xce\xc4\x24\xd6\xbb\xc7\x9e\x28\xc7\x23\x70\xcf\xb7\xe2\x84\x0b\xb3\x38\xe2\xe3\x7d\x36\x19\x87\x61\xb6\xe0\x74\x4e\x44\xe7\x3c\x9e\x7e\x93\xa5\x4c\xa6\x0d\x1c\x2b\x59\x74\xfb\xc2\x8e\xda\x4d\xd9\x54\x19\x87\xfb\x3d\xaa\xbd\x3d\x49\x95\x08\x9e\x5a\x9e\xe0\xdd\x7b\x1b\x86\xf2\x30\xed\x54\x32\x5e\xc6\x94\xed\x7c\xb9\xe4\xd8\x7c\x5c\x7c\x22\x89\x30\x19\x85\xdf\x74\x85\x9c\xc9\x98\x6d\xda\xdc\x99\x46\x7f\xcc\x8f\x37\xe1\x6a\x5e\x70\xc3\xb2\x0c\x65\x6e\x3c\xcc\xf8\xde\x00\x06\x40\xd6\x8b\xa5\xc5\xd6\xfc\x70\xd5\x5e\x22\x4e\x75\x19\x21\x79\xa1\xab\x04\x57\x8b\x44\xe5\x54\x7d\xe4\xb8\x90\x07\x17\x1c\x62\x97\xf8\x68\xbc\x13\xf0\x5a\x4e\xb9\x33\xf1\x13\xf0\x85\x5e\xdc\x1b\x05\xdd\x21\x92\x08\x05\x1c\xa7\xf2\x0d\x60\xbb\x75\x71\x07\x8b\xcf\x60\xa4\x91\xb0\xed\xcb\x7b\x7d\xcc\x4e\xad\x72\x43\x12\xf5\x74\x7a\xfb\x26\x59\xb5\x08\x07\x12\xeb\xbe\x90\x4c\x13\x34\xd2\xd8\xe1\x0b\x08\x9d\x78\xbd\xe2\xe0\x01\x1d\xcb\x71\xa0\x00\xeb\x02\x0d\x48\x84\xa1\x0f\x2c\x44\xaf\x1b\x4a\x7d\x17\xe4\x50\x40\x60\x1d\x49\x28\x90\xb0\x91\x90\xb1\x2c\x65\xdf\x64\xee\x09\x33\xf1\x0a\x15\xab\xcb\x4a\x02\x71\x18\x0e\x97\x91\x05\x4c\xbb\x49\x69\xc0\xc6\x6e\xb2\x30\x0a\x86\x20\xed\xce\xc0\x0f\x4b\x13\x2c\xe1\x21\x6d\xea\x02\xdf\xe5\xae\x43\xb1\x21\x0e\xa9\x64\x9e\x0b\xcf\x71\xd7\xe5\x7b\xec\x1a\x0d\xf2\xf4\x7e\x14\xf3\x64\xf9\xca\x48\x32\xd0\xf4\x6b\x56\x65\x28\x6c\xba\xc2\xd1\x8c\x83\x8e\x8a\x16\x38\x8f\xf2\x7d\xd8\x11\x8f\xbb\x0d\x38\x80\x1d\xf7\x09\xee\x36\xe0\x10\x76\x92\x6d\xbf\x8b\x6e\xc5\x6f\x60\x27\xe6\x8f\x5c\x0c\xf8\xee\xe4\xce\x9a\xde\x58\x13\xb4\xda\x69\x56\xba\xf5\xaf\xed\x6a\xd8\xac\x5d\xd3\x82\x04\xfa\x46\x63\x58\x9d\x8a\xd1\xa1\xa2\x1b\x07\xad\x7c\x91\x02\x49\x34\x58\xd7\x1b\x73\xd0\x65\x01\xbd\x23\xbd\x65\xea\x8d\x25\x4d\x33\x63\x0f\x08\xaa\xcc\xb7\x15\x28\xf6\x6f\x8a\xab\x14\x0a\xdf\xa6\x39\x4a\x58\x81\x81\x25\x24\x8f\x14\x54\x2c\x29\x30\xbd\x6d\xbd\xe4\xed\x5d\x79\x54\xd9\x02\x9f\xab\xb8\xdb\x65\x9e\xb9\x47\xe0\x06\xf7\xb2\x8b\x93\x25\x04\xad\xaa\x9a\xfd\xc8\x02\x4b\x9c\x45\x21\x67\x85\x92\xd1\x10\x87\x62\x75\x60\xd9\x7d\x84\x04\x24\x07\x36\x17\xd3\xc9\xd6\x42\xc2\x87\x49\x86\x08\x10\x01\x9e\xe5\xf3\xbd\xd9\xdf\xee\xab\xdc\xdd\x36\x9a\x8b\xeb\xe6\xae\xf2\x53\x61\x89\x29\xcd\xbf\x40\x7f\xbf\xbf\xc8\x9c\x92\x7e\x6a\x9e\x14\xd1\x10\x50\x82\x2e\x57\xc9\x84\x6c\x2e\x3c\x73\x70\xe5\x2c\xd1\xa5\x18\xdd\x90\xf0\x56\xb6\xe8\xf2\x98\x8f\xea\x19\x67\x32\x7f\x65\xf6\x3f\x94\x58\x97\xca\x67\xe3\x84\xa3\xab\x9f\x93\x1a\x47\x18\xde\xe4\x0b\xea\x38\xcc\x57\xa6\x4a\x04\x7f\x8d\x08\xb6\xa6\xea\x90\x29\x35\x2f\x50\x73\x75\xb6\x1c\xd0\xaf\x41\xb8\x0c\x53\xc6\x86\xd9\x2c\xd9\xa6\x5b\x0a\x28\xd8\x97\x20\x60\x1e\xe5\x78\xb3\xe7\xa4\x47\xa5\x6a\x81\x63\x81\xce\x44\x16\x84\xe6\x88\xbc\x1f\x55\xb5\xc9\xe0\xb8\xd8\xd1\xca\xa6\x30\x67\x02\x4b\xe8\xc1\xd5\xda\x89\x55\x4c\x02\xac\x9b\x83\x4f\x5b\x3e\xd1\x79\xa1\xc3\x96\x8c\x3b\xf7\x66\xf5\xfc\xd8\x9d\xeb\x78\x68\x4d\x25\xe8\x99\x94\x64\xdf\x15\x13\xb8\x88\xcc\xb9\xfa\xd6\xd1\xcb\xe4\xe9\xea\xea\xcc\x34\x5d\x1f\x3b\xd7\x55\x55\x15\xe8\xea\x55\x12\x76\xbd\x80\xb2\x66\x5d\x1d\xd5\x56\xd3\xcc\xe0\x1c\x8d\xd3\x8b\xac\x35\xa1\x88\x99\xd7\xa6\xe2\xc0\xc2\x15\x07\x0c\x5c\xbf\xa7\x7a\x03\xb8\xad\xbf\xdd\x6a\x03\xb8\x9c\xdf\x72\xad\x01\x03\xc0\xa6\xd2\xc0\xdc\xcd\xb1\xa9\x33\x50\x88\xd2\xa6\xca\xc0\x2c\x3e\x8b\x64\xae\x37\xd8\x6d\x6a\x0c\xbc\x86\x1a\x03\x66\xa5\xbe\xf1\x0a\x03\x06\x82\x4d\x7d\x01\xbb\x13\x36\xd5\x05\xe6\x41\xb4\xa9\x2d\xf0\x8c\xb5\x05\xcc\x02\xbc\xda\xca\x02\x28\x92\xbe\xd8\xba\x02\x86\xba\x17\x5d\x55\x00\xd7\xfe\x5b\xb4\xeb\x9a\x89\xbf\xae\x8a\x02\x86\xe2\x97\x55\x4f\xc0\x51\x54\x73\xaa\xb3\x1e\x09\x97\x31\x39\x9a\x66\x59\x6a\x4a\xf3\x3c\xe5\x05\x35\x4f\x5d\xe9\x22\x95\xa7\x5d\xe9\xb6\xbf\x98\x0f\x6c\x3b\xd1\x77\x5b\x0f\xb6\x48\x44\x18\xd1\x93\x1e\xc2\x7d\x87\x49\x86\x64\x11\xa0\x2f\xdc\x50\xc4\xe0\x0b\xbe\xad\xa1\x4f\x9e\xa8\x8b\x2c\xf7\x1e\xcd\x2d\x97\x71\xa5\x49\x10\x50\xbf\x81\x6f\xa1\xb9\x3e\xd1\xe0\xfc\xd3\x17\x03\x1e\x08\xe2\xea\xc1\x3a\x38\x88\xa7\xd9\x13\x55\x83\x96\x27\xc2\xbd\x88\x8a\x28\xa0\x7b\x4a\xd3\x27\xba\x87\x44\x3a\x10\x84\x4c\xba\x9e\x18\xee\xfe\x4b\x4c\x1e\xa9\x55\xde\xbb\xcf\xd5\x0c\xeb\x11\x9c\xac\x95\xa8\xec\xe4\x33\xf4\xb4\xbd\xb4\x0f\xf5\x8a\x1a\x7d\x74\x37\x9c\xad\x1e\x9f\x1e\xea\xae\x37\x37\xa8\xa4\x3c\x2b\x75\x64\x9c\x45\x53\xf1\x00\xe9\x45\x1c\xb9\xd3\x15\xd0\xc6\xa2\x5a\xaa\xcd\xbe\x02\x56\x8a\xd3\x5f\x3b\x2f\xc5\x0c\xdb\xe6\x92\x6e\x11\x01\x2d\x8a\x56\x67\xae\xd2\xba\xec\xf0\x1f\x19\x0d\xfc\x44\x0a\x64\x1c\x24\x19\xc0\x17\x9b\x2c\xc3\x5e\x93\xd0\x23\xc1\x13\x5c\x13\xc6\x1d\xd7\xe1\x0b\x6c\xef\xae\xe9\xf7\x39\x29\x0d\x49\x34\x97\xd0\x90\x44\xcf\x4e\x67\x84\x5a\x2f\x56\x4c\xa8\x79\xe9\xd9\x29\xc5\xb5\x9f\x47\xa9\xf9\xbf\xca\xe5\xb0\x34\x6f\x45\xdb\x9b\x8c\x39\x4f\x32\x46\xce\x63\xb6\x73\xa3\xf8\x2a\x39\xdd\xfb\xd1\x6f\xcb\x54\x37\x37\xcd\xf2\x6a\x05\x59\x57\x36\xd1\x05\xc2\xe1\xd3\x35\x44\x12\x2b\x75\x24\x2e\xaf\xff\x45\xf5\x09\x93\x86\x63\x78\x44\xfa\x2d\xb8\xa4\xba\xa9\x78\x18\x8d\x6c\x46\xa3\x03\x38\xa9\xac\xe0\x89\x30\x8a\x4d\x0f\x69\xf4\x72\xcf\x44\x43\xd9\xeb\x36\x5e\x9a\x19\xd4\x66\xbd\x74\xe4\xb6\x2f\x2f\xac\x15\x73\xea\xf0\xfa\xfe\x60\xad\xf6\x4c\x9c\xea\x72\x06\xcd\x15\xdc\xcc\x71\xf2\x46\x72\x8c\x39\xd3\x69\x1f\x7d\xbb\xc8\x51\xfc\x10\x30\x6f\xc6\x29\x66\x8e\x2e\x20\xe9\x2e\x17\x8e\xe3\x05\xe1\xc8\xee\x69\xad\xb1\xdc\x86\x1d\x2c\xc3\x14\x74\xb6\x67\x82\xf9\x4c\x3e\x75\x3a\xd7\xc5\x25\x53\x5a\x70\xa6\x51\xee\xc5\xa4\x56\x5c\xc8\x90\x04\x80\x44\x58\xd7\x51\x45\xbd\x58\x52\xfb\x44\xed\x26\xc5\xc7\x1a\xd0\x15\x41\x20\x06\x20\xa9\x8f\x6c\x45\x35\x40\x51\x22\xbd\xbe\x8d\xf5\x73\x36\x58\xd3\xc1\x6c\xc0\xbf\x6a\xb8\x30\xf2\x69\xb1\xae\xe1\x1a\xa0\x9d\x5f\xf0\x09\xbd\x14\xfd\x1a\x31\x39\x76\x8d\xcc\x4b\x9b\x7c\xfc\xe9\xf4\xf8\x67\x38\xbe\xba\xec\x9c\x5e\x76\xde\xc3\x18\x21\x4c\xc9\x0b\x4d\x0f\x0e\xf6\xa1\xd9\x54\x2a\x80\xe6\x27\x2c\xd5\xf2\x44\x25\x53\xac\xc7\xcd\x3d\xe2\x96\xdf\x72\xf8\xb5\x4f\x2d\x50\xdb\xd3\x3f\x6f\x8f\x6d\xc8\x3a\x96\x5c\x01\xd3\x0a\x0f\xbc\xc4\x07\x98\x71\x78\x97\x38\xbe\x34\x6e\x39\x10\x68\x77\x8e\x3a\xa7\x77\x57\x3f\x8f\xa2\x76\x6c\x53\xea\xb7\xc6\xe3\x14\x74\xfa\x10\xeb\xc4\x51\xfd\xd6\xbe\xfc\xae\x69\xfb\x1f\x7b\x96\x35\x46\xc3\xfc\xea\xd4\x34\x39\x63\x11\x6e\x13\x1d\x5a\x93\xf8\x04\x81\xc7\x89\x02\x65\xa6\x29\x42\xe2\x50\x3d\xbd\xe9\x9c\x7d\x3c\x3b\x3e\xea\x9c\x4e\x22\x3b\x0b\x24\x34\x8f\xe1\xe0\xed\x24\x9c\xe9\xd5\x14\xdd\x2c\x74\x6d\x31\x04\x66\xe3\x45\xc7\xfa\xed\x83\xb7\xa8\x6d\x9c\x02\x94\xa9\x2c\x2c\xd3\x83\x98\x83\x40\x9b\xf9\x60\xa7\x0d\x04\xd3\xf4\x3c\x4a\xcb\x7d\x3b\xee\x7b\x06\xc3\x89\xee\x8f\xe6\xc1\x04\x83\x3e\xe5\xb7\x99\x24\xe0\xc6\x5d\x09\xc8\x37\xfb\x8d\xca\xb0\x7c\xb3\x5f\x1f\x96\x49\xdf\xf8\xe3\xec\xf2\x15\x42\x7c\xcb\x17\x04\x79\x96\x29\x50\x2c\xc3\x32\xce\xb5\xee\xc6\x1b\xa1\xdd\x6e\x9f\xc3\xaf\xa7\x1f\x5c\x85\x26\xc7\x1a\xe0\x97\xb3\x23\xb8\xbe\xb9\xfa\xfb\x3f\xe0\x73\xfb\xec\xf2\x27\xcb\x29\x0f\x5a\x07\xe6\x85\xcb\xd3\xe3\xce\x7b\x04\x3c\xbd\x38\x67\x70\xf0\xc3\x61\xeb\xe0\xfb\x3f\xb7\x0e\xf6\xf7\x5b\x6f\xde\x41\x33\x82\x3f\xef\x43\x33\x86\x34\xcb\x4e\xaf\xc2\x1e\x34\xdb\xd0\xfc\x2d\xe9\x32\x73\x7d\xcd\x42\x58\xe5\xc4\x28\x88\xd5\xa5\xf6\xa4\xd4\xa7\xfe\x7b\x33\xee\x9f\x02\xfd\x63\x24\xc5\xd7\xe1\x9f\x7a\xfa\x47\x33\xec\xe8\x41\xd3\xb0\x4a\xfb\x34\xc6\xa7\x48\x70\x33\x96\x81\x7d\xd8\xde\x51\xc1\xee\x14\x09\xe6\xb5\x01\x7d\xb0\x5c\xc7\xbc\xf6\xfb\x60\x54\x19\x32\xa9\x7e\xed\x0e\x75\x66\x06\xb5\xc9\xa4\x4f\x4c\xea\x98\x04\xf6\x8a\x34\x55\xac\x4a\x51\x4c\x02\x89\xd3\xba\xdd\xfa\x24\x94\xbe\xdd\x82\x3e\x25\x7e\x6e\x94\x19\x92\xfa\x64\xfa\xaa\x9c\x50\x57\xe2\x0e\x3e\xdf\x9c\x21\xcf\xf9\xe9\xb4\x03\x42\xc2\xf5\x55\xbb\x33\x15\x4c\xbd\x77\x5f\x44\x5d\x2c\x59\xe5\xb4\x75\x8e\xb3\x04\xfa\x3f\xef\x5b\x5e\xc5\x45\x52\x92\xae\xdd\x3e\x6f\xc0\xdb\xb7\x6f\x72\x97\xbc\x66\x89\x5f\xaf\xdd\x85\x71\xaa\x5e\x61\xbb\x7d\x3e\x5f\xc5\x3e\xc7\x8f\x4b\xe5\x97\xca\x69\x2f\xe2\xba\xf0\xcb\xe9\x4d\xfb\xec\xea\xf2\x9f\xff\xe7\x5f\x05\xbb\x64\x9e\x59\xad\xca\x6b\x51\x0a\xa3\x2e\x16\x65\xe9\x9c\xb7\x9f\xca\xdd\x05\xd7\x06\xca\x1d\x52\x78\xa7\x03\xf5\x74\xf0\xdc\x00\xbd\x02\x88\xee\x9e\x1d\xa4\xc3\x57\x00\xd2\xe1\xf3\x81\xd4\x6e\x9f\x3f\xbd\x6c\x88\x94\x0a\x9e\x9e\x19\xa0\x37\x2f\x1e\xa0\x37\xcf\xfc\x99\x19\x49\xa4\xcf\x7a\x65\x93\xd4\x3f\xcf\xe7\x26\xe4\x9d\xa5\xf5\xb9\x79\xd3\xeb\x82\xed\x05\x01\x77\xf8\xaa\x80\x3b\x7c\x09\xc0\x21\xa3\x7f\x25\xb0\x21\xcb\x7f\x29\xa0\xbd\x79\x45\xa0\xbd\x79\x5e\xd0\xf0\x86\x73\x79\xb6\xb8\x13\x91\x9d\x02\xaf\xf6\x42\x7a\xe4\xfb\xb0\x9d\x64\xf9\x7b\x9f\xa4\xaf\xdb\x4e\x92\xc5\xfc\xdb\xaa\xcf\x23\xc2\x0a\x2f\xf1\xe6\xed\x3b\xf3\xd2\x33\xd1\x66\x93\xde\x4b\xf1\x35\xcf\xf1\xc4\x5e\x66\xcd\x0b\x35\xd1\x7a\x82\x3e\x4a\x89\xd7\x11\x2a\x41\x1e\x84\x3f\x6c\xc0\x6f\xb1\xab\x44\x6f\x55\x21\x79\x19\xe6\x90\x40\x97\xb6\xdb\x34\xac\x16\x48\x67\x77\xe9\xd1\xaf\x18\xfe\x12\x11\x0e\x9c\x0e\x02\xc6\x0b\xf7\x9a\xf9\xdd\xbc\x5b\x2d\x2d\x59\xe9\x9c\x6d\xe5\xc5\x04\x34\x6b\x60\xc6\x98\x80\xa4\xe4\x4a\x0b\xce\xb8\x27\xc2\x88\x68\xac\x98\x82\x16\xea\x69\xc8\xd6\x1c\xb2\x88\xc3\xdb\x6e\x70\xf8\x3b\xc4\x77\x6d\x9c\xe4\x08\x3c\xa2\x68\x33\x5d\x77\xe3\x79\x01\x95\xb4\xc7\x72\xf1\x2c\xa8\xaf\x91\x8b\xe7\x6c\x8f\x75\xe2\x79\xdc\x27\xbc\x47\x15\x3c\xd0\x3e\x79\x62\x22\x46\x8f\xf5\xec\x35\x46\x93\x63\x36\xb9\xd6\xc7\x18\x13\x25\x1c\xa7\xb2\x48\x75\x45\xcc\xfd\x86\xcb\x9d\xc0\x45\x5e\x28\x88\x5d\x00\xfe\x44\xa5\x9e\xbf\x99\xca\x4e\xb0\xd3\x5f\xbc\xa6\x23\x12\x62\x5e\xae\x3e\xbd\x87\x21\x63\x6e\x19\xc7\xfa\x8b\x60\xe3\x0c\x17\x4f\x62\x92\xb9\xd3\x96\x2c\x85\x7d\x2c\xc2\x90\x34\x7d\x1a\xb0\x90\x69\xea\x43\xc0\x14\xd6\x12\x76\x16\xf0\xc6\x38\x55\xc8\xb8\x04\x70\xe8\xcc\x82\x36\x00\xcc\x69\xd9\xbb\x4c\x2a\x0d\x3b\xd6\x71\x76\x17\x0c\xbb\x9e\x4c\x7a\x3e\x1b\xb8\xfc\x1e\x8d\x56\x7b\xe5\x94\x61\x95\xf2\xca\xb5\x7d\xd0\xcb\x85\xae\x58\x1f\x66\x22\x49\x48\x35\xc5\x33\x0a\x2b\x33\x51\x2c\xcd\xe4\x3c\x24\x22\xe7\x50\xf9\xf6\xed\x1b\x64\x05\x96\x65\xda\xdf\x3e\xdf\x9c\x9b\x6f\xdc\x96\xf2\xaf\x3c\x46\x65\x11\xcf\x14\xfd\x5c\x41\x2a\x89\x0f\x1d\x66\x1a\x19\xf9\xf4\xa1\x55\x18\xb3\xd5\x4e\x00\xbf\x73\x7d\x7a\x01\x56\x7c\x2f\x59\x01\x1f\xfb\x6a\x9a\xbe\x72\x61\xfa\xaf\x45\x6e\x0c\x1f\xcf\xce\x73\x6a\x35\x58\x08\x71\x9c\x99\x61\xea\xdc\xb1\xf9\x00\x46\x92\x3d\x19\xd4\x1e\xe9\x70\x79\xe4\x5c\x27\xcd\x47\x9a\xef\xfa\xf4\x73\x05\xc8\xb9\x71\xa6\x87\x59\x4f\x68\xf7\x38\xf7\x85\x46\x33\xa0\x8b\xff\xc9\x16\xbe\xe7\x54\x81\xc0\x36\xb9\x50\x3d\x2e\xf8\x2d\xba\xa1\x91\xc2\x67\x07\xc4\xd9\xde\xcb\xdd\xcd\x67\x49\x2f\x99\x0d\xc1\xde\x5c\xd7\x8b\x80\x61\xc4\x94\x7b\xc2\xa7\x56\x56\x43\xdb\x2f\x64\x54\x36\x9d\x67\x45\x55\x2b\x65\xc8\x76\x56\xd4\x39\x26\xee\x4a\x97\x9e\x6a\x3b\xe1\x90\xea\xbe\xf0\x61\xc7\x95\xd4\x0d\xa3\x80\xbe\x87\x4f\xa7\x47\x27\x0d\xb8\xba\xee\x9c\x5d\x5d\xb6\x1b\xd0\xb9\x39\x3a\x3e\x6d\xc0\xf5\xe7\x4e\x03\x4e\x4e\xcf\x4f\x3b\xa7\xe5\x78\x8a\x1d\x23\x17\xa0\xdf\x16\x04\x28\xa3\x9b\x5a\xb5\x30\x44\x72\x73\x4a\xfb\xc2\xb3\xc9\x38\x99\x4a\x39\x1f\xa5\x32\xe6\x95\x8d\x82\x6e\xa6\x13\x25\x4e\x83\xb1\x50\xa8\x7c\xfb\xf4\xf8\xea\xf2\xa4\x5d\xc0\x5e\x43\xf2\x75\x7a\x94\x7a\x43\xa4\xd1\xf7\x73\x08\xc7\x96\x75\x34\x3b\xc3\x28\xe1\xa7\xd6\x63\xc1\x7c\x58\x65\x73\x88\x38\x3e\x54\x5c\x72\xa9\xb3\xa8\xb4\x63\x3b\xab\xa8\xaa\x52\x59\x06\x9b\x72\x7d\xc1\xcf\xce\x41\x43\x14\x7c\x56\x54\xc2\x51\xaf\x2c\xbf\x8d\x15\x95\xc4\xb4\xca\x05\xe6\x68\x41\x60\xb2\x7b\xaa\x55\x2b\xc1\x87\xd6\x5d\x05\x34\xe9\xa9\x7c\x78\x9e\xef\x20\x5e\x1b\x14\xd7\x92\x71\x0d\xc4\xf7\x99\x1d\x62\x5c\x59\xbb\x9c\xc6\x97\x7e\xd5\x94\xfb\xd4\x4f\x9a\x57\x7a\x1b\xff\x24\x06\x86\x88\x3e\xd6\x19\x1e\x79\x66\x43\x44\x7a\x54\xb5\xe0\x5a\xb8\x0a\xc5\x36\xa9\xc6\x7b\xb8\xdd\x12\x8f\xb7\x5b\xa3\x4a\x2c\xbb\x0d\xb8\xdd\x72\x3a\x85\xdb\x2d\xf3\x8f\xe4\x46\x6d\xff\x65\x1d\xbe\xed\xdf\x4a\x33\xef\x71\x68\x1a\x07\xec\x91\x26\xbe\xe0\x0f\xb1\x06\xfc\x05\x6b\xba\x58\xaf\xb5\xdd\xf1\xeb\xe6\xa6\x35\x6a\x62\x1f\x61\x13\x12\x28\x61\x5a\x98\xdf\x77\xcb\x6c\x25\xc1\x93\x39\xe6\x6e\xa7\xee\x6a\x19\x4d\x70\xcd\x72\x86\xa9\x3c\xa9\xc9\x5f\xb2\xb3\x9a\x64\x88\x6b\x79\x3a\x13\xbb\x0e\x33\x60\x20\xd4\xd9\x4f\x0d\xe6\xff\xb9\x52\x8e\x94\xe4\x66\x6e\x76\x99\x4d\x65\x2c\x5d\x70\xe9\xfb\x0b\xf2\x35\xe7\xa7\x92\x35\x7d\x7a\x74\x26\x01\xea\x82\x09\x49\x52\xe5\xa3\xec\x89\xf9\x97\xf7\xee\x8f\xff\x2c\xba\xf4\x64\x8d\xf8\xcc\x95\x36\xd7\x1d\xde\x8a\x40\xbc\xae\x54\x01\x56\xe3\xfa\xa2\x72\x05\x24\x24\xd5\x9c\x2c\x80\x79\xe1\x32\x91\x43\xa6\x59\x46\x22\x5c\x7c\x0e\xc4\xf0\x12\x9b\xe2\x05\x9f\x62\x96\xaa\x24\xe3\x64\x5f\x28\xad\x00\x6b\xe4\x7b\x36\x54\x90\x48\x1b\xac\x7f\x6f\xbb\x88\x18\xef\xdd\xb7\xc0\xd0\x88\x05\x74\x7c\xd6\xed\x52\x49\xcd\xdb\x4c\xb9\x48\xd1\xd1\x8b\x40\xbf\x52\x2f\xd6\x4e\xeb\x66\xab\x88\x6e\xdb\x58\xd7\x9d\x83\xdd\x24\xdb\x80\x4d\xdc\x43\xa4\xa2\xd6\xf5\xdc\x45\x9d\x0e\xfa\xa8\x61\x19\x13\xae\x49\xf0\xa8\xe0\xec\xf8\xe2\xda\xbc\x46\x83\x6e\x2b\xfd\xeb\x6c\xbc\xa3\xa2\x3a\x66\x3e\x48\x21\xb2\x52\xa6\x9b\x46\xe3\xa7\x2b\x3b\x91\xa3\x4a\xd2\x23\x1c\x28\x43\xc9\xea\x81\x02\x01\xc5\x78\x2f\xa0\xe3\xd2\x7c\x12\x2b\x7c\x48\x49\x86\x18\xcf\x69\x1f\xd3\x22\x17\xf4\x9c\xed\x67\x88\xaf\xcd\x7f\xfc\xa6\x73\x34\x6b\x83\x30\xa2\x61\xc8\x82\x80\x65\xa7\xff\xdd\xcf\x2b\x38\x80\x94\x0e\x64\xc5\x12\x51\xc7\xa5\x7c\xa0\x1a\x02\xa1\x32\x12\x8c\x1b\x72\xbf\x9b\xa4\x31\x2f\x43\xb1\xa5\x30\xaa\x36\xe7\x4e\x82\xe3\xac\x11\xa5\x18\xc8\xc3\x62\x20\xbd\xba\x81\xcc\xa6\xf7\xbb\x05\x93\x3d\x5b\x1a\x6b\x80\x52\x89\x58\x7a\x13\x25\xbd\x92\x04\x91\x96\x78\x85\x69\xdc\x8a\xa8\xb2\x3d\x54\x4e\xd8\xd8\x6e\x91\x10\xe2\x08\x2b\xb1\xf7\x5c\xcb\xca\x69\x0b\x47\x62\x1a\xae\x2f\x86\x8d\x3f\x91\x60\x26\xa2\x61\x27\xbd\x1d\xf3\x32\x2b\xa5\x28\xbd\x4b\x7a\xaa\x8d\x62\x4d\x64\x2f\x4d\x71\x01\x49\xf6\xd5\xfa\x48\x1a\x2f\xb0\x3d\x1a\xad\xcd\xde\xa6\xb9\xc1\x7b\x33\x09\xd8\x13\x1d\xe7\xfc\xc2\xf8\x57\xb3\x07\x62\xcf\xa3\x33\x02\xf1\x04\xe9\xd8\xe1\x1d\xb6\xaf\x94\xec\x6b\x32\x44\xf7\x16\x94\xcc\x51\xaf\x48\xbc\xbe\x3d\x37\x5d\xc4\xcd\xd4\x16\x28\x22\xd2\x5c\x66\xef\xe6\xe7\xfb\x5b\x8a\xef\x8c\x73\xcb\x17\xa6\x96\xdf\x9f\x9b\xf6\xcb\xee\x84\x75\xa4\x98\x67\x21\x59\x4a\x20\x0b\x49\x66\x28\xf7\xd9\xc5\x51\x65\x59\xe6\xcd\x18\x15\x0a\x34\xcf\x10\x15\x67\x66\x50\x9b\x54\x63\xed\xc1\x93\xd1\x70\xb8\x38\x74\x8a\x57\x1f\xbc\x2d\xe7\x1c\xbf\x6a\x08\x17\xce\x7a\xbd\x21\x5c\xc7\x2e\x1d\x56\x41\xfe\xe9\x51\x62\x72\x21\x27\x72\x50\xc3\x85\x91\xb3\x3d\x81\x15\xc9\xf1\x52\x3b\xf1\x96\xa5\x3a\xe5\xc9\xc0\x85\xee\x63\x72\x4e\xdf\xb7\xf7\x08\xf3\xba\x1b\x12\x87\x1f\xff\x82\xfd\x74\xb1\x9f\xa2\x0d\x62\xb3\x52\x57\xba\x3f\x5e\x4c\x46\x72\x9c\xe0\x33\x25\x63\x7f\x85\x05\x09\xec\x7e\x78\x3d\x15\x09\x0c\x63\x24\x3c\xcf\xfd\xd5\xb2\xbf\x8a\xeb\x11\xbc\xae\x7c\xea\x08\xc1\x0b\x4e\xa8\x3e\x52\xaa\xbf\xc7\x7f\x96\x33\xc3\xd6\x9b\x4e\x1d\xa1\xdb\xe4\x53\x9f\x5e\x26\xf3\xb0\xa4\xb5\xbc\xe6\x6c\xea\xb8\x50\xdf\x78\x3a\x75\xc4\x60\x93\x4f\xdd\xed\x85\x4d\x42\xf5\xb9\x18\xbd\x86\x8c\xea\x55\xfb\x91\x2e\x90\xeb\x1c\xb1\x49\xf5\x75\xb7\x56\xa7\x93\x82\x84\xe7\x05\x9f\xfd\xcb\x4b\x6f\x5e\xbc\x54\x39\xb6\xda\xd1\x32\x0d\x16\x5c\xa6\xac\x7e\xea\xf4\x60\xaf\x20\xad\x7a\xfd\x1e\xfe\x76\x03\x67\x75\x54\x27\x34\x0b\x98\x65\x53\x22\xc4\xc1\x7e\x39\x5c\x2a\x30\xd2\x22\x2c\xaf\xcb\x48\x8b\x24\xbf\x2c\x23\x6d\x42\x52\xcd\x46\xda\xc0\x5f\x4a\x27\x68\x9a\x4d\x19\x69\x6d\x05\xf0\x58\xd9\xeb\xa4\xd5\x25\x9f\x9f\x1c\x5d\x27\xd9\x19\x33\xb4\x7e\xa6\x97\x25\xb5\x7e\x9f\x84\xd2\x98\x1b\xb9\x01\x67\xd7\x70\x64\xf5\x6e\x0d\x98\xd4\x34\xc2\xce\xa8\x36\x2e\x07\xf2\xa0\x44\x10\x6b\x0a\x11\xd1\xfd\xdd\x67\xd1\x11\x9a\xf9\xd6\xa2\x23\xbc\x4e\xd5\xa0\x9c\x98\xd8\x9b\x3f\xff\xb0\x56\x7d\x20\xce\x70\xbd\xfa\x40\xdc\x63\xe3\xa5\x41\x65\xc1\x28\xe7\xe7\x98\x11\xde\x6e\xed\x88\x87\xdf\xa8\xa7\xbd\x80\x28\xf5\xd7\xff\xd8\xbd\xdd\x2a\x5a\x24\xad\xab\x8d\xde\x1d\x25\xb7\x47\x72\x1f\x88\xa2\xb0\x43\x7b\x2d\x10\xf1\x5f\xc3\x61\xcc\x99\x6e\x88\xbf\x86\x43\x21\x7b\x0d\xef\xaf\xf9\x15\x73\x91\x36\xd3\x38\x97\xb6\xa5\x12\xdb\x5b\x9a\x18\xf7\xe1\xe4\x12\x2b\xe4\x24\x2e\x51\xc5\x74\xb0\x39\xaa\xbe\xa5\xc8\x48\x82\xb0\x17\xa7\xc3\xb4\xa8\x9c\x6f\xb7\x3b\x47\x37\x1d\x23\x1f\x86\xd4\xeb\x13\xce\x54\x08\x8c\x6b\x29\xfc\xd8\xb3\xe1\x71\x91\x14\x5a\x78\x22\x00\xc3\xdb\xcc\xe9\x3b\xad\x78\x9f\xa0\x51\x69\x22\xb5\x0e\xaa\xa7\xd3\x60\xd6\x86\x1d\x84\xee\xe9\x10\x2c\xc5\xba\x2f\xfc\x5d\xe7\xd6\x81\x8e\x8c\xa3\xc0\xb2\xa4\x6c\x79\x12\x60\xf6\xfd\x9b\xef\x0b\xc9\xae\x58\xdc\x4d\x28\x9e\x45\xef\x10\x76\x28\x16\x98\xc4\xfa\x4b\x89\xf7\x67\x11\x6d\x73\xb2\x10\x55\x47\xda\x1b\xd8\xf1\x99\x9a\xa1\xad\x88\xb4\xe2\xfc\x3f\xbf\xc3\x4b\x02\x4e\x7b\x73\x49\xc8\x43\x66\x73\x49\xc8\x84\x65\xed\x97\x84\x76\x5f\x0c\xc0\xa7\x9a\xb0\xc0\x39\x11\x5a\x2f\xbe\x26\x46\x36\xfb\xf4\x21\xee\xf5\xcc\xe7\x54\xfa\x83\xa7\xf2\x41\xcc\xd1\x5d\xaf\x2e\xaa\x8f\x8a\x0d\x95\x13\xd5\x05\xc9\x2d\xcf\xe0\xc5\x52\x52\xae\x9d\x77\x23\xa0\xe7\x05\x79\xc2\x90\x8e\x2c\x71\x5d\x90\x55\xca\x29\x1c\x34\x43\xc6\x8d\x88\x36\x9b\x23\x60\x21\x7f\x23\x33\xfc\xdd\xc0\xfc\x7f\x71\x16\xc3\xb2\x9b\xa2\x83\x79\x81\x17\xa3\xed\xed\x5c\xda\xde\x55\x4e\xdb\xc1\xa2\xc4\xe5\x4a\x20\x63\xe0\x6a\xa0\x2e\x21\x2e\x23\xe5\x42\x71\x31\xa4\x09\xf2\xbc\x9a\xd7\x75\x1e\x75\xb9\x62\xd0\x88\xb8\x3a\x17\x76\x1e\x75\x85\xdb\xce\xab\x61\x65\x4f\xd8\x13\xf3\x6d\x31\xb4\x34\x53\x50\x86\x1f\xea\x09\xcf\xb2\xe3\xeb\xcf\x0a\x76\x30\x4c\x2f\x72\xc1\x3c\xbb\x8b\x6b\x39\x70\x02\x11\x95\x5e\x14\xd7\xcb\x3c\x43\xc2\x82\x2f\x4b\x70\x4f\x6c\x97\xe1\x8e\xae\xa6\x60\x08\xa9\x52\x08\x90\x0b\x83\x36\xed\xe0\x4b\x4c\x63\x0a\x3b\x2a\x8e\x8c\xbc\xad\xc6\x9e\xea\x8a\x72\x7f\xfc\x86\x6a\xc0\x17\xf3\xaf\x2c\xc7\x28\x1c\x7f\x49\xa6\x3b\xba\x73\x5e\x30\xde\xca\xa1\xd5\x92\xa8\x05\xf4\x28\xa7\x92\x8c\x99\x4c\xce\x82\x21\x3d\x73\x25\xbd\xd5\xea\xbf\x95\x22\x77\xf4\xe9\x90\x80\x4a\x0d\x3b\x30\x80\xbf\x80\x07\x79\x57\x07\x4b\xff\x5c\x79\x6c\xa9\x09\xe4\xd1\x8d\xc5\x47\x48\x48\xc1\x17\x18\x76\x50\x04\x7b\x11\xd5\xb6\xf9\x42\x62\xf6\x5a\x49\x9f\x59\x82\x5f\xe1\x2f\x70\x3c\x67\x09\xdc\x64\x16\x92\x8c\xcb\xce\xe6\x3a\xcf\x39\x73\x24\xf3\xc2\x5f\xe1\xe0\x5d\x31\x81\x6b\x71\xc9\x0c\x87\xea\x4b\xb0\x0c\x5b\x32\xed\xb2\xa4\xba\xb4\x3f\xa6\x16\x40\xe0\x62\xd8\xfe\xdb\xf9\x8c\x3b\xd8\x78\xae\xa6\xa3\xe7\xd2\xc1\x96\xb9\x73\x64\x96\x40\x4b\x5f\x3a\x3e\x2d\xe2\xd9\x70\x74\x72\x72\x73\xda\xce\x09\x7e\x47\x2c\x16\xab\xb5\x96\x79\x2b\x59\x36\x8c\x77\xac\xbc\x4d\xdd\xc9\xde\xbc\xd9\xff\xbe\x64\xf6\x95\x22\xdd\xed\x02\x89\x24\xec\xf4\xd7\xab\xbc\x3d\xc3\xc4\x46\x98\x6f\x91\x72\xc3\x08\xf0\x8e\xda\x25\x2c\x88\xcd\x63\xee\x3b\x43\x02\xd6\x8b\x31\xf4\x8d\x36\xf8\x13\xd3\x43\x10\x3c\xc8\x73\x48\xb3\xb3\x71\xb9\xe6\x4c\xff\xd5\x7a\x6b\x20\x55\x3e\xd1\x04\x55\xb9\xe8\xcd\xc3\xb8\x8f\x76\x6c\x3f\xab\x66\xe3\x1c\x3f\x03\xd7\xd1\x2a\xae\x06\x76\xc2\x99\x3d\xd5\xb9\x7b\x6f\x28\xf1\xad\xe3\xcc\xa4\xe7\xb7\xcb\xc8\x94\x14\x8f\xe9\xb2\xa0\x1c\x24\xa6\x41\x2e\x1c\x05\x11\xd4\x93\x70\xcc\xf4\x52\x6b\x42\x18\x65\x1d\x12\x27\x26\xde\x93\x22\x8e\x4a\xcd\x1c\x5b\xe4\x4e\xbd\xb7\xe8\xd4\x67\xbb\xa9\x35\xb9\xa1\x2b\xfd\x6a\x0b\x8b\x98\xad\x30\xfe\x1c\x92\x04\xab\xa5\x73\x54\x14\xf2\xfb\x78\x51\x20\x32\x7b\xaa\x7b\x1f\x4c\x22\x30\x32\x6a\x98\x23\x79\xcc\xeb\xe8\x2a\xee\xaa\x49\x9f\xab\x98\xeb\x1c\xcb\xcf\xea\xa9\xde\x4c\x98\x86\x7b\x3a\x33\xab\x0a\x6c\xd9\x6d\x69\x18\x09\x53\xa3\xca\x9e\x91\x14\x11\x95\x73\xf8\xbb\x95\x86\xb0\x8b\x4a\xf9\xfb\xe9\x57\x66\x8b\xe7\xc1\xaf\x93\x1a\x76\xd6\x75\x04\x3b\x67\xe4\x89\xbc\x3e\xee\x14\x1c\x49\x9b\x0f\xb4\xcf\xb8\x0f\x21\x51\x3a\xb7\x44\x91\x9d\x47\x1d\x32\xfd\x78\x0e\xc7\x53\xda\xf0\xfc\x49\xd0\x55\x26\x51\x8b\x2c\x6f\x3e\x26\xa5\x02\xa0\xdc\x93\xc3\x48\x93\x02\x0f\x2d\x4b\x45\xd5\x36\xab\x6b\xa2\xfb\xe6\xbb\x3d\x3e\x02\xc5\x7a\xa3\xa2\xb3\x1e\x95\xe5\xd2\x1f\x14\xe6\x13\x24\x8b\x7e\xab\x1e\x59\x6b\xc2\xc0\x64\xf2\xed\xf6\x79\xda\x7d\xf0\x39\x26\xfe\x1c\xd3\x4e\xb2\x22\x9a\xe9\x3f\xd2\x72\x11\x22\x45\x49\x10\x17\x48\x28\x64\x67\xbd\xce\x14\x87\xa9\x8d\x6e\x33\xcb\x88\x99\x2a\xfb\x73\x16\x9a\x34\x7d\x96\x9f\x45\x69\x01\x97\xd0\x64\x8f\x4f\x77\x53\xe7\xb4\xcf\x5d\x72\x5c\x5b\x98\x12\x37\x3a\x8b\xfa\x65\x53\x39\xba\x36\xb9\x93\x3f\x5f\x78\xf2\x19\x1d\xad\xb5\xe0\xaf\x25\xe3\x4b\x4c\xe5\x70\x59\xc5\x84\x6d\x9d\xa9\x35\x25\x80\xbf\x25\xa6\x5a\x97\x2b\x3c\x15\xb1\x1f\xd0\x27\x1a\x28\x9b\xa4\xc3\xbd\x34\xba\x5d\xd8\xa6\xe3\x10\x48\x1e\x87\x54\x32\xaf\x05\x1f\x31\x01\xa1\x96\xc4\x56\x06\x66\x7a\xd8\x00\x4f\x52\x1b\x21\x64\xe4\x3f\x7b\x0e\x86\x8c\xb3\x90\x04\x40\x3c\x8f\xaa\x2c\x87\xb4\x14\xf5\x1b\x9d\xc8\x34\x22\xdf\xba\x66\xc4\x82\xb0\xe6\x60\xd7\x97\xaa\x67\xb0\x60\x6c\xb4\x0d\x19\xa0\x7c\xc3\x3a\x07\x0b\xc0\x46\xf3\x30\x01\xc7\x46\xff\xb0\x18\x63\x5d\xb7\x16\x62\x64\x6f\x6c\xff\xed\x1c\xfe\x86\xa2\x85\x16\x20\x63\x0e\xc2\xda\x70\xad\xe9\xa4\x5d\x3e\x92\x7e\x52\x80\x98\xc6\x65\x81\x50\xe2\x34\x2e\x2e\x0d\x59\xb1\xa9\xb2\x4a\x5c\x8a\x74\x1f\x56\x02\x63\xe8\x40\xa6\x30\x72\xd2\x2a\x71\x24\xe1\x3d\x8a\x89\xa0\x43\xa2\xdf\x03\xba\xbb\xbe\xa7\x7c\xc6\x71\xb7\x36\x47\xc4\xb1\x38\x73\x73\x74\xf9\x53\x4e\xf2\xf8\x34\xac\x4b\x3b\x2b\xae\x8c\x6a\x86\x36\xa6\x10\xd6\xb5\xb9\x2c\x96\xc6\x70\x79\xb7\xc6\xaa\x2e\x2b\xdc\xe5\x83\x5c\xe2\xa6\x92\x34\xcd\x75\xee\xf0\x02\xe1\x3d\x82\xe8\x76\x15\x1d\x47\x99\x5a\x8f\x18\x2f\xa9\x50\x8e\x19\x00\x41\xd2\x50\x68\x0a\x97\x9d\xeb\x59\x43\xab\xcb\x8b\x6e\x6e\x10\x5b\xad\xa9\xa1\xa1\xf9\x09\xb8\x8e\x4c\x1b\x68\x0e\x60\xbf\xf5\x0e\x9a\x1e\x1c\xcc\xde\x4b\x92\x06\x2b\x78\xdf\xbd\x80\x14\x39\xbc\xa6\xba\xf1\xd9\xd7\x84\x83\xc3\x37\x15\xde\x12\x16\x38\xcc\xf8\xda\xab\x99\xdf\x60\x1d\x28\x05\x9f\xf9\x23\x17\x03\x8e\xe9\x23\x8d\x80\x2c\xba\x13\xb5\xa1\xdc\x16\xf6\x08\xe7\x02\x6f\x9d\x58\x2c\xaa\x60\x91\xbe\xc4\x8c\x56\x5b\x31\xff\xca\x92\xf0\xa2\x7c\xd7\xc7\xec\xae\xf3\xe9\xe6\xb4\xfd\xe9\xea\xfc\x24\x1f\x92\x75\x1f\x17\x59\x80\x3d\xbf\x53\x7b\x29\xc8\x2a\x3c\x1d\x16\x3d\x62\x5d\xba\x0d\xb7\xe1\xdd\x21\xca\x75\x34\x4e\x6a\x13\x10\x2c\x64\xa7\x85\xe3\xe2\xee\x87\x79\x49\xda\x12\x06\x6c\x7b\xae\xf4\xd3\x78\xf1\xae\xfa\xfc\xd5\xe5\x5c\xe6\x2f\x2e\xe5\x32\x5f\x4b\xc6\x65\x3c\x81\x28\x95\x4b\x4a\x43\xa6\x69\xae\x34\xd4\xa7\x24\xd0\x7d\x4c\xfd\xcb\xd3\x92\x0e\x9c\x69\x18\x39\xb8\x8e\x72\x32\x9b\x16\xee\x2b\x1c\x67\x05\x1c\x72\x0f\xcc\x18\x0d\xfc\xe7\x6f\x4c\x6b\x2a\x51\x82\x52\x5a\x12\x1d\x87\x49\x6d\x34\x3b\xf6\x80\x05\x01\x98\x03\xcb\xa5\xa5\x2c\x21\x91\x19\xf2\x1c\x7d\x3f\x42\x14\x50\xa2\x30\x30\x19\xee\x93\xad\x7c\xef\xd2\x3e\x10\x0d\x51\x2c\x23\x91\x5e\xb7\x09\x89\xad\xcd\xcc\x9f\xa9\xf9\x5a\x6a\xde\xdf\x72\x80\xd6\x14\x74\x39\xd2\xdc\x2d\xbf\xe5\x60\xf5\x78\x6e\xca\x5a\x88\x06\x90\x27\xc1\x30\x5f\xc9\x88\xab\x73\xe1\xcc\x6b\xa8\xc3\x61\xdd\xe4\x75\xa6\xf8\xb6\x06\xf2\x44\x58\x40\x1e\x02\x7a\xcb\x61\xa7\x4d\x29\x5c\x0a\xcc\x00\xf3\x20\x5c\x06\x4f\xb4\xe0\x26\xb1\x2d\x78\x83\x75\x2a\x75\xe5\x6a\x79\xa9\xdd\x32\x64\x43\xf3\x37\x68\x1e\xbc\x3f\xd8\xdf\x87\xe6\xa3\xf9\xeb\x70\x7f\x1f\xa7\x72\xc5\x83\x61\x6a\x4d\xc6\x4e\xa3\x31\x86\xcc\xd8\x60\x2c\x9b\xb1\x56\xc1\xce\xed\x96\xd9\xd9\x5e\x9f\x85\x54\xaa\xdb\xad\x05\x48\x08\xe1\xff\xbd\x83\x26\x87\xff\xf7\x26\x85\x9c\x30\x83\xba\x6d\x32\xbf\x8b\x5f\xe1\x2d\x34\x8f\xe1\xfb\x6c\x41\xda\xbc\xbe\x11\xa4\xf3\xa6\x97\x44\x86\xc6\xe9\xd4\x6f\x5a\x18\x71\xfa\x77\x2e\x4d\x6f\x64\xd4\x0a\x00\xdb\xc8\xa8\xf3\x0b\x83\x4d\x26\x7b\x47\x17\x7b\xcb\xd9\xb0\x46\x2b\x1e\x33\xdb\x0a\x8f\xcb\xbe\x14\x7c\x54\x85\x9c\xe6\xba\xdf\xe0\xe2\xbb\x3e\xaa\x75\x73\x9d\xcd\xa8\x5e\x11\xb9\x5e\x1d\xe4\x66\x83\x6b\x8f\xd1\x22\xe8\xec\x1b\xeb\x40\x6e\x2e\x2d\x5e\x0d\xb4\x64\xc3\x52\x78\x70\x17\x6e\xb4\xea\xb3\xd1\xe7\xa0\xb5\x2c\x89\x5e\x0d\x24\x6e\xae\x69\x59\xa8\x6c\xae\x69\x4b\x5c\xd3\xa2\xde\x72\x41\x3f\xd8\x2e\x2b\xe8\x87\xc0\xb5\x50\xba\x27\x69\xfb\x6f\xe7\x70\xf2\xe1\xa2\x6d\xe6\xe9\x53\x4d\x65\xc8\x38\x85\x41\x9f\x62\x59\x17\x66\x73\xf8\x7a\xa8\x01\x41\xcd\x35\xa6\x29\x35\xac\xe1\x4b\x4c\x25\xa3\xaa\x05\x67\xdd\x91\x8b\x8e\x11\x4e\x47\x06\xf6\xb1\x75\xf5\x1e\xc9\xb0\x16\x80\x94\x2c\xdb\x00\xb4\x6f\x04\x01\x3c\xd0\xa4\x74\x8e\x0f\xa4\x6b\x6e\x30\xc9\x52\xd8\x5c\xbe\xa9\xf4\xd4\x05\x5e\x3e\xe3\x04\x85\xce\xcb\xc7\x48\x17\x42\xfa\x36\x01\xb0\x2b\xee\x63\xc6\x1c\xbb\x10\x25\x4d\x53\x37\x1f\x66\x4e\xa8\xac\x0a\x3a\x38\x89\x8d\x8f\xcf\x18\x8b\x97\xe2\xdd\xf3\xee\xed\x9b\xc3\xf5\x7a\xf7\xd8\xe9\xaf\xf7\xae\x71\x92\x78\xf4\x8c\x52\xa5\x8d\x11\xd0\x34\x8c\x02\xa2\xe9\x41\x39\x18\xaa\xf0\xed\xb1\x50\xac\xdd\xab\xe7\x5c\x18\x5e\xc6\x5d\x71\xf2\x58\xe5\x4a\x48\x96\xbe\x85\x1c\x2a\x4a\xef\xc6\x51\xde\xa9\x0f\x67\x3f\x41\xfb\xf4\xf8\xf3\xcd\x59\xe7\x1f\x70\xd6\x6e\x7f\x9e\xa9\x58\x3c\xb5\x73\x16\x71\x5c\x28\x2d\x11\x8d\xe5\x8b\x88\x48\x12\x1a\x66\xae\x60\xe7\x91\x0e\x91\xc8\xbf\xda\x82\x99\xbb\x0d\x50\x94\xc2\x03\x0d\xc4\xa0\x90\x46\xe7\x19\x54\x29\x89\xaf\x20\x2d\x91\x9d\xfc\x26\x2f\x51\x2e\x34\x9b\xc4\x44\xd9\xb8\xac\x3f\x33\xd1\xdf\xce\x13\xe9\x05\x7d\x90\x5a\x56\xcf\xda\x65\x12\x2b\x96\x04\x71\x88\xc1\xf7\xf6\xdf\x52\x0c\x46\xa2\x96\xa4\xa4\x5c\xf6\xe6\x95\x9d\x93\x52\xf2\xdf\xda\x4e\x88\x31\x3c\xc8\xf7\x8a\xb9\x8d\x2f\x62\xcc\x42\x52\x1a\x95\xe6\x3c\x96\xf3\xeb\x8a\xce\x33\x29\xe8\xd6\xae\xad\x2b\x84\x70\x86\x2f\x2d\x8f\xe1\x5c\xe6\x74\x5c\x21\x88\xcf\xef\x81\x14\x31\xde\x5b\xe6\x2e\xc7\x78\x6f\xf2\x2a\x17\x2b\x57\x6a\x14\x8b\x8f\x26\xe5\x45\x31\x08\x49\x3c\xd0\xac\xba\x5a\x5d\x21\x27\xea\x1f\xee\x44\x54\x7a\x94\x6b\xd2\xa3\xbb\x78\xbf\x93\x22\x36\x5d\x48\x16\x25\x09\x7c\x72\xeb\xe5\x8d\xd1\x4d\xef\xc9\x57\x69\x1d\x31\x33\x78\x1d\xf5\x45\x91\xd2\x17\x5d\x5f\xd4\x52\xf8\xe2\xeb\x8b\x22\x99\x2f\xbc\xbe\xa8\xa5\xb1\x06\x28\x97\x2c\xe3\x39\xcf\xbb\x7b\xb6\xae\x67\x49\x0b\x1e\x4e\x78\x91\xfa\xa0\x95\x0a\x52\x25\x8a\x33\xee\xc3\x0e\x17\xc9\x5b\xeb\x17\x34\x0d\x3c\x15\xca\x99\xcb\x9e\x5f\x62\x99\xfc\xef\x91\xc8\x2c\x09\x79\x7d\x55\x59\x45\xc8\x48\xbc\xf2\x82\x90\x91\x78\x09\xf5\x20\x67\xb2\x2e\xd6\x6b\xb5\x37\x93\xde\x94\x83\x5c\xa4\x1c\xa4\x41\xea\xf7\x5c\x0d\xd2\xcc\x6f\x53\x0c\x72\xd1\x62\x90\xb8\x1b\x7e\x2f\xb5\x20\x91\xf3\x7d\xd3\xa5\x20\x0d\x02\x9b\x4a\x90\xf9\xb7\xfb\xfc\x02\x83\x06\xb9\x4d\x21\xc8\x97\x5f\x08\xd2\xac\xd3\x37\x5e\x07\xd2\x40\xb0\x29\x03\x69\x77\xc2\xa6\x0a\xe4\x3c\x88\x36\x45\x20\x73\xa1\x79\x3d\x35\x20\x51\xa8\xfd\xf6\x4a\x40\x9a\x69\x6f\x8c\xa8\x39\xc0\x6c\x4c\xa8\x59\xa8\xbc\x2e\x4f\x44\x43\xf1\xcb\xf2\x44\x74\x14\xd5\xed\x89\x28\x85\xa7\x96\x51\xff\x99\x76\xd9\xf9\xbd\x82\x00\xcc\xaf\x54\x29\x23\x98\x70\x7f\x94\x26\x5e\x8d\xd2\x49\x08\x39\x99\x03\x81\xaa\x51\x2e\xd0\x91\x9a\x30\xa4\x1a\x7d\xfe\xc6\x29\x11\x30\x1f\x42\x92\xb2\x63\xac\x81\xc7\x14\x09\x2e\x5f\x98\x6b\xe4\xa7\x30\x4e\x29\xc7\x13\xaa\x5a\xd0\x76\x05\x02\x59\x80\x5e\x35\xae\x74\x25\x89\xa2\x80\xd9\x0b\x70\xc0\x42\x66\x3d\x0a\xc7\x73\x49\x3c\xb5\x72\x22\xc5\x52\xc0\x40\x73\x00\x87\xef\x0f\xa1\xe9\xc1\xe1\xfb\x83\xfd\x43\x0c\x46\xc2\x00\x39\xca\xb5\x1c\xde\x72\x18\x41\xc1\xba\x18\xe2\xa6\x07\x22\x35\x12\x5e\x09\x12\x03\x20\x7a\x45\x8d\x1b\xb7\x4c\xeb\x74\x70\xf7\x9f\x02\xfd\x23\x1c\x1a\x4c\xff\xd4\xd3\x3f\x02\x0e\x37\xea\x0a\x23\xa8\xa6\x28\x3b\xd8\x87\x26\x81\xed\xbd\x58\xc9\x3d\x8c\x9b\xdb\x7b\x60\x7c\x2f\xa2\x32\xd8\x86\x66\x0c\x52\x08\x9d\xa6\xd0\xe6\xf4\x37\x03\xd9\xee\xf3\xe8\x24\xb2\x17\x87\x94\xdb\x14\xf4\x9a\x30\xd3\xd8\xf4\x93\x3d\x90\x69\x21\x06\xdc\x16\x58\xb2\x43\xce\x52\xfa\x6e\x7f\x7f\x7f\x1f\x83\xd1\xf6\xed\x5f\x4d\xbb\xc0\x7f\xfd\xa5\xfd\xdf\xa6\xeb\xa3\x84\xb4\x5f\xda\xff\x6d\x03\x13\x87\x29\xea\xc4\x13\x95\xf0\x6e\xff\x67\x03\xcd\xc1\xfe\xfe\xcf\x79\x58\x78\x70\x98\xea\xfa\xf8\xfa\xf3\x44\xd7\xc7\xd7\x9f\x73\xba\x3e\xd8\xff\xee\x3b\xd3\xf7\xe1\xfe\x77\xdf\x65\xa8\xaf\xcd\x10\x2b\x28\xb0\xdd\x60\xe0\x89\x98\xeb\x79\x85\x7f\x0e\xdf\x95\xd3\xf2\xd6\x9d\x67\x05\x27\xbf\x76\x07\x87\x59\xd8\xe6\x96\xd5\x99\x31\x28\x3e\x73\x72\x15\x0b\xdc\xda\x83\x92\x8e\x5d\x34\xe7\xc8\x6d\x3a\xf1\xa9\xb6\x1f\x45\xb9\x2b\x25\x36\x59\xe6\x42\x99\x0a\xdc\xfa\xc7\x75\x21\x40\x19\x63\xd4\xaa\x59\x9e\x14\xb8\x52\xd6\x45\x3c\x9d\xd6\x2e\x5e\x21\x06\x6b\x17\xb0\x3e\xe2\x69\x69\xb8\xf6\xe8\x2b\x33\x07\xa4\x96\xc4\x67\x76\x54\x18\x90\xa1\xe1\xe7\xd7\x67\x27\xe9\x54\x24\x7b\xe6\xf5\xbd\x88\xf9\x7b\xf4\x2b\x2d\x21\x01\xd9\x69\x8e\xbb\xaf\x54\x38\x43\xef\x3a\x65\x4e\x7e\xf4\xa2\x19\x9f\xf2\x7d\xa2\xa1\x4f\x9e\x28\x08\x4e\x21\x09\xab\x76\xda\x64\x77\xdf\x30\x2b\xac\x60\x28\x62\x27\xaf\x94\x33\x16\xa0\xc4\xb3\x8c\x65\x65\xfc\x7d\xb4\x3b\x47\x9d\xcf\xed\x8f\xe7\x47\x3f\xe5\x79\xf4\x23\x76\xb3\x23\xd5\x1a\x0d\x3a\x81\xa8\xd7\x67\x81\x2f\x29\x4f\xa0\x8b\x08\x16\x1a\x4c\x76\x0e\xee\x10\x97\x9d\xae\x9c\x81\x32\x62\x4b\x65\x9c\x1b\x83\x77\x7d\x7d\x96\x13\x10\x6a\x51\x9b\x19\x61\x7d\xa0\x4d\x89\x56\x46\xac\xe9\xb3\x5e\x9f\x4a\xab\xfb\x5b\x0e\xb1\x27\xf5\xef\x5c\xc0\xfe\xbd\x08\x60\xbf\xb4\xff\xbb\x08\xaf\xe9\xfe\x9f\x0d\xae\x9b\x76\xbb\x02\xb8\xa4\xca\xd7\x86\x2e\x64\xdb\xb8\xc9\x0d\xb3\x41\xb8\xa6\xfb\x7f\x36\xb8\xae\x8d\x68\xbb\x3a\x5e\xd1\x74\xe9\xbe\x05\xa3\x6f\x52\x1f\xe4\xf1\xf5\xe7\xc2\x0f\x72\x5e\x71\xc0\xb5\x41\x86\x99\xa4\x6d\x98\x8a\x5c\x9e\x85\x99\x5e\x72\x11\x2b\xc8\x2d\x3a\x46\xec\x73\xfb\xf4\xa6\x08\xb1\x99\x11\x9e\x0d\x31\x22\x7b\xee\x4c\x75\xb7\x42\xb0\xa3\x14\x9e\xf9\xc9\x55\x72\x2d\x07\x7e\x0e\x99\x56\xdb\xd0\xa3\x5f\xcb\x10\x7c\x87\x2d\x6a\x24\x9b\x7e\x25\x9e\x86\xc4\x74\x28\xba\x70\x7c\x75\x71\x71\x74\x79\x02\x3b\x66\x1a\x22\xd6\x4b\x04\x18\xba\x0b\x7c\xee\x8e\x5c\xc8\x5d\xdb\xd1\x51\x78\xab\xc9\x18\x67\x7d\xfb\x92\x0b\x0e\x8f\x54\x72\x1a\xb8\x52\x33\xaa\xac\x24\xca\xc5\xa3\x6b\x59\xaf\x4e\x4e\xb1\x90\x2c\xe3\x92\x87\xed\xb2\x9c\xf2\xda\x67\x17\x47\x95\xb9\xe5\xe1\x28\xaf\xdb\x31\x0f\xa7\xf0\xfc\xae\x79\x3f\xfc\xb0\xde\x84\x3a\x76\xda\x1b\xe7\xbc\x45\x9c\xf3\x2c\x56\xbf\x67\xf7\x3c\x3b\xc3\x8d\x83\xde\xa2\x0e\x7a\x6e\x47\xfc\x5e\x5c\xf4\x1c\x0f\xfc\xa6\x9d\xf4\x2c\x06\x1b\x37\xbd\x65\xdc\xbf\x2c\x76\x1b\x47\xbd\x97\xef\xa8\x67\x57\xea\x1b\x77\xd5\xb3\x20\x6c\x9c\xf5\x92\xdd\xb0\x71\xd7\x9b\x0f\xd2\xc6\x61\xaf\x00\x9c\xd7\xe3\xb2\xe7\x04\xdd\x6f\xcf\x69\xcf\x4e\x7c\xe3\xb6\x97\x0b\xcd\xc6\x71\x2f\x1b\x97\xd7\xe5\xba\x67\x69\x7e\x59\xce\x7b\x23\x9a\x6a\x76\xdf\x53\xa1\x5e\x4a\x53\x18\xea\x29\x45\x21\x26\x93\x21\x5a\xd3\x30\xc2\x7c\xbe\x22\xa2\x1c\x08\x87\xf6\x45\x27\xad\x39\x1c\x2b\x0e\xfb\x42\x65\x65\xd5\x33\x3d\xbf\x72\xe5\x60\x58\x7b\x6e\xed\x05\x74\x83\x87\x25\x83\xf5\x57\x55\x0d\x86\x6b\x4f\xb6\xdd\xa1\x4a\x03\x81\x8b\xa3\xb3\x73\xf8\x78\x73\x75\x31\xf2\x23\x1c\x6d\xb1\x1e\x7b\xa2\x1c\x68\x48\x58\x30\xda\x11\x65\x40\x31\x37\x83\x5c\x50\x16\x28\xe9\x88\xa0\x98\xd1\xef\x66\x7a\x5a\xb7\x96\xcc\x66\x7d\x0a\x18\xa7\xe3\x94\xcb\x23\xd9\x38\x75\x64\x6c\x1f\x1e\xee\x6f\x97\x3b\x35\x2a\xd0\x8c\x19\x9c\xd6\xac\x18\x73\x7c\xc9\xee\x98\x9d\x90\x0c\xcd\x97\x14\x2b\xea\x83\xa4\x11\x25\x9a\xfa\xc1\x70\x6d\x56\xb0\x09\x20\xd6\x6d\xe5\x1a\xd5\xbc\x19\x6d\x07\x9b\x1d\xb5\x3a\x64\x92\x8e\x73\xa1\xb9\x59\x10\x9a\xcc\x8e\xea\xc4\xe6\xe3\xdf\x4e\x2e\xed\xdc\xcd\x6d\xe1\xd3\xe9\xf9\x55\x29\xfe\xf1\xc5\x9f\x51\x5d\x8c\xe6\xfc\x71\xc1\x39\xf7\x69\x20\xee\x66\x7a\xaa\x73\xd2\xaf\xe6\x1e\x89\x5f\xcb\xb3\x5e\x23\x3b\x47\x37\x9d\xce\x79\xbb\xc4\x5d\xd2\xd0\x8c\xb5\x2d\x75\x50\xad\x74\x80\x0c\xed\xe8\x73\xe7\x13\x98\x99\xcd\x66\x85\x05\x2e\x38\x6d\xd8\x32\x28\xe7\x57\x3f\x9d\x5d\x26\x35\x77\x68\xc9\x12\x9b\x24\xd6\x7d\x04\x2f\x6f\xe9\x8e\x16\x5c\xba\xcc\x8e\x6a\xe7\xf9\x08\xd1\x52\x55\x7d\x0d\xbd\x85\x9e\x37\x9f\x4b\x4c\x7c\xad\x0e\x36\xe3\x89\x27\x99\x66\x4b\x4f\xdc\x34\x5c\xc6\x49\x6b\x66\xe2\x33\x1d\xd5\x39\xf1\xb3\x1e\x37\xf7\xe4\x2e\x61\x41\x2c\x31\x8d\xf9\x58\x61\xf8\xb7\xcf\x67\x9d\x74\x92\xbc\x4c\x13\xea\x04\xf9\x0c\x7b\x9b\x6f\xef\x29\x4b\xe5\x6b\x50\x05\x85\xab\x54\x87\xf9\x5d\x6b\x82\xc2\x95\x8a\xc0\xfc\x6e\x15\x41\xe1\xab\x2b\x26\x61\xbf\xf1\x97\xa5\x06\x0a\xd7\x52\x4e\x42\xf1\x70\x29\x2d\x10\x0f\xa3\xdc\x6a\x7f\xee\xc3\x14\xdd\xa4\xb6\x71\x48\xbc\x3e\xe3\x2e\xa4\x53\x3c\x68\xc2\xb8\x02\x35\x54\x9a\x86\xc0\xb8\x35\x44\x9a\x0d\xfc\xc4\x08\xb4\x2f\x2f\xae\xb3\x94\x43\x3c\x7c\xed\xca\x21\x1e\xd6\xa3\x1c\x1a\x95\xa2\x37\x13\x35\xf0\xc1\xd5\xd9\x49\xa9\x8f\x5e\x14\x84\x45\x88\x45\x2c\xc8\x57\x67\x27\x3b\x6a\xb7\x60\xde\xd3\x23\xd4\x5a\x83\x7e\x84\x83\x39\xe2\x63\xce\xf4\x70\x7a\xc1\xa3\xf8\x21\x60\xde\xed\x56\xe9\x5b\x3e\xf6\xb6\xd2\x3d\xdf\xa0\x91\xdd\x53\xdd\xe1\x8d\x08\x89\x11\xfb\xa7\xd1\x38\xf8\xfe\xa0\x24\x14\x2b\xeb\x0c\x0d\x0a\xeb\xd5\x19\x5e\x8e\xae\xb4\x92\x6a\xc9\x68\x72\x87\xc5\x2b\xbe\xf3\xd9\x46\x84\x24\xfd\x12\x53\xa5\xcb\xe9\x0b\x5d\x9f\x2b\xa9\xc2\x0c\x26\x59\xfd\xd4\x9e\xf1\x74\x36\x40\xb8\xe0\x4b\x9e\x71\xca\xa8\x42\xb7\x9d\x11\x6b\x5b\x40\x02\xfa\x80\x54\xcb\x41\x75\x2c\x39\x5c\xfd\x6c\x5d\x74\x46\x09\x05\x9c\x1b\x8f\xf3\xe1\x41\xff\xf9\x60\x38\x56\x32\x3b\x2f\x12\x74\x68\x29\xe5\x7e\x89\xfd\xae\xe4\x80\x69\x60\xc8\xe8\xa6\x4e\x16\x92\x01\x12\xfd\xaa\x29\xf7\x51\x3d\xd8\x8b\x03\x22\x81\x7e\x8d\xcc\xf1\x66\xce\xf2\x9b\xd3\x9f\x4e\xff\x0e\x13\xfe\x4f\xab\x60\x46\x25\xcd\x47\x6c\xb1\xd0\x2a\x43\x50\xc1\xae\x9a\x19\x61\xcd\x60\x7a\x44\xd1\x26\xe3\x8a\x72\xc5\xb0\xc8\xd6\x08\xdd\x1a\xa0\x64\xcb\x28\x64\xcb\x61\xc9\xd6\x06\xe6\xb5\xa4\x5d\xf6\x15\x02\xf2\x40\x03\xd4\xc7\x2d\x8b\x0c\xf6\x90\x8b\x4c\xb0\xe0\x77\x39\xdb\x4b\xad\x7a\x0e\xfe\x44\xa5\x06\x65\xb3\x92\xb8\x6b\x32\xe6\xef\xb7\x5b\x6c\x32\x59\x8a\xd9\x68\x5d\x11\x4f\xdb\x18\x26\xe8\x67\xd8\xe3\x9d\xed\xb1\xda\x0b\x11\x67\x5a\xd9\x75\xda\x51\xbb\x33\x4b\x05\x3b\xb4\xd5\x6b\x35\x60\x5b\x51\xaf\x55\xd2\x14\x65\xc4\xa9\xfc\xe3\xb7\x20\x30\x6e\x62\xea\xb3\xbd\xd4\xb9\x74\xbf\x50\x89\xac\x32\x29\x98\x7c\xda\xea\xb5\xe0\xa0\x01\x87\x0d\x38\xf4\x40\x48\x98\x8e\xf1\x98\xa0\xf5\xc9\xb6\xae\x74\x81\x2e\xce\x3e\x6c\x2b\x47\x4f\xc3\x6a\xc8\x40\xd1\x88\x48\x8c\x53\x9c\x12\x1b\x8f\xce\xcf\x4b\x8a\x8d\x21\x7b\x08\x98\xca\x97\x1c\x17\xf1\x41\x34\x53\xcf\xea\xa7\xd6\x14\x17\x02\x3f\x09\x05\x06\x07\x88\xa8\x74\x29\xe1\x5b\xf0\xd1\xc6\xd5\x85\x51\x40\x1b\xe0\xea\x19\x7f\xbf\x6f\xcd\x68\xf6\xc3\xd4\x02\x1b\x84\x8c\xc7\xba\xf0\x6a\x68\xfa\xbe\x0b\x6d\x04\x03\xab\xb8\x88\xeb\x07\x21\x02\x4a\x78\x0b\x4e\x39\x96\x42\xc5\x79\x78\x24\xf0\xe2\x80\x14\x99\x2c\x12\xba\xea\x21\x06\xed\x28\x46\xe4\xfe\xe9\xb4\x73\x79\xfa\xf7\x4e\x09\xe5\x88\x21\xac\x47\x35\xa7\x5f\xab\x95\x04\x51\x18\x4d\x14\xc3\x73\x2a\x00\x1c\xec\x8f\x9e\xaf\x5b\xc3\x66\xa6\xff\xfc\xd9\xff\xd5\x72\xe9\xff\x55\x4e\xfe\xff\x76\x85\x05\x00\xd4\xab\xaf\x00\xa0\x5e\x44\x09\x80\x1f\x7e\x58\xb3\x33\xd1\xa6\x06\xc0\xc2\x61\x86\xbf\xf7\x22\x00\x6a\x53\x05\xa0\x94\xfe\xe8\x77\x55\x06\x40\x6d\xea\x00\xa8\x4d\x21\x80\x2c\x78\x16\x8a\x5b\xdb\x54\x02\x78\x25\x01\x86\x9b\x52\x00\x16\x83\x4d\x78\xa1\xdb\x0b\x9b\xe8\xc2\xb9\x18\x6d\x82\x0b\xf3\xb1\x79\x45\xb1\x85\xdf\x68\x3d\x00\xb5\x29\x08\x50\xb8\x81\x37\xfe\x64\x59\xb0\xbc\x32\x7f\xb2\x97\x57\x13\x40\xad\xa7\x28\x80\x52\xfd\x65\x54\x82\xaa\x3f\xe5\x4d\x66\x67\x88\xb3\x22\x1c\xda\xed\x4f\xc9\x6d\x8d\x68\x20\xd3\x0a\x41\x7b\x36\xcb\xcc\xa0\x42\xd5\x7f\xe5\x7a\x40\xd5\x7f\x7e\x35\xe0\xe1\xe1\x7a\xb5\x80\xaa\xbf\x66\x25\xe0\x02\x4c\x70\x5a\xf9\xbf\x76\x36\xa8\xfa\xaf\x8d\x0b\xaa\xfe\x4b\x63\x82\x96\xa2\xda\x79\xe0\x92\xa1\xd5\xb3\xb1\xd5\xce\x32\x32\x15\x4a\xbd\x9a\x69\xe4\x77\x10\x67\xfd\x32\x02\xad\xdf\x7e\xbf\x66\xe3\xc8\x33\x84\x5a\xbf\x5a\xeb\x88\x8d\x2c\xfe\x3d\x9b\x47\x6c\x40\xe1\xc6\x3e\xb2\xa8\x7d\xe4\x39\x62\xcd\x6b\x34\x90\x58\x1e\xf8\x6d\x5b\x48\x10\x83\x8d\x89\x64\x29\xcd\xbb\x0b\xab\xdf\xd8\x48\x5e\xbc\x8d\xc4\x26\x13\xf9\xc6\x8d\x24\x08\xc2\xc6\x4a\x92\xec\x86\x8d\x99\x64\x3e\x48\x1b\x3b\x49\x01\x38\xaf\xc8\x50\x62\x05\xdd\x6f\xd0\x52\xb2\x09\xbd\x9f\xb3\x87\x37\xb6\x92\x4c\x5c\x5e\x9b\x9a\xf0\x05\x46\xdf\xaf\x2b\xfc\x7e\xb0\x5c\xb9\x96\xc1\x74\xb5\x96\x74\xf8\xfd\x80\x44\xa0\x22\xe2\x51\x10\x1c\x08\x60\xf9\xdc\x24\x06\x3f\x4b\x21\x38\x58\xa9\x28\x4b\x57\xd2\x89\x31\x67\xa2\x49\x0d\xe7\xf8\x0e\x76\xa8\x0d\x3d\xb8\x37\xaf\xde\x31\xae\x69\x8f\xca\x7b\x5b\x5e\xc7\x1e\x98\x56\x26\xdd\x9d\x5c\xa4\xfb\x77\xfb\xdf\xdd\xe7\x2d\x92\xe9\x69\x60\xc6\xaf\x5c\x07\x38\x3d\xa9\xd9\x00\xd5\xd5\x66\x75\xf8\xae\x78\x56\x5e\xe5\xb3\x6a\x3b\x45\xb1\x82\x41\x9f\x6a\x5b\xb7\x8d\x4e\x94\x6d\x95\x14\x73\x04\x59\x0d\x4d\x22\xc4\x48\x88\xa8\xf4\x28\x77\x21\x5a\x19\x5f\x10\xec\x4c\xbc\x31\x73\x18\x4c\xcc\xcb\x21\x54\xad\x0c\x2f\xb8\x1f\x7b\xa8\x69\x8c\x88\x64\x4a\x70\x85\x0b\x40\x82\xc0\x2e\x61\x44\xa4\xc6\x32\xa0\xaa\x81\x85\x39\x1f\x86\xe6\x3f\x25\x98\xc1\xc0\x96\xbb\x30\xff\xad\x3a\x75\x83\x39\x5a\x13\x59\xc3\x65\x29\x32\x8b\x83\xaa\x71\x2e\x2c\xfd\x92\xf6\x88\xf4\x03\xaa\x94\xd5\xb7\x24\x4b\xd6\x82\x6b\xa1\x14\x33\xfb\xcf\x42\x8f\x6b\x78\xbb\x25\x1e\x6f\xb7\x1a\x70\x9b\x88\x20\xf6\x1f\xc9\x0e\xb6\xff\x8a\xf9\x23\x17\x03\x7e\xbb\x35\xad\xbf\x1f\xbf\x56\xea\xe8\xe2\xa2\x39\xc1\x46\xdc\xcf\xa3\xa3\x8b\xaf\x78\x05\x36\x2b\xc0\xc5\xcc\x10\x95\xdf\x7f\xff\x92\x7d\x01\xce\x10\xe4\xf2\xa4\x18\x87\xec\x7f\xe6\xdc\x8f\x97\x3c\x27\xb4\xb7\xcc\x31\xa1\xbd\x4c\x73\x92\xb9\x6c\x57\x64\x4c\xd2\xde\x2b\x37\x25\x69\x6f\x0d\x49\x59\x8a\x2c\x4a\xeb\x34\x20\x99\xc9\x16\x9a\x8f\xf2\x53\xb1\x2c\xad\x36\x78\xcd\x26\x03\x83\xd7\x2b\x32\x18\xcc\x3d\xc8\x70\xb3\x57\x6c\x31\x70\x11\xa5\xb1\x22\x3d\x34\x07\x14\x18\x0a\x27\x8c\x85\xce\x48\xb8\x4e\x8b\x19\x2e\x27\x5a\x04\x9f\xcb\x6c\xf6\xcc\x26\x43\x03\xc0\x5a\x67\xbe\xc4\xe6\x48\x5b\x90\xd7\x69\x4b\x4a\x6d\x8e\xb5\x1a\x94\x5e\x97\xc5\xcd\xa0\xf4\x82\xed\x6d\x93\xac\x10\x9f\xbc\x1c\x8b\x9b\xc1\x6e\x63\x6f\xcb\x58\x27\xf3\xfc\x45\x59\xdc\xcc\x4a\x7d\xe3\xf6\x36\x03\xc1\xc6\xda\x66\x77\xc2\xc6\xd6\x36\x0f\xa2\xd7\x60\x69\x83\x03\x95\xe4\x19\x9a\xd8\x65\xd8\xd4\xc0\xe7\x2e\xfa\x0d\x38\xe4\xbe\x79\x65\xa4\xf3\xdb\x61\x5d\xe0\x42\x8f\xaf\xc7\xef\x61\x7f\x17\x9a\xcd\x71\x6a\x1c\x78\x18\xda\xb4\x21\xcf\x61\xcf\x33\x0b\x90\xd7\xd5\x73\x59\xf2\x4a\x5d\x49\x5e\x9e\x69\x2f\x4d\xdd\xc0\xf4\xb2\x2e\xfa\x16\xb5\xb0\x4d\xac\x7d\xe5\x04\xbe\x02\x6f\x78\x33\xf1\xd7\x65\xe6\x32\x14\xbf\x2c\x23\x97\xa3\xa8\x66\x13\x57\xec\x2f\xa3\xba\x8c\xfd\x4c\xd5\xe5\xe7\x93\xca\x54\x97\xb1\xff\xca\x55\x97\xb1\xff\x0d\xa9\x2e\xcd\x64\xd7\xac\xba\x9c\xc4\x81\x0c\x03\x41\x46\x6e\xe9\x49\xc6\x60\xb3\x1f\x7d\xa2\x49\x4f\x92\x70\xad\xaa\x1c\x83\x47\xa1\x2a\xa7\xf2\xac\xda\x79\x70\x8c\xf5\xba\x06\x90\x51\x25\xa9\xa5\x50\x59\x5d\x65\x6b\x70\x99\xa3\xb2\xad\x25\xdf\xf8\xf4\xfe\xd0\x02\xb6\x51\x61\xb3\xed\x94\x7d\x98\x15\x77\xad\xba\x1a\x03\xc5\x5a\x75\x35\x2b\x1d\x8f\x86\xda\x97\x75\x3c\x3a\x8a\xea\x3e\x1e\x23\xb5\xcc\xf1\x18\xa9\xac\xe3\x11\x59\xd2\x75\x1b\xb5\x88\xcc\xfa\x7f\xcc\x1e\x8e\x2d\xf8\xe7\x25\xd5\x03\x21\x1f\xf1\xdd\x8e\x10\x81\x23\xc1\x51\xc0\xed\xaf\x71\xa4\xb4\xf9\xcd\x0c\xbf\x0b\x23\x9b\x8c\x8c\x39\x4f\x6e\x9c\x78\x61\x4f\x28\x10\x60\x5a\x65\x9d\xb4\x29\xab\x79\xb9\x93\x76\x82\xe7\xb8\xb3\x2e\xd1\x80\xe2\x39\x9f\x10\x13\x47\x6a\x26\x3f\x69\xad\x87\xf0\x9c\x6c\xb4\xd1\x4a\xb9\x68\xe3\x48\xcd\x3d\xd9\xeb\xe5\xef\x66\x63\x60\x95\xac\x49\xb7\x95\x38\x52\xd3\x6e\x2b\xb5\x03\x81\x7f\xaf\x97\x97\x0b\x9b\xb7\x75\xd0\x67\x5e\xdf\xe5\x72\x35\xdc\x63\x12\x8c\x37\x6f\x7f\x98\xce\xcf\x5b\x3b\x16\xcb\xc5\xfe\xad\x00\xc5\x13\x91\x0c\x4d\x38\x5a\x80\x63\x4c\x2e\xae\xef\x81\xa2\x2f\x8d\xe8\xc2\xf9\xd9\xe5\x69\x03\x3a\xa7\x17\xd7\x0d\xf8\x70\xd4\xe9\x5c\x1f\x77\x40\x48\x38\xbf\x3a\x3a\xb9\x3e\xee\xb4\xe0\xac\x6b\xf9\x04\x7a\xb4\x68\xfb\x95\xa1\xba\x00\x8b\xd4\x61\x55\x3a\x49\x03\x66\xee\x95\x96\x5d\x59\x25\x8d\xe8\xe2\x7e\x6b\xd9\x9b\x70\xb9\x6d\x97\x90\x9d\x8b\xf7\xd3\x62\x78\x67\xf6\x53\x37\xe6\xb3\x0e\x74\x89\x82\x45\xd1\xc0\xea\xda\x13\xba\xd6\xed\x91\x6c\x30\x59\xb7\x3f\x72\x76\x7d\x88\x8a\x30\xa9\xc2\x17\xd9\x80\xb2\x76\x4f\xe4\x13\xa6\xa2\x80\x0c\xad\x13\x1f\x0d\x23\x2a\x89\x8e\x25\x35\x62\xb8\x4f\x7b\x92\x52\x05\xc7\x34\x50\x2c\x56\xc0\xb8\xd2\x94\x60\xc0\xec\x47\xd2\x97\x94\xf7\xe9\xb4\x05\xe6\x1e\xf9\xe8\xda\x59\xbb\x67\x29\x5c\xeb\xd7\x35\x56\xfc\xaa\x49\x2d\xd7\xa4\x06\xf3\xe5\x68\xba\x0c\x50\xcf\x9f\xeb\x39\x56\x54\x2e\x25\xa8\x9a\x76\xb9\xae\xca\xe3\xc5\xc0\xf7\xc0\x8b\xa5\xa4\x5c\x07\x43\x08\x44\xaf\x67\x0b\xf3\xb8\x43\xc1\x7a\x31\xbb\xa2\x61\x84\xfb\xd0\xa3\xdc\x6c\x7a\xac\x2a\x06\x54\x4a\x21\x13\x29\xcf\xf5\x4a\xbf\x7a\x94\xfa\x6a\xda\xcf\x75\x24\x0c\x67\x49\xaa\x86\x8a\x15\xb4\x42\xa6\x3d\x78\x22\xe6\x3a\xa3\xa8\xce\x64\x46\x95\xe9\x7d\x34\x41\xc2\xdd\xa0\x27\x29\xd1\x15\x3b\xca\x4e\x51\x98\x51\x74\x67\x82\xc4\x77\xc5\x24\x7a\xe5\x48\x9c\xdc\x77\x7f\x30\x7f\xfd\xef\xff\x1f\x00\x00\xff\xff\xda\x9a\x19\x04\x2e\x01\x02\x00") - -func icingaGenJsonBytes() ([]byte, error) { - return bindataRead( - _icingaGenJson, - "icinga.gen.json", - ) -} - -func icingaGenJson() (*asset, error) { - bytes, err := icingaGenJsonBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "icinga.gen.json", size: 131374, mode: os.FileMode(420), modTime: time.Unix(1453795200, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _node_checksJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xd8\x5d\x4f\xdb\x3c\x14\x00\xe0\xfb\xfe\x8a\x23\x5f\xf1\xea\x85\x8a\x1b\x84\xa8\xb4\x49\xfd\x88\x18\x62\xea\xb4\x0c\xb6\x0b\x84\x2a\x37\x39\x6d\x2d\x1c\x3b\xd8\x4e\x4a\x87\xf8\xef\x93\xdd\xaf\xa4\xa5\x4b\xcd\x28\xa3\xd2\x6e\x50\x82\x8f\x4f\xe2\x27\x76\x9c\xd3\xc7\x1a\x00\x89\x46\x18\xdd\xf5\x22\x99\x24\x54\xc4\xa4\x01\x37\x35\x00\x80\x47\xf7\x17\x80\xc4\xa8\x23\xc5\x52\xc3\xa4\x20\x0d\x20\x57\x23\xa6\x81\x69\xc8\x34\xc6\x60\x24\xb8\xde\x70\x21\x06\x3c\x7b\xe8\xb4\xe0\x3e\x43\x35\x01\x85\x3a\xe3\x86\x1c\xce\x73\x08\x9a\xa0\xed\xcc\x5c\x58\xcf\x05\x2d\x5b\x51\xe4\x7a\x71\x5d\xf7\x1f\x29\xb0\x2f\x1f\x16\x11\x00\x24\x55\x32\x2e\x9e\xdf\xd3\xe2\x59\x8c\x39\x99\x9d\xdd\x2e\xd2\xe6\x54\x95\xd3\x3e\x2e\x8e\xd6\x87\x75\x1d\x7e\x06\x39\x58\x8e\x63\x24\xb5\xb1\xc3\x2b\xdf\xaa\xeb\x39\xe0\x74\x48\x1a\xa5\x6c\x00\x44\x8f\xa4\x32\x36\xd3\xa8\x14\x0d\x40\xb8\x14\xc3\xe5\xe0\x3f\x49\x6d\x48\x21\xe0\xa9\x94\xbb\x0c\xe5\x62\x4b\xed\x66\x92\xba\xf6\x6f\x57\xe1\x45\xf7\xbc\xdc\x96\x52\x45\x13\x34\xa8\xd8\x4f\xb4\xcf\x71\x40\xb9\xc6\x52\x44\xce\x34\xeb\x33\xce\xcc\xe4\xd9\x66\xe9\x34\x28\x27\x0d\x30\x2a\xc3\xda\x33\xb7\xf8\x3b\xc2\xcb\xac\x8f\x4a\xa0\x41\x0d\x1a\x23\x85\x06\xdc\x68\x7c\xec\xf4\x26\xbb\x69\xc2\xae\xcd\x57\x69\x57\x88\xdd\x95\x9d\xe5\xd9\x44\xe7\xba\xfa\xda\xad\xac\x9f\x83\xe6\x7f\x75\xf8\x5a\x58\x4a\x30\x66\x9c\x43\x1f\x81\x6a\xcd\x86\x62\xba\xf4\x72\xaa\x18\xed\x73\xb4\xe1\xdb\x30\xcf\x31\x9b\xd5\x86\xcd\x97\xd3\xad\xd9\xbc\xad\x5c\xcb\x4f\xae\xe5\x25\xd7\xaa\x96\x6b\xed\x4a\xee\xd5\xd7\xeb\xaa\x5c\xdb\x4f\xae\xed\x25\xd7\xae\x96\x6b\xef\xad\x5c\xc7\x4f\xae\xe3\x25\xd7\xa9\x96\xeb\xec\xad\x5c\xe0\x27\x17\x78\xc9\x05\xd5\x72\xc1\xde\xc8\x05\xf7\x19\xb5\xc7\x70\xd3\xfc\xbf\x75\x6b\x59\x86\x68\xe6\x6a\x03\x25\x13\x47\xca\x50\xd7\x21\xdc\x86\x32\xf4\xa2\x0c\xab\x29\xc3\xfd\xd9\x6d\xdb\x52\xc4\xcc\x61\x0e\xa4\x82\x31\x55\x82\x89\xe1\x21\x44\x32\x49\xa9\x42\x18\x33\x33\x9a\xc9\xd6\xe1\x20\x78\xa0\x49\xca\xb1\x01\x21\x7c\x84\xd3\x93\xad\xd8\x16\x1f\x34\xe3\x4d\x1f\x34\xb3\x8b\x56\xb3\xce\x03\xff\x06\xee\x4b\xe6\x69\xd9\x36\x52\xcc\xb0\x88\xf2\xad\x70\xcf\x8e\xfd\x70\xa3\x4d\xb8\xf3\xab\x56\xeb\x2e\x22\xdf\xc1\xdc\x5d\x2b\x60\xb4\xa1\x06\x8b\x25\x0c\xf9\x72\xb9\xac\x9a\x7e\xac\x4c\x0c\xd2\x5e\x1d\x0b\xb9\x16\x77\x42\x8e\xc5\x94\xe1\xb6\x56\x60\xf0\xab\xee\x0a\x5f\xf6\x5d\x19\x23\xd8\x1b\xcb\x74\xa1\x80\x9b\x3e\x45\xed\xca\x9f\x49\x8a\x8a\x72\x54\x66\xda\xb9\x27\x64\x8c\xbd\x69\x0f\x38\x3a\xb2\xf0\x1f\x12\xaa\x0d\xaa\x3a\x13\x06\x95\x28\xde\xf0\xfc\xb1\x14\xfa\xec\xbc\x4c\x5c\x53\x2e\x3b\x3f\x07\xbb\x4a\xfb\x47\xb8\x4e\xb4\xc3\xf4\x9d\x63\xad\x6f\xc0\xc8\x25\xcf\x0a\x05\xcd\xbb\xa8\x99\xff\x15\x7c\x2f\x7e\x4b\x7e\x77\x8f\xd3\xdf\xab\xbb\xc9\x6b\x3a\x3f\xb6\xf3\x4a\x64\x26\x4c\x2a\x99\xd8\xdd\x8f\x0b\xaf\xed\x35\x7b\xd9\x01\xc7\x1c\x39\xe4\x94\x67\x08\x07\x99\xa6\x43\x84\x14\x55\x84\xc2\xd8\xc3\x18\x07\x34\xe3\x46\xdb\xc5\x75\x7a\x52\xf7\xdc\x4e\x76\xbc\x57\x5f\x74\xaf\x82\xf0\x3c\x08\xdf\x95\xeb\xfc\xd5\xe6\x01\x7b\x76\xec\x0b\xbb\xf3\x7d\xfa\x8d\x69\x77\xba\x85\xd4\xec\xd1\x53\xed\x57\x00\x00\x00\xff\xff\x1e\xf6\x51\x60\x9a\x15\x00\x00") - -func node_checksJsonBytes() ([]byte, error) { - return bindataRead( - _node_checksJson, - "node_checks.json", - ) -} - -func node_checksJson() (*asset, error) { - bytes, err := node_checksJsonBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "node_checks.json", size: 5530, mode: os.FileMode(420), modTime: time.Unix(1453795200, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _pod_checksJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xd8\x4f\x6f\xdb\x36\x14\x00\xf0\xbb\x3f\xc5\x03\x2f\xcd\xb0\xc0\xed\xa5\x28\xea\x01\x03\x62\x5b\xeb\x82\x0c\xe9\xa6\xa5\xdb\x21\x08\x02\x5a\x7a\x92\x88\x52\xa4\x42\x52\xb2\xd3\xa0\xdf\x7d\x20\x6d\x39\x92\x1d\x4f\x66\x5a\x67\x16\xb0\x8b\x21\x87\x4f\x4f\xe2\xcf\xfc\xf7\xf2\x30\x00\x20\x51\x86\xd1\xe7\xdb\x48\xe6\x39\x15\x31\x19\xc1\xf5\x00\x00\xe0\xc1\x7d\x02\x90\x18\x75\xa4\x58\x61\x98\x14\x64\x04\xe4\x2a\x63\x1a\x98\x86\x52\x63\x0c\x46\x82\xbb\x1b\xce\x45\xc2\xcb\xc5\x74\x0c\x77\x25\xaa\x7b\x50\xa8\x4b\x6e\xc8\x69\x9d\x43\xd0\x1c\xed\xcd\xcc\x85\xdd\xba\xa0\xc7\x56\x14\x95\x5e\x3f\xd7\xfd\x45\x0a\x9c\xc9\xc5\x3a\x02\x80\x14\x4a\xc6\xcd\xef\x77\xb4\xf9\x2d\xc6\x8a\xac\xbe\xdd\xac\xd3\x56\x54\xb5\xd3\x3e\xac\xaf\xb6\xbb\xf5\x29\xfc\x0d\x64\xf2\xd8\x8f\x4c\x6a\x63\xbb\xd7\x7e\x55\x77\x67\xc2\x69\x4a\x46\xad\x6c\x00\x44\x67\x52\x19\x9b\x29\x6b\x45\x03\x10\x2e\x45\xfa\xd8\xf9\x5f\xa5\x36\xa4\x11\xf0\xb5\x95\xbb\x0d\xe5\x62\x5b\xed\xe6\xbe\x70\xed\x7f\x5e\x85\xe7\x97\x1f\xda\x6d\x05\x55\x34\x47\x83\x8a\x7d\x41\xfb\x3b\x26\x94\x6b\x6c\x45\x54\x4c\xb3\x19\xe3\xcc\xdc\x3f\xd9\x2c\x9d\x06\xe5\x64\x04\x46\x95\x38\x78\xe2\x15\xff\x8d\xf0\xa2\x9c\xa1\x12\x68\x50\x83\xc6\x48\xa1\x01\xd7\x1b\x1f\x3b\xbd\xcb\x6e\x99\xf0\xd2\xe6\xeb\xb4\x6b\xc4\x1e\xca\xce\xf2\xec\xa2\x73\xb7\xfa\xda\x6d\xcc\x9f\x93\xb3\x1f\x86\xf0\x47\x63\x2a\xc1\x9c\x71\x0e\x33\x04\xaa\x35\x4b\xc5\x72\xea\x55\x54\x31\x3a\xe3\x68\xc3\xf7\x61\xae\x31\xcf\xba\x0d\xcf\x9e\x4f\xb7\x65\xf3\xb2\x72\x63\x3f\xb9\xb1\x97\xdc\xb8\x5b\x6e\x7c\x28\xb9\xef\x3e\x5f\x37\xe5\x26\x7e\x72\x13\x2f\xb9\x49\xb7\xdc\xa4\xb7\x72\x53\x3f\xb9\xa9\x97\xdc\xb4\x5b\x6e\xda\x5b\xb9\xc0\x4f\x2e\xf0\x92\x0b\xba\xe5\x82\xde\xc8\x05\x77\x25\xb5\xd7\x70\x7d\xf6\xe3\xf8\xc6\xb2\xa4\x68\x6a\xb5\x44\xc9\xdc\x91\x32\xd4\x43\x08\xf7\xa1\x0c\xbd\x28\xc3\x6e\xca\xb0\x3f\xbb\xed\x44\x8a\x98\x39\xcc\x44\x2a\x98\x53\x25\x98\x48\x4f\x21\x92\x79\x41\x15\xc2\x9c\x99\x6c\x25\x3b\x84\x93\x60\x41\xf3\x82\xe3\x08\x42\xf8\x19\xde\xbd\xdd\x8b\x6d\x7d\xa0\x99\xef\x3a\xd0\xac\x1e\xda\xcd\x5a\x07\xfe\x17\xb8\xcf\x19\xa7\x6d\xdb\x48\x31\xc3\x22\xca\xf7\xc2\x7d\xff\xc6\x0f\x37\xda\x85\x5b\x3f\xb5\x5b\x77\x1d\x79\x04\x63\x77\xab\x80\xd1\x86\x1a\x6c\x96\x30\xe4\xe3\xc5\x63\xd5\xf4\xf7\xc6\xc0\x20\x93\xcd\xbe\x90\x4f\xe2\xb3\x90\x73\xb1\x64\xb8\x19\x34\x18\xfc\xaa\xbb\xc6\xc9\xbe\x90\x31\xd8\xf7\x2a\xf5\x76\x75\x57\xc8\xf8\x76\xb3\xed\x40\xb5\xdd\x16\x4d\x1b\xe7\x29\x8d\x4d\x8f\x6f\x12\xf9\x5d\xc6\x50\x49\x5e\xe6\xe8\x34\x86\x4f\x63\x2c\x23\x8e\xab\xd0\xfd\xbf\x4a\x7b\xf6\xd2\xf6\xd7\xf2\x07\xf7\xf6\xba\xdc\xe5\xb5\x1c\x1f\xfb\x79\x35\x62\xfb\xe2\xb5\x5a\xa1\x80\x63\x85\x1c\x2a\xca\x4b\x84\x93\x52\xd3\x14\xa1\x40\x15\xa1\x30\xf6\x32\xc6\x84\x96\xdc\x68\x3b\xb9\xde\xbd\x1d\x7a\xee\x01\x07\xde\x60\xcf\x2f\xaf\x82\xf0\x43\x10\x1e\x95\x6b\xbd\xb4\x79\xc0\xbe\x7f\xe3\x0b\x7b\xf0\xcd\xf5\x85\x69\x8f\x6e\x0b\x69\x2c\xc4\xb8\xc0\x08\x56\xff\x80\xb5\xc7\x77\x53\x2a\xa1\xe1\xe3\x05\xb0\x04\x70\xc1\x0c\x44\x32\x46\x9b\xe1\x0b\x2a\x79\x0a\xd2\x64\xa8\xe6\x4c\xe3\x29\xa8\x55\xec\xf6\xde\xdf\xdc\x87\x6c\xfe\xa3\xdd\x85\x22\x29\x0c\x65\x02\x95\x5b\x58\x81\x09\xa0\xf6\x94\xe1\x35\x58\x27\x3b\x07\x6b\x9d\x7c\x8f\xd1\xba\x0e\xed\xcb\xfa\x1a\xb4\x86\xcd\xf5\x74\x39\xdf\x47\xf0\xea\xf5\x8c\x89\xd7\x3a\x7b\x75\xf3\x9d\x66\x7c\x1e\xef\xc1\x97\xc7\xbd\x84\x03\xaa\xd2\x32\x47\x61\xf4\x10\xae\x7f\x91\x2a\xa7\x56\x90\xaa\xf4\x27\xa8\x3f\x3c\x1d\xe9\x2e\x47\xaa\xd2\xaa\x1b\xd2\x45\xf5\xa2\x1c\xf9\x86\x05\x73\x60\xaf\xbe\x0e\xfe\x09\x00\x00\xff\xff\xce\xe8\x7e\x5c\x80\x1a\x00\x00") - -func pod_checksJsonBytes() ([]byte, error) { - return bindataRead( - _pod_checksJson, - "pod_checks.json", - ) -} - -func pod_checksJson() (*asset, error) { - bytes, err := pod_checksJsonBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "pod_checks.json", size: 6784, mode: os.FileMode(420), modTime: time.Unix(1453795200, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "cluster_checks.json": cluster_checksJson, - "icinga.gen.json": icingaGenJson, - "node_checks.json": node_checksJson, - "pod_checks.json": pod_checksJson, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "cluster_checks.json": {cluster_checksJson, map[string]*bintree{}}, - "icinga.gen.json": {icingaGenJson, map[string]*bintree{}}, - "node_checks.json": {node_checksJson, map[string]*bintree{}}, - "pod_checks.json": {pod_checksJson, map[string]*bintree{}}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} diff --git a/data/files/cluster_checks.json b/data/files/cluster_checks.json deleted file mode 100644 index ab25918e8..000000000 --- a/data/files/cluster_checks.json +++ /dev/null @@ -1,857 +0,0 @@ -{ - "check_command": [ - { - "description": "This is used to check Kubernetes components", - "examples": "hyperalert check_component_status", - "name": "component_status", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "Selector (label query) to filter on, supports '=', '==', and '!='.", - "flag": { - "short": "l", - "long": "selector" - }, - "name": "selector", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Name of component whose status is checked", - "flag": { - "long": "componentName" - }, - "name": "componentName", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - } - ], - "states": [ - "OK", - "Critical", - "Unknown" - ] - }, - { - "description": "This is used to check any API response parsing JSON using JQ queries", - "examples": "hyperalert check_json_path --url='https://api.appscode.com/health' --critical='{.status} != OK'", - "name": "json_path", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "URL to get data", - "flag": { - "short": "u", - "long": "url" - }, - "name": "url", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Kubernetes secret name", - "flag": { - "short": "s", - "long": "secretName" - }, - "name": "secretName", - "type": "STRING", - "parameterized": false, - "visibility": false, - "optional": true - }, - { - "description": "Warning jsonpath query which returns [true/false]", - "flag": { - "short": "w", - "long": "warning" - }, - "name": "warning", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Critical jsonpath query which returns [true/false]", - "flag": { - "short": "c", - "long": "critical" - }, - "name": "critical", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": false - } - ], - "states": [ - "OK", - "Warning", - "Critical", - "Unknown" - ] - }, - { - "description": "This is used to check total number of Kubernetes node", - "examples": "hyperalert check_node_exists --count=3", - "name": "node_exists", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "Number of expected Kubernetes Node", - "flag": { - "short": "c", - "long": "count" - }, - "name": "count", - "type": "INTEGER", - "parameterized": false, - "visibility": true, - "optional": false - }, - { - "description": "Selector (label query) to filter on, supports '=', '==', and '!='.", - "flag": { - "short": "l", - "long": "selector" - }, - "name": "selector", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Name of node whose existence is checked", - "flag": { - "short": "n", - "long": "nodeName" - }, - "name": "nodeName", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - } - ], - "states": [ - "OK", - "Critical", - "Unknown" - ] - }, - { - "description": "This is used to check Kubernetes pod existence", - "name": "pod_exists", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "Number of expected Kubernetes Pod", - "flag": { - "short": "c", - "long": "count" - }, - "name": "count", - "type": "INTEGER", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Selector (label query) to filter on, supports '=', '==', and '!='.", - "flag": { - "short": "l", - "long": "selector" - }, - "name": "selector", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Name of pod whose existence is checked", - "flag": { - "short": "p", - "long": "podName" - }, - "name": "podName", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - } - ], - "states": [ - "OK", - "Critical", - "Unknown" - ] - }, - { - "description": "This is used to check Kubernetes events. This plugin checks for all Warning events happened in last 'c' seconds. Icinga check_interval is provided as 'c'.", - "name": "event", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "Clock skew in Duration. [Default: 30s]. This time is added with check_interval while checking events", - "flag": { - "short": "s", - "long": "clockSkew" - }, - "name": "clockSkew", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Name of object involved in an event", - "flag": { - "long": "involvedObjectName" - }, - "name": "involvedObjectName", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Namespace of object involved in an event", - "flag": { - "long": "involvedObjectNamespace" - }, - "name": "involvedObjectNamespace", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Kind of object involved in an event", - "flag": { - "long": "involvedObjectKind" - }, - "name": "involvedObjectKind", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "UID of object involved in an event", - "flag": { - "long": "involvedObjectUID" - }, - "name": "involvedObjectUID", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - } - ], - "states": [ - "OK", - "Warning", - "Unknown" - ] - }, - { - "description": "This is used to check Kubernetes api server CA Certificate expiration date", - "examples": "hyperalert check_ca_cert", - "name": "ca_cert", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "Warning level value (usage duration defaults to 360h)", - "flag": { - "short": "w", - "long": "warning" - }, - "name": "warning", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Critical level value (usage duration defaults to 120h)", - "flag": { - "short": "c", - "long": "critical" - }, - "name": "critical", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - } - ], - "states": [ - "OK", - "Warning", - "Critical", - "Unknown" - ] - }, - { - "description": "This is used to test various stuff", - "name": "env", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "states": [ - "OK", - "Warning", - "Critical", - "Unknown" - ] - }, - { - "description": "This is used to check Certificate expiration date using Secret", - "examples": "hyperalert check_cert", - "name": "cert", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "Selector (label query) to filter on, supports '=', '==', and '!='.", - "flag": { - "short": "l", - "long": "selector" - }, - "name": "selector", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Name of the Secret where certificate is stored", - "flag": { - "short": "s", - "long": "secretName" - }, - "name": "secretName", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Comma separated Secret keys", - "flag": { - "short": "k", - "long": "secretKey" - }, - "name": "secretKey", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Warning level value (usage duration defaults to 360h)", - "flag": { - "short": "w", - "long": "warning" - }, - "name": "warning", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Critical level value (usage duration defaults to 120h)", - "flag": { - "short": "c", - "long": "critical" - }, - "name": "critical", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - } - ], - "states": [ - "OK", - "Warning", - "Critical", - "Unknown" - ] - }, - { - "description": "This is used to test various stuff", - "name": "env", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "states": [ - "OK", - "Warning", - "Critical", - "Unknown" - ] - }, - { - "description": "The [check_dummy](https://www.monitoring-plugins.org/doc/man/check_dummy.html) plugin will simply return the state corresponding to the numeric value of the `dummy_state` argument with optional text.", - "name": "dummy", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "The state. Can be one of 0 (ok), 1 (warning), 2 (critical) and 3 (unknown). Defaults to 0.", - "name": "dummy_state", - "optional": true - }, - { - "description": "Plugin output. Defaults to \"Check was successful.\".", - "name": "dummy_text", - "optional": true - } - ] - }, - { - "description": "Modified check_command [http] where user can provide custom http_address", - "name": "any_http", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "The host's address. Default empty", - "name": "httpAddress", - "type": "STRING", - "optional": true - }, - { - "description": "The virtual host that should be sent in the \"Host\" header.", - "name": "httpVhost", - "type": "STRING", - "optional": true - }, - { - "description": "The request URI for GET or POST. Defaults to `/`.", - "name": "httpURI", - "type": "STRING", - "optional": true - }, - { - "description": "The TCP port. Defaults to 80 when not using SSL, 443 otherwise.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "httpPort", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Whether to use SSL. Defaults to false.", - "flag": { - "long": "ssl", - "short": "S" - }, - "name": "httpSSL", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force TLSv1.", - "flag": { - "long": "ssl", - "short": "S" - }, - "name": "httpSSLForceTLSv1", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force TLSv1.1.", - "flag": { - "long": "ssl", - "short": "S" - }, - "name": "httpSSLForceTLSv1_1", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force TLSv1.2.", - "flag": { - "long": "ssl", - "short": "S" - }, - "name": "httpSSLForceTLSv1_2", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force SSLv2.", - "flag": { - "long": "ssl", - "short": "S" - }, - "name": "httpSSLForceSSLv2", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force SSLv3.", - "flag": { - "long": "ssl", - "short": "S" - }, - "name": "httpSSLForceSSLv3", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force TLSv1 or higher.", - "flag": { - "long": "ssl", - "short": "S" - }, - "name": "httpSSLForceTLSv1_or_higher", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force TLSv1.1 or higher.", - "flag": { - "long": "ssl", - "short": "S" - }, - "name": "httpSSLForceTLSv1_1_or_higher", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force TLSv1.2 or higher.", - "flag": { - "long": "ssl", - "short": "S" - }, - "name": "httpSSLForceTLSv1_2_or_higher", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force SSLv2 or higher.", - "flag": { - "long": "ssl", - "short": "S" - }, - "name": "httpSSLForceSSLv2_or_higher", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force SSLv3 or higher.", - "flag": { - "long": "ssl", - "short": "S" - }, - "name": "httpSSLForceSSLv3_or_higher", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to use SNI. Defaults to false.", - "name": "httpSNI", - "optional": true - }, - { - "description": "Add 'username:password' authorization pair.", - "name": "httpAuthPair", - "optional": true - }, - { - "description": "Add 'username:password' authorization pair for proxy.", - "name": "httpProxyAuthPair", - "optional": true - }, - { - "description": "Don't download the body, just the headers.", - "name": "httpIgnoreBody", - "optional": true - }, - { - "description": "Allow regex to span newline.", - "name": "httpLinespan", - "optional": true - }, - { - "description": "A regular expression which the body must match against. Incompatible with httpIgnoreBody.", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "httpExpectBodyRegex", - "optional": true, - "type": "STRING" - }, - { - "description": "A case-insensitive expression which the body must match against. Incompatible with httpIgnoreBody.", - "flag": { - "long": "eregi", - "short": "R" - }, - "name": "httpExpectBodyEregi", - "optional": true, - "type": "STRING" - }, - { - "description": "Changes behaviour of httpExpectBodyRegex and httpExpectBodyEregi to return Critical if found, OK if not.", - "name": "httpInvertregex", - "optional": true - }, - { - "description": "The warning threshold.", - "name": "httpWarnTime", - "optional": true - }, - { - "description": "The critical threshold.", - "flag": { - "long": "critical", - "short": "c" - }, - "name": "httpCriticalTime", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Comma-delimited list of strings, at least one of them is expected in the first (status) line of the server response. Default: HTTP/1.", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "httpExpect", - "optional": true, - "type": "STRING" - }, - { - "description": "Minimum number of days a certificate has to be valid. This parameter explicitely sets the port to 443 and ignores the URL if passed.", - "flag": { - "long": "certificate", - "short": "C" - }, - "name": "httpCertificate", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Name of file contains the client certificate (PEM format).", - "flag": { - "long": "client-cert", - "short": "J" - }, - "name": "httpClientcert", - "optional": true, - "type": "STRING" - }, - { - "description": "Name of file contains the private key (PEM format).", - "flag": { - "long": "private-key", - "short": "K" - }, - "name": "httpPrivatekey", - "optional": true, - "type": "STRING" - }, - { - "description": "String to expect in the response headers.", - "flag": { - "long": "header", - "short": "k" - }, - "name": "httpHeaderstring", - "optional": true, - "type": "STRING" - }, - { - "description": "String to expect in the content.", - "flag": { - "long": "string", - "short": "s" - }, - "name": "httpString", - "optional": true, - "type": "STRING" - }, - { - "description": "URL encoded http POST data.", - "flag": { - "long": "post", - "short": "P" - }, - "name": "httpPost", - "optional": true, - "type": "STRING" - }, - { - "description": "Set http method (for example: HEAD, OPTIONS, TRACE, PUT, DELETE).", - "flag": { - "long": "method", - "short": "j" - }, - "name": "httpMethod", - "optional": true, - "type": "STRING" - }, - { - "description": "Warn if document is more than seconds old.", - "flag": { - "long": "max-age", - "short": "M" - }, - "name": "httpMaxage", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Specify Content-Type header when POSTing.", - "flag": { - "long": "content-type", - "short": "T" - }, - "name": "httpContenttype", - "optional": true, - "type": "STRING" - }, - { - "description": "String to be sent in http header as User Agent.", - "flag": { - "long": "useragent", - "short": "A" - }, - "name": "httpUseragent", - "optional": true, - "type": "STRING" - }, - { - "description": "Any other tags to be sent in http header.", - "flag": { - "long": "header", - "short": "k" - }, - "name": "httpHeader", - "optional": true, - "type": "STRING" - }, - { - "description": "Print additional perfdata. Defaults to false.", - "name": "httpExtendedperfdata", - "optional": true - }, - { - "description": "How to handle redirect pages. Possible values: \"ok\" (default), \"warning\", \"critical\", \"follow\", \"sticky\" (like follow but stick to address), \"stickyport\" (like sticky but also to port)", - "flag": { - "long": "onredirect", - "short": "f" - }, - "format": "enum", - "name": "httpOnredirect", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warning", - "critical", - "follow", - "sticky", - "stickyport" - ] - }, - { - "description": "Minimum page size required:Maximum page size required.", - "flag": { - "long": "pagesize", - "short": "m" - }, - "name": "httpPagesize", - "optional": true, - "type": "STRING" - }, - { - "description": "Seconds before connection times out.", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "httpTimeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "httpIPv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "httpIPv6", - "optional": true - } - ] - } - ] -} diff --git a/data/files/icinga.gen.json b/data/files/icinga.gen.json deleted file mode 100644 index 070d34326..000000000 --- a/data/files/icinga.gen.json +++ /dev/null @@ -1,4143 +0,0 @@ -{ - "plugin": [ - { - "description": "The [check_breeze](https://www.monitoring-plugins.org/doc/man/check_breeze.html) plugin reports the signal strength of a Breezecom wireless equipment.", - "name": "breeze", - "vars": [ - { - "description": "Required Name or IP address of host to check. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "flag": { - "long": "hostname", - "short": "H" - }, - "format": "HOST", - "name": "breeze_hostname", - "optional": false, - "type": "STRING" - }, - { - "description": "SNMPv1 community. Defaults to \"public\".", - "flag": { - "long": "community", - "short": "C" - }, - "format": "community", - "name": "breeze_community", - "optional": true, - "type": "STRING" - }, - { - "description": "Required Percentage strength below which a Warning status will result. Defaults to 50.", - "flag": { - "long": "warning", - "short": "w" - }, - "name": "breeze_warning", - "optional": false, - "type": "INTEGER" - }, - { - "description": "Required Percentage strength below which a Warning status will result. Defaults to 20.", - "flag": { - "long": "critical", - "short": "c" - }, - "name": "breeze_critical", - "optional": false, - "type": "INTEGER" - } - ] - }, - { - "description": "The [check_by_ssh](https://www.monitoring-plugins.org/doc/man/check_by_ssh.html) plugin uses SSH to execute commands on a remote host.", - "examples": "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C uptime -O /tmp/foo\n $ cat /tmp/foo\n [1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days\n [1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days\n [1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c3;0; up 2 days", - "name": "by_ssh", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "by_ssh_address", - "optional": true - }, - { - "description": "The SSH port. Defaults to 22.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "by_ssh_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Required The command that should be executed. Can be an array if multiple arguments should be passed to `check_by_ssh`.", - "flag": { - "long": "command", - "short": "C" - }, - "format": "COMMAND", - "name": "by_ssh_command", - "optional": false, - "type": "STRING" - }, - { - "description": "A dictionary with arguments for the command. This works exactly like the 'arguments' dictionary for ordinary CheckCommands.", - "name": "by_ssh_arguments", - "optional": true - }, - { - "description": "The SSH username.", - "flag": { - "long": "name", - "short": "n" - }, - "format": "NAME", - "name": "by_ssh_logname", - "optional": true, - "type": "STRING" - }, - { - "description": "The SSH identity.", - "flag": { - "long": "identity", - "short": "i" - }, - "format": "KEYFILE", - "name": "by_ssh_identity", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to suppress SSH warnings. Defaults to false.", - "name": "by_ssh_quiet", - "optional": true - }, - { - "description": "The warning threshold.", - "name": "by_ssh_warn", - "optional": true - }, - { - "description": "The critical threshold.", - "name": "by_ssh_crit", - "optional": true - }, - { - "description": "The timeout in seconds.", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "by_ssh_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Call ssh with '-o OPTION' (multiple options may be specified as an array).", - "flag": { - "long": "ssh-option", - "short": "o" - }, - "format": "OPTION", - "name": "by_ssh_options", - "optional": true, - "type": "STRING" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "by_ssh_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "by_ssh_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_clamd](https://www.monitoring-plugins.org/doc/man/check_clamd.html) plugin tests CLAMD connections with the specified host (or unix socket).", - "name": "clamd", - "vars": [ - { - "description": "Required The host's address or unix socket (must be an absolute path).", - "name": "clamd_address", - "optional": false - }, - { - "description": "Port number (default: none).", - "flag": { - "long": "port", - "short": "p" - }, - "name": "clamd_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "String to expect in server response. Multiple strings must be defined as array.", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "clamd_expect", - "optional": true, - "type": "STRING" - }, - { - "description": "All expect strings need to occur in server response. Defaults to false.", - "name": "clamd_all", - "optional": true - }, - { - "description": "Enable usage of \\\\n, \\\\r, \\\\t or \\\\\\\\ in send string.", - "flag": { - "long": "send", - "short": "s" - }, - "name": "clamd_escape_send", - "optional": true, - "type": "STRING" - }, - { - "description": "String to send to the server.", - "flag": { - "long": "send", - "short": "s" - }, - "name": "clamd_send", - "optional": true, - "type": "STRING" - }, - { - "description": "Enable usage of \\\\n, \\\\r, \\\\t or \\\\\\\\ in quit string.", - "flag": { - "long": "quit", - "short": "q" - }, - "name": "clamd_escape_quit", - "optional": true, - "type": "STRING" - }, - { - "description": "String to send server to initiate a clean close of the connection.", - "flag": { - "long": "quit", - "short": "q" - }, - "name": "clamd_quit", - "optional": true, - "type": "STRING" - }, - { - "description": "Accept TCP refusals with states ok, warn, crit. Defaults to crit.", - "flag": { - "long": "refuse", - "short": "r" - }, - "format": "enum", - "name": "clamd_refuse", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Accept expected string mismatches with states ok, warn, crit. Defaults to warn.", - "flag": { - "long": "mismatch", - "short": "M" - }, - "format": "enum", - "name": "clamd_mismatch", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Hide output from TCP socket.", - "name": "clamd_jail", - "optional": true - }, - { - "description": "Close connection once more than this number of bytes are received.", - "flag": { - "long": "maxbytes", - "short": "m" - }, - "name": "clamd_maxbytes", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Seconds to wait between sending string and polling for response.", - "flag": { - "long": "delay", - "short": "d" - }, - "name": "clamd_delay", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Minimum number of days a certificate has to be valid. 1st value is number of days for warning, 2nd is critical (if not specified: 0) -- separated by comma.", - "flag": { - "long": "certificate", - "short": "D" - }, - "name": "clamd_certificate", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use SSL for the connection. Defaults to false.", - "name": "clamd_ssl", - "optional": true - }, - { - "description": "Response time to result in warning status (seconds).", - "name": "clamd_wtime", - "optional": true - }, - { - "description": "Response time to result in critical status (seconds).", - "name": "clamd_ctime", - "optional": true - }, - { - "description": "Seconds before connection times out. Defaults to 10.", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "clamd_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "clamd_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "clamd_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_dhcp](https://www.monitoring-plugins.org/doc/man/check_dhcp.html) plugin tests the availability of DHCP servers on a network.", - "name": "dhcp", - "vars": [ - { - "description": "The IP address of the DHCP server which we should get a response from.", - "flag": { - "long": "serverip", - "short": "s" - }, - "format": "IPADDRESS", - "name": "dhcp_serverip", - "optional": true, - "type": "STRING" - }, - { - "description": "The IP address which we should be offered by a DHCP server.", - "flag": { - "long": "requestedip", - "short": "r" - }, - "format": "IPADDRESS", - "name": "dhcp_requestedip", - "optional": true, - "type": "STRING" - }, - { - "description": "The timeout in seconds.", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "dhcp_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "The interface to use.", - "flag": { - "long": "interface", - "short": "i" - }, - "name": "dhcp_interface", - "optional": true, - "type": "STRING" - }, - { - "description": "The MAC address to use in the DHCP request.", - "flag": { - "long": "mac", - "short": "m" - }, - "name": "dhcp_mac", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to use unicast requests. Defaults to false.", - "name": "dhcp_unicast", - "optional": true - } - ] - }, - { - "description": "The [check_dig](https://www.monitoring-plugins.org/doc/man/check_dig.html) plugin test the DNS service on the specified host using dig.", - "examples": "check_dig -H DNSSERVER -l www.example.com -A \"+tcp\"\n This will send a tcp query to DNSSERVER for www.example.com", - "name": "dig", - "vars": [ - { - "description": "The DNS server to query. Defaults to \"127.0.0.1\".", - "name": "dig_server", - "optional": true - }, - { - "description": "Port number (default: 53).", - "flag": { - "long": "port", - "short": "p" - }, - "name": "dig_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Required The address that should be looked up.", - "name": "dig_lookup", - "optional": false - }, - { - "description": "Record type to lookup (default: A).", - "flag": { - "long": "record_type", - "short": "T" - }, - "name": "dig_record_type", - "optional": true, - "type": "STRING" - }, - { - "description": "An address expected to be in the answer section. If not set, uses whatever was in -l.", - "flag": { - "long": "expected_address", - "short": "a" - }, - "name": "dig_expected_address", - "optional": true, - "type": "STRING" - }, - { - "description": "Pass STRING as argument(s) to dig.", - "flag": { - "long": "dig-arguments", - "short": "A" - }, - "name": "dig_arguments", - "optional": true, - "type": "STRING" - }, - { - "description": "Number of retries passed to dig, timeout is divided by this value (Default: 3).", - "name": "dig_retries", - "optional": true - }, - { - "description": "Response time to result in warning status (seconds).", - "flag": { - "long": "warning", - "short": "w" - }, - "name": "dig_warning", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Response time to result in critical status (seconds).", - "flag": { - "long": "critical", - "short": "c" - }, - "name": "dig_critical", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Seconds before connection times out (default: 10).", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "dig_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Force dig to only use IPv4 query transport. Defaults to false.", - "name": "dig_ipv4", - "optional": true - }, - { - "description": "Force dig to only use IPv6 query transport. Defaults to false.", - "name": "dig_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_disk](https://www.monitoring-plugins.org/doc/man/check_disk.html) plugin checks the amount of used disk space on a mounted file system and generates an alert if free space is less than one of the threshold values.", - "examples": "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /\n Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB\n check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'\n Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex\n are grouped which means the freespace thresholds are applied to all disks together\n check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar\n Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M", - "name": "disk", - "vars": [ - { - "description": "The free space warning threshold. Defaults to \"20%\". If the percent sign is omitted, units from `disk_units` are used.", - "name": "disk_wfree", - "optional": true - }, - { - "description": "The free space critical threshold. Defaults to \"10%\". If the percent sign is omitted, units from `disk_units` are used.", - "name": "disk_cfree", - "optional": true - }, - { - "description": "The free inode warning threshold.", - "name": "disk_inode_wfree", - "optional": true - }, - { - "description": "The free inode critical threshold.", - "name": "disk_inode_cfree", - "optional": true - }, - { - "description": "The partition. Deprecated in 2.3", - "name": "disk_partition", - "optional": true - }, - { - "description": "The excluded partition. Deprecated in 2.3", - "name": "disk_partition_excluded", - "optional": true - }, - { - "description": "The partition(s). Multiple partitions must be defined as array.", - "name": "disk_partitions", - "optional": true - }, - { - "description": "The excluded partition(s). Multiple partitions must be defined as array.", - "name": "disk_partitions_excluded", - "optional": true - }, - { - "description": "Clear thresholds.", - "name": "disk_clear", - "optional": true - }, - { - "description": "For paths or partitions specified with -p, only check for exact paths.", - "name": "disk_exact_match", - "optional": true - }, - { - "description": "Display only devices/mountpoints with errors. May be true or false.", - "name": "disk_errors_only", - "optional": true - }, - { - "description": "If set, account root-reserved blocks are not accounted for freespace in perfdata.", - "name": "disk_ignore_reserved", - "optional": true - }, - { - "description": "Group paths. Thresholds apply to (free-)space of all partitions together.", - "flag": { - "long": "group", - "short": "g" - }, - "format": "NAME", - "name": "disk_group", - "optional": true, - "type": "STRING" - }, - { - "description": "Same as --units kB. May be true or false.", - "name": "disk_kilobytes", - "optional": true - }, - { - "description": "Only check local filesystems. May be true or false.", - "name": "disk_local", - "optional": true - }, - { - "description": "Only check local filesystems against thresholds. Yet call stat on remote filesystems to test if they are accessible (e.g. to detect Stale NFS Handles). May be true or false.", - "name": "disk_stat_remote_fs", - "optional": true - }, - { - "description": "Display the mountpoint instead of the partition. May be true or false.", - "name": "disk_mountpoint", - "optional": true - }, - { - "description": "Same as --units MB. May be true or false.", - "name": "disk_megabytes", - "optional": true - }, - { - "description": "Explicitly select all paths. This is equivalent to -R '.\\*'. May be true or false.", - "name": "disk_all", - "optional": true - }, - { - "description": "Case insensitive regular expression for path/partition. Multiple regular expression strings must be defined as array.", - "flag": { - "long": "eregi-path", - "short": "R" - }, - "format": "PATH,", - "name": "disk_eregi_path", - "optional": true, - "type": "STRING" - }, - { - "description": "Regular expression for path or partition. Multiple regular expression strings must be defined as array.", - "flag": { - "long": "ereg-path", - "short": "r" - }, - "format": "PATH,", - "name": "disk_ereg_path", - "optional": true, - "type": "STRING" - }, - { - "description": "Regular expression to ignore selected path/partition (case insensitive). Multiple regular expression strings must be defined as array.", - "flag": { - "long": "ignore-eregi-path", - "short": "I" - }, - "format": "PATH,", - "name": "disk_ignore_eregi_path", - "optional": true, - "type": "STRING" - }, - { - "description": "Regular expression to ignore selected path or partition. Multiple regular expression strings must be defined as array.", - "flag": { - "long": "ignore-ereg-path", - "short": "i" - }, - "format": "PATH,", - "name": "disk_ignore_ereg_path", - "optional": true, - "type": "STRING" - }, - { - "description": "Seconds before connection times out (default: 10).", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "disk_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Choose bytes, kB, MB, GB, TB (default: MB).", - "flag": { - "long": "units", - "short": "u" - }, - "name": "disk_units", - "optional": true, - "type": "STRING" - }, - { - "description": "Ignore all filesystems of indicated type. Multiple regular expression strings must be defined as array.", - "flag": { - "long": "exclude-type", - "short": "X" - }, - "format": "TYPE", - "name": "disk_exclude_type", - "optional": true, - "type": "STRING" - } - ] - }, - { - "description": "The [check_disk_smb](https://www.monitoring-plugins.org/doc/man/check_disk_smb.html) plugin uses the `smbclient` binary to check SMB shares.", - "name": "disk_smb", - "vars": [ - { - "description": "Required NetBIOS name of the server.", - "flag": { - "long": "hostname", - "short": "H" - }, - "format": "HOST", - "name": "disk_smb_hostname", - "optional": false, - "type": "STRING" - }, - { - "description": "Required Share name being queried.", - "flag": { - "long": "share", - "short": "s" - }, - "name": "disk_smb_share", - "optional": false, - "type": "STRING" - }, - { - "description": "Workgroup or Domain used (defaults to 'WORKGROUP' if omitted).", - "flag": { - "long": "workgroup", - "short": "W" - }, - "name": "disk_smb_workgroup", - "optional": true, - "type": "STRING" - }, - { - "description": "IP address of the host (only necessary if host belongs to another network).", - "flag": { - "long": "address", - "short": "a" - }, - "format": "IP", - "name": "disk_smb_address", - "optional": true, - "type": "STRING" - }, - { - "description": "Username for server log-in (defaults to 'guest' if omitted).", - "flag": { - "long": "user", - "short": "u" - }, - "name": "disk_smb_username", - "optional": true, - "type": "STRING" - }, - { - "description": "Password for server log-in (defaults to an empty password if omitted).", - "flag": { - "long": "password", - "short": "p" - }, - "name": "disk_smb_password", - "optional": true, - "type": "STRING" - }, - { - "description": "The used space warning threshold. Defaults to \"85%\". If the percent sign is omitted, use optional disk units.", - "name": "disk_smb_wused", - "optional": true - }, - { - "description": "The used space critical threshold. Defaults to \"95%\". If the percent sign is omitted, use optional disk units.", - "name": "disk_smb_cused", - "optional": true - }, - { - "description": "Connection port, e.g. `139` or `445`. Defaults to `smbclient` default if omitted.", - "flag": { - "long": "port", - "short": "P" - }, - "name": "disk_smb_port", - "optional": true, - "type": "INTEGER" - } - ] - }, - { - "description": "The [check_dns](https://www.monitoring-plugins.org/doc/man/check_dns.html) plugin uses the nslookup program to obtain the IP address for the given host/domain query. An optional DNS server to use may be specified. If no DNS server is specified, the default server(s) specified in `/etc/resolv.conf` will be used.", - "name": "dns", - "vars": [ - { - "description": "The hostname or IP to query the DNS for. Defaults to \"$host_name$\".", - "name": "dns_lookup", - "optional": true - }, - { - "description": "The DNS server to query. Defaults to the server configured in the OS.", - "flag": { - "long": "server", - "short": "s" - }, - "format": "HOST", - "name": "dns_server", - "optional": true, - "type": "STRING" - }, - { - "description": "The answer to look for. A hostname must end with a dot. Deprecated in 2.3", - "name": "dns_expected_answer", - "optional": true - }, - { - "description": "The answer(s) to look for. A hostname must end with a dot. Multiple answers must be defined as array.", - "name": "dns_expected_answers", - "optional": true - }, - { - "description": "Expect the server to send an authoritative answer.", - "name": "dns_authoritative", - "optional": true - }, - { - "description": "Return warning if elapsed time exceeds value.", - "name": "dns_wtime", - "optional": true - }, - { - "description": "Return critical if elapsed time exceeds value.", - "name": "dns_ctime", - "optional": true - }, - { - "description": "Seconds before connection times out. Defaults to 10.", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "dns_timeout", - "optional": true, - "type": "INTEGER" - } - ] - }, - { - "description": "The [check_dummy](https://www.monitoring-plugins.org/doc/man/check_dummy.html) plugin will simply return the state corresponding to the numeric value of the `dummy_state` argument with optional text.", - "name": "dummy", - "vars": [ - { - "description": "The state. Can be one of 0 (ok), 1 (warning), 2 (critical) and 3 (unknown). Defaults to 0.", - "name": "dummy_state", - "optional": true - }, - { - "description": "Plugin output. Defaults to \"Check was successful.\".", - "name": "dummy_text", - "optional": true - } - ] - }, - { - "description": "The [check_file_age](https://www.monitoring-plugins.org/doc/man/check_file_age.html) plugin checks a file's size and modification time to make sure it's not empty and that it's sufficiently recent.", - "name": "file_age", - "vars": [ - { - "description": "Required File to monitor.", - "name": "file_age_file", - "optional": false - }, - { - "description": "File must be no more than this many seconds old as warning threshold. Defaults to \"240s\".", - "name": "file_age_warning_time", - "optional": true - }, - { - "description": "File must be no more than this many seconds old as critical threshold. Defaults to \"600s\".", - "name": "file_age_critical_time", - "optional": true - }, - { - "description": "File must be at least this many bytes long as warning threshold. No default given.", - "name": "file_age_warning_size", - "optional": true - }, - { - "description": "File must be at least this many bytes long as critical threshold. Defaults to \"0B\".", - "name": "file_age_critical_size", - "optional": true - }, - { - "description": "Return OK if the file does not exist. Defaults to false.", - "name": "file_age_ignoremissing", - "optional": true - } - ] - }, - { - "description": "The [check_flexlm](https://www.monitoring-plugins.org/doc/man/check_flexlm.html) plugin checks available flexlm license managers. Requires the `lmstat` command.", - "name": "flexlm", - "vars": [ - { - "description": "Required Name of license file (usually license.dat).", - "name": "flexlm_licensefile", - "optional": false - }, - { - "description": "Plugin time out in seconds. Defaults to 15.", - "name": "flexlm_timeout", - "optional": true - } - ] - }, - { - "description": "The [check_ftp](https://www.monitoring-plugins.org/doc/man/check_ftp.html) plugin tests FTP connections with the specified host (or unix socket).", - "name": "ftp", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "ftp_address", - "optional": true - }, - { - "description": "The FTP port number.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "ftp_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "String to expect in server response. Multiple strings must be defined as array.", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "ftp_expect", - "optional": true, - "type": "STRING" - }, - { - "description": "All expect strings need to occur in server response. Defaults to false.", - "name": "ftp_all", - "optional": true - }, - { - "description": "Enable usage of \\\\n, \\\\r, \\\\t or \\\\\\\\ in send string.", - "flag": { - "long": "send", - "short": "s" - }, - "name": "ftp_escape_send", - "optional": true, - "type": "STRING" - }, - { - "description": "String to send to the server.", - "flag": { - "long": "send", - "short": "s" - }, - "name": "ftp_send", - "optional": true, - "type": "STRING" - }, - { - "description": "Enable usage of \\\\n, \\\\r, \\\\t or \\\\\\\\ in quit string.", - "flag": { - "long": "quit", - "short": "q" - }, - "name": "ftp_escape_quit", - "optional": true, - "type": "STRING" - }, - { - "description": "String to send server to initiate a clean close of the connection.", - "flag": { - "long": "quit", - "short": "q" - }, - "name": "ftp_quit", - "optional": true, - "type": "STRING" - }, - { - "description": "Accept TCP refusals with states ok, warn, crit. Defaults to crit.", - "flag": { - "long": "refuse", - "short": "r" - }, - "format": "enum", - "name": "ftp_refuse", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Accept expected string mismatches with states ok, warn, crit. Defaults to warn.", - "flag": { - "long": "mismatch", - "short": "M" - }, - "format": "enum", - "name": "ftp_mismatch", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Hide output from TCP socket.", - "name": "ftp_jail", - "optional": true - }, - { - "description": "Close connection once more than this number of bytes are received.", - "flag": { - "long": "maxbytes", - "short": "m" - }, - "name": "ftp_maxbytes", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Seconds to wait between sending string and polling for response.", - "flag": { - "long": "delay", - "short": "d" - }, - "name": "ftp_delay", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Minimum number of days a certificate has to be valid. 1st value is number of days for warning, 2nd is critical (if not specified: 0) -- separated by comma.", - "flag": { - "long": "certificate", - "short": "D" - }, - "name": "ftp_certificate", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use SSL for the connection. Defaults to false.", - "name": "ftp_ssl", - "optional": true - }, - { - "description": "Response time to result in warning status (seconds).", - "name": "ftp_wtime", - "optional": true - }, - { - "description": "Response time to result in critical status (seconds).", - "name": "ftp_ctime", - "optional": true - }, - { - "description": "Seconds before connection times out. Defaults to 10.", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "ftp_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "ftp_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "ftp_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_game](https://www.monitoring-plugins.org/doc/man/check_game.html) plugin tests game server connections with the specified host. This plugin uses the 'qstat' command, the popular game server status query tool. If you don't have the package installed, you will need to [download](http://www.activesw.com/people/steve/qstat.html) or install the package `quakestat` before you can use this plugin.", - "name": "game", - "vars": [ - { - "description": "Required Name of the game.", - "name": "game_game", - "optional": false - }, - { - "description": "Required Ipaddress of the game server to query.", - "name": "game_ipaddress", - "optional": false - }, - { - "description": "Seconds before connection times out. Defaults to 10.", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "game_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Port to connect to.", - "name": "game_port", - "optional": true - }, - { - "description": "Field number in raw qstat output that contains game name.", - "name": "game_gamefield", - "optional": true - }, - { - "description": "Field number in raw qstat output that contains map name.", - "name": "game_mapfield", - "optional": true - }, - { - "description": "Field number in raw qstat output that contains ping time.", - "name": "game_pingfield", - "optional": true - }, - { - "description": "Field number in raw qstat output that contains game time.", - "name": "game_gametime", - "optional": true - }, - { - "description": "Name of the host running the game.", - "name": "game_hostname", - "optional": true - } - ] - }, - { - "description": "The [check_hpjd](https://www.monitoring-plugins.org/doc/man/check_hpjd.html) plugin tests the state of an HP printer with a JetDirect card. Net-snmp must be installed on the computer running the plugin.", - "name": "hpjd", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "hpjd_address", - "optional": true - }, - { - "description": "The host's SNMP port. Defaults to 161.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "hpjd_port", - "optional": true, - "type": "STRING" - }, - { - "description": "The SNMP community. Defaults to \"public\".", - "flag": { - "long": "community", - "short": "C" - }, - "name": "hpjd_community", - "optional": true, - "type": "STRING" - } - ] - }, - { - "description": "The [check_http](https://www.monitoring-plugins.org/doc/man/check_http.html) plugin tests the HTTP service on the specified host. It can test normal (http) and secure (https) servers, follow redirects, search for strings and regular expressions, check connection times, and report on certificate expiration times.", - "examples": "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com\n\n When the 'www.verisign.com' server returns its content within 5 seconds,\n a STATE_OK will be returned. When the server returns its content but exceeds\n the 5-second threshold, a STATE_Warning will be returned. When an error occurs,\n a STATE_Critical will be returned.\n\n CHECK CERTIFICATE: check_http -H www.verisign.com -C 14\n\n When the certificate of 'www.verisign.com' is valid for more than 14 days,\n a STATE_OK is returned. When the certificate is still valid, but for less than\n 14 days, a STATE_Warning is returned. A STATE_Critical will be returned when\n the certificate is expired.\n\n CHECK CERTIFICATE: check_http -H www.verisign.com -C 30,14\n\n When the certificate of 'www.verisign.com' is valid for more than 30 days,\n a STATE_OK is returned. When the certificate is still valid, but for less than\n 30 days, but more than 14 days, a STATE_Warning is returned.\n A STATE_Critical will be returned when certificate expires in less than 14 days\n CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT:\n\n check_http -I 192.168.100.35 -p 80 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com \n all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>\n a STATE_OK will be returned. When the server returns its content but exceeds\n the 5-second threshold, a STATE_Warning will be returned. When an error occurs,\n a STATE_Critical will be returned.", - "name": "http", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "http_address", - "optional": true - }, - { - "description": "The virtual host that should be sent in the \"Host\" header.", - "name": "http_vhost", - "optional": true - }, - { - "description": "The request URI for GET or POST. Defaults to `/`.", - "name": "http_uri", - "optional": true - }, - { - "description": "The TCP port. Defaults to 80 when not using SSL, 443 otherwise.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "http_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Whether to use SSL. Defaults to false.", - "flag": { - "long": "ssl", - "short": "S" - }, - "format": "VERSION[+]", - "name": "http_ssl", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force TLSv1.", - "flag": { - "long": "ssl", - "short": "S" - }, - "format": "VERSION[+]", - "name": "http_ssl_force_tlsv1", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force TLSv1.1.", - "flag": { - "long": "ssl", - "short": "S" - }, - "format": "VERSION[+]", - "name": "http_ssl_force_tlsv1_1", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force TLSv1.2.", - "flag": { - "long": "ssl", - "short": "S" - }, - "format": "VERSION[+]", - "name": "http_ssl_force_tlsv1_2", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force SSLv2.", - "flag": { - "long": "ssl", - "short": "S" - }, - "format": "VERSION[+]", - "name": "http_ssl_force_sslv2", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force SSLv3.", - "flag": { - "long": "ssl", - "short": "S" - }, - "format": "VERSION[+]", - "name": "http_ssl_force_sslv3", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force TLSv1 or higher.", - "flag": { - "long": "ssl", - "short": "S" - }, - "format": "VERSION[+]", - "name": "http_ssl_force_tlsv1_or_higher", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force TLSv1.1 or higher.", - "flag": { - "long": "ssl", - "short": "S" - }, - "format": "VERSION[+]", - "name": "http_ssl_force_tlsv1_1_or_higher", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force TLSv1.2 or higher.", - "flag": { - "long": "ssl", - "short": "S" - }, - "format": "VERSION[+]", - "name": "http_ssl_force_tlsv1_2_or_higher", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force SSLv2 or higher.", - "flag": { - "long": "ssl", - "short": "S" - }, - "format": "VERSION[+]", - "name": "http_ssl_force_sslv2_or_higher", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to force SSLv3 or higher.", - "flag": { - "long": "ssl", - "short": "S" - }, - "format": "VERSION[+]", - "name": "http_ssl_force_sslv3_or_higher", - "optional": true, - "type": "STRING" - }, - { - "description": "Whether to use SNI. Defaults to false.", - "name": "http_sni", - "optional": true - }, - { - "description": "Add 'username:password' authorization pair.", - "name": "http_auth_pair", - "optional": true - }, - { - "description": "Add 'username:password' authorization pair for proxy.", - "name": "http_proxy_auth_pair", - "optional": true - }, - { - "description": "Don't download the body, just the headers.", - "name": "http_ignore_body", - "optional": true - }, - { - "description": "Allow regex to span newline.", - "name": "http_linespan", - "optional": true - }, - { - "description": "A regular expression which the body must match against. Incompatible with http_ignore_body.", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "http_expect_body_regex", - "optional": true, - "type": "STRING" - }, - { - "description": "A case-insensitive expression which the body must match against. Incompatible with http_ignore_body.", - "flag": { - "long": "eregi", - "short": "R" - }, - "name": "http_expect_body_eregi", - "optional": true, - "type": "STRING" - }, - { - "description": "Changes behaviour of http_expect_body_regex and http_expect_body_eregi to return Critical if found, OK if not.", - "name": "http_invertregex", - "optional": true - }, - { - "description": "The warning threshold.", - "name": "http_warn_time", - "optional": true - }, - { - "description": "The critical threshold.", - "flag": { - "long": "critical", - "short": "c" - }, - "name": "http_critical_time", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Comma-delimited list of strings, at least one of them is expected in the first (status) line of the server response. Default: HTTP/1.", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "http_expect", - "optional": true, - "type": "STRING" - }, - { - "description": "Minimum number of days a certificate has to be valid. This parameter explicitely sets the port to 443 and ignores the URL if passed.", - "flag": { - "long": "certificate", - "short": "C" - }, - "name": "http_certificate", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Name of file contains the client certificate (PEM format).", - "flag": { - "long": "client-cert", - "short": "J" - }, - "format": "FILE", - "name": "http_clientcert", - "optional": true, - "type": "STRING" - }, - { - "description": "Name of file contains the private key (PEM format).", - "flag": { - "long": "private-key", - "short": "K" - }, - "format": "FILE", - "name": "http_privatekey", - "optional": true, - "type": "STRING" - }, - { - "description": "String to expect in the response headers.", - "flag": { - "long": "header", - "short": "k" - }, - "name": "http_headerstring", - "optional": true, - "type": "STRING" - }, - { - "description": "String to expect in the content.", - "flag": { - "long": "string", - "short": "s" - }, - "name": "http_string", - "optional": true, - "type": "STRING" - }, - { - "description": "URL encoded http POST data.", - "flag": { - "long": "post", - "short": "P" - }, - "name": "http_post", - "optional": true, - "type": "STRING" - }, - { - "description": "Set http method (for example: HEAD, OPTIONS, TRACE, PUT, DELETE).", - "flag": { - "long": "method", - "short": "j" - }, - "name": "http_method", - "optional": true, - "type": "STRING" - }, - { - "description": "Warn if document is more than seconds old.", - "flag": { - "long": "max-age", - "short": "M" - }, - "format": "SECONDS", - "name": "http_maxage", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Specify Content-Type header when POSTing.", - "flag": { - "long": "content-type", - "short": "T" - }, - "name": "http_contenttype", - "optional": true, - "type": "STRING" - }, - { - "description": "String to be sent in http header as User Agent.", - "flag": { - "long": "useragent", - "short": "A" - }, - "name": "http_useragent", - "optional": true, - "type": "STRING" - }, - { - "description": "Any other tags to be sent in http header.", - "flag": { - "long": "header", - "short": "k" - }, - "name": "http_header", - "optional": true, - "type": "STRING" - }, - { - "description": "Print additional perfdata. Defaults to false.", - "name": "http_extendedperfdata", - "optional": true - }, - { - "description": "How to handle redirect pages. Possible values: \"ok\" (default), \"warning\", \"critical\", \"follow\", \"sticky\" (like follow but stick to address), \"stickyport\" (like sticky but also to port)", - "flag": { - "long": "onredirect", - "short": "f" - }, - "format": "enum", - "name": "http_onredirect", - "optional": true, - "type": "STRING", - "values": [ - "" - ] - }, - { - "description": "Minimum page size required:Maximum page size required.", - "flag": { - "long": "pagesize", - "short": "m" - }, - "format": "INTEGER<:INTEGER>", - "name": "http_pagesize", - "optional": true, - "type": "STRING" - }, - { - "description": "Seconds before connection times out.", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "http_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "http_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "http_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_icmp](https://www.monitoring-plugins.org/doc/man/check_icmp.html) plugin check_icmp allows for checking multiple hosts at once compared to `check_ping`. The main difference is that check_ping executes the system's ping(1) command and parses its output while check_icmp talks ICMP itself. check_icmp must be installed setuid root.", - "name": "icmp", - "vars": [ - { - "description": "The host's address. This can either be a single address or an array of addresses. Defaults to \"$address$\".", - "name": "icmp_address", - "optional": true - }, - { - "description": "The RTA warning threshold in milliseconds. Defaults to 100.", - "name": "icmp_wrta", - "optional": true - }, - { - "description": "The packet loss warning threshold in %. Defaults to 5.", - "name": "icmp_wpl", - "optional": true - }, - { - "description": "The RTA critical threshold in milliseconds. Defaults to 200.", - "name": "icmp_crta", - "optional": true - }, - { - "description": "The packet loss critical threshold in %. Defaults to 15.", - "name": "icmp_cpl", - "optional": true - }, - { - "description": "The source IP address to send packets from.", - "name": "icmp_source", - "optional": true - }, - { - "description": "The number of packets to send. Defaults to 5.", - "name": "icmp_packets", - "optional": true - }, - { - "description": "The maximum packet interval. Defaults to 80 (milliseconds).", - "name": "icmp_packet_interval", - "optional": true - }, - { - "description": "The maximum target interval.", - "name": "icmp_target_interval", - "optional": true - }, - { - "description": "The number of hosts which have to be alive for the check to succeed.", - "name": "icmp_hosts_alive", - "optional": true - }, - { - "description": "Payload size for each ICMP request. Defaults to 8.", - "name": "icmp_data_bytes", - "optional": true - }, - { - "description": "The plugin timeout in seconds. Defaults to 10 (seconds).", - "name": "icmp_timeout", - "optional": true - } - ] - }, - { - "description": "The [check_imap](https://www.monitoring-plugins.org/doc/man/check_imap.html) plugin tests IMAP connections with the specified host (or unix socket).", - "name": "imap", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "imap_address", - "optional": true - }, - { - "description": "The port that should be checked. Defaults to 143.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "imap_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Can use \\\\n, \\\\r, \\\\t or \\\\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \\\\r\\\\n added to end of quit.", - "name": "imap_escape", - "optional": true - }, - { - "description": "String to send to the server.", - "flag": { - "long": "send", - "short": "s" - }, - "name": "imap_send", - "optional": true, - "type": "STRING" - }, - { - "description": "String to expect in server response. Multiple strings must be defined as array.", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "imap_expect", - "optional": true, - "type": "STRING" - }, - { - "description": "All expect strings need to occur in server response. Default is any.", - "name": "imap_all", - "optional": true - }, - { - "description": "String to send server to initiate a clean close of the connection.", - "flag": { - "long": "quit", - "short": "q" - }, - "name": "imap_quit", - "optional": true, - "type": "STRING" - }, - { - "description": "Accept TCP refusals with states ok, warn, crit (default: crit).", - "flag": { - "long": "refuse", - "short": "r" - }, - "format": "enum", - "name": "imap_refuse", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Accept expected string mismatches with states ok, warn, crit (default: warn).", - "flag": { - "long": "mismatch", - "short": "M" - }, - "format": "enum", - "name": "imap_mismatch", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Hide output from TCP socket.", - "name": "imap_jail", - "optional": true - }, - { - "description": "Close connection once more than this number of bytes are received.", - "flag": { - "long": "maxbytes", - "short": "m" - }, - "name": "imap_maxbytes", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Seconds to wait between sending string and polling for response.", - "flag": { - "long": "delay", - "short": "d" - }, - "name": "imap_delay", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Minimum number of days a certificate has to be valid.", - "flag": { - "long": "certificate", - "short": "D" - }, - "name": "imap_certificate_age", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use SSL for the connection.", - "name": "imap_ssl", - "optional": true - }, - { - "description": "Response time to result in warning status (seconds).", - "flag": { - "long": "warning", - "short": "w" - }, - "name": "imap_warning", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Response time to result in critical status (seconds).", - "flag": { - "long": "critical", - "short": "c" - }, - "name": "imap_critical", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Seconds before connection times out (default: 10).", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "imap_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "imap_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "imap_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_ldap](https://www.monitoring-plugins.org/doc/man/check_ldap.html) plugin can be used to check LDAP servers.", - "name": "ldap", - "vars": [ - { - "description": "Host name, IP Address, or unix socket (must be an absolute path). Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "ldap_address", - "optional": true - }, - { - "description": "Port number. Defaults to 389.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "ldap_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "LDAP attribute to search for (default: \"(objectclass=*)\"", - "name": "ldap_attr", - "optional": true - }, - { - "description": "Required LDAP base (eg. ou=myunit,o=myorg,c=at).", - "name": "ldap_base", - "optional": false - }, - { - "description": "LDAP bind DN (if required).", - "name": "ldap_bind", - "optional": true - }, - { - "description": "LDAP password (if required).", - "name": "ldap_pass", - "optional": true - }, - { - "description": "Use STARTSSL mechanism introduced in protocol version 3.", - "name": "ldap_starttls", - "optional": true - }, - { - "description": "Use LDAPS (LDAP v2 SSL method). This also sets the default port to 636.", - "name": "ldap_ssl", - "optional": true - }, - { - "description": "Use LDAP protocol version 2 (enabled by default).", - "name": "ldap_v2", - "optional": true - }, - { - "description": "Use LDAP protocol version 3 (disabled by default)", - "name": "ldap_v3", - "optional": true - }, - { - "description": "Response time to result in warning status (seconds).", - "flag": { - "long": "warning", - "short": "w" - }, - "name": "ldap_warning", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Response time to result in critical status (seconds).", - "flag": { - "long": "critical", - "short": "c" - }, - "name": "ldap_critical", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Seconds before connection times out (default: 10).", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "ldap_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Show details for command-line debugging (disabled by default)", - "name": "ldap_verbose", - "optional": true - } - ] - }, - { - "description": "The [check_load](https://www.monitoring-plugins.org/doc/man/check_load.html) plugin tests the current system load average.", - "name": "load", - "vars": [ - { - "description": "The 1-minute warning threshold. Defaults to 5.", - "name": "load_wload1", - "optional": true - }, - { - "description": "The 5-minute warning threshold. Defaults to 4.", - "name": "load_wload5", - "optional": true - }, - { - "description": "The 15-minute warning threshold. Defaults to 3.", - "name": "load_wload15", - "optional": true - }, - { - "description": "The 1-minute critical threshold. Defaults to 10.", - "name": "load_cload1", - "optional": true - }, - { - "description": "The 5-minute critical threshold. Defaults to 6.", - "name": "load_cload5", - "optional": true - }, - { - "description": "The 15-minute critical threshold. Defaults to 4.", - "name": "load_cload15", - "optional": true - }, - { - "description": "Divide the load averages by the number of CPUs (when possible). Defaults to false.", - "name": "load_percpu", - "optional": true - } - ] - }, - { - "description": "The [check_mailq](https://www.monitoring-plugins.org/doc/man/check_mailq.html) plugin checks the number of messages in the mail queue (supports multiple sendmail queues, qmail).", - "name": "mailq", - "vars": [ - { - "description": "Required Min. number of messages in queue to generate warning.", - "name": "mailq_warning", - "optional": false - }, - { - "description": "Required Min. number of messages in queue to generate critical alert ( w < c ).", - "name": "mailq_critical", - "optional": false - }, - { - "description": "Min. number of messages for same domain in queue to generate warning", - "name": "mailq_domain_warning", - "optional": true - }, - { - "description": "Min. number of messages for same domain in queue to generate critical alert ( W < C ).", - "name": "mailq_domain_critical", - "optional": true - }, - { - "description": "Plugin timeout in seconds (default = 15).", - "name": "mailq_timeout", - "optional": true - } - ] - }, - { - "description": "The [check_mysql](https://www.monitoring-plugins.org/doc/man/check_mysql.html) plugin tests connections to a MySQL server.", - "name": "mysql", - "vars": [ - { - "description": "Host name, IP Address, or unix socket (must be an absolute path).", - "flag": { - "long": "hostname", - "short": "H" - }, - "format": "ADDRESS", - "name": "mysql_hostname", - "optional": true, - "type": "STRING" - }, - { - "description": "Port number (default: 3306).", - "flag": { - "long": "port", - "short": "P" - }, - "name": "mysql_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Ignore authentication failure and check for mysql connectivity only.", - "name": "mysql_ignore_auth", - "optional": true - }, - { - "description": "Check database with indicated name.", - "flag": { - "long": "database", - "short": "d" - }, - "name": "mysql_database", - "optional": true, - "type": "STRING" - }, - { - "description": "Read from the specified client options file.", - "flag": { - "long": "file", - "short": "f" - }, - "name": "mysql_file", - "optional": true, - "type": "STRING" - }, - { - "description": "Use a client options group.", - "flag": { - "long": "group", - "short": "g" - }, - "name": "mysql_group", - "optional": true, - "type": "STRING" - }, - { - "description": "Connect using the indicated username.", - "flag": { - "long": "username", - "short": "u" - }, - "name": "mysql_username", - "optional": true, - "type": "STRING" - }, - { - "description": "Use the indicated password to authenticate the connection.", - "flag": { - "long": "password", - "short": "p" - }, - "name": "mysql_password", - "optional": true, - "type": "STRING" - }, - { - "description": "Check if the slave thread is running properly.", - "name": "mysql_check_slave", - "optional": true - }, - { - "description": "Exit with Warning status if slave server is more than INTEGER seconds behind master.", - "name": "mysql_warning", - "optional": true - }, - { - "description": "Exit with Critical status if slave server is more then INTEGER seconds behind master.", - "name": "mysql_critical", - "optional": true - }, - { - "description": "Use ssl encryptation.", - "name": "mysql_ssl", - "optional": true - }, - { - "description": "Path to CA signing the cert.", - "flag": { - "long": "cert", - "short": "a" - }, - "name": "mysql_cacert", - "optional": true, - "type": "STRING" - }, - { - "description": "Path to SSL certificate.", - "flag": { - "long": "cert", - "short": "a" - }, - "name": "mysql_cert", - "optional": true, - "type": "STRING" - }, - { - "description": "Path to private SSL key.", - "flag": { - "long": "key", - "short": "k" - }, - "name": "mysql_key", - "optional": true, - "type": "STRING" - }, - { - "description": "Path to CA directory.", - "flag": { - "long": "ca-dir", - "short": "D" - }, - "name": "mysql_cadir", - "optional": true, - "type": "STRING" - }, - { - "description": "List of valid SSL ciphers.", - "flag": { - "long": "ciphers", - "short": "L" - }, - "name": "mysql_ciphers", - "optional": true, - "type": "STRING" - } - ] - }, - { - "description": "The [check_mysql_query](https://www.monitoring-plugins.org/doc/man/check_mysql_query.html) plugin checks a query result against threshold levels. The result from the query should be numeric. For extra security, create a user with minimal access.", - "name": "mysql_query", - "vars": [ - { - "description": "Host name, IP Address, or unix socket (must be an absolute path).", - "flag": { - "long": "hostname", - "short": "H" - }, - "format": "ADDRESS", - "name": "mysql_query_hostname", - "optional": true, - "type": "STRING" - }, - { - "description": "Port number (default: 3306).", - "flag": { - "long": "port", - "short": "P" - }, - "name": "mysql_query_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Check database with indicated name.", - "flag": { - "long": "database", - "short": "d" - }, - "name": "mysql_query_database", - "optional": true, - "type": "STRING" - }, - { - "description": "Read from the specified client options file.", - "flag": { - "long": "file", - "short": "f" - }, - "name": "mysql_query_file", - "optional": true, - "type": "STRING" - }, - { - "description": "Use a client options group.", - "flag": { - "long": "group", - "short": "g" - }, - "name": "mysql_query_group", - "optional": true, - "type": "STRING" - }, - { - "description": "Connect using the indicated username.", - "flag": { - "long": "username", - "short": "u" - }, - "name": "mysql_query_username", - "optional": true, - "type": "STRING" - }, - { - "description": "Use the indicated password to authenticate the connection.", - "flag": { - "long": "password", - "short": "p" - }, - "name": "mysql_query_password", - "optional": true, - "type": "STRING" - }, - { - "description": "Required SQL Query to run on the MySQL Server.", - "flag": { - "long": "query", - "short": "q" - }, - "name": "mysql_query_execute", - "optional": false, - "type": "STRING" - }, - { - "description": "Exit with Warning status if query is outside of the range (format: start:end).", - "flag": { - "long": "warning", - "short": "w" - }, - "format": "RANGE", - "name": "mysql_query_warning", - "optional": true, - "type": "STRING" - }, - { - "description": "Exit with Critical status if query is outside of the range.", - "flag": { - "long": "critical", - "short": "c" - }, - "format": "RANGE", - "name": "mysql_query_critical", - "optional": true, - "type": "STRING" - } - ] - }, - { - "description": "The [check_ntp_time](https://www.monitoring-plugins.org/doc/man/check_ntp_time.html) plugin checks the clock offset between the local host and a remote NTP server.", - "examples": "./check_ntp_time -H ntpserv -w 0.5 -c 1", - "name": "ntp_time", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "ntp_address", - "optional": true - }, - { - "description": "Port number (default: 123).", - "flag": { - "long": "port", - "short": "p" - }, - "name": "ntp_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Returns Unknown instead of Critical if offset cannot be found.", - "name": "ntp_quiet", - "optional": true - }, - { - "description": "Offset to result in warning status (seconds).", - "flag": { - "long": "warning", - "short": "w" - }, - "format": "THRESHOLD", - "name": "ntp_warning", - "optional": true, - "type": "STRING" - }, - { - "description": "Offset to result in critical status (seconds).", - "flag": { - "long": "critical", - "short": "c" - }, - "format": "THRESHOLD", - "name": "ntp_critical", - "optional": true, - "type": "STRING" - }, - { - "description": "Expected offset of the ntp server relative to local server (seconds).", - "name": "ntp_timeoffset", - "optional": true - }, - { - "description": "Seconds before connection times out (default: 10).", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "ntp_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "ntp_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "ntp_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_ntp_peer](https://www.monitoring-plugins.org/doc/man/check_ntp_peer.html) plugin checks the health of an NTP server. It supports checking the offset with the sync peer, the jitter and stratum. This plugin will not check the clock offset between the local host and NTP server; please use `ntp_time` for that purpose.", - "examples": "Simple NTP server check:\n ./check_ntp_peer -H ntpserv -w 0.5 -c 1\n\n Check jitter too, avoiding critical notifications if jitter isn't available\n (See Notes above for more details on thresholds formats):\n ./check_ntp_peer -H ntpserv -w 0.5 -c 1 -j -1:100 -k -1:200\n\n Only check the number of usable time sources (\"truechimers\"):\n ./check_ntp_peer -H ntpserv -m @5 -n @3\n\n Check only stratum:\n ./check_ntp_peer -H ntpserv -W 4 -C 6", - "name": "ntp_peer", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "ntp_address", - "optional": true - }, - { - "description": "The port to use. Default to 123.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "ntp_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Offset to result in warning status (seconds).", - "flag": { - "long": "warning", - "short": "w" - }, - "format": "THRESHOLD", - "name": "ntp_warning", - "optional": true, - "type": "STRING" - }, - { - "description": "Offset to result in critical status (seconds).", - "flag": { - "long": "critical", - "short": "c" - }, - "format": "THRESHOLD", - "name": "ntp_critical", - "optional": true, - "type": "STRING" - }, - { - "description": "Warning threshold for stratum of server's synchronization peer.", - "name": "ntp_wstratum", - "optional": true - }, - { - "description": "Critical threshold for stratum of server's synchronization peer.", - "name": "ntp_cstratum", - "optional": true - }, - { - "description": "Warning threshold for jitter.", - "name": "ntp_wjitter", - "optional": true - }, - { - "description": "Critical threshold for jitter.", - "name": "ntp_cjitter", - "optional": true - }, - { - "description": "Warning threshold for number of usable time sources.", - "name": "ntp_wsource", - "optional": true - }, - { - "description": "Critical threshold for number of usable time sources.", - "name": "ntp_csource", - "optional": true - }, - { - "description": "Seconds before connection times out (default: 10).", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "ntp_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "ntp_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "ntp_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_pgsql](https://www.monitoring-plugins.org/doc/man/check_pgsql.html) plugin tests a PostgreSQL DBMS to determine whether it is active and accepting queries. If a query is specified using the `pgsql_query` attribute, it will be executed after connecting to the server. The result from the query has to be numeric in order to compare it against the query thresholds if set.", - "name": "pgsql", - "vars": [ - { - "description": "Host name, IP Address, or unix socket (must be an absolute path).", - "flag": { - "long": "hostname", - "short": "H" - }, - "format": "ADDRESS", - "name": "pgsql_hostname", - "optional": true, - "type": "STRING" - }, - { - "description": "Port number (default: 5432).", - "flag": { - "long": "port", - "short": "P" - }, - "name": "pgsql_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Database to check (default: template1).", - "flag": { - "long": "database", - "short": "d" - }, - "name": "pgsql_database", - "optional": true, - "type": "STRING" - }, - { - "description": "Login name of user.", - "name": "pgsql_username", - "optional": true - }, - { - "description": "Password (BIG SECURITY ISSUE).", - "name": "pgsql_password", - "optional": true - }, - { - "description": "Connection parameters (keyword = value), see below.", - "name": "pgsql_options", - "optional": true - }, - { - "description": "Response time to result in warning status (seconds).", - "flag": { - "long": "warning", - "short": "w" - }, - "name": "pgsql_warning", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Response time to result in critical status (seconds).", - "flag": { - "long": "critical", - "short": "c" - }, - "name": "pgsql_critical", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Seconds before connection times out (default: 10).", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "pgsql_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "SQL query to run. Only first column in first row will be read.", - "flag": { - "long": "query", - "short": "q" - }, - "name": "pgsql_query", - "optional": true, - "type": "STRING" - }, - { - "description": "SQL query value to result in warning status (double).", - "flag": { - "long": "query-warning", - "short": "W" - }, - "format": "RANGE", - "name": "pgsql_query_warning", - "optional": true, - "type": "STRING" - }, - { - "description": "SQL query value to result in critical status (double).", - "flag": { - "long": "query-critical", - "short": "C" - }, - "format": "RANGE", - "name": "pgsql_query_critical", - "optional": true, - "type": "STRING" - } - ] - }, - { - "description": "The [check_ping](https://www.monitoring-plugins.org/doc/man/check_ping.html) plugin uses the ping command to probe the specified host for packet loss (percentage) and round trip average (milliseconds).", - "name": "ping", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "ping_address", - "optional": true - }, - { - "description": "The RTA warning threshold in milliseconds. Defaults to 100.", - "name": "ping_wrta", - "optional": true - }, - { - "description": "The packet loss warning threshold in %. Defaults to 5.", - "name": "ping_wpl", - "optional": true - }, - { - "description": "The RTA critical threshold in milliseconds. Defaults to 200.", - "name": "ping_crta", - "optional": true - }, - { - "description": "The packet loss critical threshold in %. Defaults to 15.", - "name": "ping_cpl", - "optional": true - }, - { - "description": "The number of packets to send. Defaults to 5.", - "flag": { - "long": "packets", - "short": "p" - }, - "name": "ping_packets", - "optional": true, - "type": "INTEGER" - }, - { - "description": "The plugin timeout in seconds. Defaults to 0 (no timeout).", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "ping_timeout", - "optional": true, - "type": "INTEGER" - } - ] - }, - { - "description": "The [check_pop](https://www.monitoring-plugins.org/doc/man/check_pop.html) plugin tests POP connections with the specified host (or unix socket).", - "name": "pop", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "pop_address", - "optional": true - }, - { - "description": "The port that should be checked. Defaults to 110.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "pop_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Can use \\\\n, \\\\r, \\\\t or \\\\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \\\\r\\\\n added to end of quit.", - "name": "pop_escape", - "optional": true - }, - { - "description": "String to send to the server.", - "flag": { - "long": "send", - "short": "s" - }, - "name": "pop_send", - "optional": true, - "type": "STRING" - }, - { - "description": "String to expect in server response. Multiple strings must be defined as array.", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "pop_expect", - "optional": true, - "type": "STRING" - }, - { - "description": "All expect strings need to occur in server response. Default is any.", - "name": "pop_all", - "optional": true - }, - { - "description": "String to send server to initiate a clean close of the connection.", - "flag": { - "long": "quit", - "short": "q" - }, - "name": "pop_quit", - "optional": true, - "type": "STRING" - }, - { - "description": "Accept TCP refusals with states ok, warn, crit (default: crit).", - "flag": { - "long": "refuse", - "short": "r" - }, - "format": "enum", - "name": "pop_refuse", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Accept expected string mismatches with states ok, warn, crit (default: warn).", - "flag": { - "long": "mismatch", - "short": "M" - }, - "format": "enum", - "name": "pop_mismatch", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Hide output from TCP socket.", - "name": "pop_jail", - "optional": true - }, - { - "description": "Close connection once more than this number of bytes are received.", - "flag": { - "long": "maxbytes", - "short": "m" - }, - "name": "pop_maxbytes", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Seconds to wait between sending string and polling for response.", - "flag": { - "long": "delay", - "short": "d" - }, - "name": "pop_delay", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Minimum number of days a certificate has to be valid.", - "flag": { - "long": "certificate", - "short": "D" - }, - "name": "pop_certificate_age", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use SSL for the connection.", - "name": "pop_ssl", - "optional": true - }, - { - "description": "Response time to result in warning status (seconds).", - "flag": { - "long": "warning", - "short": "w" - }, - "name": "pop_warning", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Response time to result in critical status (seconds).", - "flag": { - "long": "critical", - "short": "c" - }, - "name": "pop_critical", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Seconds before connection times out (default: 10).", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "pop_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "pop_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "pop_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_procs](https://www.monitoring-plugins.org/doc/man/check_procs.html) plugin checks all processes and generates Warning or Critical states if the specified metric is outside the required threshold ranges. The metric defaults to number of processes. Search filters can be applied to limit the processes to check.", - "examples": "check_procs -w 2:2 -c 2:1024 -C portsentry\n Warning if not two processes with command name portsentry.\n Critical if < 2 or > 1024 processes\n\n check_procs -w 10 -a '/usr/local/bin/perl' -u root\n Warning alert if > 10 processes with command arguments containing\n '/usr/local/bin/perl' and owned by root\n\n check_procs -w 50000 -c 100000 --metric=VSZ\n Alert if VSZ of any processes over 50K or 100K\n\n check_procs -w 10 -c 20 --metric=CPU\n Alert if CPU of any processes over 10%% or 20%%", - "name": "procs", - "vars": [ - { - "description": "The process count warning threshold. Defaults to 250.", - "flag": { - "long": "warning", - "short": "w" - }, - "format": "RANGE", - "name": "procs_warning", - "optional": true, - "type": "STRING" - }, - { - "description": "The process count critical threshold. Defaults to 400.", - "flag": { - "long": "critical", - "short": "c" - }, - "format": "RANGE", - "name": "procs_critical", - "optional": true, - "type": "STRING" - }, - { - "description": "Check thresholds against metric.", - "flag": { - "long": "metric", - "short": "m" - }, - "format": "TYPE", - "name": "procs_metric", - "optional": true, - "type": "STRING" - }, - { - "description": "Seconds before plugin times out.", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "procs_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Filter own process the traditional way by PID instead of /proc/pid/exe. Defaults to false.", - "name": "procs_traditional", - "optional": true - }, - { - "description": "Only scan for processes that have one or more of the status flags you specify.", - "flag": { - "long": "state", - "short": "s" - }, - "format": "STATUSFLAGS", - "name": "procs_state", - "optional": true, - "type": "STRING" - }, - { - "description": "Only scan for children of the parent process ID indicated.", - "flag": { - "long": "ppid", - "short": "p" - }, - "format": "PPID", - "name": "procs_ppid", - "optional": true, - "type": "STRING" - }, - { - "description": "Only scan for processes with VSZ higher than indicated.", - "flag": { - "long": "vsz", - "short": "z" - }, - "format": "VSZ", - "name": "procs_vsz", - "optional": true, - "type": "STRING" - }, - { - "description": "Only scan for processes with RSS higher than indicated.", - "flag": { - "long": "rss", - "short": "r" - }, - "format": "RSS", - "name": "procs_rss", - "optional": true, - "type": "STRING" - }, - { - "description": "Only scan for processes with PCPU higher than indicated.", - "flag": { - "long": "pcpu", - "short": "P" - }, - "format": "PCPU", - "name": "procs_pcpu", - "optional": true, - "type": "STRING" - }, - { - "description": "Only scan for processes with user name or ID indicated.", - "flag": { - "long": "user", - "short": "u" - }, - "format": "USER", - "name": "procs_user", - "optional": true, - "type": "STRING" - }, - { - "description": "Only scan for processes with args that contain STRING.", - "name": "procs_argument", - "optional": true - }, - { - "description": "Only scan for processes with args that contain the regex STRING.", - "name": "procs_argument_regex", - "optional": true - }, - { - "description": "Only scan for exact matches of COMMAND (without path).", - "flag": { - "long": "command", - "short": "C" - }, - "format": "COMMAND", - "name": "procs_command", - "optional": true, - "type": "STRING" - }, - { - "description": "Only scan for non kernel threads. Defaults to false.", - "name": "procs_nokthreads", - "optional": true - } - ] - }, - { - "description": "The [check_simap](https://www.monitoring-plugins.org/doc/man/check_simap.html) plugin tests SIMAP connections with the specified host (or unix socket).", - "name": "simap", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "simap_address", - "optional": true - }, - { - "description": "The port that should be checked. Defaults to 993.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "simap_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Can use \\\\n, \\\\r, \\\\t or \\\\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \\\\r\\\\n added to end of quit.", - "name": "simap_escape", - "optional": true - }, - { - "description": "String to send to the server.", - "flag": { - "long": "send", - "short": "s" - }, - "name": "simap_send", - "optional": true, - "type": "STRING" - }, - { - "description": "String to expect in server response. Multiple strings must be defined as array.", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "simap_expect", - "optional": true, - "type": "STRING" - }, - { - "description": "All expect strings need to occur in server response. Default is any.", - "name": "simap_all", - "optional": true - }, - { - "description": "String to send server to initiate a clean close of the connection.", - "flag": { - "long": "quit", - "short": "q" - }, - "name": "simap_quit", - "optional": true, - "type": "STRING" - }, - { - "description": "Accept TCP refusals with states ok, warn, crit (default: crit).", - "flag": { - "long": "refuse", - "short": "r" - }, - "format": "enum", - "name": "simap_refuse", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Accept expected string mismatches with states ok, warn, crit (default: warn).", - "flag": { - "long": "mismatch", - "short": "M" - }, - "format": "enum", - "name": "simap_mismatch", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Hide output from TCP socket.", - "name": "simap_jail", - "optional": true - }, - { - "description": "Close connection once more than this number of bytes are received.", - "flag": { - "long": "maxbytes", - "short": "m" - }, - "name": "simap_maxbytes", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Seconds to wait between sending string and polling for response.", - "flag": { - "long": "delay", - "short": "d" - }, - "name": "simap_delay", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Minimum number of days a certificate has to be valid.", - "flag": { - "long": "certificate", - "short": "D" - }, - "name": "simap_certificate_age", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use SSL for the connection.", - "name": "simap_ssl", - "optional": true - }, - { - "description": "Response time to result in warning status (seconds).", - "flag": { - "long": "warning", - "short": "w" - }, - "name": "simap_warning", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Response time to result in critical status (seconds).", - "flag": { - "long": "critical", - "short": "c" - }, - "name": "simap_critical", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Seconds before connection times out (default: 10).", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "simap_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "simap_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "simap_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_smtp](https://www.monitoring-plugins.org/doc/man/check_smtp.html) plugin will attempt to open an SMTP connection with the host.", - "name": "smtp", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "smtp_address", - "optional": true - }, - { - "description": "The port that should be checked. Defaults to 25.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "smtp_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Test a MAIL FROM command with the given email address.", - "flag": { - "long": "from", - "short": "f" - }, - "name": "smtp_mail_from", - "optional": true, - "type": "STRING" - }, - { - "description": "String to expect in first line of server response (default: '220').", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "smtp_expect", - "optional": true, - "type": "STRING" - }, - { - "description": "SMTP command (may be used repeatedly).", - "flag": { - "long": "command", - "short": "C" - }, - "name": "smtp_command", - "optional": true, - "type": "STRING" - }, - { - "description": "Expected response to command (may be used repeatedly).", - "flag": { - "long": "response", - "short": "R" - }, - "name": "smtp_response", - "optional": true, - "type": "STRING" - }, - { - "description": "FQDN used for HELO", - "flag": { - "long": "fqdn", - "short": "F" - }, - "name": "smtp_helo_fqdn", - "optional": true, - "type": "STRING" - }, - { - "description": "Minimum number of days a certificate has to be valid.", - "flag": { - "long": "certificate", - "short": "D" - }, - "name": "smtp_certificate_age", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use STARTTLS for the connection.", - "name": "smtp_starttls", - "optional": true - }, - { - "description": "SMTP AUTH type to check (default none, only LOGIN supported).", - "flag": { - "long": "authtype", - "short": "A" - }, - "name": "smtp_authtype", - "optional": true, - "type": "STRING" - }, - { - "description": "SMTP AUTH username.", - "flag": { - "long": "authuser", - "short": "U" - }, - "name": "smtp_authuser", - "optional": true, - "type": "STRING" - }, - { - "description": "SMTP AUTH password.", - "flag": { - "long": "authpass", - "short": "P" - }, - "name": "smtp_authpass", - "optional": true, - "type": "STRING" - }, - { - "description": "Ignore failure when sending QUIT command to server.", - "name": "smtp_ignore_quit", - "optional": true - }, - { - "description": "Response time to result in warning status (seconds).", - "flag": { - "long": "warning", - "short": "w" - }, - "name": "smtp_warning", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Response time to result in critical status (seconds).", - "flag": { - "long": "critical", - "short": "c" - }, - "name": "smtp_critical", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Seconds before connection times out (default: 10).", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "smtp_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "smtp_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "smtp_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_snmp](https://www.monitoring-plugins.org/doc/man/check_snmp.html) plugin checks the status of remote machines and obtains system information via SNMP.", - "name": "snmp", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "snmp_address", - "optional": true - }, - { - "description": "Required The SNMP OID.", - "flag": { - "long": "oid", - "short": "o" - }, - "format": "OID(s)", - "name": "snmp_oid", - "optional": false, - "type": "STRING" - }, - { - "description": "The SNMP community. Defaults to \"public\".", - "flag": { - "long": "community", - "short": "C" - }, - "name": "snmp_community", - "optional": true, - "type": "STRING" - }, - { - "description": "The SNMP port. Defaults to \"161\".", - "flag": { - "long": "port", - "short": "p" - }, - "name": "snmp_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Number of retries to be used in the SNMP requests.", - "flag": { - "long": "retries", - "short": "e" - }, - "name": "snmp_retries", - "optional": true, - "type": "INTEGER" - }, - { - "description": "The warning threshold.", - "name": "snmp_warn", - "optional": true - }, - { - "description": "The critical threshold.", - "name": "snmp_crit", - "optional": true - }, - { - "description": "Return OK state if the string matches exactly with the output value", - "flag": { - "long": "string", - "short": "s" - }, - "name": "snmp_string", - "optional": true, - "type": "STRING" - }, - { - "description": "Return OK state if extended regular expression REGEX matches with the output value", - "flag": { - "long": "ereg", - "short": "r" - }, - "format": "REGEX", - "name": "snmp_ereg", - "optional": true, - "type": "STRING" - }, - { - "description": "Return OK state if case-insensitive extended REGEX matches with the output value", - "flag": { - "long": "eregi", - "short": "R" - }, - "format": "REGEX", - "name": "snmp_eregi", - "optional": true, - "type": "STRING" - }, - { - "description": "Prefix label for output value", - "flag": { - "long": "label", - "short": "l" - }, - "name": "snmp_label", - "optional": true, - "type": "STRING" - }, - { - "description": "Invert search result and return Critical state if found", - "name": "snmp_invert_search", - "optional": true - }, - { - "description": "Units label(s) for output value (e.g., 'sec.').", - "flag": { - "long": "units", - "short": "u" - }, - "name": "snmp_units", - "optional": true, - "type": "STRING" - }, - { - "description": "Version to use. E.g. 1, 2, 2c or 3.", - "name": "snmp_version", - "optional": true - }, - { - "description": "MIB's to use, comma separated. Defaults to \"ALL\".", - "flag": { - "long": "miblist", - "short": "m" - }, - "name": "snmp_miblist", - "optional": true, - "type": "STRING" - }, - { - "description": "Converts rate per second. For example, set to 60 to convert to per minute.", - "name": "snmp_rate_multiplier", - "optional": true - }, - { - "description": "Boolean. Enable rate calculation.", - "name": "snmp_rate", - "optional": true - }, - { - "description": "Boolean. Use SNMP GETNEXT. Defaults to false.", - "name": "snmp_getnext", - "optional": true - }, - { - "description": "The command timeout in seconds. Defaults to 10 seconds.", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "snmp_timeout", - "optional": true, - "type": "INTEGER" - } - ] - }, - { - "description": "The [check_spop](https://www.monitoring-plugins.org/doc/man/check_spop.html) plugin tests SPOP connections with the specified host (or unix socket).", - "name": "spop", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "spop_address", - "optional": true - }, - { - "description": "The port that should be checked. Defaults to 995.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "spop_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Can use \\\\n, \\\\r, \\\\t or \\\\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \\\\r\\\\n added to end of quit.", - "name": "spop_escape", - "optional": true - }, - { - "description": "String to send to the server.", - "flag": { - "long": "send", - "short": "s" - }, - "name": "spop_send", - "optional": true, - "type": "STRING" - }, - { - "description": "String to expect in server response. Multiple strings must be defined as array.", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "spop_expect", - "optional": true, - "type": "STRING" - }, - { - "description": "All expect strings need to occur in server response. Default is any.", - "name": "spop_all", - "optional": true - }, - { - "description": "String to send server to initiate a clean close of the connection.", - "flag": { - "long": "quit", - "short": "q" - }, - "name": "spop_quit", - "optional": true, - "type": "STRING" - }, - { - "description": "Accept TCP refusals with states ok, warn, crit (default: crit).", - "flag": { - "long": "refuse", - "short": "r" - }, - "format": "enum", - "name": "spop_refuse", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Accept expected string mismatches with states ok, warn, crit (default: warn).", - "flag": { - "long": "mismatch", - "short": "M" - }, - "format": "enum", - "name": "spop_mismatch", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Hide output from TCP socket.", - "name": "spop_jail", - "optional": true - }, - { - "description": "Close connection once more than this number of bytes are received.", - "flag": { - "long": "maxbytes", - "short": "m" - }, - "name": "spop_maxbytes", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Seconds to wait between sending string and polling for response.", - "flag": { - "long": "delay", - "short": "d" - }, - "name": "spop_delay", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Minimum number of days a certificate has to be valid.", - "flag": { - "long": "certificate", - "short": "D" - }, - "name": "spop_certificate_age", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use SSL for the connection.", - "name": "spop_ssl", - "optional": true - }, - { - "description": "Response time to result in warning status (seconds).", - "flag": { - "long": "warning", - "short": "w" - }, - "name": "spop_warning", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Response time to result in critical status (seconds).", - "flag": { - "long": "critical", - "short": "c" - }, - "name": "spop_critical", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Seconds before connection times out (default: 10).", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "spop_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "spop_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "spop_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_ssh](https://www.monitoring-plugins.org/doc/man/check_ssh.html) plugin connects to an SSH server at a specified host and port.", - "name": "ssh", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "ssh_address", - "optional": true - }, - { - "description": "The port that should be checked. Defaults to 22.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "ssh_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Seconds before connection times out. Defaults to 10.", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "ssh_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "ssh_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "ssh_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_ssmtp](https://www.monitoring-plugins.org/doc/man/check_ssmtp.html) plugin tests SSMTP connections with the specified host (or unix socket).", - "name": "ssmtp", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "ssmtp_address", - "optional": true - }, - { - "description": "The port that should be checked. Defaults to 465.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "ssmtp_port", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Can use \\\\n, \\\\r, \\\\t or \\\\ in send or quit string. Must come before send or quit option. Default: nothing added to send, \\\\r\\\\n added to end of quit.", - "name": "ssmtp_escape", - "optional": true - }, - { - "description": "String to send to the server.", - "flag": { - "long": "send", - "short": "s" - }, - "name": "ssmtp_send", - "optional": true, - "type": "STRING" - }, - { - "description": "String to expect in server response. Multiple strings must be defined as array.", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "ssmtp_expect", - "optional": true, - "type": "STRING" - }, - { - "description": "All expect strings need to occur in server response. Default is any.", - "name": "ssmtp_all", - "optional": true - }, - { - "description": "String to send server to initiate a clean close of the connection.", - "flag": { - "long": "quit", - "short": "q" - }, - "name": "ssmtp_quit", - "optional": true, - "type": "STRING" - }, - { - "description": "Accept TCP refusals with states ok, warn, crit (default: crit).", - "flag": { - "long": "refuse", - "short": "r" - }, - "format": "enum", - "name": "ssmtp_refuse", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Accept expected string mismatches with states ok, warn, crit (default: warn).", - "flag": { - "long": "mismatch", - "short": "M" - }, - "format": "enum", - "name": "ssmtp_mismatch", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Hide output from TCP socket.", - "name": "ssmtp_jail", - "optional": true - }, - { - "description": "Close connection once more than this number of bytes are received.", - "flag": { - "long": "maxbytes", - "short": "m" - }, - "name": "ssmtp_maxbytes", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Seconds to wait between sending string and polling for response.", - "flag": { - "long": "delay", - "short": "d" - }, - "name": "ssmtp_delay", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Minimum number of days a certificate has to be valid.", - "flag": { - "long": "certificate", - "short": "D" - }, - "name": "ssmtp_certificate_age", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use SSL for the connection.", - "name": "ssmtp_ssl", - "optional": true - }, - { - "description": "Response time to result in warning status (seconds).", - "flag": { - "long": "warning", - "short": "w" - }, - "name": "ssmtp_warning", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Response time to result in critical status (seconds).", - "flag": { - "long": "critical", - "short": "c" - }, - "name": "ssmtp_critical", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Seconds before connection times out (default: 10).", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "ssmtp_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "ssmtp_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "ssmtp_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_swap](https://www.monitoring-plugins.org/doc/man/check_swap.html) plugin checks the swap space on a local machine.", - "name": "swap", - "vars": [ - { - "description": "The free swap space warning threshold in % (enable `swap_integer` for number values). Defaults to `50%`.", - "name": "swap_wfree", - "optional": true - }, - { - "description": "The free swap space critical threshold in % (enable `swap_integer` for number values). Defaults to `25%`.", - "name": "swap_cfree", - "optional": true - }, - { - "description": "Specifies whether the thresholds are passed as number or percent value. Defaults to false (percent values).", - "name": "swap_integer", - "optional": true - }, - { - "description": "Conduct comparisons for all swap partitions, one by one. Defaults to false.", - "name": "swap_allswaps", - "optional": true - }, - { - "description": "Resulting state when there is no swap regardless of thresholds. Possible values are \"ok\", \"warning\", \"critical\", \"unknown\". Defaults to \"critical\".", - "flag": { - "long": "no-swap", - "short": "n" - }, - "format": "enum", - "name": "swap_noswap", - "optional": true, - "type": "STRING", - "values": [ - "" - ] - } - ] - }, - { - "description": "The [check_tcp](https://www.monitoring-plugins.org/doc/man/check_tcp.html) plugin tests TCP connections with the specified host (or unix socket).", - "name": "tcp", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "tcp_address", - "optional": true - }, - { - "description": "Required The port that should be checked.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "tcp_port", - "optional": false, - "type": "INTEGER" - }, - { - "description": "String to expect in server response. Multiple strings must be defined as array.", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "tcp_expect", - "optional": true, - "type": "STRING" - }, - { - "description": "All expect strings need to occur in server response. Defaults to false.", - "name": "tcp_all", - "optional": true - }, - { - "description": "Enable usage of \\\\n, \\\\r, \\\\t or \\\\\\\\ in send string.", - "flag": { - "long": "send", - "short": "s" - }, - "name": "tcp_escape_send", - "optional": true, - "type": "STRING" - }, - { - "description": "String to send to the server.", - "flag": { - "long": "send", - "short": "s" - }, - "name": "tcp_send", - "optional": true, - "type": "STRING" - }, - { - "description": "Enable usage of \\\\n, \\\\r, \\\\t or \\\\\\\\ in quit string.", - "flag": { - "long": "quit", - "short": "q" - }, - "name": "tcp_escape_quit", - "optional": true, - "type": "STRING" - }, - { - "description": "String to send server to initiate a clean close of the connection.", - "flag": { - "long": "quit", - "short": "q" - }, - "name": "tcp_quit", - "optional": true, - "type": "STRING" - }, - { - "description": "Accept TCP refusals with states ok, warn, crit. Defaults to crit.", - "flag": { - "long": "refuse", - "short": "r" - }, - "format": "enum", - "name": "tcp_refuse", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Accept expected string mismatches with states ok, warn, crit. Defaults to warn.", - "flag": { - "long": "mismatch", - "short": "M" - }, - "format": "enum", - "name": "tcp_mismatch", - "optional": true, - "type": "STRING", - "values": [ - "ok", - "warn", - "crit" - ] - }, - { - "description": "Hide output from TCP socket.", - "name": "tcp_jail", - "optional": true - }, - { - "description": "Close connection once more than this number of bytes are received.", - "flag": { - "long": "maxbytes", - "short": "m" - }, - "name": "tcp_maxbytes", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Seconds to wait between sending string and polling for response.", - "flag": { - "long": "delay", - "short": "d" - }, - "name": "tcp_delay", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Minimum number of days a certificate has to be valid. 1st value is number of days for warning, 2nd is critical (if not specified: 0) -- separated by comma.", - "flag": { - "long": "certificate", - "short": "D" - }, - "name": "tcp_certificate", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use SSL for the connection. Defaults to false.", - "name": "tcp_ssl", - "optional": true - }, - { - "description": "Response time to result in warning status (seconds).", - "name": "tcp_wtime", - "optional": true - }, - { - "description": "Response time to result in critical status (seconds).", - "name": "tcp_ctime", - "optional": true - }, - { - "description": "Seconds before connection times out. Defaults to 10.", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "tcp_timeout", - "optional": true, - "type": "INTEGER" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "tcp_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "tcp_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_udp](https://www.monitoring-plugins.org/doc/man/check_udp.html) plugin tests UDP connections with the specified host (or unix socket).", - "name": "udp", - "vars": [ - { - "description": "The host's address. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "name": "udp_address", - "optional": true - }, - { - "description": "Required The port that should be checked.", - "flag": { - "long": "port", - "short": "p" - }, - "name": "udp_port", - "optional": false, - "type": "INTEGER" - }, - { - "description": "Required The payload to send in the UDP datagram.", - "flag": { - "long": "send", - "short": "s" - }, - "name": "udp_send", - "optional": false, - "type": "STRING" - }, - { - "description": "Required The payload to expect in the response datagram.", - "flag": { - "long": "expect", - "short": "e" - }, - "name": "udp_expect", - "optional": false, - "type": "STRING" - }, - { - "description": "The payload to send to 'close' the session.", - "flag": { - "long": "quit", - "short": "q" - }, - "name": "udp_quit", - "optional": true, - "type": "STRING" - }, - { - "description": "Use IPv4 connection. Defaults to false.", - "name": "udp_ipv4", - "optional": true - }, - { - "description": "Use IPv6 connection. Defaults to false.", - "name": "udp_ipv6", - "optional": true - } - ] - }, - { - "description": "The [check_ups](https://www.monitoring-plugins.org/doc/man/check_ups.html) plugin tests the UPS service on the specified host. [Network UPS Tools](http://www.networkupstools.org) must be running for this plugin to work.", - "name": "ups", - "vars": [ - { - "description": "Required The address of the host running upsd. Defaults to \"$address$\" if the host's `address` attribute is set, \"$address6$\" otherwise.", - "flag": { - "long": "ups", - "short": "u" - }, - "name": "ups_address", - "optional": false, - "type": "STRING" - }, - { - "description": "Required The UPS name. Defaults to `ups`.", - "flag": { - "long": "ups", - "short": "u" - }, - "name": "ups_name", - "optional": false, - "type": "STRING" - }, - { - "description": "The port to which to connect. Defaults to 3493.", - "flag": { - "long": "ups", - "short": "u" - }, - "name": "ups_port", - "optional": true, - "type": "STRING" - }, - { - "description": "The variable to monitor. Must be one of LINE, TEMP, BATTPCT or LOADPCT. If this is not set, the check only relies on the value of `ups.status`.", - "flag": { - "long": "variable", - "short": "v" - }, - "name": "ups_variable", - "optional": true, - "type": "STRING" - }, - { - "description": "The warning threshold for the selected variable.", - "flag": { - "long": "warning", - "short": "w" - }, - "name": "ups_warning", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "The critical threshold for the selected variable.", - "flag": { - "long": "critical", - "short": "c" - }, - "name": "ups_critical", - "optional": true, - "type": "DOUBLE" - }, - { - "description": "Display the temperature in degrees Celsius instead of Fahrenheit. Defaults to `false`.", - "flag": { - "long": "ups", - "short": "u" - }, - "name": "ups_celsius", - "optional": true, - "type": "STRING" - }, - { - "description": "The number of seconds before the connection times out. Defaults to 10.", - "flag": { - "long": "timeout", - "short": "t" - }, - "name": "ups_timeout", - "optional": true, - "type": "INTEGER" - } - ] - }, - { - "description": "The [check_users](https://www.monitoring-plugins.org/doc/man/check_users.html) plugin checks the number of users currently logged in on the local system and generates an error if the number exceeds the thresholds specified.", - "name": "users", - "vars": [ - { - "description": "The user count warning threshold. Defaults to 20.", - "name": "users_wgreater", - "optional": true - }, - { - "description": "The user count critical threshold. Defaults to 50.", - "name": "users_cgreater", - "optional": true - } - ] - } - ] -} \ No newline at end of file diff --git a/data/files/node_checks.json b/data/files/node_checks.json deleted file mode 100644 index c36ac9605..000000000 --- a/data/files/node_checks.json +++ /dev/null @@ -1,217 +0,0 @@ -{ - "check_command": [ - { - "description": "This is used to check InfluxDB query result", - "name": "influx_query", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "URL of InfluxDB host to query", - "flag": { - "short": "h", - "long": "influxHost" - }, - "name": "influxHost", - "type": "STRING", - "parameterized": false, - "visibility": false, - "optional": true - }, - { - "description": "Kubernetes secret name", - "flag": { - "short": "s", - "long": "secretName" - }, - "name": "secretName", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": false - }, - { - "description": "InfluxDB query (A). Query result will be assigned to variable (A)", - "flag": { - "long": "A" - }, - "name": "A", - "type": "STRING", - "parameterized": true, - "visibility": true, - "optional": false - }, - { - "description": "InfluxDB query (B). Query result will be assigned to variable (B)", - "flag": { - "long": "B" - }, - "name": "B", - "type": "STRING", - "parameterized": true, - "visibility": false, - "optional": true - }, - { - "description": "InfluxDB query (C). Query result will be assigned to variable (C)", - "flag": { - "long": "C" - }, - "name": "C", - "type": "STRING", - "parameterized": true, - "visibility": false, - "optional": true - }, - { - "description": "InfluxDB query (D). Query result will be assigned to variable (D)", - "flag": { - "long": "D" - }, - "name": "D", - "type": "STRING", - "parameterized": true, - "visibility": false, - "optional": true - }, - { - "description": "InfluxDB query (E). Query result will be assigned to variable (E)", - "flag": { - "long": "E" - }, - "name": "E", - "type": "STRING", - "parameterized": true, - "visibility": false, - "optional": true - }, - { - "description": "Equation [A+B] to get result from queries. Result will be assigned to variable (R)", - "flag": { - "long": "R" - }, - "name": "R", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": false - }, - { - "description": "Condition for warning, compare with result. (Example: R > 75)", - "flag": { - "short": "w", - "long": "warning" - }, - "name": "warning", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Condition for critical, compare with result. (Example: R > 90)", - "flag": { - "short": "c", - "long": "critical" - }, - "name": "critical", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": false - } - ], - "states": [ - "OK", - "Warning", - "Critical", - "Unknown" - ] - }, - { - "description": "This is used to check Kubernetes Node status", - "examples": "hyperalert check_node_status --name=master.internal", - "name": "node_status", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "states": [ - "OK", - "Critical", - "Unknown" - ] - }, - { - "description": "This is used to check Node Disk stat.", - "name": "node_volume", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "Kubernetes secret name", - "flag": { - "short": "s", - "long": "secretName" - }, - "name": "secretName", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Volume name", - "flag": { - "short": "N", - "long": "volumeName" - }, - "name": "mountpoint", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Warning level value (usage percentage defaults to 75.0)", - "flag": { - "short": "w", - "long": "warning" - }, - "name": "warning", - "type": "INTERGER", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Critical level value (usage percentage defaults to 90.0)", - "flag": { - "short": "c", - "long": "critical" - }, - "name": "critical", - "type": "INTERGER", - "parameterized": false, - "visibility": true, - "optional": true - } - ], - "states": [ - "OK", - "Critical", - "Unknown" - ] - } - ] -} diff --git a/data/files/pod_checks.json b/data/files/pod_checks.json deleted file mode 100644 index fcebde0c5..000000000 --- a/data/files/pod_checks.json +++ /dev/null @@ -1,269 +0,0 @@ -{ - "check_command": [ - { - "description": "This is used to check InfluxDB query result", - "name": "influx_query", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "URL of InfluxDB host to query", - "flag": { - "short": "h", - "long": "influxHost" - }, - "name": "influxHost", - "type": "STRING", - "parameterized": false, - "visibility": false, - "optional": true - }, - { - "description": "Kubernetes secret name", - "flag": { - "short": "s", - "long": "secretName" - }, - "name": "secretName", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": false - }, - { - "description": "InfluxDB query (A). Query result will be assigned to variable (A)", - "flag": { - "long": "A" - }, - "name": "A", - "type": "STRING", - "parameterized": true, - "visibility": true, - "optional": false - }, - { - "description": "InfluxDB query (B). Query result will be assigned to variable (B)", - "flag": { - "long": "B" - }, - "name": "B", - "type": "STRING", - "parameterized": true, - "visibility": false, - "optional": true - }, - { - "description": "InfluxDB query (C). Query result will be assigned to variable (C)", - "flag": { - "long": "C" - }, - "name": "C", - "type": "STRING", - "parameterized": true, - "visibility": false, - "optional": true - }, - { - "description": "InfluxDB query (D). Query result will be assigned to variable (D)", - "flag": { - "long": "D" - }, - "name": "D", - "type": "STRING", - "parameterized": true, - "visibility": false, - "optional": true - }, - { - "description": "InfluxDB query (E). Query result will be assigned to variable (E)", - "flag": { - "long": "E" - }, - "name": "E", - "type": "STRING", - "parameterized": true, - "visibility": false, - "optional": true - }, - { - "description": "Equation [A+B] to get result from queries. Result will be assigned to variable (R)", - "flag": { - "long": "R" - }, - "name": "R", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": false - }, - { - "description": "Condition for warning, compare with result. (Example: R > 75)", - "flag": { - "short": "w", - "long": "warning" - }, - "name": "warning", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Condition for critical, compare with result. (Example: R > 90)", - "flag": { - "short": "c", - "long": "critical" - }, - "name": "critical", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": false - } - ], - "states": [ - "OK", - "Warning", - "Critical", - "Unknown" - ] - }, - { - "description": "This is used to check Kubernetes pod status", - "name": "pod_status", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "states": [ - "OK", - "Critical", - "Unknown" - ] - }, - { - "description": "This is used to check Pod volume stat.", - "name": "pod_volume", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "Kubernetes secret name", - "flag": { - "short": "s", - "long": "secretName" - }, - "name": "secretName", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Volume name", - "flag": { - "short": "N", - "long": "volumeName" - }, - "name": "volumeName", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Warning level value (usage percentage defaults to 75.0)", - "flag": { - "short": "w", - "long": "warning" - }, - "name": "warning", - "type": "INTERGER", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Critical level value (usage percentage defaults to 90.0)", - "flag": { - "short": "c", - "long": "critical" - }, - "name": "critical", - "type": "INTERGER", - "parameterized": false, - "visibility": true, - "optional": true - } - ], - "states": [ - "OK", - "Critical", - "Unknown" - ] - }, - { - "description": "This is used to check Kubernetes exec command. Returns OK if exit code is zero, otherwise, returns Critical", - "name": "pod_exec", - "envs": [ - "onebox", - "prod", - "qa", - "dev" - ], - "vars": [ - { - "description": "Kubernetes container name in a pod", - "flag": { - "short": "C", - "long": "container" - }, - "name": "container", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Exec command. [Default: '/bin/sh']", - "flag": { - "short": "c", - "long": "cmd" - }, - "name": "cmd", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": true - }, - { - "description": "Exec command arguments. [Format: 'arg; arg; arg']", - "flag": { - "short": "a", - "long": "argv" - }, - "name": "argv", - "type": "STRING", - "parameterized": false, - "visibility": true, - "optional": false - } - ], - "states": [ - "OK", - "Critical", - "Unknown" - ] - } - ] -} diff --git a/data/package.json b/data/package.json deleted file mode 100644 index a8d517efa..000000000 --- a/data/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "searchlight-data", - "version": "0.4.0", - "description": "Static data files used by AppsCode Searchlight", - "main": "files/icinga.json", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/appscode/searchlight.git" - }, - "keywords": [ - "appscode", - "icinga", - "nagios", - "searchlight" - ], - "author": "AppsCode Inc.", - "license": "Apache-2.0", - "homepage": "https://github.com/appscode/searchlight/blob/master/README.md" -} diff --git a/data/types.go b/data/types.go deleted file mode 100644 index 23e05c49b..000000000 --- a/data/types.go +++ /dev/null @@ -1,27 +0,0 @@ -package data - -type CommandVar struct { - Name string `json:"name"` - Description string `json:"description,omitempty"` - Type string `json:"type"` - Format string `json:"format,omitempty"` - Values []string `json:"values,omitempty"` - Parameterized bool `json:"parameterized,omitempty"` - Flag struct { - Long string `json:"long"` - Short string `json:"short"` - } `json:"flag"` - Optional bool `json:"optional"` -} - -type IcingaCheckCommand struct { - Name string `json:"name"` - Description string `json:"description,omitempty"` - Envs []string `json:"envs"` - Vars []CommandVar `json:"vars,omitempty"` - States []string `json:"states,omitempty"` -} - -type IcingaData struct { - Command []*IcingaCheckCommand `json:"check_command"` -} diff --git a/data/util.go b/data/util.go deleted file mode 100644 index c362d20c3..000000000 --- a/data/util.go +++ /dev/null @@ -1,34 +0,0 @@ -package data - -import ( - "encoding/json" - - "github.com/appscode/searchlight/data/files" -) - -func LoadClusterChecks() (ic IcingaData, err error) { - bytes, err := files.Asset("cluster_checks.json") - if err != nil { - return - } - err = json.Unmarshal(bytes, &ic) - return -} - -func LoadNodeChecks() (ic IcingaData, err error) { - bytes, err := files.Asset("node_checks.json") - if err != nil { - return - } - err = json.Unmarshal(bytes, &ic) - return -} - -func LoadPodChecks() (ic IcingaData, err error) { - bytes, err := files.Asset("pod_checks.json") - if err != nil { - return - } - err = json.Unmarshal(bytes, &ic) - return -} diff --git a/data/util_test.go b/data/util_test.go deleted file mode 100644 index 9bbf2e0ff..000000000 --- a/data/util_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package data_test - -import ( - "fmt" - "log" - "testing" - - . "github.com/appscode/searchlight/data" - "github.com/stretchr/testify/assert" -) - -func TestLoadClusterChecks(t *testing.T) { - ic, err := LoadClusterChecks() - if err != nil { - log.Fatal(err) - } - assert.NotZero(t, len(ic.Command), "No check agent found") - fmt.Println(ic.Command[0].Name) - fmt.Println(ic.Command[0].Description) -} - -func TestLoadNodeChecks(t *testing.T) { - ic, err := LoadNodeChecks() - if err != nil { - log.Fatal(err) - } - assert.NotZero(t, len(ic.Command), "No check agent found") - fmt.Println(ic.Command[0].Name) - fmt.Println(ic.Command[0].Description) -} - -func TestLoadPodChecks(t *testing.T) { - ic, err := LoadPodChecks() - if err != nil { - log.Fatal(err) - } - assert.NotZero(t, len(ic.Command), "No check agent found") - fmt.Println(ic.Command[0].Name) - fmt.Println(ic.Command[0].Description) -} diff --git a/docs/examples/cluster-alerts/node_exists/demo-0.yaml b/docs/examples/cluster-alerts/node_exists/demo-0.yaml index d82c6ecec..23a3aee30 100644 --- a/docs/examples/cluster-alerts/node_exists/demo-0.yaml +++ b/docs/examples/cluster-alerts/node_exists/demo-0.yaml @@ -7,7 +7,7 @@ spec: check: node-exists vars: selector: beta.kubernetes.io/os=linux - count: '1' + count: 'one' checkInterval: 30s alertInterval: 2m notifierSecretName: notifier-config diff --git a/docs/examples/node-alerts/influx_query/demo-0.yaml b/docs/examples/node-alerts/influx_query/demo-0.yaml deleted file mode 100644 index 581114469..000000000 --- a/docs/examples/node-alerts/influx_query/demo-0.yaml +++ /dev/null @@ -1,44 +0,0 @@ -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx - namespace: demo -spec: - replicas: 2 - template: - metadata: - name: nginx - labels: - app: nginx - spec: - containers: - - name: nginx - image: nginx - ports: - - containerPort: 80 ---- -apiVersion: monitoring.appscode.com/v1alpha1 -kind: NodeAlert -metadata: - name: influx-query-demo-0 - namespace: demo -spec: - check: influx-query - vars: - influxHost: "monitoring-influxdb.demo:8086" - secretName: "appscode-influx" - A: "select value from \"memory/limit\" where nodename='{{.NodeName}}';" - B: "select value from \"memory/usage\" where nodename='{{.NodeName}}';" - R: "(B/A)*100" - warning: "R > 75" - critical: "R > 90" - checkInterval: 30s - alertInterval: 2m - notifierSecretName: notifier-config - receivers: - - notifier: mailgun - state: Warning - to: ["ops@example.com"] - - notifier: mailgun - state: Critical - to: ["ops@example.com"] diff --git a/docs/examples/plugins/check-command/event.conf b/docs/examples/plugins/check-command/event.conf index b99c7bf24..e54a5ff87 100644 --- a/docs/examples/plugins/check-command/event.conf +++ b/docs/examples/plugins/check-command/event.conf @@ -4,12 +4,12 @@ object CheckCommand "event" { arguments = { "--icinga.checkInterval" = "$service.check_interval$" + "--involvedObjectUID" = "$involvedObjectUID$" "--clockSkew" = "$clockSkew$" "--involvedObjectName" = "$involvedObjectName$" "--involvedObjectNamespace" = "$involvedObjectNamespace$" "--involvedObjectKind" = "$involvedObjectKind$" - "--involvedObjectUID" = "$involvedObjectUID$" - "--v" = "$host.vars.verbosity$" "--host" = "$host.name$" + "--v" = "$host.vars.verbosity$" } } \ No newline at end of file diff --git a/docs/examples/plugins/check-command/json-path.conf b/docs/examples/plugins/check-command/json-path.conf index 5feadf8e3..240669596 100644 --- a/docs/examples/plugins/check-command/json-path.conf +++ b/docs/examples/plugins/check-command/json-path.conf @@ -4,11 +4,11 @@ object CheckCommand "json-path" { arguments = { "--icinga.checkInterval" = "$service.check_interval$" + "--critical" = "$critical$" "--url" = "$url$" "--secretName" = "$secretName$" "--warning" = "$warning$" - "--critical" = "$critical$" - "--host" = "$host.name$" "--v" = "$host.vars.verbosity$" + "--host" = "$host.name$" } } \ No newline at end of file diff --git a/docs/examples/plugins/check-command/node-exists.conf b/docs/examples/plugins/check-command/node-exists.conf index 6bb45255b..12a82c4b8 100644 --- a/docs/examples/plugins/check-command/node-exists.conf +++ b/docs/examples/plugins/check-command/node-exists.conf @@ -4,9 +4,9 @@ object CheckCommand "node-exists" { arguments = { "--icinga.checkInterval" = "$service.check_interval$" + "--count" = "$count$" "--selector" = "$selector$" "--nodeName" = "$nodeName$" - "--count" = "$count$" "--v" = "$host.vars.verbosity$" } } \ No newline at end of file diff --git a/docs/examples/plugins/check-command/node-status.conf b/docs/examples/plugins/check-command/node-status.conf index 512710936..9ecf1844e 100644 --- a/docs/examples/plugins/check-command/node-status.conf +++ b/docs/examples/plugins/check-command/node-status.conf @@ -4,7 +4,7 @@ object CheckCommand "node-status" { arguments = { "--icinga.checkInterval" = "$service.check_interval$" - "--host" = "$host.name$" "--v" = "$host.vars.verbosity$" + "--host" = "$host.name$" } } \ No newline at end of file diff --git a/docs/examples/plugins/check-command/node-volume.conf b/docs/examples/plugins/check-command/node-volume.conf index 3a97d0f61..1f4145d37 100644 --- a/docs/examples/plugins/check-command/node-volume.conf +++ b/docs/examples/plugins/check-command/node-volume.conf @@ -4,10 +4,10 @@ object CheckCommand "node-volume" { arguments = { "--icinga.checkInterval" = "$service.check_interval$" - "--mountPoint" = "$mountPoint$" - "--secretName" = "$secretName$" "--warning" = "$warning$" "--critical" = "$critical$" + "--mountPoint" = "$mountPoint$" + "--secretName" = "$secretName$" "--host" = "$host.name$" "--v" = "$host.vars.verbosity$" } diff --git a/docs/examples/plugins/check-command/pod-exists.conf b/docs/examples/plugins/check-command/pod-exists.conf index 62213583c..fe6ecf2f8 100644 --- a/docs/examples/plugins/check-command/pod-exists.conf +++ b/docs/examples/plugins/check-command/pod-exists.conf @@ -4,10 +4,10 @@ object CheckCommand "pod-exists" { arguments = { "--icinga.checkInterval" = "$service.check_interval$" + "--count" = "$count$" "--selector" = "$selector$" "--podName" = "$podName$" - "--count" = "$count$" - "--v" = "$host.vars.verbosity$" "--host" = "$host.name$" + "--v" = "$host.vars.verbosity$" } } \ No newline at end of file diff --git a/docs/examples/plugins/check-command/pod-status.conf b/docs/examples/plugins/check-command/pod-status.conf index d508947a4..10180a025 100644 --- a/docs/examples/plugins/check-command/pod-status.conf +++ b/docs/examples/plugins/check-command/pod-status.conf @@ -4,7 +4,7 @@ object CheckCommand "pod-status" { arguments = { "--icinga.checkInterval" = "$service.check_interval$" - "--v" = "$host.vars.verbosity$" "--host" = "$host.name$" + "--v" = "$host.vars.verbosity$" } } \ No newline at end of file diff --git a/docs/examples/pod-alerts/influx_query/demo-0.yaml b/docs/examples/pod-alerts/influx_query/demo-0.yaml deleted file mode 100644 index dd563a46a..000000000 --- a/docs/examples/pod-alerts/influx_query/demo-0.yaml +++ /dev/null @@ -1,47 +0,0 @@ -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx - namespace: demo -spec: - replicas: 2 - template: - metadata: - name: nginx - labels: - app: nginx - spec: - containers: - - name: nginx - image: nginx - ports: - - containerPort: 80 ---- -apiVersion: monitoring.appscode.com/v1alpha1 -kind: PodAlert -metadata: - name: influx-query-demo-0 - namespace: demo -spec: - selector: - matchLabels: - app: nginx - check: influx-query - vars: - influxHost: "monitoring-influxdb.demo:8086" - secretName: "appscode-influx" - A: "select value from \"memory/limit\" where pod_name='{{.PodName}}' and pod_namespace='{{.Namespace}}';" - B: "select value from \"memory/usage\" where pod_name='{{.PodName}}' and pod_namespace='{{.Namespace}}';" - R: "(B/A)*100" - warning: "R > 75" - critical: "R > 90" - checkInterval: 30s - alertInterval: 2m - notifierSecretName: notifier-config - receivers: - - notifier: mailgun - state: Warning - to: ["ops@example.com"] - - notifier: mailgun - state: Critical - to: ["ops@example.com"] diff --git a/docs/reference/hyperalert/hyperalert.md b/docs/reference/hyperalert/hyperalert.md index 62fe828c7..17dbe7d7e 100644 --- a/docs/reference/hyperalert/hyperalert.md +++ b/docs/reference/hyperalert/hyperalert.md @@ -33,6 +33,7 @@ hyperalert [flags] --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig -h, --help help for hyperalert + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory @@ -50,7 +51,6 @@ hyperalert [flags] * [hyperalert check_component_status](/docs/reference/hyperalert/hyperalert_check_component_status.md) - Check Kubernetes Component Status * [hyperalert check_env](/docs/reference/hyperalert/hyperalert_check_env.md) - * [hyperalert check_event](/docs/reference/hyperalert/hyperalert_check_event.md) - Check kubernetes events for all namespaces -* [hyperalert check_influx_query](/docs/reference/hyperalert/hyperalert_check_influx_query.md) - Check InfluxDB Query Data * [hyperalert check_json_path](/docs/reference/hyperalert/hyperalert_check_json_path.md) - Check Json Object * [hyperalert check_node_exists](/docs/reference/hyperalert/hyperalert_check_node_exists.md) - Count Kubernetes Nodes * [hyperalert check_node_status](/docs/reference/hyperalert/hyperalert_check_node_status.md) - Check Kubernetes Node @@ -58,6 +58,7 @@ hyperalert [flags] * [hyperalert check_pod_exists](/docs/reference/hyperalert/hyperalert_check_pod_exists.md) - Check Kubernetes Pod(s) * [hyperalert check_pod_status](/docs/reference/hyperalert/hyperalert_check_pod_status.md) - Check Kubernetes Pod(s) status * [hyperalert check_volume](/docs/reference/hyperalert/hyperalert_check_volume.md) - Check kubernetes volume +* [hyperalert check_webhook](/docs/reference/hyperalert/hyperalert_check_webhook.md) - Check webhook result * [hyperalert notifier](/docs/reference/hyperalert/hyperalert_notifier.md) - AppsCode Icinga2 Notifier * [hyperalert version](/docs/reference/hyperalert/hyperalert_version.md) - Prints binary version number. diff --git a/docs/reference/hyperalert/hyperalert_analytics_id.md b/docs/reference/hyperalert/hyperalert_analytics_id.md index 686fa8c91..ce28d1d61 100644 --- a/docs/reference/hyperalert/hyperalert_analytics_id.md +++ b/docs/reference/hyperalert/hyperalert_analytics_id.md @@ -32,6 +32,7 @@ hyperalert analytics_id [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_check_ca_cert.md b/docs/reference/hyperalert/hyperalert_check_ca_cert.md index 793593374..9d99c961e 100644 --- a/docs/reference/hyperalert/hyperalert_check_ca_cert.md +++ b/docs/reference/hyperalert/hyperalert_check_ca_cert.md @@ -34,6 +34,7 @@ hyperalert check_ca_cert [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_check_cert.md b/docs/reference/hyperalert/hyperalert_check_cert.md index 552049686..df979e6ee 100644 --- a/docs/reference/hyperalert/hyperalert_check_cert.md +++ b/docs/reference/hyperalert/hyperalert_check_cert.md @@ -24,13 +24,13 @@ hyperalert check_cert [flags] ### Options ``` - -c, --critical duration Remaining duration for Critical state. [Default: 120h] (default 120h0m0s) - -h, --help help for check_cert - -H, --host string Icinga host name - -k, --secretKey stringSlice Name of secret key where certificates are kept - -s, --secretName string Name of secret from where certificates are checked - -l, --selector string Selector (label query) to filter on, supports '=', '==', and '!=' - -w, --warning duration Remaining duration for Warning state. [Default: 360h] (default 360h0m0s) + -c, --critical duration Remaining duration for Critical state. [Default: 120h] (default 120h0m0s) + -h, --help help for check_cert + -H, --host string Icinga host name + -k, --secretKey strings Name of secret key where certificates are kept + -s, --secretName string Name of secret from where certificates are checked + -l, --selector string Selector (label query) to filter on, supports '=', '==', and '!=' + -w, --warning duration Remaining duration for Warning state. [Default: 360h] (default 360h0m0s) ``` ### Options inherited from parent commands @@ -38,6 +38,7 @@ hyperalert check_cert [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_check_component_status.md b/docs/reference/hyperalert/hyperalert_check_component_status.md index d43f3a667..e6f129d72 100644 --- a/docs/reference/hyperalert/hyperalert_check_component_status.md +++ b/docs/reference/hyperalert/hyperalert_check_component_status.md @@ -34,6 +34,7 @@ hyperalert check_component_status [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_check_env.md b/docs/reference/hyperalert/hyperalert_check_env.md index 58634df28..c9e1e4ea4 100644 --- a/docs/reference/hyperalert/hyperalert_check_env.md +++ b/docs/reference/hyperalert/hyperalert_check_env.md @@ -32,6 +32,7 @@ hyperalert check_env [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_check_event.md b/docs/reference/hyperalert/hyperalert_check_event.md index 36cc03352..eeac80b81 100644 --- a/docs/reference/hyperalert/hyperalert_check_event.md +++ b/docs/reference/hyperalert/hyperalert_check_event.md @@ -24,7 +24,6 @@ hyperalert check_event [flags] ### Options ``` - -c, --checkInterval duration Icinga check_interval in duration. [Format: 30s, 5m] -s, --clockSkew duration Add skew with check_interval in duration. [Default: 30s] (default 30s) -h, --help help for check_event -H, --host string Icinga host name @@ -39,6 +38,7 @@ hyperalert check_event [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_check_influx_query.md b/docs/reference/hyperalert/hyperalert_check_influx_query.md deleted file mode 100644 index a9fd84bcd..000000000 --- a/docs/reference/hyperalert/hyperalert_check_influx_query.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: Check Influx Query -menu: - product_searchlight_6.0.0-alpha.0: - identifier: hyperalert-check-influx-query - name: Check Influx Query - parent: hyperalert-cli -product_name: searchlight -section_menu_id: reference -menu_name: product_searchlight_6.0.0-alpha.0 ---- -## hyperalert check_influx_query - -Check InfluxDB Query Data - -### Synopsis - -Check InfluxDB Query Data - -``` -hyperalert check_influx_query [flags] -``` - -### Options - -``` - --A string InfluxDB query A - --B string InfluxDB query B - --C string InfluxDB query C - --D string InfluxDB query D - --E string InfluxDB query E - --R string Equation to evaluate result - -c, --critical string Critical query which returns [true/false] - -h, --help help for check_influx_query - -H, --host string Icinga host name - --influxHost string URL of InfluxDB host to query - -s, --secretName string Kubernetes secret name - -w, --warning string Warning query which returns [true/false] -``` - -### Options inherited from parent commands - -``` - --alsologtostderr log to standard error as well as files - --context string Use the context in kubeconfig - --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). - --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) - --log_dir string If non-empty, write log files in this directory - --logtostderr log to standard error instead of files - --stderrthreshold severity logs at or above this threshold go to stderr - -v, --v Level log level for V logs - --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging -``` - -### SEE ALSO - -* [hyperalert](/docs/reference/hyperalert/hyperalert.md) - AppsCode Icinga2 plugin - - diff --git a/docs/reference/hyperalert/hyperalert_check_json_path.md b/docs/reference/hyperalert/hyperalert_check_json_path.md index 265f44c67..6e48751b9 100644 --- a/docs/reference/hyperalert/hyperalert_check_json_path.md +++ b/docs/reference/hyperalert/hyperalert_check_json_path.md @@ -37,6 +37,7 @@ hyperalert check_json_path [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_check_node_exists.md b/docs/reference/hyperalert/hyperalert_check_node_exists.md index 6e402bc30..037795c12 100644 --- a/docs/reference/hyperalert/hyperalert_check_node_exists.md +++ b/docs/reference/hyperalert/hyperalert_check_node_exists.md @@ -35,6 +35,7 @@ hyperalert check_node_exists [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_check_node_status.md b/docs/reference/hyperalert/hyperalert_check_node_status.md index 3153b04db..216d50891 100644 --- a/docs/reference/hyperalert/hyperalert_check_node_status.md +++ b/docs/reference/hyperalert/hyperalert_check_node_status.md @@ -33,6 +33,7 @@ hyperalert check_node_status [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_check_pod_exec.md b/docs/reference/hyperalert/hyperalert_check_pod_exec.md index 5480d5c03..4255cefd1 100644 --- a/docs/reference/hyperalert/hyperalert_check_pod_exec.md +++ b/docs/reference/hyperalert/hyperalert_check_pod_exec.md @@ -36,6 +36,7 @@ hyperalert check_pod_exec [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_check_pod_exists.md b/docs/reference/hyperalert/hyperalert_check_pod_exists.md index 715bd6b68..29d8283b9 100644 --- a/docs/reference/hyperalert/hyperalert_check_pod_exists.md +++ b/docs/reference/hyperalert/hyperalert_check_pod_exists.md @@ -36,6 +36,7 @@ hyperalert check_pod_exists [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_check_pod_status.md b/docs/reference/hyperalert/hyperalert_check_pod_status.md index 03b84353a..377bc5470 100644 --- a/docs/reference/hyperalert/hyperalert_check_pod_status.md +++ b/docs/reference/hyperalert/hyperalert_check_pod_status.md @@ -33,6 +33,7 @@ hyperalert check_pod_status [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_check_volume.md b/docs/reference/hyperalert/hyperalert_check_volume.md index 3c9851bd8..3863946ec 100644 --- a/docs/reference/hyperalert/hyperalert_check_volume.md +++ b/docs/reference/hyperalert/hyperalert_check_volume.md @@ -27,7 +27,7 @@ hyperalert check_volume [flags] -c, --critical float Critical level value (usage percentage) (default 95) -h, --help help for check_volume -H, --host string Icinga host name - --nodeStat Checking Node disk size + -M, --mountPoint string Mount point -s, --secretName string Kubernetes secret name -N, --volumeName string Volume name -w, --warning float Warning level value (usage percentage) (default 80) @@ -38,6 +38,7 @@ hyperalert check_volume [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_check_webhook.md b/docs/reference/hyperalert/hyperalert_check_webhook.md new file mode 100644 index 000000000..957e5fc0b --- /dev/null +++ b/docs/reference/hyperalert/hyperalert_check_webhook.md @@ -0,0 +1,89 @@ +--- +title: Check Webhook +menu: + product_searchlight_6.0.0-alpha.0: + identifier: hyperalert-check-webhook + name: Check Webhook + parent: hyperalert-cli +product_name: searchlight +section_menu_id: reference +menu_name: product_searchlight_6.0.0-alpha.0 +--- +## hyperalert check_webhook + +Check webhook result + +### Synopsis + +Check webhook result + +``` +hyperalert check_webhook [flags] +``` + +### Options + +``` + -h, --help help for check_webhook + --key.0 string + --key.1 string + --key.10 string + --key.11 string + --key.12 string + --key.13 string + --key.14 string + --key.15 string + --key.16 string + --key.17 string + --key.18 string + --key.19 string + --key.2 string + --key.3 string + --key.4 string + --key.5 string + --key.6 string + --key.7 string + --key.8 string + --key.9 string + --val.0 string + --val.1 string + --val.10 string + --val.11 string + --val.12 string + --val.13 string + --val.14 string + --val.15 string + --val.16 string + --val.17 string + --val.18 string + --val.19 string + --val.2 string + --val.3 string + --val.4 string + --val.5 string + --val.6 string + --val.7 string + --val.8 string + --val.9 string +``` + +### Options inherited from parent commands + +``` + --alsologtostderr log to standard error as well as files + --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) + --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). + --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) + --log_dir string If non-empty, write log files in this directory + --logtostderr log to standard error instead of files + --stderrthreshold severity logs at or above this threshold go to stderr + -v, --v Level log level for V logs + --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging +``` + +### SEE ALSO + +* [hyperalert](/docs/reference/hyperalert/hyperalert.md) - AppsCode Icinga2 plugin + + diff --git a/docs/reference/hyperalert/hyperalert_notifier.md b/docs/reference/hyperalert/hyperalert_notifier.md index 0f40a7d31..e8d88e2c4 100644 --- a/docs/reference/hyperalert/hyperalert_notifier.md +++ b/docs/reference/hyperalert/hyperalert_notifier.md @@ -40,6 +40,7 @@ hyperalert notifier [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/hyperalert/hyperalert_version.md b/docs/reference/hyperalert/hyperalert_version.md index 658ed74f6..18d2f5e90 100644 --- a/docs/reference/hyperalert/hyperalert_version.md +++ b/docs/reference/hyperalert/hyperalert_version.md @@ -33,6 +33,7 @@ hyperalert version [flags] ``` --alsologtostderr log to standard error as well as files --context string Use the context in kubeconfig + --icinga.checkInterval int Icinga check_interval in second. [Format: 30, 300] (default 30) --kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag). --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory diff --git a/docs/reference/searchlight/searchlight_run.md b/docs/reference/searchlight/searchlight_run.md index 693cf30c1..57f7514f2 100644 --- a/docs/reference/searchlight/searchlight_run.md +++ b/docs/reference/searchlight/searchlight_run.md @@ -56,11 +56,11 @@ searchlight run [flags] --kubeconfig string kubeconfig file pointing at the 'core' kubernetes server. --ops-address string Address to listen on for web interface and telemetry. (default ":56790") --profiling Enable profiling via web interface host:port/debug/pprof/ (default true) - --requestheader-allowed-names stringSlice List of client certificate common names to allow to provide usernames in headers specified by --requestheader-username-headers. If empty, any client certificate validated by the authorities in --requestheader-client-ca-file is allowed. + --requestheader-allowed-names strings List of client certificate common names to allow to provide usernames in headers specified by --requestheader-username-headers. If empty, any client certificate validated by the authorities in --requestheader-client-ca-file is allowed. --requestheader-client-ca-file string Root certificate bundle to use to verify client certificates on incoming requests before trusting usernames in headers specified by --requestheader-username-headers - --requestheader-extra-headers-prefix stringSlice List of request header prefixes to inspect. X-Remote-Extra- is suggested. (default [x-remote-extra-]) - --requestheader-group-headers stringSlice List of request headers to inspect for groups. X-Remote-Group is suggested. (default [x-remote-group]) - --requestheader-username-headers stringSlice List of request headers to inspect for usernames. X-Remote-User is common. (default [x-remote-user]) + --requestheader-extra-headers-prefix strings List of request header prefixes to inspect. X-Remote-Extra- is suggested. (default [x-remote-extra-]) + --requestheader-group-headers strings List of request headers to inspect for groups. X-Remote-Group is suggested. (default [x-remote-group]) + --requestheader-username-headers strings List of request headers to inspect for usernames. X-Remote-User is common. (default [x-remote-user]) --resync-period duration If non-zero, will re-list this often. Otherwise, re-list will be delayed aslong as possible (until the upstream source closes the watch or times out. (default 5m0s) --secure-port int The port on which to serve HTTPS with authentication and authorization. If 0, don't serve HTTPS at all. (default 443) --tls-ca-file string If set, this certificate authority will used for secure access from Admission Controllers. This must be a valid PEM-encoded CA bundle. Altneratively, the certificate authority can be appended to the certificate provided by --tls-cert-file. diff --git a/glide.lock b/glide.lock index a58a720aa..724212c02 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ hash: e0b07167ef3650096c626670c46034935c0b8a6894a15e4fe2b9202e25ad6352 -updated: 2018-04-13T10:56:36.148148631+06:00 +updated: 2018-04-19T10:41:11.74704598+06:00 imports: - name: bitbucket.org/ww/goautoneg version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675 @@ -50,7 +50,7 @@ imports: - admission/v1beta1 - registry/admissionreview/v1beta1 - name: github.com/appscode/kutil - version: c299ac799e9bf6554ee91c5e2863c6f8392b7f83 + version: c3aa54aedcceb925ba15c7bf4a6c2e456138755e subpackages: - apiextensions/v1beta1 - core/v1 @@ -239,10 +239,6 @@ imports: version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 - name: github.com/influxdata/influxdb version: 6ac835404e7e64ea7299a6eebcce1ab1ef15fe3c - subpackages: - - client - - models - - pkg/escape - name: github.com/jaytaylor/html2text version: 64a82a6d140778896f13303121a49d8cb8007034 - name: github.com/jpillora/go-ogle-analytics @@ -276,7 +272,7 @@ imports: - name: github.com/NYTimes/gziphandler version: 56545f4a5d46df9a6648819d1664c3a03a13ffdb - name: github.com/olekukonko/tablewriter - version: b8a9be070da40449e501c3c4730a889e42d87a9e + version: d5dd8a50526aadb3d5f2c9b5233277bc2db90e88 - name: github.com/onsi/gomega version: 003f63b7f4cff3fc95357005358af2de0f5fe152 subpackages: @@ -823,7 +819,7 @@ imports: - util/jsonpath - util/workqueue - name: k8s.io/kube-openapi - version: f442ecb314a3679150c272e2b9713d8deed5955d + version: 0f2f0396e266ad24afbd02375ba74c0dda1e3611 subpackages: - pkg/builder - pkg/common diff --git a/hack/codegen.sh b/hack/codegen.sh index 3362bd847..24b5ce737 100755 --- a/hack/codegen.sh +++ b/hack/codegen.sh @@ -47,7 +47,8 @@ for gv in "${apiGroups[@]}"; do --output-package "$PACKAGE_NAME/apis/${gv}" done -# Generate crds.yaml and swagger.json +# Generate crds.yaml, plugins.yaml and swagger.json go run ./hack/gencrd/main.go +go run ./hack/genplugin/main.go popd diff --git a/hack/deploy/plugins.yaml b/hack/deploy/plugins.yaml index 58a0593f3..1ba6c4eae 100644 --- a/hack/deploy/plugins.yaml +++ b/hack/deploy/plugins.yaml @@ -11,8 +11,11 @@ spec: host: v: vars.verbosity vars: - - selector - - componentName + Item: + componentName: + type: string + selector: + type: string command: hyperalert check_component_status state: - OK @@ -32,10 +35,17 @@ spec: host: name v: vars.verbosity vars: - - url - - secretName - - warning - - critical + Item: + critical: + type: string + secretName: + type: string + url: + type: string + warning: + type: string + required: + - url command: hyperalert check_json_path state: - OK @@ -55,9 +65,13 @@ spec: host: v: vars.verbosity vars: - - selector - - nodeName - - count + Item: + count: + type: integer + nodeName: + type: string + selector: + type: string command: hyperalert check_node_exists state: - OK @@ -77,9 +91,13 @@ spec: host: name v: vars.verbosity vars: - - selector - - podName - - count + Item: + count: + type: integer + podName: + type: string + selector: + type: string command: hyperalert check_pod_exists state: - OK @@ -99,11 +117,17 @@ spec: host: name v: vars.verbosity vars: - - clockSkew - - involvedObjectName - - involvedObjectNamespace - - involvedObjectKind - - involvedObjectUID + Item: + clockSkew: + type: duration + involvedObjectKind: + type: string + involvedObjectName: + type: string + involvedObjectNamespace: + type: string + involvedObjectUID: + type: string command: hyperalert check_event state: - OK @@ -122,8 +146,11 @@ spec: host: v: vars.verbosity vars: - - warning - - critical + Item: + critical: + type: duration + warning: + type: duration command: hyperalert check_ca_cert state: - OK @@ -144,11 +171,17 @@ spec: host: name v: vars.verbosity vars: - - selector - - secretName - - secretKey - - warning - - critical + Item: + critical: + type: duration + secretKey: + type: string + secretName: + type: string + selector: + type: string + warning: + type: duration command: hyperalert check_cert state: - OK @@ -187,10 +220,17 @@ spec: host: name v: vars.verbosity vars: - - mountPoint - - secretName - - warning - - critical + Item: + critical: + type: number + mountPoint: + type: string + secretName: + type: string + warning: + type: number + required: + - mountPoint command: hyperalert check_volume state: - OK @@ -228,10 +268,17 @@ spec: host: name v: vars.verbosity vars: - - volumeName - - secretName - - warning - - critical + Item: + critical: + type: number + secretName: + type: string + volumeName: + type: string + warning: + type: number + required: + - volumeName command: hyperalert check_volume state: - OK @@ -251,9 +298,15 @@ spec: host: name v: vars.verbosity vars: - - container - - cmd - - argv + Item: + argv: + type: string + cmd: + type: string + container: + type: string + required: + - argv command: hyperalert check_pod_exec state: - OK diff --git a/hack/deploy/searchlight.sh b/hack/deploy/searchlight.sh index 072529e4d..36d4a28c7 100755 --- a/hack/deploy/searchlight.sh +++ b/hack/deploy/searchlight.sh @@ -59,7 +59,7 @@ export SEARCHLIGHT_PURGE=0 export SEARCHLIGHT_ENABLE_ANALYTICS=true export APPSCODE_ENV=${APPSCODE_ENV:-prod} -export SCRIPT_LOCATION="curl -fsSL https://raw.githubusercontent.com/appscode/searchlight/6.0.0-alpha.0/" +export SCRIPT_LOCATION="curl -fsSL https://raw.githubusercontent.com/appscode/searchlight/6.0.0-rc.0/" if [ "$APPSCODE_ENV" = "dev" ]; then export SCRIPT_LOCATION="cat " fi @@ -261,7 +261,7 @@ for crd in "${crds[@]}"; do done echo "creating built-in plugins" -{SCRIPT_LOCATION}hack/deploy/plugins.yaml| kubectl apply -f - +${SCRIPT_LOCATION}hack/deploy/plugins.yaml| kubectl apply -f - echo echo "Successfully installed Searchlight!" diff --git a/hack/dev/icinga.yaml b/hack/dev/icinga.yaml index 137e99922..6f7d7a1ff 100644 --- a/hack/dev/icinga.yaml +++ b/hack/dev/icinga.yaml @@ -28,7 +28,7 @@ spec: app: searchlight spec: containers: - - image: appscode/icinga:incident-k8s + - image: aerokite/icinga:6.0.0-k8s imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 3 diff --git a/hack/dev/testconfig/custom.d/ca-cert.conf b/hack/dev/testconfig/custom.d/ca-cert.conf new file mode 100755 index 000000000..c227b8dd0 --- /dev/null +++ b/hack/dev/testconfig/custom.d/ca-cert.conf @@ -0,0 +1,11 @@ +object CheckCommand "ca-cert" { + import "plugin-check-command" + command = [ PluginDir + "/hyperalert", "check_ca_cert"] + + arguments = { + "--icinga.checkInterval" = "$service.check_interval$" + "--warning" = "$warning$" + "--critical" = "$critical$" + "--v" = "$host.vars.verbosity$" + } +} \ No newline at end of file diff --git a/hack/dev/testconfig/custom.d/cert.conf b/hack/dev/testconfig/custom.d/cert.conf new file mode 100755 index 000000000..03ed4ca14 --- /dev/null +++ b/hack/dev/testconfig/custom.d/cert.conf @@ -0,0 +1,15 @@ +object CheckCommand "cert" { + import "plugin-check-command" + command = [ PluginDir + "/hyperalert", "check_cert"] + + arguments = { + "--icinga.checkInterval" = "$service.check_interval$" + "--critical" = "$critical$" + "--secretKey" = "$secretKey$" + "--secretName" = "$secretName$" + "--selector" = "$selector$" + "--warning" = "$warning$" + "--host" = "$host.name$" + "--v" = "$host.vars.verbosity$" + } +} \ No newline at end of file diff --git a/hack/dev/testconfig/custom.d/component-status.conf b/hack/dev/testconfig/custom.d/component-status.conf new file mode 100755 index 000000000..7505f719f --- /dev/null +++ b/hack/dev/testconfig/custom.d/component-status.conf @@ -0,0 +1,11 @@ +object CheckCommand "component-status" { + import "plugin-check-command" + command = [ PluginDir + "/hyperalert", "check_component_status"] + + arguments = { + "--icinga.checkInterval" = "$service.check_interval$" + "--componentName" = "$componentName$" + "--selector" = "$selector$" + "--v" = "$host.vars.verbosity$" + } +} \ No newline at end of file diff --git a/hack/dev/testconfig/custom.d/event.conf b/hack/dev/testconfig/custom.d/event.conf new file mode 100755 index 000000000..c0fad2c0d --- /dev/null +++ b/hack/dev/testconfig/custom.d/event.conf @@ -0,0 +1,15 @@ +object CheckCommand "event" { + import "plugin-check-command" + command = [ PluginDir + "/hyperalert", "check_event"] + + arguments = { + "--icinga.checkInterval" = "$service.check_interval$" + "--clockSkew" = "$clockSkew$" + "--involvedObjectKind" = "$involvedObjectKind$" + "--involvedObjectName" = "$involvedObjectName$" + "--involvedObjectNamespace" = "$involvedObjectNamespace$" + "--involvedObjectUID" = "$involvedObjectUID$" + "--host" = "$host.name$" + "--v" = "$host.vars.verbosity$" + } +} \ No newline at end of file diff --git a/hack/dev/testconfig/custom.d/json-path.conf b/hack/dev/testconfig/custom.d/json-path.conf new file mode 100755 index 000000000..0081e850b --- /dev/null +++ b/hack/dev/testconfig/custom.d/json-path.conf @@ -0,0 +1,14 @@ +object CheckCommand "json-path" { + import "plugin-check-command" + command = [ PluginDir + "/hyperalert", "check_json_path"] + + arguments = { + "--icinga.checkInterval" = "$service.check_interval$" + "--critical" = "$critical$" + "--secretName" = "$secretName$" + "--url" = "$url$" + "--warning" = "$warning$" + "--v" = "$host.vars.verbosity$" + "--host" = "$host.name$" + } +} \ No newline at end of file diff --git a/hack/dev/testconfig/custom.d/node-exists.conf b/hack/dev/testconfig/custom.d/node-exists.conf new file mode 100755 index 000000000..e26778bbe --- /dev/null +++ b/hack/dev/testconfig/custom.d/node-exists.conf @@ -0,0 +1,12 @@ +object CheckCommand "node-exists" { + import "plugin-check-command" + command = [ PluginDir + "/hyperalert", "check_node_exists"] + + arguments = { + "--icinga.checkInterval" = "$service.check_interval$" + "--nodeName" = "$nodeName$" + "--selector" = "$selector$" + "--count" = "$count$" + "--v" = "$host.vars.verbosity$" + } +} \ No newline at end of file diff --git a/hack/dev/testconfig/custom.d/node-status.conf b/hack/dev/testconfig/custom.d/node-status.conf new file mode 100755 index 000000000..512710936 --- /dev/null +++ b/hack/dev/testconfig/custom.d/node-status.conf @@ -0,0 +1,10 @@ +object CheckCommand "node-status" { + import "plugin-check-command" + command = [ PluginDir + "/hyperalert", "check_node_status"] + + arguments = { + "--icinga.checkInterval" = "$service.check_interval$" + "--host" = "$host.name$" + "--v" = "$host.vars.verbosity$" + } +} \ No newline at end of file diff --git a/hack/dev/testconfig/custom.d/node-volume.conf b/hack/dev/testconfig/custom.d/node-volume.conf new file mode 100755 index 000000000..2ddca6abb --- /dev/null +++ b/hack/dev/testconfig/custom.d/node-volume.conf @@ -0,0 +1,14 @@ +object CheckCommand "node-volume" { + import "plugin-check-command" + command = [ PluginDir + "/hyperalert", "check_volume"] + + arguments = { + "--icinga.checkInterval" = "$service.check_interval$" + "--critical" = "$critical$" + "--mountPoint" = "$mountPoint$" + "--secretName" = "$secretName$" + "--warning" = "$warning$" + "--host" = "$host.name$" + "--v" = "$host.vars.verbosity$" + } +} \ No newline at end of file diff --git a/hack/dev/testconfig/custom.d/pod-exec.conf b/hack/dev/testconfig/custom.d/pod-exec.conf new file mode 100755 index 000000000..1b8440806 --- /dev/null +++ b/hack/dev/testconfig/custom.d/pod-exec.conf @@ -0,0 +1,13 @@ +object CheckCommand "pod-exec" { + import "plugin-check-command" + command = [ PluginDir + "/hyperalert", "check_pod_exec"] + + arguments = { + "--icinga.checkInterval" = "$service.check_interval$" + "--cmd" = "$cmd$" + "--container" = "$container$" + "--argv" = "$argv$" + "--host" = "$host.name$" + "--v" = "$host.vars.verbosity$" + } +} \ No newline at end of file diff --git a/hack/dev/testconfig/custom.d/pod-exists.conf b/hack/dev/testconfig/custom.d/pod-exists.conf new file mode 100755 index 000000000..eba4933d3 --- /dev/null +++ b/hack/dev/testconfig/custom.d/pod-exists.conf @@ -0,0 +1,13 @@ +object CheckCommand "pod-exists" { + import "plugin-check-command" + command = [ PluginDir + "/hyperalert", "check_pod_exists"] + + arguments = { + "--icinga.checkInterval" = "$service.check_interval$" + "--count" = "$count$" + "--podName" = "$podName$" + "--selector" = "$selector$" + "--v" = "$host.vars.verbosity$" + "--host" = "$host.name$" + } +} \ No newline at end of file diff --git a/hack/dev/testconfig/custom.d/pod-status.conf b/hack/dev/testconfig/custom.d/pod-status.conf new file mode 100755 index 000000000..d508947a4 --- /dev/null +++ b/hack/dev/testconfig/custom.d/pod-status.conf @@ -0,0 +1,10 @@ +object CheckCommand "pod-status" { + import "plugin-check-command" + command = [ PluginDir + "/hyperalert", "check_pod_status"] + + arguments = { + "--icinga.checkInterval" = "$service.check_interval$" + "--v" = "$host.vars.verbosity$" + "--host" = "$host.name$" + } +} \ No newline at end of file diff --git a/hack/dev/testconfig/custom.d/pod-volume.conf b/hack/dev/testconfig/custom.d/pod-volume.conf new file mode 100755 index 000000000..3857dada9 --- /dev/null +++ b/hack/dev/testconfig/custom.d/pod-volume.conf @@ -0,0 +1,14 @@ +object CheckCommand "pod-volume" { + import "plugin-check-command" + command = [ PluginDir + "/hyperalert", "check_volume"] + + arguments = { + "--icinga.checkInterval" = "$service.check_interval$" + "--secretName" = "$secretName$" + "--volumeName" = "$volumeName$" + "--warning" = "$warning$" + "--critical" = "$critical$" + "--host" = "$host.name$" + "--v" = "$host.vars.verbosity$" + } +} \ No newline at end of file diff --git a/hack/dev/testconfig/searchlight/config.ini b/hack/dev/testconfig/searchlight/config.ini index ca63d5e0b..b29918476 100644 --- a/hack/dev/testconfig/searchlight/config.ini +++ b/hack/dev/testconfig/searchlight/config.ini @@ -1,4 +1,4 @@ -ICINGA_ADDRESS=192.168.99.100:31330 +ICINGA_ADDRESS=192.168.99.100:32703 ICINGA_API_USER=icingaapi ICINGA_API_PASSWORD=VDYBqn3wtc-MNdlX ICINGA_NOTIFIER_SECRET_NAME= diff --git a/hack/make.py b/hack/make.py index 70437627c..099ad6647 100755 --- a/hack/make.py +++ b/hack/make.py @@ -91,35 +91,30 @@ def version(): def fmt(): - libbuild.ungroup_go_imports('apis', 'client', 'cmd', 'data', 'pkg', 'plugins', 'test') - die(call('goimports -w apis client cmd data pkg plugins test')) - call('gofmt -s -w apis client cmd data pkg plugins test') + libbuild.ungroup_go_imports('apis', 'client', 'cmd', 'pkg', 'plugins', 'test') + die(call('goimports -w apis client cmd pkg plugins test')) + call('gofmt -s -w apis client cmd pkg plugins test') def vet(): - call('go vet ./apis/... ./client/... ./cmd/... ./data/... ./pkg/... ./plugins/... ./test/...') + call('go vet ./apis/... ./client/... ./cmd/... ./pkg/... ./plugins/... ./test/...') def lint(): call('golint ./apis/...') call('golint ./client/...') call('golint ./cmd/...') - call('golint ./data/...') + call('golint ./pkg/...') call('golint ./plugins/...') call('golint ./test/...') -def gen_assets(): - die(call('go-bindata -ignore=\\.go -ignore=\\.DS_Store -mode=0644 -modtime=1453795200 -o bindata.go -pkg files ./...', cwd=libbuild.REPO_ROOT + '/data/files')) - - def gen_extpoints(): die(call('go generate cmd/searchlight/main.go')) def gen(): - gen_assets() gen_extpoints() fmt() diff --git a/pkg/icinga/cluster.go b/pkg/icinga/cluster.go index 0202fec38..e71fb5e4e 100644 --- a/pkg/icinga/cluster.go +++ b/pkg/icinga/cluster.go @@ -52,7 +52,7 @@ func (h *ClusterHost) Apply(alert *api.ClusterAlert) error { attrs["check_interval"] = alertSpec.CheckInterval.Seconds() } cmd, _ := api.ClusterCommands.Get(alertSpec.Check) - commandVars := cmd.Vars + commandVars := cmd.Vars.Items for key, val := range alertSpec.Vars { if _, found := commandVars[key]; found { attrs[IVar(key)] = val diff --git a/pkg/icinga/node.go b/pkg/icinga/node.go index 344665265..910143e82 100644 --- a/pkg/icinga/node.go +++ b/pkg/icinga/node.go @@ -1,11 +1,7 @@ package icinga import ( - "bytes" - "text/template" - api "github.com/appscode/searchlight/apis/monitoring/v1alpha1" - "github.com/pkg/errors" core "k8s.io/api/core/v1" ) @@ -40,36 +36,6 @@ func (h *NodeHost) getHost(namespace string, node *core.Node) IcingaHost { } } -func (h *NodeHost) expandVars(alertSpec api.NodeAlertSpec, kh IcingaHost, attrs map[string]interface{}) error { - cmd, _ := api.NodeCommands.Get(alertSpec.Check) - commandVars := cmd.Vars - for key, val := range alertSpec.Vars { - if v, found := commandVars[key]; found { - if v.Parameterized { - type Data struct { - NodeName string - NodeIP string - } - tmpl, err := template.New("").Parse(val) - if err != nil { - return err - } - var buf bytes.Buffer - err = tmpl.Execute(&buf, Data{NodeName: kh.ObjectName, NodeIP: kh.IP}) - if err != nil { - return err - } - attrs[IVar(key)] = buf.String() - } else { - attrs[IVar(key)] = val - } - } else { - return errors.Errorf("variable %v not found", key) - } - } - return nil -} - // set Alert in Icinga LocalHost func (h *NodeHost) Apply(alert *api.NodeAlert, node *core.Node) error { alertSpec := alert.Spec @@ -97,8 +63,8 @@ func (h *NodeHost) Apply(alert *api.NodeAlert, node *core.Node) error { if alertSpec.CheckInterval.Seconds() > 0 { attrs["check_interval"] = alertSpec.CheckInterval.Seconds() } - if err := h.expandVars(alertSpec, kh, attrs); err != nil { - return err + for key, val := range alertSpec.Vars { + attrs[IVar(key)] = val } if !has { diff --git a/pkg/icinga/pod.go b/pkg/icinga/pod.go index 8cddc3a6f..e4e951b3b 100644 --- a/pkg/icinga/pod.go +++ b/pkg/icinga/pod.go @@ -1,11 +1,7 @@ package icinga import ( - "bytes" - "text/template" - api "github.com/appscode/searchlight/apis/monitoring/v1alpha1" - "github.com/pkg/errors" core "k8s.io/api/core/v1" ) @@ -31,37 +27,6 @@ func (h *PodHost) getHost(namespace string, pod *core.Pod) IcingaHost { } } -func (h *PodHost) expandVars(alertSpec api.PodAlertSpec, kh IcingaHost, attrs map[string]interface{}) error { - cmd, _ := api.PodCommands.Get(alertSpec.Check) - commandVars := cmd.Vars - for key, val := range alertSpec.Vars { - if v, found := commandVars[key]; found { - if v.Parameterized { - type Data struct { - PodName string - PodIP string - Namespace string - } - tmpl, err := template.New("").Parse(val) - if err != nil { - return err - } - var buf bytes.Buffer - err = tmpl.Execute(&buf, Data{PodName: kh.ObjectName, Namespace: kh.AlertNamespace, PodIP: kh.IP}) - if err != nil { - return err - } - attrs[IVar(key)] = buf.String() - } else { - attrs[IVar(key)] = val - } - } else { - return errors.Errorf("variable %v not found", key) - } - } - return nil -} - func (h *PodHost) Apply(alert *api.PodAlert, pod *core.Pod) error { alertSpec := alert.Spec kh := h.getHost(alert.Namespace, pod) @@ -88,8 +53,9 @@ func (h *PodHost) Apply(alert *api.PodAlert, pod *core.Pod) error { if alertSpec.CheckInterval.Seconds() > 0 { attrs["check_interval"] = alertSpec.CheckInterval.Seconds() } - if err := h.expandVars(alertSpec, kh, attrs); err != nil { - return err + + for key, val := range alertSpec.Vars { + attrs[IVar(key)] = val } if !has { diff --git a/pkg/operator/plugin.go b/pkg/operator/plugin.go index 8b8681d81..7b4007790 100644 --- a/pkg/operator/plugin.go +++ b/pkg/operator/plugin.go @@ -14,7 +14,6 @@ import ( "github.com/appscode/kutil/tools/queue" api "github.com/appscode/searchlight/apis/monitoring/v1alpha1" "github.com/appscode/searchlight/client/clientset/versioned/typed/monitoring/v1alpha1/util" - "github.com/appscode/searchlight/data" "github.com/appscode/searchlight/pkg/icinga" "github.com/appscode/searchlight/pkg/plugin" "github.com/golang/glog" @@ -67,13 +66,13 @@ func (op *Operator) ensureCheckCommand(wp *api.SearchlightPlugin) error { ic := api.IcingaCommand{ Name: wp.Name, - Vars: make(map[string]data.CommandVar), - } - - for _, item := range wp.Spec.Arguments.Vars { - ic.Vars[item] = data.CommandVar{} + Vars: &api.PluginVars{ + Items: make(map[string]api.PluginVarItem), + Required: make([]string, 0), + }, } + ic.Vars = wp.Spec.Arguments.Vars ic.States = wp.Spec.State for _, t := range wp.Spec.AlertKinds { diff --git a/pkg/plugin/check_command.go b/pkg/plugin/check_command.go index 75d99a109..759b49cd6 100644 --- a/pkg/plugin/check_command.go +++ b/pkg/plugin/check_command.go @@ -42,11 +42,13 @@ func GenerateCheckCommand(plugin *api.SearchlightPlugin) string { }) } - for _, item := range plugin.Spec.Arguments.Vars { - args = append(args, arg{ - key: item, - val: fmt.Sprintf("$%s$", item), - }) + if plugin.Spec.Arguments.Vars != nil { + for key := range plugin.Spec.Arguments.Vars.Items { + args = append(args, arg{ + key: key, + val: fmt.Sprintf("$%s$", key), + }) + } } for key, val := range plugin.Spec.Arguments.Host { diff --git a/pkg/plugin/cluster_alert.go b/pkg/plugin/cluster_alert.go index fe22335cf..40f44d3b4 100644 --- a/pkg/plugin/cluster_alert.go +++ b/pkg/plugin/cluster_alert.go @@ -15,9 +15,15 @@ func GetComponentStatusPlugin() *api.SearchlightPlugin { Command: "hyperalert check_component_status", AlertKinds: []string{api.ResourceKindClusterAlert}, Arguments: api.PluginArguments{ - Vars: []string{ - "selector", - "componentName", + Vars: &api.PluginVars{ + Items: map[string]api.PluginVarItem{ + "selector": { + Type: api.VarTypeString, + }, + "componentName": { + Type: api.VarTypeString, + }, + }, }, Host: map[string]string{ "v": "vars.verbosity", @@ -38,11 +44,22 @@ func GetJsonPathPlugin() *api.SearchlightPlugin { Command: "hyperalert check_json_path", AlertKinds: []string{api.ResourceKindClusterAlert}, Arguments: api.PluginArguments{ - Vars: []string{ - "url", - "secretName", - "warning", - "critical", + Vars: &api.PluginVars{ + Items: map[string]api.PluginVarItem{ + "url": { + Type: api.VarTypeString, + }, + "secretName": { + Type: api.VarTypeString, + }, + "warning": { + Type: api.VarTypeString, + }, + "critical": { + Type: api.VarTypeString, + }, + }, + Required: []string{"url"}, }, Host: map[string]string{ "host": "name", @@ -64,10 +81,18 @@ func GetNodeExistsPlugin() *api.SearchlightPlugin { Command: "hyperalert check_node_exists", AlertKinds: []string{api.ResourceKindClusterAlert}, Arguments: api.PluginArguments{ - Vars: []string{ - "selector", - "nodeName", - "count", + Vars: &api.PluginVars{ + Items: map[string]api.PluginVarItem{ + "selector": { + Type: api.VarTypeString, + }, + "nodeName": { + Type: api.VarTypeString, + }, + "count": { + Type: api.VarTypeInteger, + }, + }, }, Host: map[string]string{ "v": "vars.verbosity", @@ -88,10 +113,18 @@ func GetPodExistsPlugin() *api.SearchlightPlugin { Command: "hyperalert check_pod_exists", AlertKinds: []string{api.ResourceKindClusterAlert}, Arguments: api.PluginArguments{ - Vars: []string{ - "selector", - "podName", - "count", + Vars: &api.PluginVars{ + Items: map[string]api.PluginVarItem{ + "selector": { + Type: api.VarTypeString, + }, + "podName": { + Type: api.VarTypeString, + }, + "count": { + Type: api.VarTypeInteger, + }, + }, }, Host: map[string]string{ "host": "name", @@ -113,12 +146,24 @@ func GetEventPlugin() *api.SearchlightPlugin { Command: "hyperalert check_event", AlertKinds: []string{api.ResourceKindClusterAlert}, Arguments: api.PluginArguments{ - Vars: []string{ - "clockSkew", - "involvedObjectName", - "involvedObjectNamespace", - "involvedObjectKind", - "involvedObjectUID", + Vars: &api.PluginVars{ + Items: map[string]api.PluginVarItem{ + "clockSkew": { + Type: api.VarTypeDuration, + }, + "involvedObjectName": { + Type: api.VarTypeString, + }, + "involvedObjectNamespace": { + Type: api.VarTypeString, + }, + "involvedObjectKind": { + Type: api.VarTypeString, + }, + "involvedObjectUID": { + Type: api.VarTypeString, + }, + }, }, Host: map[string]string{ "host": "name", @@ -140,9 +185,15 @@ func GetCACertPlugin() *api.SearchlightPlugin { Command: "hyperalert check_ca_cert", AlertKinds: []string{api.ResourceKindClusterAlert}, Arguments: api.PluginArguments{ - Vars: []string{ - "warning", - "critical", + Vars: &api.PluginVars{ + Items: map[string]api.PluginVarItem{ + "warning": { + Type: api.VarTypeDuration, + }, + "critical": { + Type: api.VarTypeDuration, + }, + }, }, Host: map[string]string{ "v": "vars.verbosity", @@ -163,12 +214,24 @@ func GetCertPlugin() *api.SearchlightPlugin { Command: "hyperalert check_cert", AlertKinds: []string{api.ResourceKindClusterAlert}, Arguments: api.PluginArguments{ - Vars: []string{ - "selector", - "secretName", - "secretKey", - "warning", - "critical", + Vars: &api.PluginVars{ + Items: map[string]api.PluginVarItem{ + "selector": { + Type: api.VarTypeString, + }, + "secretName": { + Type: api.VarTypeString, + }, + "secretKey": { + Type: api.VarTypeString, + }, + "warning": { + Type: api.VarTypeDuration, + }, + "critical": { + Type: api.VarTypeDuration, + }, + }, }, Host: map[string]string{ "host": "name", diff --git a/pkg/plugin/node_alert.go b/pkg/plugin/node_alert.go index 3718d05c6..8b82588d7 100644 --- a/pkg/plugin/node_alert.go +++ b/pkg/plugin/node_alert.go @@ -35,11 +35,22 @@ func GetNodeVolumePlugin() *api.SearchlightPlugin { Command: "hyperalert check_volume", AlertKinds: []string{api.ResourceKindNodeAlert}, Arguments: api.PluginArguments{ - Vars: []string{ - "mountPoint", - "secretName", - "warning", - "critical", + Vars: &api.PluginVars{ + Items: map[string]api.PluginVarItem{ + "mountPoint": { + Type: api.VarTypeString, + }, + "secretName": { + Type: api.VarTypeString, + }, + "warning": { + Type: api.VarTypeNumber, + }, + "critical": { + Type: api.VarTypeNumber, + }, + }, + Required: []string{"mountPoint"}, }, Host: map[string]string{ "host": "name", diff --git a/pkg/plugin/pod_alert.go b/pkg/plugin/pod_alert.go index eaea55279..49d4afa90 100644 --- a/pkg/plugin/pod_alert.go +++ b/pkg/plugin/pod_alert.go @@ -35,11 +35,22 @@ func GetPodVolumePlugin() *api.SearchlightPlugin { Command: "hyperalert check_volume", AlertKinds: []string{api.ResourceKindPodAlert}, Arguments: api.PluginArguments{ - Vars: []string{ - "volumeName", - "secretName", - "warning", - "critical", + Vars: &api.PluginVars{ + Items: map[string]api.PluginVarItem{ + "volumeName": { + Type: api.VarTypeString, + }, + "secretName": { + Type: api.VarTypeString, + }, + "warning": { + Type: api.VarTypeNumber, + }, + "critical": { + Type: api.VarTypeNumber, + }, + }, + Required: []string{"volumeName"}, }, Host: map[string]string{ "host": "name", @@ -61,10 +72,19 @@ func GetPodExecPlugin() *api.SearchlightPlugin { Command: "hyperalert check_pod_exec", AlertKinds: []string{api.ResourceKindPodAlert}, Arguments: api.PluginArguments{ - Vars: []string{ - "container", - "cmd", - "argv", + Vars: &api.PluginVars{ + Items: map[string]api.PluginVarItem{ + "container": { + Type: api.VarTypeString, + }, + "cmd": { + Type: api.VarTypeString, + }, + "argv": { + Type: api.VarTypeString, + }, + }, + Required: []string{"argv"}, }, Host: map[string]string{ "host": "name", diff --git a/plugins/check_cert/lib_test.go b/plugins/check_cert/lib_test.go index 414165511..703ffbb82 100644 --- a/plugins/check_cert/lib_test.go +++ b/plugins/check_cert/lib_test.go @@ -8,7 +8,6 @@ import ( "math/big" "time" - . "github.com/appscode/searchlight/data" "github.com/appscode/searchlight/pkg/icinga" "github.com/appscode/searchlight/plugins" . "github.com/onsi/ginkgo" @@ -274,23 +273,6 @@ var _ = Describe("check_cert", func() { }) }) - Describe("Check bindata support", func() { - Context("bindata contain plugin info", func() { - It("should be succeeded", func() { - ic, err := LoadClusterChecks() - Expect(err).ShouldNot(HaveOccurred()) - found := false - for _, c := range ic.Command { - if c.Name == "cert" { - found = true - break - } - } - Expect(found).Should(BeTrue()) - }) - }) - }) - Describe("test options", func() { var ( cmd *cobra.Command diff --git a/plugins/check_influx_query/config.go b/plugins/check_influx_query/config.go deleted file mode 100644 index d696ce199..000000000 --- a/plugins/check_influx_query/config.go +++ /dev/null @@ -1,69 +0,0 @@ -package check_influx_query - -import ( - "errors" - "fmt" - "strings" - - ini "github.com/vaughan0/go-ini" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" -) - -const ( - admin string = ".admin" - - influxDBHost string = "INFLUX_HOST" - influxDBDatabase string = "INFLUX_DB" - influxDBReadUser string = "INFLUX_READ_USER" - influxDBReadPass string = "INFLUX_READ_PASSWORD" - - influxDBDefaultDatabase string = "k8s" - influxDBHostPort = 8086 -) - -type AuthInfo struct { - Host string - Username string - Password string - Database string -} - -func GetInfluxDBSecretData(req *Request, secretName, namespace string) (*AuthInfo, error) { - config, err := clientcmd.BuildConfigFromFlags(req.masterURL, req.kubeconfigPath) - if err != nil { - return nil, err - } - kubeClient := kubernetes.NewForConfigOrDie(config) - - secret, err := kubeClient.CoreV1().Secrets(namespace).Get(secretName, metav1.GetOptions{}) - if err != nil { - return nil, err - } - - authData := new(AuthInfo) - if data, found := secret.Data[admin]; found { - dataReader := strings.NewReader(string(data)) - secretData, err := ini.Load(dataReader) - if err != nil { - return nil, err - } - - if host, found := secretData.Get("", influxDBHost); found { - authData.Host = fmt.Sprintf("%s:%d", host, influxDBHostPort) - } - - if authData.Database, found = secretData.Get("", influxDBDatabase); !found { - authData.Database = influxDBDefaultDatabase - } - if authData.Username, found = secretData.Get("", influxDBReadUser); !found { - return nil, errors.New("No InfluxDB read user found") - } - if authData.Password, found = secretData.Get("", influxDBReadPass); !found { - return nil, errors.New("No InfluxDB read password found") - } - return authData, nil - } - return nil, errors.New("Invalid InfluxDB secret") -} diff --git a/plugins/check_influx_query/lib.go b/plugins/check_influx_query/lib.go deleted file mode 100644 index d8c08509d..000000000 --- a/plugins/check_influx_query/lib.go +++ /dev/null @@ -1,234 +0,0 @@ -package check_influx_query - -import ( - "encoding/json" - "errors" - "fmt" - "net/url" - "os" - "strconv" - - "github.com/Knetic/govaluate" - "github.com/appscode/go/flags" - "github.com/appscode/searchlight/pkg/icinga" - "github.com/influxdata/influxdb/client" - "github.com/spf13/cobra" -) - -type Request struct { - masterURL string - kubeconfigPath string - - Host string - A, B, C, D, E string - R string - Warning string - Critical string - SecretName string - Namespace string -} - -func trunc(val float64) interface{} { - intData := int64(val * 1000) - return float64(intData) / 1000.0 -} - -func getInfluxDBClient(authData *AuthInfo) (*client.Client, error) { - config := &client.Config{ - URL: url.URL{ - Scheme: "http", - Host: authData.Host, - }, - Username: authData.Username, - Password: authData.Password, - } - client, err := client.NewClient(*config) - if err != nil { - return nil, err - } - return client, nil -} - -func getInfluxdbData(con *client.Client, command, db, queryName string) (float64, error) { - q := client.Query{ - Command: command, - Database: db, - } - res, err := con.Query(q) - if err != nil { - return 0.0, err - } - - if len(res.Results[0].Series) == 0 { - return 0.0, errors.New(fmt.Sprint("Value not found for query: ", queryName)) - } - data, err := strconv.ParseFloat((string(res.Results[0].Series[0].Values[0][1].(json.Number))), 64) - if err != nil { - return 0.0, err - } - return data, nil -} - -func getValue(con *client.Client, db string, req *Request) (map[string]interface{}, error) { - valMap := make(map[string]interface{}) - - defer func() { - if e := recover(); e != nil { - fmt.Fprintln(os.Stdout, icinga.Warning, e) - os.Exit(3) - } - }() - - if req.A != "" { - data, err := getInfluxdbData(con, req.A, db, "A") - if err != nil { - return nil, err - } - valMap["A"] = data - } - - if req.B != "" { - data, err := getInfluxdbData(con, req.B, db, "B") - if err != nil { - return nil, err - } - valMap["B"] = data - } - - if req.C != "" { - data, err := getInfluxdbData(con, req.C, db, "C") - if err != nil { - return nil, err - } - valMap["C"] = data - } - - if req.D != "" { - data, err := getInfluxdbData(con, req.D, db, "D") - if err != nil { - return nil, err - } - valMap["D"] = data - } - - if req.E != "" { - data, err := getInfluxdbData(con, req.E, db, "E") - if err != nil { - return nil, err - } - valMap["E"] = data - } - - return valMap, nil -} - -func checkResult(checkQuery string, valueMap map[string]interface{}) (bool, error) { - expr, err := govaluate.NewEvaluableExpression(checkQuery) - if err != nil { - return false, err - } - - res, err := expr.Evaluate(valueMap) - if err != nil { - return false, err - } - - if res.(bool) { - return true, nil - } - return false, nil -} - -func CheckInfluxQuery(req *Request) (icinga.State, interface{}) { - authData, err := GetInfluxDBSecretData(req, req.SecretName, req.Namespace) - if err != nil { - return icinga.Unknown, err - } - - if req.Host != "" { - authData.Host = req.Host - } - if authData.Host == "" { - return icinga.Unknown, "No InfluxDB host found" - } - client, err := getInfluxDBClient(authData) - if err != nil { - return icinga.Unknown, err - } - - valMap, err := getValue(client, authData.Database, req) - if err != nil { - return icinga.Unknown, err - } - - expression, err := govaluate.NewEvaluableExpression(req.R) - if err != nil { - return icinga.Unknown, err - } - - if valMap["R"], err = expression.Evaluate(valMap); err != nil { - return icinga.Unknown, err - } - valMap["R"] = trunc(valMap["R"].(float64)) - - if req.Critical != "" { - isCritical, err := checkResult(req.Critical, valMap) - if err != nil { - return icinga.Unknown, err.Error() - } - if isCritical { - return icinga.Critical, nil - } - } - - if req.Warning != "" { - isWarning, err := checkResult(req.Warning, valMap) - if err != nil { - return icinga.Unknown, err - } - if isWarning { - return icinga.Warning, nil - } - } - - return icinga.OK, "Fine" -} - -func NewCmd() *cobra.Command { - var req Request - var icingaHost string - - c := &cobra.Command{ - Use: "check_influx_query", - Short: "Check InfluxDB Query Data", - Example: "", - - Run: func(cmd *cobra.Command, args []string) { - flags.EnsureRequiredFlags(cmd, "host") - - host, err := icinga.ParseHost(icingaHost) - if err != nil { - fmt.Fprintln(os.Stdout, icinga.Warning, "Invalid icinga host.name") - os.Exit(3) - } - req.Namespace = host.AlertNamespace - - flags.EnsureAlterableFlags(cmd, "A", "B", "C", "D", "E") - flags.EnsureAlterableFlags(cmd, "warning", "critical") - icinga.Output(CheckInfluxQuery(&req)) - }, - } - - c.Flags().StringVarP(&icingaHost, "host", "H", "", "Icinga host name") - c.Flags().StringVar(&req.Host, "influxHost", "", "URL of InfluxDB host to query") - c.Flags().StringVarP(&req.SecretName, "secretName", "s", "", `Kubernetes secret name`) - c.Flags().StringVar(&req.A, "A", "", "InfluxDB query A") - c.Flags().StringVar(&req.B, "B", "", "InfluxDB query B") - c.Flags().StringVar(&req.C, "C", "", "InfluxDB query C") - c.Flags().StringVar(&req.D, "D", "", "InfluxDB query D") - c.Flags().StringVar(&req.E, "E", "", "InfluxDB query E") - c.Flags().StringVar(&req.R, "R", "", `Equation to evaluate result`) - c.Flags().StringVarP(&req.Warning, "warning", "w", "", `Warning query which returns [true/false]`) - c.Flags().StringVarP(&req.Critical, "critical", "c", "", `Critical query which returns [true/false]`) - return c -} diff --git a/plugins/check_volume/lib.go b/plugins/check_volume/lib.go index 34f10a8b4..9fdeb0dcb 100644 --- a/plugins/check_volume/lib.go +++ b/plugins/check_volume/lib.go @@ -359,6 +359,11 @@ func (p *plugin) Check() (icinga.State, interface{}) { } } +const ( + flagVolumeName = "volumeName" + flagMountPoint = "mountPoint" +) + func NewCmd() *cobra.Command { var opts options @@ -368,6 +373,7 @@ func NewCmd() *cobra.Command { Run: func(cmd *cobra.Command, args []string) { flags.EnsureRequiredFlags(cmd, plugins.FlagHost) + flags.EnsureAlterableFlags(cmd, flagMountPoint, flagVolumeName) if err := opts.complete(cmd); err != nil { icinga.Output(icinga.Unknown, err) @@ -385,8 +391,8 @@ func NewCmd() *cobra.Command { c.Flags().StringP(plugins.FlagHost, "H", "", "Icinga host name") c.Flags().StringVarP(&opts.secretName, "secretName", "s", "", `Kubernetes secret name`) - c.Flags().StringVarP(&opts.volumeName, "volumeName", "N", "", "Volume name") - c.Flags().StringVarP(&opts.mountPoint, "mountPoint", "M", "", "Mount point") + c.Flags().StringVarP(&opts.volumeName, flagVolumeName, "N", "", "Volume name") + c.Flags().StringVarP(&opts.mountPoint, flagMountPoint, "M", "", "Mount point") c.Flags().Float64VarP(&opts.warning, "warning", "w", 80.0, "Warning level value (usage percentage)") c.Flags().Float64VarP(&opts.critical, "critical", "c", 95.0, "Critical level value (usage percentage)") return c diff --git a/plugins/hyperalert/lib.go b/plugins/hyperalert/lib.go index 17af9cb99..e5fd50847 100644 --- a/plugins/hyperalert/lib.go +++ b/plugins/hyperalert/lib.go @@ -15,7 +15,6 @@ import ( "github.com/appscode/searchlight/plugins/check_component_status" "github.com/appscode/searchlight/plugins/check_env" "github.com/appscode/searchlight/plugins/check_event" - "github.com/appscode/searchlight/plugins/check_influx_query" "github.com/appscode/searchlight/plugins/check_json_path" "github.com/appscode/searchlight/plugins/check_node_exists" "github.com/appscode/searchlight/plugins/check_node_status" @@ -82,7 +81,6 @@ func NewCmd() *cobra.Command { // Combined cmd.AddCommand(check_volume.NewCmd()) - cmd.AddCommand(check_influx_query.NewCmd()) // Notifier cmd.AddCommand(notifier.NewCmd()) diff --git a/vendor/github.com/appscode/kutil/meta/annotations.go b/vendor/github.com/appscode/kutil/meta/annotations.go index fb8775686..ace055b1d 100644 --- a/vendor/github.com/appscode/kutil/meta/annotations.go +++ b/vendor/github.com/appscode/kutil/meta/annotations.go @@ -2,6 +2,7 @@ package meta import ( "strconv" + "time" "github.com/appscode/kutil" ) @@ -13,6 +14,8 @@ var _ ParserFunc = GetInt var _ ParserFunc = GetString var _ ParserFunc = GetList var _ ParserFunc = GetMap +var _ ParserFunc = GetFloat +var _ ParserFunc = GetDuration func GetBool(m map[string]string, key string) (interface{}, error) { if m == nil { @@ -114,6 +117,40 @@ func GetMapValue(m map[string]string, key string) (map[string]string, error) { return v.(map[string]string), err } +func GetFloat(m map[string]string, key string) (interface{}, error) { + if m == nil { + return 0.0, kutil.ErrNotFound + } + f, ok := m[key] + if !ok { + return 0.0, kutil.ErrNotFound + } + + return strconv.ParseFloat(f, 64) +} + +func GetFloatValue(m map[string]string, key string) (float64, error) { + v, err := GetFloat(m, key) + return v.(float64), err +} + +func GetDuration(m map[string]string, key string) (interface{}, error) { + if m == nil { + return time.Duration(0), kutil.ErrNotFound + } + d, ok := m[key] + if !ok { + return time.Duration(0), kutil.ErrNotFound + } + + return time.ParseDuration(d) +} + +func GetDurationValue(m map[string]string, key string) (time.Duration, error) { + v, err := GetDuration(m, key) + return v.(time.Duration), err +} + type GetFunc func(map[string]string) (interface{}, error) func ParseFor(key string, fn ParserFunc) GetFunc { diff --git a/vendor/github.com/appscode/kutil/tools/queue/handler.go b/vendor/github.com/appscode/kutil/tools/queue/handler.go index 1fc23787b..7f9681782 100644 --- a/vendor/github.com/appscode/kutil/tools/queue/handler.go +++ b/vendor/github.com/appscode/kutil/tools/queue/handler.go @@ -2,6 +2,8 @@ package queue import ( "github.com/golang/glog" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/tools/cache" @@ -88,9 +90,8 @@ func NewVersionedHandler(inner cache.ResourceEventHandler, gvk schema.GroupVersi return versionedEventHandler{inner: inner, gvk: gvk} } -// versionedEventHandler is an adaptor to let you easily specify as many or -// as few of the notification functions as you want while still implementing -// ResourceEventHandler. +// versionedEventHandler is an adaptor to let you set GroupVersionKind of objects +// while still implementing ResourceEventHandler. type versionedEventHandler struct { inner cache.ResourceEventHandler gvk schema.GroupVersionKind @@ -116,3 +117,37 @@ func (w versionedEventHandler) OnUpdate(oldObj, newObj interface{}) { func (w versionedEventHandler) OnDelete(obj interface{}) { w.inner.OnDelete(w.setGroupVersionKind(obj)) } + +func NewFilteredHandler(inner cache.ResourceEventHandler, sel labels.Selector) cache.ResourceEventHandler { + return filteredEventHandler{inner: inner, sel: sel} +} + +// filteredEventHandler is an adaptor to let you handle event for objects with +// matching label. +type filteredEventHandler struct { + inner cache.ResourceEventHandler + sel labels.Selector +} + +func (w filteredEventHandler) matches(obj interface{}) bool { + accessor, err := meta.Accessor(obj) + return err == nil && w.sel.Matches(labels.Set(accessor.GetLabels())) +} + +func (w filteredEventHandler) OnAdd(obj interface{}) { + if w.matches(obj) { + w.inner.OnAdd(obj) + } +} + +func (w filteredEventHandler) OnUpdate(oldObj, newObj interface{}) { + if w.matches(oldObj) && w.matches(newObj) { + w.inner.OnUpdate(oldObj, newObj) + } +} + +func (w filteredEventHandler) OnDelete(obj interface{}) { + if w.matches(obj) { + w.inner.OnDelete(obj) + } +} diff --git a/vendor/github.com/influxdata/influxdb/client/influxdb.go b/vendor/github.com/influxdata/influxdb/client/influxdb.go deleted file mode 100644 index aa0292255..000000000 --- a/vendor/github.com/influxdata/influxdb/client/influxdb.go +++ /dev/null @@ -1,858 +0,0 @@ -// Package client implements a now-deprecated client for InfluxDB; -// use github.com/influxdata/influxdb/client/v2 instead. -package client // import "github.com/influxdata/influxdb/client" - -import ( - "bytes" - "context" - "crypto/tls" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "net/url" - "path" - "strconv" - "strings" - "time" - - "github.com/influxdata/influxdb/models" -) - -const ( - // DefaultHost is the default host used to connect to an InfluxDB instance - DefaultHost = "localhost" - - // DefaultPort is the default port used to connect to an InfluxDB instance - DefaultPort = 8086 - - // DefaultTimeout is the default connection timeout used to connect to an InfluxDB instance - DefaultTimeout = 0 -) - -// Query is used to send a command to the server. Both Command and Database are required. -type Query struct { - Command string - Database string - - // Chunked tells the server to send back chunked responses. This places - // less load on the server by sending back chunks of the response rather - // than waiting for the entire response all at once. - Chunked bool - - // ChunkSize sets the maximum number of rows that will be returned per - // chunk. Chunks are either divided based on their series or if they hit - // the chunk size limit. - // - // Chunked must be set to true for this option to be used. - ChunkSize int - - // NodeID sets the data node to use for the query results. This option only - // has any effect in the enterprise version of the software where there can be - // more than one data node and is primarily useful for analyzing differences in - // data. The default behavior is to automatically select the appropriate data - // nodes to retrieve all of the data. On a database where the number of data nodes - // is greater than the replication factor, it is expected that setting this option - // will only retrieve partial data. - NodeID int -} - -// ParseConnectionString will parse a string to create a valid connection URL -func ParseConnectionString(path string, ssl bool) (url.URL, error) { - var host string - var port int - - h, p, err := net.SplitHostPort(path) - if err != nil { - if path == "" { - host = DefaultHost - } else { - host = path - } - // If they didn't specify a port, always use the default port - port = DefaultPort - } else { - host = h - port, err = strconv.Atoi(p) - if err != nil { - return url.URL{}, fmt.Errorf("invalid port number %q: %s\n", path, err) - } - } - - u := url.URL{ - Scheme: "http", - Host: host, - } - if ssl { - u.Scheme = "https" - if port != 443 { - u.Host = net.JoinHostPort(host, strconv.Itoa(port)) - } - } else if port != 80 { - u.Host = net.JoinHostPort(host, strconv.Itoa(port)) - } - - return u, nil -} - -// Config is used to specify what server to connect to. -// URL: The URL of the server connecting to. -// Username/Password are optional. They will be passed via basic auth if provided. -// UserAgent: If not provided, will default "InfluxDBClient", -// Timeout: If not provided, will default to 0 (no timeout) -type Config struct { - URL url.URL - UnixSocket string - Username string - Password string - UserAgent string - Timeout time.Duration - Precision string - WriteConsistency string - UnsafeSsl bool -} - -// NewConfig will create a config to be used in connecting to the client -func NewConfig() Config { - return Config{ - Timeout: DefaultTimeout, - } -} - -// Client is used to make calls to the server. -type Client struct { - url url.URL - unixSocket string - username string - password string - httpClient *http.Client - userAgent string - precision string -} - -const ( - // ConsistencyOne requires at least one data node acknowledged a write. - ConsistencyOne = "one" - - // ConsistencyAll requires all data nodes to acknowledge a write. - ConsistencyAll = "all" - - // ConsistencyQuorum requires a quorum of data nodes to acknowledge a write. - ConsistencyQuorum = "quorum" - - // ConsistencyAny allows for hinted hand off, potentially no write happened yet. - ConsistencyAny = "any" -) - -// NewClient will instantiate and return a connected client to issue commands to the server. -func NewClient(c Config) (*Client, error) { - tlsConfig := &tls.Config{ - InsecureSkipVerify: c.UnsafeSsl, - } - - tr := &http.Transport{ - TLSClientConfig: tlsConfig, - } - - if c.UnixSocket != "" { - // No need for compression in local communications. - tr.DisableCompression = true - - tr.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) { - return net.Dial("unix", c.UnixSocket) - } - } - - client := Client{ - url: c.URL, - unixSocket: c.UnixSocket, - username: c.Username, - password: c.Password, - httpClient: &http.Client{Timeout: c.Timeout, Transport: tr}, - userAgent: c.UserAgent, - precision: c.Precision, - } - if client.userAgent == "" { - client.userAgent = "InfluxDBClient" - } - return &client, nil -} - -// SetAuth will update the username and passwords -func (c *Client) SetAuth(u, p string) { - c.username = u - c.password = p -} - -// SetPrecision will update the precision -func (c *Client) SetPrecision(precision string) { - c.precision = precision -} - -// Query sends a command to the server and returns the Response -func (c *Client) Query(q Query) (*Response, error) { - return c.QueryContext(context.Background(), q) -} - -// QueryContext sends a command to the server and returns the Response -// It uses a context that can be cancelled by the command line client -func (c *Client) QueryContext(ctx context.Context, q Query) (*Response, error) { - u := c.url - u.Path = path.Join(u.Path, "query") - - values := u.Query() - values.Set("q", q.Command) - values.Set("db", q.Database) - if q.Chunked { - values.Set("chunked", "true") - if q.ChunkSize > 0 { - values.Set("chunk_size", strconv.Itoa(q.ChunkSize)) - } - } - if q.NodeID > 0 { - values.Set("node_id", strconv.Itoa(q.NodeID)) - } - if c.precision != "" { - values.Set("epoch", c.precision) - } - u.RawQuery = values.Encode() - - req, err := http.NewRequest("POST", u.String(), nil) - if err != nil { - return nil, err - } - req.Header.Set("User-Agent", c.userAgent) - if c.username != "" { - req.SetBasicAuth(c.username, c.password) - } - - req = req.WithContext(ctx) - - resp, err := c.httpClient.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - var response Response - if q.Chunked { - cr := NewChunkedResponse(resp.Body) - for { - r, err := cr.NextResponse() - if err != nil { - // If we got an error while decoding the response, send that back. - return nil, err - } - - if r == nil { - break - } - - response.Results = append(response.Results, r.Results...) - if r.Err != nil { - response.Err = r.Err - break - } - } - } else { - dec := json.NewDecoder(resp.Body) - dec.UseNumber() - if err := dec.Decode(&response); err != nil { - // Ignore EOF errors if we got an invalid status code. - if !(err == io.EOF && resp.StatusCode != http.StatusOK) { - return nil, err - } - } - } - - // If we don't have an error in our json response, and didn't get StatusOK, - // then send back an error. - if resp.StatusCode != http.StatusOK && response.Error() == nil { - return &response, fmt.Errorf("received status code %d from server", resp.StatusCode) - } - return &response, nil -} - -// Write takes BatchPoints and allows for writing of multiple points with defaults -// If successful, error is nil and Response is nil -// If an error occurs, Response may contain additional information if populated. -func (c *Client) Write(bp BatchPoints) (*Response, error) { - u := c.url - u.Path = path.Join(u.Path, "write") - - var b bytes.Buffer - for _, p := range bp.Points { - err := checkPointTypes(p) - if err != nil { - return nil, err - } - if p.Raw != "" { - if _, err := b.WriteString(p.Raw); err != nil { - return nil, err - } - } else { - for k, v := range bp.Tags { - if p.Tags == nil { - p.Tags = make(map[string]string, len(bp.Tags)) - } - p.Tags[k] = v - } - - if _, err := b.WriteString(p.MarshalString()); err != nil { - return nil, err - } - } - - if err := b.WriteByte('\n'); err != nil { - return nil, err - } - } - - req, err := http.NewRequest("POST", u.String(), &b) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", "") - req.Header.Set("User-Agent", c.userAgent) - if c.username != "" { - req.SetBasicAuth(c.username, c.password) - } - - precision := bp.Precision - if precision == "" { - precision = c.precision - } - - params := req.URL.Query() - params.Set("db", bp.Database) - params.Set("rp", bp.RetentionPolicy) - params.Set("precision", precision) - params.Set("consistency", bp.WriteConsistency) - req.URL.RawQuery = params.Encode() - - resp, err := c.httpClient.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - var response Response - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK { - var err = fmt.Errorf(string(body)) - response.Err = err - return &response, err - } - - return nil, nil -} - -// WriteLineProtocol takes a string with line returns to delimit each write -// If successful, error is nil and Response is nil -// If an error occurs, Response may contain additional information if populated. -func (c *Client) WriteLineProtocol(data, database, retentionPolicy, precision, writeConsistency string) (*Response, error) { - u := c.url - u.Path = path.Join(u.Path, "write") - - r := strings.NewReader(data) - - req, err := http.NewRequest("POST", u.String(), r) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", "") - req.Header.Set("User-Agent", c.userAgent) - if c.username != "" { - req.SetBasicAuth(c.username, c.password) - } - params := req.URL.Query() - params.Set("db", database) - params.Set("rp", retentionPolicy) - params.Set("precision", precision) - params.Set("consistency", writeConsistency) - req.URL.RawQuery = params.Encode() - - resp, err := c.httpClient.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - var response Response - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK { - err := fmt.Errorf(string(body)) - response.Err = err - return &response, err - } - - return nil, nil -} - -// Ping will check to see if the server is up -// Ping returns how long the request took, the version of the server it connected to, and an error if one occurred. -func (c *Client) Ping() (time.Duration, string, error) { - now := time.Now() - - u := c.url - u.Path = path.Join(u.Path, "ping") - - req, err := http.NewRequest("GET", u.String(), nil) - if err != nil { - return 0, "", err - } - req.Header.Set("User-Agent", c.userAgent) - if c.username != "" { - req.SetBasicAuth(c.username, c.password) - } - - resp, err := c.httpClient.Do(req) - if err != nil { - return 0, "", err - } - defer resp.Body.Close() - - version := resp.Header.Get("X-Influxdb-Version") - return time.Since(now), version, nil -} - -// Structs - -// Message represents a user message. -type Message struct { - Level string `json:"level,omitempty"` - Text string `json:"text,omitempty"` -} - -// Result represents a resultset returned from a single statement. -type Result struct { - Series []models.Row - Messages []*Message - Err error -} - -// MarshalJSON encodes the result into JSON. -func (r *Result) MarshalJSON() ([]byte, error) { - // Define a struct that outputs "error" as a string. - var o struct { - Series []models.Row `json:"series,omitempty"` - Messages []*Message `json:"messages,omitempty"` - Err string `json:"error,omitempty"` - } - - // Copy fields to output struct. - o.Series = r.Series - o.Messages = r.Messages - if r.Err != nil { - o.Err = r.Err.Error() - } - - return json.Marshal(&o) -} - -// UnmarshalJSON decodes the data into the Result struct -func (r *Result) UnmarshalJSON(b []byte) error { - var o struct { - Series []models.Row `json:"series,omitempty"` - Messages []*Message `json:"messages,omitempty"` - Err string `json:"error,omitempty"` - } - - dec := json.NewDecoder(bytes.NewBuffer(b)) - dec.UseNumber() - err := dec.Decode(&o) - if err != nil { - return err - } - r.Series = o.Series - r.Messages = o.Messages - if o.Err != "" { - r.Err = errors.New(o.Err) - } - return nil -} - -// Response represents a list of statement results. -type Response struct { - Results []Result - Err error -} - -// MarshalJSON encodes the response into JSON. -func (r *Response) MarshalJSON() ([]byte, error) { - // Define a struct that outputs "error" as a string. - var o struct { - Results []Result `json:"results,omitempty"` - Err string `json:"error,omitempty"` - } - - // Copy fields to output struct. - o.Results = r.Results - if r.Err != nil { - o.Err = r.Err.Error() - } - - return json.Marshal(&o) -} - -// UnmarshalJSON decodes the data into the Response struct -func (r *Response) UnmarshalJSON(b []byte) error { - var o struct { - Results []Result `json:"results,omitempty"` - Err string `json:"error,omitempty"` - } - - dec := json.NewDecoder(bytes.NewBuffer(b)) - dec.UseNumber() - err := dec.Decode(&o) - if err != nil { - return err - } - r.Results = o.Results - if o.Err != "" { - r.Err = errors.New(o.Err) - } - return nil -} - -// Error returns the first error from any statement. -// Returns nil if no errors occurred on any statements. -func (r *Response) Error() error { - if r.Err != nil { - return r.Err - } - for _, result := range r.Results { - if result.Err != nil { - return result.Err - } - } - return nil -} - -// duplexReader reads responses and writes it to another writer while -// satisfying the reader interface. -type duplexReader struct { - r io.Reader - w io.Writer -} - -func (r *duplexReader) Read(p []byte) (n int, err error) { - n, err = r.r.Read(p) - if err == nil { - r.w.Write(p[:n]) - } - return n, err -} - -// ChunkedResponse represents a response from the server that -// uses chunking to stream the output. -type ChunkedResponse struct { - dec *json.Decoder - duplex *duplexReader - buf bytes.Buffer -} - -// NewChunkedResponse reads a stream and produces responses from the stream. -func NewChunkedResponse(r io.Reader) *ChunkedResponse { - resp := &ChunkedResponse{} - resp.duplex = &duplexReader{r: r, w: &resp.buf} - resp.dec = json.NewDecoder(resp.duplex) - resp.dec.UseNumber() - return resp -} - -// NextResponse reads the next line of the stream and returns a response. -func (r *ChunkedResponse) NextResponse() (*Response, error) { - var response Response - if err := r.dec.Decode(&response); err != nil { - if err == io.EOF { - return nil, nil - } - // A decoding error happened. This probably means the server crashed - // and sent a last-ditch error message to us. Ensure we have read the - // entirety of the connection to get any remaining error text. - io.Copy(ioutil.Discard, r.duplex) - return nil, errors.New(strings.TrimSpace(r.buf.String())) - } - r.buf.Reset() - return &response, nil -} - -// Point defines the fields that will be written to the database -// Measurement, Time, and Fields are required -// Precision can be specified if the time is in epoch format (integer). -// Valid values for Precision are n, u, ms, s, m, and h -type Point struct { - Measurement string - Tags map[string]string - Time time.Time - Fields map[string]interface{} - Precision string - Raw string -} - -// MarshalJSON will format the time in RFC3339Nano -// Precision is also ignored as it is only used for writing, not reading -// Or another way to say it is we always send back in nanosecond precision -func (p *Point) MarshalJSON() ([]byte, error) { - point := struct { - Measurement string `json:"measurement,omitempty"` - Tags map[string]string `json:"tags,omitempty"` - Time string `json:"time,omitempty"` - Fields map[string]interface{} `json:"fields,omitempty"` - Precision string `json:"precision,omitempty"` - }{ - Measurement: p.Measurement, - Tags: p.Tags, - Fields: p.Fields, - Precision: p.Precision, - } - // Let it omit empty if it's really zero - if !p.Time.IsZero() { - point.Time = p.Time.UTC().Format(time.RFC3339Nano) - } - return json.Marshal(&point) -} - -// MarshalString renders string representation of a Point with specified -// precision. The default precision is nanoseconds. -func (p *Point) MarshalString() string { - pt, err := models.NewPoint(p.Measurement, models.NewTags(p.Tags), p.Fields, p.Time) - if err != nil { - return "# ERROR: " + err.Error() + " " + p.Measurement - } - if p.Precision == "" || p.Precision == "ns" || p.Precision == "n" { - return pt.String() - } - return pt.PrecisionString(p.Precision) -} - -// UnmarshalJSON decodes the data into the Point struct -func (p *Point) UnmarshalJSON(b []byte) error { - var normal struct { - Measurement string `json:"measurement"` - Tags map[string]string `json:"tags"` - Time time.Time `json:"time"` - Precision string `json:"precision"` - Fields map[string]interface{} `json:"fields"` - } - var epoch struct { - Measurement string `json:"measurement"` - Tags map[string]string `json:"tags"` - Time *int64 `json:"time"` - Precision string `json:"precision"` - Fields map[string]interface{} `json:"fields"` - } - - if err := func() error { - var err error - dec := json.NewDecoder(bytes.NewBuffer(b)) - dec.UseNumber() - if err = dec.Decode(&epoch); err != nil { - return err - } - // Convert from epoch to time.Time, but only if Time - // was actually set. - var ts time.Time - if epoch.Time != nil { - ts, err = EpochToTime(*epoch.Time, epoch.Precision) - if err != nil { - return err - } - } - p.Measurement = epoch.Measurement - p.Tags = epoch.Tags - p.Time = ts - p.Precision = epoch.Precision - p.Fields = normalizeFields(epoch.Fields) - return nil - }(); err == nil { - return nil - } - - dec := json.NewDecoder(bytes.NewBuffer(b)) - dec.UseNumber() - if err := dec.Decode(&normal); err != nil { - return err - } - normal.Time = SetPrecision(normal.Time, normal.Precision) - p.Measurement = normal.Measurement - p.Tags = normal.Tags - p.Time = normal.Time - p.Precision = normal.Precision - p.Fields = normalizeFields(normal.Fields) - - return nil -} - -// Remove any notion of json.Number -func normalizeFields(fields map[string]interface{}) map[string]interface{} { - newFields := map[string]interface{}{} - - for k, v := range fields { - switch v := v.(type) { - case json.Number: - jv, e := v.Float64() - if e != nil { - panic(fmt.Sprintf("unable to convert json.Number to float64: %s", e)) - } - newFields[k] = jv - default: - newFields[k] = v - } - } - return newFields -} - -// BatchPoints is used to send batched data in a single write. -// Database and Points are required -// If no retention policy is specified, it will use the databases default retention policy. -// If tags are specified, they will be "merged" with all points. If a point already has that tag, it will be ignored. -// If time is specified, it will be applied to any point with an empty time. -// Precision can be specified if the time is in epoch format (integer). -// Valid values for Precision are n, u, ms, s, m, and h -type BatchPoints struct { - Points []Point `json:"points,omitempty"` - Database string `json:"database,omitempty"` - RetentionPolicy string `json:"retentionPolicy,omitempty"` - Tags map[string]string `json:"tags,omitempty"` - Time time.Time `json:"time,omitempty"` - Precision string `json:"precision,omitempty"` - WriteConsistency string `json:"-"` -} - -// UnmarshalJSON decodes the data into the BatchPoints struct -func (bp *BatchPoints) UnmarshalJSON(b []byte) error { - var normal struct { - Points []Point `json:"points"` - Database string `json:"database"` - RetentionPolicy string `json:"retentionPolicy"` - Tags map[string]string `json:"tags"` - Time time.Time `json:"time"` - Precision string `json:"precision"` - } - var epoch struct { - Points []Point `json:"points"` - Database string `json:"database"` - RetentionPolicy string `json:"retentionPolicy"` - Tags map[string]string `json:"tags"` - Time *int64 `json:"time"` - Precision string `json:"precision"` - } - - if err := func() error { - var err error - if err = json.Unmarshal(b, &epoch); err != nil { - return err - } - // Convert from epoch to time.Time - var ts time.Time - if epoch.Time != nil { - ts, err = EpochToTime(*epoch.Time, epoch.Precision) - if err != nil { - return err - } - } - bp.Points = epoch.Points - bp.Database = epoch.Database - bp.RetentionPolicy = epoch.RetentionPolicy - bp.Tags = epoch.Tags - bp.Time = ts - bp.Precision = epoch.Precision - return nil - }(); err == nil { - return nil - } - - if err := json.Unmarshal(b, &normal); err != nil { - return err - } - normal.Time = SetPrecision(normal.Time, normal.Precision) - bp.Points = normal.Points - bp.Database = normal.Database - bp.RetentionPolicy = normal.RetentionPolicy - bp.Tags = normal.Tags - bp.Time = normal.Time - bp.Precision = normal.Precision - - return nil -} - -// utility functions - -// Addr provides the current url as a string of the server the client is connected to. -func (c *Client) Addr() string { - if c.unixSocket != "" { - return c.unixSocket - } - return c.url.String() -} - -// checkPointTypes ensures no unsupported types are submitted to influxdb, returning error if they are found. -func checkPointTypes(p Point) error { - for _, v := range p.Fields { - switch v.(type) { - case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool, string, nil: - return nil - default: - return fmt.Errorf("unsupported point type: %T", v) - } - } - return nil -} - -// helper functions - -// EpochToTime takes a unix epoch time and uses precision to return back a time.Time -func EpochToTime(epoch int64, precision string) (time.Time, error) { - if precision == "" { - precision = "s" - } - var t time.Time - switch precision { - case "h": - t = time.Unix(0, epoch*int64(time.Hour)) - case "m": - t = time.Unix(0, epoch*int64(time.Minute)) - case "s": - t = time.Unix(0, epoch*int64(time.Second)) - case "ms": - t = time.Unix(0, epoch*int64(time.Millisecond)) - case "u": - t = time.Unix(0, epoch*int64(time.Microsecond)) - case "n": - t = time.Unix(0, epoch) - default: - return time.Time{}, fmt.Errorf("Unknown precision %q", precision) - } - return t, nil -} - -// SetPrecision will round a time to the specified precision -func SetPrecision(t time.Time, precision string) time.Time { - switch precision { - case "n": - case "u": - return t.Round(time.Microsecond) - case "ms": - return t.Round(time.Millisecond) - case "s": - return t.Round(time.Second) - case "m": - return t.Round(time.Minute) - case "h": - return t.Round(time.Hour) - } - return t -} diff --git a/vendor/github.com/influxdata/influxdb/models/consistency.go b/vendor/github.com/influxdata/influxdb/models/consistency.go deleted file mode 100644 index 2a3269bca..000000000 --- a/vendor/github.com/influxdata/influxdb/models/consistency.go +++ /dev/null @@ -1,48 +0,0 @@ -package models - -import ( - "errors" - "strings" -) - -// ConsistencyLevel represent a required replication criteria before a write can -// be returned as successful. -// -// The consistency level is handled in open-source InfluxDB but only applicable to clusters. -type ConsistencyLevel int - -const ( - // ConsistencyLevelAny allows for hinted handoff, potentially no write happened yet. - ConsistencyLevelAny ConsistencyLevel = iota - - // ConsistencyLevelOne requires at least one data node acknowledged a write. - ConsistencyLevelOne - - // ConsistencyLevelQuorum requires a quorum of data nodes to acknowledge a write. - ConsistencyLevelQuorum - - // ConsistencyLevelAll requires all data nodes to acknowledge a write. - ConsistencyLevelAll -) - -var ( - // ErrInvalidConsistencyLevel is returned when parsing the string version - // of a consistency level. - ErrInvalidConsistencyLevel = errors.New("invalid consistency level") -) - -// ParseConsistencyLevel converts a consistency level string to the corresponding ConsistencyLevel const. -func ParseConsistencyLevel(level string) (ConsistencyLevel, error) { - switch strings.ToLower(level) { - case "any": - return ConsistencyLevelAny, nil - case "one": - return ConsistencyLevelOne, nil - case "quorum": - return ConsistencyLevelQuorum, nil - case "all": - return ConsistencyLevelAll, nil - default: - return 0, ErrInvalidConsistencyLevel - } -} diff --git a/vendor/github.com/influxdata/influxdb/models/inline_fnv.go b/vendor/github.com/influxdata/influxdb/models/inline_fnv.go deleted file mode 100644 index eec1ae8b0..000000000 --- a/vendor/github.com/influxdata/influxdb/models/inline_fnv.go +++ /dev/null @@ -1,32 +0,0 @@ -package models // import "github.com/influxdata/influxdb/models" - -// from stdlib hash/fnv/fnv.go -const ( - prime64 = 1099511628211 - offset64 = 14695981039346656037 -) - -// InlineFNV64a is an alloc-free port of the standard library's fnv64a. -// See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function. -type InlineFNV64a uint64 - -// NewInlineFNV64a returns a new instance of InlineFNV64a. -func NewInlineFNV64a() InlineFNV64a { - return offset64 -} - -// Write adds data to the running hash. -func (s *InlineFNV64a) Write(data []byte) (int, error) { - hash := uint64(*s) - for _, c := range data { - hash ^= uint64(c) - hash *= prime64 - } - *s = InlineFNV64a(hash) - return len(data), nil -} - -// Sum64 returns the uint64 of the current resulting hash. -func (s *InlineFNV64a) Sum64() uint64 { - return uint64(*s) -} diff --git a/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go b/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go deleted file mode 100644 index 8db483738..000000000 --- a/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go +++ /dev/null @@ -1,44 +0,0 @@ -package models // import "github.com/influxdata/influxdb/models" - -import ( - "reflect" - "strconv" - "unsafe" -) - -// parseIntBytes is a zero-alloc wrapper around strconv.ParseInt. -func parseIntBytes(b []byte, base int, bitSize int) (i int64, err error) { - s := unsafeBytesToString(b) - return strconv.ParseInt(s, base, bitSize) -} - -// parseUintBytes is a zero-alloc wrapper around strconv.ParseUint. -func parseUintBytes(b []byte, base int, bitSize int) (i uint64, err error) { - s := unsafeBytesToString(b) - return strconv.ParseUint(s, base, bitSize) -} - -// parseFloatBytes is a zero-alloc wrapper around strconv.ParseFloat. -func parseFloatBytes(b []byte, bitSize int) (float64, error) { - s := unsafeBytesToString(b) - return strconv.ParseFloat(s, bitSize) -} - -// parseBoolBytes is a zero-alloc wrapper around strconv.ParseBool. -func parseBoolBytes(b []byte) (bool, error) { - return strconv.ParseBool(unsafeBytesToString(b)) -} - -// unsafeBytesToString converts a []byte to a string without a heap allocation. -// -// It is unsafe, and is intended to prepare input to short-lived functions -// that require strings. -func unsafeBytesToString(in []byte) string { - src := *(*reflect.SliceHeader)(unsafe.Pointer(&in)) - dst := reflect.StringHeader{ - Data: src.Data, - Len: src.Len, - } - s := *(*string)(unsafe.Pointer(&dst)) - return s -} diff --git a/vendor/github.com/influxdata/influxdb/models/points.go b/vendor/github.com/influxdata/influxdb/models/points.go deleted file mode 100644 index 7cfebd071..000000000 --- a/vendor/github.com/influxdata/influxdb/models/points.go +++ /dev/null @@ -1,2328 +0,0 @@ -// Package models implements basic objects used throughout the TICK stack. -package models // import "github.com/influxdata/influxdb/models" - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "io" - "math" - "sort" - "strconv" - "strings" - "time" - - "github.com/influxdata/influxdb/pkg/escape" -) - -var ( - measurementEscapeCodes = map[byte][]byte{ - ',': []byte(`\,`), - ' ': []byte(`\ `), - } - - tagEscapeCodes = map[byte][]byte{ - ',': []byte(`\,`), - ' ': []byte(`\ `), - '=': []byte(`\=`), - } - - // ErrPointMustHaveAField is returned when operating on a point that does not have any fields. - ErrPointMustHaveAField = errors.New("point without fields is unsupported") - - // ErrInvalidNumber is returned when a number is expected but not provided. - ErrInvalidNumber = errors.New("invalid number") - - // ErrInvalidPoint is returned when a point cannot be parsed correctly. - ErrInvalidPoint = errors.New("point is invalid") -) - -const ( - // MaxKeyLength is the largest allowed size of the combined measurement and tag keys. - MaxKeyLength = 65535 -) - -// enableUint64Support will enable uint64 support if set to true. -var enableUint64Support = false - -// EnableUintSupport manually enables uint support for the point parser. -// This function will be removed in the future and only exists for unit tests during the -// transition. -func EnableUintSupport() { - enableUint64Support = true -} - -// Point defines the values that will be written to the database. -type Point interface { - // Name return the measurement name for the point. - Name() []byte - - // SetName updates the measurement name for the point. - SetName(string) - - // Tags returns the tag set for the point. - Tags() Tags - - // AddTag adds or replaces a tag value for a point. - AddTag(key, value string) - - // SetTags replaces the tags for the point. - SetTags(tags Tags) - - // HasTag returns true if the tag exists for the point. - HasTag(tag []byte) bool - - // Fields returns the fields for the point. - Fields() (Fields, error) - - // Time return the timestamp for the point. - Time() time.Time - - // SetTime updates the timestamp for the point. - SetTime(t time.Time) - - // UnixNano returns the timestamp of the point as nanoseconds since Unix epoch. - UnixNano() int64 - - // HashID returns a non-cryptographic checksum of the point's key. - HashID() uint64 - - // Key returns the key (measurement joined with tags) of the point. - Key() []byte - - // String returns a string representation of the point. If there is a - // timestamp associated with the point then it will be specified with the default - // precision of nanoseconds. - String() string - - // MarshalBinary returns a binary representation of the point. - MarshalBinary() ([]byte, error) - - // PrecisionString returns a string representation of the point. If there - // is a timestamp associated with the point then it will be specified in the - // given unit. - PrecisionString(precision string) string - - // RoundedString returns a string representation of the point. If there - // is a timestamp associated with the point, then it will be rounded to the - // given duration. - RoundedString(d time.Duration) string - - // Split will attempt to return multiple points with the same timestamp whose - // string representations are no longer than size. Points with a single field or - // a point without a timestamp may exceed the requested size. - Split(size int) []Point - - // Round will round the timestamp of the point to the given duration. - Round(d time.Duration) - - // StringSize returns the length of the string that would be returned by String(). - StringSize() int - - // AppendString appends the result of String() to the provided buffer and returns - // the result, potentially reducing string allocations. - AppendString(buf []byte) []byte - - // FieldIterator retuns a FieldIterator that can be used to traverse the - // fields of a point without constructing the in-memory map. - FieldIterator() FieldIterator -} - -// FieldType represents the type of a field. -type FieldType int - -const ( - // Integer indicates the field's type is integer. - Integer FieldType = iota - - // Float indicates the field's type is float. - Float - - // Boolean indicates the field's type is boolean. - Boolean - - // String indicates the field's type is string. - String - - // Empty is used to indicate that there is no field. - Empty - - // Unsigned indicates the field's type is an unsigned integer. - Unsigned -) - -// FieldIterator provides a low-allocation interface to iterate through a point's fields. -type FieldIterator interface { - // Next indicates whether there any fields remaining. - Next() bool - - // FieldKey returns the key of the current field. - FieldKey() []byte - - // Type returns the FieldType of the current field. - Type() FieldType - - // StringValue returns the string value of the current field. - StringValue() string - - // IntegerValue returns the integer value of the current field. - IntegerValue() (int64, error) - - // UnsignedValue returns the unsigned value of the current field. - UnsignedValue() (uint64, error) - - // BooleanValue returns the boolean value of the current field. - BooleanValue() (bool, error) - - // FloatValue returns the float value of the current field. - FloatValue() (float64, error) - - // Reset resets the iterator to its initial state. - Reset() -} - -// Points represents a sortable list of points by timestamp. -type Points []Point - -// Len implements sort.Interface. -func (a Points) Len() int { return len(a) } - -// Less implements sort.Interface. -func (a Points) Less(i, j int) bool { return a[i].Time().Before(a[j].Time()) } - -// Swap implements sort.Interface. -func (a Points) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -// point is the default implementation of Point. -type point struct { - time time.Time - - // text encoding of measurement and tags - // key must always be stored sorted by tags, if the original line was not sorted, - // we need to resort it - key []byte - - // text encoding of field data - fields []byte - - // text encoding of timestamp - ts []byte - - // cached version of parsed fields from data - cachedFields map[string]interface{} - - // cached version of parsed name from key - cachedName string - - // cached version of parsed tags - cachedTags Tags - - it fieldIterator -} - -// type assertions -var ( - _ Point = (*point)(nil) - _ FieldIterator = (*point)(nil) -) - -const ( - // the number of characters for the largest possible int64 (9223372036854775807) - maxInt64Digits = 19 - - // the number of characters for the smallest possible int64 (-9223372036854775808) - minInt64Digits = 20 - - // the number of characters for the largest possible uint64 (18446744073709551615) - maxUint64Digits = 20 - - // the number of characters required for the largest float64 before a range check - // would occur during parsing - maxFloat64Digits = 25 - - // the number of characters required for smallest float64 before a range check occur - // would occur during parsing - minFloat64Digits = 27 -) - -// ParsePoints returns a slice of Points from a text representation of a point -// with each point separated by newlines. If any points fail to parse, a non-nil error -// will be returned in addition to the points that parsed successfully. -func ParsePoints(buf []byte) ([]Point, error) { - return ParsePointsWithPrecision(buf, time.Now().UTC(), "n") -} - -// ParsePointsString is identical to ParsePoints but accepts a string. -func ParsePointsString(buf string) ([]Point, error) { - return ParsePoints([]byte(buf)) -} - -// ParseKey returns the measurement name and tags from a point. -// -// NOTE: to minimize heap allocations, the returned Tags will refer to subslices of buf. -// This can have the unintended effect preventing buf from being garbage collected. -func ParseKey(buf []byte) (string, Tags) { - meas, tags := ParseKeyBytes(buf) - return string(meas), tags -} - -func ParseKeyBytes(buf []byte) ([]byte, Tags) { - // Ignore the error because scanMeasurement returns "missing fields" which we ignore - // when just parsing a key - state, i, _ := scanMeasurement(buf, 0) - - var tags Tags - if state == tagKeyState { - tags = parseTags(buf) - // scanMeasurement returns the location of the comma if there are tags, strip that off - return buf[:i-1], tags - } - return buf[:i], tags -} - -func ParseTags(buf []byte) Tags { - return parseTags(buf) -} - -func ParseName(buf []byte) ([]byte, error) { - // Ignore the error because scanMeasurement returns "missing fields" which we ignore - // when just parsing a key - state, i, _ := scanMeasurement(buf, 0) - if state == tagKeyState { - return buf[:i-1], nil - } - return buf[:i], nil -} - -// ParsePointsWithPrecision is similar to ParsePoints, but allows the -// caller to provide a precision for time. -// -// NOTE: to minimize heap allocations, the returned Points will refer to subslices of buf. -// This can have the unintended effect preventing buf from being garbage collected. -func ParsePointsWithPrecision(buf []byte, defaultTime time.Time, precision string) ([]Point, error) { - points := make([]Point, 0, bytes.Count(buf, []byte{'\n'})+1) - var ( - pos int - block []byte - failed []string - ) - for pos < len(buf) { - pos, block = scanLine(buf, pos) - pos++ - - if len(block) == 0 { - continue - } - - // lines which start with '#' are comments - start := skipWhitespace(block, 0) - - // If line is all whitespace, just skip it - if start >= len(block) { - continue - } - - if block[start] == '#' { - continue - } - - // strip the newline if one is present - if block[len(block)-1] == '\n' { - block = block[:len(block)-1] - } - - pt, err := parsePoint(block[start:], defaultTime, precision) - if err != nil { - failed = append(failed, fmt.Sprintf("unable to parse '%s': %v", string(block[start:]), err)) - } else { - points = append(points, pt) - } - - } - if len(failed) > 0 { - return points, fmt.Errorf("%s", strings.Join(failed, "\n")) - } - return points, nil - -} - -func parsePoint(buf []byte, defaultTime time.Time, precision string) (Point, error) { - // scan the first block which is measurement[,tag1=value1,tag2=value=2...] - pos, key, err := scanKey(buf, 0) - if err != nil { - return nil, err - } - - // measurement name is required - if len(key) == 0 { - return nil, fmt.Errorf("missing measurement") - } - - if len(key) > MaxKeyLength { - return nil, fmt.Errorf("max key length exceeded: %v > %v", len(key), MaxKeyLength) - } - - // scan the second block is which is field1=value1[,field2=value2,...] - pos, fields, err := scanFields(buf, pos) - if err != nil { - return nil, err - } - - // at least one field is required - if len(fields) == 0 { - return nil, fmt.Errorf("missing fields") - } - - var maxKeyErr error - walkFields(fields, func(k, v []byte) bool { - if sz := seriesKeySize(key, k); sz > MaxKeyLength { - maxKeyErr = fmt.Errorf("max key length exceeded: %v > %v", sz, MaxKeyLength) - return false - } - return true - }) - - if maxKeyErr != nil { - return nil, maxKeyErr - } - - // scan the last block which is an optional integer timestamp - pos, ts, err := scanTime(buf, pos) - if err != nil { - return nil, err - } - - pt := &point{ - key: key, - fields: fields, - ts: ts, - } - - if len(ts) == 0 { - pt.time = defaultTime - pt.SetPrecision(precision) - } else { - ts, err := parseIntBytes(ts, 10, 64) - if err != nil { - return nil, err - } - pt.time, err = SafeCalcTime(ts, precision) - if err != nil { - return nil, err - } - - // Determine if there are illegal non-whitespace characters after the - // timestamp block. - for pos < len(buf) { - if buf[pos] != ' ' { - return nil, ErrInvalidPoint - } - pos++ - } - } - return pt, nil -} - -// GetPrecisionMultiplier will return a multiplier for the precision specified. -func GetPrecisionMultiplier(precision string) int64 { - d := time.Nanosecond - switch precision { - case "u": - d = time.Microsecond - case "ms": - d = time.Millisecond - case "s": - d = time.Second - case "m": - d = time.Minute - case "h": - d = time.Hour - } - return int64(d) -} - -// scanKey scans buf starting at i for the measurement and tag portion of the point. -// It returns the ending position and the byte slice of key within buf. If there -// are tags, they will be sorted if they are not already. -func scanKey(buf []byte, i int) (int, []byte, error) { - start := skipWhitespace(buf, i) - - i = start - - // Determines whether the tags are sort, assume they are - sorted := true - - // indices holds the indexes within buf of the start of each tag. For example, - // a buf of 'cpu,host=a,region=b,zone=c' would have indices slice of [4,11,20] - // which indicates that the first tag starts at buf[4], seconds at buf[11], and - // last at buf[20] - indices := make([]int, 100) - - // tracks how many commas we've seen so we know how many values are indices. - // Since indices is an arbitrarily large slice, - // we need to know how many values in the buffer are in use. - commas := 0 - - // First scan the Point's measurement. - state, i, err := scanMeasurement(buf, i) - if err != nil { - return i, buf[start:i], err - } - - // Optionally scan tags if needed. - if state == tagKeyState { - i, commas, indices, err = scanTags(buf, i, indices) - if err != nil { - return i, buf[start:i], err - } - } - - // Now we know where the key region is within buf, and the location of tags, we - // need to determine if duplicate tags exist and if the tags are sorted. This iterates - // over the list comparing each tag in the sequence with each other. - for j := 0; j < commas-1; j++ { - // get the left and right tags - _, left := scanTo(buf[indices[j]:indices[j+1]-1], 0, '=') - _, right := scanTo(buf[indices[j+1]:indices[j+2]-1], 0, '=') - - // If left is greater than right, the tags are not sorted. We do not have to - // continue because the short path no longer works. - // If the tags are equal, then there are duplicate tags, and we should abort. - // If the tags are not sorted, this pass may not find duplicate tags and we - // need to do a more exhaustive search later. - if cmp := bytes.Compare(left, right); cmp > 0 { - sorted = false - break - } else if cmp == 0 { - return i, buf[start:i], fmt.Errorf("duplicate tags") - } - } - - // If the tags are not sorted, then sort them. This sort is inline and - // uses the tag indices we created earlier. The actual buffer is not sorted, the - // indices are using the buffer for value comparison. After the indices are sorted, - // the buffer is reconstructed from the sorted indices. - if !sorted && commas > 0 { - // Get the measurement name for later - measurement := buf[start : indices[0]-1] - - // Sort the indices - indices := indices[:commas] - insertionSort(0, commas, buf, indices) - - // Create a new key using the measurement and sorted indices - b := make([]byte, len(buf[start:i])) - pos := copy(b, measurement) - for _, i := range indices { - b[pos] = ',' - pos++ - _, v := scanToSpaceOr(buf, i, ',') - pos += copy(b[pos:], v) - } - - // Check again for duplicate tags now that the tags are sorted. - for j := 0; j < commas-1; j++ { - // get the left and right tags - _, left := scanTo(buf[indices[j]:], 0, '=') - _, right := scanTo(buf[indices[j+1]:], 0, '=') - - // If the tags are equal, then there are duplicate tags, and we should abort. - // If the tags are not sorted, this pass may not find duplicate tags and we - // need to do a more exhaustive search later. - if bytes.Equal(left, right) { - return i, b, fmt.Errorf("duplicate tags") - } - } - - return i, b, nil - } - - return i, buf[start:i], nil -} - -// The following constants allow us to specify which state to move to -// next, when scanning sections of a Point. -const ( - tagKeyState = iota - tagValueState - fieldsState -) - -// scanMeasurement examines the measurement part of a Point, returning -// the next state to move to, and the current location in the buffer. -func scanMeasurement(buf []byte, i int) (int, int, error) { - // Check first byte of measurement, anything except a comma is fine. - // It can't be a space, since whitespace is stripped prior to this - // function call. - if i >= len(buf) || buf[i] == ',' { - return -1, i, fmt.Errorf("missing measurement") - } - - for { - i++ - if i >= len(buf) { - // cpu - return -1, i, fmt.Errorf("missing fields") - } - - if buf[i-1] == '\\' { - // Skip character (it's escaped). - continue - } - - // Unescaped comma; move onto scanning the tags. - if buf[i] == ',' { - return tagKeyState, i + 1, nil - } - - // Unescaped space; move onto scanning the fields. - if buf[i] == ' ' { - // cpu value=1.0 - return fieldsState, i, nil - } - } -} - -// scanTags examines all the tags in a Point, keeping track of and -// returning the updated indices slice, number of commas and location -// in buf where to start examining the Point fields. -func scanTags(buf []byte, i int, indices []int) (int, int, []int, error) { - var ( - err error - commas int - state = tagKeyState - ) - - for { - switch state { - case tagKeyState: - // Grow our indices slice if we have too many tags. - if commas >= len(indices) { - newIndics := make([]int, cap(indices)*2) - copy(newIndics, indices) - indices = newIndics - } - indices[commas] = i - commas++ - - i, err = scanTagsKey(buf, i) - state = tagValueState // tag value always follows a tag key - case tagValueState: - state, i, err = scanTagsValue(buf, i) - case fieldsState: - indices[commas] = i + 1 - return i, commas, indices, nil - } - - if err != nil { - return i, commas, indices, err - } - } -} - -// scanTagsKey scans each character in a tag key. -func scanTagsKey(buf []byte, i int) (int, error) { - // First character of the key. - if i >= len(buf) || buf[i] == ' ' || buf[i] == ',' || buf[i] == '=' { - // cpu,{'', ' ', ',', '='} - return i, fmt.Errorf("missing tag key") - } - - // Examine each character in the tag key until we hit an unescaped - // equals (the tag value), or we hit an error (i.e., unescaped - // space or comma). - for { - i++ - - // Either we reached the end of the buffer or we hit an - // unescaped comma or space. - if i >= len(buf) || - ((buf[i] == ' ' || buf[i] == ',') && buf[i-1] != '\\') { - // cpu,tag{'', ' ', ','} - return i, fmt.Errorf("missing tag value") - } - - if buf[i] == '=' && buf[i-1] != '\\' { - // cpu,tag= - return i + 1, nil - } - } -} - -// scanTagsValue scans each character in a tag value. -func scanTagsValue(buf []byte, i int) (int, int, error) { - // Tag value cannot be empty. - if i >= len(buf) || buf[i] == ',' || buf[i] == ' ' { - // cpu,tag={',', ' '} - return -1, i, fmt.Errorf("missing tag value") - } - - // Examine each character in the tag value until we hit an unescaped - // comma (move onto next tag key), an unescaped space (move onto - // fields), or we error out. - for { - i++ - if i >= len(buf) { - // cpu,tag=value - return -1, i, fmt.Errorf("missing fields") - } - - // An unescaped equals sign is an invalid tag value. - if buf[i] == '=' && buf[i-1] != '\\' { - // cpu,tag={'=', 'fo=o'} - return -1, i, fmt.Errorf("invalid tag format") - } - - if buf[i] == ',' && buf[i-1] != '\\' { - // cpu,tag=foo, - return tagKeyState, i + 1, nil - } - - // cpu,tag=foo value=1.0 - // cpu, tag=foo\= value=1.0 - if buf[i] == ' ' && buf[i-1] != '\\' { - return fieldsState, i, nil - } - } -} - -func insertionSort(l, r int, buf []byte, indices []int) { - for i := l + 1; i < r; i++ { - for j := i; j > l && less(buf, indices, j, j-1); j-- { - indices[j], indices[j-1] = indices[j-1], indices[j] - } - } -} - -func less(buf []byte, indices []int, i, j int) bool { - // This grabs the tag names for i & j, it ignores the values - _, a := scanTo(buf, indices[i], '=') - _, b := scanTo(buf, indices[j], '=') - return bytes.Compare(a, b) < 0 -} - -// scanFields scans buf, starting at i for the fields section of a point. It returns -// the ending position and the byte slice of the fields within buf. -func scanFields(buf []byte, i int) (int, []byte, error) { - start := skipWhitespace(buf, i) - i = start - quoted := false - - // tracks how many '=' we've seen - equals := 0 - - // tracks how many commas we've seen - commas := 0 - - for { - // reached the end of buf? - if i >= len(buf) { - break - } - - // escaped characters? - if buf[i] == '\\' && i+1 < len(buf) { - i += 2 - continue - } - - // If the value is quoted, scan until we get to the end quote - // Only quote values in the field value since quotes are not significant - // in the field key - if buf[i] == '"' && equals > commas { - quoted = !quoted - i++ - continue - } - - // If we see an =, ensure that there is at least on char before and after it - if buf[i] == '=' && !quoted { - equals++ - - // check for "... =123" but allow "a\ =123" - if buf[i-1] == ' ' && buf[i-2] != '\\' { - return i, buf[start:i], fmt.Errorf("missing field key") - } - - // check for "...a=123,=456" but allow "a=123,a\,=456" - if buf[i-1] == ',' && buf[i-2] != '\\' { - return i, buf[start:i], fmt.Errorf("missing field key") - } - - // check for "... value=" - if i+1 >= len(buf) { - return i, buf[start:i], fmt.Errorf("missing field value") - } - - // check for "... value=,value2=..." - if buf[i+1] == ',' || buf[i+1] == ' ' { - return i, buf[start:i], fmt.Errorf("missing field value") - } - - if isNumeric(buf[i+1]) || buf[i+1] == '-' || buf[i+1] == 'N' || buf[i+1] == 'n' { - var err error - i, err = scanNumber(buf, i+1) - if err != nil { - return i, buf[start:i], err - } - continue - } - // If next byte is not a double-quote, the value must be a boolean - if buf[i+1] != '"' { - var err error - i, _, err = scanBoolean(buf, i+1) - if err != nil { - return i, buf[start:i], err - } - continue - } - } - - if buf[i] == ',' && !quoted { - commas++ - } - - // reached end of block? - if buf[i] == ' ' && !quoted { - break - } - i++ - } - - if quoted { - return i, buf[start:i], fmt.Errorf("unbalanced quotes") - } - - // check that all field sections had key and values (e.g. prevent "a=1,b" - if equals == 0 || commas != equals-1 { - return i, buf[start:i], fmt.Errorf("invalid field format") - } - - return i, buf[start:i], nil -} - -// scanTime scans buf, starting at i for the time section of a point. It -// returns the ending position and the byte slice of the timestamp within buf -// and and error if the timestamp is not in the correct numeric format. -func scanTime(buf []byte, i int) (int, []byte, error) { - start := skipWhitespace(buf, i) - i = start - - for { - // reached the end of buf? - if i >= len(buf) { - break - } - - // Reached end of block or trailing whitespace? - if buf[i] == '\n' || buf[i] == ' ' { - break - } - - // Handle negative timestamps - if i == start && buf[i] == '-' { - i++ - continue - } - - // Timestamps should be integers, make sure they are so we don't need - // to actually parse the timestamp until needed. - if buf[i] < '0' || buf[i] > '9' { - return i, buf[start:i], fmt.Errorf("bad timestamp") - } - i++ - } - return i, buf[start:i], nil -} - -func isNumeric(b byte) bool { - return (b >= '0' && b <= '9') || b == '.' -} - -// scanNumber returns the end position within buf, start at i after -// scanning over buf for an integer, or float. It returns an -// error if a invalid number is scanned. -func scanNumber(buf []byte, i int) (int, error) { - start := i - var isInt, isUnsigned bool - - // Is negative number? - if i < len(buf) && buf[i] == '-' { - i++ - // There must be more characters now, as just '-' is illegal. - if i == len(buf) { - return i, ErrInvalidNumber - } - } - - // how many decimal points we've see - decimal := false - - // indicates the number is float in scientific notation - scientific := false - - for { - if i >= len(buf) { - break - } - - if buf[i] == ',' || buf[i] == ' ' { - break - } - - if buf[i] == 'i' && i > start && !(isInt || isUnsigned) { - isInt = true - i++ - continue - } else if buf[i] == 'u' && i > start && !(isInt || isUnsigned) { - isUnsigned = true - i++ - continue - } - - if buf[i] == '.' { - // Can't have more than 1 decimal (e.g. 1.1.1 should fail) - if decimal { - return i, ErrInvalidNumber - } - decimal = true - } - - // `e` is valid for floats but not as the first char - if i > start && (buf[i] == 'e' || buf[i] == 'E') { - scientific = true - i++ - continue - } - - // + and - are only valid at this point if they follow an e (scientific notation) - if (buf[i] == '+' || buf[i] == '-') && (buf[i-1] == 'e' || buf[i-1] == 'E') { - i++ - continue - } - - // NaN is an unsupported value - if i+2 < len(buf) && (buf[i] == 'N' || buf[i] == 'n') { - return i, ErrInvalidNumber - } - - if !isNumeric(buf[i]) { - return i, ErrInvalidNumber - } - i++ - } - - if (isInt || isUnsigned) && (decimal || scientific) { - return i, ErrInvalidNumber - } - - numericDigits := i - start - if isInt { - numericDigits-- - } - if decimal { - numericDigits-- - } - if buf[start] == '-' { - numericDigits-- - } - - if numericDigits == 0 { - return i, ErrInvalidNumber - } - - // It's more common that numbers will be within min/max range for their type but we need to prevent - // out or range numbers from being parsed successfully. This uses some simple heuristics to decide - // if we should parse the number to the actual type. It does not do it all the time because it incurs - // extra allocations and we end up converting the type again when writing points to disk. - if isInt { - // Make sure the last char is an 'i' for integers (e.g. 9i10 is not valid) - if buf[i-1] != 'i' { - return i, ErrInvalidNumber - } - // Parse the int to check bounds the number of digits could be larger than the max range - // We subtract 1 from the index to remove the `i` from our tests - if len(buf[start:i-1]) >= maxInt64Digits || len(buf[start:i-1]) >= minInt64Digits { - if _, err := parseIntBytes(buf[start:i-1], 10, 64); err != nil { - return i, fmt.Errorf("unable to parse integer %s: %s", buf[start:i-1], err) - } - } - } else if isUnsigned { - // Return an error if uint64 support has not been enabled. - if !enableUint64Support { - return i, ErrInvalidNumber - } - // Make sure the last char is a 'u' for unsigned - if buf[i-1] != 'u' { - return i, ErrInvalidNumber - } - // Make sure the first char is not a '-' for unsigned - if buf[start] == '-' { - return i, ErrInvalidNumber - } - // Parse the uint to check bounds the number of digits could be larger than the max range - // We subtract 1 from the index to remove the `u` from our tests - if len(buf[start:i-1]) >= maxUint64Digits { - if _, err := parseUintBytes(buf[start:i-1], 10, 64); err != nil { - return i, fmt.Errorf("unable to parse unsigned %s: %s", buf[start:i-1], err) - } - } - } else { - // Parse the float to check bounds if it's scientific or the number of digits could be larger than the max range - if scientific || len(buf[start:i]) >= maxFloat64Digits || len(buf[start:i]) >= minFloat64Digits { - if _, err := parseFloatBytes(buf[start:i], 10); err != nil { - return i, fmt.Errorf("invalid float") - } - } - } - - return i, nil -} - -// scanBoolean returns the end position within buf, start at i after -// scanning over buf for boolean. Valid values for a boolean are -// t, T, true, TRUE, f, F, false, FALSE. It returns an error if a invalid boolean -// is scanned. -func scanBoolean(buf []byte, i int) (int, []byte, error) { - start := i - - if i < len(buf) && (buf[i] != 't' && buf[i] != 'f' && buf[i] != 'T' && buf[i] != 'F') { - return i, buf[start:i], fmt.Errorf("invalid boolean") - } - - i++ - for { - if i >= len(buf) { - break - } - - if buf[i] == ',' || buf[i] == ' ' { - break - } - i++ - } - - // Single char bool (t, T, f, F) is ok - if i-start == 1 { - return i, buf[start:i], nil - } - - // length must be 4 for true or TRUE - if (buf[start] == 't' || buf[start] == 'T') && i-start != 4 { - return i, buf[start:i], fmt.Errorf("invalid boolean") - } - - // length must be 5 for false or FALSE - if (buf[start] == 'f' || buf[start] == 'F') && i-start != 5 { - return i, buf[start:i], fmt.Errorf("invalid boolean") - } - - // Otherwise - valid := false - switch buf[start] { - case 't': - valid = bytes.Equal(buf[start:i], []byte("true")) - case 'f': - valid = bytes.Equal(buf[start:i], []byte("false")) - case 'T': - valid = bytes.Equal(buf[start:i], []byte("TRUE")) || bytes.Equal(buf[start:i], []byte("True")) - case 'F': - valid = bytes.Equal(buf[start:i], []byte("FALSE")) || bytes.Equal(buf[start:i], []byte("False")) - } - - if !valid { - return i, buf[start:i], fmt.Errorf("invalid boolean") - } - - return i, buf[start:i], nil - -} - -// skipWhitespace returns the end position within buf, starting at i after -// scanning over spaces in tags. -func skipWhitespace(buf []byte, i int) int { - for i < len(buf) { - if buf[i] != ' ' && buf[i] != '\t' && buf[i] != 0 { - break - } - i++ - } - return i -} - -// scanLine returns the end position in buf and the next line found within -// buf. -func scanLine(buf []byte, i int) (int, []byte) { - start := i - quoted := false - fields := false - - // tracks how many '=' and commas we've seen - // this duplicates some of the functionality in scanFields - equals := 0 - commas := 0 - for { - // reached the end of buf? - if i >= len(buf) { - break - } - - // skip past escaped characters - if buf[i] == '\\' && i+2 < len(buf) { - i += 2 - continue - } - - if buf[i] == ' ' { - fields = true - } - - // If we see a double quote, makes sure it is not escaped - if fields { - if !quoted && buf[i] == '=' { - i++ - equals++ - continue - } else if !quoted && buf[i] == ',' { - i++ - commas++ - continue - } else if buf[i] == '"' && equals > commas { - i++ - quoted = !quoted - continue - } - } - - if buf[i] == '\n' && !quoted { - break - } - - i++ - } - - return i, buf[start:i] -} - -// scanTo returns the end position in buf and the next consecutive block -// of bytes, starting from i and ending with stop byte, where stop byte -// has not been escaped. -// -// If there are leading spaces, they are skipped. -func scanTo(buf []byte, i int, stop byte) (int, []byte) { - start := i - for { - // reached the end of buf? - if i >= len(buf) { - break - } - - // Reached unescaped stop value? - if buf[i] == stop && (i == 0 || buf[i-1] != '\\') { - break - } - i++ - } - - return i, buf[start:i] -} - -// scanTo returns the end position in buf and the next consecutive block -// of bytes, starting from i and ending with stop byte. If there are leading -// spaces, they are skipped. -func scanToSpaceOr(buf []byte, i int, stop byte) (int, []byte) { - start := i - if buf[i] == stop || buf[i] == ' ' { - return i, buf[start:i] - } - - for { - i++ - if buf[i-1] == '\\' { - continue - } - - // reached the end of buf? - if i >= len(buf) { - return i, buf[start:i] - } - - // reached end of block? - if buf[i] == stop || buf[i] == ' ' { - return i, buf[start:i] - } - } -} - -func scanTagValue(buf []byte, i int) (int, []byte) { - start := i - for { - if i >= len(buf) { - break - } - - if buf[i] == ',' && buf[i-1] != '\\' { - break - } - i++ - } - if i > len(buf) { - return i, nil - } - return i, buf[start:i] -} - -func scanFieldValue(buf []byte, i int) (int, []byte) { - start := i - quoted := false - for i < len(buf) { - // Only escape char for a field value is a double-quote and backslash - if buf[i] == '\\' && i+1 < len(buf) && (buf[i+1] == '"' || buf[i+1] == '\\') { - i += 2 - continue - } - - // Quoted value? (e.g. string) - if buf[i] == '"' { - i++ - quoted = !quoted - continue - } - - if buf[i] == ',' && !quoted { - break - } - i++ - } - return i, buf[start:i] -} - -func EscapeMeasurement(in []byte) []byte { - for b, esc := range measurementEscapeCodes { - in = bytes.Replace(in, []byte{b}, esc, -1) - } - return in -} - -func unescapeMeasurement(in []byte) []byte { - for b, esc := range measurementEscapeCodes { - in = bytes.Replace(in, esc, []byte{b}, -1) - } - return in -} - -func escapeTag(in []byte) []byte { - for b, esc := range tagEscapeCodes { - if bytes.IndexByte(in, b) != -1 { - in = bytes.Replace(in, []byte{b}, esc, -1) - } - } - return in -} - -func unescapeTag(in []byte) []byte { - if bytes.IndexByte(in, '\\') == -1 { - return in - } - - for b, esc := range tagEscapeCodes { - if bytes.IndexByte(in, b) != -1 { - in = bytes.Replace(in, esc, []byte{b}, -1) - } - } - return in -} - -// escapeStringFieldReplacer replaces double quotes and backslashes -// with the same character preceded by a backslash. -// As of Go 1.7 this benchmarked better in allocations and CPU time -// compared to iterating through a string byte-by-byte and appending to a new byte slice, -// calling strings.Replace twice, and better than (*Regex).ReplaceAllString. -var escapeStringFieldReplacer = strings.NewReplacer(`"`, `\"`, `\`, `\\`) - -// EscapeStringField returns a copy of in with any double quotes or -// backslashes with escaped values. -func EscapeStringField(in string) string { - return escapeStringFieldReplacer.Replace(in) -} - -// unescapeStringField returns a copy of in with any escaped double-quotes -// or backslashes unescaped. -func unescapeStringField(in string) string { - if strings.IndexByte(in, '\\') == -1 { - return in - } - - var out []byte - i := 0 - for { - if i >= len(in) { - break - } - // unescape backslashes - if in[i] == '\\' && i+1 < len(in) && in[i+1] == '\\' { - out = append(out, '\\') - i += 2 - continue - } - // unescape double-quotes - if in[i] == '\\' && i+1 < len(in) && in[i+1] == '"' { - out = append(out, '"') - i += 2 - continue - } - out = append(out, in[i]) - i++ - - } - return string(out) -} - -// NewPoint returns a new point with the given measurement name, tags, fields and timestamp. If -// an unsupported field value (NaN) or out of range time is passed, this function returns an error. -func NewPoint(name string, tags Tags, fields Fields, t time.Time) (Point, error) { - key, err := pointKey(name, tags, fields, t) - if err != nil { - return nil, err - } - - return &point{ - key: key, - time: t, - fields: fields.MarshalBinary(), - }, nil -} - -// pointKey checks some basic requirements for valid points, and returns the -// key, along with an possible error. -func pointKey(measurement string, tags Tags, fields Fields, t time.Time) ([]byte, error) { - if len(fields) == 0 { - return nil, ErrPointMustHaveAField - } - - if !t.IsZero() { - if err := CheckTime(t); err != nil { - return nil, err - } - } - - for key, value := range fields { - switch value := value.(type) { - case float64: - // Ensure the caller validates and handles invalid field values - if math.IsNaN(value) { - return nil, fmt.Errorf("NaN is an unsupported value for field %s", key) - } - case float32: - // Ensure the caller validates and handles invalid field values - if math.IsNaN(float64(value)) { - return nil, fmt.Errorf("NaN is an unsupported value for field %s", key) - } - } - if len(key) == 0 { - return nil, fmt.Errorf("all fields must have non-empty names") - } - } - - key := MakeKey([]byte(measurement), tags) - for field := range fields { - sz := seriesKeySize(key, []byte(field)) - if sz > MaxKeyLength { - return nil, fmt.Errorf("max key length exceeded: %v > %v", sz, MaxKeyLength) - } - } - - return key, nil -} - -func seriesKeySize(key, field []byte) int { - // 4 is the length of the tsm1.fieldKeySeparator constant. It's inlined here to avoid a circular - // dependency. - return len(key) + 4 + len(field) -} - -// NewPointFromBytes returns a new Point from a marshalled Point. -func NewPointFromBytes(b []byte) (Point, error) { - p := &point{} - if err := p.UnmarshalBinary(b); err != nil { - return nil, err - } - - // This does some basic validation to ensure there are fields and they - // can be unmarshalled as well. - iter := p.FieldIterator() - var hasField bool - for iter.Next() { - if len(iter.FieldKey()) == 0 { - continue - } - hasField = true - switch iter.Type() { - case Float: - _, err := iter.FloatValue() - if err != nil { - return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) - } - case Integer: - _, err := iter.IntegerValue() - if err != nil { - return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) - } - case Unsigned: - _, err := iter.UnsignedValue() - if err != nil { - return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) - } - case String: - // Skip since this won't return an error - case Boolean: - _, err := iter.BooleanValue() - if err != nil { - return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) - } - } - } - - if !hasField { - return nil, ErrPointMustHaveAField - } - - return p, nil -} - -// MustNewPoint returns a new point with the given measurement name, tags, fields and timestamp. If -// an unsupported field value (NaN) is passed, this function panics. -func MustNewPoint(name string, tags Tags, fields Fields, time time.Time) Point { - pt, err := NewPoint(name, tags, fields, time) - if err != nil { - panic(err.Error()) - } - return pt -} - -// Key returns the key (measurement joined with tags) of the point. -func (p *point) Key() []byte { - return p.key -} - -func (p *point) name() []byte { - _, name := scanTo(p.key, 0, ',') - return name -} - -func (p *point) Name() []byte { - return escape.Unescape(p.name()) -} - -// SetName updates the measurement name for the point. -func (p *point) SetName(name string) { - p.cachedName = "" - p.key = MakeKey([]byte(name), p.Tags()) -} - -// Time return the timestamp for the point. -func (p *point) Time() time.Time { - return p.time -} - -// SetTime updates the timestamp for the point. -func (p *point) SetTime(t time.Time) { - p.time = t -} - -// Round will round the timestamp of the point to the given duration. -func (p *point) Round(d time.Duration) { - p.time = p.time.Round(d) -} - -// Tags returns the tag set for the point. -func (p *point) Tags() Tags { - if p.cachedTags != nil { - return p.cachedTags - } - p.cachedTags = parseTags(p.key) - return p.cachedTags -} - -func (p *point) HasTag(tag []byte) bool { - if len(p.key) == 0 { - return false - } - - var exists bool - walkTags(p.key, func(key, value []byte) bool { - if bytes.Equal(tag, key) { - exists = true - return false - } - return true - }) - - return exists -} - -func walkTags(buf []byte, fn func(key, value []byte) bool) { - if len(buf) == 0 { - return - } - - pos, name := scanTo(buf, 0, ',') - - // it's an empty key, so there are no tags - if len(name) == 0 { - return - } - - hasEscape := bytes.IndexByte(buf, '\\') != -1 - i := pos + 1 - var key, value []byte - for { - if i >= len(buf) { - break - } - i, key = scanTo(buf, i, '=') - i, value = scanTagValue(buf, i+1) - - if len(value) == 0 { - continue - } - - if hasEscape { - if !fn(unescapeTag(key), unescapeTag(value)) { - return - } - } else { - if !fn(key, value) { - return - } - } - - i++ - } -} - -// walkFields walks each field key and value via fn. If fn returns false, the iteration -// is stopped. The values are the raw byte slices and not the converted types. -func walkFields(buf []byte, fn func(key, value []byte) bool) { - var i int - var key, val []byte - for len(buf) > 0 { - i, key = scanTo(buf, 0, '=') - buf = buf[i+1:] - i, val = scanFieldValue(buf, 0) - buf = buf[i:] - if !fn(key, val) { - break - } - - // slice off comma - if len(buf) > 0 { - buf = buf[1:] - } - } -} - -func parseTags(buf []byte) Tags { - if len(buf) == 0 { - return nil - } - - tags := make(Tags, bytes.Count(buf, []byte(","))) - p := 0 - walkTags(buf, func(key, value []byte) bool { - tags[p].Key = key - tags[p].Value = value - p++ - return true - }) - return tags -} - -// MakeKey creates a key for a set of tags. -func MakeKey(name []byte, tags Tags) []byte { - // unescape the name and then re-escape it to avoid double escaping. - // The key should always be stored in escaped form. - return append(EscapeMeasurement(unescapeMeasurement(name)), tags.HashKey()...) -} - -// SetTags replaces the tags for the point. -func (p *point) SetTags(tags Tags) { - p.key = MakeKey(p.Name(), tags) - p.cachedTags = tags -} - -// AddTag adds or replaces a tag value for a point. -func (p *point) AddTag(key, value string) { - tags := p.Tags() - tags = append(tags, Tag{Key: []byte(key), Value: []byte(value)}) - sort.Sort(tags) - p.cachedTags = tags - p.key = MakeKey(p.Name(), tags) -} - -// Fields returns the fields for the point. -func (p *point) Fields() (Fields, error) { - if p.cachedFields != nil { - return p.cachedFields, nil - } - cf, err := p.unmarshalBinary() - if err != nil { - return nil, err - } - p.cachedFields = cf - return p.cachedFields, nil -} - -// SetPrecision will round a time to the specified precision. -func (p *point) SetPrecision(precision string) { - switch precision { - case "n": - case "u": - p.SetTime(p.Time().Truncate(time.Microsecond)) - case "ms": - p.SetTime(p.Time().Truncate(time.Millisecond)) - case "s": - p.SetTime(p.Time().Truncate(time.Second)) - case "m": - p.SetTime(p.Time().Truncate(time.Minute)) - case "h": - p.SetTime(p.Time().Truncate(time.Hour)) - } -} - -// String returns the string representation of the point. -func (p *point) String() string { - if p.Time().IsZero() { - return string(p.Key()) + " " + string(p.fields) - } - return string(p.Key()) + " " + string(p.fields) + " " + strconv.FormatInt(p.UnixNano(), 10) -} - -// AppendString appends the string representation of the point to buf. -func (p *point) AppendString(buf []byte) []byte { - buf = append(buf, p.key...) - buf = append(buf, ' ') - buf = append(buf, p.fields...) - - if !p.time.IsZero() { - buf = append(buf, ' ') - buf = strconv.AppendInt(buf, p.UnixNano(), 10) - } - - return buf -} - -// StringSize returns the length of the string that would be returned by String(). -func (p *point) StringSize() int { - size := len(p.key) + len(p.fields) + 1 - - if !p.time.IsZero() { - digits := 1 // even "0" has one digit - t := p.UnixNano() - if t < 0 { - // account for negative sign, then negate - digits++ - t = -t - } - for t > 9 { // already accounted for one digit - digits++ - t /= 10 - } - size += digits + 1 // digits and a space - } - - return size -} - -// MarshalBinary returns a binary representation of the point. -func (p *point) MarshalBinary() ([]byte, error) { - if len(p.fields) == 0 { - return nil, ErrPointMustHaveAField - } - - tb, err := p.time.MarshalBinary() - if err != nil { - return nil, err - } - - b := make([]byte, 8+len(p.key)+len(p.fields)+len(tb)) - i := 0 - - binary.BigEndian.PutUint32(b[i:], uint32(len(p.key))) - i += 4 - - i += copy(b[i:], p.key) - - binary.BigEndian.PutUint32(b[i:i+4], uint32(len(p.fields))) - i += 4 - - i += copy(b[i:], p.fields) - - copy(b[i:], tb) - return b, nil -} - -// UnmarshalBinary decodes a binary representation of the point into a point struct. -func (p *point) UnmarshalBinary(b []byte) error { - var n int - - // Read key length. - if len(b) < 4 { - return io.ErrShortBuffer - } - n, b = int(binary.BigEndian.Uint32(b[:4])), b[4:] - - // Read key. - if len(b) < n { - return io.ErrShortBuffer - } - p.key, b = b[:n], b[n:] - - // Read fields length. - if len(b) < 4 { - return io.ErrShortBuffer - } - n, b = int(binary.BigEndian.Uint32(b[:4])), b[4:] - - // Read fields. - if len(b) < n { - return io.ErrShortBuffer - } - p.fields, b = b[:n], b[n:] - - // Read timestamp. - return p.time.UnmarshalBinary(b) -} - -// PrecisionString returns a string representation of the point. If there -// is a timestamp associated with the point then it will be specified in the -// given unit. -func (p *point) PrecisionString(precision string) string { - if p.Time().IsZero() { - return fmt.Sprintf("%s %s", p.Key(), string(p.fields)) - } - return fmt.Sprintf("%s %s %d", p.Key(), string(p.fields), - p.UnixNano()/GetPrecisionMultiplier(precision)) -} - -// RoundedString returns a string representation of the point. If there -// is a timestamp associated with the point, then it will be rounded to the -// given duration. -func (p *point) RoundedString(d time.Duration) string { - if p.Time().IsZero() { - return fmt.Sprintf("%s %s", p.Key(), string(p.fields)) - } - return fmt.Sprintf("%s %s %d", p.Key(), string(p.fields), - p.time.Round(d).UnixNano()) -} - -func (p *point) unmarshalBinary() (Fields, error) { - iter := p.FieldIterator() - fields := make(Fields, 8) - for iter.Next() { - if len(iter.FieldKey()) == 0 { - continue - } - switch iter.Type() { - case Float: - v, err := iter.FloatValue() - if err != nil { - return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) - } - fields[string(iter.FieldKey())] = v - case Integer: - v, err := iter.IntegerValue() - if err != nil { - return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) - } - fields[string(iter.FieldKey())] = v - case Unsigned: - v, err := iter.UnsignedValue() - if err != nil { - return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) - } - fields[string(iter.FieldKey())] = v - case String: - fields[string(iter.FieldKey())] = iter.StringValue() - case Boolean: - v, err := iter.BooleanValue() - if err != nil { - return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) - } - fields[string(iter.FieldKey())] = v - } - } - return fields, nil -} - -// HashID returns a non-cryptographic checksum of the point's key. -func (p *point) HashID() uint64 { - h := NewInlineFNV64a() - h.Write(p.key) - sum := h.Sum64() - return sum -} - -// UnixNano returns the timestamp of the point as nanoseconds since Unix epoch. -func (p *point) UnixNano() int64 { - return p.Time().UnixNano() -} - -// Split will attempt to return multiple points with the same timestamp whose -// string representations are no longer than size. Points with a single field or -// a point without a timestamp may exceed the requested size. -func (p *point) Split(size int) []Point { - if p.time.IsZero() || p.StringSize() <= size { - return []Point{p} - } - - // key string, timestamp string, spaces - size -= len(p.key) + len(strconv.FormatInt(p.time.UnixNano(), 10)) + 2 - - var points []Point - var start, cur int - - for cur < len(p.fields) { - end, _ := scanTo(p.fields, cur, '=') - end, _ = scanFieldValue(p.fields, end+1) - - if cur > start && end-start > size { - points = append(points, &point{ - key: p.key, - time: p.time, - fields: p.fields[start : cur-1], - }) - start = cur - } - - cur = end + 1 - } - - points = append(points, &point{ - key: p.key, - time: p.time, - fields: p.fields[start:], - }) - - return points -} - -// Tag represents a single key/value tag pair. -type Tag struct { - Key []byte - Value []byte -} - -// NewTag returns a new Tag. -func NewTag(key, value []byte) Tag { - return Tag{ - Key: key, - Value: value, - } -} - -// Size returns the size of the key and value. -func (t Tag) Size() int { return len(t.Key) + len(t.Value) } - -// Clone returns a shallow copy of Tag. -// -// Tags associated with a Point created by ParsePointsWithPrecision will hold references to the byte slice that was parsed. -// Use Clone to create a Tag with new byte slices that do not refer to the argument to ParsePointsWithPrecision. -func (t Tag) Clone() Tag { - other := Tag{ - Key: make([]byte, len(t.Key)), - Value: make([]byte, len(t.Value)), - } - - copy(other.Key, t.Key) - copy(other.Value, t.Value) - - return other -} - -// String returns the string reprsentation of the tag. -func (t *Tag) String() string { - var buf bytes.Buffer - buf.WriteByte('{') - buf.WriteString(string(t.Key)) - buf.WriteByte(' ') - buf.WriteString(string(t.Value)) - buf.WriteByte('}') - return buf.String() -} - -// Tags represents a sorted list of tags. -type Tags []Tag - -// NewTags returns a new Tags from a map. -func NewTags(m map[string]string) Tags { - if len(m) == 0 { - return nil - } - a := make(Tags, 0, len(m)) - for k, v := range m { - a = append(a, NewTag([]byte(k), []byte(v))) - } - sort.Sort(a) - return a -} - -// Keys returns the list of keys for a tag set. -func (a Tags) Keys() []string { - if len(a) == 0 { - return nil - } - keys := make([]string, len(a)) - for i, tag := range a { - keys[i] = string(tag.Key) - } - return keys -} - -// Values returns the list of values for a tag set. -func (a Tags) Values() []string { - if len(a) == 0 { - return nil - } - values := make([]string, len(a)) - for i, tag := range a { - values[i] = string(tag.Value) - } - return values -} - -// String returns the string representation of the tags. -func (a Tags) String() string { - var buf bytes.Buffer - buf.WriteByte('[') - for i := range a { - buf.WriteString(a[i].String()) - if i < len(a)-1 { - buf.WriteByte(' ') - } - } - buf.WriteByte(']') - return buf.String() -} - -// Size returns the number of bytes needed to store all tags. Note, this is -// the number of bytes needed to store all keys and values and does not account -// for data structures or delimiters for example. -func (a Tags) Size() int { - var total int - for _, t := range a { - total += t.Size() - } - return total -} - -// Clone returns a copy of the slice where the elements are a result of calling `Clone` on the original elements -// -// Tags associated with a Point created by ParsePointsWithPrecision will hold references to the byte slice that was parsed. -// Use Clone to create Tags with new byte slices that do not refer to the argument to ParsePointsWithPrecision. -func (a Tags) Clone() Tags { - if len(a) == 0 { - return nil - } - - others := make(Tags, len(a)) - for i := range a { - others[i] = a[i].Clone() - } - - return others -} - -func (a Tags) Len() int { return len(a) } -func (a Tags) Less(i, j int) bool { return bytes.Compare(a[i].Key, a[j].Key) == -1 } -func (a Tags) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -// Equal returns true if a equals other. -func (a Tags) Equal(other Tags) bool { - if len(a) != len(other) { - return false - } - for i := range a { - if !bytes.Equal(a[i].Key, other[i].Key) || !bytes.Equal(a[i].Value, other[i].Value) { - return false - } - } - return true -} - -// CompareTags returns -1 if a < b, 1 if a > b, and 0 if a == b. -func CompareTags(a, b Tags) int { - // Compare each key & value until a mismatch. - for i := 0; i < len(a) && i < len(b); i++ { - if cmp := bytes.Compare(a[i].Key, b[i].Key); cmp != 0 { - return cmp - } - if cmp := bytes.Compare(a[i].Value, b[i].Value); cmp != 0 { - return cmp - } - } - - // If all tags are equal up to this point then return shorter tagset. - if len(a) < len(b) { - return -1 - } else if len(a) > len(b) { - return 1 - } - - // All tags are equal. - return 0 -} - -// Get returns the value for a key. -func (a Tags) Get(key []byte) []byte { - // OPTIMIZE: Use sort.Search if tagset is large. - - for _, t := range a { - if bytes.Equal(t.Key, key) { - return t.Value - } - } - return nil -} - -// GetString returns the string value for a string key. -func (a Tags) GetString(key string) string { - return string(a.Get([]byte(key))) -} - -// Set sets the value for a key. -func (a *Tags) Set(key, value []byte) { - for i, t := range *a { - if bytes.Equal(t.Key, key) { - (*a)[i].Value = value - return - } - } - *a = append(*a, Tag{Key: key, Value: value}) - sort.Sort(*a) -} - -// SetString sets the string value for a string key. -func (a *Tags) SetString(key, value string) { - a.Set([]byte(key), []byte(value)) -} - -// Delete removes a tag by key. -func (a *Tags) Delete(key []byte) { - for i, t := range *a { - if bytes.Equal(t.Key, key) { - copy((*a)[i:], (*a)[i+1:]) - (*a)[len(*a)-1] = Tag{} - *a = (*a)[:len(*a)-1] - return - } - } -} - -// Map returns a map representation of the tags. -func (a Tags) Map() map[string]string { - m := make(map[string]string, len(a)) - for _, t := range a { - m[string(t.Key)] = string(t.Value) - } - return m -} - -// Merge merges the tags combining the two. If both define a tag with the -// same key, the merged value overwrites the old value. -// A new map is returned. -func (a Tags) Merge(other map[string]string) Tags { - merged := make(map[string]string, len(a)+len(other)) - for _, t := range a { - merged[string(t.Key)] = string(t.Value) - } - for k, v := range other { - merged[k] = v - } - return NewTags(merged) -} - -// HashKey hashes all of a tag's keys. -func (a Tags) HashKey() []byte { - // Empty maps marshal to empty bytes. - if len(a) == 0 { - return nil - } - - // Type invariant: Tags are sorted - - escaped := make(Tags, 0, len(a)) - sz := 0 - for _, t := range a { - ek := escapeTag(t.Key) - ev := escapeTag(t.Value) - - if len(ev) > 0 { - escaped = append(escaped, Tag{Key: ek, Value: ev}) - sz += len(ek) + len(ev) - } - } - - sz += len(escaped) + (len(escaped) * 2) // separators - - // Generate marshaled bytes. - b := make([]byte, sz) - buf := b - idx := 0 - for _, k := range escaped { - buf[idx] = ',' - idx++ - copy(buf[idx:idx+len(k.Key)], k.Key) - idx += len(k.Key) - buf[idx] = '=' - idx++ - copy(buf[idx:idx+len(k.Value)], k.Value) - idx += len(k.Value) - } - return b[:idx] -} - -// CopyTags returns a shallow copy of tags. -func CopyTags(a Tags) Tags { - other := make(Tags, len(a)) - copy(other, a) - return other -} - -// DeepCopyTags returns a deep copy of tags. -func DeepCopyTags(a Tags) Tags { - // Calculate size of keys/values in bytes. - var n int - for _, t := range a { - n += len(t.Key) + len(t.Value) - } - - // Build single allocation for all key/values. - buf := make([]byte, n) - - // Copy tags to new set. - other := make(Tags, len(a)) - for i, t := range a { - copy(buf, t.Key) - other[i].Key, buf = buf[:len(t.Key)], buf[len(t.Key):] - - copy(buf, t.Value) - other[i].Value, buf = buf[:len(t.Value)], buf[len(t.Value):] - } - - return other -} - -// Fields represents a mapping between a Point's field names and their -// values. -type Fields map[string]interface{} - -// FieldIterator retuns a FieldIterator that can be used to traverse the -// fields of a point without constructing the in-memory map. -func (p *point) FieldIterator() FieldIterator { - p.Reset() - return p -} - -type fieldIterator struct { - start, end int - key, keybuf []byte - valueBuf []byte - fieldType FieldType -} - -// Next indicates whether there any fields remaining. -func (p *point) Next() bool { - p.it.start = p.it.end - if p.it.start >= len(p.fields) { - return false - } - - p.it.end, p.it.key = scanTo(p.fields, p.it.start, '=') - if escape.IsEscaped(p.it.key) { - p.it.keybuf = escape.AppendUnescaped(p.it.keybuf[:0], p.it.key) - p.it.key = p.it.keybuf - } - - p.it.end, p.it.valueBuf = scanFieldValue(p.fields, p.it.end+1) - p.it.end++ - - if len(p.it.valueBuf) == 0 { - p.it.fieldType = Empty - return true - } - - c := p.it.valueBuf[0] - - if c == '"' { - p.it.fieldType = String - return true - } - - if strings.IndexByte(`0123456789-.nNiIu`, c) >= 0 { - if p.it.valueBuf[len(p.it.valueBuf)-1] == 'i' { - p.it.fieldType = Integer - p.it.valueBuf = p.it.valueBuf[:len(p.it.valueBuf)-1] - } else if p.it.valueBuf[len(p.it.valueBuf)-1] == 'u' { - p.it.fieldType = Unsigned - p.it.valueBuf = p.it.valueBuf[:len(p.it.valueBuf)-1] - } else { - p.it.fieldType = Float - } - return true - } - - // to keep the same behavior that currently exists, default to boolean - p.it.fieldType = Boolean - return true -} - -// FieldKey returns the key of the current field. -func (p *point) FieldKey() []byte { - return p.it.key -} - -// Type returns the FieldType of the current field. -func (p *point) Type() FieldType { - return p.it.fieldType -} - -// StringValue returns the string value of the current field. -func (p *point) StringValue() string { - return unescapeStringField(string(p.it.valueBuf[1 : len(p.it.valueBuf)-1])) -} - -// IntegerValue returns the integer value of the current field. -func (p *point) IntegerValue() (int64, error) { - n, err := parseIntBytes(p.it.valueBuf, 10, 64) - if err != nil { - return 0, fmt.Errorf("unable to parse integer value %q: %v", p.it.valueBuf, err) - } - return n, nil -} - -// UnsignedValue returns the unsigned value of the current field. -func (p *point) UnsignedValue() (uint64, error) { - n, err := parseUintBytes(p.it.valueBuf, 10, 64) - if err != nil { - return 0, fmt.Errorf("unable to parse unsigned value %q: %v", p.it.valueBuf, err) - } - return n, nil -} - -// BooleanValue returns the boolean value of the current field. -func (p *point) BooleanValue() (bool, error) { - b, err := parseBoolBytes(p.it.valueBuf) - if err != nil { - return false, fmt.Errorf("unable to parse bool value %q: %v", p.it.valueBuf, err) - } - return b, nil -} - -// FloatValue returns the float value of the current field. -func (p *point) FloatValue() (float64, error) { - f, err := parseFloatBytes(p.it.valueBuf, 64) - if err != nil { - return 0, fmt.Errorf("unable to parse floating point value %q: %v", p.it.valueBuf, err) - } - return f, nil -} - -// Reset resets the iterator to its initial state. -func (p *point) Reset() { - p.it.fieldType = Empty - p.it.key = nil - p.it.valueBuf = nil - p.it.start = 0 - p.it.end = 0 -} - -// MarshalBinary encodes all the fields to their proper type and returns the binary -// represenation -// NOTE: uint64 is specifically not supported due to potential overflow when we decode -// again later to an int64 -// NOTE2: uint is accepted, and may be 64 bits, and is for some reason accepted... -func (p Fields) MarshalBinary() []byte { - var b []byte - keys := make([]string, 0, len(p)) - - for k := range p { - keys = append(keys, k) - } - - // Not really necessary, can probably be removed. - sort.Strings(keys) - - for i, k := range keys { - if i > 0 { - b = append(b, ',') - } - b = appendField(b, k, p[k]) - } - - return b -} - -func appendField(b []byte, k string, v interface{}) []byte { - b = append(b, []byte(escape.String(k))...) - b = append(b, '=') - - // check popular types first - switch v := v.(type) { - case float64: - b = strconv.AppendFloat(b, v, 'f', -1, 64) - case int64: - b = strconv.AppendInt(b, v, 10) - b = append(b, 'i') - case string: - b = append(b, '"') - b = append(b, []byte(EscapeStringField(v))...) - b = append(b, '"') - case bool: - b = strconv.AppendBool(b, v) - case int32: - b = strconv.AppendInt(b, int64(v), 10) - b = append(b, 'i') - case int16: - b = strconv.AppendInt(b, int64(v), 10) - b = append(b, 'i') - case int8: - b = strconv.AppendInt(b, int64(v), 10) - b = append(b, 'i') - case int: - b = strconv.AppendInt(b, int64(v), 10) - b = append(b, 'i') - case uint64: - b = strconv.AppendUint(b, v, 10) - b = append(b, 'u') - case uint32: - b = strconv.AppendInt(b, int64(v), 10) - b = append(b, 'i') - case uint16: - b = strconv.AppendInt(b, int64(v), 10) - b = append(b, 'i') - case uint8: - b = strconv.AppendInt(b, int64(v), 10) - b = append(b, 'i') - case uint: - // TODO: 'uint' should be converted to writing as an unsigned integer, - // but we cannot since that would break backwards compatibility. - b = strconv.AppendInt(b, int64(v), 10) - b = append(b, 'i') - case float32: - b = strconv.AppendFloat(b, float64(v), 'f', -1, 32) - case []byte: - b = append(b, v...) - case nil: - // skip - default: - // Can't determine the type, so convert to string - b = append(b, '"') - b = append(b, []byte(EscapeStringField(fmt.Sprintf("%v", v)))...) - b = append(b, '"') - - } - - return b -} diff --git a/vendor/github.com/influxdata/influxdb/models/rows.go b/vendor/github.com/influxdata/influxdb/models/rows.go deleted file mode 100644 index c087a4882..000000000 --- a/vendor/github.com/influxdata/influxdb/models/rows.go +++ /dev/null @@ -1,62 +0,0 @@ -package models - -import ( - "sort" -) - -// Row represents a single row returned from the execution of a statement. -type Row struct { - Name string `json:"name,omitempty"` - Tags map[string]string `json:"tags,omitempty"` - Columns []string `json:"columns,omitempty"` - Values [][]interface{} `json:"values,omitempty"` - Partial bool `json:"partial,omitempty"` -} - -// SameSeries returns true if r contains values for the same series as o. -func (r *Row) SameSeries(o *Row) bool { - return r.tagsHash() == o.tagsHash() && r.Name == o.Name -} - -// tagsHash returns a hash of tag key/value pairs. -func (r *Row) tagsHash() uint64 { - h := NewInlineFNV64a() - keys := r.tagsKeys() - for _, k := range keys { - h.Write([]byte(k)) - h.Write([]byte(r.Tags[k])) - } - return h.Sum64() -} - -// tagKeys returns a sorted list of tag keys. -func (r *Row) tagsKeys() []string { - a := make([]string, 0, len(r.Tags)) - for k := range r.Tags { - a = append(a, k) - } - sort.Strings(a) - return a -} - -// Rows represents a collection of rows. Rows implements sort.Interface. -type Rows []*Row - -// Len implements sort.Interface. -func (p Rows) Len() int { return len(p) } - -// Less implements sort.Interface. -func (p Rows) Less(i, j int) bool { - // Sort by name first. - if p[i].Name != p[j].Name { - return p[i].Name < p[j].Name - } - - // Sort by tag set hash. Tags don't have a meaningful sort order so we - // just compute a hash and sort by that instead. This allows the tests - // to receive rows in a predictable order every time. - return p[i].tagsHash() < p[j].tagsHash() -} - -// Swap implements sort.Interface. -func (p Rows) Swap(i, j int) { p[i], p[j] = p[j], p[i] } diff --git a/vendor/github.com/influxdata/influxdb/models/statistic.go b/vendor/github.com/influxdata/influxdb/models/statistic.go deleted file mode 100644 index 553e9d09f..000000000 --- a/vendor/github.com/influxdata/influxdb/models/statistic.go +++ /dev/null @@ -1,42 +0,0 @@ -package models - -// Statistic is the representation of a statistic used by the monitoring service. -type Statistic struct { - Name string `json:"name"` - Tags map[string]string `json:"tags"` - Values map[string]interface{} `json:"values"` -} - -// NewStatistic returns an initialized Statistic. -func NewStatistic(name string) Statistic { - return Statistic{ - Name: name, - Tags: make(map[string]string), - Values: make(map[string]interface{}), - } -} - -// StatisticTags is a map that can be merged with others without causing -// mutations to either map. -type StatisticTags map[string]string - -// Merge creates a new map containing the merged contents of tags and t. -// If both tags and the receiver map contain the same key, the value in tags -// is used in the resulting map. -// -// Merge always returns a usable map. -func (t StatisticTags) Merge(tags map[string]string) map[string]string { - // Add everything in tags to the result. - out := make(map[string]string, len(tags)) - for k, v := range tags { - out[k] = v - } - - // Only add values from t that don't appear in tags. - for k, v := range t { - if _, ok := tags[k]; !ok { - out[k] = v - } - } - return out -} diff --git a/vendor/github.com/influxdata/influxdb/models/time.go b/vendor/github.com/influxdata/influxdb/models/time.go deleted file mode 100644 index e98f2cb33..000000000 --- a/vendor/github.com/influxdata/influxdb/models/time.go +++ /dev/null @@ -1,74 +0,0 @@ -package models - -// Helper time methods since parsing time can easily overflow and we only support a -// specific time range. - -import ( - "fmt" - "math" - "time" -) - -const ( - // MinNanoTime is the minumum time that can be represented. - // - // 1677-09-21 00:12:43.145224194 +0000 UTC - // - // The two lowest minimum integers are used as sentinel values. The - // minimum value needs to be used as a value lower than any other value for - // comparisons and another separate value is needed to act as a sentinel - // default value that is unusable by the user, but usable internally. - // Because these two values need to be used for a special purpose, we do - // not allow users to write points at these two times. - MinNanoTime = int64(math.MinInt64) + 2 - - // MaxNanoTime is the maximum time that can be represented. - // - // 2262-04-11 23:47:16.854775806 +0000 UTC - // - // The highest time represented by a nanosecond needs to be used for an - // exclusive range in the shard group, so the maximum time needs to be one - // less than the possible maximum number of nanoseconds representable by an - // int64 so that we don't lose a point at that one time. - MaxNanoTime = int64(math.MaxInt64) - 1 -) - -var ( - minNanoTime = time.Unix(0, MinNanoTime).UTC() - maxNanoTime = time.Unix(0, MaxNanoTime).UTC() - - // ErrTimeOutOfRange gets returned when time is out of the representable range using int64 nanoseconds since the epoch. - ErrTimeOutOfRange = fmt.Errorf("time outside range %d - %d", MinNanoTime, MaxNanoTime) -) - -// SafeCalcTime safely calculates the time given. Will return error if the time is outside the -// supported range. -func SafeCalcTime(timestamp int64, precision string) (time.Time, error) { - mult := GetPrecisionMultiplier(precision) - if t, ok := safeSignedMult(timestamp, mult); ok { - tme := time.Unix(0, t).UTC() - return tme, CheckTime(tme) - } - - return time.Time{}, ErrTimeOutOfRange -} - -// CheckTime checks that a time is within the safe range. -func CheckTime(t time.Time) error { - if t.Before(minNanoTime) || t.After(maxNanoTime) { - return ErrTimeOutOfRange - } - return nil -} - -// Perform the multiplication and check to make sure it didn't overflow. -func safeSignedMult(a, b int64) (int64, bool) { - if a == 0 || b == 0 || a == 1 || b == 1 { - return a * b, true - } - if a == MinNanoTime || b == MaxNanoTime { - return 0, false - } - c := a * b - return c, c/b == a -} diff --git a/vendor/github.com/influxdata/influxdb/models/uint_support.go b/vendor/github.com/influxdata/influxdb/models/uint_support.go deleted file mode 100644 index 18d1ca06e..000000000 --- a/vendor/github.com/influxdata/influxdb/models/uint_support.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build uint uint64 - -package models - -func init() { - EnableUintSupport() -} diff --git a/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go b/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go deleted file mode 100644 index f3b31f42d..000000000 --- a/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go +++ /dev/null @@ -1,115 +0,0 @@ -// Package escape contains utilities for escaping parts of InfluxQL -// and InfluxDB line protocol. -package escape // import "github.com/influxdata/influxdb/pkg/escape" - -import ( - "bytes" - "strings" -) - -// Codes is a map of bytes to be escaped. -var Codes = map[byte][]byte{ - ',': []byte(`\,`), - '"': []byte(`\"`), - ' ': []byte(`\ `), - '=': []byte(`\=`), -} - -// Bytes escapes characters on the input slice, as defined by Codes. -func Bytes(in []byte) []byte { - for b, esc := range Codes { - in = bytes.Replace(in, []byte{b}, esc, -1) - } - return in -} - -const escapeChars = `," =` - -// IsEscaped returns whether b has any escaped characters, -// i.e. whether b seems to have been processed by Bytes. -func IsEscaped(b []byte) bool { - for len(b) > 0 { - i := bytes.IndexByte(b, '\\') - if i < 0 { - return false - } - - if i+1 < len(b) && strings.IndexByte(escapeChars, b[i+1]) >= 0 { - return true - } - b = b[i+1:] - } - return false -} - -// AppendUnescaped appends the unescaped version of src to dst -// and returns the resulting slice. -func AppendUnescaped(dst, src []byte) []byte { - var pos int - for len(src) > 0 { - next := bytes.IndexByte(src[pos:], '\\') - if next < 0 || pos+next+1 >= len(src) { - return append(dst, src...) - } - - if pos+next+1 < len(src) && strings.IndexByte(escapeChars, src[pos+next+1]) >= 0 { - if pos+next > 0 { - dst = append(dst, src[:pos+next]...) - } - src = src[pos+next+1:] - pos = 0 - } else { - pos += next + 1 - } - } - - return dst -} - -// Unescape returns a new slice containing the unescaped version of in. -func Unescape(in []byte) []byte { - if len(in) == 0 { - return nil - } - - if bytes.IndexByte(in, '\\') == -1 { - return in - } - - i := 0 - inLen := len(in) - - // The output size will be no more than inLen. Preallocating the - // capacity of the output is faster and uses less memory than - // letting append() do its own (over)allocation. - out := make([]byte, 0, inLen) - - for { - if i >= inLen { - break - } - if in[i] == '\\' && i+1 < inLen { - switch in[i+1] { - case ',': - out = append(out, ',') - i += 2 - continue - case '"': - out = append(out, '"') - i += 2 - continue - case ' ': - out = append(out, ' ') - i += 2 - continue - case '=': - out = append(out, '=') - i += 2 - continue - } - } - out = append(out, in[i]) - i += 1 - } - return out -} diff --git a/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go b/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go deleted file mode 100644 index db98033b0..000000000 --- a/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go +++ /dev/null @@ -1,21 +0,0 @@ -package escape - -import "strings" - -var ( - escaper = strings.NewReplacer(`,`, `\,`, `"`, `\"`, ` `, `\ `, `=`, `\=`) - unescaper = strings.NewReplacer(`\,`, `,`, `\"`, `"`, `\ `, ` `, `\=`, `=`) -) - -// UnescapeString returns unescaped version of in. -func UnescapeString(in string) string { - if strings.IndexByte(in, '\\') == -1 { - return in - } - return unescaper.Replace(in) -} - -// String returns the escaped version of in. -func String(in string) string { - return escaper.Replace(in) -}