Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

operator: Add namespace and tenantId labels to RecordingRules #9971

Merged
merged 5 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions operator/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## Main

- [9971](https://github.com/grafana/loki/pull/9971) **aminesnow**: Add namespace and tenantId labels to RecordingRules
- [9963](https://github.com/grafana/loki/pull/9963) **xperimental**: Fix application tenant alertmanager configuration
- [9795](https://github.com/grafana/loki/pull/9795) **JoaoBraveCoding**: Add initContainer to zone aware components to gatekeep them from starting without the AZ annotation
- [9503](https://github.com/grafana/loki/pull/9503) **shwetaap**: Add Pod annotations with node topology labels to support zone aware scheduling
Expand Down
7 changes: 7 additions & 0 deletions operator/apis/loki/v1/recordingrule_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ type RecordingRuleGroupSpec struct {
// +kubebuilder:validation:Required
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="LogQL Expression"
Expr string `json:"expr"`

// Labels to add to each recording rule.
//
// +optional
// +kubebuilder:validation:Optional
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Labels"
Labels map[string]string `json:"labels,omitempty"`
}

// RecordingRuleStatus defines the observed state of RecordingRule
Expand Down
9 changes: 8 additions & 1 deletion operator/apis/loki/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,9 @@ spec:
alerts.
displayName: LogQL Expression
path: groups[0].rules[0].expr
- description: Labels to add to each recording rule.
displayName: Labels
path: groups[0].rules[0].labels
- description: The name of the time series to output to. Must be a valid metric
name.
displayName: Metric Name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ spec:
cycle this is evaluated at the current time, and all
resultant time series become pending/firing alerts.
type: string
labels:
additionalProperties:
type: string
description: Labels to add to each recording rule.
type: object
record:
description: The name of the time series to output to.
Must be a valid metric name.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ spec:
cycle this is evaluated at the current time, and all
resultant time series become pending/firing alerts.
type: string
labels:
additionalProperties:
type: string
description: Labels to add to each recording rule.
type: object
record:
description: The name of the time series to output to.
Must be a valid metric name.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,9 @@ spec:
alerts.
displayName: LogQL Expression
path: groups[0].rules[0].expr
- description: Labels to add to each recording rule.
displayName: Labels
path: groups[0].rules[0].labels
- description: The name of the time series to output to. Must be a valid metric
name.
displayName: Metric Name
Expand Down
10 changes: 10 additions & 0 deletions operator/internal/manifests/internal/rules/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ func MarshalRecordingRule(a lokiv1.RecordingRule) (string, error) {
Groups: aa.Spec.Groups,
}

for _, group := range ar.Groups {
for _, rule := range group.Rules {
if rule.Labels == nil {
rule.Labels = map[string]string{}
}

rule.Labels[tenantLabel] = aa.Spec.TenantID
}
}

content, err := yaml.Marshal(ar)
if err != nil {
return "", kverrors.Wrap(err, "failed to marshal recording rule", "name", aa.Name, "namespace", aa.Namespace)
Expand Down
13 changes: 13 additions & 0 deletions operator/internal/manifests/internal/rules/marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
lokiv1 "github.com/grafana/loki/operator/apis/loki/v1"
"github.com/grafana/loki/operator/internal/manifests/internal/rules"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestMarshalAlertingRule(t *testing.T) {
Expand Down Expand Up @@ -109,15 +110,24 @@ groups:
rate({container="nginx"}[1m])
)
record: nginx:requests:rate1m
labels:
tenantId: a-tenant
environment: test
- expr: |-
sum(
rate({container="banana"}[5m])
)
record: banana:requests:rate5m
labels:
tenantId: a-tenant
`

r := lokiv1.RecordingRule{
ObjectMeta: metav1.ObjectMeta{
Namespace: "test-ns",
},
Spec: lokiv1.RecordingRuleSpec{
TenantID: "a-tenant",
Groups: []*lokiv1.RecordingRuleGroup{
{
Name: "a-recording",
Expand All @@ -129,6 +139,9 @@ groups:
rate({container="nginx"}[1m])
)`,
Record: "nginx:requests:rate1m",
Labels: map[string]string{
"environment": "test",
},
},
{
Expr: `sum(
Expand Down
195 changes: 195 additions & 0 deletions operator/internal/manifests/openshift/recordingrule_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package openshift

import (
"testing"

lokiv1 "github.com/grafana/loki/operator/apis/loki/v1"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestRecordingRuleTenantLabels(t *testing.T) {
tt := []struct {
rule *lokiv1.RecordingRule
want *lokiv1.RecordingRule
}{
{
rule: &lokiv1.RecordingRule{
ObjectMeta: metav1.ObjectMeta{
Namespace: "test-ns",
},
Spec: lokiv1.RecordingRuleSpec{
TenantID: tenantApplication,
Groups: []*lokiv1.RecordingRuleGroup{
{
Name: "test-group",
Rules: []*lokiv1.RecordingRuleGroupSpec{
{
Record: "record",
},
},
},
},
},
},
want: &lokiv1.RecordingRule{
ObjectMeta: metav1.ObjectMeta{
Namespace: "test-ns",
},
Spec: lokiv1.RecordingRuleSpec{
TenantID: tenantApplication,
Groups: []*lokiv1.RecordingRuleGroup{
{
Name: "test-group",
Rules: []*lokiv1.RecordingRuleGroupSpec{
{
Record: "record",
Labels: map[string]string{
opaDefaultLabelMatcher: "test-ns",
},
},
},
},
},
},
},
},
{
rule: &lokiv1.RecordingRule{
Spec: lokiv1.RecordingRuleSpec{
TenantID: tenantInfrastructure,
Groups: []*lokiv1.RecordingRuleGroup{
{
Name: "test-group",
Rules: []*lokiv1.RecordingRuleGroupSpec{
{
Record: "record",
},
},
},
},
},
},
want: &lokiv1.RecordingRule{
Spec: lokiv1.RecordingRuleSpec{
TenantID: tenantInfrastructure,
Groups: []*lokiv1.RecordingRuleGroup{
{
Name: "test-group",
Rules: []*lokiv1.RecordingRuleGroupSpec{
{
Record: "record",
},
},
},
},
},
},
},
{
rule: &lokiv1.RecordingRule{
Spec: lokiv1.RecordingRuleSpec{
TenantID: tenantAudit,
Groups: []*lokiv1.RecordingRuleGroup{
{
Name: "test-group",
Rules: []*lokiv1.RecordingRuleGroupSpec{
{
Record: "record",
},
},
},
},
},
},
want: &lokiv1.RecordingRule{
Spec: lokiv1.RecordingRuleSpec{
TenantID: tenantAudit,
Groups: []*lokiv1.RecordingRuleGroup{
{
Name: "test-group",
Rules: []*lokiv1.RecordingRuleGroupSpec{
{
Record: "record",
},
},
},
},
},
},
},
{
rule: &lokiv1.RecordingRule{
Spec: lokiv1.RecordingRuleSpec{
TenantID: tenantNetwork,
Groups: []*lokiv1.RecordingRuleGroup{
{
Name: "test-group",
Rules: []*lokiv1.RecordingRuleGroupSpec{
{
Record: "record",
},
},
},
},
},
},
want: &lokiv1.RecordingRule{
Spec: lokiv1.RecordingRuleSpec{
TenantID: tenantNetwork,
Groups: []*lokiv1.RecordingRuleGroup{
{
Name: "test-group",
Rules: []*lokiv1.RecordingRuleGroupSpec{
{
Record: "record",
},
},
},
},
},
},
},
{
rule: &lokiv1.RecordingRule{
Spec: lokiv1.RecordingRuleSpec{
TenantID: "unknown",
Groups: []*lokiv1.RecordingRuleGroup{
{
Name: "test-group",
Rules: []*lokiv1.RecordingRuleGroupSpec{
{
Record: "record",
},
},
},
},
},
},
want: &lokiv1.RecordingRule{
Spec: lokiv1.RecordingRuleSpec{
TenantID: "unknown",
Groups: []*lokiv1.RecordingRuleGroup{
{
Name: "test-group",
Rules: []*lokiv1.RecordingRuleGroupSpec{
{
Record: "record",
},
},
},
},
},
},
},
}
for _, tc := range tt {
tc := tc
t.Run(tc.rule.Spec.TenantID, func(t *testing.T) {
t.Parallel()
RecordingRuleTenantLabels(tc.rule)

require.Equal(t, tc.want, tc.rule)
})
}
}
27 changes: 27 additions & 0 deletions operator/internal/manifests/openshift/recordngrule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package openshift

import lokiv1 "github.com/grafana/loki/operator/apis/loki/v1"

func RecordingRuleTenantLabels(r *lokiv1.RecordingRule) {
switch r.Spec.TenantID {
case tenantApplication:
for groupIdx, group := range r.Spec.Groups {
group := group
for ruleIdx, rule := range group.Rules {
rule := rule
if rule.Labels == nil {
rule.Labels = map[string]string{}
}
rule.Labels[opaDefaultLabelMatcher] = r.Namespace
group.Rules[ruleIdx] = rule
}
r.Spec.Groups[groupIdx] = group
}
case tenantInfrastructure, tenantAudit:
// Do nothing
case tenantNetwork:
// Do nothing
default:
// Do nothing
}
}
16 changes: 16 additions & 0 deletions operator/internal/manifests/rules_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ func RulesConfigMapShards(opts *Options) ([]*corev1.ConfigMap, error) {
}

for _, r := range opts.RecordingRules {
r := r
if opts.Stack.Tenants != nil {
configureRecordingRuleForMode(&r, opts.Stack.Tenants.Mode)
}

c, err := rules.MarshalRecordingRule(r)
if err != nil {
return nil, err
Expand Down Expand Up @@ -91,3 +96,14 @@ func configureAlertingRuleForMode(ar *lokiv1.AlertingRule, mode lokiv1.ModeType)
// Do nothing
}
}

func configureRecordingRuleForMode(r *lokiv1.RecordingRule, mode lokiv1.ModeType) {
switch mode {
case lokiv1.Static, lokiv1.Dynamic:
// Do nothing
case lokiv1.OpenshiftLogging:
openshift.RecordingRuleTenantLabels(r)
case lokiv1.OpenshiftNetwork:
// Do nothing
}
}