From 297981d062d431ad98f684e6549d46f2b9a5d36d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 13:40:34 +0800 Subject: [PATCH 01/10] Bump golang.org/x/net from 0.17.0 to 0.23.0 (#261) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.17.0 to 0.23.0. - [Commits](https://github.com/golang/net/compare/v0.17.0...v0.23.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 17 +++++++++-------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index a252af8..07c9ad8 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.15.7 github.com/aws/aws-sdk-go-v2/credentials v1.12.2 github.com/aws/aws-sdk-go-v2/service/sns v1.17.6 + github.com/duke-git/lancet/v2 v2.2.9 github.com/emicklei/go-restful v2.16.0+incompatible github.com/go-chi/chi v4.0.3+incompatible github.com/go-kit/kit v0.9.0 @@ -54,7 +55,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/duke-git/lancet/v2 v2.2.9 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect @@ -89,11 +89,11 @@ require ( go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/net v0.23.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.12.0 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect diff --git a/go.sum b/go.sum index a04e1ed..f5e3030 100644 --- a/go.sum +++ b/go.sum @@ -252,6 +252,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -266,8 +267,8 @@ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -291,16 +292,16 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From cbe073c53a5291058555bc52539b1799c2bf1f1a Mon Sep 17 00:00:00 2001 From: Mohamed Rafraf <81432497+mohamed-rafraf@users.noreply.github.com> Date: Thu, 9 May 2024 13:56:54 +0100 Subject: [PATCH 02/10] Fix Typo in documentation --- docs/crds/silence.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/crds/silence.md b/docs/crds/silence.md index 7e8633d..d0ace87 100644 --- a/docs/crds/silence.md +++ b/docs/crds/silence.md @@ -2,7 +2,7 @@ ## Overview -`slience` CRD is used to define policies to mute notifications for a given time. A silence is configured based on a label selector. +`Silence` CRD is used to define policies to mute notifications for a given time. A silence is configured based on a label selector. If the incoming alert matches the label selector of an active silence, no notifications will be sent out for that alert. `Silence` can be categorized into 2 types `global` and `tenant` by label like `type = global`, `type = tenant` : From 2e504e6d33a873783b36c8d792835deb31c2cb80 Mon Sep 17 00:00:00 2001 From: wanjunlei Date: Mon, 13 May 2024 09:58:02 +0800 Subject: [PATCH 03/10] support to get tenant info from multiple cluster Signed-off-by: wanjunlei --- .github/workflows/push-sidecar-image.yaml | 75 ++++++++ config/samples/template.yaml | 2 +- pkg/constants/constants.go | 1 + pkg/controller/controller.go | 11 +- pkg/route/router.go | 17 +- sidecar/kubesphere/4.0.0/Makefile | 2 +- sidecar/kubesphere/4.0.0/backend.go | 169 ++++++++++--------- sidecar/kubesphere/4.0.0/main.go | 14 +- sidecar/kubesphere/4.0.0/test/get-tenants.sh | 2 +- 9 files changed, 196 insertions(+), 97 deletions(-) create mode 100644 .github/workflows/push-sidecar-image.yaml diff --git a/.github/workflows/push-sidecar-image.yaml b/.github/workflows/push-sidecar-image.yaml new file mode 100644 index 0000000..f6df8a2 --- /dev/null +++ b/.github/workflows/push-sidecar-image.yaml @@ -0,0 +1,75 @@ +# +# Copyright 2022 The Notification-Manager Authors. +# +# 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. +# + +name: WorkFlow for Building sidecar image + +on: + push: + branches: + - 'master' + paths: + - '.github/workflows/push-sidecar-image.yaml' + - 'sidecar/kubesphere/4.0.0/backend.go' + - 'sidecar/kubesphere/4.0.0/Dockerfile' + - 'sidecar/kubesphere/4.0.0/main.go' + - 'sidecar/kubesphere/4.0.0/Makefile' + - 'sidecar/kubesphere/4.0.0/go.sum' + - 'sidecar/kubesphere/4.0.0/go.mod' + +env: + REPO_OP: 'kubesphere' + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 30 + name: Build Operator Image + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: 1.20.x + + - uses: actions/cache@v2 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + + - name: Checkout code + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set up QEMU + id: qemu + uses: docker/setup-qemu-action@v1 + with: + image: tonistiigi/binfmt:latest + platforms: all + + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.REGISTRY_USER }} + password: ${{ secrets.REGISTRY_PASSWORD }} + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v1 + + - name: Build and Push image + run: | + cd sidecar/kubesphere/4.0.0 && make \ No newline at end of file diff --git a/config/samples/template.yaml b/config/samples/template.yaml index 4f543bb..a9dc189 100644 --- a/config/samples/template.yaml +++ b/config/samples/template.yaml @@ -5,7 +5,7 @@ data: {{ define "nm.default.message.cn" }}{{ if ne (len .Status) 0 }}[{{ .Status | translate }}] {{ end }}{{ .MessageCN }}{{ end }} {{ define "nm.default.subject" }}{{ if eq (len .Alerts) 1 }}{{ range .Alerts }}{{ template "nm.default.message" . }}{{ end }}{{ else }}{{ .Alerts | len }} {{ if ne (len .Status) 0 }}{{ .Status }} {{ end }}alerts{{ if gt (len .GroupLabels.SortedPairs) 0 }} for {{ range .GroupLabels.SortedPairs }}{{ .Name | translate }}={{ .Value }} {{ end }}{{ end }}{{ end }}{{ end }} - {{ define "nm.subject" }}{{ .Alerts | len }} {{ if ne (len .Status) 0 }}{{ .Status }} {{ end }}alerts{{ if gt (len .CommonLabels.SortedPairs) 0 }} for {{ range .CommonLabels.SortedPairs }}{{ .Name | translate }}={{ .Value }} {{ end }}{{ end }}{{ end }} + {{ define "nm.subject" }}{{ $numAlerts := len .Alerts }}{{ if eq $numAlerts 0 }}Show nothing{{ else if eq $numAlerts 1 }}{{ range .Alerts }}{{ $alertTitle := "" }}{{ $alertType := .Labels.alerttype }}{{ $alertName := .Labels.alertname }}{{ $cluster := .Labels.cluster }}{{ $node := .Labels.node }}{{ $pod := .Labels.pod }}{{ $namespace := .Labels.namespace }}{{ if eq $alertType "metric" }}{{ $alertTitle = "[Metrics Alert]" }}{{ else if eq $alertType "auditing" }}{{ $alertTitle = "[Audit Alert]" }}{{ else if eq $alertType "event" }}{{ $alertTitle = "[Event Alert]" }}{{ else }}{{ $alertTitle = "[Unknown Alert]" }}{{ end }}{{ $output := printf "%s" $alertTitle }}{{ if $alertName }}{{ $output = printf "%s alertname=%s" $output $alertName }}{{ end }}{{ if $cluster }}{{ $output = printf "%s | cluster=%s" $output $cluster }}{{ end }}{{ if $namespace }}{{ $output = printf "%s | namespace=%s" $output $namespace }}{{ end }}{{ if $pod }}{{ $output = printf "%s | pod=%s" $output $pod }}{{ if $node }}{{ $output = printf "%s/node=%s" $output $node }}{{ end }}{{ else }}{{ if $node }}{{ $output = printf "%s | node=%s" $output $node }}{{ end }}{{ end }}{{ $output }}{{ end }}{{ else }}{{ $alertTitle := "[Aggregation" }}{{ $alertType := index .GroupLabels "alerttype" }}{{ $alertName := index .GroupLabels "alertname" }}{{ $cluster := index .GroupLabels "cluster" }}{{ $namespace := index .GroupLabels "namespace" }}{{ if eq $alertType "metric" }}{{ $alertTitle = printf "%s Metrics Alert]" $alertTitle }}{{ else if eq $alertType "auditing" }}{{ $alertTitle = printf "%s Audit Alert]" $alertTitle }}{{ else if eq $alertType "event" }}{{ $alertTitle = printf "%s Event Alert]" $alertTitle }}{{ else }}{{ $alertTitle = printf "%s Alert]" $alertTitle }}{{ end }}{{ $output := printf "%s" $alertTitle }}{{ if $alertName }}{{ $output = printf "%s alertname=%s" $output $alertName }}{{ end }}{{ if $cluster }}{{ $output = printf "%s | cluster=%s" $output $cluster }}{{ end }}{{ if $namespace }}{{ $output = printf "%s | namespace=%s" $output $namespace }}{{ end }}{{ $output }}{{ end }}{{ end }} {{ define "nm.default.text" }}{{ range .Alerts }}{{ template "nm.default.message" . }} {{ range .Labels.SortedPairs }} {{ .Name | translate }}: {{ .Value }} diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index a30be1d..4380a91 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -26,6 +26,7 @@ const ( DiscordContent = "content" DiscordEmbed = "embed" + Cluster = "cluster" Namespace = "namespace" AlertFiring = "firing" diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index d0f77a7..64eda49 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -505,7 +505,7 @@ func (c *Controller) receiverChanged(t *task) { _ = level.Info(c.logger).Log("msg", "Receiver changed", "op", t.op, "name", receiver.Name) } -func (c *Controller) tenantIDFromNs(namespace string) ([]string, error) { +func (c *Controller) tenantIDFromNs(cluster, namespace string) ([]string, error) { tenantIDs := make([]string, 0) // Use namespace as TenantID directly if tenantSidecar not provided. if !c.tenantSidecar { @@ -514,7 +514,8 @@ func (c *Controller) tenantIDFromNs(namespace string) ([]string, error) { } p := make(map[string]string) - p["namespace"] = namespace + p[constants.Cluster] = cluster + p[constants.Namespace] = namespace u, err := utils.UrlWithParameters(tenantSidecarURL, p) if err != nil { return nil, err @@ -536,7 +537,7 @@ func (c *Controller) tenantIDFromNs(namespace string) ([]string, error) { return nil, err } - _ = level.Debug(c.logger).Log("msg", "get tenants from namespace", "namespace", namespace, "tenant", utils.ArrayToString(res, ",")) + _ = level.Debug(c.logger).Log("msg", "get tenants from namespace", "cluster", cluster, "namespace", namespace, "tenant", utils.ArrayToString(res, ",")) return res, nil } @@ -580,13 +581,13 @@ func getMatchedConfig(r internal.Receiver, configs map[string]map[string]interna } } -func (c *Controller) RcvsFromNs(namespace *string) []internal.Receiver { +func (c *Controller) RcvsFromNs(cluster string, namespace *string) []internal.Receiver { // Global receiver should receive all notifications. tenants := []string{globalTenantID} if namespace != nil && len(*namespace) > 0 { // Get all tenants which need to receive the notifications in this namespace. - tenantIDs, err := c.tenantIDFromNs(*namespace) + tenantIDs, err := c.tenantIDFromNs(cluster, *namespace) if err != nil { _ = level.Error(c.logger).Log("msg", "get tenantID error", "err", err, "namespace", *namespace) } else { diff --git a/pkg/route/router.go b/pkg/route/router.go index 1ad0d47..c9f8767 100644 --- a/pkg/route/router.go +++ b/pkg/route/router.go @@ -2,6 +2,8 @@ package route import ( "context" + "fmt" + "strings" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" @@ -51,25 +53,30 @@ func (s *routeStage) Exec(ctx context.Context, l log.Logger, data interface{}) ( return ctx, nil, err } - // Grouping alerts by namespace + // Grouping alerts by cluster and namespace alertMap := make(map[string][]*template.Alert) for _, alert := range input { ns := alert.Labels[constants.Namespace] - as := alertMap[ns] + cluster := alert.Labels[constants.Cluster] + key := fmt.Sprintf("%s|%s", cluster, ns) + as := alertMap[key] as = append(as, alert) - alertMap[ns] = as + alertMap[key] = as } m := make(map[string]*packet) routePolicy := s.notifierCtl.GetRoutePolicy() - for ns, alerts := range alertMap { + for key, alerts := range alertMap { flag := false + pair := strings.Split(key, "|") + cluster := pair[0] + ns := pair[1] var tenantRcvs []internal.Receiver for _, alert := range alerts { rcvs := s.rcvsFromRouter(alert, routers) if routePolicy == RouterPolicyAll || (routePolicy == RouterFirst && len(rcvs) == 0) { if len(tenantRcvs) == 0 && !flag { - tenantRcvs = s.notifierCtl.RcvsFromNs(&ns) + tenantRcvs = s.notifierCtl.RcvsFromNs(cluster, &ns) flag = true } rcvs = append(rcvs, tenantRcvs...) diff --git a/sidecar/kubesphere/4.0.0/Makefile b/sidecar/kubesphere/4.0.0/Makefile index cd3fdbe..8c5964f 100644 --- a/sidecar/kubesphere/4.0.0/Makefile +++ b/sidecar/kubesphere/4.0.0/Makefile @@ -2,7 +2,7 @@ # Use of this source code is governed by a Apache license # that can be found in the LICENSE file. -IMG ?= kubesphere/notification-tenant-sidecar:v4.0.0 +IMG ?= kubesphere/notification-tenant-sidecar:v4.0.1 AMD64 ?= -amd64 all: docker-build diff --git a/sidecar/kubesphere/4.0.0/backend.go b/sidecar/kubesphere/4.0.0/backend.go index be3dda0..7a7a12d 100644 --- a/sidecar/kubesphere/4.0.0/backend.go +++ b/sidecar/kubesphere/4.0.0/backend.go @@ -2,9 +2,9 @@ package main import ( "context" + "fmt" "time" - "k8s.io/api/authorization/v1beta1" v1 "k8s.io/api/core/v1" "k8s.io/klog" iamv1beta1 "kubesphere.io/api/iam/v1beta1" @@ -13,12 +13,14 @@ import ( type Backend struct { ksClient *rest.RESTClient - tenants map[string]map[string]string + // map[cluster]map[namespace][]{users} + tenants map[string]map[string][]string - interval time.Duration + interval time.Duration + batchSize int } -func NewBackend(host, username, password string, interval time.Duration) (*Backend, error) { +func NewBackend(host, username, password string, interval time.Duration, batchSize int) (*Backend, error) { var config *rest.Config if username != "" && password != "" { config = &rest.Config{ @@ -39,24 +41,20 @@ func NewBackend(host, username, password string, interval time.Duration) (*Backe } return &Backend{ - ksClient: c, - tenants: make(map[string]map[string]string), - interval: interval, + ksClient: c, + tenants: make(map[string]map[string][]string), + interval: interval, + batchSize: batchSize, }, err } -func (b *Backend) FromNamespace(ns string) []string { - - m, ok := b.tenants[ns] +func (b *Backend) FromNamespace(cluster, ns string) []string { + cm, ok := b.tenants[cluster] if !ok { return nil } - array := make([]string, 0) - for k := range m { - array = append(array, k) - } - return array + return cm[ns] } func (b *Backend) Run() { @@ -79,22 +77,42 @@ func (b *Backend) reload() { klog.Info("end reload tenant") }() + clusters, err := b.listClusters() + if err != nil { + klog.Errorf("list clusters error, %s", err.Error()) + } + users, err := b.listUsers() if err != nil { klog.Errorf("list users error, %s", err.Error()) + return } - namespaces, err := b.listNamespaces() + tenants := make(map[string]map[string][]string) + for _, cluster := range clusters { + m, err := getTenantInfoFromCluster(cluster, users) + if err != nil { + return + } + + tenants[cluster] = m + } + + b.tenants = tenants +} + +func getTenantInfoFromCluster(cluster string, users []string) (map[string][]string, error) { + namespaces, err := b.listNamespaces(cluster) if err != nil { klog.Errorf("list namespaces error, %s", err.Error()) + return nil, err } var items []iamv1beta1.SubjectAccessReview - - m := make(map[string]map[string]string) + m := make(map[string][]string) for _, namespace := range namespaces { for _, user := range users { - sar := iamv1beta1.SubjectAccessReview{ + items = append(items, iamv1beta1.SubjectAccessReview{ Spec: iamv1beta1.SubjectAccessReviewSpec{ ResourceAttributes: &iamv1beta1.ResourceAttributes{ Namespace: namespace, @@ -107,12 +125,42 @@ func (b *Backend) reload() { User: user, // "X-Remote-User" request header Groups: []string{}, // "X-Remote-Group" request header }, + }) + + if len(items) >= batchSize { + if err := b.batchRequest(cluster, items, m); err != nil { + return nil, err + } + items = items[:0] + continue } - items = append(items, sar) } } - b.batchRequest(items, m) - b.tenants = m + + if err := b.batchRequest(cluster, items, m); err != nil { + return nil, err + } + + return m, err +} + +func (b *Backend) listClusters() ([]string, error) { + res := b.ksClient.Get().AbsPath("/kapis/cluster.kubesphere.io/v1alpha1/clusters").Do(context.Background()) + if err := res.Error(); err != nil { + return nil, err + } + clusterList := &iamv1beta1.UserList{} + err := res.Into(clusterList) + if err != nil { + return nil, err + } + + var clusters []string + for _, cluster := range clusterList.Items { + clusters = append(clusters, cluster.Name) + } + + return clusters, nil } func (b *Backend) listUsers() ([]string, error) { @@ -134,8 +182,8 @@ func (b *Backend) listUsers() ([]string, error) { return users, nil } -func (b *Backend) listNamespaces() ([]string, error) { - res := b.ksClient.Get().AbsPath("/api/v1/namespaces").Do(context.Background()) +func (b *Backend) listNamespaces(cluster string) ([]string, error) { + res := b.ksClient.Get().AbsPath(fmt.Sprintf("/clusters/%s/api/v1/namespaces", cluster)).Do(context.Background()) if err := res.Error(); err != nil { return nil, err } @@ -153,65 +201,24 @@ func (b *Backend) listNamespaces() ([]string, error) { return namespaces, nil } -func (b *Backend) canAccess(user, namespace string) (bool, error) { - subjectAccessReview := &v1beta1.SubjectAccessReview{ - Spec: v1beta1.SubjectAccessReviewSpec{ - ResourceAttributes: &v1beta1.ResourceAttributes{ - Namespace: namespace, - Verb: "get", - Group: "notification.kubesphere.io", - Version: "v2beta2", - Resource: "receivenotification", - }, - NonResourceAttributes: nil, - User: user, // "X-Remote-User" request header - Groups: []string{}, // "X-Remote-Group" request header - }, - } - - if err := b.ksClient.Post().AbsPath("/kapis/iam.kubesphere.io/v1beta1/subjectaccessreviews"). - Body(subjectAccessReview). - Do(context.Background()). - Into(subjectAccessReview); err != nil { - return false, err +func (b *Backend) batchRequest(cluster string, items []iamv1beta1.SubjectAccessReview, m map[string][]string) error { + list := &iamv1beta1.SubjectAccessReviewList{ + Items: items, } - - return subjectAccessReview.Status.Allowed, nil -} - -func (b *Backend) batchRequest(subjectAccessReviews []iamv1beta1.SubjectAccessReview, m map[string]map[string]string) { - - batchSize := 500 - for i := 0; i < len(subjectAccessReviews); i += batchSize { - items := subjectAccessReviews[i:minimum(i+batchSize, len(subjectAccessReviews))] - list := &iamv1beta1.SubjectAccessReviewList{ - Items: items, - } - if err := b.ksClient.Post().AbsPath("/kapis/iam.kubesphere.io/v1beta1/subjectaccessreviews"). - Body(list). - Do(context.Background()). - Into(list); err != nil { - klog.Errorf("get access view error: %s", err.Error()) - return - } - for _, item := range items { - if item.Status.Allowed { - ns := item.Spec.ResourceAttributes.Namespace - user := item.Spec.User - array, ok := m[ns] - if !ok { - array = make(map[string]string) - } - array[user] = "" - m[ns] = array - } + if err := b.ksClient.Post().AbsPath(fmt.Sprintf("/clusters/%s/kapis/iam.kubesphere.io/v1beta1/subjectaccessreviews", cluster)). + Body(list). + Do(context.Background()). + Into(list); err != nil { + klog.Errorf("get access view error: %s", err.Error()) + return err + } + for _, item := range items { + if item.Status.Allowed { + ns := item.Spec.ResourceAttributes.Namespace + user := item.Spec.User + m[ns] = append(m[ns], user) } } -} -func minimum(a, b int) int { - if a < b { - return a - } - return b + return nil } diff --git a/sidecar/kubesphere/4.0.0/main.go b/sidecar/kubesphere/4.0.0/main.go index cf3add2..1defce5 100644 --- a/sidecar/kubesphere/4.0.0/main.go +++ b/sidecar/kubesphere/4.0.0/main.go @@ -29,12 +29,18 @@ import ( "k8s.io/klog" ) +const ( + defaultInterval = time.Minute * 5 + defaultBatchSize = 500 +) + var ( waitHandlerGroup sync.WaitGroup host string username string password string interval time.Duration + batchSize int b *Backend ) @@ -50,7 +56,8 @@ func AddFlags(fs *pflag.FlagSet) { fs.StringVar(&host, "host", "ks-apiserver.kubesphere-system", "the host of kubesphere apiserver") fs.StringVar(&username, "username", "", "the username of kubesphere") fs.StringVar(&password, "password", "", "the password of kubesphere") - fs.DurationVar(&interval, "interval", time.Minute*5, "interval to reload") + fs.DurationVar(&interval, "interval", defaultInterval, "interval to reload") + fs.IntVar(&batchSize, "batchSize", defaultBatchSize, "interval to reload") } func NewServerCommand() *cobra.Command { @@ -73,7 +80,7 @@ func Run() error { }) var err error - b, err = NewBackend(host, username, password, interval) + b, err = NewBackend(host, username, password, interval, batchSize) if err != nil { return err } @@ -113,8 +120,9 @@ func handler(req *restful.Request, resp *restful.Response) { waitHandlerGroup.Add(1) defer waitHandlerGroup.Done() + cluster := req.QueryParameter("cluster") ns := req.QueryParameter("namespace") - tenants := b.FromNamespace(ns) + tenants := b.FromNamespace(cluster, ns) if tenants == nil { responseWithHeaderAndEntity(resp, http.StatusNotFound, "") return diff --git a/sidecar/kubesphere/4.0.0/test/get-tenants.sh b/sidecar/kubesphere/4.0.0/test/get-tenants.sh index d060b29..a90fcf8 100755 --- a/sidecar/kubesphere/4.0.0/test/get-tenants.sh +++ b/sidecar/kubesphere/4.0.0/test/get-tenants.sh @@ -1,2 +1,2 @@ #!/bin/bash -curl -XGET http://127.0.0.1:19094/api/v2/tenant?namespace=kubesphere-monitoring-system +curl -XGET http://127.0.0.1:19094/api/v2/tenant?cluster=host&namespace=kubesphere-monitoring-system From 7d8406e71ebea6818dfd99b3da9cb4ce33b82851 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 13:40:56 +0800 Subject: [PATCH 04/10] Bump golang.org/x/net from 0.17.0 to 0.23.0 in /sidecar/kubesphere/4.0.0 (#260) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.17.0 to 0.23.0. - [Commits](https://github.com/golang/net/compare/v0.17.0...v0.23.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- sidecar/kubesphere/4.0.0/go.mod | 4 ++-- sidecar/kubesphere/4.0.0/go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sidecar/kubesphere/4.0.0/go.mod b/sidecar/kubesphere/4.0.0/go.mod index 11255e8..345797c 100644 --- a/sidecar/kubesphere/4.0.0/go.mod +++ b/sidecar/kubesphere/4.0.0/go.mod @@ -32,9 +32,9 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/net v0.23.0 // indirect golang.org/x/oauth2 v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/sidecar/kubesphere/4.0.0/go.sum b/sidecar/kubesphere/4.0.0/go.sum index 532035f..4e5bdbb 100644 --- a/sidecar/kubesphere/4.0.0/go.sum +++ b/sidecar/kubesphere/4.0.0/go.sum @@ -87,8 +87,8 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -97,13 +97,13 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From a49ed1b4de0d721ff6fb735eaaa9ce4c9063f116 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 13:41:22 +0800 Subject: [PATCH 05/10] Bump google.golang.org/protobuf in /sidecar/kubesphere/4.0.0 (#253) Bumps google.golang.org/protobuf from 1.31.0 to 1.33.0. --- updated-dependencies: - dependency-name: google.golang.org/protobuf dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- sidecar/kubesphere/4.0.0/go.mod | 2 +- sidecar/kubesphere/4.0.0/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sidecar/kubesphere/4.0.0/go.mod b/sidecar/kubesphere/4.0.0/go.mod index 345797c..4079ad2 100644 --- a/sidecar/kubesphere/4.0.0/go.mod +++ b/sidecar/kubesphere/4.0.0/go.mod @@ -37,7 +37,7 @@ require ( golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/sidecar/kubesphere/4.0.0/go.sum b/sidecar/kubesphere/4.0.0/go.sum index 4e5bdbb..eef7cd4 100644 --- a/sidecar/kubesphere/4.0.0/go.sum +++ b/sidecar/kubesphere/4.0.0/go.sum @@ -119,8 +119,8 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From f6af089934129a527ec9671bbddb1929dc9846cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 13:41:29 +0800 Subject: [PATCH 06/10] Bump google.golang.org/protobuf from 1.30.0 to 1.33.0 (#252) Bumps google.golang.org/protobuf from 1.30.0 to 1.33.0. --- updated-dependencies: - dependency-name: google.golang.org/protobuf dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 07c9ad8..94746c1 100644 --- a/go.mod +++ b/go.mod @@ -98,7 +98,7 @@ require ( golang.org/x/tools v0.12.0 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.56.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect diff --git a/go.sum b/go.sum index f5e3030..30c2761 100644 --- a/go.sum +++ b/go.sum @@ -331,8 +331,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 6333976295791f592f7cacda58c70abfa4ed2699 Mon Sep 17 00:00:00 2001 From: wanjunlei Date: Mon, 13 May 2024 15:45:49 +0800 Subject: [PATCH 07/10] add alerttime to metric alert Signed-off-by: wanjunlei --- pkg/webhook/v1/handler.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/webhook/v1/handler.go b/pkg/webhook/v1/handler.go index ad63bfc..4ebe1fb 100644 --- a/pkg/webhook/v1/handler.go +++ b/pkg/webhook/v1/handler.go @@ -66,6 +66,11 @@ func (h *HttpHandler) Alert(w http.ResponseWriter, r *http.Request) { if v := alert.Labels["cluster"]; v == "" { alert.Labels["cluster"] = cluster } + + if alert.Labels["alerttype"] == "metric" { + alert.Annotations["alerttime"] = time.Now().Local().String() + } + alert.ID = utils.Hash(alert) if err := h.alerts.Push(alert); err != nil { _ = level.Error(h.logger).Log("msg", "push alert error", "error", err.Error()) From 68b1cbc1344fa99fb127875964f9a678a63afb1d Mon Sep 17 00:00:00 2001 From: wanjunlei Date: Tue, 14 May 2024 11:00:53 +0800 Subject: [PATCH 08/10] update helm template Signed-off-by: wanjunlei --- helm/templates/notificationmanagers.yaml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/helm/templates/notificationmanagers.yaml b/helm/templates/notificationmanagers.yaml index 9559425..a4efbce 100644 --- a/helm/templates/notificationmanagers.yaml +++ b/helm/templates/notificationmanagers.yaml @@ -24,11 +24,6 @@ spec: {{- toYaml .Values.notificationmanager.receivers | nindent 4 }} defaultConfigSelector: {{- toYaml .Values.notificationmanager.defaultConfigSelector | nindent 4 }} - {{- if .Values.timezone }} - env: - - name: TZ - value: {{ .Values.timezone }} - {{- end }} volumeMounts: {{- toYaml .Values.notificationmanager.volumeMounts | nindent 4 }} volumes: @@ -60,4 +55,6 @@ spec: annotations: {{- toYaml .Values.notificationmanager.annotations | nindent 4 }} labels: - {{- toYaml .Values.notificationmanager.labels | nindent 4 }} \ No newline at end of file + {{- toYaml .Values.notificationmanager.labels | nindent 4 }} + env: + {{- toYaml .Values.notificationmanager.env | nindent 4 }} \ No newline at end of file From 7a050d98cef239c3e6cacb4683c55c1d00b64fea Mon Sep 17 00:00:00 2001 From: Gentleelephant <1132960613@qq.com> Date: Mon, 13 May 2024 15:03:15 +0800 Subject: [PATCH 09/10] update template --- config/samples/template.yaml | 2 +- helm/templates/template.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/samples/template.yaml b/config/samples/template.yaml index a9dc189..7d66f55 100644 --- a/config/samples/template.yaml +++ b/config/samples/template.yaml @@ -5,7 +5,7 @@ data: {{ define "nm.default.message.cn" }}{{ if ne (len .Status) 0 }}[{{ .Status | translate }}] {{ end }}{{ .MessageCN }}{{ end }} {{ define "nm.default.subject" }}{{ if eq (len .Alerts) 1 }}{{ range .Alerts }}{{ template "nm.default.message" . }}{{ end }}{{ else }}{{ .Alerts | len }} {{ if ne (len .Status) 0 }}{{ .Status }} {{ end }}alerts{{ if gt (len .GroupLabels.SortedPairs) 0 }} for {{ range .GroupLabels.SortedPairs }}{{ .Name | translate }}={{ .Value }} {{ end }}{{ end }}{{ end }}{{ end }} - {{ define "nm.subject" }}{{ $numAlerts := len .Alerts }}{{ if eq $numAlerts 0 }}Show nothing{{ else if eq $numAlerts 1 }}{{ range .Alerts }}{{ $alertTitle := "" }}{{ $alertType := .Labels.alerttype }}{{ $alertName := .Labels.alertname }}{{ $cluster := .Labels.cluster }}{{ $node := .Labels.node }}{{ $pod := .Labels.pod }}{{ $namespace := .Labels.namespace }}{{ if eq $alertType "metric" }}{{ $alertTitle = "[Metrics Alert]" }}{{ else if eq $alertType "auditing" }}{{ $alertTitle = "[Audit Alert]" }}{{ else if eq $alertType "event" }}{{ $alertTitle = "[Event Alert]" }}{{ else }}{{ $alertTitle = "[Unknown Alert]" }}{{ end }}{{ $output := printf "%s" $alertTitle }}{{ if $alertName }}{{ $output = printf "%s alertname=%s" $output $alertName }}{{ end }}{{ if $cluster }}{{ $output = printf "%s | cluster=%s" $output $cluster }}{{ end }}{{ if $namespace }}{{ $output = printf "%s | namespace=%s" $output $namespace }}{{ end }}{{ if $pod }}{{ $output = printf "%s | pod=%s" $output $pod }}{{ if $node }}{{ $output = printf "%s/node=%s" $output $node }}{{ end }}{{ else }}{{ if $node }}{{ $output = printf "%s | node=%s" $output $node }}{{ end }}{{ end }}{{ $output }}{{ end }}{{ else }}{{ $alertTitle := "[Aggregation" }}{{ $alertType := index .GroupLabels "alerttype" }}{{ $alertName := index .GroupLabels "alertname" }}{{ $cluster := index .GroupLabels "cluster" }}{{ $namespace := index .GroupLabels "namespace" }}{{ if eq $alertType "metric" }}{{ $alertTitle = printf "%s Metrics Alert]" $alertTitle }}{{ else if eq $alertType "auditing" }}{{ $alertTitle = printf "%s Audit Alert]" $alertTitle }}{{ else if eq $alertType "event" }}{{ $alertTitle = printf "%s Event Alert]" $alertTitle }}{{ else }}{{ $alertTitle = printf "%s Alert]" $alertTitle }}{{ end }}{{ $output := printf "%s" $alertTitle }}{{ if $alertName }}{{ $output = printf "%s alertname=%s" $output $alertName }}{{ end }}{{ if $cluster }}{{ $output = printf "%s | cluster=%s" $output $cluster }}{{ end }}{{ if $namespace }}{{ $output = printf "%s | namespace=%s" $output $namespace }}{{ end }}{{ $output }}{{ end }}{{ end }} + {{ define "nm.subject" }} {{ $rawStatus := .Status }} {{ $severity := index .CommonLabels "severity" }} {{ $status := "" }} {{- if eq $rawStatus "firing" }} {{ $status = "FIRING" }} {{- else if eq $rawStatus "resolved" }} {{ $status = "RESOLVED" }} {{- else }} {{ $status = "UNKNOWN" }} {{- end }} {{ $numAlerts := len .Alerts }} {{ if eq $numAlerts 0 }} Show nothing {{ else if eq $numAlerts 1 }} {{ range .Alerts }} {{ $alertType := .Labels.alerttype }} {{ $alertName := .Labels.alertname }} {{ $cluster := .Labels.cluster }} {{ $node := .Labels.node }} {{ $pod := .Labels.pod }} {{ $namespace := .Labels.namespace }} {{ $output := printf "[%s]" $status }} {{ if $severity }} {{ $output = printf "%s | severity=%s" $output $severity }} {{ end }} {{ if $alertType }} {{ $output = printf "%s | alerttype=%s" $output $alertType }} {{ end }} {{ if $alertName }} {{ $output = printf "%s | alertname=%s" $output $alertName }} {{ end }} {{ if $cluster }} {{ $output = printf "%s | cluster=%s" $output $cluster }} {{ end }} {{ if $node }} {{ $output = printf "%s | node=%s" $output $node }} {{ end }} {{ if $namespace }} {{ $output = printf "%s | namespace=%s" $output $namespace }} {{ end }} {{ if $pod }} {{ $output = printf "%s | pod=%s" $output $pod }} {{ end }} {{ $output }} {{ end }} {{ else }} {{ $alertType := index .GroupLabels "alerttype" }} {{ $alertName := index .GroupLabels "alertname" }} {{ $cluster := index .GroupLabels "cluster" }} {{ $namespace := index .GroupLabels "namespace" }} {{ $node := index .GroupLabels "node" }} {{ $output := printf "[%s]" $status }} {{ if $severity }} {{ $output = printf "%s | severity=%s" $output $severity }} {{ end }} {{ if $alertType }} {{ $output = printf "%s | alerttype=%s" $output $alertType }} {{ end }} {{ if $alertName }} {{ $output = printf "%s | alertname=%s" $output $alertName }} {{ end }} {{ if $cluster }} {{ $output = printf "%s | cluster=%s" $output $cluster }} {{ end }} {{ if $namespace }} {{ $output = printf "%s | namespace=%s" $output $namespace }} {{ end }} {{ if $node }} {{ $output = printf "%s | node=%s" $output $node }} {{ end }} {{ $output }} {{ end }} {{ end }} {{ define "nm.default.text" }}{{ range .Alerts }}{{ template "nm.default.message" . }} {{ range .Labels.SortedPairs }} {{ .Name | translate }}: {{ .Value }} diff --git a/helm/templates/template.yaml b/helm/templates/template.yaml index c0a6ea8..17914d9 100644 --- a/helm/templates/template.yaml +++ b/helm/templates/template.yaml @@ -5,7 +5,7 @@ data: {{ "{{ define \"nm.default.message.cn\" }}{{ if ne (len .Status) 0 }}[{{ .Status | translate }}] {{ end }}{{ .MessageCN }}{{ end }}" }} {{ "{{ define \"nm.default.subject\" }}{{ if eq (len .Alerts) 1 }}{{ range .Alerts }}{{ template \"nm.default.message\" . }}{{ end }}{{ else }}{{ .Alerts | len }} {{ if ne (len .Status) 0 }}{{ .Status }} {{ end }}alerts{{ if gt (len .GroupLabels.SortedPairs) 0 }} for {{ range .GroupLabels.SortedPairs }}{{ .Name | translate }}={{ .Value }} {{ end }}{{ end }}{{ end }}{{ end }}" }} - {{ "{{ define \"nm.subject\" }}{{ .Alerts | len }} {{ if ne (len .Status) 0 }}{{ .Status }} {{ end }}alerts{{ if gt (len .CommonLabels.SortedPairs) 0 }} for {{ range .CommonLabels.SortedPairs }}{{ .Name | translate }}={{ .Value }} {{ end }}{{ end }}{{ end }}" }} + {{ "{{ define \"nm.subject\" }} {{ $rawStatus := .Status }} {{ $severity := index .CommonLabels \"severity\" }} {{ $status := \"\" }} {{- if eq $rawStatus \"firing\" }} {{ $status = \"FIRING\" }} {{- else if eq $rawStatus \"resolved\" }} {{ $status = \"RESOLVED\" }} {{- else }} {{ $status = \"UNKNOWN\" }} {{- end }} {{ $numAlerts := len .Alerts }} {{ if eq $numAlerts 0 }} Show nothing {{ else if eq $numAlerts 1 }} {{ range .Alerts }} {{ $alertType := .Labels.alerttype }} {{ $alertName := .Labels.alertname }} {{ $cluster := .Labels.cluster }} {{ $node := .Labels.node }} {{ $pod := .Labels.pod }} {{ $namespace := .Labels.namespace }} {{ $output := printf \"[%s]\" $status }} {{ if $severity }} {{ $output = printf \"%s | severity=%s\" $output $severity }} {{ end }} {{ if $alertType }} {{ $output = printf \"%s | alerttype=%s\" $output $alertType }} {{ end }} {{ if $alertName }} {{ $output = printf \"%s | alertname=%s\" $output $alertName }} {{ end }} {{ if $cluster }} {{ $output = printf \"%s | cluster=%s\" $output $cluster }} {{ end }} {{ if $node }} {{ $output = printf \"%s | node=%s\" $output $node }} {{ end }} {{ if $namespace }} {{ $output = printf \"%s | namespace=%s\" $output $namespace }} {{ end }} {{ if $pod }} {{ $output = printf \"%s | pod=%s\" $output $pod }} {{ end }} {{ $output }} {{ end }} {{ else }} {{ $alertType := index .GroupLabels \"alerttype\" }} {{ $alertName := index .GroupLabels \"alertname\" }} {{ $cluster := index .GroupLabels \"cluster\" }} {{ $namespace := index .GroupLabels \"namespace\" }} {{ $node := index .GroupLabels \"node\" }} {{ $output := printf \"[%s]\" $status }} {{ if $severity }} {{ $output = printf \"%s | severity=%s\" $output $severity }} {{ end }} {{ if $alertType }} {{ $output = printf \"%s | alerttype=%s\" $output $alertType }} {{ end }} {{ if $alertName }} {{ $output = printf \"%s | alertname=%s\" $output $alertName }} {{ end }} {{ if $cluster }} {{ $output = printf \"%s | cluster=%s\" $output $cluster }} {{ end }} {{ if $namespace }} {{ $output = printf \"%s | namespace=%s\" $output $namespace }} {{ end }} {{ if $node }} {{ $output = printf \"%s | node=%s\" $output $node }} {{ end }} {{ $output }} {{ end }} {{ end }}" }} {{ "{{ define \"nm.default.text\" }}{{ range .Alerts }}{{ template \"nm.default.message\" . }}" }} {{ "{{ range .Labels.SortedPairs }} {{ .Name | translate }}: {{ .Value }}" }} From becde0bf77b88753e38787bbd4af647d0349ae2c Mon Sep 17 00:00:00 2001 From: zhangpeng <1132960613@qq.com> Date: Tue, 14 May 2024 15:34:44 +0800 Subject: [PATCH 10/10] trim space (#267) --- config/samples/template.yaml | 3 +-- helm/templates/template.yaml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/config/samples/template.yaml b/config/samples/template.yaml index 7d66f55..8bbfe2b 100644 --- a/config/samples/template.yaml +++ b/config/samples/template.yaml @@ -5,8 +5,7 @@ data: {{ define "nm.default.message.cn" }}{{ if ne (len .Status) 0 }}[{{ .Status | translate }}] {{ end }}{{ .MessageCN }}{{ end }} {{ define "nm.default.subject" }}{{ if eq (len .Alerts) 1 }}{{ range .Alerts }}{{ template "nm.default.message" . }}{{ end }}{{ else }}{{ .Alerts | len }} {{ if ne (len .Status) 0 }}{{ .Status }} {{ end }}alerts{{ if gt (len .GroupLabels.SortedPairs) 0 }} for {{ range .GroupLabels.SortedPairs }}{{ .Name | translate }}={{ .Value }} {{ end }}{{ end }}{{ end }}{{ end }} - {{ define "nm.subject" }} {{ $rawStatus := .Status }} {{ $severity := index .CommonLabels "severity" }} {{ $status := "" }} {{- if eq $rawStatus "firing" }} {{ $status = "FIRING" }} {{- else if eq $rawStatus "resolved" }} {{ $status = "RESOLVED" }} {{- else }} {{ $status = "UNKNOWN" }} {{- end }} {{ $numAlerts := len .Alerts }} {{ if eq $numAlerts 0 }} Show nothing {{ else if eq $numAlerts 1 }} {{ range .Alerts }} {{ $alertType := .Labels.alerttype }} {{ $alertName := .Labels.alertname }} {{ $cluster := .Labels.cluster }} {{ $node := .Labels.node }} {{ $pod := .Labels.pod }} {{ $namespace := .Labels.namespace }} {{ $output := printf "[%s]" $status }} {{ if $severity }} {{ $output = printf "%s | severity=%s" $output $severity }} {{ end }} {{ if $alertType }} {{ $output = printf "%s | alerttype=%s" $output $alertType }} {{ end }} {{ if $alertName }} {{ $output = printf "%s | alertname=%s" $output $alertName }} {{ end }} {{ if $cluster }} {{ $output = printf "%s | cluster=%s" $output $cluster }} {{ end }} {{ if $node }} {{ $output = printf "%s | node=%s" $output $node }} {{ end }} {{ if $namespace }} {{ $output = printf "%s | namespace=%s" $output $namespace }} {{ end }} {{ if $pod }} {{ $output = printf "%s | pod=%s" $output $pod }} {{ end }} {{ $output }} {{ end }} {{ else }} {{ $alertType := index .GroupLabels "alerttype" }} {{ $alertName := index .GroupLabels "alertname" }} {{ $cluster := index .GroupLabels "cluster" }} {{ $namespace := index .GroupLabels "namespace" }} {{ $node := index .GroupLabels "node" }} {{ $output := printf "[%s]" $status }} {{ if $severity }} {{ $output = printf "%s | severity=%s" $output $severity }} {{ end }} {{ if $alertType }} {{ $output = printf "%s | alerttype=%s" $output $alertType }} {{ end }} {{ if $alertName }} {{ $output = printf "%s | alertname=%s" $output $alertName }} {{ end }} {{ if $cluster }} {{ $output = printf "%s | cluster=%s" $output $cluster }} {{ end }} {{ if $namespace }} {{ $output = printf "%s | namespace=%s" $output $namespace }} {{ end }} {{ if $node }} {{ $output = printf "%s | node=%s" $output $node }} {{ end }} {{ $output }} {{ end }} {{ end }} - + {{ define "nm.subject" -}}{{- $rawStatus := .Status -}}{{- $severity := index .CommonLabels "severity" -}}{{- $status := "" -}}{{- if eq $rawStatus "firing" -}}{{- $status = "FIRING" -}}{{- else if eq $rawStatus "resolved" -}}{{- $status = "RESOLVED" -}}{{- else -}}{{- $status = "UNKNOWN" -}}{{- end -}}{{- $numAlerts := len .Alerts -}}{{- if eq $numAlerts 0 -}}Show nothing{{- else if eq $numAlerts 1 -}}{{- range .Alerts -}}{{- $alertType := .Labels.alerttype -}}{{- $alertName := .Labels.alertname -}}{{- $cluster := .Labels.cluster -}}{{- $node := .Labels.node -}}{{- $pod := .Labels.pod -}}{{- $namespace := .Labels.namespace -}}{{- $output := printf "[%s]" $status -}}{{- if $severity -}}{{- $output = printf "%s | severity=%s" $output $severity -}}{{- end -}}{{- if $alertType -}}{{- $output = printf "%s | alerttype=%s" $output $alertType -}}{{- end -}}{{- if $alertName -}}{{- $output = printf "%s | alertname=%s" $output $alertName -}}{{- end -}}{{- if $cluster -}}{{- $output = printf "%s | cluster=%s" $output $cluster -}}{{- end -}}{{- if $node -}}{{- $output = printf "%s | node=%s" $output $node -}}{{- end -}}{{- if $namespace -}}{{- $output = printf "%s | namespace=%s" $output $namespace -}}{{- end -}}{{- if $pod -}}{{- $output = printf "%s | pod=%s" $output $pod -}}{{- end -}}{{- $output -}}{{- end -}}{{- else -}}{{- $alertType := index .GroupLabels "alerttype" -}}{{- $alertName := index .GroupLabels "alertname" -}}{{- $cluster := index .GroupLabels "cluster" -}}{{- $namespace := index .GroupLabels "namespace" -}}{{- $node := index .GroupLabels "node" -}}{{- $output := printf "[%s]" $status -}}{{- if $severity -}}{{- $output = printf "%s | severity=%s" $output $severity -}}{{- end -}}{{- if $alertType -}}{{- $output = printf "%s | alerttype=%s" $output $alertType -}}{{- end -}}{{- if $alertName -}}{{- $output = printf "%s | alertname=%s" $output $alertName -}}{{- end -}}{{- if $cluster -}}{{- $output = printf "%s | cluster=%s" $output $cluster -}}{{- end -}}{{- if $namespace -}}{{- $output = printf "%s | namespace=%s" $output $namespace -}}{{- end -}}{{- if $node -}}{{- $output = printf "%s | node=%s" $output $node -}}{{- end -}}{{- $output -}}{{- end -}}{{- end -}} {{ define "nm.default.text" }}{{ range .Alerts }}{{ template "nm.default.message" . }} {{ range .Labels.SortedPairs }} {{ .Name | translate }}: {{ .Value }} {{ end }}{{ range .Annotations.SortedPairs.Filter "runbook_url" "message" "summary" "summary_cn" }} {{ .Name | translate }}: {{ .Value }} diff --git a/helm/templates/template.yaml b/helm/templates/template.yaml index 17914d9..8fe18ae 100644 --- a/helm/templates/template.yaml +++ b/helm/templates/template.yaml @@ -5,7 +5,7 @@ data: {{ "{{ define \"nm.default.message.cn\" }}{{ if ne (len .Status) 0 }}[{{ .Status | translate }}] {{ end }}{{ .MessageCN }}{{ end }}" }} {{ "{{ define \"nm.default.subject\" }}{{ if eq (len .Alerts) 1 }}{{ range .Alerts }}{{ template \"nm.default.message\" . }}{{ end }}{{ else }}{{ .Alerts | len }} {{ if ne (len .Status) 0 }}{{ .Status }} {{ end }}alerts{{ if gt (len .GroupLabels.SortedPairs) 0 }} for {{ range .GroupLabels.SortedPairs }}{{ .Name | translate }}={{ .Value }} {{ end }}{{ end }}{{ end }}{{ end }}" }} - {{ "{{ define \"nm.subject\" }} {{ $rawStatus := .Status }} {{ $severity := index .CommonLabels \"severity\" }} {{ $status := \"\" }} {{- if eq $rawStatus \"firing\" }} {{ $status = \"FIRING\" }} {{- else if eq $rawStatus \"resolved\" }} {{ $status = \"RESOLVED\" }} {{- else }} {{ $status = \"UNKNOWN\" }} {{- end }} {{ $numAlerts := len .Alerts }} {{ if eq $numAlerts 0 }} Show nothing {{ else if eq $numAlerts 1 }} {{ range .Alerts }} {{ $alertType := .Labels.alerttype }} {{ $alertName := .Labels.alertname }} {{ $cluster := .Labels.cluster }} {{ $node := .Labels.node }} {{ $pod := .Labels.pod }} {{ $namespace := .Labels.namespace }} {{ $output := printf \"[%s]\" $status }} {{ if $severity }} {{ $output = printf \"%s | severity=%s\" $output $severity }} {{ end }} {{ if $alertType }} {{ $output = printf \"%s | alerttype=%s\" $output $alertType }} {{ end }} {{ if $alertName }} {{ $output = printf \"%s | alertname=%s\" $output $alertName }} {{ end }} {{ if $cluster }} {{ $output = printf \"%s | cluster=%s\" $output $cluster }} {{ end }} {{ if $node }} {{ $output = printf \"%s | node=%s\" $output $node }} {{ end }} {{ if $namespace }} {{ $output = printf \"%s | namespace=%s\" $output $namespace }} {{ end }} {{ if $pod }} {{ $output = printf \"%s | pod=%s\" $output $pod }} {{ end }} {{ $output }} {{ end }} {{ else }} {{ $alertType := index .GroupLabels \"alerttype\" }} {{ $alertName := index .GroupLabels \"alertname\" }} {{ $cluster := index .GroupLabels \"cluster\" }} {{ $namespace := index .GroupLabels \"namespace\" }} {{ $node := index .GroupLabels \"node\" }} {{ $output := printf \"[%s]\" $status }} {{ if $severity }} {{ $output = printf \"%s | severity=%s\" $output $severity }} {{ end }} {{ if $alertType }} {{ $output = printf \"%s | alerttype=%s\" $output $alertType }} {{ end }} {{ if $alertName }} {{ $output = printf \"%s | alertname=%s\" $output $alertName }} {{ end }} {{ if $cluster }} {{ $output = printf \"%s | cluster=%s\" $output $cluster }} {{ end }} {{ if $namespace }} {{ $output = printf \"%s | namespace=%s\" $output $namespace }} {{ end }} {{ if $node }} {{ $output = printf \"%s | node=%s\" $output $node }} {{ end }} {{ $output }} {{ end }} {{ end }}" }} + {{ "{{ define \"nm.subject\" -}}{{- $rawStatus := .Status -}}{{- $severity := index .CommonLabels \"severity\" -}}{{- $status := \"\" -}}{{- if eq $rawStatus \"firing\" -}}{{- $status = \"FIRING\" -}}{{- else if eq $rawStatus \"resolved\" -}}{{- $status = \"RESOLVED\" -}}{{- else -}}{{- $status = \"UNKNOWN\" -}}{{- end -}}{{- $numAlerts := len .Alerts -}}{{- if eq $numAlerts 0 -}}Show nothing{{- else if eq $numAlerts 1 -}}{{- range .Alerts -}}{{- $alertType := .Labels.alerttype -}}{{- $alertName := .Labels.alertname -}}{{- $cluster := .Labels.cluster -}}{{- $node := .Labels.node -}}{{- $pod := .Labels.pod -}}{{- $namespace := .Labels.namespace -}}{{- $output := printf \"[%s]\" $status -}}{{- if $severity -}}{{- $output = printf \"%s | severity=%s\" $output $severity -}}{{- end -}}{{- if $alertType -}}{{- $output = printf \"%s | alerttype=%s\" $output $alertType -}}{{- end -}}{{- if $alertName -}}{{- $output = printf \"%s | alertname=%s\" $output $alertName -}}{{- end -}}{{- if $cluster -}}{{- $output = printf \"%s | cluster=%s\" $output $cluster -}}{{- end -}}{{- if $node -}}{{- $output = printf \"%s | node=%s\" $output $node -}}{{- end -}}{{- if $namespace -}}{{- $output = printf \"%s | namespace=%s\" $output $namespace -}}{{- end -}}{{- if $pod -}}{{- $output = printf \"%s | pod=%s\" $output $pod -}}{{- end -}}{{- $output -}}{{- end -}}{{- else -}}{{- $alertType := index .GroupLabels \"alerttype\" -}}{{- $alertName := index .GroupLabels \"alertname\" -}}{{- $cluster := index .GroupLabels \"cluster\" -}}{{- $namespace := index .GroupLabels \"namespace\" -}}{{- $node := index .GroupLabels \"node\" -}}{{- $output := printf \"[%s]\" $status -}}{{- if $severity -}}{{- $output = printf \"%s | severity=%s\" $output $severity -}}{{- end -}}{{- if $alertType -}}{{- $output = printf \"%s | alerttype=%s\" $output $alertType -}}{{- end -}}{{- if $alertName -}}{{- $output = printf \"%s | alertname=%s\" $output $alertName -}}{{- end -}}{{- if $cluster -}}{{- $output = printf \"%s | cluster=%s\" $output $cluster -}}{{- end -}}{{- if $namespace -}}{{- $output = printf \"%s | namespace=%s\" $output $namespace -}}{{- end -}}{{- if $node -}}{{- $output = printf \"%s | node=%s\" $output $node -}}{{- end -}}{{- $output -}}{{- end -}}{{- end -}}" }} {{ "{{ define \"nm.default.text\" }}{{ range .Alerts }}{{ template \"nm.default.message\" . }}" }} {{ "{{ range .Labels.SortedPairs }} {{ .Name | translate }}: {{ .Value }}" }}