2018-05-14 12:36:24 +00:00
// Copyright 2018 Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2017-04-20 09:04:17 +00:00
package cli
import (
2021-08-09 09:06:09 +00:00
"fmt"
2018-04-13 11:34:16 +00:00
"net/url"
2017-04-20 09:04:17 +00:00
"os"
2019-06-25 12:22:29 +00:00
"path"
2023-10-19 11:00:01 +00:00
"strings"
2018-07-17 07:50:48 +00:00
"time"
2017-04-20 09:04:17 +00:00
2023-03-01 12:47:50 +00:00
"github.com/alecthomas/kingpin/v2"
2023-10-19 11:00:01 +00:00
"github.com/go-kit/log"
"github.com/go-kit/log/level"
clientruntime "github.com/go-openapi/runtime/client"
2019-03-13 16:01:08 +00:00
"github.com/go-openapi/strfmt"
2021-11-10 09:15:33 +00:00
promconfig "github.com/prometheus/common/config"
2017-12-22 10:17:13 +00:00
"github.com/prometheus/common/version"
2021-08-09 09:06:09 +00:00
"golang.org/x/mod/semver"
2018-04-24 07:35:15 +00:00
2019-03-13 16:01:08 +00:00
"github.com/prometheus/alertmanager/api/v2/client"
2018-04-24 07:35:15 +00:00
"github.com/prometheus/alertmanager/cli/config"
"github.com/prometheus/alertmanager/cli/format"
2023-10-19 11:00:01 +00:00
"github.com/prometheus/alertmanager/featurecontrol"
"github.com/prometheus/alertmanager/matchers/compat"
2017-04-20 09:04:17 +00:00
)
2017-12-22 10:17:13 +00:00
var (
2021-11-10 09:15:33 +00:00
verbose bool
alertmanagerURL * url . URL
output string
timeout time . Duration
2022-01-19 09:01:58 +00:00
httpConfigFile string
2021-11-10 09:15:33 +00:00
versionCheck bool
2023-10-19 11:00:01 +00:00
featureFlags string
2018-04-24 07:35:15 +00:00
configFiles = [ ] string { os . ExpandEnv ( "$HOME/.config/amtool/config.yml" ) , "/etc/amtool/config.yml" }
legacyFlags = map [ string ] string { "comment_required" : "require-comment" }
2017-12-22 10:17:13 +00:00
)
2017-04-20 09:04:17 +00:00
2023-10-19 11:00:01 +00:00
func initMatchersCompat ( _ * kingpin . ParseContext ) error {
logger := log . NewLogfmtLogger ( os . Stdout )
if verbose {
logger = level . NewFilter ( logger , level . AllowDebug ( ) )
} else {
logger = level . NewFilter ( logger , level . AllowInfo ( ) )
}
featureConfig , err := featurecontrol . NewFlags ( logger , featureFlags )
if err != nil {
kingpin . Fatalf ( "error parsing the feature flag list: %v\n" , err )
}
2024-02-07 09:43:03 +00:00
compat . InitFromFlags ( logger , compat . NewMetrics ( nil ) , featureConfig )
2023-10-19 11:00:01 +00:00
return nil
}
2018-04-24 07:35:15 +00:00
func requireAlertManagerURL ( pc * kingpin . ParseContext ) error {
// Return without error if any help flag is set.
for _ , elem := range pc . Elements {
f , ok := elem . Clause . ( * kingpin . FlagClause )
if ! ok {
continue
}
name := f . Model ( ) . Name
if name == "help" || name == "help-long" || name == "help-man" {
return nil
}
}
if alertmanagerURL == nil {
kingpin . Fatalf ( "required flag --alertmanager.url not provided" )
}
return nil
}
2019-03-13 16:01:08 +00:00
const (
defaultAmHost = "localhost"
defaultAmPort = "9093"
defaultAmApiv2path = "/api/v2"
)
// NewAlertmanagerClient initializes an alertmanager client with the given URL
2022-11-30 16:06:57 +00:00
func NewAlertmanagerClient ( amURL * url . URL ) * client . AlertmanagerAPI {
2019-05-16 03:23:00 +00:00
address := defaultAmHost + ":" + defaultAmPort
schemes := [ ] string { "http" }
if amURL . Host != "" {
address = amURL . Host // URL documents host as host or host:port
}
if amURL . Scheme != "" {
schemes = [ ] string { amURL . Scheme }
}
2019-06-25 12:22:29 +00:00
cr := clientruntime . New ( address , path . Join ( amURL . Path , defaultAmApiv2path ) , schemes )
2019-03-13 16:01:08 +00:00
2022-01-19 09:01:58 +00:00
if amURL . User != nil && httpConfigFile != "" {
kingpin . Fatalf ( "basic authentication and http.config.file are mutually exclusive" )
2021-08-06 09:12:18 +00:00
}
2019-05-16 03:23:00 +00:00
if amURL . User != nil {
password , _ := amURL . User . Password ( )
cr . DefaultAuthentication = clientruntime . BasicAuth ( amURL . User . Username ( ) , password )
2019-03-13 16:01:08 +00:00
}
2019-05-16 03:23:00 +00:00
2022-01-19 09:01:58 +00:00
if httpConfigFile != "" {
var err error
2022-12-09 11:01:51 +00:00
httpConfig , _ , err := promconfig . LoadHTTPConfigFile ( httpConfigFile )
2022-01-19 09:01:58 +00:00
if err != nil {
kingpin . Fatalf ( "failed to load HTTP config file: %v" , err )
}
httpclient , err := promconfig . NewClientFromConfig ( * httpConfig , "amtool" )
if err != nil {
kingpin . Fatalf ( "failed to create a new HTTP client: %v" , err )
}
cr = clientruntime . NewWithClient ( address , path . Join ( amURL . Path , defaultAmApiv2path ) , schemes , httpclient )
}
2021-08-09 09:06:09 +00:00
c := client . New ( cr , strfmt . Default )
if ! versionCheck {
return c
}
status , err := c . General . GetStatus ( nil )
if err != nil || status . Payload . VersionInfo == nil || version . Version == "" {
// We can not get version info, or we do not know our own version. Let amtool continue.
return c
}
if semver . MajorMinor ( "v" + * status . Payload . VersionInfo . Version ) != semver . MajorMinor ( "v" + version . Version ) {
fmt . Fprintf ( os . Stderr , "Warning: amtool version (%s) and alertmanager version (%s) are different.\n" , version . Version , * status . Payload . VersionInfo . Version )
}
return c
2019-03-13 16:01:08 +00:00
}
// Execute is the main function for the amtool command
2018-04-13 11:34:16 +00:00
func Execute ( ) {
2022-03-25 16:59:51 +00:00
app := kingpin . New ( "amtool" , helpRoot ) . UsageWriter ( os . Stdout )
2017-06-02 20:51:44 +00:00
2018-04-13 11:34:16 +00:00
format . InitFormatFlags ( app )
2017-12-22 10:17:13 +00:00
2018-04-13 11:34:16 +00:00
app . Flag ( "verbose" , "Verbose running information" ) . Short ( 'v' ) . BoolVar ( & verbose )
2018-04-24 07:35:15 +00:00
app . Flag ( "alertmanager.url" , "Alertmanager to talk to" ) . URLVar ( & alertmanagerURL )
2018-04-13 11:34:16 +00:00
app . Flag ( "output" , "Output formatter (simple, extended, json)" ) . Short ( 'o' ) . Default ( "simple" ) . EnumVar ( & output , "simple" , "extended" , "json" )
2018-07-17 07:50:48 +00:00
app . Flag ( "timeout" , "Timeout for the executed command" ) . Default ( "30s" ) . DurationVar ( & timeout )
2022-01-19 09:01:58 +00:00
app . Flag ( "http.config.file" , "HTTP client configuration file for amtool to connect to Alertmanager." ) . PlaceHolder ( "<filename>" ) . ExistingFileVar ( & httpConfigFile )
2021-08-09 09:06:09 +00:00
app . Flag ( "version-check" , "Check alertmanager version. Use --no-version-check to disable." ) . Default ( "true" ) . BoolVar ( & versionCheck )
2023-10-19 11:00:01 +00:00
app . Flag ( "enable-feature" , fmt . Sprintf ( "Experimental features to enable. The flag can be repeated to enable multiple features. Valid options: %s" , strings . Join ( featurecontrol . AllowedFlags , ", " ) ) ) . Default ( "" ) . StringVar ( & featureFlags )
2018-07-17 07:50:48 +00:00
2018-04-13 11:34:16 +00:00
app . Version ( version . Print ( "amtool" ) )
app . GetFlag ( "help" ) . Short ( 'h' )
app . UsageTemplate ( kingpin . CompactUsageTemplate )
2017-12-22 10:17:13 +00:00
2018-04-24 07:35:15 +00:00
resolver , err := config . NewResolver ( configFiles , legacyFlags )
2018-04-13 11:34:16 +00:00
if err != nil {
kingpin . Fatalf ( "could not load config file: %v\n" , err )
2017-12-22 10:17:13 +00:00
}
2018-04-24 07:35:15 +00:00
configureAlertCmd ( app )
configureSilenceCmd ( app )
configureCheckConfigCmd ( app )
2020-05-18 13:25:15 +00:00
configureClusterCmd ( app )
2018-04-24 07:35:15 +00:00
configureConfigCmd ( app )
2021-08-04 11:58:33 +00:00
configureTemplateCmd ( app )
2018-04-13 11:34:16 +00:00
2023-10-19 11:00:01 +00:00
app . Action ( initMatchersCompat )
2018-04-24 07:35:15 +00:00
err = resolver . Bind ( app , os . Args [ 1 : ] )
2018-04-13 11:34:16 +00:00
if err != nil {
kingpin . Fatalf ( "%v\n" , err )
2017-12-22 10:17:13 +00:00
}
2018-04-13 11:34:16 +00:00
2018-04-24 07:35:15 +00:00
_ , err = app . Parse ( os . Args [ 1 : ] )
if err != nil {
kingpin . Fatalf ( "%v\n" , err )
}
2017-12-22 10:17:13 +00:00
}
2018-04-13 11:34:16 +00:00
const (
2018-04-24 07:35:15 +00:00
helpRoot = ` View and modify the current Alertmanager state .
2017-12-22 10:17:13 +00:00
Config File :
The alertmanager tool will read a config file in YAML format from one of two
default config locations : $ HOME / . config / amtool / config . yml or
/ etc / amtool / config . yml
All flags can be given in the config file , but the following are the suited for
static configuration :
2017-04-20 09:04:17 +00:00
alertmanager . url
Set a default alertmanager url for each request
author
2017-12-22 10:17:13 +00:00
Set a default author value for new silences . If this argument is not
specified then the username will be used
2017-04-20 09:04:17 +00:00
2017-12-22 10:17:13 +00:00
require - comment
Bool , whether to require a comment on silence creation . Defaults to true
2017-04-20 09:04:17 +00:00
output
Set a default output type . Options are ( simple , extended , json )
2017-12-22 10:17:13 +00:00
date . format
Sets the output format for dates . Defaults to "2006-01-02 15:04:05 MST"
2021-08-06 09:12:18 +00:00
2022-01-19 09:01:58 +00:00
http . config . file
HTTP client configuration file for amtool to connect to Alertmanager .
The format is https : //prometheus.io/docs/alerting/latest/configuration/#http_config.
2017-12-22 10:17:13 +00:00
`
2018-04-13 11:34:16 +00:00
)