Skip to content

Commit

Permalink
Add support for multiple clouds (#141)
Browse files Browse the repository at this point in the history
* Update makefile

Signed-off-by: rustyclock <[email protected]>

* Add support for multiple clouds

Signed-off-by: rustyclock <[email protected]>

* Separate /metrics and /probe endpoint

* fix Pedantic breaking --collect-metric-time

* describe both mode in README.md

* add /metrics endpoint for multicloud mode

* fix time collection, amended doc and log message

* all-clouds to multi-cloud

Co-authored-by: JeaNoel Vouilloz <[email protected]>
Co-authored-by: Jorge Niedbalski <[email protected]>
  • Loading branch information
3 people committed Dec 7, 2020
1 parent 4fc2447 commit 12e1802
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 65 deletions.
48 changes: 37 additions & 11 deletions Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ ifeq (, $(PRE_GO_111))

ifneq (,$(wildcard vendor))
# Always use the local vendor/ directory to satisfy the dependencies.
GOOPTS := $(GOOPTS) #-mod=vendor
GOOPTS := $(GOOPTS) -mod=vendor
endif
endif
else
Expand All @@ -69,12 +69,21 @@ else
GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)
endif

PROMU_VERSION ?= 0.4.0
GOTEST := $(GO) test
GOTEST_DIR :=
ifneq ($(CIRCLE_JOB),)
ifneq ($(shell which gotestsum),)
GOTEST_DIR := test-results
GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml --
endif
endif

PROMU_VERSION ?= 0.7.0
PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz

GOLANGCI_LINT :=
GOLANGCI_LINT_OPTS ?=
GOLANGCI_LINT_VERSION ?= v1.21.0
GOLANGCI_LINT_VERSION ?= v1.18.0
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64.
# windows isn't included here because of the path separator being different.
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
Expand All @@ -86,7 +95,8 @@ endif
PREFIX ?= $(shell pwd)
BIN_DIR ?= $(shell pwd)
DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD))
DOCKERFILE_PATH ?= ./
DOCKERFILE_PATH ?= ./Dockerfile
DOCKERBUILD_CONTEXT ?= ./
DOCKER_REPO ?= prom

DOCKER_ARCHS ?= amd64
Expand Down Expand Up @@ -140,15 +150,29 @@ else
$(GO) get $(GOOPTS) -t ./...
endif

.PHONY: update-go-deps
update-go-deps:
@echo ">> updating Go dependencies"
@for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \
$(GO) get $$m; \
done
GO111MODULE=$(GO111MODULE) $(GO) mod tidy
ifneq (,$(wildcard vendor))
GO111MODULE=$(GO111MODULE) $(GO) mod vendor
endif

.PHONY: common-test-short
common-test-short:
common-test-short: $(GOTEST_DIR)
@echo ">> running short tests"
GO111MODULE=$(GO111MODULE) $(GO) test -short $(GOOPTS) $(pkgs)
GO111MODULE=$(GO111MODULE) $(GOTEST) -short $(GOOPTS) $(pkgs)

.PHONY: common-test
common-test:
common-test: $(GOTEST_DIR)
@echo ">> running all tests"
GO111MODULE=$(GO111MODULE) $(GO) test $(test-flags) $(GOOPTS) $(pkgs)
GO111MODULE=$(GO111MODULE) $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs)

$(GOTEST_DIR):
@mkdir -p $@

.PHONY: common-format
common-format:
Expand Down Expand Up @@ -187,7 +211,6 @@ else
ifdef GO111MODULE
@echo ">> running check for unused/missing packages in go.mod"
GO111MODULE=$(GO111MODULE) $(GO) mod tidy
GO111MODULE=$(GO111MODULE) $(GO) mod vendor
ifeq (,$(wildcard vendor))
@git diff --exit-code -- go.sum go.mod
else
Expand All @@ -201,7 +224,7 @@ endif
.PHONY: common-build
common-build: promu
@echo ">> building binaries"
GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX)
GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES)

.PHONY: common-tarball
common-tarball: promu
Expand All @@ -212,19 +235,22 @@ common-tarball: promu
common-docker: $(BUILD_DOCKER_ARCHS)
$(BUILD_DOCKER_ARCHS): common-docker-%:
docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \
-f $(DOCKERFILE_PATH) \
--build-arg ARCH="$*" \
--build-arg OS="linux" \
$(DOCKERFILE_PATH)
$(DOCKERBUILD_CONTEXT)

.PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS)
common-docker-publish: $(PUBLISH_DOCKER_ARCHS)
$(PUBLISH_DOCKER_ARCHS): common-docker-publish-%:
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)"

DOCKER_MAJOR_VERSION_TAG = $(firstword $(subst ., ,$(shell cat VERSION)))
.PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS)
common-docker-tag-latest: $(TAG_DOCKER_ARCHS)
$(TAG_DOCKER_ARCHS): common-docker-tag-latest-%:
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest"
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)"

.PHONY: common-docker-manifest
common-docker-manifest:
Expand Down
51 changes: 45 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,33 @@ and must by specified with the `--os-client-config` flag.

Other options as the binding address/port can by explored with the --help flag.

By default the openstack\_exporter serves on port `0.0.0.0:9180` at the `/metrics` URL.
The exporter can operate in 2 modes

- A Legacy mode (targetting one cloud) in where the openstack\_exporter serves on port `0.0.0.0:9180` at the `/metrics` URL.
- A multi cloud mode in where the openstack\_exporter serves on port `0.0.0.0:9180` at the `/probe` URL.
And where `/metrics` URL is serving own exporter metrics

You can build it by yourself by cloning this repository and run:

```sh
make common-build
./openstack-exporter --os-client-config /etc/openstack/clouds.yaml region.mycludprovider.org
```

Multi cloud mode
```sh
./openstack-exporter --os-client-config /etc/openstack/clouds.yaml --multi-cloud
curl "http:https://localhost:9180/probe?cloud=region.mycludprovider.org"
```
or Legacy mode
```sh
./openstack-exporter --os-client-config /etc/openstack/clouds.yaml myregion.cloud.org
curl "http:https://localhost:9180/metrics" +
```
Or alternatively you can use the docker images, as follows (check the openstack configuration section for configuration
details):

```sh
docker run -v "$HOME/.config/openstack/clouds.yml":/etc/openstack/clouds.yaml -it quay.io/niedbalski/openstack-exporter-linux-amd64:master my-cloud.org
docker run -v "$HOME/.config/openstack/clouds.yml":/etc/openstack/clouds.yaml -it -p 9180:9180 quay.io/niedbalski/openstack-exporter-linux-amd64:master
curl "http:https://localhost:9180/probe?cloud=my-cloud.org"
```

### Command line options
Expand All @@ -87,6 +100,8 @@ Flags:
--prefix="openstack" Prefix for metrics
--endpoint-type="public" openstack endpoint type to use (i.e: public, internal, admin)
--collect-metric-time time spent collecting each metric
--disable-slow-metrics disable slow metrics for performance reasons
--multi-cloud Toggle the multiple cloud scraping mode under /probe?cloud=
-d, --disable-metric= ... multiple --disable-metric can be specified in the format: service-metric (i.e: cinder-snapshots)
--disable-service.network Disable the network service exporter
--disable-service.compute Disable the compute service exporter
Expand All @@ -103,14 +118,38 @@ Flags:
--disable-service.dns Disable the dns service exporter
--disable-service.baremetal
Disable the baremetal service exporter
--disable-service.gnocchi Disable the gnocchi service
--disable-slow-metrics disable slow metrics for performance reasons
--disable-service.gnocchi Disable the gnocchi service
--version Show application version.

Args:
<cloud> name or id of the cloud to gather metrics from
```

### Scrape options

In legacy mode cloud and metrics to be scraped are specified as argument or flags as described above.
To select multi cloud the --multi-cloud flag need to be used
In that case metrics and clouds are specified in the http scrape request as described below.
Which cloud (name or id from the `clouds.yaml` file) or what services from the cloud to scrape, can be specified as the parameters to http scrape request.

Query Parameter | Description
--- | ---
`cloud` | Name or id of the cloud to gather metrics from (as specified in the `clouds.yaml`)
`include_services` | A comma separated list of services for which metrics will be scraped. Defaults to all services: "network,compute,image,volume,identity,object-store,load-balancer,container-infra,dns,baremetal,gnocchi"
`exclude_services` | A comma separated list of services for which metrics will *not* be scraped. Default is empty: ""

Examples:
```
## Scrape all services from `test.cloud`
curl "https://localhost:9180/probe?cloud=test.cloud"
## Scrape only `network` and `compute` services from `test.cloud`
curl "https://localhost:9180/probe?cloud=test.cloud&include_services=network,compute"
## Scrape all services except `load-balancer` and `dns` from `test.cloud`
curl "https://localhost:9180/probe?cloud=test.cloud&exclude_services=load-balancer,dns"
```

### OpenStack configuration

The cloud credentials and identity configuration
Expand Down
21 changes: 6 additions & 15 deletions exporters/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ func EnableExporter(service, prefix, cloud string, disabledMetrics []string, end
if err != nil {
return nil, err
}
prometheus.MustRegister(exporter)
return &exporter, nil
}

Expand Down Expand Up @@ -91,19 +90,6 @@ func (exporter *BaseOpenStackExporter) Describe(ch chan<- *prometheus.Desc) {
}
}

func (exporter *BaseOpenStackExporter) AddMetricCollectTime(collectTimeSeconds float64, metricName string, ch chan<- prometheus.Metric) {
metricPromatheuslabels := prometheus.Labels{
"openstack_service": exporter.GetName(),
"openstack_metric": metricName}
metric := prometheus.NewDesc(
"openstack_metric_collect_seconds",
"Time needed to collect metric from OpenStack API",
nil,
metricPromatheuslabels)
log.Debugf("Adding metric for collecting timings: %+s", metric)
ch <- prometheus.MustNewConstMetric(metric, prometheus.GaugeValue, collectTimeSeconds)
}

func (exporter *BaseOpenStackExporter) RunCollection(metric *PrometheusMetric, metricName string, ch chan<- prometheus.Metric) error {
log.Infof("Collecting metrics for exporter: %s, metric: %s", exporter.GetName(), metricName)
now := time.Now()
Expand All @@ -114,7 +100,7 @@ func (exporter *BaseOpenStackExporter) RunCollection(metric *PrometheusMetric, m

log.Infof("Collected metrics for exporter: %s, metric: %s", exporter.GetName(), metricName)
if exporter.CollectTime {
exporter.AddMetricCollectTime(time.Since(now).Seconds(), metricName, ch)
ch <- prometheus.MustNewConstMetric(exporter.Metrics["openstack_metric_collect_seconds"].Metric, prometheus.GaugeValue, time.Since(now).Seconds(), metricName)
}
return nil
}
Expand Down Expand Up @@ -161,6 +147,11 @@ func (exporter *BaseOpenStackExporter) AddMetric(name string, fn ListFunc, label
"up", nil, constLabels),
Fn: nil,
}
exporter.Metrics["openstack_metric_collect_seconds"] = &PrometheusMetric{
Metric: prometheus.NewDesc(
"openstack_metric_collect_seconds", "Time needed to collect metric from OpenStack API", []string{"openstack_metric"}, prometheus.Labels{"openstack_service": exporter.GetName()}),
Fn: nil,
}
}

if constLabels == nil {
Expand Down
Loading

0 comments on commit 12e1802

Please sign in to comment.