Skip to content

Commit 292c332

Browse files
authored
Check if the Fleet API version is different between request and response to detect an api version switch request (#4481)
* Check if the Fleet API version is different between request and response to detect an API version switch request
1 parent bdff582 commit 292c332

File tree

3 files changed

+75
-6
lines changed

3 files changed

+75
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Kind can be one of:
2+
# - breaking-change: a change to previously-documented behavior
3+
# - deprecation: functionality that is being removed in a later release
4+
# - bug-fix: fixes a problem in a previous version
5+
# - enhancement: extends functionality but does not break or fix existing behavior
6+
# - feature: new functionality
7+
# - known-issue: problems that we are aware of in a given version
8+
# - security: impacts on the security of a product or a user’s deployment.
9+
# - upgrade: important information for someone upgrading from a prior version
10+
# - other: does not fit into any of the other categories
11+
kind: bug-fix
12+
13+
# Change summary; a 80ish characters long description of the change.
14+
summary: Reduce false positives in logging an API switch request from Fleet server
15+
16+
# Long description; in case the summary is not enough to describe the change
17+
# this field accommodate a description without length limits.
18+
# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment.
19+
#description:
20+
21+
# Affected component; a word indicating the component this changeset affects.
22+
component: elastic-agent
23+
24+
# PR URL; optional; the PR number that added the changeset.
25+
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
26+
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
27+
# Please provide it if you are adding a fragment for a different PR.
28+
#pr: https://github.com/owner/repo/1234
29+
pr: https://github.com/elastic/elastic-agent/pull/4481
30+
31+
# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
32+
# If not present is automatically filled by the tooling with the issue linked to the PR number.
33+
#issue: https://github.com/owner/repo/1234
34+
issue: https://github.com/elastic/elastic-agent/issues/4477

internal/pkg/fleetapi/client/client_test.go

+31
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,37 @@ func TestElasticApiVersion(t *testing.T) {
183183
}
184184
})
185185

186+
t.Run("verify that we don't log a generic 400 status as a downgrade request", func(t *testing.T) {
187+
ctx, cancel := context.WithCancel(context.Background())
188+
defer cancel()
189+
190+
mux := http.NewServeMux()
191+
mux.HandleFunc("/genericbadrequest", func(writer http.ResponseWriter, request *http.Request) {
192+
assert.Equal(t, request.Header.Get(elasticApiVersionHeaderKey), defaultFleetApiVersion)
193+
// request return a 400 with the defaultFleetApiVersion (just testing that we don't log that as a downgrade request)
194+
writer.Header().Add(elasticApiVersionHeaderKey, defaultFleetApiVersion)
195+
writer.WriteHeader(http.StatusBadRequest)
196+
})
197+
198+
ts := httptest.NewServer(mux)
199+
defer ts.Close()
200+
201+
testLogger, obsLogs := logger.NewTesting("testElasticApiVersion")
202+
203+
clt, err := NewWithConfig(testLogger, remote.Config{
204+
Hosts: []string{ts.URL},
205+
})
206+
require.NoError(t, err)
207+
208+
resp, err := clt.Send(ctx, http.MethodGet, "/genericbadrequest", nil, nil, nil)
209+
if assert.NoError(t, err) {
210+
defer resp.Body.Close()
211+
}
212+
logs := obsLogs.FilterMessageSnippet("fleet requested a different api version").All()
213+
t.Logf("retrieved logs: %v", logs)
214+
assert.Empty(t, logs, "downgrade response should not be logged when the fleet api version is the same as the request")
215+
})
216+
186217
t.Run("verify that we log a downgrade request", func(t *testing.T) {
187218
ctx, cancel := context.WithCancel(context.Background())
188219
defer cancel()

internal/pkg/remote/client.go

+10-6
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727

2828
const (
2929
retryOnBadConnTimeout = 5 * time.Minute
30+
requestIDHeaderName = "X-Request-ID"
3031
)
3132

3233
type wrapperFunc func(rt http.RoundTripper) (http.RoundTripper, error)
@@ -194,7 +195,7 @@ func (c *Client) Send(
194195

195196
// If available, add the request id as an HTTP header
196197
if reqID != "" {
197-
req.Header.Add("X-Request-ID", reqID)
198+
req.Header.Add(requestIDHeaderName, reqID)
198199
}
199200

200201
// copy headers.
@@ -220,27 +221,30 @@ func (c *Client) Send(
220221
c.log.With("error", err).Debugf(msg)
221222
continue
222223
}
223-
c.checkApiVersionHeaders(reqID, resp)
224+
c.checkApiVersionHeaders(req, resp)
224225

225226
return resp, nil
226227
}
227228

228229
return nil, fmt.Errorf("all hosts failed: %w", multiErr)
229230
}
230231

231-
func (c *Client) checkApiVersionHeaders(reqID string, resp *http.Response) {
232+
func (c *Client) checkApiVersionHeaders(req *http.Request, resp *http.Response) {
232233
const elasticApiVersionHeaderKey = "Elastic-Api-Version"
233234
const warningHeaderKey = "Warning"
234235

235236
warning := resp.Header.Get(warningHeaderKey)
237+
requestID := req.Header.Get(requestIDHeaderName)
236238
if warning != "" {
237-
c.log.With("http.request.id", reqID).Warnf("warning in fleet response: %q", warning)
239+
c.log.With("http.request.id", requestID).Warnf("warning in fleet response: %q", warning)
238240
}
239241

240-
if downgradeVersion := resp.Header.Get(elasticApiVersionHeaderKey); resp.StatusCode == http.StatusBadRequest && downgradeVersion != "" {
242+
requestAPIVersion := req.Header.Get(elasticApiVersionHeaderKey)
243+
downgradeVersion := resp.Header.Get(elasticApiVersionHeaderKey)
244+
if resp.StatusCode == http.StatusBadRequest && downgradeVersion != "" && downgradeVersion != requestAPIVersion {
241245
// fleet server requested a downgrade to a different api version, we should bubble up an error until some kind
242246
// of fallback mechanism can instantiate the requested version. This is not yet implemented so we log an error
243-
c.log.With("http.request.id", reqID).Errorf("fleet requested a different api version %q but this is currently not implemented", downgradeVersion)
247+
c.log.With("http.request.id", requestID).Errorf("fleet requested a different api version %q but this is currently not implemented", downgradeVersion)
244248
}
245249
}
246250

0 commit comments

Comments
 (0)