mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
app/vmagent: fixes azure service discovery pagination
Azure API response with link to the next page was incorrectly validate. Validation used url.Host header to match configure API URL. https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6784
This commit is contained in:
parent
229f8217a0
commit
49f63b2b9a
4 changed files with 40 additions and 9 deletions
|
@ -35,6 +35,7 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/).
|
||||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent/): reduce memory usage when scraping targets with big response body. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6759).
|
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent/): reduce memory usage when scraping targets with big response body. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6759).
|
||||||
* FEATURE: [vmbackup](https://docs.victoriametrics.com/vmbackup/), [vmrestore](https://docs.victoriametrics.com/vmrestore/), [vmbackupmanager](https://docs.victoriametrics.com/vmbackupmanager/): use exponential backoff for retries when uploading or downloading data from S3. This should reduce the number of failed uploads and downloads when S3 is temporarily unavailable. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6732).
|
* FEATURE: [vmbackup](https://docs.victoriametrics.com/vmbackup/), [vmrestore](https://docs.victoriametrics.com/vmrestore/), [vmbackupmanager](https://docs.victoriametrics.com/vmbackupmanager/): use exponential backoff for retries when uploading or downloading data from S3. This should reduce the number of failed uploads and downloads when S3 is temporarily unavailable. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6732).
|
||||||
|
|
||||||
|
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent/) fix service discovery of Azure Virtual Machines for response contains `nextLink`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6784).
|
||||||
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert): respect HTTP headers defined in [notifier configuration file](https://docs.victoriametrics.com/vmalert/#notifier-configuration-file) for each request to notifiers. Previously, this param was ignored by mistake.
|
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert): respect HTTP headers defined in [notifier configuration file](https://docs.victoriametrics.com/vmalert/#notifier-configuration-file) for each request to notifiers. Previously, this param was ignored by mistake.
|
||||||
* BUGFIX: [stream aggregation](https://docs.victoriametrics.com/stream-aggregation/): correctly apply `-streamAggr.dropInputLabels` when global stream deduplication is enabled without `-streamAggr.config`. Previously, `-remoteWrite.streamAggr.dropInputLabels` was used instead.
|
* BUGFIX: [stream aggregation](https://docs.victoriametrics.com/stream-aggregation/): correctly apply `-streamAggr.dropInputLabels` when global stream deduplication is enabled without `-streamAggr.config`. Previously, `-remoteWrite.streamAggr.dropInputLabels` was used instead.
|
||||||
* BUGFIX: [stream aggregation](https://docs.victoriametrics.com/stream-aggregation/): fix command-line flag `-remoteWrite.streamAggr.ignoreFirstIntervals` to accept multiple values and be applied per each corresponding `-remoteWrite.url`. Previously, this flag only could have been used globally for all URLs.
|
* BUGFIX: [stream aggregation](https://docs.victoriametrics.com/stream-aggregation/): fix command-line flag `-remoteWrite.streamAggr.ignoreFirstIntervals` to accept multiple values and be applied per each corresponding `-remoteWrite.url`. Previously, this flag only could have been used globally for all URLs.
|
||||||
|
|
|
@ -67,6 +67,9 @@ type apiConfig struct {
|
||||||
tokenLock sync.Mutex
|
tokenLock sync.Mutex
|
||||||
token string
|
token string
|
||||||
tokenExpireDeadline time.Time
|
tokenExpireDeadline time.Time
|
||||||
|
|
||||||
|
// apiServerHost is only used for verifying the `nextLink` in response of the list API.
|
||||||
|
apiServerHost string
|
||||||
}
|
}
|
||||||
|
|
||||||
type refreshTokenFunc func() (string, time.Duration, error)
|
type refreshTokenFunc func() (string, time.Duration, error)
|
||||||
|
@ -114,8 +117,12 @@ func newAPIConfig(sdc *SDConfig, baseDir string) (*apiConfig, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot create client for %q: %w", env.ResourceManagerEndpoint, err)
|
return nil, fmt.Errorf("cannot create client for %q: %w", env.ResourceManagerEndpoint, err)
|
||||||
}
|
}
|
||||||
|
// It's already verified in discoveryutils.NewClient so no need to check err.
|
||||||
|
u, _ := url.Parse(c.APIServer())
|
||||||
|
|
||||||
cfg := &apiConfig{
|
cfg := &apiConfig{
|
||||||
c: c,
|
c: c,
|
||||||
|
apiServerHost: u.Host,
|
||||||
port: port,
|
port: port,
|
||||||
resourceGroup: sdc.ResourceGroup,
|
resourceGroup: sdc.ResourceGroup,
|
||||||
subscriptionID: sdc.SubscriptionID,
|
subscriptionID: sdc.SubscriptionID,
|
||||||
|
|
|
@ -96,8 +96,8 @@ func visitAllAPIObjects(ac *apiConfig, apiURL string, cb func(data json.RawMessa
|
||||||
return fmt.Errorf("cannot parse nextLink from response %q: %w", lar.NextLink, err)
|
return fmt.Errorf("cannot parse nextLink from response %q: %w", lar.NextLink, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if nextURL.Host != "" && nextURL.Host != ac.c.APIServer() {
|
if nextURL.Host != "" && nextURL.Host != ac.apiServerHost {
|
||||||
return fmt.Errorf("unexpected nextLink host %q, expecting %q", nextURL.Host, ac.c.APIServer())
|
return fmt.Errorf("unexpected nextLink host %q, expecting %q", nextURL.Host, ac.apiServerHost)
|
||||||
}
|
}
|
||||||
|
|
||||||
nextLinkURI = nextURL.RequestURI()
|
nextLinkURI = nextURL.RequestURI()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -13,6 +14,11 @@ import (
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
testServerURL string
|
||||||
|
listAPICall int
|
||||||
|
)
|
||||||
|
|
||||||
func TestGetVirtualMachinesSuccess(t *testing.T) {
|
func TestGetVirtualMachinesSuccess(t *testing.T) {
|
||||||
prettifyVMs := func(src []virtualMachine) string {
|
prettifyVMs := func(src []virtualMachine) string {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
|
@ -41,39 +47,51 @@ func TestGetVirtualMachinesSuccess(t *testing.T) {
|
||||||
}
|
}
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
f := func(name string, expectedVMs []virtualMachine, apiResponses [4]string) {
|
f := func(name string, expectedVMs []virtualMachine, apiResponses [5]string) {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch {
|
switch {
|
||||||
// list vms response
|
// list vms response
|
||||||
case strings.Contains(r.URL.Path, "/providers/Microsoft.Compute/virtualMachines"):
|
case strings.Contains(r.URL.Path, "/providers/Microsoft.Compute/virtualMachines"):
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
fmt.Fprintf(w, apiResponses[0])
|
if listAPICall == 0 {
|
||||||
|
// with nextLink
|
||||||
|
apiResponse := strings.Replace(apiResponses[0], "{nextLinkPlaceHolder}", testServerURL+"/providers/Microsoft.Compute/virtualMachines", 1)
|
||||||
|
fmt.Fprint(w, apiResponse)
|
||||||
|
listAPICall++
|
||||||
|
} else {
|
||||||
|
// without nextLink
|
||||||
|
fmt.Fprint(w, apiResponses[1])
|
||||||
|
}
|
||||||
// list scaleSets response
|
// list scaleSets response
|
||||||
case strings.Contains(r.URL.RequestURI(), "/providers/Microsoft.Compute/virtualMachineScaleSets?api-version=2022-03-01"):
|
case strings.Contains(r.URL.RequestURI(), "/providers/Microsoft.Compute/virtualMachineScaleSets?api-version=2022-03-01"):
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
fmt.Fprintf(w, apiResponses[1])
|
fmt.Fprint(w, apiResponses[2])
|
||||||
// list scalesets vms response
|
// list scalesets vms response
|
||||||
case strings.Contains(r.URL.Path, "/providers/Microsoft.Compute/virtualMachineScaleSets/{virtualMachineScaleSetName}/virtualMach"):
|
case strings.Contains(r.URL.Path, "/providers/Microsoft.Compute/virtualMachineScaleSets/{virtualMachineScaleSetName}/virtualMach"):
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
fmt.Fprintf(w, apiResponses[2])
|
fmt.Fprint(w, apiResponses[3])
|
||||||
// nic response
|
// nic response
|
||||||
case strings.Contains(r.URL.Path, "/networkInterfaces/"):
|
case strings.Contains(r.URL.Path, "/networkInterfaces/"):
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
fmt.Fprintf(w, apiResponses[3])
|
fmt.Fprint(w, apiResponses[4])
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
fmt.Fprintf(w, "API path not found: %s", r.URL.Path)
|
fmt.Fprintf(w, "API path not found: %s", r.URL.Path)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
defer testServer.Close()
|
defer testServer.Close()
|
||||||
|
testServerURL = testServer.URL
|
||||||
c, err := discoveryutils.NewClient(testServer.URL, nil, nil, nil, &promauth.HTTPClientConfig{})
|
c, err := discoveryutils.NewClient(testServer.URL, nil, nil, nil, &promauth.HTTPClientConfig{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error at client create: %s", err)
|
t.Fatalf("unexpected error at client create: %s", err)
|
||||||
}
|
}
|
||||||
|
u, _ := url.Parse(c.APIServer())
|
||||||
|
|
||||||
defer c.Stop()
|
defer c.Stop()
|
||||||
ac := &apiConfig{
|
ac := &apiConfig{
|
||||||
c: c,
|
c: c,
|
||||||
|
apiServerHost: u.Host,
|
||||||
subscriptionID: "some-id",
|
subscriptionID: "some-id",
|
||||||
refreshToken: func() (string, time.Duration, error) {
|
refreshToken: func() (string, time.Duration, error) {
|
||||||
return "auth-token", 0, nil
|
return "auth-token", 0, nil
|
||||||
|
@ -102,7 +120,7 @@ func TestGetVirtualMachinesSuccess(t *testing.T) {
|
||||||
},
|
},
|
||||||
Tags: map[string]string{},
|
Tags: map[string]string{},
|
||||||
},
|
},
|
||||||
}, [4]string{
|
}, [5]string{
|
||||||
`
|
`
|
||||||
{
|
{
|
||||||
"value": [
|
"value": [
|
||||||
|
@ -193,6 +211,10 @@ func TestGetVirtualMachinesSuccess(t *testing.T) {
|
||||||
"name": "{virtualMachineName}"
|
"name": "{virtualMachineName}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"nextLink": "{nextLinkPlaceHolder}"
|
||||||
|
}`,
|
||||||
|
`{
|
||||||
|
"value": [],
|
||||||
"nextLink": ""
|
"nextLink": ""
|
||||||
}`,
|
}`,
|
||||||
`{}`,
|
`{}`,
|
||||||
|
@ -255,7 +277,8 @@ func TestGetVirtualMachinesSuccess(t *testing.T) {
|
||||||
},
|
},
|
||||||
Tags: map[string]string{},
|
Tags: map[string]string{},
|
||||||
},
|
},
|
||||||
}, [4]string{
|
}, [5]string{
|
||||||
|
`{}`,
|
||||||
`{}`,
|
`{}`,
|
||||||
`{
|
`{
|
||||||
"value": [
|
"value": [
|
||||||
|
|
Loading…
Reference in a new issue