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

prometheus best practices, TLS and basic auth support #200

Merged
merged 8 commits into from
May 24, 2022
Merged
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
18 changes: 9 additions & 9 deletions .github/workflows/exporter-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v2
with:
go-version: ^1.14
id: go
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v3
with:
go-version-file: 'go.mod'
id: go
- name: static analysis
run: make static-checks
- name: test
Expand All @@ -43,7 +43,7 @@ jobs:
for FILE in build/bin/*; do
gzip $FILE
done
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v3
with:
name: ha_cluster_exporter
path: build/bin
Expand Down Expand Up @@ -104,10 +104,10 @@ jobs:
if: github.event.release
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v2
- uses: actions/download-artifact@v3
with:
name: ha_cluster_exporter
- uses: AButler/[email protected]
- uses: softprops/action-gh-release@v1
with:
files: 'ha_cluster_exporter-*'
repo-token: ${{ secrets.GITHUB_TOKEN }}
token: ${{ secrets.GITHUB_TOKEN }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ ha_cluster_exporter
# we don't use vendoring
/vendor
/build

# ignore tmp promu config
.promu.release.yml
21 changes: 21 additions & 0 deletions .promu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
go:
version: 1.16
cgo: false
repository:
path: github.com/ClusterLabs/ha_cluster_exporter
build:
flags: -a -tags netgo
ldflags: |
-X github.com/prometheus/common/version.Version={{.Version}}
-X github.com/prometheus/common/version.Revision={{.Revision}}
-X github.com/prometheus/common/version.Branch={{.Branch}}
-X github.com/prometheus/common/version.BuildUser={{user}}@{{host}}
-X github.com/prometheus/common/version.BuildDate={{date "20060102-15:04:05"}}
yeoldegrove marked this conversation as resolved.
Show resolved Hide resolved
binaries:
- name: ha_cluster_exporter-amd64
- name: ha_cluster_exporter-arm64
- name: ha_cluster_exporter-ppc64le
- name: ha_cluster_exporter-s390x
tarball:
files:
- LICENSE
61 changes: 45 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
GO := GO111MODULE=on go
FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH)))
GOHOSTOS ?= $(shell $(GO) env GOHOSTOS)
GOHOSTARCH ?= $(shell $(GO) env GOHOSTARCH)
ifeq (arm, $(GOHOSTARCH))
GOHOSTARM ?= $(shell GOARM= $(GO) env GOARM)
GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)v$(GOHOSTARM)
else
GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)
endif
PROMU := $(FIRST_GOPATH)/bin/promu
PROMU_VERSION ?= 0.13.0
PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz

# this is the what ends up in the RPM "Version" field and embedded in the --version CLI flag
VERSION ?= $(shell .ci/get_version_from_git.sh)

# this will be used as the build date by the Go compile task
DATE = $(shell date --iso-8601=seconds)

# if you want to release to OBS, this must be a remotely available Git reference
REVISION ?= $(shell git rev-parse --abbrev-ref HEAD)

Expand All @@ -19,47 +30,65 @@ ARCHS ?= amd64 arm64 ppc64le s390x

default: clean mod-tidy generate fmt vet-check test build

build: amd64
promu-prepare:
sed "s/{{.Version}}/$(VERSION)/" .promu.yml >.promu.release.yml
yeoldegrove marked this conversation as resolved.
Show resolved Hide resolved
mkdir -p build/bin

# from https://github.com/prometheus/prometheus/blob/main/Makefile.common
$(PROMU):
$(eval PROMU_TMP := $(shell mktemp -d))
curl -s -L $(PROMU_URL) | tar -xvzf - -C $(PROMU_TMP)
mkdir -p $(FIRST_GOPATH)/bin
cp $(PROMU_TMP)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu
rm -r $(PROMU_TMP)

build:
$(MAKE) clean
$(MAKE) promu-prepare $(PROMU)
$(MAKE) amd64

build-all: clean $(ARCHS)
build-all:
$(MAKE) clean
$(MAKE) promu-prepare $(PROMU)
$(MAKE) $(ARCHS)

$(ARCHS):
@mkdir -p build/bin
CGO_ENABLED=0 GOOS=linux GOARCH=$@ go build -trimpath -ldflags "-s -w -X main.version=$(VERSION) -X main.buildDate=$(DATE)" -o build/bin/ha_cluster_exporter-$@
GOOS=linux GOARCH=$@ $(PROMU) build --config .promu.release.yml --prefix=build/bin ha_cluster_exporter-$@

install:
go install
$(GO) install

static-checks: vet-check fmt-check

vet-check:
go vet ./...
$(GO) vet ./...

fmt:
go fmt ./...
$(GO) fmt ./...

mod-tidy:
go mod tidy
$(GO) mod tidy

fmt-check:
.ci/go_lint.sh

generate:
go generate ./...
$(GO) generate ./...

test:
go test -v ./...
$(GO) test -v ./...

checks: static-checks test

coverage:
@mkdir -p build
go test -cover -coverprofile=build/coverage ./...
go tool cover -html=build/coverage
$(GO) test -cover -coverprofile=build/coverage ./...
$(GO) tool cover -html=build/coverage

clean:
go clean
$(GO) clean
rm -rf build
rm -f .promu.release.yml

exporter-obs-workdir: build/obs/prometheus-ha_cluster_exporter
build/obs/prometheus-ha_cluster_exporter:
Expand Down
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,47 @@ The first match has precedence, and the CLI flags have precedence over the confi

Please refer to the example [YAML configuration](ha_cluster_exporter.yaml) for more details.

Additional CLI flags can also be passed via `/etc/sysconfig/prometheus-ha_cluster_exporter`.

#### General Flags

Name | Description
---- | -----------
web.listen-address | Address to listen on for web interface and telemetry (default `:9664`).
web.telemetry-path | Path under which to expose metrics (default `/metrics`).
web.config.file | Path to a [web configuration file](#tls-and-basic-authentication) (default `/etc/ha_cluster_exporter.web.yaml`).
log.level | Logging verbosity (default `info`).
version | Print the version information.

##### Deprecated Flags
Name | Description
---- | -----------
address | deprecated: please use --web.listen-address or --web.config.file to use Prometheus Exporter Toolkit
port | deprecated: please use --web.listen-address or --web.config.file to use Prometheus Exporter Toolkit
log-level | deprecated: please use log.level
enable-timestamps | deprecated: server-side metric timestamping is discouraged by Prometheus best-practices and should be avoided

#### Collector Flags

Name | Description
---- | -----------
crm-mon-path | Path to crm_mon executable (default `/usr/sbin/crm_mon`).
cibadmin-path | Path to cibadmin executable (default `/usr/sbin/cibadmin`).
corosync-cfgtoolpath-path | Path to corosync-cfgtool executable (default `/usr/sbin/corosync-cfgtool`).
corosync-quorumtool-path | Path to corosync-quorumtool executable (default `/usr/sbin/corosync-quorumtool`).
sbd-path | Path to sbd executable (default `/usr/sbin/sbd`).
sbd-config-path | Path to sbd configuration (default `/etc/sysconfig/sbd`).
drbdsetup-path | Path to drbdsetup executable (default `/sbin/drbdsetup`).
drbdsplitbrain-path | Path to drbd splitbrain hooks temporary files (default `/var/run/drbd/splitbrain`).

### TLS and basic authentication

The ha_cluster_exporter supports TLS and basic authentication.

To use TLS and/or basic authentication, you need to pass a configuration file
using the `--web.config.file` parameter. The format of the file is described
[in the exporter-toolkit repository](https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md).

### systemd integration

A [systemd unit file](ha_cluster_exporter.service) is provided with the RPM packages. You can enable and start it as usual:
Expand All @@ -114,7 +155,7 @@ We recommend having a look at the [design document](doc/design.md) and the [deve

## License

Copyright 2019-2020 SUSE LLC
Copyright 2019-2022 SUSE LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
13 changes: 8 additions & 5 deletions collector/corosync/corosync.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,24 @@ package corosync
import (
"os/exec"

"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"

"github.com/ClusterLabs/ha_cluster_exporter/collector"
)

const subsystem = "corosync"

func NewCollector(cfgToolPath string, quorumToolPath string) (*corosyncCollector, error) {
func NewCollector(cfgToolPath string, quorumToolPath string, timestamps bool, logger log.Logger) (*corosyncCollector, error) {
err := collector.CheckExecutables(cfgToolPath, quorumToolPath)
if err != nil {
return nil, errors.Wrapf(err, "could not initialize '%s' collector", subsystem)
}

c := &corosyncCollector{
collector.NewDefaultCollector(subsystem),
collector.NewDefaultCollector(subsystem, timestamps, logger),
cfgToolPath,
quorumToolPath,
NewParser(),
Expand All @@ -41,7 +42,7 @@ type corosyncCollector struct {
}

func (c *corosyncCollector) CollectWithError(ch chan<- prometheus.Metric) error {
log.Debugln("Collecting corosync metrics...")
level.Debug(c.Logger).Log("msg", "Collecting corosync metrics...")

// We suppress the exec errors because if any interface is faulty the tools will exit with code 1, but we still want to parse the output.
cfgToolOutput, _ := exec.Command(c.cfgToolPath, "-s").Output()
Expand All @@ -62,9 +63,11 @@ func (c *corosyncCollector) CollectWithError(ch chan<- prometheus.Metric) error
}

func (c *corosyncCollector) Collect(ch chan<- prometheus.Metric) {
level.Debug(c.Logger).Log("msg", "Collecting corosync metrics...")

err := c.CollectWithError(ch)
if err != nil {
log.Warnf("'%s' collector scrape failed: %s", c.GetSubsystem(), err)
level.Warn(c.Logger).Log("msg", c.GetSubsystem()+" collector scrape failed", "err", err)
}
}

Expand Down
13 changes: 7 additions & 6 deletions collector/corosync/corosync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,46 @@ package corosync
import (
"testing"

"github.com/go-kit/log"
"github.com/stretchr/testify/assert"

assertcustom "github.com/ClusterLabs/ha_cluster_exporter/internal/assert"
)

func TestNewCorosyncCollector(t *testing.T) {
_, err := NewCollector("../../test/fake_corosync-cfgtool.sh", "../../test/fake_corosync-quorumtool.sh")
_, err := NewCollector("../../test/fake_corosync-cfgtool.sh", "../../test/fake_corosync-quorumtool.sh", false, log.NewNopLogger())
assert.Nil(t, err)
}

func TestNewCorosyncCollectorChecksCfgtoolExistence(t *testing.T) {
_, err := NewCollector("../../test/nonexistent", "../../test/fake_corosync-quorumtool.sh")
_, err := NewCollector("../../test/nonexistent", "../../test/fake_corosync-quorumtool.sh", false, log.NewNopLogger())

assert.Error(t, err)
assert.Contains(t, err.Error(), "'../../test/nonexistent' does not exist")
}

func TestNewCorosyncCollectorChecksQuorumtoolExistence(t *testing.T) {
_, err := NewCollector("../../test/fake_corosync-cfgtool.sh", "../../test/nonexistent")
_, err := NewCollector("../../test/fake_corosync-cfgtool.sh", "../../test/nonexistent", false, log.NewNopLogger())

assert.Error(t, err)
assert.Contains(t, err.Error(), "'../../test/nonexistent' does not exist")
}

func TestNewCorosyncCollectorChecksCfgtoolExecutableBits(t *testing.T) {
_, err := NewCollector("../../test/dummy", "../../test/fake_corosync-quorumtool.sh")
_, err := NewCollector("../../test/dummy", "../../test/fake_corosync-quorumtool.sh", false, log.NewNopLogger())

assert.Error(t, err)
assert.Contains(t, err.Error(), "'../../test/dummy' is not executable")
}

func TestNewCorosyncCollectorChecksQuorumtoolExecutableBits(t *testing.T) {
_, err := NewCollector("../../test/fake_corosync-cfgtool.sh", "../../test/dummy")
_, err := NewCollector("../../test/fake_corosync-cfgtool.sh", "../../test/dummy", false, log.NewNopLogger())

assert.Error(t, err)
assert.Contains(t, err.Error(), "'../../test/dummy' is not executable")
}

func TestCorosyncCollector(t *testing.T) {
collector, _ := NewCollector("../../test/fake_corosync-cfgtool.sh", "../../test/fake_corosync-quorumtool.sh")
collector, _ := NewCollector("../../test/fake_corosync-cfgtool.sh", "../../test/fake_corosync-quorumtool.sh", false, log.NewNopLogger())
assertcustom.Metrics(t, collector, "corosync.metrics")
}
10 changes: 7 additions & 3 deletions collector/default_collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package collector

import (
"github.com/ClusterLabs/ha_cluster_exporter/internal/clock"
"github.com/go-kit/log"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
config "github.com/spf13/viper"
"os"
)

Expand All @@ -18,13 +18,17 @@ type DefaultCollector struct {
subsystem string
descriptors map[string]*prometheus.Desc
Clock clock.Clock
timestamps bool
Logger log.Logger
}

func NewDefaultCollector(subsystem string) DefaultCollector {
func NewDefaultCollector(subsystem string, timestamps bool, logger log.Logger) DefaultCollector {
return DefaultCollector{
subsystem,
make(map[string]*prometheus.Desc),
&clock.SystemClock{},
timestamps,
logger,
}
}

Expand Down Expand Up @@ -67,7 +71,7 @@ func (c *DefaultCollector) MakeCounterMetric(name string, value float64, labelVa
func (c *DefaultCollector) makeMetric(name string, value float64, valueType prometheus.ValueType, labelValues ...string) prometheus.Metric {
desc := c.GetDescriptor(name)
metric := prometheus.MustNewConstMetric(desc, valueType, value, labelValues...)
if config.GetBool("enable-timestamps") {
if c.timestamps == true {
metric = prometheus.NewMetricWithTimestamp(c.Clock.Now(), metric)
}
return metric
Expand Down
Loading