github.com/thanos-io/thanos@v0.32.5/pkg/alert/config.go (about)

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