Skip to content

Commit

Permalink
refactoring #1
Browse files Browse the repository at this point in the history
  • Loading branch information
preved911 committed Nov 8, 2021
1 parent 4387f08 commit f8e1a93
Show file tree
Hide file tree
Showing 23 changed files with 947 additions and 1,942 deletions.
2 changes: 1 addition & 1 deletion cmd/bot/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package main
import (
"fmt"

"github.com/sputnik-systems/alertmanager_bot/pkg/app"
"github.com/sputnik-systems/alertmanager_bot/internal/app"
)

func main() {
Expand Down
6 changes: 0 additions & 6 deletions deployments/helm-chart/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ spec:
- --bot.webhook-url=http://{{ include "alertmanager-bot.fullname" . }}:80/webhook
- --bot.token=$(BOT_TOKEN)
- --kube.namespace=$(NAMESPACE)
- --user.registration-token=$(USER_REGISTER_TOKEN)
env:
- name: NAMESPACE
valueFrom:
Expand All @@ -52,11 +51,6 @@ spec:
secretKeyRef:
name: {{ include "alertmanager-bot.fullname" . }}
key: bot_token
- name: USER_REGISTER_TOKEN
valueFrom:
secretKeyRef:
name: {{ include "alertmanager-bot.fullname" . }}
key: user_register_token
ports:
- name: http
containerPort: 8000
Expand Down
1 change: 0 additions & 1 deletion deployments/helm-chart/templates/secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,3 @@ metadata:
{{- include "alertmanager-bot.labels" . | nindent 4 }}
data:
bot_token: {{ .Values.bot_token | b64enc | quote }}
user_register_token: {{ .Values.user_register_token | b64enc | quote }}
10 changes: 4 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,30 @@ go 1.16

require (
github.com/VictoriaMetrics/operator v0.9.1
github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20201107014523-54104a08f947
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/imdario/mergo v0.3.11 // indirect
github.com/magefile/mage v1.11.0 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/prometheus/alertmanager v0.21.1-0.20200911160112-1fdff6b3f939
github.com/prometheus/common v0.15.0
github.com/prometheus/procfs v0.6.0 // indirect
github.com/sirupsen/logrus v1.8.0
github.com/spf13/afero v1.3.4 // indirect
github.com/spf13/cobra v1.1.3
github.com/spf13/viper v1.7.0
github.com/stretchr/testify v1.7.0
github.com/stretchr/testify v1.7.0 // indirect
github.com/vcraescu/go-paginator/v2 v2.0.0
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d // indirect
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93 // indirect
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43 // indirect
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect
golang.org/x/text v0.3.5 // indirect
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
gopkg.in/tucnak/telebot.v3 v3.0.0-20211105204051-d2269534fa9b
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/api v0.20.4 // indirect
k8s.io/api v0.20.4
k8s.io/apimachinery v0.20.4
k8s.io/client-go v12.0.0+incompatible
sigs.k8s.io/controller-runtime v0.8.1
)

replace (
Expand Down
506 changes: 16 additions & 490 deletions go.sum

Large diffs are not rendered by default.

55 changes: 55 additions & 0 deletions internal/alertmanager/alertmanager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package alertmanager

import (
"fmt"
"io"
"net/http"
"net/url"

"github.com/sputnik-systems/alertmanager_bot/internal/alertmanager/config"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)

type Alertmanager struct {
url, tp string

*config.Config
}

func New(a, w, tp string, key types.NamespacedName, kc client.Client) (*Alertmanager, error) {
if _, err := url.Parse(a); err != nil {
return nil, fmt.Errorf("given alertmanager url %s is incorrect: %s", a, err)
}

wu, err := url.Parse(w)
if err != nil {
return nil, fmt.Errorf("given webhook url %s is incorrect: %s", w, err)
}

c := config.New(key, wu, kc)

return &Alertmanager{url: a, tp: tp, Config: c}, nil
}

func (a *Alertmanager) Reload() (*http.Response, error) {
resp, err := http.Post(
fmt.Sprintf("%s/-/reload", a.url),
"application/x-www-form-urlencoded",
nil,
)
if err != nil {
return nil, fmt.Errorf("failed reload alertmanager: %s", err)
}

if resp.StatusCode >= 400 {
body, err := io.ReadAll(resp.Body)
if err != nil {
return resp, fmt.Errorf("response body read failed: %s", err)
}

return resp, fmt.Errorf("failed alertmanager reload with status code \"%d\" and body \"%s\"", resp.StatusCode, body)
}

return resp, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ func (r *Receivers) contains(receiver string) bool {
}

// ListAlerts returns a slice of Alert and an error.
func ListAlerts(url, receiver string, params map[string]string) ([]*model.Alert, error) {
func (a *Alertmanager) ListAlerts(receiver string, params map[string]string) ([]*model.Alert, error) {
req, err := http.NewRequest(
http.MethodGet,
fmt.Sprintf("%s/api/v1/alerts", url),
fmt.Sprintf("%s/api/v1/alerts", a.url),
nil,
)
if err != nil {
Expand Down
232 changes: 232 additions & 0 deletions internal/alertmanager/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
package config

import (
"context"
"fmt"
"log"
"net/url"
"strconv"
"sync"

amcfg "github.com/prometheus/alertmanager/config"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)

type Config struct {
key types.NamespacedName
wh []*amcfg.WebhookConfig
kc client.Client
mux *sync.Mutex
}

func New(key types.NamespacedName, wu *url.URL, kc client.Client) *Config {
wc := &amcfg.WebhookConfig{
NotifierConfig: amcfg.NotifierConfig{
VSendResolved: true,
},
URL: &amcfg.URL{
URL: wu,
},
}
wh := []*amcfg.WebhookConfig{wc}

return &Config{
key: key,
wh: wh,
kc: kc,
mux: &sync.Mutex{},
}
}

func (c *Config) RegisterReceiver(receiver int64) error {
conf, err := c.Get()
if err != nil {
return fmt.Errorf("failed to get alertmanager config from specified secret: %s", err)
}

c.mux.Lock()
defer c.mux.Unlock()

err = c.addReceiver(conf, receiver)
if err != nil {
return fmt.Errorf("failed to add receiver: %s", err)
}

err = c.write(conf)
if err != nil {
return fmt.Errorf("failed to save alertmanger config: %s", err)
}

return nil
}

func (c *Config) DisableReceiver(receiver int64) error {
conf, err := c.Get()
if err != nil {
return fmt.Errorf("failed to get alertmanager config from specified secret: %s", err)
}

c.mux.Lock()
defer c.mux.Unlock()

err = delAllRoutes(conf, receiver)
if err != nil {
return fmt.Errorf("failed deleting all routes for given receiver: %s", err)
}

err = removeReceiver(conf, receiver)
if err != nil {
return fmt.Errorf("failed to remove receiver from config: %s", err)
}

err = c.write(conf)
if err != nil {
return fmt.Errorf("failed to save alertmanger config: %s", err)
}

return nil
}

func (c *Config) IsReceiverExists(receiver int64) (bool, error) {
conf, err := c.Get()
if err != nil {
return false, fmt.Errorf("failed to get alertmanager config from specified secret: %s", err)
}

r := strconv.FormatInt(receiver, 10)
if p := getReceiverPosition(conf, r); p == -1 {
return false, nil
}

return true, nil
}

func (c *Config) AddRoute(receiver int64, group string) error {
conf, err := c.Get()
if err != nil {
return fmt.Errorf("failed to get alertmanager config from specified secret: %s", err)
}

c.mux.Lock()
defer c.mux.Unlock()

r := strconv.FormatInt(receiver, 10)
match := make(map[string]string)
match["alertgroup"] = group

p := getRoutePosition(conf.Route.Routes, r, match)
if p != -1 {
log.Printf("route already exists: %s/%s", r, group)

return nil
}

route := &amcfg.Route{
Receiver: r,
Continue: true,
Match: match,
}

conf.Route.Routes = append(conf.Route.Routes, route)

err = c.write(conf)
if err != nil {
return fmt.Errorf("failed to save alertmanger config: %s", err)
}

return nil
}

func (c *Config) RemoveRoute(receiver int64, group string) error {
conf, err := c.Get()
if err != nil {
return fmt.Errorf("failed to get alertmanager config from specified secret: %s", err)
}

c.mux.Lock()
defer c.mux.Unlock()

r := strconv.FormatInt(receiver, 10)
match := make(map[string]string)
match["alertgroup"] = group

p := getRoutePosition(conf.Route.Routes, r, match)
if p == -1 {
log.Printf("receiver doesn't have routes now: %s/%s", r, group)

return nil
}

conf.Route.Routes[p] = conf.Route.Routes[len(conf.Route.Routes)-1]
conf.Route.Routes = conf.Route.Routes[:len(conf.Route.Routes)-1]

err = c.write(conf)
if err != nil {
return fmt.Errorf("failed to save alertmanger config: %s", err)
}

return nil
}

func (c *Config) getSecret() (*v1.Secret, error) {
secret := &v1.Secret{}

err := c.kc.Get(context.Background(), c.key, secret)
if err != nil {
return nil, err
}

if _, ok := secret.Data["alertmanager.yaml"]; !ok {
return nil, fmt.Errorf("secret not contain alertmanager.yaml file")
}

return secret, nil
}

func (c *Config) Get() (*amcfg.Config, error) {
secret, err := c.getSecret()
if err != nil {
return nil, fmt.Errorf("failed to get secret with alertmanager config: %s", err)
}

conf, err := amcfg.Load(string(secret.Data["alertmanager.yaml"]))
if err != nil {
return nil, fmt.Errorf("failed unmarshal alertmanager.yaml file: %s", err)
}

return conf, nil
}

func (c *Config) write(conf *amcfg.Config) error {
secret, err := c.getSecret()
if err != nil {
return fmt.Errorf("failed to get secret with alertmanager config: %s", err)
}

data := conf.String()
secret.Data["alertmanager.yaml"] = []byte(data)

err = c.kc.Update(context.Background(), secret)
if err != nil {
return fmt.Errorf("failed to update alertmanager secret with config: %s", err)
}

return nil
}

func (c *Config) addReceiver(conf *amcfg.Config, receiver int64) error {
r := strconv.FormatInt(receiver, 10)
if pos := getReceiverPosition(conf, r); pos == -1 {
rc := &amcfg.Receiver{
Name: r,
WebhookConfigs: c.wh,
}
conf.Receivers = append(conf.Receivers, rc)
} else {
conf.Receivers[pos].WebhookConfigs = c.wh
}

return nil
}
Loading

0 comments on commit f8e1a93

Please sign in to comment.