1// Copyright (c) The Thanos Authors. 2// Licensed under the Apache License 2.0. 3 4package alert 5 6import ( 7 "net" 8 "net/url" 9 "strconv" 10 "strings" 11 "time" 12 13 "github.com/pkg/errors" 14 "github.com/prometheus/common/model" 15 "gopkg.in/yaml.v2" 16 17 "github.com/thanos-io/thanos/pkg/discovery/dns" 18 http_util "github.com/thanos-io/thanos/pkg/http" 19) 20 21type AlertingConfig struct { 22 Alertmanagers []AlertmanagerConfig `yaml:"alertmanagers"` 23} 24 25// AlertmanagerConfig represents a client to a cluster of Alertmanager endpoints. 26type AlertmanagerConfig struct { 27 HTTPClientConfig http_util.ClientConfig `yaml:"http_config"` 28 EndpointsConfig http_util.EndpointsConfig `yaml:",inline"` 29 Timeout model.Duration `yaml:"timeout"` 30 APIVersion APIVersion `yaml:"api_version"` 31} 32 33// APIVersion represents the API version of the Alertmanager endpoint. 34type APIVersion string 35 36const ( 37 APIv1 APIVersion = "v1" 38 APIv2 APIVersion = "v2" 39) 40 41var supportedAPIVersions = []APIVersion{ 42 APIv1, APIv2, 43} 44 45// UnmarshalYAML implements the yaml.Unmarshaler interface. 46func (v *APIVersion) UnmarshalYAML(unmarshal func(interface{}) error) error { 47 var s string 48 if err := unmarshal(&s); err != nil { 49 return errors.Wrap(err, "invalid Alertmanager API version") 50 } 51 52 for _, ver := range supportedAPIVersions { 53 if APIVersion(s) == ver { 54 *v = ver 55 return nil 56 } 57 } 58 return errors.Errorf("expected Alertmanager API version to be one of %v but got %q", supportedAPIVersions, s) 59} 60 61func DefaultAlertmanagerConfig() AlertmanagerConfig { 62 return AlertmanagerConfig{ 63 EndpointsConfig: http_util.EndpointsConfig{ 64 Scheme: "http", 65 StaticAddresses: []string{}, 66 FileSDConfigs: []http_util.FileSDConfig{}, 67 }, 68 Timeout: model.Duration(time.Second * 10), 69 APIVersion: APIv1, 70 } 71} 72 73// UnmarshalYAML implements the yaml.Unmarshaler interface. 74func (c *AlertmanagerConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { 75 *c = DefaultAlertmanagerConfig() 76 type plain AlertmanagerConfig 77 return unmarshal((*plain)(c)) 78} 79 80// LoadAlertingConfig loads a list of AlertmanagerConfig from YAML data. 81func LoadAlertingConfig(confYaml []byte) (AlertingConfig, error) { 82 var cfg AlertingConfig 83 if err := yaml.UnmarshalStrict(confYaml, &cfg); err != nil { 84 return cfg, err 85 } 86 return cfg, nil 87} 88 89// BuildAlertmanagerConfig initializes and returns an Alertmanager client configuration from a static address. 90func BuildAlertmanagerConfig(address string, timeout time.Duration) (AlertmanagerConfig, error) { 91 parsed, err := url.Parse(address) 92 if err != nil { 93 return AlertmanagerConfig{}, err 94 } 95 96 scheme := parsed.Scheme 97 host := parsed.Host 98 for _, qType := range []dns.QType{dns.A, dns.SRV, dns.SRVNoA} { 99 prefix := string(qType) + "+" 100 if strings.HasPrefix(strings.ToLower(scheme), prefix) { 101 // Scheme is of the form "<dns type>+<http scheme>". 102 scheme = strings.TrimPrefix(scheme, prefix) 103 host = prefix + parsed.Host 104 if qType == dns.A { 105 if _, _, err := net.SplitHostPort(parsed.Host); err != nil { 106 // The host port could be missing. Append the defaultAlertmanagerPort. 107 host = host + ":" + strconv.Itoa(defaultAlertmanagerPort) 108 } 109 } 110 break 111 } 112 } 113 var basicAuth http_util.BasicAuth 114 if parsed.User != nil && parsed.User.String() != "" { 115 basicAuth.Username = parsed.User.Username() 116 pw, _ := parsed.User.Password() 117 basicAuth.Password = pw 118 } 119 120 return AlertmanagerConfig{ 121 HTTPClientConfig: http_util.ClientConfig{ 122 BasicAuth: basicAuth, 123 }, 124 EndpointsConfig: http_util.EndpointsConfig{ 125 PathPrefix: parsed.Path, 126 Scheme: scheme, 127 StaticAddresses: []string{host}, 128 }, 129 Timeout: model.Duration(timeout), 130 APIVersion: APIv1, 131 }, nil 132} 133