forked from prometheus/alertmanager
-
Notifications
You must be signed in to change notification settings - Fork 0
/
root.go
180 lines (153 loc) · 4.76 KB
/
root.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package cli
import (
"io/ioutil"
"os"
"github.com/alecthomas/kingpin"
"github.com/prometheus/alertmanager/cli/format"
"github.com/prometheus/common/version"
"gopkg.in/yaml.v2"
)
var (
app = kingpin.New("amtool", "Alertmanager CLI").DefaultEnvars()
verbose = app.Flag("verbose", "Verbose running information").Short('v').Bool()
alertmanagerUrl = app.Flag("alertmanager.url", "Alertmanager to talk to").Required().URL()
output = app.Flag("output", "Output formatter (simple, extended, json)").Short('o').Default("simple").Enum("simple", "extended", "json")
// This contains a mapping from command path to the long-format help string
// Separate subcommands with spaces, eg longHelpText["silence query"]
longHelpText = make(map[string]string)
)
type amtoolConfigResolver struct {
configData []map[string]string
}
func newConfigResolver() (amtoolConfigResolver, error) {
files := []string{
os.ExpandEnv("$HOME/.config/amtool/config.yml"),
"/etc/amtool/config.yml",
}
resolver := amtoolConfigResolver{
configData: make([]map[string]string, 0),
}
for _, f := range files {
b, err := ioutil.ReadFile(f)
if err != nil {
if os.IsNotExist(err) {
continue
}
return resolver, err
}
var config map[string]string
err = yaml.Unmarshal(b, &config)
if err != nil {
return resolver, err
}
resolver.configData = append(resolver.configData, config)
}
return resolver, nil
}
func (r amtoolConfigResolver) Resolve(key string, context *kingpin.ParseContext) ([]string, error) {
for _, c := range r.configData {
if v, ok := c[key]; ok {
return []string{v}, nil
}
}
return nil, nil
}
// This function maps things which have previously had different names in the
// config file to their new names, so old configurations keep working
func backwardsCompatibilityResolver(key string) string {
switch key {
case "require-comment":
return "comment_required"
}
return key
}
func init() {
longHelpText["root"] = `View and modify the current Alertmanager state.
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:
alertmanager.url
Set a default alertmanager url for each request
author
Set a default author value for new silences. If this argument is not
specified then the username will be used
require-comment
Bool, whether to require a comment on silence creation. Defaults to true
output
Set a default output type. Options are (simple, extended, json)
date.format
Sets the output format for dates. Defaults to "2006-01-02 15:04:05 MST"
`
}
// Execute parses the arguments and executes the corresponding command, it is
// called by cmd/amtool/main.main().
func Execute() {
format.InitFormatFlags(app)
app.Version(version.Print("amtool"))
app.GetFlag("help").Short('h')
app.UsageTemplate(kingpin.CompactUsageTemplate)
app.Flag("help-long", "Give more detailed help output").UsageAction(&kingpin.UsageContext{
Template: longHelpTemplate,
Vars: map[string]interface{}{"LongHelp": longHelpText},
}).Bool()
configResolver, err := newConfigResolver()
if err != nil {
kingpin.Fatalf("could not load config file: %v\n", err)
}
// Use the same resolver twice, first for checking backwards compatibility,
// then again for the new names. This order ensures that the newest wins, if
// both old and new are present
app.Resolver(
kingpin.RenamingResolver(configResolver, backwardsCompatibilityResolver),
configResolver,
)
_, err = app.Parse(os.Args[1:])
if err != nil {
kingpin.Fatalf("%v\n", err)
}
}
const longHelpTemplate = `{{define "FormatCommands" -}}
{{range .FlattenedCommands -}}
{{if not .Hidden}}
{{.CmdSummary}}
{{.Help|Wrap 4}}
{{if .Flags -}}
{{with .Flags|FlagsToTwoColumns}}{{FormatTwoColumnsWithIndent . 4 2}}{{end}}
{{end -}}
{{end -}}
{{end -}}
{{end -}}
{{define "FormatUsage" -}}
{{.AppSummary}}
{{if .Help}}
{{.Help|Wrap 0 -}}
{{end -}}
{{end -}}
{{if .Context.SelectedCommand -}}
{{T "usage:"}} {{.App.Name}} {{.App.FlagSummary}} {{.Context.SelectedCommand.CmdSummary}}
{{index .LongHelp .Context.SelectedCommand.FullCommand}}
{{else}}
{{T "usage:"}} {{template "FormatUsage" .App}}
{{index .LongHelp "root"}}
{{end}}
{{if .Context.Flags -}}
{{T "Flags:"}}
{{.Context.Flags|FlagsToTwoColumns|FormatTwoColumns}}
{{end -}}
{{if .Context.Args -}}
{{T "Args:"}}
{{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}}
{{end -}}
{{if .Context.SelectedCommand -}}
{{if len .Context.SelectedCommand.Commands -}}
{{T "Subcommands:"}}
{{template "FormatCommands" .Context.SelectedCommand}}
{{end -}}
{{else if .App.Commands -}}
{{T "Commands:" -}}
{{template "FormatCommands" .App}}
{{end -}}
`