...

Source file src/github.com/prometheus/alertmanager/cli/root.go

Documentation: github.com/prometheus/alertmanager/cli

     1  // Copyright 2018 Prometheus Team
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package cli
    15  
    16  import (
    17  	"fmt"
    18  	"net/url"
    19  	"os"
    20  	"path"
    21  	"time"
    22  
    23  	"github.com/go-openapi/strfmt"
    24  	promconfig "github.com/prometheus/common/config"
    25  	"github.com/prometheus/common/version"
    26  	"golang.org/x/mod/semver"
    27  	"gopkg.in/alecthomas/kingpin.v2"
    28  
    29  	"github.com/prometheus/alertmanager/api/v2/client"
    30  	"github.com/prometheus/alertmanager/cli/config"
    31  	"github.com/prometheus/alertmanager/cli/format"
    32  
    33  	clientruntime "github.com/go-openapi/runtime/client"
    34  )
    35  
    36  var (
    37  	verbose         bool
    38  	alertmanagerURL *url.URL
    39  	output          string
    40  	timeout         time.Duration
    41  	httpConfigFile  string
    42  	versionCheck    bool
    43  
    44  	configFiles = []string{os.ExpandEnv("$HOME/.config/amtool/config.yml"), "/etc/amtool/config.yml"}
    45  	legacyFlags = map[string]string{"comment_required": "require-comment"}
    46  )
    47  
    48  func requireAlertManagerURL(pc *kingpin.ParseContext) error {
    49  	// Return without error if any help flag is set.
    50  	for _, elem := range pc.Elements {
    51  		f, ok := elem.Clause.(*kingpin.FlagClause)
    52  		if !ok {
    53  			continue
    54  		}
    55  		name := f.Model().Name
    56  		if name == "help" || name == "help-long" || name == "help-man" {
    57  			return nil
    58  		}
    59  	}
    60  	if alertmanagerURL == nil {
    61  		kingpin.Fatalf("required flag --alertmanager.url not provided")
    62  	}
    63  	return nil
    64  }
    65  
    66  const (
    67  	defaultAmHost      = "localhost"
    68  	defaultAmPort      = "9093"
    69  	defaultAmApiv2path = "/api/v2"
    70  )
    71  
    72  // NewAlertmanagerClient initializes an alertmanager client with the given URL
    73  func NewAlertmanagerClient(amURL *url.URL) *client.AlertmanagerAPI {
    74  	address := defaultAmHost + ":" + defaultAmPort
    75  	schemes := []string{"http"}
    76  
    77  	if amURL.Host != "" {
    78  		address = amURL.Host // URL documents host as host or host:port
    79  	}
    80  	if amURL.Scheme != "" {
    81  		schemes = []string{amURL.Scheme}
    82  	}
    83  
    84  	cr := clientruntime.New(address, path.Join(amURL.Path, defaultAmApiv2path), schemes)
    85  
    86  	if amURL.User != nil && httpConfigFile != "" {
    87  		kingpin.Fatalf("basic authentication and http.config.file are mutually exclusive")
    88  	}
    89  
    90  	if amURL.User != nil {
    91  		password, _ := amURL.User.Password()
    92  		cr.DefaultAuthentication = clientruntime.BasicAuth(amURL.User.Username(), password)
    93  	}
    94  
    95  	if httpConfigFile != "" {
    96  		var err error
    97  		httpConfig, _, err := promconfig.LoadHTTPConfigFile(httpConfigFile)
    98  		if err != nil {
    99  			kingpin.Fatalf("failed to load HTTP config file: %v", err)
   100  		}
   101  
   102  		httpclient, err := promconfig.NewClientFromConfig(*httpConfig, "amtool")
   103  		if err != nil {
   104  			kingpin.Fatalf("failed to create a new HTTP client: %v", err)
   105  		}
   106  		cr = clientruntime.NewWithClient(address, path.Join(amURL.Path, defaultAmApiv2path), schemes, httpclient)
   107  	}
   108  
   109  	c := client.New(cr, strfmt.Default)
   110  
   111  	if !versionCheck {
   112  		return c
   113  	}
   114  
   115  	status, err := c.General.GetStatus(nil)
   116  	if err != nil || status.Payload.VersionInfo == nil || version.Version == "" {
   117  		// We can not get version info, or we do not know our own version. Let amtool continue.
   118  		return c
   119  	}
   120  
   121  	if semver.MajorMinor("v"+*status.Payload.VersionInfo.Version) != semver.MajorMinor("v"+version.Version) {
   122  		fmt.Fprintf(os.Stderr, "Warning: amtool version (%s) and alertmanager version (%s) are different.\n", version.Version, *status.Payload.VersionInfo.Version)
   123  	}
   124  
   125  	return c
   126  }
   127  
   128  // Execute is the main function for the amtool command
   129  func Execute() {
   130  	app := kingpin.New("amtool", helpRoot).UsageWriter(os.Stdout)
   131  
   132  	format.InitFormatFlags(app)
   133  
   134  	app.Flag("verbose", "Verbose running information").Short('v').BoolVar(&verbose)
   135  	app.Flag("alertmanager.url", "Alertmanager to talk to").URLVar(&alertmanagerURL)
   136  	app.Flag("output", "Output formatter (simple, extended, json)").Short('o').Default("simple").EnumVar(&output, "simple", "extended", "json")
   137  	app.Flag("timeout", "Timeout for the executed command").Default("30s").DurationVar(&timeout)
   138  	app.Flag("http.config.file", "HTTP client configuration file for amtool to connect to Alertmanager.").PlaceHolder("<filename>").ExistingFileVar(&httpConfigFile)
   139  	app.Flag("version-check", "Check alertmanager version. Use --no-version-check to disable.").Default("true").BoolVar(&versionCheck)
   140  
   141  	app.Version(version.Print("amtool"))
   142  	app.GetFlag("help").Short('h')
   143  	app.UsageTemplate(kingpin.CompactUsageTemplate)
   144  
   145  	resolver, err := config.NewResolver(configFiles, legacyFlags)
   146  	if err != nil {
   147  		kingpin.Fatalf("could not load config file: %v\n", err)
   148  	}
   149  
   150  	configureAlertCmd(app)
   151  	configureSilenceCmd(app)
   152  	configureCheckConfigCmd(app)
   153  	configureClusterCmd(app)
   154  	configureConfigCmd(app)
   155  	configureTemplateCmd(app)
   156  
   157  	err = resolver.Bind(app, os.Args[1:])
   158  	if err != nil {
   159  		kingpin.Fatalf("%v\n", err)
   160  	}
   161  
   162  	_, err = app.Parse(os.Args[1:])
   163  	if err != nil {
   164  		kingpin.Fatalf("%v\n", err)
   165  	}
   166  }
   167  
   168  const (
   169  	helpRoot = `View and modify the current Alertmanager state.
   170  
   171  Config File:
   172  The alertmanager tool will read a config file in YAML format from one of two
   173  default config locations: $HOME/.config/amtool/config.yml or
   174  /etc/amtool/config.yml
   175  
   176  All flags can be given in the config file, but the following are the suited for
   177  static configuration:
   178  
   179  	alertmanager.url
   180  		Set a default alertmanager url for each request
   181  
   182  	author
   183  		Set a default author value for new silences. If this argument is not
   184  		specified then the username will be used
   185  
   186  	require-comment
   187  		Bool, whether to require a comment on silence creation. Defaults to true
   188  
   189  	output
   190  		Set a default output type. Options are (simple, extended, json)
   191  
   192  	date.format
   193  		Sets the output format for dates. Defaults to "2006-01-02 15:04:05 MST"
   194  
   195  	http.config.file
   196  		HTTP client configuration file for amtool to connect to Alertmanager.
   197  		The format is https://prometheus.io/docs/alerting/latest/configuration/#http_config.
   198  `
   199  )
   200  

View as plain text