mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-09 23:24:05 -08:00
Merge branch 'main' into beorn7/sparsehistogram
This commit is contained in:
commit
40ad5e284a
|
@ -38,6 +38,7 @@ jobs:
|
|||
GO111MODULE: "on"
|
||||
- run: go test ./tsdb/ -test.tsdb-isolation=false
|
||||
- run: make -C documentation/examples/remote_storage
|
||||
- run: make -C documentation/examples
|
||||
- prometheus/check_proto:
|
||||
version: "3.15.8"
|
||||
- prometheus/store_artifact:
|
||||
|
|
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
|
@ -4,4 +4,4 @@
|
|||
/discovery/kubernetes @brancz
|
||||
/tsdb @codesome
|
||||
/promql @codesome @roidelapluie
|
||||
/cmd/promtool @jessicagreben @dgl
|
||||
/cmd/promtool @dgl
|
||||
|
|
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
|
@ -4,6 +4,10 @@ updates:
|
|||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/documentation/examples/remote_storage"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/web/ui"
|
||||
schedule:
|
||||
|
|
2
.github/workflows/buf-lint.yml
vendored
2
.github/workflows/buf-lint.yml
vendored
|
@ -10,7 +10,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: bufbuild/buf-setup-action@v1.4.0
|
||||
- uses: bufbuild/buf-setup-action@v1.5.0
|
||||
- uses: bufbuild/buf-lint-action@v1
|
||||
with:
|
||||
input: 'prompb'
|
||||
|
|
2
.github/workflows/buf.yml
vendored
2
.github/workflows/buf.yml
vendored
|
@ -9,7 +9,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: bufbuild/buf-setup-action@v1.4.0
|
||||
- uses: bufbuild/buf-setup-action@v1.5.0
|
||||
- uses: bufbuild/buf-lint-action@v1
|
||||
with:
|
||||
input: 'prompb'
|
||||
|
|
5
.github/workflows/golangci-lint.yml
vendored
5
.github/workflows/golangci-lint.yml
vendored
|
@ -21,7 +21,10 @@ jobs:
|
|||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.18.x
|
||||
- name: Install snmp_exporter/generator dependencies
|
||||
run: sudo apt-get update && sudo apt-get -y install libsnmp-dev
|
||||
if: github.repository == 'prometheus/snmp_exporter'
|
||||
- name: Lint
|
||||
uses: golangci/golangci-lint-action@v3.1.0
|
||||
uses: golangci/golangci-lint-action@v3.2.0
|
||||
with:
|
||||
version: v1.45.2
|
||||
|
|
|
@ -14,6 +14,7 @@ rules:
|
|||
document-start: disable
|
||||
indentation:
|
||||
spaces: consistent
|
||||
indent-sequences: consistent
|
||||
key-duplicates:
|
||||
ignore: |
|
||||
config/testdata/section_key_dup.bad.yml
|
||||
|
|
20
CHANGELOG.md
20
CHANGELOG.md
|
@ -1,5 +1,25 @@
|
|||
# Changelog
|
||||
|
||||
## 2.36.1 / 2022-06-09
|
||||
|
||||
* [BUGFIX] promtool: Add --lint-fatal option #10840
|
||||
|
||||
## 2.36.0 / 2022-05-30
|
||||
|
||||
* [FEATURE] Add lowercase and uppercase relabel action. #10641
|
||||
* [FEATURE] SD: Add IONOS Cloud integration. #10514
|
||||
* [FEATURE] SD: Add Vultr integration. #10714
|
||||
* [FEATURE] SD: Add Linode SD failure count metric. #10673
|
||||
* [FEATURE] Add prometheus_ready metric. #10682
|
||||
* [ENHANCEMENT] Add stripDomain to template function. #10475
|
||||
* [ENHANCEMENT] UI: Enable active search through dropped targets. #10668
|
||||
* [ENHANCEMENT] promtool: support matchers when querying label values. #10727
|
||||
* [ENHANCEMENT] Add agent mode identifier. #9638
|
||||
* [BUGFIX] Changing TotalQueryableSamples from int to int64. #10549
|
||||
* [BUGFIX] tsdb/agent: Ignore duplicate exemplars. #10595
|
||||
* [BUGFIX] TSDB: Fix chunk overflow appending samples at a variable rate. #10607
|
||||
* [BUGFIX] Stop rule manager before TSDB is stopped. #10680
|
||||
|
||||
## 2.35.0 / 2022-04-21
|
||||
|
||||
This Prometheus release is built with go1.18, which contains two noticeable changes related to TLS:
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Julien Pivotto (<roidelapluie@prometheus.io> / @roidelapluie) and Levi Harrison (<levi@leviharrison.dev> / @LeviHarrison) are the main/default maintainers, some parts of the codebase have other maintainers:
|
||||
|
||||
* `cmd`
|
||||
* `promtool`: David Leadbeater (<dgl@dgl.cx> / @dgl), Jessica Grebenschikov (<jessicagreben@prometheus.io> / @jessicagreben)
|
||||
* `promtool`: David Leadbeater (<dgl@dgl.cx> / @dgl)
|
||||
* `discovery`
|
||||
* `k8s`: Frederic Branczyk (<fbranczyk@gmail.com> / @brancz)
|
||||
* `documentation`
|
||||
|
|
|
@ -59,7 +59,7 @@ Prometheus will now be reachable at <http://localhost:9090/>.
|
|||
|
||||
To build Prometheus from source code, You need:
|
||||
|
||||
* Go [version 1.16 or greater](https://golang.org/doc/install).
|
||||
* Go [version 1.17 or greater](https://golang.org/doc/install).
|
||||
* NodeJS [version 16 or greater](https://nodejs.org/).
|
||||
* npm [version 7 or greater](https://www.npmjs.com/).
|
||||
|
||||
|
|
11
RELEASE.md
11
RELEASE.md
|
@ -80,7 +80,10 @@ Maintaining the release branches for older minor releases happens on a best effo
|
|||
|
||||
A few days before a major or minor release, consider updating the dependencies.
|
||||
|
||||
Then create a pull request against the main branch.
|
||||
Note that we use [Dependabot](.github/dependabot.yml) to continuously update most things automatically. Therefore, most dependencies should be up to date.
|
||||
Check the [dependencies GitHub label](https://github.com/prometheus/prometheus/labels/dependencies) to see if there are any pending updates.
|
||||
|
||||
This bot currently does not manage `+incompatible` and `v0.0.0` in the version specifier for Go modules.
|
||||
|
||||
Note that after a dependency update, you should look out for any weirdness that
|
||||
might have happened. Such weirdnesses include but are not limited to: flaky
|
||||
|
@ -95,7 +98,9 @@ This is also a good time to consider any experimental features and feature
|
|||
flags for promotion to stable or for deprecation or ultimately removal. Do any
|
||||
of these in pull requests, one per feature.
|
||||
|
||||
#### Updating Go dependencies
|
||||
#### Manually updating Go dependencies
|
||||
|
||||
This is usually only needed for `+incompatible` and `v0.0.0` non-semver updates.
|
||||
|
||||
```bash
|
||||
make update-go-deps
|
||||
|
@ -103,7 +108,7 @@ git add go.mod go.sum
|
|||
git commit -m "Update dependencies"
|
||||
```
|
||||
|
||||
#### Updating React dependencies
|
||||
#### Manually updating React dependencies
|
||||
|
||||
The React application recently moved to a monorepo system with multiple internal npm packages. Dependency upgrades are
|
||||
quite sensitive for the time being.
|
||||
|
|
|
@ -16,6 +16,7 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/bits"
|
||||
|
@ -38,7 +39,6 @@ import (
|
|||
"github.com/grafana/regexp"
|
||||
conntrack "github.com/mwitkow/go-conntrack"
|
||||
"github.com/oklog/run"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/promlog"
|
||||
|
@ -388,6 +388,9 @@ func main() {
|
|||
serverOnlyFlag(a, "query.max-samples", "Maximum number of samples a single query can load into memory. Note that queries will fail if they try to load more samples than this into memory, so this also limits the number of samples a query can return.").
|
||||
Default("50000000").IntVar(&cfg.queryMaxSamples)
|
||||
|
||||
a.Flag("scrape.discovery-reload-interval", "Interval used by scrape manager to throttle target groups updates.").
|
||||
Hidden().Default("5s").SetValue(&cfg.scrape.DiscoveryReloadInterval)
|
||||
|
||||
a.Flag("enable-feature", "Comma separated feature names to enable. Valid options: agent, exemplar-storage, expand-external-labels, memory-snapshot-on-shutdown, promql-at-modifier, promql-negative-offset, promql-per-step-stats, remote-write-receiver (DEPRECATED), extra-scrape-metrics, new-service-discovery-manager, auto-gomaxprocs. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details.").
|
||||
Default("").StringsVar(&cfg.featureList)
|
||||
|
||||
|
@ -395,7 +398,7 @@ func main() {
|
|||
|
||||
_, err := a.Parse(os.Args[1:])
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, errors.Wrapf(err, "Error parsing commandline arguments"))
|
||||
fmt.Fprintln(os.Stderr, fmt.Errorf("Error parsing commandline arguments: %w", err))
|
||||
a.Usage(os.Args[1:])
|
||||
os.Exit(2)
|
||||
}
|
||||
|
@ -403,7 +406,7 @@ func main() {
|
|||
logger := promlog.New(&cfg.promlogConfig)
|
||||
|
||||
if err := cfg.setFeatureListOptions(logger); err != nil {
|
||||
fmt.Fprintln(os.Stderr, errors.Wrapf(err, "Error parsing feature list"))
|
||||
fmt.Fprintln(os.Stderr, fmt.Errorf("Error parsing feature list: %w", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
@ -424,13 +427,13 @@ func main() {
|
|||
|
||||
cfg.web.ExternalURL, err = computeExternalURL(cfg.prometheusURL, cfg.web.ListenAddress)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, errors.Wrapf(err, "parse external URL %q", cfg.prometheusURL))
|
||||
fmt.Fprintln(os.Stderr, fmt.Errorf("parse external URL %q: %w", cfg.prometheusURL, err))
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
cfg.web.CORSOrigin, err = compileCORSRegexString(cfg.corsRegexString)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, errors.Wrapf(err, "could not compile CORS regex string %q", cfg.corsRegexString))
|
||||
fmt.Fprintln(os.Stderr, fmt.Errorf("could not compile CORS regex string %q: %w", cfg.corsRegexString, err))
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
|
@ -523,7 +526,14 @@ func main() {
|
|||
klogv2.ClampLevel(6)
|
||||
klogv2.SetLogger(log.With(logger, "component", "k8s_client_runtime"))
|
||||
|
||||
level.Info(logger).Log("msg", "Starting Prometheus", "version", version.Info())
|
||||
modeAppName := "Prometheus Server"
|
||||
mode := "server"
|
||||
if agentMode {
|
||||
modeAppName = "Prometheus Agent"
|
||||
mode = "agent"
|
||||
}
|
||||
|
||||
level.Info(logger).Log("msg", "Starting "+modeAppName, "mode", mode, "version", version.Info())
|
||||
if bits.UintSize < 64 {
|
||||
level.Warn(logger).Log("msg", "This Prometheus binary has not been compiled for a 64-bit architecture. Due to virtual memory constraints of 32-bit systems, it is highly recommended to switch to a 64-bit binary of Prometheus.", "GOARCH", runtime.GOARCH)
|
||||
}
|
||||
|
@ -627,6 +637,7 @@ func main() {
|
|||
cfg.web.Notifier = notifierManager
|
||||
cfg.web.LookbackDelta = time.Duration(cfg.lookbackDelta)
|
||||
cfg.web.IsAgent = agentMode
|
||||
cfg.web.AppName = modeAppName
|
||||
|
||||
cfg.web.Version = &web.PrometheusVersion{
|
||||
Version: version.Version,
|
||||
|
@ -730,7 +741,7 @@ func main() {
|
|||
fs, err := filepath.Glob(pat)
|
||||
if err != nil {
|
||||
// The only error can be a bad pattern.
|
||||
return errors.Wrapf(err, "error retrieving rule files for %s", pat)
|
||||
return fmt.Errorf("error retrieving rule files for %s: %w", pat, err)
|
||||
}
|
||||
files = append(files, fs...)
|
||||
}
|
||||
|
@ -805,6 +816,7 @@ func main() {
|
|||
},
|
||||
func(err error) {
|
||||
close(cancel)
|
||||
webHandler.SetReady(false)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -836,6 +848,19 @@ func main() {
|
|||
},
|
||||
)
|
||||
}
|
||||
if !agentMode {
|
||||
// Rule manager.
|
||||
g.Add(
|
||||
func() error {
|
||||
<-reloadReady.C
|
||||
ruleManager.Run()
|
||||
return nil
|
||||
},
|
||||
func(err error) {
|
||||
ruleManager.Stop()
|
||||
},
|
||||
)
|
||||
}
|
||||
{
|
||||
// Scrape manager.
|
||||
g.Add(
|
||||
|
@ -853,6 +878,8 @@ func main() {
|
|||
func(err error) {
|
||||
// Scrape manager needs to be stopped before closing the local TSDB
|
||||
// so that it doesn't try to write samples to a closed storage.
|
||||
// We should also wait for rule manager to be fully stopped to ensure
|
||||
// we don't trigger any false positive alerts for rules using absent().
|
||||
level.Info(logger).Log("msg", "Stopping scrape manager...")
|
||||
scrapeManager.Stop()
|
||||
},
|
||||
|
@ -922,12 +949,12 @@ func main() {
|
|||
}
|
||||
|
||||
if err := reloadConfig(cfg.configFile, cfg.enableExpandExternalLabels, cfg.tsdb.EnableExemplarStorage, logger, noStepSubqueryInterval, reloaders...); err != nil {
|
||||
return errors.Wrapf(err, "error loading config from %q", cfg.configFile)
|
||||
return fmt.Errorf("error loading config from %q: %w", cfg.configFile, err)
|
||||
}
|
||||
|
||||
reloadReady.Close()
|
||||
|
||||
webHandler.Ready()
|
||||
webHandler.SetReady(true)
|
||||
level.Info(logger).Log("msg", "Server is ready to receive web requests.")
|
||||
<-cancel
|
||||
return nil
|
||||
|
@ -938,18 +965,6 @@ func main() {
|
|||
)
|
||||
}
|
||||
if !agentMode {
|
||||
// Rule manager.
|
||||
g.Add(
|
||||
func() error {
|
||||
<-reloadReady.C
|
||||
ruleManager.Run()
|
||||
return nil
|
||||
},
|
||||
func(err error) {
|
||||
ruleManager.Stop()
|
||||
},
|
||||
)
|
||||
|
||||
// TSDB.
|
||||
opts := cfg.tsdb.ToTSDBOptions()
|
||||
cancel := make(chan struct{})
|
||||
|
@ -969,7 +984,7 @@ func main() {
|
|||
|
||||
db, err := openDBWithMetrics(localStoragePath, logger, prometheus.DefaultRegisterer, &opts, localStorage.getStats())
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "opening storage failed")
|
||||
return fmt.Errorf("opening storage failed: %w", err)
|
||||
}
|
||||
|
||||
switch fsType := prom_runtime.Statfs(localStoragePath); fsType {
|
||||
|
@ -1025,7 +1040,7 @@ func main() {
|
|||
&opts,
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "opening storage failed")
|
||||
return fmt.Errorf("opening storage failed: %w", err)
|
||||
}
|
||||
|
||||
switch fsType := prom_runtime.Statfs(localStoragePath); fsType {
|
||||
|
@ -1063,7 +1078,7 @@ func main() {
|
|||
g.Add(
|
||||
func() error {
|
||||
if err := webHandler.Run(ctxWeb, listener, *webConfig); err != nil {
|
||||
return errors.Wrapf(err, "error starting web server")
|
||||
return fmt.Errorf("error starting web server: %w", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
@ -1173,7 +1188,7 @@ func reloadConfig(filename string, expandExternalLabels, enableExemplarStorage b
|
|||
|
||||
conf, err := config.LoadFile(filename, agentMode, expandExternalLabels, logger)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "couldn't load configuration (--config.file=%q)", filename)
|
||||
return fmt.Errorf("couldn't load configuration (--config.file=%q): %w", filename, err)
|
||||
}
|
||||
|
||||
if enableExemplarStorage {
|
||||
|
@ -1192,7 +1207,7 @@ func reloadConfig(filename string, expandExternalLabels, enableExemplarStorage b
|
|||
timings = append(timings, rl.name, time.Since(rstart))
|
||||
}
|
||||
if failed {
|
||||
return errors.Errorf("one or more errors occurred while applying the new configuration (--config.file=%q)", filename)
|
||||
return fmt.Errorf("one or more errors occurred while applying the new configuration (--config.file=%q)", filename)
|
||||
}
|
||||
|
||||
noStepSuqueryInterval.Set(conf.GlobalConfig.EvaluationInterval)
|
||||
|
|
|
@ -16,6 +16,7 @@ package main
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
|
@ -121,7 +122,8 @@ func TestFailedStartupExitCode(t *testing.T) {
|
|||
err := prom.Run()
|
||||
require.Error(t, err)
|
||||
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
var exitError *exec.ExitError
|
||||
if errors.As(err, &exitError) {
|
||||
status := exitError.Sys().(syscall.WaitStatus)
|
||||
require.Equal(t, expectedExitStatus, status.ExitStatus())
|
||||
} else {
|
||||
|
@ -233,7 +235,8 @@ func TestWALSegmentSizeBounds(t *testing.T) {
|
|||
|
||||
err = prom.Wait()
|
||||
require.Error(t, err)
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
var exitError *exec.ExitError
|
||||
if errors.As(err, &exitError) {
|
||||
status := exitError.Sys().(syscall.WaitStatus)
|
||||
require.Equal(t, expectedExitStatus, status.ExitStatus())
|
||||
} else {
|
||||
|
@ -278,7 +281,8 @@ func TestMaxBlockChunkSegmentSizeBounds(t *testing.T) {
|
|||
|
||||
err = prom.Wait()
|
||||
require.Error(t, err)
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
var exitError *exec.ExitError
|
||||
if errors.As(err, &exitError) {
|
||||
status := exitError.Sys().(syscall.WaitStatus)
|
||||
require.Equal(t, expectedExitStatus, status.ExitStatus())
|
||||
} else {
|
||||
|
@ -467,7 +471,8 @@ func TestModeSpecificFlags(t *testing.T) {
|
|||
|
||||
err = prom.Wait()
|
||||
require.Error(t, err)
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
var exitError *exec.ExitError
|
||||
if errors.As(err, &exitError) {
|
||||
status := exitError.Sys().(syscall.WaitStatus)
|
||||
require.Equal(t, tc.exitStatus, status.ExitStatus())
|
||||
} else {
|
||||
|
|
|
@ -16,9 +16,8 @@ package main
|
|||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const filePerm = 0o666
|
||||
|
@ -32,7 +31,7 @@ type tarGzFileWriter struct {
|
|||
func newTarGzFileWriter(archiveName string) (*tarGzFileWriter, error) {
|
||||
file, err := os.Create(archiveName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error creating archive %q", archiveName)
|
||||
return nil, fmt.Errorf("error creating archive %q: %w", archiveName, err)
|
||||
}
|
||||
gzw := gzip.NewWriter(file)
|
||||
tw := tar.NewWriter(gzw)
|
||||
|
|
|
@ -15,12 +15,13 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/model/textparse"
|
||||
|
@ -33,11 +34,11 @@ func getMinAndMaxTimestamps(p textparse.Parser) (int64, int64, error) {
|
|||
|
||||
for {
|
||||
entry, err := p.Next()
|
||||
if err == io.EOF {
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return 0, 0, errors.Wrap(err, "next")
|
||||
return 0, 0, fmt.Errorf("next: %w", err)
|
||||
}
|
||||
|
||||
if entry != textparse.EntrySeries {
|
||||
|
@ -46,7 +47,7 @@ func getMinAndMaxTimestamps(p textparse.Parser) (int64, int64, error) {
|
|||
|
||||
_, ts, _ := p.Series()
|
||||
if ts == nil {
|
||||
return 0, 0, errors.Errorf("expected timestamp for series got none")
|
||||
return 0, 0, fmt.Errorf("expected timestamp for series got none")
|
||||
}
|
||||
|
||||
if *ts > maxt {
|
||||
|
@ -118,7 +119,7 @@ func createBlocks(input []byte, mint, maxt, maxBlockDuration int64, maxSamplesIn
|
|||
// original interval later.
|
||||
w, err := tsdb.NewBlockWriter(log.NewNopLogger(), outputDir, 2*blockDuration)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "block writer")
|
||||
return fmt.Errorf("block writer: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
err = tsdb_errors.NewMulti(err, w.Close()).Err()
|
||||
|
@ -130,11 +131,11 @@ func createBlocks(input []byte, mint, maxt, maxBlockDuration int64, maxSamplesIn
|
|||
samplesCount := 0
|
||||
for {
|
||||
e, err := p.Next()
|
||||
if err == io.EOF {
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "parse")
|
||||
return fmt.Errorf("parse: %w", err)
|
||||
}
|
||||
if e != textparse.EntrySeries {
|
||||
continue
|
||||
|
@ -144,7 +145,7 @@ func createBlocks(input []byte, mint, maxt, maxBlockDuration int64, maxSamplesIn
|
|||
if ts == nil {
|
||||
l := labels.Labels{}
|
||||
p.Metric(&l)
|
||||
return errors.Errorf("expected timestamp for series %v, got none", l)
|
||||
return fmt.Errorf("expected timestamp for series %v, got none", l)
|
||||
}
|
||||
if *ts < t {
|
||||
continue
|
||||
|
@ -160,7 +161,7 @@ func createBlocks(input []byte, mint, maxt, maxBlockDuration int64, maxSamplesIn
|
|||
p.Metric(&l)
|
||||
|
||||
if _, err := app.Append(0, l, *ts, v); err != nil {
|
||||
return errors.Wrap(err, "add sample")
|
||||
return fmt.Errorf("add sample: %w", err)
|
||||
}
|
||||
|
||||
samplesCount++
|
||||
|
@ -172,7 +173,7 @@ func createBlocks(input []byte, mint, maxt, maxBlockDuration int64, maxSamplesIn
|
|||
// Therefore the old appender is committed and a new one is created.
|
||||
// This prevents keeping too many samples lined up in an appender and thus in RAM.
|
||||
if err := app.Commit(); err != nil {
|
||||
return errors.Wrap(err, "commit")
|
||||
return fmt.Errorf("commit: %w", err)
|
||||
}
|
||||
|
||||
app = w.Appender(ctx)
|
||||
|
@ -180,18 +181,18 @@ func createBlocks(input []byte, mint, maxt, maxBlockDuration int64, maxSamplesIn
|
|||
}
|
||||
|
||||
if err := app.Commit(); err != nil {
|
||||
return errors.Wrap(err, "commit")
|
||||
return fmt.Errorf("commit: %w", err)
|
||||
}
|
||||
|
||||
block, err := w.Flush(ctx)
|
||||
switch err {
|
||||
case nil:
|
||||
switch {
|
||||
case err == nil:
|
||||
if quiet {
|
||||
break
|
||||
}
|
||||
blocks, err := db.Blocks()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get blocks")
|
||||
return fmt.Errorf("get blocks: %w", err)
|
||||
}
|
||||
for _, b := range blocks {
|
||||
if b.Meta().ULID == block {
|
||||
|
@ -200,15 +201,15 @@ func createBlocks(input []byte, mint, maxt, maxBlockDuration int64, maxSamplesIn
|
|||
break
|
||||
}
|
||||
}
|
||||
case tsdb.ErrNoSeriesAppended:
|
||||
case errors.Is(err, tsdb.ErrNoSeriesAppended):
|
||||
default:
|
||||
return errors.Wrap(err, "flush")
|
||||
return fmt.Errorf("flush: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "process blocks")
|
||||
return fmt.Errorf("process blocks: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -218,7 +219,10 @@ func backfill(maxSamplesInAppender int, input []byte, outputDir string, humanRea
|
|||
p := textparse.NewOpenMetricsParser(input)
|
||||
maxt, mint, err := getMinAndMaxTimestamps(p)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting min and max timestamp")
|
||||
return fmt.Errorf("getting min and max timestamp: %w", err)
|
||||
}
|
||||
return errors.Wrap(createBlocks(input, mint, maxt, int64(maxBlockDuration/time.Millisecond), maxSamplesInAppender, outputDir, humanReadable, quiet), "block creation")
|
||||
if err = createBlocks(input, mint, maxt, int64(maxBlockDuration/time.Millisecond), maxSamplesInAppender, outputDir, humanReadable, quiet); err != nil {
|
||||
return fmt.Errorf("block creation: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type debugWriterConfig struct {
|
||||
|
@ -30,7 +28,7 @@ type debugWriterConfig struct {
|
|||
func debugWrite(cfg debugWriterConfig) error {
|
||||
archiver, err := newTarGzFileWriter(cfg.tarballName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error creating a new archiver")
|
||||
return fmt.Errorf("error creating a new archiver: %w", err)
|
||||
}
|
||||
|
||||
for _, endPointGroup := range cfg.endPointGroups {
|
||||
|
@ -39,28 +37,28 @@ func debugWrite(cfg debugWriterConfig) error {
|
|||
fmt.Println("collecting:", url)
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error executing HTTP request")
|
||||
return fmt.Errorf("error executing HTTP request: %w", err)
|
||||
}
|
||||
body, err := io.ReadAll(res.Body)
|
||||
res.Body.Close()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error reading the response body")
|
||||
return fmt.Errorf("error reading the response body: %w", err)
|
||||
}
|
||||
|
||||
if endPointGroup.postProcess != nil {
|
||||
body, err = endPointGroup.postProcess(body)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error post-processing HTTP response body")
|
||||
return fmt.Errorf("error post-processing HTTP response body: %w", err)
|
||||
}
|
||||
}
|
||||
if err := archiver.write(filename, body); err != nil {
|
||||
return errors.Wrap(err, "error writing into the archive")
|
||||
return fmt.Errorf("error writing into the archive: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := archiver.close(); err != nil {
|
||||
return errors.Wrap(err, "error closing archive writer")
|
||||
return fmt.Errorf("error closing archive writer: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Compiling debug information complete, all files written in %q.\n", cfg.tarballName)
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
|
@ -32,7 +33,6 @@ import (
|
|||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/google/pprof/profile"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/api"
|
||||
v1 "github.com/prometheus/client_golang/api/prometheus/v1"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
|
@ -95,6 +95,9 @@ func main() {
|
|||
"lint",
|
||||
"Linting checks to apply to the rules specified in the config. Available options are: "+strings.Join(lintOptions, ", ")+". Use --lint=none to disable linting",
|
||||
).Default(lintOptionDuplicateRules).String()
|
||||
checkConfigLintFatal := checkConfigCmd.Flag(
|
||||
"lint-fatal",
|
||||
"Make lint errors exit with exit code 3.").Default("false").Bool()
|
||||
|
||||
checkWebConfigCmd := checkCmd.Command("web-config", "Check if the web config files are valid or not.")
|
||||
webConfigFiles := checkWebConfigCmd.Arg(
|
||||
|
@ -111,6 +114,9 @@ func main() {
|
|||
"lint",
|
||||
"Linting checks to apply. Available options are: "+strings.Join(lintOptions, ", ")+". Use --lint=none to disable linting",
|
||||
).Default(lintOptionDuplicateRules).String()
|
||||
checkRulesLintFatal := checkRulesCmd.Flag(
|
||||
"lint-fatal",
|
||||
"Make lint errors exit with exit code 3.").Default("false").Bool()
|
||||
|
||||
checkMetricsCmd := checkCmd.Command("metrics", checkMetricsUsage)
|
||||
checkMetricsExtended := checkCmd.Flag("extended", "Print extended information related to the cardinality of the metrics.").Bool()
|
||||
|
@ -151,6 +157,7 @@ func main() {
|
|||
queryLabelsName := queryLabelsCmd.Arg("name", "Label name to provide label values for.").Required().String()
|
||||
queryLabelsBegin := queryLabelsCmd.Flag("start", "Start time (RFC3339 or Unix timestamp).").String()
|
||||
queryLabelsEnd := queryLabelsCmd.Flag("end", "End time (RFC3339 or Unix timestamp).").String()
|
||||
queryLabelsMatch := queryLabelsCmd.Flag("match", "Series selector. Can be specified multiple times.").Strings()
|
||||
|
||||
testCmd := app.Command("test", "Unit testing.")
|
||||
testRulesCmd := testCmd.Command("rules", "Unit tests for rules.")
|
||||
|
@ -235,13 +242,13 @@ func main() {
|
|||
os.Exit(CheckSD(*sdConfigFile, *sdJobName, *sdTimeout))
|
||||
|
||||
case checkConfigCmd.FullCommand():
|
||||
os.Exit(CheckConfig(*agentMode, *checkConfigSyntaxOnly, newLintConfig(*checkConfigLint), *configFiles...))
|
||||
os.Exit(CheckConfig(*agentMode, *checkConfigSyntaxOnly, newLintConfig(*checkConfigLint, *checkConfigLintFatal), *configFiles...))
|
||||
|
||||
case checkWebConfigCmd.FullCommand():
|
||||
os.Exit(CheckWebConfig(*webConfigFiles...))
|
||||
|
||||
case checkRulesCmd.FullCommand():
|
||||
os.Exit(CheckRules(newLintConfig(*checkRulesLint), *ruleFiles...))
|
||||
os.Exit(CheckRules(newLintConfig(*checkRulesLint, *checkRulesLintFatal), *ruleFiles...))
|
||||
|
||||
case checkMetricsCmd.FullCommand():
|
||||
os.Exit(CheckMetrics(*checkMetricsExtended))
|
||||
|
@ -265,7 +272,7 @@ func main() {
|
|||
os.Exit(debugAll(*debugAllServer))
|
||||
|
||||
case queryLabelsCmd.FullCommand():
|
||||
os.Exit(QueryLabels(*queryLabelsServer, *queryLabelsName, *queryLabelsBegin, *queryLabelsEnd, p))
|
||||
os.Exit(QueryLabels(*queryLabelsServer, *queryLabelsMatch, *queryLabelsName, *queryLabelsBegin, *queryLabelsEnd, p))
|
||||
|
||||
case testRulesCmd.FullCommand():
|
||||
os.Exit(RulesUnitTest(
|
||||
|
@ -302,11 +309,14 @@ var lintError = fmt.Errorf("lint error")
|
|||
type lintConfig struct {
|
||||
all bool
|
||||
duplicateRules bool
|
||||
fatal bool
|
||||
}
|
||||
|
||||
func newLintConfig(stringVal string) lintConfig {
|
||||
func newLintConfig(stringVal string, fatal bool) lintConfig {
|
||||
items := strings.Split(stringVal, ",")
|
||||
ls := lintConfig{}
|
||||
ls := lintConfig{
|
||||
fatal: fatal,
|
||||
}
|
||||
for _, setting := range items {
|
||||
switch setting {
|
||||
case lintOptionAll:
|
||||
|
@ -328,7 +338,7 @@ func (ls lintConfig) lintDuplicateRules() bool {
|
|||
// CheckConfig validates configuration files.
|
||||
func CheckConfig(agentMode, checkSyntaxOnly bool, lintSettings lintConfig, files ...string) int {
|
||||
failed := false
|
||||
hasLintErrors := false
|
||||
hasErrors := false
|
||||
|
||||
for _, f := range files {
|
||||
ruleFiles, err := checkConfig(agentMode, f, checkSyntaxOnly)
|
||||
|
@ -351,7 +361,7 @@ func CheckConfig(agentMode, checkSyntaxOnly bool, lintSettings lintConfig, files
|
|||
}
|
||||
failed = true
|
||||
for _, err := range errs {
|
||||
hasLintErrors = hasLintErrors || errors.Is(err, lintError)
|
||||
hasErrors = hasErrors || !errors.Is(err, lintError)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf(" SUCCESS: %d rules found\n", n)
|
||||
|
@ -359,12 +369,12 @@ func CheckConfig(agentMode, checkSyntaxOnly bool, lintSettings lintConfig, files
|
|||
fmt.Println()
|
||||
}
|
||||
}
|
||||
if failed && hasLintErrors {
|
||||
return lintErrExitCode
|
||||
}
|
||||
if failed {
|
||||
if failed && hasErrors {
|
||||
return failureExitCode
|
||||
}
|
||||
if failed && lintSettings.fatal {
|
||||
return lintErrExitCode
|
||||
}
|
||||
return successExitCode
|
||||
}
|
||||
|
||||
|
@ -413,10 +423,10 @@ func checkConfig(agentMode bool, filename string, checkSyntaxOnly bool) ([]strin
|
|||
// If an explicit file was given, error if it is not accessible.
|
||||
if !strings.Contains(rf, "*") {
|
||||
if len(rfs) == 0 {
|
||||
return nil, errors.Errorf("%q does not point to an existing file", rf)
|
||||
return nil, fmt.Errorf("%q does not point to an existing file", rf)
|
||||
}
|
||||
if err := checkFileExists(rfs[0]); err != nil {
|
||||
return nil, errors.Wrapf(err, "error checking rule file %q", rfs[0])
|
||||
return nil, fmt.Errorf("error checking rule file %q: %w", rfs[0], err)
|
||||
}
|
||||
}
|
||||
ruleFiles = append(ruleFiles, rfs...)
|
||||
|
@ -426,7 +436,7 @@ func checkConfig(agentMode bool, filename string, checkSyntaxOnly bool) ([]strin
|
|||
for _, scfg := range cfg.ScrapeConfigs {
|
||||
if !checkSyntaxOnly && scfg.HTTPClientConfig.Authorization != nil {
|
||||
if err := checkFileExists(scfg.HTTPClientConfig.Authorization.CredentialsFile); err != nil {
|
||||
return nil, errors.Wrapf(err, "error checking authorization credentials or bearer token file %q", scfg.HTTPClientConfig.Authorization.CredentialsFile)
|
||||
return nil, fmt.Errorf("error checking authorization credentials or bearer token file %q: %w", scfg.HTTPClientConfig.Authorization.CredentialsFile, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,7 +464,7 @@ func checkConfig(agentMode bool, filename string, checkSyntaxOnly bool) ([]strin
|
|||
var targetGroups []*targetgroup.Group
|
||||
targetGroups, err = checkSDFile(f)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("checking SD file %q: %v", file, err)
|
||||
return nil, fmt.Errorf("checking SD file %q: %w", file, err)
|
||||
}
|
||||
if err := checkTargetGroupsForScrapeConfig(targetGroups, scfg); err != nil {
|
||||
return nil, err
|
||||
|
@ -490,7 +500,7 @@ func checkConfig(agentMode bool, filename string, checkSyntaxOnly bool) ([]strin
|
|||
var targetGroups []*targetgroup.Group
|
||||
targetGroups, err = checkSDFile(f)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("checking SD file %q: %v", file, err)
|
||||
return nil, fmt.Errorf("checking SD file %q: %w", file, err)
|
||||
}
|
||||
|
||||
if err := checkTargetGroupsForAlertmanager(targetGroups, amcfg); err != nil {
|
||||
|
@ -513,10 +523,10 @@ func checkConfig(agentMode bool, filename string, checkSyntaxOnly bool) ([]strin
|
|||
|
||||
func checkTLSConfig(tlsConfig config_util.TLSConfig, checkSyntaxOnly bool) error {
|
||||
if len(tlsConfig.CertFile) > 0 && len(tlsConfig.KeyFile) == 0 {
|
||||
return errors.Errorf("client cert file %q specified without client key file", tlsConfig.CertFile)
|
||||
return fmt.Errorf("client cert file %q specified without client key file", tlsConfig.CertFile)
|
||||
}
|
||||
if len(tlsConfig.KeyFile) > 0 && len(tlsConfig.CertFile) == 0 {
|
||||
return errors.Errorf("client key file %q specified without client cert file", tlsConfig.KeyFile)
|
||||
return fmt.Errorf("client key file %q specified without client cert file", tlsConfig.KeyFile)
|
||||
}
|
||||
|
||||
if checkSyntaxOnly {
|
||||
|
@ -524,10 +534,10 @@ func checkTLSConfig(tlsConfig config_util.TLSConfig, checkSyntaxOnly bool) error
|
|||
}
|
||||
|
||||
if err := checkFileExists(tlsConfig.CertFile); err != nil {
|
||||
return errors.Wrapf(err, "error checking client cert file %q", tlsConfig.CertFile)
|
||||
return fmt.Errorf("error checking client cert file %q: %w", tlsConfig.CertFile, err)
|
||||
}
|
||||
if err := checkFileExists(tlsConfig.KeyFile); err != nil {
|
||||
return errors.Wrapf(err, "error checking client key file %q", tlsConfig.KeyFile)
|
||||
return fmt.Errorf("error checking client key file %q: %w", tlsConfig.KeyFile, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -557,12 +567,12 @@ func checkSDFile(filename string) ([]*targetgroup.Group, error) {
|
|||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, errors.Errorf("invalid file extension: %q", ext)
|
||||
return nil, fmt.Errorf("invalid file extension: %q", ext)
|
||||
}
|
||||
|
||||
for i, tg := range targetGroups {
|
||||
if tg == nil {
|
||||
return nil, errors.Errorf("nil target group item found (index %d)", i)
|
||||
return nil, fmt.Errorf("nil target group item found (index %d)", i)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -572,7 +582,7 @@ func checkSDFile(filename string) ([]*targetgroup.Group, error) {
|
|||
// CheckRules validates rule files.
|
||||
func CheckRules(ls lintConfig, files ...string) int {
|
||||
failed := false
|
||||
hasLintErrors := false
|
||||
hasErrors := false
|
||||
|
||||
for _, f := range files {
|
||||
if n, errs := checkRules(f, ls); errs != nil {
|
||||
|
@ -582,19 +592,19 @@ func CheckRules(ls lintConfig, files ...string) int {
|
|||
}
|
||||
failed = true
|
||||
for _, err := range errs {
|
||||
hasLintErrors = hasLintErrors || errors.Is(err, lintError)
|
||||
hasErrors = hasErrors || !errors.Is(err, lintError)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf(" SUCCESS: %d rules found\n", n)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
if failed && hasLintErrors {
|
||||
return lintErrExitCode
|
||||
}
|
||||
if failed {
|
||||
if failed && hasErrors {
|
||||
return failureExitCode
|
||||
}
|
||||
if failed && ls.fatal {
|
||||
return lintErrExitCode
|
||||
}
|
||||
return successExitCode
|
||||
}
|
||||
|
||||
|
@ -929,7 +939,7 @@ func QuerySeries(url *url.URL, matchers []string, start, end string, p printer)
|
|||
}
|
||||
|
||||
// QueryLabels queries for label values against a Prometheus server.
|
||||
func QueryLabels(url *url.URL, name, start, end string, p printer) int {
|
||||
func QueryLabels(url *url.URL, matchers []string, name, start, end string, p printer) int {
|
||||
if url.Scheme == "" {
|
||||
url.Scheme = "http"
|
||||
}
|
||||
|
@ -953,7 +963,7 @@ func QueryLabels(url *url.URL, name, start, end string, p printer) int {
|
|||
// Run query against client.
|
||||
api := v1.NewAPI(c)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
val, warn, err := api.LabelValues(ctx, name, []string{}, stime, etime)
|
||||
val, warn, err := api.LabelValues(ctx, name, matchers, stime, etime)
|
||||
cancel()
|
||||
|
||||
for _, v := range warn {
|
||||
|
@ -991,14 +1001,14 @@ func parseStartTimeAndEndTime(start, end string) (time.Time, time.Time, error) {
|
|||
if start != "" {
|
||||
stime, err = parseTime(start)
|
||||
if err != nil {
|
||||
return stime, etime, errors.Wrap(err, "error parsing start time")
|
||||
return stime, etime, fmt.Errorf("error parsing start time: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if end != "" {
|
||||
etime, err = parseTime(end)
|
||||
if err != nil {
|
||||
return stime, etime, errors.Wrap(err, "error parsing end time")
|
||||
return stime, etime, fmt.Errorf("error parsing end time: %w", err)
|
||||
}
|
||||
}
|
||||
return stime, etime, nil
|
||||
|
@ -1012,7 +1022,7 @@ func parseTime(s string) (time.Time, error) {
|
|||
if t, err := time.Parse(time.RFC3339Nano, s); err == nil {
|
||||
return t, nil
|
||||
}
|
||||
return time.Time{}, errors.Errorf("cannot parse %q to a valid timestamp", s)
|
||||
return time.Time{}, fmt.Errorf("cannot parse %q to a valid timestamp", s)
|
||||
}
|
||||
|
||||
type endpointsGroup struct {
|
||||
|
@ -1038,7 +1048,7 @@ var (
|
|||
}
|
||||
var buf bytes.Buffer
|
||||
if err := p.WriteUncompressed(&buf); err != nil {
|
||||
return nil, errors.Wrap(err, "writing the profile to the buffer")
|
||||
return nil, fmt.Errorf("writing the profile to the buffer: %w", err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
|
@ -1148,13 +1158,13 @@ func importRules(url *url.URL, start, end, outputDir string, evalInterval, maxBl
|
|||
} else {
|
||||
etime, err = parseTime(end)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing end time: %v", err)
|
||||
return fmt.Errorf("error parsing end time: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
stime, err = parseTime(start)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing start time: %v", err)
|
||||
return fmt.Errorf("error parsing start time: %w", err)
|
||||
}
|
||||
|
||||
if !stime.Before(etime) {
|
||||
|
@ -1172,14 +1182,14 @@ func importRules(url *url.URL, start, end, outputDir string, evalInterval, maxBl
|
|||
Address: url.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("new api client error: %v", err)
|
||||
return fmt.Errorf("new api client error: %w", err)
|
||||
}
|
||||
|
||||
ruleImporter := newRuleImporter(log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)), cfg, v1.NewAPI(client))
|
||||
errs := ruleImporter.loadGroups(ctx, files)
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
return fmt.Errorf("rule importer parse error: %v", err)
|
||||
return fmt.Errorf("rule importer parse error: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/pkg/errors"
|
||||
v1 "github.com/prometheus/client_golang/api/prometheus/v1"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
|
@ -122,7 +121,7 @@ func (importer *ruleImporter) importRule(ctx context.Context, ruleExpr, ruleName
|
|||
},
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "query range")
|
||||
return fmt.Errorf("query range: %w", err)
|
||||
}
|
||||
if warnings != nil {
|
||||
level.Warn(importer.logger).Log("msg", "Range query returned warnings.", "warnings", warnings)
|
||||
|
@ -136,7 +135,7 @@ func (importer *ruleImporter) importRule(ctx context.Context, ruleExpr, ruleName
|
|||
// original interval later.
|
||||
w, err := tsdb.NewBlockWriter(log.NewNopLogger(), importer.config.outputDir, 2*blockDuration)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "new block writer")
|
||||
return fmt.Errorf("new block writer: %w", err)
|
||||
}
|
||||
var closed bool
|
||||
defer func() {
|
||||
|
@ -167,7 +166,7 @@ func (importer *ruleImporter) importRule(ctx context.Context, ruleExpr, ruleName
|
|||
|
||||
for _, value := range sample.Values {
|
||||
if err := app.add(ctx, lb.Labels(), timestamp.FromTime(value.Timestamp.Time()), float64(value.Value)); err != nil {
|
||||
return errors.Wrap(err, "add")
|
||||
return fmt.Errorf("add: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -176,7 +175,7 @@ func (importer *ruleImporter) importRule(ctx context.Context, ruleExpr, ruleName
|
|||
}
|
||||
|
||||
if err := app.flushAndCommit(ctx); err != nil {
|
||||
return errors.Wrap(err, "flush and commit")
|
||||
return fmt.Errorf("flush and commit: %w", err)
|
||||
}
|
||||
err = tsdb_errors.NewMulti(err, w.Close()).Err()
|
||||
closed = true
|
||||
|
@ -204,7 +203,7 @@ type multipleAppender struct {
|
|||
|
||||
func (m *multipleAppender) add(ctx context.Context, l labels.Labels, t int64, v float64) error {
|
||||
if _, err := m.appender.Append(0, l, t, v); err != nil {
|
||||
return errors.Wrap(err, "multiappender append")
|
||||
return fmt.Errorf("multiappender append: %w", err)
|
||||
}
|
||||
m.currentSampleCount++
|
||||
if m.currentSampleCount >= m.maxSamplesInMemory {
|
||||
|
@ -218,7 +217,7 @@ func (m *multipleAppender) commit(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
if err := m.appender.Commit(); err != nil {
|
||||
return errors.Wrap(err, "multiappender commit")
|
||||
return fmt.Errorf("multiappender commit: %w", err)
|
||||
}
|
||||
m.appender = m.writer.Appender(ctx)
|
||||
m.currentSampleCount = 0
|
||||
|
@ -230,7 +229,7 @@ func (m *multipleAppender) flushAndCommit(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
if _, err := m.writer.Flush(ctx); err != nil {
|
||||
return errors.Wrap(err, "multiappender flush")
|
||||
return fmt.Errorf("multiappender flush: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ import (
|
|||
|
||||
"github.com/alecthomas/units"
|
||||
"github.com/go-kit/log"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/tsdb"
|
||||
|
@ -237,29 +236,29 @@ func (b *writeBenchmark) startProfiling() error {
|
|||
// Start CPU profiling.
|
||||
b.cpuprof, err = os.Create(filepath.Join(b.outPath, "cpu.prof"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("bench: could not create cpu profile: %v", err)
|
||||
return fmt.Errorf("bench: could not create cpu profile: %w", err)
|
||||
}
|
||||
if err := pprof.StartCPUProfile(b.cpuprof); err != nil {
|
||||
return fmt.Errorf("bench: could not start CPU profile: %v", err)
|
||||
return fmt.Errorf("bench: could not start CPU profile: %w", err)
|
||||
}
|
||||
|
||||
// Start memory profiling.
|
||||
b.memprof, err = os.Create(filepath.Join(b.outPath, "mem.prof"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("bench: could not create memory profile: %v", err)
|
||||
return fmt.Errorf("bench: could not create memory profile: %w", err)
|
||||
}
|
||||
runtime.MemProfileRate = 64 * 1024
|
||||
|
||||
// Start fatal profiling.
|
||||
b.blockprof, err = os.Create(filepath.Join(b.outPath, "block.prof"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("bench: could not create block profile: %v", err)
|
||||
return fmt.Errorf("bench: could not create block profile: %w", err)
|
||||
}
|
||||
runtime.SetBlockProfileRate(20)
|
||||
|
||||
b.mtxprof, err = os.Create(filepath.Join(b.outPath, "mutex.prof"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("bench: could not create mutex profile: %v", err)
|
||||
return fmt.Errorf("bench: could not create mutex profile: %w", err)
|
||||
}
|
||||
runtime.SetMutexProfileFraction(20)
|
||||
return nil
|
||||
|
@ -273,14 +272,14 @@ func (b *writeBenchmark) stopProfiling() error {
|
|||
}
|
||||
if b.memprof != nil {
|
||||
if err := pprof.Lookup("heap").WriteTo(b.memprof, 0); err != nil {
|
||||
return fmt.Errorf("error writing mem profile: %v", err)
|
||||
return fmt.Errorf("error writing mem profile: %w", err)
|
||||
}
|
||||
b.memprof.Close()
|
||||
b.memprof = nil
|
||||
}
|
||||
if b.blockprof != nil {
|
||||
if err := pprof.Lookup("block").WriteTo(b.blockprof, 0); err != nil {
|
||||
return fmt.Errorf("error writing block profile: %v", err)
|
||||
return fmt.Errorf("error writing block profile: %w", err)
|
||||
}
|
||||
b.blockprof.Close()
|
||||
b.blockprof = nil
|
||||
|
@ -288,7 +287,7 @@ func (b *writeBenchmark) stopProfiling() error {
|
|||
}
|
||||
if b.mtxprof != nil {
|
||||
if err := pprof.Lookup("mutex").WriteTo(b.mtxprof, 0); err != nil {
|
||||
return fmt.Errorf("error writing mutex profile: %v", err)
|
||||
return fmt.Errorf("error writing mutex profile: %w", err)
|
||||
}
|
||||
b.mtxprof.Close()
|
||||
b.mtxprof = nil
|
||||
|
@ -681,7 +680,7 @@ func backfillOpenMetrics(path, outputDir string, humanReadable, quiet bool, maxB
|
|||
defer inputFile.Close()
|
||||
|
||||
if err := os.MkdirAll(outputDir, 0o777); err != nil {
|
||||
return checkErr(errors.Wrap(err, "create output dir"))
|
||||
return checkErr(fmt.Errorf("create output dir: %w", err))
|
||||
}
|
||||
|
||||
return checkErr(backfill(5000, inputFile.Bytes(), outputDir, humanReadable, quiet, maxBlockDuration))
|
||||
|
|
|
@ -15,6 +15,7 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -25,7 +26,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
|
@ -87,7 +87,7 @@ func ruleUnitTest(filename string, queryOpts promql.LazyLoaderOpts) []error {
|
|||
groupOrderMap := make(map[string]int)
|
||||
for i, gn := range unitTestInp.GroupEvalOrder {
|
||||
if _, ok := groupOrderMap[gn]; ok {
|
||||
return []error{errors.Errorf("group name repeated in evaluation order: %s", gn)}
|
||||
return []error{fmt.Errorf("group name repeated in evaluation order: %s", gn)}
|
||||
}
|
||||
groupOrderMap[gn] = i
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ func (tg *testGroup) test(evalInterval time.Duration, groupOrderMap map[string]i
|
|||
if tg.TestGroupName != "" {
|
||||
testGroupLog = fmt.Sprintf(" (in TestGroup %s)", tg.TestGroupName)
|
||||
}
|
||||
return []error{errors.Errorf("an item under alert_rule_test misses required attribute alertname at eval_time %v%s", alert.EvalTime, testGroupLog)}
|
||||
return []error{fmt.Errorf("an item under alert_rule_test misses required attribute alertname at eval_time %v%s", alert.EvalTime, testGroupLog)}
|
||||
}
|
||||
alertEvalTimesMap[alert.EvalTime] = struct{}{}
|
||||
|
||||
|
@ -240,7 +240,7 @@ func (tg *testGroup) test(evalInterval time.Duration, groupOrderMap map[string]i
|
|||
g.Eval(suite.Context(), ts)
|
||||
for _, r := range g.Rules() {
|
||||
if r.LastError() != nil {
|
||||
evalErrs = append(evalErrs, errors.Errorf(" rule: %s, time: %s, err: %v",
|
||||
evalErrs = append(evalErrs, fmt.Errorf(" rule: %s, time: %s, err: %v",
|
||||
r.Name(), ts.Sub(time.Unix(0, 0).UTC()), r.LastError()))
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ func (tg *testGroup) test(evalInterval time.Duration, groupOrderMap map[string]i
|
|||
}
|
||||
expString := indentLines(expAlerts.String(), " ")
|
||||
gotString := indentLines(gotAlerts.String(), " ")
|
||||
errs = append(errs, errors.Errorf("%s alertname: %s, time: %s, \n exp:%v, \n got:%v",
|
||||
errs = append(errs, fmt.Errorf("%s alertname: %s, time: %s, \n exp:%v, \n got:%v",
|
||||
testName, testcase.Alertname, testcase.EvalTime.String(), expString, gotString))
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ Outer:
|
|||
got, err := query(suite.Context(), testCase.Expr, mint.Add(time.Duration(testCase.EvalTime)),
|
||||
suite.QueryEngine(), suite.Queryable())
|
||||
if err != nil {
|
||||
errs = append(errs, errors.Errorf(" expr: %q, time: %s, err: %s", testCase.Expr,
|
||||
errs = append(errs, fmt.Errorf(" expr: %q, time: %s, err: %s", testCase.Expr,
|
||||
testCase.EvalTime.String(), err.Error()))
|
||||
continue
|
||||
}
|
||||
|
@ -355,9 +355,9 @@ Outer:
|
|||
for _, s := range testCase.ExpSamples {
|
||||
lb, err := parser.ParseMetric(s.Labels)
|
||||
if err != nil {
|
||||
err = errors.Wrapf(err, "labels %q", s.Labels)
|
||||
errs = append(errs, errors.Errorf(" expr: %q, time: %s, err: %s", testCase.Expr,
|
||||
testCase.EvalTime.String(), err.Error()))
|
||||
err = fmt.Errorf("labels %q: %w", s.Labels, err)
|
||||
errs = append(errs, fmt.Errorf(" expr: %q, time: %s, err: %w", testCase.Expr,
|
||||
testCase.EvalTime.String(), err))
|
||||
continue Outer
|
||||
}
|
||||
expSamples = append(expSamples, parsedSample{
|
||||
|
@ -373,7 +373,7 @@ Outer:
|
|||
return labels.Compare(gotSamples[i].Labels, gotSamples[j].Labels) <= 0
|
||||
})
|
||||
if !reflect.DeepEqual(expSamples, gotSamples) {
|
||||
errs = append(errs, errors.Errorf(" expr: %q, time: %s,\n exp: %v\n got: %v", testCase.Expr,
|
||||
errs = append(errs, fmt.Errorf(" expr: %q, time: %s,\n exp: %v\n got: %v", testCase.Expr,
|
||||
testCase.EvalTime.String(), parsedSamplesString(expSamples), parsedSamplesString(gotSamples)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
|
@ -25,7 +26,6 @@ import (
|
|||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/grafana/regexp"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/sigv4"
|
||||
|
@ -108,7 +108,7 @@ func LoadFile(filename string, agentMode, expandExternalLabels bool, logger log.
|
|||
}
|
||||
cfg, err := Load(string(content), expandExternalLabels, logger)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "parsing YAML file %s", filename)
|
||||
return nil, fmt.Errorf("parsing YAML file %s: %w", filename, err)
|
||||
}
|
||||
|
||||
if agentMode {
|
||||
|
@ -276,7 +276,7 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
|
||||
for _, rf := range c.RuleFiles {
|
||||
if !patRulePath.MatchString(rf) {
|
||||
return errors.Errorf("invalid rule file path %q", rf)
|
||||
return fmt.Errorf("invalid rule file path %q", rf)
|
||||
}
|
||||
}
|
||||
// Do global overrides and validate unique names.
|
||||
|
@ -291,7 +291,7 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
scfg.ScrapeInterval = c.GlobalConfig.ScrapeInterval
|
||||
}
|
||||
if scfg.ScrapeTimeout > scfg.ScrapeInterval {
|
||||
return errors.Errorf("scrape timeout greater than scrape interval for scrape config with job name %q", scfg.JobName)
|
||||
return fmt.Errorf("scrape timeout greater than scrape interval for scrape config with job name %q", scfg.JobName)
|
||||
}
|
||||
if scfg.ScrapeTimeout == 0 {
|
||||
if c.GlobalConfig.ScrapeTimeout > scfg.ScrapeInterval {
|
||||
|
@ -302,7 +302,7 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
}
|
||||
|
||||
if _, ok := jobNames[scfg.JobName]; ok {
|
||||
return errors.Errorf("found multiple scrape configs with job name %q", scfg.JobName)
|
||||
return fmt.Errorf("found multiple scrape configs with job name %q", scfg.JobName)
|
||||
}
|
||||
jobNames[scfg.JobName] = struct{}{}
|
||||
}
|
||||
|
@ -313,7 +313,7 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
}
|
||||
// Skip empty names, we fill their name with their config hash in remote write code.
|
||||
if _, ok := rwNames[rwcfg.Name]; ok && rwcfg.Name != "" {
|
||||
return errors.Errorf("found multiple remote write configs with job name %q", rwcfg.Name)
|
||||
return fmt.Errorf("found multiple remote write configs with job name %q", rwcfg.Name)
|
||||
}
|
||||
rwNames[rwcfg.Name] = struct{}{}
|
||||
}
|
||||
|
@ -324,7 +324,7 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
}
|
||||
// Skip empty names, we fill their name with their config hash in remote read code.
|
||||
if _, ok := rrNames[rrcfg.Name]; ok && rrcfg.Name != "" {
|
||||
return errors.Errorf("found multiple remote read configs with job name %q", rrcfg.Name)
|
||||
return fmt.Errorf("found multiple remote read configs with job name %q", rrcfg.Name)
|
||||
}
|
||||
rrNames[rrcfg.Name] = struct{}{}
|
||||
}
|
||||
|
@ -363,10 +363,10 @@ func (c *GlobalConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
|
||||
for _, l := range gc.ExternalLabels {
|
||||
if !model.LabelName(l.Name).IsValid() {
|
||||
return errors.Errorf("%q is not a valid label name", l.Name)
|
||||
return fmt.Errorf("%q is not a valid label name", l.Name)
|
||||
}
|
||||
if !model.LabelValue(l.Value).IsValid() {
|
||||
return errors.Errorf("%q is not a valid label value", l.Value)
|
||||
return fmt.Errorf("%q is not a valid label value", l.Value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -741,7 +741,7 @@ func checkStaticTargets(configs discovery.Configs) error {
|
|||
func CheckTargetAddress(address model.LabelValue) error {
|
||||
// For now check for a URL, we may want to expand this later.
|
||||
if strings.Contains(string(address), "/") {
|
||||
return errors.Errorf("%q is not a valid hostname", address)
|
||||
return fmt.Errorf("%q is not a valid hostname", address)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -810,7 +810,7 @@ func validateHeadersForTracing(headers map[string]string) error {
|
|||
return errors.New("custom authorization header configuration is not yet supported")
|
||||
}
|
||||
if _, ok := reservedHeaders[strings.ToLower(header)]; ok {
|
||||
return errors.Errorf("%s is a reserved header. It must not be changed", header)
|
||||
return fmt.Errorf("%s is a reserved header. It must not be changed", header)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -822,7 +822,7 @@ func validateHeaders(headers map[string]string) error {
|
|||
return errors.New("authorization header must be changed via the basic_auth, authorization, oauth2, or sigv4 parameter")
|
||||
}
|
||||
if _, ok := reservedHeaders[strings.ToLower(header)]; ok {
|
||||
return errors.Errorf("%s is a reserved header. It must not be changed", header)
|
||||
return fmt.Errorf("%s is a reserved header. It must not be changed", header)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -40,6 +40,7 @@ import (
|
|||
"github.com/prometheus/prometheus/discovery/file"
|
||||
"github.com/prometheus/prometheus/discovery/hetzner"
|
||||
"github.com/prometheus/prometheus/discovery/http"
|
||||
"github.com/prometheus/prometheus/discovery/ionos"
|
||||
"github.com/prometheus/prometheus/discovery/kubernetes"
|
||||
"github.com/prometheus/prometheus/discovery/linode"
|
||||
"github.com/prometheus/prometheus/discovery/marathon"
|
||||
|
@ -50,6 +51,7 @@ import (
|
|||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
"github.com/prometheus/prometheus/discovery/triton"
|
||||
"github.com/prometheus/prometheus/discovery/uyuni"
|
||||
"github.com/prometheus/prometheus/discovery/vultr"
|
||||
"github.com/prometheus/prometheus/discovery/xds"
|
||||
"github.com/prometheus/prometheus/discovery/zookeeper"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
|
@ -987,11 +989,61 @@ var expectedConf = &Config{
|
|||
Scheme: DefaultScrapeConfig.Scheme,
|
||||
ServiceDiscoveryConfigs: discovery.Configs{
|
||||
&uyuni.SDConfig{
|
||||
Server: "https://localhost:1234",
|
||||
Username: "gopher",
|
||||
Password: "hole",
|
||||
Entitlement: "monitoring_entitled",
|
||||
Separator: ",",
|
||||
Server: "https://localhost:1234",
|
||||
Username: "gopher",
|
||||
Password: "hole",
|
||||
Entitlement: "monitoring_entitled",
|
||||
Separator: ",",
|
||||
RefreshInterval: model.Duration(60 * time.Second),
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
JobName: "ionos",
|
||||
HonorTimestamps: true,
|
||||
ScrapeInterval: model.Duration(15 * time.Second),
|
||||
ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
|
||||
|
||||
MetricsPath: DefaultScrapeConfig.MetricsPath,
|
||||
Scheme: DefaultScrapeConfig.Scheme,
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
|
||||
ServiceDiscoveryConfigs: discovery.Configs{
|
||||
&ionos.SDConfig{
|
||||
DatacenterID: "8feda53f-15f0-447f-badf-ebe32dad2fc0",
|
||||
HTTPClientConfig: config.HTTPClientConfig{
|
||||
Authorization: &config.Authorization{Type: "Bearer", Credentials: "abcdef"},
|
||||
FollowRedirects: true,
|
||||
EnableHTTP2: true,
|
||||
},
|
||||
Port: 80,
|
||||
RefreshInterval: model.Duration(60 * time.Second),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
JobName: "vultr",
|
||||
|
||||
HonorTimestamps: true,
|
||||
ScrapeInterval: model.Duration(15 * time.Second),
|
||||
ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
|
||||
|
||||
MetricsPath: DefaultScrapeConfig.MetricsPath,
|
||||
Scheme: DefaultScrapeConfig.Scheme,
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
|
||||
ServiceDiscoveryConfigs: discovery.Configs{
|
||||
&vultr.SDConfig{
|
||||
HTTPClientConfig: config.HTTPClientConfig{
|
||||
Authorization: &config.Authorization{
|
||||
Type: "Bearer",
|
||||
Credentials: "abcdef",
|
||||
},
|
||||
FollowRedirects: true,
|
||||
EnableHTTP2: true,
|
||||
},
|
||||
Port: 80,
|
||||
RefreshInterval: model.Duration(60 * time.Second),
|
||||
},
|
||||
},
|
||||
|
@ -1093,7 +1145,7 @@ func TestElideSecrets(t *testing.T) {
|
|||
yamlConfig := string(config)
|
||||
|
||||
matches := secretRe.FindAllStringIndex(yamlConfig, -1)
|
||||
require.Equal(t, 16, len(matches), "wrong number of secret matches found")
|
||||
require.Equal(t, 18, len(matches), "wrong number of secret matches found")
|
||||
require.NotContains(t, yamlConfig, "mysecret",
|
||||
"yaml marshal reveals authentication credentials.")
|
||||
}
|
||||
|
@ -1532,6 +1584,10 @@ var expectedErrors = []struct {
|
|||
filename: "uyuni_no_server.bad.yml",
|
||||
errMsg: "Uyuni SD configuration requires server host",
|
||||
},
|
||||
{
|
||||
filename: "ionos_datacenter.bad.yml",
|
||||
errMsg: "datacenter id can't be empty",
|
||||
},
|
||||
}
|
||||
|
||||
func TestBadConfigs(t *testing.T) {
|
||||
|
|
11
config/testdata/conf.good.yml
vendored
11
config/testdata/conf.good.yml
vendored
|
@ -367,6 +367,17 @@ scrape_configs:
|
|||
username: gopher
|
||||
password: hole
|
||||
|
||||
- job_name: ionos
|
||||
ionos_sd_configs:
|
||||
- datacenter_id: 8feda53f-15f0-447f-badf-ebe32dad2fc0
|
||||
authorization:
|
||||
credentials: abcdef
|
||||
|
||||
- job_name: vultr
|
||||
vultr_sd_configs:
|
||||
- authorization:
|
||||
credentials: abcdef
|
||||
|
||||
alerting:
|
||||
alertmanagers:
|
||||
- scheme: https
|
||||
|
|
3
config/testdata/ionos_datacenter.bad.yml
vendored
Normal file
3
config/testdata/ionos_datacenter.bad.yml
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
scrape_configs:
|
||||
- ionos_sd_configs:
|
||||
- datacenter_id: ""
|
|
@ -131,7 +131,7 @@ the Prometheus server will be able to see them.
|
|||
|
||||
### The SD interface
|
||||
|
||||
A Service Discovery (SD) mechanism has to discover targets and provide them to Prometheus. We expect similar targets to be grouped together, in the form of a [target group](https://pkg.go.dev/github.com/prometheus/prometheus@v1.8.2-0.20211105201321-411021ada9ab/discovery/targetgroup#Group). The SD mechanism sends the targets down to prometheus as list of target groups.
|
||||
A Service Discovery (SD) mechanism has to discover targets and provide them to Prometheus. We expect similar targets to be grouped together, in the form of a [target group](https://pkg.go.dev/github.com/prometheus/prometheus/discovery/targetgroup#Group). The SD mechanism sends the targets down to prometheus as list of target groups.
|
||||
|
||||
An SD mechanism has to implement the `Discoverer` Interface:
|
||||
```go
|
||||
|
|
|
@ -15,6 +15,7 @@ package aws
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
@ -29,7 +30,6 @@ import (
|
|||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
|
@ -179,7 +179,7 @@ func (d *EC2Discovery) ec2Client(ctx context.Context) (*ec2.EC2, error) {
|
|||
Profile: d.cfg.Profile,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create aws session")
|
||||
return nil, fmt.Errorf("could not create aws session: %w", err)
|
||||
}
|
||||
|
||||
if d.cfg.RoleARN != "" {
|
||||
|
@ -328,10 +328,11 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
|
|||
}
|
||||
return true
|
||||
}); err != nil {
|
||||
if awsErr, ok := err.(awserr.Error); ok && (awsErr.Code() == "AuthFailure" || awsErr.Code() == "UnauthorizedOperation") {
|
||||
var awsErr awserr.Error
|
||||
if errors.As(err, &awsErr) && (awsErr.Code() == "AuthFailure" || awsErr.Code() == "UnauthorizedOperation") {
|
||||
d.ec2 = nil
|
||||
}
|
||||
return nil, errors.Wrap(err, "could not describe instances")
|
||||
return nil, fmt.Errorf("could not describe instances: %w", err)
|
||||
}
|
||||
return []*targetgroup.Group{tg}, nil
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ package aws
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
@ -28,7 +29,6 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/lightsail"
|
||||
"github.com/go-kit/log"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
|
@ -152,7 +152,7 @@ func (d *LightsailDiscovery) lightsailClient() (*lightsail.Lightsail, error) {
|
|||
Profile: d.cfg.Profile,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create aws session")
|
||||
return nil, fmt.Errorf("could not create aws session: %w", err)
|
||||
}
|
||||
|
||||
if d.cfg.RoleARN != "" {
|
||||
|
@ -179,10 +179,11 @@ func (d *LightsailDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
|
|||
|
||||
output, err := lightsailClient.GetInstancesWithContext(ctx, input)
|
||||
if err != nil {
|
||||
if awsErr, ok := err.(awserr.Error); ok && (awsErr.Code() == "AuthFailure" || awsErr.Code() == "UnauthorizedOperation") {
|
||||
var awsErr awserr.Error
|
||||
if errors.As(err, &awsErr) && (awsErr.Code() == "AuthFailure" || awsErr.Code() == "UnauthorizedOperation") {
|
||||
d.lightsail = nil
|
||||
}
|
||||
return nil, errors.Wrap(err, "could not get instances")
|
||||
return nil, fmt.Errorf("could not get instances: %w", err)
|
||||
}
|
||||
|
||||
for _, inst := range output.Instances {
|
||||
|
|
|
@ -15,6 +15,7 @@ package azure
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -29,7 +30,6 @@ import (
|
|||
"github.com/Azure/go-autorest/autorest/azure"
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
config_util "github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
@ -109,7 +109,7 @@ func (c *SDConfig) NewDiscoverer(opts discovery.DiscovererOptions) (discovery.Di
|
|||
|
||||
func validateAuthParam(param, name string) error {
|
||||
if len(param) == 0 {
|
||||
return errors.Errorf("azure SD configuration requires a %s", name)
|
||||
return fmt.Errorf("azure SD configuration requires a %s", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
}
|
||||
|
||||
if c.AuthenticationMethod != authMethodOAuth && c.AuthenticationMethod != authMethodManagedIdentity {
|
||||
return errors.Errorf("unknown authentication_type %q. Supported types are %q or %q", c.AuthenticationMethod, authMethodOAuth, authMethodManagedIdentity)
|
||||
return fmt.Errorf("unknown authentication_type %q. Supported types are %q or %q", c.AuthenticationMethod, authMethodOAuth, authMethodManagedIdentity)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -271,7 +271,7 @@ func newAzureResourceFromID(id string, logger log.Logger) (azureResource, error)
|
|||
// /subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/PROVIDER/TYPE/NAME/TYPE/NAME
|
||||
s := strings.Split(id, "/")
|
||||
if len(s) != 9 && len(s) != 11 {
|
||||
err := errors.Errorf("invalid ID '%s'. Refusing to create azureResource", id)
|
||||
err := fmt.Errorf("invalid ID '%s'. Refusing to create azureResource", id)
|
||||
level.Error(logger).Log("err", err)
|
||||
return azureResource{}, err
|
||||
}
|
||||
|
@ -288,13 +288,13 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|||
client, err := createAzureClient(*d.cfg)
|
||||
if err != nil {
|
||||
failuresCount.Inc()
|
||||
return nil, errors.Wrap(err, "could not create Azure client")
|
||||
return nil, fmt.Errorf("could not create Azure client: %w", err)
|
||||
}
|
||||
|
||||
machines, err := client.getVMs(ctx, d.cfg.ResourceGroup)
|
||||
if err != nil {
|
||||
failuresCount.Inc()
|
||||
return nil, errors.Wrap(err, "could not get virtual machines")
|
||||
return nil, fmt.Errorf("could not get virtual machines: %w", err)
|
||||
}
|
||||
|
||||
level.Debug(d.logger).Log("msg", "Found virtual machines during Azure discovery.", "count", len(machines))
|
||||
|
@ -303,14 +303,14 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|||
scaleSets, err := client.getScaleSets(ctx, d.cfg.ResourceGroup)
|
||||
if err != nil {
|
||||
failuresCount.Inc()
|
||||
return nil, errors.Wrap(err, "could not get virtual machine scale sets")
|
||||
return nil, fmt.Errorf("could not get virtual machine scale sets: %w", err)
|
||||
}
|
||||
|
||||
for _, scaleSet := range scaleSets {
|
||||
scaleSetVms, err := client.getScaleSetVMs(ctx, scaleSet)
|
||||
if err != nil {
|
||||
failuresCount.Inc()
|
||||
return nil, errors.Wrap(err, "could not get virtual machine scale set vms")
|
||||
return nil, fmt.Errorf("could not get virtual machine scale set vms: %w", err)
|
||||
}
|
||||
machines = append(machines, scaleSetVms...)
|
||||
}
|
||||
|
@ -396,7 +396,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|||
}
|
||||
// If we made it here, we don't have a private IP which should be impossible.
|
||||
// Return an empty target and error to ensure an all or nothing situation.
|
||||
err = errors.Errorf("unable to find a private IP for VM %s", vm.Name)
|
||||
err = fmt.Errorf("unable to find a private IP for VM %s", vm.Name)
|
||||
ch <- target{labelSet: nil, err: err}
|
||||
return
|
||||
}
|
||||
|
@ -412,7 +412,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|||
for tgt := range ch {
|
||||
if tgt.err != nil {
|
||||
failuresCount.Inc()
|
||||
return nil, errors.Wrap(tgt.err, "unable to complete Azure service discovery")
|
||||
return nil, fmt.Errorf("unable to complete Azure service discovery: %w", tgt.err)
|
||||
}
|
||||
if tgt.labelSet != nil {
|
||||
tg.Targets = append(tg.Targets, tgt.labelSet)
|
||||
|
@ -432,7 +432,7 @@ func (client *azureClient) getVMs(ctx context.Context, resourceGroup string) ([]
|
|||
result, err = client.vm.List(ctx, resourceGroup)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not list virtual machines")
|
||||
return nil, fmt.Errorf("could not list virtual machines: %w", err)
|
||||
}
|
||||
for result.NotDone() {
|
||||
for _, vm := range result.Values() {
|
||||
|
@ -440,7 +440,7 @@ func (client *azureClient) getVMs(ctx context.Context, resourceGroup string) ([]
|
|||
}
|
||||
err = result.NextWithContext(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not list virtual machines")
|
||||
return nil, fmt.Errorf("could not list virtual machines: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -461,14 +461,14 @@ func (client *azureClient) getScaleSets(ctx context.Context, resourceGroup strin
|
|||
var rtn compute.VirtualMachineScaleSetListWithLinkResultPage
|
||||
rtn, err = client.vmss.ListAll(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not list virtual machine scale sets")
|
||||
return nil, fmt.Errorf("could not list virtual machine scale sets: %w", err)
|
||||
}
|
||||
result = &rtn
|
||||
} else {
|
||||
var rtn compute.VirtualMachineScaleSetListResultPage
|
||||
rtn, err = client.vmss.List(ctx, resourceGroup)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not list virtual machine scale sets")
|
||||
return nil, fmt.Errorf("could not list virtual machine scale sets: %w", err)
|
||||
}
|
||||
result = &rtn
|
||||
}
|
||||
|
@ -477,7 +477,7 @@ func (client *azureClient) getScaleSets(ctx context.Context, resourceGroup strin
|
|||
scaleSets = append(scaleSets, result.Values()...)
|
||||
err = result.NextWithContext(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not list virtual machine scale sets")
|
||||
return nil, fmt.Errorf("could not list virtual machine scale sets: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,12 +489,12 @@ func (client *azureClient) getScaleSetVMs(ctx context.Context, scaleSet compute.
|
|||
// TODO do we really need to fetch the resourcegroup this way?
|
||||
r, err := newAzureResourceFromID(*scaleSet.ID, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse scale set ID")
|
||||
return nil, fmt.Errorf("could not parse scale set ID: %w", err)
|
||||
}
|
||||
|
||||
result, err := client.vmssvm.List(ctx, r.ResourceGroup, *(scaleSet.Name), "", "", "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not list virtual machine scale set vms")
|
||||
return nil, fmt.Errorf("could not list virtual machine scale set vms: %w", err)
|
||||
}
|
||||
for result.NotDone() {
|
||||
for _, vm := range result.Values() {
|
||||
|
@ -502,7 +502,7 @@ func (client *azureClient) getScaleSetVMs(ctx context.Context, scaleSet compute.
|
|||
}
|
||||
err = result.NextWithContext(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not list virtual machine scale set vms")
|
||||
return nil, fmt.Errorf("could not list virtual machine scale set vms: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ package consul
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
@ -24,7 +25,6 @@ import (
|
|||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
consul "github.com/hashicorp/consul/api"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
@ -291,7 +291,7 @@ func (d *Discovery) getDatacenter() error {
|
|||
|
||||
dc, ok := info["Config"]["Datacenter"].(string)
|
||||
if !ok {
|
||||
err := errors.Errorf("invalid value '%v' for Config.Datacenter", info["Config"]["Datacenter"])
|
||||
err := fmt.Errorf("invalid value '%v' for Config.Datacenter", info["Config"]["Datacenter"])
|
||||
level.Error(d.logger).Log("msg", "Error retrieving datacenter name", "err", err)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ package dns
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
@ -24,7 +25,6 @@ import (
|
|||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
|
@ -105,7 +105,7 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
return errors.New("a port is required in DNS-SD configs for all record types except SRV")
|
||||
}
|
||||
default:
|
||||
return errors.Errorf("invalid DNS-SD records type %s", c.Type)
|
||||
return fmt.Errorf("invalid DNS-SD records type %s", c.Type)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|||
wg.Add(len(d.names))
|
||||
for _, name := range d.names {
|
||||
go func(n string) {
|
||||
if err := d.refreshOne(ctx, n, ch); err != nil && err != context.Canceled {
|
||||
if err := d.refreshOne(ctx, n, ch); err != nil && !errors.Is(err, context.Canceled) {
|
||||
level.Error(d.logger).Log("msg", "Error refreshing DNS targets", "err", err)
|
||||
}
|
||||
wg.Done()
|
||||
|
@ -265,7 +265,7 @@ func (d *Discovery) refreshOne(ctx context.Context, name string, ch chan<- *targ
|
|||
func lookupWithSearchPath(name string, qtype uint16, logger log.Logger) (*dns.Msg, error) {
|
||||
conf, err := dns.ClientConfigFromFile(resolvConf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not load resolv.conf")
|
||||
return nil, fmt.Errorf("could not load resolv.conf: %w", err)
|
||||
}
|
||||
|
||||
allResponsesValid := true
|
||||
|
@ -291,7 +291,7 @@ func lookupWithSearchPath(name string, qtype uint16, logger log.Logger) (*dns.Ms
|
|||
return &dns.Msg{}, nil
|
||||
}
|
||||
// Outcome 3: boned.
|
||||
return nil, errors.Errorf("could not resolve %q: all servers responded with errors to at least one search domain", name)
|
||||
return nil, fmt.Errorf("could not resolve %q: all servers responded with errors to at least one search domain", name)
|
||||
}
|
||||
|
||||
// lookupFromAnyServer uses all configured servers to try and resolve a specific
|
||||
|
@ -327,7 +327,7 @@ func lookupFromAnyServer(name string, qtype uint16, conf *dns.ClientConfig, logg
|
|||
}
|
||||
}
|
||||
|
||||
return nil, errors.Errorf("could not resolve %s: no servers returned a viable answer", name)
|
||||
return nil, fmt.Errorf("could not resolve %s: no servers returned a viable answer", name)
|
||||
}
|
||||
|
||||
// askServerForName makes a request to a specific DNS server for a specific
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/version"
|
||||
)
|
||||
|
||||
|
@ -99,13 +98,13 @@ func fetchApps(ctx context.Context, server string, client *http.Client) (*Applic
|
|||
}()
|
||||
|
||||
if resp.StatusCode/100 != 2 {
|
||||
return nil, errors.Errorf("non 2xx status '%d' response during eureka service discovery", resp.StatusCode)
|
||||
return nil, fmt.Errorf("non 2xx status '%d' response during eureka service discovery", resp.StatusCode)
|
||||
}
|
||||
|
||||
var apps Applications
|
||||
err = xml.NewDecoder(resp.Body).Decode(&apps)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "%q", url)
|
||||
return nil, fmt.Errorf("%q: %w", url, err)
|
||||
}
|
||||
return &apps, nil
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ package eureka
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -22,7 +23,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ package file
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
@ -28,7 +29,6 @@ import (
|
|||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/grafana/regexp"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
@ -99,7 +99,7 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
}
|
||||
for _, name := range c.Files {
|
||||
if !patFileSDName.MatchString(name) {
|
||||
return errors.Errorf("path name %q is not valid for file discovery", name)
|
||||
return fmt.Errorf("path name %q is not valid for file discovery", name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -398,7 +398,7 @@ func (d *Discovery) readFile(filename string) ([]*targetgroup.Group, error) {
|
|||
return nil, err
|
||||
}
|
||||
default:
|
||||
panic(errors.Errorf("discovery.File.readFile: unhandled file extension %q", ext))
|
||||
panic(fmt.Errorf("discovery.File.readFile: unhandled file extension %q", ext))
|
||||
}
|
||||
|
||||
for i, tg := range targetGroups {
|
||||
|
|
|
@ -15,6 +15,7 @@ package gce
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
@ -22,7 +23,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
"golang.org/x/oauth2/google"
|
||||
compute "google.golang.org/api/compute/v1"
|
||||
|
@ -132,11 +132,11 @@ func NewDiscovery(conf SDConfig, logger log.Logger) (*Discovery, error) {
|
|||
var err error
|
||||
d.client, err = google.DefaultClient(context.Background(), compute.ComputeReadonlyScope)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error setting up communication with GCE service")
|
||||
return nil, fmt.Errorf("error setting up communication with GCE service: %w", err)
|
||||
}
|
||||
d.svc, err = compute.NewService(context.Background(), option.WithHTTPClient(d.client))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error setting up communication with GCE service")
|
||||
return nil, fmt.Errorf("error setting up communication with GCE service: %w", err)
|
||||
}
|
||||
d.isvc = compute.NewInstancesService(d.svc)
|
||||
|
||||
|
@ -221,7 +221,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error retrieving refresh targets from gce")
|
||||
return nil, fmt.Errorf("error retrieving refresh targets from gce: %w", err)
|
||||
}
|
||||
return []*targetgroup.Group{tg}, nil
|
||||
}
|
||||
|
|
|
@ -15,11 +15,12 @@ package hetzner
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/hetznercloud/hcloud-go/hcloud"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
|
@ -95,7 +96,7 @@ func (c *role) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
case hetznerRoleRobot, hetznerRoleHcloud:
|
||||
return nil
|
||||
default:
|
||||
return errors.Errorf("unknown role %q", *c)
|
||||
return fmt.Errorf("unknown role %q", *c)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,6 +115,11 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
return c.HTTPClientConfig.Validate()
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *SDConfig) SetDirectory(dir string) {
|
||||
c.HTTPClientConfig.SetDirectory(dir)
|
||||
}
|
||||
|
||||
// Discovery periodically performs Hetzner requests. It implements
|
||||
// the Discoverer interface.
|
||||
type Discovery struct {
|
||||
|
|
|
@ -25,7 +25,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/version"
|
||||
|
@ -89,7 +88,7 @@ func (d *robotDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, err
|
|||
}()
|
||||
|
||||
if resp.StatusCode/100 != 2 {
|
||||
return nil, errors.Errorf("non 2xx status '%d' response during hetzner service discovery with role robot", resp.StatusCode)
|
||||
return nil, fmt.Errorf("non 2xx status '%d' response during hetzner service discovery with role robot", resp.StatusCode)
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
|
|
|
@ -16,6 +16,7 @@ package http
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
@ -26,7 +27,6 @@ import (
|
|||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/grafana/regexp"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
@ -162,12 +162,12 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
failuresCount.Inc()
|
||||
return nil, errors.Errorf("server returned HTTP status %s", resp.Status)
|
||||
return nil, fmt.Errorf("server returned HTTP status %s", resp.Status)
|
||||
}
|
||||
|
||||
if !matchContentType.MatchString(strings.TrimSpace(resp.Header.Get("Content-Type"))) {
|
||||
failuresCount.Inc()
|
||||
return nil, errors.Errorf("unsupported content type %q", resp.Header.Get("Content-Type"))
|
||||
return nil, fmt.Errorf("unsupported content type %q", resp.Header.Get("Content-Type"))
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
_ "github.com/prometheus/prometheus/discovery/gce" // register gce
|
||||
_ "github.com/prometheus/prometheus/discovery/hetzner" // register hetzner
|
||||
_ "github.com/prometheus/prometheus/discovery/http" // register http
|
||||
_ "github.com/prometheus/prometheus/discovery/ionos" // register ionos
|
||||
_ "github.com/prometheus/prometheus/discovery/kubernetes" // register kubernetes
|
||||
_ "github.com/prometheus/prometheus/discovery/linode" // register linode
|
||||
_ "github.com/prometheus/prometheus/discovery/marathon" // register marathon
|
||||
|
@ -35,6 +36,7 @@ import (
|
|||
_ "github.com/prometheus/prometheus/discovery/scaleway" // register scaleway
|
||||
_ "github.com/prometheus/prometheus/discovery/triton" // register triton
|
||||
_ "github.com/prometheus/prometheus/discovery/uyuni" // register uyuni
|
||||
_ "github.com/prometheus/prometheus/discovery/vultr" // register vultr
|
||||
_ "github.com/prometheus/prometheus/discovery/xds" // register xds
|
||||
_ "github.com/prometheus/prometheus/discovery/zookeeper" // register zookeeper
|
||||
)
|
||||
|
|
111
discovery/ionos/ionos.go
Normal file
111
discovery/ionos/ionos.go
Normal file
|
@ -0,0 +1,111 @@
|
|||
// Copyright 2022 The Prometheus 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.
|
||||
|
||||
package ionos
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery"
|
||||
"github.com/prometheus/prometheus/discovery/refresh"
|
||||
)
|
||||
|
||||
const (
|
||||
// metaLabelPrefix is the meta prefix used for all meta labels in this
|
||||
// discovery.
|
||||
metaLabelPrefix = model.MetaLabelPrefix + "ionos_"
|
||||
metaLabelSeparator = ","
|
||||
)
|
||||
|
||||
func init() {
|
||||
discovery.RegisterConfig(&SDConfig{})
|
||||
}
|
||||
|
||||
// Discovery periodically performs IONOS Cloud target discovery. It implements
|
||||
// the Discoverer interface.
|
||||
type Discovery struct{}
|
||||
|
||||
// NewDiscovery returns a new refresh.Discovery for IONOS Cloud.
|
||||
func NewDiscovery(conf *SDConfig, logger log.Logger) (*refresh.Discovery, error) {
|
||||
if conf.ionosEndpoint == "" {
|
||||
conf.ionosEndpoint = "https://api.ionos.com"
|
||||
}
|
||||
|
||||
d, err := newServerDiscovery(conf, logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return refresh.NewDiscovery(
|
||||
logger,
|
||||
"ionos",
|
||||
time.Duration(conf.RefreshInterval),
|
||||
d.refresh,
|
||||
), nil
|
||||
}
|
||||
|
||||
// DefaultSDConfig is the default IONOS Cloud service discovery configuration.
|
||||
var DefaultSDConfig = SDConfig{
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
RefreshInterval: model.Duration(60 * time.Second),
|
||||
Port: 80,
|
||||
}
|
||||
|
||||
// SDConfig configuration to use for IONOS Cloud Discovery.
|
||||
type SDConfig struct {
|
||||
// DatacenterID: IONOS Cloud data center ID used to discover targets.
|
||||
DatacenterID string `yaml:"datacenter_id"`
|
||||
|
||||
HTTPClientConfig config.HTTPClientConfig `yaml:",inline"`
|
||||
|
||||
RefreshInterval model.Duration `yaml:"refresh_interval"`
|
||||
Port int `yaml:"port"`
|
||||
|
||||
ionosEndpoint string // For tests only.
|
||||
}
|
||||
|
||||
// Name returns the name of the IONOS Cloud service discovery.
|
||||
func (c SDConfig) Name() string {
|
||||
return "ionos"
|
||||
}
|
||||
|
||||
// NewDiscoverer returns a new discovery.Discoverer for IONOS Cloud.
|
||||
func (c SDConfig) NewDiscoverer(options discovery.DiscovererOptions) (discovery.Discoverer, error) {
|
||||
return NewDiscovery(&c, options.Logger)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*c = DefaultSDConfig
|
||||
type plain SDConfig
|
||||
err := unmarshal((*plain)(c))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.DatacenterID == "" {
|
||||
return errors.New("datacenter id can't be empty")
|
||||
}
|
||||
|
||||
return c.HTTPClientConfig.Validate()
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *SDConfig) SetDirectory(dir string) {
|
||||
c.HTTPClientConfig.SetDirectory(dir)
|
||||
}
|
166
discovery/ionos/server.go
Normal file
166
discovery/ionos/server.go
Normal file
|
@ -0,0 +1,166 @@
|
|||
// Copyright 2022 The Prometheus 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.
|
||||
|
||||
package ionos
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
ionoscloud "github.com/ionos-cloud/sdk-go/v6"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/version"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery/refresh"
|
||||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
"github.com/prometheus/prometheus/util/strutil"
|
||||
)
|
||||
|
||||
const (
|
||||
serverLabelPrefix = metaLabelPrefix + "server_"
|
||||
|
||||
serverAvailabilityZoneLabel = serverLabelPrefix + "availability_zone"
|
||||
serverBootCDROMIDLabel = serverLabelPrefix + "boot_cdrom_id"
|
||||
serverBootImageIDLabel = serverLabelPrefix + "boot_image_id"
|
||||
serverBootVolumeIDLabel = serverLabelPrefix + "boot_volume_id"
|
||||
serverCPUFamilyLabel = serverLabelPrefix + "cpu_family"
|
||||
serverIDLabel = serverLabelPrefix + "id"
|
||||
serverIPLabel = serverLabelPrefix + "ip"
|
||||
serverLifecycleLabel = serverLabelPrefix + "lifecycle"
|
||||
serverNameLabel = serverLabelPrefix + "name"
|
||||
serverNICIPLabelPrefix = serverLabelPrefix + "nic_ip_"
|
||||
serverServersIDLabel = serverLabelPrefix + "servers_id"
|
||||
serverStateLabel = serverLabelPrefix + "state"
|
||||
serverTypeLabel = serverLabelPrefix + "type"
|
||||
|
||||
nicDefaultName = "unnamed"
|
||||
)
|
||||
|
||||
type serverDiscovery struct {
|
||||
*refresh.Discovery
|
||||
client *ionoscloud.APIClient
|
||||
port int
|
||||
datacenterID string
|
||||
}
|
||||
|
||||
func newServerDiscovery(conf *SDConfig, logger log.Logger) (*serverDiscovery, error) {
|
||||
d := &serverDiscovery{
|
||||
port: conf.Port,
|
||||
datacenterID: conf.DatacenterID,
|
||||
}
|
||||
|
||||
rt, err := config.NewRoundTripperFromConfig(conf.HTTPClientConfig, "ionos_sd")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Username, password and token are set via http client config.
|
||||
cfg := ionoscloud.NewConfiguration("", "", "", conf.ionosEndpoint)
|
||||
cfg.HTTPClient = &http.Client{
|
||||
Transport: rt,
|
||||
Timeout: time.Duration(conf.RefreshInterval),
|
||||
}
|
||||
cfg.UserAgent = fmt.Sprintf("Prometheus/%s", version.Version)
|
||||
|
||||
d.client = ionoscloud.NewAPIClient(cfg)
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (d *serverDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
||||
api := d.client.ServersApi
|
||||
|
||||
servers, _, err := api.DatacentersServersGet(ctx, d.datacenterID).
|
||||
Depth(3).
|
||||
Execute()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var targets []model.LabelSet
|
||||
for _, server := range *servers.Items {
|
||||
var ips []string
|
||||
ipsByNICName := make(map[string][]string)
|
||||
|
||||
if server.Entities != nil && server.Entities.Nics != nil {
|
||||
for _, nic := range *server.Entities.Nics.Items {
|
||||
nicName := nicDefaultName
|
||||
if name := nic.Properties.Name; name != nil {
|
||||
nicName = *name
|
||||
}
|
||||
|
||||
nicIPs := *nic.Properties.Ips
|
||||
ips = append(nicIPs, ips...)
|
||||
ipsByNICName[nicName] = append(nicIPs, ipsByNICName[nicName]...)
|
||||
}
|
||||
}
|
||||
|
||||
// If a server has no IP addresses, it's being dropped from the targets.
|
||||
if len(ips) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
addr := net.JoinHostPort(ips[0], strconv.FormatUint(uint64(d.port), 10))
|
||||
labels := model.LabelSet{
|
||||
model.AddressLabel: model.LabelValue(addr),
|
||||
serverAvailabilityZoneLabel: model.LabelValue(*server.Properties.AvailabilityZone),
|
||||
serverCPUFamilyLabel: model.LabelValue(*server.Properties.CpuFamily),
|
||||
serverServersIDLabel: model.LabelValue(*servers.Id),
|
||||
serverIDLabel: model.LabelValue(*server.Id),
|
||||
serverIPLabel: model.LabelValue(join(ips, metaLabelSeparator)),
|
||||
serverLifecycleLabel: model.LabelValue(*server.Metadata.State),
|
||||
serverNameLabel: model.LabelValue(*server.Properties.Name),
|
||||
serverStateLabel: model.LabelValue(*server.Properties.VmState),
|
||||
serverTypeLabel: model.LabelValue(*server.Properties.Type),
|
||||
}
|
||||
|
||||
for nicName, nicIPs := range ipsByNICName {
|
||||
name := serverNICIPLabelPrefix + strutil.SanitizeLabelName(nicName)
|
||||
labels[model.LabelName(name)] = model.LabelValue(join(nicIPs, metaLabelSeparator))
|
||||
}
|
||||
|
||||
if server.Properties.BootCdrom != nil {
|
||||
labels[serverBootCDROMIDLabel] = model.LabelValue(*server.Properties.BootCdrom.Id)
|
||||
}
|
||||
|
||||
if server.Properties.BootVolume != nil {
|
||||
labels[serverBootVolumeIDLabel] = model.LabelValue(*server.Properties.BootVolume.Id)
|
||||
}
|
||||
|
||||
if server.Entities != nil && server.Entities.Volumes != nil {
|
||||
volumes := *server.Entities.Volumes.Items
|
||||
if len(volumes) > 0 {
|
||||
image := volumes[0].Properties.Image
|
||||
if image != nil {
|
||||
labels[serverBootImageIDLabel] = model.LabelValue(*image)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
targets = append(targets, labels)
|
||||
}
|
||||
|
||||
return []*targetgroup.Group{{Source: "ionos", Targets: targets}}, nil
|
||||
}
|
||||
|
||||
// join returns strings.Join with additional separators at beginning and end.
|
||||
func join(elems []string, sep string) string {
|
||||
return sep + strings.Join(elems, sep) + sep
|
||||
}
|
115
discovery/ionos/server_test.go
Normal file
115
discovery/ionos/server_test.go
Normal file
|
@ -0,0 +1,115 @@
|
|||
// Copyright 2022 The Prometheus 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.
|
||||
|
||||
package ionos
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
ionoscloud "github.com/ionos-cloud/sdk-go/v6"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
ionosTestBearerToken = config.Secret("jwt")
|
||||
ionosTestDatacenterID = "8feda53f-15f0-447f-badf-ebe32dad2fc0"
|
||||
)
|
||||
|
||||
func TestIONOSServerRefresh(t *testing.T) {
|
||||
mock := httptest.NewServer(http.HandlerFunc(mockIONOSServers))
|
||||
defer mock.Close()
|
||||
|
||||
cfg := DefaultSDConfig
|
||||
cfg.DatacenterID = ionosTestDatacenterID
|
||||
cfg.HTTPClientConfig.BearerToken = ionosTestBearerToken
|
||||
cfg.ionosEndpoint = mock.URL
|
||||
|
||||
d, err := newServerDiscovery(&cfg, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
tgs, err := d.refresh(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(tgs))
|
||||
|
||||
tg := tgs[0]
|
||||
require.NotNil(t, tg)
|
||||
require.NotNil(t, tg.Targets)
|
||||
require.Equal(t, 2, len(tg.Targets))
|
||||
|
||||
for i, lbls := range []model.LabelSet{
|
||||
{
|
||||
"__address__": "85.215.243.177:80",
|
||||
"__meta_ionos_server_availability_zone": "ZONE_2",
|
||||
"__meta_ionos_server_boot_cdrom_id": "0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"__meta_ionos_server_cpu_family": "INTEL_SKYLAKE",
|
||||
"__meta_ionos_server_id": "b501942c-4e08-43e6-8ec1-00e59c64e0e4",
|
||||
"__meta_ionos_server_ip": ",85.215.243.177,185.56.150.9,85.215.238.118,",
|
||||
"__meta_ionos_server_nic_ip_metrics": ",85.215.243.177,",
|
||||
"__meta_ionos_server_nic_ip_unnamed": ",185.56.150.9,85.215.238.118,",
|
||||
"__meta_ionos_server_lifecycle": "AVAILABLE",
|
||||
"__meta_ionos_server_name": "prometheus-2",
|
||||
"__meta_ionos_server_servers_id": "8feda53f-15f0-447f-badf-ebe32dad2fc0/servers",
|
||||
"__meta_ionos_server_state": "RUNNING",
|
||||
"__meta_ionos_server_type": "ENTERPRISE",
|
||||
},
|
||||
{
|
||||
"__address__": "85.215.248.84:80",
|
||||
"__meta_ionos_server_availability_zone": "ZONE_1",
|
||||
"__meta_ionos_server_boot_cdrom_id": "0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"__meta_ionos_server_cpu_family": "INTEL_SKYLAKE",
|
||||
"__meta_ionos_server_id": "523415e6-ff8c-4dc0-86d3-09c256039b30",
|
||||
"__meta_ionos_server_ip": ",85.215.248.84,",
|
||||
"__meta_ionos_server_nic_ip_unnamed": ",85.215.248.84,",
|
||||
"__meta_ionos_server_lifecycle": "AVAILABLE",
|
||||
"__meta_ionos_server_name": "prometheus-1",
|
||||
"__meta_ionos_server_servers_id": "8feda53f-15f0-447f-badf-ebe32dad2fc0/servers",
|
||||
"__meta_ionos_server_state": "RUNNING",
|
||||
"__meta_ionos_server_type": "ENTERPRISE",
|
||||
},
|
||||
} {
|
||||
t.Run(fmt.Sprintf("item %d", i), func(t *testing.T) {
|
||||
require.Equal(t, lbls, tg.Targets[i])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func mockIONOSServers(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get("Authorization") != fmt.Sprintf("Bearer %s", ionosTestBearerToken) {
|
||||
http.Error(w, "bad token", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
if r.URL.Path != fmt.Sprintf("%s/datacenters/%s/servers", ionoscloud.DefaultIonosBasePath, ionosTestDatacenterID) {
|
||||
http.Error(w, fmt.Sprintf("bad url: %s", r.URL.Path), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
server, err := os.ReadFile("testdata/servers.json")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_, err = w.Write(server)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
615
discovery/ionos/testdata/servers.json
vendored
Normal file
615
discovery/ionos/testdata/servers.json
vendored
Normal file
|
@ -0,0 +1,615 @@
|
|||
{
|
||||
"id": "8feda53f-15f0-447f-badf-ebe32dad2fc0/servers",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers",
|
||||
"items": [
|
||||
{
|
||||
"id": "d6bf44ee-f7e8-4e19-8716-96fdd18cc697",
|
||||
"type": "server",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/d6bf44ee-f7e8-4e19-8716-96fdd18cc697",
|
||||
"metadata": {
|
||||
"etag": "3bd2cf1f190fdba8502ba8c0cc79433e",
|
||||
"createdDate": "2019-09-02T11:51:53Z",
|
||||
"createdBy": "System",
|
||||
"createdByUserId": "[UNKNOWN]",
|
||||
"lastModifiedDate": "2019-09-02T11:51:53Z",
|
||||
"lastModifiedBy": "System",
|
||||
"lastModifiedByUserId": "[UNKNOWN]",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": "prometheus-3",
|
||||
"cores": 2,
|
||||
"ram": 4096,
|
||||
"availabilityZone": "AUTO",
|
||||
"vmState": "RUNNING",
|
||||
"bootCdrom": {
|
||||
"id": "0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"type": "image",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/images/0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"metadata": {
|
||||
"etag": "ca643281fd2a5b68002bc00ac0ecd920",
|
||||
"createdDate": "2019-09-02T11:51:53Z",
|
||||
"createdBy": "System",
|
||||
"createdByUserId": "[UNKNOWN]",
|
||||
"lastModifiedDate": "2019-09-02T11:51:53Z",
|
||||
"lastModifiedBy": "System",
|
||||
"lastModifiedByUserId": "[UNKNOWN]",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": "debian-10.0.0-amd64-netinst.iso",
|
||||
"description": null,
|
||||
"location": "de/txl",
|
||||
"size": 0.33,
|
||||
"cpuHotPlug": true,
|
||||
"cpuHotUnplug": false,
|
||||
"ramHotPlug": true,
|
||||
"ramHotUnplug": false,
|
||||
"nicHotPlug": true,
|
||||
"nicHotUnplug": true,
|
||||
"discVirtioHotPlug": true,
|
||||
"discVirtioHotUnplug": true,
|
||||
"discScsiHotPlug": false,
|
||||
"discScsiHotUnplug": false,
|
||||
"licenceType": "LINUX",
|
||||
"imageType": "CDROM",
|
||||
"imageAliases": [
|
||||
"debian:latest_iso",
|
||||
"debian:10_iso"
|
||||
],
|
||||
"cloudInit": "NONE",
|
||||
"public": true
|
||||
}
|
||||
},
|
||||
"bootVolume": null,
|
||||
"cpuFamily": "INTEL_SKYLAKE",
|
||||
"type": "ENTERPRISE"
|
||||
},
|
||||
"entities": {
|
||||
"cdroms": {
|
||||
"id": "d6bf44ee-f7e8-4e19-8716-96fdd18cc697/cdroms",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/d6bf44ee-f7e8-4e19-8716-96fdd18cc697/cdroms",
|
||||
"items": [
|
||||
{
|
||||
"id": "0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"type": "image",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/images/0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"metadata": {
|
||||
"etag": "ca643281fd2a5b68002bc00ac0ecd920",
|
||||
"createdDate": "2019-09-02T11:51:53Z",
|
||||
"createdBy": "System",
|
||||
"createdByUserId": "[UNKNOWN]",
|
||||
"lastModifiedDate": "2019-09-02T11:51:53Z",
|
||||
"lastModifiedBy": "System",
|
||||
"lastModifiedByUserId": "[UNKNOWN]",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": "debian-10.0.0-amd64-netinst.iso",
|
||||
"description": null,
|
||||
"location": "de/txl",
|
||||
"size": 0.33,
|
||||
"cpuHotPlug": true,
|
||||
"cpuHotUnplug": false,
|
||||
"ramHotPlug": true,
|
||||
"ramHotUnplug": false,
|
||||
"nicHotPlug": true,
|
||||
"nicHotUnplug": true,
|
||||
"discVirtioHotPlug": true,
|
||||
"discVirtioHotUnplug": true,
|
||||
"discScsiHotPlug": false,
|
||||
"discScsiHotUnplug": false,
|
||||
"licenceType": "LINUX",
|
||||
"imageType": "CDROM",
|
||||
"imageAliases": [
|
||||
"debian:10_iso",
|
||||
"debian:latest_iso"
|
||||
],
|
||||
"cloudInit": "NONE",
|
||||
"public": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"volumes": {
|
||||
"id": "d6bf44ee-f7e8-4e19-8716-96fdd18cc697/volumes",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/d6bf44ee-f7e8-4e19-8716-96fdd18cc697/volumes",
|
||||
"items": []
|
||||
},
|
||||
"nics": {
|
||||
"id": "d6bf44ee-f7e8-4e19-8716-96fdd18cc697/nics",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/d6bf44ee-f7e8-4e19-8716-96fdd18cc697/nics",
|
||||
"items": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "b501942c-4e08-43e6-8ec1-00e59c64e0e4",
|
||||
"type": "server",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/b501942c-4e08-43e6-8ec1-00e59c64e0e4",
|
||||
"metadata": {
|
||||
"etag": "fe405a5f2e041d506086ee0c2159b678",
|
||||
"createdDate": "2019-09-02T11:51:53Z",
|
||||
"createdBy": "System",
|
||||
"createdByUserId": "[UNKNOWN]",
|
||||
"lastModifiedDate": "2019-09-02T11:51:53Z",
|
||||
"lastModifiedBy": "System",
|
||||
"lastModifiedByUserId": "[UNKNOWN]",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": "prometheus-2",
|
||||
"cores": 1,
|
||||
"ram": 1024,
|
||||
"availabilityZone": "ZONE_2",
|
||||
"vmState": "RUNNING",
|
||||
"bootCdrom": {
|
||||
"id": "0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"type": "image",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/images/0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"metadata": {
|
||||
"etag": "ca643281fd2a5b68002bc00ac0ecd920",
|
||||
"createdDate": "2019-09-02T11:51:53Z",
|
||||
"createdBy": "System",
|
||||
"createdByUserId": "[UNKNOWN]",
|
||||
"lastModifiedDate": "2019-09-02T11:51:53Z",
|
||||
"lastModifiedBy": "System",
|
||||
"lastModifiedByUserId": "[UNKNOWN]",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": "debian-10.0.0-amd64-netinst.iso",
|
||||
"description": null,
|
||||
"location": "de/txl",
|
||||
"size": 0.33,
|
||||
"cpuHotPlug": true,
|
||||
"cpuHotUnplug": false,
|
||||
"ramHotPlug": true,
|
||||
"ramHotUnplug": false,
|
||||
"nicHotPlug": true,
|
||||
"nicHotUnplug": true,
|
||||
"discVirtioHotPlug": true,
|
||||
"discVirtioHotUnplug": true,
|
||||
"discScsiHotPlug": false,
|
||||
"discScsiHotUnplug": false,
|
||||
"licenceType": "LINUX",
|
||||
"imageType": "CDROM",
|
||||
"imageAliases": [
|
||||
"debian:latest_iso",
|
||||
"debian:10_iso"
|
||||
],
|
||||
"cloudInit": "NONE",
|
||||
"public": true
|
||||
}
|
||||
},
|
||||
"bootVolume": null,
|
||||
"cpuFamily": "INTEL_SKYLAKE",
|
||||
"type": "ENTERPRISE"
|
||||
},
|
||||
"entities": {
|
||||
"cdroms": {
|
||||
"id": "b501942c-4e08-43e6-8ec1-00e59c64e0e4/cdroms",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/b501942c-4e08-43e6-8ec1-00e59c64e0e4/cdroms",
|
||||
"items": [
|
||||
{
|
||||
"id": "0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"type": "image",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/images/0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"metadata": {
|
||||
"etag": "ca643281fd2a5b68002bc00ac0ecd920",
|
||||
"createdDate": "2019-09-02T11:51:53Z",
|
||||
"createdBy": "System",
|
||||
"createdByUserId": "[UNKNOWN]",
|
||||
"lastModifiedDate": "2019-09-02T11:51:53Z",
|
||||
"lastModifiedBy": "System",
|
||||
"lastModifiedByUserId": "[UNKNOWN]",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": "debian-10.0.0-amd64-netinst.iso",
|
||||
"description": null,
|
||||
"location": "de/txl",
|
||||
"size": 0.33,
|
||||
"cpuHotPlug": true,
|
||||
"cpuHotUnplug": false,
|
||||
"ramHotPlug": true,
|
||||
"ramHotUnplug": false,
|
||||
"nicHotPlug": true,
|
||||
"nicHotUnplug": true,
|
||||
"discVirtioHotPlug": true,
|
||||
"discVirtioHotUnplug": true,
|
||||
"discScsiHotPlug": false,
|
||||
"discScsiHotUnplug": false,
|
||||
"licenceType": "LINUX",
|
||||
"imageType": "CDROM",
|
||||
"imageAliases": [
|
||||
"debian:10_iso",
|
||||
"debian:latest_iso"
|
||||
],
|
||||
"cloudInit": "NONE",
|
||||
"public": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"volumes": {
|
||||
"id": "b501942c-4e08-43e6-8ec1-00e59c64e0e4/volumes",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/b501942c-4e08-43e6-8ec1-00e59c64e0e4/volumes",
|
||||
"items": [
|
||||
{
|
||||
"id": "97a58f00-e2a5-4ebb-8b9a-f694837b0548",
|
||||
"type": "volume",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/volumes/97a58f00-e2a5-4ebb-8b9a-f694837b0548",
|
||||
"metadata": {
|
||||
"etag": "27491713a77c5453c6ae7d0f98a1beec",
|
||||
"createdDate": "2019-09-02T11:51:53Z",
|
||||
"createdBy": "System",
|
||||
"createdByUserId": "[UNKNOWN]",
|
||||
"lastModifiedDate": "2019-09-02T11:51:53Z",
|
||||
"lastModifiedBy": "System",
|
||||
"lastModifiedByUserId": "[UNKNOWN]",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": "prometheus-data-1",
|
||||
"type": "HDD",
|
||||
"size": 10,
|
||||
"availabilityZone": "AUTO",
|
||||
"image": null,
|
||||
"imagePassword": null,
|
||||
"sshKeys": null,
|
||||
"bus": "VIRTIO",
|
||||
"licenceType": "UNKNOWN",
|
||||
"cpuHotPlug": false,
|
||||
"ramHotPlug": false,
|
||||
"nicHotPlug": false,
|
||||
"nicHotUnplug": false,
|
||||
"discVirtioHotPlug": false,
|
||||
"discVirtioHotUnplug": false,
|
||||
"deviceNumber": 1,
|
||||
"userData": null,
|
||||
"pciSlot": 6,
|
||||
"bootServer": "b501942c-4e08-43e6-8ec1-00e59c64e0e4"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"nics": {
|
||||
"id": "b501942c-4e08-43e6-8ec1-00e59c64e0e4/nics",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/b501942c-4e08-43e6-8ec1-00e59c64e0e4/nics",
|
||||
"items": [
|
||||
{
|
||||
"id": "206e9a88-097c-4c87-8544-1f5fe0b6b0f1",
|
||||
"type": "nic",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/b501942c-4e08-43e6-8ec1-00e59c64e0e4/nics/206e9a88-097c-4c87-8544-1f5fe0b6b0f1",
|
||||
"metadata": {
|
||||
"etag": "be2b6fff29e7e09c1a4a5ca150876eaa",
|
||||
"createdDate": "2019-09-02T11:51:53Z",
|
||||
"createdBy": "System",
|
||||
"createdByUserId": "[UNKNOWN]",
|
||||
"lastModifiedDate": "2019-09-02T11:51:53Z",
|
||||
"lastModifiedBy": "System",
|
||||
"lastModifiedByUserId": "[UNKNOWN]",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": null,
|
||||
"mac": "02:01:4b:1c:cf:57",
|
||||
"ips": [
|
||||
"85.215.238.118"
|
||||
],
|
||||
"dhcp": true,
|
||||
"lan": 1,
|
||||
"firewallActive": false,
|
||||
"firewallType": "INGRESS",
|
||||
"deviceNumber": 1,
|
||||
"pciSlot": 5
|
||||
},
|
||||
"entities": {
|
||||
"firewallrules": {
|
||||
"id": "206e9a88-097c-4c87-8544-1f5fe0b6b0f1/firewallrules",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/b501942c-4e08-43e6-8ec1-00e59c64e0e4/nics/206e9a88-097c-4c87-8544-1f5fe0b6b0f1/firewallrules"
|
||||
},
|
||||
"flowlogs": {
|
||||
"id": "206e9a88-097c-4c87-8544-1f5fe0b6b0f1/flowlogs",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/b501942c-4e08-43e6-8ec1-00e59c64e0e4/nics/206e9a88-097c-4c87-8544-1f5fe0b6b0f1/flowlogs"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "8a568a32-da62-437d-8b73-f580d1a1588f",
|
||||
"type": "nic",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/b501942c-4e08-43e6-8ec1-00e59c64e0e4/nics/8a568a32-da62-437d-8b73-f580d1a1588f",
|
||||
"metadata": {
|
||||
"etag": "2dca0340a0610b1dfdb2e66f6aae3ed3",
|
||||
"createdDate": "2022-05-05T13:12:31Z",
|
||||
"createdBy": "felix.ehrenpfort@codecentric.cloud",
|
||||
"createdByUserId": "cfcb4526-fbe0-461e-9149-ffb00a83fbec",
|
||||
"lastModifiedDate": "2022-05-05T13:12:31Z",
|
||||
"lastModifiedBy": "felix.ehrenpfort@codecentric.cloud",
|
||||
"lastModifiedByUserId": "cfcb4526-fbe0-461e-9149-ffb00a83fbec",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": null,
|
||||
"mac": "02:01:56:f6:47:a8",
|
||||
"ips": [
|
||||
"185.56.150.9"
|
||||
],
|
||||
"dhcp": true,
|
||||
"lan": 1,
|
||||
"firewallActive": false,
|
||||
"firewallType": "INGRESS",
|
||||
"deviceNumber": 3,
|
||||
"pciSlot": 8
|
||||
},
|
||||
"entities": {
|
||||
"firewallrules": {
|
||||
"id": "8a568a32-da62-437d-8b73-f580d1a1588f/firewallrules",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/b501942c-4e08-43e6-8ec1-00e59c64e0e4/nics/8a568a32-da62-437d-8b73-f580d1a1588f/firewallrules"
|
||||
},
|
||||
"flowlogs": {
|
||||
"id": "8a568a32-da62-437d-8b73-f580d1a1588f/flowlogs",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/b501942c-4e08-43e6-8ec1-00e59c64e0e4/nics/8a568a32-da62-437d-8b73-f580d1a1588f/flowlogs"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "17ecc866-4a08-4ada-858f-7b726a5f5070",
|
||||
"type": "nic",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/b501942c-4e08-43e6-8ec1-00e59c64e0e4/nics/17ecc866-4a08-4ada-858f-7b726a5f5070",
|
||||
"metadata": {
|
||||
"etag": "f6a82276c6fdb460811d3789e54e0054",
|
||||
"createdDate": "2022-05-05T11:45:36Z",
|
||||
"createdBy": "felix.ehrenpfort@codecentric.cloud",
|
||||
"createdByUserId": "cfcb4526-fbe0-461e-9149-ffb00a83fbec",
|
||||
"lastModifiedDate": "2022-05-05T11:45:36Z",
|
||||
"lastModifiedBy": "felix.ehrenpfort@codecentric.cloud",
|
||||
"lastModifiedByUserId": "cfcb4526-fbe0-461e-9149-ffb00a83fbec",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": "metrics",
|
||||
"mac": "02:01:93:80:fa:a4",
|
||||
"ips": [
|
||||
"85.215.243.177"
|
||||
],
|
||||
"dhcp": true,
|
||||
"lan": 1,
|
||||
"firewallActive": false,
|
||||
"firewallType": "INGRESS",
|
||||
"deviceNumber": 2,
|
||||
"pciSlot": 7
|
||||
},
|
||||
"entities": {
|
||||
"firewallrules": {
|
||||
"id": "17ecc866-4a08-4ada-858f-7b726a5f5070/firewallrules",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/b501942c-4e08-43e6-8ec1-00e59c64e0e4/nics/17ecc866-4a08-4ada-858f-7b726a5f5070/firewallrules"
|
||||
},
|
||||
"flowlogs": {
|
||||
"id": "17ecc866-4a08-4ada-858f-7b726a5f5070/flowlogs",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/b501942c-4e08-43e6-8ec1-00e59c64e0e4/nics/17ecc866-4a08-4ada-858f-7b726a5f5070/flowlogs"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "523415e6-ff8c-4dc0-86d3-09c256039b30",
|
||||
"type": "server",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/523415e6-ff8c-4dc0-86d3-09c256039b30",
|
||||
"metadata": {
|
||||
"etag": "fe405a5f2e041d506086ee0c2159b678",
|
||||
"createdDate": "2019-09-02T11:51:53Z",
|
||||
"createdBy": "System",
|
||||
"createdByUserId": "[UNKNOWN]",
|
||||
"lastModifiedDate": "2019-09-02T11:51:53Z",
|
||||
"lastModifiedBy": "System",
|
||||
"lastModifiedByUserId": "[UNKNOWN]",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": "prometheus-1",
|
||||
"cores": 1,
|
||||
"ram": 1024,
|
||||
"availabilityZone": "ZONE_1",
|
||||
"vmState": "RUNNING",
|
||||
"bootCdrom": {
|
||||
"id": "0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"type": "image",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/images/0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"metadata": {
|
||||
"etag": "ca643281fd2a5b68002bc00ac0ecd920",
|
||||
"createdDate": "2019-09-02T11:51:53Z",
|
||||
"createdBy": "System",
|
||||
"createdByUserId": "[UNKNOWN]",
|
||||
"lastModifiedDate": "2019-09-02T11:51:53Z",
|
||||
"lastModifiedBy": "System",
|
||||
"lastModifiedByUserId": "[UNKNOWN]",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": "debian-10.0.0-amd64-netinst.iso",
|
||||
"description": null,
|
||||
"location": "de/txl",
|
||||
"size": 0.33,
|
||||
"cpuHotPlug": true,
|
||||
"cpuHotUnplug": false,
|
||||
"ramHotPlug": true,
|
||||
"ramHotUnplug": false,
|
||||
"nicHotPlug": true,
|
||||
"nicHotUnplug": true,
|
||||
"discVirtioHotPlug": true,
|
||||
"discVirtioHotUnplug": true,
|
||||
"discScsiHotPlug": false,
|
||||
"discScsiHotUnplug": false,
|
||||
"licenceType": "LINUX",
|
||||
"imageType": "CDROM",
|
||||
"imageAliases": [
|
||||
"debian:latest_iso",
|
||||
"debian:10_iso"
|
||||
],
|
||||
"cloudInit": "NONE",
|
||||
"public": true
|
||||
}
|
||||
},
|
||||
"bootVolume": null,
|
||||
"cpuFamily": "INTEL_SKYLAKE",
|
||||
"type": "ENTERPRISE"
|
||||
},
|
||||
"entities": {
|
||||
"cdroms": {
|
||||
"id": "523415e6-ff8c-4dc0-86d3-09c256039b30/cdroms",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/523415e6-ff8c-4dc0-86d3-09c256039b30/cdroms",
|
||||
"items": [
|
||||
{
|
||||
"id": "0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"type": "image",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/images/0e4d57f9-cd78-11e9-b88c-525400f64d8d",
|
||||
"metadata": {
|
||||
"etag": "ca643281fd2a5b68002bc00ac0ecd920",
|
||||
"createdDate": "2019-09-02T11:51:53Z",
|
||||
"createdBy": "System",
|
||||
"createdByUserId": "[UNKNOWN]",
|
||||
"lastModifiedDate": "2019-09-02T11:51:53Z",
|
||||
"lastModifiedBy": "System",
|
||||
"lastModifiedByUserId": "[UNKNOWN]",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": "debian-10.0.0-amd64-netinst.iso",
|
||||
"description": null,
|
||||
"location": "de/txl",
|
||||
"size": 0.33,
|
||||
"cpuHotPlug": true,
|
||||
"cpuHotUnplug": false,
|
||||
"ramHotPlug": true,
|
||||
"ramHotUnplug": false,
|
||||
"nicHotPlug": true,
|
||||
"nicHotUnplug": true,
|
||||
"discVirtioHotPlug": true,
|
||||
"discVirtioHotUnplug": true,
|
||||
"discScsiHotPlug": false,
|
||||
"discScsiHotUnplug": false,
|
||||
"licenceType": "LINUX",
|
||||
"imageType": "CDROM",
|
||||
"imageAliases": [
|
||||
"debian:10_iso",
|
||||
"debian:latest_iso"
|
||||
],
|
||||
"cloudInit": "NONE",
|
||||
"public": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"volumes": {
|
||||
"id": "523415e6-ff8c-4dc0-86d3-09c256039b30/volumes",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/523415e6-ff8c-4dc0-86d3-09c256039b30/volumes",
|
||||
"items": [
|
||||
{
|
||||
"id": "5dc21326-7e33-4dc7-84ac-63b02aad4624",
|
||||
"type": "volume",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/volumes/5dc21326-7e33-4dc7-84ac-63b02aad4624",
|
||||
"metadata": {
|
||||
"etag": "27491713a77c5453c6ae7d0f98a1beec",
|
||||
"createdDate": "2019-09-02T11:51:53Z",
|
||||
"createdBy": "System",
|
||||
"createdByUserId": "[UNKNOWN]",
|
||||
"lastModifiedDate": "2019-09-02T11:51:53Z",
|
||||
"lastModifiedBy": "System",
|
||||
"lastModifiedByUserId": "[UNKNOWN]",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": "prometheus-data-2",
|
||||
"type": "HDD",
|
||||
"size": 10,
|
||||
"availabilityZone": "AUTO",
|
||||
"image": null,
|
||||
"imagePassword": null,
|
||||
"sshKeys": null,
|
||||
"bus": "VIRTIO",
|
||||
"licenceType": "UNKNOWN",
|
||||
"cpuHotPlug": false,
|
||||
"ramHotPlug": false,
|
||||
"nicHotPlug": false,
|
||||
"nicHotUnplug": false,
|
||||
"discVirtioHotPlug": false,
|
||||
"discVirtioHotUnplug": false,
|
||||
"deviceNumber": 1,
|
||||
"userData": null,
|
||||
"pciSlot": 6,
|
||||
"bootServer": "523415e6-ff8c-4dc0-86d3-09c256039b30"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"nics": {
|
||||
"id": "523415e6-ff8c-4dc0-86d3-09c256039b30/nics",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/523415e6-ff8c-4dc0-86d3-09c256039b30/nics",
|
||||
"items": [
|
||||
{
|
||||
"id": "684033a2-317f-4977-8a01-68263d59336c",
|
||||
"type": "nic",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/523415e6-ff8c-4dc0-86d3-09c256039b30/nics/684033a2-317f-4977-8a01-68263d59336c",
|
||||
"metadata": {
|
||||
"etag": "fe405a5f2e041d506086ee0c2159b678",
|
||||
"createdDate": "2019-09-02T11:51:53Z",
|
||||
"createdBy": "System",
|
||||
"createdByUserId": "[UNKNOWN]",
|
||||
"lastModifiedDate": "2019-09-02T11:51:53Z",
|
||||
"lastModifiedBy": "System",
|
||||
"lastModifiedByUserId": "[UNKNOWN]",
|
||||
"state": "AVAILABLE"
|
||||
},
|
||||
"properties": {
|
||||
"name": null,
|
||||
"mac": "02:01:17:12:27:1b",
|
||||
"ips": [
|
||||
"85.215.248.84"
|
||||
],
|
||||
"dhcp": true,
|
||||
"lan": 1,
|
||||
"firewallActive": false,
|
||||
"firewallType": "INGRESS",
|
||||
"deviceNumber": 1,
|
||||
"pciSlot": 5
|
||||
},
|
||||
"entities": {
|
||||
"firewallrules": {
|
||||
"id": "684033a2-317f-4977-8a01-68263d59336c/firewallrules",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/523415e6-ff8c-4dc0-86d3-09c256039b30/nics/684033a2-317f-4977-8a01-68263d59336c/firewallrules"
|
||||
},
|
||||
"flowlogs": {
|
||||
"id": "684033a2-317f-4977-8a01-68263d59336c/flowlogs",
|
||||
"type": "collection",
|
||||
"href": "https://api.ionos.com/cloudapi/v6/datacenters/8feda53f-15f0-447f-badf-ebe32dad2fc0/servers/523415e6-ff8c-4dc0-86d3-09c256039b30/nics/684033a2-317f-4977-8a01-68263d59336c/flowlogs"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -15,12 +15,13 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
@ -135,7 +136,7 @@ func (e *Endpoints) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
|
|||
defer e.queue.ShutDown()
|
||||
|
||||
if !cache.WaitForCacheSync(ctx.Done(), e.endpointsInf.HasSynced, e.serviceInf.HasSynced, e.podInf.HasSynced) {
|
||||
if ctx.Err() != context.Canceled {
|
||||
if !errors.Is(ctx.Err(), context.Canceled) {
|
||||
level.Error(e.logger).Log("msg", "endpoints informer unable to sync cache")
|
||||
}
|
||||
return
|
||||
|
@ -188,7 +189,7 @@ func convertToEndpoints(o interface{}) (*apiv1.Endpoints, error) {
|
|||
return endpoints, nil
|
||||
}
|
||||
|
||||
return nil, errors.Errorf("received unexpected object: %v", o)
|
||||
return nil, fmt.Errorf("received unexpected object: %v", o)
|
||||
}
|
||||
|
||||
func endpointsSource(ep *apiv1.Endpoints) string {
|
||||
|
|
|
@ -15,12 +15,12 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/discovery/v1"
|
||||
|
@ -193,7 +193,7 @@ func (e *EndpointSlice) getEndpointSliceAdaptor(o interface{}) (endpointSliceAda
|
|||
case *v1beta1.EndpointSlice:
|
||||
return newEndpointSliceAdaptorFromV1beta1(endpointSlice), nil
|
||||
default:
|
||||
return nil, errors.Errorf("received unexpected object: %v", o)
|
||||
return nil, fmt.Errorf("received unexpected object: %v", o)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -644,10 +644,16 @@ func TestEndpointSliceDiscoveryWithServiceUpdate(t *testing.T) {
|
|||
Targets: []model.LabelSet{
|
||||
{
|
||||
"__address__": "1.2.3.4:9000",
|
||||
"__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1",
|
||||
"__meta_kubernetes_endpointslice_port": "9000",
|
||||
"__meta_kubernetes_endpointslice_port_name": "testport",
|
||||
"__meta_kubernetes_endpointslice_port_protocol": "TCP",
|
||||
"__meta_kubernetes_endpointslice_address_target_kind": "",
|
||||
"__meta_kubernetes_endpointslice_address_target_name": "",
|
||||
"__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true",
|
||||
"__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1",
|
||||
"__meta_kubernetes_endpointslice_endpoint_topology_present_topology": "true",
|
||||
"__meta_kubernetes_endpointslice_endpoint_topology_topology": "value",
|
||||
"__meta_kubernetes_endpointslice_port": "9000",
|
||||
"__meta_kubernetes_endpointslice_port_app_protocol": "http",
|
||||
"__meta_kubernetes_endpointslice_port_name": "testport",
|
||||
"__meta_kubernetes_endpointslice_port_protocol": "TCP",
|
||||
},
|
||||
{
|
||||
"__address__": "2.3.4.5:9000",
|
||||
|
@ -655,6 +661,7 @@ func TestEndpointSliceDiscoveryWithServiceUpdate(t *testing.T) {
|
|||
"__meta_kubernetes_endpointslice_port": "9000",
|
||||
"__meta_kubernetes_endpointslice_port_name": "testport",
|
||||
"__meta_kubernetes_endpointslice_port_protocol": "TCP",
|
||||
"__meta_kubernetes_endpointslice_port_app_protocol": "http",
|
||||
},
|
||||
{
|
||||
"__address__": "3.4.5.6:9000",
|
||||
|
@ -662,6 +669,7 @@ func TestEndpointSliceDiscoveryWithServiceUpdate(t *testing.T) {
|
|||
"__meta_kubernetes_endpointslice_port": "9000",
|
||||
"__meta_kubernetes_endpointslice_port_name": "testport",
|
||||
"__meta_kubernetes_endpointslice_port_protocol": "TCP",
|
||||
"__meta_kubernetes_endpointslice_port_app_protocol": "http",
|
||||
},
|
||||
},
|
||||
Labels: model.LabelSet{
|
||||
|
@ -755,10 +763,16 @@ func TestEndpointSliceDiscoveryNamespaces(t *testing.T) {
|
|||
Targets: []model.LabelSet{
|
||||
{
|
||||
"__address__": "1.2.3.4:9000",
|
||||
"__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1",
|
||||
"__meta_kubernetes_endpointslice_port": "9000",
|
||||
"__meta_kubernetes_endpointslice_port_name": "testport",
|
||||
"__meta_kubernetes_endpointslice_port_protocol": "TCP",
|
||||
"__meta_kubernetes_endpointslice_address_target_kind": "",
|
||||
"__meta_kubernetes_endpointslice_address_target_name": "",
|
||||
"__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true",
|
||||
"__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1",
|
||||
"__meta_kubernetes_endpointslice_endpoint_topology_present_topology": "true",
|
||||
"__meta_kubernetes_endpointslice_endpoint_topology_topology": "value",
|
||||
"__meta_kubernetes_endpointslice_port": "9000",
|
||||
"__meta_kubernetes_endpointslice_port_app_protocol": "http",
|
||||
"__meta_kubernetes_endpointslice_port_name": "testport",
|
||||
"__meta_kubernetes_endpointslice_port_protocol": "TCP",
|
||||
},
|
||||
{
|
||||
"__address__": "2.3.4.5:9000",
|
||||
|
@ -766,6 +780,7 @@ func TestEndpointSliceDiscoveryNamespaces(t *testing.T) {
|
|||
"__meta_kubernetes_endpointslice_port": "9000",
|
||||
"__meta_kubernetes_endpointslice_port_name": "testport",
|
||||
"__meta_kubernetes_endpointslice_port_protocol": "TCP",
|
||||
"__meta_kubernetes_endpointslice_port_app_protocol": "http",
|
||||
},
|
||||
{
|
||||
"__address__": "3.4.5.6:9000",
|
||||
|
@ -773,6 +788,7 @@ func TestEndpointSliceDiscoveryNamespaces(t *testing.T) {
|
|||
"__meta_kubernetes_endpointslice_port": "9000",
|
||||
"__meta_kubernetes_endpointslice_port_name": "testport",
|
||||
"__meta_kubernetes_endpointslice_port_protocol": "TCP",
|
||||
"__meta_kubernetes_endpointslice_port_app_protocol": "http",
|
||||
},
|
||||
},
|
||||
Labels: model.LabelSet{
|
||||
|
@ -871,10 +887,16 @@ func TestEndpointSliceDiscoveryOwnNamespace(t *testing.T) {
|
|||
Targets: []model.LabelSet{
|
||||
{
|
||||
"__address__": "1.2.3.4:9000",
|
||||
"__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1",
|
||||
"__meta_kubernetes_endpointslice_port": "9000",
|
||||
"__meta_kubernetes_endpointslice_port_name": "testport",
|
||||
"__meta_kubernetes_endpointslice_port_protocol": "TCP",
|
||||
"__meta_kubernetes_endpointslice_address_target_kind": "",
|
||||
"__meta_kubernetes_endpointslice_address_target_name": "",
|
||||
"__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true",
|
||||
"__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1",
|
||||
"__meta_kubernetes_endpointslice_endpoint_topology_present_topology": "true",
|
||||
"__meta_kubernetes_endpointslice_endpoint_topology_topology": "value",
|
||||
"__meta_kubernetes_endpointslice_port": "9000",
|
||||
"__meta_kubernetes_endpointslice_port_app_protocol": "http",
|
||||
"__meta_kubernetes_endpointslice_port_name": "testport",
|
||||
"__meta_kubernetes_endpointslice_port_protocol": "TCP",
|
||||
},
|
||||
{
|
||||
"__address__": "2.3.4.5:9000",
|
||||
|
@ -882,6 +904,7 @@ func TestEndpointSliceDiscoveryOwnNamespace(t *testing.T) {
|
|||
"__meta_kubernetes_endpointslice_port": "9000",
|
||||
"__meta_kubernetes_endpointslice_port_name": "testport",
|
||||
"__meta_kubernetes_endpointslice_port_protocol": "TCP",
|
||||
"__meta_kubernetes_endpointslice_port_app_protocol": "http",
|
||||
},
|
||||
{
|
||||
"__address__": "3.4.5.6:9000",
|
||||
|
@ -889,6 +912,7 @@ func TestEndpointSliceDiscoveryOwnNamespace(t *testing.T) {
|
|||
"__meta_kubernetes_endpointslice_port": "9000",
|
||||
"__meta_kubernetes_endpointslice_port_name": "testport",
|
||||
"__meta_kubernetes_endpointslice_port_protocol": "TCP",
|
||||
"__meta_kubernetes_endpointslice_port_app_protocol": "http",
|
||||
},
|
||||
},
|
||||
Labels: model.LabelSet{
|
||||
|
|
|
@ -15,11 +15,12 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
v1 "k8s.io/api/networking/v1"
|
||||
"k8s.io/api/networking/v1beta1"
|
||||
|
@ -78,7 +79,7 @@ func (i *Ingress) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
|
|||
defer i.queue.ShutDown()
|
||||
|
||||
if !cache.WaitForCacheSync(ctx.Done(), i.informer.HasSynced) {
|
||||
if ctx.Err() != context.Canceled {
|
||||
if !errors.Is(ctx.Err(), context.Canceled) {
|
||||
level.Error(i.logger).Log("msg", "ingress informer unable to sync cache")
|
||||
}
|
||||
return
|
||||
|
@ -123,7 +124,7 @@ func (i *Ingress) process(ctx context.Context, ch chan<- []*targetgroup.Group) b
|
|||
ia = newIngressAdaptorFromV1beta1(ingress)
|
||||
default:
|
||||
level.Error(i.logger).Log("msg", "converting to Ingress object failed", "err",
|
||||
errors.Errorf("received unexpected object: %v", o))
|
||||
fmt.Errorf("received unexpected object: %v", o))
|
||||
return true
|
||||
}
|
||||
send(ctx, ch, i.buildIngress(ia))
|
||||
|
|
|
@ -15,6 +15,7 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
|
@ -24,7 +25,6 @@ import (
|
|||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
@ -114,7 +114,7 @@ func (c *Role) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
case RoleNode, RolePod, RoleService, RoleEndpoint, RoleEndpointSlice, RoleIngress:
|
||||
return nil
|
||||
default:
|
||||
return errors.Errorf("unknown Kubernetes SD role %q", *c)
|
||||
return fmt.Errorf("unknown Kubernetes SD role %q", *c)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,7 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
return err
|
||||
}
|
||||
if c.Role == "" {
|
||||
return errors.Errorf("role missing (one of: pod, service, endpoints, endpointslice, node, ingress)")
|
||||
return fmt.Errorf("role missing (one of: pod, service, endpoints, endpointslice, node, ingress)")
|
||||
}
|
||||
err = c.HTTPClientConfig.Validate()
|
||||
if err != nil {
|
||||
|
@ -186,20 +186,20 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
}
|
||||
if c.APIServer.URL != nil && c.KubeConfig != "" {
|
||||
// Api-server and kubeconfig_file are mutually exclusive
|
||||
return errors.Errorf("cannot use 'kubeconfig_file' and 'api_server' simultaneously")
|
||||
return fmt.Errorf("cannot use 'kubeconfig_file' and 'api_server' simultaneously")
|
||||
}
|
||||
if c.KubeConfig != "" && !reflect.DeepEqual(c.HTTPClientConfig, config.DefaultHTTPClientConfig) {
|
||||
// Kubeconfig_file and custom http config are mutually exclusive
|
||||
return errors.Errorf("cannot use a custom HTTP client configuration together with 'kubeconfig_file'")
|
||||
return fmt.Errorf("cannot use a custom HTTP client configuration together with 'kubeconfig_file'")
|
||||
}
|
||||
if c.APIServer.URL == nil && !reflect.DeepEqual(c.HTTPClientConfig, config.DefaultHTTPClientConfig) {
|
||||
return errors.Errorf("to use custom HTTP client configuration please provide the 'api_server' URL explicitly")
|
||||
return fmt.Errorf("to use custom HTTP client configuration please provide the 'api_server' URL explicitly")
|
||||
}
|
||||
if c.APIServer.URL != nil && c.NamespaceDiscovery.IncludeOwnNamespace {
|
||||
return errors.Errorf("cannot use 'api_server' and 'namespaces.own_namespace' simultaneously")
|
||||
return fmt.Errorf("cannot use 'api_server' and 'namespaces.own_namespace' simultaneously")
|
||||
}
|
||||
if c.KubeConfig != "" && c.NamespaceDiscovery.IncludeOwnNamespace {
|
||||
return errors.Errorf("cannot use 'kubeconfig_file' and 'namespaces.own_namespace' simultaneously")
|
||||
return fmt.Errorf("cannot use 'kubeconfig_file' and 'namespaces.own_namespace' simultaneously")
|
||||
}
|
||||
|
||||
foundSelectorRoles := make(map[Role]struct{})
|
||||
|
@ -214,12 +214,12 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
|
||||
for _, selector := range c.Selectors {
|
||||
if _, ok := foundSelectorRoles[selector.Role]; ok {
|
||||
return errors.Errorf("duplicated selector role: %s", selector.Role)
|
||||
return fmt.Errorf("duplicated selector role: %s", selector.Role)
|
||||
}
|
||||
foundSelectorRoles[selector.Role] = struct{}{}
|
||||
|
||||
if _, ok := allowedSelectors[c.Role]; !ok {
|
||||
return errors.Errorf("invalid role: %q, expecting one of: pod, service, endpoints, endpointslice, node or ingress", c.Role)
|
||||
return fmt.Errorf("invalid role: %q, expecting one of: pod, service, endpoints, endpointslice, node or ingress", c.Role)
|
||||
}
|
||||
var allowed bool
|
||||
for _, role := range allowedSelectors[c.Role] {
|
||||
|
@ -230,7 +230,7 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
}
|
||||
|
||||
if !allowed {
|
||||
return errors.Errorf("%s role supports only %s selectors", c.Role, strings.Join(allowedSelectors[c.Role], ", "))
|
||||
return fmt.Errorf("%s role supports only %s selectors", c.Role, strings.Join(allowedSelectors[c.Role], ", "))
|
||||
}
|
||||
|
||||
_, err := fields.ParseSelector(selector.Field)
|
||||
|
|
|
@ -16,11 +16,11 @@ package kubernetes
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
|
@ -163,11 +163,11 @@ Loop:
|
|||
|
||||
func requireTargetGroups(t *testing.T, expected, res map[string]*targetgroup.Group) {
|
||||
t.Helper()
|
||||
b1, err := json.Marshal(expected)
|
||||
b1, err := marshalTargetGroups(expected)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b2, err := json.Marshal(res)
|
||||
b2, err := marshalTargetGroups(res)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -175,6 +175,22 @@ func requireTargetGroups(t *testing.T, expected, res map[string]*targetgroup.Gro
|
|||
require.Equal(t, string(b1), string(b2))
|
||||
}
|
||||
|
||||
// marshalTargetGroups serializes a set of target groups to JSON, ignoring the
|
||||
// custom MarshalJSON function defined on the targetgroup.Group struct.
|
||||
// marshalTargetGroups can be used for making exact comparisons between target groups
|
||||
// as it will serialize all target labels.
|
||||
func marshalTargetGroups(tgs map[string]*targetgroup.Group) ([]byte, error) {
|
||||
type targetGroupAlias targetgroup.Group
|
||||
|
||||
aliases := make(map[string]*targetGroupAlias, len(tgs))
|
||||
for k, v := range tgs {
|
||||
tg := targetGroupAlias(*v)
|
||||
aliases[k] = &tg
|
||||
}
|
||||
|
||||
return json.Marshal(aliases)
|
||||
}
|
||||
|
||||
type hasSynced interface {
|
||||
// hasSynced returns true if all informers synced.
|
||||
// This is only used in testing to determine when discoverer synced to
|
||||
|
|
|
@ -15,12 +15,13 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
@ -85,7 +86,7 @@ func (n *Node) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
|
|||
defer n.queue.ShutDown()
|
||||
|
||||
if !cache.WaitForCacheSync(ctx.Done(), n.informer.HasSynced) {
|
||||
if ctx.Err() != context.Canceled {
|
||||
if !errors.Is(ctx.Err(), context.Canceled) {
|
||||
level.Error(n.logger).Log("msg", "node informer unable to sync cache")
|
||||
}
|
||||
return
|
||||
|
@ -136,7 +137,7 @@ func convertToNode(o interface{}) (*apiv1.Node, error) {
|
|||
return node, nil
|
||||
}
|
||||
|
||||
return nil, errors.Errorf("received unexpected object: %v", o)
|
||||
return nil, fmt.Errorf("received unexpected object: %v", o)
|
||||
}
|
||||
|
||||
func nodeSource(n *apiv1.Node) string {
|
||||
|
|
|
@ -15,13 +15,14 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@ -118,7 +119,7 @@ func (p *Pod) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
|
|||
}
|
||||
|
||||
if !cache.WaitForCacheSync(ctx.Done(), cacheSyncs...) {
|
||||
if ctx.Err() != context.Canceled {
|
||||
if !errors.Is(ctx.Err(), context.Canceled) {
|
||||
level.Error(p.logger).Log("msg", "pod informer unable to sync cache")
|
||||
}
|
||||
return
|
||||
|
@ -169,7 +170,7 @@ func convertToPod(o interface{}) (*apiv1.Pod, error) {
|
|||
return pod, nil
|
||||
}
|
||||
|
||||
return nil, errors.Errorf("received unexpected object: %v", o)
|
||||
return nil, fmt.Errorf("received unexpected object: %v", o)
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
|
@ -15,12 +15,13 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
@ -81,7 +82,7 @@ func (s *Service) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
|
|||
defer s.queue.ShutDown()
|
||||
|
||||
if !cache.WaitForCacheSync(ctx.Done(), s.informer.HasSynced) {
|
||||
if ctx.Err() != context.Canceled {
|
||||
if !errors.Is(ctx.Err(), context.Canceled) {
|
||||
level.Error(s.logger).Log("msg", "service informer unable to sync cache")
|
||||
}
|
||||
return
|
||||
|
@ -131,7 +132,7 @@ func convertToService(o interface{}) (*apiv1.Service, error) {
|
|||
if ok {
|
||||
return service, nil
|
||||
}
|
||||
return nil, errors.Errorf("received unexpected object: %v", o)
|
||||
return nil, fmt.Errorf("received unexpected object: %v", o)
|
||||
}
|
||||
|
||||
func serviceSource(s *apiv1.Service) string {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
package legacymanager
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
@ -248,7 +249,8 @@ func writeConfigs(structVal reflect.Value, configs discovery.Configs) error {
|
|||
}
|
||||
|
||||
func replaceYAMLTypeError(err error, oldTyp, newTyp reflect.Type) error {
|
||||
if e, ok := err.(*yaml.TypeError); ok {
|
||||
var e *yaml.TypeError
|
||||
if errors.As(err, &e) {
|
||||
oldStr := oldTyp.String()
|
||||
newStr := newTyp.String()
|
||||
for i, s := range e.Errors {
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/linode/linodego"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/version"
|
||||
|
@ -65,15 +66,24 @@ const (
|
|||
)
|
||||
|
||||
// DefaultSDConfig is the default Linode SD configuration.
|
||||
var DefaultSDConfig = SDConfig{
|
||||
TagSeparator: ",",
|
||||
Port: 80,
|
||||
RefreshInterval: model.Duration(60 * time.Second),
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
}
|
||||
var (
|
||||
DefaultSDConfig = SDConfig{
|
||||
TagSeparator: ",",
|
||||
Port: 80,
|
||||
RefreshInterval: model.Duration(60 * time.Second),
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
}
|
||||
|
||||
failuresCount = prometheus.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Name: "prometheus_sd_linode_failures_total",
|
||||
Help: "Number of Linode service discovery refresh failures.",
|
||||
})
|
||||
)
|
||||
|
||||
func init() {
|
||||
discovery.RegisterConfig(&SDConfig{})
|
||||
prometheus.MustRegister(failuresCount)
|
||||
}
|
||||
|
||||
// SDConfig is the configuration for Linode based service discovery.
|
||||
|
@ -211,12 +221,14 @@ func (d *Discovery) refreshData(ctx context.Context) ([]*targetgroup.Group, erro
|
|||
// Gather all linode instances.
|
||||
instances, err := d.client.ListInstances(ctx, &linodego.ListOptions{PageSize: 500})
|
||||
if err != nil {
|
||||
failuresCount.Inc()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Gather detailed IP address info for all IPs on all linode instances.
|
||||
detailedIPs, err := d.client.ListIPAddresses(ctx, &linodego.ListOptions{PageSize: 500})
|
||||
if err != nil {
|
||||
failuresCount.Inc()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ package marathon
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
|
@ -27,7 +28,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
|
@ -188,7 +188,7 @@ func newAuthTokenFileRoundTripper(tokenFile string, rt http.RoundTripper) (http.
|
|||
// fail-fast if we can't read the file.
|
||||
_, err := os.ReadFile(tokenFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to read auth token file %s", tokenFile)
|
||||
return nil, fmt.Errorf("unable to read auth token file %s: %w", tokenFile, err)
|
||||
}
|
||||
return &authTokenFileRoundTripper{tokenFile, rt}, nil
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ func newAuthTokenFileRoundTripper(tokenFile string, rt http.RoundTripper) (http.
|
|||
func (rt *authTokenFileRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||
b, err := os.ReadFile(rt.authTokenFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to read auth token file %s", rt.authTokenFile)
|
||||
return nil, fmt.Errorf("unable to read auth token file %s: %w", rt.authTokenFile, err)
|
||||
}
|
||||
authToken := strings.TrimSpace(string(b))
|
||||
|
||||
|
@ -336,7 +336,7 @@ func fetchApps(ctx context.Context, client *http.Client, url string) (*appList,
|
|||
}()
|
||||
|
||||
if (resp.StatusCode < 200) || (resp.StatusCode >= 300) {
|
||||
return nil, errors.Errorf("non 2xx status '%v' response during marathon service discovery", resp.StatusCode)
|
||||
return nil, fmt.Errorf("non 2xx status '%v' response during marathon service discovery", resp.StatusCode)
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
|
@ -347,7 +347,7 @@ func fetchApps(ctx context.Context, client *http.Client, url string) (*appList,
|
|||
var apps appList
|
||||
err = json.Unmarshal(b, &apps)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "%q", url)
|
||||
return nil, fmt.Errorf("%q: %w", url, err)
|
||||
}
|
||||
return &apps, nil
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ func TestMarathonSDHandleError(t *testing.T) {
|
|||
}
|
||||
)
|
||||
tgs, err := testUpdateServices(client)
|
||||
if err != errTesting {
|
||||
if !errors.Is(err, errTesting) {
|
||||
t.Fatalf("Expected error: %s", err)
|
||||
}
|
||||
if len(tgs) != 0 {
|
||||
|
|
|
@ -23,7 +23,6 @@ import (
|
|||
"github.com/gophercloud/gophercloud/openstack"
|
||||
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/hypervisors"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
|
@ -62,14 +61,14 @@ func (h *HypervisorDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group
|
|||
h.provider.Context = ctx
|
||||
err := openstack.Authenticate(h.provider, *h.authOpts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not authenticate to OpenStack")
|
||||
return nil, fmt.Errorf("could not authenticate to OpenStack: %w", err)
|
||||
}
|
||||
|
||||
client, err := openstack.NewComputeV2(h.provider, gophercloud.EndpointOpts{
|
||||
Region: h.region, Availability: h.availability,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create OpenStack compute session")
|
||||
return nil, fmt.Errorf("could not create OpenStack compute session: %w", err)
|
||||
}
|
||||
|
||||
tg := &targetgroup.Group{
|
||||
|
@ -81,7 +80,7 @@ func (h *HypervisorDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group
|
|||
err = pagerHypervisors.EachPage(func(page pagination.Page) (bool, error) {
|
||||
hypervisorList, err := hypervisors.ExtractHypervisors(page)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "could not extract hypervisors")
|
||||
return false, fmt.Errorf("could not extract hypervisors: %w", err)
|
||||
}
|
||||
for _, hypervisor := range hypervisorList {
|
||||
labels := model.LabelSet{}
|
||||
|
|
|
@ -25,7 +25,6 @@ import (
|
|||
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips"
|
||||
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
|
@ -79,14 +78,14 @@ func (i *InstanceDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
|
|||
i.provider.Context = ctx
|
||||
err := openstack.Authenticate(i.provider, *i.authOpts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not authenticate to OpenStack")
|
||||
return nil, fmt.Errorf("could not authenticate to OpenStack: %w", err)
|
||||
}
|
||||
|
||||
client, err := openstack.NewComputeV2(i.provider, gophercloud.EndpointOpts{
|
||||
Region: i.region, Availability: i.availability,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create OpenStack compute session")
|
||||
return nil, fmt.Errorf("could not create OpenStack compute session: %w", err)
|
||||
}
|
||||
|
||||
// OpenStack API reference
|
||||
|
@ -97,7 +96,7 @@ func (i *InstanceDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
|
|||
err = pagerFIP.EachPage(func(page pagination.Page) (bool, error) {
|
||||
result, err := floatingips.ExtractFloatingIPs(page)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "could not extract floatingips")
|
||||
return false, fmt.Errorf("could not extract floatingips: %w", err)
|
||||
}
|
||||
for _, ip := range result {
|
||||
// Skip not associated ips
|
||||
|
@ -124,11 +123,11 @@ func (i *InstanceDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
|
|||
}
|
||||
err = pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||
if ctx.Err() != nil {
|
||||
return false, errors.Wrap(ctx.Err(), "could not extract instances")
|
||||
return false, fmt.Errorf("could not extract instances: %w", ctx.Err())
|
||||
}
|
||||
instanceList, err := servers.ExtractServers(page)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "could not extract instances")
|
||||
return false, fmt.Errorf("could not extract instances: %w", err)
|
||||
}
|
||||
|
||||
for _, s := range instanceList {
|
||||
|
|
|
@ -15,6 +15,7 @@ package openstack
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
@ -23,7 +24,6 @@ import (
|
|||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/openstack"
|
||||
conntrack "github.com/mwitkow/go-conntrack"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
|
@ -100,7 +100,7 @@ func (c *Role) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
case OpenStackRoleHypervisor, OpenStackRoleInstance:
|
||||
return nil
|
||||
default:
|
||||
return errors.Errorf("unknown OpenStack SD role %q", *c)
|
||||
return fmt.Errorf("unknown OpenStack SD role %q", *c)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ import (
|
|||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/grafana/regexp"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/version"
|
||||
|
@ -191,11 +190,11 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|||
}()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, errors.Errorf("server returned HTTP status %s", resp.Status)
|
||||
return nil, fmt.Errorf("server returned HTTP status %s", resp.Status)
|
||||
}
|
||||
|
||||
if ct := resp.Header.Get("Content-Type"); !matchContentType.MatchString(ct) {
|
||||
return nil, errors.Errorf("unsupported content type %s", resp.Header.Get("Content-Type"))
|
||||
return nil, fmt.Errorf("unsupported content type %s", resp.Header.Get("Content-Type"))
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
|
|
|
@ -15,6 +15,7 @@ package refresh
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
|
@ -75,7 +76,7 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
|
|||
// Get an initial set right away.
|
||||
tgs, err := d.refresh(ctx)
|
||||
if err != nil {
|
||||
if ctx.Err() != context.Canceled {
|
||||
if !errors.Is(ctx.Err(), context.Canceled) {
|
||||
level.Error(d.logger).Log("msg", "Unable to refresh target groups", "err", err.Error())
|
||||
}
|
||||
} else {
|
||||
|
@ -94,7 +95,7 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
|
|||
case <-ticker.C:
|
||||
tgs, err := d.refresh(ctx)
|
||||
if err != nil {
|
||||
if ctx.Err() != context.Canceled {
|
||||
if !errors.Is(ctx.Err(), context.Canceled) {
|
||||
level.Error(d.logger).Log("msg", "Unable to refresh target groups", "err", err.Error())
|
||||
}
|
||||
continue
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
package discovery
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
@ -247,7 +248,8 @@ func writeConfigs(structVal reflect.Value, configs Configs) error {
|
|||
}
|
||||
|
||||
func replaceYAMLTypeError(err error, oldTyp, newTyp reflect.Type) error {
|
||||
if e, ok := err.(*yaml.TypeError); ok {
|
||||
var e *yaml.TypeError
|
||||
if errors.As(err, &e) {
|
||||
oldStr := oldTyp.String()
|
||||
newStr := newTyp.String()
|
||||
for i, s := range e.Errors {
|
||||
|
|
|
@ -15,13 +15,14 @@ package scaleway
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/scaleway/scaleway-sdk-go/scw"
|
||||
|
@ -61,7 +62,7 @@ func (c *role) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
case roleInstance, roleBaremetal:
|
||||
return nil
|
||||
default:
|
||||
return errors.Errorf("unknown role %q", *c)
|
||||
return fmt.Errorf("unknown role %q", *c)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,7 +229,7 @@ func newAuthTokenFileRoundTripper(tokenFile string, rt http.RoundTripper) (http.
|
|||
// fail-fast if we can't read the file.
|
||||
_, err := os.ReadFile(tokenFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to read auth token file %s", tokenFile)
|
||||
return nil, fmt.Errorf("unable to read auth token file %s: %w", tokenFile, err)
|
||||
}
|
||||
return &authTokenFileRoundTripper{tokenFile, rt}, nil
|
||||
}
|
||||
|
@ -236,7 +237,7 @@ func newAuthTokenFileRoundTripper(tokenFile string, rt http.RoundTripper) (http.
|
|||
func (rt *authTokenFileRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||
b, err := os.ReadFile(rt.authTokenFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to read auth token file %s", rt.authTokenFile)
|
||||
return nil, fmt.Errorf("unable to read auth token file %s: %w", rt.authTokenFile, err)
|
||||
}
|
||||
authToken := strings.TrimSpace(string(b))
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ package triton
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
@ -25,7 +26,6 @@ import (
|
|||
|
||||
"github.com/go-kit/log"
|
||||
conntrack "github.com/mwitkow/go-conntrack"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
|
@ -202,7 +202,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|||
req = req.WithContext(ctx)
|
||||
resp, err := d.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "an error occurred when requesting targets from the discovery endpoint")
|
||||
return nil, fmt.Errorf("an error occurred when requesting targets from the discovery endpoint: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
|
@ -212,7 +212,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|||
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "an error occurred when reading the response body")
|
||||
return nil, fmt.Errorf("an error occurred when reading the response body: %w", err)
|
||||
}
|
||||
|
||||
// The JSON response body is different so it needs to be processed/mapped separately.
|
||||
|
@ -234,7 +234,7 @@ func (d *Discovery) processContainerResponse(data []byte, endpoint string) ([]*t
|
|||
dr := DiscoveryResponse{}
|
||||
err := json.Unmarshal(data, &dr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "an error occurred unmarshaling the discovery response json")
|
||||
return nil, fmt.Errorf("an error occurred unmarshaling the discovery response json: %w", err)
|
||||
}
|
||||
|
||||
for _, container := range dr.Containers {
|
||||
|
@ -267,7 +267,7 @@ func (d *Discovery) processComputeNodeResponse(data []byte, endpoint string) ([]
|
|||
dr := ComputeNodeDiscoveryResponse{}
|
||||
err := json.Unmarshal(data, &dr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "an error occurred unmarshaling the compute node discovery response json")
|
||||
return nil, fmt.Errorf("an error occurred unmarshaling the compute node discovery response json: %w", err)
|
||||
}
|
||||
|
||||
for _, cn := range dr.ComputeNodes {
|
||||
|
|
|
@ -15,6 +15,7 @@ package uyuni
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -24,7 +25,6 @@ import (
|
|||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/kolo/xmlrpc"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
|
@ -52,9 +52,10 @@ const (
|
|||
|
||||
// DefaultSDConfig is the default Uyuni SD configuration.
|
||||
var DefaultSDConfig = SDConfig{
|
||||
Entitlement: "monitoring_entitled",
|
||||
Separator: ",",
|
||||
RefreshInterval: model.Duration(1 * time.Minute),
|
||||
Entitlement: "monitoring_entitled",
|
||||
Separator: ",",
|
||||
RefreshInterval: model.Duration(1 * time.Minute),
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -117,6 +118,11 @@ func (c *SDConfig) NewDiscoverer(opts discovery.DiscovererOptions) (discovery.Di
|
|||
return NewDiscovery(c, opts.Logger)
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *SDConfig) SetDirectory(dir string) {
|
||||
c.HTTPClientConfig.SetDirectory(dir)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*c = DefaultSDConfig
|
||||
|
@ -131,7 +137,7 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
|
||||
_, err = url.Parse(c.Server)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Uyuni Server URL is not valid")
|
||||
return fmt.Errorf("Uyuni Server URL is not valid: %w", err)
|
||||
}
|
||||
|
||||
if c.Username == "" {
|
||||
|
@ -276,7 +282,7 @@ func (d *Discovery) getTargetsForSystems(
|
|||
|
||||
systemGroupIDsBySystemID, err := getSystemGroupsInfoOfMonitoredClients(rpcClient, d.token, entitlement)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to get the managed system groups information of monitored clients")
|
||||
return nil, fmt.Errorf("unable to get the managed system groups information of monitored clients: %w", err)
|
||||
}
|
||||
|
||||
systemIDs := make([]int, 0, len(systemGroupIDsBySystemID))
|
||||
|
@ -286,12 +292,12 @@ func (d *Discovery) getTargetsForSystems(
|
|||
|
||||
endpointInfos, err := getEndpointInfoForSystems(rpcClient, d.token, systemIDs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to get endpoints information")
|
||||
return nil, fmt.Errorf("unable to get endpoints information: %w", err)
|
||||
}
|
||||
|
||||
networkInfoBySystemID, err := getNetworkInformationForSystems(rpcClient, d.token, systemIDs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to get the systems network information")
|
||||
return nil, fmt.Errorf("unable to get the systems network information: %w", err)
|
||||
}
|
||||
|
||||
for _, endpoint := range endpointInfos {
|
||||
|
@ -317,7 +323,7 @@ func (d *Discovery) refresh(_ context.Context) ([]*targetgroup.Group, error) {
|
|||
// Uyuni API takes duration in seconds.
|
||||
d.token, err = login(rpcClient, d.username, d.password, int(tokenDuration.Seconds()))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to login to Uyuni API")
|
||||
return nil, fmt.Errorf("unable to login to Uyuni API: %w", err)
|
||||
}
|
||||
// Login again at half the token lifetime.
|
||||
d.tokenExpiration = time.Now().Add(tokenDuration / 2)
|
||||
|
|
170
discovery/vultr/mock_test.go
Normal file
170
discovery/vultr/mock_test.go
Normal file
|
@ -0,0 +1,170 @@
|
|||
// Copyright 2022 The Prometheus 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.
|
||||
|
||||
package vultr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// SDMock is the interface for the Vultr mock
|
||||
type SDMock struct {
|
||||
t *testing.T
|
||||
Server *httptest.Server
|
||||
Mux *http.ServeMux
|
||||
}
|
||||
|
||||
// NewSDMock returns a new Vultr mock server.
|
||||
func NewSDMock(t *testing.T) *SDMock {
|
||||
return &SDMock{
|
||||
t: t,
|
||||
}
|
||||
}
|
||||
|
||||
// Endpoint returns the URI to the mock server.
|
||||
func (m *SDMock) Endpoint() string {
|
||||
return m.Server.URL + "/"
|
||||
}
|
||||
|
||||
// Setup creates the mock server.
|
||||
func (m *SDMock) Setup() {
|
||||
m.Mux = http.NewServeMux()
|
||||
m.Server = httptest.NewServer(m.Mux)
|
||||
}
|
||||
|
||||
// ShutdownServer shuts down the mock server.
|
||||
func (m *SDMock) ShutdownServer() {
|
||||
m.Server.Close()
|
||||
}
|
||||
|
||||
const APIKey = "ABCBTDG35OTGH2UKCC3S6CNMDUPCN3ZWSGFQ"
|
||||
|
||||
// HandleInstanceList mocks vultr instances list.
|
||||
func (m *SDMock) HandleInstanceList() {
|
||||
m.Mux.HandleFunc("/v2/instances", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get("Authorization") != fmt.Sprintf("Bearer %s", APIKey) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Add("content-type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
fmt.Fprint(w, `
|
||||
{
|
||||
"instances": [
|
||||
{
|
||||
"id": "dbdbd38c-9884-4c92-95fe-899e50dee717",
|
||||
"os": "Marketplace",
|
||||
"ram": 4096,
|
||||
"disk": 128,
|
||||
"main_ip": "149.28.234.27",
|
||||
"vcpu_count": 2,
|
||||
"region": "ewr",
|
||||
"plan": "vhf-2c-4gb",
|
||||
"date_created": "2022-03-10T02:25:30+00:00",
|
||||
"status": "active",
|
||||
"allowed_bandwidth": 3000,
|
||||
"netmask_v4": "255.255.254.0",
|
||||
"gateway_v4": "149.28.234.1",
|
||||
"power_status": "running",
|
||||
"server_status": "ok",
|
||||
"v6_network": "",
|
||||
"v6_main_ip": "",
|
||||
"v6_network_size": 0,
|
||||
"label": "np-2-eae38a19b0f3",
|
||||
"internal_ip": "10.1.96.5",
|
||||
"kvm": "https://my.vultr.com/subs/vps/novnc/api.php?data=djJ8Q2k2NlVpNUlZNE5kM3NZMWdBNzFKUkVadDBDU3ItTEJ8-yNWBdMn1AWPqX-EnpTVbA1qBeP0txBZbahSOh3UtHIL2p0fZKEdFJwFNjWtvBKC9BGvJkoJdWBoo7hF-6RzavdUKPD3KIU5xD_T6keV8X-PPukPgXMuSUaAqurAuJvwAWXcTcodBjaIH961xgbvfkFyqVl0ZgHf3ErZQE-EmpZ0Jc3uF1DO2McJ4UL8KUvHLwa-ZDUZ_AtWJjQWsjNkxjvOiA",
|
||||
"hostname": "np-2-eae38a19b0f3",
|
||||
"os_id": 426,
|
||||
"app_id": 0,
|
||||
"image_id": "vke-worker",
|
||||
"firewall_group_id": "",
|
||||
"features": ["backups"],
|
||||
"tags": ["tag1", "tag2", "tag3"]
|
||||
},
|
||||
{
|
||||
"id": "fccb117c-62f7-4b17-995d-a8e56dd30b33",
|
||||
"os": "Marketplace",
|
||||
"ram": 4096,
|
||||
"disk": 128,
|
||||
"main_ip": "45.63.1.222",
|
||||
"vcpu_count": 2,
|
||||
"region": "ewr",
|
||||
"plan": "vhf-2c-4gb",
|
||||
"date_created": "2022-03-10T02:25:32+00:00",
|
||||
"status": "active",
|
||||
"allowed_bandwidth": 3000,
|
||||
"netmask_v4": "255.255.254.0",
|
||||
"gateway_v4": "45.63.0.1",
|
||||
"power_status": "running",
|
||||
"server_status": "ok",
|
||||
"v6_network": "",
|
||||
"v6_main_ip": "",
|
||||
"v6_network_size": 0,
|
||||
"label": "np-2-fd0714b5fe42",
|
||||
"internal_ip": "10.1.96.6",
|
||||
"kvm": "https://my.vultr.com/subs/vps/novnc/api.php?data=djJ8R0tzbmI0VWVfSDR6VE51Q0FGUTBCamwyTFNzZDNkVTF8Zwm93t6L2BLTYSNmM0g0Ppf43r71aIbqLiJCx6_1NuCugUqIKz8POshH91vi6XXDorpb3hYTk8RrJWQbaFMak7XbbfMObzsrFxKAQUVGfbjTBIHCKftxNIXeQOp1fEIDa3p-vkfSxEpx6ZX8nChGYYSVuOjS1twV6oI_IKtHXKdFJiVFz0Unay_K3HuXW_H2wrYSjmAChloR-eA1jSmBXLccJQ",
|
||||
"hostname": "np-2-fd0714b5fe42",
|
||||
"os_id": 426,
|
||||
"app_id": 0,
|
||||
"image_id": "vke-worker",
|
||||
"firewall_group_id": "",
|
||||
"features": [],
|
||||
"tags": []
|
||||
},
|
||||
{
|
||||
"id": "c4e58767-f61b-4c5e-9bce-43761cc04868",
|
||||
"os": "Marketplace",
|
||||
"ram": 4096,
|
||||
"disk": 128,
|
||||
"main_ip": "149.28.237.151",
|
||||
"vcpu_count": 2,
|
||||
"region": "ewr",
|
||||
"plan": "vhf-2c-4gb",
|
||||
"date_created": "2022-03-10T02:25:33+00:00",
|
||||
"status": "active",
|
||||
"allowed_bandwidth": 3000,
|
||||
"netmask_v4": "255.255.254.0",
|
||||
"gateway_v4": "149.28.236.1",
|
||||
"power_status": "running",
|
||||
"server_status": "ok",
|
||||
"v6_network": "",
|
||||
"v6_main_ip": "",
|
||||
"v6_network_size": 0,
|
||||
"label": "np-2-d04e7829fa43",
|
||||
"internal_ip": "10.1.96.7",
|
||||
"kvm": "https://my.vultr.com/subs/vps/novnc/api.php?data=djJ8NFEzbFZmV2hOUWNrc2R4bndnckhFQTJ3ME1yWmxVeW98P-p-KeyNtP73wzVvuWZSOrV5PvQDiBmYyB3cp99btIy5nczmvX8DOGSChbEldk3idKNdFLQMIieWnpR5xU5K-dMYlL6n6oYv2u-rh8zxS6-8hQsSbL2OsoywNPoLpQ3xPkT9Rb-yPrZX4fDLbt8yPVKDHqHO0GB-TxVPemueovfkkUZMXSraAXgHtl1YgK2uLMQf1WBFVzgwnQ7MYcfMGGYFQw",
|
||||
"hostname": "np-2-d04e7829fa43",
|
||||
"os_id": 426,
|
||||
"app_id": 0,
|
||||
"image_id": "vke-worker",
|
||||
"firewall_group_id": "",
|
||||
"features": [],
|
||||
"tags": []
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"total": 3,
|
||||
"links": {
|
||||
"next": "",
|
||||
"prev": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
})
|
||||
}
|
212
discovery/vultr/vultr.go
Normal file
212
discovery/vultr/vultr.go
Normal file
|
@ -0,0 +1,212 @@
|
|||
// Copyright 2022 The Prometheus 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.
|
||||
|
||||
package vultr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/version"
|
||||
"github.com/vultr/govultr/v2"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery"
|
||||
"github.com/prometheus/prometheus/discovery/refresh"
|
||||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
)
|
||||
|
||||
const (
|
||||
vultrInstanceLabel = model.MetaLabelPrefix + "vultr_instance_"
|
||||
vultrInstanceLabelID = vultrInstanceLabel + "id"
|
||||
vultrInstanceLabelLabel = vultrInstanceLabel + "label"
|
||||
vultrInstanceLabelOS = vultrInstanceLabel + "os"
|
||||
vultrInstanceLabelOSID = vultrInstanceLabel + "os_id"
|
||||
vultrInstanceLabelRegion = vultrInstanceLabel + "region"
|
||||
vultrInstanceLabelPlan = vultrInstanceLabel + "plan"
|
||||
vultrInstanceLabelMainIP = vultrInstanceLabel + "main_ip"
|
||||
vultrInstanceLabelMainIPV6 = vultrInstanceLabel + "main_ipv6"
|
||||
vultrInstanceLabelInternalIP = vultrInstanceLabel + "internal_ip"
|
||||
vultrInstanceLabelFeatures = vultrInstanceLabel + "features"
|
||||
vultrInstanceLabelTags = vultrInstanceLabel + "tags"
|
||||
vultrInstanceLabelHostname = vultrInstanceLabel + "hostname"
|
||||
vultrInstanceLabelServerStatus = vultrInstanceLabel + "server_status"
|
||||
vultrInstanceLabelVCPU = vultrInstanceLabel + "vcpu_count"
|
||||
vultrInstanceLabelMemory = vultrInstanceLabel + "ram_mb"
|
||||
vultrInstanceLabelBandwidth = vultrInstanceLabel + "allowed_bandwidth_gb"
|
||||
vultrInstanceLabelDisk = vultrInstanceLabel + "disk_gb"
|
||||
separator = ","
|
||||
)
|
||||
|
||||
// DefaultSDConfig is the default Vultr SD configuration.
|
||||
var DefaultSDConfig = SDConfig{
|
||||
Port: 80,
|
||||
RefreshInterval: model.Duration(60 * time.Second),
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
}
|
||||
|
||||
func init() {
|
||||
discovery.RegisterConfig(&SDConfig{})
|
||||
}
|
||||
|
||||
type SDConfig struct {
|
||||
HTTPClientConfig config.HTTPClientConfig `yaml:",inline"`
|
||||
|
||||
RefreshInterval model.Duration `yaml:"refresh_interval"`
|
||||
Port int `yaml:"port"`
|
||||
}
|
||||
|
||||
// Name returns the name of the Config.
|
||||
func (*SDConfig) Name() string { return "vultr" }
|
||||
|
||||
// NewDiscoverer returns a Discoverer for the Config.
|
||||
func (c *SDConfig) NewDiscoverer(opts discovery.DiscovererOptions) (discovery.Discoverer, error) {
|
||||
return NewDiscovery(c, opts.Logger)
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *SDConfig) SetDirectory(dir string) {
|
||||
c.HTTPClientConfig.SetDirectory(dir)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*c = DefaultSDConfig
|
||||
type plain SDConfig
|
||||
if err := unmarshal((*plain)(c)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.HTTPClientConfig.Validate()
|
||||
}
|
||||
|
||||
// Discovery periodically performs Vultr requests. It implements
|
||||
// the Discoverer interface.
|
||||
type Discovery struct {
|
||||
*refresh.Discovery
|
||||
client *govultr.Client
|
||||
port int
|
||||
}
|
||||
|
||||
// NewDiscovery returns a new Discovery which periodically refreshes its targets.
|
||||
func NewDiscovery(conf *SDConfig, logger log.Logger) (*Discovery, error) {
|
||||
d := &Discovery{
|
||||
port: conf.Port,
|
||||
}
|
||||
|
||||
rt, err := config.NewRoundTripperFromConfig(conf.HTTPClientConfig, "vultr_sd")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.client = govultr.NewClient(&http.Client{
|
||||
Transport: rt,
|
||||
Timeout: time.Duration(conf.RefreshInterval),
|
||||
})
|
||||
|
||||
d.client.SetUserAgent(fmt.Sprintf("Prometheus/%s", version.Version))
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error setting up vultr agent: %w", err)
|
||||
}
|
||||
|
||||
d.Discovery = refresh.NewDiscovery(
|
||||
logger,
|
||||
"vultr",
|
||||
time.Duration(conf.RefreshInterval),
|
||||
d.refresh,
|
||||
)
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
||||
tg := &targetgroup.Group{
|
||||
Source: "Vultr",
|
||||
}
|
||||
|
||||
instances, err := d.listInstances(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, instance := range instances {
|
||||
labels := model.LabelSet{
|
||||
vultrInstanceLabelID: model.LabelValue(instance.ID),
|
||||
vultrInstanceLabelLabel: model.LabelValue(instance.Label),
|
||||
vultrInstanceLabelOS: model.LabelValue(instance.Os),
|
||||
vultrInstanceLabelOSID: model.LabelValue(strconv.Itoa(instance.OsID)),
|
||||
vultrInstanceLabelRegion: model.LabelValue(instance.Region),
|
||||
vultrInstanceLabelPlan: model.LabelValue(instance.Plan),
|
||||
vultrInstanceLabelVCPU: model.LabelValue(strconv.Itoa(instance.VCPUCount)),
|
||||
vultrInstanceLabelMemory: model.LabelValue(strconv.Itoa(instance.RAM)),
|
||||
vultrInstanceLabelBandwidth: model.LabelValue(strconv.Itoa(instance.AllowedBandwidth)),
|
||||
vultrInstanceLabelDisk: model.LabelValue(strconv.Itoa(instance.Disk)),
|
||||
vultrInstanceLabelMainIP: model.LabelValue(instance.MainIP),
|
||||
vultrInstanceLabelMainIPV6: model.LabelValue(instance.V6MainIP),
|
||||
vultrInstanceLabelInternalIP: model.LabelValue(instance.InternalIP),
|
||||
vultrInstanceLabelHostname: model.LabelValue(instance.Hostname),
|
||||
vultrInstanceLabelServerStatus: model.LabelValue(instance.ServerStatus),
|
||||
}
|
||||
|
||||
addr := net.JoinHostPort(instance.MainIP, strconv.FormatUint(uint64(d.port), 10))
|
||||
labels[model.AddressLabel] = model.LabelValue(addr)
|
||||
|
||||
// We surround the separated list with the separator as well. This way regular expressions
|
||||
// in relabeling rules don't have to consider feature positions.
|
||||
if len(instance.Features) > 0 {
|
||||
features := separator + strings.Join(instance.Features, separator) + separator
|
||||
labels[vultrInstanceLabelFeatures] = model.LabelValue(features)
|
||||
}
|
||||
|
||||
if len(instance.Tags) > 0 {
|
||||
tags := separator + strings.Join(instance.Tags, separator) + separator
|
||||
labels[vultrInstanceLabelTags] = model.LabelValue(tags)
|
||||
}
|
||||
|
||||
tg.Targets = append(tg.Targets, labels)
|
||||
}
|
||||
|
||||
return []*targetgroup.Group{tg}, nil
|
||||
}
|
||||
|
||||
func (d *Discovery) listInstances(ctx context.Context) ([]govultr.Instance, error) {
|
||||
var instances []govultr.Instance
|
||||
|
||||
listOptions := &govultr.ListOptions{
|
||||
PerPage: 100,
|
||||
}
|
||||
|
||||
for {
|
||||
pagedInstances, meta, err := d.client.Instance.List(ctx, listOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instances = append(instances, pagedInstances...)
|
||||
|
||||
if meta.Links.Next == "" {
|
||||
break
|
||||
} else {
|
||||
listOptions.Cursor = meta.Links.Next
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return instances, nil
|
||||
}
|
128
discovery/vultr/vultr_test.go
Normal file
128
discovery/vultr/vultr_test.go
Normal file
|
@ -0,0 +1,128 @@
|
|||
// Copyright 2022 The Prometheus 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.
|
||||
|
||||
package vultr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type VultrSDTestSuite struct {
|
||||
Mock *SDMock
|
||||
}
|
||||
|
||||
func (s *VultrSDTestSuite) TearDownSuite() {
|
||||
s.Mock.ShutdownServer()
|
||||
}
|
||||
|
||||
func (s *VultrSDTestSuite) SetupTest(t *testing.T) {
|
||||
s.Mock = NewSDMock(t)
|
||||
s.Mock.Setup()
|
||||
|
||||
s.Mock.HandleInstanceList()
|
||||
}
|
||||
|
||||
func TestVultrSDRefresh(t *testing.T) {
|
||||
sdMock := &VultrSDTestSuite{}
|
||||
sdMock.SetupTest(t)
|
||||
t.Cleanup(sdMock.TearDownSuite)
|
||||
|
||||
cfg := DefaultSDConfig
|
||||
cfg.HTTPClientConfig.BearerToken = APIKey
|
||||
d, err := NewDiscovery(&cfg, log.NewNopLogger())
|
||||
require.NoError(t, err)
|
||||
endpoint, err := url.Parse(sdMock.Mock.Endpoint())
|
||||
require.NoError(t, err)
|
||||
d.client.BaseURL = endpoint
|
||||
|
||||
ctx := context.Background()
|
||||
tgs, err := d.refresh(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(tgs))
|
||||
|
||||
tg := tgs[0]
|
||||
require.NotNil(t, tg)
|
||||
require.NotNil(t, tg.Targets)
|
||||
require.Equal(t, 3, len(tg.Targets))
|
||||
|
||||
for i, k := range []model.LabelSet{
|
||||
{
|
||||
"__address__": model.LabelValue("149.28.234.27:80"),
|
||||
"__meta_vultr_instance_id": model.LabelValue("dbdbd38c-9884-4c92-95fe-899e50dee717"),
|
||||
"__meta_vultr_instance_label": model.LabelValue("np-2-eae38a19b0f3"),
|
||||
"__meta_vultr_instance_os": model.LabelValue("Marketplace"),
|
||||
"__meta_vultr_instance_os_id": model.LabelValue("426"),
|
||||
"__meta_vultr_instance_region": model.LabelValue("ewr"),
|
||||
"__meta_vultr_instance_plan": model.LabelValue("vhf-2c-4gb"),
|
||||
"__meta_vultr_instance_main_ip": model.LabelValue("149.28.234.27"),
|
||||
"__meta_vultr_instance_internal_ip": model.LabelValue("10.1.96.5"),
|
||||
"__meta_vultr_instance_main_ipv6": model.LabelValue(""),
|
||||
"__meta_vultr_instance_features": model.LabelValue(",backups,"),
|
||||
"__meta_vultr_instance_tags": model.LabelValue(",tag1,tag2,tag3,"),
|
||||
"__meta_vultr_instance_hostname": model.LabelValue("np-2-eae38a19b0f3"),
|
||||
"__meta_vultr_instance_server_status": model.LabelValue("ok"),
|
||||
"__meta_vultr_instance_vcpu_count": model.LabelValue("2"),
|
||||
"__meta_vultr_instance_ram_mb": model.LabelValue("4096"),
|
||||
"__meta_vultr_instance_disk_gb": model.LabelValue("128"),
|
||||
"__meta_vultr_instance_allowed_bandwidth_gb": model.LabelValue("3000"),
|
||||
},
|
||||
{
|
||||
"__address__": model.LabelValue("45.63.1.222:80"),
|
||||
"__meta_vultr_instance_id": model.LabelValue("fccb117c-62f7-4b17-995d-a8e56dd30b33"),
|
||||
"__meta_vultr_instance_label": model.LabelValue("np-2-fd0714b5fe42"),
|
||||
"__meta_vultr_instance_os": model.LabelValue("Marketplace"),
|
||||
"__meta_vultr_instance_os_id": model.LabelValue("426"),
|
||||
"__meta_vultr_instance_region": model.LabelValue("ewr"),
|
||||
"__meta_vultr_instance_plan": model.LabelValue("vhf-2c-4gb"),
|
||||
"__meta_vultr_instance_main_ip": model.LabelValue("45.63.1.222"),
|
||||
"__meta_vultr_instance_internal_ip": model.LabelValue("10.1.96.6"),
|
||||
"__meta_vultr_instance_main_ipv6": model.LabelValue(""),
|
||||
"__meta_vultr_instance_hostname": model.LabelValue("np-2-fd0714b5fe42"),
|
||||
"__meta_vultr_instance_server_status": model.LabelValue("ok"),
|
||||
"__meta_vultr_instance_vcpu_count": model.LabelValue("2"),
|
||||
"__meta_vultr_instance_ram_mb": model.LabelValue("4096"),
|
||||
"__meta_vultr_instance_disk_gb": model.LabelValue("128"),
|
||||
"__meta_vultr_instance_allowed_bandwidth_gb": model.LabelValue("3000"),
|
||||
},
|
||||
{
|
||||
"__address__": model.LabelValue("149.28.237.151:80"),
|
||||
"__meta_vultr_instance_id": model.LabelValue("c4e58767-f61b-4c5e-9bce-43761cc04868"),
|
||||
"__meta_vultr_instance_label": model.LabelValue("np-2-d04e7829fa43"),
|
||||
"__meta_vultr_instance_os": model.LabelValue("Marketplace"),
|
||||
"__meta_vultr_instance_os_id": model.LabelValue("426"),
|
||||
"__meta_vultr_instance_region": model.LabelValue("ewr"),
|
||||
"__meta_vultr_instance_plan": model.LabelValue("vhf-2c-4gb"),
|
||||
"__meta_vultr_instance_main_ip": model.LabelValue("149.28.237.151"),
|
||||
"__meta_vultr_instance_internal_ip": model.LabelValue("10.1.96.7"),
|
||||
"__meta_vultr_instance_main_ipv6": model.LabelValue(""),
|
||||
"__meta_vultr_instance_hostname": model.LabelValue("np-2-d04e7829fa43"),
|
||||
"__meta_vultr_instance_server_status": model.LabelValue("ok"),
|
||||
"__meta_vultr_instance_vcpu_count": model.LabelValue("2"),
|
||||
"__meta_vultr_instance_ram_mb": model.LabelValue("4096"),
|
||||
"__meta_vultr_instance_disk_gb": model.LabelValue("128"),
|
||||
"__meta_vultr_instance_allowed_bandwidth_gb": model.LabelValue("3000"),
|
||||
},
|
||||
} {
|
||||
t.Run(fmt.Sprintf("item %d", i), func(t *testing.T) {
|
||||
require.Equal(t, k, tg.Targets[i])
|
||||
})
|
||||
}
|
||||
}
|
|
@ -20,7 +20,6 @@ import (
|
|||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
|
@ -92,7 +91,7 @@ func (c *KumaSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
}
|
||||
|
||||
if len(c.Server) == 0 {
|
||||
return errors.Errorf("kuma SD server must not be empty: %s", c.Server)
|
||||
return fmt.Errorf("kuma SD server must not be empty: %s", c.Server)
|
||||
}
|
||||
parsedURL, err := url.Parse(c.Server)
|
||||
if err != nil {
|
||||
|
@ -100,7 +99,7 @@ func (c *KumaSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
}
|
||||
|
||||
if len(parsedURL.Scheme) == 0 || len(parsedURL.Host) == 0 {
|
||||
return errors.Errorf("kuma SD server must not be empty and have a scheme: %s", c.Server)
|
||||
return fmt.Errorf("kuma SD server must not be empty and have a scheme: %s", c.Server)
|
||||
}
|
||||
|
||||
return c.HTTPClientConfig.Validate()
|
||||
|
@ -159,7 +158,7 @@ func convertKumaUserLabels(labels map[string]string) model.LabelSet {
|
|||
// kumaMadsV1ResourceParser is an xds.resourceParser.
|
||||
func kumaMadsV1ResourceParser(resources []*anypb.Any, typeURL string) ([]model.LabelSet, error) {
|
||||
if typeURL != KumaMadsV1ResourceTypeURL {
|
||||
return nil, errors.Errorf("received invalid typeURL for Kuma MADS v1 Resource: %s", typeURL)
|
||||
return nil, fmt.Errorf("received invalid typeURL for Kuma MADS v1 Resource: %s", typeURL)
|
||||
}
|
||||
|
||||
var targets []model.LabelSet
|
||||
|
|
|
@ -15,12 +15,12 @@ package xds
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
v3 "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
|
|
@ -16,6 +16,7 @@ package zookeeper
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
@ -24,7 +25,6 @@ import (
|
|||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-zookeeper/zk"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery"
|
||||
|
@ -80,7 +80,7 @@ func (c *ServersetSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) err
|
|||
}
|
||||
for _, path := range c.Paths {
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
return errors.Errorf("serverset SD config paths must begin with '/': %s", path)
|
||||
return fmt.Errorf("serverset SD config paths must begin with '/': %s", path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -117,7 +117,7 @@ func (c *NerveSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
}
|
||||
for _, path := range c.Paths {
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
return errors.Errorf("nerve SD config paths must begin with '/': %s", path)
|
||||
return fmt.Errorf("nerve SD config paths must begin with '/': %s", path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -263,7 +263,7 @@ func parseServersetMember(data []byte, path string) (model.LabelSet, error) {
|
|||
member := serversetMember{}
|
||||
|
||||
if err := json.Unmarshal(data, &member); err != nil {
|
||||
return nil, errors.Wrapf(err, "error unmarshaling serverset member %q", path)
|
||||
return nil, fmt.Errorf("error unmarshaling serverset member %q: %w", path, err)
|
||||
}
|
||||
|
||||
labels := model.LabelSet{}
|
||||
|
@ -305,7 +305,7 @@ func parseNerveMember(data []byte, path string) (model.LabelSet, error) {
|
|||
member := nerveMember{}
|
||||
err := json.Unmarshal(data, &member)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error unmarshaling nerve member %q", path)
|
||||
return nil, fmt.Errorf("error unmarshaling nerve member %q: %w", path, err)
|
||||
}
|
||||
|
||||
labels := model.LabelSet{}
|
||||
|
|
|
@ -256,6 +256,11 @@ hetzner_sd_configs:
|
|||
http_sd_configs:
|
||||
[ - <http_sd_config> ... ]
|
||||
|
||||
|
||||
# List of IONOS service discovery configurations.
|
||||
ionos_sd_configs:
|
||||
[ - <ionos_sd_config> ... ]
|
||||
|
||||
# List of Kubernetes service discovery configurations.
|
||||
kubernetes_sd_configs:
|
||||
[ - <kubernetes_sd_config> ... ]
|
||||
|
@ -1539,6 +1544,86 @@ tls_config:
|
|||
[ <tls_config> ]
|
||||
```
|
||||
|
||||
### `<ionos_sd_config>`
|
||||
|
||||
IONOS SD configurations allows retrieving scrape targets from
|
||||
[IONOS Cloud](https://cloud.ionos.com/) API. This service discovery uses the
|
||||
first NICs IP address by default, but that can be changed with relabeling. The
|
||||
following meta labels are available on all targets during
|
||||
[relabeling](#relabel_config):
|
||||
|
||||
* `__meta_ionos_server_availability_zone`: the availability zone of the server
|
||||
* `__meta_ionos_server_boot_cdrom_id`: the ID of the CD-ROM the server is booted
|
||||
from
|
||||
* `__meta_ionos_server_boot_image_id`: the ID of the boot image or snapshot the
|
||||
server is booted from
|
||||
* `__meta_ionos_server_boot_volume_id`: the ID of the boot volume
|
||||
* `__meta_ionos_server_cpu_family`: the CPU family of the server
|
||||
to
|
||||
* `__meta_ionos_server_id`: the ID of the server
|
||||
* `__meta_ionos_server_ip`: comma separated list of all IPs assigned to the
|
||||
server
|
||||
* `__meta_ionos_server_lifecycle`: the lifecycle state of the server resource
|
||||
* `__meta_ionos_server_name`: the name of the server
|
||||
* `__meta_ionos_server_nic_ip_<nic_name>`: comma separated list of IPs, grouped
|
||||
by the name of each NIC attached to the server
|
||||
* `__meta_ionos_server_servers_id`: the ID of the servers the server belongs to
|
||||
* `__meta_ionos_server_state`: the execution state of the server
|
||||
* `__meta_ionos_server_type`: the type of the server
|
||||
|
||||
```yaml
|
||||
# The unique ID of the data center.
|
||||
datacenter_id: <string>
|
||||
|
||||
# Authentication information used to authenticate to the API server.
|
||||
# Note that `basic_auth` and `authorization` options are
|
||||
# mutually exclusive.
|
||||
# password and password_file are mutually exclusive.
|
||||
|
||||
# Optional HTTP basic authentication information, required when using IONOS
|
||||
# Cloud username and password as authentication method.
|
||||
basic_auth:
|
||||
[ username: <string> ]
|
||||
[ password: <secret> ]
|
||||
[ password_file: <string> ]
|
||||
|
||||
# Optional `Authorization` header configuration, required when using IONOS
|
||||
# Cloud token as authentication method.
|
||||
authorization:
|
||||
# Sets the authentication type.
|
||||
[ type: <string> | default: Bearer ]
|
||||
# Sets the credentials. It is mutually exclusive with
|
||||
# `credentials_file`.
|
||||
[ credentials: <secret> ]
|
||||
# Sets the credentials to the credentials read from the configured file.
|
||||
# It is mutually exclusive with `credentials`.
|
||||
[ credentials_file: <filename> ]
|
||||
|
||||
# Optional OAuth 2.0 configuration.
|
||||
# Cannot be used at the same time as basic_auth or authorization.
|
||||
oauth2:
|
||||
[ <oauth2> ]
|
||||
|
||||
# Optional proxy URL.
|
||||
[ proxy_url: <string> ]
|
||||
|
||||
# Configure whether HTTP requests follow HTTP 3xx redirects.
|
||||
[ follow_redirects: <boolean> | default = true ]
|
||||
|
||||
# Whether to enable HTTP2.
|
||||
[ enable_http2: <bool> | default: true ]
|
||||
|
||||
# TLS configuration.
|
||||
tls_config:
|
||||
[ <tls_config> ]
|
||||
|
||||
# The port to scrape metrics from.
|
||||
[ port: <int> | default = 80 ]
|
||||
|
||||
# The time after which the servers are refreshed.
|
||||
[ refresh_interval: <duration> | default = 60s ]
|
||||
```
|
||||
|
||||
### `<kubernetes_sd_config>`
|
||||
|
||||
Kubernetes SD configurations allow retrieving scrape targets from
|
||||
|
@ -2453,6 +2538,83 @@ tls_config:
|
|||
See [the Prometheus uyuni-sd configuration file](/documentation/examples/prometheus-uyuni.yml)
|
||||
for a practical example on how to set up Uyuni Prometheus configuration.
|
||||
|
||||
### `<vultr_sd_config>`
|
||||
|
||||
Vultr SD configurations allow retrieving scrape targets from [Vultr](https://www.vultr.com/).
|
||||
|
||||
This service discovery uses the main IPv4 address by default, which that be
|
||||
changed with relabelling, as demonstrated in [the Prometheus vultr-sd
|
||||
configuration file](/documentation/examples/prometheus-vultr.yml).
|
||||
|
||||
The following meta labels are available on targets during [relabeling](#relabel_config):
|
||||
|
||||
* `__meta_vultr_instance_id` : A unique ID for the vultr Instance.
|
||||
* `__meta_vultr_instance_label` : The user-supplied label for this instance.
|
||||
* `__meta_vultr_instance_os` : The Operating System name.
|
||||
* `__meta_vultr_instance_os_id` : The Operating System id used by this instance.
|
||||
* `__meta_vultr_instance_region` : The Region id where the Instance is located.
|
||||
* `__meta_vultr_instance_plan` : A unique ID for the Plan.
|
||||
* `__meta_vultr_instance_main_ip` : The main IPv4 address.
|
||||
* `__meta_vultr_instance_internal_ip` : The private IP address.
|
||||
* `__meta_vultr_instance_main_ipv6` : The main IPv6 address.
|
||||
* `__meta_vultr_instance_features` : List of features that are available to the instance.
|
||||
* `__meta_vultr_instance_tags` : List of tags associated with the instance.
|
||||
* `__meta_vultr_instance_hostname` : The hostname for this instance.
|
||||
* `__meta_vultr_instance_server_status` : The server health status.
|
||||
* `__meta_vultr_instance_vcpu_count` : Number of vCPUs.
|
||||
* `__meta_vultr_instance_ram_mb` : The amount of RAM in MB.
|
||||
* `__meta_vultr_instance_disk_gb` : The size of the disk in GB.
|
||||
* `__meta_vultr_instance_allowed_bandwidth_gb` : Monthly bandwidth quota in GB.
|
||||
|
||||
```yaml
|
||||
# Authentication information used to authenticate to the API server.
|
||||
# Note that `basic_auth` and `authorization` options are
|
||||
# mutually exclusive.
|
||||
# password and password_file are mutually exclusive.
|
||||
|
||||
# Optional HTTP basic authentication information, not currently supported by Vultr.
|
||||
basic_auth:
|
||||
[ username: <string> ]
|
||||
[ password: <secret> ]
|
||||
[ password_file: <string> ]
|
||||
|
||||
# Optional `Authorization` header configuration.
|
||||
authorization:
|
||||
# Sets the authentication type.
|
||||
[ type: <string> | default: Bearer ]
|
||||
# Sets the credentials. It is mutually exclusive with
|
||||
# `credentials_file`.
|
||||
[ credentials: <secret> ]
|
||||
# Sets the credentials to the credentials read from the configured file.
|
||||
# It is mutually exclusive with `credentials`.
|
||||
[ credentials_file: <filename> ]
|
||||
|
||||
# Optional OAuth 2.0 configuration.
|
||||
# Cannot be used at the same time as basic_auth or authorization.
|
||||
oauth2:
|
||||
[ <oauth2> ]
|
||||
|
||||
# Optional proxy URL.
|
||||
[ proxy_url: <string> ]
|
||||
|
||||
# Configure whether HTTP requests follow HTTP 3xx redirects.
|
||||
[ follow_redirects: <boolean> | default = true ]
|
||||
|
||||
# Whether to enable HTTP2.
|
||||
[ enable_http2: <bool> | default: true ]
|
||||
|
||||
# TLS configuration.
|
||||
tls_config:
|
||||
[ <tls_config> ]
|
||||
|
||||
# The port to scrape metrics from.
|
||||
[ port: <int> | default = 80 ]
|
||||
|
||||
# The time after which the instances are refreshed.
|
||||
[ refresh_interval: <duration> | default = 60s ]
|
||||
```
|
||||
|
||||
|
||||
### `<static_config>`
|
||||
|
||||
A `static_config` allows specifying a list of targets and a common label set
|
||||
|
@ -2680,6 +2842,10 @@ hetzner_sd_configs:
|
|||
http_sd_configs:
|
||||
[ - <http_sd_config> ... ]
|
||||
|
||||
# List of IONOS service discovery configurations.
|
||||
ionos_sd_configs:
|
||||
[ - <ionos_sd_config> ... ]
|
||||
|
||||
# List of Kubernetes service discovery configurations.
|
||||
kubernetes_sd_configs:
|
||||
[ - <kubernetes_sd_config> ... ]
|
||||
|
@ -2724,6 +2890,10 @@ triton_sd_configs:
|
|||
uyuni_sd_configs:
|
||||
[ - <uyuni_sd_config> ... ]
|
||||
|
||||
# List of Vultr service discovery configurations.
|
||||
vultr_sd_configs:
|
||||
[ - <vultr_sd_config> ... ]
|
||||
|
||||
# List of labeled statically configured Alertmanagers.
|
||||
static_configs:
|
||||
[ - <static_config> ... ]
|
||||
|
|
|
@ -103,6 +103,12 @@ for each of the given times in UTC. Returned values are from 1 to 31.
|
|||
each of the given times in UTC. Returned values are from 0 to 6, where 0 means
|
||||
Sunday etc.
|
||||
|
||||
## `day_of_year()`
|
||||
|
||||
`day_of_year(v=vector(time()) instant-vector)` returns the day of the year for
|
||||
each of the given times in UTC. Returned values are from 1 to 365 for non-leap years,
|
||||
and 1 to 366 in leap years.
|
||||
|
||||
## `days_in_month()`
|
||||
|
||||
`days_in_month(v=vector(time()) instant-vector)` returns number of days in the
|
||||
|
@ -405,8 +411,6 @@ expression is to be evaluated.
|
|||
`timestamp(v instant-vector)` returns the timestamp of each of the samples of
|
||||
the given vector as the number of seconds since January 1, 1970 UTC.
|
||||
|
||||
*This function was added in Prometheus 2.0*
|
||||
|
||||
## `vector()`
|
||||
|
||||
`vector(s scalar)` returns the scalar `s` as a vector with no labels.
|
||||
|
|
20
documentation/examples/Makefile
Normal file
20
documentation/examples/Makefile
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Copyright 2022 The Prometheus 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.
|
||||
|
||||
.PHONY: all
|
||||
all: check-examples-syntax
|
||||
|
||||
.PHONY: check-examples-syntax
|
||||
check-examples-syntax: prometheus-*.yml
|
||||
@echo ">> check example configurations syntax"
|
||||
@set -e; for file in $^; do ../../promtool check config --syntax-only $$file; done
|
|
@ -155,6 +155,7 @@ func (a *Adapter) runCustomSD(ctx context.Context) {
|
|||
|
||||
// Run starts a Discovery Manager and the custom service discovery implementation.
|
||||
func (a *Adapter) Run() {
|
||||
//nolint:errcheck
|
||||
go a.manager.Run()
|
||||
a.manager.StartCustomProvider(a.ctx, a.name, a.disc)
|
||||
go a.runCustomSD(a.ctx)
|
||||
|
|
|
@ -13,7 +13,7 @@ scrape_configs:
|
|||
hetzner_sd_configs:
|
||||
- authorization:
|
||||
credentials: "<replace with a Hetzner Cloud API Token>"
|
||||
platform: "hcloud"
|
||||
role: "hcloud"
|
||||
relabel_configs:
|
||||
# Use the public IPv4 and port 9100 to scrape the target.
|
||||
- source_labels: [__meta_hetzner_public_ipv4]
|
||||
|
@ -26,7 +26,7 @@ scrape_configs:
|
|||
hetzner_sd_configs:
|
||||
- authorization:
|
||||
credentials: "<replace with a Hetzner Cloud API Token>"
|
||||
platform: "hcloud"
|
||||
role: "hcloud"
|
||||
relabel_configs:
|
||||
# Use the private IPv4 within the Hetzner Cloud Network and port 9100 to scrape the target.
|
||||
- source_labels: [__meta_hetzner_hcloud_private_ipv4_mynet]
|
||||
|
@ -40,7 +40,7 @@ scrape_configs:
|
|||
- basic_auth:
|
||||
username: "<replace with a Hetzner Robot API username>"
|
||||
password: "<replace with a Hetzner Robot API password>"
|
||||
platform: "robot"
|
||||
role: "robot"
|
||||
relabel_configs:
|
||||
# Use the public IPv4 and port 9100 to scrape the target.
|
||||
- source_labels: [__meta_hetzner_public_ipv4]
|
||||
|
|
30
documentation/examples/prometheus-ionos.yml
Normal file
30
documentation/examples/prometheus-ionos.yml
Normal file
|
@ -0,0 +1,30 @@
|
|||
# A example scrape configuration for running Prometheus with IONOS Cloud.
|
||||
scrape_configs:
|
||||
- job_name: "node"
|
||||
ionos_sd_configs:
|
||||
- basic_auth:
|
||||
# Replace with your username.
|
||||
username: username
|
||||
# Replace with your password.
|
||||
password: password
|
||||
# You can find your data center unique ID here: https://dcd.ionos.com/latest/
|
||||
datacenter_id: 11111111-1111-1111-1111-111111111111
|
||||
port: 9100
|
||||
relabel_configs:
|
||||
# Only scrape servers that are available via API.
|
||||
- source_labels: [__meta_ionos_server_lifecycle]
|
||||
action: keep
|
||||
regex: "AVAILABLE"
|
||||
|
||||
# Only scrape servers that are in a running state.
|
||||
- source_labels: [__meta_ionos_server_state]
|
||||
action: keep
|
||||
regex: "RUNNING"
|
||||
|
||||
# Replace instance label with server name.
|
||||
- source_labels: [__meta_ionos_server_name]
|
||||
target_label: instance
|
||||
|
||||
# Add server availability zone as label.
|
||||
- source_labels: [__meta_ionos_availability_zone]
|
||||
target_label: ionos_zone
|
|
@ -11,7 +11,7 @@ scrape_configs:
|
|||
- job_name: "node"
|
||||
linode_sd_configs:
|
||||
- authorization:
|
||||
credentials: "<replace with a Personal Access Token with linodes:read_only, ips:read_only, and events:read_only access>"
|
||||
credentials: "<replace with a Personal Access Token with linodes:read_only, ips:read_only, and events:read_only access>"
|
||||
relabel_configs:
|
||||
# Only scrape targets that have a tag 'monitoring'.
|
||||
- source_labels: [__meta_linode_tags]
|
||||
|
|
24
documentation/examples/prometheus-vultr.yml
Normal file
24
documentation/examples/prometheus-vultr.yml
Normal file
|
@ -0,0 +1,24 @@
|
|||
# An example scrape configuration for running Prometheus with
|
||||
# Vultr.
|
||||
|
||||
scrape_configs:
|
||||
# Make Prometheus scrape itself for metrics.
|
||||
- job_name: "prometheus"
|
||||
static_configs:
|
||||
- targets: ["localhost:9090"]
|
||||
|
||||
# Discover Node Exporter instances to scrape.
|
||||
- job_name: "node"
|
||||
vultr_sd_configs:
|
||||
- authorization:
|
||||
credentials: "<replace with a Personal Access Token>"
|
||||
relabel_configs:
|
||||
# Only scrape targets that have a tag 'monitoring'.
|
||||
- source_labels: [__meta_vultr_instance_tags]
|
||||
regex: ".*,monitoring,.*"
|
||||
action: keep
|
||||
|
||||
# Use the public IPv6 address and port 9100 to scrape the target.
|
||||
- source_labels: [__meta_vultr_instance_main_ipv6]
|
||||
target_label: __address__
|
||||
replacement: "[$1]:9100"
|
|
@ -3,15 +3,14 @@ module github.com/prometheus/prometheus/documentation/examples/remote_storage
|
|||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/go-kit/log v0.2.0
|
||||
github.com/go-kit/log v0.2.1
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/snappy v0.0.4
|
||||
github.com/influxdata/influxdb v1.9.5
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.12.1
|
||||
github.com/prometheus/common v0.32.1
|
||||
github.com/prometheus/client_golang v1.12.2
|
||||
github.com/prometheus/common v0.34.0
|
||||
github.com/prometheus/prometheus v1.8.2-0.20220202104425-d819219dd438
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/stretchr/testify v1.7.2
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||
)
|
||||
|
||||
|
@ -30,6 +29,7 @@ require (
|
|||
github.com/jpillora/backoff v1.0.0 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common/sigv4 v0.1.0 // indirect
|
||||
|
@ -41,13 +41,13 @@ require (
|
|||
go.opentelemetry.io/otel/trace v1.2.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/goleak v1.1.12 // indirect
|
||||
golang.org/x/net v0.0.0-20220105145211-5b0dc2dfae98 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
|
@ -458,8 +458,9 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
|||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw=
|
||||
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
||||
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
|
@ -1104,8 +1105,9 @@ github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3O
|
|||
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=
|
||||
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
|
@ -1126,8 +1128,9 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8
|
|||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.34.0 h1:RBmGO9d/FVjqHT0yUGQwBJhkwKV+wPCn7KGpvfab0uE=
|
||||
github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE=
|
||||
github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4=
|
||||
github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI=
|
||||
github.com/prometheus/exporter-toolkit v0.6.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g=
|
||||
|
@ -1228,8 +1231,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
|||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
|
@ -1502,8 +1506,10 @@ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220105145211-5b0dc2dfae98 h1:+6WJMRLHlD7X7frgp7TUZ36RnQzSf9wVVTNakEp+nqY=
|
||||
golang.org/x/net v0.0.0-20220105145211-5b0dc2dfae98/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -1519,8 +1525,9 @@ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ
|
|||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -1653,8 +1660,9 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8
|
|||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -1975,8 +1983,9 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||
|
|
|
@ -15,6 +15,7 @@ package influxdb
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
|
@ -23,7 +24,6 @@ import (
|
|||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
influx "github.com/influxdata/influxdb/client/v2"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
|
@ -174,7 +174,7 @@ func (c *Client) buildCommand(q *prompb.Query) (string, error) {
|
|||
case prompb.LabelMatcher_NRE:
|
||||
matchers = append(matchers, fmt.Sprintf("%q !~ /^%s$/", m.Name, escapeSlashes(m.Value)))
|
||||
default:
|
||||
return "", errors.Errorf("unknown match type %v", m.Type)
|
||||
return "", fmt.Errorf("unknown match type %v", m.Type)
|
||||
}
|
||||
}
|
||||
matchers = append(matchers, fmt.Sprintf("time >= %vms", q.StartTimestampMs))
|
||||
|
@ -253,27 +253,27 @@ func valuesToSamples(values [][]interface{}) ([]prompb.Sample, error) {
|
|||
samples := make([]prompb.Sample, 0, len(values))
|
||||
for _, v := range values {
|
||||
if len(v) != 2 {
|
||||
return nil, errors.Errorf("bad sample tuple length, expected [<timestamp>, <value>], got %v", v)
|
||||
return nil, fmt.Errorf("bad sample tuple length, expected [<timestamp>, <value>], got %v", v)
|
||||
}
|
||||
|
||||
jsonTimestamp, ok := v[0].(json.Number)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("bad timestamp: %v", v[0])
|
||||
return nil, fmt.Errorf("bad timestamp: %v", v[0])
|
||||
}
|
||||
|
||||
jsonValue, ok := v[1].(json.Number)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("bad sample value: %v", v[1])
|
||||
return nil, fmt.Errorf("bad sample value: %v", v[1])
|
||||
}
|
||||
|
||||
timestamp, err := jsonTimestamp.Int64()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to convert sample timestamp to int64")
|
||||
return nil, fmt.Errorf("unable to convert sample timestamp to int64: %w", err)
|
||||
}
|
||||
|
||||
value, err := jsonValue.Float64()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to convert sample value to float64")
|
||||
return nil, fmt.Errorf("unable to convert sample value to float64: %w", err)
|
||||
}
|
||||
|
||||
samples = append(samples, prompb.Sample{
|
||||
|
|
|
@ -30,7 +30,6 @@ import (
|
|||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/golang/snappy"
|
||||
influx "github.com/influxdata/influxdb/client/v2"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/prometheus/common/model"
|
||||
|
@ -148,7 +147,7 @@ func parseFlags() *config {
|
|||
|
||||
_, err := a.Parse(os.Args[1:])
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, errors.Wrapf(err, "Error parsing commandline arguments"))
|
||||
fmt.Fprintln(os.Stderr, fmt.Errorf("Error parsing commandline arguments: %w", err))
|
||||
a.Usage(os.Args[1:])
|
||||
os.Exit(2)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
|
@ -25,7 +26,6 @@ import (
|
|||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
|
@ -136,7 +136,7 @@ func (c *Client) Write(samples model.Samples) error {
|
|||
if err := json.Unmarshal(buf, &r); err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.Errorf("failed to write %d samples to OpenTSDB, %d succeeded", r["failed"], r["success"])
|
||||
return fmt.Errorf("failed to write %d samples to OpenTSDB, %d succeeded", r["failed"], r["success"])
|
||||
}
|
||||
|
||||
// Name identifies the client as an OpenTSDB client.
|
||||
|
|
|
@ -17,7 +17,6 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
|
@ -98,13 +97,13 @@ func (tv *TagValue) UnmarshalJSON(json []byte) error {
|
|||
for i, b := range json {
|
||||
if i == 0 {
|
||||
if b != '"' {
|
||||
return errors.Errorf("expected '\"', got %q", b)
|
||||
return fmt.Errorf("expected '\"', got %q", b)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if i == len(json)-1 {
|
||||
if b != '"' {
|
||||
return errors.Errorf("expected '\"', got %q", b)
|
||||
return fmt.Errorf("expected '\"', got %q", b)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
@ -130,7 +129,7 @@ func (tv *TagValue) UnmarshalJSON(json []byte) error {
|
|||
parsedByte = (b - 55) << 4
|
||||
escapeLevel = 2
|
||||
default:
|
||||
return errors.Errorf(
|
||||
return fmt.Errorf(
|
||||
"illegal escape sequence at byte %d (%c)",
|
||||
i, b,
|
||||
)
|
||||
|
@ -142,7 +141,7 @@ func (tv *TagValue) UnmarshalJSON(json []byte) error {
|
|||
case b >= 'A' && b <= 'F': // A-F
|
||||
parsedByte += b - 55
|
||||
default:
|
||||
return errors.Errorf(
|
||||
return fmt.Errorf(
|
||||
"illegal escape sequence at byte %d (%c)",
|
||||
i, b,
|
||||
)
|
||||
|
|
272
go.mod
272
go.mod
|
@ -1,52 +1,45 @@
|
|||
module github.com/prometheus/prometheus
|
||||
|
||||
go 1.16
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go v63.0.0+incompatible
|
||||
github.com/Azure/go-autorest/autorest v0.11.25
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.18
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
||||
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v65.0.0+incompatible
|
||||
github.com/Azure/go-autorest/autorest v0.11.27
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.20
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137
|
||||
github.com/armon/go-metrics v0.3.3 // indirect
|
||||
github.com/aws/aws-sdk-go v1.43.31
|
||||
github.com/aws/aws-sdk-go v1.44.29
|
||||
github.com/cespare/xxhash/v2 v2.1.2
|
||||
github.com/containerd/containerd v1.6.1 // indirect
|
||||
github.com/dennwc/varint v1.0.0
|
||||
github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245
|
||||
github.com/digitalocean/godo v1.78.0
|
||||
github.com/docker/docker v20.10.14+incompatible
|
||||
github.com/digitalocean/godo v1.80.0
|
||||
github.com/docker/docker v20.10.16+incompatible
|
||||
github.com/edsrzf/mmap-go v1.1.0
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.7
|
||||
github.com/fsnotify/fsnotify v1.5.1
|
||||
github.com/go-kit/log v0.2.0
|
||||
github.com/fsnotify/fsnotify v1.5.4
|
||||
github.com/go-kit/log v0.2.1
|
||||
github.com/go-logfmt/logfmt v0.5.1
|
||||
github.com/go-openapi/strfmt v0.21.2
|
||||
github.com/go-zookeeper/zk v1.0.2
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/snappy v0.0.4
|
||||
github.com/google/pprof v0.0.0-20220318212150-b2ab0324ddda
|
||||
github.com/gophercloud/gophercloud v0.24.0
|
||||
github.com/google/pprof v0.0.0-20220520215854-d04f2422c8a1
|
||||
github.com/gophercloud/gophercloud v0.25.0
|
||||
github.com/grafana/regexp v0.0.0-20220304095617-2e8d9baf4ac2
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
||||
github.com/hashicorp/consul/api v1.12.0
|
||||
github.com/hashicorp/go-hclog v0.12.2 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.2.0 // indirect
|
||||
github.com/hetznercloud/hcloud-go v1.33.1
|
||||
github.com/hashicorp/consul/api v1.13.0
|
||||
github.com/hetznercloud/hcloud-go v1.33.2
|
||||
github.com/ionos-cloud/sdk-go/v6 v6.0.5851
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b
|
||||
github.com/linode/linodego v1.4.1
|
||||
github.com/miekg/dns v1.1.48
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||
github.com/linode/linodego v1.6.0
|
||||
github.com/miekg/dns v1.1.49
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f
|
||||
github.com/oklog/run v1.1.0
|
||||
github.com/oklog/ulid v1.3.1
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/alertmanager v0.24.0
|
||||
github.com/prometheus/client_golang v1.12.1
|
||||
github.com/prometheus/client_golang v1.12.2
|
||||
github.com/prometheus/client_model v0.2.0
|
||||
github.com/prometheus/common v0.34.0
|
||||
github.com/prometheus/common/assets v0.1.0
|
||||
|
@ -55,34 +48,139 @@ require (
|
|||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749
|
||||
github.com/stretchr/testify v1.7.1
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0
|
||||
github.com/vultr/govultr/v2 v2.17.1
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0
|
||||
go.opentelemetry.io/otel v1.7.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.1
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.1
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.1
|
||||
go.opentelemetry.io/otel/sdk v1.6.1
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.7.0
|
||||
go.opentelemetry.io/otel/sdk v1.7.0
|
||||
go.opentelemetry.io/otel/trace v1.7.0
|
||||
go.uber.org/atomic v1.9.0
|
||||
go.uber.org/automaxprocs v1.5.1
|
||||
go.uber.org/goleak v1.1.12
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d
|
||||
golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65
|
||||
golang.org/x/tools v0.1.10
|
||||
google.golang.org/api v0.77.0
|
||||
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4
|
||||
google.golang.org/grpc v1.46.0
|
||||
google.golang.org/api v0.83.0
|
||||
google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8
|
||||
google.golang.org/grpc v1.47.0
|
||||
google.golang.org/protobuf v1.28.0
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
k8s.io/api v0.23.6
|
||||
k8s.io/apimachinery v0.23.6
|
||||
k8s.io/client-go v0.23.5
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/api v0.24.1
|
||||
k8s.io/apimachinery v0.24.1
|
||||
k8s.io/client-go v0.24.0
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/klog/v2 v2.40.1
|
||||
k8s.io/klog/v2 v2.60.1
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.6.1 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
||||
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/armon/go-metrics v0.3.3 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-kit/kit v0.10.0 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/analysis v0.21.2 // indirect
|
||||
github.com/go-openapi/errors v0.20.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/loads v0.21.1 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
github.com/go-openapi/validate v0.21.0 // indirect
|
||||
github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
|
||||
github.com/golang/glog v1.0.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/uuid v1.2.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.2 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-hclog v0.12.2 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.2.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/serf v0.9.6 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/jpillora/backoff v1.0.0 // indirect
|
||||
github.com/julienschmidt/httprouter v1.3.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||
github.com/onsi/gomega v1.15.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/objx v0.2.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.8.3 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v0.30.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.16.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gotest.tools/v3 v3.0.3 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
|
@ -98,95 +196,3 @@ exclude (
|
|||
github.com/grpc-ecosystem/grpc-gateway v1.14.7
|
||||
google.golang.org/api v0.30.0
|
||||
)
|
||||
|
||||
// Exclude pre-go-mod kubernetes tags, as they are older
|
||||
// than v0.x releases but are picked when we update the dependencies.
|
||||
exclude (
|
||||
k8s.io/client-go v1.4.0
|
||||
k8s.io/client-go v1.4.0+incompatible
|
||||
k8s.io/client-go v1.5.0
|
||||
k8s.io/client-go v1.5.0+incompatible
|
||||
k8s.io/client-go v1.5.1
|
||||
k8s.io/client-go v1.5.1+incompatible
|
||||
k8s.io/client-go v10.0.0+incompatible
|
||||
k8s.io/client-go v11.0.0+incompatible
|
||||
k8s.io/client-go v2.0.0+incompatible
|
||||
k8s.io/client-go v2.0.0-alpha.1+incompatible
|
||||
k8s.io/client-go v3.0.0+incompatible
|
||||
k8s.io/client-go v3.0.0-beta.0+incompatible
|
||||
k8s.io/client-go v4.0.0+incompatible
|
||||
k8s.io/client-go v4.0.0-beta.0+incompatible
|
||||
k8s.io/client-go v5.0.0+incompatible
|
||||
k8s.io/client-go v5.0.1+incompatible
|
||||
k8s.io/client-go v6.0.0+incompatible
|
||||
k8s.io/client-go v7.0.0+incompatible
|
||||
k8s.io/client-go v8.0.0+incompatible
|
||||
k8s.io/client-go v9.0.0+incompatible
|
||||
k8s.io/client-go v9.0.0-invalid+incompatible
|
||||
)
|
||||
|
||||
retract (
|
||||
v2.5.0+incompatible
|
||||
v2.5.0-rc.2+incompatible
|
||||
v2.5.0-rc.1+incompatible
|
||||
v2.5.0-rc.0+incompatible
|
||||
v2.4.3+incompatible
|
||||
v2.4.2+incompatible
|
||||
v2.4.1+incompatible
|
||||
v2.4.0+incompatible
|
||||
v2.4.0-rc.0+incompatible
|
||||
v2.3.2+incompatible
|
||||
v2.3.1+incompatible
|
||||
v2.3.0+incompatible
|
||||
v2.2.1+incompatible
|
||||
v2.2.0+incompatible
|
||||
v2.2.0-rc.1+incompatible
|
||||
v2.2.0-rc.0+incompatible
|
||||
v2.1.0+incompatible
|
||||
v2.0.0+incompatible
|
||||
v2.0.0-rc.3+incompatible
|
||||
v2.0.0-rc.2+incompatible
|
||||
v2.0.0-rc.1+incompatible
|
||||
v2.0.0-rc.0+incompatible
|
||||
v2.0.0-beta.5+incompatible
|
||||
v2.0.0-beta.4+incompatible
|
||||
v2.0.0-beta.3+incompatible
|
||||
v2.0.0-beta.2+incompatible
|
||||
v2.0.0-beta.1+incompatible
|
||||
v2.0.0-beta.0+incompatible
|
||||
v2.0.0-alpha.3+incompatible
|
||||
v2.0.0-alpha.2+incompatible
|
||||
v2.0.0-alpha.1+incompatible
|
||||
v2.0.0-alpha.0+incompatible
|
||||
v1.8.2
|
||||
v1.8.1
|
||||
v1.8.0
|
||||
v1.7.2
|
||||
v1.7.1
|
||||
v1.7.0
|
||||
v1.6.3
|
||||
v1.6.2
|
||||
v1.6.1
|
||||
v1.6.0
|
||||
v1.5.3
|
||||
v1.5.2
|
||||
v1.5.1
|
||||
v1.5.0
|
||||
v1.4.1
|
||||
v1.4.0
|
||||
v1.3.1
|
||||
v1.3.0
|
||||
v1.3.0-beta.0
|
||||
v1.2.3
|
||||
v1.2.2
|
||||
v1.2.1
|
||||
v1.2.0
|
||||
v1.1.3
|
||||
v1.1.2
|
||||
v1.1.1
|
||||
v1.1.0
|
||||
v1.0.2
|
||||
v1.0.1
|
||||
v1.0.0
|
||||
v1.0.0-rc.0
|
||||
)
|
||||
|
|
|
@ -119,7 +119,7 @@ func (ls *Labels) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
func (ls Labels) MatchLabels(on bool, names ...string) Labels {
|
||||
matchedLabels := Labels{}
|
||||
|
||||
nameSet := map[string]struct{}{}
|
||||
nameSet := make(map[string]struct{}, len(names))
|
||||
for _, n := range names {
|
||||
nameSet[n] = struct{}{}
|
||||
}
|
||||
|
@ -202,11 +202,11 @@ func (ls Labels) HashWithoutLabels(b []byte, names ...string) (uint64, []byte) {
|
|||
return xxhash.Sum64(b), b
|
||||
}
|
||||
|
||||
// WithLabels returns a new labels.Labels from ls that only contains labels matching names.
|
||||
// BytesWithLabels is just as Bytes(), but only for labels matching names.
|
||||
// 'names' have to be sorted in ascending order.
|
||||
func (ls Labels) WithLabels(names ...string) Labels {
|
||||
ret := make([]Label, 0, len(ls))
|
||||
|
||||
func (ls Labels) BytesWithLabels(buf []byte, names ...string) []byte {
|
||||
b := bytes.NewBuffer(buf[:0])
|
||||
b.WriteByte(labelSep)
|
||||
i, j := 0, 0
|
||||
for i < len(ls) && j < len(names) {
|
||||
if names[j] < ls[i].Name {
|
||||
|
@ -214,30 +214,40 @@ func (ls Labels) WithLabels(names ...string) Labels {
|
|||
} else if ls[i].Name < names[j] {
|
||||
i++
|
||||
} else {
|
||||
ret = append(ret, ls[i])
|
||||
if b.Len() > 1 {
|
||||
b.WriteByte(seps[0])
|
||||
}
|
||||
b.WriteString(ls[i].Name)
|
||||
b.WriteByte(seps[0])
|
||||
b.WriteString(ls[i].Value)
|
||||
i++
|
||||
j++
|
||||
}
|
||||
}
|
||||
return ret
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
// WithoutLabels returns a new labels.Labels from ls that contains labels not matching names.
|
||||
// BytesWithoutLabels is just as Bytes(), but only for labels not matching names.
|
||||
// 'names' have to be sorted in ascending order.
|
||||
func (ls Labels) WithoutLabels(names ...string) Labels {
|
||||
ret := make([]Label, 0, len(ls))
|
||||
|
||||
func (ls Labels) BytesWithoutLabels(buf []byte, names ...string) []byte {
|
||||
b := bytes.NewBuffer(buf[:0])
|
||||
b.WriteByte(labelSep)
|
||||
j := 0
|
||||
for i := range ls {
|
||||
for j < len(names) && names[j] < ls[i].Name {
|
||||
j++
|
||||
}
|
||||
if ls[i].Name == MetricName || (j < len(names) && ls[i].Name == names[j]) {
|
||||
if j < len(names) && ls[i].Name == names[j] {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, ls[i])
|
||||
if b.Len() > 1 {
|
||||
b.WriteByte(seps[0])
|
||||
}
|
||||
b.WriteString(ls[i].Name)
|
||||
b.WriteByte(seps[0])
|
||||
b.WriteString(ls[i].Value)
|
||||
}
|
||||
return ret
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
// Copy returns a copy of the labels.
|
||||
|
@ -349,7 +359,7 @@ func FromStrings(ss ...string) Labels {
|
|||
if len(ss)%2 != 0 {
|
||||
panic("invalid number of strings")
|
||||
}
|
||||
var res Labels
|
||||
res := make(Labels, 0, len(ss)/2)
|
||||
for i := 0; i < len(ss); i += 2 {
|
||||
res = append(res, Label{Name: ss[i], Value: ss[i+1]})
|
||||
}
|
||||
|
@ -426,6 +436,20 @@ func (b *Builder) Del(ns ...string) *Builder {
|
|||
return b
|
||||
}
|
||||
|
||||
// Keep removes all labels from the base except those with the given names.
|
||||
func (b *Builder) Keep(ns ...string) *Builder {
|
||||
Outer:
|
||||
for _, l := range b.base {
|
||||
for _, n := range ns {
|
||||
if l.Name == n {
|
||||
continue Outer
|
||||
}
|
||||
}
|
||||
b.del = append(b.del, l.Name)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Set the name/value pair as a label.
|
||||
func (b *Builder) Set(n, v string) *Builder {
|
||||
if v == "" {
|
||||
|
@ -467,8 +491,9 @@ Outer:
|
|||
}
|
||||
res = append(res, l)
|
||||
}
|
||||
res = append(res, b.add...)
|
||||
sort.Sort(res)
|
||||
|
||||
if len(b.add) > 0 { // Base is already in order, so we only need to sort if we add to it.
|
||||
res = append(res, b.add...)
|
||||
sort.Sort(res)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -624,81 +624,94 @@ func TestLabels_Map(t *testing.T) {
|
|||
require.Equal(t, map[string]string{"aaa": "111", "bbb": "222"}, Labels{{"aaa", "111"}, {"bbb", "222"}}.Map())
|
||||
}
|
||||
|
||||
func TestLabels_WithLabels(t *testing.T) {
|
||||
require.Equal(t, Labels{{"aaa", "111"}, {"bbb", "222"}}, Labels{{"aaa", "111"}, {"bbb", "222"}, {"ccc", "333"}}.WithLabels("aaa", "bbb"))
|
||||
func TestLabels_BytesWithLabels(t *testing.T) {
|
||||
require.Equal(t, Labels{{"aaa", "111"}, {"bbb", "222"}}.Bytes(nil), Labels{{"aaa", "111"}, {"bbb", "222"}, {"ccc", "333"}}.BytesWithLabels(nil, "aaa", "bbb"))
|
||||
require.Equal(t, Labels{}.Bytes(nil), Labels{{"aaa", "111"}, {"bbb", "222"}, {"ccc", "333"}}.BytesWithLabels(nil))
|
||||
}
|
||||
|
||||
func TestLabels_WithoutLabels(t *testing.T) {
|
||||
require.Equal(t, Labels{{"aaa", "111"}}, Labels{{"aaa", "111"}, {"bbb", "222"}, {"ccc", "333"}}.WithoutLabels("bbb", "ccc"))
|
||||
require.Equal(t, Labels{{"aaa", "111"}}, Labels{{"aaa", "111"}, {"bbb", "222"}, {MetricName, "333"}}.WithoutLabels("bbb"))
|
||||
func TestLabels_BytesWithoutLabels(t *testing.T) {
|
||||
require.Equal(t, Labels{{"aaa", "111"}}.Bytes(nil), Labels{{"aaa", "111"}, {"bbb", "222"}, {"ccc", "333"}}.BytesWithoutLabels(nil, "bbb", "ccc"))
|
||||
require.Equal(t, Labels{{"aaa", "111"}}.Bytes(nil), Labels{{MetricName, "333"}, {"aaa", "111"}, {"bbb", "222"}}.BytesWithoutLabels(nil, MetricName, "bbb"))
|
||||
}
|
||||
|
||||
func TestBulider_NewBulider(t *testing.T) {
|
||||
require.Equal(
|
||||
t,
|
||||
&Builder{
|
||||
base: Labels{{"aaa", "111"}},
|
||||
del: []string{},
|
||||
add: []Label{},
|
||||
func TestBuilder(t *testing.T) {
|
||||
for i, tcase := range []struct {
|
||||
base Labels
|
||||
del []string
|
||||
keep []string
|
||||
set []Label
|
||||
want Labels
|
||||
}{
|
||||
{
|
||||
base: FromStrings("aaa", "111"),
|
||||
want: FromStrings("aaa", "111"),
|
||||
},
|
||||
NewBuilder(Labels{{"aaa", "111"}}),
|
||||
)
|
||||
}
|
||||
|
||||
func TestBuilder_Del(t *testing.T) {
|
||||
require.Equal(
|
||||
t,
|
||||
&Builder{
|
||||
del: []string{"bbb"},
|
||||
add: []Label{{"aaa", "111"}, {"ccc", "333"}},
|
||||
},
|
||||
(&Builder{
|
||||
del: []string{},
|
||||
add: []Label{{"aaa", "111"}, {"bbb", "222"}, {"ccc", "333"}},
|
||||
}).Del("bbb"),
|
||||
)
|
||||
}
|
||||
|
||||
func TestBuilder_Set(t *testing.T) {
|
||||
require.Equal(
|
||||
t,
|
||||
&Builder{
|
||||
base: Labels{{"aaa", "111"}},
|
||||
del: []string{},
|
||||
add: []Label{{"bbb", "222"}},
|
||||
},
|
||||
(&Builder{
|
||||
base: Labels{{"aaa", "111"}},
|
||||
del: []string{},
|
||||
add: []Label{},
|
||||
}).Set("bbb", "222"),
|
||||
)
|
||||
|
||||
require.Equal(
|
||||
t,
|
||||
&Builder{
|
||||
base: Labels{{"aaa", "111"}},
|
||||
del: []string{},
|
||||
add: []Label{{"bbb", "333"}},
|
||||
},
|
||||
(&Builder{
|
||||
base: Labels{{"aaa", "111"}},
|
||||
del: []string{},
|
||||
add: []Label{{"bbb", "222"}},
|
||||
}).Set("bbb", "333"),
|
||||
)
|
||||
}
|
||||
|
||||
func TestBuilder_Labels(t *testing.T) {
|
||||
require.Equal(
|
||||
t,
|
||||
Labels{{"aaa", "111"}, {"ccc", "333"}, {"ddd", "444"}},
|
||||
(&Builder{
|
||||
base: Labels{{"aaa", "111"}, {"bbb", "222"}, {"ccc", "333"}},
|
||||
{
|
||||
base: FromStrings("aaa", "111", "bbb", "222", "ccc", "333"),
|
||||
del: []string{"bbb"},
|
||||
add: []Label{{"ddd", "444"}},
|
||||
}).Labels(),
|
||||
)
|
||||
want: FromStrings("aaa", "111", "ccc", "333"),
|
||||
},
|
||||
{
|
||||
base: nil,
|
||||
set: []Label{{"aaa", "111"}, {"bbb", "222"}, {"ccc", "333"}},
|
||||
del: []string{"bbb"},
|
||||
want: FromStrings("aaa", "111", "ccc", "333"),
|
||||
},
|
||||
{
|
||||
base: FromStrings("aaa", "111"),
|
||||
set: []Label{{"bbb", "222"}},
|
||||
want: FromStrings("aaa", "111", "bbb", "222"),
|
||||
},
|
||||
{
|
||||
base: FromStrings("aaa", "111"),
|
||||
set: []Label{{"bbb", "222"}, {"bbb", "333"}},
|
||||
want: FromStrings("aaa", "111", "bbb", "333"),
|
||||
},
|
||||
{
|
||||
base: FromStrings("aaa", "111", "bbb", "222", "ccc", "333"),
|
||||
del: []string{"bbb"},
|
||||
set: []Label{{"ddd", "444"}},
|
||||
want: FromStrings("aaa", "111", "ccc", "333", "ddd", "444"),
|
||||
},
|
||||
{ // Blank value is interpreted as delete.
|
||||
base: FromStrings("aaa", "111", "bbb", "", "ccc", "333"),
|
||||
want: FromStrings("aaa", "111", "ccc", "333"),
|
||||
},
|
||||
{
|
||||
base: FromStrings("aaa", "111", "bbb", "222", "ccc", "333"),
|
||||
set: []Label{{"bbb", ""}},
|
||||
want: FromStrings("aaa", "111", "ccc", "333"),
|
||||
},
|
||||
{
|
||||
base: FromStrings("aaa", "111", "bbb", "222", "ccc", "333"),
|
||||
keep: []string{"bbb"},
|
||||
want: FromStrings("bbb", "222"),
|
||||
},
|
||||
{
|
||||
base: FromStrings("aaa", "111", "bbb", "222", "ccc", "333"),
|
||||
keep: []string{"aaa", "ccc"},
|
||||
want: FromStrings("aaa", "111", "ccc", "333"),
|
||||
},
|
||||
{
|
||||
base: FromStrings("aaa", "111", "bbb", "222", "ccc", "333"),
|
||||
del: []string{"bbb"},
|
||||
set: []Label{{"ddd", "444"}},
|
||||
keep: []string{"aaa", "ddd"},
|
||||
want: FromStrings("aaa", "111", "ddd", "444"),
|
||||
},
|
||||
} {
|
||||
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||
b := NewBuilder(tcase.base)
|
||||
for _, lbl := range tcase.set {
|
||||
b.Set(lbl.Name, lbl.Value)
|
||||
}
|
||||
if len(tcase.keep) > 0 {
|
||||
b.Keep(tcase.keep...)
|
||||
}
|
||||
b.Del(tcase.del...)
|
||||
require.Equal(t, tcase.want, b.Labels())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabels_Hash(t *testing.T) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
- github.com/prometheus/prometheus/discovery/eureka
|
||||
- github.com/prometheus/prometheus/discovery/gce
|
||||
- github.com/prometheus/prometheus/discovery/hetzner
|
||||
- github.com/prometheus/prometheus/discovery/ionos
|
||||
- github.com/prometheus/prometheus/discovery/kubernetes
|
||||
- github.com/prometheus/prometheus/discovery/linode
|
||||
- github.com/prometheus/prometheus/discovery/marathon
|
||||
|
|
|
@ -40,6 +40,9 @@ import (
|
|||
// Register hetzner plugin.
|
||||
_ "github.com/prometheus/prometheus/discovery/hetzner"
|
||||
|
||||
// Register ionos plugin.
|
||||
_ "github.com/prometheus/prometheus/discovery/ionos"
|
||||
|
||||
// Register kubernetes plugin.
|
||||
_ "github.com/prometheus/prometheus/discovery/kubernetes"
|
||||
|
||||
|
@ -67,6 +70,9 @@ import (
|
|||
// Register uyuni plugin.
|
||||
_ "github.com/prometheus/prometheus/discovery/uyuni"
|
||||
|
||||
// Register vultr plugin.
|
||||
_ "github.com/prometheus/prometheus/discovery/vultr"
|
||||
|
||||
// Register xds plugin.
|
||||
_ "github.com/prometheus/prometheus/discovery/xds"
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"bytes"
|
||||
"container/heap"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
|
@ -29,7 +30,6 @@ import (
|
|||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/grafana/regexp"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/model"
|
||||
"go.opentelemetry.io/otel"
|
||||
|
@ -209,10 +209,10 @@ func contextDone(ctx context.Context, env string) error {
|
|||
}
|
||||
|
||||
func contextErr(err error, env string) error {
|
||||
switch err {
|
||||
case context.Canceled:
|
||||
switch {
|
||||
case errors.Is(err, context.Canceled):
|
||||
return ErrQueryCanceled(env)
|
||||
case context.DeadlineExceeded:
|
||||
case errors.Is(err, context.DeadlineExceeded):
|
||||
return ErrQueryTimeout(env)
|
||||
default:
|
||||
return err
|
||||
|
@ -417,7 +417,7 @@ func (ng *Engine) NewRangeQuery(q storage.Queryable, opts *QueryOpts, qs string,
|
|||
return nil, err
|
||||
}
|
||||
if expr.Type() != parser.ValueTypeVector && expr.Type() != parser.ValueTypeScalar {
|
||||
return nil, errors.Errorf("invalid expression type %q for range query, must be Scalar or instant Vector", parser.DocumentedType(expr.Type()))
|
||||
return nil, fmt.Errorf("invalid expression type %q for range query, must be Scalar or instant Vector", parser.DocumentedType(expr.Type()))
|
||||
}
|
||||
qry, err := ng.newQuery(q, opts, expr, start, end, interval)
|
||||
if err != nil {
|
||||
|
@ -598,7 +598,7 @@ func (ng *Engine) exec(ctx context.Context, q *query) (v parser.Value, ws storag
|
|||
return nil, nil, s(ctx)
|
||||
}
|
||||
|
||||
panic(errors.Errorf("promql.Engine.exec: unhandled statement of type %T", q.Statement()))
|
||||
panic(fmt.Errorf("promql.Engine.exec: unhandled statement of type %T", q.Statement()))
|
||||
}
|
||||
|
||||
func timeMilliseconds(t time.Time) int64 {
|
||||
|
@ -658,7 +658,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *parser.Eval
|
|||
case String:
|
||||
return result, warnings, nil
|
||||
default:
|
||||
panic(errors.Errorf("promql.Engine.exec: invalid expression type %q", val.Type()))
|
||||
panic(fmt.Errorf("promql.Engine.exec: invalid expression type %q", val.Type()))
|
||||
}
|
||||
|
||||
query.matrix = mat
|
||||
|
@ -677,7 +677,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *parser.Eval
|
|||
case parser.ValueTypeMatrix:
|
||||
return mat, warnings, nil
|
||||
default:
|
||||
panic(errors.Errorf("promql.Engine.exec: unexpected expression type %q", s.Expr.Type()))
|
||||
panic(fmt.Errorf("promql.Engine.exec: unexpected expression type %q", s.Expr.Type()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -702,7 +702,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *parser.Eval
|
|||
|
||||
mat, ok := val.(Matrix)
|
||||
if !ok {
|
||||
panic(errors.Errorf("promql.Engine.exec: invalid expression type %q", val.Type()))
|
||||
panic(fmt.Errorf("promql.Engine.exec: invalid expression type %q", val.Type()))
|
||||
}
|
||||
query.matrix = mat
|
||||
|
||||
|
@ -929,7 +929,7 @@ type evaluator struct {
|
|||
|
||||
// errorf causes a panic with the input formatted into an error.
|
||||
func (ev *evaluator) errorf(format string, args ...interface{}) {
|
||||
ev.error(errors.Errorf(format, args...))
|
||||
ev.error(fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
// error causes a panic with the given error.
|
||||
|
@ -951,7 +951,7 @@ func (ev *evaluator) recover(ws *storage.Warnings, errp *error) {
|
|||
buf = buf[:runtime.Stack(buf, false)]
|
||||
|
||||
level.Error(ev.logger).Log("msg", "runtime panic in parser", "err", e, "stacktrace", string(buf))
|
||||
*errp = errors.Wrap(err, "unexpected error")
|
||||
*errp = fmt.Errorf("unexpected error: %w", err)
|
||||
case errWithWarnings:
|
||||
*errp = err.err
|
||||
*ws = append(*ws, err.warnings...)
|
||||
|
@ -1347,7 +1347,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
|
|||
ws, err := checkAndExpandSeriesSet(ev.ctx, sel)
|
||||
warnings = append(warnings, ws...)
|
||||
if err != nil {
|
||||
ev.error(errWithWarnings{errors.Wrap(err, "expanding series"), warnings})
|
||||
ev.error(errWithWarnings{fmt.Errorf("expanding series: %w", err), warnings})
|
||||
}
|
||||
mat := make(Matrix, 0, len(selVS.Series)) // Output matrix.
|
||||
offset := durationMilliseconds(selVS.Offset)
|
||||
|
@ -1544,7 +1544,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
|
|||
case *parser.VectorSelector:
|
||||
ws, err := checkAndExpandSeriesSet(ev.ctx, e)
|
||||
if err != nil {
|
||||
ev.error(errWithWarnings{errors.Wrap(err, "expanding series"), ws})
|
||||
ev.error(errWithWarnings{fmt.Errorf("expanding series: %w", err), ws})
|
||||
}
|
||||
mat := make(Matrix, 0, len(e.Series))
|
||||
it := storage.NewMemoizedEmptyIterator(durationMilliseconds(ev.lookbackDelta))
|
||||
|
@ -1660,11 +1660,11 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
|
|||
// with changed timestamps.
|
||||
mat, ok := res.(Matrix)
|
||||
if !ok {
|
||||
panic(errors.Errorf("unexpected result in StepInvariantExpr evaluation: %T", expr))
|
||||
panic(fmt.Errorf("unexpected result in StepInvariantExpr evaluation: %T", expr))
|
||||
}
|
||||
for i := range mat {
|
||||
if len(mat[i].Points) != 1 {
|
||||
panic(errors.Errorf("unexpected number of samples"))
|
||||
panic(fmt.Errorf("unexpected number of samples"))
|
||||
}
|
||||
for ts := ev.startTimestamp + ev.interval; ts <= ev.endTimestamp; ts = ts + ev.interval {
|
||||
mat[i].Points = append(mat[i].Points, Point{
|
||||
|
@ -1682,14 +1682,14 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
|
|||
return res, ws
|
||||
}
|
||||
|
||||
panic(errors.Errorf("unhandled expression of type: %T", expr))
|
||||
panic(fmt.Errorf("unhandled expression of type: %T", expr))
|
||||
}
|
||||
|
||||
// vectorSelector evaluates a *parser.VectorSelector expression.
|
||||
func (ev *evaluator) vectorSelector(node *parser.VectorSelector, ts int64) (Vector, storage.Warnings) {
|
||||
ws, err := checkAndExpandSeriesSet(ev.ctx, node)
|
||||
if err != nil {
|
||||
ev.error(errWithWarnings{errors.Wrap(err, "expanding series"), ws})
|
||||
ev.error(errWithWarnings{fmt.Errorf("expanding series: %w", err), ws})
|
||||
}
|
||||
vec := make(Vector, 0, len(node.Series))
|
||||
it := storage.NewMemoizedEmptyIterator(durationMilliseconds(ev.lookbackDelta))
|
||||
|
@ -1779,7 +1779,7 @@ func (ev *evaluator) matrixSelector(node *parser.MatrixSelector) (Matrix, storag
|
|||
)
|
||||
ws, err := checkAndExpandSeriesSet(ev.ctx, node)
|
||||
if err != nil {
|
||||
ev.error(errWithWarnings{errors.Wrap(err, "expanding series"), ws})
|
||||
ev.error(errWithWarnings{fmt.Errorf("expanding series: %w", err), ws})
|
||||
}
|
||||
|
||||
series := vs.Series
|
||||
|
@ -2094,14 +2094,16 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *
|
|||
}
|
||||
|
||||
func signatureFunc(on bool, b []byte, names ...string) func(labels.Labels) string {
|
||||
sort.Strings(names)
|
||||
if on {
|
||||
sort.Strings(names)
|
||||
return func(lset labels.Labels) string {
|
||||
return string(lset.WithLabels(names...).Bytes(b))
|
||||
return string(lset.BytesWithLabels(b, names...))
|
||||
}
|
||||
}
|
||||
names = append([]string{labels.MetricName}, names...)
|
||||
sort.Strings(names)
|
||||
return func(lset labels.Labels) string {
|
||||
return string(lset.WithoutLabels(names...).Bytes(b))
|
||||
return string(lset.BytesWithoutLabels(b, names...))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2136,15 +2138,7 @@ func resultMetric(lhs, rhs labels.Labels, op parser.ItemType, matching *parser.V
|
|||
|
||||
if matching.Card == parser.CardOneToOne {
|
||||
if matching.On {
|
||||
Outer:
|
||||
for _, l := range lhs {
|
||||
for _, n := range matching.MatchingLabels {
|
||||
if l.Name == n {
|
||||
continue Outer
|
||||
}
|
||||
}
|
||||
enh.lb.Del(l.Name)
|
||||
}
|
||||
enh.lb.Keep(matching.MatchingLabels...)
|
||||
} else {
|
||||
enh.lb.Del(matching.MatchingLabels...)
|
||||
}
|
||||
|
@ -2231,7 +2225,7 @@ func scalarBinop(op parser.ItemType, lhs, rhs float64) float64 {
|
|||
case parser.ATAN2:
|
||||
return math.Atan2(lhs, rhs)
|
||||
}
|
||||
panic(errors.Errorf("operator %q not allowed for Scalar operations", op))
|
||||
panic(fmt.Errorf("operator %q not allowed for Scalar operations", op))
|
||||
}
|
||||
|
||||
// vectorElemBinop evaluates a binary operation between two Vector elements.
|
||||
|
@ -2272,7 +2266,7 @@ func vectorElemBinop(op parser.ItemType, lhs, rhs float64, hlhs, hrhs *histogram
|
|||
case parser.ATAN2:
|
||||
return math.Atan2(lhs, rhs), nil, true
|
||||
}
|
||||
panic(errors.Errorf("operator %q not allowed for operations between Vectors", op))
|
||||
panic(fmt.Errorf("operator %q not allowed for operations between Vectors", op))
|
||||
}
|
||||
|
||||
type groupedAggregation struct {
|
||||
|
@ -2350,16 +2344,14 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
|
|||
group, ok := result[groupingKey]
|
||||
// Add a new group if it doesn't exist.
|
||||
if !ok {
|
||||
var m labels.Labels
|
||||
|
||||
lb.Reset(metric)
|
||||
if without {
|
||||
lb.Reset(metric)
|
||||
lb.Del(grouping...)
|
||||
lb.Del(labels.MetricName)
|
||||
m = lb.Labels()
|
||||
} else {
|
||||
m = metric.WithLabels(grouping...)
|
||||
lb.Keep(grouping...)
|
||||
}
|
||||
m := lb.Labels()
|
||||
newAgg := &groupedAggregation{
|
||||
labels: m,
|
||||
value: s.V,
|
||||
|
@ -2511,7 +2503,7 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
|
|||
group.heap = append(group.heap, s)
|
||||
|
||||
default:
|
||||
panic(errors.Errorf("expected aggregation operator but got %q", op))
|
||||
panic(fmt.Errorf("expected aggregation operator but got %q", op))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -684,7 +684,6 @@ load 10s
|
|||
Result: Matrix{
|
||||
Series{
|
||||
Points: []Point{{V: 1, T: 0}, {V: 1, T: 1000}, {V: 1, T: 2000}},
|
||||
Metric: labels.FromStrings(),
|
||||
},
|
||||
},
|
||||
Start: time.Unix(0, 0),
|
||||
|
@ -721,24 +720,26 @@ load 10s
|
|||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var err error
|
||||
var qry Query
|
||||
if c.Interval == 0 {
|
||||
qry, err = test.QueryEngine().NewInstantQuery(test.Queryable(), nil, c.Query, c.Start)
|
||||
} else {
|
||||
qry, err = test.QueryEngine().NewRangeQuery(test.Queryable(), nil, c.Query, c.Start, c.End, c.Interval)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
for i, c := range cases {
|
||||
t.Run(fmt.Sprintf("%d query=%s", i, c.Query), func(t *testing.T) {
|
||||
var err error
|
||||
var qry Query
|
||||
if c.Interval == 0 {
|
||||
qry, err = test.QueryEngine().NewInstantQuery(test.Queryable(), nil, c.Query, c.Start)
|
||||
} else {
|
||||
qry, err = test.QueryEngine().NewRangeQuery(test.Queryable(), nil, c.Query, c.Start, c.End, c.Interval)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
res := qry.Exec(test.Context())
|
||||
if c.ShouldError {
|
||||
require.Error(t, res.Err, "expected error for the query %q", c.Query)
|
||||
continue
|
||||
}
|
||||
res := qry.Exec(test.Context())
|
||||
if c.ShouldError {
|
||||
require.Error(t, res.Err, "expected error for the query %q", c.Query)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, res.Err)
|
||||
require.Equal(t, c.Result, res.Value, "query %q failed", c.Query)
|
||||
require.NoError(t, res.Err)
|
||||
require.Equal(t, c.Result, res.Value, "query %q failed", c.Query)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
package promql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
@ -21,7 +22,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/grafana/regexp"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/prometheus/prometheus/model/histogram"
|
||||
|
@ -300,10 +300,10 @@ func funcHoltWinters(vals []parser.Value, args parser.Expressions, enh *EvalNode
|
|||
|
||||
// Sanity check the input.
|
||||
if sf <= 0 || sf >= 1 {
|
||||
panic(errors.Errorf("invalid smoothing factor. Expected: 0 < sf < 1, got: %f", sf))
|
||||
panic(fmt.Errorf("invalid smoothing factor. Expected: 0 < sf < 1, got: %f", sf))
|
||||
}
|
||||
if tf <= 0 || tf >= 1 {
|
||||
panic(errors.Errorf("invalid trend factor. Expected: 0 < tf < 1, got: %f", tf))
|
||||
panic(fmt.Errorf("invalid trend factor. Expected: 0 < tf < 1, got: %f", tf))
|
||||
}
|
||||
|
||||
l := len(samples.Points)
|
||||
|
@ -868,7 +868,6 @@ func funcPredictLinear(vals []parser.Value, args parser.Expressions, enh *EvalNo
|
|||
func funcHistogramQuantile(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
q := vals[0].(Vector)[0].V
|
||||
inVec := vals[1].(Vector)
|
||||
sigf := signatureFunc(false, enh.lblBuf, labels.BucketLabel)
|
||||
|
||||
if enh.signatureToMetricWithBuckets == nil {
|
||||
enh.signatureToMetricWithBuckets = map[string]*metricWithBuckets{}
|
||||
|
@ -896,21 +895,15 @@ func funcHistogramQuantile(vals []parser.Value, args parser.Expressions, enh *Ev
|
|||
// TODO(beorn7): Issue a warning somehow.
|
||||
continue
|
||||
}
|
||||
|
||||
l := sigf(sample.Metric)
|
||||
// Add the metric name (which is always removed) to the signature to prevent combining multiple histograms
|
||||
// with the same label set. See https://github.com/prometheus/prometheus/issues/9910
|
||||
// TODO(beorn7): What's the performance impact? We might need to implement this more efficiently.
|
||||
l = l + sample.Metric.Get(model.MetricNameLabel)
|
||||
|
||||
mb, ok := enh.signatureToMetricWithBuckets[l]
|
||||
enh.lblBuf = sample.Metric.BytesWithoutLabels(enh.lblBuf, labels.BucketLabel)
|
||||
mb, ok := enh.signatureToMetricWithBuckets[string(enh.lblBuf)]
|
||||
if !ok {
|
||||
sample.Metric = labels.NewBuilder(sample.Metric).
|
||||
Del(excludedLabels...).
|
||||
Labels()
|
||||
|
||||
mb = &metricWithBuckets{sample.Metric, nil}
|
||||
enh.signatureToMetricWithBuckets[l] = mb
|
||||
enh.signatureToMetricWithBuckets[string(enh.lblBuf)] = mb
|
||||
}
|
||||
mb.buckets = append(mb.buckets, bucket{upperBound, sample.V})
|
||||
|
||||
|
@ -920,17 +913,13 @@ func funcHistogramQuantile(vals []parser.Value, args parser.Expressions, enh *Ev
|
|||
for _, sample := range histogramSamples {
|
||||
// We have to reconstruct the exact same signature as above for
|
||||
// a conventional histogram, just ignoring any le label.
|
||||
// TODO(beorn7): This replicates the inefficient implementation
|
||||
// from above and has to be improved under the same
|
||||
// circumstances.
|
||||
l := string(sample.Metric.WithoutLabels().Bytes(enh.lblBuf))
|
||||
l = l + sample.Metric.Get(model.MetricNameLabel)
|
||||
if mb, ok := enh.signatureToMetricWithBuckets[l]; ok && len(mb.buckets) > 0 {
|
||||
enh.lblBuf = sample.Metric.Bytes(enh.lblBuf)
|
||||
if mb, ok := enh.signatureToMetricWithBuckets[string(enh.lblBuf)]; ok && len(mb.buckets) > 0 {
|
||||
// At this data point, we have conventional histogram
|
||||
// buckets and a native histogram with the same name and
|
||||
// labels. Do not evaluate anything.
|
||||
// TODO(beorn7): Issue a warning somehow.
|
||||
delete(enh.signatureToMetricWithBuckets, l)
|
||||
delete(enh.signatureToMetricWithBuckets, string(enh.lblBuf))
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -1004,10 +993,10 @@ func funcLabelReplace(vals []parser.Value, args parser.Expressions, enh *EvalNod
|
|||
var err error
|
||||
enh.regex, err = regexp.Compile("^(?:" + regexStr + ")$")
|
||||
if err != nil {
|
||||
panic(errors.Errorf("invalid regular expression in label_replace(): %s", regexStr))
|
||||
panic(fmt.Errorf("invalid regular expression in label_replace(): %s", regexStr))
|
||||
}
|
||||
if !model.LabelNameRE.MatchString(dst) {
|
||||
panic(errors.Errorf("invalid destination label name in label_replace(): %s", dst))
|
||||
panic(fmt.Errorf("invalid destination label name in label_replace(): %s", dst))
|
||||
}
|
||||
enh.Dmn = make(map[uint64]labels.Labels, len(enh.Out))
|
||||
}
|
||||
|
@ -1069,13 +1058,13 @@ func funcLabelJoin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
|
|||
for i := 3; i < len(args); i++ {
|
||||
src := stringFromArg(args[i])
|
||||
if !model.LabelName(src).IsValid() {
|
||||
panic(errors.Errorf("invalid source label name in label_join(): %s", src))
|
||||
panic(fmt.Errorf("invalid source label name in label_join(): %s", src))
|
||||
}
|
||||
srcLabels[i-3] = src
|
||||
}
|
||||
|
||||
if !model.LabelName(dst).IsValid() {
|
||||
panic(errors.Errorf("invalid destination label name in label_join(): %s", dst))
|
||||
panic(fmt.Errorf("invalid destination label name in label_join(): %s", dst))
|
||||
}
|
||||
|
||||
srcVals := make([]string, len(srcLabels))
|
||||
|
@ -1152,6 +1141,13 @@ func funcDayOfWeek(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
|
|||
})
|
||||
}
|
||||
|
||||
// === day_of_year(v Vector) Scalar ===
|
||||
func funcDayOfYear(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return dateWrapper(vals, enh, func(t time.Time) float64 {
|
||||
return float64(t.YearDay())
|
||||
})
|
||||
}
|
||||
|
||||
// === hour(v Vector) Scalar ===
|
||||
func funcHour(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return dateWrapper(vals, enh, func(t time.Time) float64 {
|
||||
|
@ -1203,6 +1199,7 @@ var FunctionCalls = map[string]FunctionCall{
|
|||
"days_in_month": funcDaysInMonth,
|
||||
"day_of_month": funcDayOfMonth,
|
||||
"day_of_week": funcDayOfWeek,
|
||||
"day_of_year": funcDayOfYear,
|
||||
"deg": funcDeg,
|
||||
"delta": funcDelta,
|
||||
"deriv": funcDeriv,
|
||||
|
@ -1257,7 +1254,7 @@ var FunctionCalls = map[string]FunctionCall{
|
|||
// that can also change with change in eval time.
|
||||
var AtModifierUnsafeFunctions = map[string]struct{}{
|
||||
// Step invariant functions.
|
||||
"days_in_month": {}, "day_of_month": {}, "day_of_week": {},
|
||||
"days_in_month": {}, "day_of_month": {}, "day_of_week": {}, "day_of_year": {},
|
||||
"hour": {}, "minute": {}, "month": {}, "year": {},
|
||||
"predict_linear": {}, "time": {},
|
||||
// Uses timestamp of the argument for the result,
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package promql
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/prometheus/prometheus/model/textparse"
|
||||
|
@ -71,7 +72,7 @@ func fuzzParseMetricWithContentType(in []byte, contentType string) int {
|
|||
break
|
||||
}
|
||||
}
|
||||
if err == io.EOF {
|
||||
if errors.Is(err, io.EOF) {
|
||||
err = nil
|
||||
}
|
||||
|
||||
|
|
|
@ -15,10 +15,9 @@ package parser
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/storage"
|
||||
)
|
||||
|
@ -394,7 +393,7 @@ func Children(node Node) []Node {
|
|||
// nothing to do
|
||||
return []Node{}
|
||||
default:
|
||||
panic(errors.Errorf("promql.Children: unhandled node type %T", node))
|
||||
panic(fmt.Errorf("promql.Children: unhandled node type %T", node))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -132,6 +132,12 @@ var Functions = map[string]*Function{
|
|||
Variadic: 1,
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"day_of_year": {
|
||||
Name: "day_of_year",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
Variadic: 1,
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"deg": {
|
||||
Name: "deg",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
package parser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
|
@ -23,7 +24,6 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
|
@ -224,7 +224,7 @@ func ParseSeriesDesc(input string) (labels labels.Labels, values []SequenceValue
|
|||
|
||||
// addParseErrf formats the error and appends it to the list of parsing errors.
|
||||
func (p *parser) addParseErrf(positionRange PositionRange, format string, args ...interface{}) {
|
||||
p.addParseErr(positionRange, errors.Errorf(format, args...))
|
||||
p.addParseErr(positionRange, fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
// addParseErr appends the provided error to the list of parsing errors.
|
||||
|
@ -801,7 +801,7 @@ func MustLabelMatcher(mt labels.MatchType, name, val string) *labels.Matcher {
|
|||
func MustGetFunction(name string) *Function {
|
||||
f, ok := getFunction(name)
|
||||
if !ok {
|
||||
panic(errors.Errorf("function %q does not exist", name))
|
||||
panic(fmt.Errorf("function %q does not exist", name))
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
package parser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
|
@ -3570,7 +3570,8 @@ func TestParseExpressions(t *testing.T) {
|
|||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), test.errMsg, "unexpected error on input '%s', expected '%s', got '%s'", test.input, test.errMsg, err.Error())
|
||||
|
||||
errorList, ok := err.(ParseErrors)
|
||||
var errorList ParseErrors
|
||||
ok := errors.As(err, &errorList)
|
||||
|
||||
require.True(t, ok, "unexpected error type")
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ package promql
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
|
@ -23,7 +24,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/grafana/regexp"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
|
@ -122,7 +122,7 @@ func (t *Test) ExemplarQueryable() storage.ExemplarQueryable {
|
|||
func raise(line int, format string, v ...interface{}) error {
|
||||
return &parser.ParseErr{
|
||||
LineOffset: line,
|
||||
Err: errors.Errorf(format, v...),
|
||||
Err: fmt.Errorf(format, v...),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,8 @@ func parseLoad(lines []string, i int) (int, *loadCmd, error) {
|
|||
}
|
||||
metric, vals, err := parser.ParseSeriesDesc(defLine)
|
||||
if err != nil {
|
||||
if perr, ok := err.(*parser.ParseErr); ok {
|
||||
var perr *parser.ParseErr
|
||||
if errors.As(err, &perr) {
|
||||
perr.LineOffset = i
|
||||
}
|
||||
return i, nil, err
|
||||
|
@ -168,7 +169,8 @@ func (t *Test) parseEval(lines []string, i int) (int, *evalCmd, error) {
|
|||
)
|
||||
_, err := parser.ParseExpr(expr)
|
||||
if err != nil {
|
||||
if perr, ok := err.(*parser.ParseErr); ok {
|
||||
var perr *parser.ParseErr
|
||||
if errors.As(err, &perr) {
|
||||
perr.LineOffset = i
|
||||
posOffset := parser.Pos(strings.Index(lines[i], expr))
|
||||
perr.PositionRange.Start += posOffset
|
||||
|
@ -205,7 +207,8 @@ func (t *Test) parseEval(lines []string, i int) (int, *evalCmd, error) {
|
|||
}
|
||||
metric, vals, err := parser.ParseSeriesDesc(defLine)
|
||||
if err != nil {
|
||||
if perr, ok := err.(*parser.ParseErr); ok {
|
||||
var perr *parser.ParseErr
|
||||
if errors.As(err, &perr) {
|
||||
perr.LineOffset = i
|
||||
}
|
||||
return i, nil, err
|
||||
|
@ -388,14 +391,14 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
|||
for pos, v := range val {
|
||||
fp := v.Metric.Hash()
|
||||
if _, ok := ev.metrics[fp]; !ok {
|
||||
return errors.Errorf("unexpected metric %s in result", v.Metric)
|
||||
return fmt.Errorf("unexpected metric %s in result", v.Metric)
|
||||
}
|
||||
exp := ev.expected[fp]
|
||||
if ev.ordered && exp.pos != pos+1 {
|
||||
return errors.Errorf("expected metric %s with %v at position %d but was at %d", v.Metric, exp.vals, exp.pos, pos+1)
|
||||
return fmt.Errorf("expected metric %s with %v at position %d but was at %d", v.Metric, exp.vals, exp.pos, pos+1)
|
||||
}
|
||||
if !almostEqual(exp.vals[0].Value, v.V) {
|
||||
return errors.Errorf("expected %v for %s but got %v", exp.vals[0].Value, v.Metric, v.V)
|
||||
return fmt.Errorf("expected %v for %s but got %v", exp.vals[0].Value, v.Metric, v.V)
|
||||
}
|
||||
|
||||
seen[fp] = true
|
||||
|
@ -406,17 +409,17 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
|||
for _, ss := range val {
|
||||
fmt.Println(" ", ss.Metric, ss.Point)
|
||||
}
|
||||
return errors.Errorf("expected metric %s with %v not found", ev.metrics[fp], expVals)
|
||||
return fmt.Errorf("expected metric %s with %v not found", ev.metrics[fp], expVals)
|
||||
}
|
||||
}
|
||||
|
||||
case Scalar:
|
||||
if !almostEqual(ev.expected[0].vals[0].Value, val.V) {
|
||||
return errors.Errorf("expected Scalar %v but got %v", val.V, ev.expected[0].vals[0].Value)
|
||||
return fmt.Errorf("expected Scalar %v but got %v", val.V, ev.expected[0].vals[0].Value)
|
||||
}
|
||||
|
||||
default:
|
||||
panic(errors.Errorf("promql.Test.compareResult: unexpected result type %T", result))
|
||||
panic(fmt.Errorf("promql.Test.compareResult: unexpected result type %T", result))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -543,14 +546,14 @@ func (t *Test) exec(tc testCommand) error {
|
|||
if cmd.fail {
|
||||
continue
|
||||
}
|
||||
return errors.Wrapf(res.Err, "error evaluating query %q (line %d)", iq.expr, cmd.line)
|
||||
return fmt.Errorf("error evaluating query %q (line %d): %w", iq.expr, cmd.line, res.Err)
|
||||
}
|
||||
if res.Err == nil && cmd.fail {
|
||||
return errors.Errorf("expected error evaluating query %q (line %d) but got none", iq.expr, cmd.line)
|
||||
return fmt.Errorf("expected error evaluating query %q (line %d) but got none", iq.expr, cmd.line)
|
||||
}
|
||||
err = cmd.compareResult(res.Value)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error in %s %s", cmd, iq.expr)
|
||||
return fmt.Errorf("error in %s %s: %w", cmd, iq.expr, err)
|
||||
}
|
||||
|
||||
// Check query returns same result in range mode,
|
||||
|
@ -561,7 +564,7 @@ func (t *Test) exec(tc testCommand) error {
|
|||
}
|
||||
rangeRes := q.Exec(t.context)
|
||||
if rangeRes.Err != nil {
|
||||
return errors.Wrapf(rangeRes.Err, "error evaluating query %q (line %d) in range mode", iq.expr, cmd.line)
|
||||
return fmt.Errorf("error evaluating query %q (line %d) in range mode: %w", iq.expr, cmd.line, rangeRes.Err)
|
||||
}
|
||||
defer q.Close()
|
||||
if cmd.ordered {
|
||||
|
@ -584,7 +587,7 @@ func (t *Test) exec(tc testCommand) error {
|
|||
err = cmd.compareResult(vec)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error in %s %s (line %d) range mode", cmd, iq.expr, cmd.line)
|
||||
return fmt.Errorf("error in %s %s (line %d) range mode: %w", cmd, iq.expr, cmd.line, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -658,7 +661,7 @@ func parseNumber(s string) (float64, error) {
|
|||
f, err = strconv.ParseFloat(s, 64)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "error parsing number")
|
||||
return 0, fmt.Errorf("error parsing number: %w", err)
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue