Skip to content

Commit cb76276

Browse files
author
Guðmundur Björn Birkisson
authored
Add id-labels flag (#3)
1 parent 16634a2 commit cb76276

File tree

7 files changed

+44
-6
lines changed

7 files changed

+44
-6
lines changed

cmd/sloth/commands/generate.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,23 @@ type generateCommand struct {
3636
disableAlerts bool
3737
disableOptimizedRules bool
3838
extraLabels map[string]string
39+
idLabels map[string]string
3940
sliPluginsPaths []string
4041
sloPeriodWindowsPath string
4142
sloPeriod string
4243
}
4344

4445
// NewGenerateCommand returns the generate command.
4546
func NewGenerateCommand(app *kingpin.Application) Command {
46-
c := &generateCommand{extraLabels: map[string]string{}}
47+
c := &generateCommand{extraLabels: map[string]string{}, idLabels: map[string]string{}}
4748
cmd := app.Command("generate", "Generates Prometheus SLOs.")
4849
cmd.Flag("input", "SLO spec input file path or directory (if directory is used, slos will be discovered recursively and out must be a directory).").Short('i').StringVar(&c.slosInput)
4950
cmd.Flag("out", "Generated rules output file path or directory. If `-` it will use stdout (if input is a directory this must be a directory).").Default("-").Short('o').StringVar(&c.slosOut)
5051
cmd.Flag("fs-exclude", "Filter regex to ignore matched discovered SLO file paths (used with directory based input/output).").Short('e').StringVar(&c.slosExcludeRegex)
5152
cmd.Flag("fs-include", "Filter regex to include matched discovered SLO file paths, everything else will be ignored. Exclude has preference (used with directory based input/output).").Short('n').StringVar(&c.slosIncludeRegex)
5253

5354
cmd.Flag("extra-labels", "Extra labels that will be added to all the generated Prometheus rules ('key=value' form, can be repeated).").Short('l').StringMapVar(&c.extraLabels)
55+
cmd.Flag("id-labels", "Id labels that used as filters for generated recording rules. These will also be added as extra labels ('key=value' form, can be repeated).").Short('d').StringMapVar(&c.idLabels)
5456
cmd.Flag("disable-recordings", "Disables recording rules generation.").BoolVar(&c.disableRecordings)
5557
cmd.Flag("disable-alerts", "Disables alert rules generation.").BoolVar(&c.disableAlerts)
5658
cmd.Flag("sli-plugins-path", "The path to SLI plugins (can be repeated), if not set it disable plugins support.").Short('p').StringsVar(&c.sliPluginsPaths)
@@ -94,6 +96,11 @@ func (g generateCommand) Run(ctx context.Context, config RootConfig) error {
9496
}
9597
}
9698

99+
// Make sure id labels are set in extra labels as well
100+
for key, value := range g.idLabels {
101+
g.extraLabels[key] = value
102+
}
103+
97104
// SLO period.
98105
sp, err := prometheusmodel.ParseDuration(g.sloPeriod)
99106
if err != nil {
@@ -245,6 +252,7 @@ func (g generateCommand) Run(ctx context.Context, config RootConfig) error {
245252
disableAlerts: g.disableAlerts,
246253
disableOptimizedRules: g.disableOptimizedRules,
247254
extraLabels: g.extraLabels,
255+
idLabels: g.idLabels,
248256
}
249257

250258
for _, genTarget := range genTargets {
@@ -305,6 +313,7 @@ type generator struct {
305313
disableAlerts bool
306314
disableOptimizedRules bool
307315
extraLabels map[string]string
316+
idLabels map[string]string
308317
}
309318

310319
// GeneratePrometheus generates the SLOs based on a raw regular Prometheus spec format input and outs a Prometheus raw yaml.
@@ -434,6 +443,7 @@ func (g generator) generateRules(ctx context.Context, info info.Info, slos prome
434443

435444
result, err := controller.Generate(ctx, generate.Request{
436445
ExtraLabels: g.extraLabels,
446+
IDLabels: g.idLabels,
437447
Info: info,
438448
SLOGroup: slos,
439449
})

cmd/sloth/commands/k8scontroller.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ const (
5353

5454
type kubeControllerCommand struct {
5555
extraLabels map[string]string
56+
idLabels map[string]string
5657
workers int
5758
kubeConfig string
5859
kubeContext string
@@ -73,7 +74,7 @@ type kubeControllerCommand struct {
7374

7475
// NewKubeControllerCommand returns the Kubernetes controller command.
7576
func NewKubeControllerCommand(app *kingpin.Application) Command {
76-
c := &kubeControllerCommand{extraLabels: map[string]string{}}
77+
c := &kubeControllerCommand{extraLabels: map[string]string{}, idLabels: map[string]string{}}
7778
cmd := app.Command("kubernetes-controller", "Runs Sloth in Kubernetes controller/operator mode.")
7879
cmd.Alias("controller")
7980
cmd.Alias("k8s-controller")
@@ -92,6 +93,7 @@ func NewKubeControllerCommand(app *kingpin.Application) Command {
9293
cmd.Flag("hot-reload-addr", "The listen address for hot-reloading components that allow it.").Default(":8082").StringVar(&c.hotReloadAddr)
9394
cmd.Flag("hot-reload-path", "The webhook path for hot-reloading components that allow it.").Default("/-/reload").StringVar(&c.hotReloadPath)
9495
cmd.Flag("extra-labels", "Extra labels that will be added to all the generated Prometheus rules ('key=value' form, can be repeated).").Short('l').StringMapVar(&c.extraLabels)
96+
cmd.Flag("id-labels", "Id labels that used as filters for generated recording rules. These will also be added as extra labels ('key=value' form, can be repeated).").Short('d').StringMapVar(&c.idLabels)
9597
cmd.Flag("sli-plugins-path", "The path to SLI plugins (can be repeated), if not set it disable plugins support.").Short('p').StringsVar(&c.sliPluginsPaths)
9698
cmd.Flag("slo-period-windows-path", "The directory path to custom SLO period windows catalog (replaces default ones).").StringVar(&c.sloPeriodWindowsPath)
9799
cmd.Flag("default-slo-period", "The default SLO period windows to be used for the SLOs.").Default("30d").StringVar(&c.sloPeriod)
@@ -104,6 +106,11 @@ func (k kubeControllerCommand) Name() string { return "kubernetes-controller" }
104106
func (k kubeControllerCommand) Run(ctx context.Context, config RootConfig) error {
105107
logger := config.Logger.WithValues(log.Kv{"window": k.sloPeriod})
106108

109+
// Make sure id labels are set in extra labels as well
110+
for key, value := range k.idLabels {
111+
k.extraLabels[key] = value
112+
}
113+
107114
// SLO period.
108115
sp, err := prometheusmodel.ParseDuration(k.sloPeriod)
109116
if err != nil {
@@ -323,6 +330,7 @@ func (k kubeControllerCommand) Run(ctx context.Context, config RootConfig) error
323330
Repository: k8sprometheus.NewPrometheusOperatorCRDRepo(ksvc, logger),
324331
KubeStatusStorer: ksvc,
325332
ExtraLabels: k.extraLabels,
333+
IDLabels: k.idLabels,
326334
Logger: logger,
327335
}
328336
handler, err := kubecontroller.NewHandler(config)

cmd/sloth/commands/validate.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,21 @@ type validateCommand struct {
2424
slosExcludeRegex string
2525
slosIncludeRegex string
2626
extraLabels map[string]string
27+
idLabels map[string]string
2728
sliPluginsPaths []string
2829
sloPeriodWindowsPath string
2930
sloPeriod string
3031
}
3132

3233
// NewValidateCommand returns the validate command.
3334
func NewValidateCommand(app *kingpin.Application) Command {
34-
c := &validateCommand{extraLabels: map[string]string{}}
35+
c := &validateCommand{extraLabels: map[string]string{}, idLabels: map[string]string{}}
3536
cmd := app.Command("validate", "Validates the SLO manifests and generation of Prometheus SLOs.")
3637
cmd.Flag("input", "SLO spec discovery path, will discover recursively all YAML files.").Short('i').Required().StringVar(&c.slosInput)
3738
cmd.Flag("fs-exclude", "Filter regex to ignore matched discovered SLO file paths.").Short('e').StringVar(&c.slosExcludeRegex)
3839
cmd.Flag("fs-include", "Filter regex to include matched discovered SLO file paths, everything else will be ignored. Exclude has preference.").Short('n').StringVar(&c.slosIncludeRegex)
3940
cmd.Flag("extra-labels", "Extra labels that will be added to all the generated Prometheus rules ('key=value' form, can be repeated).").Short('l').StringMapVar(&c.extraLabels)
41+
cmd.Flag("id-labels", "Id labels that used as filters for generated recording rules. These will also be added as extra labels ('key=value' form, can be repeated).").Short('d').StringMapVar(&c.idLabels)
4042
cmd.Flag("sli-plugins-path", "The path to SLI plugins (can be repeated), if not set it disable plugins support.").Short('p').StringsVar(&c.sliPluginsPaths)
4143
cmd.Flag("slo-period-windows-path", "The directory path to custom SLO period windows catalog (replaces default ones).").StringVar(&c.sloPeriodWindowsPath)
4244
cmd.Flag("default-slo-period", "The default SLO period windows to be used for the SLOs.").Default("30d").StringVar(&c.sloPeriod)
@@ -48,6 +50,11 @@ func (v validateCommand) Name() string { return "validate" }
4850
func (v validateCommand) Run(ctx context.Context, config RootConfig) error {
4951
logger := config.Logger.WithValues(log.Kv{"window": v.sloPeriod})
5052

53+
// Make sure id labels are set in extra labels as well
54+
for key, value := range v.idLabels {
55+
v.extraLabels[key] = value
56+
}
57+
5158
// SLO period.
5259
sp, err := prometheusmodel.ParseDuration(v.sloPeriod)
5360
if err != nil {
@@ -129,6 +136,7 @@ func (v validateCommand) Run(ctx context.Context, config RootConfig) error {
129136
logger: log.Noop,
130137
windowsRepo: windowsRepo,
131138
extraLabels: v.extraLabels,
139+
idLabels: v.idLabels,
132140
}
133141

134142
// Prepare file validation result and start validation result for every SLO in the file.

internal/app/generate/prometheus.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ type Request struct {
9696
Info info.Info
9797
// ExtraLabels are the extra labels added to the SLOs on execution time.
9898
ExtraLabels map[string]string
99+
// IDLabels are the extra labels added to the SLOs recording rules on execution time.
100+
IDLabels map[string]string
99101
// SLOGroup are the SLOs group that will be used to generate the SLO results and Prom rules.
100102
SLOGroup prometheus.SLOGroup
101103
}
@@ -121,6 +123,7 @@ func (s Service) Generate(ctx context.Context, r Request) (*Response, error) {
121123
for _, slo := range r.SLOGroup.SLOs {
122124
// Add extra labels.
123125
slo.Labels = mergeLabels(slo.Labels, r.ExtraLabels)
126+
slo.IDLabels = r.IDLabels
124127

125128
// Generate SLO result.
126129
result, err := s.generateSLO(ctx, r.Info, slo)

internal/app/kubecontroller/handler.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type HandlerConfig struct {
4242
Repository Repository
4343
KubeStatusStorer KubeStatusStorer
4444
ExtraLabels map[string]string
45+
IDLabels map[string]string
4546
// IgnoreHandleBefore makes the handles of objects with a success state and no spec change,
4647
// be ignored if the last success is less than this setting.
4748
// Be aware that this setting should be less than the controller resync interval.
@@ -66,6 +67,10 @@ func (c *HandlerConfig) defaults() error {
6667
c.ExtraLabels = map[string]string{}
6768
}
6869

70+
if c.IDLabels == nil {
71+
c.IDLabels = map[string]string{}
72+
}
73+
6974
if c.Repository == nil {
7075
return fmt.Errorf("repository is required")
7176
}
@@ -88,6 +93,7 @@ type handler struct {
8893
repository Repository
8994
kubeStatusStorer KubeStatusStorer
9095
extraLabels map[string]string
96+
IDLabels map[string]string
9197
ignoreHandleBefore time.Duration
9298
logger log.Logger
9399
}
@@ -103,6 +109,7 @@ func NewHandler(config HandlerConfig) (controller.Handler, error) {
103109
repository: config.Repository,
104110
kubeStatusStorer: config.KubeStatusStorer,
105111
extraLabels: config.ExtraLabels,
112+
IDLabels: config.IDLabels,
106113
ignoreHandleBefore: config.IgnoreHandleBefore,
107114
logger: config.Logger,
108115
}, nil
@@ -152,6 +159,7 @@ func (h handler) handlePrometheusServiceLevelV1(ctx context.Context, psl *slothv
152159
Spec: fmt.Sprintf("%s/%s", slothv1.SchemeGroupVersion.Group, slothv1.SchemeGroupVersion.Version),
153160
},
154161
ExtraLabels: h.extraLabels,
162+
IDLabels: h.IDLabels,
155163
SLOGroup: model.SLOGroup,
156164
}
157165
resp, err := h.generator.Generate(ctx, req)

internal/prometheus/alert_rules.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func defaultSLOAlertGenerator(slo SLO, sloAlert AlertMeta, quick, slow alert.MWM
101101
Alert: sloAlert.Name,
102102
Expr: expr.String(),
103103
Annotations: mergeLabels(extraAnnotations, sloAlert.Annotations),
104-
Labels: mergeLabels(extraLabels, sloAlert.Labels),
104+
Labels: mergeLabels(extraLabels, sloAlert.Labels, slo.IDLabels),
105105
}, nil
106106
}
107107

internal/prometheus/model.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type SLO struct {
4747
TimeWindow time.Duration `validate:"required"`
4848
Objective float64 `validate:"gt=0,lte=100"`
4949
Labels map[string]string `validate:"dive,keys,prom_label_key,endkeys,required,prom_label_value"`
50+
IDLabels map[string]string `validate:"dive,keys,prom_label_key,endkeys,required,prom_label_value"`
5051
PageAlertMeta AlertMeta
5152
TicketAlertMeta AlertMeta
5253
}
@@ -68,11 +69,11 @@ func (s SLO) GetSLIErrorMetric(window time.Duration) string {
6869
// GetSLOIDPromLabels returns the ID labels of an SLO, these can be used to identify
6970
// an SLO recorded metrics and alerts.
7071
func (s SLO) GetSLOIDPromLabels() map[string]string {
71-
return map[string]string{
72+
return mergeLabels(map[string]string{
7273
sloIDLabelName: s.ID,
7374
sloNameLabelName: s.Name,
7475
sloServiceLabelName: s.Service,
75-
}
76+
}, s.IDLabels)
7677
}
7778

7879
var modelSpecValidate = func() *validator.Validate {

0 commit comments

Comments
 (0)