mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-06-08 03:14:09 +03:00
Compare commits
25 Commits
v0.27.1-vi
...
split-chec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32039b0ecf | ||
|
|
6d54fff850 | ||
|
|
b5d43e2ee2 | ||
|
|
0e1dbdee28 | ||
|
|
f41f5ef62e | ||
|
|
7478d2de4c | ||
|
|
108a5e10d8 | ||
|
|
4527020a68 | ||
|
|
8786a08d27 | ||
|
|
35b3b95cbc | ||
|
|
c1c2286e09 | ||
|
|
8ba914d0f1 | ||
|
|
5275b36380 | ||
|
|
c14e827cc5 | ||
|
|
d5e4857a27 | ||
|
|
fe42884b1b | ||
|
|
4d92f875fd | ||
|
|
3d164d7e31 | ||
|
|
7e781f0f78 | ||
|
|
ee66fb4387 | ||
|
|
959a4383c5 | ||
|
|
7e169a767d | ||
|
|
11989db586 | ||
|
|
3169524fb7 | ||
|
|
c429bbf889 |
54
.github/workflows/build.yml
vendored
Normal file
54
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
name: build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- cluster
|
||||
- master
|
||||
paths:
|
||||
- '**.go'
|
||||
- '**/Dockerfile*' # The trailing * is for app/vmui/Dockerfile-*.
|
||||
- '**/Makefile'
|
||||
pull_request:
|
||||
branches:
|
||||
- cluster
|
||||
- master
|
||||
paths:
|
||||
- '**.go'
|
||||
- '**/Dockerfile*' # The trailing * is for app/vmui/Dockerfile-*.
|
||||
- '**/Makefile'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
cancel-in-progress: true
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Go
|
||||
id: go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
cache: false
|
||||
|
||||
- name: Cache Go artifacts
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/bin
|
||||
~/go/pkg/mod
|
||||
key: go-artifacts-${{ runner.os }}-crossbuild-${{ steps.go.outputs.go-version }}-${{ hashFiles('go.sum', 'Makefile', 'app/**/Makefile') }}
|
||||
restore-keys: go-artifacts-${{ runner.os }}-crossbuild-
|
||||
|
||||
- name: Run crossbuild
|
||||
run: make crossbuild
|
||||
88
.github/workflows/main.yml
vendored
88
.github/workflows/main.yml
vendored
@@ -1,29 +1,27 @@
|
||||
name: main
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- cluster
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
- "**.md"
|
||||
- "dashboards/**"
|
||||
- "deployment/**.yml"
|
||||
- master
|
||||
paths:
|
||||
- '.github/workflows/main.yml'
|
||||
- '**.go'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- cluster
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
- "**.md"
|
||||
- "dashboards/**"
|
||||
- "deployment/**.yml"
|
||||
- master
|
||||
paths:
|
||||
- '.github/workflows/main.yml'
|
||||
- '**.go'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
@@ -37,59 +35,51 @@ jobs:
|
||||
id: go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
cache: false
|
||||
go-version: stable
|
||||
|
||||
- name: Cache Go artifacts
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
~/go/bin
|
||||
~/go/pkg/mod
|
||||
key: go-artifacts-${{ runner.os }}-check-all-${{ steps.go.outputs.go-version }}-${{ hashFiles('go.sum', 'Makefile', 'app/**/Makefile') }}
|
||||
restore-keys: go-artifacts-${{ runner.os }}-check-all-
|
||||
|
||||
- name: Run check-all
|
||||
run: |
|
||||
make check-all
|
||||
git diff --exit-code
|
||||
- name: Run fmt
|
||||
run: make fmt
|
||||
|
||||
build:
|
||||
needs: lint
|
||||
name: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Go
|
||||
id: go
|
||||
uses: actions/setup-go@v5
|
||||
- name: Run vet
|
||||
run: make vet
|
||||
|
||||
# Use action instead of `make golangci-lint` to speed up the process
|
||||
# as it caches data between builds.
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
go-version: stable
|
||||
cache: false
|
||||
# The version must match "install-golangci-lint" Makefile target version.
|
||||
version: v1.59.1
|
||||
|
||||
- name: Cache Go artifacts
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
~/go/bin
|
||||
key: go-artifacts-${{ runner.os }}-crossbuild-${{ steps.go.outputs.go-version }}-${{ hashFiles('go.sum', 'Makefile', 'app/**/Makefile') }}
|
||||
restore-keys: go-artifacts-${{ runner.os }}-crossbuild-
|
||||
- name: Run govulncheck
|
||||
run: make govulncheck
|
||||
|
||||
- name: Build
|
||||
run: make crossbuild
|
||||
- name: Check diff
|
||||
run: git diff --exit-code
|
||||
|
||||
test:
|
||||
name: test
|
||||
needs: lint
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
scenario: ["test-full", "test-pure", "test-full-386"]
|
||||
name: test
|
||||
runs-on: ubuntu-latest
|
||||
scenario:
|
||||
- 'test-full'
|
||||
- 'test-full-386'
|
||||
- 'test-pure'
|
||||
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -98,20 +88,20 @@ jobs:
|
||||
id: go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
cache: false
|
||||
go-version: stable
|
||||
|
||||
- name: Cache Go artifacts
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
~/go/bin
|
||||
~/go/pkg/mod
|
||||
key: go-artifacts-${{ runner.os }}-${{ matrix.scenario }}-${{ steps.go.outputs.go-version }}-${{ hashFiles('go.sum', 'Makefile', 'app/**/Makefile') }}
|
||||
restore-keys: go-artifacts-${{ runner.os }}-${{ matrix.scenario }}-
|
||||
|
||||
- name: run tests
|
||||
- name: Run tests
|
||||
run: make ${{ matrix.scenario}}
|
||||
|
||||
- name: Publish coverage
|
||||
|
||||
1
Makefile
1
Makefile
@@ -493,6 +493,7 @@ golangci-lint: install-golangci-lint
|
||||
golangci-lint run
|
||||
|
||||
install-golangci-lint:
|
||||
# The version must match GitHub main.yml lint job "Run golangci-lint" step version.
|
||||
which golangci-lint || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.59.1
|
||||
|
||||
remove-golangci-lint:
|
||||
|
||||
@@ -318,8 +318,8 @@ This allows Grafana to use a more efficient API to get label values.
|
||||
Then build graphs and dashboards for the created datasource using [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/)
|
||||
or [MetricsQL](https://docs.victoriametrics.com/metricsql/).
|
||||
|
||||
Alternatively, use VictoriaMetrics [datasource plugin](https://github.com/VictoriaMetrics/grafana-datasource) with support of extra features.
|
||||
See more in [description](https://github.com/VictoriaMetrics/grafana-datasource#victoriametrics-data-source-for-grafana).
|
||||
Alternatively, use VictoriaMetrics [datasource plugin](https://github.com/VictoriaMetrics/victoriametrics-datasource) with support of extra features.
|
||||
See more in [description](https://docs.victoriametrics.com/victoriametrics-datasource/).
|
||||
|
||||
Creating a datasource may require [specific permissions](https://grafana.com/docs/grafana/latest/administration/data-source-management/).
|
||||
If you don't see an option to create a data source - try contacting system administrator.
|
||||
@@ -3088,7 +3088,7 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
|
||||
-search.maxLabelsAPIDuration duration
|
||||
The maximum duration for /api/v1/labels, /api/v1/label/.../values and /api/v1/series requests. See also -search.maxLabelsAPISeries and -search.ignoreExtraFiltersAtLabelsAPI (default 5s)
|
||||
-search.maxLabelsAPISeries int
|
||||
The maximum number of time series, which could be scanned when searching for the the matching time series at /api/v1/labels and /api/v1/label/.../values. This option allows limiting memory usage and CPU usage. See also -search.maxLabelsAPIDuration, -search.maxTagKeys, -search.maxTagValues and -search.ignoreExtraFiltersAtLabelsAPI (default 1000000)
|
||||
The maximum number of time series, which could be scanned when searching for the matching time series at /api/v1/labels and /api/v1/label/.../values. This option allows limiting memory usage and CPU usage. See also -search.maxLabelsAPIDuration, -search.maxTagKeys, -search.maxTagValues and -search.ignoreExtraFiltersAtLabelsAPI (default 1000000)
|
||||
-search.maxLookback duration
|
||||
Synonym to -search.lookback-delta from Prometheus. The value is dynamically detected from interval between time series datapoints if not set. It can be overridden on per-query basis via max_lookback arg. See also '-search.maxStalenessInterval' flag, which has the same meaning due to historical reasons
|
||||
-search.maxMemoryPerQuery size
|
||||
|
||||
@@ -101,8 +101,7 @@ replay-vmalert: vmalert
|
||||
-remoteWrite.url=http://localhost:8428 \
|
||||
-external.label=cluster=east-1 \
|
||||
-external.label=replica=a \
|
||||
-replay.timeFrom=2021-05-11T07:21:43Z \
|
||||
-replay.timeTo=2021-05-29T18:40:43Z
|
||||
-replay.timeFrom=2024-06-01T00:00:00Z
|
||||
|
||||
vmalert-linux-amd64:
|
||||
APP_NAME=vmalert CGO_ENABLED=1 GOOS=linux GOARCH=amd64 $(MAKE) app-local-goos-goarch
|
||||
|
||||
@@ -72,7 +72,7 @@ absolute path to all .tpl files in root.
|
||||
externalAlertSource = flag.String("external.alert.source", "", `External Alert Source allows to override the Source link for alerts sent to AlertManager `+
|
||||
`for cases where you want to build a custom link to Grafana, Prometheus or any other service. `+
|
||||
`Supports templating - see https://docs.victoriametrics.com/vmalert/#templating . `+
|
||||
`For example, link to Grafana: -external.alert.source='explore?orgId=1&left={"datasource":"VictoriaMetrics","queries":[{"expr":{{$expr|jsonEscape|queryEscape}},"refId":"A"}],"range":{"from":"now-1h","to":"now"}}'. `+
|
||||
`For example, link to Grafana: -external.alert.source='explore?orgId=1&left={"datasource":"VictoriaMetrics","queries":[{"expr":{{.Expr|jsonEscape|queryEscape}},"refId":"A"}],"range":{"from":"now-1h","to":"now"}}'. `+
|
||||
`Link to VMUI: -external.alert.source='vmui/#/?g0.expr={{.Expr|queryEscape}}'. `+
|
||||
`If empty 'vmalert/alert?group_id={{.GroupID}}&alert_id={{.AlertID}}' is used.`)
|
||||
externalLabels = flagutil.NewArrayString("external.label", "Optional label in the form 'Name=value' to add to all generated recording rules and alerts. "+
|
||||
@@ -132,7 +132,7 @@ func main() {
|
||||
validateTplFn = notifier.ValidateTemplates
|
||||
}
|
||||
|
||||
if *replayFrom != "" || *replayTo != "" {
|
||||
if *replayFrom != "" {
|
||||
rw, err := remotewrite.Init(context.Background())
|
||||
if err != nil {
|
||||
logger.Fatalf("failed to init remoteWrite: %s", err)
|
||||
|
||||
@@ -15,9 +15,10 @@ import (
|
||||
|
||||
var (
|
||||
replayFrom = flag.String("replay.timeFrom", "",
|
||||
"The time filter in RFC3339 format to select time series with timestamp equal or higher than provided value. E.g. '2020-01-01T20:07:00Z'")
|
||||
"The time filter in RFC3339 format to start the replay from. E.g. '2020-01-01T20:07:00Z'")
|
||||
replayTo = flag.String("replay.timeTo", "",
|
||||
"The time filter in RFC3339 format to select timeseries with timestamp equal or lower than provided value. E.g. '2020-01-01T20:07:00Z'")
|
||||
"The time filter in RFC3339 format to finish the replay by. E.g. '2020-01-01T20:07:00Z'. "+
|
||||
"By default, is set to the current time.")
|
||||
replayRulesDelay = flag.Duration("replay.rulesDelay", time.Second,
|
||||
"Delay between rules evaluation within the group. Could be important if there are chained rules inside the group "+
|
||||
"and processing need to wait for previous rule results to be persisted by remote storage before evaluating the next rule."+
|
||||
@@ -36,14 +37,20 @@ func replay(groupsCfg []config.Group, qb datasource.QuerierBuilder, rw remotewri
|
||||
}
|
||||
tFrom, err := time.Parse(time.RFC3339, *replayFrom)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse %q: %w", *replayFrom, err)
|
||||
return fmt.Errorf("failed to parse replay.timeFrom=%q: %w", *replayFrom, err)
|
||||
}
|
||||
tTo, err := time.Parse(time.RFC3339, *replayTo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse %q: %w", *replayTo, err)
|
||||
|
||||
// use tFrom location for default value, otherwise filters could have different locations
|
||||
tTo := time.Now().In(tFrom.Location())
|
||||
if *replayTo != "" {
|
||||
tTo, err = time.Parse(time.RFC3339, *replayTo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse replay.timeTo=%q: %w", *replayTo, err)
|
||||
}
|
||||
}
|
||||
|
||||
if !tTo.After(tFrom) {
|
||||
return fmt.Errorf("replay.timeTo must be bigger than replay.timeFrom")
|
||||
return fmt.Errorf("replay.timeTo=%v must be bigger than replay.timeFrom=%v", tTo, tFrom)
|
||||
}
|
||||
labels := make(map[string]string)
|
||||
for _, s := range *externalLabels {
|
||||
|
||||
@@ -52,7 +52,7 @@ var (
|
||||
maxExportSeries = flag.Int("search.maxExportSeries", 10e6, "The maximum number of time series, which can be returned from /api/v1/export* APIs. This option allows limiting memory usage")
|
||||
maxTSDBStatusSeries = flag.Int("search.maxTSDBStatusSeries", 10e6, "The maximum number of time series, which can be processed during the call to /api/v1/status/tsdb. This option allows limiting memory usage")
|
||||
maxSeriesLimit = flag.Int("search.maxSeries", 30e3, "The maximum number of time series, which can be returned from /api/v1/series. This option allows limiting memory usage")
|
||||
maxLabelsAPISeries = flag.Int("search.maxLabelsAPISeries", 1e6, "The maximum number of time series, which could be scanned when searching for the the matching time series "+
|
||||
maxLabelsAPISeries = flag.Int("search.maxLabelsAPISeries", 1e6, "The maximum number of time series, which could be scanned when searching for the matching time series "+
|
||||
"at /api/v1/labels and /api/v1/label/.../values. This option allows limiting memory usage and CPU usage. See also -search.maxLabelsAPIDuration, "+
|
||||
"-search.maxTagKeys, -search.maxTagValues and -search.ignoreExtraFiltersAtLabelsAPI")
|
||||
maxPointsPerTimeseries = flag.Int("search.maxPointsPerTimeseries", 30e3, "The maximum points per a single timeseries returned from /api/v1/query_range. "+
|
||||
|
||||
@@ -12,7 +12,17 @@ export interface JsonViewProps {
|
||||
const JsonView: FC<JsonViewProps> = ({ data }) => {
|
||||
const copyToClipboard = useCopyToClipboard();
|
||||
|
||||
const formattedJson = useMemo(() => JSON.stringify(data, null, 2), [data]);
|
||||
const formattedJson = useMemo(() => {
|
||||
const space = " ";
|
||||
const values = data.map(item => {
|
||||
if (Object.keys(item).length === 1) {
|
||||
return JSON.stringify(item);
|
||||
} else {
|
||||
return JSON.stringify(item, null, space.length);
|
||||
}
|
||||
}).join(",\n").replace(/^/gm, `${space}`);
|
||||
return `[\n${values}\n]`;
|
||||
}, [data]);
|
||||
|
||||
const handlerCopy = async () => {
|
||||
await copyToClipboard(formattedJson, "Formatted JSON has been copied");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
The directory contains the official list of Grafana dashboards for VictoriaMetrics components.
|
||||
The `vm` folder contains copies of the listed dashboards but alternated to use
|
||||
[VictoriaMetrics datasource](https://github.com/VictoriaMetrics/grafana-datasource).
|
||||
[VictoriaMetrics datasource](https://github.com/VictoriaMetrics/victoriametrics-datasource).
|
||||
|
||||
The listed dashboards can be found on [Grafana website](https://grafana.com/orgs/victoriametrics/dashboards).
|
||||
|
||||
|
||||
@@ -4978,7 +4978,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "rate(vm_streamaggr_matched_samples_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]) > 0",
|
||||
"expr": "sum(rate(vm_streamaggr_matched_samples_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval])) without (instance, pod) > 0",
|
||||
"instant": false,
|
||||
"legendFormat": "{{url}} ({{job}}): match={{match}}; outputs={{outputs}}",
|
||||
"range": true,
|
||||
@@ -5075,7 +5075,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "rate(vm_streamaggr_ignored_samples_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]) > 0",
|
||||
"expr": "sum(rate(vm_streamaggr_ignored_samples_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]) > 0) without (instance, pod)",
|
||||
"instant": false,
|
||||
"legendFormat": "{{url}} ({{job}}): match={{match}}; outputs={{outputs}}",
|
||||
"range": true,
|
||||
@@ -5178,7 +5178,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "rate(vm_streamaggr_flushed_samples_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]) > 0",
|
||||
"expr": "sum(rate(vm_streamaggr_flushed_samples_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval])) without (instance, pod) > 0",
|
||||
"instant": false,
|
||||
"legendFormat": "{{url}} ({{job}}): match={{match}}; output={{output}}",
|
||||
"range": true,
|
||||
@@ -5276,7 +5276,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "increase(vm_streamaggr_flush_timeouts_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval])",
|
||||
"expr": "increase(vm_streamaggr_flush_timeouts_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]) > 0",
|
||||
"instant": false,
|
||||
"legendFormat": "aggregation: {{url}} ({{job}}): match={{match}}; outputs={{outputs}}",
|
||||
"range": true,
|
||||
@@ -5288,7 +5288,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "increase(vm_streamaggr_dedup_flush_timeouts_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval])",
|
||||
"expr": "increase(vm_streamaggr_dedup_flush_timeouts_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]) > 0",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
"legendFormat": "deduplication: {{url}} ({{job}}): match={{match}}; outputs={{outputs}}",
|
||||
@@ -5388,7 +5388,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "histogram_quantile(0.99, rate(vm_streamaggr_samples_lag_seconds_bucket{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]))",
|
||||
"expr": "histogram_quantile(0.99, sum(rate(vm_streamaggr_samples_lag_seconds_bucket{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval])) without (instance, pod))",
|
||||
"instant": false,
|
||||
"legendFormat": "{{url}} ({{job}}): match={{match}}; outputs={{outputs}}",
|
||||
"range": true,
|
||||
|
||||
@@ -4977,7 +4977,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "rate(vm_streamaggr_matched_samples_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]) > 0",
|
||||
"expr": "sum(rate(vm_streamaggr_matched_samples_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval])) without (instance, pod) > 0",
|
||||
"instant": false,
|
||||
"legendFormat": "{{url}} ({{job}}): match={{match}}; outputs={{outputs}}",
|
||||
"range": true,
|
||||
@@ -5074,7 +5074,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "rate(vm_streamaggr_ignored_samples_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]) > 0",
|
||||
"expr": "sum(rate(vm_streamaggr_ignored_samples_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]) > 0) without (instance, pod)",
|
||||
"instant": false,
|
||||
"legendFormat": "{{url}} ({{job}}): match={{match}}; outputs={{outputs}}",
|
||||
"range": true,
|
||||
@@ -5177,7 +5177,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "rate(vm_streamaggr_flushed_samples_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]) > 0",
|
||||
"expr": "sum(rate(vm_streamaggr_flushed_samples_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval])) without (instance, pod) > 0",
|
||||
"instant": false,
|
||||
"legendFormat": "{{url}} ({{job}}): match={{match}}; output={{output}}",
|
||||
"range": true,
|
||||
@@ -5275,7 +5275,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "increase(vm_streamaggr_flush_timeouts_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval])",
|
||||
"expr": "increase(vm_streamaggr_flush_timeouts_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]) > 0",
|
||||
"instant": false,
|
||||
"legendFormat": "aggregation: {{url}} ({{job}}): match={{match}}; outputs={{outputs}}",
|
||||
"range": true,
|
||||
@@ -5287,7 +5287,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "increase(vm_streamaggr_dedup_flush_timeouts_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval])",
|
||||
"expr": "increase(vm_streamaggr_dedup_flush_timeouts_total{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]) > 0",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
"legendFormat": "deduplication: {{url}} ({{job}}): match={{match}}; outputs={{outputs}}",
|
||||
@@ -5387,7 +5387,7 @@
|
||||
"uid": "$ds"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "histogram_quantile(0.99, rate(vm_streamaggr_samples_lag_seconds_bucket{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval]))",
|
||||
"expr": "histogram_quantile(0.99, sum(rate(vm_streamaggr_samples_lag_seconds_bucket{job=~\"$job\",instance=~\"$instance\", url=~\"$url\"}[$__rate_interval])) without (instance, pod))",
|
||||
"instant": false,
|
||||
"legendFormat": "{{url}} ({{job}}): match={{match}}; outputs={{outputs}}",
|
||||
"range": true,
|
||||
|
||||
@@ -168,7 +168,7 @@ package-via-docker-pure:
|
||||
|
||||
package-via-docker-amd64:
|
||||
EXTRA_DOCKER_ENVS='CC=/opt/cross-builder/x86_64-linux-musl-cross/bin/x86_64-linux-musl-gcc' \
|
||||
CO_ENABLED=1 GOARCH=amd64 $(MAKE) package-via-docker-goarch
|
||||
CGO_ENABLED=1 GOARCH=amd64 $(MAKE) package-via-docker-goarch
|
||||
|
||||
package-via-docker-arm64:
|
||||
EXTRA_DOCKER_ENVS='CC=/opt/cross-builder/aarch64-linux-musl-cross/bin/aarch64-linux-musl-gcc' \
|
||||
|
||||
@@ -138,7 +138,7 @@ Grafana is provisioned by default with following entities:
|
||||
|
||||
Remember to pick `VictoriaMetrics - cluster` datasource when viewing `VictoriaMetrics - cluster` dashboard.
|
||||
|
||||
Optionally, environment with [VictoriaMetrics Grafana datasource](https://github.com/VictoriaMetrics/grafana-datasource)
|
||||
Optionally, environment with [VictoriaMetrics Grafana datasource](https://github.com/VictoriaMetrics/victoriametrics-datasource)
|
||||
can be started with the following commands:
|
||||
```
|
||||
make docker-single-vm-datasource-up # start single server
|
||||
|
||||
@@ -145,8 +145,7 @@ services:
|
||||
- '--rule=/etc/alerts/*.yml'
|
||||
# display source of alerts in grafana
|
||||
- '-external.url=http://127.0.0.1:3000' #grafana outside container
|
||||
# when copypaste the line below be aware of '$$' for escaping in '$expr'
|
||||
- '--external.alert.source=explore?orgId=1&left={"datasource":"VictoriaMetrics","queries":[{"expr":{{$$expr|jsonEscape|queryEscape}},"refId":"A"}],"range":{"from":"now-1h","to":"now"}}'
|
||||
- '--external.alert.source=explore?orgId=1&left={"datasource":"VictoriaMetrics","queries":[{"expr":{{.Expr|jsonEscape|queryEscape}},"refId":"A"}],"range":{"from":"{{ .ActiveAt.UnixMilli }}","to":"now"}}'
|
||||
restart: always
|
||||
|
||||
# alertmanager receives alerting notifications from vmalert
|
||||
|
||||
@@ -84,8 +84,7 @@ services:
|
||||
- "--rule=/etc/alerts/*.yml"
|
||||
# display source of alerts in grafana
|
||||
- "--external.url=http://127.0.0.1:3000" #grafana outside container
|
||||
# when copypaste the line be aware of '$$' for escaping in '$expr'
|
||||
- '--external.alert.source=explore?orgId=1&left={"datasource":"VictoriaMetrics","queries":[{"expr":{{$$expr|jsonEscape|queryEscape}},"refId":"A"}],"range":{"from":"now-1h","to":"now"}}'
|
||||
- '--external.alert.source=explore?orgId=1&left={"datasource":"VictoriaMetrics","queries":[{"expr":{{.Expr|jsonEscape|queryEscape}},"refId":"A"}],"range":{"from":"{{ .ActiveAt.UnixMilli }}","to":"now"}}'
|
||||
networks:
|
||||
- vm_net
|
||||
restart: always
|
||||
|
||||
@@ -16,6 +16,6 @@ services:
|
||||
- ./../../dashboards/vm/vmalert.json:/var/lib/grafana/dashboards/vmalert.json
|
||||
- ./../../dashboards/vm/vmauth.json:/var/lib/grafana/dashboards/vmauth.json
|
||||
environment:
|
||||
- "GF_INSTALL_PLUGINS=https://github.com/VictoriaMetrics/grafana-datasource/releases/download/v0.8.2/victoriametrics-datasource-v0.8.2.zip;victoriametrics-datasource"
|
||||
- "GF_INSTALL_PLUGINS=https://github.com/VictoriaMetrics/victoriametrics-datasource/releases/download/v0.8.2/victoriametrics-datasource-v0.8.2.zip;victoriametrics-datasource"
|
||||
- "GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=victoriametrics-datasource"
|
||||
restart: always
|
||||
|
||||
@@ -15,7 +15,7 @@ services:
|
||||
- ./../../dashboards/vm/vmagent.json:/var/lib/grafana/dashboards/vmagent.json
|
||||
- ./../../dashboards/vm/vmalert.json:/var/lib/grafana/dashboards/vmalert.json
|
||||
environment:
|
||||
- "GF_INSTALL_PLUGINS=https://github.com/VictoriaMetrics/grafana-datasource/releases/download/v0.8.2/victoriametrics-datasource-v0.8.2.zip;victoriametrics-datasource"
|
||||
- "GF_INSTALL_PLUGINS=https://github.com/VictoriaMetrics/victoriametrics-datasource/releases/download/v0.8.2/victoriametrics-datasource-v0.8.2.zip;victoriametrics-datasource"
|
||||
- "GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=victoriametrics-datasource"
|
||||
networks:
|
||||
- vm_net
|
||||
|
||||
@@ -47,6 +47,8 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/).
|
||||
* These and other metrics were reflected on the [vmagent dashboard](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/dashboards/vmagent.json) in `stream aggregation` section.
|
||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent/) and [Single-node VictoriaMetrics](https://docs.victoriametrics.com/): add `-graphite.sanitizeMetricName` cmd-line flag for sanitizing metrics ingested via [Graphite protocol](https://docs.victoriametrics.com/#how-to-send-data-from-graphite-compatible-agents-such-as-statsd). See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6077).
|
||||
* FEATURE: [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): do not retry RPC calls to vmstorage nodes if [complexity limits](https://docs.victoriametrics.com/#resource-usage-limits) were exceeded.
|
||||
* FEATURE: [vmalert](https://docs.victoriametrics.com/vmalert/): make `-replay.timeTo` optional in [replay mode](https://docs.victoriametrics.com/vmalert/#rules-backfilling). When omitted, the current timestamp will be used. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6492).
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): show compacted result in the JSON tab for query results. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6559).
|
||||
|
||||
* BUGFIX: [docker-compose](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/deployment/docker#docker-compose-environment-for-victoriametrics): fix incorrect link to vmui from [VictoriaMetrics plugin in Grafana](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/deployment/docker#grafana).
|
||||
* BUGFIX: [docker-compose](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/deployment/docker#docker-compose-environment-for-victoriametrics): fix incorrect link to vmui from [VictoriaMetrics plugin in Grafana](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/deployment/docker#grafana).
|
||||
@@ -461,7 +463,7 @@ The v1.97.x line will be supported for at least 12 months since [v1.97.0](https:
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add `-vmui.defaultTimezone` flag to set a default timezone. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5375) and [these docs](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/app/vmui#timezone-configuration).
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): include UTC in the timezone selection dropdown for standardized time referencing. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5375).
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add the ability to expand/collapse all tracing entries and download tracing data in .json format. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5677).
|
||||
* FEATURE: add [VictoriaMetrics datasource](https://github.com/VictoriaMetrics/grafana-datasource) to docker compose environment. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5363).
|
||||
* FEATURE: add [VictoriaMetrics datasource](https://github.com/VictoriaMetrics/victoriametrics-datasource) to docker compose environment. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5363).
|
||||
|
||||
* BUGFIX: properly return the list of matching label names and label values from [`/api/v1/labels`](https://docs.victoriametrics.com/url-examples/#apiv1labels) and [`/api/v1/label/.../values`](https://docs.victoriametrics.com/url-examples/#apiv1labelvalues) when the database contains more than `-search.maxUniqueTimeseries` unique [time series](https://docs.victoriametrics.com/keyconcepts/#time-series) on the selected time range. Previously VictoriaMetrics could return `the number of matching timeseries exceeds ...` error in this case. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5055).
|
||||
* BUGFIX: properly return errors from [export APIs](https://docs.victoriametrics.com/#how-to-export-time-series). Previously these errors were silently suppressed. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5649).
|
||||
|
||||
@@ -651,7 +651,7 @@ Another option is to upgrade to [v1.89.1](https://docs.victoriametrics.com/chang
|
||||
* BUGFIX: [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): properly take into account `-rpc.disableCompression` command-line flag at `vmstorage`. It was ignored since [v1.78.0](https://docs.victoriametrics.com/changelog/#v1780). See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/3932).
|
||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent/): fix panic when [writing data to Kafka](https://docs.victoriametrics.com/vmagent/#writing-metrics-to-kafka). The panic has been introduced in [v1.88.0](https://docs.victoriametrics.com/changelog/#v1880).
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): stop showing `Please enter a valid Query and execute it` error message on the first load of vmui.
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): properly process `Run in VMUI` button click in [VictoriaMetrics datasource plugin for Grafana](https://github.com/VictoriaMetrics/grafana-datasource).
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): properly process `Run in VMUI` button click in [VictoriaMetrics datasource plugin for Grafana](https://github.com/VictoriaMetrics/victoriametrics-datasource).
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix the display of the selected value for dropdowns on `Explore` page.
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): do not send `step` param for instant queries. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3896).
|
||||
* BUGFIX: [vmauth](https://docs.victoriametrics.com/vmauth/): fix `cannot serve http` panic when plain HTTP request is sent to `vmauth` configured to accept requests over [proxy protocol](https://www.haproxy.org/download/2.3/doc/proxy-protocol.txt)-encoded request (e.g. when `vmauth` runs with `-httpListenAddr.useProxyProtocol` command-line flag). The issue has been introduced at [v1.87.0](https://docs.victoriametrics.com/changelog/#v1870) when implementing [this feature](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3335).
|
||||
|
||||
@@ -1523,7 +1523,7 @@ Below is the output for `/path/to/vmselect -help`:
|
||||
-search.maxLabelsAPIDuration duration
|
||||
The maximum duration for /api/v1/labels, /api/v1/label/.../values and /api/v1/series requests. See also -search.maxLabelsAPISeries and -search.ignoreExtraFiltersAtLabelsAPI (default 5s)
|
||||
-search.maxLabelsAPISeries int
|
||||
The maximum number of time series, which could be scanned when searching for the the matching time series at /api/v1/labels and /api/v1/label/.../values. This option allows limiting memory usage and CPU usage. See also -search.maxLabelsAPIDuration, -search.maxTagKeys, -search.maxTagValues and -search.ignoreExtraFiltersAtLabelsAPI (default 1000000)
|
||||
The maximum number of time series, which could be scanned when searching for the matching time series at /api/v1/labels and /api/v1/label/.../values. This option allows limiting memory usage and CPU usage. See also -search.maxLabelsAPIDuration, -search.maxTagKeys, -search.maxTagValues and -search.ignoreExtraFiltersAtLabelsAPI (default 1000000)
|
||||
-search.maxLookback duration
|
||||
Synonym to -search.lookback-delta from Prometheus. The value is dynamically detected from interval between time series datapoints if not set. It can be overridden on per-query basis via max_lookback arg. See also '-search.maxStalenessInterval' flag, which has the same meaning due to historical reasons
|
||||
-search.maxMemoryPerQuery size
|
||||
|
||||
@@ -27,6 +27,7 @@ Single-server-VictoriaMetrics VictoriaMetrics is available as:
|
||||
* [Docker images](https://hub.docker.com/r/victoriametrics/victoria-metrics/)
|
||||
* [Helm Charts](https://github.com/VictoriaMetrics/helm-charts#list-of-charts)
|
||||
* [Binary releases](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest)
|
||||
* [Ansible Roles](https://github.com/VictoriaMetrics/ansible-playbooks)
|
||||
* [Source code](https://github.com/VictoriaMetrics/VictoriaMetrics).
|
||||
See [How to build from sources](https://docs.victoriametrics.com/single-server-victoriametrics/#how-to-build-from-sources)
|
||||
* [VictoriaMetrics on Linode](https://www.linode.com/marketplace/apps/victoriametrics/victoriametrics/)
|
||||
@@ -40,7 +41,7 @@ and [Grafana setup](https://docs.victoriametrics.com/single-server-victoriametri
|
||||
VictoriaMetrics is developed at a fast pace, so it is recommended periodically checking the [CHANGELOG](https://docs.victoriametrics.com/changelog/) and performing [regular upgrades](https://docs.victoriametrics.com/#how-to-upgrade-victoriametrics).
|
||||
|
||||
|
||||
### Starting VM-Single via Docker
|
||||
### Starting VictoriaMetrics Single via Docker
|
||||
|
||||
The following commands download the latest available
|
||||
[Docker image of VictoriaMetrics](https://hub.docker.com/r/victoriametrics/victoria-metrics)
|
||||
@@ -60,7 +61,7 @@ and read [these docs](https://docs.victoriametrics.com/#operation).
|
||||
There is also [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/)
|
||||
- horizontally scalable installation, which scales to multiple nodes.
|
||||
|
||||
### Starting VM-Cluster via Docker
|
||||
### Starting VictoriaMetrics Cluster via Docker
|
||||
|
||||
The following commands clone the latest available
|
||||
[VictoriaMetrics repository](https://github.com/VictoriaMetrics/VictoriaMetrics)
|
||||
@@ -79,6 +80,245 @@ See more details [here](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/
|
||||
|
||||
* [Cluster setup](https://docs.victoriametrics.com/cluster-victoriametrics/#cluster-setup)
|
||||
|
||||
|
||||
### Starting VictoriaMetrics Single from a Binary
|
||||
|
||||
1. Download the correct archive from [github](https://github.com/VictoriaMetrics/VictoriaMetrics/releases)
|
||||
|
||||
For open source it will look like
|
||||
|
||||
```victoria-metrics-<os>-<architecture>-v<version>.tar.gz```
|
||||
|
||||
For Enterprise it will look like
|
||||
|
||||
`victoria-metrics-<os>-<architecture>-v<version>-enterprise.tar.gz`
|
||||
|
||||
In order for VictoriaMetrics Enterprise to start the, the -license flag must be set equal to a valid VictoriaMetrics key or the -licenseFile flag needs to point to a file containing your VictoriaMetrics license. Please, see more information about license configuration [here](https://docs.victoriametrics.com/enterprise/#binary-releases).
|
||||
|
||||
2. Extract the archive to /usr/local/bin by running
|
||||
|
||||
`sudo tar -xvf <victoriametrics-archive> -C /usr/local/bin`
|
||||
|
||||
Replace victoriametrics-archive with the path to the archive you downloaded in step 1
|
||||
|
||||
3. Create a VictoriaMetrics user on the system
|
||||
|
||||
`sudo useradd -s /usr/sbin/nologin victoriametrics`
|
||||
|
||||
4. Create a folder for storing VictoriaMetrics data
|
||||
|
||||
`mkdir -p /var/lib/victoria-metrics && chown -R victoriametrics:victoriametrics /var/lib/victoria-metrics`
|
||||
|
||||
|
||||
5. Create a Linux Service by running the following
|
||||
|
||||
```bash
|
||||
cat <<END >/etc/systemd/system/victoriametrics.service
|
||||
[Unit]
|
||||
Description=VictoriaMetrics service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=victoriametrics
|
||||
Group=victoriametrics
|
||||
ExecStart=/usr/local/bin/victoria-metrics-prod -storageDataPath=/var/lib/victoria-metrics -retentionPeriod=90d -selfScrapeInterval=10s
|
||||
SyslogIdentifier=victoriametrics
|
||||
Restart=always
|
||||
|
||||
PrivateTmp=yes
|
||||
ProtectHome=yes
|
||||
NoNewPrivileges=yes
|
||||
|
||||
ProtectSystem=full
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
END
|
||||
```
|
||||
|
||||
If you want to deploy VictoriaMetrics single as a Windows Service review the [running as a windows service docs](https://docs.victoriametrics.com/single-server-victoriametrics/#running-as-windows-service)
|
||||
|
||||
6. Adjust the command line flags in the `ExecStart` line to fit your needs.
|
||||
|
||||
The list of command line flags for VictoriaMetrics can be found [here](https://docs.victoriametrics.com/single-server-victoriametrics/#list-of-command-line-flags)
|
||||
|
||||
7. Start and enable the service by running
|
||||
|
||||
`sudo systemctl daemon-reload && sudo systemctl enable --now victoriametrics.service`
|
||||
|
||||
8. Check the that service started successfully
|
||||
|
||||
`sudo systemctl status victoriametrics.service`
|
||||
|
||||
9. After VictoriaMetrics is Running verify VMUI is working by going to `http://<ip_or_hostname>:8428/vmui`
|
||||
|
||||
|
||||
### Starting VictoriaMetrics Cluster from Binaries
|
||||
|
||||
On all nodes you will need to do the following
|
||||
|
||||
1. Download the archive that matches your operating system and processor architecture from [github releases](https://github.com/VictoriaMetrics/VictoriaMetrics/releases)
|
||||
|
||||
For open source it will look like
|
||||
|
||||
`victoria-metrics-<os>-<architecture>-v<version>-cluster.tar.gz`
|
||||
|
||||
For Enterprise versions of VictoriaMetrics the ar will look like
|
||||
|
||||
`victoria-metrics-<os>-<architecture>-v<version>-enterprise-cluster.tar.gz`
|
||||
|
||||
In order for VictoriaMetrics Enterprise to start the, the -license flag must be set equal to a valid VictoriaMetrics key or the -licenseFile flag needs to point to a file containing your VictoriaMetrics license. Please, see more information about license configuration [here](https://docs.victoriametrics.com/enterprise/#binary-releases).
|
||||
|
||||
|
||||
2. Extract the archive to /usr/local/bin by running
|
||||
|
||||
`sudo tar -xvf <victoriametrics-archive> -C /usr/local/bin`
|
||||
|
||||
Replace victoriametrics-archive with the path to the archive you downloaded in step 1
|
||||
|
||||
3. Create a user account for VictoriaMetrics
|
||||
|
||||
`sudo useradd -s /usr/sbin/nologin victoriametrics`
|
||||
|
||||
##### vmstorage
|
||||
|
||||
1. Create a folder for storing VictoriaMetrics data
|
||||
|
||||
`mkdir -p /var/lib/vmstorage && chown -R victoriametrics:victoriametrics /var/lib/vmstorage`
|
||||
|
||||
2. Create a Linux Service for `vmstorage` service by running
|
||||
|
||||
```bash
|
||||
cat <<END >/etc/systemd/system/vmstorage.service
|
||||
[Unit]
|
||||
Description=VictoriaMetrics vmstorage service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=victoriametrics
|
||||
Group=victoriametrics
|
||||
Restart=always
|
||||
ExecStart=/usr/local/bin/vmstorage-prod -retentionPeriod=90d -storageDataPath=/var/lib/vmstorage
|
||||
|
||||
PrivateTmp=yes
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=full
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
END
|
||||
```
|
||||
|
||||
3. Adjust the command line flags in the ExecStart line to fit your needs.
|
||||
|
||||
The list of command line flags for `vmstorage` can be found [here](https://docs.victoriametrics.com/cluster-victoriametrics/#list-of-command-line-flags-for-vmstorage)
|
||||
|
||||
4. Start and Enable `vmstorage`
|
||||
|
||||
`sudo systemctl daemon-reload && systemctl enable --now vmstorage`
|
||||
|
||||
5. Check that the service is running
|
||||
|
||||
`sudo systemctl status vmstorage`
|
||||
|
||||
6. After `vmstorage` is running confirm the service healthy by going to
|
||||
|
||||
|
||||
`http://<ip_or_hostname>:8482/-/healthy`
|
||||
|
||||
It should say "VictoriaMetrics is Healthy"
|
||||
|
||||
##### vminsert
|
||||
|
||||
1. Create a Linux Service for `vminsert` by running
|
||||
|
||||
```bash
|
||||
cat << END >/etc/systemd/system/vminsert.service
|
||||
[Unit]
|
||||
Description=VictoriaMetrics vminsert service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=victoriametrics
|
||||
Group=victoriametrics
|
||||
Restart=always
|
||||
ExecStart=/usr/local/bin/vminsert-prod -replicationFactor=1 -storageNode=localhost
|
||||
|
||||
PrivateTmp=yes
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=full
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
END
|
||||
```
|
||||
|
||||
2. Adjust the command line flags in the ExecStart line to fit your needs.
|
||||
|
||||
The list of command line flags for `vminsert` can be found [here](https://docs.victoriametrics.com/cluster-victoriametrics/#list-of-command-line-flags-for-vminsert).
|
||||
|
||||
3. Start and enable `vminsert`
|
||||
|
||||
`sudo systemctl daemon-reload && sudo systemctl enable --now vminsert.service`
|
||||
|
||||
4. Make sure `vminsert` is running
|
||||
|
||||
`sudo systemctl status vminsert.service`
|
||||
|
||||
5. After `vminsert` is started you can confirm that is healthy by going to
|
||||
|
||||
`http://<ip_or_hostname>:8480/-/healthy`
|
||||
|
||||
It should say "VictoriaMetrics is Healthy"
|
||||
|
||||
##### vmselect
|
||||
|
||||
1. Create a folder to store query cache data `sudo mkdir -p /var/lib/vmselect-cache && sudo chown -R victoriametrics:victoriametrics /var/lib/vmselect-cache`
|
||||
|
||||
2. Add a Linux Service for `vmselect` by running
|
||||
|
||||
```bash
|
||||
cat << END >/etc/systemd/system/vmselect.service
|
||||
[Unit]
|
||||
Description=VictoriaMetrics vmselect service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=victoriametrics
|
||||
Group=victoriametrics
|
||||
Restart=always
|
||||
ExecStart=/usr/local/bin/vmselect-prod -storageNode localhost -cacheDataPath=/var/lib/vmselect-cache
|
||||
|
||||
PrivateTmp=yes
|
||||
NoNewPrivileges=yes
|
||||
|
||||
ProtectSystem=full
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
END
|
||||
```
|
||||
|
||||
3. Adjust the command line flags in the ExecStart line to fit your needs.
|
||||
|
||||
The list of command line flags for `vmselect` can be found [here](https://docs.victoriametrics.com/cluster-victoriametrics/#list-of-command-line-flags-for-vmselect)
|
||||
|
||||
4. Start and enable `vmselect`
|
||||
|
||||
`sudo systemctl daemon-reload && sudo systemctl enable --now vmselect.service`
|
||||
|
||||
5. Make sure the `vmselect` service is running
|
||||
|
||||
`sudo systemctl status vmselect.service`
|
||||
|
||||
6. After `vmselect` is running you can verify it is working by going to VMUI located at
|
||||
|
||||
`http://<ip_or_hostname>:8481/select/vmui/vmui/`
|
||||
|
||||
## Write data
|
||||
|
||||
There are two main models in monitoring for data collection:
|
||||
|
||||
@@ -321,8 +321,8 @@ This allows Grafana to use a more efficient API to get label values.
|
||||
Then build graphs and dashboards for the created datasource using [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/)
|
||||
or [MetricsQL](https://docs.victoriametrics.com/metricsql/).
|
||||
|
||||
Alternatively, use VictoriaMetrics [datasource plugin](https://github.com/VictoriaMetrics/grafana-datasource) with support of extra features.
|
||||
See more in [description](https://github.com/VictoriaMetrics/grafana-datasource#victoriametrics-data-source-for-grafana).
|
||||
Alternatively, use VictoriaMetrics [datasource plugin](https://github.com/VictoriaMetrics/victoriametrics-datasource) with support of extra features.
|
||||
See more in [description](https://docs.victoriametrics.com/victoriametrics-datasource/).
|
||||
|
||||
Creating a datasource may require [specific permissions](https://grafana.com/docs/grafana/latest/administration/data-source-management/).
|
||||
If you don't see an option to create a data source - try contacting system administrator.
|
||||
|
||||
@@ -329,8 +329,8 @@ This allows Grafana to use a more efficient API to get label values.
|
||||
Then build graphs and dashboards for the created datasource using [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/)
|
||||
or [MetricsQL](https://docs.victoriametrics.com/metricsql/).
|
||||
|
||||
Alternatively, use VictoriaMetrics [datasource plugin](https://github.com/VictoriaMetrics/grafana-datasource) with support of extra features.
|
||||
See more in [description](https://github.com/VictoriaMetrics/grafana-datasource#victoriametrics-data-source-for-grafana).
|
||||
Alternatively, use VictoriaMetrics [datasource plugin](https://github.com/VictoriaMetrics/victoriametrics-datasource) with support of extra features.
|
||||
See more in [description](https://docs.victoriametrics.com/victoriametrics-datasource/).
|
||||
|
||||
Creating a datasource may require [specific permissions](https://grafana.com/docs/grafana/latest/administration/data-source-management/).
|
||||
If you don't see an option to create a data source - try contacting system administrator.
|
||||
@@ -3099,7 +3099,7 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
|
||||
-search.maxLabelsAPIDuration duration
|
||||
The maximum duration for /api/v1/labels, /api/v1/label/.../values and /api/v1/series requests. See also -search.maxLabelsAPISeries and -search.ignoreExtraFiltersAtLabelsAPI (default 5s)
|
||||
-search.maxLabelsAPISeries int
|
||||
The maximum number of time series, which could be scanned when searching for the the matching time series at /api/v1/labels and /api/v1/label/.../values. This option allows limiting memory usage and CPU usage. See also -search.maxLabelsAPIDuration, -search.maxTagKeys, -search.maxTagValues and -search.ignoreExtraFiltersAtLabelsAPI (default 1000000)
|
||||
The maximum number of time series, which could be scanned when searching for the matching time series at /api/v1/labels and /api/v1/label/.../values. This option allows limiting memory usage and CPU usage. See also -search.maxLabelsAPIDuration, -search.maxTagKeys, -search.maxTagValues and -search.ignoreExtraFiltersAtLabelsAPI (default 1000000)
|
||||
-search.maxLookback duration
|
||||
Synonym to -search.lookback-delta from Prometheus. The value is dynamically detected from interval between time series datapoints if not set. It can be overridden on per-query basis via max_lookback arg. See also '-search.maxStalenessInterval' flag, which has the same meaning due to historical reasons
|
||||
-search.maxMemoryPerQuery size
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
weight: 9
|
||||
title: VictoriaLogs datasource for Grafana
|
||||
editLink: https://github.com/VictoriaMetrics/victorialogs-datasource/blob/main/README.md
|
||||
menu:
|
||||
docs:
|
||||
parent: victorialogs
|
||||
@@ -93,7 +94,7 @@ docker-compose -f docker-compose.yaml up
|
||||
|
||||
After Grafana starts successfully, datasource should be available in the datasources tab
|
||||
|
||||
<img src="provision_datasources.png" width="800" alt="Configuration">
|
||||
<img src="/victorialogsprovision_datasources.png" width="800" alt="Configuration">
|
||||
|
||||
### Install in Kubernetes
|
||||
|
||||
@@ -134,9 +135,9 @@ extraInitContainers:
|
||||
set -ex
|
||||
mkdir -p /var/lib/grafana/plugins/
|
||||
ver=$(curl -s https://api.github.com/repos/VictoriaMetrics/victorialogs-datasource/releases/latest | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
curl -L https://github.com/VictoriaMetrics/victorialogs-datasource/releases/download/$ver/victorialogs-datasource-$ver.tar.gz -o /var/lib/grafana/plugins/plugin.tar.gz
|
||||
tar -xf /var/lib/grafana/plugins/plugin.tar.gz -C /var/lib/grafana/plugins/
|
||||
rm /var/lib/grafana/plugins/plugin.tar.gz
|
||||
curl -L https://github.com/VictoriaMetrics/victorialogs-datasource/releases/download/$ver/victorialogs-datasource-$ver.tar.gz -o /var/lib/grafana/plugins/vl-plugin.tar.gz
|
||||
tar -xf /var/lib/grafana/plugins/vl-plugin.tar.gz -C /var/lib/grafana/plugins/
|
||||
rm /var/lib/grafana/plugins/vl-plugin.tar.gz
|
||||
volumeMounts:
|
||||
# For grafana-operator users, change `name: storage` to `name: grafana-data`
|
||||
- name: storage
|
||||
@@ -185,18 +186,18 @@ spec:
|
||||
command: [ "/bin/sh" ]
|
||||
workingDir: "/var/lib/grafana"
|
||||
securityContext:
|
||||
runAsUser: 10001
|
||||
runAsUser: 472
|
||||
runAsNonRoot: true
|
||||
runAsGroup: 10001
|
||||
runAsGroup: 472
|
||||
args:
|
||||
- "-c"
|
||||
- |
|
||||
set -ex
|
||||
mkdir -p /var/lib/grafana/plugins/
|
||||
ver=$(curl -s https://api.github.com/repos/VictoriaMetrics/victorialogs-datasource/releases/latest | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
curl -L https://github.com/VictoriaMetrics/victorialogs-datasource/releases/download/$ver/victorialogs-datasource-$ver.tar.gz -o /var/lib/grafana/plugins/plugin.tar.gz
|
||||
tar -xf /var/lib/grafana/plugins/plugin.tar.gz -C /var/lib/grafana/plugins/
|
||||
rm /var/lib/grafana/plugins/plugin.tar.gz
|
||||
curl -L https://github.com/VictoriaMetrics/victorialogs-datasource/releases/download/$ver/victorialogs-datasource-$ver.tar.gz -o /var/lib/grafana/plugins/vl-plugin.tar.gz
|
||||
tar -xf /var/lib/grafana/plugins/vl-plugin.tar.gz -C /var/lib/grafana/plugins/
|
||||
rm /var/lib/grafana/plugins/vl-plugin.tar.gz
|
||||
volumeMounts:
|
||||
- name: grafana-data
|
||||
mountPath: /var/lib/grafana
|
||||
@@ -214,9 +215,9 @@ This example uses init container to download and install plugin.
|
||||
|
||||
``` bash
|
||||
ver=$(curl -s https://api.github.com/repos/VictoriaMetrics/victorialogs-datasource/releases/latest | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
curl -L https://github.com/VictoriaMetrics/victorialogs-datasource/releases/download/$ver/victorialogs-datasource-$ver.tar.gz -o /var/lib/grafana/plugins/plugin.tar.gz
|
||||
tar -xf /var/lib/grafana/plugins/plugin.tar.gz -C /var/lib/grafana/plugins/
|
||||
rm /var/lib/grafana/plugins/plugin.tar.gz
|
||||
curl -L https://github.com/VictoriaMetrics/victorialogs-datasource/releases/download/$ver/victorialogs-datasource-$ver.tar.gz -o /var/lib/grafana/plugins/vl-plugin.tar.gz
|
||||
tar -xf /var/lib/grafana/plugins/vl-plugin.tar.gz -C /var/lib/grafana/plugins/
|
||||
rm /var/lib/grafana/plugins/vl-plugin.tar.gz
|
||||
```
|
||||
|
||||
1. Restart Grafana
|
||||
|
||||
@@ -617,7 +617,7 @@ Here in this guide, we will
|
||||
> **Note**: By default, each custom model is created as [**univariate**](#univariate-models) / [**non-rolling**](#non-rolling-models) model. If you want to override this behavior, define models inherited from `RollingModel` (to get a rolling model), or having `is_multivariate` class arg set to `True` (please refer to the code example below).
|
||||
|
||||
We'll create `custom_model.py` file with `CustomModel` class that will inherit from `vmanomaly`'s `Model` base class.
|
||||
In the `CustomModel` class there should be three required methods - `__init__`, `fit` and `infer`:
|
||||
In the `CustomModel` class, the following methods are required: - `__init__`, `fit`, `infer`, `serialize` and `deserialize`:
|
||||
* `__init__` method should initiate parameters for the model.
|
||||
|
||||
**Note**: if your model relies on configs that have `arg` [key-value pair argument](./models.md#section-overview), do not forget to use Python's `**kwargs` in method's signature and to explicitly call
|
||||
@@ -628,6 +628,8 @@ In the `CustomModel` class there should be three required methods - `__init__`,
|
||||
to initialize the base class each model derives from
|
||||
* `fit` method should contain the model training process. Please be aware that for `RollingModel` defining `fit` method is not needed, as the whole fit/infer process should be defined completely in `infer` method.
|
||||
* `infer` should return Pandas.DataFrame object with model's inferences.
|
||||
* `serialize` method that saves the model on disk.
|
||||
* `deserialize` load the saved model from disk.
|
||||
|
||||
For the sake of simplicity, the model in this example will return one of two values of `anomaly_score` - 0 or 1 depending on input parameter `percentage`.
|
||||
|
||||
@@ -637,45 +639,56 @@ import numpy as np
|
||||
import pandas as pd
|
||||
import scipy.stats as st
|
||||
import logging
|
||||
from pickle import dumps
|
||||
|
||||
from model.model import Model
|
||||
from model.model import (
|
||||
PICKLE_PROTOCOL,
|
||||
Model,
|
||||
deserialize_basic
|
||||
)
|
||||
# from model.model import RollingModel # inherit from it for your model to be of rolling type
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CustomModel(Model):
|
||||
"""
|
||||
Custom model implementation.
|
||||
"""
|
||||
"""
|
||||
Custom model implementation.
|
||||
"""
|
||||
# by default, each `Model` will be created as a univariate one
|
||||
# uncomment line below for it to be of multivariate type
|
||||
#`is_multivariate = True`
|
||||
|
||||
def __init__(self, percentage: float = 0.95, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.percentage = percentage
|
||||
self._mean = np.nan
|
||||
self._std = np.nan
|
||||
|
||||
# by default, each `Model` will be created as a univariate one
|
||||
# uncomment line below for it to be of multivariate type
|
||||
# is_multivariate = True
|
||||
def fit(self, df: pd.DataFrame):
|
||||
# Model fit process:
|
||||
y = df['y']
|
||||
self._mean = np.mean(y)
|
||||
self._std = np.std(y)
|
||||
if self._std == 0.0:
|
||||
self._std = 1 / 65536
|
||||
|
||||
def __init__(self, percentage: float = 0.95, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.percentage = percentage
|
||||
self._mean = np.nan
|
||||
self._std = np.nan
|
||||
def infer(self, df: pd.DataFrame) -> np.array:
|
||||
# Inference process:
|
||||
y = df['y']
|
||||
zscores = (y - self._mean) / self._std
|
||||
anomaly_score_cdf = st.norm.cdf(np.abs(zscores))
|
||||
df_pred = df[['timestamp', 'y']].copy()
|
||||
df_pred['anomaly_score'] = anomaly_score_cdf > self.percentage
|
||||
df_pred['anomaly_score'] = df_pred['anomaly_score'].astype('int32', errors='ignore')
|
||||
|
||||
def fit(self, df: pd.DataFrame):
|
||||
# Model fit process:
|
||||
y = df['y']
|
||||
self._mean = np.mean(y)
|
||||
self._std = np.std(y)
|
||||
if self._std == 0.0:
|
||||
self._std = 1 / 65536
|
||||
return df_pred
|
||||
|
||||
def infer(self, df: pd.DataFrame) -> np.array:
|
||||
# Inference process:
|
||||
y = df['y']
|
||||
zscores = (y - self._mean) / self._std
|
||||
anomaly_score_cdf = st.norm.cdf(np.abs(zscores))
|
||||
df_pred = df[['timestamp', 'y']].copy()
|
||||
df_pred['anomaly_score'] = anomaly_score_cdf > self.percentage
|
||||
df_pred['anomaly_score'] = df_pred['anomaly_score'].astype('int32', errors='ignore')
|
||||
def serialize(self) -> None:
|
||||
return dumps(self, protocol=PICKLE_PROTOCOL)
|
||||
|
||||
return df_pred
|
||||
@staticmethod
|
||||
def deserialize(model: str | bytes) -> 'CustomModel':
|
||||
return deserialize_basic(model)
|
||||
```
|
||||
|
||||
|
||||
@@ -694,19 +707,19 @@ schedulers:
|
||||
|
||||
models:
|
||||
custom_model:
|
||||
# note: every custom model should implement this exact path, specified in `class` field
|
||||
class: "custom" # or 'model.model.CustomModel' until v1.13.0
|
||||
# custom model params are defined here
|
||||
percentage: 0.9
|
||||
|
||||
|
||||
reader:
|
||||
datasource_url: "http://localhost:8428/"
|
||||
datasource_url: "http://victoriametrics:8428/"
|
||||
sampling_period: '1m'
|
||||
queries:
|
||||
ingestion_rate: 'sum(rate(vm_rows_inserted_total)) by (type)'
|
||||
churn_rate: 'sum(rate(vm_new_timeseries_created_total[5m]))'
|
||||
|
||||
writer:
|
||||
datasource_url: "http://localhost:8428/"
|
||||
datasource_url: "http://victoriametrics:8428/"
|
||||
metric_format:
|
||||
__name__: "custom_$VAR"
|
||||
for: "$QUERY_KEY"
|
||||
@@ -717,7 +730,7 @@ monitoring:
|
||||
pull:
|
||||
port: 8080
|
||||
push:
|
||||
url: "http://localhost:8428/"
|
||||
url: "http://victoriametrics:8428/"
|
||||
extra_labels:
|
||||
job: "vmanomaly-develop"
|
||||
config: "custom.yaml"
|
||||
@@ -735,14 +748,15 @@ Now we can run the docker container putting as volumes both config and model fil
|
||||
|
||||
> **Note**: place the model file to `/model/custom.py` path when copying
|
||||
|
||||
./custom_model.py:/vmanomaly/model/custom.py
|
||||
|
||||
```sh
|
||||
docker run -it \
|
||||
--net [YOUR_NETWORK] \
|
||||
-v [YOUR_LICENSE_FILE_PATH]:/license.txt \
|
||||
-v $(PWD)/custom_model.py:/vmanomaly/src/model/custom.py \
|
||||
-v $(PWD)/license:/license \
|
||||
-v $(PWD)/custom_model.py:/vmanomaly/model/custom.py \
|
||||
-v $(PWD)/custom.yaml:/config.yaml \
|
||||
victoriametrics/vmanomaly:latest /config.yaml \
|
||||
--license-file=/license.txt
|
||||
--license-file=/license
|
||||
```
|
||||
|
||||
Please find more detailed instructions (license, etc.) [here](/anomaly-detection/overview.html#run-vmanomaly-docker-container)
|
||||
|
||||
@@ -203,8 +203,8 @@ In the "Type and version" section it is recommended to set the type to "Promethe
|
||||
|
||||
This allows Grafana to use a more efficient API to get label values.
|
||||
|
||||
You can also use VictoriaMetrics [Grafana datasource](https://github.com/VictoriaMetrics/grafana-datasource) plugin.
|
||||
See installation instructions [here](https://github.com/VictoriaMetrics/grafana-datasource#installation).
|
||||
You can also use VictoriaMetrics [Grafana datasource](https://github.com/VictoriaMetrics/victoriametrics-datasource) plugin.
|
||||
See installation instructions [here](https://docs.victoriametrics.com/victoriametrics-datasource/#installation).
|
||||
|
||||
Enable `Forward OAuth identity` flag.<br>
|
||||
<img src="grafana-vmgateway-openid-configuration/grafana-ds.webp" >
|
||||
|
||||
@@ -13,6 +13,10 @@ aliases:
|
||||
---
|
||||
# CHANGELOG
|
||||
|
||||
## [v0.46.3](https://github.com/VictoriaMetrics/operator/releases/tag/v0.46.3) - 5 Jul 2024
|
||||
|
||||
- [operator](./README.md): fixes `config-reloader` image tag name after 0.46.0 release. See this [issue](https://github.com/VictoriaMetrics/operator/issues/1017) for details.
|
||||
- [prometheus-converter](./README.md): fixes panic at `PodMonitor` convertion with configured `tlsConfig`. See this [issue](https://github.com/VictoriaMetrics/operator/issues/1025) for details.
|
||||
- [api](./api.md): return back `targetPort` for `VMPodScrape` definition. See this [issue](https://github.com/VictoriaMetrics/operator/issues/1015) for details.
|
||||
|
||||
## [v0.46.0](https://github.com/VictoriaMetrics/operator/releases/tag/v0.46.0) - 3 Jul 2024
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +0,0 @@
|
||||
---
|
||||
sort: 11
|
||||
weight: 11
|
||||
title: Variables
|
||||
menu:
|
||||
docs:
|
||||
parent: "operator"
|
||||
weight: 11
|
||||
---
|
||||
|
||||
<!-- this doc autogenerated - don't edit it manually -->
|
||||
@@ -6,10 +6,13 @@ menu:
|
||||
docs:
|
||||
parent: "operator"
|
||||
weight: 11
|
||||
aliases:
|
||||
- /operator/vars.html
|
||||
---
|
||||
|
||||
<!-- this doc autogenerated - don't edit it manually -->
|
||||
# Auto Generated vars for package config
|
||||
updated at Fri Jul 5 11:51:01 UTC 2024
|
||||
|
||||
|
||||
| variable name | variable default value | variable required | variable description |
|
||||
@@ -128,3 +131,4 @@ menu:
|
||||
| VM_PODWAITREADYINITDELAY | 10s | false | - |
|
||||
| VM_FORCERESYNCINTERVAL | 60s | false | configures force resync interval for VMAgent, VMAlert, VMAlertmanager and VMAuth. |
|
||||
| VM_ENABLESTRICTSECURITY | false | false | EnableStrictSecurity will add default `securityContext` to pods and containers created by operatorDefault PodSecurityContext include:1. RunAsNonRoot: true2. RunAsUser/RunAsGroup/FSGroup: 65534'65534' refers to 'nobody' in all the used default images like alpine, busybox.If you're using customize image, please make sure '65534' is a valid uid in there or specify SecurityContext.3. FSGroupChangePolicy: &onRootMismatchIf KubeVersion>=1.20, use `FSGroupChangePolicy="onRootMismatch"` to skip the recursive permission changewhen the root of the volume already has the correct permissions4. SeccompProfile:type: RuntimeDefaultUse `RuntimeDefault` seccomp profile by default, which is defined by the container runtime,instead of using the Unconfined (seccomp disabled) mode.Default container SecurityContext include:1. AllowPrivilegeEscalation: false2. ReadOnlyRootFilesystem: true3. Capabilities:drop:- allturn off `EnableStrictSecurity` by default, see https://github.com/VictoriaMetrics/operator/issues/749 for details |
|
||||
[envconfig-sum]: 3308f7a50407d573736a9fe441821a37
|
||||
|
||||
@@ -1547,28 +1547,28 @@ scrape_configs:
|
||||
|
||||
```
|
||||
|
||||
Each discovered target has an [`__address__`](https://docs.victoriametrics.com/relabeling.html#how-to-modify-scrape-urls-in-targets) label set
|
||||
Each discovered target has an [`__address__`](https://docs.victoriametrics.com/relabeling/#how-to-modify-scrape-urls-in-targets) label set
|
||||
to `<FQDN>:<port>`, where FQDN is discovered instance address and `<port>` is the port from the `vultr_sd_configs` (default port is `80`).
|
||||
|
||||
The following meta labels are available on discovered targets during [relabeling](https://docs.victoriametrics.com/vmagent.html#relabeling):
|
||||
The following meta labels are available on discovered targets during [relabeling](https://docs.victoriametrics.com/vmagent/#relabeling):
|
||||
|
||||
* `__meta_vultr_instance_id`: A unique ID for the VPS Instance.
|
||||
* `__meta_vultr_instance_label`: The user-supplied label for this instance.
|
||||
* `__meta_vultr_instance_os`: The [Operating System name](https://www.vultr.com/api/#operation/list-os).
|
||||
* `__meta_vultr_instance_os_id`: The [Operating System id](https://www.vultr.com/api/#operation/list-os) used by this instance.
|
||||
* `__meta_vultr_instance_region`: The [Region id](https://www.vultr.com/api/#operation/list-regions) 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 internal IP used by this instance, if set. Only relevant when a VPC is attached.
|
||||
* `__meta_vultr_instance_main_ipv6`: The main IPv6 network address.
|
||||
* `__meta_vultr_instance_hostname`: The hostname for this instance.
|
||||
* `__meta_vultr_instance_server_status`: The server health status, which could be `none`, `locked`, `installingbooting`, `ok`.
|
||||
* `__meta_vultr_instance_vcpu_count`: Number of vCPUs.
|
||||
* `__meta_vultr_instance_ram_mb`: The amount of RAM in MB.
|
||||
* `__meta_vultr_instance_allowed_bandwidth_gb`: Monthly bandwidth quota in GB.
|
||||
* `__meta_vultr_instance_disk_gb`: The size of the disk in GB.
|
||||
* `__meta_vultr_instance_features`: "auto_backups", "ipv6", "ddos_protection".
|
||||
* `__meta_vultr_instance_tags`: Tags to apply to the instance.
|
||||
* `__meta_vultr_instance_allowed_bandwidth_gb`: monthly bandwidth quota in GB.
|
||||
* `__meta_vultr_instance_disk_gb`: the size of the disk in GB.
|
||||
* `__meta_vultr_instance_features`: comma-separated list of features avabilable to instance, such as "auto_backups", "ipv6", "ddos_protection".
|
||||
* `__meta_vultr_instance_hostname`: hostname for this instance.
|
||||
* `__meta_vultr_instance_id`: unique ID for the VPS Instance.
|
||||
* `__meta_vultr_instance_internal_ip`: internal IP used by this instance, if set. Only relevant when a VPC is attached.
|
||||
* `__meta_vultr_instance_label`: user-supplied label for this instance.
|
||||
* `__meta_vultr_instance_main_ip`: main IPv4 address.
|
||||
* `__meta_vultr_instance_main_ipv6`: main IPv6 network address.
|
||||
* `__meta_vultr_instance_os`: [operating System name](https://www.vultr.com/api/#operation/list-os).
|
||||
* `__meta_vultr_instance_os_id`: [operating System id](https://www.vultr.com/api/#operation/list-os) used by this instance.
|
||||
* `__meta_vultr_instance_plan`: unique ID for the Plan.
|
||||
* `__meta_vultr_instance_ram_mb`: the amount of RAM in MB.
|
||||
* `__meta_vultr_instance_region`: [region id](https://www.vultr.com/api/#operation/list-regions) where the Instance is located.
|
||||
* `__meta_vultr_instance_server_status`: server health status, which could be `none`, `locked`, `installingbooting`, `ok`.
|
||||
* `__meta_vultr_instance_tags`: comma-separated list of tags applied to the instance.
|
||||
* `__meta_vultr_instance_vcpu_count`: the number of vCPUs.
|
||||
|
||||
The list of discovered Vultr targets is refreshed at the interval, which can be configured via `-promscrape.vultrSDCheckInterval` command-line flag, default: 30s.
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ In this case it may be a good idea to drop the aggregated data during the first
|
||||
just after the restart of `vmagent` or single-node VictoriaMetrics. This can be done via the following options:
|
||||
|
||||
- The `-streamAggr.ignoreFirstIntervals=N` command-line flag at `vmagent` and single-node VictoriaMetrics. This flag instructs skipping the first `N`
|
||||
[aggregation intervals](#stream-aggregation-config) just after the restart accross all the [configured stream aggregation configs](#configuration).
|
||||
[aggregation intervals](#stream-aggregation-config) just after the restart across all the [configured stream aggregation configs](#configuration).
|
||||
|
||||
The `-remoteWrite.streamAggr.ignoreFirstIntervals=N` command-line flag can be specified individually per each `-remoteWrite.url` at [vmagent](https://docs.victoriametrics.com/vmagent/).
|
||||
|
||||
@@ -710,7 +710,7 @@ See also [quantiles](#quantiles), [min](#min), [max](#max) and [avg](#avg).
|
||||
|
||||
`last` returns the last input [sample value](https://docs.victoriametrics.com/keyconcepts/#raw-samples) over the given `interval`.
|
||||
|
||||
The results of `last` is roughly equal to the the following [MetricsQL](https://docs.victoriametrics.com/metricsql/) query:
|
||||
The results of `last` is roughly equal to the following [MetricsQL](https://docs.victoriametrics.com/metricsql/) query:
|
||||
|
||||
```metricsql
|
||||
last_over_time(some_metric[interval])
|
||||
@@ -804,7 +804,7 @@ See also [count_samples](#count_samples) and [count_series](#count_series).
|
||||
`total` generates output [counter](https://docs.victoriametrics.com/keyconcepts/#counter) by summing the input counters over the given `interval`.
|
||||
`total` makes sense only for aggregating [counters](https://docs.victoriametrics.com/keyconcepts/#counter).
|
||||
|
||||
The results of `total` is roughly equal to the the following [MetricsQL](https://docs.victoriametrics.com/metricsql/) query:
|
||||
The results of `total` is roughly equal to the following [MetricsQL](https://docs.victoriametrics.com/metricsql/) query:
|
||||
|
||||
```metricsql
|
||||
sum(running_sum(increase_pure(some_counter)))
|
||||
@@ -841,7 +841,7 @@ See also [total_prometheus](#total_prometheus), [increase](#increase) and [incre
|
||||
`total_prometheus` generates output [counter](https://docs.victoriametrics.com/keyconcepts/#counter) by summing the input counters over the given `interval`.
|
||||
`total_prometheus` makes sense only for aggregating [counters](https://docs.victoriametrics.com/keyconcepts/#counter).
|
||||
|
||||
The results of `total_prometheus` is roughly equal to the the following [MetricsQL](https://docs.victoriametrics.com/metricsql/) query:
|
||||
The results of `total_prometheus` is roughly equal to the following [MetricsQL](https://docs.victoriametrics.com/metricsql/) query:
|
||||
|
||||
```metricsql
|
||||
sum(running_sum(increase_prometheus(some_counter)))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
sort: 38
|
||||
weight: 38
|
||||
editLink: https://github.com/VictoriaMetrics/victoriametrics-datasource/blob/main/README.md
|
||||
title: VictoriaMetrics datasource for Grafana
|
||||
menu:
|
||||
docs:
|
||||
@@ -15,8 +16,8 @@ aliases:
|
||||
|
||||
# VictoriaMetrics datasource for Grafana
|
||||
|
||||
The [VictoriaMetrics](http://docs.victoriametrics.com/) datasource plugin allows you to query and visualize
|
||||
data from VictoriaMetrics in Grafana.
|
||||
The [VictoriaMetrics datasource plugin](https://github.com/VictoriaMetrics/victoriametrics-datasource)
|
||||
allows to query and visualize data from VictoriaMetrics in Grafana.
|
||||
|
||||
* [Motivation](#motivation)
|
||||
* [Installation](#installation)
|
||||
@@ -158,7 +159,7 @@ Option 2. Using Grafana plugins section in `values.yaml`:
|
||||
|
||||
``` yaml
|
||||
plugins:
|
||||
- https://github.com/VictoriaMetrics/victoriametrics-datasource/releases/download/v0.8.2/victoriametrics-datasource-v0.8.2zip;victoriametrics-datasource
|
||||
- https://github.com/VictoriaMetrics/victoriametrics-datasource/releases/download/v0.8.2/victoriametrics-datasource-v0.8.2.zip;victoriametrics-datasource
|
||||
```
|
||||
|
||||
Option 3. Using init container:
|
||||
@@ -178,9 +179,9 @@ extraInitContainers:
|
||||
set -ex
|
||||
mkdir -p /var/lib/grafana/plugins/
|
||||
ver=$(curl -s https://api.github.com/repos/VictoriaMetrics/victoriametrics-datasource/releases/latest | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
curl -L https://github.com/VictoriaMetrics/victoriametrics-datasource/releases/download/$ver/victoriametrics-datasource-$ver.tar.gz -o /var/lib/grafana/plugins/plugin.tar.gz
|
||||
tar -xf /var/lib/grafana/plugins/plugin.tar.gz -C /var/lib/grafana/plugins/
|
||||
rm /var/lib/grafana/plugins/plugin.tar.gz
|
||||
curl -L https://github.com/VictoriaMetrics/victoriametrics-datasource/releases/download/$ver/victoriametrics-datasource-$ver.tar.gz -o /var/lib/grafana/plugins/vm-plugin.tar.gz
|
||||
tar -xf /var/lib/grafana/plugins/vm-plugin.tar.gz -C /var/lib/grafana/plugins/
|
||||
rm /var/lib/grafana/plugins/vm-plugin.tar.gz
|
||||
volumeMounts:
|
||||
# For grafana-operator users, change `name: storage` to `name: grafana-data`
|
||||
- name: storage
|
||||
@@ -229,18 +230,18 @@ spec:
|
||||
command: [ "/bin/sh" ]
|
||||
workingDir: "/var/lib/grafana"
|
||||
securityContext:
|
||||
runAsUser: 10001
|
||||
runAsUser: 472
|
||||
runAsNonRoot: true
|
||||
runAsGroup: 10001
|
||||
runAsGroup: 472
|
||||
args:
|
||||
- "-c"
|
||||
- |
|
||||
set -ex
|
||||
mkdir -p /var/lib/grafana/plugins/
|
||||
ver=$(curl -s https://api.github.com/repos/VictoriaMetrics/victoriametrics-datasource/releases/latest | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
curl -L https://github.com/VictoriaMetrics/victoriametrics-datasource/releases/download/$ver/victoriametrics-datasource-$ver.tar.gz -o /var/lib/grafana/plugins/plugin.tar.gz
|
||||
tar -xf /var/lib/grafana/plugins/plugin.tar.gz -C /var/lib/grafana/plugins/
|
||||
rm /var/lib/grafana/plugins/plugin.tar.gz
|
||||
curl -L https://github.com/VictoriaMetrics/victoriametrics-datasource/releases/download/$ver/victoriametrics-datasource-$ver.tar.gz -o /var/lib/grafana/plugins/vm-plugin.tar.gz
|
||||
tar -xf /var/lib/grafana/plugins/vm-plugin.tar.gz -C /var/lib/grafana/plugins/
|
||||
rm /var/lib/grafana/plugins/vm-plugin.tar.gz
|
||||
volumeMounts:
|
||||
- name: grafana-data
|
||||
mountPath: /var/lib/grafana
|
||||
@@ -258,9 +259,9 @@ This example uses init container to download and install plugin.
|
||||
|
||||
``` bash
|
||||
ver=$(curl -s https://api.github.com/repos/VictoriaMetrics/victoriametrics-datasource/releases/latest | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
curl -L https://github.com/VictoriaMetrics/victoriametrics-datasource/releases/download/$ver/victoriametrics-datasource-$ver.tar.gz -o /var/lib/grafana/plugins/plugin.tar.gz
|
||||
tar -xf /var/lib/grafana/plugins/plugin.tar.gz -C /var/lib/grafana/plugins/
|
||||
rm /var/lib/grafana/plugins/plugin.tar.gz
|
||||
curl -L https://github.com/VictoriaMetrics/victoriametrics-datasource/releases/download/$ver/victoriametrics-datasource-$ver.tar.gz -o /var/lib/grafana/plugins/vm-plugin.tar.gz
|
||||
tar -xf /var/lib/grafana/plugins/vm-plugin.tar.gz -C /var/lib/grafana/plugins/
|
||||
rm /var/lib/grafana/plugins/vm-plugin.tar.gz
|
||||
```
|
||||
|
||||
1. Restart Grafana
|
||||
|
||||
@@ -348,9 +348,10 @@ scrape_configs:
|
||||
target_label: vm_account_id
|
||||
```
|
||||
|
||||
`vmagent` can accept data via the same multitenant endpoints as `vminsert` at [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/)
|
||||
`vmagent` can accept data via the same multitenant endpoints (`/insert/<accountID>/<suffix>`) as `vminsert` at [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/)
|
||||
does according to [these docs](https://docs.victoriametrics.com/cluster-victoriametrics/#url-format) if `-enableMultitenantHandlers` command-line flag is set.
|
||||
In this case it automatically converts tenant identifiers to `vm_account_id` and `vm_project_id` labels before applying [relabeling](#relabeling) specified via `-remoteWrite.relabelConfig`
|
||||
In this case, vmagent automatically converts tenant identifiers from the URL to `vm_account_id` and `vm_project_id` labels.
|
||||
These tenant labels are added before applying [relabeling](#relabeling) specified via `-remoteWrite.relabelConfig`
|
||||
and `-remoteWrite.urlRelabelConfig` command-line flags. Metrics with `vm_account_id` and `vm_project_id` labels can be routed to the corresponding tenants
|
||||
when specifying `-remoteWrite.url` to [multitenant url at VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/#multitenancy-via-labels).
|
||||
|
||||
|
||||
@@ -418,6 +418,38 @@ in configured `-remoteRead.url`, weren't updated in the last `1h` (controlled by
|
||||
or received state doesn't match current `vmalert` rules configuration. `vmalert` marks successfully restored rules
|
||||
with `restored` label in [web UI](#web).
|
||||
|
||||
### Link to alert source
|
||||
|
||||
Alerting notifications sent by vmalert always contain a `source` link. By default, the link format
|
||||
is the following `http://<vmalert-addr>/vmalert/alert?group_id=<group_id>&alert_id=<alert_id>`. On click, it opens
|
||||
vmalert [web UI](https://docs.victoriametrics.com/vmalert/#web) to show the alert status and its fields.
|
||||
|
||||
It is possible to override the link format. For example, to make the link to [vmui](https://docs.victoriametrics.com/single-server-victoriametrics/#vmui)
|
||||
specify the following cmd-line flags:
|
||||
```
|
||||
./bin/vmalert \
|
||||
-external.url=http://<vmui-addr> \ # the hostname and port for datasource vmui
|
||||
-external.alert.source='vmui/#/?g0.expr={{.Expr|queryEscape}}' # the path built using alert expr
|
||||
```
|
||||
|
||||
Now, all `source` links will lead to `http://<vmui-addr>/vmui/#/?g0.expr=$expr`, where $expr is an alerting rule
|
||||
expression.
|
||||
|
||||
The `-external.alert.source` cmd-line flag supports [templating](https://docs.victoriametrics.com/vmalert/#templating)
|
||||
and allows using labels and extra data related to the alert. For example, see the following link to Grafana:
|
||||
```
|
||||
./bin/vmalert \
|
||||
-external.url=http://<grafana-addr> \ # the hostname and port for Grafana
|
||||
-external.alert.source='explore?left={"datasource":"VictoriaMetrics","queries":[{"expr":{{ .Expr|jsonEscape|queryEscape }},"refId":"A"}],"range":{"from":"{{ .ActiveAt.UnixMilli }}","to":"now"}}'
|
||||
```
|
||||
|
||||
In this example, `-external.alert.source` will lead to Grafana's Explore page with `expr` field equal to alert expression,
|
||||
and time range will be selected starting from `"from":"{{ .ActiveAt.UnixMilli }}"` when alert became active.
|
||||
|
||||
In addition to `source` link, some extra links could be added to alert's [annotations](https://docs.victoriametrics.com/vmalert/#alerting-rules)
|
||||
field. See [how we use them](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/839596c00df123c639d1244b28ee8137dfc9609c/deployment/docker/alerts-cluster.yml#L43)
|
||||
to link alerting rule and the corresponding panel on Grafana dashboard.
|
||||
|
||||
### Multitenancy
|
||||
|
||||
There are the following approaches exist for alerting and recording rules across
|
||||
@@ -705,8 +737,8 @@ To run vmalert in `replay` mode:
|
||||
./bin/vmalert -rule=path/to/your.rules \ # path to files with rules you usually use with vmalert
|
||||
-datasource.url=http://localhost:8428 \ # Prometheus HTTP API compatible datasource
|
||||
-remoteWrite.url=http://localhost:8428 \ # remote write compatible storage to persist results
|
||||
-replay.timeFrom=2021-05-11T07:21:43Z \ # time from begin replay
|
||||
-replay.timeTo=2021-05-29T18:40:43Z # time to finish replay
|
||||
-replay.timeFrom=2021-05-11T07:21:43Z \ # to start replay from
|
||||
-replay.timeTo=2021-05-29T18:40:43Z # to finish replay by, is optional
|
||||
```
|
||||
|
||||
The output of the command will look like the following:
|
||||
@@ -738,12 +770,12 @@ max range per request: 8h20m0s
|
||||
```
|
||||
|
||||
In `replay` mode all groups are executed sequentially one-by-one. Rules within the group are
|
||||
executed sequentially as well (`concurrency` setting is ignored). Vmalert sends rule's expression
|
||||
executed sequentially as well (`concurrency` setting is ignored). vmalert sends rule's expression
|
||||
to [/query_range](https://docs.victoriametrics.com/keyconcepts/#range-query) endpoint
|
||||
of the configured `-datasource.url`. Returned data is then processed according to the rule type and
|
||||
backfilled to `-remoteWrite.url` via [remote Write protocol](https://prometheus.io/docs/prometheus/latest/storage/#remote-storage-integrations).
|
||||
Vmalert respects `evaluationInterval` value set by flag or per-group during the replay.
|
||||
Vmalert automatically disables caching on VictoriaMetrics side by sending `nocache=1` param. It allows
|
||||
vmalert respects `evaluationInterval` value set by flag or per-group during the replay.
|
||||
vmalert automatically disables caching on VictoriaMetrics side by sending `nocache=1` param. It allows
|
||||
to prevent cache pollution and unwanted time range boundaries adjustment during backfilling.
|
||||
|
||||
#### Recording rules
|
||||
@@ -1064,7 +1096,7 @@ The shortlist of configuration flags is the following:
|
||||
-evaluationInterval duration
|
||||
How often to evaluate the rules (default 1m0s)
|
||||
-external.alert.source string
|
||||
External Alert Source allows to override the Source link for alerts sent to AlertManager for cases where you want to build a custom link to Grafana, Prometheus or any other service. Supports templating - see https://docs.victoriametrics.com/vmalert/#templating . For example, link to Grafana: -external.alert.source='explore?orgId=1&left={"datasource":"VictoriaMetrics","queries":[{"expr":{{$expr|jsonEscape|queryEscape}},"refId":"A"}],"range":{"from":"now-1h","to":"now"}}'. Link to VMUI: -external.alert.source='vmui/#/?g0.expr={{.Expr|queryEscape}}'. If empty 'vmalert/alert?group_id={{.GroupID}}&alert_id={{.AlertID}}' is used.
|
||||
External Alert Source allows to override the Source link for alerts sent to AlertManager for cases where you want to build a custom link to Grafana, Prometheus or any other service. Supports templating - see https://docs.victoriametrics.com/vmalert/#templating . For example, link to Grafana: -external.alert.source='explore?orgId=1&left={"datasource":"VictoriaMetrics","queries":[{"expr":{{.Expr|jsonEscape|queryEscape}},"refId":"A"}],"range":{"from":"now-1h","to":"now"}}'. Link to VMUI: -external.alert.source='vmui/#/?g0.expr={{.Expr|queryEscape}}'. If empty 'vmalert/alert?group_id={{.GroupID}}&alert_id={{.AlertID}}' is used.
|
||||
-external.label array
|
||||
Optional label in the form 'Name=value' to add to all generated recording rules and alerts. Pass multiple -label flags in order to add multiple label sets.
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
@@ -1376,9 +1408,9 @@ The shortlist of configuration flags is the following:
|
||||
-replay.rulesDelay duration
|
||||
Delay between rules evaluation within the group. Could be important if there are chained rules inside the group and processing need to wait for previous rule results to be persisted by remote storage before evaluating the next rule.Keep it equal or bigger than -remoteWrite.flushInterval. (default 1s)
|
||||
-replay.timeFrom string
|
||||
The time filter in RFC3339 format to select time series with timestamp equal or higher than provided value. E.g. '2020-01-01T20:07:00Z'
|
||||
The time filter in RFC3339 format to start the replay from. E.g. '2020-01-01T20:07:00Z'
|
||||
-replay.timeTo string
|
||||
The time filter in RFC3339 format to select timeseries with timestamp equal or lower than provided value. E.g. '2020-01-01T20:07:00Z'
|
||||
The time filter in RFC3339 format to finish the replay by. E.g. '2020-01-01T20:07:00Z'. By default, is set to the current time.
|
||||
-rule array
|
||||
Path to the files or http url with alerting and/or recording rules.
|
||||
Supports hierarchical patterns and regexpes.
|
||||
|
||||
@@ -313,7 +313,7 @@ type ScrapeConfig struct {
|
||||
NomadSDConfigs []nomad.SDConfig `yaml:"nomad_sd_configs,omitempty"`
|
||||
OpenStackSDConfigs []openstack.SDConfig `yaml:"openstack_sd_configs,omitempty"`
|
||||
StaticConfigs []StaticConfig `yaml:"static_configs,omitempty"`
|
||||
VultrConfigs []vultr.SDConfig `yaml:"vultr_configs,omitempty"`
|
||||
VultrSDConfigs []vultr.SDConfig `yaml:"vultr_configs,omitempty"`
|
||||
YandexCloudSDConfigs []yandexcloud.SDConfig `yaml:"yandexcloud_sd_configs,omitempty"`
|
||||
|
||||
// These options are supported only by lib/promscrape.
|
||||
@@ -394,8 +394,11 @@ func (sc *ScrapeConfig) mustStop() {
|
||||
for i := range sc.OpenStackSDConfigs {
|
||||
sc.OpenStackSDConfigs[i].MustStop()
|
||||
}
|
||||
for i := range sc.VultrConfigs {
|
||||
sc.VultrConfigs[i].MustStop()
|
||||
for i := range sc.VultrSDConfigs {
|
||||
sc.VultrSDConfigs[i].MustStop()
|
||||
}
|
||||
for i := range sc.YandexCloudSDConfigs {
|
||||
sc.YandexCloudSDConfigs[i].MustStop()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -757,8 +760,8 @@ func (cfg *Config) getOpenStackSDScrapeWork(prev []*ScrapeWork) []*ScrapeWork {
|
||||
// getVultrSDScrapeWork returns `vultr_sd_configs` ScrapeWork from cfg.
|
||||
func (cfg *Config) getVultrSDScrapeWork(prev []*ScrapeWork) []*ScrapeWork {
|
||||
visitConfigs := func(sc *ScrapeConfig, visitor func(sdc targetLabelsGetter)) {
|
||||
for i := range sc.VultrConfigs {
|
||||
visitor(&sc.VultrConfigs[i])
|
||||
for i := range sc.VultrSDConfigs {
|
||||
visitor(&sc.VultrSDConfigs[i])
|
||||
}
|
||||
}
|
||||
return cfg.getScrapeWorkGeneric(visitConfigs, "vultr_sd_config", prev)
|
||||
|
||||
@@ -2,6 +2,7 @@ package vultr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
|
||||
)
|
||||
@@ -11,22 +12,7 @@ type apiConfig struct {
|
||||
c *discoveryutils.Client
|
||||
port int
|
||||
|
||||
listParams
|
||||
}
|
||||
|
||||
// listParams is the query params of vultr ListInstance API.
|
||||
type listParams struct {
|
||||
// paging params are not exposed to user, they will be filled
|
||||
// dynamically during request. See `getInstances`.
|
||||
// perPage int
|
||||
// cursor string
|
||||
|
||||
// API query params for filtering.
|
||||
label string
|
||||
mainIP string
|
||||
region string
|
||||
firewallGroupID string
|
||||
hostname string
|
||||
listQueryParams string
|
||||
}
|
||||
|
||||
// getAPIConfig get or create API config from configMap.
|
||||
@@ -48,6 +34,10 @@ func newAPIConfig(sdc *SDConfig, baseDir string) (*apiConfig, error) {
|
||||
// See: https://www.vultr.com/api/
|
||||
apiServer := "https://api.vultr.com"
|
||||
|
||||
if sdc.HTTPClientConfig.BearerToken == nil {
|
||||
return nil, fmt.Errorf("missing `bearer_token` option")
|
||||
}
|
||||
|
||||
ac, err := sdc.HTTPClientConfig.NewConfig(baseDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse auth config: %w", err)
|
||||
@@ -61,16 +51,31 @@ func newAPIConfig(sdc *SDConfig, baseDir string) (*apiConfig, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create client for %q: %w", apiServer, err)
|
||||
}
|
||||
|
||||
// Prepare additional query params for list instance API.
|
||||
// See https://www.vultr.com/api/#tag/instances/operation/list-instances
|
||||
var qp url.Values
|
||||
if sdc.Label != "" {
|
||||
qp.Set("label", sdc.Label)
|
||||
}
|
||||
if sdc.MainIP != "" {
|
||||
qp.Set("main_ip", sdc.MainIP)
|
||||
}
|
||||
if sdc.Region != "" {
|
||||
qp.Set("region", sdc.Region)
|
||||
}
|
||||
if sdc.FirewallGroupID != "" {
|
||||
qp.Set("firewall_group_id", sdc.FirewallGroupID)
|
||||
}
|
||||
if sdc.Hostname != "" {
|
||||
qp.Set("hostname", sdc.Hostname)
|
||||
}
|
||||
|
||||
cfg := &apiConfig{
|
||||
c: c,
|
||||
port: port,
|
||||
listParams: listParams{
|
||||
label: sdc.Label,
|
||||
mainIP: sdc.MainIP,
|
||||
region: sdc.Region,
|
||||
firewallGroupID: sdc.FirewallGroupID,
|
||||
hostname: sdc.Hostname,
|
||||
},
|
||||
|
||||
listQueryParams: qp.Encode(),
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
@@ -2,15 +2,30 @@ package vultr
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
|
||||
)
|
||||
|
||||
func TestNewAPIConfig(t *testing.T) {
|
||||
|
||||
func TestNewAPIConfig_Failure(t *testing.T) {
|
||||
sdc := &SDConfig{}
|
||||
baseDir := "."
|
||||
_, err := newAPIConfig(sdc, baseDir)
|
||||
if err != nil {
|
||||
t.Errorf("newAPIConfig failed with, err: %v", err)
|
||||
return
|
||||
if err == nil {
|
||||
t.Fatalf("expecting non-nil error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewAPIConfig_Success(t *testing.T) {
|
||||
sdc := &SDConfig{
|
||||
HTTPClientConfig: promauth.HTTPClientConfig{
|
||||
BearerToken: &promauth.Secret{
|
||||
S: "foobar",
|
||||
},
|
||||
},
|
||||
}
|
||||
baseDir := "."
|
||||
_, err := newAPIConfig(sdc, baseDir)
|
||||
if err != nil {
|
||||
t.Fatalf("newAPIConfig failed with, err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,21 +4,20 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||
)
|
||||
|
||||
// ListInstanceResponse is the response structure of Vultr ListInstance API.
|
||||
type ListInstanceResponse struct {
|
||||
Instances []Instance `json:"instances"`
|
||||
Meta *Meta `json:"Meta"`
|
||||
Meta Meta `json:"meta"`
|
||||
}
|
||||
|
||||
// Instance represents Vultr Instance (VPS).
|
||||
//
|
||||
// See: https://github.com/vultr/govultr/blob/5125e02e715ae6eb3ce854f0e7116c7ce545a710/instance.go#L81
|
||||
type Instance struct {
|
||||
ID string `json:"id"`
|
||||
Os string `json:"os"`
|
||||
OS string `json:"os"`
|
||||
RAM int `json:"ram"`
|
||||
Disk int `json:"disk"`
|
||||
MainIP string `json:"main_ip"`
|
||||
@@ -30,39 +29,22 @@ type Instance struct {
|
||||
Hostname string `json:"hostname"`
|
||||
Label string `json:"label"`
|
||||
InternalIP string `json:"internal_ip"`
|
||||
OsID int `json:"os_id"`
|
||||
OSID int `json:"os_id"`
|
||||
Features []string `json:"features"`
|
||||
Plan string `json:"plan"`
|
||||
Tags []string `json:"tags"`
|
||||
|
||||
// The following fields are defined in the response but are not used during service discovery.
|
||||
//DefaultPassword string `json:"default_password,omitempty"`
|
||||
//DateCreated string `json:"date_created"`
|
||||
//Status string `json:"status"`
|
||||
//PowerStatus string `json:"power_status"`
|
||||
//NetmaskV4 string `json:"netmask_v4"`
|
||||
//GatewayV4 string `json:"gateway_v4"`
|
||||
//V6Network string `json:"v6_network"`
|
||||
//V6NetworkSize int `json:"v6_network_size"`
|
||||
//// Deprecated: Tag should no longer be used. Instead, use Tags.
|
||||
//Tag string `json:"tag"`
|
||||
//KVM string `json:"kvm"`
|
||||
//AppID int `json:"app_id"`
|
||||
//ImageID string `json:"image_id"`
|
||||
//FirewallGroupID string `json:"firewall_group_id"`
|
||||
//UserScheme string `json:"user_scheme"`
|
||||
}
|
||||
|
||||
// Meta represents the available pagination information
|
||||
//
|
||||
// See https://www.vultr.com/api/#section/Introduction/Meta-and-Pagination
|
||||
type Meta struct {
|
||||
Total int `json:"total"`
|
||||
Links *Links
|
||||
Links Links `json:"links"`
|
||||
}
|
||||
|
||||
// Links represent the next/previous cursor in your pagination calls
|
||||
type Links struct {
|
||||
Next string `json:"next"`
|
||||
Prev string `json:"prev"`
|
||||
}
|
||||
|
||||
// getInstances retrieve instance from Vultr HTTP API.
|
||||
@@ -70,39 +52,30 @@ func getInstances(cfg *apiConfig) ([]Instance, error) {
|
||||
var instances []Instance
|
||||
|
||||
// prepare GET params
|
||||
params := url.Values{}
|
||||
params.Set("per_page", "100")
|
||||
params.Set("label", cfg.label)
|
||||
params.Set("main_ip", cfg.mainIP)
|
||||
params.Set("region", cfg.region)
|
||||
params.Set("firewall_group_id", cfg.firewallGroupID)
|
||||
params.Set("hostname", cfg.hostname)
|
||||
queryParams := cfg.listQueryParams
|
||||
|
||||
// send request to vultr API
|
||||
for {
|
||||
// See: https://www.vultr.com/api/#tag/instances/operation/list-instances
|
||||
path := fmt.Sprintf("/v2/instances?%s", params.Encode())
|
||||
resp, err := cfg.c.GetAPIResponse(path)
|
||||
path := "/v2/instances?" + queryParams + "&per_page=100"
|
||||
data, err := cfg.c.GetAPIResponse(path)
|
||||
if err != nil {
|
||||
logger.Errorf("get response from vultr failed, path:%s, err: %v", path, err)
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("cannot get Vultr response from %q: %w", path, err)
|
||||
}
|
||||
|
||||
var listInstanceResp ListInstanceResponse
|
||||
if err = json.Unmarshal(resp, &listInstanceResp); err != nil {
|
||||
logger.Errorf("unmarshal response from vultr failed, err: %v", err)
|
||||
return nil, err
|
||||
var resp ListInstanceResponse
|
||||
if err := json.Unmarshal(data, &resp); err != nil {
|
||||
return nil, fmt.Errorf("cannot unmarshal ListInstanceResponse obtained from %q: %w; response=%q", path, err, data)
|
||||
}
|
||||
|
||||
instances = append(instances, listInstanceResp.Instances...)
|
||||
instances = append(instances, resp.Instances...)
|
||||
|
||||
if listInstanceResp.Meta != nil && listInstanceResp.Meta.Links != nil && listInstanceResp.Meta.Links.Next != "" {
|
||||
// if `next page` is available, set the cursor param and request again.
|
||||
params.Set("cursor", listInstanceResp.Meta.Links.Next)
|
||||
} else {
|
||||
// otherwise exit the loop
|
||||
if resp.Meta.Links.Next == "" {
|
||||
break
|
||||
}
|
||||
|
||||
// if `next page` is available, set the cursor param and request again.
|
||||
queryParams = cfg.listQueryParams + "&cursor=" + url.QueryEscape(resp.Meta.Links.Next)
|
||||
}
|
||||
|
||||
return instances, nil
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package vultr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@@ -9,175 +8,146 @@ import (
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
|
||||
)
|
||||
|
||||
// TestGetInstances runs general test cases for GetInstances
|
||||
func TestGetInstances(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
apiResponse string
|
||||
apiError bool
|
||||
expectError bool
|
||||
expectResponse []Instance
|
||||
}{
|
||||
{
|
||||
name: "success response",
|
||||
apiResponse: mockListInstanceSuccessResp,
|
||||
apiError: false,
|
||||
expectError: false,
|
||||
expectResponse: expectSuccessInstances,
|
||||
},
|
||||
{
|
||||
name: "failed response",
|
||||
apiResponse: mockListInstanceFailedResp,
|
||||
apiError: true,
|
||||
expectError: true,
|
||||
expectResponse: nil,
|
||||
},
|
||||
}
|
||||
func TestGetInstances_Success(t *testing.T) {
|
||||
s := newMockVultrServer(func() []byte {
|
||||
const resp = `{
|
||||
"instances": [{
|
||||
"id": "fake-id-07f7-4b68-88ac-fake-id",
|
||||
"os": "Ubuntu 22.04 x64",
|
||||
"ram": 1024,
|
||||
"disk": 25,
|
||||
"main_ip": "64.176.84.27",
|
||||
"vcpu_count": 1,
|
||||
"region": "sgp",
|
||||
"plan": "vc2-1c-1gb",
|
||||
"date_created": "2024-04-05T05:41:28+00:00",
|
||||
"status": "active",
|
||||
"allowed_bandwidth": 1,
|
||||
"netmask_v4": "255.255.254.0",
|
||||
"gateway_v4": "64.176.63.2",
|
||||
"power_status": "running",
|
||||
"server_status": "installingbooting",
|
||||
"v6_network": "2002:18f0:4100:263a::",
|
||||
"v6_main_ip": "2002:18f0:4100:263a:5300:07ff:fdd7:691c",
|
||||
"v6_network_size": 64,
|
||||
"label": "vultr-sd",
|
||||
"internal_ip": "",
|
||||
"kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=secret_data_string",
|
||||
"hostname": "vultr-sd",
|
||||
"tag": "",
|
||||
"tags": [],
|
||||
"os_id": 1743,
|
||||
"app_id": 0,
|
||||
"image_id": "",
|
||||
"firewall_group_id": "",
|
||||
"features": ["ipv6"],
|
||||
"user_scheme": "root"
|
||||
}]
|
||||
}`
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Prepare a mock Vultr server.
|
||||
mockServer := newMockVultrServer(func() ([]byte, error) {
|
||||
var e error
|
||||
if tt.apiError {
|
||||
e = errors.New("mock error")
|
||||
}
|
||||
return []byte(tt.apiResponse), e
|
||||
})
|
||||
|
||||
// Prepare a discovery HTTP client who calls mock server.
|
||||
client, _ := discoveryutils.NewClient(mockServer.URL, nil, nil, nil, &promauth.HTTPClientConfig{})
|
||||
cfg := &apiConfig{
|
||||
c: client,
|
||||
}
|
||||
|
||||
// execute `getInstances`
|
||||
instances, err := getInstances(cfg)
|
||||
|
||||
// evaluate test result
|
||||
if tt.expectError != (err != nil) {
|
||||
t.Errorf("getInstances expect (error != nil): %t, got error: %v", tt.expectError, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.expectResponse, instances) {
|
||||
t.Errorf("getInstances expect result: %v, got: %v", tt.expectResponse, instances)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetInstancesPaging run test cases for response with multiple pages.
|
||||
func TestGetInstancesPaging(t *testing.T) {
|
||||
// Prepare a mock Vultr server.
|
||||
// requestCount control the mock response for different page request.
|
||||
requestCount := 0
|
||||
|
||||
mockServer := newMockVultrServer(func() ([]byte, error) {
|
||||
// for the 1st request, response with `next` cursor
|
||||
if requestCount == 0 {
|
||||
requestCount++
|
||||
return []byte(mockListInstanceSuccessPage0Resp), nil
|
||||
}
|
||||
// for the 2nd+ request, response with `prev` cursor and empty `next`.
|
||||
return []byte(mockListInstanceSuccessPage1Resp), nil
|
||||
return []byte(resp)
|
||||
})
|
||||
|
||||
// Prepare a discovery HTTP client who calls mock server.
|
||||
client, _ := discoveryutils.NewClient(mockServer.URL, nil, nil, nil, &promauth.HTTPClientConfig{})
|
||||
client, err := discoveryutils.NewClient(s.URL, nil, nil, nil, &promauth.HTTPClientConfig{})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error wen creating http client: %s", err)
|
||||
}
|
||||
cfg := &apiConfig{
|
||||
c: client,
|
||||
}
|
||||
|
||||
// execute `getInstances`
|
||||
instances, err := getInstances(cfg)
|
||||
|
||||
// evaluate test result
|
||||
if err != nil {
|
||||
t.Errorf("getInstances expect error: %v, got error: %v", nil, err)
|
||||
t.Fatalf("unexpected error in getInstances(): %s", err)
|
||||
}
|
||||
|
||||
expectedInstances := []Instance{
|
||||
{
|
||||
ID: "fake-id-07f7-4b68-88ac-fake-id",
|
||||
OS: "Ubuntu 22.04 x64",
|
||||
RAM: 1024,
|
||||
Disk: 25,
|
||||
MainIP: "64.176.84.27",
|
||||
VCPUCount: 1,
|
||||
Region: "sgp",
|
||||
Plan: "vc2-1c-1gb",
|
||||
AllowedBandwidth: 1,
|
||||
ServerStatus: "installingbooting",
|
||||
V6MainIP: "2002:18f0:4100:263a:5300:07ff:fdd7:691c",
|
||||
Label: "vultr-sd",
|
||||
InternalIP: "",
|
||||
Hostname: "vultr-sd",
|
||||
Tags: []string{},
|
||||
OSID: 1743,
|
||||
Features: []string{"ipv6"},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(instances, expectedInstances) {
|
||||
t.Fatalf("unexpected result\ngot\n%#v\nwant\n%#v", instances, expectedInstances)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetInstances_Failure(t *testing.T) {
|
||||
s := newMockVultrServer(func() []byte {
|
||||
return []byte("some error")
|
||||
})
|
||||
|
||||
// Prepare a discovery HTTP client who calls mock server.
|
||||
client, err := discoveryutils.NewClient(s.URL, nil, nil, nil, &promauth.HTTPClientConfig{})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error wen creating http client: %s", err)
|
||||
}
|
||||
cfg := &apiConfig{
|
||||
c: client,
|
||||
}
|
||||
|
||||
// execute `getInstances`
|
||||
if _, err := getInstances(cfg); err == nil {
|
||||
t.Fatalf("expecting non-nil error from getInstances()")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetInstances_Paging(t *testing.T) {
|
||||
// Prepare a mock Vultr server.
|
||||
// requestCount control the mock response for different page request.
|
||||
requestCount := 0
|
||||
s := newMockVultrServer(func() []byte {
|
||||
// for the 1st request, response with `next` cursor
|
||||
if requestCount == 0 {
|
||||
requestCount++
|
||||
return []byte(mockListInstanceSuccessPage0Resp)
|
||||
}
|
||||
// for the 2nd+ request, response with empty `next`.
|
||||
return []byte(mockListInstanceSuccessPage1Resp)
|
||||
})
|
||||
|
||||
// Prepare a discovery HTTP client who calls mock server.
|
||||
client, err := discoveryutils.NewClient(s.URL, nil, nil, nil, &promauth.HTTPClientConfig{})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error wen creating http client: %s", err)
|
||||
}
|
||||
cfg := &apiConfig{
|
||||
c: client,
|
||||
}
|
||||
|
||||
// execute `getInstances`
|
||||
instances, err := getInstances(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error in getInstances(): %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(expectSuccessPagingInstances, instances) {
|
||||
t.Errorf("getInstances expect result: %v, got: %v", expectSuccessPagingInstances, instances)
|
||||
t.Fatalf("unexpected getInstances() result\ngot\n%#v\nwant\n%#v", instances, expectSuccessPagingInstances)
|
||||
}
|
||||
}
|
||||
|
||||
// ------------ Test dataset ------------
|
||||
var (
|
||||
// mockListInstanceSuccessResp is crawled from a real-world response of ListInstance API
|
||||
// with sensitive info removed/modified.
|
||||
mockListInstanceSuccessResp = `{
|
||||
"instances": [{
|
||||
"id": "fake-id-07f7-4b68-88ac-fake-id",
|
||||
"os": "Ubuntu 22.04 x64",
|
||||
"ram": 1024,
|
||||
"disk": 25,
|
||||
"main_ip": "64.176.84.27",
|
||||
"vcpu_count": 1,
|
||||
"region": "sgp",
|
||||
"plan": "vc2-1c-1gb",
|
||||
"date_created": "2024-04-05T05:41:28+00:00",
|
||||
"status": "active",
|
||||
"allowed_bandwidth": 1,
|
||||
"netmask_v4": "255.255.254.0",
|
||||
"gateway_v4": "64.176.63.2",
|
||||
"power_status": "running",
|
||||
"server_status": "installingbooting",
|
||||
"v6_network": "2002:18f0:4100:263a::",
|
||||
"v6_main_ip": "2002:18f0:4100:263a:5300:07ff:fdd7:691c",
|
||||
"v6_network_size": 64,
|
||||
"label": "vultr-sd",
|
||||
"internal_ip": "",
|
||||
"kvm": "https:\/\/my.vultr.com\/subs\/vps\/novnc\/api.php?data=secret_data_string",
|
||||
"hostname": "vultr-sd",
|
||||
"tag": "",
|
||||
"tags": [],
|
||||
"os_id": 1743,
|
||||
"app_id": 0,
|
||||
"image_id": "",
|
||||
"firewall_group_id": "",
|
||||
"features": ["ipv6"],
|
||||
"user_scheme": "root"
|
||||
}],
|
||||
"meta": {
|
||||
"total": 1,
|
||||
"links": {
|
||||
"next": "",
|
||||
"prev": ""
|
||||
}
|
||||
}
|
||||
}`
|
||||
expectSuccessInstances = []Instance{
|
||||
{
|
||||
ID: "fake-id-07f7-4b68-88ac-fake-id",
|
||||
Os: "Ubuntu 22.04 x64",
|
||||
RAM: 1024,
|
||||
Disk: 25,
|
||||
MainIP: "64.176.84.27",
|
||||
VCPUCount: 1,
|
||||
Region: "sgp",
|
||||
Plan: "vc2-1c-1gb",
|
||||
AllowedBandwidth: 1,
|
||||
ServerStatus: "installingbooting",
|
||||
V6MainIP: "2002:18f0:4100:263a:5300:07ff:fdd7:691c",
|
||||
Label: "vultr-sd",
|
||||
InternalIP: "",
|
||||
Hostname: "vultr-sd",
|
||||
Tags: []string{},
|
||||
OsID: 1743,
|
||||
Features: []string{"ipv6"},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
mockListInstanceFailedResp = `{"error":"Invalid API token.","status":401}`
|
||||
)
|
||||
|
||||
var (
|
||||
// mockListInstanceSuccessPage0Resp contains `next` cursor
|
||||
mockListInstanceSuccessPage0Resp = `{
|
||||
"instances": [{
|
||||
"id": "fake-id-07f7-4b68-88ac-fake-id",
|
||||
"id": "1-fake-id-07f7-4b68-88ac-fake-id",
|
||||
"os": "Ubuntu 22.04 x64",
|
||||
"ram": 1024,
|
||||
"disk": 25,
|
||||
@@ -209,17 +179,15 @@ var (
|
||||
"user_scheme": "root"
|
||||
}],
|
||||
"meta": {
|
||||
"total": 2,
|
||||
"links": {
|
||||
"next": "fake-cursor-string",
|
||||
"prev": ""
|
||||
"next": "fake-cursor-string"
|
||||
}
|
||||
}
|
||||
}`
|
||||
// mockListInstanceSuccessPage1Resp contains `prev` cursor
|
||||
// mockListInstanceSuccessPage1Resp contains empty 'next' cursor
|
||||
mockListInstanceSuccessPage1Resp = `{
|
||||
"instances": [{
|
||||
"id": "fake-id-07f7-4b68-88ac-fake-id",
|
||||
"id": "2-fake-id-07f7-4b68-88ac-fake-id",
|
||||
"os": "Ubuntu 22.04 x64",
|
||||
"ram": 1024,
|
||||
"disk": 25,
|
||||
@@ -251,17 +219,15 @@ var (
|
||||
"user_scheme": "root"
|
||||
}],
|
||||
"meta": {
|
||||
"total": 2,
|
||||
"links": {
|
||||
"next": "",
|
||||
"prev": "fake-cursor-string"
|
||||
"next": ""
|
||||
}
|
||||
}
|
||||
}`
|
||||
expectSuccessPagingInstances = []Instance{
|
||||
{
|
||||
ID: "fake-id-07f7-4b68-88ac-fake-id",
|
||||
Os: "Ubuntu 22.04 x64",
|
||||
ID: "1-fake-id-07f7-4b68-88ac-fake-id",
|
||||
OS: "Ubuntu 22.04 x64",
|
||||
RAM: 1024,
|
||||
Disk: 25,
|
||||
MainIP: "64.176.84.27",
|
||||
@@ -275,12 +241,12 @@ var (
|
||||
InternalIP: "",
|
||||
Hostname: "vultr-sd",
|
||||
Tags: []string{},
|
||||
OsID: 1743,
|
||||
OSID: 1743,
|
||||
Features: []string{"ipv6"},
|
||||
},
|
||||
{
|
||||
ID: "fake-id-07f7-4b68-88ac-fake-id",
|
||||
Os: "Ubuntu 22.04 x64",
|
||||
ID: "2-fake-id-07f7-4b68-88ac-fake-id",
|
||||
OS: "Ubuntu 22.04 x64",
|
||||
RAM: 1024,
|
||||
Disk: 25,
|
||||
MainIP: "64.176.84.27",
|
||||
@@ -294,7 +260,7 @@ var (
|
||||
InternalIP: "",
|
||||
Hostname: "vultr-sd",
|
||||
Tags: []string{},
|
||||
OsID: 1743,
|
||||
OSID: 1743,
|
||||
Features: []string{"ipv6"},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,40 +1,23 @@
|
||||
package vultr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
)
|
||||
|
||||
func newMockVultrServer(jsonResponse func() ([]byte, error)) *vultrServer {
|
||||
rw := &vultrServer{}
|
||||
rw.Server = httptest.NewServer(http.HandlerFunc(rw.handler))
|
||||
rw.jsonResponse = jsonResponse
|
||||
return rw
|
||||
}
|
||||
|
||||
type vultrServer struct {
|
||||
type mockVultrServer struct {
|
||||
*httptest.Server
|
||||
jsonResponse func() ([]byte, error)
|
||||
responseFunc func() []byte
|
||||
}
|
||||
|
||||
func (rw *vultrServer) err(w http.ResponseWriter, err error) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
func newMockVultrServer(responseFunc func() []byte) *mockVultrServer {
|
||||
var s mockVultrServer
|
||||
s.responseFunc = responseFunc
|
||||
s.Server = httptest.NewServer(http.HandlerFunc(s.handler))
|
||||
return &s
|
||||
}
|
||||
|
||||
func (rw *vultrServer) handler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
rw.err(w, fmt.Errorf("bad method %q", r.Method))
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := rw.jsonResponse()
|
||||
if err != nil {
|
||||
rw.err(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(resp)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
func (s *mockVultrServer) handler(w http.ResponseWriter, _ *http.Request) {
|
||||
data := s.responseFunc()
|
||||
w.Write(data)
|
||||
}
|
||||
|
||||
@@ -13,16 +13,13 @@ import (
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/proxy"
|
||||
)
|
||||
|
||||
const (
|
||||
separator = ","
|
||||
)
|
||||
|
||||
// SDCheckInterval defines interval for docker targets refresh.
|
||||
// SDCheckInterval defines interval for Vultr targets refresh.
|
||||
var SDCheckInterval = flag.Duration("promscrape.vultrSDCheckInterval", 30*time.Second, "Interval for checking for changes in Vultr. "+
|
||||
"This works only if vultr_sd_configs is configured in '-promscrape.config' file. "+
|
||||
"See https://docs.victoriametrics.com/sd_configs.html#vultr_sd_configs for details")
|
||||
|
||||
// SDConfig represents service discovery config for Vultr.
|
||||
//
|
||||
// See: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#vultr_sd_config
|
||||
// Additional query params are supported, while Prometheus only supports `Port` and HTTP auth.
|
||||
type SDConfig struct {
|
||||
@@ -62,7 +59,7 @@ func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
|
||||
|
||||
// MustStop stops further usage for sdc.
|
||||
func (sdc *SDConfig) MustStop() {
|
||||
configMap.Delete(sdc)
|
||||
_ = configMap.Delete(sdc)
|
||||
}
|
||||
|
||||
// getInstanceLabels returns labels for vultr instances obtained from the given cfg
|
||||
@@ -72,34 +69,36 @@ func getInstanceLabels(instances []Instance, port int) []*promutils.Labels {
|
||||
for _, instance := range instances {
|
||||
m := promutils.NewLabels(18)
|
||||
m.Add("__address__", discoveryutils.JoinHostPort(instance.MainIP, port))
|
||||
m.Add("__meta_vultr_instance_id", instance.ID)
|
||||
m.Add("__meta_vultr_instance_label", instance.Label)
|
||||
m.Add("__meta_vultr_instance_os", instance.Os)
|
||||
m.Add("__meta_vultr_instance_os_id", strconv.Itoa(instance.OsID))
|
||||
m.Add("__meta_vultr_instance_region", instance.Region)
|
||||
m.Add("__meta_vultr_instance_plan", instance.Plan)
|
||||
m.Add("__meta_vultr_instance_main_ip", instance.MainIP)
|
||||
m.Add("__meta_vultr_instance_internal_ip", instance.InternalIP)
|
||||
m.Add("__meta_vultr_instance_main_ipv6", instance.V6MainIP)
|
||||
m.Add("__meta_vultr_instance_hostname", instance.Hostname)
|
||||
m.Add("__meta_vultr_instance_server_status", instance.ServerStatus)
|
||||
m.Add("__meta_vultr_instance_vcpu_count", strconv.Itoa(instance.VCPUCount))
|
||||
m.Add("__meta_vultr_instance_ram_mb", strconv.Itoa(instance.RAM))
|
||||
m.Add("__meta_vultr_instance_allowed_bandwidth_gb", strconv.Itoa(instance.AllowedBandwidth))
|
||||
m.Add("__meta_vultr_instance_disk_gb", strconv.Itoa(instance.Disk))
|
||||
m.Add("__meta_vultr_instance_hostname", instance.Hostname)
|
||||
m.Add("__meta_vultr_instance_id", instance.ID)
|
||||
m.Add("__meta_vultr_instance_internal_ip", instance.InternalIP)
|
||||
m.Add("__meta_vultr_instance_label", instance.Label)
|
||||
m.Add("__meta_vultr_instance_main_ip", instance.MainIP)
|
||||
m.Add("__meta_vultr_instance_main_ipv6", instance.V6MainIP)
|
||||
m.Add("__meta_vultr_instance_os", instance.OS)
|
||||
m.Add("__meta_vultr_instance_os_id", strconv.Itoa(instance.OSID))
|
||||
m.Add("__meta_vultr_instance_plan", instance.Plan)
|
||||
m.Add("__meta_vultr_instance_region", instance.Region)
|
||||
m.Add("__meta_vultr_instance_ram_mb", strconv.Itoa(instance.RAM))
|
||||
m.Add("__meta_vultr_instance_server_status", instance.ServerStatus)
|
||||
m.Add("__meta_vultr_instance_vcpu_count", strconv.Itoa(instance.VCPUCount))
|
||||
|
||||
// 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
|
||||
m.Add("__meta_vultr_instance_features", features)
|
||||
m.Add("__meta_vultr_instance_features", joinStrings(instance.Features))
|
||||
}
|
||||
|
||||
if len(instance.Tags) > 0 {
|
||||
tags := separator + strings.Join(instance.Tags, separator) + separator
|
||||
m.Add("__meta_vultr_instance_tags", tags)
|
||||
m.Add("__meta_vultr_instance_tags", joinStrings(instance.Tags))
|
||||
}
|
||||
|
||||
ms = append(ms, m)
|
||||
}
|
||||
|
||||
return ms
|
||||
}
|
||||
|
||||
func joinStrings(a []string) string {
|
||||
return "," + strings.Join(a, ",") + ","
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ func TestGetInstanceLabels(t *testing.T) {
|
||||
input := []Instance{
|
||||
{
|
||||
ID: "fake-id-07f7-4b68-88ac-fake-id",
|
||||
Os: "Ubuntu 22.04 x64",
|
||||
OS: "Ubuntu 22.04 x64",
|
||||
RAM: 1024,
|
||||
Disk: 25,
|
||||
MainIP: "64.176.84.27",
|
||||
@@ -25,12 +25,12 @@ func TestGetInstanceLabels(t *testing.T) {
|
||||
InternalIP: "",
|
||||
Hostname: "vultr-sd",
|
||||
Tags: []string{"mock tags"},
|
||||
OsID: 1743,
|
||||
OSID: 1743,
|
||||
Features: []string{"ipv6"},
|
||||
},
|
||||
{
|
||||
ID: "fake-id-07f7-4b68-88ac-fake-id",
|
||||
Os: "Ubuntu 22.04 x64",
|
||||
OS: "Ubuntu 22.04 x64",
|
||||
RAM: 1024,
|
||||
Disk: 25,
|
||||
MainIP: "64.176.84.27",
|
||||
@@ -44,7 +44,7 @@ func TestGetInstanceLabels(t *testing.T) {
|
||||
InternalIP: "",
|
||||
Hostname: "vultr-sd",
|
||||
Tags: []string{"mock tags"},
|
||||
OsID: 1743,
|
||||
OSID: 1743,
|
||||
Features: []string{"ipv6"},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -38,6 +38,11 @@ func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// MustStop stops further usage for sdc.
|
||||
func (sdc *SDConfig) MustStop() {
|
||||
_ = configMap.Delete(sdc)
|
||||
}
|
||||
|
||||
func (cfg *apiConfig) getInstances(folderID string) ([]instance, error) {
|
||||
instancesURL := cfg.serviceEndpoints["compute"] + "/compute/v1/instances"
|
||||
instancesURL += "?folderId=" + url.QueryEscape(folderID)
|
||||
|
||||
Reference in New Issue
Block a user