Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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 .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/cmd/zal/zal
/zal
bin/golangci-lint
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ FROM golang:1-alpine AS build
LABEL Maintainer="info@devopy.io" Description="Fully automated Zabbix and Prometheus Alertmanager integration"
RUN apk update && apk add make git gcc musl-dev

ADD . /go/src/github.com/devopyio/zabbix-alertmanager
ADD . /go/src/github.com/Dexanir/zabbix-alertmanager

WORKDIR /go/src/github.com/devopyio/zabbix-alertmanager
WORKDIR /go/src/github.com/Dexanir/zabbix-alertmanager

ENV GO111MODULE on
RUN make build
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ linter := ./bin/golangci-lint
testflags := -v -cover

GO111MODULE := on
all: $(linter) deps test build docker-push
all: $(linter) deps test build

$(linter):
curl -sfl https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.15.0
Expand Down
34 changes: 11 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,18 @@
![zabbix-alertmanager](http://devopy.io/wp-content/uploads/2019/02/zal-200.png)

# zabbix-alertmanager

![Build Status](https://travis-ci.com/devopyio/zabbix-alertmanager.svg?branch=master)
![Go Report Card](https://goreportcard.com/badge/github.com/devopyio/zabbix-alertmanager)
[![Docker Repository on Quay](https://quay.io/repository/devopyio/zabbix-alertmanager/status "Docker Repository on Quay")](https://quay.io/repository/devopyio/zabbix-alertmanager)

Fully automated [Zabbix](https://www.zabbix.com/) and [Prometheus Alertmanager](https://prometheus.io/docs/alerting/alertmanager/) integration.

## Tutorials

[Introducing ZAL - Zabbix Alertmanager Integration](https://devopy.io/zabbix-alertmanager-integration/)
## Basic configuration
Original article:

[Setting Up Zabbix Alertmanager integration](http://devopy.io/setting-up-zabbix-alertmanager-integration/)

[Running Zabbix Alertmanager integration](http://devopy.io/)

Configuration for hosts are incorrect in the article. Working one is located [here](./zabbixprovisioner/config.yaml)

## Deployment

Checkout [kubernetes-manifests.yaml](https://github.com/devopyio/zabbix-alertmanager/blob/master/kubernetes-manifest.yaml) for deployment in Kubernetes.

[Releases](https://github.com/devopyio/zabbix-alertmanager/releases) page for binaries.

[grafana.json](https://github.com/devopyio/zabbix-alertmanager/blob/master/grafana.json) for Grafana dashboard.
[grafana.json](./grafana.json) for Grafana dashboard.

[alerts.yaml](https://github.com/devopyio/zabbix-alertmanager/blob/master/alerts.yaml) for Prometheus alerts.
[alerts.yaml](./alerts.yaml) for Prometheus alerts.

## General Info

Project consists of 2 components:
Project consists of 2 components [send](#1-zal-send) and [prov](#2-zal-prov):

## 1. zal send

Expand Down Expand Up @@ -107,3 +90,8 @@ Flags:
--key-prefix="prometheus" Prefix to add to the trapper item key.
--prometheus-url="" Prometheus URL.
```

Example of the alert's configuration is [here](./alerts.yaml)


Original repository: https://github.com/devopyio/zabbix-alertmanager
6 changes: 3 additions & 3 deletions cmd/zal/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
"strings"
"syscall"

"github.com/devopyio/zabbix-alertmanager/zabbixprovisioner/provisioner"
"github.com/devopyio/zabbix-alertmanager/zabbixsender/zabbixsnd"
"github.com/devopyio/zabbix-alertmanager/zabbixsender/zabbixsvc"
"github.com/Dexanir/zabbix-alertmanager/zabbixprovisioner/provisioner"
"github.com/Dexanir/zabbix-alertmanager/zabbixsender/zabbixsnd"
"github.com/Dexanir/zabbix-alertmanager/zabbixsender/zabbixsvc"
"github.com/povilasv/prommod"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/devopyio/zabbix-alertmanager
module github.com/Dexanir/zabbix-alertmanager

go 1.12

Expand Down
2 changes: 1 addition & 1 deletion kubernetes-manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ spec:
weight: 100
containers:
- name: zal
image: quay.io/devopyio/zabbix-alertmanager:v1.2.0
image: quay.ioDexanirzabbix-alertmanager:v1.2.0
args:
- send
- --log.level=info
Expand Down
83 changes: 11 additions & 72 deletions zabbixprovisioner/provisioner/provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"net/url"
"strings"

zabbix "github.com/devopyio/zabbix-alertmanager/zabbixprovisioner/zabbixclient"
zabbix "github.com/Dexanir/zabbix-alertmanager/zabbixprovisioner/zabbixclient"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
yaml "gopkg.in/yaml.v2"
Expand All @@ -18,7 +18,6 @@ type HostConfig struct {
HostGroups []string `yaml:"hostGroups"`
Tag string `yaml:"tag"`
DeploymentStatus string `yaml:"deploymentStatus"`
ItemDefaultApplication string `yaml:"itemDefaultApplication"`
ItemDefaultHistory string `yaml:"itemDefaultHistory"`
ItemDefaultTrends string `yaml:"itemDefaultTrends"`
ItemDefaultTrapperHosts string `yaml:"itemDefaultTrapperHosts"`
Expand Down Expand Up @@ -127,10 +126,9 @@ func (p *Provisioner) LoadRulesFromPrometheus(hostConfig HostConfig) error {
},
},
},
HostGroups: make(map[string]struct{}, len(hostConfig.HostGroups)),
Items: map[string]*CustomItem{},
Applications: map[string]*CustomApplication{},
Triggers: map[string]*CustomTrigger{},
HostGroups: make(map[string]struct{}, len(hostConfig.HostGroups)),
Items: map[string]*CustomItem{},
Triggers: map[string]*CustomTrigger{},
}

for _, hostGroupName := range hostConfig.HostGroups {
Expand Down Expand Up @@ -165,14 +163,13 @@ func (p *Provisioner) LoadRulesFromPrometheus(hostConfig HostConfig) error {
Trends: hostConfig.ItemDefaultTrends,
TrapperHosts: hostConfig.ItemDefaultTrapperHosts,
},
Applications: map[string]struct{}{},
}

newTrigger := &CustomTrigger{
State: StateNew,
Trigger: zabbix.Trigger{
Description: rule.Name,
Expression: fmt.Sprintf("{%s:%s.last()}<>0", newHost.Name, key),
Expression: fmt.Sprintf("last(/%s/%s)<>0", newHost.Name, key),
ManualClose: 1,
Tags: triggerTags,
},
Expand Down Expand Up @@ -202,18 +199,7 @@ func (p *Provisioner) LoadRulesFromPrometheus(hostConfig HostConfig) error {
// Add the special "No Data" trigger if requested
if delay, ok := rule.Annotations["zabbix_trigger_nodata"]; ok {
newTrigger.Trigger.Description = fmt.Sprintf("%s - no data for the last %s seconds", newTrigger.Trigger.Description, delay)
newTrigger.Trigger.Expression = fmt.Sprintf("{%s:%s.nodata(%s)}", newHost.Name, key, delay)
}

// If no applications are found in the rule, add the default application declared in the configuration
if len(newItem.Applications) == 0 {
newHost.AddApplication(&CustomApplication{
State: StateNew,
Application: zabbix.Application{
Name: hostConfig.ItemDefaultApplication,
},
})
newItem.Applications[hostConfig.ItemDefaultApplication] = struct{}{}
newTrigger.Trigger.Expression = fmt.Sprintf("nodata(/%s/%s,%s)", newHost.Name, key, delay)
}

log.Debugf("Loading item from Prometheus: %+v", newItem)
Expand Down Expand Up @@ -291,30 +277,14 @@ func (p *Provisioner) LoadDataFromZabbix() error {
delete(zabbixHost.Inventory, "hostid")

oldHost := p.AddHost(&CustomHost{
State: StateOld,
Host: zabbixHost,
HostGroups: hostGroups,
Items: map[string]*CustomItem{},
Applications: map[string]*CustomApplication{},
Triggers: map[string]*CustomTrigger{},
State: StateOld,
Host: zabbixHost,
HostGroups: hostGroups,
Items: map[string]*CustomItem{},
Triggers: map[string]*CustomTrigger{},
})
log.Debugf("Load host from Zabbix: %+v", oldHost)

zabbixApplications, err := p.api.ApplicationsGet(zabbix.Params{
"output": "extend",
"hostids": oldHost.HostId,
})
if err != nil {
return errors.Wrapf(err, "error getting application, hostid: %v", oldHost.HostId)
}

for _, zabbixApplication := range zabbixApplications {
oldHost.AddApplication(&CustomApplication{
State: StateOld,
Application: zabbixApplication,
})
}

zabbixItems, err := p.api.ItemsGet(zabbix.Params{
"output": "extend",
"hostids": oldHost.Host.HostId,
Expand All @@ -329,19 +299,6 @@ func (p *Provisioner) LoadDataFromZabbix() error {
Item: zabbixItem,
}

zabbixApplications, err := p.api.ApplicationsGet(zabbix.Params{
"output": "extend",
"itemids": zabbixItem.ItemId,
})
if err != nil {
return errors.Wrapf(err, "error getting item, itemid: %v", oldHost.Host.HostId)
}

newItem.Applications = make(map[string]struct{}, len(zabbixApplications))
for _, zabbixApplication := range zabbixApplications {
newItem.Applications[zabbixApplication.Name] = struct{}{}
}

log.Debugf("Loading item from Zabbix: %+v", newItem)
oldHost.AddItem(newItem)
}
Expand Down Expand Up @@ -404,24 +361,6 @@ func (p *Provisioner) ApplyChanges() error {
for _, host := range p.Hosts {
log.Debugf("Updating host, hostName: %s", host.Name)

applicationsByState := host.GetApplicationsByState()
if len(applicationsByState[StateOld]) != 0 {
log.Debugf("Deleting applications: %+v\n", applicationsByState[StateOld])
err := p.api.ApplicationsDelete(applicationsByState[StateOld])
if err != nil {
return errors.Wrap(err, "Failed in deleting applications")
}
}

if len(applicationsByState[StateNew]) != 0 {
log.Debugf("Creating applications: %+v\n", applicationsByState[StateNew])
err := p.api.ApplicationsCreate(applicationsByState[StateNew])
if err != nil {
return errors.Wrap(err, "Failed in creating applications")
}
}
host.PropagateCreatedApplications(applicationsByState[StateNew])

itemsByState := host.GetItemsByState()
triggersByState := host.GetTriggersByState()

Expand Down
2 changes: 1 addition & 1 deletion zabbixprovisioner/provisioner/provisioner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package provisioner_test
import (
"testing"

"github.com/devopyio/zabbix-alertmanager/zabbixprovisioner/provisioner"
"github.com/Dexanir/zabbix-alertmanager/zabbixprovisioner/provisioner"
)

const (
Expand Down
73 changes: 6 additions & 67 deletions zabbixprovisioner/provisioner/zabbix.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package provisioner
import (
"strings"

zabbix "github.com/devopyio/zabbix-alertmanager/zabbixprovisioner/zabbixclient"
zabbix "github.com/Dexanir/zabbix-alertmanager/zabbixprovisioner/zabbixclient"
log "github.com/sirupsen/logrus"
)

Expand All @@ -23,11 +23,6 @@ var StateName = map[State]string{
StateOld: "Old",
}

type CustomApplication struct {
State State
zabbix.Application
}

type CustomTrigger struct {
State State
zabbix.Trigger
Expand All @@ -41,16 +36,14 @@ type CustomHostGroup struct {
type CustomItem struct {
State State
zabbix.Item
Applications map[string]struct{}
}

type CustomHost struct {
State State
zabbix.Host
HostGroups map[string]struct{}
Applications map[string]*CustomApplication
Items map[string]*CustomItem
Triggers map[string]*CustomTrigger
HostGroups map[string]struct{}
Items map[string]*CustomItem
Triggers map[string]*CustomTrigger
}

type CustomZabbix struct {
Expand Down Expand Up @@ -127,15 +120,6 @@ func (host *CustomHost) AddTrigger(trigger *CustomTrigger) {
host.Triggers[trigger.Expression] = updatedTrigger
}

func (host *CustomHost) AddApplication(application *CustomApplication) {
if _, ok := host.Applications[application.Name]; ok {
if application.State == StateOld {
application.State = StateEqual
}
}
host.Applications[application.Name] = application
}

func (z *CustomZabbix) AddHostGroup(hostGroup *CustomHostGroup) {
if _, ok := z.HostGroups[hostGroup.Name]; ok {
if hostGroup.State == StateOld {
Expand Down Expand Up @@ -196,16 +180,6 @@ func (i *CustomItem) Equal(j *CustomItem) bool {
return false
}

if len(i.Applications) != len(j.Applications) {
return false
}

for appName, _ := range i.Applications {
if _, ok := j.Applications[appName]; !ok {
return false
}
}

return true
}

Expand Down Expand Up @@ -305,13 +279,6 @@ func (zabbix *CustomZabbix) PropagateCreatedHostGroups(hostGroups zabbix.HostGro
}
}

func (host *CustomHost) PropagateCreatedApplications(applications zabbix.Applications) {

for _, application := range applications {
host.Applications[application.Name].ApplicationId = application.ApplicationId
}
}

func (host *CustomHost) GetItemsByState() (itemsByState map[State]zabbix.Items) {

itemsByState = map[State]zabbix.Items{
Expand All @@ -324,16 +291,12 @@ func (host *CustomHost) GetItemsByState() (itemsByState map[State]zabbix.Items)
newItemAmmount := 0
for _, item := range host.Items {
item.HostId = host.HostId
item.Item.ApplicationIds = []string{}
for appName, _ := range item.Applications {
item.Item.ApplicationIds = append(item.Item.ApplicationIds, host.Applications[appName].ApplicationId)
}
itemsByState[item.State] = append(itemsByState[item.State], item.Item)
if StateName[item.State] == "New" || StateName[item.State] == "Updated" {
newItemAmmount++
log.Infof("GetItemsByState = State: %s, Key: %s, Applications: %+v", StateName[item.State], item.Key, item.Applications)
log.Infof("GetItemsByState = State: %s, Key: %s", StateName[item.State], item.Key)
} else {
log.Debugf("GetItemsByState = State: %s, Key: %s, Applications: %+v", StateName[item.State], item.Key, item.Applications)
log.Debugf("GetItemsByState = State: %s, Key: %s", StateName[item.State], item.Key)
}
}

Expand Down Expand Up @@ -365,30 +328,6 @@ func (host *CustomHost) GetTriggersByState() (triggersByState map[State]zabbix.T
return triggersByState
}

func (host *CustomHost) GetApplicationsByState() (applicationsByState map[State]zabbix.Applications) {

applicationsByState = map[State]zabbix.Applications{
StateNew: zabbix.Applications{},
StateOld: zabbix.Applications{},
StateUpdated: zabbix.Applications{},
StateEqual: zabbix.Applications{},
}
newAppAmmount := 0
for _, application := range host.Applications {
application.Application.HostId = host.HostId
applicationsByState[application.State] = append(applicationsByState[application.State], application.Application)
if StateName[application.State] == "New" || StateName[application.State] == "Updated" {
newAppAmmount++
log.Infof("GetApplicationsByState = State: %s, Name: %s", StateName[application.State], application.Name)
} else {
log.Debugf("GetApplicationsByState = State: %s, Name: %s", StateName[application.State], application.Name)
}
}

log.Infof("APPLICATIONS, total: %v, new or updated: %v", len(host.Applications), newAppAmmount)
return applicationsByState
}

func GetZabbixPriority(severity string) zabbix.PriorityType {

switch strings.ToLower(severity) {
Expand Down
Loading