2020-06-28 13:26:22 +02:00
package notifier
import (
2022-02-02 13:11:41 +01:00
"flag"
2020-06-28 13:26:22 +02:00
"fmt"
2022-02-02 15:18:40 +01:00
"strings"
2022-02-02 13:11:41 +01:00
"time"
2020-06-28 13:26:22 +02:00
2020-06-29 21:21:03 +02:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil"
2022-02-02 13:11:41 +01:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
2020-06-28 13:26:22 +02:00
)
var (
2022-02-02 13:11:41 +01:00
configPath = flag . String ( "notifier.config" , "" , "Path to configuration file for notifiers" )
suppressDuplicateTargetErrors = flag . Bool ( "notifier.suppressDuplicateTargetErrors" , false , "Whether to suppress 'duplicate target' errors during discovery" )
2022-03-10 12:09:12 +01:00
addrs = flagutil . NewArray ( "notifier.url" , "Prometheus alertmanager URL, e.g. http://127.0.0.1:9093" )
2022-02-02 16:56:14 +01:00
basicAuthUsername = flagutil . NewArray ( "notifier.basicAuth.username" , "Optional basic auth username for -notifier.url" )
basicAuthPassword = flagutil . NewArray ( "notifier.basicAuth.password" , "Optional basic auth password for -notifier.url" )
basicAuthPasswordFile = flagutil . NewArray ( "notifier.basicAuth.passwordFile" , "Optional path to basic auth password file for -notifier.url" )
2020-06-29 21:21:03 +02:00
2022-03-10 12:09:12 +01:00
bearerToken = flagutil . NewArray ( "notifier.bearerToken" , "Optional bearer token for -notifier.url" )
bearerTokenFile = flagutil . NewArray ( "notifier.bearerTokenFile" , "Optional path to bearer token file for -notifier.url" )
2020-12-22 21:23:04 +01:00
tlsInsecureSkipVerify = flagutil . NewArrayBool ( "notifier.tlsInsecureSkipVerify" , "Whether to skip tls verification when connecting to -notifier.url" )
2020-06-29 21:21:03 +02:00
tlsCertFile = flagutil . NewArray ( "notifier.tlsCertFile" , "Optional path to client-side TLS certificate file to use when connecting to -notifier.url" )
tlsKeyFile = flagutil . NewArray ( "notifier.tlsKeyFile" , "Optional path to client-side TLS certificate key to use when connecting to -notifier.url" )
tlsCAFile = flagutil . NewArray ( "notifier.tlsCAFile" , "Optional path to TLS CA file to use for verifying connections to -notifier.url. " +
2020-06-28 13:26:22 +02:00
"By default system CA is used" )
2020-06-29 21:21:03 +02:00
tlsServerName = flagutil . NewArray ( "notifier.tlsServerName" , "Optional TLS server name to use for connections to -notifier.url. " +
2020-06-28 13:26:22 +02:00
"By default the server name from -notifier.url is used" )
2022-03-10 12:09:12 +01:00
oauth2ClientID = flagutil . NewArray ( "notifier.oauth2.clientID" , "Optional OAuth2 clientID to use for -notifier.url. " +
"If multiple args are set, then they are applied independently for the corresponding -notifier.url" )
oauth2ClientSecret = flagutil . NewArray ( "notifier.oauth2.clientSecret" , "Optional OAuth2 clientSecret to use for -notifier.url. " +
"If multiple args are set, then they are applied independently for the corresponding -notifier.url" )
oauth2ClientSecretFile = flagutil . NewArray ( "notifier.oauth2.clientSecretFile" , "Optional OAuth2 clientSecretFile to use for -notifier.url. " +
"If multiple args are set, then they are applied independently for the corresponding -notifier.url" )
oauth2TokenURL = flagutil . NewArray ( "notifier.oauth2.tokenUrl" , "Optional OAuth2 tokenURL to use for -notifier.url. " +
"If multiple args are set, then they are applied independently for the corresponding -notifier.url" )
oauth2Scopes = flagutil . NewArray ( "notifier.oauth2.scopes" , "Optional OAuth2 scopes to use for -notifier.url. Scopes must be delimited by ';'. " +
"If multiple args are set, then they are applied independently for the corresponding -notifier.url" )
2020-06-28 13:26:22 +02:00
)
2022-02-02 13:11:41 +01:00
// cw holds a configWatcher for configPath configuration file
// configWatcher provides a list of Notifier objects discovered
// from static config or via service discovery.
// cw is not nil only if configPath is provided.
var cw * configWatcher
// Reload checks the changes in configPath configuration file
// and applies changes if any.
func Reload ( ) error {
if cw == nil {
return nil
}
return cw . reload ( * configPath )
}
var staticNotifiersFn func ( ) [ ] Notifier
2022-02-15 14:59:45 +01:00
var (
// externalLabels is a global variable for holding external labels configured via flags
// It is supposed to be inited via Init function only.
externalLabels map [ string ] string
// externalURL is a global variable for holding external URL value configured via flag
// It is supposed to be inited via Init function only.
externalURL string
)
2022-02-02 13:11:41 +01:00
// Init returns a function for retrieving actual list of Notifier objects.
// Init works in two mods:
// * configuration via flags (for backward compatibility). Is always static
// and don't support live reloads.
// * configuration via file. Supports live reloads and service discovery.
// Init returns an error if both mods are used.
2022-02-15 14:59:45 +01:00
func Init ( gen AlertURLGenerator , extLabels map [ string ] string , extURL string ) ( func ( ) [ ] Notifier , error ) {
if externalLabels != nil || externalURL != "" {
return nil , fmt . Errorf ( "BUG: notifier.Init was called multiple times" )
}
externalURL = extURL
externalLabels = extLabels
2022-02-02 13:11:41 +01:00
if * configPath == "" && len ( * addrs ) == 0 {
return nil , nil
}
if * configPath != "" && len ( * addrs ) > 0 {
return nil , fmt . Errorf ( "only one of -notifier.config or -notifier.url flags must be specified" )
}
if len ( * addrs ) > 0 {
notifiers , err := notifiersFromFlags ( gen )
if err != nil {
return nil , fmt . Errorf ( "failed to create notifier from flag values: %s" , err )
}
staticNotifiersFn = func ( ) [ ] Notifier {
return notifiers
}
return staticNotifiersFn , nil
}
var err error
cw , err = newWatcher ( * configPath , gen )
if err != nil {
return nil , fmt . Errorf ( "failed to init config watcher: %s" , err )
}
return cw . notifiers , nil
}
func notifiersFromFlags ( gen AlertURLGenerator ) ( [ ] Notifier , error ) {
2020-06-29 21:21:03 +02:00
var notifiers [ ] Notifier
for i , addr := range * addrs {
2022-02-02 13:11:41 +01:00
authCfg := promauth . HTTPClientConfig {
TLSConfig : & promauth . TLSConfig {
CAFile : tlsCAFile . GetOptionalArg ( i ) ,
CertFile : tlsCertFile . GetOptionalArg ( i ) ,
KeyFile : tlsKeyFile . GetOptionalArg ( i ) ,
ServerName : tlsServerName . GetOptionalArg ( i ) ,
InsecureSkipVerify : tlsInsecureSkipVerify . GetOptionalArg ( i ) ,
} ,
BasicAuth : & promauth . BasicAuthConfig {
2022-02-02 16:56:14 +01:00
Username : basicAuthUsername . GetOptionalArg ( i ) ,
Password : promauth . NewSecret ( basicAuthPassword . GetOptionalArg ( i ) ) ,
PasswordFile : basicAuthPasswordFile . GetOptionalArg ( i ) ,
2022-02-02 13:11:41 +01:00
} ,
2022-03-10 12:09:12 +01:00
BearerToken : promauth . NewSecret ( bearerToken . GetOptionalArg ( i ) ) ,
BearerTokenFile : bearerTokenFile . GetOptionalArg ( i ) ,
OAuth2 : & promauth . OAuth2Config {
ClientID : oauth2ClientID . GetOptionalArg ( i ) ,
ClientSecret : promauth . NewSecret ( oauth2ClientSecret . GetOptionalArg ( i ) ) ,
ClientSecretFile : oauth2ClientSecretFile . GetOptionalArg ( i ) ,
Scopes : strings . Split ( oauth2Scopes . GetOptionalArg ( i ) , ";" ) ,
TokenURL : oauth2TokenURL . GetOptionalArg ( i ) ,
} ,
2022-02-02 13:11:41 +01:00
}
2022-03-10 12:09:12 +01:00
2022-02-02 15:18:40 +01:00
addr = strings . TrimSuffix ( addr , "/" )
2022-02-02 13:11:41 +01:00
am , err := NewAlertManager ( addr + alertManagerPath , gen , authCfg , time . Minute )
2020-06-29 21:21:03 +02:00
if err != nil {
2022-02-02 13:11:41 +01:00
return nil , err
2020-06-29 21:21:03 +02:00
}
notifiers = append ( notifiers , am )
2020-06-28 13:26:22 +02:00
}
2020-06-29 21:21:03 +02:00
return notifiers , nil
2020-06-28 13:26:22 +02:00
}
2022-02-02 13:11:41 +01:00
// Target represents a Notifier and optional
// list of labels added during discovery.
type Target struct {
Notifier
Labels [ ] prompbmarshal . Label
}
// TargetType defines how the Target was discovered
type TargetType string
const (
// TargetStatic is for targets configured statically
TargetStatic TargetType = "static"
// TargetConsul is for targets discovered via Consul
TargetConsul TargetType = "consulSD"
)
// GetTargets returns list of static or discovered targets
// via notifier configuration.
func GetTargets ( ) map [ TargetType ] [ ] Target {
var targets = make ( map [ TargetType ] [ ] Target )
if staticNotifiersFn != nil {
for _ , ns := range staticNotifiersFn ( ) {
targets [ TargetStatic ] = append ( targets [ TargetStatic ] , Target {
Notifier : ns ,
} )
}
}
if cw != nil {
cw . targetsMu . RLock ( )
for key , ns := range cw . targets {
targets [ key ] = append ( targets [ key ] , ns ... )
}
cw . targetsMu . RUnlock ( )
}
return targets
}