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:
Zhu Jiekun 2024-08-09 21:22:47 +08:00 committed by f41gh7
parent 229f8217a0
commit 49f63b2b9a
No known key found for this signature in database
GPG key ID: 4558311CF775EC72
4 changed files with 40 additions and 9 deletions

View file

@ -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: [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: [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.

View file

@ -67,6 +67,9 @@ type apiConfig struct {
tokenLock sync.Mutex
token string
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)
@ -114,8 +117,12 @@ func newAPIConfig(sdc *SDConfig, baseDir string) (*apiConfig, error) {
if err != nil {
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{
c: c,
apiServerHost: u.Host,
port: port,
resourceGroup: sdc.ResourceGroup,
subscriptionID: sdc.SubscriptionID,

View file

@ -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)
}
if nextURL.Host != "" && nextURL.Host != ac.c.APIServer() {
return fmt.Errorf("unexpected nextLink host %q, expecting %q", nextURL.Host, ac.c.APIServer())
if nextURL.Host != "" && nextURL.Host != ac.apiServerHost {
return fmt.Errorf("unexpected nextLink host %q, expecting %q", nextURL.Host, ac.apiServerHost)
}
nextLinkURI = nextURL.RequestURI()

View file

@ -4,6 +4,7 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"strings"
"testing"
@ -13,6 +14,11 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
)
var (
testServerURL string
listAPICall int
)
func TestGetVirtualMachinesSuccess(t *testing.T) {
prettifyVMs := func(src []virtualMachine) string {
var sb strings.Builder
@ -41,39 +47,51 @@ func TestGetVirtualMachinesSuccess(t *testing.T) {
}
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) {
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
// list vms response
case strings.Contains(r.URL.Path, "/providers/Microsoft.Compute/virtualMachines"):
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
case strings.Contains(r.URL.RequestURI(), "/providers/Microsoft.Compute/virtualMachineScaleSets?api-version=2022-03-01"):
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, apiResponses[1])
fmt.Fprint(w, apiResponses[2])
// list scalesets vms response
case strings.Contains(r.URL.Path, "/providers/Microsoft.Compute/virtualMachineScaleSets/{virtualMachineScaleSetName}/virtualMach"):
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, apiResponses[2])
fmt.Fprint(w, apiResponses[3])
// nic response
case strings.Contains(r.URL.Path, "/networkInterfaces/"):
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, apiResponses[3])
fmt.Fprint(w, apiResponses[4])
default:
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "API path not found: %s", r.URL.Path)
}
}))
defer testServer.Close()
testServerURL = testServer.URL
c, err := discoveryutils.NewClient(testServer.URL, nil, nil, nil, &promauth.HTTPClientConfig{})
if err != nil {
t.Fatalf("unexpected error at client create: %s", err)
}
u, _ := url.Parse(c.APIServer())
defer c.Stop()
ac := &apiConfig{
c: c,
apiServerHost: u.Host,
subscriptionID: "some-id",
refreshToken: func() (string, time.Duration, error) {
return "auth-token", 0, nil
@ -102,7 +120,7 @@ func TestGetVirtualMachinesSuccess(t *testing.T) {
},
Tags: map[string]string{},
},
}, [4]string{
}, [5]string{
`
{
"value": [
@ -193,6 +211,10 @@ func TestGetVirtualMachinesSuccess(t *testing.T) {
"name": "{virtualMachineName}"
}
],
"nextLink": "{nextLinkPlaceHolder}"
}`,
`{
"value": [],
"nextLink": ""
}`,
`{}`,
@ -255,7 +277,8 @@ func TestGetVirtualMachinesSuccess(t *testing.T) {
},
Tags: map[string]string{},
},
}, [4]string{
}, [5]string{
`{}`,
`{}`,
`{
"value": [